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