;**************************************************************************
;**                                                                      **
;**                  I N T E L   P R O P R I E T A R Y                   **
;**                                                                      **
;**     COPYRIGHT (c)  1996, 1997 BY  INTEL  CORPORATION.  ALL RIGHTS    **
;**     RESERVED.   NO  PART  OF THIS PROGRAM  OR  PUBLICATION  MAY      **
;**     BE  REPRODUCED,   TRANSMITTED,   TRANSCRIBED,   STORED  IN  A    **
;**     RETRIEVAL SYSTEM, OR TRANSLATED INTO ANY LANGUAGE OR COMPUTER    **
;**     LANGUAGE IN ANY FORM OR BY ANY MEANS, ELECTRONIC, MECHANICAL,    **
;**     MAGNETIC,  OPTICAL,  CHEMICAL, MANUAL, OR OTHERWISE,  WITHOUT    **
;**     THE PRIOR WRITTEN PERMISSION OF :                                **
;**                                                                      **
;**                        INTEL  CORPORATION                            **
;**                     2200 MISSON COLLEGE BLVD                         **
;**               SANTA  CLARA,  CALIFORNIA  95052-8119                  **
;**************************************************************************
;
;   File: emb_func.asm
;
;   Universal Serial Bus 930HX Embedded Function Firmware
;
;   Revision History
;    **** Be sure to change gDevice_bcdDevice: value at end of this file
;    **** in the device descriptor to update the revision number reported
;   ---------------------------------------------
;    1.8     07-14-97          Charles H Linthicum Jr.
;                               Removed serial number string for
;                               MS Memphis Beta 1 compliance
;    1.7     03-10-97          Charles H Linthicum Jr.
;                              Fixed Get Status to return correct status of
;                              part power - whether bus or self
;                              Added string for index 0 - English Lang. ID
;                              Added string for serial number = firmware rev
;                              Removed carriage returns from strings
;                              Moved all configuration switches to SWITCH.INC include file
;                              Moved PDATA variables and buffers to internal RAM - DATA segment
;                              Revised embedded function RWU set/clear/get status fns -
;                                adding sw flag to keep track of emb fn RWU.
;                              Changed code to work with Intel Compatibility turned on.
;                              Added several equates for port switches, port LED's, etc. to
;                                SWITCH.INC & one_oh.inc
;                              Added Interface String descriptor as index 5
;                              Added display of SWITCH setup to display in the
;                               Configuration string descriptor
;                              Changed use of INTERNAL_PORT switch to be used with EVAL
;                               board to enable/disable the embedded function.
;    1.6     02-14-97          Charles H Linthicum Jr.
;                              Changed code in ResetFifos for Reset Data Toggle
;    1.5     02-13-97          Charles H Linthicum Jr.
;                              Added OHCI fix around setting TXCLR
;    1.4     12-03-96          Charles H Linthicum Jr.
;                              Added capability to enable SW fix for RXFFRC errata SW
;                              workaround, and ability to switch between LC and HC for
;                              Configuration 1 by changing CLOCK_LOW assembler directive
;    1.3     08-30-96          Kenneth Schultz
;                              Added Set & Clear RWU hooks to code
;                              Converted SJMP table to LJMP table to increase versitiliy on
;                              where the code was placed.
;                              Added EP0 sequenceing to protect the firmware from OHCI stacks.
;                              Added loopback to endpoints 1,2 & 3
;                              Changed EP Interrupt processing to avoid starving the host.
;                              Added Get Configuration command
;                              Added EP0 Stall handling as defined in RR
;                              Added Set & Get Interface routines. Checked with Chap 9 Test.
;    0.5     08-20-96          Kenneth Schultz
;                              Cleaned up stuff, Added Suspend/Resume,
;                              Fixed Control Write with Data Stages
;    0.4     08-01-96          Kenneth Schultz
;                              Cleaned up and documented better.  Also added hooks for
;                              control write command Data Stages, & Hub.
;    0.3     07-15-96          Kenneth Schultz
;                              Converted to using A Register only for future products.
;    0.2     06-29-96          Kenneth Schultz
;    0.1     05-27-96          Abdul Rahman Ismail
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

;These two equate statements allow the user to switch between the PLC
;and Keil assemblers.  Place a 1 on the assembler that is to be used to
;assemble this file.
PLC EQU 1
KEIL EQU 0

IF PLC
	include "8x930hx.inc"
	include "SWITCH.INC"                    ; include switches for code setup
ENDIF
IF KEIL
	$include (Reg930.inc)
	$include (SWITCH.INC)                    ; include switches for code setup
ENDIF

FIFO_SIZE             equ     008h
GET_COMMAND           equ     080h
EP1_RX_FIFO_SIZE      equ     08h      ;
EP1_TX_FIFO_SIZE      equ     64      ; 64 bytes
EP2_TX_FIFO_SIZE      equ     08h     ; 8 bytes
EP3_TX_FIFO_SIZE      equ     08h     ; 8 bytes
EP1_TX_LOOP_BACK_FIFO_SIZE    equ  40h
EP1_RX_LOOP_BACK_FIFO_SIZE    equ  40h
EP2_TX_LOOP_BACK_FIFO_SIZE    equ  08h
EP2_RX_LOOP_BACK_FIFO_SIZE    equ  08h
EP3_TX_LOOP_BACK_FIFO_SIZE    equ  08h
EP3_RX_LOOP_BACK_FIFO_SIZE    equ  08h

SETUP_PHASE           equ     000h
DATA_PHASE            equ     001h
STATUS_PHASE          equ     002h


EP0_MAX_PACKET_SIZE     equ      08h
NULL_DATA_PACKET        equ     000h


public   FUNCTION_ISR
public   InitilizeEmbeddedFunction, EmbeddedFunctionSofRoutine
public   FUNCTION_SUSPEND_ROUTINE,FUNCTION_RESUME_ROUTINE
public   FbRequest
public   STACK_DATA
public   FifoWatchDog

;public  RightCylon,LeftCylon,FbRequest,FwIndex,FwValue, RWUTimer
IF PLC
	extern  SV_SUSPEND_ROUTINE:CODE
	extern  SV_RESUME_ROUTINE:CODE
	extern  SV_SOF_ROUTINE:CODE
	extern  SV_ResetRoutine:CODE
	extern  VendorGetDeviceCommandExec:CODE,  VendorSetDeviceCommandExec:CODE
	extern  EMBD_FN_FLG:PDATA
ENDIF
IF KEIL
    extern  CODE (SV_SUSPEND_ROUTINE)
	extern  CODE (SV_RESUME_ROUTINE)
	extern  CODE (SV_SOF_ROUTINE)
	extern  CODE (SV_ResetRoutine)
	extern  CODE (VendorGetDeviceCommandExec),  CODE (VendorSetDeviceCommandExec)
	extern  EDATA (EMBD_FN_FLG)
ENDIF

IF PLC
	DEFINE EMBEDDED_CODE_SEGMENT, SPACE=CODE
	SEGMENT EMBEDDED_CODE_SEGMENT
ENDIF
IF KEIL
	EMBEDDED_CODE_SEGMENT SEGMENT CODE
	RSEG EMBEDDED_CODE_SEGMENT
ENDIF

;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
;M---------------------------------------------------------------------M
;M                   MAIN                                              M
;M---------------------------------------------------------------------M
;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM


InitilizeEmbeddedFunction:


        Call    INIT_VARIABLES             ; Initialize the RAM space as required
        call    SV_ResetRoutine
        Call    INIT_FUNCTION_EP0

        setb    SOFIE                      ; Enable SOF Interrupts
        setb    IEN1.1                     ; Enable Function ISR
        ret

; Initialize the USB subsystem
;       lcall   INIT_USERS_CODE            ; Call to USERS CODE FOR INTILIZATION


;----------------------------------------------------------------
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
;SS                 FUNCTION SUSPEND ROUTINE
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
;----------------------------------------------------------------
FUNCTION_SUSPEND_ROUTINE:
        call    SV_SUSPEND_ROUTINE
        ret
;----------------------------------------------------------------
;RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
;RR                 FUNCTION RESUME1 ROUTINE
;RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
;----------------------------------------------------------------
FUNCTION_RESUME_ROUTINE:
        call    SV_RESUME_ROUTINE
        ret

;----------------------------------------------------------------
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
;SS                 SOF ISR
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
;----------------------------------------------------------------
;COMMENT *------------------------------------------------------------
;Function name     : SOF_ISR
;Brief Description : Service the SOF_ISR Interrupt
;                  : This routine simply displays the upper three bytes of the
;                  : SOF in the lower three bits of the LEDs on LED_PORT = P1.
;                  : It does not affect the other LEDS.  Very usefull
;                  : in determining when the function is receiveing SOFs
;Regs preserved    : Reg. A is saved
;--------------------------------------------------------------------*
;SCOPE

SOF_ISR:
EmbeddedFunctionSofRoutine:


        jnb     ASOF,   ExitSofIsr              ; If this ASOF bit not set, the ISR could be a HUB.  Go Check.

        call    SV_SOF_ROUTINE


        clr     ASOF
        push    ACC
IF FUB_BOARD == DISABLED
        mov     A,      LED_PORT
        anl     A,      #0F8h
        mov     LED_PORT,     A


        mov     A,      SOFH
        anl     A,      #07h
        orl     LED_PORT,     A
ENDIF
        pop     ACC
ExitSofIsr:
        ret



;----------------------------------------------------------------
;FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
;FF                 FUNCTION ISR
;FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
;----------------------------------------------------------------
;COMMENT *------------------------------------------------------------
;Function name     : FUNCTION_ISR
;Brief Description : Service the FUNCTION_ISR Interrupt
;                  : This routine scans the interrupt pending bits in order
;                  : and branches to any routines that have pending interrupts.
;                  : After finishing the routine jumps back to the top of
;                  : the scanning loop to preserve interrupt priority.
;                  :
;                  : NOTE: The order of precidence is set by the order in which the
;                  : user places the checks.
;                  :
;Regs preserved    : Reg. A, B  & EPINDEX are saved
;--------------------------------------------------------------------*
;SCOPE

FUNCTION_ISR:
         push   PSW
         push   PSW1
         push   ACC
         push   B
         push   EPINDEX


ProcessFunctionEndpoints:

;----------------------------------------------------------------
;-- NOTE: Priority of the check sequence determines priority.  --
;----------------------------------------------------------------

F_EP0:
        mov     A,   FIFLG                  ; First check to see if this is EP0 Command
        anl     A,   #03h                   ; As they require extra overhead. Mask off all but EP0 Interrupts
        jz      NonEp0ISR

                                             ;----------------------------------------------------------------
                                             ;-- Process the EP0 COmmand in the correct order
                                             ;----------------------------------------------------------------

                                            ; If this an EP0 command then we need to process TX & RX
                                            ; ISRs in the correct order if, for whatever reason they occurred
                                            ; back to back.  This happens in OHCI systems.
        mov     A, gbSetupSeqTX
        cjne    A, #SETUP_PHASE, CheckDataStatusStage
        jmp     DoRxFirst                   ; If the status stage is Setup then check the RX First.

CheckDataStatusStage:
                                            ; Now check to see what stage the TX is in.
                                            ; If it is in the data stage then check it first.
                                            ; If it's in the status stage then check the RX first.

        cjne    A, #DATA_PHASE, DoRxFirst   ; If current stage a data stage->a control read
                                            ; and we should process TX before RX ISR

                                            ;----------------------------------------------------------------
                                            ;-- Process the TX FIFO first
                                            ;----------------------------------------------------------------

DoTxFirst:
F_EP0_TXA:
        jnb     FTXD0,  F_EP0_RXA
        mov     EPINDEX,#00
        lCall   ProcessInToken              ; 82930 has sent a packet to HC
        ljmp     ProcessFunctionEndpoints    ; Look at all Interrupt flags again

F_EP0_RXA:
        jnb     FRXD0,  NonEp0ISR
        mov     EPINDEX,#00
        lCall   ProcessOutToken             ; 82930 has received a packet from HC
        ljmp     ProcessFunctionEndpoints    ; Look at all Interrupt flags again

;--------------------------------------------------------------------------------

DoRxFirst:
                                            ;----------------------------------------------------------------
                                            ;-- Process the RX FIFO first
                                            ;----------------------------------------------------------------
F_EP0_RXB:
        jnb     FRXD0,  F_EP0_TXB
        mov     EPINDEX,#00
        lCall   ProcessOutToken             ; 82930 has received a packet from HC
        ljmp     ProcessFunctionEndpoints    ; Look at all Interrupt flags again

F_EP0_TXB:
        jnb     FTXD0,  NonEp0ISR
        mov     EPINDEX,#00
        lCall   ProcessInToken              ; 82930 has sent a packet to HC
        ljmp     ProcessFunctionEndpoints    ; Look at all Interrupt flags again


;--------------------------------------------------------------------------------
;--------------------------------------------------------------------------------

                                            ;----------------------------------------------------------------
                                            ;-- Process the Other EPs next
                                            ;----------------------------------------------------------------

NonEp0ISR:
F_EP1_TX:

        jnb     FTXD1,  F_EP1_RX
        mov     EPINDEX,#01

        lcall   Ep1TxLoopBack
        jb      RXFIF0, GetEp1RxData        ; If data is pending in the FIFOs go get it.
        jb      RXFIF1, GetEp1RxData        ; This is quicker than calling the routines.
        ljmp     F_EP1_RX                    ; Look at all Interrupt flags again
GetEp1RxData:
        lCall   Ep1RxLoopBack               ; 82930 has received a packet from HC
;        jmp     ProcessFunctionEndpoints    ; Look at all Interrupt flags again

F_EP1_RX:
        jnb     FRXD1,  F_EP2_TX
        mov     EPINDEX,#01
        lCall   Ep1RxLoopBack               ; 82930 has received a packet from HC
        lcall   Ep1TxLoopBack


F_EP2_TX:

        jnb     FTXD2,  F_EP2_RX
        mov     EPINDEX,#02

        lcall   Ep2TxLoopBack
        jb      RXFIF0, GetEp2RxData        ; If data is pending in the FIFOs go get it.
        jb      RXFIF1, GetEp2RxData        ; This is quicker than calling the routines.
        ljmp    F_EP2_RX                    ; Look at all Interrupt flags again
GetEp2RxData:
        lcall   Ep2RxLoopBack               ; 82930 has received a packet from HC


F_EP2_RX:
        jnb     FRXD2,  F_EP3_TX
        mov     EPINDEX,#02
        lcall   Ep2RxLoopBack               ; 82930 has received a packet from HC
        lcall   Ep2TxLoopBack

F_EP3_TX:
        jnb     FTXD3,  F_EP3_RX
        mov     EPINDEX,#03

        lcall   Ep3TxLoopBack
        jb      RXFIF0, GetEp3RxData        ; If data is pending in the FIFOs go get it.
        jb      RXFIF1, GetEp3RxData        ; This is quicker than calling the routines.
        ljmp    F_EP3_RX                    ; Look at all Interrupt flags again
GetEp3RxData:
        lcall   Ep3RxLoopBack               ; 82930 has received a packet from HC

F_EP3_RX:
        jnb     FRXD3,  EXIT_FUNCTION_ISR
        mov     EPINDEX,#03
        lcall   Ep3RxLoopBack               ; 82930 has received a packet from HC
        lcall   Ep3TxLoopBack

        mov     A, FIFLG                      ; Check to see if any other Interrupts are pending.
        jz      EXIT_FUNCTION_ISR
        ljmp    ProcessFunctionEndpoints    ; Look at all Interrupt flags again

EXIT_FUNCTION_ISR:
;         lcall  FifoWatchDog
        pop     EPINDEX
        pop     B
        pop     ACC
        pop   PSW1
        pop   PSW

        reti









;COMMENT *------------------------------------------------------------
;Function name     : ProcessOutToken
;Brief Description : Services all OUTs on EP0.
;                  : This routine checks to see if this is an OUT token oor
;                  : SETUP token.  If a SETUP token then the Control COmmand
;                  : State machine is initilized to SETUP STAGE
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
ProcessOutToken:

        anl     FIFLG,   #EP0_RX_CLR                      ; Clear the interrupt bit.
        jmp     ProcCommand

ProcCommand:
        mov     A,     RXSTAT
        jnb     ACC.6, CheckOutStatusPhase              ; Is this a setup packet??



                                                        ; Now Check for Data still in FIFO.
                                                        ; If this is true then the function
                                                        ; did not see the ACK form the host.
        mov     A,      TXFLG
        anl     A,      #0C0h
        jZ      NoEP0Error

        setb    TXCLR                                    ; Flush the Transmit FIFOS in case
                                                         ; a null packet is still left.
        mov     TXCNTL, #00h
        setb    TXCLR

NoEP0Error:
                                                         ; Check to see if the stall bit is set.
        mov     A, EPCON
        anl     A, #0C0h
        jz      NoEp0Stall
        anl     EPCON, #03Fh                             ; Clear the stalls
        orl     TXSTAT, #88h                             ; Set data toggle on TX ep0.
NoEp0Stall:
        lCall   SetupReceived
        setb    RXFFRC                                  ; Update receive FIFO state
        clr     RXSETUP

        jmp     ReturnProcessOutToken

