Subversion Repositories group.electronics

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
79 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
 */
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!
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
172
; temp variables:
173
;   byte    r18 / r22
174
;   scratch r23
175
;   resCrc  r24+r25 / r16+r17
176
;   ptr     X / Z
177
usbCrc16:
178
    mov     ptrL, argPtrL
179
    mov     ptrH, argPtrH
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
237
    ldi     polyL, lo8(0xa001)
238
    ldi     polyH, hi8(0xa001)
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:
243
    ld      byte, ptr+
244
    eor     resCrcL, byte
245
usbCrcBitLoop:
246
    ror     resCrcH     ; carry is always set here (see brcs jumps to here)
247
    ror     resCrcL
248
    brcs    usbCrcNoXor
249
    eor     resCrcL, polyL
250
    eor     resCrcH, polyH
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:
258
    ret
259
; Thanks to Reimar Doeffinger for optimizing this CRC routine!
260
 
261
#endif /* USB_USE_FAST_CRC */
262
 
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
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 */