]> git.cryptolib.org Git - labortage2013badge.git/blob - firmware/usbdrv/usbdrvasm12.inc
whitespace editing / typo correction
[labortage2013badge.git] / firmware / usbdrv / usbdrvasm12.inc
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