Ivan Ivanov's blog

notes, thoughts, and opinions on programming

Single-Cycle MIPS CPU in Verilog


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.

CPU

Why Computer organisation courses like to use MIPS as their target architecture

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)

Course assignments

The course above is the standard CS-224 Computer Organization course, which includes two assignments:

  1. Project #1. MIPS Assembly programming
  2. Project #2. Single-Cycle Processor design

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.

A CPU in Verilog

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

Instruction-Fetch Unit

IFU

What’s next

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