315 lines
8.9 KiB
ArmAsm
315 lines
8.9 KiB
ArmAsm
/* Name: usbdrvasm.S
|
|
* Project: AVR USB driver
|
|
* 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) or proprietary (CommercialLicense.txt)
|
|
* Revision: $Id$
|
|
*/
|
|
|
|
/*
|
|
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.
|
|
*/
|
|
|
|
#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 */
|
|
# define macro .macro /* GNU Assembler macro definition */
|
|
# define endm .endm /* End of GNU Assembler macro definition */
|
|
#endif /* __IAR_SYSTEMS_ASM__ */
|
|
#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 bitcnt r22
|
|
#define phase x4
|
|
#define leap x4
|
|
|
|
/* 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) & 0xff) /* not HIGH to allow XLINK to make a proper range check */
|
|
|
|
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__ */
|
|
|
|
# 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 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
|
|
|
|
; extern unsigned usbCrc16(unsigned char *data, unsigned char len);
|
|
; data: r24/25
|
|
; len: r22
|
|
; temp variables:
|
|
; r18: data byte
|
|
; r19: bit counter
|
|
; r20/21: polynomial
|
|
; r23: scratch
|
|
; r24/25: crc-sum
|
|
; r26/27=X: ptr
|
|
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
|
|
crcByteLoop:
|
|
subi argLen, -1
|
|
brcc crcReady ; modified loop to ensure that carry is set below
|
|
ld byte, ptr+
|
|
ldi bitCnt, -8 ; strange loop counter to ensure that carry is set where we need it
|
|
eor resCrcL, byte
|
|
crcBitLoop:
|
|
ror resCrcH ; carry is always set here
|
|
ror resCrcL
|
|
brcs crcNoXor
|
|
eor resCrcL, polyL
|
|
eor resCrcH, polyH
|
|
crcNoXor:
|
|
subi bitCnt, -1
|
|
brcs crcBitLoop
|
|
rjmp crcByteLoop
|
|
crcReady:
|
|
ret
|
|
; Thanks to Reimar Doeffinger for optimizing this CRC routine!
|
|
|
|
; 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_CLOCK_KHZ == 12000
|
|
# include "usbdrvasm12.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 rates!"
|
|
#endif
|