Rev Author Line No. Line
3514 miho 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) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
8 * This Revision: $Id: usbdrvasm.S,v 1.2 2007/05/19 12:30:11 harbaum Exp $
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 Timing constraints according to spec (in bit times):
21 timing subject min max CPUcycles
22 ---------------------------------------------------------------------------
23 EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2 16 16-128
24 EOP of IN to sync pattern of DATA0 (rx, then tx) 2 7.5 16-60
25 DATAx (rx) to ACK/NAK/STALL (tx) 2 7.5 16-60
26 */
27  
28 #include "iarcompat.h"
29 #ifndef __IAR_SYSTEMS_ASM__
30 /* configs for io.h */
31 # define __SFR_OFFSET 0
32 # define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */
33 # include <avr/io.h> /* for CPU I/O register definitions and vectors */
34 #endif /* __IAR_SYSTEMS_ASM__ */
35 #include "usbdrv.h" /* for common defs */
36  
37  
38 /* register names */
39 #define x1 r16
40 #define x2 r17
41 #define shift r18
42 #define cnt r19
43 #define x3 r20
44 #define x4 r21
45  
46 /* Some assembler dependent definitions and declarations: */
47  
48 #ifdef __IAR_SYSTEMS_ASM__
49  
50 # define nop2 rjmp $+2 /* jump to next instruction */
51 # define XL r26
52 # define XH r27
53 # define YL r28
54 # define YH r29
55 # define ZL r30
56 # define ZH r31
57 # define lo8(x) LOW(x)
58 # define hi8(x) ((x)>>8) /* not HIGH to allow XLINK to make a proper range check */
59  
60 extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
61 extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
62 extern usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3
63 public usbCrc16
64 public usbCrc16Append
65  
66 COMMON INTVEC
67 ORG INT0_vect
68 rjmp SIG_INTERRUPT0
69 RSEG CODE
70  
71 #else /* __IAR_SYSTEMS_ASM__ */
72  
73 # define nop2 rjmp .+0 /* jump to next instruction */
74  
75 .text
76 .global SIG_INTERRUPT0
77 .type SIG_INTERRUPT0, @function
78 .global usbCrc16
79 .global usbCrc16Append
80  
81 #endif /* __IAR_SYSTEMS_ASM__ */
82  
83  
84 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
85 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
86 ;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable
87 ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes
88 ;Numbers in brackets are maximum cycles since SOF.
89 SIG_INTERRUPT0:
90 ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt
91 push YL ;2 [35] push only what is necessary to sync with edge ASAP
92 in YL, SREG ;1 [37]
93 push YL ;2 [39]
94 ;----------------------------------------------------------------------------
95 ; Synchronize with sync pattern:
96 ;----------------------------------------------------------------------------
97 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
98 ;sync up with J to K edge during sync pattern -- use fastest possible loops
99 ;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
100 waitForJ:
101 sbis USBIN, USBMINUS ;1 [40] wait for D- == 1
102 rjmp waitForJ ;2
103 waitForK:
104 ;The following code results in a sampling window of 1/4 bit which meets the spec.
105 sbis USBIN, USBMINUS
106 rjmp foundK
107 sbis USBIN, USBMINUS
108 rjmp foundK
109 sbis USBIN, USBMINUS
110 rjmp foundK
111 sbis USBIN, USBMINUS
112 rjmp foundK
113 sbis USBIN, USBMINUS
114 rjmp foundK
115 rjmp sofError
116 foundK:
117 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
118 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
119 ;are cycles from center of first sync (double K) bit after the instruction
120 push YH ;2 [2]
121 lds YL, usbInputBufOffset;2 [4]
122 clr YH ;1 [5]
123 subi YL, lo8(-(usbRxBuf));1 [6]
124 sbci YH, hi8(-(usbRxBuf));1 [7]
125  
126 sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early]
127 rjmp haveTwoBitsK ;2 [10]
128 pop YH ; undo the push from before
129 rjmp waitForK ; this was not the end of sync, retry
130 haveTwoBitsK:
131 ;----------------------------------------------------------------------------
132 ; push more registers and initialize values while we sample the first bits:
133 ;----------------------------------------------------------------------------
134 push shift ;2 [16]
135 push x1 ;2 [12]
136 push x2 ;2 [14]
137  
138 in x1, USBIN ;1 [17] <-- sample bit 0
139 ldi shift, 0xff ;1 [18]
140 bst x1, USBMINUS ;1 [19]
141 bld shift, 0 ;1 [20]
142 push x3 ;2 [22]
143 push cnt ;2 [24]
144  
145 in x2, USBIN ;1 [25] <-- sample bit 1
146 ser x3 ;1 [26] [inserted init instruction]
147 eor x1, x2 ;1 [27]
148 bst x1, USBMINUS ;1 [28]
149 bld shift, 1 ;1 [29]
150 ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction]
151 rjmp rxbit2 ;2 [32]
152  
153 ;----------------------------------------------------------------------------
154 ; Receiver loop (numbers in brackets are cycles within byte after instr)
155 ;----------------------------------------------------------------------------
156  
157 unstuff0: ;1 (branch taken)
158 andi x3, ~0x01 ;1 [15]
159 mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit
160 in x2, USBIN ;1 [17] <-- sample bit 1 again
161 ori shift, 0x01 ;1 [18]
162 rjmp didUnstuff0 ;2 [20]
163  
164 unstuff1: ;1 (branch taken)
165 mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit
166 andi x3, ~0x02 ;1 [22]
167 ori shift, 0x02 ;1 [23]
168 nop ;1 [24]
169 in x1, USBIN ;1 [25] <-- sample bit 2 again
170 rjmp didUnstuff1 ;2 [27]
171  
172 unstuff2: ;1 (branch taken)
173 andi x3, ~0x04 ;1 [29]
174 ori shift, 0x04 ;1 [30]
175 mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit
176 nop ;1 [32]
177 in x2, USBIN ;1 [33] <-- sample bit 3
178 rjmp didUnstuff2 ;2 [35]
179  
180 unstuff3: ;1 (branch taken)
181 in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late]
182 andi x3, ~0x08 ;1 [35]
183 ori shift, 0x08 ;1 [36]
184 rjmp didUnstuff3 ;2 [38]
185  
186 unstuff4: ;1 (branch taken)
187 andi x3, ~0x10 ;1 [40]
188 in x1, USBIN ;1 [41] <-- sample stuffed bit 4
189 ori shift, 0x10 ;1 [42]
190 rjmp didUnstuff4 ;2 [44]
191  
192 unstuff5: ;1 (branch taken)
193 andi x3, ~0x20 ;1 [48]
194 in x2, USBIN ;1 [49] <-- sample stuffed bit 5
195 ori shift, 0x20 ;1 [50]
196 rjmp didUnstuff5 ;2 [52]
197  
198 unstuff6: ;1 (branch taken)
199 andi x3, ~0x40 ;1 [56]
200 in x1, USBIN ;1 [57] <-- sample stuffed bit 6
201 ori shift, 0x40 ;1 [58]
202 rjmp didUnstuff6 ;2 [60]
203  
204 ; extra jobs done during bit interval:
205 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs]
206 ; bit 1: se0 check
207 ; bit 2: overflow check
208 ; bit 3: recovery from delay [bit 0 tasks took too long]
209 ; bit 4: none
210 ; bit 5: none
211 ; bit 6: none
212 ; bit 7: jump, eor
213 rxLoop:
214 eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others
215 in x1, USBIN ;1 [1] <-- sample bit 0
216 st y+, x3 ;2 [3] store data
217 ser x3 ;1 [4]
218 nop ;1 [5]
219 eor x2, x1 ;1 [6]
220 bst x2, USBMINUS;1 [7]
221 bld shift, 0 ;1 [8]
222 in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed)
223 andi x2, USBMASK ;1 [10]
224 breq se0 ;1 [11] SE0 check for bit 1
225 andi shift, 0xf9 ;1 [12]
226 didUnstuff0:
227 breq unstuff0 ;1 [13]
228 eor x1, x2 ;1 [14]
229 bst x1, USBMINUS;1 [15]
230 bld shift, 1 ;1 [16]
231 rxbit2:
232 in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed)
233 andi shift, 0xf3 ;1 [18]
234 breq unstuff1 ;1 [19] do remaining work for bit 1
235 didUnstuff1:
236 subi cnt, 1 ;1 [20]
237 brcs overflow ;1 [21] loop control
238 eor x2, x1 ;1 [22]
239 bst x2, USBMINUS;1 [23]
240 bld shift, 2 ;1 [24]
241 in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed)
242 andi shift, 0xe7 ;1 [26]
243 breq unstuff2 ;1 [27]
244 didUnstuff2:
245 eor x1, x2 ;1 [28]
246 bst x1, USBMINUS;1 [29]
247 bld shift, 3 ;1 [30]
248 didUnstuff3:
249 andi shift, 0xcf ;1 [31]
250 breq unstuff3 ;1 [32]
251 in x1, USBIN ;1 [33] <-- sample bit 4
252 eor x2, x1 ;1 [34]
253 bst x2, USBMINUS;1 [35]
254 bld shift, 4 ;1 [36]
255 didUnstuff4:
256 andi shift, 0x9f ;1 [37]
257 breq unstuff4 ;1 [38]
258 nop2 ;2 [40]
259 in x2, USBIN ;1 [41] <-- sample bit 5
260 eor x1, x2 ;1 [42]
261 bst x1, USBMINUS;1 [43]
262 bld shift, 5 ;1 [44]
263 didUnstuff5:
264 andi shift, 0x3f ;1 [45]
265 breq unstuff5 ;1 [46]
266 nop2 ;2 [48]
267 in x1, USBIN ;1 [49] <-- sample bit 6
268 eor x2, x1 ;1 [50]
269 bst x2, USBMINUS;1 [51]
270 bld shift, 6 ;1 [52]
271 didUnstuff6:
272 cpi shift, 0x02 ;1 [53]
273 brlo unstuff6 ;1 [54]
274 nop2 ;2 [56]
275 in x2, USBIN ;1 [57] <-- sample bit 7
276 eor x1, x2 ;1 [58]
277 bst x1, USBMINUS;1 [59]
278 bld shift, 7 ;1 [60]
279 didUnstuff7:
280 cpi shift, 0x04 ;1 [61]
281 brsh rxLoop ;2 [63] loop control
282 unstuff7:
283 andi x3, ~0x80 ;1 [63]
284 ori shift, 0x80 ;1 [64]
285 in x2, USBIN ;1 [65] <-- sample stuffed bit 7
286 nop ;1 [66]
287 rjmp didUnstuff7 ;2 [68]
288  
289  
290 ;----------------------------------------------------------------------------
291 ; Processing of received packet (numbers in brackets are cycles after end of SE0)
292 ;----------------------------------------------------------------------------
293 ;This is the only non-error exit point for the software receiver loop
294 ;we don't check any CRCs here because there is no time left.
295 #define token x1
296 se0: ; [0]
297 subi cnt, USB_BUFSIZE ;1 [1]
298 neg cnt ;1 [2]
299 cpi cnt, 3 ;1 [3]
300 ldi x2, 1<<USB_INTR_PENDING_BIT ;1 [4]
301 out USB_INTR_PENDING, x2;1 [5] clear pending intr and check flag later. SE0 should be over.
302 brlo doReturn ;1 [6] this is probably an ACK, NAK or similar packet
303 sub YL, cnt ;1 [7]
304 sbci YH, 0 ;1 [8]
305 ld token, y ;2 [10]
306 cpi token, USBPID_DATA0 ;1 [11]
307 breq handleData ;1 [12]
308 cpi token, USBPID_DATA1 ;1 [13]
309 breq handleData ;1 [14]
310 ldd x2, y+1 ;2 [16] ADDR and 1 bit endpoint number
311 mov x3, x2 ;1 [17] store for endpoint number
312 andi x2, 0x7f ;1 [18] x2 is now ADDR
313 lds shift, usbDeviceAddr;2 [20]
314 cp x2, shift ;1 [21]
315 overflow: ; This is a hack: brcs overflow will never have Z flag set
316 brne ignorePacket ;1 [22] packet for different address
317 cpi token, USBPID_IN ;1 [23]
318 breq handleIn ;1 [24]
319 cpi token, USBPID_SETUP ;1 [25]
320 breq handleSetupOrOut ;1 [26]
321 cpi token, USBPID_OUT ;1 [27]
322 breq handleSetupOrOut ;1 [28]
323 ; rjmp ignorePacket ;fallthrough, should not happen anyway.
324  
325 ignorePacket:
326 clr shift
327 sts usbCurrentTok, shift
328 doReturn:
329 pop cnt
330 pop x3
331 pop x2
332 pop x1
333 pop shift
334 pop YH
335 sofError:
336 pop YL
337 out SREG, YL
338 pop YL
339 reti
340  
341 #if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_HAVE_INTRIN_ENDPOINT3
342 handleIn3: ;1 [38] (branch taken)
343 lds cnt, usbTxLen3 ;2 [40]
344 sbrc cnt, 4 ;2 [42]
345 rjmp sendCntAndReti ;0 43 + 17 = 60 until SOP
346 sts usbTxLen3, x1 ;2 [44] x1 == USBPID_NAK from above
347 ldi YL, lo8(usbTxBuf3) ;1 [45]
348 ldi YH, hi8(usbTxBuf3) ;1 [46]
349 rjmp usbSendAndReti ;2 [48] + 13 = 61 until SOP (violates the spec by 1 cycle)
350 #endif
351  
352 ;Setup and Out are followed by a data packet two bit times (16 cycles) after
353 ;the end of SE0. The sync code allows up to 40 cycles delay from the start of
354 ;the sync pattern until the first bit is sampled. That's a total of 56 cycles.
355 handleSetupOrOut: ;1 [29] (branch taken)
356 #if USB_CFG_IMPLEMENT_FN_WRITEOUT /* if we have data for second OUT endpoint, set usbCurrentTok to -1 */
357 sbrc x3, 7 ;1 [30] skip if endpoint 0
358 ldi token, -1 ;1 [31] indicate that this is endpoint 1 OUT
359 #endif
360 sts usbCurrentTok, token;2 [33]
361 pop cnt ;2 [35]
362 pop x3 ;2 [37]
363 pop x2 ;2 [39]
364 pop x1 ;2 [41]
365 pop shift ;2 [43]
366 pop YH ;2 [45]
367 in YL, USB_INTR_PENDING;1 [46]
368 sbrc YL, USB_INTR_PENDING_BIT;1 [47] check whether data is already arriving
369 rjmp waitForJ ;2 [49] save the pops and pushes -- a new interrupt is aready pending
370 rjmp sofError ;2 not an error, but it does the pops and reti we want
371  
372  
373 handleData: ;1 [15] (branch taken)
374 lds token, usbCurrentTok;2 [17]
375 tst token ;1 [18]
376 breq doReturn ;1 [19]
377 lds x2, usbRxLen ;2 [21]
378 tst x2 ;1 [22]
379 brne sendNakAndReti ;1 [23]
380 ; 2006-03-11: The following two lines fix a problem where the device was not
381 ; recognized if usbPoll() was called less frequently than once every 4 ms.
382 cpi cnt, 4 ;1 [24] zero sized data packets are status phase only -- ignore and ack
383 brmi sendAckAndReti ;1 [25] keep rx buffer clean -- we must not NAK next SETUP
384 sts usbRxLen, cnt ;2 [27] store received data, swap buffers
385 sts usbRxToken, token ;2 [29]
386 lds x2, usbInputBufOffset;2 [31] swap buffers
387 ldi cnt, USB_BUFSIZE ;1 [32]
388 sub cnt, x2 ;1 [33]
389 sts usbInputBufOffset, cnt;2 [35] buffers now swapped
390 rjmp sendAckAndReti ;2 [37] + 19 = 56 until SOP
391  
392 handleIn: ;1 [25] (branch taken)
393 ;We don't send any data as long as the C code has not processed the current
394 ;input data and potentially updated the output data. That's more efficient
395 ;in terms of code size than clearing the tx buffers when a packet is received.
396 lds x1, usbRxLen ;2 [27]
397 cpi x1, 1 ;1 [28] negative values are flow control, 0 means "buffer free"
398 brge sendNakAndReti ;1 [29] unprocessed input packet?
399 ldi x1, USBPID_NAK ;1 [30] prepare value for usbTxLen
400 #if USB_CFG_HAVE_INTRIN_ENDPOINT
401 sbrc x3, 7 ;2 [33] x3 contains addr + endpoint
402 rjmp handleIn1 ;0
403 #endif
404 lds cnt, usbTxLen ;2 [34]
405 sbrc cnt, 4 ;2 [36] all handshake tokens have bit 4 set
406 rjmp sendCntAndReti ;0 37 + 17 = 54 until SOP
407 sts usbTxLen, x1 ;2 [38] x1 == USBPID_NAK from above
408 ldi YL, lo8(usbTxBuf) ;1 [39]
409 ldi YH, hi8(usbTxBuf) ;1 [40]
410 rjmp usbSendAndReti ;2 [42] + 14 = 56 until SOP
411  
412 ; Comment about when to set usbTxLen to USBPID_NAK:
413 ; We should set it back when we receive the ACK from the host. This would
414 ; be simple to implement: One static variable which stores whether the last
415 ; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
416 ; ACK. However, we set it back immediately when we send the package,
417 ; assuming that no error occurs and the host sends an ACK. We save one byte
418 ; RAM this way and avoid potential problems with endless retries. The rest of
419 ; the driver assumes error-free transfers anyway.
420  
421 #if USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
422 handleIn1: ;1 [33] (branch taken)
423 #if USB_CFG_HAVE_INTRIN_ENDPOINT3
424 ; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
425 ldd x2, y+2 ;2 [35]
426 sbrc x2, 0 ;2 [37]
427 rjmp handleIn3 ;0
428 #endif
429 lds cnt, usbTxLen1 ;2 [39]
430 sbrc cnt, 4 ;2 [41] all handshake tokens have bit 4 set
431 rjmp sendCntAndReti ;0 42 + 17 = 59 until SOP
432 sts usbTxLen1, x1 ;2 [43] x1 == USBPID_NAK from above
433 ldi YL, lo8(usbTxBuf1) ;1 [44]
434 ldi YH, hi8(usbTxBuf1) ;1 [45]
435 rjmp usbSendAndReti ;2 [47] + 13 = 60 until SOP
436 #endif
437  
438  
439 ;----------------------------------------------------------------------------
440 ; Transmitting data
441 ;----------------------------------------------------------------------------
442  
443 bitstuff0: ;1 (for branch taken)
444 eor x1, x4 ;1
445 ldi x2, 0 ;1
446 out USBOUT, x1 ;1 <-- out
447 rjmp didStuff0 ;2 branch back 2 cycles earlier
448 bitstuff1: ;1 (for branch taken)
449 eor x1, x4 ;1
450 rjmp didStuff1 ;2 we know that C is clear, jump back to do OUT and ror 0 into x2
451 bitstuff2: ;1 (for branch taken)
452 eor x1, x4 ;1
453 rjmp didStuff2 ;2 jump back 4 cycles earlier and do out and ror 0 into x2
454 bitstuff3: ;1 (for branch taken)
455 eor x1, x4 ;1
456 rjmp didStuff3 ;2 jump back earlier and ror 0 into x2
457 bitstuff4: ;1 (for branch taken)
458 eor x1, x4 ;1
459 ldi x2, 0 ;1
460 out USBOUT, x1 ;1 <-- out
461 rjmp didStuff4 ;2 jump back 2 cycles earlier
462  
463 sendNakAndReti: ;0 [-19] 19 cycles until SOP
464 ldi x3, USBPID_NAK ;1 [-18]
465 rjmp usbSendX3 ;2 [-16]
466 sendAckAndReti: ;0 [-19] 19 cycles until SOP
467 ldi x3, USBPID_ACK ;1 [-18]
468 rjmp usbSendX3 ;2 [-16]
469 sendCntAndReti: ;0 [-17] 17 cycles until SOP
470 mov x3, cnt ;1 [-16]
471 usbSendX3: ;0 [-16]
472 ldi YL, 20 ;1 [-15] 'x3' is R20
473 ldi YH, 0 ;1 [-14]
474 ldi cnt, 2 ;1 [-13]
475 ; rjmp usbSendAndReti fallthrough
476  
477 ; USB spec says:
478 ; idle = J
479 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
480 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
481 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
482  
483 ;usbSend:
484 ;pointer to data in 'Y'
485 ;number of bytes in 'cnt' -- including sync byte
486 ;uses: x1...x4, shift, cnt, Y
487 ;Numbers in brackets are time since first bit of sync pattern is sent
488 usbSendAndReti: ;0 [-13] timing: 13 cycles until SOP
489 in x2, USBDDR ;1 [-12]
490 ori x2, USBMASK ;1 [-11]
491 sbi USBOUT, USBMINUS;2 [-9] prepare idle state; D+ and D- must have been 0 (no pullups)
492 in x1, USBOUT ;1 [-8] port mirror for tx loop
493 out USBDDR, x2 ;1 [-7] <- acquire bus
494 ; need not init x2 (bitstuff history) because sync starts with 0
495 push x4 ;2 [-5]
496 ldi x4, USBMASK ;1 [-4] exor mask
497 ldi shift, 0x80 ;1 [-3] sync byte is first byte sent
498 txLoop: ; [62]
499 sbrs shift, 0 ;1 [-2] [62]
500 eor x1, x4 ;1 [-1] [63]
501 out USBOUT, x1 ;1 [0] <-- out bit 0
502 ror shift ;1 [1]
503 ror x2 ;1 [2]
504 didStuff0:
505 cpi x2, 0xfc ;1 [3]
506 brsh bitstuff0 ;1 [4]
507 sbrs shift, 0 ;1 [5]
508 eor x1, x4 ;1 [6]
509 ror shift ;1 [7]
510 didStuff1:
511 out USBOUT, x1 ;1 [8] <-- out bit 1
512 ror x2 ;1 [9]
513 cpi x2, 0xfc ;1 [10]
514 brsh bitstuff1 ;1 [11]
515 sbrs shift, 0 ;1 [12]
516 eor x1, x4 ;1 [13]
517 ror shift ;1 [14]
518 didStuff2:
519 ror x2 ;1 [15]
520 out USBOUT, x1 ;1 [16] <-- out bit 2
521 cpi x2, 0xfc ;1 [17]
522 brsh bitstuff2 ;1 [18]
523 sbrs shift, 0 ;1 [19]
524 eor x1, x4 ;1 [20]
525 ror shift ;1 [21]
526 didStuff3:
527 ror x2 ;1 [22]
528 cpi x2, 0xfc ;1 [23]
529 out USBOUT, x1 ;1 [24] <-- out bit 3
530 brsh bitstuff3 ;1 [25]
531 nop2 ;2 [27]
532 ld x3, y+ ;2 [29]
533 sbrs shift, 0 ;1 [30]
534 eor x1, x4 ;1 [31]
535 out USBOUT, x1 ;1 [32] <-- out bit 4
536 ror shift ;1 [33]
537 ror x2 ;1 [34]
538 didStuff4:
539 cpi x2, 0xfc ;1 [35]
540 brsh bitstuff4 ;1 [36]
541 sbrs shift, 0 ;1 [37]
542 eor x1, x4 ;1 [38]
543 ror shift ;1 [39]
544 didStuff5:
545 out USBOUT, x1 ;1 [40] <-- out bit 5
546 ror x2 ;1 [41]
547 cpi x2, 0xfc ;1 [42]
548 brsh bitstuff5 ;1 [43]
549 sbrs shift, 0 ;1 [44]
550 eor x1, x4 ;1 [45]
551 ror shift ;1 [46]
552 didStuff6:
553 ror x2 ;1 [47]
554 out USBOUT, x1 ;1 [48] <-- out bit 6
555 cpi x2, 0xfc ;1 [49]
556 brsh bitstuff6 ;1 [50]
557 sbrs shift, 0 ;1 [51]
558 eor x1, x4 ;1 [52]
559 ror shift ;1 [53]
560 didStuff7:
561 ror x2 ;1 [54]
562 cpi x2, 0xfc ;1 [55]
563 out USBOUT, x1 ;1 [56] <-- out bit 7
564 brsh bitstuff7 ;1 [57]
565 mov shift, x3 ;1 [58]
566 dec cnt ;1 [59]
567 brne txLoop ;1/2 [60/61]
568 ;make SE0:
569 cbr x1, USBMASK ;1 [61] prepare SE0 [spec says EOP may be 15 to 18 cycles]
570 pop x4 ;2 [63]
571 ;brackets are cycles from start of SE0 now
572 out USBOUT, x1 ;1 [0] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
573 nop2 ;2 [2]
574 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
575 ;set address only after data packet was sent, not after handshake
576 lds x2, usbNewDeviceAddr;2 [4]
577 subi YL, 20 + 2 ;1 [5]
578 sbci YH, 0 ;1 [6]
579 breq skipAddrAssign ;2 [8]
580 sts usbDeviceAddr, x2;0 if not skipped: SE0 is one cycle longer
581 skipAddrAssign:
582 ;end of usbDeviceAddress transfer
583 ldi x2, 1<<USB_INTR_PENDING_BIT;1 [9] int0 occurred during TX -- clear pending flag
584 out USB_INTR_PENDING, x2;1 [10]
585 ori x1, USBIDLE ;1 [11]
586 in x2, USBDDR ;1 [12]
587 cbr x2, USBMASK ;1 [13] set both pins to input
588 mov x3, x1 ;1 [14]
589 cbr x3, USBMASK ;1 [15] configure no pullup on both pins
590 out USBOUT, x1 ;1 [16] <-- out J (idle) -- end of SE0 (EOP signal)
591 out USBDDR, x2 ;1 [17] <-- release bus now
592 out USBOUT, x3 ;1 [18] <-- ensure no pull-up resistors are active
593 rjmp doReturn
594  
595 bitstuff5: ;1 (for branch taken)
596 eor x1, x4 ;1
597 rjmp didStuff5 ;2 same trick as above...
598 bitstuff6: ;1 (for branch taken)
599 eor x1, x4 ;1
600 rjmp didStuff6 ;2 same trick as above...
601 bitstuff7: ;1 (for branch taken)
602 eor x1, x4 ;1
603 rjmp didStuff7 ;2 same trick as above...
604  
605  
606 ;----------------------------------------------------------------------------
607 ; Utility functions
608 ;----------------------------------------------------------------------------
609  
610 #ifdef __IAR_SYSTEMS_ASM__
611 /* Register assignments for usbCrc16 on IAR cc */
612 /* Calling conventions on IAR:
613 * First parameter passed in r16/r17, second in r18/r19 and so on.
614 * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
615 * Result is passed in r16/r17
616 * In case of the "tiny" memory model, pointers are only 8 bit with no
617 * padding. We therefore pass argument 1 as "16 bit unsigned".
618 */
619 RTMODEL "__rt_version", "3"
620 /* The line above will generate an error if cc calling conventions change.
621 * The value "3" above is valid for IAR 4.10B/W32
622 */
623 # define argLen r18 /* argument 2 */
624 # define argPtrL r16 /* argument 1 */
625 # define argPtrH r17 /* argument 1 */
626  
627 # define resCrcL r16 /* result */
628 # define resCrcH r17 /* result */
629  
630 # define ptrL ZL
631 # define ptrH ZH
632 # define ptr Z
633 # define byte r22
634 # define bitCnt r19
635 # define polyL r20
636 # define polyH r21
637 # define scratch r23
638  
639 #else /* __IAR_SYSTEMS_ASM__ */
640 /* Register assignments for usbCrc16 on gcc */
641 /* Calling conventions on gcc:
642 * First parameter passed in r24/r25, second in r22/23 and so on.
643 * Callee must preserve r1-r17, r28/r29
644 * Result is passed in r24/r25
645 */
646 # define argLen r22 /* argument 2 */
647 # define argPtrL r24 /* argument 1 */
648 # define argPtrH r25 /* argument 1 */
649  
650 # define resCrcL r24 /* result */
651 # define resCrcH r25 /* result */
652  
653 # define ptrL XL
654 # define ptrH XH
655 # define ptr x
656 # define byte r18
657 # define bitCnt r19
658 # define polyL r20
659 # define polyH r21
660 # define scratch r23
661  
662 #endif
663  
664 ; extern unsigned usbCrc16(unsigned char *data, unsigned char len);
665 ; data: r24/25
666 ; len: r22
667 ; temp variables:
668 ; r18: data byte
669 ; r19: bit counter
670 ; r20/21: polynomial
671 ; r23: scratch
672 ; r24/25: crc-sum
673 ; r26/27=X: ptr
674 usbCrc16:
675 mov ptrL, argPtrL
676 mov ptrH, argPtrH
677 ldi resCrcL, 0xff
678 ldi resCrcH, 0xff
679 ldi polyL, lo8(0xa001)
680 ldi polyH, hi8(0xa001)
681 crcByteLoop:
682 subi argLen, 1
683 brcs crcReady
684 ld byte, ptr+
685 ldi bitCnt, 8
686 crcBitLoop:
687 mov scratch, byte
688 eor scratch, resCrcL
689 lsr resCrcH
690 ror resCrcL
691 lsr byte
692 sbrs scratch, 0
693 rjmp crcNoXor
694 eor resCrcL, polyL
695 eor resCrcH, polyH
696 crcNoXor:
697 dec bitCnt
698 brne crcBitLoop
699 rjmp crcByteLoop
700 crcReady:
701 com resCrcL
702 com resCrcH
703 ret
704  
705 ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
706 usbCrc16Append:
707 rcall usbCrc16
708 st ptr+, resCrcL
709 st ptr+, resCrcH
710 ret