Things have finally settled down in the tool hacking land and I’ve moved on to spending most of my time drawing up schematics. And all of the work I’ve been doing is now up on GitHub! Here’s links to all of the repositories, plus descriptions of what they are:
Logisim is a great tool for visualizing logic circuits, but has has two shortcomings that prevent it from being useful in its unmodified form: it doesn’t allow you to set initial conditions, and it doesn’t simulate gate propagation delay. I had addressed the former before my blog post on simulation, but propagation delays do matter in the AGC, which is why I said it had some features that prevented it from being more useful at the time.
The particular circuit that inspired to me to ahead and hack propagation delays into Logisim is this thing from page 1 of the Timer module:
My Verilog simulations showed that produces a pulse whose width is exactly 5 propagation delays on the rising edge of its input (pin B of 37148 above). Logisim disagreed:
Now that I’ve got propagation delays added in as a configurable property of logic gates, the Logisim simulation looks like this:
Unlike Logisim, my changes to KiCAD are fairly minimal; they simply flesh out the XML format for the generic netlist generator a bit. KiCAD allows you to set user-defined attributes per part. I’m using this feature to feed part parameters like initial conditions into the Verilog generator. However for multipart components, only one (seemingly random) part’s attributes actually get written to the XML file. My fork addresses this and writes out attributes for all parts of multipart components.
It’s worth noting that unlike my Logisim stuff, the official version of KiCAD will work totally fine for opening and editing the schematics and boards; my changes are only needed for proper functioning of the Verilog generator. I also might be able to get these changes pushed upstream.
This repository contains the real meat of this project: all of the KiCAD projects, schematics, board layouts, and components for the physical AGC. It’s a bit sparse at the moment, since I’ve been spending a lot of time figuring out how to group modules and how to best use KiCAD’s heirarchical sheets, but it should grow quickly.
This repository holds all of the simulation harnesses and tests for the Verilog models of the stuff in the AGC Hardware repository, plus any supporting tooling I develop. The Verilog generator that I spend so much time talking about is in here.
It also houses the autogenerated Verilog, at least for now. I’m normally not one for committing generated products to repositories, but the Verilog generation process is quite manual at the moment and I’m not aware of an easy way to script it. I’ll probably end up addressing that issue later when I’ve got multiple interfacing modules to deal with.
The registers in the AGC are all constructed using classic cross-coupled NOR gates. They’re divided into two classes, the “central” registers A, L, Q, and Z, and the “special” registers, which includes all of the rest of them. The central registers, as well as the banking registers, are also mapped over the lower area of Erasable memory; i.e., memory location 0 is not actually part of the Erasable memory core RAM, but rather is redirected to the A register. These registers are shown in R-700 in Table 2-II:
Outside of these, there’s a handful of non-addressable special registers:
Non-Addressable Special Registers
Contains the next instruction to be executed
Memory buffer register; contains data read from or data to be written to erasable or fixed memory
One of two ALU input registers
One of two ALU input registers
Upper 6 bits of current instruction; used for instruction decoding
Lower 12 bits of current instruction, used as address argument for opcode
There’s also a couple of “fake” registers that get thrown around a lot, but don’t exist as physical flip-flops:
The complement of the B register
The output of the ALU
Before I start talking about the real schematics, I want to mention a small section from R-700 that’s particularly helpful here. It’s so good, in fact, that I’m going to just reproduce the text and accompanying figure verbatim:
An illustrative example of the NOR logic in the computer is provided by the operation of the flip-flop registers in the central processor. Digits are transferred from one register to another through a common set of lines called the write buses. The central register flip-flops are selected by read and write pulses applied to gates that either set or interrogate the flip-flop of the corresponding register. Figure 3-2 shows a hypothetical set of three flip-flops similar to those in one bit column of the computer’s central register section.
Information transfers between the registers are controlled by three clocked action pulses: read, write, and clear. Thus the WRITE BUS is normally in the 1 state, and changes to 0, while transferring a 1. Suppose REG 1 contains a 1, i.e., the top gate of its flip-flop has an output of 0. At the time that the READ 1 signal goes to 0 from its normal 1 state, the output of the read gate, CONTENT 1, becomes a 1. This propagates through a read bus fan-in and an inverter and fan-out amplifier to make WRITE BUS become 0. Suppose that WRITE 2 is made 0 concurrently with READ 1. Then the coincidence of 0’s at the write gate of REG 2 generates a 1 at the SET 2 input, thus setting the bit to 1.
If REG 1 had contained a 0, the write bus would have remained at 1, and no setting input would have appeared at the upper gate of REG 2. The CLEAR 2 pulse, that always occurs during the first half of WRITE 2, would have forced the flip-flop to the 0 state, where it would remain; whereas when a 1 is transferred, the SET 2 signal persists after the CLEAR 2, and thus forces the register back to the 1 state. Thus the simultaneous occurrence of READ 1, WRITE 2, and the short CLEAR 2 pulses transfers the content of REG 1 to REG 2. Only the content of REG 2 may be altered in the process. REG 1 and REG 3 retain their original contents. An instance of gates being used to increase fan-in is shown where several CONTENT signals are mixed together to form the signal READ BUS. An increase in fan-out is achieved by the two gates connected in parallel to form the signal WRITE BUS.
This should provide some good context for upcoming discussions. Plus, we’ve already seen the generation of the Read and Write pulses for each register in the Instructions portion of this tour (the Clear pulses are a bit weird, I’ll get to them later). As a quick refresher, many of the control pulses coming out of the Cross Point Generator modules have names like “WA” (write A register) or “RB” (read B register).
Without further ado, here’s what the real deal looks like:
This is the first page of the first of four 4 Bit Modules. All four of the 4 Bit Modules are very nearly identical, and consist of two very nearly identical pages. Furthermore, as you can kind of see above, each page is split into two almost identical “one bit columns”.
These one bit columns consist of flip-flops for the X, Y, A, L, Q, Z, B, and G registers, along with the necessary circuitry to read and write each. The X and Y registers at the top feed into one bit of the ALU, which is, quite simply, just an adder. I’ve also marked the one bit column’s “read bus” and “write bus” that correspond to R-700’s example above.
On closer inspection, though, the signals controlling these registers aren’t quite what we might be expecting based on the output of the Cross Point Generators.
Instead of WA/ (write A not), CA (clear A), and RA/ (read A not), we’ve got WAG/, CAG, and RAG/. This is because there’s one more stop for the control pulses before they reach the central registers: the Service Gates module.
Also note that this is the birthplace of the register Clear signals. The Cross Point Generators don’t generate any sort of clear control pulses; instead, they’re created here as the intersection between a register Write control pulse and the CT/ timing control pulse.
At this point, the only registers we haven’t looked at are the banking registers EB and FB, and the instruction argument register S.
The banking registers are (for some reason) located in the Rupt Service Module, whose main purpose is to handle interrupts. I’ll go over the other functionalities of this module later, but for now, here’s EB and FB:
The BB register is also only “real” in the sense that it’s accessible in the AGC’s address space; only the EB and FB registers exist as physical flip-flops. BB accesses simply access both of these registers simultaneously.
Lastly, we have the S register, which is in the Parity and S Register Module. Here is the second page of that module:
It’s mostly the S register, plus a bit of logic about editing operations which I’ll talk about in the Memory part of the tour. But while we’re here, I’ll talk about what’s on the first page of this module too:
This structure computes the parity (i.e., whether the number of 1’s is even or odd) of the contents of the G register. It’s a very basic used to verify that the contents of memory are self-consistent. If for some reason a 1 unexpectedly becomes a 0 or vice-versa in memory, this circuit will catch and flag the problem before the data leaves the G register.
That’s all for now! I’ll be getting into more detailed circuit analyses before continuing this schematic overview tour. All that’s left to go, though, is Memory, Interrupts, and I/O!
Simulation is going to be extremely important for this project to be successful. The most obvious reason is that PCB errors are going to be expensive and painful to debug, but there’s a handful of reasons specific to the AGC:
The available schematics are incomplete. All of the Tray A modules are there, which is the really important bit. But we’re missing almost all of Tray B. That means all of the memory-interfacing circuitry needs to be recreated to work well with the core logic. (To be fair, I was probably going to do this anyways; building ferrite core memory is currently out of scope for this project).
The AGC uses chains of NOTs to create delays in some places. The below image, is an example from the Timer module, puts the CT signal through three inversion stages before driving the main line everything that uses the signal is connected to.
The propagation delay for AGC NOR gates was 20us nominal, and 30us worst case. Both 74HC and 74LS NOR gate components are roughly twice as fast as this, so the timing surrounding such circuits in my computer will be quite different, and very well may require modification.
The scans of the schematics aren’t perfect.
There’s errors in the schematics. This is a list of errors compiled from a signal list, made by Jim Lawton. Most of the things in this list aren’t concerning. Signals with no sinks have no negative impact whatsoever, it just means a signal got put out on a pin and it never ended up needing to be used. Even most of the seemingly more egregious “signals with multiple sources” can safely be ignored; almost all of the entries here are actually instances of fan-out expansion gates or open-collector buses, being incorrectly marked as errors. The really concerning ones are the signals with no source. Those I’ll need to figure out.
My initial reaction to simulating a processor was to put it into an FPGA, but I learned quite quickly that this is a BadIdea. The AGC is built mostly on asynchronous logic, which doesn’t translate well at all to the Look-Up Tables of FPGAs (and makes replication of timing quite difficult, even outside of an FPGA).
With all that said, an attempt to do exactly that has already been made by Dave Roberts. However, it doesn’t appear he ever got it fully working (though he got pretty close), and comments in the files he provides allude to issues with timing. Still, the fact that he got as far as he did is both very cool, and very promising!
Anyways, with the FPGA idea gone, I started testing out some digital simulation programs. I very quickly learned that doing any sort of digital simulation for the AGC is going to be an interesting challenge.
To demonstrate, I’m going to focus on a specific circuit, whose properties have been driving my selection of an approach to simulation.
The entry point of the 2.048MHz oscillator into the Tray A logic modules is Module A2, the Timer. It immediately runs into a rather interesting structure of 6 NOR gates (ignore the one in the upper right). This circuit accomplishes something pretty remarkable. And as it turns out, it’s a pain to simulate.
For the purposes of this discussion, I’ll focus on another instance of this circuit, also in the Timer module. It’s exactly the same, but all of the nodes have labels, which makes it easier to show what’s going on.
I was pretty confused by this thing when I first started looking at it. Normally you only see NOR gates cross coupled in pairs to build SR latches, but here we have four gates that are all cross-coupled, feeding another, more common cross-coupled pair (which then feed back into the group of four).
So, let’s throw it into a simulator to see what it does. My first attempt was to implement it in Logisim, which some people have used to implement fully working processors. Unfortunately, this didn’t really work out too well.
The entire circuit flashing on and off nonstop! Circuitmaker 2000 initializes all nodes to 0 during the first time step of the simulation. Because everything here is a NOR gate, that means the next time step, all of them will put out a 1. However this makes all inputs a 1, so the next time step, all of their outputs will go to 0, and so on and so forth. Logisim fails for a similar reason: it tries to derive the initial state of the circuit through propagation, and quite simply can’t. Another interesting thing about this circuit: watch what happens as the input signal (P01/ in the sample circuit) changes. The two gates it feeds into are prevented from oscillating, but only while P01/ is high. In other words, there’s no input you can give this circuit to make it settle on a state, like you can with an SR latch (which will also oscillate forever in a simulator like this given bad inputs).
The core of the problem is that simulators like this implement ideal gates. In the real world, small variations in the construction of the components will cause the circuit to settle into a stable state quite quickly, preventing oscillations like this from occurring for too long. Analog simulators like SPICE, which also model ideal components, typically let you set initial conditions on the circuit to force the circuit into a known state at the beginning of a simulation (otherwise, they’re subject to the same oscillations). But unfortunately, it seems that this is not a common thing for digital engines, or at least the free ones I was able to get my hands on. Even Verilog doesn’t let you set initial values on wires.
So what to do? It’s possible to force the clock divider into a known state by increasing the number of inputs on the NOR gates and adding additional circuitry:
This approach doesn’t sit well with me, though, because it means the circuit being simulated isn’t the same as the one being built. Moreover, I’d have to sketch out two separate versions of the schematic, one for PCB layout and one for simulation, and that’s just asking for errors.
After doing a lot of research, I’ve decided to take a three-pronged approach to simulation. First, I’ll be using LTSpice for analog simulation, in small-to-medium-sized doses. That’ll be important both for signal integrity, and to be sure the propagation delays I put into the digital simulation are at least somewhat accurate.
Second, I patched Logisim to accept initial conditions for gates.
Logisim will be primarily used for simple circuits like this, just to figure out what’s going on. It’s got a few features that prevent it from being more useful beyond that without further modification, but for simple stuff, it’s great.
The bulk of the work will be done in KiCAD, an open-source PCB design program that’s roughly comparable to Eagle. KiCAD doesn’t have any simulation built in, aside from very basic SPICE integration that can call out to LTSpice. Instead, I’ll be using Icarus Verilog as the primary simulation engine. I’ve been working on a Verilog exporter to generate Verilog from KiCAD-exported netlists. This approach has a lot of advantages: there’ll be one source of truth for both PCB layout and simulation (what is simulated is what will be built), and I can insert the additional circuitry shown above automatically into the generated Verilog without having any of it in the schematic or PCB. Verilog is also more or less an industry standard for digital design and simulation. It’s really fast compared to the graphical tools, and I’ll be able to do a lot with it. (Incidentally, it’s the simulation-only features of Verilog that allow me to simulate the AGC at all; the generated Verilog won’t be synthesizable, so unfortunately it still can’t be put into real hardware).
KiCAD’s generic netlist exporter also requires some patches to fully support everything we need.
The modified netlist exporter makes sure the 1’s circled on U1C and U2B in the above image make it into the netlist file. I’ve placed these as markers for gates that have their “ResetValue” attribute set to 1. This attribute tells the Verilog generator what to use as the reset value for each gate.
I’ll go into more detail on the Verilog generator in a later post. For now, let’s wrap this one up by using the patched Logisim and Icarus Verilog to analyze the clock divider circuit.
As expected, FS01 is a square wave with half the frequency of P01/. But more interesting are F01A, F01B, F01C, and F01D — they constitute a four-phase clock of the same frequency as FS01. And as described in R-393, “signals FxA, FxB, FxC, FxD represent pulses 90° (electrical) out of phase. A leads C (not B) by 90°; C leads B by 90°; B leads D by 90°”. This is actually a really neat circuit — only 6 gates, and it produces 6 useful clocking signals. No wonder it’s used so much throughout the AGC!
Finally, here’s a waveform output from the same circuit, simulated in Icarus Verilog:
Exactly as expected! Unlike Logisim, my Verilog models are taking the propagation delays of the individual NOR gates into account. You can see the results of this as overlapping signals — most conspicuously in the above image, F01B overlapping with F01C.
That’s all for simulation for now! The Verilog generator should be done shortly, after which the analysis can really take off. Until then!