Subversion Repositories group.electronics

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7 pfowler 1
/* Name: usbdrvasm16.inc
2
 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3
 * Author: Christian Starkjohann
4
 * Creation Date: 2007-06-15
5
 * Tabsize: 4
6
 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7
 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
8
 * 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 16 MHz version of the asssembler part of the USB driver. It
18
requires a 16 MHz crystal (not a ceramic resonator and not a calibrated RC
19
oscillator).
20
 
21
See usbdrv.h for a description of the entire driver.
22
 
23
Since almost all of this code is timing critical, don't change unless you
24
really know what you are doing! Many parts require not only a maximum number
25
of CPU cycles, but even an exact number of cycles!
26
*/
27
 
28
;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
29
;nominal frequency: 16 MHz -> 10.6666666 cycles per bit, 85.333333333 cycles per byte
30
; Numbers in brackets are clocks counted from center of last sync bit
31
; when instruction starts
32
 
33
USB_INTR_VECTOR:
34
;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt
35
    push    YL                  ;[-25] push only what is necessary to sync with edge ASAP
36
    in      YL, SREG            ;[-23]
37
    push    YL                  ;[-22]
38
    push    YH                  ;[-20]
39
;----------------------------------------------------------------------------
40
; Synchronize with sync pattern:
41
;----------------------------------------------------------------------------
42
;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
43
;sync up with J to K edge during sync pattern -- use fastest possible loops
44
;The first part waits at most 1 bit long since we must be in sync pattern.
45
;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
46
;waitForJ, ensure that this prerequisite is met.
47
waitForJ:
48
    inc     YL
49
    sbis    USBIN, USBMINUS
50
    brne    waitForJ        ; just make sure we have ANY timeout
51
waitForK:
52
;The following code results in a sampling window of < 1/4 bit which meets the spec.
53
    sbis    USBIN, USBMINUS     ;[-15]
54
    rjmp    foundK              ;[-14]
55
    sbis    USBIN, USBMINUS
56
    rjmp    foundK
57
    sbis    USBIN, USBMINUS
58
    rjmp    foundK
59
    sbis    USBIN, USBMINUS
60
    rjmp    foundK
61
    sbis    USBIN, USBMINUS
62
    rjmp    foundK
63
    sbis    USBIN, USBMINUS
64
    rjmp    foundK
65
#if USB_COUNT_SOF
66
    lds     YL, usbSofCount
67
    inc     YL
68
    sts     usbSofCount, YL
69
#endif  /* USB_COUNT_SOF */
70
#ifdef USB_SOF_HOOK
71
    USB_SOF_HOOK
72
#endif
73
    rjmp    sofError
74
foundK:                         ;[-12]
75
;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
76
;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
77
;are cycles from center of first sync (double K) bit after the instruction
78
    push    bitcnt              ;[-12]
79
;   [---]                       ;[-11]
80
    lds     YL, usbInputBufOffset;[-10]
81
;   [---]                       ;[-9]
82
    clr     YH                  ;[-8]
83
    subi    YL, lo8(-(usbRxBuf));[-7] [rx loop init]
84
    sbci    YH, hi8(-(usbRxBuf));[-6] [rx loop init]
85
    push    shift               ;[-5]
86
;   [---]                       ;[-4]
87
    ldi     bitcnt, 0x55        ;[-3] [rx loop init]
88
    sbis    USBIN, USBMINUS     ;[-2] we want two bits K (sample 2 cycles too early)
89
    rjmp    haveTwoBitsK        ;[-1]
90
    pop     shift               ;[0] undo the push from before
91
    pop     bitcnt              ;[2] undo the push from before
92
    rjmp    waitForK            ;[4] this was not the end of sync, retry
93
; The entire loop from waitForK until rjmp waitForK above must not exceed two
94
; bit times (= 21 cycles).
95
 
96
;----------------------------------------------------------------------------
97
; push more registers and initialize values while we sample the first bits:
98
;----------------------------------------------------------------------------
99
haveTwoBitsK:
100
    push    x1              ;[1]
101
    push    x2              ;[3]
102
    push    x3              ;[5]
103
    ldi     shift, 0        ;[7]
104
    ldi     x3, 1<<4        ;[8] [rx loop init] first sample is inverse bit, compensate that
105
    push    x4              ;[9] == leap
106
 
107
    in      x1, USBIN       ;[11] <-- sample bit 0
108
    andi    x1, USBMASK     ;[12]
109
    bst     x1, USBMINUS    ;[13]
110
    bld     shift, 7        ;[14]
111
    push    cnt             ;[15]
112
    ldi     leap, 0         ;[17] [rx loop init]
113
    ldi     cnt, USB_BUFSIZE;[18] [rx loop init]
114
    rjmp    rxbit1          ;[19] arrives at [21]
115
 
116
;----------------------------------------------------------------------------
117
; Receiver loop (numbers in brackets are cycles within byte after instr)
118
;----------------------------------------------------------------------------
119
 
120
; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap"
121
; accordingly to approximate this value in the long run.
122
 
123
unstuff6:
124
    andi    x2, USBMASK ;[03]
