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)
8 * This Revision: $Id: usbdrvasm12.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 12 MHz version of the asssembler part of the USB driver. It
18 requires a 12 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 Timing constraints according to spec (in bit times):
29 timing subject min max CPUcycles
30 ---------------------------------------------------------------------------
31 EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2 16 16-128
32 EOP of IN to sync pattern of DATA0 (rx, then tx) 2 7.5 16-60
33 DATAx (rx) to ACK/NAK/STALL (tx) 2 7.5 16-60
36 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
37 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
38 ;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable
39 ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes
40 ;Numbers in brackets are maximum cycles since SOF.
42 ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt
43 push YL ;2 [35] push only what is necessary to sync with edge ASAP
46 ;----------------------------------------------------------------------------
47 ; Synchronize with sync pattern:
48 ;----------------------------------------------------------------------------
49 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
50 ;sync up with J to K edge during sync pattern -- use fastest possible loops
51 ;The first part waits at most 1 bit long since we must be in sync pattern.
52 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
53 ;waitForJ, ensure that this prerequisite is met.
57 brne waitForJ ; just make sure we have ANY timeout
59 ;The following code results in a sampling window of 1/4 bit which meets the spec.
74 #endif /* USB_COUNT_SOF */
80 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
81 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
82 ;are cycles from center of first sync (double K) bit after the instruction
84 lds YL, usbInputBufOffset;2 [4]
86 subi YL, lo8(-(usbRxBuf));1 [6]
87 sbci YH, hi8(-(usbRxBuf));1 [7]
89 sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early]
90 rjmp haveTwoBitsK ;2 [10]
91 pop YH ;2 [11] undo the push from before
92 rjmp waitForK ;2 [13] this was not the end of sync, retry
94 ;----------------------------------------------------------------------------
95 ; push more registers and initialize values while we sample the first bits:
96 ;----------------------------------------------------------------------------
101 in x1, USBIN ;1 [17] <-- sample bit 0
102 ldi shift, 0xff ;1 [18]
103 bst x1, USBMINUS ;1 [19]
108 in x2, USBIN ;1 [25] <-- sample bit 1
109 ser x3 ;1 [26] [inserted init instruction]
111 bst x1, USBMINUS ;1 [28]
113 ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction]
116 ;----------------------------------------------------------------------------
117 ; Receiver loop (numbers in brackets are cycles within byte after instr)
118 ;----------------------------------------------------------------------------
120 unstuff0: ;1 (branch taken)
121 andi x3, ~0x01 ;1 [15]
122 mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit
123 in x2, USBIN ;1 [17] <-- sample bit 1 again
124 ori shift, 0x01 ;1 [18]
125 rjmp didUnstuff0 ;2 [20]
127 unstuff1: ;1 (branch taken)
128 mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit
129 andi x3, ~0x02 ;1 [22]
130 ori shift, 0x02 ;1 [23]
132 in x1, USBIN ;1 [25] <-- sample bit 2 again
133 rjmp didUnstuff1 ;2 [27]
135 unstuff2: ;1 (branch taken)
136 andi x3, ~0x04 ;1 [29]
137 ori shift, 0x04 ;1 [30]
138 mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit
140 in x2, USBIN ;1 [33] <-- sample bit 3
141 rjmp didUnstuff2 ;2 [35]
143 unstuff3: ;1 (branch taken)
144 in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late]
145 andi x3, ~0x08 ;1 [35]
146 ori shift, 0x08 ;1 [36]
147 rjmp didUnstuff3 ;2 [38]
149 unstuff4: ;1 (branch taken)
150 andi x3, ~0x10 ;1 [40]
151 in x1, USBIN ;1 [41] <-- sample stuffed bit 4
152 ori shift, 0x10 ;1 [42]
153 rjmp didUnstuff4 ;2 [44]
155 unstuff5: ;1 (branch taken)
156 andi x3, ~0x20 ;1 [48]
157 in x2, USBIN ;1 [49] <-- sample stuffed bit 5
158 ori shift, 0x20 ;1 [50]
159 rjmp didUnstuff5 ;2 [52]
161 unstuff6: ;1 (branch taken)
162 andi x3, ~0x40 ;1 [56]
163 in x1, USBIN ;1 [57] <-- sample stuffed bit 6
164 ori shift, 0x40 ;1 [58]
165 rjmp didUnstuff6 ;2 [60]
167 ; extra jobs done during bit interval:
168 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs]
170 ; bit 2: overflow check
171 ; bit 3: recovery from delay [bit 0 tasks took too long]
177 eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others
178 in x1, USBIN ;1 [1] <-- sample bit 0
179 st y+, x3 ;2 [3] store data
183 bst x2, USBMINUS;1 [7]
185 in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed)
186 andi x2, USBMASK ;1 [10]
187 breq se0 ;1 [11] SE0 check for bit 1
188 andi shift, 0xf9 ;1 [12]
190 breq unstuff0 ;1 [13]
192 bst x1, USBMINUS;1 [15]
195 in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed)
196 andi shift, 0xf3 ;1 [18]
197 breq unstuff1 ;1 [19] do remaining work for bit 1
200 brcs overflow ;1 [21] loop control
202 bst x2, USBMINUS;1 [23]
204 in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed)
205 andi shift, 0xe7 ;1 [26]
206 breq unstuff2 ;1 [27]
209 bst x1, USBMINUS;1 [29]
212 andi shift, 0xcf ;1 [31]
213 breq unstuff3 ;1 [32]
214 in x1, USBIN ;1 [33] <-- sample bit 4
216 bst x2, USBMINUS;1 [35]
219 andi shift, 0x9f ;1 [37]
220 breq unstuff4 ;1 [38]
222 in x2, USBIN ;1 [41] <-- sample bit 5
224 bst x1, USBMINUS;1 [43]
227 andi shift, 0x3f ;1 [45]
228 breq unstuff5 ;1 [46]
230 in x1, USBIN ;1 [49] <-- sample bit 6
232 bst x2, USBMINUS;1 [51]
235 cpi shift, 0x02 ;1 [53]
236 brlo unstuff6 ;1 [54]
238 in x2, USBIN ;1 [57] <-- sample bit 7
240 bst x1, USBMINUS;1 [59]
243 cpi shift, 0x04 ;1 [61]
244 brsh rxLoop ;2 [63] loop control
246 andi x3, ~0x80 ;1 [63]
247 ori shift, 0x80 ;1 [64]
248 in x2, USBIN ;1 [65] <-- sample stuffed bit 7
250 rjmp didUnstuff7 ;2 [68]
252 macro POP_STANDARD ; 12 cycles
260 macro POP_RETI ; 5 cycles
266 #include "asmcommon.inc"
268 ;----------------------------------------------------------------------------
270 ;----------------------------------------------------------------------------
275 ror shift ;[-5] [11] [59]
276 brcc doExorN1 ;[-4] [60]
279 lsl shift ;[-1] compensate ror after rjmp stuffDelay
280 nop ;[00] stuffing consists of just waiting 8 cycles
281 rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear
283 sendNakAndReti: ;0 [-19] 19 cycles until SOP
284 ldi x3, USBPID_NAK ;1 [-18]
285 rjmp usbSendX3 ;2 [-16]
286 sendAckAndReti: ;0 [-19] 19 cycles until SOP
287 ldi x3, USBPID_ACK ;1 [-18]
288 rjmp usbSendX3 ;2 [-16]
289 sendCntAndReti: ;0 [-17] 17 cycles until SOP
292 ldi YL, 20 ;1 [-15] 'x3' is R20
295 ; rjmp usbSendAndReti fallthrough
299 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
300 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
301 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
304 ;pointer to data in 'Y'
305 ;number of bytes in 'cnt' -- including sync byte
306 ;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt]
307 ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
309 in x2, USBDDR ;[-12] 12 cycles until SOP
310 ori x2, USBMASK ;[-11]
311 sbi USBOUT, USBMINUS ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
312 out USBDDR, x2 ;[-8] <--- acquire bus
313 in x1, USBOUT ;[-7] port mirror for tx loop
314 ldi shift, 0x40 ;[-6] sync byte is first byte sent (we enter loop after ror)
315 ldi x2, USBMASK ;[-5]
318 eor x1, x2 ;[-2] [06] [62]
319 ldi x4, 6 ;[-1] [07] [63]
322 out USBOUT, x1 ;[00] [08] [64] <--- set bit
327 lsl shift ;[05] compensate ror after rjmp stuffDelay
328 rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear
330 eor x1, x2 ;[04] [12]
334 subi cnt, 171 ;[07] [15] trick: (3 * 171) & 0xff = 1
335 out USBOUT, x1 ;[08] [16] <--- set bit
336 brcs txBitloop ;[09] [25] [41]
343 lsl shift ;[46] compensate ror after rjmp stuffDelay
344 nop ;[47] stuffing consists of just waiting 8 cycles
345 rjmp stuff6Delay ;[48] after ror, C bit is reliably clear
347 eor x1, x2 ;[45] [53]
352 out USBOUT, x1 ;[48] <--- set bit
356 lsl shift ;[52] compensate ror after rjmp stuffDelay
357 rjmp stuff7Delay ;[53] after ror, C bit is reliably clear
359 eor x1, x2 ;[51] [59]
364 out USBOUT, x1 ;[56] <--- set bit
365 brne txByteLoop ;[57]
368 cbr x1, USBMASK ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles]
369 lds x2, usbNewDeviceAddr;[59]
370 lsl x2 ;[61] we compare with left shifted address
371 subi YL, 2 + 20 ;[62] Only assign address on data packets, not ACK/NAK in x3
373 out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
374 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
375 ;set address only after data packet was sent, not after handshake
376 breq skipAddrAssign ;[01]
377 sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer
379 ;end of usbDeviceAddress transfer
380 ldi x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
381 USB_STORE_PENDING(x2) ;[04]
382 ori x1, USBIDLE ;[05]
384 cbr x2, USBMASK ;[07] set both pins to input
386 cbr x3, USBMASK ;[09] configure no pullup on both pins
390 out USBOUT, x1 ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
391 out USBDDR, x2 ;[17] <-- release bus now
392 out USBOUT, x3 ;[18] <-- ensure no pull-up resistors are active