Subversion Repositories group.NITPanels

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
8 pfowler 1
/* Name: usbdrvasm12.inc
2
 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3
 * Author: Christian Starkjohann
4
 * Creation Date: 2004-12-29
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 12 MHz version of the asssembler part of the USB driver. It
17
requires a 12 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
Timing constraints according to spec (in bit times):
28
timing subject                                      min max    CPUcycles
29
---------------------------------------------------------------------------
30
EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2   16     16-128
31
EOP of IN to sync pattern of DATA0 (rx, then tx)    2   7.5    16-60
32
DATAx (rx) to ACK/NAK/STALL (tx)                    2   7.5    16-60
33
*/
34
 
35
;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
36
;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
37
;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable
38
;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes
39
;Numbers in brackets are maximum cycles since SOF.
40
USB_INTR_VECTOR:
41
;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt
42
    push    YL              ;2 [35] push only what is necessary to sync with edge ASAP
43
    in      YL, SREG        ;1 [37]
44
    push    YL              ;2 [39]
45
;----------------------------------------------------------------------------
46
; Synchronize with sync pattern:
47
;----------------------------------------------------------------------------
48
;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
49
;sync up with J to K edge during sync pattern -- use fastest possible loops
50
;The first part waits at most 1 bit long since we must be in sync pattern.
51
;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
52
;waitForJ, ensure that this prerequisite is met.
53
waitForJ:
54
    inc     YL
55
    sbis    USBIN, USBMINUS
56
    brne    waitForJ        ; just make sure we have ANY timeout
57
waitForK:
58
;The following code results in a sampling window of 1/4 bit which meets the spec.
59
    sbis    USBIN, USBMINUS
60
    rjmp    foundK
61
    sbis    USBIN, USBMINUS
62
    rjmp    foundK
63
    sbis    USBIN, USBMINUS
64
    rjmp    foundK
65
    sbis    USBIN, USBMINUS
66
    rjmp    foundK
67
    sbis    USBIN, USBMINUS
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
foundK:
79
;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
80
;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
81
;are cycles from center of first sync (double K) bit after the instruction
82
    push    YH                  ;2 [2]
83
    lds     YL, usbInputBufOffset;2 [4]
84
    clr     YH                  ;1 [5]
85
    subi    YL, lo8(-(usbRxBuf));1 [6]
86
    sbci    YH, hi8(-(usbRxBuf));1 [7]
87
 
88
    sbis    USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early]
89
    rjmp    haveTwoBitsK    ;2 [10]
90
    pop     YH              ;2 [11] undo the push from before
91
    rjmp    waitForK        ;2 [13] this was not the end of sync, retry
92
haveTwoBitsK:
93
;----------------------------------------------------------------------------
94
; push more registers and initialize values while we sample the first bits:
95
;----------------------------------------------------------------------------
96
    push    shift           ;2 [16]
97
    push    x1              ;2 [12]
98
    push    x2              ;2 [14]
99
 
100
    in      x1, USBIN       ;1 [17] <-- sample bit 0
101
    ldi     shift, 0xff     ;1 [18]
102
    bst     x1, USBMINUS    ;1 [19]
103
    bld     shift, 0        ;1 [20]
104
    push    x3              ;2 [22]
105
    push    cnt             ;2 [24]
106
 
107
    in      x2, USBIN       ;1 [25] <-- sample bit 1
108
    ser     x3              ;1 [26] [inserted init instruction]
109
    eor     x1, x2          ;1 [27]
110
    bst     x1, USBMINUS    ;1 [28]
111
    bld     shift, 1        ;1 [29]
112
    ldi     cnt, USB_BUFSIZE;1 [30] [inserted init instruction]
113
    rjmp    rxbit2          ;2 [32]
114
 
115
;----------------------------------------------------------------------------
116
; Receiver loop (numbers in brackets are cycles within byte after instr)
117
;----------------------------------------------------------------------------
118
 
119
unstuff0:               ;1 (branch taken)
120
    andi    x3, ~0x01   ;1 [15]
121
    mov     x1, x2      ;1 [16] x2 contains last sampled (stuffed) bit
122
    in      x2, USBIN   ;1 [17] <-- sample bit 1 again
123
    ori     shift, 0x01 ;1 [18]
124
    rjmp    didUnstuff0 ;2 [20]
125
 
