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