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