; Device data
;
; v1.20 sxkey sofware for AB0004AA+ does not support TURBO, STACKX directives
; but stops at opcode instruction
;
; v1.12 is used for AA9999 devices, v1.2 cannot be used for that one.
; 
;
; V5 utilise le double paquet de 2x1K
;



;RS232_SETTING
RS485_setting

                
                ; device  TURBO, STACKX, OSCHS, DRT18MS
                ; device  TURBO, STACKX
                device OSCHS3, DRT18MS

		id	'SX52'
		reset	reset_entry
		freq	50_000_000


                ; stackx allows 8 levels of stack, otherwise only 2 are used
                ; and screws up completely the SW
                ; carryx allows add/sub Do not use
                ; OSCHS : External High Speed Osc, mandatory to enable external oscillator
                ;         Disable it when using SX-KEY !!!
                ; DRT18MS : Boots after 18ms


; RS232 variables
IFDEF RS232_SETTING
rx_pin		=	rd.7			;RS232 receive	port D7
tx_pin		=	rd.6			;RS232 transmit	port D6
ENDIF


; RS485 variables

IFDEF RS485_setting
DI_pin          =       re.4
DE_pin          =       re.5
RO_pin          =       re.6
ENDIF



; ram variables
; Equates
RESET_CS8900           	=	rc.3
RAMWrite		=	rc.4
RAMRead 		=	rc.5


; FIFOs variables
; Equates
FIFOWrite		=	rc.7
FIFORead		=	rd.0
FIFOFull                =       rd.1
ClearFIFO		=	rd.2
EmptyFIFO 		=	rc.6




;Priority
IPPriority             equ  $7C


; Constants
; *Change these* : Configuration equates.

Timeout equ     50
NbRetry equ     200


IP1     equ     $86 ;  134           first octet of IP address
IP2     equ     $AB ;  171           second octet of IP address
IP3     equ     12  ;                  third octet of IP address
IP4     equ     147 ;                  fourth octet of IP address


MAC1    equ     $00                    ;\
MAC2    equ     $11                    ;  \
MAC3    equ     $86                    ;    \
MAC4    equ     $54                    ;    48 bit IEEE OUI (Organizationally Unique Identifier)
MAC5    equ     $80                    ;  /
MAC6    equ     $96                    ;/


;Gateway IP adress
GIP1     equ     $86 ;  134           first octet of IP address
GIP2     equ     $AB ;  171           second octet of IP address
GIP3     equ     $0C ;  12            third octet of IP address
GIP4     equ     $C7 ;  199           fourth octet of IP address


; Crystal CS8900 PacketPage equates

portRxTxData  equ $00   ;Receive/Transmit data (port 0)
portRxTxData1 equ $02   ;Receive/Transmit data (port 0)
portTxCmd     equ $04   ;Transmit Commnad
portTxLength  equ $06   ;Transmit Length
portISQ       equ $08   ;Interrupt status queue
portPtr       equ $0A   ;PacketPage pointer
portData      equ $0C   ;PacketPage data (port 0)
portData1     equ $0E   ;PacketPage data (port 1)

; CS8900 PacketPage Offsets

ppEISA       equ $0000  ;EISA Registration number of CS8900
ppProdID     equ $0002  ;Product ID Number
ppIOBase     equ $0020  ;I/O Base Address
ppIntNum     equ $0022  ;Interrupt number (0,1,2, or 3)
ppMemBase    equ $002C  ;Memory Base address register (20 bit)
ppRxCfg      equ $0102  ;Receiver Configuration
ppRxCtl      equ $0104  ;Receiver Control
ppTxCfg      equ $0106  ;Transmit Configuration
ppBufCfg     equ $010A  ;Buffer Configuration
ppLineCtl    equ $0112  ;Line Control
ppSelfCtl    equ $0114  ;Self Control
ppBusCtl     equ $0116  ;Bus Control
ppTestCtl    equ $0118  ;Test Control
ppISQ        equ $0120  ;Interrupt status queue
ppRxEvt      equ $0124  ;Receiver Event
ppTxEvt      equ $0128  ;Transmitter Event
ppBufEvt     equ $012C  ;Buffer Event
ppRxMiss     equ $0130  ;Receiver Miss Counter
ppTxCol      equ $0132  ;Transmit Collision Counter
ppLineSt     equ $0134  ;Line Status
ppSelfSt     equ $0136  ;Self Status
ppBusSt      equ $0138  ;Bus Status
ppTxCmd      equ $0144  ;Transmit Command Request
ppTxLength   equ $0146  ;Transmit Length
ppIndAddr    equ $0158  ;Individual Address (IA)
ppRxStat     equ $0400  ;Receive Status
ppRxLength   equ $0402  ;Receive Length
ppRxFrame    equ $0404  ;Receive Frame Location
ppTxFrame    equ $0A00  ;Transmit Frame Location

; Register Numbers

REG_NUM_MASK        equ     $003F
REG_NUM_RX_EVENT    equ     $0004
REG_NUM_TX_EVENT    equ     $0008
REG_NUM_BUF_EVENT   equ     $000C
REG_NUM_RX_MISS     equ     $0010
REG_NUM_TX_COL      equ     $0012

; Self Control Register

SELF_CTL_RESET      equ     $0040
SELF_CTL_HC1E       equ     $2000
SELF_CTL_HCB1       equ     $8000

; Self Status Register 

SELF_ST_INIT_DONE   equ     $0080
SELF_ST_SI_BUSY     equ     $0100
SELF_ST_EEP_PRES    equ     $0200
SELF_ST_EEP_OK      equ     $0400
SELF_ST_EL_PRES     equ     $0800

; Bus Control Register

BUS_CTL_USE_SA      equ     $0200
BUS_CTL_MEM_MODE    equ     $0400
BUS_CTL_IOCHRDY     equ     $1000
BUS_CTL_INT_ENBL    equ     $8000

; Bus Status Register

BUS_ST_TX_BID_ERR   equ     $0080
BUS_ST_RDY4TXNOW    equ     $0100

; Line Control Register

LINE_CTL_RX_ON      equ     $0040
LINE_CTL_TX_ON      equ     $0080
LINE_CTL_AUI_ONLY   equ     $0100
LINE_CTL_10BASET    equ     $0000

; Test Control Register

TEST_CTL_DIS_LT     equ     $0080
TEST_CTL_ENDEC_LP   equ     $0200
TEST_CTL_AUI_LOOP   equ     $0400
TEST_CTL_DIS_BKOFF  equ     $0800
TEST_CTL_FDX        equ     $4000

; Receiver Configuration Register

RX_CFG_SKIP         equ     $0040
RX_CFG_RX_OK_IE     equ     $0100
RX_CFG_CRC_ERR_IE   equ     $1000
RX_CFG_RUNT_IE      equ     $2000
RX_CFG_X_DATA_IE    equ     $4000

; Receiver Event Register

RX_EVENT_RX_OK      equ     $0100
RX_EVENT_IND_ADDR   equ     $0400
RX_EVENT_BCAST      equ     $0800
RX_EVENT_CRC_ERR    equ     $1000
RX_EVENT_RUNT       equ     $2000
RX_EVENT_X_DATA     equ     $4000

;Receiver Control Register

RX_CTL_RX_OK_A      equ     $0100
RX_CTL_MCAST_A      equ     $0200
RX_CTL_IND_A        equ     $0400
RX_CTL_BCAST_A      equ     $0800
RX_CTL_CRC_ERR_A    equ     $1000
RX_CTL_RUNT_A       equ     $2000
RX_CTL_X_DATA_A     equ     $4000

;Transmit Configuration Register

TX_CFG_LOSS_CRS_IE  equ     $0040
TX_CFG_SQE_ERR_IE   equ     $0080
TX_CFG_TX_OK_IE     equ     $0100
TX_CFG_OUT_WIN_IE   equ     $0200
TX_CFG_JABBER_IE    equ     $0400
TX_CFG_16_COLL_IE   equ     $8000
TX_CFG_ALL_IE       equ     $8FC0

;Transmit Event Register

TX_EVENT_TX_OK      equ     $0100
TX_EVENT_OUT_WIN    equ     $0200
TX_EVENT_JABBER     equ     $0400
TX_EVENT_16_COLL    equ     $1000

; Transmit Command Register

TX_CMD_START_5      equ     $0000
TX_CMD_START_381    equ     $0080
TX_CMD_START_1021   equ     $0040
TX_CMD_START_ALL    equ     $00C0
TX_CMD_FORCE        equ     $0100
TX_CMD_ONE_COLL     equ     $0200
TX_CMD_NO_CRC       equ     $1000
TX_CMD_NO_PAD       equ     $2000

;Buffer Configuration Register

BUF_CFG_SW_INT      equ     $0040
BUF_CFG_RDY4TX_IE   equ     $0100
BUF_CFG_TX_UNDR_IE  equ     $0200

; PORTA pin assignments (Crystal address bus)

SA0     equ     0
SA1     equ     1
SA2     equ     2
SA3     equ     3




; PORTB pin assignments (Crystal data bus)

SD0     equ     0
SD1     equ     1
SD2     equ     2
SD3     equ     3
SD4     equ     4
SD5     equ     5
SD6     equ     6
SD7     equ     7

; PORTC pin assignments (Crystal signals CHIPSEL/IOW/IOR)

_IOR     equ     0       ;active low signal to initiate I/O read operation
_IOW     equ     1       ;active low signal to initiate I/O write operation
INTR     equ     2       ;active HIGH interrupt pending signal. Auto cleared after read of ISQ

; Register file assignments
; GLOBAL Register are accessible from $0A to $0F (6)

          org $0A

tempH     ds    1   ; GLOBAL REGISTER SPACE
tempL     ds    1
valueH    ds    1
valueL    ds    1
offsetH   ds    1
offsetL   ds    1
                   ; Bank 0, adress $10

          org   $10
manageUDP	=	$

flags     ds    1  ;$10    bit1=valid frame, bit2=ARP frame,  bit3=Send back init , bit4=send ARP Request
lengthH   ds    1  ;$11
lengthL   ds    1  ;$12
AdrssH    ds    1  ;$13
AdrssL    ds    1  ;$14
ppEISH    ds    1  ;$15
ppEISL    ds    1  ;$16
ppProdIDV ds    1  ;$17

packetNbReceive ds  1  ;$19
packetNbSend    ds  1  ;$1a

HandCheckCountH ds  1  ;$1b
HandCheckCountL ds  1  ;$1c
HandCheckFlags  ds  1  ;$1d
HandCheckNbTry  ds  1  ;$1e
HandCheckTimeOut ds  1  ;$1f


                org     $20
