Registers

Memory

This is a Harvard (2-memory) architecture. This allows us to implement it as a single-cycle machine.

The instruction memory is a word-addressed read-only memory with 16 address bits and 20 data bits. Unlike MIPS, the instruction memory is not byte-addressed. Instead, each address holds 1 instruction, meaning the memory can hold 65536 instructions. This also means that the “next instruction” is at PC + 1, not PC + 4.

The data memory is a word-addressed RAM with 16 address bits and 16 data bits. Again this is unlike MIPS which is a byte-addressed architecture. This memory can hold 65536 16-bit words.

Instruction formats

All instructions are 16 bits long. There are actually four instruction formats, with three being similar to MIPS.


The instruction set


Basic instructions

The tutorial walks you through implementing these instructions so I won’t say much here.

Format Opcode Mnemonic Operation
R 00000 hlt disable PC register and turn on HALT LED
R 00001 put rs DISP <- REG[rs]
I 00010 li rd, imm8 REG[rd] <- sxt_16(imm8)
I 00011 lui rd, imm8 REG[rd] <- (imm8 : REG[rd][7:0])

ALU operations

Format Opcode Mnemonic Operation
R 00100 add rd, rs, rt REG[rd] <- REG[rs] + REG[rt]
R 00101 sub rd, rs, rt REG[rd] <- REG[rs] - REG[rt]
R 00110 and rd, rs, rt REG[rd] <- REG[rs] & REG[rt]
R 00111 or rd, rs, rt REG[rd] <- REG[rs] | REG[rt]
R 01000 xor rd, rs, rt REG[rd] <- REG[rs] ^ REG[rt]
R 01001 not rd, rt REG[rd] <- ~REG[rt] (see below)
R 01010 shl rd, rs, rt REG[rd] <- REG[rs] << REG[rt][3:0] (see below)
R 01011 shr rd, rs, rt REG[rd] <- REG[rs] >>> REG[rt][3:0] (see below)
I 01100 adi rd, imm8 REG[rd] <- REG[rd] + sxt_16(imm8)
I 01101 sbi rd, imm8 REG[rd] <- REG[rd] - sxt_16(imm8)
I 01110 ani rd, imm8 REG[rd] <- REG[rd] & zxt_16(imm8)
I 01111 ori rd, imm8 REG[rd] <- REG[rd] | zxt_16(imm8)
I 10000 xri rd, imm8 REG[rd] <- REG[rd] ^ zxt_16(imm8)
I 10001 sli rd, imm8 REG[rd] <- REG[rd] << imm8[3:0] (see below)
I 10010 sri rd, imm8 REG[rd] <- REG[rd] >>> imm8[3:0] (see below)

The not instruction does not use rs or REG[rs] at all. It does bitwise NOT on the second input to the ALU. If you followed the directions in lab 7, your ALU already does this correctly.

Notes on shifting:


Memory access

Format Opcode Mnemonic Operation
L 10011 ld rd, [rs+imm5] REG[rd] <- RAM[REG[rs] + sxt_16(imm5)]
L 10100 st rd, [rs+imm5] RAM[REG[rs] + sxt_16(imm5)] <- REG[rd]

Tricky: for st and only for st, rd is actually used as the second register to read out of the register file… so it takes the place of rt. (Your control handles this.)

When implementing these, think to yourself: do you really need another component to do the addition for the memory address? ;) (Remember the interconnect slides…)


Jumps

Format Opcode Mnemonic Operation
J 10101 j target PC <- zxt_16(target)
R 10110 jr rs PC <- REG[rs]
J 10111 jal target REG[7] <- PC + 1 (see below!)
PC <- zxt_16(target)
R 11000 jlr rs REG[7] <- PC + 1 (see below!)
PC <- REG[rs]

There are actually two function call instructions: jal, which jumps to an immediate address, and jlr, which jumps to an address in a register just like jr. (MIPS has an instruction like this too, called jalr.)

Two important things about jal and jlr:


Comparisons and Branches

Format Opcode Mnemonic Operation
R 11001 slt rd, rs, rt if(REG[rs] < REG[rt]) REG[rd] <- 1; else REG[rd] <- 0;
R 11010 sle rd, rs, rt if(REG[rs] <= REG[rt]) REG[rd] <- 1; else REG[rd] <- 0;
R 11011 seq rd, rs, rt if(REG[rs] == REG[rt]) REG[rd] <- 1; else REG[rd] <- 0;
I 11100 bez rd, imm8 if(REG[rd] == 0) PC <- PC + sxt_16(imm8); else PC <- PC+1;
I 11101 bnz rd, imm8 if(REG[rd] != 0) PC <- PC + sxt_16(imm8); else PC <- PC+1;

All comparisons should be done as signed arithmetic. That means any Comparator component you use must be set to do signed (“2’s complement”) comparisons, or else certain tests will break!


Multiplication

Format Opcode Mnemonic Operation
R 11110 mul rs, rt PROD <- REG[rs] * REG[rt]
I 11111 mfp rd, imm8 if(imm8 == 0) REG[rd] <- PROD[15:0]; else REG[rd] <- PROD[31:16]

mul starts the multiplier unit.

mfp stands for “move from product.” mfp rd, 0 gets the lower 16 bits of the product; mfp rd, 1 gets the upper 16. It will pause the rest of the CPU if the product is not done being computed yet.