RISC CPU Design
The register layout is shown in the graphic above. The instruction set is given below. It is modeled on the PowerPC RISC architecture, although the size and number of working registers is significantly reduced.
Registers A-E, the Stack Pointer, the MBR, and the Instruction Register are all 16 bit registers. The MAR needs to have enough bits to address all of memory (8 bits). The input and output ports can be 8-bits (if you don't want to assign lots of pins). The program counter is 8-bits, and the Condition Register is 4-bits. The ALU circuit takes in two 16-bit values and an opcode and outputs the 16-bit result as well as the 4-bits for the Condition Register.
The instructions are 16 bits. All instructions have a 4-bit opcode in bits (15 downto 12), with some instructions having an additional one or two bits of opcode. The remaining bits are used to specify source and destination registers, addresses, or immediate values. Instructions that have an address make use of the low 8 bits of the instruction to hold the information.
|Load from RAM||0000||R-DDD-AAAAAAAA: DDD = dest (table B), R = add register E to immediate value, AAAAAAAA - immediate address value|
|Store to RAM||0001||R-SSS-AAAAAAAA: SSS = src (table B), R = add register E to immediate value, AAAAAAAA - immediate address value|
|Unconditional Branch||0010||UUUU-AAAAAAAA: U = unused, AAAAAAAA = immediate address value.|
|Conditional Branch||0011||00-CC-AAAAAAAA: CC = condition (00 = zero, 01 = overflow, 10 = negative, 11 = carry), U = unused, AAAAAAAA = immediate address value.|
|Call||0011||01-UU-AAAAAAAA: the cpu should push the PC and CR on the stack and then jump to the immediate address value AAAAAAAA.|
|Return||0011||10-UU-UUUUUUUU: the cpu should pop the CR and then pop the PC to continue execution at the stored address.|
|Exit||0011||11-UU-UUUUUUUU: The CPU should enter a halt state and not leave until the user resets the circuit.|
|Push||0100||SSS-UUUUUUUUU: SSS = src (table C) U = unused, operation puts the value into memory at location SP and increments SP.|
|Pop||0101||SSS-UUUUUUUUU: SSS = dest (table C) U = unused, operation reads the value from memory at location SP-1 and decrements SP.|
|Store to Output||0110||SSS-UUUUUUUUU: SSS = source (table D) U = unused.|
|Load from Input||0111||DDD-UUUUUUUUU: DDD = dest (table B) U = unused.|
|Add||1000||SSS-TTT-UUU-DDD: SSS = srcA (table E), DDD = dest (table B), TTT = srcB (table E)|
|Subtract||1001||SSS-TTT-UUU-DDD: SSS = srcA (table E), DDD = dest (table B), TTT = srcB (table E)|
|And||1010||SSS-TTT-UUU-DDD: SSS = srcA (table E), DDD = dest (table B), TTT = srcB (table E)|
|Or||1011||SSS-TTT-UUU-DDD: SSS = srcA (table E), DDD = dest (table B), TTT = srcB (table E)|
|Exclusive-or||1100||SSS-TTT-UUU-DDD: SSS = srcA (table E), DDD = dest (table B), TTT = srcB (table E)|
|Shift||1101||R-SSS-UUUUU-DDD: SSS = srcA (table E), DDD = dest (table B), R = direction bit '0' = left, '1' = right, maintains sign bit|
|Rotate||1110||R-SSS-UUUUU-DDD: SSS = srcA (table E), DDD = dest (table B), R = direction bit '0' = left, '1' = right|
|Move||1111||T-(IIIIIIII or SSS-UUUUU)-DDD: DDD = dest (table B), T = if '1', treat next 8 bits as a sign-extended immediate value, else SSS = source location (table D)|
Below are the tables that show how to interpret the various register selection fields.
The ALU circuit takes in two source registers and an opcode, and it returns a destination value and a set of condition flags. The ALU opcodes correspond to the low three bits of the 4-bit opcode for instructions 1000 through 1111.
The condition register should be set by the ALU only for instructions at or above 1000: arithmetic, logical, and move instructions.
The CPU defined above requires nine states: Start, Fetch, Execute-Setup, Execute-ALU, Execute-MemoryWait, Execute-Write, Execute-ReturnPause1, Execute-ReturnPause2, and Halt.
The Fetch state is a single clock cycle. The execute cycle can take anywhere from three to six clock cycles, depending on the instruction. The Execute-Setup, Execute-ALU, and Execute-Write, are necessary for all instructions. The Execute-MemoryWait state is optional for all instructions except LOAD, POP, and RETURN. The RETURN instruction requires the Execute-ReturnPause1 and Execute-ReturnPause2 after the Execute-Write state in order to load the instruction at the return address into the IR.
- Start: The computer should go to this state upon reset and wait for at least three clock cycles for the memory to complete its startup. Then it should move to the Fetch state.
- Fetch: The circuit should grab the current instruction from the ROM, increment the PC, and move to the Execute-Setup state.
Execute-Setup: The purpose of the setup phase is to take one of
- If the instruction is a load, store, push, pop, call, or return then set up the MBR and MAR and take whatever action is necessary with the stack pointer.
- If the instruction is an ALU operation or a move, then assign srcA and srcB according to the instruction.
- If the instruction is a branch, then assign the PC.
- If the instruction is an exit instruction, then the next state should be a halt state, otherwise the next state should be Execute-ALU.
Execute-ALU: The purpose of this state is to let the ALU circuit
process the inputs.
- If the instruction requires a write to the RAM, then the write enable line should be set high.
- If the instruction is not reading from memory (LOAD, POP, or RETURN), then go to the Execute-Write state. If the instruction is reading from memory, go to the ExecuteMemoryWait state.
- Execute-MemWait: The instructions that are reading from memory, LOAD, POP, RETURN, need an extra state for the memory data to become available. The next state is Execute-Write.
Execute-Write: The purpose of the write phase is to take the
information from the dest bus, the input port, or the memory
buffer register and and write it to the correct location.
- If the instruction writes to the output port, that should occur here.
- The call and return functions will need to complete their actions.
- RETURN will write the return address to the PC and then move to the Pause-1 state.
- All instructions other than return can go back to the Fetch state.
- Execute-ReturnPause1: Used only for the RETURN instruction, this waits for the return address to propogate through the ROM. Move to the Execute-ReturnPause2 state.
- Execute-ReturnPause2: Used only for the RETURN instruction, this waits for the return address to propagate through the ROM. Move to the Fetch state.