packet    ds    10*15    ; what's remains : 112 bytes for reception

                org     $90
packetbackup    ds      3*16 ; Packet backup to return a message



		org     $C0
rx_byte                  ds     1              ;RX buffer (FIFO)
rx_buffer                ds     1

		org	$D0
; RS232 or RS485 variables

rx_byte1 	         ds	1               ;RX buffer adress
rx_byte2  	         ds	1

tx_high		         ds	1               ;tx
tx_low	                 ds	1
tx_count	         ds	1
tx_divide	         ds	1

rx_count	         ds	1   		;rx
rx_divide	         ds	1



                org       $E0
RRefreshARPCounterLL     ds      1
RRefreshARPCounterLH     ds      1
RRefreshARPCounterHL     ds      1
RRefreshARPCounterHH     ds      1


                org       $F0
RAMCurrentSlot      ds     1
RAMNbSlotFree       ds     1
RAMSlotToWriteRead  ds     1
RAMSlotFree         ds     2

RAMpacketNbSendSlot  ds   2

RAMPacketToSendSlotH ds   2
RAMPacketToSendSlotL ds   2




RAMPacketToSendH  ds      1
RAMPacketToSendL  ds      1
RAMPacket         ds      1
RAMPacketH        ds      1
RAMPacketL        ds      1











; Packet offset equates
; Packet header
; all fit in a single bank $20

pktLenH   equ   $00
pktLenL   equ   $01
pktDest0H equ   $02
pktDest0L equ   $03
pktDest1H equ   $04
pktDest1L equ   $05
pktDest2H equ   $06
pktDest2L equ   $07
pktSrc0H  equ   $08
pktSrc0L  equ   $09
pktSrc1H  equ   $0a
pktSrc1L  equ   $0b
pktSrc2H  equ   $0c
pktSrc2L  equ   $0d
pktTypeH  equ   $0e
pktTypeL  equ   $0f

; ARP
; next bank,    $30

ar_hwtype equ   $10            ;hardware type
ar_prtype equ   $12            ;protocol type
ar_hwlen  equ   $14            ;hardware address length
ar_prlen  equ   $15            ;protocol address length
ar_op     equ   $16            ;ARP operation (1=request, 2=reply)
ar_sha    equ   $18            ;senders hardware address
ar_spa    equ   $1e            ;senders IP address
                               ;next bank , $40
ar_tha    equ   $22            ;target hardware address
ar_tpa    equ   $28            ;target IP address


; IP header
; next bank, $30

ip_verlen equ   $10            ;IP version and header length(in longs)
ip_tos    equ   $11            ;IP type of service
ip_len    equ   $12            ;packet length (length-header_length)
ip_id     equ   $14            ;datagram id
ip_fragoff equ  $16            ;fragment offset
ip_ttl    equ   $18            ;time to live (in gateway hops)
ip_proto  equ   $19            ;protocol (ICMP=1, TCP=6, EGP=8, UDP=17)
ip_cksum  equ   $1a            ;header checksum
ip_src    equ   $1c            ;IP address of source

                               ;next bank $40
ip_dst    equ   $20            ;IP addess of destination
ip_data   equ   $24

; IP value equates

IPT_ICMP  equ   1               ;protocol type for ICMP packets
IPT_TCP   equ   6               ;protocol type for TCP packets
IPT_EGP   equ   8               ;protocol type for EGP packets
IPT_UDP   equ   $11             ;protocol type for UDP packets

;
; ICMP header
; bank 40

ic_type   equ   ip_data         ;0=reply, 8=request, others=who-cares
ic_code   equ   ic_type+1       ;code
ic_cksum  equ   ic_code+1       ;checksum of header+data
ic_id     equ   ic_cksum+2      ;message id
ic_seq    equ   ic_id+2         ;sequence number

; UDP Header

u_src     equ   ip_data         ;source udp port number
u_dst     equ   u_src+2         ;destination UDP port number
u_len     equ   u_dst+2         ;length of UDP header+data
u_cksum   equ   u_len+2         ;checksum  (see note)
u_data    equ   u_cksum+2       ;start of data



UDP_PORT_SCR  equ 191            ;UDP port we are listenning here





; Note: checksum is calculated by taking the 16 bit sums of the ip_src, ip_dst,
; ip_proto, u_len, and the sum starting at u_src for a length of u_len
; yes, this means that u_len is taken twice! u_cksum is zero during the calc.
; The sum is then one's complemented. This is the checksum







; PORTA is Adresses
; PORTB is DATA
; PortC is control

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WHAT this program does ?
;
; This program uses the cs8900 as 8 bits and the IO mode
; Initialise the cs8900
; - Gives its mac adresses
; waits for interrupts on IRQ line port C
; if one, reads the frame, checks it's an IP frame or ARP frame.
; if it's an ARP frame nothing is done.
; if it's an IP  frame, checks if it's an ICMP frame (for ping requests)
;   -if yes sends back the ping request





        ; Global register space
        Watch ValueH  ,8,UHex
        Watch ValueL  ,8,UHex
        Watch offsetH ,8,UHex
        Watch offsetL ,8,UHex
        Watch TempH   ,8,UHex
        Watch TempL   ,8,UHex
        ;BanK 1
        Watch lengthH  ,8,UHex
        Watch lengthL  ,8,UHex
        Watch flags    ,8,UHex
        Watch AdrssH   ,8,UHex
        Watch AdrssL   ,8,UHex
        Watch ppEISH   ,8,UHex
        Watch ppEISL   ,8,UHex
        Watch ppProdIDV,8,UHex

        Watch RAMPacketToSendH,8,UHex
        Watch RAMPacketToSendL,8,UHex
        Watch RAMPacketH,8,UHex
        Watch RAMPacketL,8,UHex




        org 0

interrupt
                jmp     @interrupt_



Dinput  macro                   ;Change the data bus to input
         mov	!RB,#%11111111	;Set port B to input direction , crystal data bus input
        endm
Doutput macro                   ;Change the data bus to output
         mov	!RB,#%00000000	;Set port B to output direction , crystal data bus output
        endm



; Write to Port B the W value at the address \1

iow    	macro    1	      ; I/O port write PORT is the parameter
        mov      RB,W         ; writes W to the port B
        mov      W,#\1        ; writes port value to W
        mov      RA,W         ; Activates A address port
	nop
        clrb     RC._IOW      ; Add nops here to make 1 nop=20ns
        nop
        nop
        nop
        nop
        nop
        nop
	nop
	nop
        setb     RC._IOW
        endm


; performs IO read, \1 is the PORT parameter, or the PORT
; Result : W is the read value.

iortoW  macro   1            ;I/O port read no bank related
        mov     W,#\1
        mov     RA,W         ;set port
	nop
        clrb    RC._IOR
        nop
        nop
        nop
        nop
        nop
        nop
	nop
	nop
        mov     W,RB         ;Get to W the Data in port B
        setb    RC._IOR
        endm

iortoWp
        mov     RA,W         ;set port
	nop
        clrb    RC._IOR
        nop
        nop
        nop
        nop
        nop
        nop
	nop
	nop
        mov     W,RB         ;Get to W the Data in port B
        setb    RC._IOR
        retp



; Reads values from packetPage port
; \1 is the 16 bits adress
; OffsetL,offsetH the low byte and high byte of \1
; result in : ValueL and ValueH

ppRD    macro   1               ;Read PacketPage port
        mov     W,#\1 & $ff
        mov     offsetL,W
        mov     W,#\1 >> 8
        mov     offsetH,W
        Doutput                 ;make the data bus output
        mov     W,offsetL      ;get the offset to read
        iow     portPtr         ;write to PacketPage Ptr
        mov     W,offsetH      ;get the high order offset
        iow     portPtr+1       ;PagePacket Pointer Register high byte
        Dinput
                                 ;make the data bus input
        mov     w,#portData        ;read the PacketPage data
        call    @iortoWp
        mov     valueL,W        ;save value low        
        mov     W,#portData+1      ;read the high order byte
        call    @iortoWp
        mov     valueH,W        ;save the high order byte value
        endm

; Write to PacketPage port setup and command values to cs8900 registers
; \1 is the 16 bits adress
; \2 is the parameter to write
; offsetL,offsetH the low byte and high byte of \1
ppWR    macro  2        ;Write PacketPage port
        mov    W,#\1 & $ff
        mov    offsetL,W
        mov    W,#\1 >> 8
        mov    offsetH,W
        mov    W,#\2 & $ff
        mov    valueL,W
        mov    W,#\2 >> 8
        mov    valueH,W
        call   WritePP 
        endm







        
;jmp TABLE
        _InitFIFO          jmp @InitFIFO
        _ResetFIFO         jmp @ResetFIFO
        _InitRAM           jmp @InitRAM
        _testFIFO          jmp @testFIFO


        _VerChip           jmp @VerChip
        _ResetChip         jmp @ResetChip
        _InitChip          jmp @InitChip

        _SendArp           jmp @SendArp
        _SendARPResponse   jmp @SendARPResponse

        _ReceiveEvent      jmp @ReceiveEvent
        _TransmitEventJMP  jmp @TransmitEvent
        _wait1ms           jmp @wait1ms
        _wait500ms         jmp @wait500ms
        _wait500ns         jmp @wait500ns

        _send_byte	   jmp @send_byte

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; STARTING POINT 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


reset_entry

        mov     W,#31
        mov     M,W       ; Mov M,#$1F  DOES not WORK
                          ; IMPORTANT -> Define that all  mov	!rx,#lit are 
                          ; related to define port direction, otherwise, PORT can behave as dead !!!!

                     ;76543210
        mov	!rd,#%10000010   ; init rd
        mov	!RC,#%01000100	 ; Set port C to output direction
        mov	!RA,#%00000000	; Set port A to output direction , crystal address bus output
        mov	!RB,#%11111111	; Set port B to input  direction , crystal data bus

        IFDEF    RS485_setting
        mov	!RE,#%11000000	; Set port E
        ELSE
        mov	!RE,#%10000000	; Set port E
        ENDIF

      	mov 	fsr,#$0A	; reset ram banks 1..F, global
