notes, thoughts, and opinions on programming
For those who want to know how the CPU works, there’s an excellent set of lectures available on YouTube courtesy of the Bilkent University (Turkey). Sure, not every course or book clicks with everyone, but personally I find that one extremely clear and well explained, so highly recommend to go and check it out if you’re interested.
Because this is probably the most consistent, minimalistic, and clean RISC architecture available, which means it’s easier to explain the core concepts of the CPU design without having to be distracted on irrelevant minutiae that do not contribute to the general understanding of the subject. (I cannot imagine what the course would look like if it were to use x86 as an example)
The course above is the standard CS-224 Computer Organization course, which includes two assignments:
The first project is simple and there’s not much to talk about, but the second one is interesting, because you are asked to design a CPU that implements a subset of standard MIPS instructions as well as some additional ones (the practical usefulness of which is dubious, but which are great for learning) and then model it using Verilog.
I have completed both projects and found them very rewarding in terms of my understanding of computer hardware. If you decide to do them too and get stuck, feel free to ask me.
Here’s my code on GitHub that implements the CPU as per the Project #2 assignment. It includes a simple assembler for all the instructions below, as well as Verilog testbenches for each.
# R-format
instr func syntax description
add 0x20 rd, rs, rt
and 0x24 rd, rs, rt
balrn 0x17 rs, rd if [z]=0, branch to rs, store return in rd (31 by default)
balrz 0x16 rs, rd if [z]=1, branch to rs, store return in rd (31 by default)
brn 0x15 rs if [z]=0, branch to rs
brz 0x14 rs if [z]=1, branch to rs
jalr 0x09 rs, rd unconditional jump to rs and link rd
jr 0x08 rs unconditional jump to rs
nor 0x27 rd, rs, rt
or 0x25 rd, rs, rt
slt 0x2a rd, rs, rt set rd to (rs < rt)
sll 0x00 rd, rt, shamt rd = rt << shamt
srl 0x02 rd, rt, shamt rd = rt >> shamt
sub 0x22 rd, rs, rt rd = rs - rt
# I-format
instr opcode syntax description
addi 0x08 rt, rs, imm rt = rs + imm
andi 0x0C rt, rs, imm rt = rs & zeroext(imm)
balmn 0x17 rt, imm(rs) if [z]=0, branches to address in memory and links to rt(31)
balmz 0x16 rt, imm(rs) if [z]=1, branches to address in memory and links to rt(31)
beq 0x04 rs, rt, offset if rs=rt, branch to offset
beqal 0x2C rs, rt, offset if rs=rt, branch to offset and link 31
bmn 0x15 imm(rs) if [z]=0, branch to address in memory
bmz 0x14 imm(rs) if [z]=1, branch to address in memory
bne 0x05 rs, rt, offset if rs!=rt, branch to offset
bneal 0x2D rs, rt, offset if rs!=rt, branch to offset and link 31
jalm 0x13 rt, imm(rs) jump to address in memory and link to rt(31)
jalpc 0x1F rt, offset jump to pc-relative address, and link to rt(31)
jm 0x12 imm(rs) jump to address in memory
jpc 0x1E offset jump to pc-relative address
lw 0x23 rt, imm(rs) load word at rs+imm into rt
ori 0x0D rt, rs, imm rt = rs | zeroext(imm)
sw 0x2B rt, imm(rs) store word in rt into memory at rs+imm
# J-format
instr opcode syntax description
baln 0x1B target26 if [z]=0, branch to target and link 31
balz 0x1A target26 if [z]=1, branch to target and link 31
bn 0x19 target26 if [z]=0, branch to target
bz 0x18 target26 if [z]=1, branch to target
jal 0x03 target26 jump and link 31
j 0x02 target26 jump
I’m happy to help anyone who’s studying CPU design if I can - just drop me a message.
When I have more free time for a project I will probably add pipelining to the CPU above, which should be interesting.
Hosted on GitHub Pages — Theme by mattgraham