]> git.cryptolib.org Git - labortage2013badge.git/blob - firmware/usbdrv/usbdrvasm165.inc
initial - non working - stuff
[labortage2013badge.git] / firmware / usbdrv / usbdrvasm165.inc
1 /* Name: usbdrvasm165.inc
2  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3  * Author: Christian Starkjohann
4  * Creation Date: 2007-04-22
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 16.5 MHz version of the USB driver. It is intended for the
17 ATTiny45 and similar controllers running on 16.5 MHz internal RC oscillator.
18 This version contains a phase locked loop in the receiver routine to cope with
19 slight clock rate deviations of up to +/- 1%.
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 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
29 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
30 ;max allowable interrupt latency: 59 cycles -> max 52 cycles interrupt disable
31 ;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes
32 ;nominal frequency: 16.5 MHz -> 11 cycles per bit
33 ; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%)
34 ; Numbers in brackets are clocks counted from center of last sync bit
35 ; when instruction starts
36
37
38 USB_INTR_VECTOR:
39 ;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt
40     push    YL                  ;[-23] push only what is necessary to sync with edge ASAP
41     in      YL, SREG            ;[-21]
42     push    YL                  ;[-20]
43 ;----------------------------------------------------------------------------
44 ; Synchronize with sync pattern:
45 ;----------------------------------------------------------------------------
46 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
47 ;sync up with J to K edge during sync pattern -- use fastest possible loops
48 ;The first part waits at most 1 bit long since we must be in sync pattern.
49 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
50 ;waitForJ, ensure that this prerequisite is met.
51 waitForJ:
52     inc     YL
53     sbis    USBIN, USBMINUS
54     brne    waitForJ        ; just make sure we have ANY timeout
55 waitForK:
56 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
57     sbis    USBIN, USBMINUS     ;[-15]
58     rjmp    foundK              ;[-14]
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:                         ;[-12]
79 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 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    r0                  ;[-12]
83 ;   [---]                       ;[-11]
84     push    YH                  ;[-10]
85 ;   [---]                       ;[-9]
86     lds     YL, usbInputBufOffset;[-8]
87 ;   [---]                       ;[-7]
88     clr     YH                  ;[-6]
89     subi    YL, lo8(-(usbRxBuf));[-5] [rx loop init]
90     sbci    YH, hi8(-(usbRxBuf));[-4] [rx loop init]
91     mov     r0, x2              ;[-3] [rx loop init]
92     sbis    USBIN, USBMINUS     ;[-2] we want two bits K (sample 2 cycles too early)
93     rjmp    haveTwoBitsK        ;[-1]
94     pop     YH                  ;[0] undo the pushes from before
95     pop     r0                  ;[2]
96     rjmp    waitForK            ;[4] this was not the end of sync, retry
97 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
98 ; bit times (= 22 cycles).
99
100 ;----------------------------------------------------------------------------
101 ; push more registers and initialize values while we sample the first bits:
102 ;----------------------------------------------------------------------------
103 haveTwoBitsK:               ;[1]
104     push    shift           ;[1]
105     push    x1              ;[3]
106     push    x2              ;[5]
107     push    x3              ;[7]
108     ldi     shift, 0xff     ;[9] [rx loop init]
109     ori     x3, 0xff        ;[10] [rx loop init] == ser x3, clear zero flag
110
111     in      x1, USBIN       ;[11] <-- sample bit 0
112     bst     x1, USBMINUS    ;[12]
113     bld     shift, 0        ;[13]
114     push    x4              ;[14] == phase
115 ;   [---]                   ;[15]
116     push    cnt             ;[16]
117 ;   [---]                   ;[17]
118     ldi     phase, 0        ;[18] [rx loop init]
119     ldi     cnt, USB_BUFSIZE;[19] [rx loop init]
120     rjmp    rxbit1          ;[20]
121 ;   [---]                   ;[21]
122
123 ;----------------------------------------------------------------------------
124 ; Receiver loop (numbers in brackets are cycles within byte after instr)
125 ;----------------------------------------------------------------------------
126 /*
127 byte oriented operations done during loop:
128 bit 0: store data
129 bit 1: SE0 check
130 bit 2: overflow check
131 bit 3: catch up
132 bit 4: rjmp to achieve conditional jump range
133 bit 5: PLL
134 bit 6: catch up
135 bit 7: jump, fixup bitstuff
136 ; 87 [+ 2] cycles
137 ------------------------------------------------------------------
138 */
139 continueWithBit5:
140     in      x2, USBIN       ;[055] <-- bit 5
141     eor     r0, x2          ;[056]
142     or      phase, r0       ;[057]
143     sbrc    phase, USBMINUS ;[058]
144     lpm                     ;[059] optional nop3; modifies r0
145     in      phase, USBIN    ;[060] <-- phase
146     eor     x1, x2          ;[061]
147     bst     x1, USBMINUS    ;[062]
148     bld     shift, 5        ;[063]
149     andi    shift, 0x3f     ;[064]
150     in      x1, USBIN       ;[065] <-- bit 6
151     breq    unstuff5        ;[066] *** unstuff escape
152     eor     phase, x1       ;[067]
153     eor     x2, x1          ;[068]
154     bst     x2, USBMINUS    ;[069]
155     bld     shift, 6        ;[070]
156 didUnstuff6:                ;[   ]
157     in      r0, USBIN       ;[071] <-- phase
158     cpi     shift, 0x02     ;[072]
159     brlo    unstuff6        ;[073] *** unstuff escape
160 didUnstuff5:                ;[   ]
161     nop2                    ;[074]
162 ;   [---]                   ;[075]
163     in      x2, USBIN       ;[076] <-- bit 7
164     eor     x1, x2          ;[077]
165     bst     x1, USBMINUS    ;[078]
166     bld     shift, 7        ;[079]
167 didUnstuff7:                ;[   ]
168     eor     r0, x2          ;[080]
169     or      phase, r0       ;[081]
170     in      r0, USBIN       ;[082] <-- phase
171     cpi     shift, 0x04     ;[083]
172     brsh    rxLoop          ;[084]
173 ;   [---]                   ;[085]
174 unstuff7:                   ;[   ]
175     andi    x3, ~0x80       ;[085]
176     ori     shift, 0x80     ;[086]
177     in      x2, USBIN       ;[087] <-- sample stuffed bit 7
178     nop                     ;[088]
179     rjmp    didUnstuff7     ;[089]
180 ;   [---]                   ;[090]
181                             ;[080]
182
183 unstuff5:                   ;[067]
184     eor     phase, x1       ;[068]
185     andi    x3, ~0x20       ;[069]
186     ori     shift, 0x20     ;[070]
187     in      r0, USBIN       ;[071] <-- phase
188     mov     x2, x1          ;[072]
189     nop                     ;[073]
190     nop2                    ;[074]
191 ;   [---]                   ;[075]
192     in      x1, USBIN       ;[076] <-- bit 6
193     eor     r0, x1          ;[077]
194     or      phase, r0       ;[078]
195     eor     x2, x1          ;[079]
196     bst     x2, USBMINUS    ;[080]
197     bld     shift, 6        ;[081] no need to check bitstuffing, we just had one
198     in      r0, USBIN       ;[082] <-- phase
199     rjmp    didUnstuff5     ;[083]
200 ;   [---]                   ;[084]
201                             ;[074]
202
203 unstuff6:                   ;[074]
204     andi    x3, ~0x40       ;[075]
205     in      x1, USBIN       ;[076] <-- bit 6 again
206     ori     shift, 0x40     ;[077]
207     nop2                    ;[078]
208 ;   [---]                   ;[079]
209     rjmp    didUnstuff6     ;[080]
210 ;   [---]                   ;[081]
211                             ;[071]
212
213 unstuff0:                   ;[013]
214     eor     r0, x2          ;[014]
215     or      phase, r0       ;[015]
216     andi    x2, USBMASK     ;[016] check for SE0
217     in      r0, USBIN       ;[017] <-- phase
218     breq    didUnstuff0     ;[018] direct jump to se0 would be too long
219     andi    x3, ~0x01       ;[019]
220     ori     shift, 0x01     ;[020]
221     mov     x1, x2          ;[021] mov existing sample
222     in      x2, USBIN       ;[022] <-- bit 1 again
223     rjmp    didUnstuff0     ;[023]
224 ;   [---]                   ;[024]
225                             ;[014]
226
227 unstuff1:                   ;[024]
228     eor     r0, x1          ;[025]
229     or      phase, r0       ;[026]
230     andi    x3, ~0x02       ;[027]
231     in      r0, USBIN       ;[028] <-- phase
232     ori     shift, 0x02     ;[029]
233     mov     x2, x1          ;[030]
234     rjmp    didUnstuff1     ;[031]
235 ;   [---]                   ;[032]
236                             ;[022]
237
238 unstuff2:                   ;[035]
239     eor     r0, x2          ;[036]
240     or      phase, r0       ;[037]
241     andi    x3, ~0x04       ;[038]
242     in      r0, USBIN       ;[039] <-- phase
243     ori     shift, 0x04     ;[040]
244     mov     x1, x2          ;[041]
245     rjmp    didUnstuff2     ;[042]
246 ;   [---]                   ;[043]
247                             ;[033]
248
249 unstuff3:                   ;[043]
250     in      x2, USBIN       ;[044] <-- bit 3 again
251     eor     r0, x2          ;[045]
252     or      phase, r0       ;[046]
253     andi    x3, ~0x08       ;[047]
254     ori     shift, 0x08     ;[048]
255     nop                     ;[049]
256     in      r0, USBIN       ;[050] <-- phase
257     rjmp    didUnstuff3     ;[051]
258 ;   [---]                   ;[052]
259                             ;[042]
260
261 unstuff4:                   ;[053]
262     andi    x3, ~0x10       ;[054]
263     in      x1, USBIN       ;[055] <-- bit 4 again
264     ori     shift, 0x10     ;[056]
265     rjmp    didUnstuff4     ;[057]
266 ;   [---]                   ;[058]
267                             ;[048]
268
269 rxLoop:                     ;[085]
270     eor     x3, shift       ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others
271     in      x1, USBIN       ;[000] <-- bit 0
272     st      y+, x3          ;[001]
273 ;   [---]                   ;[002]
274     eor     r0, x1          ;[003]
275     or      phase, r0       ;[004]
276     eor     x2, x1          ;[005]
277     in      r0, USBIN       ;[006] <-- phase
278     ser     x3              ;[007]
279     bst     x2, USBMINUS    ;[008]
280     bld     shift, 0        ;[009]
281     andi    shift, 0xf9     ;[010]
282 rxbit1:                     ;[   ]
283     in      x2, USBIN       ;[011] <-- bit 1
284     breq    unstuff0        ;[012] *** unstuff escape
285     andi    x2, USBMASK     ;[013] SE0 check for bit 1
286 didUnstuff0:                ;[   ] Z only set if we detected SE0 in bitstuff
287     breq    se0             ;[014]
288     eor     r0, x2          ;[015]
289     or      phase, r0       ;[016]
290     in      r0, USBIN       ;[017] <-- phase
291     eor     x1, x2          ;[018]
292     bst     x1, USBMINUS    ;[019]
293     bld     shift, 1        ;[020]
294     andi    shift, 0xf3     ;[021]
295 didUnstuff1:                ;[   ]
296     in      x1, USBIN       ;[022] <-- bit 2
297     breq    unstuff1        ;[023] *** unstuff escape
298     eor     r0, x1          ;[024]
299     or      phase, r0       ;[025]
300     subi    cnt, 1          ;[026] overflow check
301     brcs    overflow        ;[027]
302     in      r0, USBIN       ;[028] <-- phase
303     eor     x2, x1          ;[029]
304     bst     x2, USBMINUS    ;[030]
305     bld     shift, 2        ;[031]
306     andi    shift, 0xe7     ;[032]
307 didUnstuff2:                ;[   ]
308     in      x2, USBIN       ;[033] <-- bit 3
309     breq    unstuff2        ;[034] *** unstuff escape
310     eor     r0, x2          ;[035]
311     or      phase, r0       ;[036]
312     eor     x1, x2          ;[037]
313     bst     x1, USBMINUS    ;[038]
314     in      r0, USBIN       ;[039] <-- phase
315     bld     shift, 3        ;[040]
316     andi    shift, 0xcf     ;[041]
317 didUnstuff3:                ;[   ]
318     breq    unstuff3        ;[042] *** unstuff escape
319     nop                     ;[043]
320     in      x1, USBIN       ;[044] <-- bit 4
321     eor     x2, x1          ;[045]
322     bst     x2, USBMINUS    ;[046]
323     bld     shift, 4        ;[047]
324 didUnstuff4:                ;[   ]
325     eor     r0, x1          ;[048]
326     or      phase, r0       ;[049]
327     in      r0, USBIN       ;[050] <-- phase
328     andi    shift, 0x9f     ;[051]
329     breq    unstuff4        ;[052] *** unstuff escape
330     rjmp    continueWithBit5;[053]
331 ;   [---]                   ;[054]
332
333 macro POP_STANDARD ; 16 cycles
334     pop     cnt
335     pop     x4
336     pop     x3
337     pop     x2
338     pop     x1
339     pop     shift
340     pop     YH
341     pop     r0
342     endm
343 macro POP_RETI     ; 5 cycles
344     pop     YL
345     out     SREG, YL
346     pop     YL
347     endm
348
349 #include "asmcommon.inc"
350
351
352 ; USB spec says:
353 ; idle = J
354 ; J = (D+ = 0), (D- = 1)
355 ; K = (D+ = 1), (D- = 0)
356 ; Spec allows 7.5 bit times from EOP to SOP for replies
357
358 bitstuff7:
359     eor     x1, x4          ;[4]
360     ldi     x2, 0           ;[5]
361     nop2                    ;[6] C is zero (brcc)
362     rjmp    didStuff7       ;[8]
363
364 bitstuffN:
365     eor     x1, x4          ;[5]
366     ldi     x2, 0           ;[6]
367     lpm                     ;[7] 3 cycle NOP, modifies r0
368     out     USBOUT, x1      ;[10] <-- out
369     rjmp    didStuffN       ;[0]
370
371 #define bitStatus   x3
372
373 sendNakAndReti:
374     ldi     cnt, USBPID_NAK ;[-19]
375     rjmp    sendCntAndReti  ;[-18]
376 sendAckAndReti:
377     ldi     cnt, USBPID_ACK ;[-17]
378 sendCntAndReti:
379     mov     r0, cnt         ;[-16]
380     ldi     YL, 0           ;[-15] R0 address is 0
381     ldi     YH, 0           ;[-14]
382     ldi     cnt, 2          ;[-13]
383 ;   rjmp    usbSendAndReti      fallthrough
384
385 ;usbSend:
386 ;pointer to data in 'Y'
387 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
388 ;uses: x1...x4, shift, cnt, Y
389 ;Numbers in brackets are time since first bit of sync pattern is sent
390 usbSendAndReti:             ; 12 cycles until SOP
391     in      x2, USBDDR      ;[-12]
392     ori     x2, USBMASK     ;[-11]
393     sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
394     in      x1, USBOUT      ;[-8] port mirror for tx loop
395     out     USBDDR, x2      ;[-7] <- acquire bus
396 ; need not init x2 (bitstuff history) because sync starts with 0
397     ldi     x4, USBMASK     ;[-6] exor mask
398     ldi     shift, 0x80     ;[-5] sync byte is first byte sent
399     ldi     bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes
400 byteloop:
401 bitloop:
402     sbrs    shift, 0        ;[8] [-3]
403     eor     x1, x4          ;[9] [-2]
404     out     USBOUT, x1      ;[10] [-1] <-- out
405     ror     shift           ;[0]
406     ror     x2              ;[1]
407 didStuffN:
408     cpi     x2, 0xfc        ;[2]
409     brcc    bitstuffN       ;[3]
410     nop                     ;[4]
411     subi    bitStatus, 37   ;[5] 256 / 7 ~=~ 37
412     brcc    bitloop         ;[6] when we leave the loop, bitStatus has almost the initial value
413     sbrs    shift, 0        ;[7]
414     eor     x1, x4          ;[8]
415     ror     shift           ;[9]
416 didStuff7:
417     out     USBOUT, x1      ;[10] <-- out
418     ror     x2              ;[0]
419     cpi     x2, 0xfc        ;[1]
420     brcc    bitstuff7       ;[2]
421     ld      shift, y+       ;[3]
422     dec     cnt             ;[5]
423     brne    byteloop        ;[6]
424 ;make SE0:
425     cbr     x1, USBMASK     ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles]
426     lds     x2, usbNewDeviceAddr;[8]
427     lsl     x2              ;[10] we compare with left shifted address
428     out     USBOUT, x1      ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
429 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
430 ;set address only after data packet was sent, not after handshake
431     subi    YL, 2           ;[0] Only assign address on data packets, not ACK/NAK in r0
432     sbci    YH, 0           ;[1]
433     breq    skipAddrAssign  ;[2]
434     sts     usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
435 skipAddrAssign:
436 ;end of usbDeviceAddress transfer
437     ldi     x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag
438     USB_STORE_PENDING(x2)   ;[5]
439     ori     x1, USBIDLE     ;[6]
440     in      x2, USBDDR      ;[7]
441     cbr     x2, USBMASK     ;[8] set both pins to input
442     mov     x3, x1          ;[9]
443     cbr     x3, USBMASK     ;[10] configure no pullup on both pins
444     ldi     x4, 4           ;[11]
445 se0Delay:
446     dec     x4              ;[12] [15] [18] [21]
447     brne    se0Delay        ;[13] [16] [19] [22]
448     out     USBOUT, x1      ;[23] <-- out J (idle) -- end of SE0 (EOP signal)
449     out     USBDDR, x2      ;[24] <-- release bus now
450     out     USBOUT, x3      ;[25] <-- ensure no pull-up resistors are active
451     rjmp    doReturn
452