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)
 
  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 */
 
  61 #           define USB_INTR_VECTOR  INT0_vect       // this is the "new" define for the vector
 
  63 #           define USB_INTR_VECTOR  SIG_INTERRUPT0  // this is the "old" vector
 
  67     .global USB_INTR_VECTOR
 
  68     .type   USB_INTR_VECTOR, @function
 
  70     .global usbCrc16Append
 
  71 #endif /* __IAR_SYSTEMS_ASM__ */
 
  74 #if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */
 
  75 #   define  USB_LOAD_PENDING(reg)   in reg, USB_INTR_PENDING
 
  76 #   define  USB_STORE_PENDING(reg)  out USB_INTR_PENDING, reg
 
  77 #else   /* It's a memory address, use lds and sts */
 
  78 #   define  USB_LOAD_PENDING(reg)   lds reg, USB_INTR_PENDING
 
  79 #   define  USB_STORE_PENDING(reg)  sts USB_INTR_PENDING, reg
 
  82 #define usbTxLen1   usbTxStatus1
 
  83 #define usbTxBuf1   (usbTxStatus1 + 1)
 
  84 #define usbTxLen3   usbTxStatus3
 
  85 #define usbTxBuf3   (usbTxStatus3 + 1)
 
  88 ;----------------------------------------------------------------------------
 
  90 ;----------------------------------------------------------------------------
 
  92 #ifdef __IAR_SYSTEMS_ASM__
 
  93 /* Register assignments for usbCrc16 on IAR cc */
 
  94 /* Calling conventions on IAR:
 
  95  * First parameter passed in r16/r17, second in r18/r19 and so on.
 
  96  * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
 
  97  * Result is passed in r16/r17
 
  98  * In case of the "tiny" memory model, pointers are only 8 bit with no
 
  99  * padding. We therefore pass argument 1 as "16 bit unsigned".
 
 101 RTMODEL "__rt_version", "3"
 
 102 /* The line above will generate an error if cc calling conventions change.
 
 103  * The value "3" above is valid for IAR 4.10B/W32
 
 105 #   define argLen   r18 /* argument 2 */
 
 106 #   define argPtrL  r16 /* argument 1 */
 
 107 #   define argPtrH  r17 /* argument 1 */
 
 109 #   define resCrcL  r16 /* result */
 
 110 #   define resCrcH  r17 /* result */
 
 121 #else  /* __IAR_SYSTEMS_ASM__ */ 
 
 122 /* Register assignments for usbCrc16 on gcc */
 
 123 /* Calling conventions on gcc:
 
 124  * First parameter passed in r24/r25, second in r22/23 and so on.
 
 125  * Callee must preserve r1-r17, r28/r29
 
 126  * Result is passed in r24/r25
 
 128 #   define argLen   r22 /* argument 2 */
 
 129 #   define argPtrL  r24 /* argument 1 */
 
 130 #   define argPtrH  r25 /* argument 1 */
 
 132 #   define resCrcL  r24 /* result */
 
 133 #   define resCrcH  r25 /* result */
 
 148 ; This implementation is faster, but has bigger code size
 
 149 ; Thanks to Slawomir Fras (BoskiDialer) for this code!
 
 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
 
 183     rjmp    usbCrc16LoopTest
 
 186     eor     resCrcL, byte   ; resCrcL is now 'x' in table()
 
 187     mov     byte, resCrcL   ; compute parity of 'x'
 
 196     andi    byte, 1         ; byte is now parity(x)
 
 199     eor     resCrcL, byte   ; low byte of if(parity(x)) value ^= 0xc001;
 
 202     mov     resCrcH, byte   ; high byte of if(parity(x)) value ^= 0xc001;
 
 214     brsh    usbCrc16ByteLoop
 
 219 #else   /* USB_USE_FAST_CRC */
 
 221 ; This implementation is slower, but has less code size
 
 223 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
 
 224 ;   argPtr  r24+25 / r16+r17
 
 231 ;   resCrc  r24+r25 / r16+r17
 
 238     ldi     polyL, lo8(0xa001)
 
 239     ldi     polyH, hi8(0xa001)
 
 240     com     argLen      ; argLen = -argLen - 1: modified loop to ensure that carry is set
 
 241     ldi     bitCnt, 0   ; loop counter with starnd condition = end condition
 
 247     ror     resCrcH     ; carry is always set here (see brcs jumps to here)
 
 253     subi    bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
 
 260 ; Thanks to Reimar Doeffinger for optimizing this CRC routine!
 
 262 #endif /* USB_USE_FAST_CRC */
 
 264 ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
 
 286 #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
 
 287 #ifdef __IAR_SYSTEMS_ASM__
 
 288 /* Register assignments for usbMeasureFrameLength on IAR cc */
 
 289 /* Calling conventions on IAR:
 
 290  * First parameter passed in r16/r17, second in r18/r19 and so on.
 
 291  * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
 
 292  * Result is passed in r16/r17
 
 293  * In case of the "tiny" memory model, pointers are only 8 bit with no
 
 294  * padding. We therefore pass argument 1 as "16 bit unsigned".
 
 302 #else  /* __IAR_SYSTEMS_ASM__ */ 
 
 303 /* Register assignments for usbMeasureFrameLength on gcc */
 
 304 /* Calling conventions on gcc:
 
 305  * First parameter passed in r24/r25, second in r22/23 and so on.
 
 306  * Callee must preserve r1-r17, r28/r29
 
 307  * Result is passed in r24/r25
 
 315 #   define cnt16    cnt16L
 
 317 ; extern unsigned usbMeasurePacketLength(void);
 
 318 ; returns time between two idle strobes in multiples of 7 CPU clocks
 
 319 .global usbMeasureFrameLength
 
 320 usbMeasureFrameLength:
 
 321     ldi     cntH, 6         ; wait ~ 10 ms for D- == 0
 
 327 usbMFWaitStrobe:            ; first wait for D- == 0 (idle strobe)
 
 328     sbiw    cnt16, 1        ;[0] [6]
 
 329     breq    usbMFTime16     ;[2]
 
 330     sbic    USBIN, USBMINUS ;[3]
 
 331     rjmp    usbMFWaitStrobe ;[4]
 
 332 usbMFWaitIdle:              ; then wait until idle again
 
 333     sbis    USBIN, USBMINUS ;1 wait for D- == 1
 
 334     rjmp    usbMFWaitIdle   ;2
 
 335     ldi     cnt16L, 1       ;1 represents cycles so far
 
 338     in      cntH, USBIN     ;[0] [7]
 
 340     breq    usbMFTimeout    ;[3]
 
 341     andi    cntH, USBMASK   ;[4]
 
 342     brne    usbMFWaitLoop   ;[5]
 
 357 #endif  /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
 
 359 ;----------------------------------------------------------------------------
 
 360 ; Now include the clock rate specific code
 
 361 ;----------------------------------------------------------------------------
 
 363 #ifndef USB_CFG_CLOCK_KHZ
 
 365 #       define USB_CFG_CLOCK_KHZ (F_CPU/1000)
 
 367 #       error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!"
 
 371 #if USB_CFG_CHECK_CRC   /* separate dispatcher for CRC type modules */
 
 372 #   if USB_CFG_CLOCK_KHZ == 18000
 
 373 #       include "usbdrvasm18-crc.inc"
 
 375 #       error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!"
 
 377 #else   /* USB_CFG_CHECK_CRC */
 
 378 #   if USB_CFG_CLOCK_KHZ == 12000
 
 379 #       include "usbdrvasm12.inc"
 
 380 #   elif USB_CFG_CLOCK_KHZ == 12800
 
 381 #       include "usbdrvasm128.inc"
 
 382 #   elif USB_CFG_CLOCK_KHZ == 15000
 
 383 #       include "usbdrvasm15.inc"
 
 384 #   elif USB_CFG_CLOCK_KHZ == 16000
 
 385 #       include "usbdrvasm16.inc"
 
 386 #   elif USB_CFG_CLOCK_KHZ == 16500
 
 387 #       include "usbdrvasm165.inc"
 
 388 #   elif USB_CFG_CLOCK_KHZ == 20000
 
 389 #       include "usbdrvasm20.inc"
 
 391 #       error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!"
 
 393 #endif /* USB_CFG_CHECK_CRC */