usbdrv/usbdrvasm165.inc

changeset 0
9e9b2c78bd31
equal deleted inserted replaced
-1:000000000000 0:9e9b2c78bd31
1 /* Name: usbdrvasm165.inc
2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3 * Author: Christian Starkjohann
4 * Creation Date: 2007-04-22
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 16.5 MHz version of the USB driver. It is intended for the
17 ATTiny45 and similar controllers running on 16.5 MHz internal RC oscillator.
18 This version contains a phase locked loop in the receiver routine to cope with
19 slight clock rate deviations of up to +/- 1%.
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 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
29 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
30 ;max allowable interrupt latency: 59 cycles -> max 52 cycles interrupt disable
31 ;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes
32 ;nominal frequency: 16.5 MHz -> 11 cycles per bit
33 ; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%)
34 ; Numbers in brackets are clocks counted from center of last sync bit
35 ; when instruction starts
36
37
38 USB_INTR_VECTOR:
39 ;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt
40 push YL ;[-23] push only what is necessary to sync with edge ASAP
41 in YL, SREG ;[-21]
42 push YL ;[-20]
43 ;----------------------------------------------------------------------------
44 ; Synchronize with sync pattern:
45 ;----------------------------------------------------------------------------
46 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
47 ;sync up with J to K edge during sync pattern -- use fastest possible loops
48 ;The first part waits at most 1 bit long since we must be in sync pattern.
49 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
50 ;waitForJ, ensure that this prerequisite is met.
51 waitForJ:
52 inc YL
53 sbis USBIN, USBMINUS
54 brne waitForJ ; just make sure we have ANY timeout
55 waitForK:
56 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
57 sbis USBIN, USBMINUS ;[-15]
58 rjmp foundK ;[-14]
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: ;[-12]
79 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 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 r0 ;[-12]
83 ; [---] ;[-11]
84 push YH ;[-10]
85 ; [---] ;[-9]
86 lds YL, usbInputBufOffset;[-8]
87 ; [---] ;[-7]
88 clr YH ;[-6]
89 subi YL, lo8(-(usbRxBuf));[-5] [rx loop init]
90 sbci YH, hi8(-(usbRxBuf));[-4] [rx loop init]
91 mov r0, x2 ;[-3] [rx loop init]
92 sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early)
93 rjmp haveTwoBitsK ;[-1]
94 pop YH ;[0] undo the pushes from before
95 pop r0 ;[2]
96 rjmp waitForK ;[4] this was not the end of sync, retry
97 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
98 ; bit times (= 22 cycles).
99
100 ;----------------------------------------------------------------------------
101 ; push more registers and initialize values while we sample the first bits:
102 ;----------------------------------------------------------------------------
103 haveTwoBitsK: ;[1]
104 push shift ;[1]
105 push x1 ;[3]
106 push x2 ;[5]
107 push x3 ;[7]
108 ldi shift, 0xff ;[9] [rx loop init]
109 ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag
110
111 in x1, USBIN ;[11] <-- sample bit 0
112 bst x1, USBMINUS ;[12]
113 bld shift, 0 ;[13]
114 push x4 ;[14] == phase
115 ; [---] ;[15]
116 push cnt ;[16]
117 ; [---] ;[17]
118 ldi phase, 0 ;[18] [rx loop init]
119 ldi cnt, USB_BUFSIZE;[19] [rx loop init]
120 rjmp rxbit1 ;[20]
121 ; [---] ;[21]
122
123 ;----------------------------------------------------------------------------
124 ; Receiver loop (numbers in brackets are cycles within byte after instr)
125 ;----------------------------------------------------------------------------
126 /*
127 byte oriented operations done during loop:
128 bit 0: store data
129 bit 1: SE0 check
130 bit 2: overflow check
131 bit 3: catch up
132 bit 4: rjmp to achieve conditional jump range
133 bit 5: PLL
134 bit 6: catch up
135 bit 7: jump, fixup bitstuff
136 ; 87 [+ 2] cycles
137 ------------------------------------------------------------------
138 */
139 continueWithBit5:
140 in x2, USBIN ;[055] <-- bit 5
141 eor r0, x2 ;[056]
142 or phase, r0 ;[057]
143 sbrc phase, USBMINUS ;[058]
144 lpm ;[059] optional nop3; modifies r0
145 in phase, USBIN ;[060] <-- phase
146 eor x1, x2 ;[061]
147 bst x1, USBMINUS ;[062]
148 bld shift, 5 ;[063]
149 andi shift, 0x3f ;[064]
150 in x1, USBIN ;[065] <-- bit 6
151 breq unstuff5 ;[066] *** unstuff escape
152 eor phase, x1 ;[067]
153 eor x2, x1 ;[068]
154 bst x2, USBMINUS ;[069]
155 bld shift, 6 ;[070]
156 didUnstuff6: ;[ ]
157 in r0, USBIN ;[071] <-- phase
158 cpi shift, 0x02 ;[072]
159 brlo unstuff6 ;[073] *** unstuff escape
160 didUnstuff5: ;[ ]
161 nop2 ;[074]
162 ; [---] ;[075]
163 in x2, USBIN ;[076] <-- bit 7
164 eor x1, x2 ;[077]
165 bst x1, USBMINUS ;[078]
166 bld shift, 7 ;[079]
167 didUnstuff7: ;[ ]
168 eor r0, x2 ;[080]
169 or phase, r0 ;[081]
170 in r0, USBIN ;[082] <-- phase
171 cpi shift, 0x04 ;[083]
172 brsh rxLoop ;[084]
173 ; [---] ;[085]
174 unstuff7: ;[ ]
175 andi x3, ~0x80 ;[085]
176 ori shift, 0x80 ;[086]
177 in x2, USBIN ;[087] <-- sample stuffed bit 7
178 nop ;[088]
179 rjmp didUnstuff7 ;[089]
180 ; [---] ;[090]
181 ;[080]
182
183 unstuff5: ;[067]
184 eor phase, x1 ;[068]
185 andi x3, ~0x20 ;[069]
186 ori shift, 0x20 ;[070]
187 in r0, USBIN ;[071] <-- phase
188 mov x2, x1 ;[072]
189 nop ;[073]
190 nop2 ;[074]
191 ; [---] ;[075]
192 in x1, USBIN ;[076] <-- bit 6
193 eor r0, x1 ;[077]
194 or phase, r0 ;[078]
195 eor x2, x1 ;[079]
196 bst x2, USBMINUS ;[080]
197 bld shift, 6 ;[081] no need to check bitstuffing, we just had one
198 in r0, USBIN ;[082] <-- phase
199 rjmp didUnstuff5 ;[083]
200 ; [---] ;[084]
201 ;[074]
202
203 unstuff6: ;[074]
204 andi x3, ~0x40 ;[075]
205 in x1, USBIN ;[076] <-- bit 6 again
206 ori shift, 0x40 ;[077]
207 nop2 ;[078]
208 ; [---] ;[079]
209 rjmp didUnstuff6 ;[080]
210 ; [---] ;[081]
211 ;[071]
212
213 unstuff0: ;[013]
214 eor r0, x2 ;[014]
215 or phase, r0 ;[015]
216 andi x2, USBMASK ;[016] check for SE0
217 in r0, USBIN ;[017] <-- phase
218 breq didUnstuff0 ;[018] direct jump to se0 would be too long
219 andi x3, ~0x01 ;[019]
220 ori shift, 0x01 ;[020]
221 mov x1, x2 ;[021] mov existing sample
222 in x2, USBIN ;[022] <-- bit 1 again
223 rjmp didUnstuff0 ;[023]
224 ; [---] ;[024]
225 ;[014]
226
227 unstuff1: ;[024]
228 eor r0, x1 ;[025]
229 or phase, r0 ;[026]
230 andi x3, ~0x02 ;[027]
231 in r0, USBIN ;[028] <-- phase
232 ori shift, 0x02 ;[029]
233 mov x2, x1 ;[030]
234 rjmp didUnstuff1 ;[031]
235 ; [---] ;[032]
236 ;[022]
237
238 unstuff2: ;[035]
239 eor r0, x2 ;[036]
240 or phase, r0 ;[037]
241 andi x3, ~0x04 ;[038]
242 in r0, USBIN ;[039] <-- phase
243 ori shift, 0x04 ;[040]
244 mov x1, x2 ;[041]
245 rjmp didUnstuff2 ;[042]
246 ; [---] ;[043]
247 ;[033]
248
249 unstuff3: ;[043]
250 in x2, USBIN ;[044] <-- bit 3 again
251 eor r0, x2 ;[045]
252 or phase, r0 ;[046]
253 andi x3, ~0x08 ;[047]
254 ori shift, 0x08 ;[048]
255 nop ;[049]
256 in r0, USBIN ;[050] <-- phase
257 rjmp didUnstuff3 ;[051]
258 ; [---] ;[052]
259 ;[042]
260
261 unstuff4: ;[053]
262 andi x3, ~0x10 ;[054]
263 in x1, USBIN ;[055] <-- bit 4 again
264 ori shift, 0x10 ;[056]
265 rjmp didUnstuff4 ;[057]
266 ; [---] ;[058]
267 ;[048]
268
269 rxLoop: ;[085]
270 eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others
271 in x1, USBIN ;[000] <-- bit 0
272 st y+, x3 ;[001]
273 ; [---] ;[002]
274 eor r0, x1 ;[003]
275 or phase, r0 ;[004]
276 eor x2, x1 ;[005]
277 in r0, USBIN ;[006] <-- phase
278 ser x3 ;[007]
279 bst x2, USBMINUS ;[008]
280 bld shift, 0 ;[009]
281 andi shift, 0xf9 ;[010]
282 rxbit1: ;[ ]
283 in x2, USBIN ;[011] <-- bit 1
284 breq unstuff0 ;[012] *** unstuff escape
285 andi x2, USBMASK ;[013] SE0 check for bit 1
286 didUnstuff0: ;[ ] Z only set if we detected SE0 in bitstuff
287 breq se0 ;[014]
288 eor r0, x2 ;[015]
289 or phase, r0 ;[016]
290 in r0, USBIN ;[017] <-- phase
291 eor x1, x2 ;[018]
292 bst x1, USBMINUS ;[019]
293 bld shift, 1 ;[020]
294 andi shift, 0xf3 ;[021]
295 didUnstuff1: ;[ ]
296 in x1, USBIN ;[022] <-- bit 2
297 breq unstuff1 ;[023] *** unstuff escape
298 eor r0, x1 ;[024]
299 or phase, r0 ;[025]
300 subi cnt, 1 ;[026] overflow check
301 brcs overflow ;[027]
302 in r0, USBIN ;[028] <-- phase
303 eor x2, x1 ;[029]
304 bst x2, USBMINUS ;[030]
305 bld shift, 2 ;[031]
306 andi shift, 0xe7 ;[032]
307 didUnstuff2: ;[ ]
308 in x2, USBIN ;[033] <-- bit 3
309 breq unstuff2 ;[034] *** unstuff escape
310 eor r0, x2 ;[035]
311 or phase, r0 ;[036]
312 eor x1, x2 ;[037]
313 bst x1, USBMINUS ;[038]
314 in r0, USBIN ;[039] <-- phase
315 bld shift, 3 ;[040]
316 andi shift, 0xcf ;[041]
317 didUnstuff3: ;[ ]
318 breq unstuff3 ;[042] *** unstuff escape
319 nop ;[043]
320 in x1, USBIN ;[044] <-- bit 4
321 eor x2, x1 ;[045]
322 bst x2, USBMINUS ;[046]
323 bld shift, 4 ;[047]
324 didUnstuff4: ;[ ]
325 eor r0, x1 ;[048]
326 or phase, r0 ;[049]
327 in r0, USBIN ;[050] <-- phase
328 andi shift, 0x9f ;[051]
329 breq unstuff4 ;[052] *** unstuff escape
330 rjmp continueWithBit5;[053]
331 ; [---] ;[054]
332
333 macro POP_STANDARD ; 16 cycles
334 pop cnt
335 pop x4
336 pop x3
337 pop x2
338 pop x1
339 pop shift
340 pop YH
341 pop r0
342 endm
343 macro POP_RETI ; 5 cycles
344 pop YL
345 out SREG, YL
346 pop YL
347 endm
348
349 #include "asmcommon.inc"
350
351
352 ; USB spec says:
353 ; idle = J
354 ; J = (D+ = 0), (D- = 1)
355 ; K = (D+ = 1), (D- = 0)
356 ; Spec allows 7.5 bit times from EOP to SOP for replies
357
358 bitstuff7:
359 eor x1, x4 ;[4]
360 ldi x2, 0 ;[5]
361 nop2 ;[6] C is zero (brcc)
362 rjmp didStuff7 ;[8]
363
364 bitstuffN:
365 eor x1, x4 ;[5]
366 ldi x2, 0 ;[6]
367 lpm ;[7] 3 cycle NOP, modifies r0
368 out USBOUT, x1 ;[10] <-- out
369 rjmp didStuffN ;[0]
370
371 #define bitStatus x3
372
373 sendNakAndReti:
374 ldi cnt, USBPID_NAK ;[-19]
375 rjmp sendCntAndReti ;[-18]
376 sendAckAndReti:
377 ldi cnt, USBPID_ACK ;[-17]
378 sendCntAndReti:
379 mov r0, cnt ;[-16]
380 ldi YL, 0 ;[-15] R0 address is 0
381 ldi YH, 0 ;[-14]
382 ldi cnt, 2 ;[-13]
383 ; rjmp usbSendAndReti fallthrough
384
385 ;usbSend:
386 ;pointer to data in 'Y'
387 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
388 ;uses: x1...x4, shift, cnt, Y
389 ;Numbers in brackets are time since first bit of sync pattern is sent
390 usbSendAndReti: ; 12 cycles until SOP
391 in x2, USBDDR ;[-12]
392 ori x2, USBMASK ;[-11]
393 sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
394 in x1, USBOUT ;[-8] port mirror for tx loop
395 out USBDDR, x2 ;[-7] <- acquire bus
396 ; need not init x2 (bitstuff history) because sync starts with 0
397 ldi x4, USBMASK ;[-6] exor mask
398 ldi shift, 0x80 ;[-5] sync byte is first byte sent
399 ldi bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes
400 byteloop:
401 bitloop:
402 sbrs shift, 0 ;[8] [-3]
403 eor x1, x4 ;[9] [-2]
404 out USBOUT, x1 ;[10] [-1] <-- out
405 ror shift ;[0]
406 ror x2 ;[1]
407 didStuffN:
408 cpi x2, 0xfc ;[2]
409 brcc bitstuffN ;[3]
410 nop ;[4]
411 subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37
412 brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value
413 sbrs shift, 0 ;[7]
414 eor x1, x4 ;[8]
415 ror shift ;[9]
416 didStuff7:
417 out USBOUT, x1 ;[10] <-- out
418 ror x2 ;[0]
419 cpi x2, 0xfc ;[1]
420 brcc bitstuff7 ;[2]
421 ld shift, y+ ;[3]
422 dec cnt ;[5]
423 brne byteloop ;[6]
424 ;make SE0:
425 cbr x1, USBMASK ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles]
426 lds x2, usbNewDeviceAddr;[8]
427 lsl x2 ;[10] we compare with left shifted address
428 out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
429 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
430 ;set address only after data packet was sent, not after handshake
431 subi YL, 2 ;[0] Only assign address on data packets, not ACK/NAK in r0
432 sbci YH, 0 ;[1]
433 breq skipAddrAssign ;[2]
434 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
435 skipAddrAssign:
436 ;end of usbDeviceAddress transfer
437 ldi x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag
438 USB_STORE_PENDING(x2) ;[5]
439 ori x1, USBIDLE ;[6]
440 in x2, USBDDR ;[7]
441 cbr x2, USBMASK ;[8] set both pins to input
442 mov x3, x1 ;[9]
443 cbr x3, USBMASK ;[10] configure no pullup on both pins
444 ldi x4, 4 ;[11]
445 se0Delay:
446 dec x4 ;[12] [15] [18] [21]
447 brne se0Delay ;[13] [16] [19] [22]
448 out USBOUT, x1 ;[23] <-- out J (idle) -- end of SE0 (EOP signal)
449 out USBDDR, x2 ;[24] <-- release bus now
450 out USBOUT, x3 ;[25] <-- ensure no pull-up resistors are active
451 rjmp doReturn
452

mercurial