CARDIAC to FPGA
Over the last few weeks, I've been playing with the old Bell paper teaching computer called CARDIAC. I've gone from a real version, to a spreadsheet simulation, to a Verilog simulation. The Verilog simulation worked pretty well (except for a few bugs I've recently fixed or that I'm in the process of fixing). However, the whole point to putting it in Verilog was to move it to an FPGA.
Why put a 35-year-old paper computer into an FPGA? I am hopeful that a simple CPU like this can help students (and non-students) get their feet wet in building FPGA-based designs. Sure, there are plenty of more modern CPUs around, but they are also possibly more complicated.
My Verilog implementation (called VTACH) runs fine under the Icarus Verilog simulator. To move it to real hardware, I needed a few things. First, I needed an FPGA board. My favorite for this kind of project is the Digilent Spartan-3 Board. I happened to have the 1000K gate version, but the CPU is simple enough to fit on the less expensive 200K part. I like this board because it is self-contained, not too expensive, and has enough I/O devices like LEDs and switches to make for an interesting project.
I also needed some implementation software. I used Xilinx ISE WebPack, which is available for free on its website. The software allows you to simulate (like Icarus but with many more features) and then build a configuration file that will set up your circuit inside the FPGA. Speaking of that, you need a JTAG cable to go with the Digilent board. I happen to have a Xilinx cable (fairly pricey), but Digilent sells less expensive options that would work just as well.
The JTAG interface lets you either directly send the configuration to the FPGA or to the onboard serial EEPROM. If you configure the FPGA, a power cycle will reset the FPGA (which is no big deal during development; you simply reload it). The FPGA normally reads the configuration from the EEPROM so if you put it there, the board will load it on every power up or reset.
It is common to hear people talk about "programming" an FPGA. However, you don't really program an FPGA. The configuration file tells the FPGA how to connect its various parts, but it isn't like an executable program. Of course, this is a CPU so part of the configuration will be a bit image of software for the processor to execute. You could consider that programming.
In a perfect world, you could just pour the existing Verilog code into the Xilinx ISE software, press a button, and get an FPGA out of it. That's close, but not quite practical. The simulation has a few things that are specific to the simulation. For one thing, the clock isn't a real piece of hardware. The io_input.v and io_output.v modules are also highly specific to simulation. There's also a few other tweaks that can make things work better on the real hardware. Specifically, I wanted to use one of the FPGA's specific memory blocks for the main memory.
The final piece of the puzzle is that you need to build a constraint file. The simulated code isn't real. But on the FPGA there are specific pins that connect to clocks, input devices, and output devices. If you don't tell the translation software what to do, it simply picks any pins it wants for different functions. That might be acceptable if you were building a new board and didn't have it built yet. In this case we are using a commercial board that has very specific ideas about what the pins do, and the constraints file tells the translator what pins to use for different signals. You can find the UCF file in the online listings that the Xilinx tool uses to set constraints. There are several ways to set constraints, and if you use a UCF file you can edit it with a text editor or with special Xilinx GUI tools.
One other piece was useful, although not strictly necessary. It is tiresome to hand assemble code every time you want to try a piece of software out on your new CPU. It is also tiresome to write a new assembler to go with each new CPU. I got tired of doing that after developing a few CPUs, so I built axasm that is a very simple (and very hackish) assembler that is easy to configure. I won't go into the details here (you can read the previous article), but the configuration file for CARDIAC and VTACH is in the online listings.
Here's one of my sample programs:
;; Test program to debug the BCD math ORG 0 SFT 8,0 ; read switches to AC STO 70 top: OUT 70 SFT 9,0 ; read pushbutton (-1 or 1) TAC exe ; button down? SFT 0,9 ; read other pushbutton TAC exe2 JMP top exe: ; add one to the count LOD 70 ADD one STO 70 wait: SFT 9,0 ; wait for button up TAC wait JMP top exe2: LOD 70 ; subtract one from the count SUB one STO 70 wait2: SFT 0,9 ; wait for button up TAC wait2 JMP top one: DATA 1 END