CheckOutStatusPhase:
        mov     A,     gbSetupSeqRX
        cjne    A,     #STATUS_PHASE, CheckDataPhase     ; Is this the status phase of a "GET"
                                                         ; command?

        setb    RXFFRC                                   ; Update receive FIFO state


        mov     A,     #SETUP_PHASE                      ; Update the state machine-Expect
                                                         ; a setup packet
        mov     gbSetupSeqRX, A
        mov     gbSetupSeqTX, A
        jmp     ReturnProcessOutToken

            ;---------------------------------------------------------------
            ; -   Control Write Data Stage
            ;---------------------------------------------------------------

                ; If this is a control write command with a datastage then this
                ; routine will be called on all data stages of the control write.
                ; When all the data has been collected(Bytes received=wLength)
                ; the actual routine is called.  The size of data is limited to this
                ; buffer length.
                ; THE CALLING CODE MUST THEN CALL SetUpControlWriteStatusStage to allow
                ; the status stage to continue.  The user must NOT do this themselves.
                ; Later in the life of this code, other features will be added here.

CheckDataPhase:
        cjne    A,     #DATA_PHASE, BadOutToken
                                       ; Are we processing a Control Write,
                                       ; i.e. Set Descr...
                                       ; Added to handle control writes with data stages.
                                       ; When a control Write with a data stage is detected
                                       ; the data is placed in the buffer 'CntlWriteDataBuffer'
                                       ; When all the data
                                       ; has been collected(Bytes received=wLength) the actual routine is
                                       ; called.  The size of data is limited to this buffer length.
                                       ;---------------------------------------------------------
                                       ;------------------- NOTE --------------------------------
                                       ;---------------------------------------------------------
                                       ; For this routine to work all the data must be stored below
                                       ; 100h as I am using byte addressing.  Also, since 80-FF is used
                                       ; as SFRs and I don't want to for the user to use indirect
                                       ; addressing, the data must ne stored between 20h-7Fh.
                                       ; Also, these routines will only work for data sets of less than
                                       ; 256.  But the above limitations put this the max much ower than
                                       ; this. MaxBuffer = (7F-20h-Other varaibles in this region)


         push    R0
         mov     A,     #CntlWriteDataBuffer         ; Get location of buffer

         add     A,     CntlWriteDataPntr            ; Add the offset
         mov     R0,    A                            ; R0 now contains the location to start storing the
                                                     ; data.

                                                     ; Update the data stored in memory
         mov     A,     RXCNTL                       ; Get number of bytes to move
         add     A,     CntlWriteDataPntr            ; Add number received
         mov     CntlWriteDataPntr,  A               ; update memory variable

         mov     A,     RXCNTL
         JZ      RdDone                              ; If no data in the buffer, then exit.

ReadData:
         mov     @R0,   RXDAT                        ; Get the data and store it.
         inc     R0
         djnz    ACC,   ReadData
         pop     R0
RdDone:
         setb    RXFFRC                              ; Update receive FIFO state

                                                     ; Now check to see if this was the last
                                                     ; read by checking if (Bytes received=wLength)
         mov     A,    CntlWriteDataPntr
         cjne    A,    wLength+1, NeedMoreData       ; If this is not equal to the expected, then jmp around.

                                                     ; When all the data has been received, the
                                                     ; other routines in this program will
                                                     ; be called to process it.
ProcessControlWriteData:

        push     DPX                                 ; Processing the jump table will
                                                     ; corrupt DPX.  Save it here
        lcall    DoJumpTable                         ; At this point all data has been
                                                     ; stored and all we need to do now is to
                                                     ; process it.
        pop      DPX                                 ; Restore DPX
        jmp      ReturnProcessOutToken

NeedMoreData:

CheckCommand2:

BadOutToken:
        orl      EPCON, #0C0h                        ; Who knows what this was.  Stall the EP.
ReturnProcessOutToken:
        Ret


;COMMENT *------------------------------------------------------------
;Function name     : SetupReceived
;Brief Description : Service all Setup Tokens recd. on EP0
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
SetupReceived:
         mov     A,     RXCNTL                   ; Get the no. of bytes
         clr     CY

         subb    A,     #8                       ; 8 is length of all setup packets.
         JNZ     ReturnSetup                      ; If less than 8 bytes recd.
                                                 ; Return

                                                 ; Since buffer will reside within the
                                                 ; the first 255 bytes, I can use
                                                 ; register indirect addressing
        ; Move FIFO to command buffer.
        ; Notice byte swapping of word fields
        ; For Word Fields make USB Little Endian words->'251 Big Endian words
        clr      EDOVW
        mov      COMMAND_BUFFER,   RXDAT          ; bmRequestType
        mov      COMMAND_BUFFER+1, RXDAT          ; bRequest
        mov      COMMAND_BUFFER+3, RXDAT          ; wValue LSB
        mov      COMMAND_BUFFER+2, RXDAT          ; wValue MSB
        mov      COMMAND_BUFFER+5, RXDAT          ; wIndex LSB
        mov      COMMAND_BUFFER+4, RXDAT          ; wIndex MSB
        mov      COMMAND_BUFFER+7, RXDAT          ; wLength LSB
        mov      COMMAND_BUFFER+6, RXDAT          ; wLength MSB

        push     DPX                              ; Processing the jump table will
                                                  ; corrupt DPX.  Save it here

        lCall    ProcessSetup
        pop      DPX                              ; Restore DPX
ReturnSetup:
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : ProcessSetup
;Brief Description : Process a Setup token recd. on EP0. Thile some of the
;                  : code may look sifficult to understand the end result is not.
;                  : The following simply prepares a byte of data for use in a jump table.
;                  : The code compresses the 8 byte bmRequestValue into 4 1/2
;                  : bits by removing bits 2,3 & 4.  These bits are never used
;                  : and it allows the jump table to be signfigantly smaller.
;                  : By using this jump table, the code size reduces by several
;                  : hundred bytes over the entire code!
;                  : THIS FIRMWARE IS ASSUMES BITS 2,3 & 4 are zero!!!!
;                  : By compressing the byte down, we limit the size
;                  : of the jump table.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
ProcessSetup:

        ; The First step is setting up the Stage tracing variable by examing the
        ; bmRequest value.  This will tell us if this is a control Write
        ; or control read command.  For right now we will assume that this
        ; is a no data command and will therefore pre-initilize the data
        ; byte counters used to send data back, to zero.

        mov     gbFControlBufferBytesLeft,     #00h
        mov     gbFControlBufferBytesLeft + 1, #00h
        mov     A,            bmRequestType
        jb      ACC.7,        SetupGetCommand

SetupSetCommand:
        mov     gbSetupSeqRX, #DATA_PHASE        ; Advance State Machine to next state
        mov     gbSetupSeqTX, #STATUS_PHASE
                                                 ; Now check to see if this is a control write with a data stage.
        mov     A,            wLength
        orl     A,            wLength+1
        jz      DoJumpTable                      ; If this is a no data command then process it
        mov     CntlWriteDataPntr, #0            ; Initilize the data pointer for future control write
                                                 ; data stages.
        ret                                      ; If we are expecting data then don't
                                                 ; process the command yet.  Exit and wait
                                                 ; for the rest of the data to come in.



SetupGetCommand:
        mov     gbSetupSeqRX, #STATUS_PHASE      ; Advance State Machine to next state
        mov     gbSetupSeqTX, #DATA_PHASE

DoJumpTable:
        ; This table will jump to the correct subroutine
        ; to handle the type of command contained in bmRequestType
        ; The new jmp table will be compressed by shifting and rotating
        ; out bits, 2,3 & 4.
        ; Place bmRequestType in the following order and then do the jump table
        ; on it.
        ; xx65107x
        ; if bits 65 == 11, Reserved = Error
        ; Unless you have time, don't spend a lot of time tracing the algorythm
        ; It's fancy and it works.  If you don't understand it go ask someone for a quarter.


        mov     A,      bmRequestType            ; Get the value.

        anl     A,      #0E3h                    ; Clear out bits 2,3,4 since
                                                 ; we don't need these
                                                 ; Reg A now looks like 765xxx10
        RL      A                                ; Put bits 1,0,& 7 in new placement
        RL      A                                ; Leave LSB cleared so jump is the number of words.
                                                 ; xxxx1076
CheckBit6:                                       ; 6 is currently in bit 0 position,
        jnb     ACC.0,  CheckBit5                ; Convert it to bit 5 position
        setb    ACC.5                            ; xx6x107x
CheckBit5:                                      ; Bit 5 is currently at 7 position
        jnb     ACC.7,  CheckValidType           ; Convert it to bit 4 position
        setb    ACC.4                            ; xx65107x

CheckValidType:                                  ;
        jnb     ACC.5,  GoodCommand              ; If this bit (6) is clear we know
                                                 ; it's a valid value
        jb      ACC.4,  ReservedCommand          ; Bit (6) was set, if bit 5 is set it's
                                                 ; a reserved command.
        jmp     GoodCommand

ReservedCommand:
        orl     EPCON , #0C0h                     ; Stall EP0.
        ret


                                                     ; THis code will branch to the correct jump statement
                                                     ; in the bmRequestJumpTable below.
GoodCommand:                                         ; Code added to convert AJMP table to LJMP table.
        anl     A, #3Eh                              ; Multiply SJMP offset by 3/2 to get LJMP offsett.
        mov     B, A                                 ; Save the original
        rr      A                                    ; Divide origianl by two
        anl     A, #1fH                              ;
        clr     CY                                   ;
        ADD     A, B                                 ; 2/2 + 1/2 = 3/2

        mov     DPTR,   #bmRequestJumpTable
        IF PLC
			mov     DPXL,   #LOW HIGH16(GoodCommand)     ; Get Page of Jump Table.
		ENDIF
		IF KEIL
			mov     DPXL,   #BYTE2(GoodCommand)
		ENDIF
                                                     ; Low byte of the upper 16 bits of the 32 bit address of the
                                                     ; jump table.
                                                     ; Is this code in RAM or ROM
        jmp     @A+DPTR                              ; Used because I use RISM sometimes
                                                     ; which places code in RAM

;---------------------------------------
;-- bmRequest Jump Table ---------------
;-- The order of these are based on the
;-- compresion algorythm used above.
;-- Each of these instructions occupy two bytes of
;-- ROM.  Do not change AJMP to LJMP as the algorytm depends on the
;-- 2 byte length of AJMP.  LJMP is 3 bytes long
;-- ------------------------------------
bmRequestJumpTable:
        LJMP    StandardSetDeviceCommand
        LJMP    StandardGetDeviceCommand
        LJMP    StandardSetInterfaceCommand
        LJMP    StandardGetInterfaceCommand
        LJMP    StandardSetEndpointCommand
        LJMP    StandardGetEndpointCommand
        LJMP    StandardSetOtherCommand
        LJMP    StandardGetOtherCommand

        LJMP    ClassSetDeviceCommand
        LJMP    ClassGetDeviceCommand
        LJMP    ClassSetInterfaceCommand
        LJMP    ClassGetInterfaceCommand
        LJMP    ClassSetEndpointCommand
        LJMP    ClassGetEndpointCommand
        LJMP    ClassSetOtherCommand
        LJMP    ClassGetOtherCommand

        LJMP    VendorSetDeviceCommand
        LJMP    VendorGetDeviceCommand
        LJMP    VendorSetInterfaceCommand
        LJMP    VendorGetInterfaceCommand
        LJMP    VendorSetEndpointCommand
        LJMP    VendorGetEndpointCommand
        LJMP    VendorSetOtherCommand
        LJMP    VendorGetOtherCommand





;-----------------------------------------------------------------
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs
;S
;S          STANDARD TYPE COMMANDS FIRST
;S
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs
;-----------------------------------------------------------------

;COMMENT *------------------------------------------------------------
;Function name     : GetStandardDeviceCommand:
;Brief Description : Process a Get Standard Device Command Setup Token
;                  : This can only be a Get (Device or Configuration) Descriptor,
;                  : or Get Device Status, Get Configuration.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
StandardGetDeviceCommand:
        mov     A,     bRequest
        cjne    A,     #GET_DESCRIPTOR, Jump2_CheckGetConfiguration
        sjmp    GET_DESCRIPTOR_TYPE
Jump2_CheckGetConfiguration:
        ljmp    CheckGetConfiguration
GET_DESCRIPTOR_TYPE:
        mov     A,     bDescriptorType
        cjne    A,     #DEVICE_DESCR, CheckConfigDescriptor

        ; ********************** GET DESCRIPTOR,  DEVICE *******************
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(BEGIN_DEVICE_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(BEGIN_DEVICE_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(BEGIN_DEVICE_DESCRIPTOR)
		ENDIF
		IF KEIL
		    mov     gbFControlBufferLocation,   #BYTE2(BEGIN_DEVICE_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #BYTE1(BEGIN_DEVICE_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #BYTE0(BEGIN_DEVICE_DESCRIPTOR)
		ENDIF
        mov     A,  #12h
        mov     B,  #00h
        jmp     LoadBuffer

CheckConfigDescriptor:
        cjne    A,     #CONFIG_DESCR, CheckStringDescriptor
IF FUB_BOARD == DISABLED
   ; if not a FUB board just assume SELF powered
   ljmp    GiveSelfPoweredDescr
ELSE
   ;FUB BOARD - check Mode 0 Jumper to determine if bus or self powered
   ; Self Powered vs Bus Powered : Bit 1.0 = 1 = self Powered, 0 = bus powered
   jnb     PWR_SEL_SWITCH, GiveBusPoweredDescr
ENDIF

GiveSelfPoweredDescr:
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(BEGIN_CONFIG1_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(BEGIN_CONFIG1_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(BEGIN_CONFIG1_DESCRIPTOR)
		ENDIF
		IF KEIL
			mov     gbFControlBufferLocation,   #BYTE2(BEGIN_CONFIG1_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #BYTE1(BEGIN_CONFIG1_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #BYTE0(BEGIN_CONFIG1_DESCRIPTOR)
		ENDIF
        sjmp    DoConfigLoad

GiveBusPoweredDescr:
        IF PLC
 			mov     gbFControlBufferLocation,   #LOW HIGH16(BEGIN_CONFIG2_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(BEGIN_CONFIG2_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(BEGIN_CONFIG2_DESCRIPTOR)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(BEGIN_CONFIG2_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #BYTE1(BEGIN_CONFIG2_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #BYTE0(BEGIN_CONFIG2_DESCRIPTOR)
		ENDIF

DoConfigLoad:
        ; Note since config descriptors are same length - this routine works for
        ; both config1 and config2
        mov     A,  #LOW  (END_CONFIG1_DESCRIPTOR - BEGIN_CONFIG1_DESCRIPTOR)
        mov     B,  #HIGH (END_CONFIG1_DESCRIPTOR - BEGIN_CONFIG1_DESCRIPTOR)
        jmp     LoadBuffer

CheckStringDescriptor:
        cmp     R11,      #STRING_DESCR    ; R11 == Accum A
        je      Check4Index0
        ljmp    CheckForOtherDescr      ; not string descriptor check for other
        ; ******************************************************************
        ; ********************** GET DESCRIPTOR,  STRING *******************
        ; ******************************************************************
Check4Index0:
        ; if string index = 0 ... regardless of language ID, return the language ID's
        ; supported by this device
        mov     A,    bDescriptorIndex
CheckString0:
        cjne    A,   #0, CheckStringLangId
        ; *********** Return list of Languages Supported ***********
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_0)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_0)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_0)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_0)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_0)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_0)
		ENDIF

        mov     A,     #LOW (STRING_1-STRING_0)
        mov     B,     #HIGH(STRING_1-STRING_0)
        ljmp     LoadBuffer

CheckStringLangId:
; First check to make sure wIndex = language ID = 0 or 0x0409 -> English.  If not stall.
        mov     B, wIndex       ; move high byte - Sub language ID to B
        mov     A, wIndex+1     ; move low byte  - Primary language ID to A
        cmp     R11,    #09h    ; R11 == A ... low byte
        jne     Go_Bad_Lang_ID
        cmp     R10,    #04h    ; R10 == B ... high byte
        je      Get_Str
Go_Bad_Lang_ID:
        ljmp    ReturnBADSTDGetDeviceCommand

; NEW CODE-Return English ID Codes
Get_Str:
        mov     A,    bDescriptorIndex
CheckString1:
        cjne    A,   #1, CheckString2
        ; *********** Return MANUFACTURER String *************
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_1)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_1)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_1)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_1)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_1)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_1)
		ENDIF

        mov     A,     #LOW (STRING_2-STRING_1)
        mov     B,     #HIGH(STRING_2-STRING_1)
        ljmp     LoadBuffer


CheckString2:
        cjne    A,   #2, CheckString3
        ; *********** Return PRODUCT String *************
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_2)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_2)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_2)
		ENDIF
		IF KEIL
	        mov     gbFControlBufferLocation,   #BYTE2(STRING_2)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_2)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_2)
		ENDIF

        mov     A,     #LOW (STRING_3-STRING_2)
        mov     B,     #HIGH(STRING_3-STRING_2)
        ljmp     LoadBuffer
CheckString3:
        cjne    A,   #3, CheckString4
        ; *********** Return SERIAL Number String *************
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_3)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_3)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_3)
		ENDIF
		IF KEIL
	        mov     gbFControlBufferLocation,   #BYTE2(STRING_3)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_3)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_3)
		ENDIF

        mov     A,     #LOW (STRING_4-STRING_3)
        mov     B,     #HIGH(STRING_4-STRING_3)
        ljmp     LoadBuffer
CheckString4:
        cjne    A,   #4, CheckString5
        ; *********** Return CONFIGURATION String ***********
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_4)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_4)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_4)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_4)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_4)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_4)
		ENDIF

        mov     A,     #LOW (STRING_5-STRING_4)
        mov     B,     #HIGH(STRING_5-STRING_4)
        ljmp     LoadBuffer
