Rev Author Line No. Line
3471 miho 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
5 * Tabsize: 4
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 $
9 */
10  
11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
12 * appropriate implementation!
13 */
14  
15 /*
16 General Description:
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
19 oscillator).
20  
21 See usbdrv.h for a description of the entire driver.
22  
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!
26  
27  
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
34 */
35  
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.
41 USB_INTR_VECTOR:
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
44 in YL, SREG ;1 [37]
45 push YL ;2 [39]
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.
54 waitForJ:
55 inc YL
56 sbis USBIN, USBMINUS
57 brne waitForJ ; just make sure we have ANY timeout
58 waitForK:
59 ;The following code results in a sampling window of 1/4 bit which meets the spec.
60 sbis USBIN, USBMINUS
61 rjmp foundK
62 sbis USBIN, USBMINUS
63 rjmp foundK
64 sbis USBIN, USBMINUS
65 rjmp foundK
66 sbis USBIN, USBMINUS
67 rjmp foundK
68 sbis USBIN, USBMINUS
69 rjmp foundK
70 #if USB_COUNT_SOF
71 lds YL, usbSofCount
72 inc YL
73 sts usbSofCount, YL
74 #endif /* USB_COUNT_SOF */
75 #ifdef USB_SOF_HOOK
76 USB_SOF_HOOK
77 #endif
78 rjmp sofError
79 foundK:
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
83 push YH ;2 [2]
84 lds YL, usbInputBufOffset;2 [4]
85 clr YH ;1 [5]
86 subi YL, lo8(-(usbRxBuf));1 [6]
87 sbci YH, hi8(-(usbRxBuf));1 [7]
88  
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
93 haveTwoBitsK:
94 ;----------------------------------------------------------------------------
95 ; push more registers and initialize values while we sample the first bits:
96 ;----------------------------------------------------------------------------
97 push shift ;2 [16]
98 push x1 ;2 [12]
99 push x2 ;2 [14]
100  
101 in x1, USBIN ;1 [17] <-- sample bit 0
102 ldi shift, 0xff ;1 [18]
103 bst x1, USBMINUS ;1 [19]
104 bld shift, 0 ;1 [20]
105 push x3 ;2 [22]
106 push cnt ;2 [24]
107  
108 in x2, USBIN ;1 [25] <-- sample bit 1
109 ser x3 ;1 [26] [inserted init instruction]
110 eor x1, x2 ;1 [27]
111 bst x1, USBMINUS ;1 [28]
112 bld shift, 1 ;1 [29]
113 ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction]
114 rjmp rxbit2 ;2 [32]
115  
116 ;----------------------------------------------------------------------------
117 ; Receiver loop (numbers in brackets are cycles within byte after instr)
118 ;----------------------------------------------------------------------------
119  
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]
126  
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]
131 nop ;1 [24]
132 in x1, USBIN ;1 [25] <-- sample bit 2 again
133 rjmp didUnstuff1 ;2 [27]
134  
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
139 nop ;1 [32]
140 in x2, USBIN ;1 [33] <-- sample bit 3
141 rjmp didUnstuff2 ;2 [35]
142  
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]
148  
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]
154  
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]
160  
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]
166  
167 ; extra jobs done during bit interval:
168 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs]
169 ; bit 1: se0 check
170 ; bit 2: overflow check
171 ; bit 3: recovery from delay [bit 0 tasks took too long]
172 ; bit 4: none
173 ; bit 5: none
174 ; bit 6: none
175 ; bit 7: jump, eor
176 rxLoop:
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
180 ser x3 ;1 [4]
181 nop ;1 [5]
182 eor x2, x1 ;1 [6]
183 bst x2, USBMINUS;1 [7]
184 bld shift, 0 ;1 [8]
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]
189 didUnstuff0:
190 breq unstuff0 ;1 [13]
191 eor x1, x2 ;1 [14]
192 bst x1, USBMINUS;1 [15]
193 bld shift, 1 ;1 [16]
194 rxbit2:
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
198 didUnstuff1:
199 subi cnt, 1 ;1 [20]
200 brcs overflow ;1 [21] loop control
201 eor x2, x1 ;1 [22]
202 bst x2, USBMINUS;1 [23]
203 bld shift, 2 ;1 [24]
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]
207 didUnstuff2:
208 eor x1, x2 ;1 [28]
209 bst x1, USBMINUS;1 [29]
210 bld shift, 3 ;1 [30]
211 didUnstuff3:
212 andi shift, 0xcf ;1 [31]
213 breq unstuff3 ;1 [32]
214 in x1, USBIN ;1 [33] <-- sample bit 4
215 eor x2, x1 ;1 [34]
216 bst x2, USBMINUS;1 [35]
217 bld shift, 4 ;1 [36]
218 didUnstuff4:
219 andi shift, 0x9f ;1 [37]
220 breq unstuff4 ;1 [38]
221 nop2 ;2 [40]
222 in x2, USBIN ;1 [41] <-- sample bit 5
223 eor x1, x2 ;1 [42]
224 bst x1, USBMINUS;1 [43]
225 bld shift, 5 ;1 [44]
226 didUnstuff5:
227 andi shift, 0x3f ;1 [45]
228 breq unstuff5 ;1 [46]
229 nop2 ;2 [48]
230 in x1, USBIN ;1 [49] <-- sample bit 6
231 eor x2, x1 ;1 [50]
232 bst x2, USBMINUS;1 [51]
233 bld shift, 6 ;1 [52]
234 didUnstuff6:
235 cpi shift, 0x02 ;1 [53]
236 brlo unstuff6 ;1 [54]
237 nop2 ;2 [56]
238 in x2, USBIN ;1 [57] <-- sample bit 7
239 eor x1, x2 ;1 [58]
240 bst x1, USBMINUS;1 [59]
241 bld shift, 7 ;1 [60]
242 didUnstuff7:
243 cpi shift, 0x04 ;1 [61]
244 brsh rxLoop ;2 [63] loop control
245 unstuff7:
246 andi x3, ~0x80 ;1 [63]
247 ori shift, 0x80 ;1 [64]
248 in x2, USBIN ;1 [65] <-- sample stuffed bit 7
249 nop ;1 [66]
250 rjmp didUnstuff7 ;2 [68]
251  
252 macro POP_STANDARD ; 12 cycles
253 pop cnt
254 pop x3
255 pop x2
256 pop x1
257 pop shift
258 pop YH
259 endm
260 macro POP_RETI ; 5 cycles
261 pop YL
262 out SREG, YL
263 pop YL
264 endm
265  
266 #include "asmcommon.inc"
267  
268 ;----------------------------------------------------------------------------
269 ; Transmitting data
270 ;----------------------------------------------------------------------------
271  
272 txByteLoop:
273 txBitloop:
274 stuffN1Delay: ; [03]
275 ror shift ;[-5] [11] [59]
276 brcc doExorN1 ;[-4] [60]
277 subi x4, 1 ;[-3]
278 brne commonN1 ;[-2]
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
282  
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
290 mov x3, cnt ;1 [-16]
291 usbSendX3: ;0 [-16]
292 ldi YL, 20 ;1 [-15] 'x3' is R20
293 ldi YH, 0 ;1 [-14]
294 ldi cnt, 2 ;1 [-13]
295 ; rjmp usbSendAndReti fallthrough
296  
297 ; USB spec says:
298 ; idle = J
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)
302  
303 ;usbSend:
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)
308 usbSendAndReti:
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]
316 push x4 ;[-4]
317 doExorN1:
318 eor x1, x2 ;[-2] [06] [62]
319 ldi x4, 6 ;[-1] [07] [63]
320 commonN1:
321 stuffN2Delay:
322 out USBOUT, x1 ;[00] [08] [64] <--- set bit
323 ror shift ;[01]
324 brcc doExorN2 ;[02]
325 subi x4, 1 ;[03]
326 brne commonN2 ;[04]
327 lsl shift ;[05] compensate ror after rjmp stuffDelay
328 rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear
329 doExorN2:
330 eor x1, x2 ;[04] [12]
331 ldi x4, 6 ;[05] [13]
332 commonN2:
333 nop ;[06] [14]
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]
337  
338 stuff6Delay:
339 ror shift ;[42] [50]
340 brcc doExor6 ;[43]
341 subi x4, 1 ;[44]
342 brne common6 ;[45]
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
346 doExor6:
347 eor x1, x2 ;[45] [53]
348 ldi x4, 6 ;[46]
349 common6:
350 stuff7Delay:
351 ror shift ;[47] [55]
352 out USBOUT, x1 ;[48] <--- set bit
353 brcc doExor7 ;[49]
354 subi x4, 1 ;[50]
355 brne common7 ;[51]
356 lsl shift ;[52] compensate ror after rjmp stuffDelay
357 rjmp stuff7Delay ;[53] after ror, C bit is reliably clear
358 doExor7:
359 eor x1, x2 ;[51] [59]
360 ldi x4, 6 ;[52]
361 common7:
362 ld shift, y+ ;[53]
363 tst cnt ;[55]
364 out USBOUT, x1 ;[56] <--- set bit
365 brne txByteLoop ;[57]
366  
367 ;make SE0:
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
372 sbci YH, 0 ;[63]
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
378 skipAddrAssign:
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]
383 in x2, USBDDR ;[06]
384 cbr x2, USBMASK ;[07] set both pins to input
385 mov x3, x1 ;[08]
386 cbr x3, USBMASK ;[09] configure no pullup on both pins
387 pop x4 ;[10]
388 nop2 ;[12]
389 nop2 ;[14]
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
393 rjmp doReturn