Subversion Repositories group.electronics

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
20 pfowler 1
/* Name: usbdrvasm15.inc
2
 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3
 * Author: contributed by V. Bosch
4
 * Creation Date: 2007-08-06
5
 * Tabsize: 4
6
 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7
 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
8
 * Revision: $Id$
9
 */
10
 
11
/* Do not link this file! Link usbdrvasm.S instead, which includes the
12
 * appropriate implementation!
13
 */
14
 
15
/*
16
General Description:
17
This file is the 15 MHz version of the asssembler part of the USB driver. It
18
requires a 15 MHz crystal (not a ceramic resonator and not a calibrated RC
19
oscillator).
20
 
21
See usbdrv.h for a description of the entire driver.
22
 
23
Since almost all of this code is timing critical, don't change unless you
24
really know what you are doing! Many parts require not only a maximum number
25
of CPU cycles, but even an exact number of cycles!
26
*/
27
 
28
;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
29
;nominal frequency: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte
30
; Numbers in brackets are clocks counted from center of last sync bit
31
; when instruction starts
32
 
33
;----------------------------------------------------------------------------
34
; order of registers pushed: 
35
;	YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4
36
;----------------------------------------------------------------------------
37
USB_INTR_VECTOR:              
38
    push    YL                   ;2 	push only what is necessary to sync with edge ASAP
39
    in      YL, SREG             ;1 
40
    push    YL                   ;2 
41
;----------------------------------------------------------------------------
42
; Synchronize with sync pattern:
43
;
44
;   sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
45
;   sync up with J to K edge during sync pattern -- use fastest possible loops
46
;The first part waits at most 1 bit long since we must be in sync pattern.
47
;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
48
;waitForJ, ensure that this prerequisite is met.
49
waitForJ:
50
    inc     YL
51
    sbis    USBIN, USBMINUS
52
    brne    waitForJ        ; just make sure we have ANY timeout
53
;-------------------------------------------------------------------------------
54
; The following code results in a sampling window of < 1/4 bit 
55
;	which meets the spec.
56
;-------------------------------------------------------------------------------
57
waitForK:			 ;- 
58
    sbis    USBIN, USBMINUS      ;1 [00] <-- sample
59
    rjmp    foundK               ;2 [01]
60
    sbis    USBIN, USBMINUS	 ;	 <-- sample
61
    rjmp    foundK
62
    sbis    USBIN, USBMINUS	 ;	 <-- sample
63
    rjmp    foundK
64
    sbis    USBIN, USBMINUS	 ;	 <-- sample
65
    rjmp    foundK
66
    sbis    USBIN, USBMINUS	 ;	 <-- sample
67
    rjmp    foundK
68
    sbis    USBIN, USBMINUS	 ;	 <-- sample
69
    rjmp    foundK
70
#if USB_COUNT_SOF
71
    lds     YL, usbSofCount
72
    inc     YL
73
    sts     usbSofCount, YL
74
#endif  /* USB_COUNT_SOF */
75
#ifdef USB_SOF_HOOK
76
    USB_SOF_HOOK
77
#endif
78
    rjmp    sofError
79
;------------------------------------------------------------------------------
80
; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for 
81
;	center sampling] 
82
; 	we have 1 bit time for setup purposes, then sample again. 
83
;	Numbers in brackets are cycles from center of first sync (double K) 
84
;	bit after the instruction
85
;------------------------------------------------------------------------------
86
foundK:                          ;- [02]
87
    lds     YL, usbInputBufOffset;2 [03+04]	tx loop
88
    push    YH                   ;2 [05+06]
89
    clr     YH                   ;1 [07]
90
    subi    YL, lo8(-(usbRxBuf)) ;1 [08] 	[rx loop init]
91
    sbci    YH, hi8(-(usbRxBuf)) ;1 [09] 	[rx loop init]
92
    push    shift                ;2 [10+11]
93
    ser	    shift		 ;1 [12]
94
    sbis    USBIN, USBMINUS      ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early)
95
    rjmp    haveTwoBitsK         ;2 [00] [14]
96
    pop     shift                ;2 	 [15+16] undo the push from before
97
    pop     YH 			 ;2 	 [17+18] undo the push from before
98
    rjmp    waitForK             ;2 	 [19+20] this was not the end of sync, retry
99
; The entire loop from waitForK until rjmp waitForK above must not exceed two
100
; bit times (= 20 cycles).
101
 
