Simulating A Quick And Dirty Microprocessor
In preparation for playing with the Papilio Pro and diving into VHDL or Verilog, I decided to further my understanding of processor architecture. Armed with the brilliant and free app Logisim, a Microprocessor Design Wikibook and a guide to logisim I set about learning how processors work, how they digest instructions and how they perform various actions.
The result is certainly not the best, most complete microprocessor ever put together in Logisim, but it was enough for me to learn the fundamentals.
To back it up I created my own assembly language, used to instruct the simulated processor to add, subtract and compare numbers. Here's an example ( prettyprint will choke on this imaginary language somewhat ):
start: LN ACC 0x1 LN GP1 128 LN GP2 128 badger: CMP ACC GP1 -- Compare accumulator to GP1 JUMP EQL done -- Jump to done if equal ADD ACC -- Add accumulator to itself JUMP UN dostuff -- Unconditional jump out to dostuff LOOP badger done: MV GP4 ACC -- Move the value of accumulator into GP4 LOOP start -- Loop program indefinitely dostuff: -- Pointless pseudo subroutine SUB GP2 GP2 ACC -- Subtract accumulator from GP2 and save result into GP2 JUMP UN badger -- Return to our loop
To actually run this code within Logisim, I created a counterpart compiler written in Ruby. It digests the instructions into hex and outputs into a .bin format that can be loaded directly into a Logisim ROM component. Nifty! You can download my Ruby assembly compiler here but it's by no means complete or even sane.
I found that the key to successfully putting together a design in Logisim was to throw away the tedious task of wiring things up, and make liberal use of "Tunnels". A tunnel in Logisim is simply a labelled signal which you can pop up anywhere on your canvas with ease. Labelling signals also makes them crystal clear, making things easier to wire up and debug.
I also cheated somewhat, and used a counter to create a 5 stage clock. Effectively creating distinct signals for Prep, Load, Act, Save, Next which I use to trigger various events. This abstracts away the complexity of timing and rising/falling edge, making it easier to get started on the logic itself.
My Microprocessor has 8-bit general purpose registers, all of which are addressable, a latching CMP operation, functional conditional and unconditional jump instructions and, of course, the ability to add or subtract values saved in registers from each other. Not exactly useful, but educational.
I make liberal use of "off-the-shelf" Logisim components like registers, counters, adders, ROM and decoders to speed up simulation. It's really important that you learn what these do, and how they do it, before you go any further! Circuit Coder on the iPad is a fantastic way to get started with the fundamentals.
Without further ado, you can download my work in Logisim and try it for yourself.