OSDN Git Service

kazzo 0.1.1 release
[unagi/old-svn-converted.git] / kazzo / tag / 0.1.1 / firmware / usbdrv / usbdrvasm.S
1 /* Name: usbdrvasm.S
2  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3  * Author: Christian Starkjohann
4  * Creation Date: 2007-06-13
5  * Tabsize: 4
6  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
8  * Revision: $Id$
9  */
10
11 /*
12 General Description:
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.
16 */
17
18 #define __SFR_OFFSET 0      /* used by avr-libc's register definitions */
19 #include "usbportability.h"
20 #include "usbdrv.h"         /* for common defs */
21
22 /* register names */
23 #define x1      r16
24 #define x2      r17
25 #define shift   r18
26 #define cnt     r19
27 #define x3      r20
28 #define x4      r21
29 #define x5              r22
30 #define bitcnt  x5
31 #define phase   x4
32 #define leap    x4
33
34 /* Some assembler dependent definitions and declarations: */
35
36 #ifdef __IAR_SYSTEMS_ASM__
37     extern  usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
38     extern  usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
39     extern  usbTxBuf, usbTxStatus1, usbTxStatus3
40 #   if USB_COUNT_SOF
41         extern usbSofCount
42 #   endif
43     public  usbCrc16
44     public  usbCrc16Append
45
46     COMMON  INTVEC
47 #   ifndef USB_INTR_VECTOR
48         ORG     INT0_vect
49 #   else /* USB_INTR_VECTOR */
50         ORG     USB_INTR_VECTOR
51 #       undef   USB_INTR_VECTOR
52 #   endif /* USB_INTR_VECTOR */
53 #   define  USB_INTR_VECTOR usbInterruptHandler
54     rjmp    USB_INTR_VECTOR
55     RSEG    CODE
56
57 #else /* __IAR_SYSTEMS_ASM__ */
58
59 #   ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */
60 #       define USB_INTR_VECTOR  SIG_INTERRUPT0
61 #   endif
62     .text
63     .global USB_INTR_VECTOR
64     .type   USB_INTR_VECTOR, @function
65     .global usbCrc16
66     .global usbCrc16Append
67 #endif /* __IAR_SYSTEMS_ASM__ */
68
69
70 #if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */
71 #   define  USB_LOAD_PENDING(reg)   in reg, USB_INTR_PENDING
72 #   define  USB_STORE_PENDING(reg)  out USB_INTR_PENDING, reg
73 #else   /* It's a memory address, use lds and sts */
74 #   define  USB_LOAD_PENDING(reg)   lds reg, USB_INTR_PENDING
75 #   define  USB_STORE_PENDING(reg)  sts USB_INTR_PENDING, reg
76 #endif
77
78 #define usbTxLen1   usbTxStatus1
79 #define usbTxBuf1   (usbTxStatus1 + 1)
80 #define usbTxLen3   usbTxStatus3
81 #define usbTxBuf3   (usbTxStatus3 + 1)
82
83
84 ;----------------------------------------------------------------------------
85 ; Utility functions
86 ;----------------------------------------------------------------------------
87
88 #ifdef __IAR_SYSTEMS_ASM__
89 /* Register assignments for usbCrc16 on IAR cc */
90 /* Calling conventions on IAR:
91  * First parameter passed in r16/r17, second in r18/r19 and so on.
92  * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
93  * Result is passed in r16/r17
94  * In case of the "tiny" memory model, pointers are only 8 bit with no
95  * padding. We therefore pass argument 1 as "16 bit unsigned".
96  */
97 RTMODEL "__rt_version", "3"
98 /* The line above will generate an error if cc calling conventions change.
99  * The value "3" above is valid for IAR 4.10B/W32
100  */
101 #   define argLen   r18 /* argument 2 */
102 #   define argPtrL  r16 /* argument 1 */
103 #   define argPtrH  r17 /* argument 1 */
104
105 #   define resCrcL  r16 /* result */
106 #   define resCrcH  r17 /* result */
107
108 #   define ptrL     ZL
109 #   define ptrH     ZH
110 #   define ptr      Z
111 #   define byte     r22
112 #   define bitCnt   r19
113 #   define polyL    r20
114 #   define polyH    r21
115 #   define scratch  r23
116
117 #else  /* __IAR_SYSTEMS_ASM__ */ 
118 /* Register assignments for usbCrc16 on gcc */
119 /* Calling conventions on gcc:
120  * First parameter passed in r24/r25, second in r22/23 and so on.
121  * Callee must preserve r1-r17, r28/r29
122  * Result is passed in r24/r25
123  */
124 #   define argLen   r22 /* argument 2 */
125 #   define argPtrL  r24 /* argument 1 */
126 #   define argPtrH  r25 /* argument 1 */
127
128 #   define resCrcL  r24 /* result */
129 #   define resCrcH  r25 /* result */
130
131 #   define ptrL     XL
132 #   define ptrH     XH
133 #   define ptr      x
134 #   define byte     r18
135 #   define bitCnt   r19
136 #   define polyL    r20
137 #   define polyH    r21
138 #   define scratch  r23
139
140 #endif
141
142 #if USB_USE_FAST_CRC
143
144 ; This implementation is faster, but has bigger code size
145 ; Thanks to Slawomir Fras (BoskiDialer) for this code!
146 ; It implements the following C pseudo-code:
147 ; unsigned table(unsigned char x)
148 ; {
149 ; unsigned    value;
150
151 ;     value = (unsigned)x << 6;
152 ;     value ^= (unsigned)x << 7;
153 ;     if(parity(x))
154 ;         value ^= 0xc001;
155 ;     return value;
156 ; }
157 ; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen)
158 ; {
159 ; unsigned crc = 0xffff;
160
161 ;     while(argLen--)
162 ;         crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc);
163 ;     return ~crc;
164 ; }
165
166 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
167 ;   argPtr  r24+25 / r16+r17
168 ;   argLen  r22 / r18
169 ; temp variables:
170 ;   byte    r18 / r22
171 ;   scratch r23
172 ;   resCrc  r24+r25 / r16+r17
173 ;   ptr     X / Z
174 usbCrc16:
175     mov     ptrL, argPtrL
176     mov     ptrH, argPtrH
177     ldi     resCrcL, 0xFF
178     ldi     resCrcH, 0xFF
179     rjmp    usbCrc16LoopTest
180 usbCrc16ByteLoop:
181     ld      byte, ptr+
182     eor     resCrcL, byte   ; resCrcL is now 'x' in table()
183     mov     byte, resCrcL   ; compute parity of 'x'
184     swap    byte
185     eor     byte, resCrcL
186     mov     scratch, byte
187     lsr     byte
188     lsr     byte
189     eor     byte, scratch
190     inc     byte
191     lsr     byte
192     andi    byte, 1         ; byte is now parity(x)
193     mov     scratch, resCrcL
194     mov     resCrcL, resCrcH
195     eor     resCrcL, byte   ; low byte of if(parity(x)) value ^= 0xc001;
196     neg     byte
197     andi    byte, 0xc0
198     mov     resCrcH, byte   ; high byte of if(parity(x)) value ^= 0xc001;
199     clr     byte
200     lsr     scratch
201     ror     byte
202     eor     resCrcH, scratch
203     eor     resCrcL, byte
204     lsr     scratch
205     ror     byte
206     eor     resCrcH, scratch
207     eor     resCrcL, byte
208 usbCrc16LoopTest:
209     subi    argLen, 1
210     brsh    usbCrc16ByteLoop
211     com     resCrcL
212     com     resCrcH
213     ret
214
215 #else   /* USB_USE_FAST_CRC */
216
217 ; This implementation is slower, but has less code size
218 ;
219 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
220 ;   argPtr  r24+25 / r16+r17
221 ;   argLen  r22 / r18
222 ; temp variables:
223 ;   byte    r18 / r22
224 ;   bitCnt  r19
225 ;   poly    r20+r21
226 ;   scratch r23
227 ;   resCrc  r24+r25 / r16+r17
228 ;   ptr     X / Z
229 usbCrc16:
230     mov     ptrL, argPtrL
231     mov     ptrH, argPtrH
232     ldi     resCrcL, 0
233     ldi     resCrcH, 0
234     ldi     polyL, lo8(0xa001)
235     ldi     polyH, hi8(0xa001)
236     com     argLen      ; argLen = -argLen - 1: modified loop to ensure that carry is set
237     ldi     bitCnt, 0   ; loop counter with starnd condition = end condition
238     rjmp    usbCrcLoopEntry
239 usbCrcByteLoop:
240     ld      byte, ptr+
241     eor     resCrcL, byte
242 usbCrcBitLoop:
243     ror     resCrcH     ; carry is always set here (see brcs jumps to here)
244     ror     resCrcL
245     brcs    usbCrcNoXor
246     eor     resCrcL, polyL
247     eor     resCrcH, polyH
248 usbCrcNoXor:
249     subi    bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
250     brcs    usbCrcBitLoop
251 usbCrcLoopEntry:
252     subi    argLen, -1
253     brcs    usbCrcByteLoop
254 usbCrcReady:
255     ret
256 ; Thanks to Reimar Doeffinger for optimizing this CRC routine!
257
258 #endif /* USB_USE_FAST_CRC */
259
260 ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
261 usbCrc16Append:
262     rcall   usbCrc16
263     st      ptr+, resCrcL
264     st      ptr+, resCrcH
265     ret
266
267 #undef argLen
268 #undef argPtrL
269 #undef argPtrH
270 #undef resCrcL
271 #undef resCrcH
272 #undef ptrL
273 #undef ptrH
274 #undef ptr
275 #undef byte
276 #undef bitCnt
277 #undef polyL
278 #undef polyH
279 #undef scratch
280
281
282 #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
283 #ifdef __IAR_SYSTEMS_ASM__
284 /* Register assignments for usbMeasureFrameLength on IAR cc */
285 /* Calling conventions on IAR:
286  * First parameter passed in r16/r17, second in r18/r19 and so on.
287  * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
288  * Result is passed in r16/r17
289  * In case of the "tiny" memory model, pointers are only 8 bit with no
290  * padding. We therefore pass argument 1 as "16 bit unsigned".
291  */
292 #   define resL     r16
293 #   define resH     r17
294 #   define cnt16L   r30
295 #   define cnt16H   r31
296 #   define cntH     r18
297
298 #else  /* __IAR_SYSTEMS_ASM__ */ 
299 /* Register assignments for usbMeasureFrameLength on gcc */
300 /* Calling conventions on gcc:
301  * First parameter passed in r24/r25, second in r22/23 and so on.
302  * Callee must preserve r1-r17, r28/r29
303  * Result is passed in r24/r25
304  */
305 #   define resL     r24
306 #   define resH     r25
307 #   define cnt16L   r24
308 #   define cnt16H   r25
309 #   define cntH     r26
310 #endif
311 #   define cnt16    cnt16L
312
313 ; extern unsigned usbMeasurePacketLength(void);
314 ; returns time between two idle strobes in multiples of 7 CPU clocks
315 .global usbMeasureFrameLength
316 usbMeasureFrameLength:
317     ldi     cntH, 6         ; wait ~ 10 ms for D- == 0
318     clr     cnt16L
319     clr     cnt16H
320 usbMFTime16:
321     dec     cntH
322     breq    usbMFTimeout
323 usbMFWaitStrobe:            ; first wait for D- == 0 (idle strobe)
324     sbiw    cnt16, 1        ;[0] [6]
325     breq    usbMFTime16     ;[2]
326     sbic    USBIN, USBMINUS ;[3]
327     rjmp    usbMFWaitStrobe ;[4]
328 usbMFWaitIdle:              ; then wait until idle again
329     sbis    USBIN, USBMINUS ;1 wait for D- == 1
330     rjmp    usbMFWaitIdle   ;2
331     ldi     cnt16L, 1       ;1 represents cycles so far
332     clr     cnt16H          ;1
333 usbMFWaitLoop:
334     in      cntH, USBIN     ;[0] [7]
335     adiw    cnt16, 1        ;[1]
336     breq    usbMFTimeout    ;[3]
337     andi    cntH, USBMASK   ;[4]
338     brne    usbMFWaitLoop   ;[5]
339 usbMFTimeout:
340 #if resL != cnt16L
341     mov     resL, cnt16L
342     mov     resH, cnt16H
343 #endif
344     ret
345
346 #undef resL
347 #undef resH
348 #undef cnt16
349 #undef cnt16L
350 #undef cnt16H
351 #undef cntH
352
353 #endif  /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
354
355 ;----------------------------------------------------------------------------
356 ; Now include the clock rate specific code
357 ;----------------------------------------------------------------------------
358
359 #ifndef USB_CFG_CLOCK_KHZ
360 #   define USB_CFG_CLOCK_KHZ 12000
361 #endif
362
363 #if USB_CFG_CHECK_CRC   /* separate dispatcher for CRC type modules */
364 #   if USB_CFG_CLOCK_KHZ == 18000
365 #       include "usbdrvasm18-crc.inc"
366 #   else
367 #       error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!"
368 #   endif
369 #else   /* USB_CFG_CHECK_CRC */
370 #   if USB_CFG_CLOCK_KHZ == 12000
371 #       include "usbdrvasm12.inc"
372 #   elif USB_CFG_CLOCK_KHZ == 12800
373 #       include "usbdrvasm128.inc"
374 #   elif USB_CFG_CLOCK_KHZ == 15000
375 #       include "usbdrvasm15.inc"
376 #   elif USB_CFG_CLOCK_KHZ == 16000
377 #       include "usbdrvasm16.inc"
378 #   elif USB_CFG_CLOCK_KHZ == 16500
379 #       include "usbdrvasm165.inc"
380 #   elif USB_CFG_CLOCK_KHZ == 20000
381 #       include "usbdrvasm20.inc"
382 #   else
383 #       error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!"
384 #   endif
385 #endif /* USB_CFG_CHECK_CRC */