102
;----------------------------------------------------------------------------
103
; push more registers and initialize values while we sample the first bits:
104
;----------------------------------------------------------------------------
105
haveTwoBitsK:			;- [01]
106
    push    x1              	;2 [02+03]
107
    push    x2              	;2 [04+05]
108
    push    x3              	;2 [06+07]
109
    push    bitcnt              ;2 [08+09]	
110
    in      x1, USBIN       	;1 [00] [10] <-- sample bit 0
111
    bst     x1, USBMINUS    	;1 [01]
112
    bld     shift, 0        	;1 [02]
113
    push    cnt             	;2 [03+04]
114
    ldi     cnt, USB_BUFSIZE	;1 [05] 
115
    push    x4              	;2 [06+07] tx loop
116
    rjmp    rxLoop          	;2 [08]
117
;----------------------------------------------------------------------------
118
; Receiver loop (numbers in brackets are cycles within byte after instr)
119
;----------------------------------------------------------------------------
120
unstuff0:               	;- [07] (branch taken)
121
    andi    x3, ~0x01   	;1 [08]
122
    mov     x1, x2      	;1 [09] x2 contains last sampled (stuffed) bit
123
    in      x2, USBIN   	;1 [00] [10] <-- sample bit 1 again
124
    andi    x2, USBMASK 	;1 [01]
125
    breq    se0Hop         	;1 [02] SE0 check for bit 1 
126
    ori     shift, 0x01 	;1 [03] 0b00000001
127
    nop				;1 [04]
128
    rjmp    didUnstuff0 	;2 [05]
129
;-----------------------------------------------------
130
unstuff1:               	;- [05] (branch taken)
131
    mov     x2, x1      	;1 [06] x1 contains last sampled (stuffed) bit
132
    andi    x3, ~0x02   	;1 [07]
133
    ori     shift, 0x02 	;1 [08] 0b00000010
134
    nop                 	;1 [09]
135
    in      x1, USBIN   	;1 [00] [10] <-- sample bit 2 again
136
    andi    x1, USBMASK 	;1 [01]
137
    breq    se0Hop         	;1 [02] SE0 check for bit 2 
138
    rjmp    didUnstuff1 	;2 [03]
139
;-----------------------------------------------------
140
unstuff2:               	;- [05] (branch taken)
141
    andi    x3, ~0x04   	;1 [06]
142
    ori     shift, 0x04 	;1 [07] 0b00000100
143
    mov     x1, x2      	;1 [08] x2 contains last sampled (stuffed) bit
144
    nop                 	;1 [09]
145
    in      x2, USBIN   	;1 [00] [10] <-- sample bit 3
146
    andi    x2, USBMASK 	;1 [01]
147
    breq    se0Hop         	;1 [02] SE0 check for bit 3 
148
    rjmp    didUnstuff2 	;2 [03]
149
;-----------------------------------------------------
150
unstuff3:               	;- [00] [10]  (branch taken)
151
    in      x2, USBIN   	;1 [01] [11] <-- sample stuffed bit 3 one cycle too late
152
    andi    x2, USBMASK 	;1 [02]
153
    breq    se0Hop         	;1 [03] SE0 check for stuffed bit 3 
154
    andi    x3, ~0x08   	;1 [04]
155
    ori     shift, 0x08 	;1 [05] 0b00001000
156
    rjmp    didUnstuff3 	;2 [06]
157
;----------------------------------------------------------------------------
158
; extra jobs done during bit interval:
159
;
160
; bit 0:    store, clear [SE0 is unreliable here due to bit dribbling in hubs], 
161
; 		overflow check, jump to the head of rxLoop
162
; bit 1:    SE0 check
163
; bit 2:    SE0 check, recovery from delay [bit 0 tasks took too long]
164
; bit 3:    SE0 check, recovery from delay [bit 0 tasks took too long]
165
; bit 4:    SE0 check, none
166
; bit 5:    SE0 check, none
167
; bit 6:    SE0 check, none
168
; bit 7:    SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others
169
;----------------------------------------------------------------------------
170
rxLoop:				;- [09]
171
    in      x2, USBIN   	;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed)
172
    andi    x2, USBMASK 	;1 [01]
173
    brne    SkipSe0Hop		;1 [02]
174
se0Hop:				;- [02]
175
    rjmp    se0         	;2 [03] SE0 check for bit 1 
176
SkipSe0Hop:			;- [03]
177
    ser     x3          	;1 [04]
178
    andi    shift, 0xf9 	;1 [05] 0b11111001
