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)
8 * Revision: $Id: usbdrvasm15.inc 740 2009-04-13 18:23:31Z cs $
11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
12 * appropriate implementation!
17 This file is the 15 MHz version of the asssembler part of the USB driver. It
18 requires a 15 MHz crystal (not a ceramic resonator and not a calibrated RC
21 See usbdrv.h for a description of the entire driver.
23 Since almost all of this code is timing critical, don't change unless you
24 really know what you are doing! Many parts require not only a maximum number
25 of CPU cycles, but even an exact number of cycles!
28 ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
29 ;nominal frequency: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte
30 ; Numbers in brackets are clocks counted from center of last sync bit
31 ; when instruction starts
33 ;----------------------------------------------------------------------------
34 ; order of registers pushed:
35 ; YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4
36 ;----------------------------------------------------------------------------
38 push YL ;2 push only what is necessary to sync with edge ASAP
41 ;----------------------------------------------------------------------------
42 ; Synchronize with sync pattern:
44 ; sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
45 ; sync up with J to K edge during sync pattern -- use fastest possible loops
46 ;The first part waits at most 1 bit long since we must be in sync pattern.
47 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
48 ;waitForJ, ensure that this prerequisite is met.
52 brne waitForJ ; just make sure we have ANY timeout
53 ;-------------------------------------------------------------------------------
54 ; The following code results in a sampling window of < 1/4 bit
55 ; which meets the spec.
56 ;-------------------------------------------------------------------------------
58 sbis USBIN, USBMINUS ;1 [00] <-- sample
60 sbis USBIN, USBMINUS ; <-- sample
62 sbis USBIN, USBMINUS ; <-- sample
64 sbis USBIN, USBMINUS ; <-- sample
66 sbis USBIN, USBMINUS ; <-- sample
68 sbis USBIN, USBMINUS ; <-- sample
74 #endif /* USB_COUNT_SOF */
79 ;------------------------------------------------------------------------------
80 ; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for
82 ; we have 1 bit time for setup purposes, then sample again.
83 ; Numbers in brackets are cycles from center of first sync (double K)
84 ; bit after the instruction
85 ;------------------------------------------------------------------------------
87 lds YL, usbInputBufOffset;2 [03+04] tx loop
90 subi YL, lo8(-(usbRxBuf)) ;1 [08] [rx loop init]
91 sbci YH, hi8(-(usbRxBuf)) ;1 [09] [rx loop init]
94 sbis USBIN, USBMINUS ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early)
95 rjmp haveTwoBitsK ;2 [00] [14]
96 pop shift ;2 [15+16] undo the push from before
97 pop YH ;2 [17+18] undo the push from before
98 rjmp waitForK ;2 [19+20] this was not the end of sync, retry
99 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
100 ; bit times (= 20 cycles).
102 ;----------------------------------------------------------------------------
103 ; push more registers and initialize values while we sample the first bits:
104 ;----------------------------------------------------------------------------
105 haveTwoBitsK: ;- [01]
109 push bitcnt ;2 [08+09]
110 in x1, USBIN ;1 [00] [10] <-- sample bit 0
111 bst x1, USBMINUS ;1 [01]
114 ldi cnt, USB_BUFSIZE ;1 [05]
115 push x4 ;2 [06+07] tx loop
117 ;----------------------------------------------------------------------------
118 ; Receiver loop (numbers in brackets are cycles within byte after instr)
119 ;----------------------------------------------------------------------------
120 unstuff0: ;- [07] (branch taken)
121 andi x3, ~0x01 ;1 [08]
122 mov x1, x2 ;1 [09] x2 contains last sampled (stuffed) bit
123 in x2, USBIN ;1 [00] [10] <-- sample bit 1 again
124 andi x2, USBMASK ;1 [01]
125 breq se0Hop ;1 [02] SE0 check for bit 1
126 ori shift, 0x01 ;1 [03] 0b00000001
128 rjmp didUnstuff0 ;2 [05]
129 ;-----------------------------------------------------
130 unstuff1: ;- [05] (branch taken)
131 mov x2, x1 ;1 [06] x1 contains last sampled (stuffed) bit
132 andi x3, ~0x02 ;1 [07]
133 ori shift, 0x02 ;1 [08] 0b00000010
135 in x1, USBIN ;1 [00] [10] <-- sample bit 2 again
136 andi x1, USBMASK ;1 [01]
137 breq se0Hop ;1 [02] SE0 check for bit 2
138 rjmp didUnstuff1 ;2 [03]
139 ;-----------------------------------------------------
140 unstuff2: ;- [05] (branch taken)
141 andi x3, ~0x04 ;1 [06]
142 ori shift, 0x04 ;1 [07] 0b00000100
143 mov x1, x2 ;1 [08] x2 contains last sampled (stuffed) bit
145 in x2, USBIN ;1 [00] [10] <-- sample bit 3
146 andi x2, USBMASK ;1 [01]
147 breq se0Hop ;1 [02] SE0 check for bit 3
148 rjmp didUnstuff2 ;2 [03]
149 ;-----------------------------------------------------
150 unstuff3: ;- [00] [10] (branch taken)
151 in x2, USBIN ;1 [01] [11] <-- sample stuffed bit 3 one cycle too late
152 andi x2, USBMASK ;1 [02]
153 breq se0Hop ;1 [03] SE0 check for stuffed bit 3
154 andi x3, ~0x08 ;1 [04]
155 ori shift, 0x08 ;1 [05] 0b00001000
156 rjmp didUnstuff3 ;2 [06]
157 ;----------------------------------------------------------------------------
158 ; extra jobs done during bit interval:
160 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs],
161 ; overflow check, jump to the head of rxLoop
163 ; bit 2: SE0 check, recovery from delay [bit 0 tasks took too long]
164 ; bit 3: SE0 check, recovery from delay [bit 0 tasks took too long]
165 ; bit 4: SE0 check, none
166 ; bit 5: SE0 check, none
167 ; bit 6: SE0 check, none
168 ; bit 7: SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others
169 ;----------------------------------------------------------------------------
171 in x2, USBIN ;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed)
172 andi x2, USBMASK ;1 [01]
173 brne SkipSe0Hop ;1 [02]
175 rjmp se0 ;2 [03] SE0 check for bit 1
178 andi shift, 0xf9 ;1 [05] 0b11111001
179 breq unstuff0 ;1 [06]
182 bst x1, USBMINUS ;1 [08]
184 in x1, USBIN ;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed)
185 andi x1, USBMASK ;1 [01]
186 breq se0Hop ;1 [02] SE0 check for bit 2
187 andi shift, 0xf3 ;1 [03] 0b11110011
188 breq unstuff1 ;1 [04] do remaining work for bit 1
191 bst x2, USBMINUS ;1 [06]
194 in x2, USBIN ;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed)
195 andi x2, USBMASK ;1 [01]
196 breq se0Hop ;1 [02] SE0 check for bit 3
197 andi shift, 0xe7 ;1 [03] 0b11100111
198 breq unstuff2 ;1 [04]
201 bst x1, USBMINUS ;1 [06]
204 andi shift, 0xcf ;1 [08] 0b11001111
205 breq unstuff3 ;1 [09]
206 in x1, USBIN ;1 [00] [10] <-- sample bit 4
207 andi x1, USBMASK ;1 [01]
208 breq se0Hop ;1 [02] SE0 check for bit 4
210 bst x2, USBMINUS ;1 [04]
213 andi shift, 0x9f ;1 [06] 0b10011111
214 breq unstuff4 ;1 [07]
216 in x2, USBIN ;1 [00] [10] <-- sample bit 5
217 andi x2, USBMASK ;1 [01]
218 breq se0 ;1 [02] SE0 check for bit 5
220 bst x1, USBMINUS ;1 [04]
223 andi shift, 0x3f ;1 [06] 0b00111111
224 breq unstuff5 ;1 [07]
226 in x1, USBIN ;1 [00] [10] <-- sample bit 6
227 andi x1, USBMASK ;1 [01]
228 breq se0 ;1 [02] SE0 check for bit 6
230 bst x2, USBMINUS ;1 [04]
233 cpi shift, 0x02 ;1 [06] 0b00000010
234 brlo unstuff6 ;1 [07]
236 in x2, USBIN ;1 [00] [10] <-- sample bit 7
237 andi x2, USBMASK ;1 [01]
238 breq se0 ;1 [02] SE0 check for bit 7
240 bst x1, USBMINUS ;1 [04]
243 cpi shift, 0x04 ;1 [06] 0b00000100
244 brlo unstuff7 ;1 [07]
245 eor x3, shift ;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others
247 in x1, USBIN ;1 [00] [10] <-- sample bit 0
248 st y+, x3 ;2 [01+02] store data
250 bst x2, USBMINUS ;1 [04]
253 brcs overflow ;1 [07]
255 ;-----------------------------------------------------
257 andi x3, ~0x10 ;1 [09]
258 in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 4
259 andi x1, USBMASK ;1 [01]
260 breq se0 ;1 [02] SE0 check for stuffed bit 4
261 ori shift, 0x10 ;1 [03]
262 rjmp didUnstuff4 ;2 [04]
263 ;-----------------------------------------------------
265 ori shift, 0x20 ;1 [09]
266 in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 5
267 andi x2, USBMASK ;1 [01]
268 breq se0 ;1 [02] SE0 check for stuffed bit 5
269 andi x3, ~0x20 ;1 [03]
270 rjmp didUnstuff5 ;2 [04]
271 ;-----------------------------------------------------
273 andi x3, ~0x40 ;1 [09]
274 in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 6
275 andi x1, USBMASK ;1 [01]
276 breq se0 ;1 [02] SE0 check for stuffed bit 6
277 ori shift, 0x40 ;1 [03]
278 rjmp didUnstuff6 ;2 [04]
279 ;-----------------------------------------------------
281 andi x3, ~0x80 ;1 [09]
282 in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 7
283 andi x2, USBMASK ;1 [01]
284 breq se0 ;1 [02] SE0 check for stuffed bit 7
285 ori shift, 0x80 ;1 [03]
286 rjmp didUnstuff7 ;2 [04]
288 macro POP_STANDARD ; 16 cycles
298 macro POP_RETI ; 5 cycles
304 #include "asmcommon.inc"
306 ;---------------------------------------------------------------------------
309 ; J = (D+ = 0), (D- = 1)
310 ; K = (D+ = 1), (D- = 0)
311 ; Spec allows 7.5 bit times from EOP to SOP for replies
312 ;---------------------------------------------------------------------------
317 rjmp didStuffN ;1 [08]
318 ;---------------------------------------------------------------------------
322 rjmp didStuff6 ;1 [07]
323 ;---------------------------------------------------------------------------
328 rjmp didStuff7 ;1 [06]
329 ;---------------------------------------------------------------------------
330 sendNakAndReti: ;- [-19]
331 ldi x3, USBPID_NAK ;1 [-18]
332 rjmp sendX3AndReti ;1 [-17]
333 ;---------------------------------------------------------------------------
334 sendAckAndReti: ;- [-17]
335 ldi cnt, USBPID_ACK ;1 [-16]
336 sendCntAndReti: ;- [-16]
338 sendX3AndReti: ;- [-15]
339 ldi YL, 20 ;1 [-14] x3==r20 address is 20
342 ; rjmp usbSendAndReti fallthrough
343 ;---------------------------------------------------------------------------
345 ;pointer to data in 'Y'
346 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
347 ;uses: x1...x4, btcnt, shift, cnt, Y
348 ;Numbers in brackets are time since first bit of sync pattern is sent
349 ;We need not to match the transfer rate exactly because the spec demands
350 ;only 1.5% precision anyway.
351 usbSendAndReti: ;- [-13] 13 cycles until SOP
352 in x2, USBDDR ;1 [-12]
353 ori x2, USBMASK ;1 [-11]
354 sbi USBOUT, USBMINUS ;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups)
355 in x1, USBOUT ;1 [-08] port mirror for tx loop
356 out USBDDR, x2 ;1 [-07] <- acquire bus
357 ; need not init x2 (bitstuff history) because sync starts with 0
358 ldi x4, USBMASK ;1 [-06] exor mask
359 ldi shift, 0x80 ;1 [-05] sync byte is first byte sent
360 ldi bitcnt, 6 ;1 [-04]
361 txBitLoop: ;- [-04] [06]
362 sbrs shift, 0 ;1 [-03] [07]
363 eor x1, x4 ;1 [-02] [08]
364 ror shift ;1 [-01] [09]
366 out USBOUT, x1 ;1 [00] [10] <-- out N
369 brcc bitstuffN ;1 [03]
371 brne txBitLoop ;1 [05]
372 sbrs shift, 0 ;1 [06]
377 out USBOUT, x1 ;1 [00] [10] <-- out 6
380 brcc bitstuff6 ;1 [03]
381 sbrs shift, 0 ;1 [04]
386 ldi bitcnt, 6 ;1 [08]
388 out USBOUT, x1 ;1 [00] [10] <-- out 7
389 brcc bitstuff7 ;1 [01]
390 ld shift, y+ ;2 [02+03]
392 brne txBitLoop ;1 [05]
394 cbr x1, USBMASK ;1 [06] prepare SE0 [spec says EOP may be 19 to 23 cycles]
395 lds x2, usbNewDeviceAddr;2 [07+08]
396 lsl x2 ;1 [09] we compare with left shifted address
397 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
398 ;set address only after data packet was sent, not after handshake
399 out USBOUT, x1 ;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle
400 subi YL, 20 + 2 ;1 [01] Only assign address on data packets, not ACK/NAK in x3
402 breq skipAddrAssign ;1 [03]
403 sts usbDeviceAddr, x2 ;2 [04+05] if not skipped: SE0 is one cycle longer
404 ;----------------------------------------------------------------------------
405 ;end of usbDeviceAddress transfer
406 skipAddrAssign: ;- [03/04]
407 ldi x2, 1<<USB_INTR_PENDING_BIT ;1 [05] int0 occurred during TX -- clear pending flag
408 USB_STORE_PENDING(x2) ;1 [06]
409 ori x1, USBIDLE ;1 [07]
410 in x2, USBDDR ;1 [08]
411 cbr x2, USBMASK ;1 [09] set both pins to input
413 cbr x3, USBMASK ;1 [11] configure no pullup on both pins
415 se0Delay: ;- [12] [15]
417 brne se0Delay ;1 [14] [17]
419 out USBOUT, x1 ;1 [20] <--out J (idle) -- end of SE0 (EOP sig.)
420 out USBDDR, x2 ;1 [21] <--release bus now
421 out USBOUT, x3 ;1 [22] <--ensure no pull-up resistors are active
422 rjmp doReturn ;1 [23]
423 ;---------------------------------------------------------------------------