CheckString5:
        cjne    A,   #5, ReturnBADSTDGetDeviceCommand
        ; *********** Return INTERFACE String ***********
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_5)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_5)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_5)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_5)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_5)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_5)
		ENDIF

        mov     A,     #LOW (STRING_6-STRING_5)
        mov     B,     #HIGH(STRING_6-STRING_5)
        ljmp     LoadBuffer

 CheckForOtherDescr:

        sjmp    ReturnBADSTDGetDeviceCommand

LoadBuffer:                                 ; Compare to see which is shorter.
                                            ; The amount asked for or the amount
                                            ; availible.

        push    ACC
        push    B
        clr     CY                          ; A=Actual-wLength=AskedFor
        subb    A,  wLength+1
        mov     A,  B
        subb    A,  wLength
        jc      AskedFor_IsLarger

LengthsMatch:
wLengthIsSmaller:                           ; If Asked for is smaller, replace
                                            ; actual with asked for.
        pop     B
        pop     ACC
        mov     B,  wLength
        mov     A,  wLength+1
        jmp     LoadIt

AskedFor_IsLarger:
        pop     B
        pop     ACC
LoadIt:                                     ; From now on, wLength = bytes remaining.
        mov     gbFControlBufferBytesLeft,   B
        mov     gbFControlBufferBytesLeft+1, A
        Call    LoadControlTXFifo
        jmp     ReturnSTDGetDeviceCommand





CheckGetConfiguration:
        cjne    A,     #GET_CONFIGURATION,  CheckGetStatus
                   ;------------------------------------------------
                   ;- GET CONFIGURATION
                   ;------------------------------------------------
        mov     R11,    CurrentConfiguration
        mov     TXDAT , A
        mov     TXCNTL, #01


        ;------- TBD -------
        jmp     ReturnSTDGetDeviceCommand
CheckGetStatus:
        cjne    A,     #GET_STATUS, ReturnSTDGetDeviceCommand
                   ;------------------------------------------------
                   ;- GET DEVICE STATUS
                   ;------------------------------------------------
        mov     A,      #00h
        ; check the software RWU flag to see if embedded FN remote wakeup is enabled

        mov     A,      EMB_FN_RWU_FLG          ; this will set or clear ACC.1 for RWU

CheckBusSelfPwr:
IF FUB_BOARD == DISABLED
        setb    ACC.0                                   ; set self powered bit
ELSE
        ; check P1.0 Mode 0 jumper for Bus or Self Powered board
        jnb     PWR_SEL_SWITCH,   DoneGetDeviceStatus             ; don't set self powered bit
        setb    ACC.0                                   ; set self powered bit
ENDIF

DoneGetDeviceStatus:
        mov     TXDAT , A
        mov     TXDAT , #00h
        mov     TXCNTL, #02


        ;------- TBD -------
        jmp     ReturnSTDGetDeviceCommand
ReturnBADSTDGetDeviceCommand:

        orl     EPCON , #0C0h                   ; Stall EP0

ReturnSTDGetDeviceCommand:
        ret


;COMMENT *------------------------------------------------------------
;Function name     : StandardGetEndpointCommand:
;Brief Description : Process a Standard Set Endpoint Command Setup Token
;                  : This can only be a Set,Clear Feature - Endpoint Stall
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
StandardGetEndpointCommand:

        mov     A,     bRequest
        cjne    A,     #GET_STATUS,    ReturnBadSTDGetEPCommand
                   ;------------------------------------------------
                   ;- GET ENDPOINT STATUS
                   ;------------------------------------------------
        mov     A,      wIndex + 1
        anl     A,      #0Fh                     ; Mask off all but the endpoint value
        mov     EPINDEX,A                        ; Point the Index register at the

        mov     A,      wIndex + 1               ; Start by clearing out R0
        jb      ACC.7,  GetInStallStatus

GetOutStallStatus:
        mov     A,      EPCON
        jnb     ACC.7,  NotStalled
        mov     A,      #01                      ; Return Stalled
        jmp     DoneWithCommand

GetInStallStatus:
        mov     A,      EPCON
        jnb     ACC.6,  NotStalled
        mov     A,      #01
        jmp     DoneWithCommand

NotStalled:
        mov     A,      #00h


DoneWithCommand:
        anl     EPINDEX,#80h                     ; Point the index back to EP0
        mov     TXDAT , A
        mov     TXDAT , #00h
        mov     TXCNTL, #02
        ret

ReturnBadSTDGetEPCommand:

        orl     EPCON , #0C0h                    ; Stall EP0
ReturnSTDGetEPCommand:
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : SetUpSinglePacketControlReadStatusStage
;Brief Description : Sets the status in the IN buffer and initilizes all the
;                  : registers needed to do a single packet control read.
;                  : This needs to be done so the IN token is processed correctly.
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
SetUpSinglePacketControlReadStatusStage:

        mov     wLength,      #00
        mov     wLength+1,    #00
        mov     gbSetupSeqRX, #STATUS_PHASE      ; Advance State Machine to next state
        mov     gbSetupSeqTX, #DATA_PHASE
        setb    TXOE                             ; Enable data transmit
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : StandardSetEndpointCommand:
;Brief Description : Process a Standard Set Endpoint Command Setup Token
;                  : This can only be a Set,Clear Feature - Endpoint Stall
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
StandardSetEndpointCommand:
        push    EPINDEX
        mov     A,      wIndex+1                 ; Get the endpoint of the stall to clear
        anl     A,      #0Fh                     ; Find out if this is an EP0 CLear Stall Command.
        orl     EPINDEX,A                        ; Setup the EPINDEX to point at correct index.

                               ; Check to make sure this is an Endpoint Stall.
                               ; If it is not then it's a wrong command plus you
                               ; save a few bytes doing it in this order.

        mov     A,      wValue+1
        cjne    A,      #ENDPOINT_STALL, ReturnBadSTDSetEPCommand

        mov     A,      bRequest
        cjne    A,      #CLEAR_FEATURE,  CheckSetEndpointFeature

ClearEndpointFeature:
                   ;------------------------------------------------
                   ;- CLEAR ENDPOINT STALL
                   ;------------------------------------------------
ClearEndpointStall:
        mov     A,      wIndex+1                 ; Get the endpoint of the stall to clear
        anl     A,      #0Fh                     ; Find out if this is an EP0 CLear Stall Command.
        JNZ     ClearNonEP0Stall

        anl     EPCON,  #03Fh                    ; For EP0 Clear both TX & RX stall bits
        jmp     ReturnSTDSetEPCommand

ClearNonEP0Stall:
        mov     A,      wIndex+1                 ; Get the endpoint of the stall to clear
        JB      ACC.7,  ClearInStall             ; For Non EP0, examing the direction bit as well.
ClearOutStall:
        anl     EPCON , #CLEAR_OUT_STALL_MASK
        jmp     ReturnSTDSetEPCommand
ClearInStall:
        anl     EPCON , #CLEAR_IN_STALL_MASK
        jmp     ReturnSTDSetEPCommand


CheckSetEndpointFeature:
        cjne    A,      #SET_FEATURE, ReturnBadSTDSetEPCommand


SetEndpointFeature:
                   ;------------------------------------------------
                   ;- SET ENDPOINT STALL
                   ;------------------------------------------------
SetEndpointStall:
        mov     A,      wIndex+1                 ; Get the endpoint to stall
        JB      ACC.7,  SetInStall
SetOutStall:
        orl     EPCON , #SET_OUT_STALL_MASK
        jmp     ReturnSTDSetEPCommand
SetInStall:
        orl     EPCON , #SET_IN_STALL_MASK
        jmp     ReturnSTDSetEPCommand

ReturnBadSTDSetEPCommand:

        orl     EPCON , #0C0h                  ;Stall EP0
ReturnSTDSetEPCommand:
        pop     EPINDEX
        jmp     SetUpControlWriteStatusStage


;COMMENT *------------------------------------------------------------
;Function name     : StandardSetDeviceCommand:
;Brief Description : Process a Standard Set Device Command Setup Token
;                  : The only valid commands are Set Address,
;                  : Set Configuration.  Other commands which have this
;                  : field but are un-defined are
;                  : ClearDeviceFeature, SetDescriptor, SetDeviceFeature.
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
StandardSetDeviceCommand:

        mov     A,      bRequest
        cjne    A,      #SET_CONFIGURATION, CheckSetDeviceAddress
SetDeviceConfiguration:
                   ;------------------------------------------------
                   ;- SET DEVICE CONFIGURATION
                   ;------------------------------------------------

        ; Check to see what configuration we should take on.
        mov      A,    wValue+1

CheckConfig0:
        cjne     A,    #0, CheckConfig1
        mov      CurrentConfiguration, R11   ; Set up the variables
        Call     ResetFifos                  ; Empty out all of the FIFOs and return to
                                             ; the un configuraed state.
        jb       LC, ReturnSTDSetDevice      ; Are we in low power state?
        setb     LC                          ; If not then goto low power state.
        jmp      ReturnSTDSetDevice
CheckConfig1:
        cjne     A,    #1, CheckConfig2
        mov      CurrentConfiguration, R11   ; Set up the variables

        Call     SetUpConfiguration1
        jmp      ReturnSTDSetDevice

CheckConfig2:
        cjne     A,    #2, ReturnBadSetDeviceCommand


        jmp      ReturnSTDSetDevice

CheckSetDeviceAddress:
        cjne    A,      #SET_ADDRESS, CheckSetDeviceRWU
                   ;------------------------------------------------
                   ;- SET DEVICE ADDRESS
                   ;------------------------------------------------

        ; Set Address should just return.  The command will be executed following
        ; the status stage
        jmp     ReturnSTDSetDevice

CheckSetDeviceRWU:
        cjne    A,      #SET_FEATURE, CheckClearDeviceRWU
        mov     A,      wValue+1
        cjne    A,      #DEVICE_REMOTE_WAKEUP, ReturnBadSetDeviceCommand
        ; set sw flag for RWU enabled
        mov     EMB_FN_RWU_FLG, #02h    ; set the emd fn remote wakeup flag to 02 setting status.1
        jmp     ReturnSTDSetDevice

CheckClearDeviceRWU:
        cjne    A,      #CLEAR_FEATURE, ReturnBadSetDeviceCommand
        mov     A,      wValue+1
        cjne    A,      #DEVICE_REMOTE_WAKEUP, ReturnBadSetDeviceCommand
        ; clear sw flag for RWU disabled
        mov     EMB_FN_RWU_FLG, #00h    ; clear the emd fn remote wakeup flag to 00h
        jmp     ReturnSTDSetDevice

ReturnSTDSetDevice:
        jmp     SetUpControlWriteStatusStage

ReturnBadSetDeviceCommand:
;        push    EPINDEX
;        mov     EPINDEX, #01
;        mov     TXDAT,  #20h
;        mov     TXCNT, #01h
;        pop     EPINDEX

        orl    EPCON ,       #0C0h                ; Stall Endpoint
        ret

StandardSetInterfaceCommand:
        mov     A,      bRequest
        cjne    A,      #SET_INTERFACE, ReturnBadSetDeviceCommand

        mov     A,      wValue+1
        orl     A,      wIndex+1
        jnz     ReturnBadSetDeviceCommand
        mov     CurrentConfig1Interface, R11
        sjmp    ReturnSTDSetDevice

StandardGetInterfaceCommand:
        mov     A,      bRequest
        cjne    A,      #GET_INTERFACE, ReturnBadSetDeviceCommand
        mov     A,      wValue+1
        jnz     ReturnBadSetDeviceCommand
        mov     R11,    CurrentConfig1Interface
        mov     TXDAT , A
        mov     TXCNTL, #01
        ret


StandardSetOtherCommand:
StandardGetOtherCommand:
            ;------------------------------------------
            ; - Unknown Standard Command -- STALL ENDPOINT
            ;------------------------------------------


        orl    EPCON ,       #0C0h                ; Stall Endpoint
        ret

;COMMENT *------------------------------------------------------------
;Function name     : SetUpConfiguration1
;Brief Description : Setup the endpoints to the parameters specified in the
;                  : configuration 1 descriptor.
;                  :
;                  : See below for the actual values.
;                  :
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE


SetUpConfiguration1:

        push    EPINDEX

IF CLOCK_LOW == ENABLED
        setb    LC                           ; LOW clock mode
ELSE
        clr    LC                            ; High MIPs & Power mode
ENDIF

        call    ResetFifos                 ; Place all FIFOs in known state


        mov     EPINDEX, #01               ; EP1
        mov     EPCON, #00FH               ; Non Control, Non ISO, Dual Packet
        orl     FIE,   #0Ch                ; ENable the interupts

        mov     EPINDEX, #02               ; EP2
        mov     EPCON, #00FH               ; Non Control, Non ISO, Dual Packet
        orl     FIE,   #030h               ; ENable the interupts

        mov     EPINDEX, #03               ; EP3
        mov     EPCON, #00FH               ; Non Control, Non ISO, Dual Packet
        orl     FIE,   #0C0h               ; ENable the interupts

        orl     IPL1, #02h

        pop     EPINDEX
        ret

;COMMENT *------------------------------------------------------------
;Function name     : SetUpConfiguration2
;Brief Description : Setup the endpoints to the parameters specified in the
;                  : configuration 2 descriptor.
;                  :
;                  : See below for the actual values.
;                  :
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE


SetUpConfiguration2:

        push    EPINDEX
        clr     LC                         ; High MIPs & Power mode
        call    ResetFifos                 ; Place all FIFOs in known state

        ret
;        mov     EPINDEX, #01               ; For test purposes only,  Should be done in SetConfiguration
;        mov     EPCON, #00FH               ; Non COntrol, Dual Packet, Non ISO
;        orl     TXCON, #10h                ; 512/512
;        lcall   EP1_TX_ISR
;        setb    FTXIE1                     ; Enable TX1 Interrupt


;        mov     EPINDEX, #02               ; For test purposes only,  Should be done in SetConfiguration
;        mov     EPCON, #00FH               ; Non Control, Dual Packet
;        setb    TXCON.3                    ; ISO PIPE
;        lcall   EP2_TX_ISR
;        setb    FTXIE2                     ; Enable TX2 Interrupt

;        mov     EPINDEX, #03               ; For test purposes only,  Should be done in SetConfiguration
;        mov     EPCON, #00FH               ; Non Control, Dual Packet
;        setb    TXCON.3                    ; ISO PIPE
;        lcall   EP3_TX_ISR
;        setb    FTXIE3                     ; Enable TX2 Interrupt
;        mov     EPINDEX, #02               ; For test purposes only,  Should be done in SetConfiguration
;        mov     EPCON, #00FH               ; Non Control, Dual Packet
;        setb    TXCON.3                    ; ISO PIPE
;        lcall   EP3_TX_ISR
;        setb    FTXIE3                     ; Enable TX2 Interrupt


;COMMENT *------------------------------------------------------------
;Function name     : SetUpConfiguration0
;Brief Description : Setup the endpoints to the parameters specified in the
;                  : configuration 1 descriptor.
;                  :
;                  : See below for the actual values.
;                  :
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE

ResetFifos:
        ; This routine flushes and clears all of the fifos.
        ; THe routine also sets data toggle back to zero as
        ; defined in the USB spec.  This routine would be called
        ; when ever you change configurations.
        ; Subsets of this routine sould be called when changing interfaces.

        anl    FIE,     #03h
        anl    FIFLG,   #03h
        mov    A,       #03h        ; Number of FIFOS
ResetFifoLoop:
        mov    EPINDEX, A
        orl    TXCON,   #80h        ; Flush the TX FIFOs
        orl    RXCON,   #80h        ; Flush the RX FIFOs

        push   R12
        mov    R12,     TXSTAT
        anl    R12,     #07Fh       ; clear TXSEQ
        orl    R12,     #08h        ; set TXSOVW
        mov    TXSTAT,  R12         ; reset data toggle back to zero
        mov    R12,     RXSTAT
        anl    R12,     #07Fh       ; clear RXSEQ
        orl    R12,     #08h        ; set RXSOVW
        mov    RXSTAT,  R12         ; reset data toggle back to zero
        pop    R12

        mov    EPCON ,  #040h       ; Reset value
        djnz   ACC,     ResetFifoLoop
        ret

;-----------------------------------------------------------------
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs
;S
;S          END OF STANDARD TYPE COMMANDS
;S
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs
;-----------------------------------------------------------------
;-----------------------------------------------------------------
;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
;C
;C          START OF CLASS COMMANDS
;C
;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
;-----------------------------------------------------------------


ClassGetDeviceCommand:
;IF PROC == i82930HX
;        mov     P1, #0FFh
;        mov     P1, #020h
;        call    GetClassDeviceCommand
;        ret
;ENDIF
ClassGetOtherCommand:
;IF PROC == i82930HX
;        call    GetClassOtherCommand
;ENDIF
;        ret

ClassSetDeviceCommand:
;IF PROC == i82930HX
;        mov     P1, #0FFh
;        mov     P1, #022h
;        call    SetClassDeviceCommand
;        call    SetUpControlWriteStatusStage      ; We know this will was a single packet only
;        ret                                       ; command so go ahead and prepare/arm the status stage
;ENDIF
ClassSetEndpointCommand:
ClassSetOtherCommand:
;IF PROC == i82930HX
;        mov     P1, #0FFh
;        mov     P1, #023h
;        call    SetClassOtherCommand
;        call    SetUpControlWriteStatusStage      ; We know this will was a single packet only
;                                                  ; command so go ahead and prepare/arm the status stage
;        ret
;ENDIF

ClassSetInterfaceCommand:
ClassGetInterfaceCommand:


