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