For this project, we made use of a RAM and ROM in coordination to prepare to use them as part of a larger CPU design later on. The circuit we created would display on the LEDs of the circuit boards the RAM's output. Initially, the original RAM contents would be displayed, and later, the ROM's contents would move into the RAM and be shown instead.
First, I created two MIF files; they contain 16 words with 8 bits each. Since there are 16 words in each, we need 4 bits to represent all of the addresses in each (0000, 0001, etc.). The words themselves are 8 bits (00100100, for instance). These are shown here:
Using Quartus's Megawizard Plugin Manager, vhdl files were generated that I could then import into my main code. Steps 6 through 7 described the inputs, outputs, component statements, and internal signals we needed to make for the program. These include: "data", which is an output signal that will show the RAM's output and eventually will be linked to the LEDs; the reset and clock inputs; state view, rom address view, ram input, and address view for debugging purposes; RAM and ROM wires for connecting the output of the MIF files to our program; write enable for telling the ROM when it can write to the RAM.
Step 8 was to build the first half of the state machine, which would then need to be tested in GTKWave. From states 0000 to 0100, we created a way to pass in the values from the MIF RAM file to the lights so they could be displayed. First, in state 0000, in order to initialize, the program would wait for 3 clock ticks to pass by only moving on when the startup counter reached 3. In the next state, the RAM data output is sent the data from the RAM MIF, and therefore, it receives the value at address 0000 at the start. Then we increase the address of the RAM by one in preparation for the next address's value to be passed into the RAM_data output. The third state waits for this address change to go into effect. State 0011 checks if the address of the RAM is 0000, meaning it would have looped around again, and if it is, it will simply restart by going to the 0001 state. In state 4, more would be added later, but for now it went back to the first state, 0000. A picture of my gtkwave below shows it working:
The delay at the beginning before the light signal gets anything is there, and in the light signal, we see that every 3 clock ticks (because we keep the address the same through 3 states, which each take 1 clock tick), the output is changed (0F is contained in the last 8 addresses and therefore seems like it isn't changing, but the addresses still are, as ramaddrview shows).
That was fairly straightforward, but now we wanted to put the ROM values into the RAM and display those on the lights, so we needed to add more states. We changed state 0100 to put the ROM wire into the RAM input this time, and then set write-enable to on as well as advance to the next ROM address. Then, it needed another waiting-for-address-to-change state, 0101, during which we also turned write enable off, and it finished off with a state 0110 that goes to the next address in RAM, and if the address it goes to is 0000, it will have already overwritten all of the addresses, and will go back to the start in order to actually feed the new numbers into the RAM data output and into the lights.
The gtkwave for this is below. As one can see, the cycle through the RAM at the beginning is the same, except now it goes on to write the ROM in after going through all the addresses in the RAM once. The raminputview shows the data from the addresses, and one can see that the rom address is first loaded, then the ram address changes correspondingly after a delay. This repeats infinitely, and the ROM is now in the RAM, even on reset, so the old RAM initial values cannot be displayed again upon reset.
Here is a video of me testing my circuit:
This was the initial pattern. The "light show" for the last task is this:
I also did the fourth extension, which was to add a pause button to the circuit. In my main code, one can see that it was very straightforward to incorporate. I just added an input called "pause", and connected it to a button. If that button was down, pause would be 0, and I would make it so that even though the clock ticks on, if the button is down, nothing will happen. Otherwise, the process would work as normal. This and my main code are shown below:
Here is me testing the pause button:
This project was helpful in demonstrating the relationship between RAM, ROM, and main program, as well as how clock ticks work. It was a good introduction to the overarching project of making a CPU.