125
    ori     x3, 1<<6    ;[04] will not be shifted any more
126
    andi    shift, ~0x80;[05]
127
    mov     x1, x2      ;[06] sampled bit 7 is actually re-sampled bit 6
128
    subi    leap, -1    ;[07] total duration = 11 bits -> subtract 1/3
129
    rjmp    didUnstuff6 ;[08]
130
 
131
unstuff7:
132
    ori     x3, 1<<7    ;[09] will not be shifted any more
133
    in      x2, USBIN   ;[00] [10]  re-sample bit 7
134
    andi    x2, USBMASK ;[01]
135
    andi    shift, ~0x80;[02]
136
    subi    leap, 2     ;[03] total duration = 10 bits -> add 1/3
137
    rjmp    didUnstuff7 ;[04]
138
 
139
unstuffEven:
140
    ori     x3, 1<<6    ;[09] will be shifted right 6 times for bit 0
141
    in      x1, USBIN   ;[00] [10]
142
    andi    shift, ~0x80;[01]
143
    andi    x1, USBMASK ;[02]
144
    breq    se0         ;[03]
145
    subi    leap, -1    ;[04] total duration = 11 bits -> subtract 1/3
146
    nop2                ;[05]
147
    rjmp    didUnstuffE ;[06]
148
 
149
unstuffOdd:
150
    ori     x3, 1<<5    ;[09] will be shifted right 4 times for bit 1
151
    in      x2, USBIN   ;[00] [10]
152
    andi    shift, ~0x80;[01]
153
    andi    x2, USBMASK ;[02]
154
    breq    se0         ;[03]
155
    subi    leap, -1    ;[04] total duration = 11 bits -> subtract 1/3
156
    nop2                ;[05]
157
    rjmp    didUnstuffO ;[06]
158
 
159
rxByteLoop:
160
    andi    x1, USBMASK ;[03]
161
    eor     x2, x1      ;[04]
162
    subi    leap, 1     ;[05]
163
    brpl    skipLeap    ;[06]
164
    subi    leap, -3    ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte
165
    nop                 ;1
166
skipLeap:
167
    subi    x2, 1       ;[08]
168
    ror     shift       ;[09]
169
didUnstuff6:
170
    cpi     shift, 0xfc ;[10]
171
    in      x2, USBIN   ;[00] [11] <-- sample bit 7
172
    brcc    unstuff6    ;[01]
173
    andi    x2, USBMASK ;[02]
174
    eor     x1, x2      ;[03]
175
    subi    x1, 1       ;[04]
176
    ror     shift       ;[05]
177
didUnstuff7:
178
    cpi     shift, 0xfc ;[06]
179
    brcc    unstuff7    ;[07]
180
    eor     x3, shift   ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others
181
    st      y+, x3      ;[09] store data
182
rxBitLoop:
183
    in      x1, USBIN   ;[00] [11] <-- sample bit 0/2/4
184
    andi    x1, USBMASK ;[01]
185
    eor     x2, x1      ;[02]
186
    andi    x3, 0x3f    ;[03] topmost two bits reserved for 6 and 7
187
    subi    x2, 1       ;[04]
188
    ror     shift       ;[05]
189
    cpi     shift, 0xfc ;[06]
190
    brcc    unstuffEven ;[07]
191
didUnstuffE:
192
    lsr     x3          ;[08]
193
    lsr     x3          ;[09]
194
rxbit1:
195
    in      x2, USBIN   ;[00] [10] <-- sample bit 1/3/5
196
    andi    x2, USBMASK ;[01]
197
    breq    se0         ;[02]
198
    eor     x1, x2      ;[03]
199
    subi    x1, 1       ;[04]
200
    ror     shift       ;[05]
201
    cpi     shift, 0xfc ;[06]
202
    brcc    unstuffOdd  ;[07]
203
didUnstuffO:
204
    subi    bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3
205
    brcs    rxBitLoop   ;[09]
206
 
207
    subi    cnt, 1      ;[10]
208
    in      x1, USBIN   ;[00] [11] <-- sample bit 6
209
    brcc    rxByteLoop  ;[01]
210
    rjmp    overflow
211
 
212
macro POP_STANDARD ; 14 cycles
213
    pop     cnt
214
    pop     x4
215
    pop     x3
216
    pop     x2
217
    pop     x1
218
    pop     shift
219
    pop     bitcnt
220
    endm
221
macro POP_RETI     ; 7 cycles
222
    pop     YH
223
    pop     YL
224
    out     SREG, YL
225
    pop     YL
226
    endm
227
 
228
#include "asmcommon.inc"
229
 
230
; USB spec says:
231
; idle = J
232
; J = (D+ = 0), (D- = 1)
233
; K = (D+ = 1), (D- = 0)
234
; Spec allows 7.5 bit times from EOP to SOP for replies
235
 
236
bitstuffN:
237
    eor     x1, x4          ;[5]
238
    ldi     x2, 0           ;[6]
239
    nop2                    ;[7]
240
    nop                     ;[9]
241
    out     USBOUT, x1      ;[10] <-- out
242
    rjmp    didStuffN       ;[0]
243
 
244
bitstuff6:
245
    eor     x1, x4          ;[5]
