]> git.cryptolib.org Git - labortage2013badge.git/blob - firmware/usbdrv/usbdrvasm16.inc
adding old command-line-tool
[labortage2013badge.git] / firmware / usbdrv / usbdrvasm16.inc
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
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  */
9
10 /* Do not link this file! Link usbdrvasm.S instead, which includes the
11  * appropriate implementation!
12  */
13
14 /*
15 General Description:
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
18 oscillator).
19
20 See usbdrv.h for a description of the entire driver.
21
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!
25 */
26
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
31
32 USB_INTR_VECTOR:
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
35     in      YL, SREG            ;[-23]
36     push    YL                  ;[-22]
37     push    YH                  ;[-20]
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.
46 waitForJ:
47     inc     YL
48     sbis    USBIN, USBMINUS
49     brne    waitForJ        ; just make sure we have ANY timeout
50 waitForK:
51 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
52     sbis    USBIN, USBMINUS     ;[-15]
53     rjmp    foundK              ;[-14]
54     sbis    USBIN, USBMINUS
55     rjmp    foundK
56     sbis    USBIN, USBMINUS
57     rjmp    foundK
58     sbis    USBIN, USBMINUS
59     rjmp    foundK
60     sbis    USBIN, USBMINUS
61     rjmp    foundK
62     sbis    USBIN, USBMINUS
63     rjmp    foundK
64 #if USB_COUNT_SOF
65     lds     YL, usbSofCount
66     inc     YL
67     sts     usbSofCount, YL
68 #endif  /* USB_COUNT_SOF */
69 #ifdef USB_SOF_HOOK
70     USB_SOF_HOOK
71 #endif
72     rjmp    sofError
73 foundK:                         ;[-12]
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
77     push    bitcnt              ;[-12]
78 ;   [---]                       ;[-11]
79     lds     YL, usbInputBufOffset;[-10]
80 ;   [---]                       ;[-9]
81     clr     YH                  ;[-8]
82     subi    YL, lo8(-(usbRxBuf));[-7] [rx loop init]
83     sbci    YH, hi8(-(usbRxBuf));[-6] [rx loop init]
84     push    shift               ;[-5]
85 ;   [---]                       ;[-4]
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).
94
95 ;----------------------------------------------------------------------------
96 ; push more registers and initialize values while we sample the first bits:
97 ;----------------------------------------------------------------------------
98 haveTwoBitsK:
99     push    x1              ;[1]
100     push    x2              ;[3]
101     push    x3              ;[5]
102     ldi     shift, 0        ;[7]
103     ldi     x3, 1<<4        ;[8] [rx loop init] first sample is inverse bit, compensate that
104     push    x4              ;[9] == leap
105
106     in      x1, USBIN       ;[11] <-- sample bit 0
107     andi    x1, USBMASK     ;[12]
108     bst     x1, USBMINUS    ;[13]
109     bld     shift, 7        ;[14]
110     push    cnt             ;[15]
111     ldi     leap, 0         ;[17] [rx loop init]
112     ldi     cnt, USB_BUFSIZE;[18] [rx loop init]
113     rjmp    rxbit1          ;[19] arrives at [21]
114
115 ;----------------------------------------------------------------------------
116 ; Receiver loop (numbers in brackets are cycles within byte after instr)
117 ;----------------------------------------------------------------------------
118
119 ; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap"
120 ; accordingly to approximate this value in the long run.
121
122 unstuff6:
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]
129
130 unstuff7:
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]
137
138 unstuffEven:
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]
143     breq    se0         ;[03]
144     subi    leap, -1    ;[04] total duration = 11 bits -> subtract 1/3
145     nop2                ;[05]
146     rjmp    didUnstuffE ;[06]
147
148 unstuffOdd:
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]
153     breq    se0         ;[03]
154     subi    leap, -1    ;[04] total duration = 11 bits -> subtract 1/3
155     nop2                ;[05]
156     rjmp    didUnstuffO ;[06]
157
158 rxByteLoop:
159     andi    x1, USBMASK ;[03]
160     eor     x2, x1      ;[04]
161     subi    leap, 1     ;[05]
162     brpl    skipLeap    ;[06]
163     subi    leap, -3    ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte
164     nop                 ;1
165 skipLeap:
166     subi    x2, 1       ;[08]
167     ror     shift       ;[09]
168 didUnstuff6:
169     cpi     shift, 0xfc ;[10]
170     in      x2, USBIN   ;[00] [11] <-- sample bit 7
171     brcc    unstuff6    ;[01]
172     andi    x2, USBMASK ;[02]
173     eor     x1, x2      ;[03]
174     subi    x1, 1       ;[04]
175     ror     shift       ;[05]
176 didUnstuff7:
177     cpi     shift, 0xfc ;[06]
178     brcc    unstuff7    ;[07]
179     eor     x3, shift   ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others
180     st      y+, x3      ;[09] store data
181 rxBitLoop:
182     in      x1, USBIN   ;[00] [11] <-- sample bit 0/2/4
183     andi    x1, USBMASK ;[01]
184     eor     x2, x1      ;[02]
185     andi    x3, 0x3f    ;[03] topmost two bits reserved for 6 and 7
186     subi    x2, 1       ;[04]
187     ror     shift       ;[05]
188     cpi     shift, 0xfc ;[06]
189     brcc    unstuffEven ;[07]
190 didUnstuffE:
191     lsr     x3          ;[08]
192     lsr     x3          ;[09]
193 rxbit1:
194     in      x2, USBIN   ;[00] [10] <-- sample bit 1/3/5
195     andi    x2, USBMASK ;[01]
196     breq    se0         ;[02]
197     eor     x1, x2      ;[03]
198     subi    x1, 1       ;[04]
199     ror     shift       ;[05]
200     cpi     shift, 0xfc ;[06]
201     brcc    unstuffOdd  ;[07]
202 didUnstuffO:
203     subi    bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3
204     brcs    rxBitLoop   ;[09]
205
206     subi    cnt, 1      ;[10]
207     in      x1, USBIN   ;[00] [11] <-- sample bit 6
208     brcc    rxByteLoop  ;[01]
209     rjmp    overflow
210
211 macro POP_STANDARD ; 14 cycles
212     pop     cnt
213     pop     x4
214     pop     x3
215     pop     x2
216     pop     x1
217     pop     shift
218     pop     bitcnt
219     endm
220 macro POP_RETI     ; 7 cycles
221     pop     YH
222     pop     YL
223     out     SREG, YL
224     pop     YL
225     endm
226
227 #include "asmcommon.inc"
228
229 ; USB spec says:
230 ; idle = J
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
234
235 bitstuffN:
236     eor     x1, x4          ;[5]
237     ldi     x2, 0           ;[6]
238     nop2                    ;[7]
239     nop                     ;[9]
240     out     USBOUT, x1      ;[10] <-- out
241     rjmp    didStuffN       ;[0]
242     
243 bitstuff6:
244     eor     x1, x4          ;[5]
245     ldi     x2, 0           ;[6] Carry is zero due to brcc
246     rol     shift           ;[7] compensate for ror shift at branch destination
247     rjmp    didStuff6       ;[8]
248
249 bitstuff7:
250     ldi     x2, 0           ;[2] Carry is zero due to brcc
251     rjmp    didStuff7       ;[3]
252
253
254 sendNakAndReti:
255     ldi     x3, USBPID_NAK  ;[-18]
256     rjmp    sendX3AndReti   ;[-17]
257 sendAckAndReti:
258     ldi     cnt, USBPID_ACK ;[-17]
259 sendCntAndReti:
260     mov     x3, cnt         ;[-16]
261 sendX3AndReti:
262     ldi     YL, 20          ;[-15] x3==r20 address is 20
263     ldi     YH, 0           ;[-14]
264     ldi     cnt, 2          ;[-13]
265 ;   rjmp    usbSendAndReti      fallthrough
266
267 ;usbSend:
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
275     in      x2, USBDDR      ;[-12]
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
283 txByteLoop:
284     ldi     bitcnt, 0x35    ;[-4] [6] binary 0011 0101
285 txBitLoop:
286     sbrs    shift, 0        ;[-3] [7]
287     eor     x1, x4          ;[-2] [8]
288     out     USBOUT, x1      ;[-1] [9] <-- out N
289     ror     shift           ;[0] [10]
290     ror     x2              ;[1]
291 didStuffN:
292     cpi     x2, 0xfc        ;[2]
293     brcc    bitstuffN       ;[3]
294     lsr     bitcnt          ;[4]
295     brcc    txBitLoop       ;[5]
296     brne    txBitLoop       ;[6]
297
298     sbrs    shift, 0        ;[7]
299     eor     x1, x4          ;[8]
300 didStuff6:
301     out     USBOUT, x1      ;[-1] [9] <-- out 6
302     ror     shift           ;[0] [10]
303     ror     x2              ;[1]
304     cpi     x2, 0xfc        ;[2]
305     brcc    bitstuff6       ;[3]
306     ror     shift           ;[4]
307 didStuff7:
308     ror     x2              ;[5]
309     sbrs    x2, 7           ;[6]
310     eor     x1, x4          ;[7]
311     nop                     ;[8]
312     cpi     x2, 0xfc        ;[9]
313     out     USBOUT, x1      ;[-1][10] <-- out 7
314     brcc    bitstuff7       ;[0] [11]
315     ld      shift, y+       ;[1]
316     dec     cnt             ;[3]
317     brne    txByteLoop      ;[4]
318 ;make SE0:
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
323     sbci    YH, 0           ;[10]
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
329 skipAddrAssign:
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]
333     ori     x1, USBIDLE     ;[4]
334     in      x2, USBDDR      ;[5]
335     cbr     x2, USBMASK     ;[6] set both pins to input
336     mov     x3, x1          ;[7]
337     cbr     x3, USBMASK     ;[8] configure no pullup on both pins
338     ldi     x4, 4           ;[9]
339 se0Delay:
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
345     rjmp    doReturn