]> git.cryptolib.org Git - labortage2013badge.git/blob - firmware/usbdrv/usbdrvasm128.inc
whitespace editing / typo correction
[labortage2013badge.git] / firmware / usbdrv / usbdrvasm128.inc
1 /* Name: usbdrvasm128.inc
2  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3  * Author: Christian Starkjohann
4  * Creation Date: 2008-10-11
5  * Tabsize: 4
6  * Copyright: (c) 2008 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.8 MHz version of the USB driver. It is intended for use
17 with the internal RC oscillator. Although 12.8 MHz is outside the guaranteed
18 calibration range of the oscillator, almost all AVRs can reach this frequency.
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 LIMITATIONS
25 ===========
26 Although it may seem very handy to save the crystal and use the internal
27 RC oscillator of the CPU, this method (and this module) has some serious
28 limitations:
29 (1) The guaranteed calibration range of the oscillator is only 8.1 MHz.
30 They typical range is 14.5 MHz and most AVRs can actually reach this rate.
31 (2) Writing EEPROM and Flash may be unreliable (short data lifetime) since
32 the write procedure is timed from the RC oscillator.
33 (3) End Of Packet detection (SE0) should be in bit 1, bit it is only checked
34 if bits 0 and 1 both read as 0 on D- and D+ read as 0 in the middle. This may
35 cause problems with old hubs which delay SE0 by up to one cycle.
36 (4) Code size is much larger than that of the other modules.
37
38 Since almost all of this code is timing critical, don't change unless you
39 really know what you are doing! Many parts require not only a maximum number
40 of CPU cycles, but even an exact number of cycles!
41
42 Implementation notes:
43 ======================
44 min frequency: 67 cycles for 8 bit -> 12.5625 MHz
45 max frequency: 69.286 cycles for 8 bit -> 12.99 MHz
46 nominal frequency: 12.77 MHz ( = sqrt(min * max))
47
48 sampling positions: (next even number in range [+/- 0.5])
49 cycle index range: 0 ... 66
50 bits:
51 .5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125
52 [0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59]
53
54 bit number:     0   1   2   3   4   5   6   7
55 spare cycles    1   2   1   2   1   1   1   0
56
57 operations to perform:      duration cycle
58                             ----------------
59     eor     fix, shift          1 -> 00
60     andi    phase, USBMASK      1 -> 08
61     breq    se0                 1 -> 16 (moved to 11)
62     st      y+, data            2 -> 24, 25
63     mov     data, fix           1 -> 33
64     ser     data                1 -> 41
65     subi    cnt, 1              1 -> 49
66     brcs    overflow            1 -> 50
67
68 layout of samples and operations:
69 [##] = sample bit
70 <##> = sample phase
71 *##* = operation
72
73 0:  *00* [01]  02   03   04  <05>  06   07
74 1:  *08* [09]  10   11   12  <13>  14   15  *16*
75 2:  [17]  18   19   20  <21>  22   23
76 3:  *24* *25* [26]  27   28   29  <30>  31   32
77 4:  *33* [34]  35   36   37  <38>  39   40
78 5:  *41* [42]  43   44   45  <46>  47   48
79 6:  *49* *50* [51]  52   53   54  <55>  56   57   58
80 7:  [59]  60   61   62  <63>  64   65   66
81 *****************************************************************************/
82
83 /* we prefer positive expressions (do if condition) instead of negative
84  * (skip if condition), therefore use defines for skip instructions:
85  */
86 #define ifioclr sbis
87 #define ifioset sbic
88 #define ifrclr  sbrs
89 #define ifrset  sbrc
90
91 /* The registers "fix" and "data" swap their meaning during the loop. Use
92  * defines to keep their name constant.
93  */
94 #define fix     x2
95 #define data    x1
96 #undef phase        /* phase has a default definition to x4 */
97 #define phase   x3
98
99
100 USB_INTR_VECTOR:
101 ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0
102     push    YL              ;2 push only what is necessary to sync with edge ASAP
103     in      YL, SREG        ;1
104     push    YL              ;2
105 ;----------------------------------------------------------------------------
106 ; Synchronize with sync pattern:
107 ;----------------------------------------------------------------------------
108 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
109 ;sync up with J to K edge during sync pattern -- use fastest possible loops
110 ;The first part waits at most 1 bit long since we must be in sync pattern.
111 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
112 ;waitForJ, ensure that this prerequisite is met.
113 waitForJ:
114     inc     YL
115     sbis    USBIN, USBMINUS
116     brne    waitForJ        ; just make sure we have ANY timeout
117 waitForK:
118 ;The following code results in a sampling window of 1/4 bit which meets the spec.
119     sbis    USBIN, USBMINUS
120     rjmp    foundK
121     sbis    USBIN, USBMINUS
122     rjmp    foundK
123     sbis    USBIN, USBMINUS
124     rjmp    foundK
125     sbis    USBIN, USBMINUS
126     rjmp    foundK
127     sbis    USBIN, USBMINUS ;[0]
128     rjmp    foundK          ;[1]
129 #if USB_COUNT_SOF
130     lds     YL, usbSofCount
131     inc     YL
132     sts     usbSofCount, YL
133 #endif  /* USB_COUNT_SOF */
134 #ifdef USB_SOF_HOOK
135     USB_SOF_HOOK
136 #endif
137     rjmp    sofError
138
139 foundK:
140 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
141 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
142 ;are cycles from center of first sync (double K) bit after the instruction
143     push    YH                  ;[2]
144     lds     YL, usbInputBufOffset;[4]
145     clr     YH                  ;[6]
146     subi    YL, lo8(-(usbRxBuf));[7]
147     sbci    YH, hi8(-(usbRxBuf));[8]
148
149     sbis    USBIN, USBMINUS     ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5]
150     rjmp    haveTwoBitsK        ;[10]
151     pop     YH                  ;[11] undo the push from before
152     rjmp    waitForK            ;[13] this was not the end of sync, retry
153 haveTwoBitsK:
154 ;----------------------------------------------------------------------------
155 ; push more registers and initialize values while we sample the first bits:
156 ;----------------------------------------------------------------------------
157 #define fix     x2
158 #define data    x1
159
160     push    shift               ;[12]
161     push    x1                  ;[14]
162     push    x2                  ;[16]
163     ldi     shift, 0x80         ;[18] prevent bit-unstuffing but init low bits to 0
164     ifioset USBIN, USBMINUS     ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5]
165     ori     shift, 1<<0         ;[02]
166     push    x3                  ;[03]
167     push    cnt                 ;[05]
168     push    r0                  ;[07]
169     ifioset USBIN, USBMINUS     ;[09] <--- bit 1
170     ori     shift, 1<<1         ;[10]
171     ser     fix                 ;[11]
172     ldi     cnt, USB_BUFSIZE    ;[12]
173     mov     data, shift         ;[13]
174     lsl     shift               ;[14]
175     nop2                        ;[15]
176     ifioset USBIN, USBMINUS     ;[17] <--- bit 2
177     ori     data, 3<<2          ;[18] store in bit 2 AND bit 3
178     eor     shift, data         ;[19] do nrzi decoding
179     andi    data, 1<<3          ;[20]
180     in      phase, USBIN        ;[21] <- phase
181     brne    jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1
182     nop                         ;[23]
183     rjmp    entryAfterClr       ;[24]
184 jumpToEntryAfterSet:
185     rjmp    entryAfterSet       ;[24]
186
187 ;----------------------------------------------------------------------------
188 ; Receiver loop (numbers in brackets are cycles within byte after instr)
189 ;----------------------------------------------------------------------------
190 #undef  fix
191 #define  fix    x1
192 #undef  data
193 #define data    x2
194
195 bit7IsSet:
196     ifrclr  phase, USBMINUS     ;[62] check phase only if D- changed
197     lpm                         ;[63]
198     in      phase, USBIN        ;[64] <- phase (one cycle too late)
199     ori     shift, 1 << 7       ;[65]
200     nop                         ;[66]
201 ;;;;rjmp    bit0AfterSet        ; -> [00] == [67] moved block up to save jump
202 bit0AfterSet:
203     eor     fix, shift          ;[00]
204 #undef  fix
205 #define fix     x2
206 #undef  data
207 #define data    x1  /* we now have result in data, fix is reset to 0xff */
208     ifioclr USBIN, USBMINUS     ;[01] <--- sample 0
209     rjmp    bit0IsClr           ;[02]
210     andi    shift, ~(7 << 0)    ;[03]
211     breq    unstuff0s           ;[04]
212     in      phase, USBIN        ;[05] <- phase
213     rjmp    bit1AfterSet        ;[06]
214 unstuff0s:
215     in      phase, USBIN        ;[06] <- phase (one cycle too late)
216     andi    fix, ~(1 << 0)      ;[07]
217     ifioclr USBIN, USBMINUS     ;[00]
218     ifioset USBIN, USBPLUS      ;[01]
219     rjmp    bit0IsClr           ;[02] executed if first expr false or second true
220 se0AndStore:                    ; executed only if both bits 0
221     st      y+, x1              ;[15/17] cycles after start of byte
222     rjmp    se0                 ;[17/19]
223
224 bit0IsClr:
225     ifrset  phase, USBMINUS     ;[04] check phase only if D- changed
226     lpm                         ;[05]
227     in      phase, USBIN        ;[06] <- phase (one cycle too late)
228     ori     shift, 1 << 0       ;[07]
229 bit1AfterClr:
230     andi    phase, USBMASK      ;[08]
231     ifioset USBIN, USBMINUS     ;[09] <--- sample 1
232     rjmp    bit1IsSet           ;[10]
233     breq    se0AndStore         ;[11] if D- was 0 in bits 0 AND 1 and D+ was 0 in between, we have SE0
234     andi    shift, ~(7 << 1)    ;[12]
235     in      phase, USBIN        ;[13] <- phase
236     breq    unstuff1c           ;[14]
237     rjmp    bit2AfterClr        ;[15]
238 unstuff1c:
239     andi    fix, ~(1 << 1)      ;[16]
240     nop2                        ;[08]
241     nop2                        ;[10]
242 bit1IsSet:
243     ifrclr  phase, USBMINUS     ;[12] check phase only if D- changed
244     lpm                         ;[13]
245     in      phase, USBIN        ;[14] <- phase (one cycle too late)
246     ori     shift, 1 << 1       ;[15]
247     nop                         ;[16]
248 bit2AfterSet:
249     ifioclr USBIN, USBMINUS     ;[17] <--- sample 2
250     rjmp    bit2IsClr           ;[18]
251     andi    shift, ~(7 << 2)    ;[19]
252     breq    unstuff2s           ;[20]
253     in      phase, USBIN        ;[21] <- phase
254     rjmp    bit3AfterSet        ;[22]
255 unstuff2s:
256     in      phase, USBIN        ;[22] <- phase (one cycle too late)
257     andi    fix, ~(1 << 2)      ;[23]
258     nop2                        ;[16]
259     nop2                        ;[18]
260 bit2IsClr:
261     ifrset  phase, USBMINUS     ;[20] check phase only if D- changed
262     lpm                         ;[21]
263     in      phase, USBIN        ;[22] <- phase (one cycle too late)
264     ori     shift, 1 << 2       ;[23]
265 bit3AfterClr:
266     st      y+, data            ;[24]
267 entryAfterClr:
268     ifioset USBIN, USBMINUS     ;[26] <--- sample 3
269     rjmp    bit3IsSet           ;[27]
270     andi    shift, ~(7 << 3)    ;[28]
271     breq    unstuff3c           ;[29]
272     in      phase, USBIN        ;[30] <- phase
273     rjmp    bit4AfterClr        ;[31]
274 unstuff3c:
275     in      phase, USBIN        ;[31] <- phase (one cycle too late)
276     andi    fix, ~(1 << 3)      ;[32]
277     nop2                        ;[25]
278     nop2                        ;[27]
279 bit3IsSet:
280     ifrclr  phase, USBMINUS     ;[29] check phase only if D- changed
281     lpm                         ;[30]
282     in      phase, USBIN        ;[31] <- phase (one cycle too late)
283     ori     shift, 1 << 3       ;[32]
284 bit4AfterSet:
285     mov     data, fix           ;[33] undo this move by swapping defines
286 #undef  fix
287 #define fix     x1
288 #undef  data
289 #define data    x2
290     ifioclr USBIN, USBMINUS     ;[34] <--- sample 4
291     rjmp    bit4IsClr           ;[35]
292     andi    shift, ~(7 << 4)    ;[36]
293     breq    unstuff4s           ;[37]
294     in      phase, USBIN        ;[38] <- phase
295     rjmp    bit5AfterSet        ;[39]
296 unstuff4s:
297     in      phase, USBIN        ;[39] <- phase (one cycle too late)
298     andi    fix, ~(1 << 4)      ;[40]
299     nop2                        ;[33]
300     nop2                        ;[35]
301 bit4IsClr:
302     ifrset  phase, USBMINUS     ;[37] check phase only if D- changed
303     lpm                         ;[38]
304     in      phase, USBIN        ;[39] <- phase (one cycle too late)
305     ori     shift, 1 << 4       ;[40]
306 bit5AfterClr:
307     ser     data                ;[41]
308     ifioset USBIN, USBMINUS     ;[42] <--- sample 5
309     rjmp    bit5IsSet           ;[43]
310     andi    shift, ~(7 << 5)    ;[44]
311     breq    unstuff5c           ;[45]
312     in      phase, USBIN        ;[46] <- phase
313     rjmp    bit6AfterClr        ;[47]
314 unstuff5c:
315     in      phase, USBIN        ;[47] <- phase (one cycle too late)
316     andi    fix, ~(1 << 5)      ;[48]
317     nop2                        ;[41]
318     nop2                        ;[43]
319 bit5IsSet:
320     ifrclr  phase, USBMINUS     ;[45] check phase only if D- changed
321     lpm                         ;[46]
322     in      phase, USBIN        ;[47] <- phase (one cycle too late)
323     ori     shift, 1 << 5       ;[48]
324 bit6AfterSet:
325     subi    cnt, 1              ;[49]
326     brcs    jumpToOverflow      ;[50]
327     ifioclr USBIN, USBMINUS     ;[51] <--- sample 6
328     rjmp    bit6IsClr           ;[52]
329     andi    shift, ~(3 << 6)    ;[53]
330     cpi     shift, 2            ;[54]
331     in      phase, USBIN        ;[55] <- phase
332     brlt    unstuff6s           ;[56]
333     rjmp    bit7AfterSet        ;[57]
334
335 jumpToOverflow:
336     rjmp    overflow
337
338 unstuff6s:
339     andi    fix, ~(1 << 6)      ;[50]
340     lpm                         ;[51]
341 bit6IsClr:
342     ifrset  phase, USBMINUS     ;[54] check phase only if D- changed
343     lpm                         ;[55]
344     in      phase, USBIN        ;[56] <- phase (one cycle too late)
345     ori     shift, 1 << 6       ;[57]
346     nop                         ;[58]
347 bit7AfterClr:
348     ifioset USBIN, USBMINUS     ;[59] <--- sample 7
349     rjmp    bit7IsSet           ;[60]
350     andi    shift, ~(1 << 7)    ;[61]
351     cpi     shift, 4            ;[62]
352     in      phase, USBIN        ;[63] <- phase
353     brlt    unstuff7c           ;[64]
354     rjmp    bit0AfterClr        ;[65] -> [00] == [67]
355 unstuff7c:
356     andi    fix, ~(1 << 7)      ;[58]
357     nop                         ;[59]
358     rjmp    bit7IsSet           ;[60]
359
360 bit7IsClr:
361     ifrset  phase, USBMINUS     ;[62] check phase only if D- changed
362     lpm                         ;[63]
363     in      phase, USBIN        ;[64] <- phase (one cycle too late)
364     ori     shift, 1 << 7       ;[65]
365     nop                         ;[66]
366 ;;;;rjmp    bit0AfterClr        ; -> [00] == [67] moved block up to save jump
367 bit0AfterClr:
368     eor     fix, shift          ;[00]
369 #undef  fix
370 #define fix     x2
371 #undef  data
372 #define data    x1  /* we now have result in data, fix is reset to 0xff */
373     ifioset USBIN, USBMINUS     ;[01] <--- sample 0
374     rjmp    bit0IsSet           ;[02]
375     andi    shift, ~(7 << 0)    ;[03]
376     breq    unstuff0c           ;[04]
377     in      phase, USBIN        ;[05] <- phase
378     rjmp    bit1AfterClr        ;[06]
379 unstuff0c:
380     in      phase, USBIN        ;[06] <- phase (one cycle too late)
381     andi    fix, ~(1 << 0)      ;[07]
382     ifioclr USBIN, USBMINUS     ;[00]
383     ifioset USBIN, USBPLUS      ;[01]
384     rjmp    bit0IsSet           ;[02] executed if first expr false or second true
385     rjmp    se0AndStore         ;[03] executed only if both bits 0
386 bit0IsSet:
387     ifrclr  phase, USBMINUS     ;[04] check phase only if D- changed
388     lpm                         ;[05]
389     in      phase, USBIN        ;[06] <- phase (one cycle too late)
390     ori     shift, 1 << 0       ;[07]
391 bit1AfterSet:
392     andi    shift, ~(7 << 1)    ;[08] compensated by "ori shift, 1<<1" if bit1IsClr
393     ifioclr USBIN, USBMINUS     ;[09] <--- sample 1
394     rjmp    bit1IsClr           ;[10]
395     breq    unstuff1s           ;[11]
396     nop2                        ;[12] do not check for SE0 if bit 0 was 1
397     in      phase, USBIN        ;[14] <- phase (one cycle too late)
398     rjmp    bit2AfterSet        ;[15]
399 unstuff1s:
400     in      phase, USBIN        ;[13] <- phase
401     andi    fix, ~(1 << 1)      ;[14]
402     lpm                         ;[07]
403     nop2                        ;[10]
404 bit1IsClr:
405     ifrset  phase, USBMINUS     ;[12] check phase only if D- changed
406     lpm                         ;[13]
407     in      phase, USBIN        ;[14] <- phase (one cycle too late)
408     ori     shift, 1 << 1       ;[15]
409     nop                         ;[16]
410 bit2AfterClr:
411     ifioset USBIN, USBMINUS     ;[17] <--- sample 2
412     rjmp    bit2IsSet           ;[18]
413     andi    shift, ~(7 << 2)    ;[19]
414     breq    unstuff2c           ;[20]
415     in      phase, USBIN        ;[21] <- phase
416     rjmp    bit3AfterClr        ;[22]
417 unstuff2c:
418     in      phase, USBIN        ;[22] <- phase (one cycle too late)
419     andi    fix, ~(1 << 2)      ;[23]
420     nop2                        ;[16]
421     nop2                        ;[18]
422 bit2IsSet:
423     ifrclr  phase, USBMINUS     ;[20] check phase only if D- changed
424     lpm                         ;[21]
425     in      phase, USBIN        ;[22] <- phase (one cycle too late)
426     ori     shift, 1 << 2       ;[23]
427 bit3AfterSet:
428     st      y+, data            ;[24]
429 entryAfterSet:
430     ifioclr USBIN, USBMINUS     ;[26] <--- sample 3
431     rjmp    bit3IsClr           ;[27]
432     andi    shift, ~(7 << 3)    ;[28]
433     breq    unstuff3s           ;[29]
434     in      phase, USBIN        ;[30] <- phase
435     rjmp    bit4AfterSet        ;[31]
436 unstuff3s:
437     in      phase, USBIN        ;[31] <- phase (one cycle too late)
438     andi    fix, ~(1 << 3)      ;[32]
439     nop2                        ;[25]
440     nop2                        ;[27]
441 bit3IsClr:
442     ifrset  phase, USBMINUS     ;[29] check phase only if D- changed
443     lpm                         ;[30]
444     in      phase, USBIN        ;[31] <- phase (one cycle too late)
445     ori     shift, 1 << 3       ;[32]
446 bit4AfterClr:
447     mov     data, fix           ;[33] undo this move by swapping defines
448 #undef  fix
449 #define fix     x1
450 #undef  data
451 #define data    x2
452     ifioset USBIN, USBMINUS     ;[34] <--- sample 4
453     rjmp    bit4IsSet           ;[35]
454     andi    shift, ~(7 << 4)    ;[36]
455     breq    unstuff4c           ;[37]
456     in      phase, USBIN        ;[38] <- phase
457     rjmp    bit5AfterClr        ;[39]
458 unstuff4c:
459     in      phase, USBIN        ;[39] <- phase (one cycle too late)
460     andi    fix, ~(1 << 4)      ;[40]
461     nop2                        ;[33]
462     nop2                        ;[35]
463 bit4IsSet:
464     ifrclr  phase, USBMINUS     ;[37] check phase only if D- changed
465     lpm                         ;[38]
466     in      phase, USBIN        ;[39] <- phase (one cycle too late)
467     ori     shift, 1 << 4       ;[40]
468 bit5AfterSet:
469     ser     data                ;[41]
470     ifioclr USBIN, USBMINUS     ;[42] <--- sample 5
471     rjmp    bit5IsClr           ;[43]
472     andi    shift, ~(7 << 5)    ;[44]
473     breq    unstuff5s           ;[45]
474     in      phase, USBIN        ;[46] <- phase
475     rjmp    bit6AfterSet        ;[47]
476 unstuff5s:
477     in      phase, USBIN        ;[47] <- phase (one cycle too late)
478     andi    fix, ~(1 << 5)      ;[48]
479     nop2                        ;[41]
480     nop2                        ;[43]
481 bit5IsClr:
482     ifrset  phase, USBMINUS     ;[45] check phase only if D- changed
483     lpm                         ;[46]
484     in      phase, USBIN        ;[47] <- phase (one cycle too late)
485     ori     shift, 1 << 5       ;[48]
486 bit6AfterClr:
487     subi    cnt, 1              ;[49]
488     brcs    overflow            ;[50]
489     ifioset USBIN, USBMINUS     ;[51] <--- sample 6
490     rjmp    bit6IsSet           ;[52]
491     andi    shift, ~(3 << 6)    ;[53]
492     cpi     shift, 2            ;[54]
493     in      phase, USBIN        ;[55] <- phase
494     brlt    unstuff6c           ;[56]
495     rjmp    bit7AfterClr        ;[57]
496 unstuff6c:
497     andi    fix, ~(1 << 6)      ;[50]
498     lpm                         ;[51]
499 bit6IsSet:
500     ifrclr  phase, USBMINUS     ;[54] check phase only if D- changed
501     lpm                         ;[55]
502     in      phase, USBIN        ;[56] <- phase (one cycle too late)
503     ori     shift, 1 << 6       ;[57]
504 bit7AfterSet:
505     ifioclr USBIN, USBMINUS     ;[59] <--- sample 7
506     rjmp    bit7IsClr           ;[60]
507     andi    shift, ~(1 << 7)    ;[61]
508     cpi     shift, 4            ;[62]
509     in      phase, USBIN        ;[63] <- phase
510     brlt    unstuff7s           ;[64]
511     rjmp    bit0AfterSet        ;[65] -> [00] == [67]
512 unstuff7s:
513     andi    fix, ~(1 << 7)      ;[58]
514     nop                         ;[59]
515     rjmp    bit7IsClr           ;[60]
516
517 macro POP_STANDARD ; 14 cycles
518     pop     r0
519     pop     cnt
520     pop     x3
521     pop     x2
522     pop     x1
523     pop     shift
524     pop     YH
525     endm
526 macro POP_RETI     ; 5 cycles
527     pop     YL
528     out     SREG, YL
529     pop     YL
530     endm
531
532 #include "asmcommon.inc"
533
534 ;----------------------------------------------------------------------------
535 ; Transmitting data
536 ;----------------------------------------------------------------------------
537
538 txByteLoop:
539 txBitloop:
540 stuffN1Delay:                   ;     [03]
541     ror     shift               ;[-5] [11] [63]
542     brcc    doExorN1            ;[-4]      [64]
543     subi    x3, 1               ;[-3]
544     brne    commonN1            ;[-2]
545     lsl     shift               ;[-1] compensate ror after rjmp stuffDelay
546     nop                         ;[00] stuffing consists of just waiting 8 cycles
547     rjmp    stuffN1Delay        ;[01] after ror, C bit is reliably clear
548
549 sendNakAndReti:
550     ldi     cnt, USBPID_NAK ;[-19]
551     rjmp    sendCntAndReti  ;[-18]
552 sendAckAndReti:
553     ldi     cnt, USBPID_ACK ;[-17]
554 sendCntAndReti:
555     mov     r0, cnt         ;[-16]
556     ldi     YL, 0           ;[-15] R0 address is 0
557     ldi     YH, 0           ;[-14]
558     ldi     cnt, 2          ;[-13]
559 ;   rjmp    usbSendAndReti      fallthrough
560
561 ; USB spec says:
562 ; idle = J
563 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
564 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
565 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
566
567 ;usbSend:
568 ;pointer to data in 'Y'
569 ;number of bytes in 'cnt' -- including sync byte
570 ;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt]
571 ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
572 usbSendAndReti:
573     in      x2, USBDDR          ;[-10] 10 cycles until SOP
574     ori     x2, USBMASK         ;[-9]
575     sbi     USBOUT, USBMINUS    ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups)
576     out     USBDDR, x2          ;[-6] <--- acquire bus
577     in      x1, USBOUT          ;[-5] port mirror for tx loop
578     ldi     shift, 0x40         ;[-4] sync byte is first byte sent (we enter loop after ror)
579     ldi     x2, USBMASK         ;[-3]
580 doExorN1:
581     eor     x1, x2              ;[-2] [06] [62]
582     ldi     x3, 6               ;[-1] [07] [63]
583 commonN1:
584 stuffN2Delay:
585     out     USBOUT, x1          ;[00] [08] [64] <--- set bit
586     ror     shift               ;[01]
587     brcc    doExorN2            ;[02]
588     subi    x3, 1               ;[03]
589     brne    commonN2            ;[04]
590     lsl     shift               ;[05] compensate ror after rjmp stuffDelay
591     rjmp    stuffN2Delay        ;[06] after ror, C bit is reliably clear
592 doExorN2:
593     eor     x1, x2              ;[04] [12]
594     ldi     x3, 6               ;[05] [13]
595 commonN2:
596     nop2                        ;[06] [14]
597     subi    cnt, 171            ;[08] [16] trick: (3 * 171) & 0xff = 1
598     out     USBOUT, x1          ;[09] [17] <--- set bit
599     brcs    txBitloop           ;[10]      [27] [44]
600
601 stuff6Delay:
602     ror     shift               ;[45] [53]
603     brcc    doExor6             ;[46]
604     subi    x3, 1               ;[47]
605     brne    common6             ;[48]
606     lsl     shift               ;[49] compensate ror after rjmp stuffDelay
607     nop                         ;[50] stuffing consists of just waiting 8 cycles
608     rjmp    stuff6Delay         ;[51] after ror, C bit is reliably clear
609 doExor6:
610     eor     x1, x2              ;[48] [56]
611     ldi     x3, 6               ;[49]
612 common6:
613 stuff7Delay:
614     ror     shift               ;[50] [58]
615     out     USBOUT, x1          ;[51] <--- set bit
616     brcc    doExor7             ;[52]
617     subi    x3, 1               ;[53]
618     brne    common7             ;[54]
619     lsl     shift               ;[55] compensate ror after rjmp stuffDelay
620     rjmp    stuff7Delay         ;[56] after ror, C bit is reliably clear
621 doExor7:
622     eor     x1, x2              ;[54] [62]
623     ldi     x3, 6               ;[55]
624 common7:
625     ld      shift, y+           ;[56]
626     nop                         ;[58]
627     tst     cnt                 ;[59]
628     out     USBOUT, x1          ;[60] [00]<--- set bit
629     brne    txByteLoop          ;[61] [01]
630 ;make SE0:
631     cbr     x1, USBMASK         ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles]
632     lds     x2, usbNewDeviceAddr;[03]
633     lsl     x2                  ;[05] we compare with left shifted address
634     subi    YL, 2 + 0           ;[06] Only assign address on data packets, not ACK/NAK in r0
635     sbci    YH, 0               ;[07]
636     out     USBOUT, x1          ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
637 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
638 ;set address only after data packet was sent, not after handshake
639     breq    skipAddrAssign      ;[01]
640     sts     usbDeviceAddr, x2   ; if not skipped: SE0 is one cycle longer
641 skipAddrAssign:
642 ;end of usbDeviceAddress transfer
643     ldi     x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
644     USB_STORE_PENDING(x2)       ;[04]
645     ori     x1, USBIDLE         ;[05]
646     in      x2, USBDDR          ;[06]
647     cbr     x2, USBMASK         ;[07] set both pins to input
648     mov     x3, x1              ;[08]
649     cbr     x3, USBMASK         ;[09] configure no pullup on both pins
650     lpm                         ;[10]
651     lpm                         ;[13]
652     out     USBOUT, x1          ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
653     out     USBDDR, x2          ;[17] <-- release bus now
654     out     USBOUT, x3          ;[18] <-- ensure no pull-up resistors are active
655     rjmp    doReturn
656
657
658
659 /*****************************************************************************
660 The following PHP script generates a code skeleton for the receiver routine:
661
662 <?php
663
664 function printCmdBuffer($thisBit)
665 {
666 global $cycle;
667
668     $nextBit = ($thisBit + 1) % 8;
669     $s = ob_get_contents();
670     ob_end_clean();
671     $s = str_replace("#", $thisBit, $s);
672     $s = str_replace("@", $nextBit, $s);
673     $lines = explode("\n", $s);
674     for($i = 0; $i < count($lines); $i++){
675         $s = $lines[$i];
676         if(ereg("\\[([0-9-][0-9])\\]", $s, $regs)){
677             $c = $cycle + (int)$regs[1];
678             $s = ereg_replace("\\[[0-9-][0-9]\\]", sprintf("[%02d]", $c), $s);
679         }
680         if(strlen($s) > 0)
681             echo "$s\n";
682     }
683 }
684
685 function printBit($isAfterSet, $bitNum)
686 {
687     ob_start();
688     if($isAfterSet){
689 ?>
690     ifioclr USBIN, USBMINUS     ;[00] <--- sample
691     rjmp    bit#IsClr           ;[01]
692     andi    shift, ~(7 << #)    ;[02]
693     breq    unstuff#s           ;[03]
694     in      phase, USBIN        ;[04] <- phase
695     rjmp    bit@AfterSet        ;[05]
696 unstuff#s:
697     in      phase, USBIN        ;[05] <- phase (one cycle too late)
698     andi    fix, ~(1 << #)      ;[06]
699     nop2                        ;[-1]
700     nop2                        ;[01]
701 bit#IsClr:
702     ifrset  phase, USBMINUS     ;[03] check phase only if D- changed
703     lpm                         ;[04]
704     in      phase, USBIN        ;[05] <- phase (one cycle too late)
705     ori     shift, 1 << #       ;[06]
706 <?php
707     }else{
708 ?>
709     ifioset USBIN, USBMINUS     ;[00] <--- sample
710     rjmp    bit#IsSet           ;[01]
711     andi    shift, ~(7 << #)    ;[02]
712     breq    unstuff#c           ;[03]
713     in      phase, USBIN        ;[04] <- phase
714     rjmp    bit@AfterClr        ;[05]
715 unstuff#c:
716     in      phase, USBIN        ;[05] <- phase (one cycle too late)
717     andi    fix, ~(1 << #)      ;[06]
718     nop2                        ;[-1]
719     nop2                        ;[01]
720 bit#IsSet:
721     ifrclr  phase, USBMINUS     ;[03] check phase only if D- changed
722     lpm                         ;[04]
723     in      phase, USBIN        ;[05] <- phase (one cycle too late)
724     ori     shift, 1 << #       ;[06]
725 <?php
726     }
727     printCmdBuffer($bitNum);
728 }
729
730 $bitStartCycles = array(1, 9, 17, 26, 34, 42, 51, 59);
731 for($i = 0; $i < 16; $i++){
732     $bit = $i % 8;
733     $emitClrCode = ($i + (int)($i / 8)) % 2;
734     $cycle = $bitStartCycles[$bit];
735     if($emitClrCode){
736         printf("bit%dAfterClr:\n", $bit);
737     }else{
738         printf("bit%dAfterSet:\n", $bit);
739     }
740     ob_start();
741     echo "    *****                       ;[-1]\n";
742     printCmdBuffer($bit);
743     printBit(!$emitClrCode, $bit);
744     if($i == 7)
745         echo "\n";
746 }
747
748 ?>
749 *****************************************************************************/