2019-02-27 22:26:35 +00:00
|
|
|
import machine
|
|
|
|
import memory
|
|
|
|
|
|
|
|
|
|
|
|
class Uthernet(machine.Machine):
|
2019-02-27 22:46:53 +00:00
|
|
|
"""Uthernet/W5100 device simulator."""
|
2019-02-27 22:26:35 +00:00
|
|
|
|
|
|
|
def __init__(self, stream:bytes):
|
|
|
|
memory_map = [
|
|
|
|
memory.MemoryRegion(
|
|
|
|
"Registers", 0x0000, 0x002f,
|
|
|
|
read_interceptor=self.io_interceptor,
|
|
|
|
write_interceptor=self.io_interceptor),
|
|
|
|
memory.MemoryRegion(
|
|
|
|
"Socket registers", 0x0400, 0x07ff,
|
|
|
|
read_interceptor=self.io_interceptor,
|
|
|
|
write_interceptor=self.io_interceptor),
|
|
|
|
memory.MemoryRegion("TX Memory", 0x4000, 0x5fff),
|
|
|
|
memory.MemoryRegion("RX Memory", 0x6000, 0x7fff),
|
|
|
|
]
|
|
|
|
|
|
|
|
self.memory_manager = memory.MemoryManager(memory_map)
|
|
|
|
self.memory = self.memory_manager.memory
|
|
|
|
|
|
|
|
self.memory_manager.enable()
|
|
|
|
|
|
|
|
self._indirect_bus_mode = False # type: bool
|
|
|
|
self._auto_increment = False # type: bool
|
|
|
|
|
|
|
|
# Address read pointer
|
|
|
|
self.ptr = 0x0000
|
|
|
|
|
|
|
|
# Inbound data to buffer via TCP socket
|
|
|
|
self.stream = stream
|
|
|
|
|
|
|
|
def _mode(mode, value):
|
|
|
|
if not (mode & machine.AccessMode.WRITE):
|
|
|
|
return
|
|
|
|
# 7 - reset
|
|
|
|
# 1 - address auto-increment
|
|
|
|
# 0 - indirect bus mode
|
|
|
|
assert value & 0b10000011 == value, value
|
|
|
|
self._indirect_bus_mode = bool(value & 1)
|
|
|
|
self._auto_increment = bool(value & (1 << 1))
|
|
|
|
machine.Log(
|
|
|
|
"Uthernet", "Indirect bus mode: %s, Auto-incr: %s" % (
|
|
|
|
self._indirect_bus_mode, self._auto_increment
|
|
|
|
))
|
|
|
|
if value & (1 << 7):
|
|
|
|
self.reset()
|
|
|
|
|
|
|
|
def _socket_mode(mode, value):
|
|
|
|
if not (mode & machine.AccessMode.WRITE):
|
|
|
|
return
|
|
|
|
|
|
|
|
# 5 - delayed ACK disabled
|
|
|
|
# 3 - 0 for TCP
|
|
|
|
# 2 - 0 for TCP
|
|
|
|
# 1 - 0 for TCP
|
|
|
|
# 0 - 1 for TCP
|
|
|
|
|
|
|
|
assert value == 0b100001, value
|
|
|
|
|
|
|
|
def _socket_command(mode, value):
|
|
|
|
if not (mode & machine.AccessMode.WRITE):
|
|
|
|
return
|
|
|
|
|
|
|
|
def _OPEN():
|
|
|
|
# Move TCP status to SOCK_INIT
|
|
|
|
self.memory[0x403] = 0x13
|
|
|
|
machine.Log("Uthernet", "Opening socket 0")
|
|
|
|
|
|
|
|
def _CONNECT():
|
|
|
|
# Move TCP status to SOCK_ESTABLISHED
|
|
|
|
self.memory[0x403] = 0x17
|
|
|
|
|
|
|
|
def _RECV():
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
commands = {
|
|
|
|
0x01: _OPEN,
|
|
|
|
# 0x02: _LISTEN,
|
|
|
|
0x04: _CONNECT,
|
|
|
|
# 0x08: _DISCON,
|
|
|
|
# 0x10: _CLOSE,
|
|
|
|
# 0x20: _SEND,
|
|
|
|
# 0x21: _SEND_MAC,
|
|
|
|
# 0x22: _SEND_KEEP,
|
|
|
|
0x40: _RECV,
|
|
|
|
}
|
|
|
|
handler = commands.get(value)
|
|
|
|
if handler:
|
|
|
|
handler()
|
|
|
|
|
|
|
|
self.io_map = {
|
|
|
|
# CONTROL REGISTERS
|
|
|
|
|
|
|
|
0x0000: (
|
|
|
|
machine.AccessMode.RW, "Mode", _mode),
|
|
|
|
0x0001: (
|
|
|
|
machine.AccessMode.RW, "Gateway Address 0", None),
|
|
|
|
0x0002: (
|
|
|
|
machine.AccessMode.RW, "Gateway Address 1", None),
|
|
|
|
0x0003: (
|
|
|
|
machine.AccessMode.RW, "Gateway Address 2", None),
|
|
|
|
0x0004: (
|
|
|
|
machine.AccessMode.RW, "Gateway Address 3", None),
|
|
|
|
0x0005: (
|
|
|
|
machine.AccessMode.RW, "Subnet Mask Address 0", None),
|
|
|
|
0x0006: (
|
|
|
|
machine.AccessMode.RW, "Subnet Mask Address 1", None),
|
|
|
|
0x0007: (
|
|
|
|
machine.AccessMode.RW, "Subnet Mask Address 2", None),
|
|
|
|
0x0008: (
|
|
|
|
machine.AccessMode.RW, "Subnet Mask Address 3", None),
|
|
|
|
0x0009: (
|
|
|
|
machine.AccessMode.RW, "Source Hardware Address 0", None),
|
|
|
|
0x000a: (
|
|
|
|
machine.AccessMode.RW, "Source Hardware Address 1", None),
|
|
|
|
0x000b: (
|
|
|
|
machine.AccessMode.RW, "Source Hardware Address 2", None),
|
|
|
|
0x000c: (
|
|
|
|
machine.AccessMode.RW, "Source Hardware Address 3", None),
|
|
|
|
0x000d: (
|
|
|
|
machine.AccessMode.RW, "Source Hardware Address 4", None),
|
|
|
|
0x000e: (
|
|
|
|
machine.AccessMode.RW, "Source Hardware Address 5", None),
|
|
|
|
0x000f: (
|
|
|
|
machine.AccessMode.RW, "Source IP Address 0", None),
|
|
|
|
0x0010: (
|
|
|
|
machine.AccessMode.RW, "Source IP Address 1", None),
|
|
|
|
0x0011: (
|
|
|
|
machine.AccessMode.RW, "Source IP Address 2", None),
|
|
|
|
0x0012: (
|
|
|
|
machine.AccessMode.RW, "Source IP Address 3", None),
|
|
|
|
0x0015: (
|
|
|
|
machine.AccessMode.RW, "Interrupt",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0016: (
|
|
|
|
machine.AccessMode.RW, "Interrupt Mask",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0017: (
|
|
|
|
machine.AccessMode.RW, "Retry Time 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0018: (
|
|
|
|
machine.AccessMode.RW, "Retry Time 1",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0019: (
|
|
|
|
machine.AccessMode.RW, "Retry Count",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x001a: (
|
|
|
|
machine.AccessMode.RW, "RX Memory Size", None),
|
|
|
|
0x001b: (
|
|
|
|
machine.AccessMode.RW, "TX Memory Size", None),
|
|
|
|
0x001c: (
|
|
|
|
machine.AccessMode.RW, "PPPoE Auth Type 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x001d: (
|
|
|
|
machine.AccessMode.RW, "PPPoE Auth Type 1",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0028: (
|
|
|
|
machine.AccessMode.RW, "PPP LCP Request Timer",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0029: (
|
|
|
|
machine.AccessMode.RW, "PPP LCP Magic Number",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x002a: (
|
|
|
|
machine.AccessMode.RW, "Unreachable IP Address 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x002b: (
|
|
|
|
machine.AccessMode.RW, "Unreachable IP Address 1",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x002c: (
|
|
|
|
machine.AccessMode.RW, "Unreachable IP Address 2",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x002d: (
|
|
|
|
machine.AccessMode.RW, "Unreachable IP Address 3",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x002e: (
|
|
|
|
machine.AccessMode.RW, "Unreachable Port 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x002f: (
|
|
|
|
machine.AccessMode.RW, "Unreachable Port 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
|
|
|
|
# SOCKET 0 registers
|
|
|
|
|
|
|
|
0x0400: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Mode",
|
|
|
|
_socket_mode),
|
|
|
|
0x0401: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Command",
|
|
|
|
_socket_command),
|
|
|
|
0x0402: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Interrupt",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0403: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Status", None),
|
|
|
|
0x0404: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Source Port 0", None),
|
|
|
|
0x0405: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Source Port 1", None),
|
|
|
|
0x0406: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest HW Addr 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0407: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest HW Addr 1",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0408: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest HW Addr 2",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0409: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest HW Addr 3",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x040a: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest HW Addr 4",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x040b: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest HW Addr 5",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x040c: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest IP Addr 0", None),
|
|
|
|
0x040d: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest IP Addr 1", None),
|
|
|
|
0x040e: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest IP Addr 2", None),
|
|
|
|
0x040f: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest IP Addr 3", None),
|
|
|
|
0x0410: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest Port 0", None),
|
|
|
|
0x0411: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Dest Port 1", None),
|
|
|
|
0x0412: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 MSS 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0413: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 MSS 1",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0414: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 Protocol",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0415: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 IP TOS",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0416: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 IP TTL",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0420: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 TX Free Size 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0421: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 TX Free Size 1",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0422: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 TX Read Ptr 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0423: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 TX Read Ptr 1",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0424: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 TX Write Ptr 0",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0425: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 TX Write Ptr 1",
|
|
|
|
self.unimplemented_io_callback),
|
|
|
|
0x0426: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 RX Received Size 0", None),
|
|
|
|
0x0427: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 RX Received Size 1", None),
|
|
|
|
0x0428: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 RX Read Ptr 0", None),
|
|
|
|
0x0429: (
|
|
|
|
machine.AccessMode.RW, "Socket 0 RX Read Ptr 1", None),
|
|
|
|
}
|
|
|
|
|
|
|
|
def read_data(self):
|
|
|
|
val = self.memory[self.ptr]
|
|
|
|
self.ptr = (self.ptr + 1) & 0x7fff
|
|
|
|
return val
|
|
|
|
|
|
|
|
def write_data(self, value):
|
|
|
|
self.memory[self.ptr] = value
|
|
|
|
self.ptr = (self.ptr + 1) & 0x7fff
|
|
|
|
return
|
|
|
|
|
|
|
|
def read_mode(self):
|
|
|
|
return self.memory[0x0000]
|
|
|
|
|
|
|
|
def write_mode(self, value):
|
|
|
|
self.memory[0x0000] = value
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
# TODO: what state should be reset?
|
|
|
|
machine.Log("Uthernet", "Resetting")
|
|
|
|
|
|
|
|
def fill_socket(self):
|
|
|
|
# TODO: assumes 4k socket rx buffer
|
|
|
|
print("")
|