Project 7: CPU
Due 9 April 2012
The purpose of this project is to build a simple CPU that integrates all the necessary aspects of a general-purpose computer.
This is the second part of three coordinated projects. You should demonstrate the functionality of your CPU at the end of the second project.
The overall task is to create a functional CPU, using a ROM for the program memory, a RAM for the data memory, and a separate ALU circuit.
Examine the CPU Design before starting.
- Make a new project for lab 7 in a new folder. I'll refer to the project and top-level circuit as cpu.
- Using the Tools:MegaWizard Plugin Manager, create a 1-port ROM that has 256 words of 16 bits each. I'll refer to this circuit as ProgramROM. Tell it to initialize the ROM using this MIF file. This step will create a VHDL file that you need to add to your project.
- Using the Tools:MegaWizard Plug0in Manager, create a 1-port RAM that has 256 words of 16 bits each. I'll refer to this circuit as DataRAM, Tell it to initialize the RAM using this MIF file. This step will create a VHDL file that you need to add to your project.
Create a top-level VHDL file called cpu.vhd with an entity called cpu.
Your cpu entity should have a clock (std_logic), reset (std_logic),
input port (std_logic_vector(7 downto 0)), and an output port
(std_logic_vector(15 downto 0)). You can use the 4-state Moore
machine template, if you wish.
Create component statements for both the ProgramROM and DataRAM in the architecture header.
Create an arithmetic logic unit VHDL design file, alu.vhd. Add the
file to your project. You can use this template
as the basis for the ALU circuit design. The circuit is completely
asynchronous, and it does not require any additioanl signals beyond
what is in the template in order to build the circuit.
When you have your alu design complete, test it using this testbench program. It should produce the output below.
As noted in the CPU design, you probably
want to use a 5-state state machine for your CPU. The first state is
a startup state. After eight clock cycles, this state should move to
the fetch state. You will need a small internal counter (3 bits) to
implement the pause in the start state. The state machine should never
return to the start state unless it is reset.
The remaining states are fetch, execute-setup, execute-process, execute-wait, and execute-write. Set up your overall state machine structure to follow this model. Each state always leads to the next state in the process, with the execute-write state going back to the fetch state.
Set up your skeleton five state state machine, putting in only the state transitions for now.
Create the remaining internal signals you need for your CPU. There
are a lot. Following the cpu diagram,
there should be a signal for every register, including the condition
register. In addition, you will need a signal to represent the two
ALU input buses and the ALU output bus.
You will also want signals for the output port wire, the ROM data-out wire, the RAM data-out wire, the RAM write-enable wire, the ALU opcode, and the ALU condition argument.
Port map your ProgramROM, DataRAM, and ALU circuits into your cpu.
The clock, PC and ROM data wire should map to the ROM clock, address,
The MAR and MBR should map to the RAM address and data-in parameters. The RAM data wire, RAM write enable wire, and clock should map to the RAM output, RAM write enable (wren) and clock.
The srcA, srcB, and dest parameters should map to the ALU input buses and the output bus, respectively. Map the ALU opcode and condition outputs to their respective signals.
Implement your CPU.
- If the reset button is activated, set the registers PC, MAR, MBR, RA, RB, RC, RD, RE, SP, and CR to zeros. The state should should be reset to the startup state and the small counter should be reset to zeros.
- The startup state should increment the small counter and stay there until it reaches 7. Then it should move to the fetch state.
- The fetch state should copy the ROM data wire contents to the IR, increment the PC, and move to the execute-setup state.
The execute-setup state should set up each of the instructions.
- For the load and store instructions, move the correct RAM addres into the MAR. If IR(8) is set, use the 8 low bits of the IR plus register E (RE). If IR(8) is not set, just use the low bits of the IR. You will also need to put the data to write into the RAM into the MBR.
- For the unconditional branch, set the PC to the low 8 bits of the IR.
- For the conditional branch, check the condition flag specified in the instruction and move the low 8 bits of the IR to the PC if the condition is true.
- For the push operation, put the current vaue of the SP into the MAR, increment the SP, and put the value specified in the source bits into the MBR.
- For the pop operation, put the value (SP-1) into the MAR and decrement the SP.
- For the binary ALU operations (add, sub, and, or xor) set up srcA and srcB.
- For the unary ALU operations (shift, rotate) set up srcA and put the direction bit in the low bit of srcB.
- For the move operation, set up srcA, which will come either from a register or be a sign extended value from the low bits of the IR.
- The execute-process state should set the RAM write enable signal to high if the operation is a store (opcode 0001, or integer 1) or a push.
- The execute-wait state should do nothing except move to the execute-write state. In order for the RAM to work properly, it requires an extra clock cycle before the result is ready to be handled in the execute-write state.
The execute-write state should handle the final stage of the various
- For the load operation, it should write the contents of the RAM data wire to the specified destination register.
- For the store operation, it should set the write enable flag to zero.
- For the write to the output port, it should set the output port wire to the specified value.
- For the load from the input port, it should write the input port value to the specified register.
- For the push operation, it should set the write enable flag to zero.
- For the pop operation, it should write the value of the RAM data wire to the destination specified in the instruction.
- For the binary and unary arithmetic operations (add, sub, and, or, xor, shift, rotate), it should write the destination value to the proper register. It should also assign the ALU condition flags to the condition register [CR].
- For the move operation it should write the destination value to the proper register and set the condition register [CR] from the ALU condition flags.
Test your CPU using the program give in the programROM.mif file above. You should get a simulation like the following.
- Write a program for your computer that creates the first 10 values of the fibonnaci sequence. Simulate your circuit and demonstrate that it works.
- Download your CPU to the board and demonstrate it works properly.
- Write more programs, such as an unsigned multiply program.
- Write a Python program that can generate an MIF file from some other, more easily readable, format.
- Add a hold/freeze button to the CPU.
- Be creative with input.
Create a wiki page with your writeup. For each task, write a short description of the task, in your own words.
- Include a description of your top-level design.
- Include the initial contents of both your RAM and ROM.
- Include the screen shot of your simulation.
- Describe the hardware testing you undertook to prove the circuit works.
- Include a description, and pictures, of any extensions.
Give your wiki page the label cs232S12project7.
Put your VHDL files in zip file in your private subdirectory on Academics/COMP/CS232. If you have any issues with the server, send the zip file to the prof.