USBasp 2009.02.28.
[pub/USBasp.git] / firmware / usbdrv / usbdrvasm.S
index 3f67f53..c3fc0bb 100644 (file)
@@ -4,8 +4,8 @@
  * Creation Date: 2007-06-13
  * Tabsize: 4
  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
- * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
- * Revision: $Id$
+ * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
+ * Revision: $Id: usbdrvasm.S 692 2008-11-07 15:07:40Z cs $
  */
 
 /*
@@ -15,15 +15,9 @@ general code (preprocessor acrobatics and CRC computation) and then includes
 the file appropriate for the given clock rate.
 */
 
-#include "iarcompat.h"
-#ifndef __IAR_SYSTEMS_ASM__
-    /* configs for io.h */
-#   define __SFR_OFFSET 0
-#   define _VECTOR(N)   __vector_ ## N   /* io.h does not define this for asm */
-#   include <avr/io.h> /* for CPU I/O register definitions and vectors */
-#endif  /* __IAR_SYSTEMS_ASM__ */
-#include "usbdrv.h" /* for common defs */
-
+#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
@@ -39,40 +33,53 @@ the file appropriate for the given clock rate.
 /* Some assembler dependent definitions and declarations: */
 
 #ifdef __IAR_SYSTEMS_ASM__
-
-#   define nop2     rjmp    $+2 /* jump to next instruction */
-#   define XL       r26
-#   define XH       r27
-#   define YL       r28
-#   define YH       r29
-#   define ZL       r30
-#   define ZH       r31
-#   define lo8(x)   LOW(x)
-#   define hi8(x)   ((x)>>8)    /* not HIGH to allow XLINK to make a proper range check */
-
     extern  usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
     extern  usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
-    extern  usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3
+    extern  usbTxBuf, usbTxStatus1, usbTxStatus3
+#   if USB_COUNT_SOF
+        extern usbSofCount
+#   endif
     public  usbCrc16
     public  usbCrc16Append
 
     COMMON  INTVEC
-    ORG     INT0_vect
-    rjmp    SIG_INTERRUPT0
+#   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__ */
 
-#   define nop2     rjmp    .+0 /* jump to next instruction */
-
+#   ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */
+#       define USB_INTR_VECTOR  SIG_INTERRUPT0
+#   endif
     .text
-    .global SIG_INTERRUPT0
-    .type   SIG_INTERRUPT0, @function
+    .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
 ;----------------------------------------------------------------------------
@@ -144,33 +151,30 @@ RTMODEL "__rt_version", "3"
 usbCrc16:
     mov     ptrL, argPtrL
     mov     ptrH, argPtrH
-    ldi     resCrcL, 0xff
-    ldi     resCrcH, 0xff
+    ldi     resCrcL, 0
+    ldi     resCrcH, 0
     ldi     polyL, lo8(0xa001)
     ldi     polyH, hi8(0xa001)
+    com     argLen      ; argLen = -argLen - 1
 crcByteLoop:
-    subi    argLen, 1
-    brcs    crcReady
+    subi    argLen, -1
+    brcc    crcReady    ; modified loop to ensure that carry is set below
     ld      byte, ptr+
-    ldi     bitCnt, 8
+    ldi     bitCnt, -8  ; strange loop counter to ensure that carry is set where we need it
+    eor     resCrcL, byte
 crcBitLoop:
-    mov     scratch, byte
-    eor     scratch, resCrcL
-    lsr     resCrcH
+    ror     resCrcH     ; carry is always set here
     ror     resCrcL
-    lsr     byte
-    sbrs    scratch, 0
-    rjmp    crcNoXor
+    brcs    crcNoXor
     eor     resCrcL, polyL
     eor     resCrcH, polyH
 crcNoXor:
-    dec     bitCnt
-    brne    crcBitLoop
+    subi    bitCnt, -1
+    brcs    crcBitLoop
     rjmp    crcByteLoop
 crcReady:
-    com     resCrcL
-    com     resCrcH
     ret
+; Thanks to Reimar Doeffinger for optimizing this CRC routine!
 
 ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
 usbCrc16Append:
@@ -179,6 +183,93 @@ usbCrc16Append:
     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
@@ -189,11 +280,17 @@ usbCrc16Append:
 #endif
 
 #if USB_CFG_CLOCK_KHZ == 12000
-#   include "usbdrvasm12.S"
+#   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.S"
+#   include "usbdrvasm16.inc"
 #elif USB_CFG_CLOCK_KHZ == 16500
-#   include "usbdrvasm165.S"
+#   include "usbdrvasm165.inc"
+#elif USB_CFG_CLOCK_KHZ == 20000
+#   include "usbdrvasm20.inc"
 #else
 #   error "USB_CFG_CLOCK_KHZ is not one of the supported rates!"
 #endif