]> git.gir.st - tmk_keyboard.git/blob - tmk_core/protocol/vusb/usbdrv/usbdrvasm15.inc
Merge commit 'a074364c3731d66b56d988c8a6c960a83ea0e0a1' as 'tmk_core'
[tmk_keyboard.git] / tmk_core / protocol / vusb / usbdrv / usbdrvasm15.inc
1 /* Name: usbdrvasm15.inc
2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3 * Author: contributed by V. Bosch
4 * Creation Date: 2007-08-06
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: usbdrvasm15.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 15 MHz version of the asssembler part of the USB driver. It
18 requires a 15 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 ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
29 ;nominal frequency: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte
30 ; Numbers in brackets are clocks counted from center of last sync bit
31 ; when instruction starts
32
33 ;----------------------------------------------------------------------------
34 ; order of registers pushed:
35 ; YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4
36 ;----------------------------------------------------------------------------
37 USB_INTR_VECTOR:
38 push YL ;2 push only what is necessary to sync with edge ASAP
39 in YL, SREG ;1
40 push YL ;2
41 ;----------------------------------------------------------------------------
42 ; Synchronize with sync pattern:
43 ;
44 ; sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
45 ; sync up with J to K edge during sync pattern -- use fastest possible loops
46 ;The first part waits at most 1 bit long since we must be in sync pattern.
47 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
48 ;waitForJ, ensure that this prerequisite is met.
49 waitForJ:
50 inc YL
51 sbis USBIN, USBMINUS
52 brne waitForJ ; just make sure we have ANY timeout
53 ;-------------------------------------------------------------------------------
54 ; The following code results in a sampling window of < 1/4 bit
55 ; which meets the spec.
56 ;-------------------------------------------------------------------------------
57 waitForK: ;-
58 sbis USBIN, USBMINUS ;1 [00] <-- sample
59 rjmp foundK ;2 [01]
60 sbis USBIN, USBMINUS ; <-- sample
61 rjmp foundK
62 sbis USBIN, USBMINUS ; <-- sample
63 rjmp foundK
64 sbis USBIN, USBMINUS ; <-- sample
65 rjmp foundK
66 sbis USBIN, USBMINUS ; <-- sample
67 rjmp foundK
68 sbis USBIN, USBMINUS ; <-- sample
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 ;------------------------------------------------------------------------------
80 ; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for
81 ; center sampling]
82 ; we have 1 bit time for setup purposes, then sample again.
83 ; Numbers in brackets are cycles from center of first sync (double K)
84 ; bit after the instruction
85 ;------------------------------------------------------------------------------
86 foundK: ;- [02]
87 lds YL, usbInputBufOffset;2 [03+04] tx loop
88 push YH ;2 [05+06]
89 clr YH ;1 [07]
90 subi YL, lo8(-(usbRxBuf)) ;1 [08] [rx loop init]
91 sbci YH, hi8(-(usbRxBuf)) ;1 [09] [rx loop init]
92 push shift ;2 [10+11]
93 ser shift ;1 [12]
94 sbis USBIN, USBMINUS ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early)
95 rjmp haveTwoBitsK ;2 [00] [14]
96 pop shift ;2 [15+16] undo the push from before
97 pop YH ;2 [17+18] undo the push from before
98 rjmp waitForK ;2 [19+20] this was not the end of sync, retry
99 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
100 ; bit times (= 20 cycles).
101
102 ;----------------------------------------------------------------------------
103 ; push more registers and initialize values while we sample the first bits:
104 ;----------------------------------------------------------------------------
105 haveTwoBitsK: ;- [01]
106 push x1 ;2 [02+03]
107 push x2 ;2 [04+05]
108 push x3 ;2 [06+07]
109 push bitcnt ;2 [08+09]
110 in x1, USBIN ;1 [00] [10] <-- sample bit 0
111 bst x1, USBMINUS ;1 [01]
112 bld shift, 0 ;1 [02]
113 push cnt ;2 [03+04]
114 ldi cnt, USB_BUFSIZE ;1 [05]
115 push x4 ;2 [06+07] tx loop
116 rjmp rxLoop ;2 [08]
117 ;----------------------------------------------------------------------------
118 ; Receiver loop (numbers in brackets are cycles within byte after instr)
119 ;----------------------------------------------------------------------------
120 unstuff0: ;- [07] (branch taken)
121 andi x3, ~0x01 ;1 [08]
122 mov x1, x2 ;1 [09] x2 contains last sampled (stuffed) bit
123 in x2, USBIN ;1 [00] [10] <-- sample bit 1 again
124 andi x2, USBMASK ;1 [01]
125 breq se0Hop ;1 [02] SE0 check for bit 1
126 ori shift, 0x01 ;1 [03] 0b00000001
127 nop ;1 [04]
128 rjmp didUnstuff0 ;2 [05]
129 ;-----------------------------------------------------
130 unstuff1: ;- [05] (branch taken)
131 mov x2, x1 ;1 [06] x1 contains last sampled (stuffed) bit
132 andi x3, ~0x02 ;1 [07]
133 ori shift, 0x02 ;1 [08] 0b00000010
134 nop ;1 [09]
135 in x1, USBIN ;1 [00] [10] <-- sample bit 2 again
136 andi x1, USBMASK ;1 [01]
137 breq se0Hop ;1 [02] SE0 check for bit 2
138 rjmp didUnstuff1 ;2 [03]
139 ;-----------------------------------------------------
140 unstuff2: ;- [05] (branch taken)
141 andi x3, ~0x04 ;1 [06]
142 ori shift, 0x04 ;1 [07] 0b00000100
143 mov x1, x2 ;1 [08] x2 contains last sampled (stuffed) bit
144 nop ;1 [09]
145 in x2, USBIN ;1 [00] [10] <-- sample bit 3
146 andi x2, USBMASK ;1 [01]
147 breq se0Hop ;1 [02] SE0 check for bit 3
148 rjmp didUnstuff2 ;2 [03]
149 ;-----------------------------------------------------
150 unstuff3: ;- [00] [10] (branch taken)
151 in x2, USBIN ;1 [01] [11] <-- sample stuffed bit 3 one cycle too late
152 andi x2, USBMASK ;1 [02]
153 breq se0Hop ;1 [03] SE0 check for stuffed bit 3
154 andi x3, ~0x08 ;1 [04]
155 ori shift, 0x08 ;1 [05] 0b00001000
156 rjmp didUnstuff3 ;2 [06]
157 ;----------------------------------------------------------------------------
158 ; extra jobs done during bit interval:
159 ;
160 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs],
161 ; overflow check, jump to the head of rxLoop
162 ; bit 1: SE0 check
163 ; bit 2: SE0 check, recovery from delay [bit 0 tasks took too long]
164 ; bit 3: SE0 check, recovery from delay [bit 0 tasks took too long]
165 ; bit 4: SE0 check, none
166 ; bit 5: SE0 check, none
167 ; bit 6: SE0 check, none
168 ; bit 7: SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others
169 ;----------------------------------------------------------------------------
170 rxLoop: ;- [09]
171 in x2, USBIN ;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed)
172 andi x2, USBMASK ;1 [01]
173 brne SkipSe0Hop ;1 [02]
174 se0Hop: ;- [02]
175 rjmp se0 ;2 [03] SE0 check for bit 1
176 SkipSe0Hop: ;- [03]
177 ser x3 ;1 [04]
178 andi shift, 0xf9 ;1 [05] 0b11111001
179 breq unstuff0 ;1 [06]
180 didUnstuff0: ;- [06]
181 eor x1, x2 ;1 [07]
182 bst x1, USBMINUS ;1 [08]
183 bld shift, 1 ;1 [09]
184 in x1, USBIN ;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed)
185 andi x1, USBMASK ;1 [01]
186 breq se0Hop ;1 [02] SE0 check for bit 2
187 andi shift, 0xf3 ;1 [03] 0b11110011
188 breq unstuff1 ;1 [04] do remaining work for bit 1
189 didUnstuff1: ;- [04]
190 eor x2, x1 ;1 [05]
191 bst x2, USBMINUS ;1 [06]
192 bld shift, 2 ;1 [07]
193 nop2 ;2 [08+09]
194 in x2, USBIN ;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed)
195 andi x2, USBMASK ;1 [01]
196 breq se0Hop ;1 [02] SE0 check for bit 3
197 andi shift, 0xe7 ;1 [03] 0b11100111
198 breq unstuff2 ;1 [04]
199 didUnstuff2: ;- [04]
200 eor x1, x2 ;1 [05]
201 bst x1, USBMINUS ;1 [06]
202 bld shift, 3 ;1 [07]
203 didUnstuff3: ;- [07]
204 andi shift, 0xcf ;1 [08] 0b11001111
205 breq unstuff3 ;1 [09]
206 in x1, USBIN ;1 [00] [10] <-- sample bit 4
207 andi x1, USBMASK ;1 [01]
208 breq se0Hop ;1 [02] SE0 check for bit 4
209 eor x2, x1 ;1 [03]
210 bst x2, USBMINUS ;1 [04]
211 bld shift, 4 ;1 [05]
212 didUnstuff4: ;- [05]
213 andi shift, 0x9f ;1 [06] 0b10011111
214 breq unstuff4 ;1 [07]
215 nop2 ;2 [08+09]
216 in x2, USBIN ;1 [00] [10] <-- sample bit 5
217 andi x2, USBMASK ;1 [01]
218 breq se0 ;1 [02] SE0 check for bit 5
219 eor x1, x2 ;1 [03]
220 bst x1, USBMINUS ;1 [04]
221 bld shift, 5 ;1 [05]
222 didUnstuff5: ;- [05]
223 andi shift, 0x3f ;1 [06] 0b00111111
224 breq unstuff5 ;1 [07]
225 nop2 ;2 [08+09]
226 in x1, USBIN ;1 [00] [10] <-- sample bit 6
227 andi x1, USBMASK ;1 [01]
228 breq se0 ;1 [02] SE0 check for bit 6
229 eor x2, x1 ;1 [03]
230 bst x2, USBMINUS ;1 [04]
231 bld shift, 6 ;1 [05]
232 didUnstuff6: ;- [05]
233 cpi shift, 0x02 ;1 [06] 0b00000010
234 brlo unstuff6 ;1 [07]
235 nop2 ;2 [08+09]
236 in x2, USBIN ;1 [00] [10] <-- sample bit 7
237 andi x2, USBMASK ;1 [01]
238 breq se0 ;1 [02] SE0 check for bit 7
239 eor x1, x2 ;1 [03]
240 bst x1, USBMINUS ;1 [04]
241 bld shift, 7 ;1 [05]
242 didUnstuff7: ;- [05]
243 cpi shift, 0x04 ;1 [06] 0b00000100
244 brlo unstuff7 ;1 [07]
245 eor x3, shift ;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others
246 nop ;1 [09]
247 in x1, USBIN ;1 [00] [10] <-- sample bit 0
248 st y+, x3 ;2 [01+02] store data
249 eor x2, x1 ;1 [03]
250 bst x2, USBMINUS ;1 [04]
251 bld shift, 0 ;1 [05]
252 subi cnt, 1 ;1 [06]
253 brcs overflow ;1 [07]
254 rjmp rxLoop ;2 [08]
255 ;-----------------------------------------------------
256 unstuff4: ;- [08]
257 andi x3, ~0x10 ;1 [09]
258 in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 4
259 andi x1, USBMASK ;1 [01]
260 breq se0 ;1 [02] SE0 check for stuffed bit 4
261 ori shift, 0x10 ;1 [03]
262 rjmp didUnstuff4 ;2 [04]
263 ;-----------------------------------------------------
264 unstuff5: ;- [08]
265 ori shift, 0x20 ;1 [09]
266 in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 5
267 andi x2, USBMASK ;1 [01]
268 breq se0 ;1 [02] SE0 check for stuffed bit 5
269 andi x3, ~0x20 ;1 [03]
270 rjmp didUnstuff5 ;2 [04]
271 ;-----------------------------------------------------
272 unstuff6: ;- [08]
273 andi x3, ~0x40 ;1 [09]
274 in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 6
275 andi x1, USBMASK ;1 [01]
276 breq se0 ;1 [02] SE0 check for stuffed bit 6
277 ori shift, 0x40 ;1 [03]
278 rjmp didUnstuff6 ;2 [04]
279 ;-----------------------------------------------------
280 unstuff7: ;- [08]
281 andi x3, ~0x80 ;1 [09]
282 in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 7
283 andi x2, USBMASK ;1 [01]
284 breq se0 ;1 [02] SE0 check for stuffed bit 7
285 ori shift, 0x80 ;1 [03]
286 rjmp didUnstuff7 ;2 [04]
287
288 macro POP_STANDARD ; 16 cycles
289 pop x4
290 pop cnt
291 pop bitcnt
292 pop x3
293 pop x2
294 pop x1
295 pop shift
296 pop YH
297 endm
298 macro POP_RETI ; 5 cycles
299 pop YL
300 out SREG, YL
301 pop YL
302 endm
303
304 #include "asmcommon.inc"
305
306 ;---------------------------------------------------------------------------
307 ; USB spec says:
308 ; idle = J
309 ; J = (D+ = 0), (D- = 1)
310 ; K = (D+ = 1), (D- = 0)
311 ; Spec allows 7.5 bit times from EOP to SOP for replies
312 ;---------------------------------------------------------------------------
313 bitstuffN: ;- [04]
314 eor x1, x4 ;1 [05]
315 clr x2 ;1 [06]
316 nop ;1 [07]
317 rjmp didStuffN ;1 [08]
318 ;---------------------------------------------------------------------------
319 bitstuff6: ;- [04]
320 eor x1, x4 ;1 [05]
321 clr x2 ;1 [06]
322 rjmp didStuff6 ;1 [07]
323 ;---------------------------------------------------------------------------
324 bitstuff7: ;- [02]
325 eor x1, x4 ;1 [03]
326 clr x2 ;1 [06]
327 nop ;1 [05]
328 rjmp didStuff7 ;1 [06]
329 ;---------------------------------------------------------------------------
330 sendNakAndReti: ;- [-19]
331 ldi x3, USBPID_NAK ;1 [-18]
332 rjmp sendX3AndReti ;1 [-17]
333 ;---------------------------------------------------------------------------
334 sendAckAndReti: ;- [-17]
335 ldi cnt, USBPID_ACK ;1 [-16]
336 sendCntAndReti: ;- [-16]
337 mov x3, cnt ;1 [-15]
338 sendX3AndReti: ;- [-15]
339 ldi YL, 20 ;1 [-14] x3==r20 address is 20
340 ldi YH, 0 ;1 [-13]
341 ldi cnt, 2 ;1 [-12]
342 ; rjmp usbSendAndReti fallthrough
343 ;---------------------------------------------------------------------------
344 ;usbSend:
345 ;pointer to data in 'Y'
346 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
347 ;uses: x1...x4, btcnt, shift, cnt, Y
348 ;Numbers in brackets are time since first bit of sync pattern is sent
349 ;We need not to match the transfer rate exactly because the spec demands
350 ;only 1.5% precision anyway.
351 usbSendAndReti: ;- [-13] 13 cycles until SOP
352 in x2, USBDDR ;1 [-12]
353 ori x2, USBMASK ;1 [-11]
354 sbi USBOUT, USBMINUS ;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups)
355 in x1, USBOUT ;1 [-08] port mirror for tx loop
356 out USBDDR, x2 ;1 [-07] <- acquire bus
357 ; need not init x2 (bitstuff history) because sync starts with 0
358 ldi x4, USBMASK ;1 [-06] exor mask
359 ldi shift, 0x80 ;1 [-05] sync byte is first byte sent
360 ldi bitcnt, 6 ;1 [-04]
361 txBitLoop: ;- [-04] [06]
362 sbrs shift, 0 ;1 [-03] [07]
363 eor x1, x4 ;1 [-02] [08]
364 ror shift ;1 [-01] [09]
365 didStuffN: ;- [09]
366 out USBOUT, x1 ;1 [00] [10] <-- out N
367 ror x2 ;1 [01]
368 cpi x2, 0xfc ;1 [02]
369 brcc bitstuffN ;1 [03]
370 dec bitcnt ;1 [04]
371 brne txBitLoop ;1 [05]
372 sbrs shift, 0 ;1 [06]
373 eor x1, x4 ;1 [07]
374 ror shift ;1 [08]
375 didStuff6: ;- [08]
376 nop ;1 [09]
377 out USBOUT, x1 ;1 [00] [10] <-- out 6
378 ror x2 ;1 [01]
379 cpi x2, 0xfc ;1 [02]
380 brcc bitstuff6 ;1 [03]
381 sbrs shift, 0 ;1 [04]
382 eor x1, x4 ;1 [05]
383 ror shift ;1 [06]
384 ror x2 ;1 [07]
385 didStuff7: ;- [07]
386 ldi bitcnt, 6 ;1 [08]
387 cpi x2, 0xfc ;1 [09]
388 out USBOUT, x1 ;1 [00] [10] <-- out 7
389 brcc bitstuff7 ;1 [01]
390 ld shift, y+ ;2 [02+03]
391 dec cnt ;1 [04]
392 brne txBitLoop ;1 [05]
393 makeSE0:
394 cbr x1, USBMASK ;1 [06] prepare SE0 [spec says EOP may be 19 to 23 cycles]
395 lds x2, usbNewDeviceAddr;2 [07+08]
396 lsl x2 ;1 [09] we compare with left shifted address
397 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
398 ;set address only after data packet was sent, not after handshake
399 out USBOUT, x1 ;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle
400 subi YL, 20 + 2 ;1 [01] Only assign address on data packets, not ACK/NAK in x3
401 sbci YH, 0 ;1 [02]
402 breq skipAddrAssign ;1 [03]
403 sts usbDeviceAddr, x2 ;2 [04+05] if not skipped: SE0 is one cycle longer
404 ;----------------------------------------------------------------------------
405 ;end of usbDeviceAddress transfer
406 skipAddrAssign: ;- [03/04]
407 ldi x2, 1<<USB_INTR_PENDING_BIT ;1 [05] int0 occurred during TX -- clear pending flag
408 USB_STORE_PENDING(x2) ;1 [06]
409 ori x1, USBIDLE ;1 [07]
410 in x2, USBDDR ;1 [08]
411 cbr x2, USBMASK ;1 [09] set both pins to input
412 mov x3, x1 ;1 [10]
413 cbr x3, USBMASK ;1 [11] configure no pullup on both pins
414 ldi x4, 3 ;1 [12]
415 se0Delay: ;- [12] [15]
416 dec x4 ;1 [13] [16]
417 brne se0Delay ;1 [14] [17]
418 nop2 ;2 [18+19]
419 out USBOUT, x1 ;1 [20] <--out J (idle) -- end of SE0 (EOP sig.)
420 out USBDDR, x2 ;1 [21] <--release bus now
421 out USBOUT, x3 ;1 [22] <--ensure no pull-up resistors are active
422 rjmp doReturn ;1 [23]
423 ;---------------------------------------------------------------------------
Imprint / Impressum