diff --git a/modules/assignment3.sv b/modules/assignment3.sv index 8be85ab..62a405e 100644 --- a/modules/assignment3.sv +++ b/modules/assignment3.sv @@ -15,7 +15,7 @@ `include "seven_seg_4digit.sv" `endif -module assignment3 #(width, romsz, ramsz)( +module assignment3 #(width=5, romsz=9, ramsz=10)( input logic [0:0] clk, input logic [0:0] rst `ifdef QUARTUS_SYNTH , @@ -29,21 +29,23 @@ module assignment3 #(width, romsz, ramsz)( output logic[7:0] out_seg_3 `endif ); + logic [31:0] regs_out [32]; + logic [2**width-1:0] pc_addr, pc_addr_2; logic [2**width-1:0] pc_addr_write; logic [0:0] pc_we; // TODO: Verify if we need a clk gating on pc_addr instruction_counter #(width) PC (clk, rst, pc_we, pc_addr_write, pc_addr); - gatereg #(width, 2) gate_pc_addr(clk, rst, 1, pc_addr, pc_addr_2); + gatereg #(width, 2) gate_pc_addr_1(clk, rst, 1'b1, pc_addr, pc_addr_2); logic [2**width-1:0] rom_rd; logic [2**width-1:0] rom_addr; logic [2**width-1:0] instruction, instruction_1; - rom #(romsz, width) ROM (rom_addr, rom_rd); - gatereg #(width, 1) gate_pc_addr(clk, rst, 1, pc_addr, rom_addr); - gatereg #(width, 1) gate_instruction(clk, rst, 1, rom_rd, instruction); - gatereg #(width, 1) gate_instruction_1(clk, rst, 1, instruction, instruction_1); + rom #(romsz, width) ROM (rom_addr[romsz-1:0], rom_rd); + gatereg #(width, 1) gate_pc_addr(clk, rst, 1'b1, pc_addr, rom_addr); + gatereg #(width, 1) gate_instruction(clk, rst, 1'b1, rom_rd, instruction); + gatereg #(width, 1) gate_instruction_1(clk, rst, 1'b1, instruction, instruction_1); logic [0:0] cu_m2r, cu_m2w, cu_b, cu_alu_src, cu_rdst, cu_rw; @@ -52,56 +54,58 @@ module assignment3 #(width, romsz, ramsz)( control_unit CONTROL_UNIT (instruction[31:26], instruction[5:0], cu_m2r, cu_m2w, cu_b, cu_alu_fn, cu_alu_src, cu_rdst, cu_rw ); - gatereg #(0, 1) gate_cu_rdst (clk, rst, 1, cu_rdst, RDST); - gatereg #(0, 1) gate_cu_alu_src (clk, rst, 1, cu_alu_src, ALU_SRC); - gatereg #(2, 1) gate_cu_alu_fn (clk, rst, 1, cu_alu_fn, ALU_FN); + gatereg #(0, 1) gate_cu_rdst (clk, rst, 1'b1, cu_rdst, RDST); + gatereg #(0, 1) gate_cu_alu_src (clk, rst, 1'b1, cu_alu_src, ALU_SRC); + gatereg #(2, 1) gate_cu_alu_fn (clk, rst, 1'b1, cu_alu_fn, ALU_FN); - gatereg #(0, 2) gate_cu_b (clk, rst, 1, cu_b, B); - gatereg #(0, 2) gate_cu_m2w (clk, rst, 1, cu_m2w, MEM_WE); + gatereg #(0, 2) gate_cu_b (clk, rst, 1'b1, cu_b, B); + gatereg #(0, 2) gate_cu_m2w (clk, rst, 1'b1, cu_m2w, MEM_WE); - gatereg #(0, 3) gate_cu_rw (clk, rst, 1, cu_rw, REG_WE); - gatereg #(0, 3) gate_cu_m2r (clk, rst, 1, cu_m2r, REGW_MEM_OR_RD); + gatereg #(0, 3) gate_cu_rw (clk, rst, 1'b1, cu_rw, REG_WE); + gatereg #(0, 3) gate_cu_m2r (clk, rst, 1'b1, cu_m2r, REGW_MEM_OR_RD); logic [2**width-1:0] regf_rs, regf_rs_1; logic [2**width-1:0] regf_rt, regf_rt_1, regf_rt_2; logic [7:0] regf_a3, regf_a3_2; - assign rd = (REGW_MEM_OR_RD) ? rd_mem : alu_out_2; + logic [2**width-1:0] rd, rd_mem, rd_alu; + assign rd = (REGW_MEM_OR_RD) ? rd_mem : rd_alu; assign regf_a3 = (RDST) ? instruction_1[15:11] : instruction_1[20:16]; // TODO: Connect inputs - gatereg #(3, 2) gate_regf_a3 (clk, rst, 1, regf_a3, regf_a3_2); + gatereg #(3, 2) gate_regf_a3 (clk, rst, 1'b1, regf_a3, regf_a3_2); register_file #(width, 5) REGS ( ~clk, REG_WE, - regf_a3_2 & 8'b00011111, rd, + regf_a3_2[4:0], rd, instruction[25:21], regf_rs, instruction[20:16], regf_rt, regs_out ); - gatereg #(width, 1) gate_regf_rs(clk, rst, 1, regf_rs, regf_rs_1); - gatereg #(width, 1) gate_regf_rt(clk, rst, 1, regf_rt, regf_rt_1); - gatereg #(width, 1) gate_regf_rt_1(clk, rst, 1, regf_rt_1, regf_rt_2); + gatereg #(width, 1) gate_regf_rs(clk, rst, 1'b1, regf_rs, regf_rs_1); + gatereg #(width, 1) gate_regf_rt(clk, rst, 1'b1, regf_rt, regf_rt_1); + gatereg #(width, 1) gate_regf_rt_1(clk, rst, 1'b1, regf_rt_1, regf_rt_2); logic [2**width-1:0] sign_ext_imm, rt_imm; sign_extender #(4, width) SIGNEXT(1'b1, instruction[15:0], sign_ext_imm); - gatereg #(width, 1) gate_sign_ext_imm(clk, rst, 1, sign_ext_imm, rt_imm); + gatereg #(width, 1) gate_sign_ext_imm(clk, rst, 1'b1, sign_ext_imm, rt_imm); logic [2**width-1:0] alu_out, alu_out_1, alu_out_2; logic [3:0] alu_flags, alu_flags_1; - alu #(width) ALU (ALU_FN, regf_rs_1, (ALU_SRC) ? rt_imm : regf_rt_1, rd_alu, alu_flags); - gatereg #(width, 1) gate_alu_out (clk, rst, 1, alu_out, alu_out_1); - gatereg #(width, 1) gate_alu_out_1 (clk, rst, 1, alu_out_1, alu_out_2); - gatereg #(width, 1) gate_alu_flags (clk, rst, 1, alu_flags, alu_flags_1); + alu #(width) ALU (ALU_FN, regf_rs_1, (ALU_SRC) ? rt_imm : regf_rt_1, alu_out, alu_flags); + gatereg #(width, 1) gate_alu_out (clk, rst, 1'b1, alu_out, alu_out_1); + gatereg #(width, 1) gate_alu_out_1 (clk, rst, 1'b1, alu_out_1, alu_out_2); + gatereg #(width, 1) gate_alu_flags (clk, rst, 1'b1, alu_flags, alu_flags_1); + assign rd_alu = alu_out_2; logic [2**width-1:0] new_pc_addr, new_pc_addr_1; assign new_pc_addr = (rt_imm << 2) + pc_addr_2; - gatereg #(width, 1) gate_new_pc_addr (clk, rst, 1, new_pc_addr, new_pc_addr_1); + gatereg #(width, 1) gate_new_pc_addr (clk, rst, 1'b1, new_pc_addr, new_pc_addr_1); assign pc_addr_write = new_pc_addr_1; assign pc_we = B & alu_flags_1[2]; logic [2**width-1:0] mem_out, mem_out_1; ram #(ramsz, width) RAM (clk, rst, alu_out_1, MEM_WE, regf_rt_2, mem_out); - gatereg #(width, 1) gate_mem_out (clk, rst, 1, mem_out, mem_out_1); + gatereg #(width, 1) gate_mem_out (clk, rst, 1'b1, mem_out, mem_out_1); assign rd_mem = mem_out_1; endmodule `endif \ No newline at end of file diff --git a/modules/gatereg.sv b/modules/gatereg.sv index 43c8803..7c4d604 100644 --- a/modules/gatereg.sv +++ b/modules/gatereg.sv @@ -1,5 +1,5 @@ module gatereg #(width, ndelay=1)( - input logic [0:0] clk, input logic [0:0] rst, input logic en[0:0], + input logic [0:0] clk, input logic [0:0] rst, input logic [0:0] en, input logic [2**width-1:0] in, output logic [2**width-1:0] out ); logic [2**width-1:0] hold_value[ndelay]; @@ -7,10 +7,12 @@ module gatereg #(width, ndelay=1)( assign out = hold_value[ndelay-1]; always_ff @( posedge clk ) begin if (rst) begin - hold_value <= {(2**width){0}}; + for (integer i = 0; i < ndelay; ++i) begin + hold_value[i] <= {(2**width){1'b0}}; + end end else if (en) begin hold_value[0] <= in; - for (int i = 1; i < ndelay; ++i) begin + for (integer i = 1; i < ndelay; ++i) begin hold_value[i] <= hold_value[i-1]; end end diff --git a/tests/mips_pipelined.sv b/tests/mips_pipelined.sv new file mode 100644 index 0000000..7b9db58 --- /dev/null +++ b/tests/mips_pipelined.sv @@ -0,0 +1,118 @@ +`include "assignment3.sv" + +`timescale 1us/10ns + +`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",\ + 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] \ + ); +`define TEST_CHECK(cond) if (cond) begin end else begin \ + $display("Check %s failed", `"cond`"); \ + `PRINT_REGISTERS(CPU.REGS.regs); \ + num_errors += 1; \ + end + +module mips_pipelined_tb(); + logic [0:0] clk; + logic [0:0] rst; + assignment3 CPU (clk, rst); + + initial clk = 0; + initial rst = 0; + always #1 clk = ~clk; + + integer num_errors = 0; + initial begin + rst = 1; + #2; + rst = 0; + #2; + + $display("Beginning Pipelined MIPS tests"); + + #8; // 4x steps to allow pipeline to fill up + `TEST_CHECK(CPU.REGS.regs[8] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[9] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[10] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[11] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[9] == 32'd7); + #2; + `TEST_CHECK(CPU.RAM.mem[0] == 32'd7); + #2; + `TEST_CHECK(CPU.REGS.regs[10] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[11] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[12] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[10] == 32'd7); + #2; + `TEST_CHECK(CPU.REGS.regs[11] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[12] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[13] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[11] == (CPU.REGS.regs[10] + CPU.REGS.regs[11]) ); + `TEST_CHECK(CPU.REGS.regs[11] == 32'd14); + #2; + `TEST_CHECK(CPU.REGS.regs[12] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[13] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[14] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[12] == (CPU.REGS.regs[9] - CPU.REGS.regs[11])); + `TEST_CHECK(CPU.REGS.regs[12] == -32'sd7); + #2; + `TEST_CHECK(CPU.REGS.regs[13] == (CPU.REGS.regs[9] + 3) ); + `TEST_CHECK(CPU.REGS.regs[13] == 32'd10); + #2; + `TEST_CHECK(CPU.REGS.regs[14] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[15] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[16] == 32'd0); + #2; + `TEST_CHECK(CPU.REGS.regs[14] == (CPU.REGS.regs[12] + CPU.REGS.regs[13])); + `TEST_CHECK(CPU.REGS.regs[14] == 32'd3); + #2; + `TEST_CHECK(CPU.REGS.regs[16] == (CPU.REGS.regs[9] & CPU.REGS.regs[13])); + `TEST_CHECK(CPU.REGS.regs[16] == 32'd2); + #2; + `TEST_CHECK(CPU.REGS.regs[17] == (CPU.REGS.regs[9] | CPU.REGS.regs[13])); + `TEST_CHECK(CPU.REGS.regs[17] == 32'd15); + #2; + `TEST_CHECK(CPU.REGS.regs[18] == (CPU.REGS.regs[9] ^ CPU.REGS.regs[13])); + `TEST_CHECK(CPU.REGS.regs[18] == 32'd13); + #2; + `TEST_CHECK(CPU.REGS.regs[19] == ~(CPU.REGS.regs[9] | CPU.REGS.regs[13])); + `TEST_CHECK(CPU.REGS.regs[19] == 32'hfffffff0); + #2; + `TEST_CHECK(CPU.REGS.regs[20] == ( $signed(CPU.REGS.regs[12]) < $signed(CPU.REGS.regs[14]) )); + `TEST_CHECK(CPU.REGS.regs[20] == 32'd1); + #2; + `TEST_CHECK(CPU.REGS.regs[20] == ( CPU.REGS.regs[12] < CPU.REGS.regs[14] )); + `TEST_CHECK(CPU.REGS.regs[20] == 32'd0); + + // TODO: Verify program never branches + #2; + #2; + #2; + #2; + + // TODO: Verify final program register state + + + if (num_errors == 0) begin $display("\x1b[38;5;10mAll pipelined MIPS tests passing\x1b[m"); + end else begin $display("\x1b[38;5;9m%0d Single-cycle pipelined test(s) failing\x1b[m", num_errors); end + + $dumpflush; + $finish; + end +endmodule \ No newline at end of file diff --git a/tests/tests.sv b/tests/tests.sv index 49bde88..4964791 100644 --- a/tests/tests.sv +++ b/tests/tests.sv @@ -4,4 +4,5 @@ `include "tests/instruction_classifier_tb.sv" `include "tests/shifter_tb.sv" `include "tests/alu_tb.sv" -`include "tests/mips_singlecycle.sv" \ No newline at end of file +`include "tests/mips_singlecycle.sv" +`include "tests/mips_pipelined.sv" \ No newline at end of file