126
unstuff1:               ;1 (branch taken)
127
    mov     x2, x1      ;1 [21] x1 contains last sampled (stuffed) bit
128
    andi    x3, ~0x02   ;1 [22]
129
    ori     shift, 0x02 ;1 [23]
130
    nop                 ;1 [24]
131
    in      x1, USBIN   ;1 [25] <-- sample bit 2 again
132
    rjmp    didUnstuff1 ;2 [27]
133
 
134
unstuff2:               ;1 (branch taken)
135
    andi    x3, ~0x04   ;1 [29]
136
    ori     shift, 0x04 ;1 [30]
137
    mov     x1, x2      ;1 [31] x2 contains last sampled (stuffed) bit
138
    nop                 ;1 [32]
139
    in      x2, USBIN   ;1 [33] <-- sample bit 3
140
    rjmp    didUnstuff2 ;2 [35]
141
 
142
unstuff3:               ;1 (branch taken)
143
    in      x2, USBIN   ;1 [34] <-- sample stuffed bit 3 [one cycle too late]
144
    andi    x3, ~0x08   ;1 [35]
145
    ori     shift, 0x08 ;1 [36]
146
    rjmp    didUnstuff3 ;2 [38]
147
 
148
unstuff4:               ;1 (branch taken)
149
    andi    x3, ~0x10   ;1 [40]
150
    in      x1, USBIN   ;1 [41] <-- sample stuffed bit 4
151
    ori     shift, 0x10 ;1 [42]
152
    rjmp    didUnstuff4 ;2 [44]
153
 
154
unstuff5:               ;1 (branch taken)
155
    andi    x3, ~0x20   ;1 [48]
156
    in      x2, USBIN   ;1 [49] <-- sample stuffed bit 5
157
    ori     shift, 0x20 ;1 [50]
158
    rjmp    didUnstuff5 ;2 [52]
159
 
160
unstuff6:               ;1 (branch taken)
161
    andi    x3, ~0x40   ;1 [56]
162
    in      x1, USBIN   ;1 [57] <-- sample stuffed bit 6
163
    ori     shift, 0x40 ;1 [58]
164
    rjmp    didUnstuff6 ;2 [60]
165
 
166
; extra jobs done during bit interval:
167
; bit 0:    store, clear [SE0 is unreliable here due to bit dribbling in hubs]
168
; bit 1:    se0 check
169
; bit 2:    overflow check
170
; bit 3:    recovery from delay [bit 0 tasks took too long]
171
; bit 4:    none
172
; bit 5:    none
173
; bit 6:    none
174
; bit 7:    jump, eor
175
rxLoop:
176
    eor     x3, shift   ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others
177
    in      x1, USBIN   ;1 [1] <-- sample bit 0
178
    st      y+, x3      ;2 [3] store data
179
    ser     x3          ;1 [4]
180
    nop                 ;1 [5]
181
    eor     x2, x1      ;1 [6]
182
    bst     x2, USBMINUS;1 [7]
183
    bld     shift, 0    ;1 [8]
184
    in      x2, USBIN   ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed)
185
    andi    x2, USBMASK ;1 [10]
186
    breq    se0         ;1 [11] SE0 check for bit 1
187
    andi    shift, 0xf9 ;1 [12]
188
didUnstuff0:
189
    breq    unstuff0    ;1 [13]
190
    eor     x1, x2      ;1 [14]
191
    bst     x1, USBMINUS;1 [15]
192
    bld     shift, 1    ;1 [16]
193
rxbit2:
194
    in      x1, USBIN   ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed)
195
    andi    shift, 0xf3 ;1 [18]
196
    breq    unstuff1    ;1 [19] do remaining work for bit 1
197
didUnstuff1:
198
    subi    cnt, 1      ;1 [20]
199
    brcs    overflow    ;1 [21] loop control
200
    eor     x2, x1      ;1 [22]
201
    bst     x2, USBMINUS;1 [23]
202
    bld     shift, 2    ;1 [24]
203
    in      x2, USBIN   ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed)
204
    andi    shift, 0xe7 ;1 [26]
205
    breq    unstuff2    ;1 [27]
206
didUnstuff2:
207
    eor     x1, x2      ;1 [28]
208
    bst     x1, USBMINUS;1 [29]
209
    bld     shift, 3    ;1 [30]