:loopWipeMemory   ; Delete all SX52 memory
	clr	ind
	ijnz	fsr,:loopWipeMemory



        call     _wait500ms      ; Start all high !
        setb     RESET_CS8900    ; Reset Hard
        Call     _wait500ns      ; More than 400ns
        clrb     RESET_CS8900    ;

        call     _wait500ms      ; Leave time to cs8900 to initialize ....
        call     _wait1ms

	mov	!option,#%10011111	;enable rtcc interrupt

        mov     FSR,#$10        ; Change to Bank 1 , has no effect on variables on bank 0
        setb    RC._IOR         ; no read on crystal
        setb    RC._IOW         ; no write on crystal
        mov     RA,#0           ; clear PORTA



        ;FIFO and RAM init 
        call    _InitFIFO
        call    _InitRAM        
        call    _ResetFIFO
        
        
        call    @_ResetChip ; takes 12.5ms
        call    @_InitChip

        ;Setup ARP request
        mov     FSR,#$10

        setb    flags.3    ; Si a 1 parle a un gateway eventuel
	setb    flags.4    ; Si a 1 resete le cs8900 si rien n'est recu    
                           ; mettre a 1 ces flags a l'ESO 
                           

	;Send ARP counter
	mov 	fsr,#$E0
        mov	RRefreshARPCounterLL,#$FF
	mov	RRefreshARPCounterLH,#$FF
	mov	RRefreshARPCounterHL,#$FF
	mov	RRefreshARPCounterHH,#$0F


        ;Setup handcheck
        mov     FSR,#$10
        clrb    HandCheckFlags.0
        mov     HandCheckTimeOut,#TimeOut

        mov     FSR,#$F0
        mov     RAMNbSlotFree,#2





       	;Test RS232
        IFDEF RS232_SETTING
	mov   w,#145
	call _send_byte
        ENDIF
	;Test RS485
	IFDEF RS485_SETTING


	mov   w,#$02
	call _send_byte
	mov   w,#$4c
	call _send_byte
	mov   w,#$30
	call _send_byte
	mov   w,#$31
	call _send_byte
	mov   w,#$30
	call _send_byte
	mov   w,#$31
	call _send_byte
	mov   w,#$30
	call _send_byte
	mov   w,#$30
	call _send_byte
	mov   w,#$32
	call _send_byte
	mov   w,#$32
	call _send_byte
	mov   w,#$03
	call _send_byte





        ENDIF



loopCs8900INTR    ; wait for cs8900 Frame recieve interrupt


        jb      RC.INTR,endloop   ; 

        call    _testFIFO         ; Input FIFO from slave , is there is something ? 


	; Arp request refresh
        ;

        mov 	fsr,#$E0
	decsz   RRefreshARPCounterLL
        jmp     RRefreshARPCounterNext1


        mov	RRefreshARPCounterLL,#$FF
        decsz   RRefreshARPCounterLH
        jmp     RRefreshARPCounterNext1

        mov	RRefreshARPCounterLH,#$FF
        decsz   RRefreshARPCounterHL
        jmp     RRefreshARPCounterNext1

        mov	RRefreshARPCounterHL,#$50
        decsz   RRefreshARPCounterHH
        jmp     RRefreshARPCounterNext1

        mov	RRefreshARPCounterHH,#$01

        mov     FSR,#$10
        sb      flags.4
        jmp     RRefreshARPCounterNext1
        call    @_ResetChip
        call    @_InitChip

        ;FIFO and RAM init
        call    _InitFIFO
        call    _InitRAM
        call    _ResetFIFO

        call    _sendARP


RRefreshARPCounterNext1


        jmp     LoopCs8900INTR


endloop

        mov     FSR,#$10
        sb      flags.3
        jmp     NextEvt
        clrb    flags.3
        call    _sendARP



        ; Read the ISQ
NextEvt Dinput

	;Reset CS8900 counter
        ;mov 	fsr,#$E0
        ;mov	RRefreshARPCounterLL,#$FF
	;mov	RRefreshARPCounterLH,#$FF
	;mov	RRefreshARPCounterHL,#$50
	;mov	RRefreshARPCounterHH,#$01


        iortoW  portISQ         ;read interrupt status queue
        mov     valueL,W        ;save value low
        iortoW  portISQ+1       ;read interrupt status queue high
        mov     valueH,W        ;save value high

        test     valueL
        jz       endISQ          ;if zero, then done

        mov     TempL,valueL
        mov     W,#REG_NUM_RX_EVENT
        sub     TempL,W        ;IS RxEvent?
        sb      STATUS.2       ;get low value  if zero Z=1
        jmp     testeventSend:
        snb     valueH.0
        jmp     evtRecv


        ;ppRD   ppRxCfg  ;Read RxConfig
        ;setb   valueL.6
        ;call   WritePP
        ;jmp     NextEvt

testeventSend:

        mov     TempL,valueL
        mov     W,#REG_NUM_TX_EVENT
        sub     TempL,W            ; TxEvent?
        snb     STATUS.2           ; Ignore BufEvent, RxMiss, and TxCol
        call    @_TransmitEventJMP ; Nothing is done here ....
        jmp     NextEvt

evtRecv call    _ReceiveEvent
        jmp     NextEvt


endISQ  mov     FSR,#$10                ; Change to Bank 1
        sb      flags.0                 ; Is frame valid ? received frame flag
        jmp     loopCs8900INTR

        clrb    flags.0                 ; clear the receive flag
        sb      flags.1                 ; bit set when valid arp
        jmp     loopCs8900INTR

        clrb    flags.1                 ; clear the valid arp request flag
        call    @_SendARPResponse
        jmp     loopCs8900INTR







        org $200

; Writes the value at valueH/valueL to the PagePacket register who's
; address is in offsetH/offsetL

WritePP Doutput                 ;make the data bus output
        mov     W,offsetL       ;get the low order byte
        iow     portPtr         ;write to PacketPage Ptr
        mov     W,offsetH       ;get the high order byte
        iow     portPtr+1       ;write to PacketPage ptr
        mov     W,valueL        ;get low order value to write
        iow     portData        ;write to PacketPage data
        mov     W,valueH        ;get high order data
        iow     portData+1      ;write to PacketPage data
retp


; wait for 1msec millisecond
wait1ms
        mov     TempH,#25
:wait_loop1
        mov     TempL,#255
:wait_loop2
        nop
        nop
        nop
        nop
	nop
	nop
        djnz    tempL,:wait_loop2
        djnz    tempH,:wait_loop1
retp



ResetChip
        ppRD   ppSelfCtl        ;issue a reset to the chip
        setb   valueL.6
        call   WritePP          ;write it back to cs8900

ResetWait
        call   wait1ms         ;a millisecond
        ppRD   ppSelfCtl       ;get the Self Control status
        snb    valueL.6        ;see it bit 6 (RESET) was cleared
        jmp    ResetWait       ;no, then still in reset, wait some more

        ppRD   ppSelfSt        ;get self status
        sb     valueL.7        ;bit 7 is INITD
        jmp    ResetWait       ;when set, initialization of the CS8900 is done

        retp







InitChip
         ; Writes registers to cs89000

         ppWR   ppTestCtl  ,TEST_CTL_FDX                                 ; set to full duplex

                                                                         ; Receive configuration
         ppWR   ppRxCfg    ,RX_CFG_RX_OK_IE                              ; enable RxOK interrupt

                                                                         ; Set receive control
         ppWR   ppRxCtl    ,(RX_CTL_RX_OK_A|RX_CTL_IND_A|RX_CTL_BCAST_A) ; Frame with CRC ok, between 64 and 1518 bytes +
                                                                         ; Frames are Ok if destination address match individual address PacketBasePage + $0158 and $015D
                                                                         ; Frames are Ok if destination address match multicast address that passes the hash filter

         ;ppWR   ppTxCfg    ,TX_CFG_ALL_IE                               ; set transmit config
                                                                         ; all Interrup Events are SET


         ; Important: The IA needs to be byte revered IA=aa:bb:cc:dd:ee:ff
         ; send MAC adress to cs8900

         ppWR   ppIndAddr  ,(MAC2<<8|MAC1)  ;$bbaa Write
         ppWR   ppIndAddr+2,(MAC4<<8|MAC3)  ;$ddcc  out
         ppWR   ppIndAddr+4,(MAC6<<8|MAC5)  ;$ffee   48 bit IA

         ppWR   ppIntNum,$00                ;INT is on INTRQ0

         ppRD   ppBusCtl                    ;get/read Bus Control
         setb   valueH.7                    ;enable irq
         call   WritePP                     ;write it back to cs8900


         ppRD   ppLineCtl                   ;get Line Control
         setb   valueL.6                    ;set SerRxOn
         setb   valueL.7                    ;set SerTxOn
         call   WritePP                     ;write it back to cs8900

         retp


; Verifies that the CS8900 is attached and sets the STATUS,Z flag to
; indicate success or not set if failure.

VerChip


        Dinput                 ; make the data bus input
                               ; first, get the signature at portPtr which should be $3000
        iortoW portPtr         ; read PacketPage Ptr
        mov    valueL,W        ; save the read W value low
        mov    FSR,#$10
        mov    AdrssL,valueL   ; save Address
        iortoW portPtr+1       ; read PacketPage Ptr for high order byte
        mov    RA,W            ; set the address bus, copied to RA
        mov    valueH,W        ; save high low
        mov    AdrssH,valueH   ; save Address

        test   valueL          ; get low value  if zero Z=1
        sb     STATUS.2        ; should be 0 (i.e. $3000 low is $00), if Z=0 skip next
        jmp    VerBad

        mov    TempH,valueH
        mov    AdrssH,valueH   ; save Address
        mov    W,#$30          ; high part of $3000
        sub    TempH,W         ; subtract from value obtained valueH=valueH-W
        sb     STATUS.2        ; see if compared okay
        jmp    VerBad

        ppRD   ppEISA           ; get the EISA number which MUST be $630E otherwise something has failed
        mov    TempH ,valueH    ; beware here W is modified !!
        mov    ppEISH,valueH    ; beware here W is modified !!
        mov    W,#$63
        sub    TempH,W         ; compare to $63
        sb     STATUS.2
        jmp    VerBad

        mov    TempL ,valueL
        mov    ppEISL,valueL   ; beware here W is modified !!
        mov    W, #$0E         ; compare to $0E
        sub    TempL,W
        sb     STATUS.2
        jmp    VerBad

        ppRD   ppProdID      ; get the Product ID which should be 00$ xxxx 0000 0000
                             ; where x xxxx = 0 0011 for rev E and 0 0101 for rev F
        mov    ppProdIDV,W   ; set return status
        mov    W,#0    
        retp                 ; Ok everything is OK

        mov    W,#1          ; Failure !!
VerBad  retp                 ; return with status,z indicating success (Z) or not set for failure



; Transmit Event, nothing is done !
TransmitEvent  retp


