manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / usbdrv / usbdrvasm128.inc
1 /* Name: usbdrvasm128.inc
2  * Project: AVR USB driver
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 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 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 is between bit 0 and bit 1 where the EOP condition
35 may not be reliable when a hub is used. It should be in bit 1.
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 jumpToSe0AndStore:
221     rjmp    se0AndStore         ;[03] executed only if both bits 0
222 bit0IsClr:
223     ifrset  phase, USBMINUS     ;[04] check phase only if D- changed
224     lpm                         ;[05]
225     in      phase, USBIN        ;[06] <- phase (one cycle too late)
226     ori     shift, 1 << 0       ;[07]
227 bit1AfterClr:
228     andi    phase, USBMASK      ;[08]
229     ifioset USBIN, USBMINUS     ;[09] <--- sample 1
230     rjmp    bit1IsSet           ;[10]
231     breq    jumpToSe0AndStore   ;[11]
232     andi    shift, ~(7 << 1)    ;[12]
233     in      phase, USBIN        ;[13] <- phase
234     breq    unstuff1c           ;[14]
235     rjmp    bit2AfterClr        ;[15]
236 unstuff1c:
237     andi    fix, ~(1 << 1)      ;[16]
238     nop2                        ;[08]
239     nop2                        ;[10]
240 bit1IsSet:
241     ifrclr  phase, USBMINUS     ;[12] check phase only if D- changed
242     lpm                         ;[13]
243     in      phase, USBIN        ;[14] <- phase (one cycle too late)
244     ori     shift, 1 << 1       ;[15]
245     nop                         ;[16]
246 bit2AfterSet:
247     ifioclr USBIN, USBMINUS     ;[17] <--- sample 2
248     rjmp    bit2IsClr           ;[18]
249     andi    shift, ~(7 << 2)    ;[19]
250     breq    unstuff2s           ;[20]
251     in      phase, USBIN        ;[21] <- phase
252     rjmp    bit3AfterSet        ;[22]
253 unstuff2s:
254     in      phase, USBIN        ;[22] <- phase (one cycle too late)
255     andi    fix, ~(1 << 2)      ;[23]
256     nop2                        ;[16]
257     nop2                        ;[18]
258 bit2IsClr:
259     ifrset  phase, USBMINUS     ;[20] check phase only if D- changed
260     lpm                         ;[21]
261     in      phase, USBIN        ;[22] <- phase (one cycle too late)
262     ori     shift, 1 << 2       ;[23]
263 bit3AfterClr:
264     st      y+, data            ;[24]
265 entryAfterClr:
266     ifioset USBIN, USBMINUS     ;[26] <--- sample 3
267     rjmp    bit3IsSet           ;[27]
268     andi    shift, ~(7 << 3)    ;[28]
269     breq    unstuff3c           ;[29]
270     in      phase, USBIN        ;[30] <- phase
271     rjmp    bit4AfterClr        ;[31]
272 unstuff3c:
273     in      phase, USBIN        ;[31] <- phase (one cycle too late)
274     andi    fix, ~(1 << 3)      ;[32]
275     nop2                        ;[25]
276     nop2                        ;[27]
277 bit3IsSet:
278     ifrclr  phase, USBMINUS     ;[29] check phase only if D- changed
279     lpm                         ;[30]
280     in      phase, USBIN        ;[31] <- phase (one cycle too late)
281     ori     shift, 1 << 3       ;[32]
282 bit4AfterSet:
283     mov     data, fix           ;[33] undo this move by swapping defines
284 #undef  fix
285 #define fix     x1
286 #undef  data
287 #define data    x2
288     ifioclr USBIN, USBMINUS     ;[34] <--- sample 4
289     rjmp    bit4IsClr           ;[35]
290     andi    shift, ~(7 << 4)    ;[36]
291     breq    unstuff4s           ;[37]
292     in      phase, USBIN        ;[38] <- phase
293     rjmp    bit5AfterSet        ;[39]
294 unstuff4s:
295     in      phase, USBIN        ;[39] <- phase (one cycle too late)
296     andi    fix, ~(1 << 4)      ;[40]
297     nop2                        ;[33]
298     nop2                        ;[35]
299 bit4IsClr:
300     ifrset  phase, USBMINUS     ;[37] check phase only if D- changed
301     lpm                         ;[38]
302     in      phase, USBIN        ;[39] <- phase (one cycle too late)
303     ori     shift, 1 << 4       ;[40]
304 bit5AfterClr:
305     ser     data                ;[41]
306     ifioset USBIN, USBMINUS     ;[42] <--- sample 5
307     rjmp    bit5IsSet           ;[43]
308     andi    shift, ~(7 << 5)    ;[44]
309     breq    unstuff5c           ;[45]
310     in      phase, USBIN        ;[46] <- phase
311     rjmp    bit6AfterClr        ;[47]
312 unstuff5c:
313     in      phase, USBIN        ;[47] <- phase (one cycle too late)
314     andi    fix, ~(1 << 5)      ;[48]
315     nop2                        ;[41]
316     nop2                        ;[43]
317 bit5IsSet:
318     ifrclr  phase, USBMINUS     ;[45] check phase only if D- changed
319     lpm                         ;[46]
320     in      phase, USBIN        ;[47] <- phase (one cycle too late)
321     ori     shift, 1 << 5       ;[48]
322 bit6AfterSet:
323     subi    cnt, 1              ;[49]
324     brcs    jumpToOverflow      ;[50]
325     ifioclr USBIN, USBMINUS     ;[51] <--- sample 6
326     rjmp    bit6IsClr           ;[52]
327     andi    shift, ~(3 << 6)    ;[53]
328     cpi     shift, 2            ;[54]
329     in      phase, USBIN        ;[55] <- phase
330     brlt    unstuff6s           ;[56]
331     rjmp    bit7AfterSet        ;[57]
332
333 jumpToOverflow:
334     rjmp    overflow
335
336 unstuff6s:
337     andi    fix, ~(1 << 6)      ;[50]
338     lpm                         ;[51]
339 bit6IsClr:
340     ifrset  phase, USBMINUS     ;[54] check phase only if D- changed
341     lpm                         ;[55]
342     in      phase, USBIN        ;[56] <- phase (one cycle too late)
343     ori     shift, 1 << 6       ;[57]
344     nop                         ;[58]
345 bit7AfterClr:
346     ifioset USBIN, USBMINUS     ;[59] <--- sample 7
347     rjmp    bit7IsSet           ;[60]
348     andi    shift, ~(1 << 7)    ;[61]
349     cpi     shift, 4            ;[62]
350     in      phase, USBIN        ;[63] <- phase
351     brlt    unstuff7c           ;[64]
352     rjmp    bit0AfterClr        ;[65] -> [00] == [67]
353 unstuff7c:
354     andi    fix, ~(1 << 7)      ;[58]
355     nop                         ;[59]
356     rjmp    bit7IsSet           ;[60]
357
358 se0AndStore:
359     st      y+, x1              ;[15/17] cycles after start of byte
360     rjmp    se0                 ;[17/19]
361
362 bit7IsClr:
363     ifrset  phase, USBMINUS     ;[62] check phase only if D- changed
364     lpm                         ;[63]
365     in      phase, USBIN        ;[64] <- phase (one cycle too late)
366     ori     shift, 1 << 7       ;[65]
367     nop                         ;[66]
368 ;;;;rjmp    bit0AfterClr        ; -> [00] == [67] moved block up to save jump
369 bit0AfterClr:
370     eor     fix, shift          ;[00]
371 #undef  fix
372 #define fix     x2
373 #undef  data
374 #define data    x1  /* we now have result in data, fix is reset to 0xff */
375     ifioset USBIN, USBMINUS     ;[01] <--- sample 0
376     rjmp    bit0IsSet           ;[02]
377     andi    shift, ~(7 << 0)    ;[03]
378     breq    unstuff0c           ;[04]
379     in      phase, USBIN        ;[05] <- phase
380     rjmp    bit1AfterClr        ;[06]
381 unstuff0c:
382     in      phase, USBIN        ;[06] <- phase (one cycle too late)
383     andi    fix, ~(1 << 0)      ;[07]
384     ifioclr USBIN, USBMINUS     ;[00]
385     ifioset USBIN, USBPLUS      ;[01]
386     rjmp    bit0IsSet           ;[02] executed if first expr false or second true
387     rjmp    se0AndStore         ;[03] executed only if both bits 0
388 bit0IsSet:
389     ifrclr  phase, USBMINUS     ;[04] check phase only if D- changed
390     lpm                         ;[05]
391     in      phase, USBIN        ;[06] <- phase (one cycle too late)
392     ori     shift, 1 << 0       ;[07]
393 bit1AfterSet:
394     andi    phase, USBMASK      ;[08]
395     ifioclr USBIN, USBMINUS     ;[09] <--- sample 1
396     rjmp    bit1IsClr           ;[10]
397     andi    shift, ~(7 << 1)    ;[11]
398     breq    unstuff1s           ;[12]
399     in      phase, USBIN        ;[13] <- phase
400     nop                         ;[14]
401     rjmp    bit2AfterSet        ;[15]
402 unstuff1s:
403     in      phase, USBIN        ;[14] <- phase (one cycle too late)
404     andi    fix, ~(1 << 1)      ;[15]
405     nop2                        ;[08]
406     nop2                        ;[10]
407 bit1IsClr:
408     ifrset  phase, USBMINUS     ;[12] check phase only if D- changed
409     lpm                         ;[13]
410     in      phase, USBIN        ;[14] <- phase (one cycle too late)
411     breq    se0AndStore         ;[15] if we come from unstuff1s, Z bit is never set
412     ori     shift, 1 << 1       ;[16]
413 bit2AfterClr:
414     ifioset USBIN, USBMINUS     ;[17] <--- sample 2
415     rjmp    bit2IsSet           ;[18]
416     andi    shift, ~(7 << 2)    ;[19]
417     breq    unstuff2c           ;[20]
418     in      phase, USBIN        ;[21] <- phase
419     rjmp    bit3AfterClr        ;[22]
420 unstuff2c:
421     in      phase, USBIN        ;[22] <- phase (one cycle too late)
422     andi    fix, ~(1 << 2)      ;[23]
423     nop2                        ;[16]
424     nop2                        ;[18]
425 bit2IsSet:
426     ifrclr  phase, USBMINUS     ;[20] check phase only if D- changed
427     lpm                         ;[21]
428     in      phase, USBIN        ;[22] <- phase (one cycle too late)
429     ori     shift, 1 << 2       ;[23]
430 bit3AfterSet:
431     st      y+, data            ;[24]
432 entryAfterSet:
433     ifioclr USBIN, USBMINUS     ;[26] <--- sample 3
434     rjmp    bit3IsClr           ;[27]
435     andi    shift, ~(7 << 3)    ;[28]
436     breq    unstuff3s           ;[29]
437     in      phase, USBIN        ;[30] <- phase
438     rjmp    bit4AfterSet        ;[31]
439 unstuff3s:
440     in      phase, USBIN        ;[31] <- phase (one cycle too late)
441     andi    fix, ~(1 << 3)      ;[32]
442     nop2                        ;[25]
443     nop2                        ;[27]
444 bit3IsClr:
445     ifrset  phase, USBMINUS     ;[29] check phase only if D- changed
446     lpm                         ;[30]
447     in      phase, USBIN        ;[31] <- phase (one cycle too late)
448     ori     shift, 1 << 3       ;[32]
449 bit4AfterClr:
450     mov     data, fix           ;[33] undo this move by swapping defines
451 #undef  fix
452 #define fix     x1
453 #undef  data
454 #define data    x2
455     ifioset USBIN, USBMINUS     ;[34] <--- sample 4
456     rjmp    bit4IsSet           ;[35]
457     andi    shift, ~(7 << 4)    ;[36]
458     breq    unstuff4c           ;[37]
459     in      phase, USBIN        ;[38] <- phase
460     rjmp    bit5AfterClr        ;[39]
461 unstuff4c:
462     in      phase, USBIN        ;[39] <- phase (one cycle too late)
463     andi    fix, ~(1 << 4)      ;[40]
464     nop2                        ;[33]
465     nop2                        ;[35]
466 bit4IsSet:
467     ifrclr  phase, USBMINUS     ;[37] check phase only if D- changed
468     lpm                         ;[38]
469     in      phase, USBIN        ;[39] <- phase (one cycle too late)
470     ori     shift, 1 << 4       ;[40]
471 bit5AfterSet:
472     ser     data                ;[41]
473     ifioclr USBIN, USBMINUS     ;[42] <--- sample 5
474     rjmp    bit5IsClr           ;[43]
475     andi    shift, ~(7 << 5)    ;[44]
476     breq    unstuff5s           ;[45]
477     in      phase, USBIN        ;[46] <- phase
478     rjmp    bit6AfterSet        ;[47]
479 unstuff5s:
480     in      phase, USBIN        ;[47] <- phase (one cycle too late)
481     andi    fix, ~(1 << 5)      ;[48]
482     nop2                        ;[41]
483     nop2                        ;[43]
484 bit5IsClr:
485     ifrset  phase, USBMINUS     ;[45] check phase only if D- changed
486     lpm                         ;[46]
487     in      phase, USBIN        ;[47] <- phase (one cycle too late)
488     ori     shift, 1 << 5       ;[48]
489 bit6AfterClr:
490     subi    cnt, 1              ;[49]
491     brcs    overflow            ;[50]
492     ifioset USBIN, USBMINUS     ;[51] <--- sample 6
493     rjmp    bit6IsSet           ;[52]
494     andi    shift, ~(3 << 6)    ;[53]
495     cpi     shift, 2            ;[54]
496     in      phase, USBIN        ;[55] <- phase
497     brlt    unstuff6c           ;[56]
498     rjmp    bit7AfterClr        ;[57]
499 unstuff6c:
500     andi    fix, ~(1 << 6)      ;[50]
501     lpm                         ;[51]
502 bit6IsSet:
503     ifrclr  phase, USBMINUS     ;[54] check phase only if D- changed
504     lpm                         ;[55]
505     in      phase, USBIN        ;[56] <- phase (one cycle too late)
506     ori     shift, 1 << 6       ;[57]
507 bit7AfterSet:
508     ifioclr USBIN, USBMINUS     ;[59] <--- sample 7
509     rjmp    bit7IsClr           ;[60]
510     andi    shift, ~(1 << 7)    ;[61]
511     cpi     shift, 4            ;[62]
512     in      phase, USBIN        ;[63] <- phase
513     brlt    unstuff7s           ;[64]
514     rjmp    bit0AfterSet        ;[65] -> [00] == [67]
515 unstuff7s:
516     andi    fix, ~(1 << 7)      ;[58]
517     nop                         ;[59]
518     rjmp    bit7IsClr           ;[60]
519
520 macro POP_STANDARD ; 14 cycles
521     pop     r0
522     pop     cnt
523     pop     x3
524     pop     x2
525     pop     x1
526     pop     shift
527     pop     YH
528     endm
529 macro POP_RETI     ; 5 cycles
530     pop     YL
531     out     SREG, YL
532     pop     YL
533     endm
534
535 #include "asmcommon.inc"
536
537 ;----------------------------------------------------------------------------
538 ; Transmitting data
539 ;----------------------------------------------------------------------------
540
541 txByteLoop:
542 txBitloop:
543 stuffN1Delay:                   ;     [03]
544     ror     shift               ;[-5] [11] [63]
545     brcc    doExorN1            ;[-4]      [64]
546     subi    x3, 1               ;[-3]
547     brne    commonN1            ;[-2]
548     lsl     shift               ;[-1] compensate ror after rjmp stuffDelay
549     nop                         ;[00] stuffing consists of just waiting 8 cycles
550     rjmp    stuffN1Delay        ;[01] after ror, C bit is reliably clear
551
552 sendNakAndReti:
553     ldi     cnt, USBPID_NAK ;[-19]
554     rjmp    sendCntAndReti  ;[-18]
555 sendAckAndReti:
556     ldi     cnt, USBPID_ACK ;[-17]
557 sendCntAndReti:
558     mov     r0, cnt         ;[-16]
559     ldi     YL, 0           ;[-15] R0 address is 0
560     ldi     YH, 0           ;[-14]
561     ldi     cnt, 2          ;[-13]
562 ;   rjmp    usbSendAndReti      fallthrough
563
564 ; USB spec says:
565 ; idle = J
566 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
567 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
568 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
569
570 ;usbSend:
571 ;pointer to data in 'Y'
572 ;number of bytes in 'cnt' -- including sync byte
573 ;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt]
574 ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
575 usbSendAndReti:
576     in      x2, USBDDR          ;[-10] 10 cycles until SOP
577     ori     x2, USBMASK         ;[-9]
578     sbi     USBOUT, USBMINUS    ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups)
579     out     USBDDR, x2          ;[-6] <--- acquire bus
580     in      x1, USBOUT          ;[-5] port mirror for tx loop
581     ldi     shift, 0x40         ;[-4] sync byte is first byte sent (we enter loop after ror)
582     ldi     x2, USBMASK         ;[-3]
583 doExorN1:
584     eor     x1, x2              ;[-2] [06] [62]
585     ldi     x3, 6               ;[-1] [07] [63]
586 commonN1:
587 stuffN2Delay:
588     out     USBOUT, x1          ;[00] [08] [64] <--- set bit
589     ror     shift               ;[01]
590     brcc    doExorN2            ;[02]
591     subi    x3, 1               ;[03]
592     brne    commonN2            ;[04]
593     lsl     shift               ;[05] compensate ror after rjmp stuffDelay
594     rjmp    stuffN2Delay        ;[06] after ror, C bit is reliably clear
595 doExorN2:
596     eor     x1, x2              ;[04] [12]
597     ldi     x3, 6               ;[05] [13]
598 commonN2:
599     nop2                        ;[06] [14]
600     subi    cnt, 171            ;[08] [16] trick: (3 * 171) & 0xff = 1
601     out     USBOUT, x1          ;[09] [17] <--- set bit
602     brcs    txBitloop           ;[10]      [27] [44]
603
604 stuff6Delay:
605     ror     shift               ;[45] [53]
606     brcc    doExor6             ;[46]
607     subi    x3, 1               ;[47]
608     brne    common6             ;[48]
609     lsl     shift               ;[49] compensate ror after rjmp stuffDelay
610     nop                         ;[50] stuffing consists of just waiting 8 cycles
611     rjmp    stuff6Delay         ;[51] after ror, C bit is reliably clear
612 doExor6:
613     eor     x1, x2              ;[48] [56]
614     ldi     x3, 6               ;[49]
615 common6:
616 stuff7Delay:
617     ror     shift               ;[50] [58]
618     out     USBOUT, x1          ;[51] <--- set bit
619     brcc    doExor7             ;[52]
620     subi    x3, 1               ;[53]
621     brne    common7             ;[54]
622     lsl     shift               ;[55] compensate ror after rjmp stuffDelay
623     rjmp    stuff7Delay         ;[56] after ror, C bit is reliably clear
624 doExor7:
625     eor     x1, x2              ;[54] [62]
626     ldi     x3, 6               ;[55]
627 common7:
628     ld      shift, y+           ;[56]
629     nop                         ;[58]
630     tst     cnt                 ;[59]
631     out     USBOUT, x1          ;[60] [00]<--- set bit
632     brne    txByteLoop          ;[61] [01]
633 ;make SE0:
634     cbr     x1, USBMASK         ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles]
635     lds     x2, usbNewDeviceAddr;[03]
636     lsl     x2                  ;[05] we compare with left shifted address
637     subi    YL, 2 + 0           ;[06] Only assign address on data packets, not ACK/NAK in r0
638     sbci    YH, 0               ;[07]
639     out     USBOUT, x1          ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
640 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
641 ;set address only after data packet was sent, not after handshake
642     breq    skipAddrAssign      ;[01]
643     sts     usbDeviceAddr, x2   ; if not skipped: SE0 is one cycle longer
644 skipAddrAssign:
645 ;end of usbDeviceAddress transfer
646     ldi     x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
647     USB_STORE_PENDING(x2)       ;[04]
648     ori     x1, USBIDLE         ;[05]
649     in      x2, USBDDR          ;[06]
650     cbr     x2, USBMASK         ;[07] set both pins to input
651     mov     x3, x1              ;[08]
652     cbr     x3, USBMASK         ;[09] configure no pullup on both pins
653     lpm                         ;[10]
654     lpm                         ;[13]
655     out     USBOUT, x1          ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
656     out     USBDDR, x2          ;[17] <-- release bus now
657     out     USBOUT, x3          ;[18] <-- ensure no pull-up resistors are active
658     rjmp    doReturn
659
660
661
662 /*****************************************************************************
663 The following PHP script generates a code skeleton for the receiver routine:
664
665 <?php
666
667 function printCmdBuffer($thisBit)
668 {
669 global $cycle;
670
671     $nextBit = ($thisBit + 1) % 8;
672     $s = ob_get_contents();
673     ob_end_clean();
674     $s = str_replace("#", $thisBit, $s);
675     $s = str_replace("@", $nextBit, $s);
676     $lines = explode("\n", $s);
677     for($i = 0; $i < count($lines); $i++){
678         $s = $lines[$i];
679         if(ereg("\\[([0-9-][0-9])\\]", $s, $regs)){
680             $c = $cycle + (int)$regs[1];
681             $s = ereg_replace("\\[[0-9-][0-9]\\]", sprintf("[%02d]", $c), $s);
682         }
683         if(strlen($s) > 0)
684             echo "$s\n";
685     }
686 }
687
688 function printBit($isAfterSet, $bitNum)
689 {
690     ob_start();
691     if($isAfterSet){
692 ?>
693     ifioclr USBIN, USBMINUS     ;[00] <--- sample
694     rjmp    bit#IsClr           ;[01]
695     andi    shift, ~(7 << #)    ;[02]
696     breq    unstuff#s           ;[03]
697     in      phase, USBIN        ;[04] <- phase
698     rjmp    bit@AfterSet        ;[05]
699 unstuff#s:
700     in      phase, USBIN        ;[05] <- phase (one cycle too late)
701     andi    fix, ~(1 << #)      ;[06]
702     nop2                        ;[-1]
703     nop2                        ;[01]
704 bit#IsClr:
705     ifrset  phase, USBMINUS     ;[03] check phase only if D- changed
706     lpm                         ;[04]
707     in      phase, USBIN        ;[05] <- phase (one cycle too late)
708     ori     shift, 1 << #       ;[06]
709 <?php
710     }else{
711 ?>
712     ifioset USBIN, USBMINUS     ;[00] <--- sample
713     rjmp    bit#IsSet           ;[01]
714     andi    shift, ~(7 << #)    ;[02]
715     breq    unstuff#c           ;[03]
716     in      phase, USBIN        ;[04] <- phase
717     rjmp    bit@AfterClr        ;[05]
718 unstuff#c:
719     in      phase, USBIN        ;[05] <- phase (one cycle too late)
720     andi    fix, ~(1 << #)      ;[06]
721     nop2                        ;[-1]
722     nop2                        ;[01]
723 bit#IsSet:
724     ifrclr  phase, USBMINUS     ;[03] check phase only if D- changed
725     lpm                         ;[04]
726     in      phase, USBIN        ;[05] <- phase (one cycle too late)
727     ori     shift, 1 << #       ;[06]
728 <?php
729     }
730     printCmdBuffer($bitNum);
731 }
732
733 $bitStartCycles = array(1, 9, 17, 26, 34, 42, 51, 59);
734 for($i = 0; $i < 16; $i++){
735     $bit = $i % 8;
736     $emitClrCode = ($i + (int)($i / 8)) % 2;
737     $cycle = $bitStartCycles[$bit];
738     if($emitClrCode){
739         printf("bit%dAfterClr:\n", $bit);
740     }else{
741         printf("bit%dAfterSet:\n", $bit);
742     }
743     ob_start();
744     echo "    *****                       ;[-1]\n";
745     printCmdBuffer($bit);
746     printBit(!$emitClrCode, $bit);
747     if($i == 7)
748         echo "\n";
749 }
750
751 ?>
752 *****************************************************************************/
This page took 0.082343 seconds and 3 git commands to generate.