1 /* Name: usbdrvasm12.inc
2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3 * Author: Christian Starkjohann
4 * Creation Date: 2004-12-29
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 12 MHz version of the asssembler part of the USB driver. It
17 requires a 12 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 Timing constraints according to spec (in bit times):
28 timing subject min max CPUcycles
29 ---------------------------------------------------------------------------
30 EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2 16 16-128
31 EOP of IN to sync pattern of DATA0 (rx, then tx) 2 7.5 16-60
32 DATAx (rx) to ACK/NAK/STALL (tx) 2 7.5 16-60
35 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
36 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
37 ;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable
38 ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes
39 ;Numbers in brackets are maximum cycles since SOF.
41 ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt
42 push YL ;2 [35] push only what is necessary to sync with edge ASAP
45 ;----------------------------------------------------------------------------
46 ; Synchronize with sync pattern:
47 ;----------------------------------------------------------------------------
48 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
49 ;sync up with J to K edge during sync pattern -- use fastest possible loops
50 ;The first part waits at most 1 bit long since we must be in sync pattern.
51 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
52 ;waitForJ, ensure that this prerequisite is met.
56 brne waitForJ ; just make sure we have ANY timeout
58 ;The following code results in a sampling window of 1/4 bit which meets the spec.
73 #endif /* USB_COUNT_SOF */
79 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
80 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
81 ;are cycles from center of first sync (double K) bit after the instruction
83 lds YL, usbInputBufOffset;2 [4]
85 subi YL, lo8(-(usbRxBuf));1 [6]
86 sbci YH, hi8(-(usbRxBuf));1 [7]
88 sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early]
89 rjmp haveTwoBitsK ;2 [10]
90 pop YH ;2 [11] undo the push from before
91 rjmp waitForK ;2 [13] this was not the end of sync, retry
93 ;----------------------------------------------------------------------------
94 ; push more registers and initialize values while we sample the first bits:
95 ;----------------------------------------------------------------------------
100 in x1, USBIN ;1 [17] <-- sample bit 0
101 ldi shift, 0xff ;1 [18]
102 bst x1, USBMINUS ;1 [19]
107 in x2, USBIN ;1 [25] <-- sample bit 1
108 ser x3 ;1 [26] [inserted init instruction]
110 bst x1, USBMINUS ;1 [28]
112 ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction]
115 ;----------------------------------------------------------------------------
116 ; Receiver loop (numbers in brackets are cycles within byte after instr)
117 ;----------------------------------------------------------------------------
119 unstuff0: ;1 (branch taken)
120 andi x3, ~0x01 ;1 [15]
121 mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit
122 in x2, USBIN ;1 [17] <-- sample bit 1 again
123 ori shift, 0x01 ;1 [18]
124 rjmp didUnstuff0 ;2 [20]
126 unstuff1: ;1 (branch taken)
127 mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit
128 andi x3, ~0x02 ;1 [22]
129 ori shift, 0x02 ;1 [23]
131 in x1, USBIN ;1 [25] <-- sample bit 2 again
132 rjmp didUnstuff1 ;2 [27]
134 unstuff2: ;1 (branch taken)
135 andi x3, ~0x04 ;1 [29]
136 ori shift, 0x04 ;1 [30]
137 mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit
139 in x2, USBIN ;1 [33] <-- sample bit 3
140 rjmp didUnstuff2 ;2 [35]
142 unstuff3: ;1 (branch taken)
143 in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late]
144 andi x3, ~0x08 ;1 [35]
145 ori shift, 0x08 ;1 [36]
146 rjmp didUnstuff3 ;2 [38]
148 unstuff4: ;1 (branch taken)
149 andi x3, ~0x10 ;1 [40]
150 in x1, USBIN ;1 [41] <-- sample stuffed bit 4
151 ori shift, 0x10 ;1 [42]
152 rjmp didUnstuff4 ;2 [44]
154 unstuff5: ;1 (branch taken)
155 andi x3, ~0x20 ;1 [48]
156 in x2, USBIN ;1 [49] <-- sample stuffed bit 5
157 ori shift, 0x20 ;1 [50]
158 rjmp didUnstuff5 ;2 [52]
160 unstuff6: ;1 (branch taken)
161 andi x3, ~0x40 ;1 [56]
162 in x1, USBIN ;1 [57] <-- sample stuffed bit 6
163 ori shift, 0x40 ;1 [58]
164 rjmp didUnstuff6 ;2 [60]
166 ; extra jobs done during bit interval:
167 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs]
169 ; bit 2: overflow check
170 ; bit 3: recovery from delay [bit 0 tasks took too long]
176 eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others
177 in x1, USBIN ;1 [1] <-- sample bit 0
178 st y+, x3 ;2 [3] store data
182 bst x2, USBMINUS;1 [7]
184 in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed)
185 andi x2, USBMASK ;1 [10]
186 breq se0 ;1 [11] SE0 check for bit 1
187 andi shift, 0xf9 ;1 [12]
189 breq unstuff0 ;1 [13]
191 bst x1, USBMINUS;1 [15]
194 in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed)
195 andi shift, 0xf3 ;1 [18]
196 breq unstuff1 ;1 [19] do remaining work for bit 1
199 brcs overflow ;1 [21] loop control
201 bst x2, USBMINUS;1 [23]
203 in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed)
204 andi shift, 0xe7 ;1 [26]
205 breq unstuff2 ;1 [27]
208 bst x1, USBMINUS;1 [29]
211 andi shift, 0xcf ;1 [31]
212 breq unstuff3 ;1 [32]
213 in x1, USBIN ;1 [33] <-- sample bit 4
215 bst x2, USBMINUS;1 [35]
218 andi shift, 0x9f ;1 [37]
219 breq unstuff4 ;1 [38]
221 in x2, USBIN ;1 [41] <-- sample bit 5
223 bst x1, USBMINUS;1 [43]
226 andi shift, 0x3f ;1 [45]
227 breq unstuff5 ;1 [46]
229 in x1, USBIN ;1 [49] <-- sample bit 6
231 bst x2, USBMINUS;1 [51]
234 cpi shift, 0x02 ;1 [53]
235 brlo unstuff6 ;1 [54]
237 in x2, USBIN ;1 [57] <-- sample bit 7
239 bst x1, USBMINUS;1 [59]
242 cpi shift, 0x04 ;1 [61]
243 brsh rxLoop ;2 [63] loop control
245 andi x3, ~0x80 ;1 [63]
246 ori shift, 0x80 ;1 [64]
247 in x2, USBIN ;1 [65] <-- sample stuffed bit 7
249 rjmp didUnstuff7 ;2 [68]
251 macro POP_STANDARD ; 12 cycles
259 macro POP_RETI ; 5 cycles
265 #include "asmcommon.inc"
267 ;----------------------------------------------------------------------------
269 ;----------------------------------------------------------------------------
274 ror shift ;[-5] [11] [59]
275 brcc doExorN1 ;[-4] [60]
278 lsl shift ;[-1] compensate ror after rjmp stuffDelay
279 nop ;[00] stuffing consists of just waiting 8 cycles
280 rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear
282 sendNakAndReti: ;0 [-19] 19 cycles until SOP
283 ldi x3, USBPID_NAK ;1 [-18]
284 rjmp usbSendX3 ;2 [-16]
285 sendAckAndReti: ;0 [-19] 19 cycles until SOP
286 ldi x3, USBPID_ACK ;1 [-18]
287 rjmp usbSendX3 ;2 [-16]
288 sendCntAndReti: ;0 [-17] 17 cycles until SOP
291 ldi YL, 20 ;1 [-15] 'x3' is R20
294 ; rjmp usbSendAndReti fallthrough
298 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
299 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
300 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
303 ;pointer to data in 'Y'
304 ;number of bytes in 'cnt' -- including sync byte
305 ;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt]
306 ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
308 in x2, USBDDR ;[-12] 12 cycles until SOP
309 ori x2, USBMASK ;[-11]
310 sbi USBOUT, USBMINUS ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
311 out USBDDR, x2 ;[-8] <--- acquire bus
312 in x1, USBOUT ;[-7] port mirror for tx loop
313 ldi shift, 0x40 ;[-6] sync byte is first byte sent (we enter loop after ror)
314 ldi x2, USBMASK ;[-5]
317 eor x1, x2 ;[-2] [06] [62]
318 ldi x4, 6 ;[-1] [07] [63]
321 out USBOUT, x1 ;[00] [08] [64] <--- set bit
326 lsl shift ;[05] compensate ror after rjmp stuffDelay
327 rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear
329 eor x1, x2 ;[04] [12]
333 subi cnt, 171 ;[07] [15] trick: (3 * 171) & 0xff = 1
334 out USBOUT, x1 ;[08] [16] <--- set bit
335 brcs txBitloop ;[09] [25] [41]
342 lsl shift ;[46] compensate ror after rjmp stuffDelay
343 nop ;[47] stuffing consists of just waiting 8 cycles
344 rjmp stuff6Delay ;[48] after ror, C bit is reliably clear
346 eor x1, x2 ;[45] [53]
351 out USBOUT, x1 ;[48] <--- set bit
355 lsl shift ;[52] compensate ror after rjmp stuffDelay
356 rjmp stuff7Delay ;[53] after ror, C bit is reliably clear
358 eor x1, x2 ;[51] [59]
363 out USBOUT, x1 ;[56] <--- set bit
364 brne txByteLoop ;[57]
367 cbr x1, USBMASK ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles]
368 lds x2, usbNewDeviceAddr;[59]
369 lsl x2 ;[61] we compare with left shifted address
370 subi YL, 2 + 20 ;[62] Only assign address on data packets, not ACK/NAK in x3
372 out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
373 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
374 ;set address only after data packet was sent, not after handshake
375 breq skipAddrAssign ;[01]
376 sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer
378 ;end of usbDeviceAddress transfer
379 ldi x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
380 USB_STORE_PENDING(x2) ;[04]
381 ori x1, USBIDLE ;[05]
383 cbr x2, USBMASK ;[07] set both pins to input
385 cbr x3, USBMASK ;[09] configure no pullup on both pins
389 out USBOUT, x1 ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
390 out USBDDR, x2 ;[17] <-- release bus now
391 out USBOUT, x3 ;[18] <-- ensure no pull-up resistors are active