My First CPU Design

4 minute read

Published:

Recently, I completed CSE 141L this past quarter. I thought the project was fun and interesting, so I decided to write up my thoughts, as well as an overview of my design.

Architecture

The architecture I chose to work with is basically just an accumulator machine. There are 16 8-bit general purpose registers, and the instruction size is 9 bits. Nothing particularly special is going on here the only thing of interest is that there is no branch offset, only direct branching is allowed. I did this because the test programs were small enough that I didn’t need to implement anything other than this.

My Architecture Diagram

Instruction Types

TypeFormatInstructions
R(Opcode 4)_(Register)_(Opcode 1)and, orr, nand, nor, add, sub, lsr, lsrd, lsl, lsld, asr, rot, pop, popn, push, pushn
M(Opcode 4)_(Address 5)ldw, stw
B(Opcode 4)_(Label 5)bze, buc, bgt, blt, bov
N(Opcode 4)_XXXXXnop

Instructions

I’ll use acc to denote the accumulator register(r0), and rN to denote register N.

InstructionFormatDescription
andand rNBitwise logical AND of r0 and rN, outputs result into r0.
orrorr rNBitwise logical OR of r0 and rN, outputs result into r0.
nandnand rNBitwise logical NAND of r0 and rN, outputs result into r0.
nornor rNBitwise logical NOR of r0 and rN, outputs result into r0.
addadd rNAdds r0 rN, outputs result into r0. Will set overflow flag if result has unsigned overflow.
subsub rNDoes r0 - rN, outputs result into r0. Will set overflow flag if result has signed overflow.
lsrlsr rNLogical right shift of r0 by rN, outputs result into r0. Dropped off bit is placed into dropoff flag.
lsrdlsrd rNLogical right shift of r0 by rN, outputs result into r0, and loads dropoff flag into leftmost bit. Dropped off bit is placed into dropoff flag.
lsllsr rNLogical left shift of r0 by rN, outputs result into r0.
lsldlsld rNLogical left shift of r0 by rN, outputs result into r0, and loads dropoff flag into rightmost bit. Dropped off bit is placed into dropoff flag.
asrasr rNArithmetic right shift of r0 by rN. Dropped off bit is placed into dropoff flag.
rotrot rNShift left with rotate of r0 by rN.
poppop rNLoads value of r0 into rN
popnpopn rNLogically negates, then loads value of r0 into rN.
pushpush rNLoads value of rN into r0.
pushnpushn rNLogically negates, then loads value of rN into r0.
ldwldw <addr>Loads the value at address addr into r0. Assembler throws error if addr is more than 5 bits wide.
stwldw <addr>Stores the value of r0 into the address addr. Assembler throws error if addr is more than 5 bits wide.
bzebze <insn>Branches to the instruction given by insn if r0 is currently 0. Equivalently, branches if the zero flag is high. Assembler throws error if insn is more than 5 bits wide.
bgtbgt <insn>Branches to the instruction given by insn if r0 is positive (when viewed as a 2’s complement integer). Equivalently, branches if the positive flag is high. Assembler throws error if insn is more than 5 bits wide.
bltblt <insn>Branches to the instruction given by insn if r0 is negative (when viewed as a 2’s complement integer). Equivalently, branches if the negative flag is high. Assembler throws error if insn is more than 5 bits wide.
bovblt <insn>Branches to the instruction given by insn if the overflow flag is high. This may be meaningless if the last instruction was not add or sub. Assembler throws error if insn is more than 5 bits wide.
bucbuc <insn>Unconditionally branches to the instruction given by insn. Assembler throws error if insn is more than 5 bits wide.
nopnopDoes nothing.

I also wrote a small assembler with some nice features like C-style macros and (hopefully) good debug messages. ARM should hire me.

Future Directions

This design is pretty basic and uninteresting to be honest, but I’m pretty happy with how it turned out, given that I built this in a ~16 hour session. If I ever feel like it I’ll add a pipeline and some commands to make it a “real” CPU, and probably make the assembler more robust, as well as add real branching features (lookup tables, etc).