usbdrv/usbdrvasm.S

changeset 0
9e9b2c78bd31
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbdrv/usbdrvasm.S	Thu Feb 16 14:40:23 2017 +0100
@@ -0,0 +1,392 @@
+/* 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)
+ */
+
+/*
+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 */

mercurial