; It's an arp request, Could be a request or a response.
; ARP packets are small so the whole thing is always in
; the register file.

DoArp                                  ;make sure it's 1
        mov     FSR,#$30               ; change de banque
        mov     TempH,packet+ar_hwtype+1
        mov     W,#$01                 ; check if
        sub     TempH,W                ; packet type
        sb      STATUS.2               ;compare to low
        retp                           ;exit, bad request

        mov     TempH,packet+ar_prtype    ;compare to high
        mov     W,#$08
        sub     TempH,W                   ;make sure it's 0x0800
        sb      STATUS.2
        retp

        mov     TempH,packet+ar_prtype+1  ;compare to high
        mov     W,#$00
        sub     TempH,W                   ;make sure it's 0x0800
        sb      STATUS.2
        retp

        mov     TempH,packet+ar_hwlen     ;compare to high
        mov     W,#$06
        sub     TempH,W                  ;make sure it's 6 for hwlen
        sb      STATUS.2
        retp

        mov     TempH,packet+ar_prlen     ;compare to high
        mov     W,#$04                    ;make sure it's 4 for prlen
        sub     TempH,W
        sb      STATUS.2
        retp

        mov     TempH,packet+ar_op+1     ;compare to high
        mov     W,#$01                   ;make sure it's 1 for ARP request
        sub     TempH,W
        sb      STATUS.2
        retp

        mov     FSR,#$40                 ; change de banque

        mov     TempH,packet+ar_tpa      ;compare to 1st IP adress
        mov     W,#IP1                   ;make sure it's 1 for ARP request
        sub     TempH,W
        sb      STATUS.2
        retp

        mov     TempH,packet+ar_tpa+1    ;compare to 2nd IP adress
        mov     W,#IP2                   ;make sure it's 1 for ARP request
        sub     TempH,W
        sb      STATUS.2
        retp

        mov     TempH,packet+ar_tpa+2    ;compare to 3rd IP adress
        mov     W,#IP3                   ;make sure it's 1 for ARP request
        sub     TempH,W
        sb      STATUS.2
        retp

        mov     TempH,packet+ar_tpa+3    ;compare to 4th IP adress
        mov     W,#IP4                   ;make sure it's 1 for ARP request
        sub     TempH,W
        sb      STATUS.2
        retp

; If we got to here, then we have a valid ARP request for our(=in chip) IP address

        mov     FSR,#$10                 ; change de banque
        mov     W,#$02
        or      flags,W                  ; flag frame read Inclusive IOR
        retp


; wait for 1msec millisecond
wait500ms
        mov     valueH,#50 ; 500ms   
:wait_loop_500ms1
        mov     TempH,#255 ; 10 ms
:wait_loop_500ms2
        mov     TempL,#255
:wait_loop_500ms3
        nop
        nop
        nop
        nop
	nop
	nop
        djnz    tempL, :wait_loop_500ms3
        djnz    tempH, :wait_loop_500ms2
        djnz    ValueH,:wait_loop_500ms1
retp

; wait for 500ns
wait500ns
        mov     TempL,#15
:wait_loop_500ns
        nop
        djnz    tempL, :wait_loop_500ns
retp
      

        org $600

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Calc checksum. Reads packet at offset W for
; LengthH/LengthL bytes and calculates the checksum
; in valueH/valueL.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

cksum

        ;offsetH  -> W input starting address

        ;offsetL  low  checksum
        ;offsetH  med  checksum
        ;TempL    hi   checksum

        ;LengthH and lenghTL are length of the data to checksum
        ;ValueL  and ValueH  are the results

        mov     OffsetH,W                 ; saves offset
        mov     FSR,#$10
        mov     valueL ,LengthL
        mov     TempH  ,LengthH
        mov     FSR,OffsetH              ;set indirect adress

	clr     offsetH                 ; 8-16 using a 24
        clr     offsetL                 ; 0-8 We do the arithmetic
        clr     TempL                   ; 16-24 bit area
        clrb    STATUS.0                ; set carry to zero

cksuml  mov     W,INDF                  ;get high byte of 16-bit word
        mov     valueH,W                ;save it
        inc     FSR
        mov     W,INDF
        inc     FSR
        add     offsetL,W               ; add to accum (1)
        sb      STATUS.0
        jmp     noLcarry
        mov     W,#$01                  ; if carry add it to offsetH (2)
        add     offsetH,W
        snb     STATUS.0
        inc     TempL                   ; if carry add it to TempL (3)

noLcarry
        mov    W,valueH                ; get the high byte again from the string to sum
        add    offsetH,W               ; add it to accum (2)
        snb    STATUS.0                ; carry ?
        inc    TempL                   ; Yes inc (3)

        mov    W,#$02                  ; subtract
        sub    ValueL,W                ; two byte from lengthL
        snb    STATUS.0                ; see if negative (C=0)
        jmp    CK1                     ; C set so result is zero or better
                                       ; we are close to completion
        mov    W,#$01
        sub    TempH,W                 ;decrement LengthH high
        sb     STATUS.0                ;c=0 means negative
        jmp    CkDone                  ;high went neg, we're done

CK1     test   valueL                  ;get low, is lengthL
        sb     STATUS.2                ;Z=1 if zero
        jmp    cksuml                  ;not zero, continue
        test   TempH                   ; TempH is LenghH
        sb     STATUS.2                ;Z=1 if zero
        jmp    cksuml                  ;not zero, continue

CkDone  mov    W,TempL                 ;get the third byte of 24 bit area (3)
        add    offsetL,W               ;any carries into this are added in
        snb    STATUS.0                ;if that caused a carry, then
        inc    offsetH                 ; increment the middle byte


        mov    valueL,#$FF             ;get and ones complement
        mov    W,offsetL
        sub    valueL,W                ;save it to low

        mov    valueH,#$FF             ;get and ones complement
        mov    W,offsetH
        sub    valueH,W                ;save as high

    retp


SWAP_IP_MAC_ADDR_IPCKSUM

        mov    FSR,#$30                ; change de banque
        clr    packet+ip_cksum
        clr    packet+ip_cksum+1       ;clear checksum

        mov    TempH,packet+ip_src     ;move
        mov    FSR,#$40                ; change de banque
        mov    packet+ip_dst,tempH     ; ip

        mov    FSR,#$30                ; change de banque
        mov    TempH,packet+ip_src+1   ;  of
        mov    FSR,#$40
        mov    packet+ip_dst+1,TempH     ;   source

        mov    FSR,#$30
        mov    TempH,packet+ip_src+2     ;    to
        mov    FSR,#$40
        mov    packet+ip_dst+2,TempH     ;     dest

        mov    FSR,#$30
        mov    TempH,packet+ip_src+3
        mov    FSR,#$40
        mov    packet+ip_dst+3,TempH

        mov    FSR,#$30
        mov    W,#IP1                     ;move
        mov    packet+ip_src,W            ; our
        mov    W,#IP2                     ;  ip
        mov    packet+ip_src+1,W          ;   address
        mov    W,#IP3                     ;    to
        mov    packet+ip_src+2,W          ;     source
        mov    W,#IP4
        mov    packet+ip_src+3,W

        mov    FSR,#$20

        mov    W,packet+pktSrc0H       ;move
        mov    packet+pktDest0H,W      ; mac src to dest
        mov    W,packet+pktSrc0L
        mov    packet+pktDest0L,W
        mov    W,packet+pktSrc1H       ;move
        mov    packet+pktDest1H,W      ;mac src to dest
        mov    W,packet+pktSrc1L
        mov    packet+pktDest1L,W
        mov    W,packet+pktSrc2H       ;move
        mov    packet+pktDest2H,W      ;mac src to dest
        mov    W,packet+pktSrc2L
        mov    packet+pktDest2L,W

        mov    W,#MAC1                   ;move
        mov    packet+pktSrc0H,W         ; our
        mov    W,#MAC2                   ;  MAC
        mov    packet+pktSrc0L,W         ;   address
        mov    W,#MAC3                   ;    to
        mov    packet+pktSrc1H,W         ;     source
        mov    W,#MAC4
        mov    packet+pktSrc1L,W
        mov    W,#MAC5
        mov    packet+pktSrc2H,W
        mov    W,#MAC6
        mov    packet+pktSrc2L,W

        ; Compute here cheksum of IP header

        mov    FSR,#$10
        mov    W,#$14                   ; length of IP header
        mov    lengthL,W                ; set length of
        clr    lengthH                  ; checksum calculation
        mov    FSR,#$30
        mov    W,#packet+ip_verlen      ; displacement to of IP header
        call   cksum                    ; calculate the checksum

        mov    FSR,#$30
        mov    packet+ip_cksum  ,valueH  ;set new checksum
        mov    packet+ip_cksum+1,valueL

retp


;
; Process ICMP (ping) requests
;


DoICMP
        ; Create the response FRAME for PING requests
        ; builds the Frame to be sent into the chip RAM
        ; not so easy ???
        ; All Ip_* are located at $30
        ; ip_dst    equ   $20 are on bank $40
        ; ip_data   equ   $24 are on bank $40
        ; ic*       equ   $24 are on bank $40

        
        ; test checksum routine and compare it with the actual IP value
        ;mov    FSR,#$10
        ;mov    W,#$14                   ; length of IP header
        ;mov    lengthL,W                ; set length of
        ;clr    lengthH                  ; checksum calculation

        ;mov    FSR,#$30
        ;clr    packet+ip_cksum
        ;clr    packet+ip_cksum+1        ; clear checksum
        ;mov    W,#packet+ip_verlen      ; displacement to start of IP header
        ;call   cksum                    ; calculate the checksum




        
        ;mov     FSR,#$40
        ;stc
        ;cse     packet+ip_dst  ,#IP1
        ;retp
        ;cse     packet+ip_dst+1,#IP2
        ;retp
        ;cse     packet+ip_dst+2,#IP3
        ;retp
        ;cse     packet+ip_dst+3,#IP4
        ;retp


        mov     FSR,#packet+ic_type
        stc
        cje     IND,#8,:DoICMP_next1        
        retp
