Subversion Repositories group.electronics

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
122 pfowler 1
/* Name: asmcommon.inc
2
 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3
 * Author: Christian Starkjohann
4
 * Creation Date: 2007-11-05
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
/* Do not link this file! Link usbdrvasm.S instead, which includes the
11
 * appropriate implementation!
12
 */
13
 
14
/*
15
General Description:
16
This file contains assembler code which is shared among the USB driver
17
implementations for different CPU cocks. Since the code must be inserted
18
in the middle of the module, it's split out into this file and #included.
19
 
20
Jump destinations called from outside:
21
    sofError: Called when no start sequence was found.
22
    se0: Called when a package has been successfully received.
23
    overflow: Called when receive buffer overflows.
24
    doReturn: Called after sending data.
25
 
26
Outside jump destinations used by this module:
27
    waitForJ: Called to receive an already arriving packet.
28
    sendAckAndReti:
29
    sendNakAndReti:
30
    sendCntAndReti:
31
    usbSendAndReti:
32
 
33
The following macros must be defined before this file is included:
34
    .macro POP_STANDARD
35
    .endm
36
    .macro POP_RETI
37
    .endm
38
*/
39
 
40
#define token   x1
41
 
42
overflow:
43
    ldi     x2, 1<<USB_INTR_PENDING_BIT
44
    USB_STORE_PENDING(x2)       ; clear any pending interrupts
45
ignorePacket:
46
    clr     token
47
    rjmp    storeTokenAndReturn
48
 
49
;----------------------------------------------------------------------------
50
; Processing of received packet (numbers in brackets are cycles after center of SE0)
51
;----------------------------------------------------------------------------
52
;This is the only non-error exit point for the software receiver loop
53
;we don't check any CRCs here because there is no time left.
54
se0:
55
    subi    cnt, USB_BUFSIZE    ;[5]
56
    neg     cnt                 ;[6]
57
    sub     YL, cnt             ;[7]
58
    sbci    YH, 0               ;[8]
59
    ldi     x2, 1<<USB_INTR_PENDING_BIT ;[9]
60
    USB_STORE_PENDING(x2)       ;[10] clear pending intr and check flag later. SE0 should be over.
61
    ld      token, y            ;[11]
62
    cpi     token, USBPID_DATA0 ;[13]
63
    breq    handleData          ;[14]
64
    cpi     token, USBPID_DATA1 ;[15]
65
    breq    handleData          ;[16]
66
    lds     shift, usbDeviceAddr;[17]
67
    ldd     x2, y+1             ;[19] ADDR and 1 bit endpoint number
68
    lsl     x2                  ;[21] shift out 1 bit endpoint number
69
    cpse    x2, shift           ;[22]
70
    rjmp    ignorePacket        ;[23]
71
/* only compute endpoint number in x3 if required later */
72
#if USB_CFG_HAVE_INTRIN_ENDPOINT || USB_CFG_IMPLEMENT_FN_WRITEOUT
73
    ldd     x3, y+2             ;[24] endpoint number + crc
74
    rol     x3                  ;[26] shift in LSB of endpoint
75
#endif
76
    cpi     token, USBPID_IN    ;[27]
77
    breq    handleIn            ;[28]
78
    cpi     token, USBPID_SETUP ;[29]
79
    breq    handleSetupOrOut    ;[30]
80
    cpi     token, USBPID_OUT   ;[31]
81
    brne    ignorePacket        ;[32] must be ack, nak or whatever
82
;   rjmp    handleSetupOrOut    ; fallthrough
83
 
84
;Setup and Out are followed by a data packet two bit times (16 cycles) after
85
;the end of SE0. The sync code allows up to 40 cycles delay from the start of
86
;the sync pattern until the first bit is sampled. That's a total of 56 cycles.
87
handleSetupOrOut:               ;[32]
88
#if USB_CFG_IMPLEMENT_FN_WRITEOUT   /* if we have data for endpoint != 0, set usbCurrentTok to address */
89
    andi    x3, 0xf             ;[32]
90
    breq    storeTokenAndReturn ;[33]
91
    mov     token, x3           ;[34] indicate that this is endpoint x OUT
92
#endif
93
storeTokenAndReturn:
94
    sts     usbCurrentTok, token;[35]
95
doReturn:
96
    POP_STANDARD                ;[37] 12...16 cycles
97
    USB_LOAD_PENDING(YL)        ;[49]
98
    sbrc    YL, USB_INTR_PENDING_BIT;[50] check whether data is already arriving
99
    rjmp    waitForJ            ;[51] save the pops and pushes -- a new interrupt is already pending
100
sofError:
101
    POP_RETI                    ;macro call
102
    reti
103
 
104
handleData:
105
#if USB_CFG_CHECK_CRC
106
    CRC_CLEANUP_AND_CHECK       ; jumps to ignorePacket if CRC error