246
    ldi     x2, 0           ;[6] Carry is zero due to brcc
247
    rol     shift           ;[7] compensate for ror shift at branch destination
248
    rjmp    didStuff6       ;[8]
249
 
250
bitstuff7:
251
    ldi     x2, 0           ;[2] Carry is zero due to brcc
252
    rjmp    didStuff7       ;[3]
253
 
254
 
255
sendNakAndReti:
256
    ldi     x3, USBPID_NAK  ;[-18]
257
    rjmp    sendX3AndReti   ;[-17]
258
sendAckAndReti:
259
    ldi     cnt, USBPID_ACK ;[-17]
260
sendCntAndReti:
261
    mov     x3, cnt         ;[-16]
262
sendX3AndReti:
263
    ldi     YL, 20          ;[-15] x3==r20 address is 20
264
    ldi     YH, 0           ;[-14]
265
    ldi     cnt, 2          ;[-13]
266
;   rjmp    usbSendAndReti      fallthrough
267
 
268
;usbSend:
269
;pointer to data in 'Y'
270
;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
271
;uses: x1...x4, btcnt, shift, cnt, Y
272
;Numbers in brackets are time since first bit of sync pattern is sent
273
;We don't match the transfer rate exactly (don't insert leap cycles every third
274
;byte) because the spec demands only 1.5% precision anyway.
275
usbSendAndReti:             ; 12 cycles until SOP
276
    in      x2, USBDDR      ;[-12]
277
    ori     x2, USBMASK     ;[-11]
278
    sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
279
    in      x1, USBOUT      ;[-8] port mirror for tx loop
280
    out     USBDDR, x2      ;[-7] <- acquire bus
281
; need not init x2 (bitstuff history) because sync starts with 0
282
    ldi     x4, USBMASK     ;[-6] exor mask
283
    ldi     shift, 0x80     ;[-5] sync byte is first byte sent
284
txByteLoop:
285
    ldi     bitcnt, 0x35    ;[-4] [6] binary 0011 0101
286
txBitLoop:
287
    sbrs    shift, 0        ;[-3] [7]
288
    eor     x1, x4          ;[-2] [8]
289
    out     USBOUT, x1      ;[-1] [9] <-- out N
290
    ror     shift           ;[0] [10]
291
    ror     x2              ;[1]
292
didStuffN:
293
    cpi     x2, 0xfc        ;[2]
294
    brcc    bitstuffN       ;[3]
295
    lsr     bitcnt          ;[4]
296
    brcc    txBitLoop       ;[5]
297
    brne    txBitLoop       ;[6]
298
 
299
    sbrs    shift, 0        ;[7]
300
    eor     x1, x4          ;[8]
301
didStuff6:
302
    out     USBOUT, x1      ;[-1] [9] <-- out 6
303
    ror     shift           ;[0] [10]
304
    ror     x2              ;[1]
305
    cpi     x2, 0xfc        ;[2]
306
    brcc    bitstuff6       ;[3]
307
    ror     shift           ;[4]
308
didStuff7:
309
    ror     x2              ;[5]
310
    sbrs    x2, 7           ;[6]
311
    eor     x1, x4          ;[7]
312
    nop                     ;[8]
313
    cpi     x2, 0xfc        ;[9]
314
    out     USBOUT, x1      ;[-1][10] <-- out 7
315
    brcc    bitstuff7       ;[0] [11]
316
    ld      shift, y+       ;[1]
317
    dec     cnt             ;[3]
318
    brne    txByteLoop      ;[4]
319
;make SE0:
320
    cbr     x1, USBMASK     ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles]
321
    lds     x2, usbNewDeviceAddr;[6]
322
    lsl     x2              ;[8] we compare with left shifted address
323
    subi    YL, 20 + 2      ;[9] Only assign address on data packets, not ACK/NAK in x3
324
    sbci    YH, 0           ;[10]
325
    out     USBOUT, x1      ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
326
;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
327
;set address only after data packet was sent, not after handshake
328
    breq    skipAddrAssign  ;[0]
329
    sts     usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
330
skipAddrAssign:
331
;end of usbDeviceAddress transfer
332
    ldi     x2, 1<<USB_INTR_PENDING_BIT;[2] int0 occurred during TX -- clear pending flag
333
    USB_STORE_PENDING(x2)   ;[3]
334
    ori     x1, USBIDLE     ;[4]
335
    in      x2, USBDDR      ;[5]
336
    cbr     x2, USBMASK     ;[6] set both pins to input
337
    mov     x3, x1          ;[7]
338
    cbr     x3, USBMASK     ;[8] configure no pullup on both pins
339
    ldi     x4, 4           ;[9]
340
se0Delay:
341
    dec     x4              ;[10] [13] [16] [19]
342
    brne    se0Delay        ;[11] [14] [17] [20]
343
    out     USBOUT, x1      ;[21] <-- out J (idle) -- end of SE0 (EOP signal)
344
    out     USBDDR, x2      ;[22] <-- release bus now
345
    out     USBOUT, x3      ;[23] <-- ensure no pull-up resistors are active
346
    rjmp    doReturn