:DoICMP_next1               
        
        mov    FSR,#$30
        mov    packet+ip_ttl,#128       ; Update Time To Live in IP header 

        call   SWAP_IP_MAC_ADDR_IPCKSUM ; swap Adresses and compute IP checksum
                                        ; don't change anything here about IP header anymore
     
        mov    FSR,#$40
        clr    packet+ic_cksum         ;clear ICMP
        clr    packet+ic_cksum+1       ; checksum
        clr    packet+ic_type          ;make type a reply
        clr    packet+ic_code          ;clear code

        ; here remove lengthL=TotalIPacketLength-IPheaderLength to have the right value of the ICMP header+data length

        mov    FSR,#$30
        mov    TempH,packet+ip_len      ;get length high IP packet length (length-header_length)
        mov    TempL,packet+ip_len+1    ;get length low
        mov    FSR,#$10
        mov    lengthH,TempH            ; save it, typically $00
        mov    lengthL,TempL            ; save it, typically $3C
        mov    W,#$14                   ;ip header length
        sub    lengthL,W                ;calc length of ICMP header+data , remove length of IP pure header
        snb    STATUS.2
        dec    lengthH                  ;if prev sub went neg then dec high

        mov    FSR,#$40
        mov    W,#packet+ic_type         ;start of ICMP header at W for checksum
        call   cksum

        mov    FSR,#$40
        mov    W,valueH                 ;set new checksum for icmp
        mov    packet+ic_cksum,W
        mov    W,valueL
        mov    packet+ic_cksum+1,W

        ; ckecksum OK ; start to send data to cs8900


        Doutput                        ; Writes the frame to CS8900S
        mov    W,#TX_CMD_START_ALL
        iow    portTxCmd
        mov    W,#$00
        iow    portTxCmd+1

        mov    FSR,#$20
        mov    W,packet+pktLenL        ; length of ICMP response frame
        iow    portTxLength            ; is the same as
        mov    W,packet+pktLenH        ; the request.
        iow    portTxLength+1


ICMPGetStat

        ppRD    ppBusSt         ; get BusStatus
        sb      valueH.0        ; is BUS_ST_RDY4TXNOW (ready for transmit)
        jmp     ICMPGetStat     ; no, wait for it

        Doutput

        mov    FSR,#$20
        mov    ValueL,packet+pktLenL   ;length, always less than 255 bytes
        mov    W,#packet+pktDest0H
        mov    FSR,W


WritePing                             ;send the DATA to cs8900
        mov    W,INDF                 ;get next byte
        iow    portRxTxData
        inc    FSR

        mov    W,INDF                 ;get next byte
        iow    portRxTxData+1
        inc    FSR
        dec    valueL
        decsz  valueL
        jmp    WritePing              ;not zero, continue

        mov    FSR,#$10

ICMPDone  retp

;;;;;;;;;;;;; Makes UDP reply FRAME




OrderFromPCPk equ $FA



     org $800

; jump table to go across pages boudaries
_SendDATAToUDPFromRAM     jmp @SendDATAToUDPFromRAM
__ResetFIFO               jmp @ResetFIFO
_writeRAM                 jmp @writeRAM

_FillFIFO                 jmp @FillFIFO
_SWAP_IP_MAC_ADDR_IPCKSUM jmp @SWAP_IP_MAC_ADDR_IPCKSUM
_cksum                    jmp @cksum
_Send_PacketHeader        jmp @Send_PacketHeader
_Send_PacketDATA          jmp @Send_PacketDATA
_Send_UDPDATAFromRAM      jmp @Send_UDPDATAFromRAM


_FillSerialPort           jmp @FillSerialPort
_get_byte                 jmp @get_byte



    

TestFIFO
        ;Communication still not initialised
        mov     FSR,#$10
        sb      flags.2
        retp


        ;Test handCheck
        ;;;;;;;;;;;;;;;
        mov     FSR,#$10
        sb      HandCheckFlags.0
        jmp     :TestFIFO_next4  ; no handcheck,



        
        ; There is a hand check ?
        test    HandCheckCountH
        sz
        jmp     :TestFIFO_next4


        ;decsz   HandCheckNbTry    ; HandCheckNbTry is removed, send the packet until an asteroid fall on the SX52 !!..
        ;jmp     :TestFIFO_next7
        ;clrb    HandCheckFlags.0

        ; Send again and again the next slot...
        ; at first, find the next unfree slot !


        ;Choose a slot, it's always the oldest sent packet
        ; DEBUG DEBUG, it's only the next unfree slot..., find the next unfree slot

;        mov  FSR,#$F0
;        clr  RAMSlotToWriteRead
;:TestFIFO_loop20
;        mov FSR,#RAMSlotFree
;        add FSR,RAMSlotToWriteRead
;        snb  IND.0
;        jmp :TestFIFO_loop21
;        inc  RAMSlotToWriteRead

;        jmp :TestFIFO_loop20
;:TestFIFO_loop21




        mov  tempL,#0
        mov  FSR,#$10
        mov  tempH,packetNbSend
        

        mov  FSR,#$F0
        mov  RAMSlotToWriteRead,#1
:TestFIFO_loop20
        mov FSR,#RAMSlotFree
        add FSR,RAMSlotToWriteRead
        sb  IND.0
        jmp :TestFIFO_loop22

        ; select the oldest packet
        mov FSR,#RAMpacketNbSendSlot
        add FSR,RAMSlotToWriteRead

        mov OffsetH,IND
        mov OffsetL,TempH
        sub OffsetL,OffsetH

        csae OffsetL,tempL
        jmp  :TestFIFO_loop22

        ; Update the oldest packet
        mov  tempL,OffsetL
        mov  valueL,RAMSlotToWriteRead


:TestFIFO_loop22

        ; Test if RAMSlotToWriteRead is equal to 0
        test RAMSlotToWriteRead
        snz
        jmp :TestFIFO_loop21

        dec  RAMSlotToWriteRead
        jmp :TestFIFO_loop20
:TestFIFO_loop21

        mov  RAMSlotToWriteRead,valueL





        ; Slot found, it's the RAMSlotToWriteRead slot

        ; Send the slot to CS8900
        ; Set up the slot to write

        call    _SendDATAToUDPFromRAM

        ;Wait for the next handcheck
        ;Setup the next handcheck
        mov     FSR,#$10
        mov     HandCheckCountH,#HandCheckTimeOut
        mov     HandCheckCountL,#255


:TestFIFO_next4

        ;End of test hand check
        ;;;;;;;;;;;;;;








        mov    FSR,#$F0
        ;Check if there is a free memory slot, otherwise return
        test   RAMnbSlotFree
        snz
        retp


        ;Find the next free slot
:TestFIFO_loop10
        mov FSR,#RAMSlotFree
        add FSR,RAMCurrentSlot
        sb  IND.0
        jmp :TestFIFO_loop101

        inc  RAMCurrentSlot
        csne RAMCurrentSlot,#2
        clr  RAMCurrentSlot
        jmp :TestFIFO_loop10  
:TestFIFO_Loop101



        ;;;;;;;;;;;;;;
        ; Send a packet if the FIFO is not empty and if there is a free slot to put the next packet into

        ;;;;Optionnal: do the same thing for the serial port
        ;Test if FIFO is empty
        snb      EmptyFIFO
        jmp     :TestFIFO_endif100


        ; optional:
        ;Test if the serial port is empty
        mov	FSR,#$D0
        stc
        csne	rx_byte1,rx_byte2		;get the value from the buffer
        retp



        mov     FSR,#$F0
        clr     RAMPacketH
        clr     RAMPacketL

:TestFIFO_loop100
        call    _get_byte
        mov     ValueH,w
        ;On ecrit la valeur dans la RAM
        call    _writeRAM
        inc     RAMPacketL
        mov     FSR,#$D0
        stc
        cjne	rx_byte1,rx_byte2,:TestFIFO_loop100

        mov     FSR,#$F0
        clr     RAMPacketToSendH
        mov     RAMPacketToSendL,RAMPacketL

        jmp     :TestFIFO_next2

        ;;;;end optional (Serial Port)

:TestFIFO_endif100








        ;if ok, send the data to UDP
        ;Fill the buffer at first
:TestFIFO_Loop1
        mov    FSR,#$F0
        ;Set DataBus to input
        DInput
        clrb    FIFORead
        nop
	nop
        mov     FSR,#$F0
        mov     W,RB         ;Get to W the Data in port B
        setb    FIFORead


        ;Si RAMPacket=0 , on update RAMPacketToSendH
        ;Si RAMPacket=1 , on update RAMPacketToSendL

        test    RAMPacket
        jnz     :TestFIFO_next1
        mov     RAMPacketToSendH,w
        inc     RAMPacket
        jmp     :TestFIFO_next3
:TestFIFO_next1
        mov     ValueH,w

        stc
        cjne    RAMPacket,#1,:TestFIFO_next5
        mov     RAMPacketToSendL,ValueH
        inc     RAMPacket

        ;Decremente de 2 (Compatible anciennes version (V2))
        test    RAMPacketToSendL
        snz
        dec     RAMPacketToSendH
        dec     RAMPacketToSendL
        snz
        dec     RAMPacketToSendH
        dec     RAMPacketToSendL


        ; On test si la taille du packet est correcte, sinon reset FIFO
        cjbe     RAMPacketToSendH,6,:TestFIFO_next3

        call    __ResetFIFO
        clr     RAMPacket
        clr     RAMPacketL
        clr     RAMPacketH
        retp

:TestFIFO_next5


        ;On ecrit la valeur dans la RAM
        call    _writeRAM
        inc     RAMPacketL
        snz
        inc     RAMPacketH


        stc
        cjne    RAMPacketL,RAMPacketToSendL,:TestFIFO_next3
        stc
        cjne    RAMPacketH,RAMPacketToSendH,:TestFIFO_next3

        ;compare RAMPacket et RAMPacketToSend
        test    RAMPacketH
        jnz     :TestFIFO_next2
        stc
        cje     RAMPacketL,#1,:TestFIFO_next3
:TestFIFO_next2




        ; Send Data to UDP

        mov     FSR,#$10
        inc     packetNbSend
        mov     tempH,packetNbSend

        mov     FSR,#$F0

        ; Set up the slot to write
        mov     RAMSlotToWriteRead,RAMCurrentSlot

        mov     FSR,#RAMpacketNbSendSlot
        add     FSR,RAMSlotToWriteRead
        mov     IND,TempH

        ; RAMnbSlotFree decreased by one
        dec     RAMnbSlotFree

        ; Slot is no more free
        mov     FSR,#$F0
        mov     FSR,#RAMSlotFree
        add     FSR,RAMSlotToWriteRead
        setb    IND.0



        mov     FSR,#RAMPacketToSendSlotH
        add     FSR,RAMSlotToWriteRead
        mov     IND,RAMPacketToSendH

        mov     FSR,#RAMPacketToSendSlotL
        add     FSR,RAMSlotToWriteRead
        mov     IND,RAMPacketToSendL

        call    _SendDATAToUDPFromRAM

        ;Wait for the handcheck
        ;Setup the handcheck
        mov     FSR,#$10
        snb     HandCheckFlags.0
        jmp     :TestFIFO_next30
        mov     HandCheckNbTry,#NbRetry
        setb    HandCheckFlags.0
        mov     HandCheckCountH,#HandCheckTimeOut
        mov     HandCheckCountL,#255
