usbdrv/usbdrvasm16.inc

changeset 0
9e9b2c78bd31
equal deleted inserted replaced
-1:000000000000 0:9e9b2c78bd31
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

mercurial