ii-vision/simulator/uthernet.py

298 lines
11 KiB
Python

import machine
import memory
class Uthernet(machine.Machine):
"""Uthernet/W5100 device simulator."""
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("")