ClassGetEndpointCommand:

        orl    EPCON ,       #0C0h         ;Stall Endpoint
        ret

;-----------------------------------------------------------------
;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
;C
;C          END OF CLASS COMMANDS
;C
;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
;-----------------------------------------------------------------

;-----------------------------------------------------------------
;VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
;V
;V          START OF VENDOR COMMANDS
;V
;VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
;-----------------------------------------------------------------

VendorSetDeviceCommand:
            lcall   VendorSetDeviceCommandExec
            call    SetUpControlWriteStatusStage      ; We know this will was a single packet only
            ret
VendorGetDeviceCommand:
            lcall   VendorGetDeviceCommandExec
            ret
VendorSetInterfaceCommand:
VendorGetInterfaceCommand:
VendorSetEndpointCommand:
VendorGetEndpointCommand:
VendorSetOtherCommand:
VendorGetOtherCommand:
            ;------------------------------------------
            ; - UnknownVendorCommand -- STALL ENDPOINT
            ;------------------------------------------
        orl    EPCON ,       #0C0h         ;Stall Endpoint
        ret

;-----------------------------------------------------------------
;VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
;V
;V          END OF VENDOR COMMANDS
;V
;VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
;-----------------------------------------------------------------

;-----------------------------------------------------------------
;UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
;U
;U          UTILILITY ROUTINES
;U
;UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
;-----------------------------------------------------------------

;COMMENT *------------------------------------------------------------
;Function name     : ProcessInToken
;Brief Description : Services all INs on EP0.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
ProcessInToken:
;(HUB)
;        jb      EPINDEX.7, ProcessHubInToken        ; Is this a HUB or NON Hub Call?

        anl     FIFLG,   #EP0_TX_CLR                 ; clear the interrupt bit
        jmp     CheckInStatusPhase

ProcessHubInToken:
;        anl     HIS,    #EP0_TX_CLR                 ; clear the interrupt bit

CheckInStatusPhase:

        mov     A,      gbSetupSeqTX                ; read state variable
        cjne    A,      #STATUS_PHASE,SendDataBack  ; Should this be the end to
                                                    ; a setup sequence


StatusPhaseDone:
        lCall   CompleteSetCommand
        mov     gbSetupSeqTX, #SETUP_PHASE          ; Set state var. to expect setup.
        mov     gbSetupSeqRX, #SETUP_PHASE

        jmp     ReturnProcessIn

SendDataBack:
        cjne    A,      #DATA_PHASE, ReturnProcessIn
        call    LoadControlTXFifo

ReturnProcessIn:
        Ret


;COMMENT *------------------------------------------------------------
;Function name     : CompleteSetCommand
;Brief Description : Called after the status phase of a set command has
;                  : completed.  This is called everytime there is a
;                  : xmit status stage.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
CompleteSetCommand:
        mov     A,      bRequest                    ; If this was not a Std. Set
                                                    ; command then return.

        cjne    A,      #SET_ADDRESS, CheckNextCommand
   ;------------------------------------------------
   ;- SET ADDRESS
   ;------------------------------------------------
DoSetAddress:
;
SetFunctionAddress:
        mov     FADDR,  wValue+1                    ; Set to new address
        jmp     ReturnCompleteSet

CheckNextCommand:
ReturnCompleteSet:
        ret

;COMMENT *------------------------------------------------------------
;Function name     : SetUpControlWriteStatusStage
;Brief Description : Sets the status in the IN buffer.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
SetUpControlWriteStatusStage:
        mov     TXCNTL, #00                      ; Setup Null Packet
;        setb    TXOE0                            ; Enable data transmit
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : LoadControlTXFifo
;Brief Description : Copy data from the location pointed to by
;                  : the three byte value gbFControlBufferLocation.
;                  : The number of bytes left to transmit are stored in
;                  : gbFControlBufferBytesLeft.  If zero bytes are left then
;                  : a Null packet is loaded even if the null/short packet is
;                  : not needed.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
LoadControlTXFifo:
        push    R0                                  ; Need to save this register
        push    DPX
        mov     DPXL,   gbFControlBufferLocation    ; Get location of data to send.
        mov     DPH,    gbFControlBufferLocation+1
        mov     DPL,    gbFControlBufferLocation+2



        mov     A,      gbFControlBufferBytesLeft   ; First check to sei if any data is availble
        orl     A,      gbFControlBufferBytesLeft+1 ; to send.
        jnz     CntlDataAvail

        mov     R0,     #0                          ; if there is data do normal flow
        ljmp    ControlArmTx                        ; if none, do null packet

CntlDataAvail:
        mov     R0,     #0                          ; Number of bytes in FIFO- Awlays <=16
        mov     A,      DPXL
        JZ      DataInRAM

;-----------------------------------------------
; Data is in ROM, use instrcutions to pull from ROM.
;-----------------------------------------------
DataInROM:
        mov     A,      #00h

        movc    A,      @A+DPTR                     ; Get Data to transmit

        mov     TXDAT , A
        inc     DPTR
        inc     R0                                  ; Increment the number of bytes in FIFO
        djnz    gbFControlBufferBytesLeft+1, ROMCheckMaxPacket        ; If not zero, the continue.

ROMCheckUpper1:
        mov     A,       gbFControlBufferBytesLeft  ; If upper byte of wLength is also zero, buffer is empty.
        jz      ControlTxUpd                        ; Are we done with the buffer
        dec     A                                   ; If it's not zero dec. the upper byte as well.
        mov     gbFControlBufferBytesLeft, A        ; And store it.

ROMCheckMaxPacket:
        cjne    R0,      #EP0_MAX_PACKET_SIZE, DataInROM    ; Loop until FIFO is Full
        jmp     ControlTxUpd                       ; Done with this FIFO.


;-----------------------------------------------
; Data is in RAM, use instrcutions to pull from RAM.
;-----------------------------------------------

DataInRAM:


        movx    A,      @DPTR                       ; Get Data to transmit
        mov     TXDAT , A
        inc     DPTR
        inc     R0                                  ; Increment the number of bytes in FIFO
        djnz    gbFControlBufferBytesLeft+1, RAMCheckMaxPacket        ; If not zero, the continue.

RAMCheckUpper1:
        mov     A,       gbFControlBufferBytesLeft  ; If upper byte of gbFControlBufferBytesLeft is also zero, buffer is empty.
        jz      ControlTxUpd                        ; Are we done with the buffer
        dec     A                                   ; If it's not zero dec. the upper byte as well.
        mov     gbFControlBufferBytesLeft, A        ; And store it.

RAMCheckMaxPacket:
        cjne    R0,      #EP0_MAX_PACKET_SIZE, DataInRAM    ; Loop until FIFO is Full


ControlTxUpd:
        mov     gbFControlBufferLocation+1, DPH      ; Update read pointers.
        mov     gbFControlBufferLocation+2, DPL

ControlArmTx:
        mov     TXCNTL, R0                          ; Write count into TXCNT register
        setb    TXOE                                ; Enable data transmit
ReturnLoadCntl:
        pop     DPX
        pop     R0
        Ret


;COMMENT *------------------------------------------------------------
;Function name     : GetOUTData
;Brief Description : takes data from the FIFO, Puts it in memory and
;                  : then updates writes it to the fifo.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
;GetOUTData:
;        mov     WR26, #LOW16(OUT_BUFFERS)
;        mov     R7, RXCNTL                      ; Read count of bytes rec'd
;        mov     @WR26, R7                       ; Store the count in the OUT_BUFFERS space.
;        add     WR26, #01h                      ; Increment mem pointer

;        orl     R7, R7                          ; Set flags
;        je      Return

;WriteToOUTBuffer:
;        mov     R8, RXDAT
;        mov     @WR26, R8
;        inc     WR26, #01h
;        djnz    R7, WriteToOUTBuffer

;Return:
;        Ret

;COMMENT *------------------------------------------------------------
;Function name     : INIT_FUNCTION_EP0
;Brief Description : Initialize USB SFRs
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
INIT_FUNCTION_EP0:                          ; EP0 Comes up as it should except that
                                   ; all flow control is turned off except for
                                   ; OE bits.  This will turn them on so we can
                                   ; accept all data.
                                   ; All other endpoints should not be configured
                                   ; until a Set Configuration command is given.
        push    EPINDEX
        mov     EPINDEX, #00
        mov     EPCON,   #3Fh
        pop     EPINDEX
        orl     FIE,     #03h               ; Enable Function EP0 TX & RX ENpoint Interrupts.


ReturnInitUSB:
        Ret



;COMMENT *------------------------------------------------------------
;Function name     : INIT_USB
;Brief Description : Initialize USB SFRs
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
INIT_USB:                          ; EP0 Comes up as it should except that
                                   ; all flow control is turned off except for
                                   ; OE bits.  This will turn them on so we can
                                   ; accept all data.
                                   ; All other endpoints should not be configured
                                   ; until a Set Configuration command is given.
        mov     EPINDEX, #00
        nop
        nop
        mov     EPCON,   #3Fh
        ;mov     EPCON,   #00h


        Ret

;COMMENT *------------------------------------------------------------
;Function name     : INIT_VARIABLES
;Brief Description : Initializes global variables
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
INIT_VARIABLES:
;Init SETUP VARIABLES

        mov     R0, #00h
        mov     Heart1, R0
        mov     Heart1+1, R0
        mov     gbSetupSeqRX, R0                       ; SetupSeq is set to

        mov     gbSetupSeqTX, R0                       ; STATUS_PHASE
        mov     gbFControlBufferLocation, R0
        mov     gbFControlBufferLocation+1, R0
        mov     gbFControlBufferLocation+2, R0

        mov     gbFControlBufferBytesLeft, R0

        mov     WR0, #0                    ; Zero Out Counter
        mov     WR2, WR0
        mov     EP1_TX_COUNTER,     DR0
        mov     EP2_TX_COUNTER,     DR0
        mov     EP3_TX_COUNTER,     DR0
        mov     EP1_TX_ERR_COUNTER, DR0
        mov     EP2_TX_ERR_COUNTER, DR0
        mov     EP3_TX_ERR_COUNTER, DR0

        mov     EP1_RX_ERR_COUNTER, DR0
        mov     EP2_RX_ERR_COUNTER, DR0
        mov     EP3_RX_ERR_COUNTER, DR0
        mov     RWUTimer,  DR0

        mov      Ep1Tx_ERR, R0
        mov      Ep1Tx_OVF, R0
        mov      Ep1Tx_URF, R0
        mov      Ep1Rx_ERR, R0
        mov      Ep1Rx_OVF, R0
        mov      Ep1Rx_URF, R0

        mov      Ep2Tx_ERR, R0
        mov      Ep2Tx_OVF, R0
        mov      Ep2Tx_URF, R0
        mov      Ep2Rx_ERR, R0
        mov      Ep2Rx_OVF, R0
        mov      Ep2Rx_URF, R0

        mov      Ep3Tx_ERR, R0
        mov      Ep3Tx_OVF, R0
        mov      Ep3Tx_URF, R0
        mov      Ep3Rx_ERR, R0
        mov      Ep3Rx_OVF, R0
        mov      Ep3Rx_URF, R0
; EP1 Loop back variables
        mov     Ep1BytesInBuffer  , WR0
        mov     WR0, #Ep1LoopBackBuffer
        mov     Ep1WritePointer,  WR0
        mov     Ep1ReadPointer,  WR0

; EP2 Loop back variables
        xrl     WR0,  WR0
        mov     Ep2BytesInBuffer  , WR0
        mov     WR0, #Ep2LoopBackBuffer
        mov     Ep2WritePointer,  WR0
        mov     Ep2ReadPointer,  WR0

; EP3 Loop back variables
        xrl     WR0,  WR0
        mov     Ep3BytesInBuffer  , WR0
        mov     WR0, #Ep3LoopBackBuffer
        mov     Ep3WritePointer,  WR0
        mov     Ep3ReadPointer,  WR0
; Initialize EMB_FN_RWU_FLG to 00h
        mov     EMB_FN_RWU_FLG,  R0
ReturnInit:
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : RightCylon & LeftCylon
;Brief Description : Does a cylong pattern on the LEDs
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;========================================================================
; Right Cylon Pattern  on Port1
;========================================================================
RightCylon:
        push   WR2
        push   ACC
        mov    WR2, #00
        mov    A,   #80h
CylonRightLoop:
        inc   WR2, #1
        cmp   R2,  #20h
        jne   CylonRightLoop
        srl   R11
        mov   LED_PORT, A
        mov   WR2, #00h
        jnb   ACC.0, CylonRightLoop
        pop   ACC
        pop   WR2
        ret
;========================================================================
; Left Cylon Pattern on Port1
;========================================================================

LeftCylon:
        push   WR2
        push   ACC
        mov    WR2, #00
        mov    A,   #01h
CylonLeftLoop:
        inc   WR2, #1
        cmp   R2,  #20h
        jne   CylonLeftLoop
        sll   R11
        mov   LED_PORT, A
        mov   WR2, #00h
        jnb   ACC.7, CylonLeftLoop
        pop   ACC
        pop   WR2
        ret
;========================================================================
;========================================================================


;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 1 ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : EP1_TX_ISR
;Brief Description : Acts as an Infinite source of 32 byte data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
EP1_TX_ISR:
                  ; First check to see if there is room in the FIFO
EP1TXCheckEveryThing:
        anl     FIFLG,     #EP1_TX_CLR       ; CLear Interrupt Pending Flag
        jb      TXERR,   HandleTX1Error
        jnb     TXFIF0,  RoomAvailable
        jnb     TXFIF1,  RoomAvailable     ; Use if double buffered
        jmp     NoRoomAvailable

RoomAvailable:

        push    DR0
        mov     DR0,     EP1_TX_COUNTER
        mov     A,       #(EP1_TX_FIFO_SIZE/8)
DWORD_LOOP:
        mov     TXDAT,   R3
        mov     TXDAT,   R2
        mov     TXDAT,   R1
        mov     TXDAT,   R0
        mov     TXDAT,   R3
        mov     TXDAT,   R2
        mov     TXDAT,   R1
        mov     TXDAT,   R0
        djnz    ACC,     DWORD_LOOP
        mov     TXCNTH,  #HIGH (EP1_TX_FIFO_SIZE)              ; Write the high byte first.  This only needs to
                                          ; be done on EP1
        mov     TXCNTL,  #LOW (EP1_TX_FIFO_SIZE)
        inc     DR0,     #01
        mov     EP1_TX_COUNTER, DR0
        pop     DR0
        jmp     EP1TXCheckEveryThing     ; Since this is a bulk EP, go see if we need to do more stuff.

HandleTX1Error:
        orl     EPCON,   #SET_IN_STALL_MASK
NoRoomAvailable:                           ; At this point the stack needs to be cleaned up.
        ret


;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 2 ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : EP2_TX_ISR
;Brief Description : Acts as an Infinite source of 8 byte ISOC data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it along with the current SOF Value.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
EP2_TX_ISR:
                  ; First check to see if there is room in the FIFO
EP2TXCheckEveryThing:
        anl     FIFLG,   #EP2_TX_CLR       ; ISOC Pipe, Do not need to clear this bit.
        jb      TXERR,   HandleTX2Error
        jnb     TXFIF0,  RoomAvailable2
        jnb     TXFIF1,  RoomAvailable2
        jmp     NoRoomAvailable2

RoomAvailable2:

        push    DR0
        mov     DR0,     EP2_TX_COUNTER
DWORD2_LOOP:

        mov     TXDAT,   R3                 ; First load the DWORD, LSB First
        mov     TXDAT,   R2
        mov     TXDAT,   R1
        mov     TXDAT,   R0

;        mov     DR0,     EP2_TX_ERR_COUNTER
        mov     TXDAT,   R3             ; First load the DWORD, LSB First
        mov     TXDAT,   R2
        mov     TXDAT,   R1
        mov     TXDAT,   R0

        mov     TXCNTL,  #EP2_TX_FIFO_SIZE

        inc     DR0,     #01
        mov     EP2_TX_COUNTER, DR0
?t1:
        pop     DR0
        jmp     EP2TXCheckEveryThing     ; Since this is a bulk EP, go see if we need to do more stuff.

HandleTX2Error:
        orl     EPCON,   #SET_IN_STALL_MASK
NoRoomAvailable2:                           ; At this point the stack needs to be cleaned up.
        ret

;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 3 ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : EP3_TX_ISR
;Brief Description : Acts as an Infinite source of 32 byte data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
EP3_TX_ISR:
                  ; First check to see if there is room in the FIFO
EP3TXCheckEveryThing:
        anl     FIFLG,   #EP3_TX_CLR        ; CLear Interrupt Pending Flag
        jb      TXERR,   HandleTX3Error
        jnb     TXFIF0,  RoomAvailable3
        jnb     TXFIF1,  RoomAvailable3     ; Use if double buffered
        jmp     NoRoomAvailable3

RoomAvailable3:

        push    DR0
        mov     DR0,     EP3_TX_COUNTER
        mov     A,       #(EP3_TX_FIFO_SIZE/8)
DWORD_LOOP3:
        mov     TXDAT,   R3
        mov     TXDAT,   R2
        mov     TXDAT,   R1
        mov     TXDAT,   R0
        mov     TXDAT,   R3
        mov     TXDAT,   R2
        mov     TXDAT,   R1
        mov     TXDAT,   R0
        djnz    ACC,     DWORD_LOOP3