:TestFIFO_next30        


        ;clear the current RAMPointer, next Slot... 
        mov     FSR,#$F0
        clr     RAMPacket
        clr     RAMPacketH
        clr     RAMPacketL

        retp



:TestFIFO_next3

        snb     EmptyFIFO
        jmp     :TestFIFO_loop1


retp






;; Process Order, if nothings DONE udp DATA+2 is still cleared
DoUDP

        mov     FSR,#$40                 ; All the UDP header is there
        stc
        cse     packet+ip_dst,#IP1
        retp
        cse     packet+ip_dst+1,#IP2
        retp
        cse     packet+ip_dst+2,#IP3
        retp
        cse     packet+ip_dst+3,#IP4
        retp



        
        cse     packet+u_dst+1 ,#UDP_PORT_SCR
        retp
        cje     packet+u_data+1,#0,:DOUdp_ifend1        ;Reset
        cje     packet+u_data+1,#1,:DOUdp_ifend1        ;Data receive
        cje     packet+u_data+1,#2,:DOUdp_ifend3        ;Data send
        cje     packet+u_data+1,#3,:DOUdp_ifend1        ;Data receive to serial port
        retp                             





:DOUdp_ifend1

        ; Compare to last packet number
        ; If message already received, then
        ; Send back again the handcheck whitout executing the command
        mov     FSR,#$40
        mov     TempH,packet+u_data
        mov     FSR,#$10
        stc
        cje     packetNbReceive,TempH,:DOUdp_ifend2



        ;Execute command
	mov     FSR,#$40
        cje     packet+u_data+1,#1,:DOUdp_ifend4
        cje     packet+u_data+1,#3,:DOUdp_ifend100

        ;Reset all
        call    __ResetFIFO
        mov     FSR,#$F0
        clr     RAMPacketL
        clr     RAMPacketH

        mov     FSR,#$40
        mov     packet+u_data+1,#1

        mov     FSR,#$10
        mov     packetNbSend,#0

        jmp     :DOUdp_ifend2
:DOUdp_ifend4

        ;Send data to FIFO
        stc
        mov     FSR,#$40
        mov     valueL,packet+u_len+1
        sub     valueL,#10
        mov     OffsetL,#packet+u_data+2
        call    _FillFIFO
        clc

        jmp     :DOUdp_ifend2
:DOUdp_ifend100

        ;Send data to serial port
        mov     FSR,#$40
        mov     valueL,packet+u_len+1
        sub     valueL,#12
        mov     OffsetL,#packet+u_data+4
        call    _FillSerialPort
        mov     FSR,#$40
        mov     packet+u_data+1,#1




:DOUdp_ifend2
        ; Send the handcheck


        ; Update last packet number
        mov     FSR,#$40          ;   All the UDP header is there
        mov     TempH,packet+u_data
        mov     FSR,#$10
        mov     packetNbReceive,TempH

      

        ; Sends back Data
        call    _SWAP_IP_MAC_ADDR_IPCKSUM
        mov     FSR,#$40          ;   All the UDP header is there
        clr     packet+u_cksum    ;  clear UDP checksum, UDP checksum IS USELESS
        clr     packet+u_cksum+1  ;  clear byte two

        ; Swap source-dest
        mov     TempL,packet+u_src       ;get src port
        mov     packet+u_dst,TempL       ;put src port
        mov     TempL,packet+u_src+1     ;get src port
        mov     packet+u_dst+1,TempL     ;put src port

        clr     packet+u_src
        mov     packet+u_src+1,#UDP_PORT_SCR ; write the LOCAL UDP port

        ;Set priority
        mov     FSR,#$30
        and    packet+ip_tos,#$03
        or     packet+ip_tos,#IPPriority


        clc
        ; Update the packet size
        mov     offsetL,#2
        ; Update UDP header size
        mov     FSR,#$40
        mov     packet+u_len+1,offsetL
        add     packet+u_len+1,#8

        ; Update IP header size
        mov     FSR,#$30
        mov     packet+ip_len+1,offsetL
        add     packet+ip_len+1,#28

        mov     FSR,#$20
        mov     packet+pktLenL,offsetL
        add     packet+pktLenL,#42
        csa     packet+pktLenL,#60
        mov     packet+pktLenL,#60

        ; Compute here cheksum of IP header
        mov    FSR,#$30                ; change de banque
        clr    packet+ip_cksum
        clr    packet+ip_cksum+1       ;clear checksum

        mov    FSR,#$10
        mov    W,#$14                   ; length of IP header
        mov    lengthL,W                ; set length of
        clr    lengthH                  ; checksum calculation
        mov    FSR,#$30
        mov    W,#packet+ip_verlen      ; displacement to of IP header
        call   _cksum                   ; calculate the checksum

        mov    FSR,#$30
        mov    packet+ip_cksum  ,valueH  ;set new checksum
        mov    packet+ip_cksum+1,valueL


        ; OK all the frame is ready, now send it back to cs8900
        call _Send_PacketHeader
        call _Send_PacketDATA


        ; Backup the header
        mov     offsetL,#Packet
        mov     offsetH,#PacketBackup
        mov     valueL,#$30
:DoUDP_loop1
        mov     FSR,offsetL
        mov     TempH,IND
        mov     FSR,offsetH
        mov     IND,TempH
        inc     offsetL
        inc     offsetH
	djnz    valueL,:DoUDP_loop1


        ;Header saved
        mov     FSR,#$10
        setb    flags.2
        retp









:DOUdp_ifend3
        ;Read
	mov     FSR,#$40                 ; All the UDP header is there
        mov     tempL,packet+u_data

        mov     tempH,#2
:DOUdp_ifend11
        mov     FSR,#RAMpacketNbSendSlot
        add     FSR,tempH
        dec     FSR
        stc
        cje     IND,tempL,:DOUdp_ifend10
        dec     tempH
	sz
        jmp     :DOUdp_ifend11        
        retp

:DOUdp_ifend10
        ; Release a slot
        mov     FSR,#$F0
        mov     FSR,#RAMSlotFree
        add     FSR,TempH
        dec     FSR
        snb     IND.0
        inc     RAMnbSlotFree
        clrb    IND.0

        ; if all the slot are free, no more handcheck

        stc
        cse    RAMnbSlotFree,#2
        retp
        mov     FSR,#$10
        clrb    HandCheckFlags.0
        retp


:DOUdp_ifend5




        org $A00

_DoARpJMP               jmp @DoArp
_DOIPCMP                jmp @DoICMP
_DoUDP                  jmp @DoUDP
__Send_PacketHeader     jmp @Send_PacketHeader
__Send_PacketData       jmp @Send_PacketData


_prepareARPResponse     jmp @prepareARPResponse
_PrepareARP             jmp @PrepareARP
_PrepareARPForRequest   jmp @PrepareARPForRequest

__cksum                 jmp @cksum




; READ buffer from CS8900
MaxPCKsize equ 112  ; Max paquet SIZE , otherwise kills all !!

ReadBufferCS8900

        Dinput                          ;make data bus input
;
; It's important to read the status and length high-order
; byte first.
;

        iortoW  portRxTxData+1          ;read and discard status
        iortoW  portRxTxData            ;read and discard status; don't care of W


        mov     W,#packet               ;set indirect
        mov     FSR,W                   ; address
        iortoW  portRxTxData+1          ;get length high
        mov     ValueH,W
        mov     packet+pktLenH,ValueH   ;save in header area, bank 2


        mov     FSR,#$10                ; Change to Bank 1
        mov     lengthH,ValueH          ; and in lengthH
        mov     TempH,ValueH            ; and in lengthH


        mov     W,#$00
        sub     TempH,W                 ;IS packet more than n x 256 bytes ?
        snb     STATUS.2                ;if Zero
        jmp     OKlengthPP


        mov     FSR,#$20                ; Yes !
        clr     packet+pktLenL
        clr     packet+pktLenH
        retp                            ;no ? let's go out


OKlengthPP

        mov     FSR,#$20                ; Change back to Bank 2 where the data or frame is stored

        iortoW  portRxTxData            ;get length low
        mov     ValueL,W
        mov     packet+pktLenL,ValueL   ;save in header area


        mov     TempL,ValueL
        clr     W
        sub     TempL,W                 ; IS packet null ?
        snb     STATUS.2                ; if zero, go out
        retp                            ; No ? let's go out

        mov     TempL,#MaxPCKsize       ; MAX PackET SIZE
        mov     W,ValueL
        sub     TempL,W                 ; IS packet less than #MaxPCK ?
        snb     STATUS.0                ; if zero, go out
        jmp     ReadFrame
        mov     FSR,#$20                ; Yes !
        clr     packet+pktLenL
        clr     packet+pktLenH
        retp                            ;No ? let's go out


  ReadFrame

        ; Something wird here, packet MUST be even !!
        snb      ValueL.0
        inc     ValueL                 ; Add one

        mov     W,#packet+1             ;set indirect
        mov     FSR,W                   ; address

   RFCont

        iortoW  portRxTxData            ;read from CS8900
        inc     FSR                     ;increment pointer
        mov     INDF,W                  ;Writes to the RAM


        iortoW  portRxTxData+1          ;read from CS8900
        inc     FSR
        mov     INDF,W

        dec     valueL
        decsz   valueL
        jmp     RFCONT

        mov    FSR,#$10                 ; Change to Bank 1
        mov    W,#01
        or     flags,W                  ; flag frame read Inclusive IOR

        mov     W,#packet               ;set indirect
        mov     FSR,W                   ; address to bank 2

   ReadDone   ; FRAME read, DONE and stored into the RAM

       retp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Receive Event
; Input with RxEvent in valueH
;

