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