System/1 Build Log
An ongoing chronology of System/1's construction, and any other related musings.
13th September, 2014 - Breadboarding the clock generator
Today being the first day of a fortnight off work, I figured it was about time I sat down to make some more progress on the project — I've barely had a chance to touch it since July.
One aspect of the design that I haven't really thought about beyond the abstract functionality is a front panel; obviously I need some way of getting data and code into the completed system for testing, and a computer without blinkenlights is no computer at all, but apart from a rough idea of the operations it needs to perform I haven't thought at all about how it should interact with the processor's execution cycle.
In addition, I'd like to make sure my planned clocking scheme works properly before I build too much more of the system. The intention is to have a 'bit clock', which always runs in bursts of 32 pulses, and a 'memory clock' which can free run for however long it takes to perform a memory access. The reason for the split is simple; all of the registers in the system will be clocked simultaneously, so if they ever get clocked by a train of pulses that isn't a multiple of 32 the values they contain will end up rotated by some distance — which is hardly going to be useful — but making every major cycle in the system 32 clocks long will make memory access dreadfully slow. Admittedly splitting the clocks only saves maybe 30 cycles for the shortest instructions (register-to-register operations require three sets of 32 pulses and one memory read of around two clocks), but this thing's going to be slow enough without wasting cycles doing nothing!
With these two outstanding issues in mind, I think it would make sense to spend some time breadboarding the system's clock generator, which combines the main oscillator, a counter (to create the CPn clock phase signals) and a small state machine to generate the signals representing the main machine cycles (FETCH_1 to FETCH_3, COMPUTE, MEM_OP and STORE). Of these, the FETCH_2 and MEM_OP cycles are the shorter ones, whilst the other four are all 32 clocks long — although depending on instruction, the last one or two are optional.
To start off, let's get an oscillator running; a simple Pierce design using a 74HC06 and the first crystal to come to hand, which happens to be 4MHz, looks to work nicely. Great! Running that to a 74HC4024 counter with its sixth bit brought back to its RESET pin gives a steady cycle of 0-31 on the logic analyser's state trace, so that's a good (albeit trivially simple) start.
Now to see about the state machine; my original design sketches call for a device that doesn't actually exist, due to my misunderstanding a column in a table in the databook, but a combination of a 74HC161 synchronous counter and a 74HC4514 4-to-15 decoder should suffice. Hooking those up appropriately gets a nice 0-31 count in each of the six main states, but then trying to shorten the FETCH_2 and MEM_OP cycles causes some weird behaviour — sometimes the cycles get skipped entirely, or carry on for the full 32 clocks. Scratching my head in the vague direction of #eevblog on Afternet, a passing EE lecturer points out that I'm being a fool by driving the clock input of the '161 with a mess of combinatorial logic (the two state signals ANDed with the low bit of the clock counter and ORed together with the terminal count signal); the glitches as signals transition are causing my miseries, and I should instead be using the synchronous counter as an actual synchronous device. This not being exactly a groundbreaking revelation only makes it more annoying that I did actually know this, I just hadn't thought about it. Rewiring the '161 to use the system clock and count iff the same mess of combinatorial logic gives it the go-ahead works much better!
With that out of the way, it's time to think about how to interface the front panel to the rest of the machine. There are probably only three things that interface will require from the clock sequencing logic: some form of run/stop control, the ability to trigger a 32-cycle sequence of clocks (so it can push data into or read data out of a register), and the ability to trigger the shorter sequence of clocks for memory operations. It seems that adding three states to the existing machine should work — if every complete instruction cycle starts with a 'sync' state, the FSM can sit in that state until the panel allows it to continue (to give run/stop control), or branch to the long/short panel operation states as required.
Implementing this looks quite straightforward, but by the time I've added suitable debouncing and synchronisation logic to support a run/stop toggle switch I've run out of space on the breadboard, so can't add support for 'do something short' and 'do something long' pushbuttons! Guess I'll have to pop into Maplin tomorrow morning and add another breadboard to the collection...