]> git.zerfleddert.de Git - fnordlicht-mini/blob - firmware/fnordlicht-controller/usbdrv/usbdrvasm.S
reference firmware
[fnordlicht-mini] / firmware / fnordlicht-controller / 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 761 2009-08-12 16:30:23Z 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 # 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 */
Impressum, Datenschutz