manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / usbdrv / usbdrvasm16.inc
CommitLineData
93ac315e
MPM
1/* Name: usbdrvasm16.inc
2 * Project: AVR USB driver
3 * Author: Christian Starkjohann
4 * Creation Date: 2007-06-15
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: usbdrvasm16.inc 692 2008-11-07 15:07:40Z cs $
9 */
10
11/* Do not link this file! Link usbdrvasm.S instead, which includes the
12 * appropriate implementation!
13 */
14
15/*
16General Description:
17This file is the 16 MHz version of the asssembler part of the USB driver. It
18requires a 16 MHz crystal (not a ceramic resonator and not a calibrated RC
19oscillator).
20
21See usbdrv.h for a description of the entire driver.
22
23Since almost all of this code is timing critical, don't change unless you
24really know what you are doing! Many parts require not only a maximum number
25of 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: 16 MHz -> 10.6666666 cycles per bit, 85.333333333 cycles per byte
30; Numbers in brackets are clocks counted from center of last sync bit
31; when instruction starts
32
33USB_INTR_VECTOR:
34;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt
35 push YL ;[-25] push only what is necessary to sync with edge ASAP
36 in YL, SREG ;[-23]
37 push YL ;[-22]
38 push YH ;[-20]
39;----------------------------------------------------------------------------
40; Synchronize with sync pattern:
41;----------------------------------------------------------------------------
42;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
43;sync up with J to K edge during sync pattern -- use fastest possible loops
44;The first part waits at most 1 bit long since we must be in sync pattern.
45;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
46;waitForJ, ensure that this prerequisite is met.
47waitForJ:
48 inc YL
49 sbis USBIN, USBMINUS
50 brne waitForJ ; just make sure we have ANY timeout
51waitForK:
52;The following code results in a sampling window of < 1/4 bit which meets the spec.
53 sbis USBIN, USBMINUS ;[-15]
54 rjmp foundK ;[-14]
55 sbis USBIN, USBMINUS
56 rjmp foundK
57 sbis USBIN, USBMINUS
58 rjmp foundK
59 sbis USBIN, USBMINUS
60 rjmp foundK
61 sbis USBIN, USBMINUS
62 rjmp foundK
63 sbis USBIN, USBMINUS
64 rjmp foundK
65#if USB_COUNT_SOF
66 lds YL, usbSofCount
67 inc YL
68 sts usbSofCount, YL
69#endif /* USB_COUNT_SOF */
70#ifdef USB_SOF_HOOK
71 USB_SOF_HOOK
72#endif
73 rjmp sofError
74foundK: ;[-12]
75;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
76;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
77;are cycles from center of first sync (double K) bit after the instruction
78 push bitcnt ;[-12]
79; [---] ;[-11]
80 lds YL, usbInputBufOffset;[-10]
81; [---] ;[-9]
82 clr YH ;[-8]
83 subi YL, lo8(-(usbRxBuf));[-7] [rx loop init]
84 sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init]
85 push shift ;[-5]
86; [---] ;[-4]
87 ldi bitcnt, 0x55 ;[-3] [rx loop init]
88 sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early)
89 rjmp haveTwoBitsK ;[-1]
90 pop shift ;[0] undo the push from before
91 pop bitcnt ;[2] undo the push from before
92 rjmp waitForK ;[4] this was not the end of sync, retry
93; The entire loop from waitForK until rjmp waitForK above must not exceed two
94; bit times (= 21 cycles).
95
96;----------------------------------------------------------------------------
97; push more registers and initialize values while we sample the first bits:
98;----------------------------------------------------------------------------
99haveTwoBitsK:
100 push x1 ;[1]
101 push x2 ;[3]
102 push x3 ;[5]
103 ldi shift, 0 ;[7]
104 ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that
105 push x4 ;[9] == leap
106
107 in x1, USBIN ;[11] <-- sample bit 0
108 andi x1, USBMASK ;[12]
109 bst x1, USBMINUS ;[13]
110 bld shift, 7 ;[14]
111 push cnt ;[15]
112 ldi leap, 0 ;[17] [rx loop init]
113 ldi cnt, USB_BUFSIZE;[18] [rx loop init]
114 rjmp rxbit1 ;[19] arrives at [21]
115
116;----------------------------------------------------------------------------
117; Receiver loop (numbers in brackets are cycles within byte after instr)
118;----------------------------------------------------------------------------
119
120unstuff6:
121 andi x2, USBMASK ;[03]
122 ori x3, 1<<6 ;[04] will not be shifted any more
123 andi shift, ~0x80;[05]
124 mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6
125 subi leap, 3 ;[07] since this is a short (10 cycle) bit, enforce leap bit
126 rjmp didUnstuff6 ;[08]
127
128unstuff7:
129 ori x3, 1<<7 ;[09] will not be shifted any more
130 in x2, USBIN ;[00] [10] re-sample bit 7
131 andi x2, USBMASK ;[01]
132 andi shift, ~0x80;[02]
133 subi leap, 3 ;[03] since this is a short (10 cycle) bit, enforce leap bit
134 rjmp didUnstuff7 ;[04]
135
136unstuffEven:
137 ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0
138 in x1, USBIN ;[00] [10]
139 andi shift, ~0x80;[01]
140 andi x1, USBMASK ;[02]
141 breq se0 ;[03]
142 subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit
143 nop ;[05]
144 rjmp didUnstuffE ;[06]
145
146unstuffOdd:
147 ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1
148 in x2, USBIN ;[00] [10]
149 andi shift, ~0x80;[01]
150 andi x2, USBMASK ;[02]
151 breq se0 ;[03]
152 subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit
153 nop ;[05]
154 rjmp didUnstuffO ;[06]
155
156rxByteLoop:
157 andi x1, USBMASK ;[03]
158 eor x2, x1 ;[04]
159 subi leap, 1 ;[05]
160 brpl skipLeap ;[06]
161 subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte
162 nop ;1
163skipLeap:
164 subi x2, 1 ;[08]
165 ror shift ;[09]
166didUnstuff6:
167 cpi shift, 0xfc ;[10]
168 in x2, USBIN ;[00] [11] <-- sample bit 7
169 brcc unstuff6 ;[01]
170 andi x2, USBMASK ;[02]
171 eor x1, x2 ;[03]
172 subi x1, 1 ;[04]
173 ror shift ;[05]
174didUnstuff7:
175 cpi shift, 0xfc ;[06]
176 brcc unstuff7 ;[07]
177 eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others
178 st y+, x3 ;[09] store data
179rxBitLoop:
180 in x1, USBIN ;[00] [11] <-- sample bit 0/2/4
181 andi x1, USBMASK ;[01]
182 eor x2, x1 ;[02]
183 andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7
184 subi x2, 1 ;[04]
185 ror shift ;[05]
186 cpi shift, 0xfc ;[06]
187 brcc unstuffEven ;[07]
188didUnstuffE:
189 lsr x3 ;[08]
190 lsr x3 ;[09]
191rxbit1:
192 in x2, USBIN ;[00] [10] <-- sample bit 1/3/5
193 andi x2, USBMASK ;[01]
194 breq se0 ;[02]
195 eor x1, x2 ;[03]
196 subi x1, 1 ;[04]
197 ror shift ;[05]
198 cpi shift, 0xfc ;[06]
199 brcc unstuffOdd ;[07]
200didUnstuffO:
201 subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3
202 brcs rxBitLoop ;[09]
203
204 subi cnt, 1 ;[10]
205 in x1, USBIN ;[00] [11] <-- sample bit 6
206 brcc rxByteLoop ;[01]
207 rjmp overflow
208
209macro POP_STANDARD ; 14 cycles
210 pop cnt
211 pop x4
212 pop x3
213 pop x2
214 pop x1
215 pop shift
216 pop bitcnt
217 endm
218macro POP_RETI ; 7 cycles
219 pop YH
220 pop YL
221 out SREG, YL
222 pop YL
223 endm
224
225#include "asmcommon.inc"
226
227; USB spec says:
228; idle = J
229; J = (D+ = 0), (D- = 1)
230; K = (D+ = 1), (D- = 0)
231; Spec allows 7.5 bit times from EOP to SOP for replies
232
233bitstuffN:
234 eor x1, x4 ;[5]
235 ldi x2, 0 ;[6]
236 nop2 ;[7]
237 nop ;[9]
238 out USBOUT, x1 ;[10] <-- out
239 rjmp didStuffN ;[0]
240
241bitstuff6:
242 eor x1, x4 ;[5]
243 ldi x2, 0 ;[6] Carry is zero due to brcc
244 rol shift ;[7] compensate for ror shift at branch destination
245 rjmp didStuff6 ;[8]
246
247bitstuff7:
248 ldi x2, 0 ;[2] Carry is zero due to brcc
249 rjmp didStuff7 ;[3]
250
251
252sendNakAndReti:
253 ldi x3, USBPID_NAK ;[-18]
254 rjmp sendX3AndReti ;[-17]
255sendAckAndReti:
256 ldi cnt, USBPID_ACK ;[-17]
257sendCntAndReti:
258 mov x3, cnt ;[-16]
259sendX3AndReti:
260 ldi YL, 20 ;[-15] x3==r20 address is 20
261 ldi YH, 0 ;[-14]
262 ldi cnt, 2 ;[-13]
263; rjmp usbSendAndReti fallthrough
264
265;usbSend:
266;pointer to data in 'Y'
267;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
268;uses: x1...x4, btcnt, shift, cnt, Y
269;Numbers in brackets are time since first bit of sync pattern is sent
270;We don't match the transfer rate exactly (don't insert leap cycles every third
271;byte) because the spec demands only 1.5% precision anyway.
272usbSendAndReti: ; 12 cycles until SOP
273 in x2, USBDDR ;[-12]
274 ori x2, USBMASK ;[-11]
275 sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
276 in x1, USBOUT ;[-8] port mirror for tx loop
277 out USBDDR, x2 ;[-7] <- acquire bus
278; need not init x2 (bitstuff history) because sync starts with 0
279 ldi x4, USBMASK ;[-6] exor mask
280 ldi shift, 0x80 ;[-5] sync byte is first byte sent
281txByteLoop:
282 ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101
283txBitLoop:
284 sbrs shift, 0 ;[-3] [7]
285 eor x1, x4 ;[-2] [8]
286 out USBOUT, x1 ;[-1] [9] <-- out N
287 ror shift ;[0] [10]
288 ror x2 ;[1]
289didStuffN:
290 cpi x2, 0xfc ;[2]
291 brcc bitstuffN ;[3]
292 lsr bitcnt ;[4]
293 brcc txBitLoop ;[5]
294 brne txBitLoop ;[6]
295
296 sbrs shift, 0 ;[7]
297 eor x1, x4 ;[8]
298didStuff6:
299 out USBOUT, x1 ;[-1] [9] <-- out 6
300 ror shift ;[0] [10]
301 ror x2 ;[1]
302 cpi x2, 0xfc ;[2]
303 brcc bitstuff6 ;[3]
304 ror shift ;[4]
305didStuff7:
306 ror x2 ;[5]
307 sbrs x2, 7 ;[6]
308 eor x1, x4 ;[7]
309 nop ;[8]
310 cpi x2, 0xfc ;[9]
311 out USBOUT, x1 ;[-1][10] <-- out 7
312 brcc bitstuff7 ;[0] [11]
313 ld shift, y+ ;[1]
314 dec cnt ;[3]
315 brne txByteLoop ;[4]
316;make SE0:
317 cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles]
318 lds x2, usbNewDeviceAddr;[6]
319 lsl x2 ;[8] we compare with left shifted address
320 subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3
321 sbci YH, 0 ;[10]
322 out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
323;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
324;set address only after data packet was sent, not after handshake
325 breq skipAddrAssign ;[0]
326 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
327skipAddrAssign:
328;end of usbDeviceAddress transfer
329 ldi x2, 1<<USB_INTR_PENDING_BIT;[2] int0 occurred during TX -- clear pending flag
330 USB_STORE_PENDING(x2) ;[3]
331 ori x1, USBIDLE ;[4]
332 in x2, USBDDR ;[5]
333 cbr x2, USBMASK ;[6] set both pins to input
334 mov x3, x1 ;[7]
335 cbr x3, USBMASK ;[8] configure no pullup on both pins
336 ldi x4, 4 ;[9]
337se0Delay:
338 dec x4 ;[10] [13] [16] [19]
339 brne se0Delay ;[11] [14] [17] [20]
340 out USBOUT, x1 ;[21] <-- out J (idle) -- end of SE0 (EOP signal)
341 out USBDDR, x2 ;[22] <-- release bus now
342 out USBOUT, x3 ;[23] <-- ensure no pull-up resistors are active
343 rjmp doReturn
This page took 0.069276 seconds and 4 git commands to generate.