usbdrv/asmcommon.inc

changeset 0
9e9b2c78bd31
equal deleted inserted replaced
-1:000000000000 0:9e9b2c78bd31
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

mercurial