Compare commits

..
8 Commits
Author SHA1 Message Date
riley 8a682347f0 Merge branch 'main' of ssh://git.rileyk.au:19482/TroubleElectrical/FPGA_Uni 2026-10-16 11:44:03 +11:00
riley 559ff01d69 Fixed printing annoyance. Added variable dumping to a wavefile. Updated delay to 2 units (as there is 1 unit of clk being high and 1 unit low).
Removed register initialisation code from testbench.
Fixed typo when wanting to check T0 (R8) but was checking R0.
Added explicit if-else begin-end blocks to logging and a simulation exit when the testbench is done.
2026-10-16 11:41:33 +11:00
riley 92a0cb17da Updated assignment 2 to reflect prior changes. Fixed instruction ordering for register file module (again). Fixed typo that limited the space the ALU could write its flags out to. Swapped ordering to be correct when determining if we are storing the result from ALU or MEM.
Added a QUARTUS_SYNTH around the display logic at the end of the module.
Partially fixed control_unit module, still seems to need some changes as branching doesn't appear to work at all.
2026-10-16 11:38:35 +11:00
riley 65be2c2d61 Made sign extension explicit to remove bit indexing (which iverilog doesn't like) and a tad more readable. 2026-10-16 11:35:24 +11:00
riley 878f949e5f Made addrwidth sizing consistent with the 2^N used everywhere 2026-10-16 11:34:31 +11:00
riley 0ea3e0fa12 Added initialisation blocks for PC and GPR's 2026-10-16 11:33:45 +11:00
riley 12ae58ad86 Removed flag assignment from within ALU OP case statement and instead perform it at the end. Made bit index for the ASU OP more explicit. 2026-10-16 11:32:24 +11:00
riley 4c7e2ff085 Fixed instruction width issue in ROM. Stripped all comments to form minimal HEX file to rule out possible parser issues. 2026-10-16 11:29:04 +11:00
10 changed files with 113 additions and 72 deletions

No files matched your search

+18
View File
@@ -0,0 +1,18 @@
01084023
25090007
ad090000
8d0a0000
012a5821
012b6022
212d0003
018d7020
012d8024
012d8825
012d9026
012d9827
018ea02a
018ea82b
25080001
010db02b
12d4fffd
12d6ffff
+14 -12
View File
@@ -15,26 +15,28 @@ module alu #(parameter width=2)(input logic [3:0] op,
logic [2**width-1:0] asu_out; logic [2**width-1:0] asu_out;
logic [2:0] asu_flags; logic [2:0] asu_flags;
asu #(width) adder_unit(asu_op[op[1]], A, B, asu_out, asu_flags[0], asu_flags[1]); assign asu_op = op[1];
asu #(width) adder_unit(asu_op, A, B, asu_out, asu_flags[0], asu_flags[1]);
logic [2**width-1:0] lu_out; logic [2**width-1:0] lu_out;
lu #(width) logic_unit(op[1:0], A, B, lu_out); lu #(width) logic_unit(op[1:0], A, B, lu_out);
always_comb begin always_comb begin
case (op) case (op)
4'b0000: begin OUT_1 = asu_out; flags = asu_flags; end 4'b0000: begin OUT_1 = asu_out; end
4'b0001: begin OUT_1 = asu_out; flags = asu_flags; end 4'b0001: begin OUT_1 = asu_out; end
4'b0010: begin OUT_1 = asu_out; flags = asu_flags; end 4'b0010: begin OUT_1 = asu_out; end
4'b0011: begin OUT_1 = asu_out; flags = asu_flags; end 4'b0011: begin OUT_1 = asu_out; end
4'b0100: begin OUT_1 = lu_out; flags = asu_flags; end 4'b0100: begin OUT_1 = lu_out; end
4'b0101: begin OUT_1 = lu_out; flags = asu_flags; end 4'b0101: begin OUT_1 = lu_out; end
4'b0110: begin OUT_1 = lu_out; flags = asu_flags; end 4'b0110: begin OUT_1 = lu_out; end
4'b0111: begin OUT_1 = lu_out; flags = asu_flags; end 4'b0111: begin OUT_1 = lu_out; end
4'b1010: begin OUT_1 = (asu_out[2**width-1] ^ asu_flags[1]) & {{(width-1){1'b0}}, 1'b1}; flags = asu_flags; end 4'b1010: begin OUT_1 = (asu_out[2**width-1] ^ asu_flags[1]) & {{(width-1){1'b0}}, 1'b1}; end
4'b1011: begin OUT_1 = ~asu_flags[0] & {{(width-1){1'b0}}, 1'b1}; flags = asu_flags; end 4'b1011: begin OUT_1 = ~asu_flags[0] & {{(width-1){1'b0}}, 1'b1}; end
default: begin OUT_1 = {(2**width){1'b0}}; flags = asu_flags; end default: begin OUT_1 = {(2**width){1'b0}}; end
endcase endcase
asu_flags[2] = OUT_1 == 0; asu_flags[2] = OUT_1 == 0;
flags = asu_flags;
end end
endmodule endmodule
`endif `endif
+13 -15
View File
@@ -30,8 +30,8 @@ module assignment2 #(width=5, romsz=10) (
logic[15:0] PC_Reg_Display; logic[15:0] PC_Reg_Display;
// Program / Instruction Counter Intermediates // Program / Instruction Counter Intermediates
logic [romsz-1:0] pc_addr; logic [2**width-1:0] pc_addr;
logic [romsz-1:0] pc_addr_write; logic [2**width-1:0] pc_addr_write;
logic [0:0] pc_we; logic [0:0] pc_we;
logic [2**width-1:0] instruction; logic [2**width-1:0] instruction;
@@ -58,10 +58,10 @@ module assignment2 #(width=5, romsz=10) (
instruction_counter #(width) PC (clk, pc_we, pc_addr_write, pc_addr); instruction_counter #(width) PC (clk, pc_we, pc_addr_write, pc_addr);
rom #(romsz, 2**width) ROM (pc_addr, instruction); rom #(romsz, width) ROM (pc_addr, instruction);
logic [2**width-1:0] rd_mem; logic [2**width-1:0] rd_mem;
ram #(width) RAM (clk, rd_alu, M2W, rt, rd_mem); ram #(ramsz, width) RAM (clk, rd_alu, M2W, rt, rd_mem);
control_unit CONTROL_UNIT (instruction[31:26], instruction[5:0], control_unit CONTROL_UNIT (instruction[31:26], instruction[5:0],
M2R, M2W, B, ALU_FN, ALU_SRC, RDST, RW M2R, M2W, B, ALU_FN, ALU_SRC, RDST, RW
@@ -70,29 +70,27 @@ module assignment2 #(width=5, romsz=10) (
register_file #(width, 5) REGS ( register_file #(width, 5) REGS (
clk, rd_we, clk, rd_we,
instruction[20:16], rd, (RDST) ? instruction[15:11] : instruction[20:16], rd,
(RDST) ? instruction[15:11] : instruction[20:16], rt, instruction[25:21], rs,
instruction[25:21], rs, instruction[20:16], rt,
regs_out regs_out
); );
// Always use sign-extension // Always use sign-extension
logic [2**width-1:0] rt_imm; logic [2**width-1:0] rt_imm;
sign_extender #(4, width) SIGNEXT(1'b1, instruction[15:0], rt_imm); sign_extender #(4, width) SIGNEXT(1'b1, instruction[15:0], rt_imm);
// TODO:
// - ALU srcB
// - PCBranch (rel jump of 4-byte words)
logic [2**width-1:0] rd_alu;
alu #(width) ALU (ALU_FN, rs, rt_alu, rd_alu, flags[1:0]); logic [2**width-1:0] rt_alu;
alu #(width) ALU (ALU_FN, rs, rt_alu, rd_alu, flags);
assign rt_alu = (ALU_SRC) ? (rt_imm) : (rt); assign rt_alu = (ALU_SRC) ? (rt_imm) : (rt);
assign pc_we = B & flags[2]; assign pc_we = B & flags[2];
assign pc_addr_write = (rt_imm << 2) + pc_addr; assign pc_addr_write = (rt_imm << 2) + pc_addr;
assign rd_we = RW; assign rd_we = RW;
assign rd = (M2R) ? rd_alu : rd_mem; assign rd = (M2R) ? rd_mem : rd_alu;
`ifdef QUARTUS_SYNTH
// Temporary Test output // Temporary Test output
// assign PC_Reg_Display = 16'hC342; // assign PC_Reg_Display = 16'hC342;
@@ -105,6 +103,6 @@ module assignment2 #(width=5, romsz=10) (
.segments2(out_seg_2), .segments2(out_seg_2),
.segments3(out_seg_3) .segments3(out_seg_3)
); );
`endif
endmodule endmodule
`endif `endif
+6 -6
View File
@@ -23,13 +23,13 @@ module control_unit (
instruction_classifier CLASSIFIER (op, TYPE_R, TYPE_B1, TYPE_J, TYPE_B2, TYPE_I, TYPE_F, TYPE_M); instruction_classifier CLASSIFIER (op, TYPE_R, TYPE_B1, TYPE_J, TYPE_B2, TYPE_I, TYPE_F, TYPE_M);
always_comb begin always_comb begin
M2R = TYPE_M & op[3]; M2R = TYPE_M & ~((op & 6'b001000) >> 3);
M2W = TYPE_M & ~op[3]; M2W = TYPE_M & ((op & 6'b001000) >> 3);
B = TYPE_B1 | TYPE_B2 | TYPE_J; B = TYPE_B1 | TYPE_B2 | TYPE_J;
ALU_FN = (func & {(6){TYPE_R}}) | ( {4'b0000, op[1:0]} & {(6){TYPE_I}}); ALU_FN = (func & {(4){TYPE_R}}) | ( {2'b00, (op & 6'b000011)} & {(4){TYPE_I}}) | (4'b0010 & {4{TYPE_B1 | TYPE_B2}});
ALU_SRC = TYPE_B1 | TYPE_B2 | TYPE_I | TYPE_M; ALU_SRC = TYPE_I | TYPE_M;
RDST = TYPE_I; // Imm ops store back into rt RDST = TYPE_R; // Imm ops store back into rt
RW = TYPE_R | TYPE_I | (TYPE_M & op[3]); // All ALU R-type ops, Addi/Addiu ops, and memory loads RW = TYPE_R | TYPE_I | M2R;
end end
endmodule endmodule
+5
View File
@@ -8,6 +8,11 @@ module instruction_counter #(parameter width=5)(
); );
logic [2**width-1:0] pc; logic [2**width-1:0] pc;
initial begin
pc = {(2**width){1'b0}};
end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (we) begin if (we) begin
pc <= W; pc <= W;
+6 -6
View File
@@ -1,12 +1,12 @@
`ifndef RAM_H `ifndef RAM_H
`define RAM_H `define RAM_H
module ram #(datawidth=5)( module ram #(addrwidth=9, datawidth=5)(
input logic [0:0] clk, input logic [0:0] clk,
input logic [2**datawidth-1:0] addr, input logic [addrwidth-1:0] addr,
input logic [0:0] we, input logic [0:0] we,
input logic [datawidth-1:0] data_in, input logic [datawidth-1:0] data_in,
output logic [datawidth-1:0] data_out output logic [datawidth-1:0] data_out
); );
// TODO: Make this byte-sized, NOT word-sized! // TODO: Make this byte-sized, NOT word-sized!
+2 -1
View File
@@ -12,7 +12,8 @@ module register_file #(parameter width=5, parameter nregs=5)(
logic [2**width-1:0] regs[2**nregs]; logic [2**width-1:0] regs[2**nregs];
initial begin initial begin
regs[0] = {(2**width){1'b0}}; for (integer N = 0; N < (2**nregs); ++N)
regs[N] = 32'd0;
end end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
+5 -5
View File
@@ -3,19 +3,19 @@
module rom #(parameter m=7,p=4) ( module rom #(parameter m=7,p=4) (
input logic [m-1:0] Ad, input logic [m-1:0] Ad,
output logic [p-1:0] Dout output logic [2**p-1:0] Dout
); );
logic [p-1:0] mem[2**m-1:0]; logic [2**p-1:0] mem[2**m];
assign Dout = mem[Ad]; assign Dout = mem[Ad>>2]; // Because word-size versus byte size hack
//Load the program in memory //Load the program in memory
// The machine code stored in text file program.dat written in Hex format // The machine code stored in text file program.dat written in Hex format
initial begin initial begin
`ifdef QUARTUS_SYNTH `ifdef QUARTUS_SYNTH
$readmemh("../../asm/bin/ELEC4720-2026s2-Ass-02-Demo.txt",mem); //$readmemb for binary $readmemh("../../asm/bin/ELEC4720-2026s2-Ass-02-Demo.hex", mem, 0, 2**m-1); //$readmemb for binary
`else `else
$readmemh("./asm/bin/ELEC4720-2026s2-Ass-02-Demo.txt",mem); //$readmemb for binary $readmemh("./asm/bin/ELEC4720-2026s2-Ass-02-Demo.hex", mem, 0, 2**m-1); //$readmemb for binary
`endif `endif
end end
endmodule // end rom module endmodule // end rom module
+3 -1
View File
@@ -6,9 +6,11 @@ module sign_extender #(in_width=4, out_width=5)(
input logic [2**in_width-1:0] val, input logic [2**in_width-1:0] val,
output logic [2**out_width-1:0] ext_val output logic [2**out_width-1:0] ext_val
); );
logic [0:0] msb;
assign msb = (val & {1'b1, {(in_width-1){1'b0}}}) >> (in_width-1);
always_comb begin always_comb begin
if (op) begin if (op) begin
ext_val = { {(2**(out_width-in_width)){val[2**in_width-1]}}, val}; ext_val = { {(2**(out_width-in_width)){msb}}, val};
end else begin end else begin
ext_val = ({{(2**(out_width-in_width)){1'b0}}, val}); ext_val = ({{(2**(out_width-in_width)){1'b0}}, val});
end end
+41 -26
View File
@@ -1,76 +1,88 @@
`include "assignment2.sv" `include "assignment2.sv"
`timescale 1us/10ns
`define PRINT_REGISTERS(regs)\ `define PRINT_REGISTERS(regs)\
$display("\tt0-t8: \t0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n\ts0-s8: \t0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n",\ $display("\tt0-t8: \t0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n\ts0-s8: \t0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n",\
regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15], \ regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15], \
regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23] \ regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23] \
); );
`define TEST_CHECK(cond) if (cond) begin end else begin \ `define TEST_CHECK(cond) if (cond) begin end else begin \
$display("Check %s failed\n", `"cond`"); \ $display("Check %s failed", `"cond`"); \
`PRINT_REGISTERS(CPU.REGS.regs); \ `PRINT_REGISTERS(CPU.REGS.regs); \
num_errors += 1; \ num_errors += 1; \
end end
module mips_tb(input logic [0:0] clk); module mips_tb();
logic [0:0] clk;
assignment2 #(5) CPU (clk); assignment2 #(5) CPU (clk);
initial clk = 0;
always #1 clk = ~clk;
integer num_errors = 0; integer num_errors = 0;
initial begin initial begin
$dumpfile("output.vcd");
$dumpvars(0, clk);
$dumpvars(1, CPU.REGS);
$dumpvars(2, CPU.ROM);
$dumpvars(3, CPU.PC);
$dumpvars(4, CPU.pc_addr);
$dumpvars(5, CPU.CONTROL_UNIT);
$dumpvars(5, CPU.instruction);
$dumpvars(5, CPU.ALU);
// Zero out lower registers // Zero out lower registers
$display("Beginning MIPS tests"); $display("Beginning MIPS tests");
assign num_errors = 0;
for (integer N = 1; N < 32; ++N)
CPU.REGS.regs[N] = 32'd0;
// Check R-type / initialise // Check R-type / initialise
#1; #2;
`TEST_CHECK(CPU.REGS.regs[8] == 32'd0); `TEST_CHECK(CPU.REGS.regs[8] == 32'd0);
#1; #2;
`TEST_CHECK(CPU.REGS.regs[9] == (CPU.REGS.regs[8] + 32'd7)); `TEST_CHECK(CPU.REGS.regs[9] == (CPU.REGS.regs[8] + 32'd7));
// Check load-store // Check load-store
#1; #2;
`TEST_CHECK(CPU.RAM.mem[0] == CPU.REGS.regs[9]); `TEST_CHECK(CPU.RAM.mem[0] == CPU.REGS.regs[9]);
#1; #2;
`TEST_CHECK(CPU.REGS.regs[10] == CPU.RAM.mem[0]); `TEST_CHECK(CPU.REGS.regs[10] == CPU.RAM.mem[0]);
// Check arithmetic // Check arithmetic
#1; #2;
`TEST_CHECK(CPU.REGS.regs[11] == (CPU.REGS.regs[9] + CPU.REGS.regs[10])); `TEST_CHECK(CPU.REGS.regs[11] == (CPU.REGS.regs[9] + CPU.REGS.regs[10]));
#1; #2;
`TEST_CHECK(CPU.REGS.regs[12] == (CPU.REGS.regs[9] - CPU.REGS.regs[11])); `TEST_CHECK(CPU.REGS.regs[12] == (CPU.REGS.regs[9] - CPU.REGS.regs[11]));
#1; #2;
`TEST_CHECK(CPU.REGS.regs[13] == (CPU.REGS.regs[9] + 3)); `TEST_CHECK(CPU.REGS.regs[13] == (CPU.REGS.regs[9] + 3));
#1; #2;
`TEST_CHECK(CPU.REGS.regs[14] == (CPU.REGS.regs[12] + CPU.REGS.regs[13])); `TEST_CHECK(CPU.REGS.regs[14] == (CPU.REGS.regs[12] + CPU.REGS.regs[13]));
// Check logic instructions // Check logic instructions
#1; #2;
`TEST_CHECK(CPU.REGS.regs[16] == (CPU.REGS.regs[9] & CPU.REGS.regs[13])); `TEST_CHECK(CPU.REGS.regs[16] == (CPU.REGS.regs[9] & CPU.REGS.regs[13]));
#1; #2;
`TEST_CHECK(CPU.REGS.regs[17] == (CPU.REGS.regs[9] | CPU.REGS.regs[13])); `TEST_CHECK(CPU.REGS.regs[17] == (CPU.REGS.regs[9] | CPU.REGS.regs[13]));
#1; #2;
`TEST_CHECK(CPU.REGS.regs[18] == (CPU.REGS.regs[9] ^ CPU.REGS.regs[13])); `TEST_CHECK(CPU.REGS.regs[18] == (CPU.REGS.regs[9] ^ CPU.REGS.regs[13]));
#1; #2;
`TEST_CHECK(CPU.REGS.regs[19] == ( ~(CPU.REGS.regs[9] | CPU.REGS.regs[13]) )); `TEST_CHECK(CPU.REGS.regs[19] == ( ~(CPU.REGS.regs[9] | CPU.REGS.regs[13]) ));
// Check SLT instructions // Check SLT instructions
#1; #2;
`TEST_CHECK(CPU.REGS.regs[20] == $signed(CPU.REGS.regs[12]) < $signed(CPU.REGS.regs[14])); `TEST_CHECK(CPU.REGS.regs[20] == $signed(CPU.REGS.regs[12]) < $signed(CPU.REGS.regs[14]));
#1; #2;
`TEST_CHECK(CPU.REGS.regs[21] == $unsigned(CPU.REGS.regs[12]) < $unsigned(CPU.REGS.regs[14])); `TEST_CHECK(CPU.REGS.regs[21] == $unsigned(CPU.REGS.regs[12]) < $unsigned(CPU.REGS.regs[14]));
// Check loop branching // Check loop branching
for (integer N = 1; N < 11; ++N) begin for (integer N = 1; N < 11; ++N) begin
#1; #2;
`TEST_CHECK(CPU.REGS.regs[0] == 32'(N)); `TEST_CHECK(CPU.REGS.regs[8] == 32'(N));
#1; #2;
`TEST_CHECK(CPU.REGS.regs[22] == $unsigned(CPU.REGS.regs[8]) < $unsigned(CPU.REGS.regs[13])); `TEST_CHECK(CPU.REGS.regs[22] == $unsigned(CPU.REGS.regs[8]) < $unsigned(CPU.REGS.regs[13]));
end end
// Final state check // Final state check
#1; #2;
`TEST_CHECK(CPU.REGS.regs[8] == 32'd10); `TEST_CHECK(CPU.REGS.regs[8] == 32'd10);
`TEST_CHECK(CPU.REGS.regs[9] == 32'd7); `TEST_CHECK(CPU.REGS.regs[9] == 32'd7);
`TEST_CHECK(CPU.REGS.regs[10] == 32'd7); `TEST_CHECK(CPU.REGS.regs[10] == 32'd7);
@@ -89,7 +101,10 @@ module mips_tb(input logic [0:0] clk);
`TEST_CHECK(CPU.REGS.regs[22] == 32'd0); `TEST_CHECK(CPU.REGS.regs[22] == 32'd0);
`TEST_CHECK(CPU.REGS.regs[23] == 32'd0); `TEST_CHECK(CPU.REGS.regs[23] == 32'd0);
if (num_errors == 0) $display("\x1b[38;5;10mAll MIPS tests passing\x1b[m"); if (num_errors == 0) begin $display("\x1b[38;5;10mAll MIPS tests passing\x1b[m");
else $display("\x1b[38;5;9m%0d MIPS test(s) failing\x1b[m", num_errors); end else begin $display("\x1b[38;5;9m%0d MIPS test(s) failing\x1b[m", num_errors); end
$dumpflush;
$finish;
end end
endmodule endmodule