please dont rip this site

Scenix Bindicator SILO1.1.SRC

;THINGS TO DO
;TIM THE SILOS WILL GIVE YOU ALREADY IN BCD SO YOU WILL ACTUALLY NEED TO JUST MAKE SHURE YOU HAVE 3 SPOTS
;FREE FOR WHAT EVER INFO YOU WANT TO PAS TO IT.  YOU WILL ALSO WANT TO LOOK AND SEE HOW INFO IS PASSED
;AND HOW YOU COULD ADD MORE CHARACTERS AND THEN ALSO YOU WILL WANT TO SEE HOW THE POST CONTROL WORKS ON 
;TURNING ON AND OFF THINGS.




WATCH	SILO1,3,FSTR
WATCH	SILO2,3,FSTR
WATCH	SILO3,3,FSTR
WATCH	SILO4,3,FSTR
WATCH	SILO5,3,FSTR
WATCH	SILO6,3,FSTR
WATCH	SILO7,3,FSTR
WATCH	SILO8,3,FSTR
WATCH	SILO9,3,FSTR

WATCH 	ASCII_INC,8,UDEC
WATCH	ASCII,1,FSTR
WATCH	M_ASCII,1,FSTR
WATCH	SILO,8,UDEC

	DEVICE OSCHS2, DRT60MS			;USED WITH OLDER VERSION
	;DEVICE	SX52, OSCXT4, DRT60MS		;USED WITH NEWER VERSION	
	FREQ	50000000	; have to Debug at freq != resonant freq


	RESET	Main
	ID	'SILOS'




; if you need to change the demo board's (webserver) IP address (default 10.1.1.20):

SX_IP_ADDR3	= 10	; SX's static IP address 
SX_IP_ADDR2	= 41	;  "
SX_IP_ADDR1	= 128	;  "
SX_IP_ADDR0	= 20	;  "

; if you need to change the demo board's MAC address (default 00-00-00-00-00-01):

SX_ETH_ADDR0	= 1	; SX's Ethernet Phy MAC Address
SX_ETH_ADDR1	= 0	;  "
SX_ETH_ADDR2	= 1	;  "
SX_ETH_ADDR3	= 0	;  "
SX_ETH_ADDR4	= 1	;  "
SX_ETH_ADDR5	= 1	;  "


;*********************************************************************************
; SX48BD/52BD Mode addresses
; *On SX48BD/52BD, most registers addressed via mode are read and write, with the
; exception of CMP and WKPND which do an exchange with W.
;*********************************************************************************
; Timer (read) addresses
TCPL_R		=	$00	; Read Timer Capture register low byte
TCPH_R		=	$01	; Read Timer Capture register high byte
TR2CML_R	=	$02	; Read Timer R2 low byte
TR2CMH_R	=	$03	; Read Timer R2 high byte
TR1CML_R	=	$04	; Read Timer R1 low byte
TR1CMH_R	=	$05	; Read Timer R1 high byte
TCNTB_R		=	$06	; Read Timer control register B
TCNTA_R		=	$07	; Read Timer control register A

; Exchange addresses
CMP		=	$08	; Exchange Comparator enable/status register with W  WAS CMP
WKPND		=	$09	; Exchange MIWU/RB Interrupts pending with W

; Port setup (read) addresses
WKED_R		=	$0A	; Read MIWU/RB Interrupt edge setup, 0 = falling, 1 = rising
WKEN_R		=	$0B	; Read MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled
ST_R		=	$0C	; Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
LVL_R		=	$0D	; Read Port Level setup, 0 = CMOS, 1 = TTL
PLP_R		=	$0E	; Read Port Pull-up setup, 0 = enabled, 1 = disabled
DIR_R		=	$0F	; Read Port Direction

; Timer (write) addresses
TR2CML_W	=	$12	; Write Timer R2 low byte
TR2CMH_W	=	$13	; Write Timer R2 high byte
TR1CML_W	=	$14	; Write Timer R1 low byte
TR1CMH_W	=	$15	; Write Timer R1 high byte
TCNTB_W		=	$16	; Write Timer control register B
TCNTA_W		=	$17	; Write Timer control register A

; Port setup (write) addresses
WKED_W		=	$1A	; Write MIWU/RB Interrupt edge setup, 0 = falling, 1 = rising
WKEN_W		=	$1B	; Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled
ST_W		=	$1C	; Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled
LVL_W		=	$1D	; Write Port Level setup, 0 = CMOS, 1 = TTL
PLP_W		=	$1E	; Write Port Pull-up setup, 0 = enabled, 1 = disabled
DIR_W		=	$1F	; Write Port Direction

;*********************************************************************************
; Setup and enable RTCC interrupt, WREG register, RTCC/WDT prescaler
;*********************************************************************************

RTCC_ON		=	%10000000	; Enables RTCC at address $01 (RTW hi)
					; WREG at address $01 (RTW lo) by default
RTCC_ID		=	%01000000	; Disables RTCC edge interrupt (RTE_IE hi)
					; RTCC edge interrupt (RTE_IE lo) enabled by default
RTCC_INC_EXT	=	%00100000	; Sets RTCC increment on RTCC pin transition (RTS hi)
					; RTCC increment on internal instruction (RTS lo) is defalut
RTCC_FE		=	%00010000	; Sets RTCC to increment on falling edge (RTE_ES hi)
					; RTCC to increment on rising edge (RTE_ES lo) is default
RTCC_PS_OFF	=	%00001000	; Assigns prescaler to Watchdog (PSA hi)
PS_000		=	%00000000	; RTCC = 1:2, WDT = 1:1
PS_001		=	%00000001	; RTCC = 1:4, WDT = 1:2
PS_010		=	%00000010	; RTCC = 1:8, WDT = 1:4
PS_011		=	%00000011	; RTCC = 1:16, WDT = 1:8
PS_100		=	%00000100	; RTCC = 1:32, WDT = 1:16
PS_101		=	%00000101	; RTCC = 1:64, WDT = 1:32
PS_110		=	%00000110	; RTCC = 1:128, WDT = 1:64
PS_111		=	%00000111	; RTCC = 1:256, WDT = 1:128


; ***************************
; *** CONDITIONAL DEFINES ***
; ***************************

HTTP	= 1


; *****************
; *** VARIABLES ***
; *****************

; *** Global ***
GLOBAL_ORG = $0A

flags		EQU GLOBAL_ORG+0	; various flags used by TCP/IP stack
flags2		EQU GLOBAL_ORG+1	; various flags used by TCP/IP stack
flags3		EQU GLOBAL_ORG+2	; various flags used by TCP/IP stack
globTemp1	EQU GLOBAL_ORG+3	; not preserved across any function
globTemp2	EQU GLOBAL_ORG+4	; not preserved across anyfunction
globTemp3	EQU GLOBAL_ORG+5	; preserved across some functions

; *****************
; *** BANK DEFINES 
; *****************



