You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					394 lines
				
				11 KiB
			
		
		
			
		
	
	
					394 lines
				
				11 KiB
			|   
											15 years ago
										 | /* 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 785 2010-05-30 17:57:07Z 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 */ | ||
|  | #       ifdef INT0_vect | ||
|  | #           define USB_INTR_VECTOR  INT0_vect       // this is the "new" define for the vector | ||
|  | #       else | ||
|  | #           define USB_INTR_VECTOR  SIG_INTERRUPT0  // this is the "old" vector | ||
|  | #       endif | ||
|  | #   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 | ||
|  | #   ifdef F_CPU | ||
|  | #       define USB_CFG_CLOCK_KHZ (F_CPU/1000) | ||
|  | #   else | ||
|  | #       error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!" | ||
|  | #   endif | ||
|  | #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 */ |