usbdrv/usbdrvasm15.inc

changeset 0
9e9b2c78bd31
equal deleted inserted replaced
-1:000000000000 0:9e9b2c78bd31
1 /* Name: usbdrvasm15.inc
2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3 * Author: contributed by V. Bosch
4 * Creation Date: 2007-08-06
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 15 MHz version of the asssembler part of the USB driver. It
17 requires a 15 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: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte
29 ; Numbers in brackets are clocks counted from center of last sync bit
30 ; when instruction starts
31
32 ;----------------------------------------------------------------------------
33 ; order of registers pushed:
34 ; YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4
35 ;----------------------------------------------------------------------------
36 USB_INTR_VECTOR:
37 push YL ;2 push only what is necessary to sync with edge ASAP
38 in YL, SREG ;1
39 push YL ;2
40 ;----------------------------------------------------------------------------
41 ; Synchronize with sync pattern:
42 ;
43 ; sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
44 ; sync up with J to K edge during sync pattern -- use fastest possible loops
45 ;The first part waits at most 1 bit long since we must be in sync pattern.
46 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
47 ;waitForJ, ensure that this prerequisite is met.
48 waitForJ:
49 inc YL
50 sbis USBIN, USBMINUS
51 brne waitForJ ; just make sure we have ANY timeout
52 ;-------------------------------------------------------------------------------
53 ; The following code results in a sampling window of < 1/4 bit
54 ; which meets the spec.
55 ;-------------------------------------------------------------------------------
56 waitForK: ;-
57 sbis USBIN, USBMINUS ;1 [00] <-- sample
58 rjmp foundK ;2 [01]
59 sbis USBIN, USBMINUS ; <-- sample
60 rjmp foundK
61 sbis USBIN, USBMINUS ; <-- sample
62 rjmp foundK
63 sbis USBIN, USBMINUS ; <-- sample
64 rjmp foundK
65 sbis USBIN, USBMINUS ; <-- sample
66 rjmp foundK
67 sbis USBIN, USBMINUS ; <-- sample
68 rjmp foundK
69 #if USB_COUNT_SOF
70 lds YL, usbSofCount
71 inc YL
72 sts usbSofCount, YL
73 #endif /* USB_COUNT_SOF */
74 #ifdef USB_SOF_HOOK
75 USB_SOF_HOOK
76 #endif
77 rjmp sofError
78 ;------------------------------------------------------------------------------
79 ; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for
80 ; center sampling]
81 ; we have 1 bit time for setup purposes, then sample again.
82 ; Numbers in brackets are cycles from center of first sync (double K)
83 ; bit after the instruction
84 ;------------------------------------------------------------------------------
85 foundK: ;- [02]
86 lds YL, usbInputBufOffset;2 [03+04] tx loop
87 push YH ;2 [05+06]
88 clr YH ;1 [07]
89 subi YL, lo8(-(usbRxBuf)) ;1 [08] [rx loop init]
90 sbci YH, hi8(-(usbRxBuf)) ;1 [09] [rx loop init]
91 push shift ;2 [10+11]
92 ser shift ;1 [12]
93 sbis USBIN, USBMINUS ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early)
94 rjmp haveTwoBitsK ;2 [00] [14]
95 pop shift ;2 [15+16] undo the push from before
96 pop YH ;2 [17+18] undo the push from before
97 rjmp waitForK ;2 [19+20] this was not the end of sync, retry
98 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
99 ; bit times (= 20 cycles).
100
101 ;----------------------------------------------------------------------------
102 ; push more registers and initialize values while we sample the first bits:
103 ;----------------------------------------------------------------------------
104 haveTwoBitsK: ;- [01]
105 push x1 ;2 [02+03]
106 push x2 ;2 [04+05]
107 push x3 ;2 [06+07]
108 push bitcnt ;2 [08+09]
109 in x1, USBIN ;1 [00] [10] <-- sample bit 0
110 bst x1, USBMINUS ;1 [01]
111 bld shift, 0 ;1 [02]
112 push cnt ;2 [03+04]
113 ldi cnt, USB_BUFSIZE ;1 [05]
114 push x4 ;2 [06+07] tx loop
115 rjmp rxLoop ;2 [08]
116 ;----------------------------------------------------------------------------
117 ; Receiver loop (numbers in brackets are cycles within byte after instr)
118 ;----------------------------------------------------------------------------
119 unstuff0: ;- [07] (branch taken)
120 andi x3, ~0x01 ;1 [08]
121 mov x1, x2 ;1 [09] x2 contains last sampled (stuffed) bit
122 in x2, USBIN ;1 [00] [10] <-- sample bit 1 again
123 andi x2, USBMASK ;1 [01]
124 breq se0Hop ;1 [02] SE0 check for bit 1
125 ori shift, 0x01 ;1 [03] 0b00000001
126 nop ;1 [04]
127 rjmp didUnstuff0 ;2 [05]
128 ;-----------------------------------------------------
129 unstuff1: ;- [05] (branch taken)
130 mov x2, x1 ;1 [06] x1 contains last sampled (stuffed) bit
131 andi x3, ~0x02 ;1 [07]
132 ori shift, 0x02 ;1 [08] 0b00000010
133 nop ;1 [09]
134 in x1, USBIN ;1 [00] [10] <-- sample bit 2 again
135 andi x1, USBMASK ;1 [01]
136 breq se0Hop ;1 [02] SE0 check for bit 2
137 rjmp didUnstuff1 ;2 [03]
138 ;-----------------------------------------------------
139 unstuff2: ;- [05] (branch taken)
140 andi x3, ~0x04 ;1 [06]
141 ori shift, 0x04 ;1 [07] 0b00000100
142 mov x1, x2 ;1 [08] x2 contains last sampled (stuffed) bit
143 nop ;1 [09]
144 in x2, USBIN ;1 [00] [10] <-- sample bit 3
145 andi x2, USBMASK ;1 [01]
146 breq se0Hop ;1 [02] SE0 check for bit 3
147 rjmp didUnstuff2 ;2 [03]
148 ;-----------------------------------------------------
149 unstuff3: ;- [00] [10] (branch taken)
150 in x2, USBIN ;1 [01] [11] <-- sample stuffed bit 3 one cycle too late
151 andi x2, USBMASK ;1 [02]
152 breq se0Hop ;1 [03] SE0 check for stuffed bit 3
153 andi x3, ~0x08 ;1 [04]
154 ori shift, 0x08 ;1 [05] 0b00001000
155 rjmp didUnstuff3 ;2 [06]
156 ;----------------------------------------------------------------------------
157 ; extra jobs done during bit interval:
158 ;
159 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs],
160 ; overflow check, jump to the head of rxLoop
161 ; bit 1: SE0 check
162 ; bit 2: SE0 check, recovery from delay [bit 0 tasks took too long]
163 ; bit 3: SE0 check, recovery from delay [bit 0 tasks took too long]
164 ; bit 4: SE0 check, none
165 ; bit 5: SE0 check, none
166 ; bit 6: SE0 check, none
167 ; bit 7: SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others
168 ;----------------------------------------------------------------------------
169 rxLoop: ;- [09]
170 in x2, USBIN ;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed)
171 andi x2, USBMASK ;1 [01]
172 brne SkipSe0Hop ;1 [02]
173 se0Hop: ;- [02]
174 rjmp se0 ;2 [03] SE0 check for bit 1
175 SkipSe0Hop: ;- [03]
176 ser x3 ;1 [04]
177 andi shift, 0xf9 ;1 [05] 0b11111001
178 breq unstuff0 ;1 [06]
179 didUnstuff0: ;- [06]
180 eor x1, x2 ;1 [07]
181 bst x1, USBMINUS ;1 [08]
182 bld shift, 1 ;1 [09]
183 in x1, USBIN ;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed)
184 andi x1, USBMASK ;1 [01]
185 breq se0Hop ;1 [02] SE0 check for bit 2
186 andi shift, 0xf3 ;1 [03] 0b11110011
187 breq unstuff1 ;1 [04] do remaining work for bit 1
188 didUnstuff1: ;- [04]
189 eor x2, x1 ;1 [05]
190 bst x2, USBMINUS ;1 [06]
191 bld shift, 2 ;1 [07]
192 nop2 ;2 [08+09]
193 in x2, USBIN ;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed)
194 andi x2, USBMASK ;1 [01]
195 breq se0Hop ;1 [02] SE0 check for bit 3
196 andi shift, 0xe7 ;1 [03] 0b11100111
197 breq unstuff2 ;1 [04]
198 didUnstuff2: ;- [04]
199 eor x1, x2 ;1 [05]
200 bst x1, USBMINUS ;1 [06]
201 bld shift, 3 ;1 [07]
202 didUnstuff3: ;- [07]
203 andi shift, 0xcf ;1 [08] 0b11001111
204 breq unstuff3 ;1 [09]
205 in x1, USBIN ;1 [00] [10] <-- sample bit 4
206 andi x1, USBMASK ;1 [01]
207 breq se0Hop ;1 [02] SE0 check for bit 4
208 eor x2, x1 ;1 [03]
209 bst x2, USBMINUS ;1 [04]
210 bld shift, 4 ;1 [05]
211 didUnstuff4: ;- [05]
212 andi shift, 0x9f ;1 [06] 0b10011111
213 breq unstuff4 ;1 [07]
214 nop2 ;2 [08+09]
215 in x2, USBIN ;1 [00] [10] <-- sample bit 5
216 andi x2, USBMASK ;1 [01]
217 breq se0 ;1 [02] SE0 check for bit 5
218 eor x1, x2 ;1 [03]
219 bst x1, USBMINUS ;1 [04]
220 bld shift, 5 ;1 [05]
221 didUnstuff5: ;- [05]
222 andi shift, 0x3f ;1 [06] 0b00111111
223 breq unstuff5 ;1 [07]
224 nop2 ;2 [08+09]
225 in x1, USBIN ;1 [00] [10] <-- sample bit 6
226 andi x1, USBMASK ;1 [01]
227 breq se0 ;1 [02] SE0 check for bit 6
228 eor x2, x1 ;1 [03]
229 bst x2, USBMINUS ;1 [04]
230 bld shift, 6 ;1 [05]
231 didUnstuff6: ;- [05]
232 cpi shift, 0x02 ;1 [06] 0b00000010
233 brlo unstuff6 ;1 [07]
234 nop2 ;2 [08+09]
235 in x2, USBIN ;1 [00] [10] <-- sample bit 7
236 andi x2, USBMASK ;1 [01]
237 breq se0 ;1 [02] SE0 check for bit 7
238 eor x1, x2 ;1 [03]
239 bst x1, USBMINUS ;1 [04]
240 bld shift, 7 ;1 [05]
241 didUnstuff7: ;- [05]
242 cpi shift, 0x04 ;1 [06] 0b00000100
243 brlo unstuff7 ;1 [07]
244 eor x3, shift ;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others
245 nop ;1 [09]
246 in x1, USBIN ;1 [00] [10] <-- sample bit 0
247 st y+, x3 ;2 [01+02] store data
248 eor x2, x1 ;1 [03]
249 bst x2, USBMINUS ;1 [04]
250 bld shift, 0 ;1 [05]
251 subi cnt, 1 ;1 [06]
252 brcs overflow ;1 [07]
253 rjmp rxLoop ;2 [08]
254 ;-----------------------------------------------------
255 unstuff4: ;- [08]
256 andi x3, ~0x10 ;1 [09]
257 in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 4
258 andi x1, USBMASK ;1 [01]
259 breq se0 ;1 [02] SE0 check for stuffed bit 4
260 ori shift, 0x10 ;1 [03]
261 rjmp didUnstuff4 ;2 [04]
262 ;-----------------------------------------------------
263 unstuff5: ;- [08]
264 ori shift, 0x20 ;1 [09]
265 in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 5
266 andi x2, USBMASK ;1 [01]
267 breq se0 ;1 [02] SE0 check for stuffed bit 5
268 andi x3, ~0x20 ;1 [03]
269 rjmp didUnstuff5 ;2 [04]
270 ;-----------------------------------------------------
271 unstuff6: ;- [08]
272 andi x3, ~0x40 ;1 [09]
273 in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 6
274 andi x1, USBMASK ;1 [01]
275 breq se0 ;1 [02] SE0 check for stuffed bit 6
276 ori shift, 0x40 ;1 [03]
277 rjmp didUnstuff6 ;2 [04]
278 ;-----------------------------------------------------
279 unstuff7: ;- [08]
280 andi x3, ~0x80 ;1 [09]
281 in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 7
282 andi x2, USBMASK ;1 [01]
283 breq se0 ;1 [02] SE0 check for stuffed bit 7
284 ori shift, 0x80 ;1 [03]
285 rjmp didUnstuff7 ;2 [04]
286
287 macro POP_STANDARD ; 16 cycles
288 pop x4
289 pop cnt
290 pop bitcnt
291 pop x3
292 pop x2
293 pop x1
294 pop shift
295 pop YH
296 endm
297 macro POP_RETI ; 5 cycles
298 pop YL
299 out SREG, YL
300 pop YL
301 endm
302
303 #include "asmcommon.inc"
304
305 ;---------------------------------------------------------------------------
306 ; USB spec says:
307 ; idle = J
308 ; J = (D+ = 0), (D- = 1)
309 ; K = (D+ = 1), (D- = 0)
310 ; Spec allows 7.5 bit times from EOP to SOP for replies
311 ;---------------------------------------------------------------------------
312 bitstuffN: ;- [04]
313 eor x1, x4 ;1 [05]
314 clr x2 ;1 [06]
315 nop ;1 [07]
316 rjmp didStuffN ;1 [08]
317 ;---------------------------------------------------------------------------
318 bitstuff6: ;- [04]
319 eor x1, x4 ;1 [05]
320 clr x2 ;1 [06]
321 rjmp didStuff6 ;1 [07]
322 ;---------------------------------------------------------------------------
323 bitstuff7: ;- [02]
324 eor x1, x4 ;1 [03]
325 clr x2 ;1 [06]
326 nop ;1 [05]
327 rjmp didStuff7 ;1 [06]
328 ;---------------------------------------------------------------------------
329 sendNakAndReti: ;- [-19]
330 ldi x3, USBPID_NAK ;1 [-18]
331 rjmp sendX3AndReti ;1 [-17]
332 ;---------------------------------------------------------------------------
333 sendAckAndReti: ;- [-17]
334 ldi cnt, USBPID_ACK ;1 [-16]
335 sendCntAndReti: ;- [-16]
336 mov x3, cnt ;1 [-15]
337 sendX3AndReti: ;- [-15]
338 ldi YL, 20 ;1 [-14] x3==r20 address is 20
339 ldi YH, 0 ;1 [-13]
340 ldi cnt, 2 ;1 [-12]
341 ; rjmp usbSendAndReti fallthrough
342 ;---------------------------------------------------------------------------
343 ;usbSend:
344 ;pointer to data in 'Y'
345 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
346 ;uses: x1...x4, btcnt, shift, cnt, Y
347 ;Numbers in brackets are time since first bit of sync pattern is sent
348 ;We need not to match the transfer rate exactly because the spec demands
349 ;only 1.5% precision anyway.
350 usbSendAndReti: ;- [-13] 13 cycles until SOP
351 in x2, USBDDR ;1 [-12]
352 ori x2, USBMASK ;1 [-11]
353 sbi USBOUT, USBMINUS ;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups)
354 in x1, USBOUT ;1 [-08] port mirror for tx loop
355 out USBDDR, x2 ;1 [-07] <- acquire bus
356 ; need not init x2 (bitstuff history) because sync starts with 0
357 ldi x4, USBMASK ;1 [-06] exor mask
358 ldi shift, 0x80 ;1 [-05] sync byte is first byte sent
359 ldi bitcnt, 6 ;1 [-04]
360 txBitLoop: ;- [-04] [06]
361 sbrs shift, 0 ;1 [-03] [07]
362 eor x1, x4 ;1 [-02] [08]
363 ror shift ;1 [-01] [09]
364 didStuffN: ;- [09]
365 out USBOUT, x1 ;1 [00] [10] <-- out N
366 ror x2 ;1 [01]
367 cpi x2, 0xfc ;1 [02]
368 brcc bitstuffN ;1 [03]
369 dec bitcnt ;1 [04]
370 brne txBitLoop ;1 [05]
371 sbrs shift, 0 ;1 [06]
372 eor x1, x4 ;1 [07]
373 ror shift ;1 [08]
374 didStuff6: ;- [08]
375 nop ;1 [09]
376 out USBOUT, x1 ;1 [00] [10] <-- out 6
377 ror x2 ;1 [01]
378 cpi x2, 0xfc ;1 [02]
379 brcc bitstuff6 ;1 [03]
380 sbrs shift, 0 ;1 [04]
381 eor x1, x4 ;1 [05]
382 ror shift ;1 [06]
383 ror x2 ;1 [07]
384 didStuff7: ;- [07]
385 ldi bitcnt, 6 ;1 [08]
386 cpi x2, 0xfc ;1 [09]
387 out USBOUT, x1 ;1 [00] [10] <-- out 7
388 brcc bitstuff7 ;1 [01]
389 ld shift, y+ ;2 [02+03]
390 dec cnt ;1 [04]
391 brne txBitLoop ;1 [05]
392 makeSE0:
393 cbr x1, USBMASK ;1 [06] prepare SE0 [spec says EOP may be 19 to 23 cycles]
394 lds x2, usbNewDeviceAddr;2 [07+08]
395 lsl x2 ;1 [09] we compare with left shifted address
396 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
397 ;set address only after data packet was sent, not after handshake
398 out USBOUT, x1 ;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle
399 subi YL, 20 + 2 ;1 [01] Only assign address on data packets, not ACK/NAK in x3
400 sbci YH, 0 ;1 [02]
401 breq skipAddrAssign ;1 [03]
402 sts usbDeviceAddr, x2 ;2 [04+05] if not skipped: SE0 is one cycle longer
403 ;----------------------------------------------------------------------------
404 ;end of usbDeviceAddress transfer
405 skipAddrAssign: ;- [03/04]
406 ldi x2, 1<<USB_INTR_PENDING_BIT ;1 [05] int0 occurred during TX -- clear pending flag
407 USB_STORE_PENDING(x2) ;1 [06]
408 ori x1, USBIDLE ;1 [07]
409 in x2, USBDDR ;1 [08]
410 cbr x2, USBMASK ;1 [09] set both pins to input
411 mov x3, x1 ;1 [10]
412 cbr x3, USBMASK ;1 [11] configure no pullup on both pins
413 ldi x4, 3 ;1 [12]
414 se0Delay: ;- [12] [15]
415 dec x4 ;1 [13] [16]
416 brne se0Delay ;1 [14] [17]
417 nop2 ;2 [18+19]
418 out USBOUT, x1 ;1 [20] <--out J (idle) -- end of SE0 (EOP sig.)
419 out USBDDR, x2 ;1 [21] <--release bus now
420 out USBOUT, x3 ;1 [22] <--ensure no pull-up resistors are active
421 rjmp doReturn ;1 [23]
422 ;---------------------------------------------------------------------------

mercurial