Subversion Repositories group.NITPanels

Rev

Details | Last modification | View Log | RSS feed

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