179
    breq    unstuff0    	;1 [06]
180
didUnstuff0:			;- [06]
181
    eor     x1, x2      	;1 [07]
182
    bst     x1, USBMINUS	;1 [08]
183
    bld     shift, 1    	;1 [09] 
184
    in      x1, USBIN   	;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed)
185
    andi    x1, USBMASK 	;1 [01]
186
    breq    se0Hop         	;1 [02] SE0 check for bit 2 
187
    andi    shift, 0xf3 	;1 [03] 0b11110011
188
    breq    unstuff1    	;1 [04] do remaining work for bit 1
189
didUnstuff1:			;- [04]
190
    eor     x2, x1      	;1 [05]
191
    bst     x2, USBMINUS	;1 [06]
192
    bld     shift, 2    	;1 [07]
193
    nop2			;2 [08+09]
194
    in      x2, USBIN   	;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed)
195
    andi    x2, USBMASK 	;1 [01]
196
    breq    se0Hop         	;1 [02] SE0 check for bit 3 
197
    andi    shift, 0xe7 	;1 [03] 0b11100111
198
    breq    unstuff2    	;1 [04]
199
didUnstuff2:			;- [04]
200
    eor     x1, x2      	;1 [05]
201
    bst     x1, USBMINUS	;1 [06]
202
    bld     shift, 3    	;1 [07]
203
didUnstuff3:			;- [07]
204
    andi    shift, 0xcf 	;1 [08] 0b11001111
205
    breq    unstuff3    	;1 [09]
206
    in      x1, USBIN   	;1 [00] [10] <-- sample bit 4
207
    andi    x1, USBMASK 	;1 [01]
208
    breq    se0Hop         	;1 [02] SE0 check for bit 4
209
    eor     x2, x1      	;1 [03]
210
    bst     x2, USBMINUS	;1 [04]
211
    bld     shift, 4    	;1 [05]
212
didUnstuff4:			;- [05]
213
    andi    shift, 0x9f 	;1 [06] 0b10011111
214
    breq    unstuff4    	;1 [07]
215
    nop2			;2 [08+09]
216
    in      x2, USBIN   	;1 [00] [10] <-- sample bit 5
217
    andi    x2, USBMASK 	;1 [01]
218
    breq    se0         	;1 [02] SE0 check for bit 5
219
    eor     x1, x2      	;1 [03]
220
    bst     x1, USBMINUS	;1 [04]
221
    bld     shift, 5    	;1 [05]
222
didUnstuff5:			;- [05]
223
    andi    shift, 0x3f 	;1 [06] 0b00111111
224
    breq    unstuff5    	;1 [07]
225
    nop2			;2 [08+09]
226
    in      x1, USBIN   	;1 [00] [10] <-- sample bit 6
227
    andi    x1, USBMASK 	;1 [01]
228
    breq    se0         	;1 [02] SE0 check for bit 6
229
    eor     x2, x1      	;1 [03]
230
    bst     x2, USBMINUS	;1 [04]
231
    bld     shift, 6   	 	;1 [05]
232
didUnstuff6:			;- [05]
233
    cpi     shift, 0x02 	;1 [06] 0b00000010
234
    brlo    unstuff6    	;1 [07]
235
    nop2			;2 [08+09]
236
    in      x2, USBIN   	;1 [00] [10] <-- sample bit 7
237
    andi    x2, USBMASK 	;1 [01]
238
    breq    se0         	;1 [02] SE0 check for bit 7
239
    eor     x1, x2      	;1 [03]
240
    bst     x1, USBMINUS	;1 [04]
241
    bld     shift, 7    	;1 [05]
242
didUnstuff7:			;- [05] 
243
    cpi     shift, 0x04 	;1 [06] 0b00000100
244
    brlo    unstuff7		;1 [07]
245
    eor     x3, shift   	;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others
246
    nop				;1 [09]
247
    in      x1, USBIN   	;1 [00]	[10] <-- sample bit 0
248
    st      y+, x3      	;2 [01+02] store data
249
    eor     x2, x1      	;1 [03]
250
    bst     x2, USBMINUS	;1 [04]
251
    bld     shift, 0    	;1 [05]
252
    subi    cnt, 1		;1 [06]
253
    brcs    overflow	;1 [07]
254
    rjmp    rxLoop		;2 [08]
255
;-----------------------------------------------------
256
unstuff4:               	;- [08] 
257
    andi    x3, ~0x10   	;1 [09]
