Rev Author Line No. Line
3471 miho 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 */