;        mov     TXCNTH,  #HIGH (EP3_TX_FIFO_SIZE)              ; Write the high byte first.  This only needs to
                                          ; be done on EP1
        mov     TXCNTL,  #LOW (EP3_TX_FIFO_SIZE)
        inc     DR0,     #01
        mov     EP3_TX_COUNTER, DR0
        pop     DR0
        jmp     EP3TXCheckEveryThing     ; Since this is a bulk EP, go see if we need to do more stuff.

HandleTX3Error:
        orl     EPCON,   #SET_IN_STALL_MASK
NoRoomAvailable3:                           ; At this point the stack needs to be cleaned up.
        ret


;************************************************************************
;************************************************************************
;************************************************************************
;              LOOP BACK DRIVERS HERE
;************************************************************************
;************************************************************************
;************************************************************************



;************************************************************************
;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 1 RX LOOPBACK ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : Ep1RxLoopBack
;Brief Description : Acts as an Infinite source of 32 byte data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
Ep1RxLoopBack:
        push    WR0
        push    WR6
        mov     EP0_ERROR_CNT, #010h
        anl     FIFLG,   #EP1_RX_CLR          ; CLear Interrupt Pending Flag
                  ; First check to see if there is room in the FIFO
Ep1RXCheckEveryThing:
        jb      RXERR,   HandleEp1RxError

; Check to make sure there is room in the buffer.

CheckEp1NewData:
        jb      RXFIF0,  CheckEp1BufferFull
        jb      RXFIF1,  CheckEp1BufferFull
        sjmp    NoEp1RxDataReceived

CheckEp1BufferFull:

        mov     WR0,   Ep1BytesInBuffer
                                                 ; If one packet is put into this
                                                 ; buffer will it wrap durring or after all
                                                 ; pointers have been updated.
        cmp     WR0,   #(Ep1LoopBackBufferSize - EP1_RX_LOOP_BACK_FIFO_SIZE  )

        jg      Ep1RxBufferFull

CheckEp1Wrap:
        mov     R7,    RXCNTL                    ; Get bytes of data in FIFO
        mov     Ep1Temp, R7                      ; Debug (kls)
        xrl     R6,    R6                        ; Clear Upper Byte
        mov     WR0,   Ep1WritePointer           ; Get Write pointer
        add     WR0,   WR6                       ; Add them together.  If their sum is
                                                 ; Greater than the end of the buffer,
                                                 ; A wrap will happen so call a different routine
                                                 ; to handle this

        cmp     WR0,   #(Ep1LoopBackBuffer + Ep1LoopBackBufferSize - 1)    ; Will FIFO fit in buffer without wrapping

        jg      DoEp1RxWrap                  ; If wrap occurs, go deal with it.
                                                 ; Else keep on moving with out a pipeline stall.
Ep1BufferSpaceLeft:
        sub     WR0,   WR6                       ; Get original bytes in FIFO.
        push    WR6                              ; Save it.
        call    RX_64_RAM_BYTES                  ; Move the data.

        pop     WR6                              ; Get the original count and
                                                 ; Update bytes in buffer.
                                                 ; Easier to do here.
Ep1RxDone:
        jnb     RXURF, Ep1NoURF                  ; Make sure no error occured here.
        call    Ep1URF                           ; (Slow method forces a pipline stall.)
Ep1NoURF:

        setb    RXFFRC                           ; Release the FIFO
        mov     Ep1WritePointer,  WR0            ; Update write pointer
        add     WR6,   Ep1BytesInBuffer          ; Total bytes is old byte count
                                                 ; Plus bytes in FIFO
        mov     Ep1BytesInBuffer, WR6            ;
        sjmp    CheckEp1NewData                  ;


Ep1RxBufferFull:
NoEp1RxDataReceived:
        mov     EP0_ERROR_CNT, #00h
        Pop     WR6
        pop     WR0
        ret


                                                ;-----------------------------------
                                                ; EP1 Recieve Error Handling
                                                ;-----------------------------------
HandleEp1RxError:
        mov    A,      RXFLG           ; Get the type of RX Error.
        anl    A,      #03h            ; Mask off all but th error flags
        jnz    Ep1OVF                  ; If these are both Zeros then it was a CRC Error.
        mov    WR0,    EP1_RX_ERR_COUNTER
        inc    WR0,    #1
        mov    EP1_RX_ERR_COUNTER, WR0
        sjmp   CheckEp1NewData      ; If it was a CRC, go chack to see if there weas any other data.

Ep1OVF:
        mov    R0,     EP1_RX_ERR_COUNTER+2
        inc    WR0,    #1
        mov    EP1_RX_ERR_COUNTER+2, WR0
        ljmp   CheckEp1NewData

Ep1URF:
        mov    R0,     EP1_RX_ERR_COUNTER+3
        inc    WR0,    #1
        mov    EP1_RX_ERR_COUNTER+3, WR0
        ret




                                ;-------------------------------------
                                ; EP1 RX BUFFER WRAP ROUTINE
                                ;-------------------------------------

DoEp1RxWrap:                    ; This routine is called if we must wrap all or part
                                ; of the data from the end of the buffer to the beginning.
                                ; This routine could be optimized, but i'm not willing
                                ; to spend a lot of time optimizing this for every single
                                ; clock.  Therefore, I will suffer the penalty of one slow
                                ; packet and a lot of quick packets.  If you don't like it
                                ; then you are free to optimize it.

         mov     R11,  #0
         mov     Ep1Temp, R11

         sub     WR0,  WR6                              ; Update the values modifed above.
         push    WR6                                    ;
         orl     WR6,  WR6                              ; Check fro zero bytes

         je      Ep1RxFifoEmpty                         ; If fifo empty then exit.

Ep1RxMoveLoop:                                          ;
         mov     R11,  RXDAT
         mov     @WR0, R11

         mov     R11,  Ep1Temp
         inc     R11,  #1
         mov     Ep1Temp, R11

         cmp     WR0,  #(Ep1LoopBackBuffer+Ep1LoopBackBufferSize - 1 )
         je      Ep1RxAdjustWritePointer                ; If this is equal then we need to move the write
                                                        ; pointer to the beginning of the buffer
Ep1RxAdjustPointerDone:
         inc     WR0,  #1
         dec     WR6,  #1
         jne     Ep1RxMoveLoop
Ep1RxFifoEmpty:
         pop     WR6
         ljmp    Ep1RxDone


Ep1RxAdjustWritePointer:
         mov     WR0,  #(Ep1LoopBackBuffer-1)            ; Use minus one since the next instruction will be to increment it.
         sjmp    Ep1RxAdjustPointerDone




;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 1 TX LOOPBACK ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : Ep1TxLoopBack
;Brief Description : Acts as an Infinite source of 32 byte data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
Ep1TxLoopBack:
        Push    WR0
        Push    WR6
        mov     EP0_ERROR_CNT, #018h
        anl     FIFLG,   #EP1_TX_CLR       ; CLear Interrupt Pending Flag
                  ; First check to see if there is room in the FIFO
Ep1TXLpCheckEveryThing:

        jnb     TXERR,     CheckEp1TxNewData
        ljmp     HandleEp1TxError

; Check to make sure there is room in the buffer.

CheckEp1TxNewData:

        jnb     TXFIF0,  CheckEp1TxDataAvailible
        jnb     TXFIF1,  CheckEp1TxDataAvailible
        sjmp    NoEp1TxDataReceived

CheckEp1TxDataAvailible:
        mov     WR6,   Ep1BytesInBuffer
        cmp     WR6,   #0
        je      Ep1TxBufferEmpty

CheckEp1TxShortPacket:
CheckTxWrap:
        mov     WR0,    Ep1ReadPointer                    ; Check to see if a wrap will occur
        cmp     WR0,    #(Ep1LoopBackBuffer + Ep1LoopBackBufferSize - EP1_TX_LOOP_BACK_FIFO_SIZE - 1)
        jg      DoEp1TxWrap

Ep1TxBufferSpaceLeft:

        push    WR6                             ;
        call    TX_64_RAM_BYTES                ;
        pop     WR6                            ; Update bytes in buffer.  Easier to do here.

Ep1TxDone:
        mov     TXCNTH, #0h
        mov     TXCNTL, #EP1_TX_LOOP_BACK_FIFO_SIZE       ; (KLS)Release the FIFO
        mov     Ep1ReadPointer,  WR0         ; Update write pointer
        SUB     WR6,    #EP1_TX_LOOP_BACK_FIFO_SIZE
        mov     Ep1BytesInBuffer,  WR6         ; Bytes in buffer

        cmp     WR6,    #00h                   ; Are there any bytes left in the buffer?
        jne     Ep1BufferNotEmpty              ; If yes, then continue

                                               ; If =0 then reset pointers so as not to wrap.

        mov     WR0,    #Ep1LoopBackBuffer
        mov     Ep1WritePointer,  WR0
        mov     Ep1ReadPointer,   WR0
Ep1BufferNotEmpty:
        sjmp    CheckEp1TxNewData                ;





ShortPacket:
Ep1TxBufferEmpty:
NoEp1TxDataReceived:
        mov     EP0_ERROR_CNT, #00h
        Pop     WR6
        pop     WR0
        ret


DoEp1TxWrap:
                                ;-------------------------------------
                                ; EP1 TX BUFFER WRAP ROUTINE
                                ;-------------------------------------

                                ; This routine is called if we must wrap all or part
                                ; of the data from the end of the buffer to the beginning.
                                ; This routine could be optimized, but i'm not willing
                                ; to spend a lot of time optimizing this for every single
                                ; clock.  Therefore, I will suffer the penalty of one slow
                                ; packet and a lot of quick packets.  If you don't like it
                                ; then you are free to optimize it.

         push    WR6                             ;
         orl     WR6,   WR6                             ; Check fro zero bytes
         mov     WR6,   #EP1_TX_LOOP_BACK_FIFO_SIZE
         je      Ep1TxFifoEmpty                 ; If fifo empty then exit.

Ep1TxMoveLoop:                                          ;
         mov     R11,   @WR0
         mov     TXDAT, R11




         cmp     WR0,   #(Ep1LoopBackBuffer+Ep1LoopBackBufferSize - 1 )
         je      Ep1TxAdjustWritePointer                ; If this is equal then we need to move the write
                                                        ; pointer to the beginning of the buffer

Ep1TxAdjustPointerDone:
         inc     WR0,  #1                               ; Inc the Read Pointer
         dec     WR6,  #1                               ; Decrement the byte count
         jne     Ep1TxMoveLoop                          ; If more left, go get it.

Ep1TxWrapDone:
         pop     WR6
Ep1TxFifoEmpty:
         sjmp    Ep1TxDone


Ep1TxAdjustWritePointer:
         mov     WR0,     #Ep1LoopBackBuffer - 1        ; Minus one because of the inc that will occur above.
         sjmp    Ep1TxAdjustPointerDone



                                                ;-----------------------------------
                                                ; EP1 Transmit Error Handling
                                                ;-----------------------------------
HandleEp1TxError:
        mov    A,  TXFLG            ; Get the type of RX Error.
        anl    A,  #03h             ; Mask off all but th error flags
        jnz    Ep1TxOVF           ; If these are both Zeros then it was a CRC Error.
        mov    WR0, EP1_TX_ERR_COUNTER
        inc    WR0, #1
        mov    EP1_TX_ERR_COUNTER, WR0
        ljmp   CheckEp1TxNewData      ; If it was a CRC, go chack to see if there weas any other data.

Ep1TxOVF:
        jnb    ACC.0, Ep1TxURF       ; Is the OVF flag set (Over flow)
        mov    R0, EP1_RX_ERR_COUNTER+2
        inc    WR0, #1
        mov    EP1_TX_ERR_COUNTER+2, WR0
        ljmp   CheckEp1TxNewData

Ep1TxURF:
        mov    R0, EP1_TX_ERR_COUNTER+3
        inc    WR0, #1
        mov    EP1_TX_ERR_COUNTER+3, WR0
        ljmp   CheckEp1NewData


;************************************************************************
;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 2 RX LOOPBACK ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : Ep2RxLoopBack
;Brief Description : Acts as an Infinite source of 32 byte data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
Ep2RxLoopBack:
        Push    WR0
        Push    WR6
        Push    R11                     ; reg used in loopback fix checking
        Push    WR12                    ; reg used in loopback fix checking
        Push    WR14                    ; reg used in loopback fix checking

        mov     EP0_ERROR_CNT, #020h
        anl     FIFLG,     #EP2_RX_CLR              ; CLear Interrupt Pending Flag

Ep2RXCheckEveryThing:
        jnb     RXERR,     NoEp2RxError

        ljmp    HandleEp2RxError
NoEp2RxError:
                                    ; Check to make sure there is room in the buffer.
CheckEp2NewData:
        jb      RXFIF0,    CheckEp2BufferFull
        jb      RXFIF1,    CheckEp2BufferFull
        ljmp    NoEp2RxDataReceived

CheckEp2BufferFull:

        mov     WR0,    Ep2BytesInBuffer
                                                ; If one packet is put into this
                                                ; buffer will it wrap durring or after all
                                                ; pointers have been updated.
        cmp     WR0,    #(Ep2LoopBackBufferSize - EP2_RX_LOOP_BACK_FIFO_SIZE  )

        jg      Ep2RxBufferFull

CheckEp2Wrap:
        mov     R7,    RXCNTL                   ; Get bytes of data in FIFO
        xrl     R6,    R6
        mov     WR0,   Ep2WritePointer          ; Write pointer to it
        add     WR0,   WR6
        cmp     WR0,   #(Ep2LoopBackBuffer + Ep2LoopBackBufferSize - 1)    ; Will FIFO fit in buffer without wrapping
                                                 ; There is room in buffer so move it.
        jg      jmp_DoEp2RxWrap                      ; If wrap occurs, go deal with it.
        sjmp    Ep2BufferSpaceLeft
jmp_DoEp2RxWrap:
        ljmp    DoEp2RxWrap

Ep2BufferSpaceLeft:
        sub     WR0,   WR6
        push    WR6                              ;
        call    RX_08_RAM_BYTES                  ;

        pop     WR6                              ; Update bytes in buffer.  Easier to do here.

Ep2RxDone:
        jnb     RXURF,Ep2NoURF
        call    Ep2URF
Ep2NoURF:

IF SW_FIFO_FIX == ENABLED
;*****************************************************************
; LOOPBACK/RXFFRC Software Fix
;*****************************************************************
RELEASE_FIFO_2:
        mov     A,      RXFLG
        mov     R12,    RXFLG           ; before
        mov     R13,    RXSTAT

        setb    RXFFRC                         ; Release the FIFO

        ; if (RXFLG_BEFORE = RXFLG_AFTER)
        ;  then { continue and check if RXFIF="11" }
        ;  else { setting RXFFRC was successful - jump to REL_FIFOx_OK }
        cjne    A,    RXFLG, REL_FIFO2_OK

        ; if we get here R11 has RXFLG before and after - no change
        mov     R15,    RXSTAT

        ; if (RXFLG_AFTER = "11")
        ;  then { continue and check RXSEQ data toggle }
        ;  else { jump to REL_FIFOx_OK}
        anl     R11, #11000000b         ; check RXFIF after
        cjne    A,   #11000000b,  REL_FIFO2_OK
        ; RXFIF bits are "11"    RXFLG="C0"

        ; if (RXSEQ_BEFORE = RXSEQ_AFTER)
        ;  then
        ;   { no data toggle - set RXFFRC again }
        ;  else
        ;   { data toggle - OK jump to REL_FIFOx_OK}
        anl     R13, #10000000b
        anl     R15, #10000000b
        cmp     R13,   R15
        jne     REL_FIFO2_OK
        ; ERROR condition: RXFIF was "11" before & after; & RXSTAT didn't change
RELEASE_FIFO_2_AGAIN:
        ljmp    RELEASE_FIFO_2

ELSE  ; IF SW_FIFO_FIX == DISABLED

        setb    RXFFRC                         ; Release the FIFO

ENDIF
REL_FIFO2_OK:
        ;############################################################
        mov     Ep2WritePointer,  WR0            ; Update write pointer
        add     WR6,   Ep2BytesInBuffer          ; Bytes in buffer
        mov     Ep2BytesInBuffer, WR6            ;
        ljmp    CheckEp2NewData                  ;


Ep2RxBufferFull:
NoEp2RxDataReceived:
        mov     EP0_ERROR_CNT, #00h

        Pop     WR14
        Pop     WR12
        Pop     R11
        Pop     WR6
        pop     WR0

        ret


                                                ;-----------------------------------
                                                ; EP2 Recieve Error Handling
                                                ;-----------------------------------
HandleEp2RxError:
        mov    A,  RXFLG            ; Get the type of RX Error.
        anl    A,  #03h             ; Mask off all but th error flags
        jnz    Ep2OVF               ; If these are both Zeros then it was a CRC Error.
        mov    WR0, EP2_RX_ERR_COUNTER
        inc    WR0, #1
        mov    EP2_RX_ERR_COUNTER, WR0
        ljmp   CheckEp2NewData      ; If it was a CRC, go check to see if there weas any other data.

Ep2OVF:
;        jnb    ACC.0, Ep2URF        ; Is the OVF flag set (Over flow)
        mov    R0, EP2_RX_ERR_COUNTER+2
        inc    WR0, #1
        mov    EP2_RX_ERR_COUNTER+2, WR0
        ljmp   CheckEp2NewData

Ep2URF:
        mov    R0, EP2_RX_ERR_COUNTER+3
        inc    WR0, #1
        mov    EP2_RX_ERR_COUNTER+3, WR0
        ret




                                ;-------------------------------------
                                ; EP2 RX BUFFER WRAP ROUTINE
                                ;-------------------------------------

