Rev Author Line No. Line
3331 kaklik 1 ; ======================================================================
2 ; USB interrupt handler
3 ;
4 ; This is the handler for the interrupt caused by the initial rising edge
5 ; on the D+ USB signal. The NRZI encoding and bit stuffing are removed,
6 ; and the packet is saved in one of the two input buffers. In some cases,
7 ; a reply packet is sent right away.
8 ;
9 ; When a DATA0/DATA1 packet directly follows a SETUP or OUT packet, while
10 ; this interrupt handler is not yet finished, there would be no time to
11 ; return and take another interrupt. In that case, the second packet is
12 ; decoded directly in the same invocation.
13 ;
14 ; This code is *extremely* time critical. For instance, there is not a
15 ; single spare cycle in the receiver loop, and only two in the transmitter
16 ; loop. In addition, the various code paths are laid out in such a way that
17 ; the various USB timeouts are not violated, in particular the maximum time
18 ; between the reception of a packet and the reply, which is 6.5 bit times
19 ; for a detachable cable (TRSPIPD1), and 7.5 bit times for a captive cable
20 ; (TRSPIPD2). The worst-case delay here is 51 cycles, which is just below
21 ; the 52 cycles for a detachable cable.
22 ;
23 ; The interrupt handler must be reached within 34 cycles after D+ goes high
24 ; for the first time, so the interrupts should not be disabled for longer
25 ; than 34-4-2=28 cycles.
26 ;
27 ; The end-of-packet (EOP) is sampled in the second bit, because the USB
28 ; standard allows the EOP to be delayed by up to one bit. As the EOP
29 ; duration is two bits, this is not a problem.
30 ;
31 ; Stack usage including the return address: 11 bytes.
32 ;
33 ; Copyright (C) 2006 Dick Streefland
34 ;
35 ; This is free software, licensed under the terms of the GNU General
36 ; Public License as published by the Free Software Foundation.
37 ; ======================================================================
38  
39 #include "def.h"
40  
41 ; ----------------------------------------------------------------------
42 ; local data
43 ; ----------------------------------------------------------------------
44 .data
45 tx_ack: .byte USB_PID_ACK ; ACK packet
46 tx_nak: .byte USB_PID_NAK ; NAK packet
47 .lcomm token_pid, 1 ; PID of most recent token packet
48  
49 ; ----------------------------------------------------------------------
50 ; register definitions
51 ; ----------------------------------------------------------------------
52 // receiver:
53 #define count r16
54 #define usbmask r17
55 #define odd r18
56 #define byte r19
57 #define fixup r20
58 #define even r22
59  
60 // transmitter:
61 #define output odd
62 #define done fixup
63 #define next even
64  
65 // control:
66 #define pid odd
67 #define addr usbmask
68 #define tmp fixup
69  
70 #define nop2 rjmp .+0 // not .+2 for some strange reason
71  
72 ; ----------------------------------------------------------------------
73 ; interrupt handler
74 ; ----------------------------------------------------------------------
75 .text
76 .global USB_INT_VECTOR
77 .type USB_INT_VECTOR, @function
78 ; ----------------------------------------------------------------------
79 ; This handler must be reached no later than 34 cycles after D+ goes high
80 ; for the first time.
81 ; ----------------------------------------------------------------------
82 USB_INT_VECTOR:
83 ; save registers
84 push count
85 push usbmask
86 push odd
87 push YH
88 push YL
89 in count, SREG
90 push count
91  
92 ; ----------------------------------------------------------------------
93 ; Synchronize to the pattern 10101011 on D+. This code must be reached
94 ; no later than 47 cycles after D+ goes high for the first time.
95 ; ----------------------------------------------------------------------
96 sync:
97 ; wait until D+ == 0
98 sbic USB_IN, USBTINY_DPLUS
99 rjmp sync ; jump if D+ == 1
100 resync:
101 ; sync on 0-->1 transition on D+ with a 2 cycle resolution
102 sbic USB_IN, USBTINY_DPLUS
103 rjmp sync6 ; jump if D+ == 1
104 sbic USB_IN, USBTINY_DPLUS
105 rjmp sync6 ; jump if D+ == 1
106 sbic USB_IN, USBTINY_DPLUS
107 rjmp sync6 ; jump if D+ == 1
108 sbic USB_IN, USBTINY_DPLUS
109 rjmp sync6 ; jump if D+ == 1
110 sbic USB_IN, USBTINY_DPLUS
111 rjmp sync6 ; jump if D+ == 1
112 ldi count, 1<<USB_INT_PENDING_BIT
113 out USB_INT_PENDING, count
114 rjmp return ; ==> false start, bail out
115  
116 sync6:
117 ; we are now between -1 and +1 cycle from the center of the bit
118 ; following the 0-->1 transition
119 lds YL, usb_rx_off
120 clr YH
121 subi YL, lo8(-(usb_rx_buf)) ; Y = & usb_rx_buf[usb_rx_off]
122 sbci YH, hi8(-(usb_rx_buf))
123 ldi count, USB_BUFSIZE ; limit on number of bytes to receive
124 ldi usbmask, USB_MASK ; why is there no eori instruction?
125 ldi odd, USB_MASK_DPLUS
126  
127 sync7:
128 ; the last sync bit should also be 1
129 sbis USB_IN, USBTINY_DPLUS ; bit 7 of sync byte?
130 rjmp resync ; no, wait for next transition
131 push byte
132 push fixup
133 push even
134  
135 ; ----------------------------------------------------------------------
136 ; receiver loop
137 ; ----------------------------------------------------------------------
138 in even, USB_IN ; sample bit 0
139 ldi byte, 0x80 ; load sync byte for correct unstuffing
140 rjmp rxentry ; 2 cycles
141  
142 rxloop:
143 in even, USB_IN ; sample bit 0
144 or fixup, byte
145 st Y+, fixup ; 2 cycles
146 rxentry:
147 clr fixup
148 andi even, USB_MASK
149 eor odd, even
150 subi odd, 1
151 in odd, USB_IN ; sample bit 1
152 andi odd, USB_MASK
153 breq eop ; ==> EOP detected
154 ror byte
155 cpi byte, 0xfc
156 brcc skip0
157 skipped0:
158 eor even, odd
159 subi even, 1
160 in even, USB_IN ; sample bit 2
161 andi even, USB_MASK
162 ror byte
163 cpi byte, 0xfc
164 brcc skip1
165 skipped1:
166 eor odd, even
167 subi odd, 1
168 ror byte
169 in odd, USB_IN ; sample bit 3
170 andi odd, USB_MASK
171 cpi byte, 0xfc
172 brcc skip2
173 eor even, odd
174 subi even, 1
175 ror byte
176 skipped2:
177 cpi byte, 0xfc
178 in even, USB_IN ; sample bit 4
179 andi even, USB_MASK
180 brcc skip3
181 eor odd, even
182 subi odd, 1
183 ror byte
184 skipped4:
185 cpi byte, 0xfc
186 skipped3:
187 brcc skip4
188 in odd, USB_IN ; sample bit 5
189 andi odd, USB_MASK
190 eor even, odd
191 subi even, 1
192 ror byte
193 skipped5:
194 cpi byte, 0xfc
195 brcc skip5
196 dec count
197 in even, USB_IN ; sample bit 6
198 brmi overflow ; ==> overflow
199 andi even, USB_MASK
200 eor odd, even
201 subi odd, 1
202 ror byte
203 skipped6:
204 cpi byte, 0xfc
205 brcc skip6
206 in odd, USB_IN ; sample bit 7
207 andi odd, USB_MASK
208 eor even, odd
209 subi even, 1
210 ror byte
211 cpi byte, 0xfc
212 brcs rxloop ; 2 cycles
213 rjmp skip7
214  
215 eop:
216 rjmp eop2
217 overflow:
218 rjmp ignore
219  
220 ; ----------------------------------------------------------------------
221 ; out-of-line code to skip stuffing bits
222 ; ----------------------------------------------------------------------
223 skip0: ; 1+6 cycles
224 eor even, usbmask
225 in odd, USB_IN ; resample bit 1
226 andi odd, USB_MASK
227 cbr byte, (1<<7)
228 sbr fixup, (1<<0)
229 rjmp skipped0
230  
231 skip1: ; 2+5 cycles
232 cbr byte, (1<<7)
233 sbr fixup, (1<<1)
234 in even, USB_IN ; resample bit 2
235 andi even, USB_MASK
236 eor odd, usbmask
237 rjmp skipped1
238  
239 skip2: ; 3+7 cycles
240 cbr byte, (1<<7)
241 sbr fixup, (1<<2)
242 eor even, usbmask
243 in odd, USB_IN ; resample bit 3
244 andi odd, USB_MASK
245 eor even, odd
246 subi even, 1
247 ror byte
248 rjmp skipped2
249  
250 skip3: ; 4+7 cycles
251 cbr byte, (1<<7)
252 sbr fixup, (1<<3)
253 eor odd, usbmask
254 ori byte, 1
255 in even, USB_IN ; resample bit 4
256 andi even, USB_MASK
257 eor odd, even
258 subi odd, 1
259 ror byte
260 rjmp skipped3
261  
262 skip4: ; 5 cycles
263 cbr byte, (1<<7)
264 sbr fixup, (1<<4)
265 eor even, usbmask
266 rjmp skipped4
267  
268 skip5: ; 5 cycles
269 cbr byte, (1<<7)
270 sbr fixup, (1<<5)
271 eor odd, usbmask
272 rjmp skipped5
273  
274 skip6: ; 5 cycles
275 cbr byte, (1<<7)
276 sbr fixup, (1<<6)
277 eor even, usbmask
278 rjmp skipped6
279  
280 skip7: ; 7 cycles
281 cbr byte, (1<<7)
282 sbr fixup, (1<<7)
283 eor odd, usbmask
284 nop2
285 rjmp rxloop
286  
287 ; ----------------------------------------------------------------------
288 ; end-of-packet detected (worst-case: 3 cycles after end of SE0)
289 ; ----------------------------------------------------------------------
290 eop2:
291 ; clear pending interrupt (SE0+3)
292 ldi byte, 1<<USB_INT_PENDING_BIT
293 out USB_INT_PENDING, byte ; clear pending bit at end of packet
294 ; ignore packets shorter than 3 bytes
295 subi count, USB_BUFSIZE
296 neg count ; count = packet length
297 cpi count, 3
298 brlo ignore
299 ; get PID
300 sub YL, count
301 ld pid, Y
302 ; check for DATA0/DATA1 first, as this is the critical path (SE0+12)
303 cpi pid, USB_PID_DATA0
304 breq is_data ; handle DATA0 packet
305 cpi pid, USB_PID_DATA1
306 breq is_data ; handle DATA1 packet
307 ; check ADDR (SE0+16)
308 ldd addr, Y+1
309 andi addr, 0x7f
310 lds tmp, usb_address
311 cp addr, tmp ; is this packet for me?
312 brne ignore ; no, ignore
313 ; check for other PIDs (SE0+23)
314 cpi pid, USB_PID_IN
315 breq is_in ; handle IN packet
316 cpi pid, USB_PID_SETUP
317 breq is_setup_out ; handle SETUP packet
318 cpi pid, USB_PID_OUT
319 breq is_setup_out ; handle OUT packet
320  
321 ; ----------------------------------------------------------------------
322 ; exit point for ignored packets
323 ; ----------------------------------------------------------------------
324 ignore:
325 clr tmp
326 sts token_pid, tmp
327 pop even
328 pop fixup
329 pop byte
330 rjmp return
331  
332 ; ----------------------------------------------------------------------
333 ; Handle SETUP/OUT (SE0+30)
334 ; ----------------------------------------------------------------------
335 is_setup_out:
336 sts token_pid, pid ; save PID of token packet
337 pop even
338 pop fixup
339 pop byte
340 in count, USB_INT_PENDING ; next packet already started?
341 sbrc count, USB_INT_PENDING_BIT
342 rjmp sync ; yes, get it right away (SE0+42)
343  
344 ; ----------------------------------------------------------------------
345 ; restore registers and return from interrupt
346 ; ----------------------------------------------------------------------
347 return:
348 pop count
349 out SREG, count
350 pop YL
351 pop YH
352 pop odd
353 pop usbmask
354 pop count
355 reti
356  
357 ; ----------------------------------------------------------------------
358 ; Handle IN (SE0+26)
359 ; ----------------------------------------------------------------------
360 is_in:
361 lds count, usb_tx_len
362 tst count ; data ready?
363 breq nak ; no, reply with NAK
364 lds tmp, usb_rx_len
365 tst tmp ; unprocessed input packet?
366 brne nak ; yes, don't send old data for new packet
367 sts usb_tx_len, tmp ; buffer is available again (after reti)
368 ldi YL, lo8(usb_tx_buf)
369 ldi YH, hi8(usb_tx_buf)
370 rjmp send_packet ; SE0+40, SE0 --> SOP <= 51
371  
372 ; ----------------------------------------------------------------------
373 ; Handle DATA0/DATA1 (SE0+17)
374 ; ----------------------------------------------------------------------
375 is_data:
376 lds pid, token_pid
377 tst pid ; data following our SETUP/OUT
378 breq ignore ; no, ignore
379 lds tmp, usb_rx_len
380 tst tmp ; buffer free?
381 brne nak ; no, reply with NAK
382 sts usb_rx_len, count ; pass buffer length
383 sts usb_rx_token, pid ; pass PID of token (SETUP or OUT)
384 lds count, usb_rx_off ; switch to other input buffer
385 ldi tmp, USB_BUFSIZE
386 sub tmp, count
387 sts usb_rx_off, tmp
388  
389 ; ----------------------------------------------------------------------
390 ; send ACK packet (SE0+35)
391 ; ----------------------------------------------------------------------
392 ack:
393 ldi YL, lo8(tx_ack)
394 ldi YH, hi8(tx_ack)
395 rjmp send_token
396  
397 ; ----------------------------------------------------------------------
398 ; send NAK packet (SE0+36)
399 ; ----------------------------------------------------------------------
400 nak:
401 ldi YL, lo8(tx_nak)
402 ldi YH, hi8(tx_nak)
403 send_token:
404 ldi count, 1 ; SE0+40, SE0 --> SOP <= 51
405  
406 ; ----------------------------------------------------------------------
407 ; acquire the bus and send a packet (11 cycles to SOP)
408 ; ----------------------------------------------------------------------
409 send_packet:
410 in output, USB_OUT
411 cbr output, USB_MASK
412 ori output, USB_MASK_DMINUS
413 in usbmask, USB_DDR
414 ori usbmask, USB_MASK
415 out USB_OUT, output ; idle state
416 out USB_DDR, usbmask ; acquire bus
417 ldi usbmask, USB_MASK
418 ldi byte, 0x80 ; start with sync byte
419  
420 ; ----------------------------------------------------------------------
421 ; transmitter loop
422 ; ----------------------------------------------------------------------
423 txloop:
424 sbrs byte, 0
425 eor output, usbmask
426 out USB_OUT, output ; output bit 0
427 ror byte
428 ror done
429 stuffed0:
430 cpi done, 0xfc
431 brcc stuff0
432 sbrs byte, 0
433 eor output, usbmask
434 ror byte
435 stuffed1:
436 out USB_OUT, output ; output bit 1
437 ror done
438 cpi done, 0xfc
439 brcc stuff1
440 sbrs byte, 0
441 eor output, usbmask
442 ror byte
443 nop
444 stuffed2:
445 out USB_OUT, output ; output bit 2
446 ror done
447 cpi done, 0xfc
448 brcc stuff2
449 sbrs byte, 0
450 eor output, usbmask
451 ror byte
452 nop
453 stuffed3:
454 out USB_OUT, output ; output bit 3
455 ror done
456 cpi done, 0xfc
457 brcc stuff3
458 sbrs byte, 0
459 eor output, usbmask
460 ld next, Y+ ; 2 cycles
461 out USB_OUT, output ; output bit 4
462 ror byte
463 ror done
464 stuffed4:
465 cpi done, 0xfc
466 brcc stuff4
467 sbrs byte, 0
468 eor output, usbmask
469 ror byte
470 stuffed5:
471 out USB_OUT, output ; output bit 5
472 ror done
473 cpi done, 0xfc
474 brcc stuff5
475 sbrs byte, 0
476 eor output, usbmask
477 ror byte
478 stuffed6:
479 ror done
480 out USB_OUT, output ; output bit 6
481 cpi done, 0xfc
482 brcc stuff6
483 sbrs byte, 0
484 eor output, usbmask
485 ror byte
486 mov byte, next
487 stuffed7:
488 ror done
489 out USB_OUT, output ; output bit 7
490 cpi done, 0xfc
491 brcc stuff7
492 dec count
493 brpl txloop ; 2 cycles
494  
495 rjmp gen_eop
496  
497 ; ----------------------------------------------------------------------
498 ; out-of-line code to insert stuffing bits
499 ; ----------------------------------------------------------------------
500 stuff0: ; 2+3
501 eor output, usbmask
502 clr done
503 out USB_OUT, output
504 rjmp stuffed0
505  
506 stuff1: ; 3
507 eor output, usbmask
508 rjmp stuffed1
509  
510 stuff2: ; 3
511 eor output, usbmask
512 rjmp stuffed2
513  
514 stuff3: ; 3
515 eor output, usbmask
516 rjmp stuffed3
517  
518 stuff4: ; 2+3
519 eor output, usbmask
520 clr done
521 out USB_OUT, output
522 rjmp stuffed4
523  
524 stuff5: ; 3
525 eor output, usbmask
526 rjmp stuffed5
527  
528 stuff6: ; 3
529 eor output, usbmask
530 rjmp stuffed6
531  
532 stuff7: ; 3
533 eor output, usbmask
534 rjmp stuffed7
535  
536 ; ----------------------------------------------------------------------
537 ; generate EOP, release the bus, and return from interrupt
538 ; ----------------------------------------------------------------------
539 gen_eop:
540 cbr output, USB_MASK
541 out USB_OUT, output ; output SE0 for 2 bit times
542 pop even
543 pop fixup
544 pop byte
545 ldi count, 1<<USB_INT_PENDING_BIT
546 out USB_INT_PENDING, count ; interrupt was triggered by transmit
547 pop YH ; this is the saved SREG
548 pop YL
549 in usbmask, USB_DDR
550 mov count, output
551 ori output, USB_MASK_DMINUS
552 out USB_OUT, output ; output J state for 1 bit time
553 cbr usbmask, USB_MASK
554 out SREG, YH
555 pop YH
556 pop odd ; is the same register as output!
557 nop
558 out USB_DDR, usbmask ; release bus
559 out USB_OUT, count ; disable D- pullup
560 pop usbmask
561 pop count
562 reti