Subversion Repositories group.electronics

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7 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
 * This Revision: $Id$
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
*****************************************************************************/