1 /* Name: usbdrvasm15.inc
2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3 * Author: contributed by V. Bosch
4 * Creation Date: 2007-08-06
6 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
10 /* Do not link this file! Link usbdrvasm.S instead, which includes the
11 * appropriate implementation!
16 This file is the 15 MHz version of the asssembler part of the USB driver. It
17 requires a 15 MHz crystal (not a ceramic resonator and not a calibrated RC
20 See usbdrv.h for a description of the entire driver.
22 Since almost all of this code is timing critical, don't change unless you
23 really know what you are doing! Many parts require not only a maximum number
24 of CPU cycles, but even an exact number of cycles!
27 ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
28 ;nominal frequency: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte
29 ; Numbers in brackets are clocks counted from center of last sync bit
30 ; when instruction starts
32 ;----------------------------------------------------------------------------
33 ; order of registers pushed:
34 ; YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4
35 ;----------------------------------------------------------------------------
37 push YL ;2 push only what is necessary to sync with edge ASAP
40 ;----------------------------------------------------------------------------
41 ; Synchronize with sync pattern:
43 ; sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
44 ; sync up with J to K edge during sync pattern -- use fastest possible loops
45 ;The first part waits at most 1 bit long since we must be in sync pattern.
46 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
47 ;waitForJ, ensure that this prerequisite is met.
51 brne waitForJ ; just make sure we have ANY timeout
52 ;-------------------------------------------------------------------------------
53 ; The following code results in a sampling window of < 1/4 bit
54 ; which meets the spec.
55 ;-------------------------------------------------------------------------------
57 sbis USBIN, USBMINUS ;1 [00] <-- sample
59 sbis USBIN, USBMINUS ; <-- sample
61 sbis USBIN, USBMINUS ; <-- sample
63 sbis USBIN, USBMINUS ; <-- sample
65 sbis USBIN, USBMINUS ; <-- sample
67 sbis USBIN, USBMINUS ; <-- sample
73 #endif /* USB_COUNT_SOF */
78 ;------------------------------------------------------------------------------
79 ; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for
81 ; we have 1 bit time for setup purposes, then sample again.
82 ; Numbers in brackets are cycles from center of first sync (double K)
83 ; bit after the instruction
84 ;------------------------------------------------------------------------------
86 lds YL, usbInputBufOffset;2 [03+04] tx loop
89 subi YL, lo8(-(usbRxBuf)) ;1 [08] [rx loop init]
90 sbci YH, hi8(-(usbRxBuf)) ;1 [09] [rx loop init]
93 sbis USBIN, USBMINUS ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early)
94 rjmp haveTwoBitsK ;2 [00] [14]
95 pop shift ;2 [15+16] undo the push from before
96 pop YH ;2 [17+18] undo the push from before
97 rjmp waitForK ;2 [19+20] this was not the end of sync, retry
98 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
99 ; bit times (= 20 cycles).
101 ;----------------------------------------------------------------------------
102 ; push more registers and initialize values while we sample the first bits:
103 ;----------------------------------------------------------------------------
104 haveTwoBitsK: ;- [01]
108 push bitcnt ;2 [08+09]
109 in x1, USBIN ;1 [00] [10] <-- sample bit 0
110 bst x1, USBMINUS ;1 [01]
113 ldi cnt, USB_BUFSIZE ;1 [05]
114 push x4 ;2 [06+07] tx loop
116 ;----------------------------------------------------------------------------
117 ; Receiver loop (numbers in brackets are cycles within byte after instr)
118 ;----------------------------------------------------------------------------
119 unstuff0: ;- [07] (branch taken)
120 andi x3, ~0x01 ;1 [08]
121 mov x1, x2 ;1 [09] x2 contains last sampled (stuffed) bit
122 in x2, USBIN ;1 [00] [10] <-- sample bit 1 again
123 andi x2, USBMASK ;1 [01]
124 breq se0Hop ;1 [02] SE0 check for bit 1
125 ori shift, 0x01 ;1 [03] 0b00000001
127 rjmp didUnstuff0 ;2 [05]
128 ;-----------------------------------------------------
129 unstuff1: ;- [05] (branch taken)
130 mov x2, x1 ;1 [06] x1 contains last sampled (stuffed) bit
131 andi x3, ~0x02 ;1 [07]
132 ori shift, 0x02 ;1 [08] 0b00000010
134 in x1, USBIN ;1 [00] [10] <-- sample bit 2 again
135 andi x1, USBMASK ;1 [01]
136 breq se0Hop ;1 [02] SE0 check for bit 2
137 rjmp didUnstuff1 ;2 [03]
138 ;-----------------------------------------------------
139 unstuff2: ;- [05] (branch taken)
140 andi x3, ~0x04 ;1 [06]
141 ori shift, 0x04 ;1 [07] 0b00000100
142 mov x1, x2 ;1 [08] x2 contains last sampled (stuffed) bit
144 in x2, USBIN ;1 [00] [10] <-- sample bit 3
145 andi x2, USBMASK ;1 [01]
146 breq se0Hop ;1 [02] SE0 check for bit 3
147 rjmp didUnstuff2 ;2 [03]
148 ;-----------------------------------------------------
149 unstuff3: ;- [00] [10] (branch taken)
150 in x2, USBIN ;1 [01] [11] <-- sample stuffed bit 3 one cycle too late
151 andi x2, USBMASK ;1 [02]
152 breq se0Hop ;1 [03] SE0 check for stuffed bit 3
153 andi x3, ~0x08 ;1 [04]
154 ori shift, 0x08 ;1 [05] 0b00001000
155 rjmp didUnstuff3 ;2 [06]
156 ;----------------------------------------------------------------------------
157 ; extra jobs done during bit interval:
159 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs],
160 ; overflow check, jump to the head of rxLoop
162 ; bit 2: SE0 check, recovery from delay [bit 0 tasks took too long]
163 ; bit 3: SE0 check, recovery from delay [bit 0 tasks took too long]
164 ; bit 4: SE0 check, none
165 ; bit 5: SE0 check, none
166 ; bit 6: SE0 check, none
167 ; bit 7: SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others
168 ;----------------------------------------------------------------------------
170 in x2, USBIN ;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed)
171 andi x2, USBMASK ;1 [01]
172 brne SkipSe0Hop ;1 [02]
174 rjmp se0 ;2 [03] SE0 check for bit 1
177 andi shift, 0xf9 ;1 [05] 0b11111001
178 breq unstuff0 ;1 [06]
181 bst x1, USBMINUS ;1 [08]
183 in x1, USBIN ;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed)
184 andi x1, USBMASK ;1 [01]
185 breq se0Hop ;1 [02] SE0 check for bit 2
186 andi shift, 0xf3 ;1 [03] 0b11110011
187 breq unstuff1 ;1 [04] do remaining work for bit 1
190 bst x2, USBMINUS ;1 [06]
193 in x2, USBIN ;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed)
194 andi x2, USBMASK ;1 [01]
195 breq se0Hop ;1 [02] SE0 check for bit 3
196 andi shift, 0xe7 ;1 [03] 0b11100111
197 breq unstuff2 ;1 [04]
200 bst x1, USBMINUS ;1 [06]
203 andi shift, 0xcf ;1 [08] 0b11001111
204 breq unstuff3 ;1 [09]
205 in x1, USBIN ;1 [00] [10] <-- sample bit 4
206 andi x1, USBMASK ;1 [01]
207 breq se0Hop ;1 [02] SE0 check for bit 4
209 bst x2, USBMINUS ;1 [04]
212 andi shift, 0x9f ;1 [06] 0b10011111
213 breq unstuff4 ;1 [07]
215 in x2, USBIN ;1 [00] [10] <-- sample bit 5
216 andi x2, USBMASK ;1 [01]
217 breq se0 ;1 [02] SE0 check for bit 5
219 bst x1, USBMINUS ;1 [04]
222 andi shift, 0x3f ;1 [06] 0b00111111
223 breq unstuff5 ;1 [07]
225 in x1, USBIN ;1 [00] [10] <-- sample bit 6
226 andi x1, USBMASK ;1 [01]
227 breq se0 ;1 [02] SE0 check for bit 6
229 bst x2, USBMINUS ;1 [04]
232 cpi shift, 0x02 ;1 [06] 0b00000010
233 brlo unstuff6 ;1 [07]
235 in x2, USBIN ;1 [00] [10] <-- sample bit 7
236 andi x2, USBMASK ;1 [01]
237 breq se0 ;1 [02] SE0 check for bit 7
239 bst x1, USBMINUS ;1 [04]
242 cpi shift, 0x04 ;1 [06] 0b00000100
243 brlo unstuff7 ;1 [07]
244 eor x3, shift ;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others
246 in x1, USBIN ;1 [00] [10] <-- sample bit 0
247 st y+, x3 ;2 [01+02] store data
249 bst x2, USBMINUS ;1 [04]
252 brcs overflow ;1 [07]
254 ;-----------------------------------------------------
256 andi x3, ~0x10 ;1 [09]
257 in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 4
258 andi x1, USBMASK ;1 [01]
259 breq se0 ;1 [02] SE0 check for stuffed bit 4
260 ori shift, 0x10 ;1 [03]
261 rjmp didUnstuff4 ;2 [04]
262 ;-----------------------------------------------------
264 ori shift, 0x20 ;1 [09]
265 in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 5
266 andi x2, USBMASK ;1 [01]
267 breq se0 ;1 [02] SE0 check for stuffed bit 5
268 andi x3, ~0x20 ;1 [03]
269 rjmp didUnstuff5 ;2 [04]
270 ;-----------------------------------------------------
272 andi x3, ~0x40 ;1 [09]
273 in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 6
274 andi x1, USBMASK ;1 [01]
275 breq se0 ;1 [02] SE0 check for stuffed bit 6
276 ori shift, 0x40 ;1 [03]
277 rjmp didUnstuff6 ;2 [04]
278 ;-----------------------------------------------------
280 andi x3, ~0x80 ;1 [09]
281 in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 7
282 andi x2, USBMASK ;1 [01]
283 breq se0 ;1 [02] SE0 check for stuffed bit 7
284 ori shift, 0x80 ;1 [03]
285 rjmp didUnstuff7 ;2 [04]
287 macro POP_STANDARD ; 16 cycles
297 macro POP_RETI ; 5 cycles
303 #include "asmcommon.inc"
305 ;---------------------------------------------------------------------------
308 ; J = (D+ = 0), (D- = 1)
309 ; K = (D+ = 1), (D- = 0)
310 ; Spec allows 7.5 bit times from EOP to SOP for replies
311 ;---------------------------------------------------------------------------
316 rjmp didStuffN ;1 [08]
317 ;---------------------------------------------------------------------------
321 rjmp didStuff6 ;1 [07]
322 ;---------------------------------------------------------------------------
327 rjmp didStuff7 ;1 [06]
328 ;---------------------------------------------------------------------------
329 sendNakAndReti: ;- [-19]
330 ldi x3, USBPID_NAK ;1 [-18]
331 rjmp sendX3AndReti ;1 [-17]
332 ;---------------------------------------------------------------------------
333 sendAckAndReti: ;- [-17]
334 ldi cnt, USBPID_ACK ;1 [-16]
335 sendCntAndReti: ;- [-16]
337 sendX3AndReti: ;- [-15]
338 ldi YL, 20 ;1 [-14] x3==r20 address is 20
341 ; rjmp usbSendAndReti fallthrough
342 ;---------------------------------------------------------------------------
344 ;pointer to data in 'Y'
345 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
346 ;uses: x1...x4, btcnt, shift, cnt, Y
347 ;Numbers in brackets are time since first bit of sync pattern is sent
348 ;We need not to match the transfer rate exactly because the spec demands
349 ;only 1.5% precision anyway.
350 usbSendAndReti: ;- [-13] 13 cycles until SOP
351 in x2, USBDDR ;1 [-12]
352 ori x2, USBMASK ;1 [-11]
353 sbi USBOUT, USBMINUS ;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups)
354 in x1, USBOUT ;1 [-08] port mirror for tx loop
355 out USBDDR, x2 ;1 [-07] <- acquire bus
356 ; need not init x2 (bitstuff history) because sync starts with 0
357 ldi x4, USBMASK ;1 [-06] exor mask
358 ldi shift, 0x80 ;1 [-05] sync byte is first byte sent
359 ldi bitcnt, 6 ;1 [-04]
360 txBitLoop: ;- [-04] [06]
361 sbrs shift, 0 ;1 [-03] [07]
362 eor x1, x4 ;1 [-02] [08]
363 ror shift ;1 [-01] [09]
365 out USBOUT, x1 ;1 [00] [10] <-- out N
368 brcc bitstuffN ;1 [03]
370 brne txBitLoop ;1 [05]
371 sbrs shift, 0 ;1 [06]
376 out USBOUT, x1 ;1 [00] [10] <-- out 6
379 brcc bitstuff6 ;1 [03]
380 sbrs shift, 0 ;1 [04]
385 ldi bitcnt, 6 ;1 [08]
387 out USBOUT, x1 ;1 [00] [10] <-- out 7
388 brcc bitstuff7 ;1 [01]
389 ld shift, y+ ;2 [02+03]
391 brne txBitLoop ;1 [05]
393 cbr x1, USBMASK ;1 [06] prepare SE0 [spec says EOP may be 19 to 23 cycles]
394 lds x2, usbNewDeviceAddr;2 [07+08]
395 lsl x2 ;1 [09] we compare with left shifted address
396 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
397 ;set address only after data packet was sent, not after handshake
398 out USBOUT, x1 ;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle
399 subi YL, 20 + 2 ;1 [01] Only assign address on data packets, not ACK/NAK in x3
401 breq skipAddrAssign ;1 [03]
402 sts usbDeviceAddr, x2 ;2 [04+05] if not skipped: SE0 is one cycle longer
403 ;----------------------------------------------------------------------------
404 ;end of usbDeviceAddress transfer
405 skipAddrAssign: ;- [03/04]
406 ldi x2, 1<<USB_INTR_PENDING_BIT ;1 [05] int0 occurred during TX -- clear pending flag
407 USB_STORE_PENDING(x2) ;1 [06]
408 ori x1, USBIDLE ;1 [07]
409 in x2, USBDDR ;1 [08]
410 cbr x2, USBMASK ;1 [09] set both pins to input
412 cbr x3, USBMASK ;1 [11] configure no pullup on both pins
414 se0Delay: ;- [12] [15]
416 brne se0Delay ;1 [14] [17]
418 out USBOUT, x1 ;1 [20] <--out J (idle) -- end of SE0 (EOP sig.)
419 out USBDDR, x2 ;1 [21] <--release bus now
420 out USBOUT, x3 ;1 [22] <--ensure no pull-up resistors are active
421 rjmp doReturn ;1 [23]
422 ;---------------------------------------------------------------------------