USBasp 2005.04.21.
[pub/USBasp.git] / firmware / usbdrv / usbdrvasm.S
1 /* Name: usbdrvasm.S
2 * Project: AVR USB driver
3 * Author: Christian Starkjohann
4 * Creation Date: 2004-12-29
5 * Tabsize: 4
6 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: Proprietary, free under certain conditions. See Documentation.
8 * This Revision: $Id: usbdrvasm.S 52 2005-04-12 16:57:29Z cs $
9 */
10
11 /*
12 General Description:
13 This module implements the assembler part of the USB driver. See usbdrv.h
14 for a description of the entire driver.
15 Since almost all of this code is timing critical, don't change unless you
16 really know what you are doing! Many parts require not only a maximum number
17 of CPU cycles, but even an exact number of cycles!
18 */
19
20 /* configs for io.h */
21 #define __SFR_OFFSET 0
22 #define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */
23
24 #include <avr/io.h> /* for CPU I/O register definitions and vectors */
25 #include "usbdrv.h" /* for common defs */
26
27
28 /* register names */
29 #define x1 r16
30 #define x2 r17
31 #define shift r18
32 #define cnt r19
33 #define x3 r20
34 #define x4 r21
35
36 #define nop2 rjmp .+0 /* jump to next instruction */
37
38 .text
39
40 .global SIG_INTERRUPT0
41 .type SIG_INTERRUPT0, @function
42 SIG_INTERRUPT0:
43 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
44 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
45 ;max allowable interrupt latency: 32 cycles -> max 25 cycles interrupt disable
46 ;max stack usage: [ret(2), x1, SREG, x2, cnt, shift, YH, YL, x3, x4] = 11 bytes
47 usbInterrupt:
48 ;order of registers pushed:
49 ;x1, SREG, x2, cnt, shift, [YH, YL, x3]
50 push x1 ;2 push only what is necessary to sync with edge ASAP
51 in x1, SREG ;1
52 push x1 ;2
53 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
54 ;sync up with J to K edge during sync pattern -- use fastest possible loops
55 ;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
56 #if !USB_CFG_SAMPLE_EXACT
57 ldi x1, 5 ;1 setup a timeout for waitForK
58 #endif
59 waitForJ:
60 sbis USBIN, USBMINUS ;1 wait for D- == 1
61 rjmp waitForJ ;2
62 #if USB_CFG_SAMPLE_EXACT
63 ;The following code represents the unrolled loop in the else branch. It
64 ;results in a sampling window of 1/4 bit which meets the spec.
65 sbis USBIN, USBMINUS
66 rjmp foundK
67 sbis USBIN, USBMINUS
68 rjmp foundK
69 sbis USBIN, USBMINUS
70 rjmp foundK
71 nop
72 nop2
73 foundK:
74 #else
75 waitForK:
76 dec x1 ;1
77 sbic USBIN, USBMINUS ;1 wait for D- == 0
78 brne waitForK ;2
79 #endif
80 ;{2, 6} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
81 ;we have 1 bit time for setup purposes, then sample again:
82 push x2 ;2
83 push cnt ;2
84 push shift ;2
85 shortcutEntry:
86 ldi cnt, 1 ;1 pre-init bit counter (-1 because no dec follows, -1 because 1 bit already sampled)
87 ldi x2, 1<<USB_CFG_DPLUS_BIT ;1 -> 8 edge sync ended with D- == 0
88 ;now wait until SYNC byte is over. Wait for either 2 bits low (success) or 2 bits high (failure)
89 waitNoChange:
90 in x1, USBIN ;1 <-- sample, timing: edge + {2, 6} cycles
91 eor x2, x1 ;1
92 sbrc x2, 0 ;1 | 2
93 ldi cnt, 2 ;1 | 0 cnt = numBits - 1 (because dec follows)
94 mov x2, x1 ;1
95 dec cnt ;1
96 brne waitNoChange ;2 | 1
97 sbrc x1, USBMINUS ;2
98 rjmp sofError ;0 two consecutive "1" bits -> framing error
99 ;start reading data, but don't check for bitstuffing because these are the
100 ;first bits. Use the cycles for initialization instead. Note that we read and
101 ;store the binary complement of the data stream because eor results in 1 for
102 ;a change and 0 for no change.
103 in x1, USBIN ;1 <-- sample bit 0, timing: edge + {3, 7} cycles
104 eor x2, x1 ;1
105 ror x2 ;1
106 ldi shift, 0x7f ;1 The last bit of the sync pattern was a "no change"
107 ror shift ;1
108 push YH ;2 -> 7
109 in x2, USBIN ;1 <-- sample bit 1, timing: edge + {2, 6} cycles
110 eor x1, x2 ;1
111 ror x1 ;1
112 ror shift ;1
113 push YL ;2
114 lds YL, usbInputBuf ;2 -> 8
115 in x1, USBIN ;1 <-- sample bit 2, timing: edge + {2, 6} cycles
116 eor x2, x1 ;1
117 ror x2 ;1
118 ror shift ;1
119 ldi cnt, USB_BUFSIZE;1
120 clr YH ;1
121 push x3 ;2 -> 8
122 in x2, USBIN ;1 <-- sample bit 3, timing: edge + {2, 6} cycles
123 eor x1, x2 ;1
124 ror x1 ;1
125 ror shift ;1
126 ser x3 ;1
127 nop ;1
128 rjmp rxbit4 ;2 -> 8
129
130 shortcutToStart: ;{,43} into next frame: max 5.5 sync bits missed
131 #if !USB_CFG_SAMPLE_EXACT
132 ldi x1, 5 ;2 setup timeout
133 #endif
134 waitForJ1:
135 sbis USBIN, USBMINUS ;1 wait for D- == 1
136 rjmp waitForJ1 ;2
137 #if USB_CFG_SAMPLE_EXACT
138 ;The following code represents the unrolled loop in the else branch. It
139 ;results in a sampling window of 1/4 bit which meets the spec.
140 sbis USBIN, USBMINUS
141 rjmp foundK1
142 sbis USBIN, USBMINUS
143 rjmp foundK1
144 sbis USBIN, USBMINUS
145 rjmp foundK1
146 nop
147 nop2
148 foundK1:
149 #else
150 waitForK1:
151 dec x1 ;1
152 sbic USBIN, USBMINUS ;1 wait for D- == 0
153 brne waitForK1 ;2
154 #endif
155 pop YH ;2 correct stack alignment
156 nop2 ;2 delay for the same time as the pushes in the original code
157 rjmp shortcutEntry ;2
158
159 ; ################# receiver loop #################
160 ; extra jobs done during bit interval:
161 ; bit 6: se0 check
162 ; bit 7: or, store, clear
163 ; bit 0: recover from delay [SE0 is unreliable here due to bit dribbling in hubs]
164 ; bit 1: se0 check
165 ; bit 2: se0 check
166 ; bit 3: overflow check
167 ; bit 4: se0 check
168 ; bit 5: rjmp
169
170 ; stuffed* helpers have the functionality of a subroutine, but we can't afford
171 ; the overhead of a call. We therefore need a separate routine for each caller
172 ; which jumps back appropriately.
173
174 stuffed5: ;1 for branch taken
175 in x2, USBIN ;1 <-- sample @ +1
176 andi x2, USBMASK ;1
177 breq se0a ;1
178 andi x3, 0xc0 ;1 (0xff03 >> 2) & 0xff
179 ori shift, 0xfc ;1
180 rjmp rxbit6 ;2
181
182 stuffed6: ;1 for branch taken
183 in x1, USBIN ;1 <-- sample @ +1
184 andi x1, USBMASK ;1
185 breq se0a ;1
186 andi x3, 0x81 ;1 (0xff03 >> 1) & 0xff
187 ori shift, 0xfc ;1
188 rjmp rxbit7 ;2
189
190 ; This is somewhat special because it has to compensate for the delay in bit 7
191 stuffed7: ;1 for branch taken
192 andi x1, USBMASK ;1 already sampled by caller
193 breq se0a ;1
194 mov x2, x1 ;1 ensure correct NRZI sequence [we can save andi x3 here]
195 ori shift, 0xfc ;1
196 in x1, USBIN ;1 <-- sample bit 0
197 rjmp unstuffed7 ;2
198
199 stuffed0: ;1 for branch taken
200 in x1, USBIN ;1 <-- sample @ +1
201 andi x1, USBMASK ;1
202 breq se0a ;1
203 andi x3, 0xfe ;1 (0xff03 >> 7) & 0xff
204 ori shift, 0xfc ;1
205 rjmp rxbit1 ;2
206
207 ;-----------------------------
208 rxLoop:
209 brlo stuffed5 ;1
210 rxbit6:
211 in x1, USBIN ;1 <-- sample bit 6
212 andi x1, USBMASK ;1
213 breq se0a ;1
214 eor x2, x1 ;1
215 ror x2 ;1
216 ror shift ;1
217 cpi shift, 4 ;1
218 brlo stuffed6 ;1
219 rxbit7:
220 in x2, USBIN ;1 <-- sample bit 7
221 eor x1, x2 ;1
222 ror x1 ;1
223 ror shift ;1
224 eor x3, shift ;1 x3 is 0 at bit locations we changed, 1 at others
225 st y+, x3 ;2 the eor above reconstructed modified bits and inverted rx data
226 ser x3 ;1
227 rxbit0:
228 in x1, USBIN ;1 <-- sample bit 0
229 cpi shift, 4 ;1
230 brlo stuffed7 ;1
231 unstuffed7:
232 eor x2, x1 ;1
233 ror x2 ;1
234 ror shift ;1
235 cpi shift, 4 ;1
236 brlo stuffed0 ;1
237 rxbit1:
238 in x2, USBIN ;1 <-- sample bit 1
239 andi x2, USBMASK ;1
240 se0a: ; enlarge jump range to SE0
241 breq se0 ;1 check for SE0 more often close to start of byte
242 eor x1, x2 ;1
243 ror x1 ;1
244 ror shift ;1
245 cpi shift, 4 ;1
246 brlo stuffed1 ;1
247 rxbit2:
248 in x1, USBIN ;1 <-- sample bit 2
249 andi x1, USBMASK ;1
250 breq se0 ;1
251 eor x2, x1 ;1
252 ror x2 ;1
253 ror shift ;1
254 cpi shift, 4 ;1
255 brlo stuffed2 ;1
256 rxbit3:
257 in x2, USBIN ;1 <-- sample bit 3
258 eor x1, x2 ;1
259 ror x1 ;1
260 ror shift ;1
261 dec cnt ;1 check for buffer overflow
262 breq overflow ;1
263 cpi shift, 4 ;1
264 brlo stuffed3 ;1
265 rxbit4:
266 in x1, USBIN ;1 <-- sample bit 4
267 andi x1, USBMASK ;1
268 breq se0 ;1
269 eor x2, x1 ;1
270 ror x2 ;1
271 ror shift ;1
272 cpi shift, 4 ;1
273 brlo stuffed4 ;1
274 rxbit5:
275 in x2, USBIN ;1 <-- sample bit 5
276 eor x1, x2 ;1
277 ror x1 ;1
278 ror shift ;1
279 cpi shift, 4 ;1
280 rjmp rxLoop ;2
281 ;-----------------------------
282
283 stuffed1: ;1 for branch taken
284 in x2, USBIN ;1 <-- sample @ +1
285 andi x2, USBMASK ;1
286 breq se0 ;1
287 andi x3, 0xfc ;1 (0xff03 >> 6) & 0xff
288 ori shift, 0xfc ;1
289 rjmp rxbit2 ;2
290
291 stuffed2: ;1 for branch taken
292 in x1, USBIN ;1 <-- sample @ +1
293 andi x1, USBMASK ;1
294 breq se0 ;1
295 andi x3, 0xf8 ;1 (0xff03 >> 5) & 0xff
296 ori shift, 0xfc ;1
297 rjmp rxbit3 ;2
298
299 stuffed3: ;1 for branch taken
300 in x2, USBIN ;1 <-- sample @ +1
301 andi x2, USBMASK ;1
302 breq se0 ;1
303 andi x3, 0xf0 ;1 (0xff03 >> 4) & 0xff
304 ori shift, 0xfc ;1
305 rjmp rxbit4 ;2
306
307 stuffed4: ;1 for branch taken
308 in x1, USBIN ;1 <-- sample @ +1
309 andi x1, USBMASK ;1
310 breq se0 ;1
311 andi x3, 0xe0 ;1 (0xff03 >> 3) & 0xff
312 ori shift, 0xfc ;1
313 rjmp rxbit5 ;2
314
315 ;################ end receiver loop ###############
316
317 overflow: ; ignore package if buffer overflow
318 rjmp rxDoReturn ; enlarge jump range
319
320 ;This is the only non-error exit point for the software receiver loop
321 ;{4, 20} cycles after start of SE0, typically {10, 18} after SE0 start = {-6, 2} from end of SE0
322 ;next sync starts {16,} cycles after SE0 -> worst case start: +4 from next sync start
323 ;we don't check any CRCs here because there is no time left.
324 se0: ;{-6, 2} from end of SE0 / {,4} into next frame
325 mov cnt, YL ;1 assume buffer in lower 256 bytes of memory
326 lds YL, usbInputBuf ;2 reposition to buffer start
327 sub cnt, YL ;1 length of message
328 ldi x1, 1<<USB_INTR_PENDING_BIT ;1
329 cpi cnt, 3 ;1
330 out USB_INTR_PENDING, x1;1 clear pending intr and check flag later. SE0 must be over. {,10} into next frame
331 brlo rxDoReturn ;1 ensure valid packet size, ignore others
332 ld x1, y ;2 PID
333 ldd x2, y+1 ;2 ADDR + 1 bit endpoint number
334 mov x3, x2 ;1 store for endpoint number
335 andi x2, 0x7f ;1 mask endpoint number bit
336 lds shift, usbDeviceId ;2
337 cpi x1, USBPID_SETUP ;1
338 breq isSetupOrOut ;2 -> 19 = {13, 21} from SE0 end
339 cpi x1, USBPID_OUT ;1
340 breq isSetupOrOut ;2 -> 22 = {16, 24} from SE0 end / {,24} into next frame
341 cpi x1, USBPID_IN ;1
342 breq handleIn ;1
343 cpi x1, USBPID_DATA0 ;1
344 breq isData ;1
345 cpi x1, USBPID_DATA1 ;1
346 brne rxDoReturn ;1 ignore all other PIDs
347 isData:
348 lds x2, usbCurrentTok ;2
349 tst x2 ;1
350 breq rxDoReturn ;1 for other device or spontaneous data -- ignore
351 lds x1, usbRxLen ;2
352 cpi x1, 0 ;1
353 brne sendNakAndReti ;1 no buffer space available / {30, 38} from SE0 end
354 sts usbRxLen, cnt ;2 store received data, swap buffers
355 sts usbRxToken, x2 ;2
356 lds x1, usbAppBuf ;2
357 sts usbAppBuf, YL ;2
358 sts usbInputBuf, x1 ;2 buffers now swapped
359 rjmp sendAckAndReti ;2 -> {42, 50} from SE0 end
360
361 handleIn: ; {18, 26} from SE0 end
362 cp x2, shift ;1 shift contains our device ID
363 brne rxDoReturn ;1 other device
364 #if USB_CFG_HAVE_INTRIN_ENDPOINT
365 sbrc x3, 7 ;2
366 rjmp handleIn1 ;0
367 #endif
368 lds cnt, usbTxLen ;2
369 cpi cnt, -1 ;1
370 breq sendNakAndReti ;1 -> {27, 35} from SE0 end
371 ldi x1, -1 ;1
372 sts usbTxLen, x1 ;2 buffer is now free
373 ldi YL, lo8(usbTxBuf) ;1
374 ldi YH, hi8(usbTxBuf) ;1
375 rjmp usbSendAndReti ;2 -> {34, 43} from SE0 end
376
377 ; Comment about when to set usbTxLen to -1:
378 ; We should set it back to -1 when we receive the ACK from the host. This would
379 ; be simple to implement: One static variable which stores whether the last
380 ; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
381 ; ACK. However, we set it back to -1 immediately when we send the package,
382 ; assuming that no error occurs and the host sends an ACK. We save one byte
383 ; RAM this way and avoid potential problems with endless retries. The rest of
384 ; the driver assumes error-free transfers anyway.
385
386 otherOutOrSetup:
387 clr x1
388 sts usbCurrentTok, x1
389 rxDoReturn:
390 pop x3 ;2
391 pop YL ;2
392 pop YH ;2
393 rjmp sofError ;2
394
395 isSetupOrOut: ; we must be fast here -- a data package may follow / {,24} into next frame
396 cp x2, shift ;1 shift contains our device ID
397 brne otherOutOrSetup ;1 other device -- ignore
398 sts usbCurrentTok, x1 ;2
399 #if 0 /* we implement only one rx endpoint */
400 sts usbRxEndp, x3 ;2 only stored if we may have to distinguish endpoints
401 #endif
402 ;A transmission can still have data in the output buffer while we receive a
403 ;SETUP package with an IN phase. To avoid that the old data is sent as a reply,
404 ;we abort transmission. ### This mechanism assumes that NO OUT OR SETUP package
405 ;is ever sent to endpoint 1. We would abort transmission for endpoint 0
406 ;in this case.
407 ldi x1, -1 ;1
408 sts usbMsgLen, x1 ;2
409 sts usbTxLen, x1 ;2 abort transmission
410 pop x3 ;2
411 pop YL ;2
412 in x1, USB_INTR_PENDING;1
413 sbrc x1, USB_INTR_PENDING_BIT;1 check whether data is already arriving {,41} into next frame
414 rjmp shortcutToStart ;2 save the pops and pushes -- a new interrupt is aready pending
415 ;If the jump above was not taken, we can be at {,2} into the next frame here
416 pop YH ;2
417 sofError: ; error in start of frame -- ignore frame
418 ldi x1, 1<<USB_INTR_PENDING_BIT;1 many int0 events occurred during our processing -- clear pending flag
419 out USB_INTR_PENDING, x1;1
420 pop shift ;2
421 pop cnt ;2
422 pop x2 ;2
423 pop x1 ;2
424 out SREG, x1 ;1
425 pop x1 ;2
426 reti ;4 -> {,21} into next frame -> up to 3 sync bits missed
427
428
429 sendNakAndReti: ; 21 cycles until SOP
430 ldi YL, lo8(usbNakBuf) ;1
431 ldi YH, hi8(usbNakBuf) ;1
432 rjmp usbSendToken ;2
433
434 sendAckAndReti: ; 19 cycles until SOP
435 ldi YL, lo8(usbAckBuf) ;1
436 ldi YH, hi8(usbAckBuf) ;1
437 usbSendToken:
438 ldi cnt, 2 ;1
439 ;;;;rjmp usbSendAndReti fallthrough
440
441 ; USB spec says:
442 ; idle = J
443 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
444 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
445 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
446
447 ;usbSend:
448 ;pointer to data in 'Y'
449 ;number of bytes in 'cnt'
450 ;uses: x1...x4, shift, cnt, Y
451 usbSendAndReti: ; SOP starts 16 cycles after call
452 push x4 ;2
453 in x1, USBOUT ;1
454 cbr x1, USBMASK ;1 mask out data bits
455 ori x1, USBIDLE ;1 idle
456 out USBOUT, x1 ;1 prepare idle state
457 ldi x4, USBMASK ;1 exor mask
458 in x2, USBDDR ;1
459 ori x2, USBMASK ;1 set both pins to output
460 out USBDDR, x2 ;1 <-- acquire bus now
461 ; need not init x2 (bitstuff history) because sync starts with 0
462 ldi shift, 0x80 ;1 sync byte is first byte sent
463 rjmp txLoop ;2 -> 13 + 3 = 16 cycles until SOP
464
465 #if USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
466 handleIn1:
467 lds cnt, usbTxLen1
468 cpi cnt, -1
469 breq sendNakAndReti
470 ldi x1, -1
471 sts usbTxLen1, x1
472 ldi YL, lo8(usbTxBuf1)
473 ldi YH, hi8(usbTxBuf1)
474 rjmp usbSendAndReti
475 #endif
476
477 bitstuff0: ;1 (for branch taken)
478 eor x1, x4 ;1
479 ldi x2, 0 ;1
480 out USBOUT, x1 ;1 <-- out
481 rjmp didStuff0 ;2 branch back 2 cycles earlier
482 bitstuff1: ;1 (for branch taken)
483 eor x1, x4 ;1
484 ldi x2, 0 ;1
485 sec ;1 set carry so that brsh will not jump
486 out USBOUT, x1 ;1 <-- out
487 rjmp didStuff1 ;2 jump back 1 cycle earler
488 bitstuff2: ;1 (for branch taken)
489 eor x1, x4 ;1
490 ldi x2, 0 ;1
491 rjmp didStuff2 ;2 jump back 3 cycles earlier and do out
492 bitstuff3: ;1 (for branch taken)
493 eor x1, x4 ;1
494 ldi x2, 0 ;1
495 rjmp didStuff3 ;2 jump back earlier
496
497 txLoop:
498 sbrs shift, 0 ;1
499 eor x1, x4 ;1
500 out USBOUT, x1 ;1 <-- out
501 ror shift ;1
502 ror x2 ;1
503 didStuff0:
504 cpi x2, 0xfc ;1
505 brsh bitstuff0 ;1
506 sbrs shift, 0 ;1
507 eor x1, x4 ;1
508 ror shift ;1
509 out USBOUT, x1 ;1 <-- out
510 ror x2 ;1
511 cpi x2, 0xfc ;1
512 didStuff1:
513 brsh bitstuff1 ;1
514 sbrs shift, 0 ;1
515 eor x1, x4 ;1
516 ror shift ;1
517 ror x2 ;1
518 didStuff2:
519 out USBOUT, x1 ;1 <-- out
520 cpi x2, 0xfc ;1
521 brsh bitstuff2 ;1
522 sbrs shift, 0 ;1
523 eor x1, x4 ;1
524 ror shift ;1
525 ror x2 ;1
526 didStuff3:
527 cpi x2, 0xfc ;1
528 out USBOUT, x1 ;1 <-- out
529 brsh bitstuff3 ;1
530 nop2 ;2
531 ld x3, y+ ;2
532 sbrs shift, 0 ;1
533 eor x1, x4 ;1
534 out USBOUT, x1 ;1 <-- out
535 ror shift ;1
536 ror x2 ;1
537 didStuff4:
538 cpi x2, 0xfc ;1
539 brsh bitstuff4 ;1
540 sbrs shift, 0 ;1
541 eor x1, x4 ;1
542 ror shift ;1
543 out USBOUT, x1 ;1 <-- out
544 ror x2 ;1
545 cpi x2, 0xfc ;1
546 didStuff5:
547 brsh bitstuff5 ;1
548 sbrs shift, 0 ;1
549 eor x1, x4 ;1
550 ror shift ;1
551 ror x2 ;1
552 didStuff6:
553 out USBOUT, x1 ;1 <-- out
554 cpi x2, 0xfc ;1
555 brsh bitstuff6 ;1
556 sbrs shift, 0 ;1
557 eor x1, x4 ;1
558 ror shift ;1
559 ror x2 ;1
560 didStuff7:
561 cpi x2, 0xfc ;1
562 out USBOUT, x1 ;1 <-- out
563 brsh bitstuff7 ;1
564 mov shift, x3 ;1
565 dec cnt ;1
566 brne txLoop ;2 | 1
567 cbr x1, USBMASK ;1 prepare SE0
568 pop x4 ;2
569 out USBOUT, x1 ;1 <-- out SE0
570 ldi cnt, 4 ;1 two bits = 16 cycles
571 se0Delay:
572 dec cnt ;1
573 brne se0Delay ;2 | 1
574 ori x1, USBIDLE ;1
575 in x2, USBDDR ;1
576 cbr x2, USBMASK ;1 set both pins to input
577 out USBOUT, x1 ;1 <-- out J (idle)
578 cbr x1, USBMASK ;1 configure no pullup on both pins
579 pop x3 ;2
580 pop YL ;2
581 out USBDDR, x2 ;1 <-- release bus now
582 out USBOUT, x1 ;1 set pullup state
583 pop YH ;2
584 rjmp sofError ;2 [we want to jump to rxDoReturn, but this saves cycles]
585
586 bitstuff4: ;1 (for branch taken)
587 eor x1, x4 ;1
588 ldi x2, 0 ;1
589 out USBOUT, x1 ;1 <-- out
590 rjmp didStuff4 ;2 jump back 2 cycles earlier
591 bitstuff5: ;1 (for branch taken)
592 eor x1, x4 ;1
593 ldi x2, 0 ;1
594 sec ;1 set carry so that brsh is not taken
595 out USBOUT, x1 ;1 <-- out
596 rjmp didStuff5 ;2 jump back 1 cycle earlier
597 bitstuff6: ;1 (for branch taken)
598 eor x1, x4 ;1
599 ldi x2, 0 ;1
600 rjmp didStuff6 ;2 jump back 3 cycles earlier and do out there
601 bitstuff7: ;1 (for branch taken)
602 eor x1, x4 ;1
603 ldi x2, 0 ;1
604 rjmp didStuff7 ;2 jump back 4 cycles earlier
605
606 ; ######################## utility functions ########################
607
608 ; extern unsigned usbCrc16(unsigned char *data, unsigned char len);
609 ; data: r24/25
610 ; len: r22
611 ; temp variables:
612 ; r18: data byte
613 ; r19: bit counter
614 ; r20/21: polynomial
615 ; r23: scratch
616 ; r24/25: crc-sum
617 ; r26/27=X: ptr
618 .global usbCrc16
619 usbCrc16:
620 mov XL, r24
621 mov XH, r25
622 ldi r24, 0xff
623 ldi r25, 0xff
624 ldi r20, lo8(0xa001)
625 ldi r21, hi8(0xa001)
626 crcByteLoop:
627 subi r22, 1
628 brcs crcReady
629 ld r18, x+
630 ldi r19, 8
631 crcBitLoop:
632 mov r23, r18
633 eor r23, r24
634 lsr r25
635 ror r24
636 lsr r18
637 sbrs r23, 0
638 rjmp crcNoXor
639 eor r24, r20
640 eor r25, r21
641 crcNoXor:
642 dec r19
643 brne crcBitLoop
644 rjmp crcByteLoop
645 crcReady:
646 com r24
647 com r25
648 ret