Subversion Repositories group.NITPanels

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 pfowler 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
*****************************************************************************/