SAM/IP

The SAM port of uIP seems to be on hold at the moment, so I’ve been looking at other IP stacks to use until it’s ready. The most appealing is Mark Rison’s CPC/IP, not least because it’s written in Z80 and should work without extensive changes. It also comes with a number of built-in client (telnet, finger, host, ping) and server (web, tftp, dns) modules.

So far I’ve modified the source so it assembles with pyz80. A global search and replace made quick work of changing the label format from “.label” to “label:”, but I had to change many data statements manually. Strings were often combined with other single bytes in defb statements, but the Comet format used by pyz80 doesn’t allow that, requiring defm be used instead.

The existing code is nice and modular, but there are CPC-specific ROM calls sprinkled throughout them. All those need to be changed before a test run on SAM, to avoid us unexpectedly jumping into the middle of nowhere! I changed the stdio.z module to use SAM’s ROM calls for character output, leaving the cursor control and keyboard input doing nothing for now. I also replaced the serial module with a dummy ethernet module, with no-op versions of the required interface functions. They will be fleshed out with calls to the Trinity driver when the rest of the code is ready.

Those changes are enough for a basic run on SAM, without being connected to a real network. Here’s what you see when it’s launched:

The program continues polling for serial and keyboard input in a main loop. The CPC version uses a 300Hz timer to poll for new data from the serial link, which is buffered for later reading from the main loop. Each received byte is passed into either the SLIP or PPP module (whichever was configured during the build), which builds up complete datagrams. These are then passed into the ‘ip_handle’ function inside ip.z for the processing.

The SAM implementation will read complete datagrams from the Trinity driver, so they can be passed straight into ‘ip_handle’. This vastly simplifies the setup above, but introduces a new requirement: ARP. SLIP and PPP push datagrams back into the link and let the remote end deal with routing. With ethernet we need to determine the hardware addresses for delivery, for both local and routed traffic.

I’ll need to write a new arp.z module to sit between the Trinity driver and the IP module. Outgoing traffic for hosts already in the ARP cache can be sent immediately. Anything for as-yet-unknown targets must be buffered, and a who-has ARP request made for the address owner to reply. Once a reply is received, an entry for it is added to the local ARP cache and data buffered for that host is sent. If no reply is received (ideally after multiple attempts), data for the target will be discarded. We must also reply to incoming ARP requests for our own address so other hosts can to talk to us.

I’m still torn between using the SAM ROM routines for I/O and something based on the terminal code I wrote for the Apple 1 emulator. The ROM code would give the same output flexibility as in BASIC, but the general ROM code is a bit on the slow side. My own code could be tailored for a specific mode, either mode 2 for speed or mode 3 for hi-res. It might be easier to stick with the ROM code for now, and change it if it’s too slow.