258
    in      x1, USBIN   	;1 [00] [10] <-- sample stuffed bit 4
259
    andi    x1, USBMASK 	;1 [01]
260
    breq    se0         	;1 [02] SE0 check for stuffed bit 4
261
    ori     shift, 0x10 	;1 [03]
262
    rjmp    didUnstuff4 	;2 [04]
263
;-----------------------------------------------------
264
unstuff5:               	;- [08] 
265
    ori     shift, 0x20 	;1 [09]
266
    in      x2, USBIN   	;1 [00] [10] <-- sample stuffed bit 5
267
    andi    x2, USBMASK 	;1 [01]
268
    breq    se0         	;1 [02] SE0 check for stuffed bit 5
269
    andi    x3, ~0x20   	;1 [03]
270
    rjmp    didUnstuff5		;2 [04]
271
;-----------------------------------------------------
272
unstuff6:               	;- [08] 
273
    andi    x3, ~0x40   	;1 [09]
274
    in      x1, USBIN   	;1 [00] [10] <-- sample stuffed bit 6
275
    andi    x1, USBMASK 	;1 [01]
276
    breq    se0         	;1 [02] SE0 check for stuffed bit 6
277
    ori     shift, 0x40 	;1 [03]
278
    rjmp    didUnstuff6 	;2 [04]
279
;-----------------------------------------------------
280
unstuff7:			;- [08]
281
    andi    x3, ~0x80   	;1 [09]
282
    in      x2, USBIN   	;1 [00] [10] <-- sample stuffed bit 7
283
    andi    x2, USBMASK 	;1 [01]
284
    breq    se0         	;1 [02] SE0 check for stuffed bit 7
285
    ori     shift, 0x80 	;1 [03]
286
    rjmp    didUnstuff7 	;2 [04]
287
 
288
macro POP_STANDARD ; 16 cycles
289
    pop     x4    
290
    pop     cnt
291
    pop     bitcnt
292
    pop     x3
293
    pop     x2
294
    pop     x1
295
    pop     shift
296
    pop     YH
297
    endm
298
macro POP_RETI     ; 5 cycles
299
    pop     YL
300
    out     SREG, YL
301
    pop     YL
302
    endm
303
 
304
#include "asmcommon.inc"
305
 
306
;---------------------------------------------------------------------------
307
; USB spec says:
308
; idle = J
309
; J = (D+ = 0), (D- = 1)
310
; K = (D+ = 1), (D- = 0)
311
; Spec allows 7.5 bit times from EOP to SOP for replies
312
;---------------------------------------------------------------------------
313
bitstuffN:		    	;- [04]
314
    eor     x1, x4          	;1 [05]
315
    clr	    x2			;1 [06]
316
    nop				;1 [07]
317
    rjmp    didStuffN       	;1 [08]
318
;---------------------------------------------------------------------------    
319
bitstuff6:		    	;- [04]
320
    eor     x1, x4          	;1 [05]
321
    clr	    x2			;1 [06]
322
    rjmp    didStuff6       	;1 [07]
323
;---------------------------------------------------------------------------
324
bitstuff7:		    	;- [02]
325
    eor     x1, x4          	;1 [03]
326
    clr	    x2			;1 [06]
327
    nop			    	;1 [05]
328
    rjmp    didStuff7       	;1 [06]
329
;---------------------------------------------------------------------------
330
sendNakAndReti:			;- [-19]
331
    ldi     x3, USBPID_NAK  	;1 [-18]
332
    rjmp    sendX3AndReti   	;1 [-17]
333
;---------------------------------------------------------------------------
334
sendAckAndReti:			;- [-17]
335
    ldi     cnt, USBPID_ACK 	;1 [-16]
336
sendCntAndReti:			;- [-16]
337
    mov     x3, cnt         	;1 [-15]
338
sendX3AndReti:			;- [-15]
339
    ldi     YL, 20          	;1 [-14] x3==r20 address is 20
340
    ldi     YH, 0           	;1 [-13]
341
    ldi     cnt, 2          	;1 [-12]
342
;   rjmp    usbSendAndReti      fallthrough
343
;---------------------------------------------------------------------------
344
;usbSend:
345
;pointer to data in 'Y'
346
;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
347
;uses: x1...x4, btcnt, shift, cnt, Y
348
;Numbers in brackets are time since first bit of sync pattern is sent
349
;We need not to match the transfer rate exactly because the spec demands 
350
;only 1.5% precision anyway.
351
usbSendAndReti:             	;- [-13] 13 cycles until SOP
352
    in      x2, USBDDR      	;1 [-12]
