;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