210
didUnstuff3:
211
    andi    shift, 0xcf ;1 [31]
212
    breq    unstuff3    ;1 [32]
213
    in      x1, USBIN   ;1 [33] <-- sample bit 4
214
    eor     x2, x1      ;1 [34]
215
    bst     x2, USBMINUS;1 [35]
216
    bld     shift, 4    ;1 [36]
217
didUnstuff4:
218
    andi    shift, 0x9f ;1 [37]
219
    breq    unstuff4    ;1 [38]
220
    nop2                ;2 [40]
221
    in      x2, USBIN   ;1 [41] <-- sample bit 5
222
    eor     x1, x2      ;1 [42]
223
    bst     x1, USBMINUS;1 [43]
224
    bld     shift, 5    ;1 [44]
225
didUnstuff5:
226
    andi    shift, 0x3f ;1 [45]
227
    breq    unstuff5    ;1 [46]
228
    nop2                ;2 [48]
229
    in      x1, USBIN   ;1 [49] <-- sample bit 6
230
    eor     x2, x1      ;1 [50]
231
    bst     x2, USBMINUS;1 [51]
232
    bld     shift, 6    ;1 [52]
233
didUnstuff6:
234
    cpi     shift, 0x02 ;1 [53]
235
    brlo    unstuff6    ;1 [54]
236
    nop2                ;2 [56]
237
    in      x2, USBIN   ;1 [57] <-- sample bit 7
238
    eor     x1, x2      ;1 [58]
239
    bst     x1, USBMINUS;1 [59]
240
    bld     shift, 7    ;1 [60]
241
didUnstuff7:
242
    cpi     shift, 0x04 ;1 [61]
243
    brsh    rxLoop      ;2 [63] loop control
244
unstuff7:
245
    andi    x3, ~0x80   ;1 [63]
246
    ori     shift, 0x80 ;1 [64]
247
    in      x2, USBIN   ;1 [65] <-- sample stuffed bit 7
248
    nop                 ;1 [66]
249
    rjmp    didUnstuff7 ;2 [68]
250
 
251
macro POP_STANDARD ; 12 cycles
252
    pop     cnt
253
    pop     x3
254
    pop     x2
255
    pop     x1
256
    pop     shift
257
    pop     YH
258
    endm
259
macro POP_RETI     ; 5 cycles
260
    pop     YL
261
    out     SREG, YL
262
    pop     YL
263
    endm
264
 
265
#include "asmcommon.inc"
266
 
267
;----------------------------------------------------------------------------
268
; Transmitting data
269
;----------------------------------------------------------------------------
270
 
271
txByteLoop:
272
txBitloop:
273
stuffN1Delay:                   ;     [03]
274
    ror     shift               ;[-5] [11] [59]
275
    brcc    doExorN1            ;[-4]      [60]
276
    subi    x4, 1               ;[-3]
277
    brne    commonN1            ;[-2]
278
    lsl     shift               ;[-1] compensate ror after rjmp stuffDelay
279
    nop                         ;[00] stuffing consists of just waiting 8 cycles
280
    rjmp    stuffN1Delay        ;[01] after ror, C bit is reliably clear
281
 
282
sendNakAndReti:                 ;0 [-19] 19 cycles until SOP
283
    ldi     x3, USBPID_NAK      ;1 [-18]
284
    rjmp    usbSendX3           ;2 [-16]
285
sendAckAndReti:                 ;0 [-19] 19 cycles until SOP
286
    ldi     x3, USBPID_ACK      ;1 [-18]
287
    rjmp    usbSendX3           ;2 [-16]
288
sendCntAndReti:                 ;0 [-17] 17 cycles until SOP
289
    mov     x3, cnt             ;1 [-16]
290
usbSendX3:                      ;0 [-16]
291
    ldi     YL, 20              ;1 [-15] 'x3' is R20
292
    ldi     YH, 0               ;1 [-14]
293
    ldi     cnt, 2              ;1 [-13]
294
;   rjmp    usbSendAndReti      fallthrough
295
 
296
; USB spec says:
297
; idle = J
298
; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
299
; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
300
; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
301
 
302
;usbSend:
303
;pointer to data in 'Y'
304
;number of bytes in 'cnt' -- including sync byte
305
;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt]
306
;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
307
usbSendAndReti:
308
    in      x2, USBDDR          ;[-12] 12 cycles until SOP
