]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/vusb/usbdrv/usbdrvasm.S
Add support for Atmega32A to pin declarations and universal matrix (#4015)
[qmk_firmware.git] / tmk_core / protocol / vusb / 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: usbdrvasm.S 785 2010-05-30 17:57:07Z cs $
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 #       ifdef INT0_vect
61 #           define USB_INTR_VECTOR  INT0_vect       // this is the "new" define for the vector
62 #       else
63 #           define USB_INTR_VECTOR  SIG_INTERRUPT0  // this is the "old" vector
64 #       endif
65 #   endif
66     .text
67     .global USB_INTR_VECTOR
68     .type   USB_INTR_VECTOR, @function
69     .global usbCrc16
70     .global usbCrc16Append
71 #endif /* __IAR_SYSTEMS_ASM__ */
72
73
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
80 #endif
81
82 #define usbTxLen1   usbTxStatus1
83 #define usbTxBuf1   (usbTxStatus1 + 1)
84 #define usbTxLen3   usbTxStatus3
85 #define usbTxBuf3   (usbTxStatus3 + 1)
86
87
88 ;----------------------------------------------------------------------------
89 ; Utility functions
90 ;----------------------------------------------------------------------------
91
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".
100  */
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
104  */
105 #   define argLen   r18 /* argument 2 */
106 #   define argPtrL  r16 /* argument 1 */
107 #   define argPtrH  r17 /* argument 1 */
108
109 #   define resCrcL  r16 /* result */
110 #   define resCrcH  r17 /* result */
111
112 #   define ptrL     ZL
113 #   define ptrH     ZH
114 #   define ptr      Z
115 #   define byte     r22
116 #   define bitCnt   r19
117 #   define polyL    r20
118 #   define polyH    r21
119 #   define scratch  r23
120
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
127  */
128 #   define argLen   r22 /* argument 2 */
129 #   define argPtrL  r24 /* argument 1 */
130 #   define argPtrH  r25 /* argument 1 */
131
132 #   define resCrcL  r24 /* result */
133 #   define resCrcH  r25 /* result */
134
135 #   define ptrL     XL
136 #   define ptrH     XH
137 #   define ptr      x
138 #   define byte     r18
139 #   define bitCnt   r19
140 #   define polyL    r20
141 #   define polyH    r21
142 #   define scratch  r23
143
144 #endif
145
146 #if USB_USE_FAST_CRC
147
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)
152 ; {
153 ; unsigned    value;
154 ;
155 ;     value = (unsigned)x << 6;
156 ;     value ^= (unsigned)x << 7;
157 ;     if(parity(x))
158 ;         value ^= 0xc001;
159 ;     return value;
160 ; }
161 ; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen)
162 ; {
163 ; unsigned crc = 0xffff;
164 ;
165 ;     while(argLen--)
166 ;         crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc);
167 ;     return ~crc;
168 ; }
169
170 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
171 ;   argPtr  r24+25 / r16+r17
172 ;   argLen  r22 / r18
173 ; temp variables:
174 ;   byte    r18 / r22
175 ;   scratch r23
176 ;   resCrc  r24+r25 / r16+r17
177 ;   ptr     X / Z
178 usbCrc16:
179     mov     ptrL, argPtrL
180     mov     ptrH, argPtrH
181     ldi     resCrcL, 0xFF
182     ldi     resCrcH, 0xFF
183     rjmp    usbCrc16LoopTest
184 usbCrc16ByteLoop:
185     ld      byte, ptr+
186     eor     resCrcL, byte   ; resCrcL is now 'x' in table()
187     mov     byte, resCrcL   ; compute parity of 'x'
188     swap    byte
189     eor     byte, resCrcL
190     mov     scratch, byte
191     lsr     byte
192     lsr     byte
193     eor     byte, scratch
194     inc     byte
195     lsr     byte
196     andi    byte, 1         ; byte is now parity(x)
197     mov     scratch, resCrcL
198     mov     resCrcL, resCrcH
199     eor     resCrcL, byte   ; low byte of if(parity(x)) value ^= 0xc001;
200     neg     byte
201     andi    byte, 0xc0
202     mov     resCrcH, byte   ; high byte of if(parity(x)) value ^= 0xc001;
203     clr     byte
204     lsr     scratch
205     ror     byte
206     eor     resCrcH, scratch
207     eor     resCrcL, byte
208     lsr     scratch
209     ror     byte
210     eor     resCrcH, scratch
211     eor     resCrcL, byte
212 usbCrc16LoopTest:
213     subi    argLen, 1
214     brsh    usbCrc16ByteLoop
215     com     resCrcL
216     com     resCrcH
217     ret
218
219 #else   /* USB_USE_FAST_CRC */
220
221 ; This implementation is slower, but has less code size
222 ;
223 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
224 ;   argPtr  r24+25 / r16+r17
225 ;   argLen  r22 / r18
226 ; temp variables:
227 ;   byte    r18 / r22
228 ;   bitCnt  r19
229 ;   poly    r20+r21
230 ;   scratch r23
231 ;   resCrc  r24+r25 / r16+r17
232 ;   ptr     X / Z
233 usbCrc16:
234     mov     ptrL, argPtrL
235     mov     ptrH, argPtrH
236     ldi     resCrcL, 0
237     ldi     resCrcH, 0
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
242     rjmp    usbCrcLoopEntry
243 usbCrcByteLoop:
244     ld      byte, ptr+
245     eor     resCrcL, byte
246 usbCrcBitLoop:
247     ror     resCrcH     ; carry is always set here (see brcs jumps to here)
248     ror     resCrcL
249     brcs    usbCrcNoXor
250     eor     resCrcL, polyL
251     eor     resCrcH, polyH
252 usbCrcNoXor:
253     subi    bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
254     brcs    usbCrcBitLoop
255 usbCrcLoopEntry:
256     subi    argLen, -1
257     brcs    usbCrcByteLoop
258 usbCrcReady:
259     ret
260 ; Thanks to Reimar Doeffinger for optimizing this CRC routine!
261
262 #endif /* USB_USE_FAST_CRC */
263
264 ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
265 usbCrc16Append:
266     rcall   usbCrc16
267     st      ptr+, resCrcL
268     st      ptr+, resCrcH
269     ret
270
271 #undef argLen
272 #undef argPtrL
273 #undef argPtrH
274 #undef resCrcL
275 #undef resCrcH
276 #undef ptrL
277 #undef ptrH
278 #undef ptr
279 #undef byte
280 #undef bitCnt
281 #undef polyL
282 #undef polyH
283 #undef scratch
284
285
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".
295  */
296 #   define resL     r16
297 #   define resH     r17
298 #   define cnt16L   r30
299 #   define cnt16H   r31
300 #   define cntH     r18
301
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
308  */
309 #   define resL     r24
310 #   define resH     r25
311 #   define cnt16L   r24
312 #   define cnt16H   r25
313 #   define cntH     r26
314 #endif
315 #   define cnt16    cnt16L
316
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
322     clr     cnt16L
323     clr     cnt16H
324 usbMFTime16:
325     dec     cntH
326     breq    usbMFTimeout
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
336     clr     cnt16H          ;1
337 usbMFWaitLoop:
338     in      cntH, USBIN     ;[0] [7]
339     adiw    cnt16, 1        ;[1]
340     breq    usbMFTimeout    ;[3]
341     andi    cntH, USBMASK   ;[4]
342     brne    usbMFWaitLoop   ;[5]
343 usbMFTimeout:
344 #if resL != cnt16L
345     mov     resL, cnt16L
346     mov     resH, cnt16H
347 #endif
348     ret
349
350 #undef resL
351 #undef resH
352 #undef cnt16
353 #undef cnt16L
354 #undef cnt16H
355 #undef cntH
356
357 #endif  /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
358
359 ;----------------------------------------------------------------------------
360 ; Now include the clock rate specific code
361 ;----------------------------------------------------------------------------
362
363 #ifndef USB_CFG_CLOCK_KHZ
364 #   ifdef F_CPU
365 #       define USB_CFG_CLOCK_KHZ (F_CPU/1000)
366 #   else
367 #       error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!"
368 #   endif
369 #endif
370
371 #if USB_CFG_CHECK_CRC   /* separate dispatcher for CRC type modules */
372 #   if USB_CFG_CLOCK_KHZ == 18000
373 #       include "usbdrvasm18-crc.inc"
374 #   else
375 #       error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!"
376 #   endif
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"
390 #   else
391 #       error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!"
392 #   endif
393 #endif /* USB_CFG_CHECK_CRC */