mirror of
https://github.com/bobbimanners/emailler.git
synced 2025-01-19 00:29:56 +00:00
Removed W5100 demo code.
The W5100 demo programs are now available at https://github.com/oliverschmidt/uthernet
This commit is contained in:
parent
51abda7b8d
commit
ac653f55bd
@ -1,273 +0,0 @@
|
||||
/******************************************************************************
|
||||
|
||||
Copyright (c) 2015, Oliver Schmidt
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
// Both pragmas are obligatory to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
#pragma optimize (on)
|
||||
#pragma static-locals (on)
|
||||
|
||||
#include "w5100.h"
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
static volatile byte* w5100_mode;
|
||||
static volatile byte* w5100_addr_hi;
|
||||
static volatile byte* w5100_addr_lo;
|
||||
volatile byte* w5100_data;
|
||||
|
||||
static void set_addr(word addr)
|
||||
{
|
||||
*w5100_addr_hi = addr >> 8;
|
||||
*w5100_addr_lo = addr;
|
||||
}
|
||||
|
||||
static byte get_byte(word addr)
|
||||
{
|
||||
set_addr(addr);
|
||||
|
||||
return *w5100_data;
|
||||
}
|
||||
|
||||
static void set_byte(word addr, byte data)
|
||||
{
|
||||
set_addr(addr);
|
||||
|
||||
*w5100_data = data;
|
||||
}
|
||||
|
||||
static word get_word(word addr)
|
||||
{
|
||||
set_addr(addr);
|
||||
|
||||
{
|
||||
// The variables are necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
byte data_hi = *w5100_data;
|
||||
byte data_lo = *w5100_data;
|
||||
return data_hi << 8 | data_lo;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_word(word addr, word data)
|
||||
{
|
||||
set_addr(addr);
|
||||
|
||||
{
|
||||
// The variables are necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
byte data_hi = data >> 8;
|
||||
byte data_lo = data;
|
||||
*w5100_data = data_hi;
|
||||
*w5100_data = data_lo;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_bytes(word addr, byte data[], word size)
|
||||
{
|
||||
set_addr(addr);
|
||||
|
||||
{
|
||||
word i;
|
||||
for (i = 0; i < size; ++i)
|
||||
*w5100_data = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
byte w5100_init(word base_addr, byte *ip_addr,
|
||||
byte *submask,
|
||||
byte *gateway)
|
||||
{
|
||||
w5100_mode = (byte*)base_addr;
|
||||
w5100_addr_hi = (byte*)base_addr + 1;
|
||||
w5100_addr_lo = (byte*)base_addr + 2;
|
||||
w5100_data = (byte*)base_addr + 3;
|
||||
|
||||
// Assert Indirect Bus I/F mode & Address Auto-Increment
|
||||
*w5100_mode |= 0x03;
|
||||
|
||||
// Retry Time-value Register: Default ?
|
||||
if (get_word(0x0017) != 2000)
|
||||
return 0;
|
||||
|
||||
// S/W Reset
|
||||
*w5100_mode = 0x80;
|
||||
while (*w5100_mode & 0x80)
|
||||
;
|
||||
|
||||
// Indirect Bus I/F mode & Address Auto-Increment
|
||||
*w5100_mode = 0x03;
|
||||
|
||||
// RX Memory Size Register: Assign 8KB to Socket 0
|
||||
set_byte(0x001A, 0x03);
|
||||
|
||||
// TX Memory Size Register: Assign 8KB to Socket 0
|
||||
set_byte(0x001B, 0x03);
|
||||
|
||||
// Source Hardware Address Register
|
||||
{
|
||||
static byte mac_addr[6] = {0x00, 0x08, 0xDC, // OUI of WIZnet
|
||||
0x11, 0x11, 0x11};
|
||||
set_bytes(0x0009, mac_addr, sizeof(mac_addr));
|
||||
}
|
||||
|
||||
// Source IP Address Register
|
||||
set_bytes(0x000F, ip_addr, 4);
|
||||
|
||||
// Subnet Mask Register
|
||||
set_bytes(0x0005, submask, 4);
|
||||
|
||||
// Gateway IP Address Register
|
||||
set_bytes(0x0001, gateway, 4);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
byte w5100_connect(byte *server_addr, word server_port)
|
||||
{
|
||||
// Socket 0 Mode Register: TCP
|
||||
set_byte(0x0400, 0x01);
|
||||
|
||||
// Socket 0 Source Port Register
|
||||
set_word(0x0404, 6502);
|
||||
|
||||
// Socket 0 Command Register: OPEN
|
||||
set_byte(0x0401, 0x01);
|
||||
|
||||
// Socket 0 Status Register: SOCK_INIT ?
|
||||
while (get_byte(0x0403) != 0x13)
|
||||
;
|
||||
|
||||
// Socket 0 Destination IP Address Register
|
||||
set_bytes(0x040C, server_addr, 4);
|
||||
|
||||
// Socket 0 Destination Port Register
|
||||
set_word(0x0410, server_port);
|
||||
|
||||
// Socket 0 Command Register: CONNECT
|
||||
set_byte(0x0401, 0x04);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Socket 0 Status Register
|
||||
switch (get_byte(0x0403))
|
||||
{
|
||||
case 0x00: return 0; // Socket Status: SOCK_CLOSED
|
||||
case 0x17: return 1; // Socket Status: SOCK_ESTABLISHED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte w5100_connected(void)
|
||||
{
|
||||
// Socket 0 Status Register: SOCK_ESTABLISHED ?
|
||||
return get_byte(0x0403) == 0x17;
|
||||
}
|
||||
|
||||
void w5100_disconnect(void)
|
||||
{
|
||||
// Socket 0 Command Register: Command Pending ?
|
||||
while (get_byte(0x0401))
|
||||
;
|
||||
|
||||
// Socket 0 Command Register: DISCON
|
||||
set_byte(0x0401, 0x08);
|
||||
|
||||
// Socket 0 Status Register: SOCK_CLOSED ?
|
||||
while (get_byte(0x0403))
|
||||
// Wait for disconnect to allow for reconnect
|
||||
;
|
||||
}
|
||||
|
||||
word w5100_data_request(byte do_send)
|
||||
{
|
||||
// Socket 0 Command Register: Command Pending ?
|
||||
if (get_byte(0x0401))
|
||||
return 0;
|
||||
|
||||
// Reread of nonzero RX Received Size Register / TX Free Size Register
|
||||
// until its value settles ...
|
||||
// - is present in the WIZnet driver - getSn_RX_RSR() / getSn_TX_FSR()
|
||||
// - was additionally tested on 6502 machines to be actually necessary
|
||||
{
|
||||
word size = 0;
|
||||
word prev_size;
|
||||
do
|
||||
{
|
||||
prev_size = size;
|
||||
{
|
||||
static word reg[2] = {0x0426, // Socket 0 RX Received Size Register
|
||||
0x0420}; // Socket 0 TX Free Size Register
|
||||
size = get_word(reg[do_send]);
|
||||
}
|
||||
}
|
||||
while (size != prev_size);
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
{
|
||||
static word reg[2] = {0x0428, // Socket 0 RX Read Pointer Register
|
||||
0x0424}; // Socket 0 TX Write Pointer Register
|
||||
|
||||
static word bas[2] = {0x6000, // Socket 0 RX Memory Base
|
||||
0x4000}; // Socket 0 TX Memory Base
|
||||
|
||||
static word lim[2] = {0x8000, // Socket 0 RX Memory Limit
|
||||
0x6000}; // Socket 0 TX Memory Limit
|
||||
|
||||
// Calculate and set physical address
|
||||
word addr = get_word(reg[do_send]) & 0x1FFF | bas[do_send];
|
||||
set_addr(addr);
|
||||
|
||||
// Access to *w5100_data is limited both by ...
|
||||
// - size of received / free space
|
||||
// - end of physical address space
|
||||
return MIN(size, lim[do_send] - addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void w5100_data_commit(byte do_send, word size)
|
||||
{
|
||||
{
|
||||
static word reg[2] = {0x0428, // Socket 0 RX Read Pointer Register
|
||||
0x0424}; // Socket 0 TX Write Pointer Register
|
||||
set_word(reg[do_send], get_word(reg[do_send]) + size);
|
||||
}
|
||||
|
||||
{
|
||||
static byte cmd[2] = {0x40, // Socket Command: RECV
|
||||
0x20}; // Socket Command: SEND
|
||||
// Socket 0 Command Register
|
||||
set_byte(0x0401, cmd[do_send]);
|
||||
}
|
||||
|
||||
// Do NOT wait for command completion here, rather
|
||||
// let W5100 operation overlap with 6502 operation
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
/******************************************************************************
|
||||
|
||||
Copyright (c) 2014, Oliver Schmidt
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Some notes by Oliver Schmidt on the WIZnet W5100 Ethernet controller:
|
||||
|
||||
1. Operation Modes
|
||||
|
||||
1.1 MAC-Raw
|
||||
In MAC-Raw mode the W5100 behaves pretty much like a CS8900A or a LAN91C96. The
|
||||
W5100 is usually only configured with a MAC address which is used by the W5100
|
||||
to limit incoming frames to those sent to its MAC address (or broadcasts).
|
||||
|
||||
1.2 IP-Raw
|
||||
IP-Raw mode is usable to implement non-UDP/non-TCP IP protocols like ICMP. The
|
||||
W5100 is usually configured with a full IP profile (IP addr, netmask, gateway).
|
||||
It transparently takes care of incoming/outgoing ARP and optionally of incoming
|
||||
ICMP Echo (aka Ping).
|
||||
|
||||
1.3 UDP
|
||||
UDP mode is pretty simlar to IP-Raw mode but additionally takes care of header
|
||||
checksum calculation.
|
||||
|
||||
1.4 TCP
|
||||
TCP mode is rather different from the other modes. Incoming/outgoing data isn't
|
||||
delimited by headers like in all other modes. Rather the W5100 behaves like a
|
||||
BSD socket delivering/taking a data stream - in chunks not necessarily related
|
||||
to data packets received/sent. The W5100 transparently takes care of TCP flow
|
||||
control by sending ACK packets. It advertises a receive window identical to the
|
||||
free space in the its receive memory buffer.
|
||||
|
||||
The W5100 offers up to 4 'sockets' allowing to specify the operation mode for
|
||||
each socket individually. However MAC-Raw mode is only available for the first
|
||||
socket. It is possible to combine MAC-Raw mode with other modes for the other
|
||||
sockets - which is called 'hybrid TCP/IP stack'. I have no personal experience
|
||||
with this hybrid TCP/IP stack and see open questions:
|
||||
- Are packets delivered to other sockets filtered from the first socket?
|
||||
- Who takes care of incoming ARP and incoming ICMP Echo?
|
||||
|
||||
The W5100 divides its 16kB memory buffer statically into 8kB for receive and
|
||||
8kB for send (in contrast to the CS8900A and the LAN91C96 which both do dynamic
|
||||
receive/send buffer division). When using several sockets it is additionally
|
||||
necessary to statically assign the two 8kB memory buffers to the sockets.
|
||||
|
||||
2. Memory Buffer Access
|
||||
In 6502 machines the W5100 is accessed using its indirect bus interface. This
|
||||
interface optionally allows for pointer auto-increment (like the CS8900A and
|
||||
the LAN91C96). However in contrast to those two Ethernet controllers the W5100
|
||||
does NOT virtualize access to its memory buffer! So when reading/writing data
|
||||
from/to the W5100 and reaching the end of the memory buffer assigned to the
|
||||
socket it's the responsibility of the 6502 program to continue reading/writing
|
||||
at the begin of the memory buffer. Please note that the pointer auto-increment
|
||||
does NOT take care of that wraparound operation! I have implemented several
|
||||
ways to handle this difficulty.
|
||||
|
||||
2.1 Copy Split
|
||||
If it is necessary or desired to have the interface to the upper layers being
|
||||
based on a receive/send buffer and one can afford the memory for a little more
|
||||
code than it is appropriate to check in advance if receive/send will require a
|
||||
wraparound and in that case split the copy from/to the buffer into two copy
|
||||
operations. That approach is used in all WIZnet code and I implemented it in
|
||||
pretty optimized 6502 code for the Contiki/IP65 MAC-Raw mode driver located in
|
||||
drivers/w5100.s - however the copy split technique is in general applicable to
|
||||
all W5100 operation modes.
|
||||
|
||||
2.2 Shadow Register
|
||||
When it comes to using as little memory as possible I consider it in general
|
||||
questionable if a buffer is the right interface paradigm. In many scenarios it
|
||||
makes more sense to read/write bytes individually. This allows i.e. to directly
|
||||
write bytes from individual already existing data structures to the W5100 or
|
||||
analyze bytes directly on reading from the W5100 to decide on processing of
|
||||
subsequent bytes - and maybe ignore them altogether. This approach splits a
|
||||
receive/send operation into three phases: The initialization, the individual
|
||||
byte read/write and the finalization. The initialization sets up a 16-bit
|
||||
shadow register to be as far away from overflow as the auto-increment pointer
|
||||
is away from the necessary wraparound. The individual byte read/write then
|
||||
increments the shadow register and on its overflow resets the auto-increment
|
||||
pointer to the begin of the memory buffer. I implemented this approach in two
|
||||
drivers using heavily size-optimized 6502 code for the W5100 UDP mode and TCP
|
||||
mode showing that the shadow register technique yields the smallest code. They
|
||||
are located in supplement/w5100_udp.s and supplement/w5100_tcp.s with C test
|
||||
programs located in test/w5100_udp_main.c and test/w5100_tcp_main.c. There's a
|
||||
Win32 communication peer for the test programs located in test/w5100_peer.c.
|
||||
|
||||
2.3 TCP Stream Split
|
||||
A correct BSD TCP socket program never presumes to be able to read/write any
|
||||
amount of data. Rather it is always prepared to call recv()/send() as often as
|
||||
necessary to receive/send the expected amount data in whatever chunks - and the
|
||||
very same holds true for any program using the W5100 TCP mode! But this already
|
||||
necessary complexity in the upper layers allows to handle W5100 memory buffer
|
||||
wraparounds transparently by artificially limiting the size of a read/write
|
||||
operation to the end of the memory buffer if necessary. The next read/write
|
||||
operation then works with the begin of the memory buffer. This approach shares
|
||||
the benefits of the shadow register technique while avoiding its performance
|
||||
penalties coming from maintaining the shadow register. Additionally it allows
|
||||
the upper layers to directly access the auto-increment W5100 data register for
|
||||
individual byte read/write because it is known to stay within the memory buffer
|
||||
limits. Therefore the TCP stream split technique avoids both the overhead of a
|
||||
buffer as well as the overhead of function calls for individual bytes. It sort
|
||||
of combines the best of both sides but it means larger code than the shadow
|
||||
register technique and is only applicable to the W5100 TCP mode. I implemented
|
||||
the TCP stream split technique in a C-only driver located in supplement/w5100.c
|
||||
with a test program representing the upper layers located in test/w5100_main.c
|
||||
being compatible with test/w5100_peer.c.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _W5100_H_
|
||||
#define _W5100_H_
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
|
||||
word w5100_data_request(byte do_send);
|
||||
void w5100_data_commit(byte do_send, word size);
|
||||
|
||||
// After w5100_receive_request() every read operation returns the next byte
|
||||
// from the server.
|
||||
// After w5100_send_request() every write operation prepares the next byte
|
||||
// to be sent to the server.
|
||||
extern volatile byte* w5100_data;
|
||||
|
||||
// Initialize W5100 Ethernet controller with indirect bus interface located
|
||||
// at <base_addr>. Use <ip_addr>, <submask> and <gateway> to configure the
|
||||
// TCP/IP stack.
|
||||
// Return <1> if a W5100 was found at <base_addr>, return <0> otherwise.
|
||||
byte w5100_init(word base_addr, byte *ip_addr,
|
||||
byte *submask,
|
||||
byte *gateway);
|
||||
|
||||
// Connect to server with IP address <server_addr> on TCP port <server_port>.
|
||||
// Use <6502> as fixed local port.
|
||||
// Return <1> if the connection is established, return <0> otherwise.
|
||||
byte w5100_connect(byte *server_addr, word server_port);
|
||||
|
||||
// Check if still connected to server.
|
||||
// Return <1> if the connection is established, return <0> otherwise.
|
||||
byte w5100_connected(void);
|
||||
|
||||
// Disconnect from server.
|
||||
void w5100_disconnect(void);
|
||||
|
||||
// Request to receive data from the server.
|
||||
// Return maximum number of bytes to be received by reading from *w5100_data.
|
||||
#define w5100_receive_request() w5100_data_request(0)
|
||||
|
||||
// Commit receiving of <size> bytes from server. <size> may be smaller than
|
||||
// the return value of w5100_receive_request(). Not commiting at all just
|
||||
// makes the next request receive the same data again.
|
||||
#define w5100_receive_commit(size) w5100_data_commit(0, (size))
|
||||
|
||||
// Request to send data to the server.
|
||||
// Return maximum number of bytes to be send by writing to *w5100_data.
|
||||
#define w5100_send_request() w5100_data_request(1)
|
||||
|
||||
// Commit sending of <size> bytes to server. <size> is usually smaller than
|
||||
// the return value of w5100_send_request(). Not commiting at all just turns
|
||||
// the w5100_send_request() - and the writes to *w5100_data - into NOPs.
|
||||
#define w5100_send_commit(size) w5100_data_commit(1, (size))
|
||||
|
||||
#endif
|
@ -1,458 +0,0 @@
|
||||
.feature c_comments
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Copyright (c) 2014, Oliver Schmidt
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
.export _w5100_init, _w5100_done
|
||||
.export _w5100_recv_init, _w5100_recv_byte, _w5100_recv_done
|
||||
.export _w5100_send_init, _w5100_send_byte, _w5100_send_done
|
||||
|
||||
ptr := $06 ; 2 byte pointer value
|
||||
sha := $08 ; 2 byte physical addr shadow ($F000-$FFFF)
|
||||
adv := $EB ; 2 byte pointer register advancement
|
||||
tmp := $ED ; 1 byte temporary value
|
||||
bas := $EE ; 1 byte socket 1 Base Address (hibyte)
|
||||
|
||||
mode := $C0B4
|
||||
addr := $C0B5
|
||||
data := $C0B7
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_init:
|
||||
; Input
|
||||
; AX: Address of ip_parms (serverip, cfg_ip, cfg_netmask ,cfg_gateway)
|
||||
; Output
|
||||
; A: Nonzero if connected to server
|
||||
; Remark
|
||||
; The ip_parms are only accessed during this function.
|
||||
|
||||
; Set ip_parms pointer
|
||||
sta ptr
|
||||
stx ptr+1
|
||||
|
||||
; S/W Reset
|
||||
lda #$80
|
||||
sta mode
|
||||
: lda mode
|
||||
bmi :-
|
||||
|
||||
; Indirect Bus I/F mode, Address Auto-Increment
|
||||
lda #$03
|
||||
sta mode
|
||||
|
||||
; Gateway IP Address Register: IP address of router on local network
|
||||
ldx #$00 ; Hibyte
|
||||
ldy #$01 ; Lobyte
|
||||
jsr set_addr
|
||||
ldy #3*4 ; ip_parms::cfg_gateway
|
||||
jsr set_ipv4value
|
||||
|
||||
; Subnet Mask Register: Netmask of local network
|
||||
; -> addr is already set
|
||||
ldy #2*4 ; ip_parms::cfg_netmask
|
||||
jsr set_ipv4value
|
||||
|
||||
; Source Hardware Address Register: MAC Address
|
||||
; -> addr is already set
|
||||
ldx #$00
|
||||
: lda mac,x
|
||||
sta data
|
||||
inx
|
||||
cpx #$06
|
||||
bcc :-
|
||||
|
||||
; Source IP Address Register: IP address of local machine
|
||||
; -> addr is already set
|
||||
ldy #1*4 ; ip_parms::cfg_ip
|
||||
jsr set_ipv4value
|
||||
|
||||
; RX Memory Size Register: Assign 4KB each to sockets 0 and 1
|
||||
ldx #$00 ; Hibyte
|
||||
ldy #$1A ; Lobyte
|
||||
jsr set_addr
|
||||
lda #$0A
|
||||
sta data
|
||||
|
||||
; TX Memory Size Register: Assign 4KB each to sockets 0 and 1
|
||||
; -> addr is already set
|
||||
; -> A is still $0A
|
||||
sta data
|
||||
|
||||
; Socket 1 Mode Register: TCP
|
||||
ldy #$00
|
||||
jsr set_addrsocket1
|
||||
lda #$01
|
||||
sta data
|
||||
|
||||
; Socket 1 Source Port Register: 6502
|
||||
ldy #$04
|
||||
jsr set_addrsocket1
|
||||
jsr set_data6502
|
||||
|
||||
; Socket 1 Destination IP Address Register: Destination IP address
|
||||
ldy #$0C
|
||||
jsr set_addrsocket1
|
||||
ldy #0*4 ; ip_parms::serverip
|
||||
jsr set_ipv4value
|
||||
|
||||
; Socket 1 Destination Port Register: 6502
|
||||
; -> addr is already set
|
||||
jsr set_data6502
|
||||
|
||||
; Socket 1 Command Register: OPEN
|
||||
lda #$01
|
||||
jsr set_cmdsocket1
|
||||
|
||||
; Socket 1 Command Register: CONNECT
|
||||
lda #$04
|
||||
jsr set_cmdsocket1
|
||||
|
||||
; Socket 1 Status Register: SOCK_CLOSED or SOCK_ESTABLISHED ?
|
||||
: ldy #$03
|
||||
jsr set_addrsocket1
|
||||
lda data
|
||||
beq error ; SOCK_CLOSED (:= 0)
|
||||
cmp #$17 ; SOCK_ESTABLISHED
|
||||
bne :- ; Intermediate status -> retry
|
||||
|
||||
; Return success
|
||||
beq success ; Always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_ipv4value:
|
||||
ldx #$03
|
||||
: lda (ptr),y
|
||||
iny
|
||||
sta data
|
||||
dex
|
||||
bpl :-
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_data6502:
|
||||
lda #<6502
|
||||
ldx #>6502
|
||||
stx data ; Hibyte
|
||||
sta data ; Lobyte
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_done:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; None
|
||||
; Remark
|
||||
; Disconnect from the server.
|
||||
|
||||
; Check for completion of previous command
|
||||
jsr get_cmdsocket1
|
||||
|
||||
; Socket 1 Command Register: DISCON
|
||||
lda #$08
|
||||
|
||||
set_cmdsocket1:
|
||||
; Socket 1 Command Register: command
|
||||
jsr set_addrcmdreg1
|
||||
sta data
|
||||
|
||||
get_cmdsocket1:
|
||||
; Check for completion of command
|
||||
; Socket 1 Command Register: 0 ?
|
||||
: jsr set_addrcmdreg1
|
||||
lda data
|
||||
bne :- ; Not completed -> retry
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_recv_init:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; AX: Number of bytes to receive or -1 if not connected anymore
|
||||
; Remark
|
||||
; To be called before recv_byte.
|
||||
|
||||
; Socket 1 Status Register: SOCK_ESTABLISHED ?
|
||||
ldy #$03
|
||||
jsr set_addrsocket1
|
||||
lda data
|
||||
cmp #$17
|
||||
beq :+
|
||||
|
||||
; Return -1
|
||||
lda #<$FFFF
|
||||
tax
|
||||
rts
|
||||
|
||||
; Socket 1 RX Received Size Register: 0 or volatile ?
|
||||
: lda #$26 ; Socket RX Received Size Register
|
||||
jsr prolog
|
||||
bne error
|
||||
|
||||
; Save pointer advancement
|
||||
stx adv ; Lobyte
|
||||
sta adv+1 ; Hibyte
|
||||
|
||||
; Socket 1 RX Read Pointer Register
|
||||
; -> addr already set
|
||||
|
||||
; Calculate and set pyhsical address
|
||||
ldx #>$7000 ; Socket 1 RX Base Address
|
||||
jsr set_addrphysical
|
||||
|
||||
; Return pointer advancement
|
||||
lda adv
|
||||
ldx adv+1
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_send_init:
|
||||
; Input
|
||||
; AX: Number of bytes to send
|
||||
; Output
|
||||
; A: Nonzero if ready to send
|
||||
; Remark
|
||||
; To be called before send_byte.
|
||||
|
||||
; Set pointer advancement
|
||||
sta adv
|
||||
stx adv+1
|
||||
|
||||
; Socket 1 TX Free Size Register: 0 or volatile ?
|
||||
lda #$20 ; Socket TX Free Size Register
|
||||
jsr prolog
|
||||
bne error
|
||||
|
||||
; Socket 1 TX Free Size Register: < advancement ?
|
||||
cpx adv ; Lobyte
|
||||
sbc adv+1 ; Hibyte
|
||||
bcc error ; Not enough free size
|
||||
|
||||
; Socket 1 TX Write Pointer Register
|
||||
ldy #$24
|
||||
jsr set_addrsocket1
|
||||
|
||||
; Calculate and set pyhsical address
|
||||
ldx #>$5000 ; Socket 1 TX Base Address
|
||||
jsr set_addrphysical
|
||||
|
||||
success:
|
||||
; Return success
|
||||
lda #$01
|
||||
ldx #>$0000 ; Required by cc65 C callers
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
error:
|
||||
lda #<$0000
|
||||
tax
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
prolog:
|
||||
; Check for completion of previous command
|
||||
; Socket 1 Command Register: 0 ?
|
||||
jsr set_addrcmdreg1
|
||||
ldx data
|
||||
bne :++ ; Not completed -> Z = 0
|
||||
|
||||
; Socket Size Register: not 0 ?
|
||||
tay ; Select Size Register
|
||||
jsr get_wordsocket1
|
||||
stx ptr ; Lobyte
|
||||
sta ptr+1 ; Hibyte
|
||||
ora ptr
|
||||
bne :+
|
||||
inx ; -> Z = 0
|
||||
rts
|
||||
|
||||
; Socket Size Register: volatile ?
|
||||
: jsr get_wordsocket1
|
||||
cpx ptr ; Lobyte
|
||||
bne :+ ; Volatile size -> Z = 0
|
||||
cmp ptr+1 ; Hibyte
|
||||
; bne :+ ; Volatile size -> Z = 0
|
||||
: rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_recv_byte:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; A: Byte received
|
||||
; Remark
|
||||
; May be called as often as indicated by recv_init.
|
||||
|
||||
; Read byte
|
||||
lda data
|
||||
|
||||
; Increment physical addr shadow lobyte
|
||||
inc sha
|
||||
beq incsha
|
||||
ldx #>$0000 ; Required by cc65 C callers
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_send_byte:
|
||||
; Input
|
||||
; A: Byte to send
|
||||
; Output
|
||||
; None
|
||||
; Remark
|
||||
; Should be called as often as indicated to send_init.
|
||||
|
||||
; Write byte
|
||||
sta data
|
||||
|
||||
; Increment physical addr shadow lobyte
|
||||
inc sha
|
||||
beq incsha
|
||||
rts
|
||||
|
||||
incsha:
|
||||
; Increment physical addr shadow hibyte
|
||||
inc sha+1
|
||||
beq set_addrbase
|
||||
ldx #>$0000 ; Required by cc65 C callers (_w5100_recv_byte)
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_recv_done:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; None
|
||||
; Remark
|
||||
; Mark data indicated by recv_init as processed (independently from how
|
||||
; often recv_byte was called), if not called then next call of recv_init
|
||||
; will just indicate the very same data again.
|
||||
|
||||
; Set parameters for commit code
|
||||
lda #$40 ; RECV
|
||||
ldy #$28 ; Socket RX Read Pointer Register
|
||||
bne epilog ; Always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_send_done:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; None
|
||||
; Remark
|
||||
; Actually send data indicated to send_init (independently from how often
|
||||
; send_byte was called), if not called then send_init (and send_byte) are
|
||||
; just NOPs.
|
||||
|
||||
; Set parameters for commit code
|
||||
lda #$20 ; SEND
|
||||
ldy #$24 ; Socket TX Write Pointer Register
|
||||
|
||||
epilog:
|
||||
; Advance pointer register
|
||||
jsr set_addrsocket1
|
||||
tay ; Save command
|
||||
clc
|
||||
lda ptr
|
||||
adc adv
|
||||
tax
|
||||
lda ptr+1
|
||||
adc adv+1
|
||||
sta data ; Hibyte
|
||||
stx data ; Lobyte
|
||||
|
||||
; Set command register
|
||||
tya ; Restore command
|
||||
jsr set_addrcmdreg1
|
||||
sta data
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_addrphysical:
|
||||
lda data ; Hibyte
|
||||
ldy data ; Lobyte
|
||||
sty ptr
|
||||
sta ptr+1
|
||||
and #>$0FFF ; Socket Mask Address (hibyte)
|
||||
stx bas ; Socket Base Address (hibyte)
|
||||
ora bas
|
||||
tax
|
||||
ora #>$F000 ; Move sha/sha+1 to $F000-$FFFF
|
||||
sty sha
|
||||
sta sha+1
|
||||
|
||||
set_addr:
|
||||
stx addr ; Hibyte
|
||||
sty addr+1 ; Lobyte
|
||||
ldx #>$0000 ; Required by cc65 C callers (_w5100_recv_byte)
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_addrcmdreg1:
|
||||
ldy #$01 ; Socket Command Register
|
||||
|
||||
set_addrsocket1:
|
||||
ldx #>$0500 ; Socket 1 register base address
|
||||
bne set_addr ; Always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_addrbase:
|
||||
ldx bas ; Socket Base Address (hibyte)
|
||||
ldy #<$0000 ; Socket Base Address (lobyte)
|
||||
beq set_addr ; Always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
get_wordsocket1:
|
||||
jsr set_addrsocket1
|
||||
lda data ; Hibyte
|
||||
ldx data ; Lobyte
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
.rodata
|
||||
|
||||
mac: .byte $00, $08, $DC ; OUI of WIZnet
|
||||
.byte $11, $11, $11
|
@ -1,446 +0,0 @@
|
||||
.feature c_comments
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Copyright (c) 2014, Oliver Schmidt
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
.export _w5100_init
|
||||
.export _w5100_recv_init, _w5100_recv_byte, _w5100_recv_done
|
||||
.export _w5100_send_init, _w5100_send_byte, _w5100_send_done
|
||||
|
||||
ptr := $06 ; 2 byte pointer value
|
||||
sha := $08 ; 2 byte physical addr shadow ($F000-$FFFF)
|
||||
adv := $EB ; 2 byte pointer register advancement
|
||||
len := $ED ; 2 byte frame length
|
||||
tmp := $FA ; 1 byte temporary value
|
||||
bas := $FB ; 1 byte socket 1 Base Address (hibyte)
|
||||
|
||||
mode := $C0B4
|
||||
addr := $C0B5
|
||||
data := $C0B7
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_init:
|
||||
; Input
|
||||
; AX: Address of ip_parms (serverip, cfg_ip, cfg_netmask, cfg_gateway)
|
||||
; Output
|
||||
; None
|
||||
; Remark
|
||||
; The ip_parms are only accessed during this function.
|
||||
|
||||
; Set ip_parms pointer
|
||||
sta ptr
|
||||
stx ptr+1
|
||||
|
||||
; S/W Reset
|
||||
lda #$80
|
||||
sta mode
|
||||
: lda mode
|
||||
bmi :-
|
||||
|
||||
; Indirect Bus I/F mode, Address Auto-Increment
|
||||
lda #$03
|
||||
sta mode
|
||||
|
||||
; Gateway IP Address Register: IP address of router on local network
|
||||
ldx #$00 ; Hibyte
|
||||
ldy #$01 ; Lobyte
|
||||
jsr set_addr
|
||||
ldy #3*4 ; ip_parms::cfg_gateway
|
||||
jsr set_ipv4value
|
||||
|
||||
; Subnet Mask Register: Netmask of local network
|
||||
; -> addr is already set
|
||||
ldy #2*4 ; ip_parms::cfg_netmask
|
||||
jsr set_ipv4value
|
||||
|
||||
; Source Hardware Address Register: MAC Address
|
||||
; -> addr is already set
|
||||
ldx #$00
|
||||
: lda mac,x
|
||||
sta data
|
||||
inx
|
||||
cpx #$06
|
||||
bcc :-
|
||||
|
||||
; Source IP Address Register: IP address of local machine
|
||||
; -> addr is already set
|
||||
ldy #1*4 ; ip_parms::cfg_ip
|
||||
jsr set_ipv4value
|
||||
|
||||
; RX Memory Size Register: Assign 4KB each to sockets 0 and 1
|
||||
ldx #$00 ; Hibyte
|
||||
ldy #$1A ; Lobyte
|
||||
jsr set_addr
|
||||
lda #$0A
|
||||
sta data
|
||||
|
||||
; TX Memory Size Register: Assign 4KB each to sockets 0 and 1
|
||||
; -> addr is already set
|
||||
; -> A is still $0A
|
||||
sta data
|
||||
|
||||
; Socket 1 Source Port Register: 6502
|
||||
ldy #$04
|
||||
jsr set_addrsocket1
|
||||
jsr set_data6502
|
||||
|
||||
; Socket 1 Destination IP Address Register: Destination IP address
|
||||
; This has to be the last call to set_ipv4value because it writes
|
||||
; as a side effect to 'hdr' and it is the destination IP address
|
||||
; that has to be present in 'hdr' after initialization
|
||||
ldy #$0C
|
||||
jsr set_addrsocket1
|
||||
ldy #0*4 ; ip_parms::serverip
|
||||
jsr set_ipv4value
|
||||
|
||||
; Socket 1 Destination Port Register: 6502
|
||||
; -> addr is already set
|
||||
jsr set_data6502
|
||||
|
||||
; Socket 1 Mode Register: UDP
|
||||
ldy #$00
|
||||
jsr set_addrsocket1
|
||||
lda #$02
|
||||
sta data
|
||||
|
||||
; Socket 1 Command Register: OPEN
|
||||
; -> addr is already set
|
||||
lda #$01
|
||||
sta data
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_ipv4value:
|
||||
ldx #$03
|
||||
: lda (ptr),y
|
||||
iny
|
||||
sta data
|
||||
sta hdr+2,x
|
||||
dex
|
||||
bpl :-
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_data6502:
|
||||
lda #<6502
|
||||
ldx #>6502
|
||||
stx data ; Hibyte
|
||||
sta data ; Lobyte
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_recv_init:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; AX: Number of bytes to receive
|
||||
; Remark
|
||||
; To be called before recv_byte.
|
||||
|
||||
; Socket 1 RX Received Size Register: 0 or volatile ?
|
||||
lda #$26 ; Socket RX Received Size Register
|
||||
jsr prolog
|
||||
bne error
|
||||
|
||||
; Socket 1 RX Read Pointer Register
|
||||
; -> addr already set
|
||||
|
||||
; Calculate and set pyhsical address
|
||||
ldx #>$7000 ; Socket 1 RX Base Address
|
||||
jsr set_addrphysical
|
||||
|
||||
; Compare peer IP addr and peer port with expected values
|
||||
; in 'hdr' and set C(arry flag) if there's a mismatch
|
||||
clc
|
||||
ldx #$05
|
||||
stx tmp
|
||||
: jsr _w5100_recv_byte ; Doesn't trash C
|
||||
ldx tmp
|
||||
eor hdr,x ; Doesn't trash C
|
||||
beq :+
|
||||
sec
|
||||
: dec tmp
|
||||
bpl :--
|
||||
php ; Save C
|
||||
|
||||
; Read data length
|
||||
jsr _w5100_recv_byte ; Hibyte
|
||||
sta len+1
|
||||
jsr _w5100_recv_byte ; Lobyte
|
||||
sta len
|
||||
|
||||
; Add 8 byte header to set pointer advancement
|
||||
clc
|
||||
adc #<$0008
|
||||
sta adv
|
||||
lda len+1
|
||||
adc #>$0008
|
||||
sta adv+1
|
||||
|
||||
; Skip frame if it doesn't originate from our
|
||||
; expected communicaion peer
|
||||
plp ; Restore C
|
||||
bcs _w5100_recv_done
|
||||
|
||||
; Return data length
|
||||
lda len
|
||||
ldx len+1
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_send_init:
|
||||
; Input
|
||||
; AX: Number of bytes to send
|
||||
; Output
|
||||
; A: Nonzero if ready to send
|
||||
; Remark
|
||||
; To be called before send_byte.
|
||||
|
||||
; Set pointer advancement
|
||||
sta adv
|
||||
stx adv+1
|
||||
|
||||
; Socket 1 TX Free Size Register: 0 or volatile ?
|
||||
lda #$20 ; Socket TX Free Size Register
|
||||
jsr prolog
|
||||
bne error
|
||||
|
||||
; Socket 1 TX Free Size Register: < advancement ?
|
||||
cpx adv ; Lobyte
|
||||
sbc adv+1 ; Hibyte
|
||||
bcc error ; Not enough free size
|
||||
|
||||
; Socket 1 TX Write Pointer Register
|
||||
ldy #$24
|
||||
jsr set_addrsocket1
|
||||
|
||||
; Calculate and set pyhsical address
|
||||
ldx #>$5000 ; Socket 1 TX Base Address
|
||||
jsr set_addrphysical
|
||||
|
||||
; Return success
|
||||
lda #$01
|
||||
ldx #>$0000 ; Required by cc65 C callers
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
error:
|
||||
lda #<$0000
|
||||
tax
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
prolog:
|
||||
; Check for completion of previous command
|
||||
; Socket 1 Command Register: 0 ?
|
||||
jsr set_addrcmdreg1
|
||||
ldx data
|
||||
bne :++ ; Not completed -> Z = 0
|
||||
|
||||
; Socket Size Register: not 0 ?
|
||||
tay ; Select Size Register
|
||||
jsr get_wordsocket1
|
||||
stx ptr ; Lobyte
|
||||
sta ptr+1 ; Hibyte
|
||||
ora ptr
|
||||
bne :+
|
||||
inx ; -> Z = 0
|
||||
rts
|
||||
|
||||
; Socket Size Register: volatile ?
|
||||
: jsr get_wordsocket1
|
||||
cpx ptr ; Lobyte
|
||||
bne :+ ; Volatile size -> Z = 0
|
||||
cmp ptr+1 ; Hibyte
|
||||
; bne :+ ; Volatile size -> Z = 0
|
||||
: rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_recv_byte:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; A: Byte received
|
||||
; Remark
|
||||
; May be called as often as indicated by recv_init.
|
||||
|
||||
; Read byte
|
||||
lda data
|
||||
|
||||
; Increment physical addr shadow lobyte
|
||||
inc sha
|
||||
beq incsha
|
||||
ldx #>$0000 ; Required by cc65 C callers
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_send_byte:
|
||||
; Input
|
||||
; A: Byte to send
|
||||
; Output
|
||||
; None
|
||||
; Remark
|
||||
; Should be called as often as indicated to send_init.
|
||||
|
||||
; Write byte
|
||||
sta data
|
||||
|
||||
; Increment physical addr shadow lobyte
|
||||
inc sha
|
||||
beq incsha
|
||||
rts
|
||||
|
||||
incsha:
|
||||
; Increment physical addr shadow hibyte
|
||||
inc sha+1
|
||||
beq set_addrbase
|
||||
ldx #>$0000 ; Required by cc65 C callers (_w5100_recv_byte)
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_recv_done:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; None
|
||||
; Remark
|
||||
; Mark data indicated by recv_init as processed (independently from how
|
||||
; often recv_byte was called), if not called then next call of recv_init
|
||||
; will just indicate the very same data again.
|
||||
|
||||
; Set parameters for commit code
|
||||
lda #$40 ; RECV
|
||||
ldy #$28 ; Socket RX Read Pointer Register
|
||||
bne epilog ; Always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
_w5100_send_done:
|
||||
; Input
|
||||
; None
|
||||
; Output
|
||||
; None
|
||||
; Remark
|
||||
; Actually send data indicated to send_init (independently from how often
|
||||
; send_byte was called), if not called then send_init (and send_byte) are
|
||||
; just NOPs.
|
||||
|
||||
; Set parameters for commit code
|
||||
lda #$20 ; SEND
|
||||
ldy #$24 ; Socket TX Write Pointer Register
|
||||
|
||||
epilog:
|
||||
; Advance pointer register
|
||||
jsr set_addrsocket1
|
||||
tay ; Save command
|
||||
clc
|
||||
lda ptr
|
||||
adc adv
|
||||
tax
|
||||
lda ptr+1
|
||||
adc adv+1
|
||||
sta data ; Hibyte
|
||||
stx data ; Lobyte
|
||||
|
||||
; Set command register
|
||||
tya ; Restore command
|
||||
jsr set_addrcmdreg1
|
||||
sta data
|
||||
|
||||
; Return error (_w5100_recv_init)
|
||||
bne error ; Always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_addrphysical:
|
||||
lda data ; Hibyte
|
||||
ldy data ; Lobyte
|
||||
sty ptr
|
||||
sta ptr+1
|
||||
and #>$0FFF ; Socket Mask Address (hibyte)
|
||||
stx bas ; Socket Base Address (hibyte)
|
||||
ora bas
|
||||
tax
|
||||
ora #>$F000 ; Move sha/sha+1 to $F000-$FFFF
|
||||
sty sha
|
||||
sta sha+1
|
||||
|
||||
set_addr:
|
||||
stx addr ; Hibyte
|
||||
sty addr+1 ; Lobyte
|
||||
ldx #>$0000 ; Required by cc65 C callers (_w5100_recv_byte)
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_addrcmdreg1:
|
||||
ldy #$01 ; Socket Command Register
|
||||
|
||||
set_addrsocket1:
|
||||
ldx #>$0500 ; Socket 1 register base address
|
||||
bne set_addr ; Always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
set_addrbase:
|
||||
ldx bas ; Socket Base Address (hibyte)
|
||||
ldy #<$0000 ; Socket Base Address (lobyte)
|
||||
beq set_addr ; Always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
get_wordsocket1:
|
||||
jsr set_addrsocket1
|
||||
lda data ; Hibyte
|
||||
ldx data ; Lobyte
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
.rodata
|
||||
|
||||
mac: .byte $00, $08, $DC ; OUI of WIZnet
|
||||
.byte $11, $11, $11
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
.data
|
||||
|
||||
hdr: .word 6502 ; Destination Port
|
||||
.res 4 ; Destination IP Address
|
@ -145,21 +145,9 @@ ip65demo.dsk: httpd.bin httpd-slotscan.bin
|
||||
java -jar $(AC) -cc65 $@ webserver-slot3 B < httpd.bin
|
||||
java -jar $(AC) -cc65 $@ webserver-slotscan B < httpd-slotscan.bin
|
||||
|
||||
w5100.bin: ../supplement/w5100.c w5100_main.c
|
||||
cl65 -o $@ -t apple2enh -m $(basename $@).map $^
|
||||
|
||||
w5100_%.bin: ../supplement/w5100_%.s w5100_%_main.c
|
||||
cl65 -o $@ -t apple2enh -m $(basename $@).map $^
|
||||
|
||||
w5100.dsk: w5100.bin w5100_udp.bin w5100_tcp.bin
|
||||
cp prodos.dsk $@
|
||||
java -jar $(AC) -cc65 $@ w5100 bin < w5100.bin
|
||||
java -jar $(AC) -cc65 $@ w5100.udp bin < w5100_udp.bin
|
||||
java -jar $(AC) -cc65 $@ w5100.tcp bin < w5100_tcp.bin
|
||||
|
||||
clean:
|
||||
make -C ../ip65 clean
|
||||
make -C ../drivers clean
|
||||
-rm -f ../supplement/*.o
|
||||
-rm -f *.o *.prg *.bin *.com *.vicprg *.map
|
||||
-rm -f ip65.d64 ip65.dsk ip65.atr ip65demo.dsk w5100.dsk
|
||||
-rm -f ip65.d64 ip65.dsk ip65.atr ip65demo.dsk
|
||||
|
@ -1,112 +0,0 @@
|
||||
// Both pragmas are obligatory to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
#pragma optimize (on)
|
||||
#pragma static-locals (on)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
|
||||
#include "../supplement/w5100.h"
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
byte ip_addr[4] = {192, 168, 0, 123};
|
||||
byte submask[4] = {255, 255, 255, 0};
|
||||
byte gateway[4] = {192, 168, 0, 1};
|
||||
|
||||
byte server[4] = {192, 168, 0, 2}; // IP addr of machine running w5100_peer.c
|
||||
|
||||
void main(void)
|
||||
{
|
||||
char key;
|
||||
|
||||
videomode(VIDEOMODE_80COL);
|
||||
printf("Init\n");
|
||||
if (!w5100_init(0xC0B4, ip_addr,
|
||||
submask,
|
||||
gateway))
|
||||
{
|
||||
printf("No Hardware Found\n");
|
||||
return;
|
||||
}
|
||||
printf("Connect\n");
|
||||
if (!w5100_connect(server, 6502))
|
||||
{
|
||||
printf("Faild To Connect To %d.%d.%d.%d\n", server[0],
|
||||
server[1],
|
||||
server[2],
|
||||
server[3]);
|
||||
return;
|
||||
}
|
||||
printf("Connected To %d.%d.%d.%d\n", server[0],
|
||||
server[1],
|
||||
server[2],
|
||||
server[3]);
|
||||
|
||||
printf("(S)end or e(X)it\n");
|
||||
do
|
||||
{
|
||||
word len, all;
|
||||
|
||||
if (kbhit())
|
||||
{
|
||||
key = cgetc();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = '\0';
|
||||
}
|
||||
|
||||
if (key == 's')
|
||||
{
|
||||
all = 500;
|
||||
printf("Send Len %d", all);
|
||||
do
|
||||
{
|
||||
word i;
|
||||
|
||||
while (!(len = w5100_send_request()))
|
||||
{
|
||||
printf("!");
|
||||
}
|
||||
len = MIN(all, len);
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
*w5100_data = 500 - all + i;
|
||||
}
|
||||
w5100_send_commit(len);
|
||||
all -= len;
|
||||
}
|
||||
while (all);
|
||||
printf(".\n");
|
||||
}
|
||||
|
||||
len = w5100_receive_request();
|
||||
if (len)
|
||||
{
|
||||
word i;
|
||||
|
||||
printf("Recv Len %d", len);
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
if ((i % 24) == 0)
|
||||
{
|
||||
printf("\n$%04X:", i);
|
||||
}
|
||||
printf(" %02X", *w5100_data);
|
||||
}
|
||||
w5100_receive_commit(len);
|
||||
printf(".\n");
|
||||
}
|
||||
|
||||
if (!w5100_connected())
|
||||
{
|
||||
printf("Disconnect\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (key != 'x');
|
||||
|
||||
w5100_disconnect();
|
||||
printf("Done\n");
|
||||
}
|
@ -1,197 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
static void dump(unsigned char *buf, unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
if ((i % 24) == 0)
|
||||
{
|
||||
printf("\n$%04X:", i);
|
||||
}
|
||||
printf(" %02X", buf[i]);
|
||||
}
|
||||
printf(".\n");
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
printf("Init\n");
|
||||
WSADATA wsa;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SOCKET udp = socket(AF_INET, SOCK_DGRAM , IPPROTO_UDP);
|
||||
if (udp == INVALID_SOCKET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SOCKET srv = socket(AF_INET, SOCK_STREAM , IPPROTO_TCP);
|
||||
if (srv == INVALID_SOCKET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u_long arg = 1;
|
||||
if (ioctlsocket(udp, FIONBIO, &arg) == SOCKET_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (ioctlsocket(srv, FIONBIO, &arg) == SOCKET_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SOCKADDR_IN local;
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_addr.s_addr = INADDR_ANY;
|
||||
local.sin_port = htons(6502);
|
||||
if (bind(udp, (SOCKADDR *)&local, sizeof(local)) == SOCKET_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (bind(srv, (SOCKADDR *)&local, sizeof(local)) == SOCKET_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(srv, 1) == SOCKET_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SOCKADDR_IN remote;
|
||||
remote.sin_addr.s_addr = INADDR_NONE;
|
||||
|
||||
SOCKET tcp = INVALID_SOCKET;
|
||||
|
||||
printf("(S)end or e(X)it\n");
|
||||
char key;
|
||||
do
|
||||
{
|
||||
int len;
|
||||
unsigned char buf[1500];
|
||||
|
||||
if (kbhit())
|
||||
{
|
||||
key = getch();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = '\0';
|
||||
}
|
||||
|
||||
if (key == 's')
|
||||
{
|
||||
if (remote.sin_addr.s_addr == INADDR_NONE && tcp == INVALID_SOCKET)
|
||||
{
|
||||
printf("Peer Unknown As Yet\n", len);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
len = 500;
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
buf[i] = i;
|
||||
}
|
||||
if (tcp == INVALID_SOCKET)
|
||||
{
|
||||
printf("Send Len %d To %s", len, inet_ntoa(remote.sin_addr));
|
||||
if (sendto(udp, buf, len, 0, (SOCKADDR *)&remote, sizeof(remote)) == SOCKET_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Send Len %d", len);
|
||||
if (send(tcp, buf, len, 0) == SOCKET_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
printf(".\n");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned remote_size = sizeof(remote);
|
||||
len = recvfrom(udp, buf, sizeof(buf), 0, (SOCKADDR *)&remote, &remote_size);
|
||||
if (len == SOCKET_ERROR)
|
||||
{
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (len)
|
||||
{
|
||||
printf("Recv Len %d From %s", len, inet_ntoa(remote.sin_addr));
|
||||
dump(buf, len);
|
||||
}
|
||||
|
||||
if (tcp == INVALID_SOCKET)
|
||||
{
|
||||
SOCKADDR_IN conn;
|
||||
unsigned conn_size = sizeof(conn);
|
||||
tcp = accept(srv, (SOCKADDR *)&conn, &conn_size);
|
||||
if (tcp == INVALID_SOCKET)
|
||||
{
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Connect From %s\n", inet_ntoa(conn.sin_addr));
|
||||
|
||||
u_long arg = 1;
|
||||
if (ioctlsocket(tcp, FIONBIO, &arg) == SOCKET_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
len = recv(tcp, buf, sizeof(buf), 0);
|
||||
if (len == SOCKET_ERROR)
|
||||
{
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (len)
|
||||
{
|
||||
printf("Recv Len %d", len);
|
||||
dump(buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Disconnect\n");
|
||||
closesocket(tcp);
|
||||
tcp = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(10);
|
||||
}
|
||||
while (key != 'x');
|
||||
|
||||
closesocket(udp);
|
||||
closesocket(tcp);
|
||||
closesocket(srv);
|
||||
WSACleanup();
|
||||
printf("Done\n");
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
|
||||
unsigned char __fastcall__ w5100_init(void *parms);
|
||||
void w5100_done(void);
|
||||
|
||||
int w5100_recv_init(void);
|
||||
unsigned char w5100_recv_byte(void);
|
||||
void w5100_recv_done(void);
|
||||
|
||||
unsigned char __fastcall__ w5100_send_init(unsigned int len);
|
||||
void __fastcall__ w5100_send_byte(unsigned char val);
|
||||
void w5100_send_done(void);
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned char serverip [4];
|
||||
unsigned char cfg_ip [4];
|
||||
unsigned char cfg_netmask[4];
|
||||
unsigned char cfg_gateway[4];
|
||||
}
|
||||
parms =
|
||||
{
|
||||
{192, 168, 0, 2}, // IP addr of machine running w5100_peer.c
|
||||
{192, 168, 0, 123},
|
||||
{255, 255, 255, 0},
|
||||
{192, 168, 0, 1}
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
char key;
|
||||
|
||||
videomode(VIDEOMODE_80COL);
|
||||
printf("Init\n");
|
||||
if (!w5100_init(&parms))
|
||||
{
|
||||
printf("Faild To Connect To %d.%d.%d.%d\n", parms.serverip[0],
|
||||
parms.serverip[1],
|
||||
parms.serverip[2],
|
||||
parms.serverip[3]);
|
||||
return;
|
||||
}
|
||||
printf("Connected To %d.%d.%d.%d\n", parms.serverip[0],
|
||||
parms.serverip[1],
|
||||
parms.serverip[2],
|
||||
parms.serverip[3]);
|
||||
|
||||
printf("(S)end or e(X)it\n");
|
||||
do
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
if (kbhit())
|
||||
{
|
||||
key = cgetc();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = '\0';
|
||||
}
|
||||
|
||||
if (key == 's')
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
len = 500;
|
||||
printf("Send Len %d", len);
|
||||
while (!w5100_send_init(len))
|
||||
{
|
||||
printf("!");
|
||||
}
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
w5100_send_byte(i);
|
||||
}
|
||||
w5100_send_done();
|
||||
printf(".\n");
|
||||
}
|
||||
|
||||
len = w5100_recv_init();
|
||||
if (len == -1)
|
||||
{
|
||||
printf("Disconnect\n");
|
||||
return;
|
||||
}
|
||||
else if (len)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
printf("Recv Len %d", len);
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
if ((i % 24) == 0)
|
||||
{
|
||||
printf("\n$%04X:", i);
|
||||
}
|
||||
printf(" %02X", w5100_recv_byte());
|
||||
}
|
||||
w5100_recv_done();
|
||||
printf(".\n");
|
||||
}
|
||||
}
|
||||
while (key != 'x');
|
||||
|
||||
w5100_done();
|
||||
printf("Done\n");
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
|
||||
void __fastcall__ w5100_init(void *parms);
|
||||
|
||||
unsigned int w5100_recv_init(void);
|
||||
unsigned char w5100_recv_byte(void);
|
||||
void w5100_recv_done(void);
|
||||
|
||||
unsigned char __fastcall__ w5100_send_init(unsigned int len);
|
||||
void __fastcall__ w5100_send_byte(unsigned char val);
|
||||
void w5100_send_done(void);
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned char serverip [4];
|
||||
unsigned char cfg_ip [4];
|
||||
unsigned char cfg_netmask[4];
|
||||
unsigned char cfg_gateway[4];
|
||||
}
|
||||
parms =
|
||||
{
|
||||
{192, 168, 0, 2}, // IP addr of machine running w5100_peer.c
|
||||
{192, 168, 0, 123},
|
||||
{255, 255, 255, 0},
|
||||
{192, 168, 0, 1}
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
char key;
|
||||
|
||||
videomode(VIDEOMODE_80COL);
|
||||
printf("Init\n");
|
||||
w5100_init(&parms);
|
||||
|
||||
printf("(S)end or e(X)it\n");
|
||||
do
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
if (kbhit())
|
||||
{
|
||||
key = cgetc();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = '\0';
|
||||
}
|
||||
|
||||
if (key == 's')
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
len = 500;
|
||||
printf("Send Len %d To %d.%d.%d.%d", len, parms.serverip[0],
|
||||
parms.serverip[1],
|
||||
parms.serverip[2],
|
||||
parms.serverip[3]);
|
||||
while (!w5100_send_init(len))
|
||||
{
|
||||
printf("!");
|
||||
}
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
w5100_send_byte(i);
|
||||
}
|
||||
w5100_send_done();
|
||||
printf(".\n");
|
||||
}
|
||||
|
||||
len = w5100_recv_init();
|
||||
if (len)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
printf("Recv Len %d From %d.%d.%d.%d", len, parms.serverip[0],
|
||||
parms.serverip[1],
|
||||
parms.serverip[2],
|
||||
parms.serverip[3]);
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
if ((i % 24) == 0)
|
||||
{
|
||||
printf("\n$%04X:", i);
|
||||
}
|
||||
printf(" %02X", w5100_recv_byte());
|
||||
}
|
||||
w5100_recv_done();
|
||||
printf(".\n");
|
||||
}
|
||||
}
|
||||
while (key != 'x');
|
||||
|
||||
printf("Done\n");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user