; *** Bank 0 ***
; (Don't use this bank - Difficulties with addressing Data)
	ORG	$00

; *** Bank 1 ***
	ORG	$10

NIC_BANK	= $

nicIOAddr		DS 1	; points to currently addressed register on NIC
nicNextPktPtr		DS 1	; points to next packet in NIC's rx queue
nicCurrPktPtr		DS 1	; points to current packet in NIC's rx queue
nicRemoteEth0		DS 1	; ethernet addr used for outgoing packet, overwritten by incoming packet
nicRemoteEth1		DS 1	;  "
nicRemoteEth2		DS 1	;  "
nicRemoteEth3		DS 1	;  "
nicRemoteEth4		DS 1	;  "
nicRemoteEth5		DS 1	;  "
nicCopySrcMSB		DS 1	; used by NICBufferCopy()
nicCopySrcLSB		DS 1	;  "
nicCopyDestMSB		DS 1	;  "
nicCopyDestLSB		DS 1	;  "
nicCopyLenMSB		DS 1	;  "
nicCopyLenLSB		DS 1	;  "
nicCopyTemp		DS 1	;  "

; *** Bank 2 ***
	ORG	$20

IP_BANK		= $	; make sure IP_BANK[7] = NIC_BANK[7]

remoteIP3		DS 1	; IP addr used for outgoing packet, overwritten by incoming packet
remoteIP2		DS 1	;  "
remoteIP1		DS 1	;  "
remoteIP0		DS 1	;  "
myIP3			DS 1	; filter value for incoming IP packets, also used in outgoing packet
myIP2			DS 1	;  "
myIP1			DS 1	;  "
myIP0			DS 1	;  "
ipCheckSumMSB		DS 1	; IP <header_checksum>
ipCheckSumLSB		DS 1	;  "
ipLengthMSB		DS 1	; IP <length>
ipLengthLSB		DS 1	;  "
ipProtocol		DS 1	; IP <protocol>
ipIdentMSB		DS 1	; IP <identifier>, incremented each outgoing packet
ipIdentLSB		DS 1	;  "
counter1		DS 1	; general purpose counter variable

; *** Bank 3 ***
	ORG	$30

TCB1_BANK	= $	; make sure TCB1_BANK[7] = NIC_BANK[7]

; TCB1 is bound to tcp connection1 indicated by flags2.TCP_SOCK cleared
; The ordering of these variables is significant. It is the same as the TCP
; header. This simpifies the send-packet code
tcb1LocalPortMSB	DS 1	; source port - tcp conn1
tcb1LocalPortLSB	DS 1	;  "
tcb1RemotePortMSB	DS 1	; destination port - tcp conn1
tcb1RemotePortLSB	DS 1	;  "
tcb1SndUna4		DS 1	; SND.UNA: oldest unacknowledged byte - tcp conn1
tcb1SndUna3		DS 1	;  "
tcb1SndUna2		DS 1	;  "
tcb1SndUna1		DS 1	;  "
tcb1RcvNxt4		DS 1	; RCV.NXT: next byte to receive - tcp conn1
tcb1RcvNxt3		DS 1	;  "
tcb1RcvNxt2		DS 1	;  "
tcb1RcvNxt1		DS 1	;  "
tcb1Offset		DS 1	; length of the TCP options
tcb1Flags		DS 1	; flags field
tcb1SendWinMSB		DS 1	; send window
tcb1SendWinLSB		DS 1	;  "

TCB1_END	= $

; *** Bank 4 ***
	ORG	$40

TCB2_BANK	= $	; make sure TCB2_BANK[7] = NIC_BANK[7]

; TCB2 is bound to tcp connection2 indicated by flags2.TCP_SOCK set
; The ordering of these variables is significant. It is the same as the TCP
; header. This simpifies the send-packet code
tcb2LocalPortMSB	DS 1	; source port - tcp conn2
tcb2LocalPortLSB	DS 1	;  "
tcb2RemotePortMSB	DS 1	; destination port - tcp conn2
tcb2RemotePortLSB	DS 1	;  "
tcb2SndUna4		DS 1	; SND.UNA: oldest unacknowledged byte - tcp conn2
tcb2SndUna3		DS 1	;  "
tcb2SndUna2		DS 1	;  "
tcb2SndUna1		DS 1	;  "
tcb2RcvNxt4		DS 1	; RCV.NXT: next byte to receive - tcp conn2
tcb2RcvNxt3		DS 1	;  "
tcb2RcvNxt2		DS 1	;  "
tcb2RcvNxt1		DS 1	;  "
tcb2Offset		DS 1	; length of the TCP options
tcb2Flags		DS 1	; flags field
tcb2SendWinMSB		DS 1	; send window
tcb2SendWinLSB		DS 1	;  "

TCB2_END	= $

; *** Bank 5 ***
	ORG	$50

TCP_BANK = $	; make sure TCP_BANK[7] = NIC_BANK[7]

tcp1State		DS 1	; tcp connection1 state-machine state
tcp2State		DS 1	; tcp connection2 state-machine state
tcpTmpSeq4		DS 1	; TMP.SEQ. 1=LSB, 4=MSB
tcpTmpSeq3		DS 1	; temporary information from the received packet
tcpTmpSeq2		DS 1
tcpTmpSeq1		DS 1
tcp1UnAckMSB		DS 1	; number of unacknowledged bytes for tcp connection1
tcp1UnAckLSB		DS 1	;  "
tcp2UnAckMSB		DS 1	; number of unacknowledged bytes for tcp connection2
tcp2UnAckLSB		DS 1	;  "
tcpRxFlags		DS 1	; copy of the received flags field
tcpCheckSumMSB		DS 1
tcpCheckSumLSB		DS 1
tcpLengthMSB		DS 1
tcpLengthLSB		DS 1

tcpTmpMSB		= tcpTmpSeq4
tcpTmpLSB		= tcpTmpSeq3
tcpAppTxBytesMSB	= tcp1UnAckMSB	; number of bytes app wants to transmit
tcpAppTxBytesLSB	= tcp1UnAckLSB	;  "
tcpAppTxBytesMSB	= tcp2UnAckMSB	; number of bytes app wants to transmit
tcpAppTxBytesLSB	= tcp2UnAckLSB	;  "
tcpAppRxBytesMSB	= tcpLengthMSB	; number of bytes app will be receiving
tcpAppRxBytesLSB	= tcpLengthLSB	;  "

; *** Bank 6 ***
	ORG	$60

ARP_BANK	= $	; make sure ARP_BANK[7] = NIC_BANK[7]

host1IP3		DS 1	; remote host1 IP address
host1IP2		DS 1	;  "
host1IP1		DS 1	;  "
host1IP0		DS 1	;  "
host1Eth0		DS 1	; remote host1 Ethernet address
host1Eth1		DS 1	;  "
host1Eth2		DS 1	;  "
host1Eth3		DS 1	;  "
host1Eth4		DS 1	;  "
host1Eth5		DS 1	;  "
stPktTxBufStart		DS 1	; start address of stalled packet in NIC tx buffer

TCPPORT_BANK	= $

; Incoming tcp packet ports
tcpRemotePortMSB	DS 1
tcpRemotePortLSB	DS 1
tcpLocalPortMSB		DS 1
tcpLocalPortLSB		DS 1

; *** Bank 7 ***
	ORG	$70

TIMER_BANK	= $	; make sure TIMER_BANK[7] = NIC_BANK[7]

baseTimer		DS 1	; lowest/common cog in timer chain
arpTimerMSB		DS 1	; ARP-timer count
arpTimerLSB		DS 1	;  "
tcp1TimerMSB		DS 1	; tcp1 re-transmission timer count
tcp1TimerLSB		DS 1	;  "
tcp2TimerMSB		DS 1	; tcp2 re-transmission timer count
tcp2TimerLSB		DS 1	;  "
conn1TimerMSB		DS 1	; tcp1 timeout timer count
conn1TimerLSB		DS 1	;  "
conn2TimerMSB		DS 1	; tcp2 timeout timer count
conn2TimerLSB		DS 1	;  "

	IF	HTTP
HTTP_BANK	= $	; make sure HTTP_BANK[7] = NIC_BANK[7]

httpParseState		DS 1	; state of the HTTP header parser
httpURIHash		DS 1	; hash of the current URI
httpParseState2		DS 1	; state of the HTTP message parser
	ENDIF



; *** Bank 8 ***
	ORG	$80
MISC_BANK	= $

; Watch out for this when moving Databanks! This is the only place where more
; than 1 byte is reserved for Data and it's not so obvious!
BCD3			DS 3	; buffer for binary-to-ascii conversion

ADC_BANK	= $	; must be same bank as bcd3

EEPROM_BANK	= $	; make sure EEPROM_BANK[7] = NIC_BANK[7]

e2AddrMSB		DS 1	; address in EEPROM to start reading from
e2AddrLSB		DS 1	;  "
e2FileLenMSB		DS 1	; length of the file being read
e2FileLenLSB		DS 1	;  "


;THIS WAS ADDED BY TIM HOSEY
SERIAL		= $	;THIS IS WHERE YOU ARE GETTING ASCII INPUT AT 2400 BPS FROM THE SILO.

RX_COUNT		DS 1
RX_DIVIDE		DS 1
RX_BYTE			DS 1
RX_BIT			DS 1
RX_FLAG

; *** Bank 9 ***
	ORG	$90



; *** Bank A ***
	ORG	$A0

UDP_BANK	= $

udpRxSrcPortMSB		DS 1
udpRxSrcPortLSB		DS 1
udpRxDestPortMSB	DS 1	; filter value for incoming UDP packets
udpRxDestPortLSB	DS 1	;  "
udpRxDataLenMSB		DS 1	; length of <data> field of incoming UDP packet
udpRxDataLenLSB		DS 1	;  "
udpTxSrcPortMSB		DS 1
udpTxSrcPortLSB		DS 1
udpTxDestPortMSB	DS 1
udpTxDestPortLSB	DS 1
udpTxDataLenMSB		DS 1	; length of <data> field of outgoing UDP packet
udpTxDataLenLSB		DS 1	;  "

TCPTMP_BANK	= $	; stores temporary tcp info

tcpTmpAck4		DS 1	; TMP.ACK
tcpTmpAck3		DS 1	; temporary information from the received packet
tcpTmpAck2		DS 1
tcpTmpAck1		DS 1

; *** Bank B ***
	ORG	$B0

TCPSOCKET_BANK	= $	; contains the 2 TCP sockets

; socket1 - will always be bound to TCB1_BANK
sock1RemoteIP3		DS 1
sock1RemoteIP2		DS 1
sock1RemoteIP1		DS 1
sock1RemoteIP0		DS 1
sock1RemotePortMSB	DS 1
sock1RemotePortLSB	DS 1

; socket2 - will always be bound to TCB2_BANK
sock2RemoteIP3		DS 1
sock2RemoteIP2		DS 1
sock2RemoteIP1		DS 1
sock2RemoteIP0		DS 1
sock2RemotePortMSB	DS 1
sock2RemotePortLSB	DS 1


; *** Bank C ***
	ORG	$C0

;INFO FOR SILOS 1 - 8
SILO_BANK	=	$
SILO1			DS 3
SILO2			DS 3
SILO3			DS 3
SILO4			DS 3
SILOINC			DS 1  	;THIS IS THE INCREMENTAL COUNT TO DETERMINE WHICH SILO TO LOOK AT.
ASCII			DS 1	;THIS IS THE HOLD FOR W
ASCII_INC		DS 1	;THIS IS WHAT NUMBER YOU ARE LOOKING AT IN THE STRING
SILO			DS 1	;THIS IS THE SILO NUMBER YOU ARE RECEIVING DATA FOR.

;THAT IS IT FOR THIS BANK


; *** Bank D ***
	ORG	$D0
SILO_BANK1	= $	; INFO ON SILO 1
SILO5			DS 3
SILO6			DS 3
SILO7			DS 3
SILO8			DS 3
SILO9			DS 3
M_ASCII			DS 1

; *** Bank E ***
	ORG	$E0
INFO_BANK	= $
INFO			DS 2			;USE THIS TO STORE THE ASCII COMING IN
INFO_CNT		DS 1			;USE THIS TO LET ME KNOW WHICH INFO TO PUT IT INTO.
; *** Bank F ***
	ORG	$F0


; ***************
; *** EQUATES ***
; ***************

INT_PERIOD	= 254				;254	; RTCC interrupt periodicity (345kHz)
						; change this if you're not clocking the SX at 50MHz

; *** Pin Definitions ***

RA_DIR		= %10101010				;GOOD RA.3 IS BEING SET AS AN INPUT
RA_OUT		= %01110101				;THIS WAS LIKE THIS RA_OUT = %01110101
RA_LVL		= %11111111
RA_PLP		= %01110111

RB_DIR		= %10000000
RB_OUT		= %01100000
RB_LVL		= %11111111
RB_PLP		= %01111111

RC_DIR		= %11111111
RC_OUT		= %00000000
RC_LVL		= %11111111
RC_PLP		= %11111111

RD_DIR		= %11111111
RD_OUT		= %00000000
RD_LVL		= %11111111
RD_PLP		= %00000000

RE_DIR		= %01111111
RE_OUT		= %00000000
RE_LVL		= %00111111
RE_PLP		= %11000000

NIC_DATA_PORT	= rc
NIC_CTRL_PORT	= rb

IOWB_PIN	= NIC_CTRL_PORT.5
IORB_PIN	= NIC_CTRL_PORT.6
IOCH_PIN	= NIC_CTRL_PORT.7

E2_PORT		= ra

E2SCL		= 4
E2SDA		= 5
E2SCL_PIN	= E2_PORT.E2SCL
E2SDA_PIN	= E2_PORT.E2SDA

LED_PORT	= ra
LED		= 6
LED_PIN		= LED_PORT.LED

SW_PORT		= ra
SW		= 7
SW_PIN		= SW_PORT.SW


;RS-232 PORT SETTINGS AND BAUD RATE DIVIDERS.

;TIM A LITTLE REMINDER, GROUND THE DARN THING AND IT WILL WORK. OKAY!!!!!!!!  LOL

RX_PIN		=  RD.0			;CHANGED THIS FROM RA.3  82 FRO 254 RTCC FOR 2400 BPS
BAUD		=  82			
BAUD15		=  123			;This should be .03% deviant.			

; *** flags ***

RX_IS_ARP	= 0	; incoming packet is an ARP packet
RX_IS_ICMP	= 1	; incoming packet is an ICMP packet
RX_IS_UDP	= 2	; incoming packet is a UDP packet
RX_IS_TCP	= 3	; incoming packet is a TCP packet
RX_IS_IP_BCST	= 4	; incoming packet is an IP Broadcast packet
GOT_IP_ADDR	= 6	; received an IP address assignment (recv'ed DHCP ACK)
IP_CHKSUM_LSB	= 7	; next byte to accumulate IP checksum is LSB
TCP_CHKSUM_LSB	= 5	; next byte to accumulate TCP checksum is LSB

; *** flags2 ***

GOT_RX_FRAME	= 0	; used by NICWaitRxFrame to indicate we got one. 
RENEW_IP_LEASE	= 2	; indicates an IP lease renewal is in progress
TCP_SOCK	= 3	; tcp connection/socket indicator. 0=tcp1, 1=tcp2
TCP_TXSEMA	= 4	; tcp transmit semaphore.
SW_PRESSED	= 6	; indicates the switch SW2 is held in (pressed) when 1
BROWSER_TYPE	= 7	; 1=netscape type, 0=IE type

; *** flags3 ***

ARP_REQ_SENT	= 0	; indicates that an ARP request has been sent
ARP_RSP_RCVD	= 1	; indicates that an ARP response has been received
ARP_STL_TX	= 2	; indicates that the stalled packet is to be transmitted
HTTP_METHOD	= 4	; 0=get, 1=post/put (requested method by remote browser)
GOT_HTTP_METHOD	= 5	; indicates the HTTP_METHOD bit is valid
GOT_URI		= 6	; indicates the file URI is complete
LED_LOCK	= 7	; locks access to the LED when set to 1.

; *** NIC Constants ***

RXBUF_START	= $40	; 3328 byte receive buffer (2 max-size packets)
RXBUF_END	= $4D	;  "

TXBUF1_START	= $4D	; 1536 byte transmit buffer for ICMP/UDP
TXBUF2_START	= $53	; 1536 byte transmit buffer for tcp connection1
TXBUF3_START	= $59	; 1536 byte transmit buffer for tcp connection2
TXBUF4_START	= $5F	; 256 byte transmit buffer for ARP

; *** Ethernet Constants ***

; also see in "DEMO DEFINES" section

; *** ARP Constants ***

ARP_TIMEOUT	= 5	; waiting for an ARP response timeout period

; *** IP Constants ***

; also see in "DEMO DEFINES" section

IP_TTL = 32



; *** UDP Constants ***

UDP_RX_DEST_MSB	= $04	; user UDP RX Port: 1025
UDP_RX_DEST_LSB	= $01	;  "

; *** TCP Constants ***

; TCP state-machine states (numbering order is signifcant)
TCP_ST_CLOSED	= 0
TCP_ST_LISTEN	= 1
TCP_ST_SYNSENT	= 2
TCP_ST_SYNRCVED	= 3
TCP_ST_ESTABED	= 4
TCP_ST_FINWAIT1	= 5
TCP_ST_FINWAIT2	= 6
TCP_ST_CLOSEWAIT= 7
TCP_ST_CLOSING	= 8
TCP_ST_LASTACK	= 9
TCP_ST_TIMEWAIT	= 10

; Bit positions in the TCP <flag> byte.
TCP_FLAG_ACK	= 4
TCP_FLAG_PSH	= 3
TCP_FLAG_RST	= 2
TCP_FLAG_SYN	= 1
TCP_FLAG_FIN	= 0

; TCP Options
TCP_OPTION_END	= 0
TCP_OPTION_NOP	= 1
TCP_OPTION_MSS	= 2	; max segment size

TCP_HDR_LENGTH	= 5	; normal TCP header length.
TCP_OFFSET_MASK	= $F0

TCP_WINDOW_SIZE	= 1400	; max # of Data bytes we will accept
TCP_SEG_SIZE	= 1400	; max # of Data bytes TCP will transmit per segment

TCP_RESTART_EXP	= 8	; TCP re-transmission timeout period (0.19s per tick)
TCP_CONN_EXP	= 160	; TCP connection timeout period (0.19s per tick)

; *** HTTP Constants ***

; States for parsing HTTP headers

HTTP_PORT_MSB	= 0	; local tcp port number for HTTP server.
HTTP_PORT_LSB	= 80	;  "

HTTP_SEG_SIZE	= 1400
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################
;################################################################################################################




URI1		= $FF	; NOTHING RIGHT NOW	
URI2		= $2A	; hash of "INDEX.HTML"
URI3		= $21	; hash of "postctrl.htm"

; *** EEPROM Constants ***

E2_CMD_RD	= $A1	; most-significant 7-bits is the I2C slave addr
E2_CMD_WR	= $A0	; most-significant 7-bits is the I2C slave addr

E2_SDA_MASK	= (1 << E2SDA)	; a '1' in the SDA bit, '0' everywhere else

E2_DDR_SDA_IN	= (RA_DIR | E2_SDA_MASK)	; direction of SDA port when SDA is input

E2_DDR_SDA_OUT	= (RA_DIR & (~E2_SDA_MASK))	; direction of SDA port when SDA is output


; **************
; *** MACROS ***
; **************

_bank	MACRO	1		; sets FSR[7:4]
		bank	\1
	IF \1 &	%10000000	; SX48BD and SX52BD (production release)
				; BANK instruction
		setb	fsr.7	; modifies FSR bits 4,5 and 6. FSR.7 needs
				; to be set by sw.
	ELSE
		clrb	fsr.7
	ENDIF
	ENDM

_banky	MACRO	1		; set FSR[7] ~only~
	IF \1 &	%10000000	; SX48BD and SX52BD (production release)
				; bank instruction
		setb	fsr.7	; modifies FSR bits 4,5 and 6. FSR.7 needs to
				; be set by sw.
	ELSE
		clrb	fsr.7
	ENDIF
	ENDM

_mode	MACRO	1
		mov	w, #\1	; loads the M register correctly for the SX48BD
				; and SX52BD
		mov	m, w
	ENDM

_pc_check	MACRO	0
	IF ($ &	$100)
		ERROR 'ERROR!! ADD PC,W	instruction at invalid addr'
	ENDIF
	ENDM


; ***********
; *** ISR ***
; ***********
	ORG	0	; Page0

ISR					;THIS IS THE BEGINING OF THE INTERRUPTS ROUTINES.


				
; ********************
; *** RS-232 @ 2400 BPS
; ********************

;TIM A LITTLE REMINDER, GROUND THE DARN THING AND IT WILL WORK. OKAY!!!!!!!!  LOL
	_BANK	SERIAL

	MOVB	C,/RX_PIN				;SERIAL RECEIVE WAS MOVB C,/RX_PIN
	TEST	RX_COUNT
	JNZ	:RXBIT					;IF NOT, :BIT
	MOV	W,#9					;IN CASE START READY 9
	SC						;IF START, SET RX_COUNT
	MOV	RX_COUNT,W
	MOV	RX_DIVIDE,#BAUD15			;READY 1.5 BIT PERIODS
:RXBIT	DJNZ	RX_DIVIDE,RXDONE			;8TH TIME THROUGH ?
	MOV	RX_DIVIDE,#BAUD
	DEC	RX_COUNT				;LAST BIT ?
	SZ						;IF NOT, SAVE BIT
	RR	RX_BYTE					;ROTATE THE INFO RIGHT
	SNZ						;IF SO, SET FLAG
	SETB	RX_FLAG.0
RXDONE

Timer		; implement various SW timers

		; lowest-common-denominator timer
		_bank	TIMER_BANK
		incsz	baseTimer	; inc at 2.9us per tick with 50MHz clk
		jmp	:timerEnd

:tcp1Timer	; TCP1-timer (used for TCP1 re-transmission timeouts)
		incsz	tcp1TimerLSB	; inc at 742.4us per tick with 50MHz clk
		jmp	:tcp2Timer
		inc	tcp1TimerMSB	; inc at 190.0544ms per tick with 50MHz clk

:tcp2Timer	; TCP2-timer (used for TCP2 re-transmission timeouts)
		incsz	tcp2TimerLSB	; inc at 742.4us per tick with 50MHz clk
		jmp	:conn1Timer
		inc	tcp2TimerMSB	; inc at 190.0544ms per tick with 50MHz clk

:conn1Timer	; Connection-timer (used for TCP1 connection timeouts)
		incsz	conn1TimerLSB
		jmp	:conn2Timer
		inc	conn1TimerMSB

:conn2Timer	; Connection-timer (used for TCP2 connection timeouts)
		incsz	conn2TimerLSB
		jmp	:arpTimer
		inc	conn2TimerMSB

:arpTimer	; ARP-timer (used for ARP response timeouts)
		incsz	arpTimerLSB
		jmp	:dhcpTimer
		inc	arpTimerMSB

:dhcpTimer      
;TOOK THE DHCP CRAP OUT OF HERE TO FREE UP MORE ROOM.
:timerEnd



	
;AFTER THE ABOVE IS DONE THEN HERE IS THE FUN PART OF PUTTING DATA WHERE IT BELONGS CORRESPONDING TO THE SILO #.

GET_BYTE						;ATTEMPT TO GET A BYTE OF INFO
	_BANK	SERIAL
	JNB	RX_FLAG.0,RXDONE1
	MOV	W,RX_BYTE
	_BANK	SILO_BANK
	MOV	ASCII,W
	SETB	FSR.4					;NEXT SILO BANK
	MOV	M_ASCII,W				;SET THE HIGHTER ASCII IN ALSO.
	_BANK	SILO_BANK
	INC	ASCII_INC				;YOU ARE LOOKING FOR ONLY 9-11 & 2,3 FOR SILO #
	CJE	ASCII_INC,#5,@GET_SILO_NUMBER
	CJE	ASCII_INC,#11,@TEST1			;11
	CJE	ASCII_INC,#12,@TEST2			;12
	CJE	ASCII_INC,#13,@TEST3
	JMP	RXDONE1					;DUH, DUH, DUH LOL
		

RXDONE1
	_BANK	SILO_BANK
	CSNE	ASCII,#10				;IF NOT LINE FEED SKIP OR #10
	CLR	ASCII_INC
	CLR	ASCII
	_BANK	SERIAL
	CLRB	RX_FLAG.0



ISRExit		MOV	W, #-INT_PERIOD
		retiw					;THIS IS THE END OF THE INTERUPT PERIOD.
; ********************
; *** MAIN PROGRAM ***
; ********************

Init			jmp	_Init
ARPInit			jmp	_ARPInit
TCPIPInit		jmp	_TCPIPInit
StartupDelay		jmp	_StartupDelay
CopyRemoteIPSocket1	jmp	_CopyRemoteIPSocket1
CopyRemoteIPSocket2	jmp	_CopyRemoteIPSocket2
CheckRemotePortTCB1	jmp	_CheckRemotePortTCB1
CheckRemotePortTCB2	jmp	_CheckRemotePortTCB2
	IF	HTTP
E2Init			jmp	_E2Init
	ENDIF


Main
	_BANK	SILO_BANK
	CLR	SILO
	CLR	SILOINC
	

MAIN_NEXT


		call	@Init

		call	@UDPAppInit		; initialise UDP application

		_bank	MISC_BANK


; main program loop
:mainLoop

		call	@NICCheckRxFrame	; check if we received a frame
		jz	:noRxFrame		; no

		call	@NICWaitRxFrame		; no waiting cus we've already
						; checked

		call	@ARPCheckIfIs		; check and process if ARP
		jb	flags.RX_IS_ARP, :mainLoop

		call	@CheckIPDatagram	; not ARP, check if IP

		jb	flags.RX_IS_ICMP, :icmp
		jb	flags.RX_IS_UDP, :udp
		jb	flags.RX_IS_TCP, :tcp

		jmp	:mainLoop

:icmp		call	@ICMPProcPktIn		; process incoming ICMP packet
		jmp	:mainLoop

:udp		call	@UDPProcPktIn		; process incoming UDP packet
		jmp	:mainLoop

:tcp		call	@TCPProcPktIn		; process incoming TCP packet
		jmp	:mainLoop

:noRxFrame	call	@ARPSendStPacket	; send ARP stalled packets if any

		bank	TCP_BANK
		cje	tcp2State, #TCP_ST_CLOSED, :tcp2Closed	; check if tcp2
								; in listen
		cje	tcp2State, #TCP_ST_LISTEN, :tcp2Listen	; check if tcp2
								; closed

		; tcp2 is in another state, check if hanging connection
		bank	TIMER_BANK
		cjae	conn2TimerMSB, #TCP_CONN_EXP, :resetTCP2
		jmp	:tcpTx			; connection timer not timed out

:tcp2Closed	call	@TCPApp2Init		; initialise tcp2 application
		_bank	TIMER_BANK
		clr	conn2TimerMSB		; clear the connection timer
		jmp	:tcp1Check

:tcp2Listen	bank	TIMER_BANK
		clr	conn2TimerMSB		; tcp2 in listen, clr conn timer
		jmp	:tcp1Check

:tcp1Check	_bank	TCP_BANK
		cje	tcp1State, #TCP_ST_CLOSED, :tcp1Closed	; check if tcp1
								; in listen
		cje	tcp1State, #TCP_ST_LISTEN, :tcp1Listen	; check if tcp1
								; closed

		; tcp1 is in another state, check if hanging connection
		bank	TIMER_BANK
		cjae	conn1TimerMSB, #TCP_CONN_EXP, :resetTCP1
		jmp	:tcpTx			; connection timer not timed out

:tcp1Closed	call	@TCPApp1Init		; initialise tcp1 application
		_bank	TIMER_BANK
		clr	conn1TimerMSB		; clear the connection timer
		jmp	:mainLoop

:tcp1Listen	bank	TIMER_BANK
		clr	conn1TimerMSB		; tcp2 in listen, clr conn timer
		jmp	:mainLoop

:resetTCP2	; reset hung TCP2 connection
		bank	TCP_BANK
		clr	tcp2UnAckMSB		; clear bytes to still send on tcp2
		clr	tcp2UnAckLSB
		mov	tcp2State, #TCP_ST_CLOSED
	IF	HTTP
		bank	HTTP_BANK		; reset HTTP webserver state
		clr	httpParseState
	ENDIF
		jmp	:mainLoop

:resetTCP1	; reset hung TCP1 connection
		bank	TCP_BANK
		clr	tcp1UnAckMSB		; clear bytes to still send on tcp1
		clr	tcp1UnAckLSB
		mov	tcp1State, #TCP_ST_CLOSED

		jmp	:mainLoop		; repeat cycle by returning to entry

		; do not allow new tx if waiting for ARP response
:tcpTx		jb	flags3.ARP_REQ_SENT, :mainLoop
		mov	w, #(1<<TCP_TXSEMA)
		xor	flags2,	w		; toggle TCP_TXSEMA to give other tcp
						; connection a time-slice to transmit
		call	@TCPTransmit		; check if app has anything to transmit
		jmp	:mainLoop		; repeat cycle by returning to entry


; *******************
; *** SUBROUTINES ***
; *******************

	ORG	$D0	; Page0

; ******************************************************************************
_Init
; Main program initialization code
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		_mode	LVL_W
		mov	!ra, #RA_LVL
		mov	!rb, #RB_LVL
		mov	!rc, #RC_LVL
		;mov	!rd, #RD_LVL
		mov	!re, #RE_LVL

		_mode	PLP_W
		mov	!ra, #RA_PLP
		mov	!rb, #RB_PLP
		mov	!rc, #RC_PLP
		;mov	!rd, #RD_PLP
		mov	!re, #RE_PLP

		_mode	DIR_W
		mov	!ra, #RA_DIR
		mov	!rb, #RB_DIR
		mov	!rc, #RC_DIR
		;mov	!rd, #RD_DIR
		mov	!re, #RE_DIR

		mov	ra, #RA_OUT
		mov	rb, #RB_OUT
		mov	rc, #RC_OUT
		;mov	rd, #RD_OUT
		mov	re, #RE_OUT


MOV		!RD,#$FF			;YOU CHANGED THIS TO ALL INPUTS


		clr	flags
		clr	flags2
		clr	flags3

		call	@NICInit
		call	@ARPInit
		call	@TCPIPInit
	IF	HTTP
		call	@E2Init
	ENDIF
OPT
		mov	w, #(RTCC_PS_OFF)	; setup option register
		mov	!option, w

		retp

; ******************************************************************************
_ARPInit
; ARP initialization code
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		_bank	ARP_BANK
		clr	host1IP0	; clear the cache
		clr	host1IP1	;  "
		clr	host1IP2	;  "
		clr	host1IP3	;  "
		retp

; ******************************************************************************
_TCPIPInit
; TCP/IP stack initialization code
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		_bank	IP_BANK


		; initialize SX's IP addr
		setb	flags.GOT_IP_ADDR
		mov	myIP3, #SX_IP_ADDR3
		mov	myIP2, #SX_IP_ADDR2
		mov	myIP1, #SX_IP_ADDR1
		mov	myIP0, #SX_IP_ADDR0

		; initialize IP Identifier sequence number
		clr	ipIdentMSB
		clr	ipIdentLSB

		; initialise the TCP variables
		bank	TCP_BANK
		clr	tcp1UnAckMSB
		clr	tcp1UnAckLSB
		clr	tcp2UnAckMSB
		clr	tcp2UnAckLSB
		mov	tcp1State, #TCP_ST_CLOSED
		mov	tcp2State, #TCP_ST_CLOSED

		; clear the tcp socket local ports (used for listening on).
		bank	TCB1_BANK
		clr	tcb1LocalPortLSB
		clr	tcb1LocalPortMSB

		bank	TCB2_BANK
		clr	tcb2LocalPortLSB
		clr	tcb2LocalPortMSB

		; clear the tcp sockets remote IP addresses
		_bank	TCPSOCKET_BANK
		clr	sock1RemoteIP3
		clr	sock2RemoteIP3

		retp

	IF	HTTP
; ******************************************************************************
_E2Init
; EEPROM initialization code
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; get the I2C Device into a known state
		call	@E2SDAInput
:e2InitLoop	clrb	E2SCL_PIN
		call	@E2Delay1300ns
		setb	E2SCL_PIN
		call	@E2Delay900ns
		jnb	E2SDA_PIN, :e2InitLoop
		retp
	ENDIF

; ******************************************************************************
_StartupDelay
; Delay for ?ms @ 50MHz
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		mov	globTemp2, #10
:loop3		clr	globTemp1
:loop2		clr	w
:loop1		decsz	wreg
		jmp	:loop1
		decsz	globTemp1
		jmp	:loop2
		decsz	globTemp2
		jmp	:loop3
		retp

; ******************************************************************************
_CopyRemoteIPSocket1
; Copies remoteIP3-0 into sock1RemoteIP3
; INPUT: remoteIP3-0
; OUTPUT: sock1RemoteIP3
; ******************************************************************************
		mov	globTemp1, #sock1RemoteIP3
		mov	globTemp3, #remoteIP3
		call	@Copy4Inc
		retp

; ******************************************************************************
_CopyRemoteIPSocket2
; Copies remoteIP3-0 into sock2RemoteIP3
; INPUT: remoteIP3-0
; OUTPUT: sock2RemoteIP3
; ******************************************************************************
		mov	globTemp1, #sock2RemoteIP3
		mov	globTemp3, #remoteIP3
		call	@Copy4Inc
		retp

; ******************************************************************************
_CheckRemotePortTCB1
; Checks if the remote port in the TCP packet is in TCB1_BANK
; INPUT: tcpRemotePortLSB, tcpRemotePortMSB, tcb1RemotePortLSB,
;	 tcb1RemotePortMSB
; OUTPUT: Z set if in there
; ******************************************************************************
		_bank	TCPPORT_BANK
		mov	w, tcpRemotePortMSB
		bank	TCB1_BANK
		xor	w, tcb1RemotePortMSB
		sz
		retp
		mov	w, tcb1RemotePortLSB
		bank	TCPPORT_BANK
		xor	w, tcpRemotePortLSB
		retp

; ******************************************************************************
_CheckRemotePortTCB2
; Checks if the remote port in the TCP packet is in TCB2_BANK
; INPUT: tcpRemotePortLSB, tcpRemotePortMSB, tcb2RemotePortLSB,
; tcb2RemotePortMSB
; OUTPUT: Z set if in there
; ******************************************************************************
		_bank	TCPPORT_BANK
		mov	w, tcpRemotePortMSB
		bank	TCB2_BANK
		xor	w, tcb2RemotePortMSB
		sz
		retp
		mov	w, tcb2RemotePortLSB
		bank	TCPPORT_BANK
		xor	w, tcpRemotePortLSB
		retp


;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
; YOU SHOULD HAVE 151 WORDS LEFT HERE FROM 
; $168 TO $1FF
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
	ORG	$168
TEST3
	_BANK	SILO_BANK
	CJE	SILO,#1,SB1
	CJE	SILO,#2,SB2
	CJE	SILO,#3,SB3
	CJE	SILO,#4,SB4
	CJE	SILO,#5,SB5
	CJE	SILO,#6,SB6
	CJE	SILO,#7,SB7
	CJE	SILO,#8,SB8
	CJE	SILO,#9,SB9
	JMP	@RXDONE1			;IF NONE THEN JUMP BACK		
SB1
	MOV	SILO1+2,ASCII
	JMP	@RXDONE1
SB2
	MOV	SILO2+2,ASCII
	JMP	@RXDONE1
SB3
	MOV	SILO3+2,ASCII
	JMP	@RXDONE1
SB4
	MOV	SILO4+2,ASCII
	JMP	@RXDONE1
SB5
	SETB	FSR.4
	MOV	SILO5+2,M_ASCII
	JMP	@RXDONE1
SB6
	SETB	FSR.4
	MOV	SILO6+2,M_ASCII
	JMP	@RXDONE1
SB7
	SETB	FSR.4
	MOV	SILO7+2,M_ASCII
	JMP	@RXDONE1
SB8
	SETB	FSR.4
	MOV	SILO8+2,M_ASCII
	JMP	@RXDONE1
SB9
	SETB	FSR.4
	MOV	SILO9+2,M_ASCII
	JMP	@RXDONE1			
		
	ORG	$200	; Page1

NICBufCopy	jmp	_NICBufCopy
NICBufWrite	jmp	_NICBufWrite
NICBufRead	jmp	_NICBufRead
NICBufIPAddrWr	jmp	_NICBufIPAddrWr
NICWriteSrcIP	jmp	_NICWriteSrcIP
NICWriteDestIP	jmp	_NICWriteDestIP
NICWriteSrcEth	jmp	_NICWriteSrcEth
NICWriteDestEth	jmp	_NICWriteDestEth
NICDMAInit	jmp	_NICDMAInit

; ******************************************************************************
NICInit
; Initializes and configures Realtek RTL8019AS NIC
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		_bank	NIC_BANK

		mov	nicIOAddr, #$1F		; write to reset port
		mov	w, #0
		call	NICWrite
		call	@StartupDelay		; give it a little time to reset

		; --- Page3 Registers ---

		clr	nicIOAddr		; CR
		mov	w, #%11000001		; Page3, Stop
		call	NICWrite

		mov	nicIOAddr, #$01		; 9346CR
		mov	w, #%11000000		; config register write enable
		call	NICWrite

		mov	nicIOAddr, #$05		; CONFIG2
		mov	w, #%00000000		; link test enable
		call	NICWrite

		; --- Page1 Registers ---

		clr	nicIOAddr		; CR
		mov	w, #%01000001		; Page1, Stop
		call	NICWrite

		inc	nicIOAddr		; ($01) PAR0
		mov	w, #SX_ETH_ADDR0
		call	NICWrite
		inc	nicIOAddr		; ($02) PAR1
		mov	w, #SX_ETH_ADDR1
		call	NICWrite
		inc	nicIOAddr		; ($03) PAR2
		mov	w, #SX_ETH_ADDR2
		call	NICWrite
		inc	nicIOAddr		; ($04) PAR3
		mov	w, #SX_ETH_ADDR3
		call	NICWrite
		inc	nicIOAddr		; ($05) PAR4
		mov	w, #SX_ETH_ADDR4
		call	NICWrite
		inc	nicIOAddr		; ($06) PAR5
		mov	w, #SX_ETH_ADDR5
		call	NICWrite

		inc	nicIOAddr		; ($07) CURR
		mov	w, #RXBUF_START
		call	NICWrite

		; --- Page0 Registers ---

		clr	nicIOAddr		; CR
		mov	w, #%00000001		; Page0, Stop
		call	NICWrite

		inc	nicIOAddr		; ($01) PSTART
		mov	w, #RXBUF_START
		call	NICWrite

		inc	nicIOAddr		; ($02) PSTOP
		mov	w, #RXBUF_END
		call	NICWrite

		inc	nicIOAddr		; ($03) BNRY
		mov	w, #RXBUF_START
		call	NICWrite

		mov	nicIOAddr, #$07		; ISR
		mov	w, #$FF
		call	NICWrite

		mov	nicIOAddr, #$0C		; RCR
		mov	w, #%11000110
		call	NICWrite

		inc	nicIOAddr		; ($0D) TCR
		mov	w, #%11100000
		call	NICWrite

		inc	nicIOAddr		; ($0E) DCR
		mov	w, #%10111000
		call	NICWrite

		clr	nicIOAddr		; CR
		mov	w, #%00000010		; Page0, Start
		call	NICWrite

		retp

; ******************************************************************************
NICWrite
; Does an I/O Write of a byte on the ISA host bus to the NIC
; INPUT:  w = byte to be written
;	  nicIOAddr = I/O address (most-significant 3 bits must be zero)
; OUTPUT: none
; ******************************************************************************
		bank	NIC_BANK

		; put Data out on Data bus
		mov	NIC_DATA_PORT, w
		_mode	DIR_W
		mov	w, #0			; output
		mov	!NIC_DATA_PORT,	w

		; put addr out on addr bus
		mov	w, NIC_CTRL_PORT
		and	w, #%11100000
		or	w, nicIOAddr
		mov	NIC_CTRL_PORT, w

		; strobe IOWB pin
		jmp	$+1
		clrb	IOWB_PIN
		jmp	$+1
		jnb	IOCH_PIN, $
		setb	IOWB_PIN

		retp

; ******************************************************************************
NICWriteAgain
; Write to the same nicIOAddr as the previous call to NICWrite()
; INPUT:  w = byte to be written
; OUTPUT: none
; ******************************************************************************
		; put Data out on Data bus
		mov	NIC_DATA_PORT, w
		; strobe IOWB pin
		jmp	$+1
		clrb	IOWB_PIN
		jmp	$+1
		jnb	IOCH_PIN, $
		setb	IOWB_PIN
		retp

; ******************************************************************************
NICRead
; Does an I/O Read of a byte on the ISA host bus from the NIC
; INPUT:  nicIOAddr = I/O address (most-significant 3 bits must be zero)
; OUTPUT: w = byte read
; ******************************************************************************
		bank	NIC_BANK

		; configure Data bus for input
		_mode	DIR_W
		mov	w, #$FF			; input
		mov	!NIC_DATA_PORT,	w

		; put addr out on addr bus
		mov	w, NIC_CTRL_PORT
		and	w, #%11100000
		or	w, nicIOAddr
		mov	NIC_CTRL_PORT, w

		; strobe IORB pin and latch Data
		jmp	$+1
		clrb	IORB_PIN
		jmp	$+1
		jnb	IOCH_PIN, $
		mov	w, NIC_DATA_PORT
		setb	IORB_PIN

		retp

; ******************************************************************************
NICReadAgain
; Read the NIC using the same nicIOAddr as the previous call to NICRead()
; INPUT:  none
; OUTPUT: w = byte read
; ******************************************************************************
		; strobe IORB pin and latch Data
		jmp	$+1
		clrb	IORB_PIN
		jmp	$+1
		jnb	IOCH_PIN, $
		mov	w, NIC_DATA_PORT
		setb	IORB_PIN
		retp

; ******************************************************************************
NICPseudoRead
; 'Read' the NIC, but ignore Data. Must have called NICRead() or NICReadAgain()
; priorly
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; strobe IORB pin
		jmp	$+1
		clrb	IORB_PIN
		jmp	$+1
		jnb	IOCH_PIN, $
		setb	IORB_PIN
		retp

; ******************************************************************************
NICPseudoRead6
; 'Read' the NIC (6) times, but ignore Data. Must have called NICRead() or
; NICReadAgain() priorly
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		mov	w, #6
:loop		call	NICPseudoRead
		decsz	wreg
		jmp	:loop
		retp

; ******************************************************************************
NICCheckRxFrame
; Checks to see if an ethernet frame has been received
; INPUT:  none
; OUTPUT: z is cleared if there's a frame waiting, otherwise z is set
; ******************************************************************************
		_bank	NIC_BANK

		clr	nicIOAddr		; CR
		mov	w, #%01100010		; Page1, abort DMA
		call	NICWrite

		mov	nicIOAddr, #$07		; CURR
		call	NICRead
		mov	globTemp1, w

		clr	nicIOAddr		; CR
		mov	w, #%00000010		; Page0
		call	NICWrite

		mov	nicIOAddr, #$03		; BNRY
		call	NICRead
		xor	w, globTemp1		; CURR = BNRY => no packets
		retp

; ******************************************************************************
NICWaitRxFrame
; Wait for an ethernet frame to be received.
; INPUT:  none
; OUTPUT: nicCurrPktPtr = points to beginning of packet just received
;	  nicNextPktPtr = points to beginnig of next packet
;	  nicRemoteEth0-5 = source (remote) ethernet address
; ******************************************************************************
		clrb	flags2.GOT_RX_FRAME	; clear indication of prev.
						; rcvd frame

		_bank	NIC_BANK

:loop		clr	nicIOAddr		; CR
		mov	w, #%01100010		; Page1, abort DMA
		call	NICWrite

		mov	nicIOAddr, #$07		; CURR
		call	NICRead
		mov	globTemp1, w

		clr	nicIOAddr		; CR
		mov	w, #%00000010		; Page0
		call	NICWrite

		mov	nicIOAddr, #$03		; BNRY
		call	NICRead
		xor	w, globTemp1

		snz				; CURR = BNRY => no packets
		retp				; Return immediately

		setb	flags2.GOT_RX_FRAME	; indicate we got something

		clr	nicIOAddr		; CR
		mov	w, #%00011010		; Page0, packet send
		call	NICWrite

		; store current-packet pointer
		mov	nicIOAddr, #$03		; BNRY
		call	NICRead
		mov	nicCurrPktPtr, w

		mov	nicIOAddr, #$10		; RDMA

		; ignore receive status
		call	NICRead

		; store next-packet pointer
		call	NICReadAgain
		mov	nicNextPktPtr, w

		; ignore ethernet frame size
		call	NICPseudoRead
		call	NICPseudoRead

		; ignore the <destination> ethernet addr
		call	NICPseudoRead6

		; record the sender's <source> ethernet addr
		call	NICReadAgain
		mov	nicRemoteEth0, w
		call	NICReadAgain
		mov	nicRemoteEth1, w
		call	NICReadAgain
		mov	nicRemoteEth2, w
		call	NICReadAgain
		mov	nicRemoteEth3, w
		call	NICReadAgain
		mov	nicRemoteEth4, w
		call	NICReadAgain
		mov	nicRemoteEth5, w

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite

		retp

; ******************************************************************************
NICDumpRxFrame
; Discard the current received frame by advancing the receive circular buffer
; tail pointer
; INPUT:  nicNextPktPtr = next packet page
; OUTPUT: none
; ******************************************************************************
		bank	NIC_BANK

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite

		mov	nicIOAddr, #$03		; BNRY
		mov	w, nicNextPktPtr	; advance tail pointer
		call	NICWrite

		retp

; ******************************************************************************
NICInitTxFrame
; i. initialize NIC for remote-DMA writes
; ii. fills in ethernet <destination> and <source>
; INPUT:  w = starting page number of tx buffer
;	  nicRemoteEth0-5 = Destination ethernet address
; OUTPUT: none
; ******************************************************************************
		mov	globTemp1, w

		bank	NIC_BANK

		; wait for prior transmission to complete
		clr	nicIOAddr		; CR
:wait		call	NICRead
		jb	wreg.2,	:wait

		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite

		mov	nicIOAddr, #$04		; TPSR
		mov	w, globTemp1
		call	NICWrite

		mov	nicIOAddr, #$08		; RSAR0
		mov	w, #$00
		call	NICWrite
		inc	nicIOAddr		; ($09) RSAR1
		mov	w, globTemp1
		call	NICWrite

		mov	nicIOAddr, #$0A		; RBCR0
		mov	w, #$EA			; max ethernet packet size
		call	NICWrite
		inc	nicIOAddr		; ($0B) RBCR1
		mov	w, #$05
		call	NICWrite

		clr	nicIOAddr		; CR
		mov	w, #%00010010		; Page0, remote write
		call	NICWrite

		mov	nicIOAddr, #$10		; RDMA

		; <destination>
		call	NICWriteDestEth

		; <source>
		call	NICWriteSrcEth

		retp

; ******************************************************************************
NICSendTxFrame
; Once the transmit buffer on the NIC is filled, call this to tell the NIC to
; start sending
; INPUT:  {ipLengthMSB,ipLengthLSB} = length of IP frame to be transmitted
; OUTPUT: none
; ******************************************************************************
		call	@ARPCheckCache		; start ARP routine
		snb	flags3.ARP_REQ_SENT	; Continue if an ARP request
						; was not sent

		retp				; exit, ARP request was sent
						; or we are still waiting
						; for a response

; an entry point into the function to skip the ARP routines
; no code space left in this bank to elegantly check a bit
NICSendTxFrameNow
		bank	NIC_BANK

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite

		bank	IP_BANK
		mov	w, #(64-6-6-2)
		mov	w, ipLengthLSB-w
		jc	:notRunt
		mov	w, #1
		mov	w, ipLengthMSB-w
		jc	:notRunt

		bank	NIC_BANK
		mov	nicIOAddr, #$05		; TBCR0
		mov	w, #64			; min ethernet frame size
		call	NICWrite
		inc	nicIOAddr		; ($06) TBCR1
		mov	w, #0
		call	NICWrite
		jmp	:transmit

:notRunt	bank	NIC_BANK
		mov	nicIOAddr, #$05		; TBCR0
		bank	IP_BANK
		mov	w, #(6+6+2)
		add	w, ipLengthLSB
		call	NICWrite		; should not affect carry flag

		inc	nicIOAddr		; ($06) TBCR1
		bank	IP_BANK
		mov	w, ipLengthMSB
		snc
		inc	wreg
		call	NICWrite

:transmit	clr	nicIOAddr		; CR
		mov	w, #%00000110		; Page0, transmit
		call	NICWrite

		retp

; ******************************************************************************
_NICBufCopy
; Copy one part of the NIC's SRAM buffer to another part
; INPUT:  {nicCopySrcMSB,nicCopySrcLSB} = source address in NIC's SRAM
;	  {nicCopyDestMSB,nicCopyDestLSB} = Destination address in NIC's SRAM
;	  {nicCopyLenMSB,nicCopyLenLSB} = length of buffer to copy
; OUTPUT: none
; ******************************************************************************
		bank	NIC_BANK

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite

		mov	nicIOAddr, #$0B		; RBCR1
		mov	w, #0			; MSB is always zero
		call	NICWrite

		; initialize RDMA to get source byte

:loop		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite

		mov	nicIOAddr, #$08		; RSAR0
		mov	w, nicCopySrcLSB
		call	NICWrite

		inc	nicIOAddr		; ($09) RSAR1
		mov	w, nicCopySrcMSB
		call	NICWrite

		mov	nicIOAddr, #$0A		; RBCR0
		mov	w, #1			; one-byte DMA
		call	NICWrite

		clr	nicIOAddr		; CR
		mov	w, #%00001010		; Page0, remote read
		call	NICWrite

		mov	nicIOAddr, #$10		; RDMA
		call	NICRead
		mov	nicCopyTemp, w		; store source byte temporarily

		; initialize RDMA to write byte to Destination
		mov	nicIOAddr, #$08		; RSAR0
		mov	w, nicCopyDestLSB
		call	NICWrite

		inc	nicIOAddr		; ($09) RSAR1
		mov	w, nicCopyDestMSB
		call	NICWrite

		inc	nicIOAddr		; ($0A) RBCR0
		mov	w, #1			; one-byte DMA
		call	NICWrite

		clr	nicIOAddr		; CR
		mov	w, #%00010010		; Page0, remote write
		call	NICWrite

		mov	nicIOAddr, #$10		; RDMA
		mov	w, nicCopyTemp
		call	NICWrite

		; increment source and Destination pointers
		inc	nicCopySrcLSB
		snz
		inc	nicCopySrcMSB
		inc	nicCopyDestLSB
		snz
		inc	nicCopyDestMSB

		; check if source page pointer hit receive buffer ceiling
		mov	w, nicCopySrcMSB
		xor	w, #RXBUF_END
		jnz	:here
		mov	nicCopySrcMSB, #RXBUF_START

		; loop as many times as there are bytes to copy
:here		decsz	nicCopyLenLSB
		jmp	:loop
		test	nicCopyLenMSB
		snz
		retp
		dec	nicCopyLenMSB
		jmp	:loop

; ******************************************************************************
_NICBufWrite
; Writes a byte to the SRAM buffer in the NIC
; INPUT:  {nicCopySrcMSB,nicCopySrcLSB} = address in buffer memory to write to
;	  w = byte to write
; OUTPUT: none
; ******************************************************************************
		bank	NIC_BANK

		mov	nicCopyTemp, w

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA

		mov	nicIOAddr, #$08		; RSAR0
		mov	w, nicCopySrcLSB
		call	NICWrite

		inc	nicIOAddr		; ($09) RSAR1
		mov	w, nicCopySrcMSB
		call	NICWrite

		inc	nicIOAddr		; ($0A) RBCR0
		mov	w, #1			; one-byte DMA
		call	NICWrite

		inc	nicIOAddr		; ($0B) RBCR1
		mov	w, #0			; MSB is always zero
		call	NICWrite

		clr	nicIOAddr		; CR
		mov	w, #%00010010		; Page0, remote write
		call	NICWrite

		mov	nicIOAddr, #$10		; RDMA
		mov	w, nicCopyTemp
		call	NICWrite

		retp

; ******************************************************************************
_NICBufRead
; Reads a byte from the SRAM buffer in the NIC
; INPUT:  {nicCopySrcMSB,nicCopySrcLSB} = address in buffer memory to read from
; OUTPUT: w = byte read
; ******************************************************************************
		bank	NIC_BANK

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA

		mov	nicIOAddr, #$08		; RSAR0
		mov	w, nicCopySrcLSB
		call	NICWrite

		inc	nicIOAddr		; ($09) RSAR1
		mov	w, nicCopySrcMSB
		call	NICWrite

		inc	nicIOAddr		; ($0A) RBCR0
		mov	w, #1			; one-byte DMA
		call	NICWrite

		inc	nicIOAddr		; ($0B) RBCR1
		mov	w, #0			; MSB is always zero
		call	NICWrite

		clr	nicIOAddr		; CR
		mov	w, #%00001010		; Page0, remote read
		call	NICWrite

		mov	nicIOAddr, #$10		; RDMA
		call	NICRead

		retp

; ******************************************************************************
_NICBufIPAddrWr
; Writes the source and destination IP addresses to the SRAM buffer in the NIC
; INPUT:  {nicCopySrcMSB,nicCopySrcLSB} = address in buffer memory to write to
;	  myIP3-0 = <source_IP>
;	  remoteIP3-0 = <destination_IP>
; OUTPUT: none
; ******************************************************************************
		bank	NIC_BANK

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA

		mov	nicIOAddr, #$08		; RSAR0
		mov	w, nicCopySrcLSB
		call	NICWrite

		inc	nicIOAddr		; ($09) RSAR1
		mov	w, nicCopySrcMSB
		call	NICWrite

		inc	nicIOAddr		; ($0A) RBCR0
		mov	w, #(4+4)		; 8-byte DMA
		call	NICWrite

		inc	nicIOAddr		; ($0B) RBCR1
		mov	w, #0			; MSB is always zero
		call	NICWrite

		clr	nicIOAddr		; CR
		mov	w, #%00010010		; Page0, remote write
		call	NICWrite

		mov	nicIOAddr, #$10		; RDMA

		; <source_IP>
		call	NICWriteSrcIP

		; <destination_IP>
		call	NICWriteDestIP

		retp

; ******************************************************************************
_NICWriteSrcIP
; Write Source IP address to NIC's buffer using remote DMA. NIC must be pre-
; initialized for this.
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		jnb	flags.GOT_IP_ADDR, :noIP	; use IP address at noIP if
		bank	IP_BANK				; we got none from DHCP
		mov	w, myIP3
		call	NICWrite
		bank	IP_BANK
		mov	w, myIP2
		call	NICWriteAgain
		mov	w, myIP1
		call	NICWriteAgain
		mov	w, myIP0
		call	NICWriteAgain
		retp

:noIP		mov	w, #0			; 0.0.0.0
		call	NICWrite
		mov	w, #0
		call	NICWriteAgain
		call	NICWriteAgain
		call	NICWriteAgain
		retp

; ******************************************************************************
_NICWriteDestIP
; Write Destination IP address to NIC's buffer using remote DMA. NIC must be
; pre-initialized for this.
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		bank	IP_BANK
		mov	w, remoteIP3
		call	NICWrite
		bank	IP_BANK
		mov	w, remoteIP2
		call	NICWriteAgain
		bank	IP_BANK
		mov	w, remoteIP1
		call	NICWriteAgain
		bank	IP_BANK
		mov	w, remoteIP0
		call	NICWriteAgain
		retp

; ******************************************************************************
_NICWriteSrcEth
; Write Source Ethernet address to NIC's buffer using remote DMA. NIC must be
; pre-initialized for this.
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		mov	w, #SX_ETH_ADDR0
		call	NICWrite
		mov	w, #SX_ETH_ADDR1
		call	NICWriteAgain
		mov	w, #SX_ETH_ADDR2
		call	NICWriteAgain
		mov	w, #SX_ETH_ADDR3
		call	NICWriteAgain
		mov	w, #SX_ETH_ADDR4
		call	NICWriteAgain
		mov	w, #SX_ETH_ADDR5
		call	NICWriteAgain
		retp

; ******************************************************************************
_NICWriteDestEth
; Write Destination Ethernet address to NIC's buffer using remote DMA. NIC must
; be pre-initialized for this.
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		mov	w, nicRemoteEth0
		call	NICWrite
		mov	w, nicRemoteEth1
		call	NICWriteAgain
		mov	w, nicRemoteEth2
		call	NICWriteAgain
		mov	w, nicRemoteEth3
		call	NICWriteAgain
		mov	w, nicRemoteEth4
		call	NICWriteAgain
		mov	w, nicRemoteEth5
		call	NICWriteAgain
		retp

; ******************************************************************************
_NICDMAInit
; Setup the NIC's RSAR and RBCR register in preparation for remote DMA.
; INPUT:  nicCurrPktPtr = beginning of packet
; OUTPUT: none
; ******************************************************************************
		bank	NIC_BANK

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite

		; initialize DMA to <type> field in ethernet frame
		mov	nicIOAddr, #$08		; RSAR0
		mov	w, #(4+6+6)		; point to <type> field
		call	NICWrite
		inc	nicIOAddr		; ($09) RSAR1
		mov	w, nicCurrPktPtr
		call	NICWrite

		inc	nicIOAddr		; ($0A) RBCR0
		mov	w, #$FF
		call	NICWrite
		inc	nicIOAddr		; ($0B) RBCR1
		mov	w, #$0F
		call	NICWrite

		retp


	ORG	$400	; Page2

ARPSendResponse	jmp	_ARPSendResponse
ARPSendStPacket	jmp	_ARPSendStPacket
CheckIPDatagram	jmp	_CheckIPDatagram
CheckIPDestAddr	jmp	_CheckIPDestAddr
ICMPProcPktIn	jmp	_ICMPProcPktIn
Copy4Inc	jmp	_Copy4Inc

; ******************************************************************************
NICRead_2
; Shortform for calling NICRead(), which is in Page1 (This is in Page2)
; ******************************************************************************
		jmp	@NICRead

; ******************************************************************************
NICReadAgain_2
; Shortform for calling NICReadAgain(), which is in Page1 (This is in Page2)
; ******************************************************************************
		jmp	@NICReadAgain

; ******************************************************************************
NICPseudoRead_2
; Shortform for calling NICPseudoRead(), which is in Page1 (This is in Page2)
; ******************************************************************************
		jmp	@NICPseudoRead

; ******************************************************************************
NICPseudoRead6_2
; Shortform for calling NICPseudoRead(), which is in Page1 (This is in Page2)
; ******************************************************************************
		jmp	@NICPseudoRead6

; ******************************************************************************
NICWrite_2
; Shortform for calling NICWrite(), which is in Page1 (This is in Page2)
; ******************************************************************************
		jmp	@NICWrite

; ******************************************************************************
NICWriteAgain_2
; Shortform for calling NICWriteAgain(), which is in Page1 (This is in Page2)
; ******************************************************************************
		jmp	@NICWriteAgain

; ******************************************************************************
NICDumpRxFrame_2
; Shortform for calling NICDumpRxFrame(), which is in Page1 (This is in Page2)
; ******************************************************************************
		jmp	@NICDumpRxFrame

; ******************************************************************************
ARPCheckCache
; Checks if remote(destination) host IP address is in cache. If so, update
; packet Ethernet address in NIC with cache entry, else send ARP request.
; INPUT:  remoteIP0-3, host1IP0-3
; OUTPUT: none
; ******************************************************************************
		jnb	flags3.ARP_STL_TX, :cacheGo	; do not check cache
							; if stalled packet
							; to be txed
		call	ARPUpdateEthAddr	; update stalled packet's ethernet address
		mov	w, #%11111000
		and	flags3, w		; reset ARP
		retp

:cacheGo	; check if remote host IP is in cache
		bank	IP_BANK
		mov	w, remoteIP0
		bank	ARP_BANK
		xor	w, host1IP0
		jnz	:cacheNoMatch		; no match

		mov	w, host1IP1
		bank	IP_BANK
		xor	w, remoteIP1
		jnz	:cacheNoMatch		; no match

		mov	w, remoteIP2
		bank	ARP_BANK
		xor	w, host1IP2
		jnz	:cacheNoMatch		; no match

		mov	w, host1IP3
		bank	IP_BANK
		xor	w, remoteIP3
		jz	:cacheMatch		; match! remoteIP0-3 = host1IP0-3

:cacheNoMatch	setb	flags3.ARP_REQ_SENT	; indicate an ARP request is sent
		jmp	ARPSendRequest		; do an ARP request to get the
						; remote Eth address

:cacheMatch	mov	w, #%11111000
		and	flags3, w		; reset ARP
		jmp	ARPUpdateEthAddr	; update remote Eth address of
						; pending packet

; ******************************************************************************
ARPUpdateEthAddr
; Updates Eth Address of pending packet to be txed in NIC's buffer with that in
; ARP cache
; INPUT:  host1Eth0-5, stPktTxBufStart
; OUTPUT: none
; ******************************************************************************
		bank	NIC_BANK

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite_2

		mov	nicIOAddr, #$08		; RSAR0
		mov	w, #0
		call	NICWrite_2

		inc	nicIOAddr		; ($09) RSAR1
		bank	ARP_BANK
		mov	w, stPktTxBufStart	; store page no of stalled pkt
		call	NICWrite_2

		bank	NIC_BANK
		inc	nicIOAddr		; ($0A) RBCR0
		mov	w, #(6+6)		; 12-byte DMA
		call	NICWrite_2

		inc	nicIOAddr		; ($0B) RBCR1
		mov	w, #0			; MSB is always zero
		call	NICWrite_2

		clr	nicIOAddr		; CR
		mov	w, #%00010010		; Page0, remote write
		call	NICWrite_2

		mov	nicIOAddr, #$10		; RDMA

		; <destination_Eth>
		bank	ARP_BANK
		mov	w, host1Eth0
		call	NICWrite_2
		bank	ARP_BANK
		mov	w, host1Eth1
		call	NICWriteAgain_2
		mov	w, host1Eth2
		call	NICWriteAgain_2
		mov	w, host1Eth3
		call	NICWriteAgain_2
		mov	w, host1Eth4
		call	NICWriteAgain_2
		mov	w, host1Eth5
		jmp	NICWriteAgain_2

; ******************************************************************************
ARPCheckIfIs
; Checks received packet to see if it is ARP.
; Sends an ARP response if its a request.
; Updates cache if it's an ARP response.
; INPUT:  nicCurrPktPtr = points to beginning of received packet
; OUTPUT: remoteIP0-3 (:rcvdARPRequest), host1Eth0-5 (:rcvdARPResponse)
; ******************************************************************************
		clrb	flags.RX_IS_ARP

		call	@NICDMAInit

		clr	nicIOAddr		; CR
		mov	w, #%00001010		; Page0, remote read
		call	NICWrite_2

		mov	nicIOAddr, #$10		; RDMA

		; check if ethernet <type> field
		; contains ARP identifier (0x0806)
		call	NICRead_2
		xor	w, #$08
		jnz	:outtaHere
		call	NICReadAgain_2
		xor	w, #$06
		jnz	:outtaHere

		setb	flags.RX_IS_ARP		; yes, it's ARP, indicate that for
						; main loop

		; ignore <hardware_type>,<protocol_type>,<HLEN>,<PLEN>
		call	NICPseudoRead6_2

		; checks if the ARP packet received is a request or a response
		call	NICReadAgain_2
		xor	w, #$00
		jnz	:outtaHere		; not ARP at all

		call	NICReadAgain_2
		mov	globTemp1, w		; store ARP opcode
		xor	w, #$01			; check if ARP Request (0x0001)
		jz	:rcvdARPRequest		; yes, process ARP request
		mov	w, globTemp1
		xor	w, #$02			; check if ARP Response (0x0002)
		jz	:rcvdARPResponse	; yes, process ARP response
		jmp	:outtaHere		; no, not ARP at all

		; ignore <sender_HA>
:rcvdARPRequest	call	NICPseudoRead6_2

		; record the sender's IP addr (<sender_IP>)
		; will be used to reply to sender
:senderIP	bank	IP_BANK
		call	NICReadAgain_2
		mov	remoteIP3, w
		call	NICReadAgain_2
		mov	remoteIP2, w
		call	NICReadAgain_2
		mov	remoteIP1, w
		call	NICReadAgain_2
		mov	remoteIP0, w

		; ignore <target_HA>
:targetHA	call	NICPseudoRead6_2

		; check if <target_IP> is me
		mov	fsr, #myIP3
		call	ARPCompare4
		jnz	:outtaHere

		; so it's for me!
		call	ARPSendResponse
		jmp	NICDumpRxFrame_2	; we're done with this packet, dump it

:rcvdARPResponse
		; <sender_HA>
		; record sender's Eth address in ARP cache
		mov	fsr, #host1Eth0
		mov	globTemp1, #6
:ethLoop	call	NICReadAgain_2
		mov	indf, w
		inc	fsr
		decsz	globTemp1
		jmp	:ethLoop

		; <sender_IP>
		; check if sender's IP corrresponds to IP address in ARP cache
		mov	fsr, #host1IP3
		call	ARPCompare4
		jz	:ipAddrResolved

		; whoops, sender doesn't correspond to who we're trying to resolve!
		;   if we're waiting for an ARP response (no problem here)
		jb	flags3.ARP_REQ_SENT, :outtaHere
		;   otherwise, we need to invalidate the now corrupted ARP cache
		clr	host1IP3
		clr	host1IP1
		clr	host1IP2
		clr	host1IP0
		jmp	:outtaHere

:ipAddrResolved	setb	flags3.ARP_RSP_RCVD	; indicate we got a successfull ARP response
		setb	flags3.ARP_STL_TX	; transmit the stalled packet now

:outtaHere	snb	flags.RX_IS_ARP		; check if packet was ARP
		call	NICDumpRxFrame_2	; if it was ARP, we dump it; otherwise, don't touch it
		retp

; ******************************************************************************
ARPCompare4
; Compares Data from NICReadAgain() against a 4-byte word store consequtively
; in the SX's Data memory
; INPUT:  fsr = points to beginning of 4-byte word to compare against
; OUTPUT: z: 1 = match, 0 = not match
; ******************************************************************************
		mov	globTemp1, #4
:loop		call	NICReadAgain_2
		xor	w, indf
		sz
		retp				; mis-match
		inc	fsr
		decsz	globTemp1
		jmp	:loop
		stz
		retp

; ******************************************************************************
ARPSendCommon1
; Helper function for ARPSendRequest and ARPSendResponse
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; <type> = 0x0806
		mov	w, #$08
		call	NICWriteAgain_2
		mov	w, #$06
		call	NICWriteAgain_2

		; <hardware_type> = 0x0001
		mov	w, #$00
		call	NICWriteAgain_2
		mov	w, #$01
		call	NICWriteAgain_2

		; <protocol_type> = 0x0800
		mov	w, #$08
		call	NICWriteAgain_2
		mov	w, #$00
		call	NICWriteAgain_2

		; <HLEN> = 0x06
		mov	w, #$06
		call	NICWriteAgain_2

		; <PLEN> = 0x04
		mov	w, #$04
		jmp	NICWriteAgain_2

; ******************************************************************************
ARPSendCommon2
; Helper function for ARPSendRequest and ARPSendResponse
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; <sender_HA>
		call	@NICWriteSrcEth

		; <sender_IP>
		call	@NICWriteSrcIP

		; <target_HA>
		call	@NICWriteDestEth

		; <target_IP>
		call	@NICWriteDestIP

		; whew! the ethernet frame is now complete, get ready to send ..
		bank	NIC_BANK		; NICWriteDestIP changes bank
		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite_2

		mov	nicIOAddr, #$05		; TBCR0
		mov	w, #$40			; min ethernet packet size
		call	NICWrite_2
		inc	nicIOAddr		; ($06) TBCR1
		mov	w, #$00
		call	NICWrite_2

		clr	nicIOAddr		; CR
		mov	w, #%00000110		; transmit
		jmp	NICWrite_2

; ******************************************************************************
ARPSendRequest
; Stores remote IP address for which pending packet is intended in ARP cache and
; sends an ARP Request
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		bank	IP_BANK
		mov	w, remoteIP3		; store IP address of target in ARP cache
		bank	ARP_BANK
		mov	host1IP3, w
		bank	IP_BANK
		mov	w, remoteIP2
		bank	ARP_BANK
		mov	host1IP2, w
		bank	IP_BANK
		mov	w, remoteIP1
		bank	ARP_BANK
		mov	host1IP1, w
		bank	IP_BANK
		mov	w, remoteIP0
		bank	ARP_BANK
		mov	host1IP0, w

		bank	NIC_BANK
		mov	w, #$FF
		mov	nicRemoteEth0, w	; setup broadcast Ethernet address
		mov	nicRemoteEth1, w
		mov	nicRemoteEth2, w
		mov	nicRemoteEth3, w
		mov	nicRemoteEth4, w
		mov	nicRemoteEth5, w

		mov	w, #TXBUF4_START	; point to ARP transmit buffer
		call	@NICInitTxFrame

		call	ARPSendCommon1

		; <operation> = 0x0001 , ARP request opcode
		mov	w, #$00
		call	NICWriteAgain_2
		mov	w, #$01
		call	NICWriteAgain_2

		call	ARPSendCommon2

		bank	TIMER_BANK		; initialise the APR timeout timer
		clr	arpTimerMSB
		clr	arpTimerLSB

		retp

; ******************************************************************************
_ARPSendResponse
; Send an ARP Response in reply to a ARP request.
; INPUT: none
; OUTPUT: none
; ******************************************************************************
		mov	w, #TXBUF4_START	; point to ARP transmit buffer
		call	@NICInitTxFrame

		call	ARPSendCommon1

		; <operation> = 0x0002
		mov	w, #$00
		call	NICWriteAgain_2
		mov	w, #$02
		call	NICWriteAgain_2

		jmp	ARPSendCommon2

; ******************************************************************************
_ARPSendStPacket
; Sends the ARP stalled packet if any and also check if a timeout on waiting for
; an ARP response occured. If timeout, clear ARP cache
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		sb	flags3.ARP_REQ_SENT	; check if we are waiting for
						; an ARP response
		retp				; no, nothing to Do here

		; if no ARP response rcvd, check if timed out on waiting for it
		jnb	flags3.ARP_STL_TX, :checkARPTimeout

		; yes we have rcvd a response we've been waiting for
		; now we can send the stalled packet
		mov	w, #%11111000
		and	flags3,	w		; reset ARP

		; re-initialize the NIC's TPSR
		bank	NIC_BANK
		clr	nicIOAddr		; CR
:wait		call	NICRead_2
		jb	wreg.2,	:wait		; wait for prior transmission
						; to complete
		mov	w, #%00100010		; Page0, abort DMA
		call	NICWrite_2
		mov	nicIOAddr, #$04		; TPSR
		bank	ARP_BANK
		mov	w, stPktTxBufStart	; load stalled packet's
						; address pointer
		call	NICWrite_2

		; read the NIC's transmit buffer to find out the IP <length>
		; so that we can re-initialize the NIC's TBCR
		bank	ARP_BANK
		mov	w, stPktTxBufStart
		bank	NIC_BANK
		mov	nicCopySrcMSB, w
		mov	nicCopySrcLSB, #(6+6+2+2)	; IP <length> (MSB)
		call	@NICBufRead
		bank	IP_BANK
		mov	ipLengthMSB, w
		bank	NIC_BANK
		inc	nicCopySrcLSB		; IP <length> (LSB)
		call	@NICBufRead
		bank	IP_BANK
		mov	ipLengthLSB, w
		jmp	@NICSendTxFrame		; transmit the stalled ethernet frame

:checkARPTimeout
		bank	TIMER_BANK
		csae	arpTimerMSB, #ARP_TIMEOUT	; has the timer expired?
		retp					; no, just return

		mov	w, #%11111000
		and	flags3,	w			; yes, reset ARP flags
		; Clear the ARP cache, since it acted as a temporary storage
		; of the requested IP address. If we Do not clear the cache now,
		; the next re-transmit routine will find a false match in the
		; ARP cache.
		bank	ARP_BANK
		clr	host1IP3
		clr	host1IP2
		clr	host1IP1
		clr	host1IP0
		retp

; ******************************************************************************
_CheckIPDatagram
; Checks to see if received ethernet frame contains an IP Datagram. If not, the
; frame	will be discarded since this stack Doesn't Deal with any other kinds of
; Data-link layer protocol.
; INPUT:  nicCurrPktPtr = points to beginning of received packet
; OUTPUT: none
; ******************************************************************************
		clrb	flags.RX_IS_IP_BCST	; clear broadcast IP indication

CHKIP_MASK = ~((1<<RX_IS_ICMP)|(1<<RX_IS_UDP)|(1<<RX_IS_TCP)|(1<<RX_IS_IP_BCST))
		mov	w, #CHKIP_MASK
		and	flags, w

		call	@NICDMAInit

		clr	nicIOAddr		; CR
		mov	w, #%00001010		; Page0, remote read
		call	NICWrite_2

		mov	nicIOAddr, #$10		; RDMA

		; check if ethernet <type> field contains IP identifier (0x0800)
		call	NICRead_2
		xor	w, #$08
		jnz	:outtaHere
		call	NICReadAgain_2
		xor	w, #$00
		jnz	:outtaHere

		; check <version> and <HLEN>
		call	NICReadAgain_2
		xor	w, #$45			; version = 4, header length = 5
		jnz	:outtaHere

		; ignore <service_type>
		call	NICPseudoRead_2

		; record <total_length>
		call	NICReadAgain_2
		bank	IP_BANK
		mov	ipLengthMSB, w
		call	NICReadAgain_2
		mov	ipLengthLSB, w
		; adjust {ipLengthMSB,ipLengthLSB} to reflect number of
		; Data bytes
		sub	ipLengthLSB, #20
		sc
		dec	ipLengthMSB

		; ignore <identification>
	REPT	2
		call	NICPseudoRead_2
	ENDR

		; check against IP packet fragmentation
		call	NICReadAgain_2
		jb	wreg.5,	:outtaHere	; <flags>
		call	NICReadAgain_2
		xor	w, #0			; <fragment_offset>
		jnz	:outtaHere

		; ignore <time_to_live>
		call	NICPseudoRead_2

		; record <protocol>
		call	NICReadAgain_2
		mov	ipProtocol, w

		; ignore <header_checksum>
	REPT	2
		call	NICPseudoRead_2
	ENDR

		; record <source_IP>
:srcIP		bank	IP_BANK
		call	NICReadAgain_2
		mov	remoteIP3, w
		call	NICReadAgain_2
		mov	remoteIP2, w
		call	NICReadAgain_2
		mov	remoteIP1, w
		call	NICReadAgain_2
		mov	remoteIP0, w

		; check <destination_IP>
:destIP		clr	globTemp2
		mov	w, myIP3
		call	CheckIPDestAddr
		jnz	:outtaHere
		mov	w, myIP2
		call	CheckIPDestAddr
		jnz	:outtaHere
		mov	w, myIP1
		call	CheckIPDestAddr
		jnz	:outtaHere
		mov	w, myIP0
		call	CheckIPDestAddr
		jnz	:outtaHere
		xor	globTemp2, #4
		snz
		setb	flags.RX_IS_IP_BCST	; IP broadcast addr Detected

		; ok! Determine which higher-level protocol
		mov	w, #1			; ICMP
		xor	w, ipProtocol
		snz
		setb	flags.RX_IS_ICMP
		mov	w, #17			; UDP
		xor	w, ipProtocol
		snz
		setb	flags.RX_IS_UDP
		mov	w, #6			; TCP
		xor	w, ipProtocol
		snz
		setb	flags.RX_IS_TCP
		retp

:outtaHere	jmp	NICDumpRxFrame_2	; if it ain't IP, forget it!

; ******************************************************************************
_CheckIPDestAddr
; Helper function for CheckIPDatagram
; Check for a match of the IP <destination_IP> field
; INPUT:  w = byte of IP to check against
; OUTPUT: z = set if match
;	  globTemp2 = incremented if matched against 0xFF
; ******************************************************************************
		mov	globTemp1, w
		call	NICReadAgain_2
		xor	globTemp1, w
		snz
		retp
		xor	w, #$FF			; IP broadcast addr
		sz
		retp
		inc	globTemp2
		stz
		retp

; ******************************************************************************
_ICMPProcPktIn
; Process ICMP message. Only Echo Request ICMP messages are handled. All others
; are ignored. If Echo Request message is Detected, this will generate the echo
; reply.
; INPUT:  nicCurrPktPtr = points to beginning of received packet
; OUTPUT: none
; ******************************************************************************
		; check <type>
		call	NICReadAgain_2
		xor	w, #$08				; echo-request
		jnz	:outtaHere

		bank	IP_BANK
		add	ipLengthLSB, #(2+20)
		snc
		inc	ipLengthMSB

		bank	NIC_BANK
		mov	nicCopySrcMSB, nicCurrPktPtr	; point to receive
							; buffer
		mov	nicCopySrcLSB, #(4+6+6)		; don't copy NIC header
							; , eth src & Destn

		mov	nicCopyDestMSB, #TXBUF1_START	; point to transmit
							; buffer
		mov	nicCopyDestLSB, #(6+6)

		bank	IP_BANK
		mov	w, ipLengthMSB
		bank	NIC_BANK
		mov	nicCopyLenMSB, w
		bank	IP_BANK
		mov	w, ipLengthLSB
		bank	NIC_BANK
		mov	nicCopyLenLSB, w

		mov	w, #TXBUF1_START	; point to transmit buffer

		bank	ARP_BANK
		mov	stPktTxBufStart, w	; Store ICMP packet start address
		bank	NIC_BANK

		call	@NICInitTxFrame
		call	@NICBufCopy

		; change ICMP <type> to echo reply (0)
		mov	nicCopySrcMSB, #TXBUF1_START	; point to transmit
							; buffer
		mov	nicCopySrcLSB, #(6+6+2+20)	; point to ICMP <type>
		mov	w, #$00
		call	@NICBufWrite

		; generate ICMP <checksum>
		mov	nicCopySrcMSB, #TXBUF1_START	; point to transmit
							; buffer
		bank	IP_BANK
		mov	w, ipLengthMSB
		bank	NIC_BANK
		mov	nicCopyLenMSB, w
		bank	IP_BANK
		mov	w, ipLengthLSB
		bank	NIC_BANK
		mov	nicCopyLenLSB, w
		sub	nicCopyLenLSB, #(2+20+4)
		sc
		dec	nicCopyLenMSB
		call	@ICMPGenCheckSum

		; adjust IP <source_IP> and <destination_IP>
		mov	nicCopySrcMSB, #TXBUF1_START	; point to transmit
							; buffer
		mov	nicCopySrcLSB, #(6+6+2+12)	; point to IP <source_IP>
		call	@NICBufIPAddrWr

		bank	IP_BANK
		sub	ipLengthLSB, #2
		sc
		dec	ipLengthMSB
		call	@NICSendTxFrame

:outtaHere	jmp	NICDumpRxFrame_2

; ******************************************************************************
_Copy4Inc
; Copies 4 variables incrementally by copying from var pointed to by globTemp3
; to variable pointed to by globTemp1
; INPUT:  globTemp1,3 points to variables
; OUTPUT: none
; ******************************************************************************
		_bank	IP_BANK
		mov	counter1, #4	; load the counter
:loop
		mov	fsr, globTemp3	; move tcp pointer to fsr
		mov	w, indf		; move tcp var in w
		mov	globTemp2, w	; store tcp var in glob
		mov	fsr, globTemp1	; move tcb pointer to fsr
		mov	indf, globTemp2	; overwrite tcb var with tcp var
		inc	globTemp1	; increment pointer
		inc	globTemp3	; increment pointer

		_bank	IP_BANK		; check loop counter until finished
		dec	counter1
		sz
		jmp	:loop

		retp
;WE ARE STARTING TO FIT THINGS ANYWHERE THAT WE CAN RIGHT NOW! LOL
GET_SILO_NUMBER
	STC						;SAID TO ADD IT TO THE CODE TO AVOID STRANGE RESULT.
	SUB	ASCII,#48				;MAKE AN ACTUAL NUMBER OUT OF THIS.
	MOV	SILO,ASCII				;MAKE SILOINC EQUAL THE ACTUAL NUMBER.
	JMP	@RXDONE1


	ORG	$600	; Page3

; ******************************************************************************
NICWrite_3
; Shortform for calling NICWrite(), which is in Page1 (This is in Page3)
; ******************************************************************************
		jmp	@NICWrite

; ******************************************************************************
NICWriteAgain_3
; Shortform for calling NICWriteAgain(), which is in Page1 (This is in Page3)
; ******************************************************************************
		jmp	@NICWriteAgain

; ******************************************************************************
ICMPGenCheckSum
; Goes through the ICMP message stored in the NIC's SRAM buffer and computes
; the ICMP message checksum.
; INPUT:  nicCopySrcMSB = transmit buffer page
;	  {nicCopyLenMSB,nicCopyLenLSB} = (length of ICMP message - 4)
; OUTPUT: {ipCheckSumMSB,ipCheckSumLSB} = new checksum value
; ******************************************************************************
		call	IPCheckSumInit

		bank	NIC_BANK

		mov	nicCopyTemp, nicCopySrcMSB

		clr	nicIOAddr		; CR
		mov	w, #%00100010		; Page0, abort DMA

		mov	nicIOAddr, #$08		; RSAR0
		mov	w, #(6+6+2+20+4)	; point to ICMP <identifier>
		call	NICWrite_3

		inc	nicIOAddr		; ($09) RSAR1
		mov	w, nicCopySrcMSB
		call	NICWrite_3

		inc	nicIOAddr		; ($0A) RBCR0
		mov	w, nicCopyLenLSB
		call	NICWrite_3

		inc	nicIOAddr		; ($0B) RBCR1
		mov	w, nicCopyLenMSB
		call	NICWrite_3

		clr	nicIOAddr		; CR
		mov	w, #%00001010		; Page0, remote read
		call	NICWrite_3

		mov	nicIOAddr, #$10		; RDMA

		; configure Data bus for input
		_mode	DIR_W
		mov	w, #$FF			; input
		mov	!NIC_DATA_PORT,	w

		; put addr out on addr bus
		mov	w, NIC_CTRL_PORT
		and	w, #%11100000
		or	w, nicIOAddr
		mov	NIC_CTRL_PORT, w

		inc	nicCopyLenMSB		; in order to loop easier later

:loop		call	@NICReadAgain
		call	IPCheckSumAcc
		bank	NIC_BANK
		decsz	nicCopyLenLSB
		jmp	:loop
		decsz	nicCopyLenMSB
		jmp	:loop

		mov	nicCopySrcMSB, nicCopyTemp
		mov	nicCopySrcLSB, #(6+6+2+20+2)
		bank	IP_BANK
		mov	w, /ipCheckSumMSB
		call	@NICBufWrite
		inc	nicCopySrcLSB
		bank	IP_BANK
		mov	w, /ipCheckSumLSB
		call	@NICBufWrite
		retp

; ******************************************************************************
IPCheckSumInit
; Initializes the IP checksum routine.
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		bank	IP_BANK
		clr	ipCheckSumMSB
		clr	ipCheckSumLSB
		clrb	flags.IP_CHKSUM_LSB	; next byte is MSB
		retp

; ******************************************************************************
IPCheckSumAcc
; Accumulate the IP checksum value by adding the next 16-bit number
; IP header checksum (also used to compute ICMP checksum) is computed by Doing
; the one's complement of the one's complement sum of the 16-bit numbers in the
; header.
; INPUT:  w = byte to accumulate
;	  flags.IP_CHKSUM_LSB = set if processing LSB, clear if processing MSB
; OUTPUT: {ipCheckSumMSB,ipCheckSumLSB} = new checksum value
; ******************************************************************************
		bank	IP_BANK

		jnb	flags.IP_CHKSUM_LSB, :msb	; are we processing an MSB?

:lsb		add	ipCheckSumLSB, w	; add it to the checksum
		sc				; was there a carry?
		jmp	:done
		inc	ipCheckSumMSB		; yes
		snz
		inc	ipCheckSumLSB
		jmp	:done

:msb		add	ipCheckSumMSB, w	; add it to the checksum
		sc				; was there a carry?
		jmp	:done
		inc	ipCheckSumLSB		; yes, this time it is added
						; to the LSB
		snz
		inc	ipCheckSumMSB

:done		xor	flags, #(1<<IP_CHKSUM_LSB)
		retp

; ******************************************************************************
IPGenCheckSum
; Generate the IP header checksum
; INPUT:  {ipLengthMSB,ipLengthLSB} = IP <total_length>
;	  {ipIdentMSB,ipIdentLSB} = IP <identification>
;	  ipProtocol = 1(ICMP)/ 6(TCP)/ 17(UDP)
; OUTPUT: {ipCheckSumMSB,ipCheckSumLSB} = new checksum value
; ******************************************************************************
		bank	IP_BANK

		call	IPCheckSumInit

		mov	w, #$45			; Version 4, 5x 32 bit words in IP header
		call	IPCheckSumAcc
		mov	w, #$00
		call	IPCheckSumAcc

		mov	w, ipLengthMSB
		call	IPCheckSumAcc
		mov	w, ipLengthLSB
		call	IPCheckSumAcc

		mov	w, ipIdentMSB
		call	IPCheckSumAcc
		mov	w, ipIdentLSB
		call	IPCheckSumAcc

		mov	w, #%01000000		; don't fragment
		call	IPCheckSumAcc
		mov	w, #0
		call	IPCheckSumAcc

		mov	w, #IP_TTL
		call	IPCheckSumAcc
		mov	w, ipProtocol
		call	IPCheckSumAcc

		jnb	flags.GOT_IP_ADDR, :remoteIP	; IP = 0.0.0.0 if no IP

		mov	w, myIP3
		call	IPCheckSumAcc
		mov	w, myIP2
		call	IPCheckSumAcc
		mov	w, myIP1
		call	IPCheckSumAcc
		mov	w, myIP0
		call	IPCheckSumAcc

		; check if this is a tcp packet being constructed and use
		; the remoteIP address of the correct socket.
		; we can only respond to hosts Defined in the tcp sockets
		; foreign incoming packets are not responded to by sending
		; a reset since this will need another TCB, they are flat-out
		; ignored. The foreign remote host will eventually give up .
:remoteIP	mov	w, ipProtocol
		xor	w, #6		; is it tcp?
		jnz	:skipSocketCpy	; no, Don't use remoteIP in tcp sockets

		; check which is the current tcp connection
		mov	globTemp1, #remoteIP3		; set source pointer
		sb	flags2.TCP_SOCK
		mov	globTemp3, #sock1RemoteIP3	; destination pointer
		snb	flags2.TCP_SOCK
		mov	globTemp3, #sock2RemoteIP3	; destination pointer

		call	@Copy4Inc	; copy sockRemoteIP into remoteIP

:skipSocketCpy	_bank	IP_BANK		; accumulate checksum with remoteIP
		mov	w, remoteIP3
		call	IPCheckSumAcc
		mov	w, remoteIP2
		call	IPCheckSumAcc
		mov	w, remoteIP1
		call	IPCheckSumAcc
		mov	w, remoteIP0
		call	IPCheckSumAcc

		retp

; ******************************************************************************
IPStartPktOut
; Starts an outgoing IP packet by constructing the IP packet header
; INPUT:  {ipLengthMSB,ipLengthLSB} = IP <total_length>
;	  {ipIdentMSB,ipIdentLSB} = IP <identification>
;	  ipProtocol = 1(ICMP)/ 6(TCP)/ 17(UDP)
;	  {ipCheckSumMSB,ipCheckSumLSB} = IP <header_checksum>
; OUTPUT: none
; ******************************************************************************
		bank	IP_BANK
		mov	w, #6			; is it tcp?
		xor	w, ipProtocol
		jz	:useTcpBuf		; yes

		mov	w, #TXBUF1_START	; no, Default tx buffer is TXBUF1
		jmp	:contIpStartP

:useTcpBuf	sb	flags2.TCP_SOCK		; point to correct tcp conn.
						; tx buffer
		mov	w, #TXBUF2_START	; tcp connection1 tx buffer
		snb	flags2.TCP_SOCK
		mov	w, #TXBUF3_START	; tcp connection2 tx buffer

:contIpStartP	bank	ARP_BANK
		sb	flags3.ARP_REQ_SENT	; check if a prev packet
						; is stalled
		mov	stPktTxBufStart, w	; no, store new address pointer
						; to new packet
		call	@NICInitTxFrame

		; <type> = 0x0800
		mov	w, #$08
		call	NICWrite_3
		mov	w, #$00
		call	NICWriteAgain_3

		; <version> = 4, <HLEN> = 5
		mov	w, #$45
		call	NICWriteAgain_3

		; <service_type>
		mov	w, #$00			; normal precedence, D=T=R=0
		call	NICWriteAgain_3

		; <total_length>
		bank	IP_BANK
		mov	w, ipLengthMSB
		call	NICWriteAgain_3
		mov	w, ipLengthLSB
		call	NICWriteAgain_3

		; <identification>
		mov	w, ipIdentMSB
		call	NICWriteAgain_3
		mov	w, ipIdentLSB
		call	NICWriteAgain_3

		; <flags>, <fragment_offset>
		mov	w, #%01000000		; do not fragment
		call	NICWriteAgain_3
		mov	w, #0			; offset = 0
		call	NICWriteAgain_3

		; <time_to_live>
		mov	w, #IP_TTL
		call	NICWriteAgain_3

		; <protocol>
		mov	w, ipProtocol
		call	NICWriteAgain_3

		; <header_checksum>
		mov	w, /ipCheckSumMSB
		call	NICWriteAgain_3
		mov	w, /ipCheckSumLSB
		call	NICWriteAgain_3

		; <source_IP>
		call	@NICWriteSrcIP

		; <destination_IP>
		call	@NICWriteDestIP

		retp

; ******************************************************************************
TCPAppPassiveOpen
; Do a passive open. i.e. listen for connections on a given port.
; [TCP API Function]
; INPUT:  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP port to listen on
; OUTPUT: none
; ******************************************************************************
		_bank	TCP_BANK
		mov	tcp2State, #TCP_ST_LISTEN
		clr	tcp2UnAckMSB
		clr	tcp2UnAckLSB
		retp

; ******************************************************************************
TCPAppActiveOpen
; Do a active open. i.e. initiate a connect to a remote TCP.
; [TCP API Function]
; INPUT:  {remoteIP0-3} = Destination IP addr
;	  {tcbLocalPortMSB,tcbLocalPortLSB} = local TCP port
;	  {tcbRemotePortMSB,tcbRemotePortLSB} = remote TCP port
; OUTPUT: none
; ******************************************************************************
		_bank	TCP_BANK
		clr	tcp1UnAckMSB
		clr	tcp1UnAckLSB
		mov	tcp1State, #TCP_ST_SYNSENT
		bank	TCB1_BANK
		mov	tcb1Flags, #(1<<TCP_FLAG_SYN)
		jmp	@TCPSendSyn

; ******************************************************************************
TCPAppClose
; Force the current connection to close
; [TCP API Function]
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; check which tcp connection to close
		_bank	TCP_BANK
		jb	flags2.TCP_SOCK, :finwaitSock2

		; close tcp connection1
		mov	tcp1State, #TCP_ST_FINWAIT1
		clr	tcp1UnAckMSB
		clr	tcp1UnAckLSB
		jmp	:contAppClose

		; close tcp connection2
:finwaitSock2	mov	tcp2State, #TCP_ST_FINWAIT1
		clr	tcp2UnAckMSB
		clr	tcp2UnAckLSB

		; common tcp close code
:contAppClose	mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		call	@SetTCBPointer
		mov	indf, #((1<<TCP_FLAG_FIN)|(1<<TCP_FLAG_ACK))
		jmp	@TCPSendEmptyPkt

; ******************************************************************************
TCPProcPktIn
; Process a received TCP packet. This function implements the TCP state machine
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		call	@TCPRxHeader		; receive the header
		snz				; is the packet OK?
		retp				; no, return

		; check if incoming packet is for tcp conn. 1 or 2
		bank	TCP_BANK
		jb	flags2.TCP_SOCK, :isTcp2

		; check the special states for tcp connection1
		cje	tcp1State, #TCP_ST_CLOSED, :CLOSED
		cje	tcp1State, #TCP_ST_LISTEN, :LISTEN
		cje	tcp1State, #TCP_ST_SYNSENT, :SYNSENT
		cje	tcp1State, #TCP_ST_FINWAIT1, :FINWAIT1
		cje	tcp1State, #TCP_ST_FINWAIT2, :FINWAIT2
		cje	tcp1State, #TCP_ST_LASTACK, :LASTACK
		jmp	:contProc

		; check the special states for tcp connection2
:isTcp2		cje	tcp2State, #TCP_ST_CLOSED, :CLOSED
		cje	tcp2State, #TCP_ST_LISTEN, :LISTEN
		cje	tcp2State, #TCP_ST_SYNSENT, :SYNSENT
		cje	tcp2State, #TCP_ST_FINWAIT1, :FINWAIT1
		cje	tcp2State, #TCP_ST_FINWAIT2, :FINWAIT2
		cje	tcp2State, #TCP_ST_LASTACK, :LASTACK

:contProc	call	@TCPCmpNxtSeq		; check if RCV.NXT == SEG.SEQ
		sz				; are they equal?
		jmp	@TCPSendAck		; no, send an ACK and Drop packet

		; check the flags
		mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		call	@SetTCBPointer		; point to tcp conn's TCB

		snb	indf.TCP_FLAG_RST	; is the reset flag set?
		jmp	:gotoClosed		; yes, Drop packet and
						; close the connection

		snb	indf.TCP_FLAG_SYN	; is the SYN bit set?
		jmp	@TCPSendReset		; yes, Drop the packet and
						; send a reset

		sb	indf.TCP_FLAG_ACK	; is the ACK bit set?
		jmp	@NICDumpRxFrame		; no, Drop the packet

		; we only accept ACKs of complete packets.
		; Assume the ACK is for our last packet
		mov	w, #TCP_ST_ESTABED	; indicate tcp conn established
		bank	TCP_BANK
		sb	flags2.TCP_SOCK		; indicate tcp state to correct
		mov	tcp1State, w		; tcp conn. state variable
		snb	flags2.TCP_SOCK
		mov	tcp2State, w

		; if we were in Syn-received then need to send an ACK
		; check if for tcp1 or 2
		jb	flags2.TCP_SOCK, :tcp2AckCheck

		;tcp1
		test	tcp1UnAckLSB
		sz
		jmp	:outstanding
		test	tcp1UnAckMSB
		snz
		jmp	:noOutstanding
		jmp	:outstanding

		; tcp2
:tcp2AckCheck	test	tcp2UnAckLSB
		sz
		jmp	:outstanding
		test	tcp2UnAckMSB
		snz
		jmp	:noOutstanding
		jmp	:outstanding

:outstanding	call	@TCPAppTxDone		; tell the application it was ACKed
		_bank	TCP_BANK		; _bank cus we called TCPAppTxDone priorly

		; check if for tcp1 or 2
		jb	flags2.TCP_SOCK, :clrTcpUnack2
		clr	tcp1UnAckLSB		; there should be no Data outstanding now
		clr	tcp1UnAckMSB
		jmp	:noOutstanding

:clrTcpUnack2	clr	tcp2UnAckLSB		; there should be no Data outstanding now
		clr	tcp2UnAckMSB

:noOutstanding	;	Does the packet contain Data? (Determine this from the length)
		test	tcpLengthMSB
		jnz	:packetHasData		; MSB is not zero
		test	tcpLengthLSB		; MSB is zero
		jz	:noData			; MSB = LSB = 0

:packetHasData	call	@TCPAppRxBytes	; inform app how many bytes available
		_bank	TCP_BANK
		inc	tcpLengthMSB
:processData	call	@NICReadAgain	; receive a byte
		call	@TCPAppRxData	; pass the byte to the application
		_bank	TCP_BANK	; _bank cus we called TCPAppRxData
					; priorly
		decsz	tcpLengthLSB
		jmp	:processData
		decsz	tcpLengthMSB
		jmp	:processData
		inc	tcpLengthLSB	; indicate for later there was Data
					; received

:noData		call	@TCPAckUpdate
		; send an ACK packet
		bank	TCP_BANK
		test	tcpLengthLSB	; was Data received?
		jz	:checkFIN	; no, it was an ACK packet. Just return
		call	@TCPAppRxDone	; indicate the packet was OK to the app

		_bank	TCP_BANK	; _bank cus we called TCPAppRxDone
					; priorly
		jb	tcpRxFlags.TCP_FLAG_FIN, :doClose	; if FIN bit set,
								; close the conn.
		call	@NICDumpRxFrame
		jmp	@TCPSendAck

:checkFIN	bank	TCP_BANK
		jb	tcpRxFlags.TCP_FLAG_FIN, :doClose	; is the FIN bit set?
		jmp	@NICDumpRxFrame

:doClose	call	@NICDumpRxFrame
		call	@TCPIncRcvNxt		; ACK the FIN
		mov	w, #TCP_ST_LASTACK	; change state
		bank	TCP_BANK
		sb	flags2.TCP_SOCK
		mov	tcp1State, w		; indicate tcp conn state to tcp conn
		snb	flags2.TCP_SOCK		; state variable
		mov	tcp2State, w
		jmp	@TCPSendFin

:gotoClosed	mov	w, #TCP_ST_CLOSED	; go to the closed state
		bank	TCP_BANK		; indicate tcp closed conn state to
		sb	flags2.TCP_SOCK		; correct tcp conn state variable
		mov	tcp1State, w
		snb	flags2.TCP_SOCK
		mov	tcp2State, w
		jmp	@NICDumpRxFrame		; discard received packet

:FINWAIT1	call	@NICDumpRxFrame
		bank	TCP_BANK
		sb	tcpRxFlags.TCP_FLAG_ACK	; check for ACK of FIN
		retp
		mov	w, #TCP_ST_FINWAIT2	; rcved ACK of FIN
		sb	flags2.TCP_SOCK		; indicate tcp finwait2 conn state to
		mov	tcp1State, w		; correct tcp conn state variable
		snb	flags2.TCP_SOCK
		mov	tcp2State, w
		retp

:FINWAIT2	call	@NICDumpRxFrame
		bank	TCP_BANK
		sb	tcpRxFlags.TCP_FLAG_FIN	; check for FIN
		retp
		mov	w, #TCP_ST_CLOSED	; rcved FIN
		sb	flags2.TCP_SOCK
		mov	tcp1State, w
		snb	flags2.TCP_SOCK
		mov	tcp2State, w
		call	@TCPIncRcvNxt		; ACK the FIN
		jmp	@TCPSendAck

:LASTACK	; ignore the packet
		; should check the packet is actually an ACK
		mov	w, #TCP_ST_CLOSED	; go to the closed state

		jb	flags2.TCP_SOCK, :lastackTcp2	; checkk which tcp conn
							; is current

		mov	tcp1State, w
		call	@DeleteSocket1		; delete the tcp conn. socket
		jmp	:dumpy

:lastackTcp2	mov	tcp2State, w
		call	@DeleteSocket2		; delete the tcp conn. socket

:dumpy		_bank	NIC_BANK		; needed for NICDumpRxFrame, we came from
						; an upper bank
		jmp	@NICDumpRxFrame

:CLOSED		call	@NICDumpRxFrame
		jmp	@TCPSendReset		; we shouldn't receive packets
						; while closed

:LISTEN		call	@NICDumpRxFrame		; discard received packet
		jb	flags2.TCP_SOCK, :listen2Check

		bank	TCB1_BANK
		snb	tcb1Flags.TCP_FLAG_RST	; check for an RST
		retp				; ignore a packet with RST
		snb	tcb1Flags.TCP_FLAG_ACK	; check for an ACK
		jmp	@TCPSendReset		; bad ACK, send a RST
		jmp	:contListen

:listen2Check	bank	TCB2_BANK
		snb	tcb2Flags.TCP_FLAG_RST	; check for an RST
		retp				; ignore a packet with RST
		snb	tcb2Flags.TCP_FLAG_ACK	; check for an ACK
		jmp	@TCPSendReset		; bad ACK, send a RST

:contListen	call	@TCPCopySeqToNxt
		call	@TCPSendSynAck
		bank	TCP_BANK
		mov	w, #TCP_ST_SYNRCVED	; change state
		sb	flags2.TCP_SOCK
		mov	tcp1State, w
		snb	flags2.TCP_SOCK
		mov	tcp2State, w
		retp

:SYNSENT	call	@NICDumpRxFrame
		jb	flags2.TCP_SOCK, :synsentCheck2

		bank	TCB1_BANK
		jnb	tcb1Flags.TCP_FLAG_ACK,	:noAck	; is the ACK bit set?
		jb	tcb1Flags.TCP_FLAG_RST,	:rst	; is the reset bit set?
		jnb	tcb1Flags.TCP_FLAG_SYN,	:noAck	; if SYN bit not set,
							; ignore packet
		jmp	:contSynsent

:synsentCheck2	bank	TCB2_BANK
		jnb	tcb2Flags.TCP_FLAG_ACK,	:noAck	; is the ACK bit set?
		jb	tcb2Flags.TCP_FLAG_RST,	:rst	; is the reset bit set?
		jnb	tcb2Flags.TCP_FLAG_SYN,	:noAck	; if SYN bit not set,
							; ignore packet

:contSynsent	bank	TCP_BANK
		mov	w, #TCP_ST_ESTABED	; the connection is now estabished
		sb	flags2.TCP_SOCK
		mov	tcp1State, w
		snb	flags2.TCP_SOCK
		mov	tcp2State, w
		bank	IP_BANK
		clr	ipLengthMSB		; set the received data length to 1
		mov	ipLengthLSB, #1		;  "
		call	@TCPAckUpdate
		jmp	@TCPSendAck

:rst		bank	TCP_BANK
		mov	w, #TCP_ST_CLOSED	; close the TCP
		sb	flags2.TCP_SOCK
		mov	tcp1State, w
		snb	flags2.TCP_SOCK
		mov	tcp2State, w
		retp

		; the peer wants us to raise the precedence. We can't.
		; We are not happy about not being Acked. Send a Reset.
:noAck		jmp	@TCPSendReset


	ORG	$800	; Page4

TCPRxHeader	jmp	_TCPRxHeader
TCPStartPktOut	jmp	_TCPStartPktOut
TCPTxByte	jmp	_TCPTxByte
TCPReTransmit	jmp	_TCPReTransmit
Compare4Inc	jmp	_Compare4Inc
TCPAppTxDone	jmp	_TCPAppTxDone

; ******************************************************************************
NICReadAgain_4
; Shortform for calling NICReadAgain(), which is in Page1 (This is in Page4)
; ******************************************************************************
		jmp	@NICReadAgain

; ******************************************************************************
NICWriteAgain_4
; Shortform for calling NICWriteAgain(), which is in Page1 (This is in Page4)
; ******************************************************************************
		jmp	@NICWriteAgain

; ******************************************************************************
NICDumpRxFrame_4
; Shortform for calling NICDumpRxFrame(), which is in Page1 (This is in Page4)
; ******************************************************************************
		jmp	@NICDumpRxFrame

; ******************************************************************************
TCPAddRcvNxt
; Add an 16-bit number to RCV.NXT
; INPUT:  {ipLengthMSB,ipLengthLSB} = number to add
; OUTPUT: {tcb1RcvNxt1-4,tcb2RcvNxt1-4}
; ******************************************************************************
		; check for which tcp connection to add
		sb	flags2.TCP_SOCK
		mov	globTemp1, #tcb1RcvNxt1	; make pointer to TCB1_BANK
		snb	flags2.TCP_SOCK
		mov	globTemp1, #tcb2RcvNxt1	; make pointer to TCB2_BANK

		bank	IP_BANK
		mov	w, ipLengthLSB
		mov	globTemp2, w		; store ipLengthLSB in globTemp2

		mov	fsr, globTemp1		; point to TCB variable
		add	indf, globTemp2		; add ipLengthLSB to tcbRcvNxt1

		bank	IP_BANK
		mov	w, ipLengthMSB
		snc
		mov	w, ++ipLengthMSB
		mov	globTemp2, w		; store in globTemp2

		dec	globTemp1
		mov	fsr, globTemp1		; point to TCB variable
		add	indf, globTemp2		; add to tcb1(2)RcvNxt2
		sc
		retp
		dec	fsr
		incsz	indf			; tcb1(2)RcvNxt3
		retp
		dec	fsr
		inc	indf			; tcb1(2)RcvNxt4
		retp

; ******************************************************************************
TCPIncRcvNxt
; Increment RCV.NXT by one
; INPUT:  none
; OUTPUT: {tcb1RcvNxt1-4,tcb2RcvNxt1-4}
; ******************************************************************************
		; set pointer to correct TCB (TCB1_BANK for tcp1,
		; TCB2_BANK for tcp2)
		mov	globTemp1, #(tcb1RcvNxt1-TCB1_BANK)
		call	@SetTCBPointer

		incsz	indf	; 1
		retp

		dec	fsr	; 2
		incsz	indf
		retp

		dec	fsr	; 3
		incsz	indf
		retp

		dec	fsr	; 4
		inc	indf
		retp

; ******************************************************************************
TCPIncSndUna
; Increment SND.UNA by one
; INPUT:  none
; OUTPUT: {tcb1SndUna1-4,tcb2SndUna1-4}
; ******************************************************************************
		; set pointer to correct TCB (TCB1_BANK for tcp1,
		; TCB2_BANK for tcp2)
		mov	globTemp1, #(tcb1SndUna1-TCB1_BANK)
		call	@SetTCBPointer

		incsz	indf	; 1
		retp

		dec	fsr	; 2
		incsz	indf
		retp

		dec	fsr	; 3
		incsz	indf
		retp

		dec	fsr	; 4
		inc	indf
		retp

; ******************************************************************************
TCPCopySeqToNxt
; Copy {tcpTmpSeq4-1} -> {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1}
; INPUT:  {tcpTmpSeq4-1}
; OUTPUT: {tcb1RcvNxt4-1,tcb2RcvNxt4-1}
; ******************************************************************************
		sb	flags2.TCP_SOCK
		mov	globTemp1, #tcb1RcvNxt4	; make pointer to TCB1_BANK
		snb	flags2.TCP_SOCK
		mov	globTemp1, #tcb2RcvNxt4	; make pointer to TCB2_BANK
		mov	globTemp3, #tcpTmpSeq4	; make pointer to TCP BANK
		call	@Copy4Inc		; copy 4 TCP variables to TCB
		retp				; by incrementing the pointers

; ******************************************************************************
TCPCopyAckToUna
; Copy {tcpTmpAck4-1} -> {tcb1SndUna4-1} or {tcb2SndUna4-1}
; INPUT:  {tcpTmpAck4-1}
; OUTPUT: {tcb1SndUna4-1,{tcb2SndUna4-1}}
; ******************************************************************************
		sb	flags2.TCP_SOCK
		mov	globTemp1, #tcb1SndUna4	; make pointer to TCB1_BANK
		snb	flags2.TCP_SOCK
		mov	globTemp1, #tcb2SndUna4	; make pointer to TCB2_BANK

		mov	globTemp3, #tcpTmpAck4	; make pointer to TCP BANK
		call	@Copy4Inc		; copy 4 TCP variables to TCB
		retp

; ******************************************************************************
TCPAckUpdate
; Update SND.UNA and RCV.NXT
; INPUT:  {tcpTmpAck4-1}
;	  {tcpTmpSeq4-1}
;	  {ipLengthMSB,ipLengthLSB} = length of received TCP Data
; OUTPUT: {tcpSndUna4-1}
;	  {tcpRcvNxt4-1}
; ******************************************************************************
		call	@TCPCopyAckToUna	; set SND.UNA = SEG.ACK
		call	@TCPCopySeqToNxt	; set RCV.NXT = SEG.SEQ
		jmp	@TCPAddRcvNxt		; add the length of the received
						; packet to the ACK

; ******************************************************************************
TCPCmpNxtSeq
; Check if RCV.NXT == SEG.SEQ
; INPUT:  {tcpTmpSeq4-1} = SEG.SEQ
;	  {tcb1RcvNxt4-1} = RCV.NXT or {tcb2RcvNxt4-1} = RCV.NXT
; OUTPUT: z is set if RCV.NXT == SEG.SEQ
; ******************************************************************************
		sb	flags2.TCP_SOCK
		mov	globTemp1, #tcb1RcvNxt1	; make pointer to TCB1_BANK
		snb	flags2.TCP_SOCK
		mov	globTemp1, #tcb2RcvNxt1	; make pointer to TCB2_BANK
		mov	globTemp3, #tcpTmpSeq1	; make pointer to TCP BANK

		bank	IP_BANK
		mov	counter1, #4		; load the counter
:loop
		mov	fsr, globTemp3		; move tcp pointer to fsr
		mov	w, indf			; move tcp var in w
		mov	globTemp2, w		; store tcp var in global2

		mov	fsr, globTemp1		; move tcb pointer to fsr
		mov	w, indf			; move tcb var into w

		xor	w, globTemp2		; xor tcp var with tcb var
		jnz	:CmpEnd			; test if equal

		dec	globTemp1		; dec pointer to tcb
		dec	globTemp3		; dec pointer to tcp

		_bank	IP_BANK			; check loop counter until
						; finished
		dec	counter1
		sz
		jmp	:loop

:CmpEnd		retp

; ******************************************************************************
TCPSendEmptyPkt
; Constructs and sends a TCP packet containing no Data
; INPUT:  {remoteIP0-3} = Destination IP addr for TCP pkt
;	  {tcb1SndUna4-1} or {tcb2SndUna4-1} = sequence number
;	  {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
;	  tcb1Flags or tcb2Flags = code flags
;	  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
;	  or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
		call	@TCPCheckSumInit
		bank	TCP_BANK
		clr	tcpLengthMSB
		clr	tcpLengthLSB
		call	TCPStartPktOut
		call	@NICSendTxFrame
		bank	TIMER_BANK

		; clear correct tcp connection's re-tx counters
		jb	flags2.TCP_SOCK, :clrTcp2timer

		; tcp conn1
		clr	tcp1TimerMSB
		clr	tcp1TimerLSB
		retp

		; tcp conn2
:clrTcp2timer	clr	tcp2TimerMSB
		clr	tcp2TimerLSB
		retp

; ******************************************************************************
TCPSendReset
; Send a reset packet with <SEQ=SEG.ACK><CTL=RST> and Discard the received
; packet
; INPUT:  {remoteIP0-3} = Destination IP addr for TCP pkt
;	  {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
;	  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
;	  or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
		; point to correct tcb for current tcp connection
		mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		call	@SetTCBPointer
		mov	indf, #(1<<TCP_FLAG_RST)

		call	@TCPCopyAckToUna	; copy the acknowledgement number.
		call	@TCPSendEmptyPkt
		jmp	NICDumpRxFrame_4	; discard the received pkt

; ******************************************************************************
TCPSendSyn
; Send a SYN packet
; INPUT:  {remoteIP0-3} = Destination IP addr for TCP pkt
;	  {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
;	  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
;	  or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT: {tcpSndUna4-1} = new sequence number
; ******************************************************************************
		; point to correct tcb for current tcp connection
		mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		call	@SetTCBPointer
		mov	indf, #(1<<TCP_FLAG_SYN)
		jmp	TCPSendISN

; ******************************************************************************
TCPSendISN
; Send the TCP initial sequence number
; INPUT:  {remoteIP0-3} = Destination IP addr for TCP pkt
;	  {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
;	  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
;	  or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT: {tcpSndUna4-1} = new sequence number
; ******************************************************************************
		; obtain a random number for starting sequence number
		bank	NIC_BANK
		mov	w, nicCurrPktPtr
		xor	w, nicRemoteEth0
		bank	IP_BANK
		xor	w, ipIdentLSB
		mov	globTemp2, w	; store

		; point to the correct tcb for current tcp connection
		mov	globTemp1, #(tcb1SndUna4-TCB1_BANK)
		call	@SetTCBPointer

		mov	w, globTemp2	; restore

		mov	indf, w		; 1
		inc	fsr
		mov	indf, w		; 2
		inc	fsr
		mov	indf, w		; 3
		inc	fsr
		mov	indf, w		; 4

		call	@TCPIncRcvNxt
		call	@TCPSendEmptyPkt
		jmp	@TCPIncSndUna

; ******************************************************************************
TCPSendSynAck
; Send an SYN-ACK packet with <SEQ=SND.NXT><ACK=RCV.NXT><CTL=SYN>
; INPUT:  {remoteIP0-3} = Destination IP addr for TCP pkt
;	  {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
;	  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
;	  or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT: {tcpSndUna4-1} = new sequence number
; ******************************************************************************
		; point to correct tcb for current tcp connection
		mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		call	@SetTCBPointer
		mov	indf, #((1<<TCP_FLAG_SYN)|(1<<TCP_FLAG_ACK))

		jmp	@TCPSendISN

; ******************************************************************************
TCPSendAck
; Send an ACK packet with <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> and Discard the
; received packet
; INPUT:  {remoteIP0-3} = Destination IP addr for TCP pkt
;	  {tcb1SndUna4-1} or {tcb2SndUna4-1} = sequence number
;	  {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
;	  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
;	  or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
		; point to correct tcb for current tcp connection
		mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		call	@SetTCBPointer
		mov	indf, #(1<<TCP_FLAG_ACK)

		call	@TCPSendEmptyPkt
		jmp	NICDumpRxFrame_4	; discard the received pkt

; ******************************************************************************
TCPSendFin
; Send a FIN packet and discard the received packet
; INPUT:  {remoteIP0-3} = Destination IP addr for TCP pkt
;	  {tcb1SndUna4-1} or {tcb2SndUna4-1} = sequence number
;	  {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
;	  tcb1Flags or tcb2Flags = code flags
;	  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
;	  or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
		; point to correct tcb for current tcp connection
		mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		call	@SetTCBPointer

		mov	indf, #(1<<TCP_FLAG_FIN)|(1<<TCP_FLAG_ACK)
		call	@TCPSendEmptyPkt
		jmp	NICDumpRxFrame_4	; discard the received pkt

; ******************************************************************************
TCPCheckSumInit
; Clear TCP checksum value to prepare for new checksum calculation
; INPUT:  none
; OUTPUT: {tcpCheckSumMSB,tcpCheckSumLSB}
; ******************************************************************************
		bank	TCP_BANK
		clr	tcpCheckSumMSB
		clr	tcpCheckSumLSB
		clrb	flags.TCP_CHKSUM_LSB	; next byte is MSB
		retp

; ******************************************************************************
TCPCheckSumAcc
; Accumulate the TCP checksum. Checksum is computed by Doing the one's
; complement of the one's complement sum of 16-bit numbers
; INPUT:  w = byte to accumulate
;	  flags.TCP_CHKSUM_LSB = set if processing LSB, clear if processing MSB
; OUTPUT: {tcpCheckSumMSB,tcpCheckSumLSB}
; ******************************************************************************
		bank	TCP_BANK

		jnb	flags.TCP_CHKSUM_LSB, :msb	; are we processing an MSB?

:lsb		add	tcpCheckSumLSB,	w		; add it to the checksum
		sc					; was there a carry?
		jmp	:done
		inc	tcpCheckSumMSB			; yes
		snz
		inc	tcpCheckSumLSB
		jmp	:done

:msb		add	tcpCheckSumMSB,	w		; add it to the checksum
		sc					; was there a carry?
		jmp	:done
		inc	tcpCheckSumLSB			; yes, this time it is
							; added to the LSB
		snz
		inc	tcpCheckSumMSB

:done		xor	flags, #(1<<TCP_CHKSUM_LSB)
		retp

; ******************************************************************************
TCPCheckSumAddHdr
; Add to the TCP checksum, the pseudo-header fields
; INPUT:  {myIP0-3} = source IP addr
;	  {remoteIP0-3} = Destination IP addr
;	  {tcpLengthMSB,tcpLengthLSB} = length of TCP header and Data
; OUTPUT: {tcpCheckSumMSB,tcpCheckSumLSB}
; ******************************************************************************
		bank	TCP_BANK

		; <TCP_length>
		mov	w, tcpLengthMSB
		call	TCPCheckSumAcc
		mov	w, tcpLengthLSB
		call	TCPCheckSumAcc

		; <zero>,<protocol>
		mov	w, #0
		call	TCPCheckSumAcc
		mov	w, #6
		call	TCPCheckSumAcc

		; <source_IP>
		bank	IP_BANK
		mov	w, myIP3
		call	TCPCheckSumAcc
		bank	IP_BANK
		mov	w, myIP2
		call	TCPCheckSumAcc
		bank	IP_BANK
		mov	w, myIP1
		call	TCPCheckSumAcc
		bank	IP_BANK
		mov	w, myIP0
		call	TCPCheckSumAcc

		; <destination_IP>
		bank	IP_BANK
		mov	w, remoteIP3
		call	TCPCheckSumAcc
		bank	IP_BANK
		mov	w, remoteIP2
		call	TCPCheckSumAcc
		bank	IP_BANK
		mov	w, remoteIP1
		call	TCPCheckSumAcc
		bank	IP_BANK
		mov	w, remoteIP0
		call	TCPCheckSumAcc

		retp

; ******************************************************************************
_TCPTxByte
; Transmit a TCP byte accumulating the checksum each time
; INPUT:  w = byte to send
; OUTPUT: none
; ******************************************************************************
		mov	globTemp1, w
		call	@TCPCheckSumAcc
		mov	w, globTemp1
		call	NICWriteAgain_4
		retp

; ******************************************************************************
_TCPStartPktOut
; Constructs the TCP and IP headers
; INPUT:  {remoteIP0-3} = Destination IP addr for TCP pkt
;	  {tcpLengthMSB,tcpLengthLSB} = length of TCP Data (just Data)
;	  {tcpCheckSumMSB,tcpCheckSumLSB} = TCP checksum computed over just Data
;	  {tcb1SndUna4-1} or {tcb2SndUna4-1} = sequence number
;	  {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
;	  tcb1Flags or tcb2Flags = code flags
;	  {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
;	  or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
		; tcpLength += <TCP header length>
		_bank	TCP_BANK
		mov	w, #(TCP_HDR_LENGTH<<2)	; add in size of TCP hdr (20)
		add	tcpLengthLSB, w
		snc
		inc	tcpLengthMSB		; tcpLength now is the length of
						; TCP hdr and Data

		; IP <total_length> = tcpLength + <IP header length>
		mov	w, #20			; add in size of IP hdr (20)
		add	w, tcpLengthLSB
		bank	IP_BANK
		mov	ipLengthLSB, w
		bank	TCP_BANK
		mov	w, tcpLengthMSB
		bank	IP_BANK
		mov	ipLengthMSB, w
		snc
		inc	ipLengthMSB

		; update IP <identifier>
		inc	ipIdentLSB
		snz
		inc	ipIdentMSB

		; set IP <protocol> for TCP
		mov	ipProtocol, #6

		; We should rather load remoteIP with tcp socketIP here, but Due
		; to limited code space it is Done in IPGenCheckSum.

		; compute IP <header_checksum>
		call	@IPGenCheckSum

		; now we're ready to construct the IP header
		call	@IPStartPktOut

		; then construct the TCP header

		; point to correct tcb for current tcp connection
		mov	globTemp1, #(tcb1Offset-TCB1_BANK)
		call	@SetTCBPointer

		; TCP <source_port>,<destination_port>,<sequence_number>,
		; <acknowledgement_number>,<hlen>,<code>,<window>
		mov	indf, #(TCP_HDR_LENGTH<<4)
		inc	fsr
		inc	fsr
		mov	indf, #((TCP_WINDOW_SIZE&$FF00)>>8)
		inc	fsr
		mov	indf, #(TCP_WINDOW_SIZE&$00FF)

		; make a pointer to the tcb for the current tcp connection
		sb	flags2.TCP_SOCK
		mov	globTemp3, #TCB1_BANK
		snb	flags2.TCP_SOCK
		mov	globTemp3, #TCB2_BANK

:loop		mov	fsr, globTemp3
		mov	w, indf			; load the value
		call	@TCPTxByte		; transmit and accumulate header
						; checksum
		inc	globTemp3

		jb	flags2.TCP_SOCK, :check2
		cse	globTemp3, #TCB1_END	; is the loop finished?
		jmp	:loop
		jmp	:outloop

:check2		cse	globTemp3, #TCB2_END	; is the loop finished?
		jmp	:loop

:outloop	; TCP <checksum>
		call	@TCPCheckSumAddHdr
		bank	TCP_BANK
		mov	w, /tcpCheckSumMSB
		call	NICWriteAgain_4
		mov	w, /tcpCheckSumLSB
		call	NICWriteAgain_4

		; TCP <urgent_ptr>
		mov	w, #0
		call	NICWriteAgain_4
		call	NICWriteAgain_4

		retp

; ******************************************************************************
_TCPRxHeader
; Process the TCP header of a received TCP packet
; INPUT:  none
; OUTPUT: Z is set to 1 if the packet is invalid, 0 otherwise
;	  {tcb1RemotePortMSB,tcb1RemotePortLSB}
;	  or {tcb2RemotePortMSB,tcb2RemotePortLSB}
;	  {tcb1SendWinMSB,tcb1SendWinLSB} or {tcb2SendWinMSB,tcb2SendWinLSB}
;	  tcb1Offset or tcb2Offset
;	  tcb1Flags or tcb2Flags
;	  tcpRxFlags
;	  {tcpTmpSeq4-1} = <sequence_number>
;	  {tcpTmpAck4-1} = <acknowledgement_number>
;	  {tcpLengthMSB,tcpLengthLSB} = length of TCP Data
;	  {ipLengthMSB,ipLengthLSB} = length of TCP Data
; ******************************************************************************
		bank	TCPPORT_BANK

		; <remote_port>
		call	NICReadAgain_4
		mov	tcpRemotePortMSB, w		; store remote port MSB
		call	NICReadAgain_4
		mov	tcpRemotePortLSB, w		; store remote port LSB

		; <destination_port>
		call	NICReadAgain_4
		mov	tcpLocalPortMSB, w	; store dest port MSB
		call	NICReadAgain_4		;
		mov	tcpLocalPortLSB, w	; store dest port LSB

		call	@TCPConnectionManager	; start the tcp conn/socket
						; manager
		snz				; is the packet OK?
		retp				; no, return

		; <sequence_number>
		bank	TCP_BANK
		call	NICReadAgain_4
		mov	tcpTmpSeq4, w
		call	NICReadAgain_4
		mov	tcpTmpSeq3, w
		call	NICReadAgain_4
		mov	tcpTmpSeq2, w
		call	NICReadAgain_4
		mov	tcpTmpSeq1, w

		_bank	TCPTMP_BANK
		; <acknowledgement_number>
		call	NICReadAgain_4
		mov	tcpTmpAck4, w
		call	NICReadAgain_4
		mov	tcpTmpAck3, w
		call	NICReadAgain_4
		mov	tcpTmpAck2,w
		call	NICReadAgain_4
		mov	tcpTmpAck1, w

		call	NICReadAgain_4		; receive the Data offset.
				;	Used to skip the options
		and	w, #TCP_OFFSET_MASK	; mask out the offset
		mov	globTemp2, w		; store	w

		; point to the correct tcb for the current tcp connection
		mov	globTemp1, #(tcb1Offset-TCB1_BANK)
		call	@SetTCBPointer

		mov	indf, globTemp2
		clc
		rr	indf
		rr	indf

		; ipLength = tcpLength = length of TCP Data
		mov	w, indf

		_bank	IP_BANK
		sub	ipLengthLSB, w		; subtract out size of TCP header
		mov	w, ipLengthLSB
		bank	TCP_BANK
		mov	tcpLengthLSB, w
		bank	IP_BANK
		sc
		dec	ipLengthMSB
		mov	w, ipLengthMSB
		bank	TCP_BANK
		mov	tcpLengthMSB, w

		; <code>
		call	NICReadAgain_4		; receive the flags
		mov	tcpRxFlags, w
		mov	globTemp2, w
		; point to the correct tcb for the current tcp connection
		mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		call	@SetTCBPointer
		mov	indf, globTemp2

		; <window>
		call	NICReadAgain_4
		mov	globTemp2, w

		; point to the correct tcb for the current tcp connection
		mov	globTemp1, #(tcb1SendWinMSB-TCB1_BANK)
		call	@SetTCBPointer
		mov	indf, globTemp2		; receive the window

		call	NICReadAgain_4
		mov	globTemp2, w

		; point to the correct tcb for the current tcp connection
		mov	globTemp1, #(tcb1SendWinLSB-TCB1_BANK)
		call	@SetTCBPointer
		mov	indf, globTemp2

		; point to the correct tcb for the current tcp connection
		mov	globTemp1, #(tcb1Offset-TCB1_BANK)
		call	@SetTCBPointer
		sub	indf, #((TCP_HDR_LENGTH<<2)-4)
		mov	w, indf
		mov	globTemp3, w
		clr	indf

:loop		call	NICReadAgain_4
		decsz	globTemp3
		jmp	:loop
		clz
		retp

; ******************************************************************************
_TCPReTransmit
; This is called to retransmit the TCP packet that's already setup in the NIC's
; TCP transmit buffer. Remember that a UDP/ICMP/ARP packet may have been sent
; after the TCP packet was initially sent, so we have to re-setup the NIC
; carefully.
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; re-initialize the NIC's TPSR
		bank	NIC_BANK
		clr	nicIOAddr		; CR
:wait		call	@NICRead
		jb	wreg.2,	:wait		; wait for prior transmission to
						; complete
		mov	w, #%00100010		; Page0, abort DMA
		call	@NICWrite
		mov	nicIOAddr, #$04		; TPSR

		; point to correct tcp tx buffer for current tcp connection
		sb	flags2.TCP_SOCK
		mov	w, #TXBUF2_START
		snb	flags2.TCP_SOCK
		mov	w, #TXBUF3_START

		call	@NICWrite

		; read the NIC's TCP transmit buffer to find out the IP <length>
		; so that we can re-initialize the NIC's TBCR
		sb	flags2.TCP_SOCK
		mov	w, #TXBUF2_START
		snb	flags2.TCP_SOCK
		mov	w, #TXBUF3_START

		mov	nicCopySrcMSB, w
		mov	nicCopySrcLSB, #(6+6+2+2)	; IP <length> (MSB)
		call	@NICBufRead
		bank	IP_BANK
		mov	ipLengthMSB, w
		bank	NIC_BANK
		inc	nicCopySrcLSB		; IP <length> (LSB)
		call	@NICBufRead
		bank	IP_BANK
		mov	ipLengthLSB, w

		jmp	@NICSendTxFrame		; re-transmit the ethernet frame

; ******************************************************************************
_Compare4Inc
; Compares 4 variables in Databanks
; INPUT: globTemp1 = pointer1, globTemp3 = pointer2
; OUTPUT: Z is set on a full match
; ******************************************************************************
		bank	IP_BANK
		mov	counter1, #4		; load the counter
:loop
		mov	fsr, globTemp3		; move pointer to fsr
		mov	w, indf			; move var in w
		mov	globTemp2, w		; store var in global2

		mov	fsr, globTemp1		; move pointer to fsr
		mov	w, indf			; move var into w

		xor	w, globTemp2		; xor tcp var with tcb var
		jnz	:CmpEnd			; test if equal

		inc	globTemp1		; increment pointer
		inc	globTemp3		; increment pointer

		_bank	IP_BANK			; check loop counter until finished
		dec	counter1
		sz
		jmp	:loop

:CmpEnd		retp

; ******************************************************************************
_TCPAppTxDone
; This is called following the last call to TCPAppTxData(). It signifies the
; transmitted Data has successfully reached the remote host
; [TCP API Function]
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; jump to current tcp connection code
		jb	flags2.TCP_SOCK, :TCPAppTxDone2

		; tcp1
		retp

		; tcp2
:TCPAppTxDone2	retp


	ORG	$A00	; Page5

TCPAppRxData	jmp	_TCPAppRxData

; ******************************************************************************
TCPAppRxBytes
; Indicator to the application that a packet has been received and that
; TCPAppRxByte is about to be called as many times as they are bytes of data
; [TCP API Function]
; INPUT:  {tcpAppRxBytesMSB,tcpAppRxBytesLSB} = number of received Data bytes
; OUTPUT: none
; ******************************************************************************
		; jump to current tcp connection code
		jb	flags2.TCP_SOCK, :TCPAppRxBytes2

		; tcp1

		retp

		; tcp2
:TCPAppRxBytes2	retp

; ******************************************************************************
TCPAppTxBytes
; Called before transmitting a TCP packet to see if the application has any
; Data it wishes to send. The application cannot send more than TCP_SEG_SIZE
; bytes at one go.
; [TCP API Function]
; INPUT:  none
; OUTPUT: {tcp1UnAckMSB,tcp1UnAckLSB}
;	  or {tcp2UnAckMSB,tcp2UnAckLSB} = number of bytes to transmit
; ******************************************************************************
		; check if tcp1 or tcp2's chance to transmit
		jb	flags2.TCP_TXSEMA, :tcpConn2Tx

		; tcp1
		clrb	flags2.TCP_SOCK			; indicate tcp1 conn.
		cse	tcp1State, #TCP_ST_ESTABED	; check if in
							; established state
		retp					; no, return


		; tcp2
:tcpConn2Tx	setb	flags2.TCP_SOCK			; indicate tcp2 conn.
		cse	tcp2State, #TCP_ST_ESTABED	; check if in
							; established state
		retp					; no, return

	IF	HTTP
		snb	flags2.BROWSER_TYPE	; do not send anything to netscape
						; type browser on a post.
		retp
				
		bank	HTTP_BANK
		cje	httpParseState,	#2, :state2
		cje	httpParseState,	#3, :state3
		cje	httpParseState,	#4, :state4
		retp

:state2		; check how much there is to send
		_bank	EEPROM_BANK
		csae	e2FileLenMSB, #(HTTP_SEG_SIZE>>8)
		jmp	:lastSegment				;	msb#1 < msb#2
		cse	e2FileLenMSB, #(HTTP_SEG_SIZE>>8)
		jmp	:notLast				;	msb#1 > msb#2
		csa	e2FileLenLSB, #(HTTP_SEG_SIZE&$00FF)
		jmp	:lastSegment				;	#1 <= #2

:notLast	; not the last segment so send as much as possible
		; (i.e. full segment)
		sub	e2FileLenLSB, #(HTTP_SEG_SIZE&$00FF)	;	e2FileLen
								;	-= HTTP_SEG_SIZE
		sc						;
		dec	e2FileLenMSB				;
		sub	e2FileLenMSB, #(HTTP_SEG_SIZE>>8)	;
		_bank	TCP_BANK
		mov	tcp2UnAckMSB, #(HTTP_SEG_SIZE>>8)
		mov	tcp2UnAckLSB, #(HTTP_SEG_SIZE&$00FF)
		retp

:lastSegment	; last segment so send whatever is leftover
		mov	w, e2FileLenMSB
		_bank	TCP_BANK
		mov	tcp2UnAckMSB, w
		_bank	EEPROM_BANK
		mov	w, e2FileLenLSB
		_bank	TCP_BANK
		mov	tcp2UnAckLSB, w
		bank	HTTP_BANK
		inc	httpParseState	; next-state = 3
		retp

		; no more to send so we close
:state3		call	@TCPAppClose
		retp

:state4
	ENDIF
		retp

; ******************************************************************************
TCPAppTxData
; This routine is called once for each byte the application has says it wishes
; to transmit.
; [TCP API Function]
; INPUT:  none
; OUTPUT: w = Data byte to transmit
; ******************************************************************************
		; jump to current tcp connection code
		jb	flags2.TCP_SOCK, :TCPAppTxData2

		; tcp1

		retp

		; tcp2

;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


;THIS IS TO SEE IF YOU NEED TO LOOK FOR DYNAMIC INFORMATION


:TCPAppTxData2

	IF	HTTP
		bank	HTTP_BANK
		cje	httpURIHash, #URI1, :specialFile	; NOTHING HERE
		cje	httpURIHash, #URI2, :specialFile	; INDEX.HTML 
		cje	httpURIHash, #URI3, :specialFile2	; postctrl.htm
		call	@E2Read8Ack
		retp

:specialFile	call	@E2Read8Ack
		mov	globTemp1, w		; save temporarily
		csb	globTemp1, #$F0
		jmp	:match
		mov	w, globTemp1
		retp

		; look for magic number in file indicating Dynamic content
:specialFile2	setb	flags3.LED_LOCK		 ; lock access to LED
		call	@E2Read8Ack
		mov	globTemp1, w		; save temporarily
		csb	globTemp1, #$F0
		jmp	:match2
		mov	w, globTemp1
		retp

:match2		; look if led is on or off now
		jb	LED_PORT.LED, :ledOffChar

		; it is on, return last char of image for ledon.gif
		mov	w, #'n'
		retp

		; it is off, return last char of image for ledof.gif
:ledOffChar	mov	w, #'f'
		retp

:match		cjne	globTemp1, #$F0, :subMatch	; 0xF0 is the magic number

:firstMatch	bank	HTTP_BANK
		mov	globTemp2, httpURIHash
		mov	fsr, #bcd3

		cjne	globTemp2, #URI1, :here

		jmp	:here1
:here	
		
		_BANK	SILO_BANK
	CSB	SILOINC,#10			;SKIP IF BELOW 10
	CLR	SILOINC
	INC	SILOINC				;INCREMENT THE SILO NUMBERS FROM 1 TO 9

	CJE	SILOINC,#1,:SILO1
	CJE	SILOINC,#2,:SILO2
	CJE	SILOINC,#3,:SILO3
	CJE	SILOINC,#4,:SILO4
	CJE	SILOINC,#5,:SILO5
	CJE	SILOINC,#6,:SILO6
	CJE	SILOINC,#7,@SILO7W
	CJE	SILOINC,#8,@SILO8W
	CJE	SILOINC,#9,@SILO9W
;CLR AFTER 9 OKAY


;THIS IS SILO 1
:SILO1	
		_BANK	SILO_BANK		;THIS IS THE WAY TO MOV THINGS ABOUT
		MOV	W,SILO1
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		MOV	W,SILO1+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		MOV	W,SILO1+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		JMP	:HERE1
:SILO2	
		_BANK	SILO_BANK		;THIS IS THE WAY TO MOV THINGS ABOUT
		MOV	W,SILO2
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		MOV	W,SILO2+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		MOV	W,SILO2+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		JMP	:HERE1
:SILO3		
		_BANK	SILO_BANK
		MOV	W,SILO3
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		MOV	W,SILO3+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		MOV	W,SILO3+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		JMP	:HERE1

:SILO4		
		_BANK	SILO_BANK
		MOV	W,SILO4
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		MOV	W,SILO4+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		MOV	W,SILO4+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		JMP	:HERE1

:SILO5		
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO5
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO5+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO5+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		JMP	:HERE1

:SILO6		

		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO6
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO6+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO6+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		JMP	:HERE1


:here1		BANK	MISC_BANK			;YOU HAVE TO HAVE THIS.
		MOV	W, bcd3+0
		retp

:subMatch

		sub	globTemp1, #$F0
		_bank	MISC_BANK
		mov	fsr, #bcd3
		add	fsr, globTemp1
		mov	w, indf
		;call	@BCDToASCII
	ENDIF
		retp

; ******************************************************************************
_TCPAppRxData
; Called once for each byte received in a packet. Will only be called when
; tcpState is established.
; [TCP API Function]
; INPUT:  w = received Data byte
; OUTPUT: none
; ******************************************************************************
		; jump to current tcp connection code
		jb	flags2.TCP_SOCK, :TCPAppRxData2

		; tcp1

		retp

		; tcp2
:TCPAppRxData2
	IF	HTTP
		mov	globTemp1, w
		_bank	HTTP_BANK

		; check if this is 2nd packet from Netscape type browser, post
		jb	flags2.BROWSER_TYPE, :fieldSrch
		
		; look if we got the method already
		sb	flags3.GOT_HTTP_METHOD
		jmp	:methodSrch1		; no, go to method search

		; yes, we have the method, jump to correct method parser
		jb	flags3.HTTP_METHOD, :postMethod
		jmp	:defaultMethod

:methodSrch1	cje	globTemp1, #'P', :isPost	; is it a P ?
		clrb	flags3.HTTP_METHOD		; it's GET
		setb	flags3.GOT_HTTP_METHOD		; indicate we have the method
		jmp	:defaultMethod

:isPost		setb	flags3.HTTP_METHOD		; yes, so it must be POST or PUT
		setb	flags3.GOT_HTTP_METHOD		; indicate we have the method
		setb	flags3.LED_LOCK			; lock access to the LED
		clr	httpParseState
		clr	httpParseState2
		retp

:postMethod	; have to get the requested resource now to set file pointer
		jb	flags3.GOT_URI,	:fieldSrch	; check if we have to go
		test	httpParseState			; directly to field srch
		jz	:stateN0
		cje	httpParseState,	#1, :stateN1

:stateN0	cse	globTemp1, #' '			; search for the space after the method
		retp					; keyword
		inc	httpParseState			; got it, next-state = 1
		retp

:stateN1	cje	globTemp1, #' ', :gotURI	; make URI until space after
							; requested resource
		add	httpURIHash, globTemp1
		retp

		; we have to search for the input field now. It's after 2 CRLFs
:fieldSrch	cje	httpParseState,	#1, :gotCtrl
		cje	httpParseState,	#2, :gotLf
		cje	httpParseState,	#3, :gotBlkLine
		cje	httpParseState,	#4, :gotField

		csne	globTemp1, #$0d		; check for first ctrl
		inc	httpParseState		; yes, got it
		retp				; no

:gotCtrl	cjne	globTemp1, #$0a, :fldSrchRst
		inc	httpParseState		; yes, got it
		retp				; no

:gotLf		cjne	globTemp1, #$0d, :fldSrchRst	; check for blank line
		inc	httpParseState			; yes, got to blank line
		retp					; no

:gotBlkLine	cjne	globTemp1, #$0a, :fldSrchRst	; check for last char of
							; blank line
		inc	httpParseState			; yes, we are at the field now
		retp

:gotField	cje	httpParseState2, #1, :gotl
		cje	httpParseState2, #2, :gote
		cje	httpParseState2, #3, :gotd
		cje	httpParseState2, #4, :gotequal

		csne	globTemp1, #'l'		; look for 'l'
		inc	httpParseState2		; yes, got it
		retp				; no

:gotl		csne	globTemp1, #'e'		; look for 'e'
		inc	httpParseState2		; yes, got it
		retp				; no

:gote		csne	globTemp1, #'d'		; look for 'd'
		inc	httpParseState2		; yes, got it
		retp				; no

:gotd		csne	globTemp1, #'='		; look for '='
		inc	httpParseState2		; yes, got it
		retp				; no

		; now the next byte is the control byte for the led control
:gotequal	cje	globTemp1, #'1', :ledOn
		cje	globTemp1, #'0', :ledOff
		cje	globTemp1, #'t', :ledToggle
		retp

:ledOn		clrb	LED_PORT.LED		; switch led on
		retp

:ledOff		setb	LED_PORT.LED		; switch led off
		retp

:ledToggle	mov	w, #(1<<LED)		; toggle led status
		xor	LED_PORT, w
		retp

:fldSrchRst	clr	httpParseState		; no, gotta start over.
		retp

:defaultMethod	test	httpParseState
		jz	:state0
		cje	httpParseState,	#1, :state1
		cjae	httpParseState,	#2, :state2

:state0		cse	globTemp1, #' '		; search for the space after the method
		retp
		inc	httpParseState		; got it, next-state = 1
		retp

:state1		cje	globTemp1, #' ', :gotURI; make URI until space after
						; requested resource
		add	httpURIHash, globTemp1
		retp

:gotURI		; got the requested resource, obtain pointer to file
		; check if coming from post method
		jnb	flags3.HTTP_METHOD, :gotURICont

		; bit is set, so we came from post method
		clr	httpParseState	; clear for field parser
		setb	flags3.GOT_URI	; indicate we got URI for post field parser

:gotURICont	mov	w, httpURIHash
		_bank	EEPROM_BANK
		mov	e2AddrLSB, w
		clr	e2AddrMSB
		clc			; e2Addr = httpURIHash * 2
		rl	e2AddrLSB	;
		rl	e2AddrMSB	;
		call	@E2Init		; reset EEPROM
		call	@E2SetAddr
		call	@E2SendRdCmd
		call	@E2Read8Ack
		mov	e2AddrMSB, w
		call	@E2Read8NoAckStop
		mov	e2AddrLSB, w

		; start reading from file
		call	@E2SetAddr
		call	@E2SendRdCmd

		; file length
		call	@E2Read8Ack
		mov	e2FileLenMSB, w
		call	@E2Read8Ack
		mov	e2FileLenLSB, w

		; file checksum (ignore)
		call	@E2Read8Ack
		call	@E2Read8Ack

		_bank	HTTP_BANK
		sb	flags3.HTTP_METHOD	; do not increment if post
		inc	httpParseState		; next-state = 2
		retp

:state2		 ; here we receive bytes from after the requested resource
	ENDIF
		retp


	ORG	$C00	; Page6

TCPTransmit	jmp	_TCPTransmit
TCPAppRxDone	jmp	_TCPAppRxDone
TCPApp1Init	jmp	_TCPApp1Init



; ******************************************************************************
SetTCBPointer
; Sets the fsr register to point to the correct TCB
; INPUT:  globTemp1=offset into TCB1_BANK or TCB2_BANK
; OUTPUT: fsr contains pointer to variable in TCB bank
; ******************************************************************************
		; check if pointer to be set for tcp1 or 2 connection.
		jb	flags2.TCP_SOCK, :tcb2pointer

		; tcp1
		add	globTemp1, #TCB1_BANK
		mov	fsr, globTemp1	; make pointer to TCB1_BANK for tcp1
		retp

		; tcp2
:tcb2pointer	add	globTemp1, #TCB2_BANK
		mov	fsr, globTemp1	; make pointer to TCB2_BANK for tcp2
		retp

; ******************************************************************************
CheckSocket1IP
; Checks if remoteIP is in tcp socket1
; INPUT: remoteIP3-0, sock1RemoteIP3-0
; OUTPUT: Z set if in there
; ******************************************************************************
		mov	globTemp1, #remoteIP3
		mov	globTemp3, #sock1RemoteIP3
		call	@Compare4Inc
		retp

; ******************************************************************************
CheckSocket2IP
; Checks if remoteIP is in tcp socket2
; INPUT: remoteIP3-0, sock2RemoteIP3-0
; OUTPUT: Z set if in there
; ******************************************************************************
		mov	globTemp1, #remoteIP3
		mov	globTemp3, #sock2RemoteIP3
		call	@Compare4Inc
		retp

; ******************************************************************************
CopyRemotePortTCB1
; Copies tcpRemotePortMSB,LSB into tcb1RemotePortMSB,LSB
; INPUT: tcpRemotePortMSB,LSB
; OUTPUT: tcb1RemotePortMSB,LSB
; ******************************************************************************
		bank	TCPPORT_BANK
		mov	w, tcpRemotePortMSB
		bank	TCB1_BANK
		mov	tcb1RemotePortMSB, w

		bank	TCPPORT_BANK
		mov	w, tcpRemotePortLSB
		bank	TCB1_BANK
		mov	tcb1RemotePortLSB, w

		retp

; ******************************************************************************
CopyRemotePortTCB2
; Copies tcpRemotePortMSB,LSB into tcb2RemotePortMSB,LSB
; INPUT: tcpRemotePortMSB,LSB
; OUTPUT: tcb2RemotePortMSB,LSB
; ******************************************************************************
		bank	TCPPORT_BANK
		mov	w, tcpRemotePortMSB
		bank	TCB2_BANK
		mov	tcb2RemotePortMSB, w

		bank	TCPPORT_BANK
		mov	w, tcpRemotePortLSB
		bank	TCB2_BANK
		mov	tcb2RemotePortLSB, w

		retp

; ******************************************************************************
CheckLocalPortTCB1
; Compares tcpLocalPortLSB, tcpLocalPortMSB against tcb1LocalPortLSB,
;	   tcb1LocalPortMSB
; INPUT: tcpLocalPortLSB, tcpLocalPortMSB, tcb1LocalPortLSB, tcb1LocalPortMSB
; OUTPUT: Z set if match
; ******************************************************************************
		bank	TCPPORT_BANK
		mov	w, tcpLocalPortMSB
		bank	TCB1_BANK
		xor	w, tcb1LocalPortMSB
		sz
		retp
		mov	w, tcb1LocalPortLSB
		bank	TCPPORT_BANK
		xor	w, tcpLocalPortLSB
		retp

; ******************************************************************************
CheckLocalPortTCB2
; Compares tcpLocalPortLSB, tcpLocalPortMSB against tcb2LocalPortLSB,
;	   tcb2LocalPortMSB
; INPUT: tcpLocalPortLSB, tcpLocalPortMSB, tcb2LocalPortLSB, tcb2LocalPortMSB
; OUTPUT: Z set if match
; ******************************************************************************
		bank	TCPPORT_BANK
		mov	w, tcpLocalPortMSB
		bank	TCB2_BANK
		xor	w, tcb2LocalPortMSB
		sz
		retp
		mov	w, tcb2LocalPortLSB
		bank	TCPPORT_BANK
		xor	w, tcpLocalPortLSB
		retp

; ******************************************************************************
TCPConnectionManager
; Manages TCP connections. Checks incoming tcp packets against listening ports,
; makes new sockets and indicates for which tcp connection the packet is.
; INPUT: none
; OUTPUT: flags2.TCP_SOCK
; ******************************************************************************
		; check if we are waiting for an ARP response.
		; have to Dump & ignore all incoming tcp packets until ARP
		; response received or ARP timed out. The tcp receive functions
		; can respond with sending tcp packets which will overwrite
		; the stalled tcp packet. If we recorded which tcp conn. buffer
		; has a stalled packet, we can accept tcp packets for the other
		; tcp conn. but let's keep it simple now
		jb	flags3.ARP_REQ_SENT, :ignorePacket

		; pre-screening to check if the local port=service is offered
		call	@CheckLocalPortTCB1	; check if for a port
						; we're listening on
		jz	:TCPSocket1		; yes, service is bound
						; to TCB1_BANK
		call	@CheckLocalPortTCB2	; check if for a port
						; we're listening on
		jz	:TCPSocket2		; yes, service is bound
						; to TCB2_BANK
		jmp	:ignorePacket		; no, we Don't offer the service

:TCPSocket1	call	@CheckSocket1IP		; check if remote IP
						; is in socket1
		jnz	:CreateTCPSocket1	; no, make a new conn./socket
		call	@CheckRemotePortTCB1	; yes, check if remote port
						; is in TCB1_BANK
		jz	:TCPConnection1		; yes, packet is for tcp conn. 1
		jmp	:CreateTCPSocket1	; no, but make a new conn.
						; if we're listening

:TCPSocket2	call	@CheckSocket2IP		; check if remote IP
						; is in socket2
		jnz	:CreateTCPSocket2	; no, make a new conn./socket
		call	@CheckRemotePortTCB2	; yes, check if remote port
						; is in TCB2_BANK
		jz	:TCPConnection2		; yes, packet is for tcp conn. 2
		jmp	:CreateTCPSocket2	; no, but make a new conn.
						; if we're listening

:CreateTCPSocket1
		; we may only create a socket when tcp1 connection is in
		; LISTEN state
		_bank	TCP_BANK
		cjne	tcp1State, #TCP_ST_LISTEN, :ignorePacket

		; create tcp1 socket
		call	@CopyRemoteIPSocket1	; store remote IP in socket1
		call	@CopyRemotePortTCB1	; store remote port in socket1
		jmp	:TCPConnection1

:CreateTCPSocket2
		; we may only create a socket when tcp2 connection is in
		; LISTEN state
		_bank	TCP_BANK
		cjne	tcp2State, #TCP_ST_LISTEN, :ignorePacket

		; create tcp2 socket
		call	@CopyRemoteIPSocket2	; store remote IP in socket2
		call	@CopyRemotePortTCB2	; store remote port in socket2
		jmp	:TCPConnection2

:TCPConnection1	clrb	flags2.TCP_SOCK		; indicate tcp packet is for tcp1
		clz				; indicate packet is ok
		retp

:TCPConnection2	setb	flags2.TCP_SOCK		; indicate tcp packet is for tcp2
		clz				; indicate packet is ok
		retp

:ignorePacket	call	@NICDumpRxFrame		; discard the tcp packet
		stz				; indicate packet is not ok -
						; don't process it
		retp

; ******************************************************************************
_TCPTransmit
; See if the application has any Data to transmit. If there are no outstanding
; packets and the application has Data, then transmit a packet.
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		_bank	TCP_BANK		; _bank cus we called
						; TCPAppInit priorly

		; check which tcp connection has chance to tx
		jb	flags2.TCP_TXSEMA, :tcp2Tx

		; tcp1 has tx chance
		cjae	tcp1State, #TCP_ST_ESTABED, :ok1	; is tcp1
								; connection estab?
		retp				; exit, tcp1 connection
						; not established

		; yes, tcp1 is est.
:ok1		test	tcp1UnAckMSB		; are there any bytes
						; unacknowledged?
		jnz	:timeout1
		test	tcp1UnAckLSB
		jnz	:timeout1
		cje	tcp1State, #TCP_ST_FINWAIT1, :finTimeout	; check for
									; FIN timeout
		jmp	:askAppTxData

		; tcp2 has tx chance
:tcp2Tx		cjae	tcp2State, #TCP_ST_ESTABED, :ok2	; is tcp2
								; connection estab?
		retp				; exit, tcp2 connection
						; not established

		; yes, tcp2 is est.
:ok2		test	tcp2UnAckMSB		; are there any bytes
						; unacknowledged?
		jnz	:timeout2
		test	tcp2UnAckLSB
		jnz	:timeout2
		cje	tcp2State, #TCP_ST_FINWAIT1, :finTimeout	; check for
									; FIN timeout

:askAppTxData	call	@TCPAppTxBytes		; ask the application if
						; it wants to tx
		_bank	TCP_BANK		; _bank cus we called
						; TCPAppTxBytes priorly

		; check if unack bytes from tcp1 or 2
		jb	flags2.TCP_SOCK, :chkAppTxDataCon2

		; tcp1
		mov	w, tcp1UnAckMSB
		or	w, tcp1UnAckLSB
		jnz	:appHasTxData
		retp	; nope, it Doesn't; so we're Done here then

		; tcp2
:chkAppTxDataCon2
		mov	w, tcp2UnAckMSB
		or	w, tcp2UnAckLSB
		jnz	:appHasTxData
		retp	; nope, it Doesn't; so we're Done here then

:appHasTxData	; start a TCP packet

		; check if for tcp1 or 2
		jb	flags2.TCP_SOCK, :loadUnackTcp2

		; tcp1
		mov	tcpLengthLSB, tcp1UnAckLSB	; tcpLength =
							; # bytes to transmit
		mov	tcpLengthMSB, tcp1UnAckMSB
		jmp	:contAppHasTxData

		; tcp2
	;	tcpLength = # bytes to transmit
:loadUnackTcp2	mov	tcpLengthLSB, tcp2UnAckLSB
		mov	tcpLengthMSB, tcp2UnAckMSB

:contAppHasTxData
		mov	globTemp1, #(tcb1Flags-TCB1_BANK)
		; set pointer to correct tcb for current tcp connection
		call	@SetTCBPointer
		mov	indf, #((1<<TCP_FLAG_PSH)|(1<<TCP_FLAG_ACK))
		call	@TCPCheckSumInit
		call	@TCPStartPktOut		; send the header

		; insert the packet Data while computing the checksum
		; over the Data
		bank	TCP_BANK
		; check if copy for tcp1 or 2
		jb	flags2.TCP_SOCK, :cpyUnAckTCP2

		; tcp1
		mov	tcpTmpLSB, tcp1UnAckLSB
		mov	tcpTmpMSB, tcp1UnAckMSB
		jmp	:dataLoopBgn

		; tcp2
:cpyUnAckTCP2	mov	tcpTmpLSB, tcp2UnAckLSB
		mov	tcpTmpMSB, tcp2UnAckMSB

:dataLoopBgn	inc	tcpTmpMSB		; so that we can loop easier later
:dataLoop	call	@TCPAppTxData
		_banky	TCP_BANK		; cus we called TCPAppTxData
						; priorly
		call	@NICWriteAgain		; which Doesn't clobber w,
						; which is nice
		call	@TCPCheckSumAcc		; accumulate the checksum
		decsz	tcpTmpLSB
		jmp	:dataLoop
		decsz	tcpTmpMSB
		jmp	:dataLoop

		; now go back and fill in the TCP checksum
		bank	NIC_BANK

		; use correct tx buffer for current tcp connection
		sb	flags2.TCP_SOCK
		mov	w, #TXBUF2_START
		snb	flags2.TCP_SOCK
		mov	w, #TXBUF3_START

		mov	nicCopySrcMSB, w
		mov	nicCopySrcLSB, #(6+6+2+20+16)	; TCP <checksum> (MSB)
		bank	TCP_BANK
		mov	w, /tcpCheckSumMSB
		call	@NICBufWrite
		bank	NIC_BANK
		inc	nicCopySrcLSB
		bank	TCP_BANK
		mov	w, /tcpCheckSumLSB
		call	@NICBufWrite

		call	@NICSendTxFrame		; end and send the packet

		bank	TIMER_BANK		; initialise the restart timer

		; check if tcp1 or 2 timer to be cleared
		jb	flags2.TCP_SOCK, :initTcp2Timer

		; tcp1
		clr	tcp1TimerMSB
		clr	tcp1TimerLSB
		retp

		; tcp2
:initTcp2Timer	clr	tcp2TimerMSB
		clr	tcp2TimerLSB
		retp

:finTimeout	bank	TIMER_BANK
		; check if tcp1 or 2 timer to be checked
		jb	flags2.TCP_TXSEMA, :chkClrTcp2Tmr

		; tcp1
		csae	tcp1TimerMSB, #TCP_RESTART_EXP	; has the restart timer
							; expired?
		retp					; no
		clr	tcp1TimerMSB			; yes, initialise the
							; restart timer
		clr	tcp1TimerLSB
		jmp	@TCPSendFin

		; tcp2
:chkClrTcp2Tmr	csae	tcp2TimerMSB, #TCP_RESTART_EXP	; has the timer expired?
		retp					; no
		clr	tcp2TimerMSB			; yes, initialise the
							; restart timer
		clr	tcp2TimerLSB
		jmp	@TCPSendFin

		; check if timed out on waiting for ack on tcp connection1
:timeout1	bank	TIMER_BANK
		csae	tcp1TimerMSB, #TCP_RESTART_EXP	; has the restart timer
							; expired?
		retp					; no
		clr	tcp1TimerMSB			; yes, initialise the
							; restart timer
		clr	tcp1TimerLSB
		clrb	flags2.TCP_SOCK			; indicate conn1.
		jmp	@TCPReTransmit			; transmit the packet
							; again

:timeout2	bank	TIMER_BANK
		csae	tcp2TimerMSB, #TCP_RESTART_EXP	; has the restart timer
							; expired?
		retp					; no
		clr	tcp2TimerMSB			; yes, initialise the
							; restart timer
		clr	tcp2TimerLSB
		setb	flags2.TCP_SOCK			; indicate conn2.
		jmp	@TCPReTransmit			; transmit the packet
							; again



; ******************************************************************************
_TCPAppRxDone
; This is called following the last call to TCPAppRxData(). It signifies the
; end of the received packet
; [TCP API Function]
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; jump to current tcp connection code
		jb	flags2.TCP_SOCK, :TCPAppRxDone2

		; tcp1

		retp

		; tcp2
:TCPAppRxDone2
	IF	HTTP
		; check if end of 2nd packet rcvd from Netscape type browser
		_bank	HTTP_BANK
		jnb	flags2.BROWSER_TYPE, :methodChk
		clrb	flags2.BROWSER_TYPE	; yes, clear flag
		jmp	:getM			; reset other flags				
		
		; check if we rcvd a packet with http post and did not get 'led'
		; field meaning it came from a Netscape browser.
:methodChk	jnb	flags3.HTTP_METHOD, :getM	; skip chk if method get 
		
		; it is post. check if we got the 'led' field in this packet
		cje	httpParseState2, #4, :getM
		setb	flags2.BROWSER_TYPE	; no, netscape type browser				
		clr	httpParseState		; clear for parser in 2nd pkt
				
:getM		clrb	flags3.GOT_HTTP_METHOD	; clear have method for nxt pkt
		clrb	flags3.GOT_URI		
		mov	w, #2			; restore the state of the
		mov	httpParseState,	w	; httpParseState variable we
	ENDIF					; borrowed for the POST parser
		retp

; ******************************************************************************
_TCPApp1Init
; Called repeatedly as long as TCP connection1 state is closed
; [TCP API Function]
; INPUT:  none
; OUTPUT: none
; ******************************************************************************

		retp
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
; YOU SHOULD HAVE 199 WORDS LEFT HERE FROM 
; $D3B TO $DFF
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################
;####################################################

	ORG	$D3B
;#############################################################
;THIS IS JUMPED TO FROM THE ISR
;#############################################################
TEST1			;NOT GOING TO WORK.
	_BANK	SILO_BANK
	CJE	SILO,#1,S1
	CJE	SILO,#2,S2
	CJE	SILO,#3,S3
	CJE	SILO,#4,S4
	CJE	SILO,#5,S5
	CJE	SILO,#6,S6
	CJE	SILO,#7,S7
	CJE	SILO,#8,S8
	CJE	SILO,#9,S9
	JMP	@RXDONE1			;IF NONE THEN JUMP BACK		
S1
	MOV	SILO1,ASCII
	JMP	@RXDONE1
S2
	MOV	SILO2,ASCII
	JMP	@RXDONE1
S3
	MOV	SILO3,ASCII
	JMP	@RXDONE1
S4	
	MOV	SILO4,ASCII
	JMP	@RXDONE1
S5
	SETB	FSR.4
	MOV	SILO5,M_ASCII
	JMP	@RXDONE1
S6
	SETB	FSR.4
	MOV	SILO6,M_ASCII
	JMP	@RXDONE1
S7
	SETB	FSR.4
	MOV	SILO7,M_ASCII
	JMP	@RXDONE1
S8
	SETB	FSR.4
	MOV	SILO8,M_ASCII
	JMP	@RXDONE1
S9
	SETB	FSR.4
	MOV	SILO9,M_ASCII
	JMP	@RXDONE1

TEST2
	_BANK	SILO_BANK
	CJE	SILO,#1,SA1
	CJE	SILO,#2,SA2
	CJE	SILO,#3,SA3
	CJE	SILO,#4,SA4
	CJE	SILO,#5,SA5
	CJE	SILO,#6,SA6
	CJE	SILO,#7,SA7
	CJE	SILO,#8,SA8
	CJE	SILO,#9,SA9
	JMP	@RXDONE1			;IF NONE THEN JUMP BACK		
SA1
	MOV	SILO1+1,ASCII
	JMP	@RXDONE1
SA2
	MOV	SILO2+1,ASCII
	JMP	@RXDONE1
SA3
	MOV	SILO3+1,ASCII
	JMP	@RXDONE1
SA4
	MOV	SILO4+1,ASCII
	JMP	@RXDONE1
SA5
	SETB	FSR.4
	MOV	SILO5+1,M_ASCII
	JMP	@RXDONE1
SA6
	SETB	FSR.4
	MOV	SILO6+1,M_ASCII
	JMP	@RXDONE1
SA7
	SETB	FSR.4
	MOV	SILO7+1,M_ASCII
	JMP	@RXDONE1
SA8
	SETB	FSR.4
	MOV	SILO8+1,M_ASCII
	JMP	@RXDONE1
SA9
	SETB	FSR.4
	MOV	SILO9+1,M_ASCII
	JMP	@RXDONE1			




	ORG	$E00	; Page7

TCPApp2Init	jmp	_TCPApp2Init
DeleteSocket1	jmp	_DeleteSocket1
DeleteSocket2	jmp	_DeleteSocket2

	IF	HTTP
; jump table can be moved with all E2 functions if neccessary.
E2Delay600ns	jmp	_E2Delay600ns
E2Delay900ns	jmp	_E2Delay900ns
E2Delay1300ns	jmp	_E2Delay1300ns
E2SDAInput	jmp	_E2SDAInput
E2SDAOutputHi	jmp	_E2SDAOutputHi
E2SDAOutputLo	jmp	_E2SDAOutputLo
E2GenStartCond	jmp	_E2GenStartCond
E2GenStopCond	jmp	_E2GenStopCond
E2Write8	jmp	_E2Write8
E2Read8		jmp	_E2Read8
E2Read8Ack	jmp	_E2Read8Ack
E2Read8NoAckStop jmp	_E2Read8NoAckStop
E2RecvAck	jmp	_E2RecvAck
E2SendAck	jmp	_E2SendAck
E2SendNotAck	jmp	_E2SendNotAck
E2SendRdCmd	jmp	_E2SendRdCmd
E2SendWrCmd	jmp	_E2SendWrCmd
E2SetAddr	jmp	_E2SetAddr
Bin8ToBCD	jmp	_Bin8ToBCD
BCDToASCII	jmp	_BCDToASCII
	ENDIF



; ******************************************************************************
NICReadAgain_7
; Shortform for calling NICReadAgain(), which is in Page1 (This is in Page7)
; ******************************************************************************
		jmp	@NICReadAgain

; ******************************************************************************
NICWriteAgain_7
; Shortform for calling NICWriteAgain(), which is in Page1 (This is in Page7)
; ******************************************************************************
		jmp	@NICWriteAgain

; ******************************************************************************
NICDumpRxFrame_7
; Shortform for calling NICDumpRxFrame(), which is in Page1 (This is in Page7)
; ******************************************************************************
		jmp	@NICDumpRxFrame

; ******************************************************************************
UDPEndPktOut
; Wraps up and transmits the UDP packet
; [UDP API Function]
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		_bank	NIC_BANK
		jmp	@NICSendTxFrameNow

; ******************************************************************************
UDPAppInit
; Application UDP Initialization code (Example)
; This function is called automatically once by the stack During startup
; [UDP API Function]
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		_bank	 UDP_BANK
		mov	udpRxDestPortMSB, #UDP_RX_DEST_MSB
		mov	udpRxDestPortLSB, #UDP_RX_DEST_LSB
		retp

; ******************************************************************************
UDPAppProcPktIn
; Application Incoming UDP packet handler (Example)
; This function is called whenever an application (matches udpRxDestPortxSB)
; packet is received. The appplication can call NICReadAgain() to extract
; sequentially extract each byte of the <data> field in the UDP packet.
; [UDP API Function]
; INPUT:  {udpRxDataLenMSB,udpRxDataLenLSB} = number of bytes in UDP <data>
;	  {udpRxSrcPortMSB,udpRxSrcPortLSB} = UDP <source_port>
; OUTPUT: none
; ******************************************************************************									
		call	NICReadAgain_7
		and	w, #%01000000
		xor	ra, w		; toggle I/O pins
		_bank	UDP_BANK
		clr	udpTxSrcPortMSB
		clr	udpTxSrcPortLSB

		mov	udpTxDestPortMSB, udpRxSrcPortMSB
		mov	udpTxDestPortLSB, udpRxSrcPortLSB

		clr	udpTxDataLenMSB		; send 2 bytes of data
		mov	udpTxDataLenLSB, #2	;

		call	UDPStartPktOut

		mov	w, ra		; send new port state
		call	NICWriteAgain_7
		mov	w, #$00		; one-byte padding
		call	NICWriteAgain_7

		jmp	UDPEndPktOut

; ******************************************************************************
UDPStartPktOut
; Starts an outgoing UDP packet by constructing an IP and UDP packet header
; [UDP API Function]
; INPUT:  {remoteIP0-3} = Destination IP addr for UDP pkt
;	  {udpTxSrcPortMSB,udpTxSrcPortLSB} = UDP Source Port
;	  {udpTxDestPortMSB,udpTxDestPortLSB} = UDP Destination Port
;	  {udpTxDataLenMSB,udpTxDataLenLSB} = UDP Data Length (just Data)
; OUTPUT: none
; ******************************************************************************
		; compute IP <total_length>
		_bank	UDP_BANK
		mov	w, udpTxDataLenLSB
		_bank	IP_BANK
		mov	ipLengthLSB, w
		_bank	UDP_BANK
		mov	w, udpTxDataLenMSB
		_bank	IP_BANK
		mov	ipLengthMSB, w
		add	ipLengthLSB, #(20+8)	; add in size of UDP hdr (8)
						; and IP hdr (20)
		snc
		inc	ipLengthMSB

		; update IP <identifier>
		inc	ipIdentLSB
		snz
		inc	ipIdentMSB

		; set IP <protocol> for UDP
		mov	ipProtocol, #17

		; compute IP <header_checksum>
		call	@IPGenCheckSum

		; now we're ready to construct the IP header
		call	@IPStartPktOut

		; then construct the UDP header

		_bank	UDP_BANK

		; UDP <source_port>
		mov	w, udpTxSrcPortMSB
		call	NICWriteAgain_7
		mov	w, udpTxSrcPortLSB
		call	NICWriteAgain_7

		; UDP <destination_port>
		mov	w, udpTxDestPortMSB
		call	NICWriteAgain_7
		mov	w, udpTxDestPortLSB
		call	NICWriteAgain_7

		; UDP <length>
		mov	w, #8
		add	w, udpTxDataLenLSB
		mov	w, udpTxDataLenMSB
		snc
		inc	wreg
		call	NICWriteAgain_7
		mov	w, #8
		add	w, udpTxDataLenLSB
		call	NICWriteAgain_7

		; UDP <checksum> = 0
		mov	w, #$0
		call	NICWriteAgain_7
		jmp	NICWriteAgain_7

; ******************************************************************************
UDPProcPktIn
; Processes an Incoming UDP packet
; INPUT:  nicCurrPktPtr = points to beginning of received packet
; OUTPUT: none
; ******************************************************************************					
		_bank	UDP_BANK

		; UDP <source_port>
		call	NICReadAgain_7
		mov	udpRxSrcPortMSB, w
		call	NICReadAgain_7
		mov	udpRxSrcPortLSB, w

		; UDP <destination_port>
		call	NICReadAgain_7
		xor	w, udpRxDestPortMSB
		jnz	:outtaHere
		call	NICReadAgain_7
		xor	w, udpRxDestPortLSB
		jnz	:outtaHere

		; UDP <message_length>
		call	NICReadAgain_7
		mov	udpRxDataLenMSB, w
		call	NICReadAgain_7
		mov	udpRxDataLenLSB, w

		; ignore UDP <checksum>
	REPT	2
		call	NICReadAgain_7
	ENDR

		; UDP <data>

		
		sb	flags.RX_IS_IP_BCST
		call	UDPAppProcPktIn		

:outtaHere	_bank	IP_BANK
		jmp	NICDumpRxFrame_7



	IF	HTTP
; ******************************************************************************
_E2Delay600ns
;	Delay 600ns
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		mov	w, #6
:loop		decsz	wreg
		jmp	:loop
		retp

; ******************************************************************************
_E2Delay900ns
;	Delay 900ns
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		mov	w, #8
:loop		decsz	wreg
		jmp	:loop
		retp

; ******************************************************************************
_E2Delay1300ns
;	Delay 1300ns
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		mov	w, #13
:loop		decsz	wreg
		jmp	:loop
		retp

; ******************************************************************************
_E2SDAInput
_E2SDAOutputHi
; Set SDA as input
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		mov	!E2_PORT, #E2_DDR_SDA_IN
		retp

; ******************************************************************************
_E2SDAOutputLo
; Set SDA as output-low
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		clrb	E2SDA_PIN
		mov	!E2_PORT, #E2_DDR_SDA_OUT
		retp

; ******************************************************************************
_E2GenStartCond
; Generate START condition
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		call	E2SDAOutputHi
		setb	E2SCL_PIN
		call	E2Delay600ns
		call	E2SDAOutputLo
		call	E2Delay600ns
		clrb	E2SCL_PIN
		call	E2Delay600ns
		retp

; ******************************************************************************
_E2GenStopCond
; Generate STOP condition
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		call	E2SDAOutputLo
		setb	E2SCL_PIN
		call	E2Delay600ns
		call	E2SDAOutputHi
		call	E2Delay1300ns
		retp

; ******************************************************************************
_E2Write8
; Write 8 bits out the I2C bus
; INPUT:  w = Data to write
; OUTPUT: none
; ******************************************************************************
		mov	globTemp1, w	;	Data buffer
		mov	globTemp2, #8	; bit counter
:loop		call	E2Delay900ns
		sb	globTemp1.7
		call	E2SDAOutputLo
		snb	globTemp1.7
		call	E2SDAOutputHi
		call	E2Delay900ns
		setb	E2SCL_PIN
		call	E2Delay600ns
		clrb	E2SCL_PIN
		rl	globTemp1
		decsz	globTemp2
		jmp	:loop
		retp

; ******************************************************************************
_E2Read8
; Read 8 bits from the I2C bus
; INPUT:  none
; OUTPUT: w = Data read
; ******************************************************************************
		call	E2SDAInput
		mov	globTemp2, #8	; bit counter
:loop		call	E2Delay900ns
		sb	E2SDA_PIN
		clc
		snb	E2SDA_PIN
		stc
		rl	globTemp1
		setb	E2SCL_PIN
		call	E2Delay600ns
		clrb	E2SCL_PIN
		call	E2Delay900ns
		decsz	globTemp2
		jmp	:loop
		mov	w, globTemp1
		retp

; ******************************************************************************
_E2Read8Ack
; Read 8 bits from the I2C bus and send ACK
; INPUT:  none
; OUTPUT: w = Data read
; ******************************************************************************
		call	E2Read8
		mov	globTemp1, w
		call	E2SendAck
		mov	w, globTemp1
		retp

; ******************************************************************************
_E2Read8NoAckStop
; Read 8 bits from the I2C bus and send a no-ACK and stop-condition
; (terminates sequential read mode on EEPROM)
; INPUT:  none
; OUTPUT: w = Data read
; ******************************************************************************
		call	E2Read8
		mov	globTemp1, w
		call	E2SendNotAck
		call	E2GenStopCond
		mov	w, globTemp1
		retp

; ******************************************************************************
_E2RecvAck
; Receive ACK bit from I2C receiver
; INPUT:  none
; OUTPUT: z: 1 = received ACK, 0 = Didn't receive ACK
; ******************************************************************************
		call	E2SDAInput
		call	E2Delay900ns
		setb	E2SCL_PIN
		sb	E2SDA_PIN
		stz
		snb	E2SDA_PIN
		clz
		call	E2Delay600ns
		clrb	E2SCL_PIN
		call	E2Delay900ns
		retp

; ******************************************************************************
_E2SendAck
; Send ACK bit as acknowledge
; INPUT:  none
; OUTPUT: z: 1 = received ACK, 0 = Didn't receive ACK
; ******************************************************************************
		call	E2SDAOutputLo
		call	E2Delay900ns
		setb	E2SCL_PIN
		call	E2Delay600ns
		clrb	E2SCL_PIN
		call	E2Delay900ns
		retp

; ******************************************************************************
_E2SendNotAck
; Send ACK bit as not-acknowledge
; INPUT:  none
; OUTPUT: z: 1 = received ACK, 0 = Didn't receive ACK
; ******************************************************************************
		call	E2SDAOutputHi
		call	E2Delay900ns
		setb	E2SCL_PIN
		call	E2Delay600ns
		clrb	E2SCL_PIN
		call	E2Delay900ns
		retp

; ******************************************************************************
_E2SendRdCmd
; Tell I2C Device we wish to read from it for this transaction
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		call	E2GenStartCond
		mov	w, #E2_CMD_RD
		call	E2Write8
		call	E2RecvAck
		retp

; ******************************************************************************
_E2SendWrCmd
; Tell I2C Device we wish to write to it for this transaction
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		call	E2GenStartCond
		mov	w, #E2_CMD_WR
		call	E2Write8
		call	E2RecvAck
		retp

; ******************************************************************************
_E2SetAddr
; Set address pointer
; INPUT:  {e2AddrMSB, e2AddrLSB} = address to set to
; OUTPUT: none
; ******************************************************************************
		call	E2SendWrCmd
		_bank	EEPROM_BANK
		mov	w, e2AddrMSB
		call	E2Write8
		call	E2RecvAck
		mov	w, e2AddrLSB
		call	E2Write8
		call	E2RecvAck
		retp

; ******************************************************************************
_Bin8ToBCD
; Converts 8-bit binary number to unpacked BCD
; INPUT:  w = binary number to convert
;	  fsr = pointer to MSD (lowest addr) of a 3-byte buffer
; OUTPUT: [fsr] = unpacked BCD
; ******************************************************************************
		clr	indf
		inc	fsr
		clr	indf
		inc	fsr		; LSD
		mov	indf, w

:loopHun	mov	w, #100
		mov	w, indf-w
		jnc	:loopTen
		mov	indf, w
		dec	fsr
		dec	fsr		; MSD
		inc	indf
		inc	fsr
		inc	fsr		; LSD
		jmp	:loopHun

:loopTen	mov	w, #10
		mov	w, indf-w
		sc
		jmp	:exit
		mov	indf, w
		dec	fsr
		inc	indf
		inc	fsr
		jmp	:loopTen

:exit		retp

; ******************************************************************************
_BCDToASCII
; Converts an unpacked BCD number to an ASCII character
; INPUT:  w = unpacked BCD
; OUTPUT: w = ASCII character
; ******************************************************************************
		mov	globTemp1, w
		mov	w, #'0'
		add	w, globTemp1
		retp
	ENDIF

; ******************************************************************************
_TCPApp2Init
; Called repeatedly as long as TCP connection2 state is closed
; [TCP API Function]
; INPUT:  none
; OUTPUT: none
; ******************************************************************************
		; set up local port for tcp2 connection
	IF	HTTP
		_bank	TCB2_BANK
		mov	tcb2LocalPortLSB, #HTTP_PORT_LSB
		mov	tcb2LocalPortMSB, #HTTP_PORT_MSB

		bank	HTTP_BANK
		clr	httpParseState
		clr	httpURIHash

		; indicate tcp2 connection
		setb	flags2.TCP_SOCK
		jmp	@TCPAppPassiveOpen
	ENDIF
		retp

; ******************************************************************************
_DeleteSocket1
; Deletes TCP socket1
; INPUT: none
; OUTPUT: sock1RemoteIP3-0
; ******************************************************************************
		_bank	TCPSOCKET_BANK
		clr	sock1RemoteIP3
		clr	sock1RemoteIP2
		clr	sock1RemoteIP1
		clr	sock1RemoteIP0
		retp

; ******************************************************************************
_DeleteSocket2
; Deletes TCP socket1
; INPUT: none
; OUTPUT: sock2RemoteIP3-0
; ******************************************************************************
		_bank	TCPSOCKET_BANK
		clr	sock2RemoteIP3
		clr	sock2RemoteIP2
		clr	sock2RemoteIP1
		clr	sock2RemoteIP0
		retp


SILO7W	

		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO7
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO7+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO7+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		JMP	@HERE1

SILO8W	
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO8
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO8+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO8+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		JMP	@HERE1

SILO9W	
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO9
		BANK	MISC_BANK
		MOV	BCD3,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO9+1
		BANK	MISC_BANK
		MOV	BCD3+1,W
		_BANK	SILO_BANK
		SETB	FSR.4
		MOV	W,SILO9+2
		BANK	MISC_BANK
		MOV	BCD3+2,W
		_BANK	SILO_BANK
		CLR	SILOINC				;CLEAR THE SILOINC SO IT CAN START OVER FROM 1
HERE1
		BANK	MISC_BANK			;YOU HAVE TO HAVE THIS.
		MOV	W, bcd3+0
		retp

;
;TIM FOR THIS TO BE MOVED INTO :HERE1 THEN YOU MIGHT WANT TO TRY AND MOV TO IT USING THE JMP WITH A 
;MOV M,$B THIS WILL  TAKE YOU TO IT I THINK.


; ***********
; *** END ***
; ***********
	END



file: /Techref/scenix/bindicator/silo1.1.src, 158KB, , updated: 2002/1/7 13:22, local time: 2024/4/24 17:48,
TOP NEW HELP FIND: 
13.58.77.98:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://www.sxlist.com/techref/scenix/bindicator/silo1.1.src"> scenix bindicator silo1</A>

Did you find what you needed?

 

Welcome to sxlist.com!


Site supported by
sales, advertizing,
& kind contributors
just like you!

Please don't rip/copy
(here's why

Copies of the site on CD
are available at minimal cost.
 

Welcome to www.sxlist.com!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  .