Subversion Repositories group.electronics

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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