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