manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / usbdrv / usbdrvasm20.inc
1 /* Name: usbdrvasm20.inc
2  * Project: AVR USB driver
3  * Author: Jeroen Benschop
4  * Based on usbdrvasm16.inc from Christian Starkjohann
5  * Creation Date: 2008-03-05
6  * Tabsize: 4
7  * Copyright: (c) 2008 by Jeroen Benschop and OBJECTIVE DEVELOPMENT Software GmbH
8  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
9  * Revision: $Id: usbdrvasm20.inc 692 2008-11-07 15:07:40Z cs $
10  */
11
12 /* Do not link this file! Link usbdrvasm.S instead, which includes the
13  * appropriate implementation!
14  */
15
16 /*
17 General Description:
18 This file is the 20 MHz version of the asssembler part of the USB driver. It
19 requires a 20 MHz crystal (not a ceramic resonator and not a calibrated RC
20 oscillator).
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 #define leap2   x3
30 #ifdef __IAR_SYSTEMS_ASM__
31 #define nextInst    $+2
32 #else
33 #define nextInst    .+0
34 #endif
35
36 ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
37 ;nominal frequency: 20 MHz -> 13.333333 cycles per bit, 106.666667 cycles per byte
38 ; Numbers in brackets are clocks counted from center of last sync bit
39 ; when instruction starts
40 ;register use in receive loop:
41 ; shift assembles the byte currently being received
42 ; x1 holds the D+ and D- line state
43 ; x2 holds the previous line state
44 ; x4 (leap)  is used to add a leap cycle once every three bytes received
45 ; X3 (leap2) is used to add a leap cycle once every three stuff bits received
46 ; bitcnt is used to determine when a stuff bit is due
47 ; cnt holds the number of bytes left in the receive buffer
48
49 USB_INTR_VECTOR:
50 ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt
51     push    YL                  ;[-28] push only what is necessary to sync with edge ASAP
52     in      YL, SREG            ;[-26]
53     push    YL                  ;[-25]
54     push    YH                  ;[-23]
55 ;----------------------------------------------------------------------------
56 ; Synchronize with sync pattern:
57 ;----------------------------------------------------------------------------
58 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
59 ;sync up with J to K edge during sync pattern -- use fastest possible loops
60 ;The first part waits at most 1 bit long since we must be in sync pattern.
61 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
62 ;waitForJ, ensure that this prerequisite is met.
63 waitForJ:
64     inc     YL
65     sbis    USBIN, USBMINUS
66     brne    waitForJ        ; just make sure we have ANY timeout
67 waitForK:
68 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
69     sbis    USBIN, USBMINUS     ;[-19]
70     rjmp    foundK              ;[-18]
71     sbis    USBIN, USBMINUS
72     rjmp    foundK
73     sbis    USBIN, USBMINUS
74     rjmp    foundK
75     sbis    USBIN, USBMINUS
76     rjmp    foundK
77     sbis    USBIN, USBMINUS
78     rjmp    foundK
79     sbis    USBIN, USBMINUS
80     rjmp    foundK
81     sbis    USBIN, USBMINUS
82     rjmp    foundK
83     sbis    USBIN, USBMINUS
84     rjmp    foundK
85     sbis    USBIN, USBMINUS
86     rjmp    foundK
87 #if USB_COUNT_SOF
88     lds     YL, usbSofCount
89     inc     YL
90     sts     usbSofCount, YL
91 #endif  /* USB_COUNT_SOF */
92 #ifdef USB_SOF_HOOK
93     USB_SOF_HOOK
94 #endif
95     rjmp    sofError
96 foundK:                         ;[-16]
97 ;{3, 5} after falling D- edge, average delay: 4 cycles
98 ;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample
99 ;use 1 bit time for setup purposes, then sample again. Numbers in brackets
100 ;are cycles from center of first sync (double K) bit after the instruction
101     push    bitcnt              ;[-16]
102 ;   [---]                       ;[-15]
103     lds     YL, usbInputBufOffset;[-14]
104 ;   [---]                       ;[-13]
105     clr     YH                  ;[-12]
106     subi    YL, lo8(-(usbRxBuf));[-11] [rx loop init]
107     sbci    YH, hi8(-(usbRxBuf));[-10] [rx loop init]
108     push    shift               ;[-9]
109 ;   [---]                       ;[-8]
110     ldi     shift,0x40          ;[-7] set msb to "1" so processing bit7 can be detected
111     nop2                        ;[-6]
112 ;   [---]                       ;[-5]
113     ldi     bitcnt, 5           ;[-4] [rx loop init]
114     sbis    USBIN, USBMINUS     ;[-3] we want two bits K (sample 3 cycles too early)
115     rjmp    haveTwoBitsK        ;[-2]
116     pop     shift               ;[-1] undo the push from before
117     pop     bitcnt              ;[1] 
118     rjmp    waitForK            ;[3] this was not the end of sync, retry
119 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
120 ; bit times (= 27 cycles).
121
122 ;----------------------------------------------------------------------------
123 ; push more registers and initialize values while we sample the first bits:
124 ;----------------------------------------------------------------------------
125 haveTwoBitsK:
126     push    x1                  ;[0]
127     push    x2                  ;[2]
128     push    x3                  ;[4] (leap2)
129     ldi     leap2, 0x55         ;[6] add leap cycle on 2nd,5th,8th,... stuff bit
130     push    x4                  ;[7] == leap
131     ldi     leap, 0x55          ;[9] skip leap cycle on 2nd,5th,8th,... byte received
132     push    cnt                 ;[10]
133     ldi     cnt, USB_BUFSIZE    ;[12] [rx loop init]
134     ldi     x2, 1<<USBPLUS      ;[13] current line state is K state. D+=="1", D-=="0"
135 bit0:       
136     in      x1, USBIN           ;[0] sample line state
137     andi    x1, USBMASK         ;[1] filter only D+ and D- bits
138     rjmp    handleBit           ;[2] make bit0 14 cycles long
139
140 ;----------------------------------------------------------------------------
141 ; Process bit7. However, bit 6 still may need unstuffing.
142 ;----------------------------------------------------------------------------
143
144 b6checkUnstuff:
145     dec     bitcnt              ;[9]
146     breq    unstuff6            ;[10]
147 bit7:
148     subi    cnt, 1              ;[11] cannot use dec becaus it does not affect the carry flag
149     brcs    overflow            ;[12] Too many bytes received. Ignore packet
150     in      x1, USBIN           ;[0] sample line state
151     andi    x1, USBMASK         ;[1] filter only D+ and D- bits
152     cpse    x1, x2              ;[2] when previous line state equals current line state, handle "1"
153     rjmp    b7handle0           ;[3] when line state differs, handle "0"
154     sec                         ;[4]
155     ror     shift               ;[5] shift "1" into the data
156     st      y+, shift           ;[6] store the data into the buffer
157     ldi     shift, 0x40         ;[7] reset data for receiving the next byte
158     subi    leap, 0x55          ;[9] trick to introduce a leap cycle every 3 bytes
159     brcc    nextInst            ;[10 or 11] it will fail after 85 bytes. However low speed can only receive 11
160     dec     bitcnt              ;[11 or 12]
161     brne    bit0                ;[12 or 13]
162     ldi     x1, 1               ;[13 or 14] unstuffing bit 7
163     in      bitcnt, USBIN       ;[0] sample stuff bit
164     rjmp    unstuff             ;[1]
165
166 b7handle0:
167     mov     x2,x1               ;[5] Set x2 to current line state
168     ldi     bitcnt, 6           ;[6]
169     lsr     shift               ;[7] shift "0" into the data
170     st      y+, shift           ;[8] store data into the buffer
171     ldi     shift, 0x40         ;[10] reset data for receiving the next byte
172     subi    leap, 0x55          ;[11] trick to introduce a leap cycle every 3 bytes
173     brcs    bit0                ;[12] it will fail after 85 bytes. However low speed can only receive 11
174     rjmp    bit0                ;[13]
175
176
177 ;----------------------------------------------------------------------------
178 ; Handle unstuff
179 ; x1==0xFF indicate unstuffing bit6
180 ;----------------------------------------------------------------------------
181
182 unstuff6:
183     ldi     x1,0xFF             ;[12] indicate unstuffing bit 6
184     in      bitcnt, USBIN       ;[0]  sample stuff bit
185     nop                         ;[1]  fix timing
186 unstuff:                        ;b0-5  b6   b7
187     mov     x2,bitcnt           ;[3]  [2]  [3]  Set x2 to match line state
188     subi    leap2, 0x55         ;[4]  [3]  [4]  delay loop
189     brcs    nextInst            ;[5]  [4]  [5]  add one cycle every three stuff bits
190     sbci    leap2,0             ;[6]  [5]  [6]
191     ldi     bitcnt,6            ;[7]  [6]  [7]  reset bit stuff counter
192     andi    x2, USBMASK         ;[8]  [7]  [8] only keep D+ and D-
193     cpi     x1,0                ;[9]  [8]  [9]
194     brmi    bit7                ;[10] [9]  [10] finished unstuffing bit6 When x1<0
195     breq    bitloop             ;[11] ---  [11] finished unstuffing bit0-5 when x1=0
196     nop                         ;---  ---  [12]
197     in      x1, USBIN           ;---  ---  [0] sample line state for bit0
198     andi    x1, USBMASK         ;---  ---  [1] filter only D+ and D- bits
199     rjmp    handleBit           ;---  ---  [2] make bit0 14 cycles long
200
201 ;----------------------------------------------------------------------------
202 ; Receiver loop (numbers in brackets are cycles within byte after instr)
203 ;----------------------------------------------------------------------------
204 bitloop:
205     in      x1, USBIN           ;[0] sample line state
206     andi    x1, USBMASK         ;[1] filter only D+ and D- bits
207     breq    se0                 ;[2] both lines are low so handle se0
208 handleBit:
209     cpse    x1, x2              ;[3] when previous line state equals current line state, handle "1"
210     rjmp    handle0             ;[4] when line state differs, handle "0"
211     sec                         ;[5]
212     ror     shift               ;[6] shift "1" into the data
213     brcs    b6checkUnstuff      ;[7] When after shift C is set, next bit is bit7
214     nop2                        ;[8]
215     dec     bitcnt              ;[10]
216     brne    bitloop             ;[11]
217     ldi     x1,0                ;[12] indicate unstuff for bit other than bit6 or bit7
218     in      bitcnt, USBIN       ;[0] sample stuff bit
219     rjmp    unstuff             ;[1]
220
221 handle0:
222     mov     x2, x1              ;[6] Set x2 to current line state
223     ldi     bitcnt, 6           ;[7] reset unstuff counter. 
224     lsr     shift               ;[8] shift "0" into the data
225     brcs    bit7                ;[9] When after shift C is set, next bit is bit7
226     nop                         ;[10]
227     rjmp    bitloop             ;[11] 
228     
229 ;----------------------------------------------------------------------------
230 ; End of receive loop. Now start handling EOP
231 ;----------------------------------------------------------------------------
232
233 macro POP_STANDARD ; 14 cycles
234     pop     cnt
235     pop     x4
236     pop     x3
237     pop     x2
238     pop     x1
239     pop     shift
240     pop     bitcnt
241     endm
242 macro POP_RETI     ; 7 cycles
243     pop     YH
244     pop     YL
245     out     SREG, YL
246     pop     YL
247     endm
248
249
250
251 #include "asmcommon.inc"
252
253 ; USB spec says:
254 ; idle = J
255 ; J = (D+ = 0), (D- = 1)
256 ; K = (D+ = 1), (D- = 0)
257 ; Spec allows 7.5 bit times from EOP to SOP for replies
258 ; 7.5 bit times is 100 cycles. This implementation arrives a bit later at se0
259 ; then specified in the include file but there is plenty of time
260
261 bitstuffN:
262     eor     x1, x4          ;[8]
263     ldi     x2, 0           ;[9]
264     nop2                    ;[10]
265     out     USBOUT, x1      ;[12] <-- out
266     rjmp    didStuffN       ;[0]
267     
268 bitstuff7:
269     eor     x1, x4          ;[6]
270     ldi     x2, 0           ;[7] Carry is zero due to brcc
271     rol     shift           ;[8] compensate for ror shift at branch destination
272     nop2                    ;[9]
273     rjmp    didStuff7       ;[11]
274
275 sendNakAndReti:
276     ldi     x3, USBPID_NAK  ;[-18]
277     rjmp    sendX3AndReti   ;[-17]
278 sendAckAndReti:
279     ldi     cnt, USBPID_ACK ;[-17]
280 sendCntAndReti:
281     mov     x3, cnt         ;[-16]
282 sendX3AndReti:
283     ldi     YL, 20          ;[-15] x3==r20 address is 20
284     ldi     YH, 0           ;[-14]
285     ldi     cnt, 2          ;[-13]
286 ;   rjmp    usbSendAndReti      fallthrough
287
288 ;usbSend:
289 ;pointer to data in 'Y'
290 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
291 ;uses: x1...x4, btcnt, shift, cnt, Y
292 ;Numbers in brackets are time since first bit of sync pattern is sent
293 ;We don't match the transfer rate exactly (don't insert leap cycles every third
294 ;byte) because the spec demands only 1.5% precision anyway.
295 usbSendAndReti:             ; 12 cycles until SOP
296     in      x2, USBDDR      ;[-12]
297     ori     x2, USBMASK     ;[-11]
298     sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
299     in      x1, USBOUT      ;[-8] port mirror for tx loop
300     out     USBDDR, x2      ;[-7] <- acquire bus
301 ; need not init x2 (bitstuff history) because sync starts with 0
302     ldi     x4, USBMASK     ;[-6] exor mask
303     ldi     shift, 0x80     ;[-5] sync byte is first byte sent
304 txByteLoop:
305     ldi     bitcnt, 0x49    ;[-4]        [10] binary 01001001
306 txBitLoop:
307     sbrs    shift, 0        ;[-3] [10]   [11]
308     eor     x1, x4          ;[-2] [11]   [12]
309     out     USBOUT, x1      ;[-1] [12]   [13]   <-- out N
310     ror     shift           ;[0]  [13]   [14]
311     ror     x2              ;[1]
312 didStuffN:
313     nop2                    ;[2]
314     nop                     ;[4]
315     cpi     x2, 0xfc        ;[5]
316     brcc    bitstuffN       ;[6]
317     lsr     bitcnt          ;[7]
318     brcc    txBitLoop       ;[8]
319     brne    txBitLoop       ;[9]
320
321     sbrs    shift, 0        ;[10]
322     eor     x1, x4          ;[11]
323 didStuff7:
324     out     USBOUT, x1      ;[-1] [13] <-- out 7
325     ror     shift           ;[0] [14]
326     ror     x2              ;[1]
327     nop                     ;[2]
328     cpi     x2, 0xfc        ;[3]
329     brcc    bitstuff7       ;[4]
330     ld      shift, y+       ;[5]
331     dec     cnt             ;[7]
332     brne    txByteLoop      ;[8]
333 ;make SE0:
334     cbr     x1, USBMASK     ;[9] prepare SE0 [spec says EOP may be 25 to 30 cycles]
335     lds     x2, usbNewDeviceAddr;[10]
336     lsl     x2              ;[12] we compare with left shifted address
337     out     USBOUT, x1      ;[13] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
338     subi    YL, 20 + 2      ;[0] Only assign address on data packets, not ACK/NAK in x3
339     sbci    YH, 0           ;[1]
340 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
341 ;set address only after data packet was sent, not after handshake
342     breq    skipAddrAssign  ;[2]
343     sts     usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
344 skipAddrAssign:
345 ;end of usbDeviceAddress transfer
346     ldi     x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag
347     USB_STORE_PENDING(x2)   ;[5]
348     ori     x1, USBIDLE     ;[6]
349     in      x2, USBDDR      ;[7]
350     cbr     x2, USBMASK     ;[8] set both pins to input
351     mov     x3, x1          ;[9]
352     cbr     x3, USBMASK     ;[10] configure no pullup on both pins
353     ldi     x4, 5           ;[11]
354 se0Delay:
355     dec     x4              ;[12] [15] [18] [21] [24]
356     brne    se0Delay        ;[13] [16] [19] [22] [25]
357     out     USBOUT, x1      ;[26] <-- out J (idle) -- end of SE0 (EOP signal)
358     out     USBDDR, x2      ;[27] <-- release bus now
359     out     USBOUT, x3      ;[28] <-- ensure no pull-up resistors are active
360     rjmp    doReturn
This page took 0.062709 seconds and 3 git commands to generate.