Add support for ATmega168p CPU
[pub/USBasp.git] / 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 */
9
10 /*
11 General Description:
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.
15 */
16
17 #define __SFR_OFFSET 0 /* used by avr-libc's register definitions */
18 #include "usbportability.h"
19 #include "usbdrv.h" /* for common defs */
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
28 #define x5 r22
29 #define bitcnt x5
30 #define phase x4
31 #define leap x4
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
38 extern usbTxBuf, usbTxStatus1, usbTxStatus3
39 # if USB_COUNT_SOF
40 extern usbSofCount
41 # endif
42 public usbCrc16
43 public usbCrc16Append
44
45 COMMON INTVEC
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
54 RSEG CODE
55
56 #else /* __IAR_SYSTEMS_ASM__ */
57
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
65 .text
66 .global USB_INTR_VECTOR
67 .type USB_INTR_VECTOR, @function
68 .global usbCrc16
69 .global usbCrc16Append
70 #endif /* __IAR_SYSTEMS_ASM__ */
71
72
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
79 #endif
80
81 #define usbTxLen1 usbTxStatus1
82 #define usbTxBuf1 (usbTxStatus1 + 1)
83 #define usbTxLen3 usbTxStatus3
84 #define usbTxBuf3 (usbTxStatus3 + 1)
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
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 and to Shay Green for
149 ; even further optimizations!
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 movw ptrL, argPtrL
180 ldi resCrcL, 0xFF
181 ldi resCrcH, 0xFF
182 clr bitCnt ; zero reg
183 rjmp usbCrc16LoopTest
184 usbCrc16ByteLoop:
185 ld byte, ptr+
186 eor byte, resCrcL ; scratch is now 'x' in table()
187 mov scratch, byte ; compute parity of 'x'
188 swap byte
189 eor byte, scratch
190 mov resCrcL, byte
191 lsr byte
192 lsr byte
193 eor byte, resCrcL
194 inc byte
195 andi byte, 2 ; byte is now parity(x) << 1
196 cp bitCnt, byte ; c = (byte != 0), then put in high bit
197 ror scratch ; so that after xoring, shifting, and xoring, it gives
198 ror byte ; the desired 0xC0 with resCrcH
199 mov resCrcL, byte
200 eor resCrcL, resCrcH
201 mov resCrcH, scratch
202 lsr scratch
203 ror byte
204 eor resCrcH, scratch
205 eor resCrcL, byte
206 usbCrc16LoopTest:
207 subi argLen, 1
208 brsh usbCrc16ByteLoop
209 com resCrcL
210 com resCrcH
211 ret
212
213 #else /* USB_USE_FAST_CRC */
214
215 ; This implementation is slower, but has less code size
216 ;
217 ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
218 ; argPtr r24+25 / r16+r17
219 ; argLen r22 / r18
220 ; temp variables:
221 ; byte r18 / r22
222 ; bitCnt r19
223 ; poly r20+r21
224 ; scratch r23
225 ; resCrc r24+r25 / r16+r17
226 ; ptr X / Z
227 usbCrc16:
228 mov ptrL, argPtrL
229 mov ptrH, argPtrH
230 ldi resCrcL, 0
231 ldi resCrcH, 0
232 ldi polyL, lo8(0xa001)
233 ldi polyH, hi8(0xa001)
234 com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set
235 ldi bitCnt, 0 ; loop counter with starnd condition = end condition
236 rjmp usbCrcLoopEntry
237 usbCrcByteLoop:
238 ld byte, ptr+
239 eor resCrcL, byte
240 usbCrcBitLoop:
241 ror resCrcH ; carry is always set here (see brcs jumps to here)
242 ror resCrcL
243 brcs usbCrcNoXor
244 eor resCrcL, polyL
245 eor resCrcH, polyH
246 usbCrcNoXor:
247 subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
248 brcs usbCrcBitLoop
249 usbCrcLoopEntry:
250 subi argLen, -1
251 brcs usbCrcByteLoop
252 usbCrcReady:
253 ret
254 ; Thanks to Reimar Doeffinger for optimizing this CRC routine!
255
256 #endif /* USB_USE_FAST_CRC */
257
258 ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
259 usbCrc16Append:
260 rcall usbCrc16
261 st ptr+, resCrcL
262 st ptr+, resCrcH
263 ret
264
265 #undef argLen
266 #undef argPtrL
267 #undef argPtrH
268 #undef resCrcL
269 #undef resCrcH
270 #undef ptrL
271 #undef ptrH
272 #undef ptr
273 #undef byte
274 #undef bitCnt
275 #undef polyL
276 #undef polyH
277 #undef scratch
278
279
280 #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
281 #ifdef __IAR_SYSTEMS_ASM__
282 /* Register assignments for usbMeasureFrameLength on IAR cc */
283 /* Calling conventions on IAR:
284 * First parameter passed in r16/r17, second in r18/r19 and so on.
285 * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
286 * Result is passed in r16/r17
287 * In case of the "tiny" memory model, pointers are only 8 bit with no
288 * padding. We therefore pass argument 1 as "16 bit unsigned".
289 */
290 # define resL r16
291 # define resH r17
292 # define cnt16L r30
293 # define cnt16H r31
294 # define cntH r18
295
296 #else /* __IAR_SYSTEMS_ASM__ */
297 /* Register assignments for usbMeasureFrameLength on gcc */
298 /* Calling conventions on gcc:
299 * First parameter passed in r24/r25, second in r22/23 and so on.
300 * Callee must preserve r1-r17, r28/r29
301 * Result is passed in r24/r25
302 */
303 # define resL r24
304 # define resH r25
305 # define cnt16L r24
306 # define cnt16H r25
307 # define cntH r26
308 #endif
309 # define cnt16 cnt16L
310
311 ; extern unsigned usbMeasurePacketLength(void);
312 ; returns time between two idle strobes in multiples of 7 CPU clocks
313 .global usbMeasureFrameLength
314 usbMeasureFrameLength:
315 ldi cntH, 6 ; wait ~ 10 ms for D- == 0
316 clr cnt16L
317 clr cnt16H
318 usbMFTime16:
319 dec cntH
320 breq usbMFTimeout
321 usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe)
322 sbiw cnt16, 1 ;[0] [6]
323 breq usbMFTime16 ;[2]
324 sbic USBIN, USBMINUS ;[3]
325 rjmp usbMFWaitStrobe ;[4]
326 usbMFWaitIdle: ; then wait until idle again
327 sbis USBIN, USBMINUS ;1 wait for D- == 1
328 rjmp usbMFWaitIdle ;2
329 ldi cnt16L, 1 ;1 represents cycles so far
330 clr cnt16H ;1
331 usbMFWaitLoop:
332 in cntH, USBIN ;[0] [7]
333 adiw cnt16, 1 ;[1]
334 breq usbMFTimeout ;[3]
335 andi cntH, USBMASK ;[4]
336 brne usbMFWaitLoop ;[5]
337 usbMFTimeout:
338 #if resL != cnt16L
339 mov resL, cnt16L
340 mov resH, cnt16H
341 #endif
342 ret
343
344 #undef resL
345 #undef resH
346 #undef cnt16
347 #undef cnt16L
348 #undef cnt16H
349 #undef cntH
350
351 #endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
352
353 ;----------------------------------------------------------------------------
354 ; Now include the clock rate specific code
355 ;----------------------------------------------------------------------------
356
357 #ifndef USB_CFG_CLOCK_KHZ
358 # ifdef F_CPU
359 # define USB_CFG_CLOCK_KHZ (F_CPU/1000)
360 # else
361 # error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!"
362 # endif
363 #endif
364
365 #if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */
366 # if USB_CFG_CLOCK_KHZ == 18000
367 # include "usbdrvasm18-crc.inc"
368 # else
369 # error "USB_CFG_CLOCK_KHZ is not one of the supported rates for USB_CFG_CHECK_CRC!"
370 # endif
371 #else /* USB_CFG_CHECK_CRC */
372 # if USB_CFG_CLOCK_KHZ == 12000
373 # include "usbdrvasm12.inc"
374 # elif USB_CFG_CLOCK_KHZ == 12800
375 # include "usbdrvasm128.inc"
376 # elif USB_CFG_CLOCK_KHZ == 15000
377 # include "usbdrvasm15.inc"
378 # elif USB_CFG_CLOCK_KHZ == 16000
379 # include "usbdrvasm16.inc"
380 # elif USB_CFG_CLOCK_KHZ == 16500
381 # include "usbdrvasm165.inc"
382 # elif USB_CFG_CLOCK_KHZ == 18000
383 # include "usbdrvasm18.inc"
384 # elif USB_CFG_CLOCK_KHZ == 20000
385 # include "usbdrvasm20.inc"
386 # else
387 # error "USB_CFG_CLOCK_KHZ is not one of the supported rates!"
388 # endif
389 #endif /* USB_CFG_CHECK_CRC */