emailler/docs/drivers_w5100_s.html

1123 lines
28 KiB
HTML

<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><link rel="stylesheet" type="text/css" href="ca65-doc-style.css"/></head><body><a href="ref_index.html"><h1>ip65 technical reference</h1></a><h1>File : drivers/w5100.s</h1><pre> Ethernet driver for W5100 W5100 chip
</pre><h2 id="functions">functions</h2><table><tr><th>function</th><th>description</th></tr><tr><td id="eth_init">eth_init</td><td><pre>initialize the ethernet adaptor
inputs: none
outputs: carry flag is set if there was an error, clear otherwise
this implementation uses a default address for the w5100, and can be
called as a 'generic' eth driver init function
</pre></td></tr><tr><td id="eth_rx">eth_rx</td><td><pre>receive a packet
inputs: none
outputs:
if there was an error receiving the packet (or no packet was ready) then carry flag is set
if packet was received correctly then carry flag is clear,
eth_inp contains the received packet,
and eth_inp_len contains the length of the packet
</pre></td></tr><tr><td id="eth_tx">eth_tx</td><td><pre> send a packet
inputs:
eth_outp: packet to send
eth_outp_len: length of packet to send
outputs:
if there was an error sending the packet then carry flag is set
otherwise carry flag is cleared
</pre></td></tr><tr><td id="tcp_close">tcp_close</td><td><pre>close the current connection
inputs:
none
outputs:
carry flag is set if an error occured, clear otherwise
</pre></td></tr><tr><td id="tcp_connect">tcp_connect</td><td><pre>make outbound tcp connection
inputs:
tcp_connect_ip: destination ip address (4 bytes)
AX: destination port (2 bytes)
tcp_callback: vector to call when data arrives on this connection
outputs:
carry flag is set if an error occured, clear otherwise
</pre></td></tr><tr><td id="tcp_listen">tcp_listen</td><td><pre>listen for an inbound tcp connection
this is a 'blocking' call, i.e. it will not return until a connection has been made
inputs:
AX: destination port (2 bytes)
tcp_callback: vector to call when data arrives on this connection
outputs:
carry flag is set if an error occured, clear otherwise
</pre></td></tr><tr><td id="tcp_send">tcp_send</td><td><pre>send tcp data
inputs:
tcp connection should already be opened
tcp_send_data_len: length of data to send (exclusive of any headers)
AX: pointer to buffer containing data to be sent
outputs:
carry flag is set if an error occured, clear otherwise
</pre></td></tr><tr><td id="tcp_send_keep_alive">tcp_send_keep_alive</td><td><pre>send an empty ACK packet on the current connection
inputs:
none
outputs:
carry flag is set if an error occured, clear otherwise
</pre></td></tr><tr><td id="tcp_send_string">tcp_send_string</td><td><pre>send a string over the current tcp connection
inputs:
tcp connection should already be opened
AX: pointer to buffer - data up to (but not including)
the first nul byte will be sent. max of 255 bytes will be sent.
outputs:
carry flag is set if an error occured, clear otherwise
</pre></td></tr><tr><td id="w5100_ip65_init">w5100_ip65_init</td><td><pre>initialize the ip65 stack for the w5100 ethernet adaptor
inputs: none
outputs: carry flag is set if there was an error, clear otherwise
</pre></td></tr><tr><td id="w5100_read_register">w5100_read_register</td><td><pre> read one of the W5100 registers
inputs: AX = register number to read
outputs: A = value of nominated register
y is overwritten
</pre></td></tr><tr><td id="w5100_select_register">w5100_select_register</td><td><pre>
select one of the W5100 registers for subsequent read or write
inputs: AX = register number to select
outputs: none
</pre></td></tr><tr><td id="w5100_set_ip_config">w5100_set_ip_config</td><td><pre>copy the IP65 configuration to the the w5100 onchip configuration
we assume MAC has been configured already via eth_init, but IP
address etc may not be known when the w5100 was initialised (e.g.
if using DHCP).
</pre></td></tr><tr><td id="w5100_write_register">w5100_write_register</td><td><pre> write to one of the W5100 registers
inputs: AX = register number to write
Y = value to write to register
outputs: none
</pre></td></tr></table><h2 id="variables">variables</h2><table><tr><th>variable</th><th>description</th><th>size (bytes)</th></tr><tr><td id="tcp_callback">tcp_callback</td><td>vector to routine to be called when data is received over tcp connection
</td><td>2</td></tr><tr><td id="tcp_connect_ip">tcp_connect_ip</td><td>ip address of remote server to connect to
</td><td>4</td></tr><tr><td id="tcp_connect_remote_port">tcp_connect_remote_port</td><td></td><td>2</td></tr><tr><td id="tcp_inbound_data_length">tcp_inbound_data_length</td><td></td><td>2</td></tr><tr><td id="tcp_inbound_data_ptr">tcp_inbound_data_ptr</td><td></td><td>2</td></tr><tr><td id="tcp_send_data_len">tcp_send_data_len</td><td></td><td>2</td></tr><tr><td id="tcp_state">tcp_state</td><td></td><td>1</td></tr></table><h2 id="constants">constants</h2><table><tr><th>constants</th><th>description</th><th>value</th></tr><tr><td id="eth_driver_io_base">eth_driver_io_base</td><td></td><td></td></tr><tr><td id="eth_driver_name">eth_driver_name</td><td></td><td>"RR-NET MK3 (WIZNET 5100)"
</td></tr><tr><td id="tcp_remote_ip">tcp_remote_ip</td><td></td><td>tcp_connect_ip
</td></tr></table><h2>implementation</h2><pre id="code">; Ethernet driver for W5100 W5100 chip
;
.ifndef KPR_API_VERSION_NUMBER
.define EQU =
.include "../inc/kipper_constants.i"
.endif
.include "../inc/common.i"
.include "w5100.i"
WIZNET_BASE=$DE04
WIZNET_MODE_REG = WIZNET_BASE
WIZNET_ADDR_HI = WIZNET_BASE+1
WIZNET_ADDR_LO = WIZNET_BASE+2
WIZNET_DATA_REG = WIZNET_BASE+3
;DEBUG = 1
.export eth_init
.export eth_rx
.export eth_tx
.export eth_driver_name
.export eth_driver_io_base
.import eth_inp
.import eth_inp_len
.import eth_outp
.import eth_outp_len
.import timer_init
.import timer_read
.import arp_init
.import ip_init
.import cfg_init
.importzp eth_dest
.importzp eth_src
.importzp eth_type
.importzp eth_data
.importzp copy_src
.importzp copy_dest
.export w5100_ip65_init
.export w5100_read_register
.export w5100_select_register
.export w5100_write_register
.export w5100_set_ip_config
.export tcp_connect
.export tcp_connect_ip
.export tcp_callback
.export tcp_send_data_len
.export tcp_send_string
.export tcp_send
.export tcp_send_keep_alive
.export tcp_close
.export tcp_state
.export tcp_connect_remote_port
.export tcp_remote_ip
.export tcp_listen
.export tcp_inbound_data_ptr
.export tcp_inbound_data_length
.import cfg_mac
.import cfg_ip
.import cfg_netmask
.import cfg_gateway
.import ip65_error
.import ip65_process
.import check_for_abort_key
.code
;initialize the ethernet adaptor
;inputs: none
;outputs: carry flag is set if there was an error, clear otherwise
;this implementation uses a default address for the w5100, and can be
;called as a 'generic' eth driver init function
eth_init:
lda $de01
ora #1 ;turn on clockport
sta $de01
lda #$80 ;reset
sta WIZNET_MODE_REG
lda WIZNET_MODE_REG
bne @error ;writing a byte to the MODE register with bit 7 set should reset.
;after a reset, mode register is zero
;therefore, if there is a real W5100 at the specified address,
;we should be able to write a $80 and read back a $00
lda #$13 ;set indirect mode, with autoinc, no auto PING
sta WIZNET_MODE_REG
lda WIZNET_MODE_REG
cmp #$13
bne @error ;make sure if we write to mode register without bit 7 set,
;the value persists.
lda #$00
sta WIZNET_ADDR_HI
lda #$16
sta WIZNET_ADDR_LO
ldx #$00 ;start writing to reg $0016 - Interrupt Mask Register
@loop:
lda w5100_config_data,x
sta WIZNET_DATA_REG
inx
cpx #$06
bne @loop
lda #$09
sta WIZNET_ADDR_LO
ldx #$00 ;start writing to reg $0009 - MAC address
@mac_loop:
lda cfg_mac,x
sta WIZNET_DATA_REG
inx
cpx #$06
bne @mac_loop
;set up socket 0 for MAC RAW mode
ldax #W5100_RMSR ;rx memory size (each socket)
stx WIZNET_ADDR_HI
sta WIZNET_ADDR_LO
lda #$0A ;sockets 0 & 1 4KB each, other sockets 0KB
;if this is changed, change the mask in eth_rx as well!
sta WIZNET_DATA_REG
ldax #W5100_TMSR ;rx memory size (each socket)
stx WIZNET_ADDR_HI
sta WIZNET_ADDR_LO
lda #$0A ;sockets 0 & 1 4KB each, other sockets 0KB
;if this is changed, change the mask in eth_tx as well!
sta WIZNET_DATA_REG
ldax #W5100_S0_MR
stx WIZNET_ADDR_HI
sta WIZNET_ADDR_LO
lda #W5100_MODE_MAC_RAW
sta WIZNET_DATA_REG
;open socket 0
jsr w5100_write_register
ldax #W5100_S0_CR
stx WIZNET_ADDR_HI
sta WIZNET_ADDR_LO
lda #W5100_CMD_OPEN
sta WIZNET_DATA_REG
lda #tcp_cxn_state_closed
sta tcp_state
clc
rts
@error:
sec
rts ;
;initialize the ip65 stack for the w5100 ethernet adaptor
;inputs: none
;outputs: carry flag is set if there was an error, clear otherwise
w5100_ip65_init:
jsr cfg_init ;copy default values (including MAC address) to RAM
jsr eth_init
bcc @ok
lda #KPR_ERROR_DEVICE_FAILURE
sta ip65_error
rts
@ok:
jsr timer_init ; initialize timer
jsr arp_init ; initialize arp
jsr ip_init ; initialize ip, icmp, udp, and tcp
clc
rts
;receive a packet
;inputs: none
;outputs:
; if there was an error receiving the packet (or no packet was ready) then carry flag is set
; if packet was received correctly then carry flag is clear,
; eth_inp contains the received packet,
; and eth_inp_len contains the length of the packet
eth_rx:
;eth_rx will get called in the main polling loop
;we shoe horn a check for data on the TCP socket here
;if we do get TCP data, we will call the TCP callback routine
;but we hide all of this from the ip65 stack proper.
lda tcp_state
beq @no_tcp
jsr tcp_rx
bcc @no_tcp ;if we didn't get any TCP traffic, go check for a raw ethernet packet
;eth_inp and eth_inp_len are not valid, so leave carry flag set to indicate no ethernet frame data
rts
@no_tcp:
ldax #W5100_S0_RX_RSR0
jsr w5100_read_register
sta eth_inp_len+1
ldax #W5100_S0_RX_RSR1
jsr w5100_read_register
sta eth_inp_len
bne @got_data
lda eth_inp_len+1
bne @got_data
sec
rts
@got_data:
lda #$8D ;opcode for STA
sta next_eth_packet_byte
ldax #eth_inp
stax copy_dest
lda #2
sta byte_ctr_lo
lda #0
sta byte_ctr_hi
;read the 2 byte frame length
jsr @get_current_rx_rd
jsr @mask_and_adjust_rx_read
ldax rx_rd_ptr
jsr w5100_read_register
sta eth_inp_len+1 ;high byte of frame length
jsr @inc_rx_rd_ptr
ldax rx_rd_ptr
jsr w5100_read_register
sta eth_inp_len ;lo byte of frame length
;now copy the rest of the frame to the eth_inp buffer
;we keep our own copy of RX_RD_PTR in sync, rather than read WIZNET_ADDR registers
;because of issue where reads to WIZNET_ADDR can cause the autoinc ptr to advance erroneously
;when WizNet cart used in a cartridge expander
ldy #0
@get_next_byte:
inc rx_rd_ptr
bne :+
inc rx_rd_ptr+1
lda rx_rd_ptr+1
and #$0F
clc
adc #$60
sta rx_rd_ptr+1
sta WIZNET_ADDR_HI
:
lda WIZNET_DATA_REG
sta (copy_dest),y
iny
bne :+
inc copy_dest+1
:
inc byte_ctr_lo
bne :+
inc byte_ctr_hi
:
lda byte_ctr_lo
cmp eth_inp_len
bne @get_next_byte
lda byte_ctr_hi
cmp eth_inp_len+1
bne @get_next_byte
;update the RX RD pointer past the frame we just read
jsr @get_current_rx_rd
clc
lda rx_rd_ptr
adc eth_inp_len
sta rx_rd_ptr
lda rx_rd_ptr+1
adc eth_inp_len+1
tay
ldax #W5100_S0_RX_RD0
jsr w5100_write_register
ldy rx_rd_ptr
ldax #W5100_S0_RX_RD1
jsr w5100_write_register
ldax #W5100_S0_CR
ldy #W5100_CMD_RECV
jsr w5100_write_register
;now adjust the input length to remove the 2 byte header length
sec
lda eth_inp_len
sbc #2
sta eth_inp_len
bcs :+
dec eth_inp_len
:
clc
rts
@inc_rx_rd_ptr:
inc rx_rd_ptr
bne :+
inc rx_rd_ptr+1
@mask_and_adjust_rx_read:
lda rx_rd_ptr+1
and #$0F
clc
adc #$60
sta rx_rd_ptr+1
:
rts
@get_current_rx_rd:
ldax #W5100_S0_RX_RD0
jsr w5100_read_register
sta rx_rd_ptr+1
ldax #W5100_S0_RX_RD1
jsr w5100_read_register
sta rx_rd_ptr
rts
; send a packet
;inputs:
; eth_outp: packet to send
; eth_outp_len: length of packet to send
;outputs:
; if there was an error sending the packet then carry flag is set
; otherwise carry flag is cleared
eth_tx:
lda #$AD ;opcode for LDA
sta next_eth_packet_byte
ldax #eth_outp
sta eth_ptr_lo
stx eth_ptr_hi
lda #0
sta byte_ctr_lo
sta byte_ctr_hi
jsr @get_current_tx_wr
jmp @calculate_tx_wr_ptr
@send_next_byte:
jsr next_eth_packet_byte
tay
ldax tx_wr_ptr
jsr w5100_write_register
inc byte_ctr_lo
bne :+
inc byte_ctr_hi
:
inc tx_wr_ptr
bne :+
inc tx_wr_ptr+1
@calculate_tx_wr_ptr:
lda tx_wr_ptr+1
and #$0F
clc
adc #$40
sta tx_wr_ptr+1
:
lda byte_ctr_lo
cmp eth_outp_len
bne @send_next_byte
lda byte_ctr_hi
cmp eth_outp_len+1
bne @send_next_byte
;all bytes copied, now adjust the tx write ptr and SEND
jsr @get_current_tx_wr
clc
lda tx_wr_ptr
adc eth_outp_len
sta tx_wr_ptr
lda tx_wr_ptr+1
adc eth_outp_len+1
tay
ldax #W5100_S0_TX_WR0
jsr w5100_write_register
ldy tx_wr_ptr
ldax #W5100_S0_TX_WR1
jsr w5100_write_register
ldax #W5100_S0_CR
ldy #W5100_CMD_SEND
jsr w5100_write_register
clc
rts
@get_current_tx_wr:
ldax #W5100_S0_TX_WR0
jsr w5100_read_register
sta tx_wr_ptr+1
ldax #W5100_S0_TX_WR1
jsr w5100_read_register
sta tx_wr_ptr
rts
advance_eth_ptr:
inc eth_ptr_lo
bne :+
inc eth_ptr_hi
:
rts
; read one of the W5100 registers
; inputs: AX = register number to read
; outputs: A = value of nominated register
; y is overwritten
w5100_read_register:
jsr w5100_select_register
lda WIZNET_DATA_REG
rts
; write to one of the W5100 registers
; inputs: AX = register number to write
; Y = value to write to register
; outputs: none
w5100_write_register:
jsr w5100_select_register
tya
sta WIZNET_DATA_REG
rts
;listen for an inbound tcp connection
;this is a 'blocking' call, i.e. it will not return until a connection has been made
;inputs:
; AX: destination port (2 bytes)
; tcp_callback: vector to call when data arrives on this connection
;outputs:
; carry flag is set if an error occured, clear otherwise
tcp_listen:
stax tcp_local_port
jsr setup_tcp_socket
ldax #W5100_S1_CR
ldy #W5100_CMD_LISTEN
jsr w5100_write_register
;now wait for the status to change to 'established'
@listen_loop:
; inc $d020
jsr ip65_process
jsr check_for_abort_key
bcc @no_abort
lda #KPR_ERROR_ABORTED_BY_USER
sta ip65_error
sec
rts
@no_abort:
ldax #W5100_S1_SR
jsr w5100_read_register
cmp #W5100_STATUS_SOCK_ESTABLISHED
bne @listen_loop
lda #tcp_cxn_state_established
sta tcp_state
;copy the remote IP address & port number
ldax #W5100_S1_DIPR0
jsr w5100_select_register
ldx #0
@ip_loop:
lda WIZNET_DATA_REG
sta tcp_remote_ip,x
inx
cpx #$04
bne @ip_loop
ldax #W5100_S1_DPORT0
jsr w5100_select_register
lda WIZNET_DATA_REG
sta tcp_connect_remote_port+1
lda WIZNET_DATA_REG
sta tcp_connect_remote_port
clc
rts
;make outbound tcp connection
;inputs:
; tcp_connect_ip: destination ip address (4 bytes)
; AX: destination port (2 bytes)
; tcp_callback: vector to call when data arrives on this connection
;outputs:
; carry flag is set if an error occured, clear otherwise
tcp_connect:
stax tcp_remote_port
jsr timer_read ;get a pseudo random value
sta tcp_local_port+1
inc tcp_local_port
jsr setup_tcp_socket
;set the destination IP address
ldax #W5100_S1_DIPR0
jsr w5100_select_register
ldx #0
@remote_ip_loop:
lda tcp_connect_ip,x
sta WIZNET_DATA_REG
inx
cpx #$04
bne @remote_ip_loop
ldx #0
;W5100 register address is now W5100_S1_DPORT0, so set the destination port
lda tcp_remote_port+1
sta WIZNET_DATA_REG
lda tcp_remote_port
sta WIZNET_DATA_REG
ldax #W5100_S1_CR
ldy #W5100_CMD_CONNECT
jsr w5100_write_register
;now wait for the status to change to 'established'
@connect_loop:
ldax #W5100_S1_SR
jsr w5100_read_register
cmp #W5100_STATUS_SOCK_CLOSED
beq @error
cmp #W5100_STATUS_SOCK_ESTABLISHED
beq @ok
jsr check_for_abort_key
bcc @connect_loop
lda #KPR_ERROR_ABORTED_BY_USER
jmp @set_error_and_exit
@ok:
lda #tcp_cxn_state_established
sta tcp_state
clc
rts
@error:
lda #KPR_ERROR_CONNECTION_CLOSED
@set_error_and_exit:
sta ip65_error
sec
rts
;send a string over the current tcp connection
;inputs:
; tcp connection should already be opened
; AX: pointer to buffer - data up to (but not including)
; the first nul byte will be sent. max of 255 bytes will be sent.
;outputs:
; carry flag is set if an error occured, clear otherwise
tcp_send_string:
stax tcp_send_data_ptr
stax copy_src
lda #0
tay
sta tcp_send_data_len
sta tcp_send_data_len+1
lda (copy_src),y
bne @find_end_of_string
rts ; if the string is empty, don't send anything!
@find_end_of_string:
lda (copy_src),y
beq @done
inc tcp_send_data_len
iny
bne @find_end_of_string
@done:
ldax tcp_send_data_ptr
;now we can fall through into tcp_send
;send tcp data
;inputs:
; tcp connection should already be opened
; tcp_send_data_len: length of data to send (exclusive of any headers)
; AX: pointer to buffer containing data to be sent
;outputs:
; carry flag is set if an error occured, clear otherwise
tcp_send:
stax tcp_send_data_ptr
;are we connected?
ldax #W5100_S1_SR
jsr w5100_read_register
cmp #W5100_STATUS_SOCK_ESTABLISHED
beq @ok
lda #KPR_ERROR_CONNECTION_CLOSED
sta ip65_error
sec
rts
@ok:
lda #$AD ;opcode for LDA
sta next_eth_packet_byte
lda #0
sta byte_ctr_lo
sta byte_ctr_hi
jsr @get_current_tx_wr
jmp @calculate_tx_wr_ptr
@send_next_byte:
jsr next_eth_packet_byte
tay
ldax tx_wr_ptr
jsr w5100_write_register
inc byte_ctr_lo
bne :+
inc byte_ctr_hi
:
inc tx_wr_ptr
bne :+
inc tx_wr_ptr+1
@calculate_tx_wr_ptr:
lda tx_wr_ptr+1
and #$0F
clc
adc #$50
sta tx_wr_ptr+1
:
lda byte_ctr_lo
cmp tcp_send_data_len
bne @send_next_byte
lda byte_ctr_hi
cmp tcp_send_data_len+1
bne @send_next_byte
;all bytes copied, now adjust the tx write ptr and SEND
jsr @get_current_tx_wr
clc
lda tx_wr_ptr
adc tcp_send_data_len
sta tx_wr_ptr
lda tx_wr_ptr+1
adc tcp_send_data_len+1
tay
ldax #W5100_S1_TX_WR0
jsr w5100_write_register
ldy tx_wr_ptr
ldax #W5100_S1_TX_WR1
jsr w5100_write_register
ldax #W5100_S1_CR
ldy #W5100_CMD_SEND
jsr w5100_write_register
clc
rts
@get_current_tx_wr:
ldax #W5100_S1_TX_WR0
jsr w5100_read_register
sta tx_wr_ptr+1
ldax #W5100_S1_TX_WR1
jsr w5100_read_register
sta tx_wr_ptr
rts
;send an empty ACK packet on the current connection
;inputs:
; none
;outputs:
; carry flag is set if an error occured, clear otherwise
tcp_send_keep_alive:
;are we connected?
ldax #W5100_S1_SR
jsr w5100_read_register
cmp #W5100_STATUS_SOCK_ESTABLISHED
beq @ok
lda #KPR_ERROR_CONNECTION_CLOSED
sta ip65_error
sec
rts
@ok:
ldax #W5100_S1_CR
ldy #W5100_CMD_SEND_KEEP
jsr w5100_write_register
clc
rts
;close the current connection
;inputs:
; none
;outputs:
; carry flag is set if an error occured, clear otherwise
tcp_close:
ldax #W5100_S1_CR
ldy #W5100_CMD_DISCONNECT
jsr w5100_write_register
clc
rts
;poll the TCP socket
;if there is data available, call the user supplied TCP callback
;inputs:
; none
;outputs:
; carry flag is set if there was data, clear otherwise
tcp_rx:
;is there data?
ldax #W5100_S1_RX_RSR0
jsr w5100_read_register
sta tcp_inbound_data_length+1
ldax #W5100_S1_RX_RSR1
jsr w5100_read_register
sta tcp_inbound_data_length
bne @got_data
lda tcp_inbound_data_length+1
bne @got_data
;are we connected?
ldax #W5100_S1_SR
jsr w5100_read_register
cmp #W5100_STATUS_SOCK_ESTABLISHED
beq @connected_but_no_data
;no longer connected
lda #tcp_cxn_state_closed
sta tcp_state
lda #$ff
sta tcp_inbound_data_length
sta tcp_inbound_data_length+1
jsr @make_fake_eth_header
jsr jmp_to_callback ;let the caller see the connection has closed
sec ;don't poll the MAC RAW socket, else it may clobber the output buffer
rts
@connected_but_no_data:
clc ;no data - go check the MAC RAW socket
rts
@got_data:
lda #$8D ;opcode for STA
sta next_eth_packet_byte
ldax #eth_inp+$36 ;we will write to the location that TCP data would appear if this was a raw eth frame,
;14 bytes of ethernet header
;20 bytes of IP header
;20 bytes of TCP header
stax tcp_inbound_data_ptr
sta eth_ptr_lo
stx eth_ptr_hi
lda #0
sta byte_ctr_lo
sta byte_ctr_hi
lda tcp_inbound_data_length+1
cmp #4 ;don't allow more than $4FF bytes at once ($1279) since we are writing to a 1500 byte
bmi :+
lda #4
sta tcp_inbound_data_length+1
:
;now copy the data just arrived to the eth_inp buffer
jsr @get_current_rx_rd
jsr @mask_and_adjust_rx_read
@get_next_byte:
ldax rx_rd_ptr
jsr w5100_read_register
jsr next_eth_packet_byte
jsr @inc_rx_rd_ptr
inc byte_ctr_lo
bne :+
inc byte_ctr_hi
:
lda byte_ctr_lo
cmp tcp_inbound_data_length
bne @get_next_byte
lda byte_ctr_hi
cmp tcp_inbound_data_length+1
bne @get_next_byte
;update the RX RD pointer past the frame we just read
jsr @get_current_rx_rd
clc
lda rx_rd_ptr
adc tcp_inbound_data_length
sta rx_rd_ptr
lda rx_rd_ptr+1
adc tcp_inbound_data_length+1
tay
ldax #W5100_S1_RX_RD0
jsr w5100_write_register
ldy rx_rd_ptr
ldax #W5100_S1_RX_RD1
jsr w5100_write_register
ldax #W5100_S1_CR
ldy #W5100_CMD_RECV
jsr w5100_write_register
jsr @make_fake_eth_header
jsr jmp_to_callback ;let the caller see the connection has closed
sec ;don't poll the MAC RAW socket, else it may clobber the output buffer
rts
@inc_rx_rd_ptr:
inc rx_rd_ptr
bne :+
inc rx_rd_ptr+1
@mask_and_adjust_rx_read:
lda rx_rd_ptr+1
and #$0F
clc
adc #$70
sta rx_rd_ptr+1
:
rts
@get_current_rx_rd:
ldax #W5100_S1_RX_RD0
jsr w5100_read_register
sta rx_rd_ptr+1
ldax #W5100_S1_RX_RD1
jsr w5100_read_register
sta rx_rd_ptr
rts
;the function dispatcher (and possibly other parts of the ip65 stack) expect to find valid values in the eth_inp frame
;when processing tcp data
@make_fake_eth_header:
.import ip_inp
.import udp_inp
;first set the TCP protocol value
lda #6 ;TCP protocol number
sta ip_inp+9 ;proto number
;now copy the remote IP address
ldx #0
@ip_loop:
lda tcp_remote_ip,x
sta ip_inp+12,x ;src IP
inx
cpx #$04
bne @ip_loop
;now the local & remote ports
lda tcp_connect_remote_port
sta udp_inp+1 ;remote port (lo byte)
lda tcp_connect_remote_port+1
sta udp_inp+0 ;remote port (high byte)
lda tcp_local_port
sta udp_inp+3 ;local port (lo byte)
lda tcp_local_port+1
sta udp_inp+2 ;local port (high byte)
rts
jmp_to_callback:
jmp (tcp_callback)
;copy the IP65 configuration to the the w5100 onchip configuration
;we assume MAC has been configured already via eth_init, but IP
;address etc may not be known when the w5100 was initialised (e.g.
;if using DHCP).
w5100_set_ip_config:
ldax #W5100_GAR0
jsr w5100_select_register
ldx #0
@gateway_loop:
lda cfg_gateway,x
sta WIZNET_DATA_REG
inx
cpx #$04
bne @gateway_loop
ldx #0
@netmask_loop:
lda cfg_netmask,x
sta WIZNET_DATA_REG
inx
cpx #$04
bne @netmask_loop
ldax #W5100_SIPR0
jsr w5100_select_register
ldx #0
@ip_loop:
lda cfg_ip,x
sta WIZNET_DATA_REG
inx
cpx #$04
bne @ip_loop
rts
setup_tcp_socket:
jsr w5100_set_ip_config
ldax #W5100_S1_PORT0
jsr w5100_select_register
lda tcp_local_port+1
sta WIZNET_DATA_REG
lda tcp_local_port
sta WIZNET_DATA_REG
lda #0
sta tcp_state
ldax #W5100_S1_MR
ldy #W5100_MODE_TCP
jsr w5100_write_register
;open socket 1
ldax #W5100_S1_CR
ldy #W5100_CMD_OPEN
jsr w5100_write_register
rts
.rodata
eth_driver_name:
.asciiz "RR-NET MK3 (WIZNET 5100)"
eth_driver_io_base:
.word WIZNET_BASE
w5100_config_data:
.byte $00 ;no interrupts
.byte $0f ;400ms retry (default)
.byte $a0
.byte $08 ;# of timeouts
.byte $55 ;4 sockets @2K each, tx/rx
.byte $55
;
; select one of the W5100 registers for subsequent read or write
; inputs: AX = register number to select
; outputs: none
w5100_select_register:
set_hi:
stx WIZNET_ADDR_HI
set_lo:
sta WIZNET_ADDR_LO
rts
; return which W5100 register the next read or write will access
; inputs: none
; outputs: AX = selected register number
w5100_get_current_register:
get_hi:
ldx WIZNET_ADDR_HI
get_lo:
lda WIZNET_ADDR_LO
rts
.segment "SELF_MODIFIED_CODE"
next_eth_packet_byte:
lda $FFFF ;eth_packet
jmp advance_eth_ptr
eth_ptr_lo=next_eth_packet_byte+1
eth_ptr_hi=next_eth_packet_byte+2
; .bss
; don't use BSS because we are out of room in the location that lives in the
; config used for 16K carts ($C010..$CFFF)
;there seems to be a little room still free in the seg used for SELF_MODIFIED_CODE
w5100_addr: .res 2
byte_ctr_lo: .res 1
byte_ctr_hi: .res 1
tx_wr_ptr: .res 2
rx_rd_ptr: .res 2
tcp_local_port: .res 2
tcp_state: .res 1
tcp_connect_ip: .res 4 ;ip address of remote server to connect to
tcp_callback: .res 2 ;vector to routine to be called when data is received over tcp connection
tcp_remote_port: .res 2 ;temp space for holding port to listen on or connect to
tcp_send_data_len: .res 2
tcp_send_data_ptr = eth_ptr_lo
tcp_inbound_data_length: .res 2
tcp_inbound_data_ptr: .res 2
tcp_connect_remote_port: .res 2
tcp_remote_ip = tcp_connect_ip
tcp_cxn_state_closed = 0
tcp_cxn_state_listening = 1 ;(waiting for an inbound SYN)
tcp_cxn_state_syn_sent = 2 ;(waiting for an inbound SYN/ACK)
tcp_cxn_state_established = 3 ;
;-- LICENSE FOR w5100a.s --
; The contents of this file are subject to the Mozilla Public License
; Version 1.1 (the "License"); you may not use this file except in
; compliance with the License. You may obtain a copy of the License at
; http://www.mozilla.org/MPL/
;
; Software distributed under the License is distributed on an "AS IS"
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
; License for the specific language governing rights and limitations
; under the License.
;
; The Original Code is ip65.
;
; The Initial Developer of the Original Code is Jonno Downes (jonno@jamtronix.com)
; Portions created by the Initial Developer is Copyright (C) 2010
; Jonno Downes. All Rights Reserved.
; -- LICENSE END --
</pre></body></html>