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)
8 * Revision: $Id: usbdrvasm.S 761 2009-08-12 16:30:23Z cs $
13 This module is the assembler part of the USB driver. This file contains
14 general code (preprocessor acrobatics and CRC computation) and then includes
15 the file appropriate for the given clock rate.
18 #define __SFR_OFFSET 0 /* used by avr-libc's register definitions */
19 #include "usbportability.h"
20 #include "usbdrv.h" /* for common defs */
34 /* Some assembler dependent definitions and declarations: */
36 #ifdef __IAR_SYSTEMS_ASM__
37 extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
38 extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
39 extern usbTxBuf, usbTxStatus1, usbTxStatus3
47 # ifndef USB_INTR_VECTOR
49 # else /* USB_INTR_VECTOR */
51 # undef USB_INTR_VECTOR
52 # endif /* USB_INTR_VECTOR */
53 # define USB_INTR_VECTOR usbInterruptHandler
57 #else /* __IAR_SYSTEMS_ASM__ */
59 # ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */
60 # define USB_INTR_VECTOR SIG_INTERRUPT0
63 .global USB_INTR_VECTOR
64 .type USB_INTR_VECTOR, @function
66 .global usbCrc16Append
67 #endif /* __IAR_SYSTEMS_ASM__ */
70 #if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */
71 # define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING
72 # define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg
73 #else /* It's a memory address, use lds and sts */
74 # define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING
75 # define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg
78 #define usbTxLen1 usbTxStatus1
79 #define usbTxBuf1 (usbTxStatus1 + 1)
80 #define usbTxLen3 usbTxStatus3
81 #define usbTxBuf3 (usbTxStatus3 + 1)
84 ;----------------------------------------------------------------------------
86 ;----------------------------------------------------------------------------
88 #ifdef __IAR_SYSTEMS_ASM__
89 /* Register assignments for usbCrc16 on IAR cc */
90 /* Calling conventions on IAR:
91 * First parameter passed in r16/r17, second in r18/r19 and so on.
92 * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
93 * Result is passed in r16/r17
94 * In case of the "tiny" memory model, pointers are only 8 bit with no
95 * padding. We therefore pass argument 1 as "16 bit unsigned".
97 RTMODEL "__rt_version", "3"
98 /* The line above will generate an error if cc calling conventions change.
99 * The value "3" above is valid for IAR 4.10B/W32
101 # define argLen r18 /* argument 2 */
102 # define argPtrL r16 /* argument 1 */
103 # define argPtrH r17 /* argument 1 */
105 # define resCrcL r16 /* result */
106 # define resCrcH r17 /* result */
117 #else /* __IAR_SYSTEMS_ASM__ */
118 /* Register assignments for usbCrc16 on gcc */
119 /* Calling conventions on gcc:
120 * First parameter passed in r24/r25, second in r22/23 and so on.
121 * Callee must preserve r1-r17, r28/r29
122 * Result is passed in r24/r25
124 # define argLen r22 /* argument 2 */
125 # define argPtrL r24 /* argument 1 */
126 # define argPtrH r25 /* argument 1 */
128 # define resCrcL r24 /* result */
129 # define resCrcH r25 /* result */
144 ; This implementation is faster, but has bigger code size
145 ; Thanks to Slawomir Fras (BoskiDialer) for this code!
146 ; It implements the following C pseudo-code:
147 ; unsigned table(unsigned char x)
151 ; value = (unsigned)x << 6;
152 ; value ^= (unsigned)x << 7;
157 ; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen)
159 ; unsigned crc = 0xffff;
162 ; crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc);
166 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
167 ; argPtr r24+25 / r16+r17
172 ; resCrc r24+r25 / r16+r17
179 rjmp usbCrc16LoopTest
182 eor resCrcL, byte ; resCrcL is now 'x' in table()
183 mov byte, resCrcL ; compute parity of 'x'
192 andi byte, 1 ; byte is now parity(x)
195 eor resCrcL, byte ; low byte of if(parity(x)) value ^= 0xc001;
198 mov resCrcH, byte ; high byte of if(parity(x)) value ^= 0xc001;
210 brsh usbCrc16ByteLoop
215 #else /* USB_USE_FAST_CRC */
217 ; This implementation is slower, but has less code size
219 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
220 ; argPtr r24+25 / r16+r17
227 ; resCrc r24+r25 / r16+r17
234 ldi polyL, lo8(0xa001)
235 ldi polyH, hi8(0xa001)
236 com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set
237 ldi bitCnt, 0 ; loop counter with starnd condition = end condition
243 ror resCrcH ; carry is always set here (see brcs jumps to here)
249 subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
256 ; Thanks to Reimar Doeffinger for optimizing this CRC routine!
258 #endif /* USB_USE_FAST_CRC */
260 ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
282 #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
283 #ifdef __IAR_SYSTEMS_ASM__
284 /* Register assignments for usbMeasureFrameLength on IAR cc */
285 /* Calling conventions on IAR:
286 * First parameter passed in r16/r17, second in r18/r19 and so on.
287 * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
288 * Result is passed in r16/r17
289 * In case of the "tiny" memory model, pointers are only 8 bit with no
290 * padding. We therefore pass argument 1 as "16 bit unsigned".
298 #else /* __IAR_SYSTEMS_ASM__ */
299 /* Register assignments for usbMeasureFrameLength on gcc */
300 /* Calling conventions on gcc:
301 * First parameter passed in r24/r25, second in r22/23 and so on.
302 * Callee must preserve r1-r17, r28/r29
303 * Result is passed in r24/r25
311 # define cnt16 cnt16L
313 ; extern unsigned usbMeasurePacketLength(void);
314 ; returns time between two idle strobes in multiples of 7 CPU clocks
315 .global usbMeasureFrameLength
316 usbMeasureFrameLength:
317 ldi cntH, 6 ; wait ~ 10 ms for D- == 0
323 usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe)
324 sbiw cnt16, 1 ;[0] [6]
325 breq usbMFTime16 ;[2]
326 sbic USBIN, USBMINUS ;[3]
327 rjmp usbMFWaitStrobe ;[4]
328 usbMFWaitIdle: ; then wait until idle again
329 sbis USBIN, USBMINUS ;1 wait for D- == 1
330 rjmp usbMFWaitIdle ;2
331 ldi cnt16L, 1 ;1 represents cycles so far
334 in cntH, USBIN ;[0] [7]
336 breq usbMFTimeout ;[3]
337 andi cntH, USBMASK ;[4]
338 brne usbMFWaitLoop ;[5]
353 #endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
355 ;----------------------------------------------------------------------------
356 ; Now include the clock rate specific code
357 ;----------------------------------------------------------------------------
359 #ifndef USB_CFG_CLOCK_KHZ
360 # define USB_CFG_CLOCK_KHZ 12000
363 #if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */
364 # if USB_CFG_CLOCK_KHZ == 18000
365 # include "usbdrvasm18-crc.inc"
367 # error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!"
369 #else /* USB_CFG_CHECK_CRC */
370 # if USB_CFG_CLOCK_KHZ == 12000
371 # include "usbdrvasm12.inc"
372 # elif USB_CFG_CLOCK_KHZ == 12800
373 # include "usbdrvasm128.inc"
374 # elif USB_CFG_CLOCK_KHZ == 15000
375 # include "usbdrvasm15.inc"
376 # elif USB_CFG_CLOCK_KHZ == 16000
377 # include "usbdrvasm16.inc"
378 # elif USB_CFG_CLOCK_KHZ == 16500
379 # include "usbdrvasm165.inc"
380 # elif USB_CFG_CLOCK_KHZ == 20000
381 # include "usbdrvasm20.inc"
383 # error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!"
385 #endif /* USB_CFG_CHECK_CRC */