/* Name: usbdrvasm12.S * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2004-12-29 * Tabsize: 4 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) * This Revision: $Id: usbdrvasm12.S 353 2007-06-21 19:05:08Z cs $ */ /* Do not link this file! Link usbdrvasm.S instead, which includes the * appropriate implementation! */ /* General Description: This file is the 12 MHz version of the asssembler part of the USB driver. It requires a 12 MHz crystal (not a ceramic resonator and not a calibrated RC oscillator). See usbdrv.h for a description of the entire driver. Since almost all of this code is timing critical, don't change unless you really know what you are doing! Many parts require not only a maximum number of CPU cycles, but even an exact number of cycles! Timing constraints according to spec (in bit times): timing subject min max CPUcycles --------------------------------------------------------------------------- EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2 16 16-128 EOP of IN to sync pattern of DATA0 (rx, then tx) 2 7.5 16-60 DATAx (rx) to ACK/NAK/STALL (tx) 2 7.5 16-60 */ ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing! ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled ;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes ;Numbers in brackets are maximum cycles since SOF. SIG_INTERRUPT0: ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt push YL ;2 [35] push only what is necessary to sync with edge ASAP in YL, SREG ;1 [37] push YL ;2 [39] ;---------------------------------------------------------------------------- ; Synchronize with sync pattern: ;---------------------------------------------------------------------------- ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] ;sync up with J to K edge during sync pattern -- use fastest possible loops ;first part has no timeout because it waits for IDLE or SE1 (== disconnected) waitForJ: sbis USBIN, USBMINUS ;1 [40] wait for D- == 1 rjmp waitForJ ;2 waitForK: ;The following code results in a sampling window of 1/4 bit which meets the spec. sbis USBIN, USBMINUS rjmp foundK sbis USBIN, USBMINUS rjmp foundK sbis USBIN, USBMINUS rjmp foundK sbis USBIN, USBMINUS rjmp foundK sbis USBIN, USBMINUS rjmp foundK rjmp sofError foundK: ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets ;are cycles from center of first sync (double K) bit after the instruction push YH ;2 [2] lds YL, usbInputBufOffset;2 [4] clr YH ;1 [5] subi YL, lo8(-(usbRxBuf));1 [6] sbci YH, hi8(-(usbRxBuf));1 [7] sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early] rjmp haveTwoBitsK ;2 [10] pop YH ;2 [11] undo the push from before rjmp waitForK ;2 [13] this was not the end of sync, retry haveTwoBitsK: ;---------------------------------------------------------------------------- ; push more registers and initialize values while we sample the first bits: ;---------------------------------------------------------------------------- push shift ;2 [16] push x1 ;2 [12] push x2 ;2 [14] in x1, USBIN ;1 [17] <-- sample bit 0 ldi shift, 0xff ;1 [18] bst x1, USBMINUS ;1 [19] bld shift, 0 ;1 [20] push x3 ;2 [22] push cnt ;2 [24] in x2, USBIN ;1 [25] <-- sample bit 1 ser x3 ;1 [26] [inserted init instruction] eor x1, x2 ;1 [27] bst x1, USBMINUS ;1 [28] bld shift, 1 ;1 [29] ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction] rjmp rxbit2 ;2 [32] ;---------------------------------------------------------------------------- ; Receiver loop (numbers in brackets are cycles within byte after instr) ;---------------------------------------------------------------------------- unstuff0: ;1 (branch taken) andi x3, ~0x01 ;1 [15] mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit in x2, USBIN ;1 [17] <-- sample bit 1 again ori shift, 0x01 ;1 [18] rjmp didUnstuff0 ;2 [20] unstuff1: ;1 (branch taken) mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit andi x3, ~0x02 ;1 [22] ori shift, 0x02 ;1 [23] nop ;1 [24] in x1, USBIN ;1 [25] <-- sample bit 2 again rjmp didUnstuff1 ;2 [27] unstuff2: ;1 (branch taken) andi x3, ~0x04 ;1 [29] ori shift, 0x04 ;1 [30] mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit nop ;1 [32] in x2, USBIN ;1 [33] <-- sample bit 3 rjmp didUnstuff2 ;2 [35] unstuff3: ;1 (branch taken) in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late] andi x3, ~0x08 ;1 [35] ori shift, 0x08 ;1 [36] rjmp didUnstuff3 ;2 [38] unstuff4: ;1 (branch taken) andi x3, ~0x10 ;1 [40] in x1, USBIN ;1 [41] <-- sample stuffed bit 4 ori shift, 0x10 ;1 [42] rjmp didUnstuff4 ;2 [44] unstuff5: ;1 (branch taken) andi x3, ~0x20 ;1 [48] in x2, USBIN ;1 [49] <-- sample stuffed bit 5 ori shift, 0x20 ;1 [50] rjmp didUnstuff5 ;2 [52] unstuff6: ;1 (branch taken) andi x3, ~0x40 ;1 [56] in x1, USBIN ;1 [57] <-- sample stuffed bit 6 ori shift, 0x40 ;1 [58] rjmp didUnstuff6 ;2 [60] ; extra jobs done during bit interval: ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs] ; bit 1: se0 check ; bit 2: overflow check ; bit 3: recovery from delay [bit 0 tasks took too long] ; bit 4: none ; bit 5: none ; bit 6: none ; bit 7: jump, eor rxLoop: eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others in x1, USBIN ;1 [1] <-- sample bit 0 st y+, x3 ;2 [3] store data ser x3 ;1 [4] nop ;1 [5] eor x2, x1 ;1 [6] bst x2, USBMINUS;1 [7] bld shift, 0 ;1 [8] in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed) andi x2, USBMASK ;1 [10] breq se0 ;1 [11] SE0 check for bit 1 andi shift, 0xf9 ;1 [12] didUnstuff0: breq unstuff0 ;1 [13] eor x1, x2 ;1 [14] bst x1, USBMINUS;1 [15] bld shift, 1 ;1 [16] rxbit2: in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed) andi shift, 0xf3 ;1 [18] breq unstuff1 ;1 [19] do remaining work for bit 1 didUnstuff1: subi cnt, 1 ;1 [20] brcs overflow ;1 [21] loop control eor x2, x1 ;1 [22] bst x2, USBMINUS;1 [23] bld shift, 2 ;1 [24] in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed) andi shift, 0xe7 ;1 [26] breq unstuff2 ;1 [27] didUnstuff2: eor x1, x2 ;1 [28] bst x1, USBMINUS;1 [29] bld shift, 3 ;1 [30] didUnstuff3: andi shift, 0xcf ;1 [31] breq unstuff3 ;1 [32] in x1, USBIN ;1 [33] <-- sample bit 4 eor x2, x1 ;1 [34] bst x2, USBMINUS;1 [35] bld shift, 4 ;1 [36] didUnstuff4: andi shift, 0x9f ;1 [37] breq unstuff4 ;1 [38] nop2 ;2 [40] in x2, USBIN ;1 [41] <-- sample bit 5 eor x1, x2 ;1 [42] bst x1, USBMINUS;1 [43] bld shift, 5 ;1 [44] didUnstuff5: andi shift, 0x3f ;1 [45] breq unstuff5 ;1 [46] nop2 ;2 [48] in x1, USBIN ;1 [49] <-- sample bit 6 eor x2, x1 ;1 [50] bst x2, USBMINUS;1 [51] bld shift, 6 ;1 [52] didUnstuff6: cpi shift, 0x02 ;1 [53] brlo unstuff6 ;1 [54] nop2 ;2 [56] in x2, USBIN ;1 [57] <-- sample bit 7 eor x1, x2 ;1 [58] bst x1, USBMINUS;1 [59] bld shift, 7 ;1 [60] didUnstuff7: cpi shift, 0x04 ;1 [61] brsh rxLoop ;2 [63] loop control unstuff7: andi x3, ~0x80 ;1 [63] ori shift, 0x80 ;1 [64] in x2, USBIN ;1 [65] <-- sample stuffed bit 7 nop ;1 [66] rjmp didUnstuff7 ;2 [68] ;---------------------------------------------------------------------------- ; Processing of received packet (numbers in brackets are cycles after end of SE0) ;---------------------------------------------------------------------------- ;This is the only non-error exit point for the software receiver loop ;we don't check any CRCs here because there is no time left. #define token x1 se0: ; [0] subi cnt, USB_BUFSIZE ;1 [1] neg cnt ;1 [2] cpi cnt, 3 ;1 [3] ldi x2, 1<