usbdrv/usbdrvasm12.inc

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

mercurial