Subversion Repositories group.electronics

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7 pfowler 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$
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 */