?? usbdrvasm.s
字號:
/* Name: usbdrvasm.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: usbdrvasm.S 275 2007-03-20 09:58:28Z cs $ *//*General Description:This module implements the assembler part of the USB driver. See usbdrv.hfor a description of the entire driver.Since almost all of this code is timing critical, don't change unless youreally know what you are doing! Many parts require not only a maximum numberof 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-128EOP of IN to sync pattern of DATA0 (rx, then tx) 2 7.5 16-60DATAx (rx) to ACK/NAK/STALL (tx) 2 7.5 16-60*/#include "iarcompat.h"#ifndef __IAR_SYSTEMS_ASM__ /* configs for io.h */# define __SFR_OFFSET 0# define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */# include <avr/io.h> /* for CPU I/O register definitions and vectors */#endif /* __IAR_SYSTEMS_ASM__ */#include "usbdrv.h" /* for common defs *//* register names */#define x1 r16#define x2 r17#define shift r18#define cnt r19#define x3 r20#define x4 r21/* Some assembler dependent definitions and declarations: */#ifdef __IAR_SYSTEMS_ASM__# define nop2 rjmp $+2 /* jump to next instruction */# define XL r26# define XH r27# define YL r28# define YH r29# define ZL r30# define ZH r31# define lo8(x) LOW(x)# define hi8(x) ((x)>>8) /* not HIGH to allow XLINK to make a proper range check */ extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen extern usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3 public usbCrc16 public usbCrc16Append COMMON INTVEC ORG INT0_vect rjmp SIG_INTERRUPT0 RSEG CODE#else /* __IAR_SYSTEMS_ASM__ */# define nop2 rjmp .+0 /* jump to next instruction */ .text .global SIG_INTERRUPT0 .type SIG_INTERRUPT0, @function .global usbCrc16 .global usbCrc16Append#endif /* __IAR_SYSTEMS_ASM__ */;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 ;2waitForK:;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 sofErrorfoundK:;{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 ; undo the push from before rjmp waitForK ; this was not the end of sync, retryhaveTwoBitsK:;----------------------------------------------------------------------------; 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, eorrxLoop: 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 1didUnstuff1: 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 controlunstuff7: 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 x1se0: ; [0] subi cnt, USB_BUFSIZE ;1 [1] neg cnt ;1 [2] cpi cnt, 3 ;1 [3] ldi x2, 1<<USB_INTR_PENDING_BIT ;1 [4] out USB_INTR_PENDING, x2;1 [5] clear pending intr and check flag later. SE0 should be over. brlo doReturn ;1 [6] this is probably an ACK, NAK or similar packet sub YL, cnt ;1 [7] sbci YH, 0 ;1 [8] ld token, y ;2 [10] cpi token, USBPID_DATA0 ;1 [11] breq handleData ;1 [12] cpi token, USBPID_DATA1 ;1 [13] breq handleData ;1 [14] ldd x2, y+1 ;2 [16] ADDR and 1 bit endpoint number mov x3, x2 ;1 [17] store for endpoint number andi x2, 0x7f ;1 [18] x2 is now ADDR lds shift, usbDeviceAddr;2 [20] cp x2, shift ;1 [21]overflow: ; This is a hack: brcs overflow will never have Z flag set brne ignorePacket ;1 [22] packet for different address cpi token, USBPID_IN ;1 [23] breq handleIn ;1 [24] cpi token, USBPID_SETUP ;1 [25] breq handleSetupOrOut ;1 [26] cpi token, USBPID_OUT ;1 [27] breq handleSetupOrOut ;1 [28]; rjmp ignorePacket ;fallthrough, should not happen anyway.ignorePacket: clr shift sts usbCurrentTok, shiftdoReturn: pop cnt pop x3 pop x2 pop x1 pop shift pop YHsofError: pop YL out SREG, YL pop YL reti#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_HAVE_INTRIN_ENDPOINT3handleIn3: ;1 [38] (branch taken) lds cnt, usbTxLen3 ;2 [40] sbrc cnt, 4 ;2 [42] rjmp sendCntAndReti ;0 43 + 17 = 60 until SOP sts usbTxLen3, x1 ;2 [44] x1 == USBPID_NAK from above ldi YL, lo8(usbTxBuf3) ;1 [45] ldi YH, hi8(usbTxBuf3) ;1 [46] rjmp usbSendAndReti ;2 [48] + 13 = 61 until SOP (violates the spec by 1 cycle)#endif;Setup and Out are followed by a data packet two bit times (16 cycles) after;the end of SE0. The sync code allows up to 40 cycles delay from the start of;the sync pattern until the first bit is sampled. That's a total of 56 cycles.handleSetupOrOut: ;1 [29] (branch taken)#if USB_CFG_IMPLEMENT_FN_WRITEOUT /* if we have data for second OUT endpoint, set usbCurrentTok to -1 */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -