123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- /* Name: usbdrvasm.S
- * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
- * Author: Christian Starkjohann
- * Creation Date: 2007-06-13
- * Tabsize: 4
- * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
- * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
- * Revision: $Id: usbdrvasm.S 761 2009-08-12 16:30:23Z cs $
- */
-
- /*
- General Description:
- This module is the assembler part of the USB driver. This file contains
- general code (preprocessor acrobatics and CRC computation) and then includes
- the file appropriate for the given clock rate.
- */
-
- #define __SFR_OFFSET 0 /* used by avr-libc's register definitions */
- #include "usbportability.h"
- #include "usbdrv.h" /* for common defs */
-
- /* register names */
- #define x1 r16
- #define x2 r17
- #define shift r18
- #define cnt r19
- #define x3 r20
- #define x4 r21
- #define x5 r22
- #define bitcnt x5
- #define phase x4
- #define leap x4
-
- /* Some assembler dependent definitions and declarations: */
-
- #ifdef __IAR_SYSTEMS_ASM__
- extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
- extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
- extern usbTxBuf, usbTxStatus1, usbTxStatus3
- # if USB_COUNT_SOF
- extern usbSofCount
- # endif
- public usbCrc16
- public usbCrc16Append
-
- COMMON INTVEC
- # ifndef USB_INTR_VECTOR
- ORG INT0_vect
- # else /* USB_INTR_VECTOR */
- ORG USB_INTR_VECTOR
- # undef USB_INTR_VECTOR
- # endif /* USB_INTR_VECTOR */
- # define USB_INTR_VECTOR usbInterruptHandler
- rjmp USB_INTR_VECTOR
- RSEG CODE
-
- #else /* __IAR_SYSTEMS_ASM__ */
-
- # ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */
- # define USB_INTR_VECTOR SIG_INTERRUPT0
- # endif
- .text
- .global USB_INTR_VECTOR
- .type USB_INTR_VECTOR, @function
- .global usbCrc16
- .global usbCrc16Append
- #endif /* __IAR_SYSTEMS_ASM__ */
-
-
- #if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */
- # define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING
- # define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg
- #else /* It's a memory address, use lds and sts */
- # define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING
- # define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg
- #endif
-
- #define usbTxLen1 usbTxStatus1
- #define usbTxBuf1 (usbTxStatus1 + 1)
- #define usbTxLen3 usbTxStatus3
- #define usbTxBuf3 (usbTxStatus3 + 1)
-
-
- ;----------------------------------------------------------------------------
- ; Utility functions
- ;----------------------------------------------------------------------------
-
- #ifdef __IAR_SYSTEMS_ASM__
- /* Register assignments for usbCrc16 on IAR cc */
- /* Calling conventions on IAR:
- * First parameter passed in r16/r17, second in r18/r19 and so on.
- * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
- * Result is passed in r16/r17
- * In case of the "tiny" memory model, pointers are only 8 bit with no
- * padding. We therefore pass argument 1 as "16 bit unsigned".
- */
- RTMODEL "__rt_version", "3"
- /* The line above will generate an error if cc calling conventions change.
- * The value "3" above is valid for IAR 4.10B/W32
- */
- # define argLen r18 /* argument 2 */
- # define argPtrL r16 /* argument 1 */
- # define argPtrH r17 /* argument 1 */
-
- # define resCrcL r16 /* result */
- # define resCrcH r17 /* result */
-
- # define ptrL ZL
- # define ptrH ZH
- # define ptr Z
- # define byte r22
- # define bitCnt r19
- # define polyL r20
- # define polyH r21
- # define scratch r23
-
- #else /* __IAR_SYSTEMS_ASM__ */
- /* Register assignments for usbCrc16 on gcc */
- /* Calling conventions on gcc:
- * First parameter passed in r24/r25, second in r22/23 and so on.
- * Callee must preserve r1-r17, r28/r29
- * Result is passed in r24/r25
- */
- # define argLen r22 /* argument 2 */
- # define argPtrL r24 /* argument 1 */
- # define argPtrH r25 /* argument 1 */
-
- # define resCrcL r24 /* result */
- # define resCrcH r25 /* result */
-
- # define ptrL XL
- # define ptrH XH
- # define ptr x
- # define byte r18
- # define bitCnt r19
- # define polyL r20
- # define polyH r21
- # define scratch r23
-
- #endif
-
- #if USB_USE_FAST_CRC
-
- ; This implementation is faster, but has bigger code size
- ; Thanks to Slawomir Fras (BoskiDialer) for this code!
- ; It implements the following C pseudo-code:
- ; unsigned table(unsigned char x)
- ; {
- ; unsigned value;
- ;
- ; value = (unsigned)x << 6;
- ; value ^= (unsigned)x << 7;
- ; if(parity(x))
- ; value ^= 0xc001;
- ; return value;
- ; }
- ; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen)
- ; {
- ; unsigned crc = 0xffff;
- ;
- ; while(argLen--)
- ; crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc);
- ; return ~crc;
- ; }
-
- ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
- ; argPtr r24+25 / r16+r17
- ; argLen r22 / r18
- ; temp variables:
- ; byte r18 / r22
- ; scratch r23
- ; resCrc r24+r25 / r16+r17
- ; ptr X / Z
- usbCrc16:
- mov ptrL, argPtrL
- mov ptrH, argPtrH
- ldi resCrcL, 0xFF
- ldi resCrcH, 0xFF
- rjmp usbCrc16LoopTest
- usbCrc16ByteLoop:
- ld byte, ptr+
- eor resCrcL, byte ; resCrcL is now 'x' in table()
- mov byte, resCrcL ; compute parity of 'x'
- swap byte
- eor byte, resCrcL
- mov scratch, byte
- lsr byte
- lsr byte
- eor byte, scratch
- inc byte
- lsr byte
- andi byte, 1 ; byte is now parity(x)
- mov scratch, resCrcL
- mov resCrcL, resCrcH
- eor resCrcL, byte ; low byte of if(parity(x)) value ^= 0xc001;
- neg byte
- andi byte, 0xc0
- mov resCrcH, byte ; high byte of if(parity(x)) value ^= 0xc001;
- clr byte
- lsr scratch
- ror byte
- eor resCrcH, scratch
- eor resCrcL, byte
- lsr scratch
- ror byte
- eor resCrcH, scratch
- eor resCrcL, byte
- usbCrc16LoopTest:
- subi argLen, 1
- brsh usbCrc16ByteLoop
- com resCrcL
- com resCrcH
- ret
-
- #else /* USB_USE_FAST_CRC */
-
- ; This implementation is slower, but has less code size
- ;
- ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
- ; argPtr r24+25 / r16+r17
- ; argLen r22 / r18
- ; temp variables:
- ; byte r18 / r22
- ; bitCnt r19
- ; poly r20+r21
- ; scratch r23
- ; resCrc r24+r25 / r16+r17
- ; ptr X / Z
- usbCrc16:
- mov ptrL, argPtrL
- mov ptrH, argPtrH
- ldi resCrcL, 0
- ldi resCrcH, 0
- ldi polyL, lo8(0xa001)
- ldi polyH, hi8(0xa001)
- com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set
- ldi bitCnt, 0 ; loop counter with starnd condition = end condition
- rjmp usbCrcLoopEntry
- usbCrcByteLoop:
- ld byte, ptr+
- eor resCrcL, byte
- usbCrcBitLoop:
- ror resCrcH ; carry is always set here (see brcs jumps to here)
- ror resCrcL
- brcs usbCrcNoXor
- eor resCrcL, polyL
- eor resCrcH, polyH
- usbCrcNoXor:
- subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
- brcs usbCrcBitLoop
- usbCrcLoopEntry:
- subi argLen, -1
- brcs usbCrcByteLoop
- usbCrcReady:
- ret
- ; Thanks to Reimar Doeffinger for optimizing this CRC routine!
-
- #endif /* USB_USE_FAST_CRC */
-
- ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
- usbCrc16Append:
- rcall usbCrc16
- st ptr+, resCrcL
- st ptr+, resCrcH
- ret
-
- #undef argLen
- #undef argPtrL
- #undef argPtrH
- #undef resCrcL
- #undef resCrcH
- #undef ptrL
- #undef ptrH
- #undef ptr
- #undef byte
- #undef bitCnt
- #undef polyL
- #undef polyH
- #undef scratch
-
-
- #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
- #ifdef __IAR_SYSTEMS_ASM__
- /* Register assignments for usbMeasureFrameLength on IAR cc */
- /* Calling conventions on IAR:
- * First parameter passed in r16/r17, second in r18/r19 and so on.
- * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
- * Result is passed in r16/r17
- * In case of the "tiny" memory model, pointers are only 8 bit with no
- * padding. We therefore pass argument 1 as "16 bit unsigned".
- */
- # define resL r16
- # define resH r17
- # define cnt16L r30
- # define cnt16H r31
- # define cntH r18
-
- #else /* __IAR_SYSTEMS_ASM__ */
- /* Register assignments for usbMeasureFrameLength on gcc */
- /* Calling conventions on gcc:
- * First parameter passed in r24/r25, second in r22/23 and so on.
- * Callee must preserve r1-r17, r28/r29
- * Result is passed in r24/r25
- */
- # define resL r24
- # define resH r25
- # define cnt16L r24
- # define cnt16H r25
- # define cntH r26
- #endif
- # define cnt16 cnt16L
-
- ; extern unsigned usbMeasurePacketLength(void);
- ; returns time between two idle strobes in multiples of 7 CPU clocks
- .global usbMeasureFrameLength
- usbMeasureFrameLength:
- ldi cntH, 6 ; wait ~ 10 ms for D- == 0
- clr cnt16L
- clr cnt16H
- usbMFTime16:
- dec cntH
- breq usbMFTimeout
- usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe)
- sbiw cnt16, 1 ;[0] [6]
- breq usbMFTime16 ;[2]
- sbic USBIN, USBMINUS ;[3]
- rjmp usbMFWaitStrobe ;[4]
- usbMFWaitIdle: ; then wait until idle again
- sbis USBIN, USBMINUS ;1 wait for D- == 1
- rjmp usbMFWaitIdle ;2
- ldi cnt16L, 1 ;1 represents cycles so far
- clr cnt16H ;1
- usbMFWaitLoop:
- in cntH, USBIN ;[0] [7]
- adiw cnt16, 1 ;[1]
- breq usbMFTimeout ;[3]
- andi cntH, USBMASK ;[4]
- brne usbMFWaitLoop ;[5]
- usbMFTimeout:
- #if resL != cnt16L
- mov resL, cnt16L
- mov resH, cnt16H
- #endif
- ret
-
- #undef resL
- #undef resH
- #undef cnt16
- #undef cnt16L
- #undef cnt16H
- #undef cntH
-
- #endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
-
- ;----------------------------------------------------------------------------
- ; Now include the clock rate specific code
- ;----------------------------------------------------------------------------
-
- #ifndef USB_CFG_CLOCK_KHZ
- # define USB_CFG_CLOCK_KHZ 12000
- #endif
-
- #if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */
- # if USB_CFG_CLOCK_KHZ == 18000
- # include "usbdrvasm18-crc.inc"
- # else
- # error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!"
- # endif
- #else /* USB_CFG_CHECK_CRC */
- # if USB_CFG_CLOCK_KHZ == 12000
- # include "usbdrvasm12.inc"
- # elif USB_CFG_CLOCK_KHZ == 12800
- # include "usbdrvasm128.inc"
- # elif USB_CFG_CLOCK_KHZ == 15000
- # include "usbdrvasm15.inc"
- # elif USB_CFG_CLOCK_KHZ == 16000
- # include "usbdrvasm16.inc"
- # elif USB_CFG_CLOCK_KHZ == 16500
- # include "usbdrvasm165.inc"
- # elif USB_CFG_CLOCK_KHZ == 20000
- # include "usbdrvasm20.inc"
- # else
- # error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!"
- # endif
- #endif /* USB_CFG_CHECK_CRC */
|