ReceiveEvent

        call ReadBufferCS8900


        mov  TempH,packet+pktLenL  ; If packet is null go OUT
        mov  W,#$00
        snb  STATUS.2
        retp

        ;;;;;;;;; Analyze the FRAME ;;;;;;;;;;;;;

        mov    TempH,packet+pktTypeH
        mov    W,#$08                 ; check if
        sub    TempH,W                ; packet type
        sb     STATUS.2               ; is $0806 ->>>>>>>>> (ARP)
        jmp    @ChkIP                  ; no, check IP

        mov    TempH,packet+pktTypeL
        mov    W,#$06
        sub    TempH,W
        snb    STATUS.2
        call    _DoARpJMP              ; goes to the JMP table, simple call


   ChkIP
        mov     W,#packet+pktTypeH      ;set indirect
        mov     FSR,W                   ; address to bank 2

        mov    TempH,packet+pktTypeH
        mov    W,#$08                 ; check if
        sub    TempH,W
        sb     STATUS.2               ; is $0800 ->>>>>>>>> (IP)
        retp                          ; no IP ?, then just return

        mov    TempL,packet+pktTypeL  ; test low byte
        test   TempL
        sb     STATUS.2
        retp
        mov    W,#packet+ip_proto    ; set indirect
        mov    FSR,W                 ; address to bank
        

        mov    TempH,packet+ip_proto
        mov    W,#IPT_ICMP            ; get protocol number for ICMP
        sub    TempH,W                ; compare to this packet's proto
        snb    STATUS.2               ; if zero, then it's ICMP (Ping)
        call   _DOIPCMP               ; process ICMP packet

        mov    TempH,packet+ip_proto
        mov    W,#IPT_UDP             ; get protocol number for ICMP
        sub    TempH,W                ; compare to this packet's proto
        snb    STATUS.2               ; if zero, then it's ICMP (Ping)
        call   _DoUDP                  ; process ICMP packet


        retp






PrepareARPForRequest


        mov     FSR,#$20
        mov     packet+pktDest0H,#$FF
        mov     packet+pktDest0L,#$FF
        mov     packet+pktDest1H,#$FF
        mov     packet+pktDest1L,#$FF
        mov     packet+pktDest2H,#$FF
        mov     packet+pktDest2L,#$FF


        mov     FSR,#$30
        ; Send operation (request)
        mov     packet+ar_op  , #$00
        mov     packet+ar_op+1, #$01


        ; Send Target HW address

        mov     FSR,#$40
        mov     packet+ar_tha  ,#0
        mov     packet+ar_tha+1,#0
        mov     packet+ar_tha+2,#0
        mov     packet+ar_tha+3,#0
        mov     packet+ar_tha+4,#0
        mov     packet+ar_tha+5,#0


        ; Send Target IP
        mov     packet+ar_tpa  ,#GIP1
        mov     packet+ar_tpa+1,#GIP2
        mov     packet+ar_tpa+2,#GIP3
        mov     packet+ar_tpa+3,#GIP4    


retp



PrepareARP

        mov     FSR,#$20
        clr     packet+pktLenH
        mov     packet+pktLenL,#60
        
        mov     packet+pktSrc0H,#MAC1
        mov     packet+pktSrc0L,#MAC2
        mov     packet+pktSrc1H,#MAC3
        mov     packet+pktSrc1L,#MAC4
        mov     packet+pktSrc2H,#MAC5
        mov     packet+pktSrc2L,#MAC6

        ; Send type
        mov     packet+pktTypeH,#$08
        mov     packet+pktTypeL,#$06

        mov     FSR,#$30

        ; Send hwtype
        mov     packet+ar_hwtype  , #$00
        mov     packet+ar_hwtype+1, #$01

        ; Send prtype (protocol type)
        mov     packet+ar_prtype  , #$08
        mov     packet+ar_prtype+1, #$00

        ; Send hardware and protocol address lengths
        mov     packet+ar_hwlen, #$06
        mov     packet+ar_hwlen+1, #$04

        ; Send Senders HW address
        mov     packet+ar_sha  ,#MAC1
        mov     packet+ar_sha+1,#MAC2
        mov     packet+ar_sha+2,#MAC3
        mov     packet+ar_sha+3,#MAC4
        mov     packet+ar_sha+4,#MAC5
        mov     packet+ar_sha+5,#MAC6


        ; Send Senders IP
        mov     FSR,#$30
        mov     packet+ar_spa  , #IP1
        mov     packet+ar_spa+1, #IP2
        mov     FSR,#$40
        mov     packet+ar_spa+2, #IP3
        mov     packet+ar_spa+3, #IP4


        retp



prepareARPResponse

        mov     FSR,#$20
        mov     packet+pktDest0H,packet+pktSrc0H
        mov     packet+pktDest0L,packet+pktSrc0L
        mov     packet+pktDest1H,packet+pktSrc1H
        mov     packet+pktDest1L,packet+pktSrc1L
        mov     packet+pktDest2H,packet+pktSrc2H
        mov     packet+pktDest2L,packet+pktSrc2L

        mov     FSR,#$30

        ; Send operation (response)
        mov     packet+ar_op  , #$00
        mov     packet+ar_op+1, #$02

        ; Send Target IP
        mov     FSR,#$30
        mov     TempL, packet+ar_spa
        mov     FSR,#$40
        mov     packet+ar_tpa,TempL

        mov     FSR,#$30
        mov     TempL, packet+ar_spa+1
        mov     FSR,#$40
        mov     packet+ar_tpa+1,TempL

        mov     packet+ar_tpa+2,packet+ar_spa+2
        mov     packet+ar_tpa+3,packet+ar_spa+3
        

        ; Send Target HW address
        mov     FSR,#$20
        mov     TempL,packet+pktDest0H
        mov     FSR,#$40
        mov     packet+ar_tha  ,TempL

        mov     FSR,#$20
        mov     TempL,packet+pktDest0L
        mov     FSR,#$40
        mov     packet+ar_tha+1,TempL

        mov     FSR,#$20
        mov     TempL,packet+pktDest1H
        mov     FSR,#$40
        mov     packet+ar_tha+2,TempL

        mov     FSR,#$20
        mov     TempL,packet+pktDest1L
        mov     FSR,#$40
        mov     packet+ar_tha+3,TempL

        mov     FSR,#$20
        mov     TempL,packet+pktDest2H
        mov     FSR,#$40
        mov     packet+ar_tha+4,TempL

        mov     FSR,#$20
        mov     TempL,packet+pktDest2L
        mov     FSR,#$40
        mov     packet+ar_tha+5,TempL




        retp





; SendARP - Send a response ARP to the requestor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SendARPResponse

        call    _prepareARPResponse
        call    _PrepareARP
        
        call    __Send_PacketHeader
        call    __Send_PacketData
   retp

   
SendARP
        call    _PrepareARPForRequest
        call    _PrepareARP

        
        call    __Send_PacketHeader
        call    __Send_PacketData
   retp








   



InitRAM
        setb    RAMWrite
        setb    RAMRead

        mov     FSR,#$F0
        clr     RAMPacketToSendH
        clr     RAMPacketToSendL
        clr     RAMPacketH
        clr     RAMPacketL      
retp

InitFIFO
        setb    FIFOWrite
        setb    FIFORead
        setb    clearFIFO
retp


ResetFIFO
        clrb    clearFIFO
        nop
	nop
	nop
	nop
	nop
	nop
        setb    clearFIFO
retp


fillFIFO
        DOutput
        clr     TempL
:fillFIFO_loop1

        mov     FSR,offsetL
        add     FSR,TempL
        mov     w,IND
        mov     RB,w
        nop
	nop
        clrb    FIFOWrite
        nop
	nop
        setb    FIFOWrite
        inc     TempL
        djnz    valueL,:fillFIFO_loop1
retp



writeRAM
        DOutput
        mov     FSR,#$F0
        mov     RA,RAMPacketL


        IFDEF RS485_setting

        setb    RE.3
        setb    RE.2
        setb    RE.1
        setb    RE.0

        sb      RAMPacketH.0
        clrb    RE.0
        sb      RAMPacketH.1
        clrb    RE.1
        sb      RAMCurrentSlot.0
        clrb    RE.2
        sb      RAMCurrentSlot.1
        clrb    RE.3

        ELSE

	mov	RE,$7F

        sb      RAMPacketH.0
        clrb    RE.0
        sb      RAMPacketH.1
        clrb    RE.1
        sb      RAMCurrentSlot.0
        clrb    RE.2
        sb      RAMCurrentSlot.1
        clrb    RE.3
        sb      RAMCurrentSlot.2
        clrb    RE.4
        sb      RAMCurrentSlot.3
        clrb    RE.5
        sb      RAMCurrentSlot.4
        clrb    RE.6
        
        ENDIF

        mov     RB,valueH
	nop
        clrb    RAMWrite
	nop
        setb    RAMWrite

retp




readRAM
        DInput
        mov     RA,OffsetL

        IFDEF RS485_setting

        setb    RE.3
        setb    RE.2
        setb    RE.1
        setb    RE.0
        sb      OffsetH.0
        clrb    RE.0
        sb      OffsetH.1
        clrb    RE.1
        sb      RAMSlotToWriteRead.0
        clrb    RE.2
        sb      RAMSlotToWriteRead.1
        clrb    RE.3

        ELSE

	mov	RE,$7F
        sb      OffsetH.0
        clrb    RE.0
        sb      OffsetH.1
        clrb    RE.1
        sb      RAMSlotToWriteRead.0
        clrb    RE.2
        sb      RAMSlotToWriteRead.1
        clrb    RE.3
        sb      RAMSlotToWriteRead.2
        clrb    RE.4
        sb      RAMSlotToWriteRead.3
        clrb    RE.5
        sb      RAMSlotToWriteRead.4
        clrb    RE.6

        ENDIF
        

	nop
        clrb    RAMRead
	nop
        mov     w,RB
        mov     valueH,w
        setb    RAMRead
retp                   


org     $C00

___Send_PacketHeader     jmp @Send_PacketHeader
__Send_UDPDATAFromRAM   jmp @Send_UDPDATAFromRAM
___cksum                 jmp @cksum



SendDATAToUDPFromRAM
        ;Send data to UDP
:SendDATAToUDPFromRAM_next7
        ; Restore the header
        mov     offsetL,#Packet
        mov     offsetH,#PacketBackup
        mov     valueL,#$30
