OSDN Git Service

kazzo 0.1.2 release
[unagi/old-svn-converted.git] / kazzo / tag / 0.1.2 / firmware / usbdrv / usbdrvasm16.inc
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: usbdrvasm16.inc 760 2009-08-09 18:59:43Z 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 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