The Xmodem protocol
Xmodem has been used to transfer files over serial connections for about 40 years. It was designed to be simple and easy to implement on different machines. It incorporates error checking as it could be used over slow low-quality telephone lines. Back in 1984 I used it to transfer files between PCs with cross-over cables and also to communicate between commodity traders in London and New York.
For the protocol to work between two local machines they need to be connected using a cross-over cable. The transmit (TX) pin on the first computer is connected to the receive (RX) pin on the second, and vice versa. The sender program prepares a file ready to be sent over the comms line and waits. The receive requests the sender to start transmitting 128 data byte blocks. Each block starts with SOH (Start of Header), contains a block number in the header and a check sum in the trailer so the receiver can verify data. The receiver acknowledges (ACK) or reports an error (NAK) causing a new block or the same block repeated to be sent down the wire. On completion the sender transmits an EOT (end of transmission) byte.
6502 implementation
I found a 6502 xmodem implementation by Daryl Rictor and have based my work on his xreceive program. The PC xmodem implementation is available in ExtraPutty, a version of the Putty terminal emulator with added file transfer capabilities.
I started an xmodem implementation in August 2021 but ran into difficulties for a number of reasons:
My breadboard hardware was unreliable
I couldn't run my 6502 system at the full 1MHz speed
My library system was not robust and wrong versions were used
My understanding of xmodem wasn't very good
It was difficult to see what was happening on the serial wire, particularly when bytes were missing.
These factors meant that, although I had some success, I couldn't get the protocol working reliably despite expending a lot of effort on the work, especially lots of time troubleshooting with trial-and-error solutions. The result was that I shelved the project and after some time decided to build BEN2 in the hope that it would be more successful because:
I have used soldered connections on stripboard
I am already runnig the clock at 1MHz for testing terminal programs
I am not going to use libraries during development
I understand xmodem a little better
My serial interface seems more stable
Approach
On the 6502 monitor program which is loaded when BEN2 is turned on or RESET, there are options to jump to a memory address to run a program and to look at the data at specific RAM addresses. These are very useful for xmodem testing so I need to keep the monitor loaded. Consequently I added the 6502 xmodem receiver as a monitor menu option / subroutine rather than a standalone program.
Rather than try to implement a full xmodem client initially, I wrote my own "cut-down" version of the "sender" in C on the PC and I then understood more precisely what was being sent down the line and I could write a corresponding "receiver" on BEN2.
Windows Subsystem for Linux (WSL) allows you to use serial ports and although the parameters for opening a port are somewhat esoteric, copying a sample from Google make it easy to try out. As I wrote the sender program previously I only had to change the COM port number used to work for this implementation.
One snag with avoiding Putty for the download is that it is necessary to stop using Putty terminal emulation whilst downloading. As I use the terminal extensively for my monitor program to control BEN2 this is a nuisance. However, at least for the moment, it isn't too onerous to "hang up" before starting the sender program and "restart session" afterwards.
Simple code to download and execute a program
As xmodem (xm) is a subroutine my starting point for the receiver was the monitor program. The first version added 'x' to the monitor menu to initiate the receiver and wait for something to be received on the ACIA/UART. It simply saved the first four bytes received in memory address $1000-$1003.
I could then look at those RAM locations using the monitor. The first three bytes received are the header and the fourth byte is the first character of my program data (just a string of text to begin with).
The next xm version downloaded 133 bytes to RAM starting at $1000. This represents an entire block:
<SOH><BlockNum 1><BlockNum 2><n program bytes><128-n filler bytes><checksum 1><checksum 2>
Again I could look at it in memory and check that all bytes were received. I was very pleased to see that my receiver isn't dropping any bytes when the 1MHz crystal is used for 6502 clock.
I could now try to download a real program providing it was less than 128 bytes. The program, which can turn an LED on or off is shown below.
I couldn't actually copy my existing blink program as it is compiled to run at $1000 and this new program was being loaded at $1000. However it was easy enough to manually translate the program to machine code and type it in to my hex editor.The ACIA addresses for PORTA LED are $6003 (for the Data Direction register A) and $6001 (for PORTA data). The appropriate address to jump back into the monitor in completion is $8013.
To turn the LED on I entered the monitor command "j1000"; to turn the LED off the command is "j100d".
Multiple blocks
The previous xm version only allowed programs upto 128 bytes to be downloaded in a single block. It was easy to extend the code to process multiple blocks which are saved contiguously in RAM. The complete subroutine is shown below.
Verdict
This is very exciting. I have a simple application which enables me to download an executable program from my PC to BEN2 and run it, without using a ROM programmer or an Arduino to perform the downloads.It is only a prototype, it doesn't implement xmodem protocol fully and has a lot of rough edges but it does form the basis for a working system which I can build on.