1 /* Name: usbdrvasm16.inc
2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3 * Author: Christian Starkjohann
4 * Creation Date: 2007-06-15
6 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
10 /* Do not link this file! Link usbdrvasm.S instead, which includes the
11 * appropriate implementation!
16 This file is the 16 MHz version of the asssembler part of the USB driver. It
17 requires a 16 MHz crystal (not a ceramic resonator and not a calibrated RC
20 See usbdrv.h for a description of the entire driver.
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!
27 ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
28 ;nominal frequency: 16 MHz -> 10.6666666 cycles per bit, 85.333333333 cycles per byte
29 ; Numbers in brackets are clocks counted from center of last sync bit
30 ; when instruction starts
33 ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt
34 push YL ;[-25] push only what is necessary to sync with edge ASAP
38 ;----------------------------------------------------------------------------
39 ; Synchronize with sync pattern:
40 ;----------------------------------------------------------------------------
41 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
42 ;sync up with J to K edge during sync pattern -- use fastest possible loops
43 ;The first part waits at most 1 bit long since we must be in sync pattern.
44 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
45 ;waitForJ, ensure that this prerequisite is met.
49 brne waitForJ ; just make sure we have ANY timeout
51 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
52 sbis USBIN, USBMINUS ;[-15]
68 #endif /* USB_COUNT_SOF */
74 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
75 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
76 ;are cycles from center of first sync (double K) bit after the instruction
79 lds YL, usbInputBufOffset;[-10]
82 subi YL, lo8(-(usbRxBuf));[-7] [rx loop init]
83 sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init]
86 ldi bitcnt, 0x55 ;[-3] [rx loop init]
87 sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early)
88 rjmp haveTwoBitsK ;[-1]
89 pop shift ;[0] undo the push from before
90 pop bitcnt ;[2] undo the push from before
91 rjmp waitForK ;[4] this was not the end of sync, retry
92 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
93 ; bit times (= 21 cycles).
95 ;----------------------------------------------------------------------------
96 ; push more registers and initialize values while we sample the first bits:
97 ;----------------------------------------------------------------------------
103 ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that
106 in x1, USBIN ;[11] <-- sample bit 0
107 andi x1, USBMASK ;[12]
108 bst x1, USBMINUS ;[13]
111 ldi leap, 0 ;[17] [rx loop init]
112 ldi cnt, USB_BUFSIZE;[18] [rx loop init]
113 rjmp rxbit1 ;[19] arrives at [21]
115 ;----------------------------------------------------------------------------
116 ; Receiver loop (numbers in brackets are cycles within byte after instr)
117 ;----------------------------------------------------------------------------
119 ; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap"
120 ; accordingly to approximate this value in the long run.
123 andi x2, USBMASK ;[03]
124 ori x3, 1<<6 ;[04] will not be shifted any more
125 andi shift, ~0x80;[05]
126 mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6
127 subi leap, -1 ;[07] total duration = 11 bits -> subtract 1/3
128 rjmp didUnstuff6 ;[08]
131 ori x3, 1<<7 ;[09] will not be shifted any more
132 in x2, USBIN ;[00] [10] re-sample bit 7
133 andi x2, USBMASK ;[01]
134 andi shift, ~0x80;[02]
135 subi leap, 2 ;[03] total duration = 10 bits -> add 1/3
136 rjmp didUnstuff7 ;[04]
139 ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0
140 in x1, USBIN ;[00] [10]
141 andi shift, ~0x80;[01]
142 andi x1, USBMASK ;[02]
144 subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3
146 rjmp didUnstuffE ;[06]
149 ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1
150 in x2, USBIN ;[00] [10]
151 andi shift, ~0x80;[01]
152 andi x2, USBMASK ;[02]
154 subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3
156 rjmp didUnstuffO ;[06]
159 andi x1, USBMASK ;[03]
163 subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte
169 cpi shift, 0xfc ;[10]
170 in x2, USBIN ;[00] [11] <-- sample bit 7
172 andi x2, USBMASK ;[02]
177 cpi shift, 0xfc ;[06]
179 eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others
180 st y+, x3 ;[09] store data
182 in x1, USBIN ;[00] [11] <-- sample bit 0/2/4
183 andi x1, USBMASK ;[01]
185 andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7
188 cpi shift, 0xfc ;[06]
189 brcc unstuffEven ;[07]
194 in x2, USBIN ;[00] [10] <-- sample bit 1/3/5
195 andi x2, USBMASK ;[01]
200 cpi shift, 0xfc ;[06]
201 brcc unstuffOdd ;[07]
203 subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3
207 in x1, USBIN ;[00] [11] <-- sample bit 6
208 brcc rxByteLoop ;[01]
211 macro POP_STANDARD ; 14 cycles
220 macro POP_RETI ; 7 cycles
227 #include "asmcommon.inc"
231 ; J = (D+ = 0), (D- = 1)
232 ; K = (D+ = 1), (D- = 0)
233 ; Spec allows 7.5 bit times from EOP to SOP for replies
240 out USBOUT, x1 ;[10] <-- out
245 ldi x2, 0 ;[6] Carry is zero due to brcc
246 rol shift ;[7] compensate for ror shift at branch destination
250 ldi x2, 0 ;[2] Carry is zero due to brcc
255 ldi x3, USBPID_NAK ;[-18]
256 rjmp sendX3AndReti ;[-17]
258 ldi cnt, USBPID_ACK ;[-17]
262 ldi YL, 20 ;[-15] x3==r20 address is 20
265 ; rjmp usbSendAndReti fallthrough
268 ;pointer to data in 'Y'
269 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
270 ;uses: x1...x4, btcnt, shift, cnt, Y
271 ;Numbers in brackets are time since first bit of sync pattern is sent
272 ;We don't match the transfer rate exactly (don't insert leap cycles every third
273 ;byte) because the spec demands only 1.5% precision anyway.
274 usbSendAndReti: ; 12 cycles until SOP
276 ori x2, USBMASK ;[-11]
277 sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
278 in x1, USBOUT ;[-8] port mirror for tx loop
279 out USBDDR, x2 ;[-7] <- acquire bus
280 ; need not init x2 (bitstuff history) because sync starts with 0
281 ldi x4, USBMASK ;[-6] exor mask
282 ldi shift, 0x80 ;[-5] sync byte is first byte sent
284 ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101
286 sbrs shift, 0 ;[-3] [7]
288 out USBOUT, x1 ;[-1] [9] <-- out N
301 out USBOUT, x1 ;[-1] [9] <-- out 6
313 out USBOUT, x1 ;[-1][10] <-- out 7
314 brcc bitstuff7 ;[0] [11]
319 cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles]
320 lds x2, usbNewDeviceAddr;[6]
321 lsl x2 ;[8] we compare with left shifted address
322 subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3
324 out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
325 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
326 ;set address only after data packet was sent, not after handshake
327 breq skipAddrAssign ;[0]
328 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
330 ;end of usbDeviceAddress transfer
331 ldi x2, 1<<USB_INTR_PENDING_BIT;[2] int0 occurred during TX -- clear pending flag
332 USB_STORE_PENDING(x2) ;[3]
335 cbr x2, USBMASK ;[6] set both pins to input
337 cbr x3, USBMASK ;[8] configure no pullup on both pins
340 dec x4 ;[10] [13] [16] [19]
341 brne se0Delay ;[11] [14] [17] [20]
342 out USBOUT, x1 ;[21] <-- out J (idle) -- end of SE0 (EOP signal)
343 out USBDDR, x2 ;[22] <-- release bus now
344 out USBOUT, x3 ;[23] <-- ensure no pull-up resistors are active