DoEp2RxWrap:                    ; This routine is called if we must wrap all or part
                                ; of the data from the end of the buffer to the beginning.
                                ; This routine could be optimized, but i'm not willing
                                ; to spend a lot of time optimizing this for every single
                                ; clock.  Therefore, I will suffer the penalty of one slow
                                ; packet and a lot of quick packets.  If you don't like it
                                ; then you are free to optimize it.

         mov     R11,     #0
         mov     Ep2Temp, R11
         sub     WR0,   WR6                             ; Update the values modifed above.
         push    WR6                             ;
         orl     WR6,   WR6                             ; Check fro zero bytes

         je      Ep2RxFifoEmpty                         ; If fifo empty then exit.

Ep2RxMoveLoop:                                          ;
         mov     R11,    RXDAT
         mov     @WR0,   R11
         mov     R11,    Ep2Temp
         inc     R11,    #1
         mov     Ep2Temp, R11
         cmp     WR0,   #(Ep2LoopBackBuffer+Ep2LoopBackBufferSize - 1 )
         je      Ep2RxAdjustWritePointer                ; If this is equal then we need to move the write
                                                        ; pointer to the beginning of the buffer
Ep2RxAdjustPointerDone:
         inc     WR0, #1
         dec     WR6, #1
         jne     Ep2RxMoveLoop
Ep2RxFifoEmpty:
         pop     WR6
         ljmp    Ep2RxDone


Ep2RxAdjustWritePointer:
         mov     WR0,     #(Ep2LoopBackBuffer-1)          ; Use minus one since the next instruction will be to increment it.
         sjmp    Ep2RxAdjustPointerDone




;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 2 TX LOOPBACK ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : Ep2TxLoopBack
;Brief Description : Acts as an Infinite source of 32 byte data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
Ep2TxLoopBack:
        Push    WR0
        Push    WR6
        mov     EP0_ERROR_CNT, #028h
        anl     FIFLG,   #EP2_TX_CLR       ; CLear Interrupt Pending Flag
                  ; First check to see if there is room in the FIFO
Ep2TXLpCheckEveryThing:

        jnb     TXERR,     CheckEp2TxNewData
        ljmp     HandleEp2TxError

; Check to make sure there is room in the buffer.

CheckEp2TxNewData:

        jnb     TXFIF0,  CheckEp2TxDataAvailible
        jnb     TXFIF1,  CheckEp2TxDataAvailible
        sjmp    NoEp2TxDataReceived

CheckEp2TxDataAvailible:
        mov     WR6,   Ep2BytesInBuffer
        cmp     WR6,   #0
        je      Ep2TxBufferEmpty

CheckEp2TxShortPacket:
CheckEp2TxWrap:
        mov     WR0,   Ep2ReadPointer            ; Check to see if a wrap will occur
        cmp     WR0,   #(Ep2LoopBackBuffer + Ep2LoopBackBufferSize - EP1_TX_LOOP_BACK_FIFO_SIZE - 1)
        jg      DoEp2TxWrap

Ep2TxBufferSpaceLeft:

        push    WR6                              ;
        call    TX_08_RAM_BYTES                  ;
        pop     WR6                              ; Update bytes in buffer.  Easier to do here.

Ep2TxDone:
        mov     TXCNTL, #EP2_TX_LOOP_BACK_FIFO_SIZE       ; (KLS)Release the FIFO
        mov     Ep2ReadPointer,  WR0             ; Update write pointer
        SUB     WR6,    #EP2_TX_LOOP_BACK_FIFO_SIZE
        mov     Ep2BytesInBuffer,  WR6           ; Bytes in buffer

        cmp     WR6,    #00h                     ; Are there any bytes left in the buffer?
        jne     Ep2BufferNotEmpty                ; If yes, then continue
                                                 ; If =0 then reset pointers so as not to wrap.

        mov     WR0,    #Ep2LoopBackBuffer
        mov     Ep2WritePointer,  WR0
        mov     Ep2ReadPointer,   WR0
Ep2BufferNotEmpty:


        sjmp    CheckEp2TxNewData                ;





Ep2ShortPacket:
Ep2TxBufferEmpty:
NoEp2TxDataReceived:
        mov     EP0_ERROR_CNT, #00h
        Pop     WR6
        pop     WR0
        ret


DoEp2TxWrap:
                                ;-------------------------------------
                                ; EP1 TX BUFFER WRAP ROUTINE
                                ;-------------------------------------

                                ; This routine is called if we must wrap all or part
                                ; of the data from the end of the buffer to the beginning.
                                ; This routine could be optimized, but i'm not willing
                                ; to spend a lot of time optimizing this for every single
                                ; clock.  Therefore, I will suffer the penalty of one slow
                                ; packet and a lot of quick packets.  If you don't like it
                                ; then you are free to optimize it.

         push    WR6                             ;
         orl     WR6,   WR6                             ; Check fro zero bytes
         mov     WR6,   #EP2_TX_LOOP_BACK_FIFO_SIZE
         je      Ep2TxFifoEmpty                 ; If fifo empty then exit.

Ep2TxMoveLoop:                                          ;
         mov     R11,   @WR0
         mov     TXDAT, R11




         cmp     WR0,   #(Ep2LoopBackBuffer+Ep2LoopBackBufferSize - 1 )
         je      Ep2TxAdjustWritePointer                ; If this is equal then we need to move the write
                                                        ; pointer to the beginning of the buffer

Ep2TxAdjustPointerDone:
         inc     WR0,  #1                               ; Inc the Read Pointer
         dec     WR6,  #1                               ; Decrement the byte count
         jne     Ep2TxMoveLoop                          ; If more left, go get it.

Ep2TxWrapDone:
         pop     WR6
Ep2TxFifoEmpty:
         sjmp    Ep2TxDone


Ep2TxAdjustWritePointer:
         mov     WR0,     #Ep2LoopBackBuffer - 1        ; Minus one because of the inc that will occur above.
         sjmp    Ep2TxAdjustPointerDone



                                            ;-----------------------------------
                                            ; EP2 Transmit Error Handling
                                            ;-----------------------------------
HandleEp2TxError:
        mov    A,  TXFLG                    ; Get the type of RX Error.
        anl    A,  #03h                     ; Mask off all but th error flags
        jnz    Ep2TxOVF                     ; If these are both Zeros then it was a CRC Error.
        mov    WR0, EP2_TX_ERR_COUNTER
        inc    WR0, #1
        mov    EP2_TX_ERR_COUNTER, WR0
        ljmp   CheckEp2TxNewData            ; If it was a CRC, go chack to see if there weas any other data.

Ep2TxOVF:
        jnb    ACC.0, Ep2TxURF              ; Is the OVF flag set (Over flow)
        mov    R0, EP2_RX_ERR_COUNTER+2
        inc    WR0, #1
        mov    EP2_TX_ERR_COUNTER+2, WR0
        ljmp   CheckEp2TxNewData

Ep2TxURF:
;       jnb    ACC.1                        ; Is the URF flag set (Over flow)
        mov    R0, EP2_TX_ERR_COUNTER+3
        inc    WR0, #1
        mov    EP2_TX_ERR_COUNTER+3, WR0
        ljmp   CheckEp2NewData



;************************************************************************
;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 3 RX LOOPBACK ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : Ep3RxLoopBack
;Brief Description : Acts as an Infinite source of 32 byte data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
Ep3RxLoopBack:
        Push    WR0
        Push    WR6
        Push    R11                     ; reg used in loopback fix checking
        Push    WR12                    ; reg used in loopback fix checking
        Push    WR14                    ; reg used in loopback fix checking

        mov     EP0_ERROR_CNT, #030h
        anl     FIFLG,     #EP3_RX_CLR          ; CLear Interrupt Pending Flag
                  ; First check to see if there is room in the FIFO
Ep3RXCheckEveryThing:
        jnb     RXERR,     NoEp3RxError

        ljmp    HandleEp3RxError
NoEp3RxError:

; Check to make sure there is room in the buffer.

CheckEp3NewData:
        jb      RXFIF0,  CheckEp3BufferFull
        jb      RXFIF1,  CheckEp3BufferFull
        ljmp    NoEp3RxDataReceived

CheckEp3BufferFull:

        mov     WR0,   Ep3BytesInBuffer
                                                ; If one packet is put into this
                                                ; buffer will it wrap durring or after all
                                                ; pointers have been updated.
        cmp     WR0,   #(Ep3LoopBackBufferSize - EP3_RX_LOOP_BACK_FIFO_SIZE  )

        jg      goto_Ep3RxBufferFull
        sjmp    CheckEp3Wrap
goto_Ep3RxBufferFull:
        ljmp    Ep3RxBufferFull
CheckEp3Wrap:
        mov     R7,    RXCNTL                  ; Get bytes of data in FIFO
        mov     Ep3Temp, R7
        xrl     R6,    R6
        mov     WR0,   Ep3WritePointer         ; Write pointer to it
        add     WR0,   WR6
        cmp     WR0,   #(Ep3LoopBackBuffer + Ep3LoopBackBufferSize - 1)    ; Will FIFO fit in buffer without wrapping
;There is room in buffer so move it.
        jg      jmp_DoEp3RxWrap                      ; If wrap occurs, go deal with it.
        sjmp    Ep3BufferSpaceLeft
jmp_DoEp3RxWrap:
        ljmp    DoEp3RxWrap


Ep3BufferSpaceLeft:
        sub     WR0,   WR6
        push    WR6                            ;
        lcall   RX_08_RAM_BYTES                ;

        pop     WR6                            ; Update bytes in buffer.  Easier to do here.
Ep3RxDone:
        jnb     RXURF,Ep3NoURF
        lcall   Ep3URF
Ep3NoURF:

IF SW_FIFO_FIX == ENABLED
;*****************************************************************
; LOOPBACK/RXFFRC Software Fix
;*****************************************************************
RELEASE_FIFO_3:
        mov     A,      RXFLG
        mov     R12,    RXFLG           ; before
        mov     R13,    RXSTAT

        setb    RXFFRC                         ; Release the FIFO

        ; if (RXFLG_BEFORE = RXFLG_AFTER)
        ;  then { continue and check if RXFIF="11" }
        ;  else { setting RXFFRC was successful - jump to REL_FIFOx_OK }
        cjne    A,    RXFLG, REL_FIFO3_OK

        ; if we get here R11 has RXFLG before and after - no change
        mov     R15,    RXSTAT

        ; if (RXFLG_AFTER = "11")
        ;  then { continue and check RXSEQ data toggle }
        ;  else { jump to REL_FIFOx_OK}
        anl     R11, #11000000b         ; check RXFIF after
        cjne    A,   #11000000b,  REL_FIFO3_OK
        ; RXFIF bits are "11"    RXFLG="C0"

        ; if (RXSEQ_BEFORE = RXSEQ_AFTER)
        ;  then
        ;   { no data toggle - set RXFFRC again }
        ;  else
        ;   { data toggle - OK jump to REL_FIFOx_OK}
        anl     R13, #10000000b
        anl     R15, #10000000b
        cmp     R13,   R15
        jne     REL_FIFO3_OK
        ; ERROR condition: RXFIF was "11" before & after; & RXSTAT didn't change
RELEASE_FIFO_3_AGAIN:
        ljmp    RELEASE_FIFO_3

ELSE  ; IF SW_FIFO_FIX == DISABLED

        setb    RXFFRC                         ; Release the FIFO

ENDIF

REL_FIFO3_OK:
        ;############################################################

        mov     Ep3WritePointer,  WR0          ; Update write pointer
        add     WR6,   Ep3BytesInBuffer        ; Bytes in buffer
        mov     Ep3BytesInBuffer, WR6          ;
        ljmp    CheckEp3NewData                ;


Ep3RxBufferFull:
NoEp3RxDataReceived:
        mov     EP0_ERROR_CNT, #00h

        Pop     WR14
        Pop     WR12
        Pop     R11
        Pop     WR6
        pop     WR0
        ret


                                                ;-----------------------------------
                                                ; EP3 Recieve Error Handling
                                                ;-----------------------------------
HandleEp3RxError:
        mov    A,  RXFLG            ; Get the type of RX Error.
        anl    A,  #03h             ; Mask off all but th error flags
        jnz    Ep3OVF               ; If these are both Zeros then it was a CRC Error.
        mov    WR0, EP3_RX_ERR_COUNTER
        inc    WR0, #1
        mov    EP3_RX_ERR_COUNTER, WR0
        ljmp    CheckEp3NewData      ; If it was a CRC, go chack to see if there weas any other data.

Ep3OVF:
;        jnb    ACC.0, Ep3URF        ; Is the OVF flag set (Over flow)
        mov    R0, EP3_RX_ERR_COUNTER+2
        inc    WR0, #1
        mov    EP3_RX_ERR_COUNTER+2, WR0
        ljmp    CheckEp3NewData

Ep3URF:
        mov    R0, EP3_RX_ERR_COUNTER+3
        inc    WR0, #1
        mov    EP3_RX_ERR_COUNTER+3, WR0
        ret




                                ;-------------------------------------
                                ; EP3 RX BUFFER WRAP ROUTINE
                                ;-------------------------------------

DoEp3RxWrap:                    ; This routine is called if we must wrap all or part
                                ; of the data from the end of the buffer to the beginning.
                                ; This routine could be optimized, but i'm not willing
                                ; to spend a lot of time optimizing this for every single
                                ; clock.  Therefore, I will suffer the penalty of one slow
                                ; packet and a lot of quick packets.  If you don't like it
                                ; then you are free to optimize it.

         mov     R11,     #0
         mov     Ep2Temp, R11

         sub     WR0,   WR6                 ; Update the values modifed above.
         push    WR6                        ;
         orl     WR6,   WR6                 ; Check for zero bytes

         je      Ep3RxFifoEmpty             ; If fifo empty then exit.

Ep3RxMoveLoop:                              ;
         mov     R11,    RXDAT
         mov     @WR0,   R11

         mov     R11,    Ep3Temp
         inc     R11,    #1
         mov     Ep3Temp, R11

         cmp     WR0,   #(Ep3LoopBackBuffer+Ep3LoopBackBufferSize - 1 )
         je      Ep3RxAdjustWritePointer    ; If this is equal then we need to move the write
                                            ; pointer to the beginning of the buffer
Ep3RxAdjustPointerDone:
         inc     WR0, #1
         dec     WR6, #1
         jne     Ep3RxMoveLoop
Ep3RxFifoEmpty:
         pop     WR6
         ljmp    Ep3RxDone


Ep3RxAdjustWritePointer:
         mov     WR0,     #(Ep3LoopBackBuffer-1)          ; Use minus one since the next instruction will be to increment it.
         sjmp     Ep3RxAdjustPointerDone




;************************************************************************
;------------------------------------------------------------------------
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;EE                   ENDPOINT 3 TX LOOPBACK ISR.
;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
;------------------------------------------------------------------------
;************************************************************************
;COMMENT *------------------------------------------------------------
;Function name     : Ep3TxLoopBack
;Brief Description : Acts as an Infinite source of 32 byte data packets.
;                  : Each data packet has an incremented DWORD varaiable in
;                  : it.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*

;
Ep3TxLoopBack:
        Push    WR0
        Push    WR6
        mov     EP0_ERROR_CNT, #038h
        anl     FIFLG,   #EP3_TX_CLR       ; CLear Interrupt Pending Flag
                  ; First check to see if there is room in the FIFO
Ep3TXLpCheckEveryThing:

        jnb     TXERR,     CheckEp3TxNewData
        ljmp     HandleEp3TxError


; Check to make sure there is room in the buffer.

CheckEp3TxNewData:

        jnb     TXFIF0,  CheckEp3TxDataAvailible
        jnb     TXFIF1,  CheckEp3TxDataAvailible
        ljmp    NoEp3TxDataReceived

CheckEp3TxDataAvailible:
        mov     WR6,   Ep3BytesInBuffer
        cmp     WR6,   #0
        je      Ep3TxBufferEmpty

CheckEp3TxShortPacket:
CheckEp3TxWrap:
        mov     WR0,   Ep3ReadPointer          ; Check to see if a wrap will occur
        cmp     WR0,   #(Ep3LoopBackBuffer + Ep3LoopBackBufferSize - EP1_TX_LOOP_BACK_FIFO_SIZE - 1)
        jg      DoEp3TxWrap

Ep3TxBufferSpaceLeft:

        push    WR6                            ;
        call    TX_08_RAM_BYTES                ;
        pop     WR6                            ; Update bytes in buffer.  Easier to do here.

Ep3TxDone:
        mov     TXCNTL, #EP3_TX_LOOP_BACK_FIFO_SIZE       ; (KLS)Release the FIFO
        mov     Ep3ReadPointer,  WR0           ; Update write pointer
        SUB     WR6,    #EP3_TX_LOOP_BACK_FIFO_SIZE
        mov     Ep3BytesInBuffer,  WR6         ; Bytes in buffer

        cmp     WR6,    #00h                   ; Are there any bytes left in the buffer?
        jne     Ep3BufferNotEmpty              ; If yes, then continue

                                               ; If =0 then reset pointers so as not to wrap.

        mov     WR0,    #Ep3LoopBackBuffer
        mov     Ep3WritePointer,  WR0
        mov     Ep3ReadPointer,   WR0
Ep3BufferNotEmpty:

        sjmp    CheckEp3TxNewData              ;





Ep3ShortPacket:
Ep3TxBufferEmpty:
NoEp3TxDataReceived:
        mov     EP0_ERROR_CNT, #000h
        Pop     WR6
        pop     WR0
        ret