:SendDATAToUDPFromRAM_loop2
        mov     FSR,offsetH
        mov     TempH,IND
        mov     FSR,offsetL
        mov     IND,TempH
        inc     offsetL
        inc     offsetH
	djnz    valueL,:SendDATAToUDPFromRAM_loop2       


        ; Send data header (2 bytes)
        mov     FSR,#RAMpacketNbSendSlot
        add     FSR,RAMSlotToWriteRead
        mov     TempH,IND
        mov     FSR,#packet+u_data
        mov     IND,TempH
        inc     FSR
        mov     IND,#2


        ;Set priority
        mov    FSR,#$30
        and    packet+ip_tos,#$03
        or     packet+ip_tos,#IPPriority



        
        mov     FSR,#RAMPacketToSendSlotH
        add     FSR,RAMSlotToWriteRead
        mov     offsetH,IND

        mov     FSR,#RAMPacketToSendSlotL
        add     FSR,RAMSlotToWriteRead
        mov     offsetL,IND
        clc
        add     offsetL,#2
        snc
        inc     OffsetH



        ; Update UDP header size
        mov     FSR,#$40
        mov     packet+u_len,offsetH
        mov     packet+u_len+1,offsetL
        add     packet+u_len+1,#8
        snc
        inc     packet+u_len



        ; Update IP header size
        mov     FSR,#$30
        mov     packet+ip_len  ,offsetH
        mov     packet+ip_len+1,offsetL
        add     packet+ip_len+1,#28
        snc
        inc     packet+ip_len

        

        mov     FSR,#$20
        mov     packet+pktLenH,offsetH
        mov     packet+pktLenL,offsetL
        add     packet+pktLenL,#42
        snc
        inc     packet+pktLenH
        test    packet+pktLenH
        sz
        jmp     :SendDATAToUDPFromRAM_next6        
        stc
        cjae    packet+pktLenL,#60,:SendDATAToUDPFromRAM_next6
        mov     packet+pktLenL,#60
:SendDATAToUDPFromRAM_next6


        clc
        ; Compute here cheksum of IP header
        mov    FSR,#$30                ; change de banque
        clr    packet+ip_cksum
        clr    packet+ip_cksum+1       ;clear checksum

        mov    FSR,#$10
        mov    W,#$14                   ; length of IP header
        mov    lengthL,W                ; set length of
        clr    lengthH                  ; checksum calculation
        mov    FSR,#$30
        mov    W,#packet+ip_verlen      ; displacement to of IP header
        call   ___cksum                   ; calculate the checksum

        mov    FSR,#$30
        mov    packet+ip_cksum  ,valueH  ;set new checksum
        mov    packet+ip_cksum+1,valueL

        ; Send UDP packet
        call ___Send_PacketHeader
        call __Send_UDPDATAFromRAM ;Write from RAM

        retp







        org $E00

; JMP table
__ReadRAM               jmp @ReadRAM


; Interrupt routine
interrupt_

                mov     FSR,#$10

                test    HandCheckCountH
                snz
                jmp     :interrupt_endif1

                decsz    HandCheckCountL
                jmp     :interrupt_nextif2

                dec     HandCheckCountH
                mov     HandCheckCountL,#255
                jmp     :interrupt_endif2
:interrupt_nextif2
                dec     HandCheckCountL
:interrupt_endif2
:interrupt_endif1



                IFDEF RS232_SETTING

		mov	FSR,#$D0
		clrb	tx_divide.5		;1	;serial transmit
		inc	tx_divide		;1	;only execute every 16th time
		mov	w,tx_divide		;1
		and	w,#$20			;1
		sz				;1
		test	tx_count		;1	;busy?
		clc				;1	;ready stop bit
		sz				;1	;if busy, shift bits
		rr	tx_high			;1
		sz				;1
		rr	tx_low			;1
		sz				;1	;if busy, dec counter
		dec	tx_count		;1
                movb	tx_pin,/tx_low.6	;4 =18	;output next bit

		movb	c,rx_pin		;4	;serial receive
		test	rx_count		;1	;waiting for stop bit?
		jnz	:rxbit			;3,2	;if not, :bit
		mov	w,#9			;1	;in case start, ready 9 bits
		sc				;1	;if start, set rx_count
		mov	rx_count,w		;1
		mov	rx_divide,#32+16+1	;2	;ready 1.5 bit periods
:rxbit		djnz	rx_divide,:rxdone	;3,2	;8th time through?
		setb	rx_divide.5		;1	;yes, ready 1 bit period
		dec	rx_count		;1	;last bit?

		jz	:rxvalue        	;1	;if not, save bit
		rr	rx_byte
		jmp     :rxdone
:rxvalue
	      	mov     FSR,#rx_buffer		; Put the value in the buffer
		add     FSR,rx_byte2
		mov 	INDF,rx_byte

		inc     rx_byte2
		stc
		csb     rx_byte2,#15
		clr     rx_byte2
:rxdone                

                ENDIF




                IFDEF RS485_setting
                
                mov	FSR,#$D0

		test	tx_count		;test if busy
                jz      :interrupt_nextif3

		stc
	        cse     tx_count,#10		
                setb    DE_pin

                
		clrb	tx_divide.5		;1	;serial transmit
		inc	tx_divide		;1	;only execute every 16th time
		mov	w,tx_divide		;1
		and	w,#$20			;1
		sz				;1
		test	tx_count		;1	;busy?
		clc				;1	;ready stop bit
		sz				;1	;if busy, shift bits
		rr	tx_high			;1
		sz				;1
		rr	tx_low			;1
		sz				;1	;if busy, dec counter
		dec	tx_count		;1		
                movb	DI_pin,/tx_low.6	       ;4 =18	;output next bit

                jmp     :interrupt_endif3
:interrupt_nextif3

                clrb    DE_pin
		movb	c,RO_pin		;4	;serial receive
		test	rx_count		;1	;waiting for stop bit?
		jnz	:rxbit			;3,2	;if not, :bit
		mov	w,#9			;1	;in case start, ready 9 bits
		sc				;1	;if start, set rx_count
		mov	rx_count,w		;1
		mov	rx_divide,#32+16+1	;2	;ready 1.5 bit periods
:rxbit		djnz	rx_divide,:rxdone	;3,2	;8th time through?
		setb	rx_divide.5		;1	;yes, ready 1 bit period
		dec	rx_count		;1	;last bit?


		mov	FSR,#$C0
		jz	:rxvalue        	;1	;if not, save bit
		rr	rx_byte
		jmp     :rxdone
:rxvalue
                mov	FSR,#$D0
                mov     FSR,rx_byte2
	      	add     FSR,#rx_buffer		; Put the value in the buffer

		mov 	INDF,rx_byte

                mov	FSR,#$D0
		inc     rx_byte2
		stc
		csb     rx_byte2,#15
		clr     rx_byte2
:rxdone

:interrupt_endif3

                ENDIF


		mov	w,#-163			;1	;interrupt every 163 clocks (0.8 mics for 50megas)
 		retiw				;3




; Serial port 
; Get byte via serial port
get_byte        mov	FSR,#$D0
                stc
                cje	rx_byte1,rx_byte2,$		;get the value from the buffer

                
                mov     FSR,rx_byte1
		add     FSR,#rx_buffer
                mov     TempH,INDF

                mov	FSR,#$D0
		inc     rx_byte1
		stc
		csb     rx_byte1,#15
		clr     rx_byte1

                mov	FSR,#$C0
		mov     w,TempH
		retp

; Serial port 
; Send byte via serial port
;
send_byte	mov	tempL,w
		mov	FSR,#$D0
		mov	w,tempL		

:wait		test	tx_count		;wait for not busy
		jnz	:wait 
		not	w			;ready bits
		mov	tx_high,w
		setb	tx_low.7
		mov	tx_count,#10		;1 start + 8 data + 1 stop bit
		retp




Send_PacketHeader
        Doutput

        mov     W,#TX_CMD_START_ALL
        iow     portTxCmd
        clr     W
        iow     portTxCmd+1
        mov     FSR,#$20
        ; Something wird here, packet MUST be even !!

        sb      (packet+pktLenL).0
        jmp     :Send_PacketHeader_next1
        inc     packet+pktLenL
        snz
        inc     packet+pktLenH
:Send_PacketHeader_next1

        mov     W,packet+pktLenL      ; send length to CS8900
        iow     portTxLength
        mov     W,packet+pktLenH
        iow     portTxLength+1

UDPGetStat
        ppRD    ppBusSt         ; get BusStatus
        sb      valueH.0        ; is BUS_ST_RDY4TXNOW (ready for transmit)
        jmp     UDPGetStat      ; no, wait for it
        
        mov     ValueL,#44        ; set it for the final loop

        mov     FSR,#packet+pktDest0H
        Doutput

WriteUDP   ; writes DATA to cs8900

        mov    W,INDF                 ;get next byte
        iow    portRxTxData
        inc    FSR

        mov    W,INDF                 ;get next byte
        iow    portRxTxData+1
        inc    FSR

        dec    valueL
        decsz  valueL
        jmp    WriteUDP               ;not zero, continue

retp


Send_PacketData
        mov     FSR,#$20
        mov     ValueL,packet+pktLenL         ; set it for the final loop
        stc
        sub     ValueL,#44

        mov     FSR,#packet+u_data+2

WriteUDPDATA   ; writes DATA to cs8900

        mov    W,INDF                 ;get next byte
        iow    portRxTxData
        inc    FSR

        mov    W,INDF                 ;get next byte
        iow    portRxTxData+1
        inc    FSR

        dec    valueL
        decsz  valueL
        jmp    WriteUDPDATA               ;not zero, continue

        DInput
retp


Send_UDPDataFromRAM

        ;Write from RAM
        mov     FSR,#$20
        mov     TempH,packet+pktLenH         ; set it for the final loop
        mov     TempL,packet+pktLenL         ; set it for the final loop
        stc
        sub     TempL,#44
        sc
        dec     TempH


        
        clr     OffsetH
        clr     OffsetL

        mov     FSR,#$F0
WriteUDPFromRAM
        call    __ReadRAM
        doutput

        ;Optimisation
        mov      RB,ValueH    ; writes W to the port B
        mov      RA,#portRxTxData
	nop
        clrb     RC._IOW      ; Add nops here to make 1 nop=20ns
        inc     OffsetL
        snz
        inc     OffsetH
	nop
	nop
        nop
        nop
        setb     RC._IOW


        call    __ReadRAM
        doutput

        ;Optimisation
        mov      RB,ValueH    ; writes W to the port B
        mov      RA,#portRxTxData+1         ; Activates A address port
	nop
        clrb     RC._IOW      ; Add nops here to make 1 nop=20ns
        inc     OffsetL
        snz
        inc     OffsetH
        stc
        sub     TempL,#2
        sc
        dec     TempH
        setb     RC._IOW

        Test    TempL
        jnz     WriteUDPFromRAM
        Test    TempH
        jnz     WriteUDPFromRAM
retp



FillSerialPort
        clr     TempH
:fillFIFO_loop1
        mov     FSR,offsetL
        add     FSR,TempH
        mov     w,IND
        call    send_byte
        inc     TempH
        djnz    valueL,:fillFIFO_loop1
retp