353
    ori     x2, USBMASK     	;1 [-11]
354
    sbi     USBOUT, USBMINUS	;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups)
355
    in      x1, USBOUT      	;1 [-08] port mirror for tx loop
356
    out     USBDDR, x2      	;1 [-07] <- acquire bus
357
	; need not init x2 (bitstuff history) because sync starts with 0 
358
    ldi     x4, USBMASK     	;1 [-06] 	exor mask
359
    ldi     shift, 0x80     	;1 [-05] 	sync byte is first byte sent
360
    ldi     bitcnt, 6    	;1 [-04] 
361
txBitLoop:		    	;- [-04] [06]
362
    sbrs    shift, 0        	;1 [-03] [07]
363
    eor     x1, x4          	;1 [-02] [08] 
364
    ror     shift           	;1 [-01] [09]  
365
didStuffN:		    	;-       [09]
366
    out     USBOUT, x1      	;1 [00]  [10] <-- out N
367
    ror     x2              	;1 [01]
368
    cpi     x2, 0xfc        	;1 [02]
369
    brcc    bitstuffN       	;1 [03]
370
    dec     bitcnt          	;1 [04]
371
    brne    txBitLoop       	;1 [05]
372
    sbrs    shift, 0        	;1 [06]
373
    eor     x1, x4          	;1 [07]
374
    ror     shift           	;1 [08]
375
didStuff6:			;- [08]
376
    nop				;1 [09]
377
    out     USBOUT, x1      	;1 [00] [10] <-- out 6
378
    ror     x2              	;1 [01] 
379
    cpi     x2, 0xfc        	;1 [02]
380
    brcc    bitstuff6       	;1 [03]
381
    sbrs    shift, 0        	;1 [04]
382
    eor     x1, x4          	;1 [05]
383
    ror     shift           	;1 [06]
384
    ror     x2              	;1 [07]
385
didStuff7:			;- [07]
386
    ldi     bitcnt, 6    	;1 [08]
387
    cpi     x2, 0xfc        	;1 [09]
388
    out     USBOUT, x1      	;1 [00] [10] <-- out 7
389
    brcc    bitstuff7       	;1 [01]
390
    ld      shift, y+       	;2 [02+03]
391
    dec     cnt             	;1 [04]
392
    brne    txBitLoop      	;1 [05]
393
makeSE0:
394
    cbr     x1, USBMASK     	;1 [06] 	prepare SE0 [spec says EOP may be 19 to 23 cycles]
395
    lds     x2, usbNewDeviceAddr;2 [07+08]
396
    lsl     x2                  ;1 [09] we compare with left shifted address
397
;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
398
;set address only after data packet was sent, not after handshake
399
    out     USBOUT, x1      	;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle
400
    subi    YL, 20 + 2          ;1 [01] Only assign address on data packets, not ACK/NAK in x3
401
    sbci    YH, 0           	;1 [02]
402
    breq    skipAddrAssign  	;1 [03]
403
    sts     usbDeviceAddr, x2	;2 [04+05] if not skipped: SE0 is one cycle longer
404
;----------------------------------------------------------------------------
405
;end of usbDeviceAddress transfer
406
skipAddrAssign:				;- [03/04]
407
    ldi     x2, 1<<USB_INTR_PENDING_BIT	;1 [05] int0 occurred during TX -- clear pending flag
408
    USB_STORE_PENDING(x2)           ;1 [06]
409
    ori     x1, USBIDLE     		;1 [07]
410
    in      x2, USBDDR      		;1 [08]
411
    cbr     x2, USBMASK     		;1 [09] set both pins to input
412
    mov     x3, x1          		;1 [10]
413
    cbr     x3, USBMASK     		;1 [11] configure no pullup on both pins
414
    ldi     x4, 3           		;1 [12]
415
se0Delay:				;- [12] [15] 
416
    dec     x4              		;1 [13] [16] 
417
    brne    se0Delay        		;1 [14] [17] 
418
    nop2				;2      [18+19]
419
    out     USBOUT, x1      		;1      [20] <--out J (idle) -- end of SE0 (EOP sig.)
420
    out     USBDDR, x2      		;1      [21] <--release bus now
421
    out     USBOUT, x3      		;1      [22] <--ensure no pull-up resistors are active
422
    rjmp    doReturn			;1	[23]
423
;---------------------------------------------------------------------------