manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / usbdrv / usbdrvasm16.inc
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 /*
16 General Description:
17 This file is the 16 MHz version of the asssembler part of the USB driver. It
18 requires a 16 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: 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
33 USB_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.
47 waitForJ:
48     inc     YL
49     sbis    USBIN, USBMINUS
50     brne    waitForJ        ; just make sure we have ANY timeout
51 waitForK:
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
74 foundK:                         ;[-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 ;----------------------------------------------------------------------------
99 haveTwoBitsK:
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
120 unstuff6:
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
128 unstuff7:
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
136 unstuffEven:
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
146 unstuffOdd:
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
156 rxByteLoop:
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
163 skipLeap:
164     subi    x2, 1       ;[08]
165     ror     shift       ;[09]
166 didUnstuff6:
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]
174 didUnstuff7:
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
179 rxBitLoop:
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]
188 didUnstuffE:
189     lsr     x3          ;[08]
190     lsr     x3          ;[09]
191 rxbit1:
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]
200 didUnstuffO:
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
209 macro 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
218 macro 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
233 bitstuffN:
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     
241 bitstuff6:
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
247 bitstuff7:
248     ldi     x2, 0           ;[2] Carry is zero due to brcc
249     rjmp    didStuff7       ;[3]
250
251
252 sendNakAndReti:
253     ldi     x3, USBPID_NAK  ;[-18]
254     rjmp    sendX3AndReti   ;[-17]
255 sendAckAndReti:
256     ldi     cnt, USBPID_ACK ;[-17]
257 sendCntAndReti:
258     mov     x3, cnt         ;[-16]
259 sendX3AndReti:
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.
272 usbSendAndReti:             ; 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
281 txByteLoop:
282     ldi     bitcnt, 0x35    ;[-4] [6] binary 0011 0101
283 txBitLoop:
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]
289 didStuffN:
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]
298 didStuff6:
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]
305 didStuff7:
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
327 skipAddrAssign:
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]
337 se0Delay:
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.054634 seconds and 3 git commands to generate.