DoEp3TxWrap:
                                ;-------------------------------------
                                ; EP3 TX BUFFER WRAP ROUTINE
                                ;-------------------------------------

                                ; This routine is called if we must wrap all or part
                                ; of the data from the end of the buffer to the beginning.
                                ; This routine could be optimized, but i'm not willing
                                ; to spend a lot of time optimizing this for every single
                                ; clock.  Therefore, I will suffer the penalty of one slow
                                ; packet and a lot of quick packets.  If you don't like it
                                ; then you are free to optimize it.

         push    WR6                             ;
;         orl     WR6,   WR6                             ; Check fro zero bytes
         mov     WR6,   #EP3_TX_LOOP_BACK_FIFO_SIZE
         je      Ep3TxFifoEmpty                 ; If fifo empty then exit.

Ep3TxMoveLoop:                                          ;
         mov     R11,   @WR0
         mov     TXDAT, R11




         cmp     WR0,   #(Ep3LoopBackBuffer+Ep3LoopBackBufferSize - 1 )
         je      Ep3TxAdjustWritePointer                ; If this is equal then we need to move the write
                                                        ; pointer to the beginning of the buffer

Ep3TxAdjustPointerDone:
         inc     WR0,  #1                               ; Inc the Read Pointer
         dec     WR6,  #1                               ; Decrement the byte count
         jne     Ep3TxMoveLoop                          ; If more left, go get it.

Ep3TxWrapDone:
         pop     WR6
Ep3TxFifoEmpty:
         sjmp    Ep3TxDone


Ep3TxAdjustWritePointer:
         mov     WR0,     #Ep3LoopBackBuffer - 1        ; Minus one because of the inc that will occur above.
         sjmp    Ep3TxAdjustPointerDone



                                                ;-----------------------------------
                                                ; EP3 Transmit Error Handling
                                                ;-----------------------------------
HandleEp3TxError:
        mov    A,  TXFLG            ; Get the type of RX Error.
        anl    A,  #03h             ; Mask off all but th error flags
        jnz    Ep3TxOVF           ; If these are both Zeros then it was a CRC Error.
        mov    WR0, EP3_TX_ERR_COUNTER
        inc    WR0, #1
        mov    EP3_TX_ERR_COUNTER, WR0
        ljmp   CheckEp3TxNewData      ; If it was a CRC, go chack to see if there weas any other data.

Ep3TxOVF:
        jnb    ACC.0, Ep3TxURF       ; Is the OVF flag set (Over flow)
        mov    R0, EP3_RX_ERR_COUNTER+2
        inc    WR0, #1
        mov    EP3_TX_ERR_COUNTER+2, WR0
        ljmp   CheckEp3TxNewData

Ep3TxURF:
;       jnb    ACC.1                ; Is the URF flag set (Over flow)
        mov    R0, EP3_TX_ERR_COUNTER+3
        inc    WR0, #1
        mov    EP3_TX_ERR_COUNTER+3, WR0
        ljmp    CheckEp3NewData





;===================================================================================
; RX_64_RAM_BYTES..RX_01_RAM_BYTES
; Moves BYTES in the FIFOs to memory pointed to by WR0
; No Error Checking is done.  All Little Endian -> Big Endian is handled by
; The routine.
;===================================================================================

RX_64_RAM_BYTES:
                                       ;  Binary/Source states

       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_62_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_60_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_58_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_56_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_54_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_52_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_50_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_48_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_46_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_44_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_42_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_40_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_38_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_36_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_34_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_32_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_30_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_28_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_26_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_24_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_22_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_20_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_18_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_16_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_14_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_12_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_10_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_08_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_06_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_04_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1

RX_02_RAM_BYTES:
       mov   R6,     RXDAT             ;  2/3 High  Byte First
       mov   R7,     RXDAT             ;  2/3 Low Byte Second
       mov   @WR0,   WR6               ;  4/3
       inc   WR0,    #2                ;  2/1
RX_00_RAM_BYTES:
       ret

;--------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------
TX_64_RAM_BYTES:
                                       ;  Binary/Source states

       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_62_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_60_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_58_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_56_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_54_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_52_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_50_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_48_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_46_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_44_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_42_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_40_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_38_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_36_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_34_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_32_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_30_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_28_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_26_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_24_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_22_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_20_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_18_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_16_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_14_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_12_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_10_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_08_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_06_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_04_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1

TX_02_RAM_BYTES:
       mov   WR6,    @WR0              ;  4/3
       mov   TXDAT , R6                ;  2/3 High  Byte First
       mov   TXDAT , R7                ;  2/3 Low Byte Second
       inc   WR0,    #2                ;  2/1
TX_00_RAM_BYTES:
       ret



FifoWatchDog:
        push    R11
        push    EPINDEX
        mov     EPINDEX,  #01h
        mov     EP0_ERROR_CNT, #0Fh
;
; -- EP1 TX ERRORS
;
CheckEp1TxERR:
        jnb      TXERR,    CheckEp1TxOVF
        mov      R11,        Ep1Tx_ERR
        inc      R11, #01h
        mov      Ep1Tx_ERR, R11
        clr      TXERR
CheckEp1TxOVF:
        jnb      TXOVF,    CheckEp1TxURF
        mov      R11,        Ep1Tx_OVF
        inc      R11, #01h
        mov      Ep1Tx_OVF, R11
        clr      TXOVF
CheckEp1TxURF:
        jnb      TXURF,    CheckEp1RxERR
        mov      R11,        Ep1Tx_URF
        inc      R11,  #01h
        mov      Ep1Tx_URF, R11
        clr      TXURF
;
; -- EP1 RX ERRORS
;
CheckEp1RxERR:
        jnb      RXERR,    CheckEp1RxOVF
        mov      R11,        Ep1Rx_ERR
        inc      R11,  #01h
        mov      Ep1Rx_ERR, R11
        clr      RXERR
CheckEp1RxOVF:
        jnb      RXOVF,    CheckEp1RxURF
        mov      R11,        Ep1Rx_OVF
        inc      R11,  #01h
        mov      Ep1Rx_OVF, R11
        clr      RXOVF
CheckEp1RxURF:
        jnb      RXURF,    CheckEp2Fifos
        mov      R11,        Ep1Rx_URF
        inc      R11, #01h
        mov      Ep1Rx_URF, R11
        clr      RXURF


CheckEp2Fifos:
        mov     EPINDEX,  #02h
;
; -- EP2 TX ERRORS
;
CheckEp2TxERR:
        jnb      TXERR,    CheckEp2TxOVF
        mov      R11,        Ep2Tx_ERR
        inc      R11,  #01h
        mov      Ep2Tx_ERR, R11
        clr      TXERR
CheckEp2TxOVF:
        jnb      TXOVF,    CheckEp2TxURF
        mov      R11,        Ep2Tx_OVF
        inc      R11, #01h
        mov      Ep2Tx_OVF, R11
        clr      TXOVF

CheckEp2TxURF:
        jnb      TXURF,    CheckEp2RxERR
        mov      R11,        Ep2Tx_URF
        inc      R11, #01h
        mov      Ep2Tx_URF, R11
        clr      TXURF

;
; -- EP2 RX ERRORS
;
CheckEp2RxERR:
        jnb      RXERR,    CheckEp2RxOVF
        mov      R11,        Ep2Rx_ERR
        inc      R11,  #01h
        mov      Ep2Rx_ERR, R11
        clr      RXERR
CheckEp2RxOVF:
        jnb      RXOVF,    CheckEp2RxURF
        mov      R11,        Ep2Rx_OVF
        inc      R11,  #01h
        mov      Ep2Rx_OVF, R11
        clr      RXOVF

CheckEp2RxURF:
        jnb      RXURF,    CheckEp3Fifos
        mov      R11,        Ep2Rx_URF
        inc      R11,  #01h
        mov      Ep2Rx_URF, R11
        clr      RXURF

CheckEp3Fifos:
        mov     EPINDEX,  #03h

; -- EP3 TX ERRORS
;
CheckEp3TxERR:
        jnb      TXERR,    CheckEp3TxOVF
        mov      R11,        Ep3Tx_ERR
        inc      R11,  #01h
        mov      Ep3Tx_ERR, R11
        clr      TXERR
CheckEp3TxOVF:
        jnb      TXOVF,    CheckEp3TxURF
        mov      R11,        Ep3Tx_OVF
        inc      R11,  #01h
        mov      Ep3Tx_OVF, R11
        clr      TXOVF

CheckEp3TxURF:
        jnb      TXURF,    CheckEp3RxERR
        mov      R11,        Ep3Tx_URF
        inc      R11,  #01h
        mov      Ep3Tx_URF, R11
        clr      TXURF
;
; -- EP3 RX ERRORS
;
CheckEp3RxERR:
        jnb      RXERR,    CheckEp3RxOVF
        mov      R11,        Ep3Rx_ERR
        inc      R11,  #01h
        mov      Ep3Rx_ERR, R11
        clr      RXERR
CheckEp3RxOVF:
        jnb      RXOVF,    CheckEp3RxURF
        mov      R11,        Ep3Rx_OVF
        inc      R11,  #01h
        mov      Ep3Rx_OVF, R11
        clr      RXOVF

CheckEp3RxURF:
        jnb      RXURF,    ExitFifoWatchDog
        mov      R11,        Ep3Rx_URF
        inc      R11,  #01h
        mov      Ep3Rx_URF, R11
        clr      RXURF

ExitFifoWatchDog:
        mov     EP0_ERROR_CNT, #00h
        pop      EPINDEX
        pop      R11
        ret

;************************************************************************
;************* DEVICE DESCRIPTOR ****************************************
;************************************************************************


; NOTE!!!!! '251 is a Big Endian machine. Words and DWords are stored with the
; LSB in the numerically higher address.

;------------------------------------------------
;-------- FUNCTION DESCRIPTOR -------------------
;------------------------------------------------

;
; NOTE!!!!! '251 is a Big Endian machine. Words and DWords are stored with the
; LSB in the numerically higher address.
;
IF PLC
	DEFINE  EMBEDDED_FN_DESCRIPTORS_CODE_SEG, SPACE=CODE
	SEGMENT EMBEDDED_FN_DESCRIPTORS_CODE_SEG
ENDIF
IF KEIL
    EMBEDDED_FN_DESCRIPTORS_CODE_SEG SEGMENT CODE
	RSEG EMBEDDED_FN_DESCRIPTORS_CODE_SEG
ENDIF

BEGIN_DEVICE_DESCRIPTOR:
        gDevice_bLength:            db  12h     ;DEVICE_DESCRIPTOR_LENGTH
        gDevice_bDescriptorType:    db  DEVICE_DESCR
        gDevice_bcdUSB:             dw  0001h  ; Version 1.00 compliant
        gDevice_bDeviceClass:       db  00h
        gDevice_bDeviceSubClass:    db  00h
        gDevice_bDeviceProtocol:    db  00h
        gDevice_wMaxPacketSize0:    db  08h    ;8 byte max for EP0
        gDevice_widVendor:          dw  8680h  ;Intel Vendor ID (8086)
        gDevice_widProduct:         dw  9098h  ;product ID 9890
        ;**********************************************************************
        ; Change the device number to match the firmware version number:
        gDevice_bcdDevice:          dw  8001h  ;device version 1.80
        ;**********************************************************************
        gDevice_iManufacturer:      db  01h
        gDevice_iProduct:           db  02h
        ;gDevice_iSerialNumber:      db  03h
        gDevice_iSerialNumber:      db  00h      ; No serial number - Rev 1.8 change
        gDevice_bNumConfigurations: db  1
END_DEVICE_DESCRIPTOR:



;************************************************************************
;************* CONFIG DESCRIPTOR 1 **************************************
;************************************************************************

;/*--------------- Config descriptor 1----------------*/
; This descriptor sets up the device for loopback on EP1, 2 & 3.
; See below for the specifics.
BEGIN_CONFIG1_DESCRIPTOR:
        gConfig1_bLength:               db 09h
        gConfig1_bDescriptorType:       db CONFIG_DESCR
        gConfig1_bTotalLength:          db END_CONFIG1_DESCRIPTOR - BEGIN_CONFIG1_DESCRIPTOR
        gConfig1_bCorrection:           db 0
        gConfig1_bNumInterfaces:        db 1  ; NUM_OF_INTERFACES;
        gConfig1_bConfigurationValue:   db 1
        gConfig1_iConfiguration:        db 04h
        gConfig1_bmAttributes:          db 060h        ; Self Powered, RWU enabled
        gConfig1_MaxPower:              db 001         ; 2 ma

;       /*------------- Initialize global Interface descriptor ---------------*/
BEGIN_INTERFACE1_DESCRIPTOR:
        gInterface1_bLength:            db END_INTERFACE1_DESCRIPTOR - BEGIN_INTERFACE1_DESCRIPTOR
        gInterface1_bDescriptorType:    db INTERFACE_DESCR
        gInterface1_bInterfaceNumber:   db 0
        gInterface1_bAlternateSetting:  db 0
        gInterface1_bNumEndpoints:      db 06h
        gInterface1_bInterfaceClass:    db 00h
        gInterface1_bInterfaceSubClass: db 00h
        gInterface1_bInterfaceProtocol: db 00h
        gInterface1_iInterface:         db 05h
END_INTERFACE1_DESCRIPTOR:

;      /*------------- Initialize Endpoint 1 TX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR1_TX1:
        gEP1Tx_1Length:             db  END_ENDPOINT_DESCRIPTOR1_TX1 - BEGIN_ENDPOINT_DESCRIPTOR1_TX1
        gEP1Tx_1bDescriptorType:    db  ENDPOINT_DESCR
        gEP1Tx_1bEndpointAddress:   db  81h     ;EP address 1, in
        gEP1Tx_1bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP1Tx_1wMaxPacketSize_LSb: db  EP1_TX_LOOP_BACK_FIFO_SIZE
        gEP1Tx_1wMaxPacketSize_MSb: db  00
        gEP1Tx_1bInterval:          db  00h
END_ENDPOINT_DESCRIPTOR1_TX1:

;      /*------------- Initialize Endpoint 1 RX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR1_RX1:
        gEP1Rx_1Length:             db  END_ENDPOINT_DESCRIPTOR1_RX1 - BEGIN_ENDPOINT_DESCRIPTOR1_RX1
        gEP1Rx_1bDescriptorType:    db  ENDPOINT_DESCR
        gEP1Rx_1bEndpointAddress:   db  01h     ;EP address 1, out
        gEP1Rx_1bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP1Rx_1wMaxPacketSize_LSb: db  EP1_RX_LOOP_BACK_FIFO_SIZE
        gEP1Rx_1wMaxPacketSize_MSb: db  00
        gEP1Rx_1bInterval:          db  00h
END_ENDPOINT_DESCRIPTOR1_RX1:

;      /*------------- Initialize Endpoint 2 TX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR1_TX2:
        gEP2Tx_1bLength:            db  END_ENDPOINT_DESCRIPTOR1_TX2 - BEGIN_ENDPOINT_DESCRIPTOR1_TX2
        gEP2Tx_1bDescriptorType:    db  ENDPOINT_DESCR
        gEP2Tx_1bEndpointAddress:   db  82h     ;EP address 2, in
        gEP2Tx_1bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP2Tx_1wMaxPacketSize_LSb: db  EP2_TX_LOOP_BACK_FIFO_SIZE
        gEP2Tx_1wMaxPacketSize_MSb: db  00
        gEP2Tx_1bInterval:          db  00h
END_ENDPOINT_DESCRIPTOR1_TX2:

;      /*------------- Initialize Endpoint 2 RX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR1_RX2:
        gEP2Rx_1bLength:            db  END_ENDPOINT_DESCRIPTOR1_RX2 - BEGIN_ENDPOINT_DESCRIPTOR1_RX2
        gEP2Rx_1bDescriptorType:    db  ENDPOINT_DESCR
        gEP2Rx_1bEndpointAddress:   db  02h     ;EP address 2, Out
        gEP2Rx_1bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP2Rx_1wMaxPacketSize_LSb: db  EP2_TX_LOOP_BACK_FIFO_SIZE
        gEP2Rx_1wMaxPacketSize_MSb: db  00
        gEP2Rx_1bInterval:          db  02h
END_ENDPOINT_DESCRIPTOR1_RX2:

;      /*------------- Initialize Endpoint 3 TX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR1_TX3:
        gEP3Tx_1bLength:            db  END_ENDPOINT_DESCRIPTOR1_TX3 - BEGIN_ENDPOINT_DESCRIPTOR1_TX3
        gEP3Tx_1bDescriptorType:    db  ENDPOINT_DESCR
        gEP3Tx_1bEndpointAddress:   db  83h     ;EP address 3, in
        gEP3Tx_1bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP3Tx_1wMaxPacketSize_LSb: db  EP3_TX_LOOP_BACK_FIFO_SIZE
        gEP3Tx_1wMaxPacketSize_MSb: db  00
        gEP3Tx_1bInterval:          db  8h      ; 8 millisecond polling rate.
END_ENDPOINT_DESCRIPTOR1_TX3:

;      /*------------- Initialize Endpoint 3 RX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR1_RX3:
        gEP3Rx_1bLength:            db  END_ENDPOINT_DESCRIPTOR1_RX3 - BEGIN_ENDPOINT_DESCRIPTOR1_RX3
        gEP3Rx_1bDescriptorType:    db  ENDPOINT_DESCR
        gEP3Rx_1bEndpointAddress:   db  03h     ;EP address 3, Out
        gEP3Rx_1bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP3Rx_1wMaxPacketSize_LSb: db  EP3_RX_LOOP_BACK_FIFO_SIZE
        gEP3Rx_1wMaxPacketSize_MSb: db  00
        gEP3Rx_1bInterval:          db  1h
END_ENDPOINT_DESCRIPTOR1_RX3:

END_CONFIG1_DESCRIPTOR:

BEGIN_CONFIG2_DESCRIPTOR:
        gConfig2_bLength:               db 09h
        gConfig2_bDescriptorType:       db CONFIG_DESCR
        gConfig2_bTotalLength:          db END_CONFIG2_DESCRIPTOR - BEGIN_CONFIG2_DESCRIPTOR
        gConfig2_bCorrection:           db 0
        gConfig2_bNumInterfaces:        db 1  ; NUM_OF_INTERFACES;
        gConfig2_bConfigurationValue:   db 1
        gConfig2_iConfiguration:        db 04h
        gConfig2_bmAttributes:          db 0A0h ; Bus  Powered, RWU Capable
        gConfig2_MaxPower:              db 045        ;90ma
;       /*------------- Initialize global Interface descriptor ---------------*/
BEGIN_INTERFACE2_DESCRIPTOR:
        gInterface2_bLength:            db END_INTERFACE2_DESCRIPTOR - BEGIN_INTERFACE2_DESCRIPTOR
        gInterface2_bDescriptorType:    db INTERFACE_DESCR
        gInterface2_bInterfaceNumber:   db 0
        gInterface2_bAlternateSetting:  db 0
        gInterface2_bNumEndpoints:      db 06h
        gInterface2_bInterfaceClass:    db 00h
        gInterface2_bInterfaceSubClass: db 00h
        gInterface2_bInterfaceProtocol: db 00h
        gInterface2_iInterface:         db 05h