309
    ori     x2, USBMASK         ;[-11]
310
    sbi     USBOUT, USBMINUS    ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
311
    out     USBDDR, x2          ;[-8] <--- acquire bus
312
    in      x1, USBOUT          ;[-7] port mirror for tx loop
313
    ldi     shift, 0x40         ;[-6] sync byte is first byte sent (we enter loop after ror)
314
    ldi     x2, USBMASK         ;[-5]
315
    push    x4                  ;[-4]
316
doExorN1:
317
    eor     x1, x2              ;[-2] [06] [62]
318
    ldi     x4, 6               ;[-1] [07] [63]
319
commonN1:
320
stuffN2Delay:
321
    out     USBOUT, x1          ;[00] [08] [64] <--- set bit
322
    ror     shift               ;[01]
323
    brcc    doExorN2            ;[02]
324
    subi    x4, 1               ;[03]
325
    brne    commonN2            ;[04]
326
    lsl     shift               ;[05] compensate ror after rjmp stuffDelay
327
    rjmp    stuffN2Delay        ;[06] after ror, C bit is reliably clear
328
doExorN2:
329
    eor     x1, x2              ;[04] [12]
330
    ldi     x4, 6               ;[05] [13]
331
commonN2:
332
    nop                         ;[06] [14]
333
    subi    cnt, 171            ;[07] [15] trick: (3 * 171) & 0xff = 1
334
    out     USBOUT, x1          ;[08] [16] <--- set bit
335
    brcs    txBitloop           ;[09]      [25] [41]
336
 
337
stuff6Delay:
338
    ror     shift               ;[42] [50]
339
    brcc    doExor6             ;[43]
340
    subi    x4, 1               ;[44]
341
    brne    common6             ;[45]
342
    lsl     shift               ;[46] compensate ror after rjmp stuffDelay
343
    nop                         ;[47] stuffing consists of just waiting 8 cycles
344
    rjmp    stuff6Delay         ;[48] after ror, C bit is reliably clear
345
doExor6:
346
    eor     x1, x2              ;[45] [53]
347
    ldi     x4, 6               ;[46]
348
common6:
349
stuff7Delay:
350
    ror     shift               ;[47] [55]
351
    out     USBOUT, x1          ;[48] <--- set bit
352
    brcc    doExor7             ;[49]
353
    subi    x4, 1               ;[50]
354
    brne    common7             ;[51]
355
    lsl     shift               ;[52] compensate ror after rjmp stuffDelay
356
    rjmp    stuff7Delay         ;[53] after ror, C bit is reliably clear
357
doExor7:
358
    eor     x1, x2              ;[51] [59]
359
    ldi     x4, 6               ;[52]
360
common7:
361
    ld      shift, y+           ;[53]
362
    tst     cnt                 ;[55]
363
    out     USBOUT, x1          ;[56] <--- set bit
364
    brne    txByteLoop          ;[57]
365
 
366
;make SE0:
367
    cbr     x1, USBMASK         ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles]
368
    lds     x2, usbNewDeviceAddr;[59]
369
    lsl     x2                  ;[61] we compare with left shifted address
370
    subi    YL, 2 + 20          ;[62] Only assign address on data packets, not ACK/NAK in x3
371
    sbci    YH, 0               ;[63]
372
    out     USBOUT, x1          ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
373
;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
374
;set address only after data packet was sent, not after handshake
375
    breq    skipAddrAssign      ;[01]
376
    sts     usbDeviceAddr, x2   ; if not skipped: SE0 is one cycle longer
377
skipAddrAssign:
378
;end of usbDeviceAddress transfer
379
    ldi     x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
380
    USB_STORE_PENDING(x2)       ;[04]
381
    ori     x1, USBIDLE         ;[05]
382
    in      x2, USBDDR          ;[06]
383
    cbr     x2, USBMASK         ;[07] set both pins to input
384
    mov     x3, x1              ;[08]
385
    cbr     x3, USBMASK         ;[09] configure no pullup on both pins
386
    pop     x4                  ;[10]
387
    nop2                        ;[12]
388
    nop2                        ;[14]
389
    out     USBOUT, x1          ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
390
    out     USBDDR, x2          ;[17] <-- release bus now
391
    out     USBOUT, x3          ;[18] <-- ensure no pull-up resistors are active
392
    rjmp    doReturn