2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3 * Author: Christian Starkjohann
4 * Creation Date: 2007-06-13
6 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
12 This module is the assembler part of the USB driver. This file contains
13 general code (preprocessor acrobatics and CRC computation) and then includes
14 the file appropriate for the given clock rate.
17 #define __SFR_OFFSET 0 /* used by avr-libc's register definitions */
18 #include "usbportability.h"
19 #include "usbdrv.h" /* for common defs */
33 /* Some assembler dependent definitions and declarations: */
35 #ifdef __IAR_SYSTEMS_ASM__
36 extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
37 extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
38 extern usbTxBuf, usbTxStatus1, usbTxStatus3
46 # ifndef USB_INTR_VECTOR
48 # else /* USB_INTR_VECTOR */
50 # undef USB_INTR_VECTOR
51 # endif /* USB_INTR_VECTOR */
52 # define USB_INTR_VECTOR usbInterruptHandler
56 #else /* __IAR_SYSTEMS_ASM__ */
58 # ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */
60 # define USB_INTR_VECTOR INT0_vect // this is the "new" define for the vector
62 # define USB_INTR_VECTOR SIG_INTERRUPT0 // this is the "old" vector
66 .global USB_INTR_VECTOR
67 .type USB_INTR_VECTOR, @function
69 .global usbCrc16Append
70 #endif /* __IAR_SYSTEMS_ASM__ */
73 #if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */
74 # define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING
75 # define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg
76 #else /* It's a memory address, use lds and sts */
77 # define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING
78 # define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg
81 #define usbTxLen1 usbTxStatus1
82 #define usbTxBuf1 (usbTxStatus1 + 1)
83 #define usbTxLen3 usbTxStatus3
84 #define usbTxBuf3 (usbTxStatus3 + 1)
87 ;----------------------------------------------------------------------------
89 ;----------------------------------------------------------------------------
91 #ifdef __IAR_SYSTEMS_ASM__
92 /* Register assignments for usbCrc16 on IAR cc */
93 /* Calling conventions on IAR:
94 * First parameter passed in r16/r17, second in r18/r19 and so on.
95 * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
96 * Result is passed in r16/r17
97 * In case of the "tiny" memory model, pointers are only 8 bit with no
98 * padding. We therefore pass argument 1 as "16 bit unsigned".
100 RTMODEL "__rt_version", "3"
101 /* The line above will generate an error if cc calling conventions change.
102 * The value "3" above is valid for IAR 4.10B/W32
104 # define argLen r18 /* argument 2 */
105 # define argPtrL r16 /* argument 1 */
106 # define argPtrH r17 /* argument 1 */
108 # define resCrcL r16 /* result */
109 # define resCrcH r17 /* result */
120 #else /* __IAR_SYSTEMS_ASM__ */
121 /* Register assignments for usbCrc16 on gcc */
122 /* Calling conventions on gcc:
123 * First parameter passed in r24/r25, second in r22/23 and so on.
124 * Callee must preserve r1-r17, r28/r29
125 * Result is passed in r24/r25
127 # define argLen r22 /* argument 2 */
128 # define argPtrL r24 /* argument 1 */
129 # define argPtrH r25 /* argument 1 */
131 # define resCrcL r24 /* result */
132 # define resCrcH r25 /* result */
147 ; This implementation is faster, but has bigger code size
148 ; Thanks to Slawomir Fras (BoskiDialer) for this code and to Shay Green for
149 ; even further optimizations!
150 ; It implements the following C pseudo-code:
151 ; unsigned table(unsigned char x)
155 ; value = (unsigned)x << 6;
156 ; value ^= (unsigned)x << 7;
161 ; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen)
163 ; unsigned crc = 0xffff;
166 ; crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc);
170 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
171 ; argPtr r24+25 / r16+r17
176 ; resCrc r24+r25 / r16+r17
182 clr bitCnt ; zero reg
183 rjmp usbCrc16LoopTest
186 eor byte, resCrcL ; scratch is now 'x' in table()
187 mov scratch, byte ; compute parity of 'x'
195 andi byte, 2 ; byte is now parity(x) << 1
196 cp bitCnt, byte ; c = (byte != 0), then put in high bit
197 ror scratch ; so that after xoring, shifting, and xoring, it gives
198 ror byte ; the desired 0xC0 with resCrcH
208 brsh usbCrc16ByteLoop
213 #else /* USB_USE_FAST_CRC */
215 ; This implementation is slower, but has less code size
217 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
218 ; argPtr r24+25 / r16+r17
225 ; resCrc r24+r25 / r16+r17
232 ldi polyL, lo8(0xa001)
233 ldi polyH, hi8(0xa001)
234 com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set
235 ldi bitCnt, 0 ; loop counter with starnd condition = end condition
241 ror resCrcH ; carry is always set here (see brcs jumps to here)
247 subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
254 ; Thanks to Reimar Doeffinger for optimizing this CRC routine!
256 #endif /* USB_USE_FAST_CRC */
258 ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
280 #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
281 #ifdef __IAR_SYSTEMS_ASM__
282 /* Register assignments for usbMeasureFrameLength on IAR cc */
283 /* Calling conventions on IAR:
284 * First parameter passed in r16/r17, second in r18/r19 and so on.
285 * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
286 * Result is passed in r16/r17
287 * In case of the "tiny" memory model, pointers are only 8 bit with no
288 * padding. We therefore pass argument 1 as "16 bit unsigned".
296 #else /* __IAR_SYSTEMS_ASM__ */
297 /* Register assignments for usbMeasureFrameLength on gcc */
298 /* Calling conventions on gcc:
299 * First parameter passed in r24/r25, second in r22/23 and so on.
300 * Callee must preserve r1-r17, r28/r29
301 * Result is passed in r24/r25
309 # define cnt16 cnt16L
311 ; extern unsigned usbMeasurePacketLength(void);
312 ; returns time between two idle strobes in multiples of 7 CPU clocks
313 .global usbMeasureFrameLength
314 usbMeasureFrameLength:
315 ldi cntH, 6 ; wait ~ 10 ms for D- == 0
321 usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe)
322 sbiw cnt16, 1 ;[0] [6]
323 breq usbMFTime16 ;[2]
324 sbic USBIN, USBMINUS ;[3]
325 rjmp usbMFWaitStrobe ;[4]
326 usbMFWaitIdle: ; then wait until idle again
327 sbis USBIN, USBMINUS ;1 wait for D- == 1
328 rjmp usbMFWaitIdle ;2
329 ldi cnt16L, 1 ;1 represents cycles so far
332 in cntH, USBIN ;[0] [7]
334 breq usbMFTimeout ;[3]
335 andi cntH, USBMASK ;[4]
336 brne usbMFWaitLoop ;[5]
351 #endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
353 ;----------------------------------------------------------------------------
354 ; Now include the clock rate specific code
355 ;----------------------------------------------------------------------------
357 #ifndef USB_CFG_CLOCK_KHZ
359 # define USB_CFG_CLOCK_KHZ (F_CPU/1000)
361 # error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!"
365 #if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */
366 # if USB_CFG_CLOCK_KHZ == 18000
367 # include "usbdrvasm18-crc.inc"
369 # error "USB_CFG_CLOCK_KHZ is not one of the supported rates for USB_CFG_CHECK_CRC!"
371 #else /* USB_CFG_CHECK_CRC */
372 # if USB_CFG_CLOCK_KHZ == 12000
373 # include "usbdrvasm12.inc"
374 # elif USB_CFG_CLOCK_KHZ == 12800
375 # include "usbdrvasm128.inc"
376 # elif USB_CFG_CLOCK_KHZ == 15000
377 # include "usbdrvasm15.inc"
378 # elif USB_CFG_CLOCK_KHZ == 16000
379 # include "usbdrvasm16.inc"
380 # elif USB_CFG_CLOCK_KHZ == 16500
381 # include "usbdrvasm165.inc"
382 # elif USB_CFG_CLOCK_KHZ == 18000
383 # include "usbdrvasm18.inc"
384 # elif USB_CFG_CLOCK_KHZ == 20000
385 # include "usbdrvasm20.inc"
387 # error "USB_CFG_CLOCK_KHZ is not one of the supported rates!"
389 #endif /* USB_CFG_CHECK_CRC */