System/1 Build Log
An ongoing chronology of System/1's construction, and any other related musings.
1st May, 2016 - Starting work on a front panel
(Apologies for the long break between updates, folks, I know a few of you have been asking for them — between life being distracting and wanting to actually make progress on the project, I haven't really found the time to keep these pages current! However, over the next few days I hope to clear my backlog of buildlog entries that I'd already started writing at various points during the last year. This is the first of those. — BALJ, 17th November 2016.)
When we last looked in on progress, I had the control unit prototyped across a pair of breadboards and happily running code; over the course of a handful of evenings in September (2015) I committed it to solder, then spent a bit more time experimenting with the ultrasonic cleaner to find a way to rid the board — and more importantly the IC sockets! — of unpleasantly-sticky flux residue. My earlier IPA-based cleaning concoction looked like it worked well at first, but once the boards dried fully it left behind an unsightly white powdery residue of its own. The answer appears to have been to bite the bullet and invest in some dedicated flux-cleaning solvent from an ultrasonics supplier; it's not all that much more expensive than IPA, and so far appears to be working considerably better.
With that out of the way, there's one major functional block left to work out before I can move on to finalising the clock and machine cycle generator design (which I'm leaving until last just in case there's a flaw lurking in the assumptions I made when prototyping it a while back). The machine's front panel is a considerable chunk of logic, as it needs to not only provide the basic controls like Run/Halt buttons but also some basic register and memory I/O facilities so the operator can feed the machine with code and data to chew over.
The core of this I/O facility is a pair of 32-bit shift registers (which should come as no surprise in this machine!), the first of which is fed from the A, B or R buses as appropriate and then brought out to a row of LEDs through a latch that triggers when the register currently selected for display has been updated. The second register works in the opposite direction, latching the setting of a bank of toggle switches at the top of each word cycle and then shifting it out into the selected target register when the user presses a Deposit button. These registers are straightforward enough that I took advantage of an Elecrow discount voucher to order a set of 8-bit-wide register PCBs without prototyping them first; however, rather than using them right away I built an equivalent temporary front panel on a Eurocard to use when prototyping the control logic. This initially met with failure due to swapping the input and output pins of the '573 latches; after some slightly-irritated checking of the PCBs I satisfied myself that I had made the mistake only on the temporary board, and that simply rotating the chips through 180 degrees (and swapping the power rails to match!) would rescue matters.
With that out of the way, and the now-traditional forgetting to tie RESET high leading to a little light head-scratching, register contents could be inspected as the machine ran and updated with some small manual intervention (so that the mbed playing the part of the clock cycle generator knew when to insert word-length supervisory cycles). The next step is to automate that manual process; the plan was to use a '148 priority encoder to detect when any of the various supervisory operations are pending, and request a suitable cycle from the clock generator. Alas I had exhausted my mbed's supply of GPIO pins at this point, so I ordered a new mbed-compatible dev board (an ST Nucleo F411RE) with more pins and an appropriate set of jumper cables so I could continue.
While I waited for those (the board, coming from Farnell, was with me next day — the cables from an anonymous eBay seller in some part of the U.K. that apparently uses Chinese customs declarations took a little longer!) I wired up a couple of extra chips that allow the front panel to provide a 'next address' option. This just adds four to the current value in the MAR, allowing the operator to easily move to the next word when inspecting or depositing values in memory, but due to the design of the MAR it has to be done in two stages — first adding four to the existing value and storing it in a temporary register, then moving it back to the MAR. Rather than trample over the contents of any of the machine's own registers, it would be best if this temporary storage were local to the front panel; luckily we can access both ends of the I/O registers easily enough, and if we use the input register then the associated switches will still be set for us to reload the original value when we're done. Problem solved!
... although not quite. The first attempt managed to count 0, 2, 3, 3, 3..., which turned out to be because the contents of the temporary register were getting shifted right one bit before being moved back to the MAR. This was due to a single clock cycle at the top of a complete machine cycle, during which front-panel and other supervisory operations are checked; usually the input register is loaded from the switches during this cycle, but since that operation is suppressed between the 'add four' and 'move back' cycles the existing contents end up get shifted along instead. Fearing a redesign of the I/O register boards would be needed in order to gate the clock to the input register, I tried an experimental bodge instead — putting a single D-type flip-flop in front of the register extends it to 33 bits, which allows the temporary value to be loaded into the top 32 bits then shifted down one place to the correct location by the stray clock pulse. This did the job nicely, and upon checking the draft schematics I found I had a suitable flip-flop spare already — perfect!
By this point I had everything I needed to try wiring up that priority encoder to the new dev board, which worked nicely; the encoder decides when something needs to happen and requests the corresponding supervisory cycle from the clock generator, and then a latch and decoder turn that decision back into signals telling the rest of the front-panel logic what it should be doing. The highest priority task is the second half of the 'next address' operation, so that the input register doesn't get inadvertently overwritten; the other tasks are currently allocated approximately at random, with the lowest priority being a 'selection changed' task which simply reloads the selected register from itself. This is needed to allow the panel to react to the user changing the displayed register in a timely fashion; without it, the display will be incorrect until the next time the machine updates the relevant register, which could be quite some time in the case of the general-purpose registers.
With all this in place, I have two things: a working I/O bank on the temporary front panel board, and two very full breadboards. To make progress, I need to both free up some space on the latter and implement a whole pile of debounced push buttons on the former — not two particularly compatible aims. Stay tuned...