This repository contains scripts, Verilog modules, and test harnesses for simulation of my Apollo Guidance Computer replica hardware designs. It also contains an Altera Quartus II project for the DE0-Nano development board. Auto-generated Verilog files are committed to the repository as well, because in addition to being quite a chore to generate, I've found historical diffs of them to be quite useful.
- Icarus Verilog. Used for digital simulations.
- GTKWave. Used to view waveforms generated by Icarus.
- A clone of the hardware repo. Only required if generating the code from the hardware. NOTE: Various things currently expect agc_simulation and agc_hardware to exist side-by-side. If you'd like to put them in different places, you may need to find and change those things.
- A clone of virtualagc. Also expected to be side-by-side with agc_simulation. Contains the source for all currently-known AGC programs, from which hardware-compatible ropes are built.
- My fork of KiCad. Only required if generating the code from the hardware. Currently code must be generated using my fork, due to some limitations of the netlist format that I've addressed. I plan on getting these changes pushed upstream, so some day this may no longer be a requirement. KiCad Libraries may also be required, if the libraries aren't available through your package manager.
- Python IntelHex. Used to generate hex files for FPGA programming.
- Python Tkinter. Only required if generating code.
- xdotool. Only required if using the included Makefile to batch-generate code.
Setting Up and Generating Code
Setting up KiCad for Code Generation
- Install all of the required packages listed above.
- Open any of the projects in KiCad, then open EESChema. Click on the Generate Netlist button.
- Click the Add Plugin button.
- In the dialog that pops up, enter the following information, then press OK.
python %P/../../agc_simulation/scripts/generate_agc_verilog.py -g "%I" "%O"
NOTE: The project Makefile currently assumes that "AGC Verilog" is the first custom netlist exporter after "Spice".
- Code can now be generated by changing to the new AGC Verilog tab and clicking the Generate button.
- Change the target directory to be the "modules" directory in agc_simulation.
- After a brief pause, you should see a success message from generate_agc_verilog.py.
Building the Code (and Batch Generation)
- If you intend to batch generate code, close all open instances of KiCad.
- In the top-level folder for agc_simulation, run make.
cd agc_simulation make
- If agc_hardware is present in the expected location and module changes are detected, the Makefile will spin up an instance of KiCad for each and do a code generation.
NOTE: While this is happening, DO NOT touch the keyboard or mouse. Just let it be. KiCad does not expose a command-line interface, and I'm too lazy to add one, so instead I've used xdotool to script GUI interaction.
- If at any point the generation process becomes desynchronized (a KiCad instance is left open and doesn't appear to be doing anything), simply close completely out of KiCad, Ctrl-C the make process, and start it over.
Running and Viewing Results
- Make any changes desired to test_agc.v and rebuild using the above process. This file is the main test harness used for digital simulation.
- Still in the agc_simulation directory, run the simulation with Icarus by entering:
vvp test_agc -lxt2
- Upon completion of the simulation, the output waveform can be viewed using GTKWave. To do so, enter the following command:
gtkwave dump.lxt &
- The window that appears will be empty. Open the File menu and select Read Save File.
- Navigate to the agc_simulation folder and select agc.gtkw.
And voila! The fundamental timepulses, all of the central and special registers, and the write and sense amplifier buses are available for viewing. You can now delve through the simulation results.
How It Works
####generate_agc_verilog.py This script functions as a KiCad netlist exporter function, translates KiCad netlists into board-level Verilog modules. At a basic level, it does the following:
- Generates a module declaration that includes all nets attached to the backplane connector. Currently, this connector must be designated as P1 on every module.
- Processes the connectivity of every backplane-connected net to determine whether it is an output, an input, or an inout. The conditions for this determination are as follows:
- output: The net is directly connected to the output pin of a NOR gate.
- input: The net is connected only to inputs of NOR gates.
- inout: The net is connected to the output of an open drain buffer.
- Emits the complete list of nets used in the module, with input/output annotations.
- Emits a list of components. Component argument positions correspond directly to the pinout of that component. If the component metadata includes any non-zero initial conditions, a list of initial conditions precedes the instance name. Two additional simulation-only nets are attached to each component:
- SIM_RST: Used only in digital simulations. Resets the NOR gate to its initial condition value.
- SIM_CLK: Used only in FPGA targets. Simulates propagation delay of the component. Namely, inputs are latched on the rising edge, and outputs are changed on the falling edge.
This script reads in a specified group of Verilog modules created by generate_agc_verilog.py, and generates a top-level computer backplane module that instatiates each logic module and interconnects them. It does the following:
- As each module is loaded, its inputs and outputs are catalogued. If a net is both the input of one module and the output of another, it is marked as "internal". At the end of processing, any module inputs for which no source was found is considered to be a system input (through some external connector). Similarly, any module outputs that are not used by any other module are considered system outputs.
- The declaration for the computer module is emitted using the determined system-level inputs and outputs.
- A complete list of nets going through the backplane is emitted, including I/O type annotation.
- Instantiations for each module are emitted.
If given the --fpga argument, its behavior is rather different. Due to the limitations of the Quartus compiler, the entire code for every logic module must be combined into one file. In addition to the above, generate_agc_backplane performs the following steps:
- Emits declarations for every net used in every module. Codegen hints from generate_agc_verilog.py are used to identify open-drain buses; for these, the net type is changed to "wand".
- The entire list of components for each module, excluding pull-up and pull-down resistors, is emitted.
- For every component with open-drain or tristate outputs (identified using more codegen hints), "proxy wires" are generated and net connections on those pins are replaced with connections to the proxy wires. Before emission of the affected component, a series of assignments of each proxy wire to its original net are emitted.
This script, given an AGC ROM file generated by Ron Burkey's yaYUL, generates a verilog lookup table used by the flash chip model.