107
#endif
108
    lds     shift, usbCurrentTok;[18]
109
    tst     shift               ;[20]
110
    breq    doReturn            ;[21]
111
    lds     x2, usbRxLen        ;[22]
112
    tst     x2                  ;[24]
113
    brne    sendNakAndReti      ;[25]
114
; 2006-03-11: The following two lines fix a problem where the device was not
115
; recognized if usbPoll() was called less frequently than once every 4 ms.
116
    cpi     cnt, 4              ;[26] zero sized data packets are status phase only -- ignore and ack
117
    brmi    sendAckAndReti      ;[27] keep rx buffer clean -- we must not NAK next SETUP
118
#if USB_CFG_CHECK_DATA_TOGGLING
119
    sts     usbCurrentDataToken, token  ; store for checking by C code
120
#endif
121
    sts     usbRxLen, cnt       ;[28] store received data, swap buffers
122
    sts     usbRxToken, shift   ;[30]
123
    lds     x2, usbInputBufOffset;[32] swap buffers
124
    ldi     cnt, USB_BUFSIZE    ;[34]
125
    sub     cnt, x2             ;[35]
126
    sts     usbInputBufOffset, cnt;[36] buffers now swapped
127
    rjmp    sendAckAndReti      ;[38] 40 + 17 = 57 until SOP
128
 
129
handleIn:
130
;We don't send any data as long as the C code has not processed the current
131
;input data and potentially updated the output data. That's more efficient
132
;in terms of code size than clearing the tx buffers when a packet is received.
133
    lds     x1, usbRxLen        ;[30]
134
    cpi     x1, 1               ;[32] negative values are flow control, 0 means "buffer free"
135
    brge    sendNakAndReti      ;[33] unprocessed input packet?
136
    ldi     x1, USBPID_NAK      ;[34] prepare value for usbTxLen
137
#if USB_CFG_HAVE_INTRIN_ENDPOINT
138
    andi    x3, 0xf             ;[35] x3 contains endpoint
139
#if USB_CFG_SUPPRESS_INTR_CODE
140
    brne    sendNakAndReti      ;[36]
141
#else
142
    brne    handleIn1           ;[36]
143
#endif
144
#endif
145
    lds     cnt, usbTxLen       ;[37]
146
    sbrc    cnt, 4              ;[39] all handshake tokens have bit 4 set
147
    rjmp    sendCntAndReti      ;[40] 42 + 16 = 58 until SOP
148
    sts     usbTxLen, x1        ;[41] x1 == USBPID_NAK from above
149
    ldi     YL, lo8(usbTxBuf)   ;[43]
150
    ldi     YH, hi8(usbTxBuf)   ;[44]
151
    rjmp    usbSendAndReti      ;[45] 57 + 12 = 59 until SOP
152
 
153
; Comment about when to set usbTxLen to USBPID_NAK:
154
; We should set it back when we receive the ACK from the host. This would
155
; be simple to implement: One static variable which stores whether the last
156
; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
157
; ACK. However, we set it back immediately when we send the package,
158
; assuming that no error occurs and the host sends an ACK. We save one byte
159
; RAM this way and avoid potential problems with endless retries. The rest of
160
; the driver assumes error-free transfers anyway.
161
 
162
#if !USB_CFG_SUPPRESS_INTR_CODE && USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
163
handleIn1:                      ;[38]
164
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
165
; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
166
    cpi     x3, USB_CFG_EP3_NUMBER;[38]
167
    breq    handleIn3           ;[39]
168
#endif
169
    lds     cnt, usbTxLen1      ;[40]
170
    sbrc    cnt, 4              ;[42] all handshake tokens have bit 4 set
171
    rjmp    sendCntAndReti      ;[43] 47 + 16 = 63 until SOP
172
    sts     usbTxLen1, x1       ;[44] x1 == USBPID_NAK from above
173
    ldi     YL, lo8(usbTxBuf1)  ;[46]
174
    ldi     YH, hi8(usbTxBuf1)  ;[47]
175
    rjmp    usbSendAndReti      ;[48] 50 + 12 = 62 until SOP
176
 
177
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
178
handleIn3:
179
    lds     cnt, usbTxLen3      ;[41]
180
    sbrc    cnt, 4              ;[43]
181
    rjmp    sendCntAndReti      ;[44] 49 + 16 = 65 until SOP
182
    sts     usbTxLen3, x1       ;[45] x1 == USBPID_NAK from above
183
    ldi     YL, lo8(usbTxBuf3)  ;[47]
184
    ldi     YH, hi8(usbTxBuf3)  ;[48]
185
    rjmp    usbSendAndReti      ;[49] 51 + 12 = 63 until SOP
186
#endif
187
#endif