System/1 Build Log
An ongoing chronology of System/1's construction, and any other related musings.
20th August, 2017 - Learning to talk to the outside world
With the clock board built and working (well, working well enough that I'm fairly sure I can iron out the remaining problems when my extender card turns up!) we have something that we can reasonably suggest is a complete computer — the CPU itself, some RAM, and a front panel for getting words into the machine and back out again. However, as I/O options go, that's a bit limiting. It's time to do something about that.
The obvious choice for a first I/O peripheral for the machine would be a serial port. That way, not only do we get support for an interactive terminal, but we can easily dump code into the machine from a more capable development environment — if only for bootstrapping. I have a handful of common-or-garden UART chips floating around the place (8250s, 16550s, etc.) which would theoretically be easy enough to hook up as memory-mapped I/O, but not only would that feel like a bit of a cop-out having come this far with 74HC logic and perfboard, it's not much fun.
With that in mind, and a enforced delay in clock board testing brought about by the wait for an extender card, I sat down with a breadboard and a pile of chips to build a UART of my own. Admittedly, it won't be particularly universal (I can't see any need to support anything other than 8N1 at a variety of common baud rates, since I'm not going to be hooking it up to anything too exotic or ancient), but I'm not sure calling it a Somewhat-Hardwired Asynchronous Receiver/Transmitter is going to lead to a particularly dignified board label when it's all finished...
The core design I have in mind consists of a pair of 74HC161 counters, which are effectively used as the state variables — they can be held in an idle state until some trigger event happens, then clock the right number of bits in to or out of the transmit/receive shift registers. The transmit side is straightforward enough to prototype; it only took an hour or so to wire something up on the breadboard that was capable of sending a hard-wired byte value, either as a one-shot or a continuous stream, and that includes starting from scratch half-way through when I realised I didn't like the way I'd implemented the idle state.
On the receive side I wasn't entirely sure at first how complicated I ought to make the handling of the incoming bits; obviously they first needed to be synchronised to the same clock as the receiver is using, to avoid problems with setup/hold times, and since this requires at least an extra D flip-flop on the input side I realised I might as well use a quad flip-flop for this, which makes oversampling the input trivial. This lead to the hasty construction of a simple majority detector, operating over the 4x oversampled input; it seemed to work reliably, although I'm not sure how valid my efforts to introduce some noise or jitter into the input for testing were.
At the end of a first evening's experimentation, I had an almost-full breadboard that could send a byte (set via DIP switches) on demand and display the most-recently-received byte on a set of LEDs — great for proving I wasn't heading in completely the wrong direction, but not so useful for practical purposes. Luckily I didn't have to wait long before I had another spare evening to work on improving the situation; rather than hook the prototype up to the CPU's memory bus right away, though, I wanted to try out the 74HC40105 FIFOs I bought a little while back. Each of these provides a 16-slot-deep queue of 4-bit words, so replacing the DIP switches with one pair of them and putting another pair between the receive register and the LEDs should give me the ability to queue up data for transmission and receive more than single bytes.
I tackled the receive FIFO first, as it is the easier of the two to implement; bytes can be clocked into the FIFO whenever the counter reaches the stop bit, and then just adding a debounced pushbutton to clock bytes out of the other side allowed the received data to be reviewed on the existing bank of LEDs. The transmit FIFO was a bit more of a head-scratcher, as I initially wired it up to clock bytes out on the wrong state transition so it would occasionally drop the first byte in the queue if I'd been holding the transmitter in the idle state to build up a buffer. Once I noticed that, though, I could (somewhat labouriously) toggle a Hello World message into the buffer and have it appear in my terminal window. This is a much more satisfying result than the stream of repeated exclamation marks I'd had at the end of the previous experiment, and seems like a good place to take a break whilst I think of a way to hook this up to the memory bus for some testing under software control.