END_INTERFACE2_DESCRIPTOR:

;      /*------------- Initialize Endpoint 1 TX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR2_TX1:
        gEP1Tx_2Length:             db  END_ENDPOINT_DESCRIPTOR2_TX1 - BEGIN_ENDPOINT_DESCRIPTOR2_TX1
        gEP1Tx_2bDescriptorType:    db  ENDPOINT_DESCR
        gEP1Tx_2bEndpointAddress:   db  81h     ;EP address 1, in
        gEP1Tx_2bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP1Tx_2wMaxPacketSize_LSb: db  EP1_TX_LOOP_BACK_FIFO_SIZE
        gEP1Tx_2wMaxPacketSize_MSb: db  00
        gEP1Tx_2bInterval:          db  00h
END_ENDPOINT_DESCRIPTOR2_TX1:

;      /*------------- Initialize Endpoint 1 RX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR2_RX1:
        gEP1Rx_2Length:             db  END_ENDPOINT_DESCRIPTOR1_RX1 - BEGIN_ENDPOINT_DESCRIPTOR1_RX1
        gEP1Rx_2bDescriptorType:    db  ENDPOINT_DESCR
        gEP1Rx_2bEndpointAddress:   db  01h     ;EP address 1, out
        gEP1Rx_2bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP1Rx_2wMaxPacketSize_LSb: db  EP1_RX_LOOP_BACK_FIFO_SIZE
        gEP1Rx_2wMaxPacketSize_MSb: db  00
        gEP1Rx_2bInterval:          db  00h
END_ENDPOINT_DESCRIPTOR2_RX1:

;      /*------------- Initialize Endpoint 2 TX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR2_TX2:
        gEP2Tx_2bLength:            db  END_ENDPOINT_DESCRIPTOR1_TX2 - BEGIN_ENDPOINT_DESCRIPTOR1_TX2
        gEP2Tx_2bDescriptorType:    db  ENDPOINT_DESCR
        gEP2Tx_2bEndpointAddress:   db  82h     ;EP address 2, in
        gEP2Tx_2bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP2Tx_2wMaxPacketSize_LSb: db  EP2_TX_LOOP_BACK_FIFO_SIZE
        gEP2Tx_2wMaxPacketSize_MSb: db  00
        gEP2Tx_2bInterval:          db  00h
END_ENDPOINT_DESCRIPTOR2_TX2:

;      /*------------- Initialize Endpoint 2 RX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR2_RX2:
        gEP2Rx_2bLength:            db  END_ENDPOINT_DESCRIPTOR2_RX2 - BEGIN_ENDPOINT_DESCRIPTOR2_RX2
        gEP2Rx_2bDescriptorType:    db  ENDPOINT_DESCR
        gEP2Rx_2bEndpointAddress:   db  02h     ;EP address 2, Out
        gEP2Rx_2bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP2Rx_2wMaxPacketSize_LSb: db  EP2_TX_LOOP_BACK_FIFO_SIZE
        gEP2Rx_2wMaxPacketSize_MSb: db  00
        gEP2Rx_2bInterval:          db  02h
END_ENDPOINT_DESCRIPTOR2_RX2:

;      /*------------- Initialize Endpoint 3 TX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR2_TX3:
        gEP3Tx_2bLength:            db  END_ENDPOINT_DESCRIPTOR2_TX3 - BEGIN_ENDPOINT_DESCRIPTOR2_TX3
        gEP3Tx_2bDescriptorType:    db  ENDPOINT_DESCR
        gEP3Tx_2bEndpointAddress:   db  83h     ;EP address 3, in
        gEP3Tx_2bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP3Tx_2wMaxPacketSize_LSb: db  EP3_TX_LOOP_BACK_FIFO_SIZE
        gEP3Tx_2wMaxPacketSize_MSb: db  00
        gEP3Tx_2bInterval:          db  8h      ; 8 millisecond polling rate.
END_ENDPOINT_DESCRIPTOR2_TX3:

;      /*------------- Initialize Endpoint 3 RX descriptor ---------------*/
BEGIN_ENDPOINT_DESCRIPTOR2_RX3:
        gEP3Rx_2bLength:            db  END_ENDPOINT_DESCRIPTOR2_RX3 - BEGIN_ENDPOINT_DESCRIPTOR2_RX3
        gEP3Rx_2bDescriptorType:    db  ENDPOINT_DESCR
        gEP3Rx_2bEndpointAddress:   db  03h     ;EP address 3, Out
        gEP3Rx_2bmAtrributes:       db  02h     ;00-Control, 1-ISO, 2-Bulk,3-Interrupt
        gEP3Rx_2wMaxPacketSize_LSb: db  EP3_RX_LOOP_BACK_FIFO_SIZE
        gEP3Rx_2wMaxPacketSize_MSb: db  00
        gEP3Rx_2bInterval:          db  1h
END_ENDPOINT_DESCRIPTOR2_RX3:

END_CONFIG2_DESCRIPTOR:


IF PLC
	DEFINE  EMBEDDED_FN_STRINGS_CODE_SEG, SPACE=CODE
	SEGMENT EMBEDDED_FN_STRINGS_CODE_SEG
ENDIF
IF KEIL
    EMBEDDED_FN_STRINGS_CODE_SEG SEGMENT CODE
	RSEG EMBEDDED_FN_STRINGS_CODE_SEG
ENDIF

STRING_LOC_TABLE:
;*********** LANGUAGE ID's supported text ***************
STRING_0:      db  LOW(STRING_1-STRING_0)
               db  STRING_DESCR
               db  09h,04h              ; 2 Byte lang id for English: ie. 0409h
;*********** MANUFACTURER String Descriptor text ***************
STRING_1:      db  LOW(STRING_2-STRING_1)
               db  STRING_DESCR
               db  'I',00,'n',00,'t',00,'e',00,'l',00,' ',00,' ',00,'1',00,'9',00,'9',00,'7',00,' ',00
               db  'C',00,'E',00,'G',00,' ',00,'-',00,' ',00,'U',00,'S',00,'B',00,' ',00
               db  'W',00,'r',00,'i',00,'t',00,'t',00,'e',00,'n',00,' ',00,'b',00,'y',00,' ',00
               db  'K',00,'e',00,'n',00,' ',00,'S',00,'c',00,'h',00,'u',00,'l',00,'t',00,'z',00,' ',00,'-',00,' ',00
               db  'C',00,'h',00,'i',00,'p',00,' ',00
               db  'L',00,'i',00,'n',00,'t',00,'h',00,'i',00,'c',00,'u',00,'m',00
;*********** PRODUCT String Descriptor text ***************
STRING_2:      db  LOW(STRING_3-STRING_2)
               db  STRING_DESCR
               db  '8',00,'X',00,'9',00,'3',00,'0',00,'H',00,'X',00,' ',00
               db  'H',00,'u',00,'b',00,' ',00,'E',00,'m',00,'b',00,'e',00,'d',00,'d',00,'e',00,'d',00,' ',00
               db  'F',00,'u',00,'n',00,'c',00,'t',00,'i',00,'o',00,'n',00
;*********** SERIAL # String Descriptor text ***************
STRING_3:      db  LOW(STRING_4-STRING_3)
               db  STRING_DESCR
               db  'C',00,'o',00,'d',00,'e',00,':',00,' ',00
               db  'E',00,'M',00,'B',00,'_',00,'F',00,'U',00,'N',00,'C',00,'.',00,'A',00,'S',00,'M',00,' ',00
               ;******  CHANGE FIRMWARE REV HERE WITH EACH RELEASE *****
               db  'R',00,'e',00,'v',00,'.',00,' ',00,'1',00,'.',00,'8',00,'0',00
;*********** CONFIGURATION String Descriptor text **************
STRING_4:
               db  LOW(STRING_5-STRING_4)
               db  STRING_DESCR
IF FUB_BOARD == ENABLED         ; fub board setup message
               db  'F',00,'U',00,'B',00,' ',00,'B',00,'o',00,'a',00,'r',00,'d',00,' ',00,'S',00,'e',00,'t',00,'u',00,'p',00,',',00,' ',00
ELSE                            ; eval board setup message
               db  'E',00,'V',00,'A',00,'L',00,' ',00,'B',00,'o',00,'a',00,'r',00,'d',00,' ',00,'S',00,'e',00,'t',00,'u',00,'p',00,',',00,' ',00
ENDIF
               db  '3',00,'E',00,'P',00,'P',00,' ',00,'L',00,'o',00,'o',00,'p',00,'b',00,'a',00,'c',00,'k',00,',',00,' ',00
IF LC_TOGGLE == ENABLED
               db  'H',00,'C',00,'/',00,'L',00,'C',00,' ',00,'T',00,'o',00,'g',00,'g',00,'l',00,'e',00,'.',00
ELSE
  IF CLOCK_LOW   == ENABLED
               db  'L',00,'C',00,' ',00,'M',00,'o',00,'d',00,'e',00,',',00,' ',00
  ELSE
               db  'H',00,'C',00,' ',00,'M',00,'o',00,'d',00,'e',00,',',00,' ',00
  ENDIF
ENDIF

;*********** INTERFACE String Descriptor text ***************
STRING_5:      db  LOW(STRING_6-STRING_5)
               db  STRING_DESCR
               db  '<',00,' ',00,'I',00,'n',00,'t',00,'e',00,'r',00,'f',00,'a',00,'c',00,'e',00,' ',00
               db  'S',00,'t',00,'r',00,'i',00,'n',00,'g',00,' ',00,'>',00
STRING_6:


;#############################################################
;####### RAM MEMORY MAP ######################################
;#############################################################

;----------------------------------------------------------------------------
;- Control varaibles need to be placed between 20h & 7fh for the addressing mode
;- If RISM is running, RISM needs 20h-3fH so be careful running RISM.
;----------------------------------------------------------------------------
IF PLC
	DEFINE EMBEDDED_DATA_SEG, SPACE=DATA
	SEGMENT EMBEDDED_DATA_SEG
ENDIF
IF KEIL
    EMBEDDED_DATA_SEG SEGMENT DATA
	RSEG EMBEDDED_DATA_SEG
ENDIF

;;
;; Buffer and associated variables for Control Endpoint management

gbSetupSeqTX:             ds 1
gbSetupSeqRX:             ds 1
SuspendResumeFlag:        ds 1         ; If 0, then we are not suspended, and no suspend event is pending
                                       ; If 1, then we are not suspended, but a suspend event is pending
                                       ; If 2, then we are suspended, and no resume event is pending
                                       ; If 3, then we are suspended, but a  resume event is pending


COMMAND_BUFFER:
StandardDeviceRequest:
bmRequestType:            ds  1
FbRequest:
bRequest:                 ds  1
FwValue:
wValue:
wFeatureSelector:
bDescriptorType:          ds  1
bDescriptorIndex:         ds  1
wTargetSelector:
FwIndex:
wIndex:                   ds  2
wLength:                  ds  2

CntlWriteDataBuffer:      ds  8        ; Added to handle control writes with data stages.
                                       ; When a control Write with a data stage is detected
                                       ; the data is placed in this buffer.  When all the data
                                       ; has been collected(Bytes received=wLength) the actual routine is
                                       ; called.  The size of data is limited to this buffer length.

CntlWriteDataPntr:       ds  1        ; Used to point into the CntlWriteDataBuffer.

gbFControlBufferLocation:  ds  3
gbFControlBufferBytesLeft: ds  2

Heart1:                   ds  2


EP0_ERROR_CNT:            ds  1
FTLOCK_FLG:               ds  1
EMB_FN_RWU_FLG:           ds  1

IF PLC
	DEFINE EMBEDDED_PDATA_SEG, SPACE=PDATA
	SEGMENT EMBEDDED_PDATA_SEG
ENDIF
IF KEIL
    EMBEDDED_PDATA_SEG SEGMENT EDATA
	RSEG EMBEDDED_PDATA_SEG
ENDIF

Ep1WritePointer:              ds 2  ; Where the next byte of data
                                    ;will be written in Memory (Zero Relitive)
Ep1ReadPointer:               ds 2  ; Where the next byte of data
                                    ;will be Read From in Memory (Zero Relitive)
Ep1BytesInBuffer:             ds 2


Ep2WritePointer:              ds 2  ; Where the next byte of data
                                    ;will be written in Memory (Zero Relitive)
Ep2ReadPointer:               ds 2  ; Where the next byte of data
                                    ;will be Read From in Memory (Zero Relitive)
Ep2BytesInBuffer:             ds 2


Ep3WritePointer:              ds 2  ; Where the next byte of data
                                    ;will be written in Memory (Zero Relitive)
Ep3ReadPointer:               ds 2  ; Where the next byte of data
                                    ;will be Read From in Memory (Zero Relitive)
Ep3BytesInBuffer:             ds 2

Ep1Temp:                      ds 1
Ep2Temp:                      ds 1
Ep3Temp:                      ds 1

EP1_TX_COUNTER:           ds  4
EP1_TX_ERR_COUNTER:       ds  4
EP1_RX_COUNTER:           ds  4
EP1_RX_ERR_COUNTER:       ds  4
EP2_TX_COUNTER:           ds  4
EP2_TX_ERR_COUNTER:       ds  4
EP2_RX_COUNTER:           ds  4
EP2_RX_ERR_COUNTER:       ds  4
EP3_TX_COUNTER:           ds  4
EP3_TX_ERR_COUNTER:       ds  4
EP3_RX_COUNTER:           ds  4
EP3_RX_ERR_COUNTER:       ds  4


RWUTimer:                 ds  4

CurrentConfiguration:     ds  1
CurrentConfig1Interface:  ds  1
STACK_DATA:               ds  40h


Ep1Tx_ERR:      ds   1
Ep1Tx_OVF:      ds   1
Ep1Tx_URF:      ds   1
Ep1Rx_ERR:      ds   1
Ep1Rx_OVF:      ds   1
Ep1Rx_URF:      ds   1

Ep2Tx_ERR:      ds   1
Ep2Tx_OVF:      ds   1
Ep2Tx_URF:      ds   1
Ep2Rx_ERR:      ds   1
Ep2Rx_OVF:      ds   1
Ep2Rx_URF:      ds   1

Ep3Tx_ERR:      ds   1
Ep3Tx_OVF:      ds   1
Ep3Tx_URF:      ds   1
Ep3Rx_ERR:      ds   1
Ep3Rx_OVF:      ds   1
Ep3Rx_URF:      ds   1

IF PLC
IF FUB_BOARD == ENABLED                                 ; Buffers for FUB board
  Ep1LoopBackBufferSize:        equ     0100h
  Ep2LoopBackBufferSize:        equ     0100h
  Ep3LoopBackBufferSize:        equ     0100h
ELSE                                                    ; Buffers for Eval board
  Ep1LoopBackBufferSize:        equ     0141h  ; 256 + 64 + 1
  Ep2LoopBackBufferSize:        equ     0109h  ; 256 + 8 + 1
  Ep3LoopBackBufferSize:        equ     0109h  ; 256 + 8 + 1
ENDIF
ENDIF
IF KEIL
IF FUB_BOARD == ENABLED                                 ; Buffers for FUB board
  Ep1LoopBackBufferSize        equ     0100h
  Ep2LoopBackBufferSize        equ     0100h
  Ep3LoopBackBufferSize        equ     0100h
ELSE                                                    ; Buffers for Eval board
  Ep1LoopBackBufferSize        equ     0141h  ; 256 + 64 + 1
  Ep2LoopBackBufferSize        equ     0109h  ; 256 + 8 + 1
  Ep3LoopBackBufferSize        equ     0109h  ; 256 + 8 + 1
ENDIF
ENDIF
; Allocate the area for each buffer size.
  Ep1LoopBackBuffer:            ds  Ep1LoopBackBufferSize
  Ep2LoopBackBuffer:            ds  Ep2LoopBackBufferSize
  Ep3LoopBackBuffer:            ds  Ep3LoopBackBufferSize

END
