diff options
-rw-r--r-- | README.md | 0 | ||||
-rw-r--r-- | hdl/alu.v | 29 | ||||
-rw-r--r-- | hdl/alu_ctrl.v | 31 | ||||
-rw-r--r-- | hdl/control.v | 114 | ||||
-rw-r--r-- | hdl/dp_memory.v | 37 | ||||
-rw-r--r-- | hdl/ex_stage.v | 120 | ||||
-rw-r--r-- | hdl/forwarding_unit.v | 138 | ||||
-rw-r--r-- | hdl/hazard_unit.v | 66 | ||||
-rw-r--r-- | hdl/id_stage.v | 188 | ||||
-rw-r--r-- | hdl/if_stage.v | 77 | ||||
-rw-r--r-- | hdl/mem_stage.v | 59 | ||||
-rw-r--r-- | hdl/mips_system.v | 55 | ||||
-rw-r--r-- | hdl/pipeline.v | 250 | ||||
-rw-r--r-- | hdl/regfile.v | 40 | ||||
-rw-r--r-- | hdl/testbench.v | 73 | ||||
-rw-r--r-- | hdl/wb_stage.v | 11 | ||||
-rw-r--r-- | sw/Makefile | 22 | ||||
-rw-r--r-- | sw/test.asm | 19 |
18 files changed, 1329 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/README.md diff --git a/hdl/alu.v b/hdl/alu.v new file mode 100644 index 0000000..17008a9 --- /dev/null +++ b/hdl/alu.v @@ -0,0 +1,29 @@ +`timescale 1ns / 1ps + +/** + ALU Unit + */ +module alu ( + input wire [4:0] alu_ctl, + input wire [31:0] a_in, b_in, + output reg [31:0] result, + output wire zero_flag + ); + + assign zero_flag = (result == 0); + + always @(alu_ctl, a_in, b_in) begin // reevaluate if these change + case (alu_ctl) + 0: result = a_in & b_in; // bitwise and + 1: result = a_in | b_in; // bitwise or + 2: result = a_in + b_in; // addition + 6: result = a_in - b_in; // substraction + 7: result = a_in < b_in ? 1 : 0; // set on less than + 8: result = ~(a_in | b_in); // bitwise nor + 9: result = a_in ^ b_in; // bitwise xor + + default: result = 0; + endcase + end + +endmodule diff --git a/hdl/alu_ctrl.v b/hdl/alu_ctrl.v new file mode 100644 index 0000000..881c2c7 --- /dev/null +++ b/hdl/alu_ctrl.v @@ -0,0 +1,31 @@ +`timescale 1ns / 1ps + +/** +ALU Control unit + */ +module alu_ctrl( + input wire [1:0] alu_op, + input wire [5:0] func_code, + output reg [4:0] alu_ctl + ); + +always @* + begin + if(alu_op == 0) + alu_ctl = 2; // add + else if(alu_op == 1) + alu_ctl = 6; + else case( func_code ) + 32: alu_ctl = 2; // add + 34: alu_ctl = 6; // subtract + 36: alu_ctl = 0; // and + 37: alu_ctl = 1; // or + 38: alu_ctl = 9; // xor + 39: alu_ctl = 8; // nor + 42: alu_ctl = 7; // slt + default: alu_ctl = 15; // should not happen + endcase + end + +endmodule + diff --git a/hdl/control.v b/hdl/control.v new file mode 100644 index 0000000..58f273f --- /dev/null +++ b/hdl/control.v @@ -0,0 +1,114 @@ +`timescale 1ns / 1ps + +module control( + input [5:0] opcode, + input branch_eq, // result of comparison for conditional branch + + output reg [1:0] if_pc_source, + output id_rt_is_source, // rt is source + + output ex_imm_command, + output reg ex_alu_src_b, + output reg ex_dst_reg_sel, + output reg [1:0] ex_alu_op, + output reg mem_read, + output reg mem_write, + output reg wb_mem_to_reg, + output reg wb_reg_write + ); + + + localparam + LW = 6'b100011, + SW = 6'b101011, + BEQ=6'b000100, + RTYPE = 6'b0, + J=6'd2, + JAL=6'd3, + ADDI = 6'b001000, + ANDI = 6'b001100, + ORI = 6'b001101, + XORI = 6'b001110, + SLTI = 6'b001010; // opcodes + + reg memory_op; + reg r_type_op; + reg immediate_op; + reg branch_op; + reg jump_op; + + + assign ex_imm_command = immediate_op; + assign id_rt_is_source = (r_type_op | branch_op | opcode == SW); + + + always @* + begin + // default values + if_pc_source = 0; + ex_alu_src_b = 0; + ex_dst_reg_sel = 0; + ex_alu_op = 0; + mem_read = 0; + mem_write = 0; + wb_mem_to_reg = 0; + wb_reg_write = 0; + + memory_op = ( (opcode == LW) | (opcode == SW) ); + r_type_op = ( opcode == RTYPE ); + branch_op = ( opcode == BEQ ); + immediate_op = ( (opcode == ADDI) | (opcode == ANDI) | (opcode == ORI) | (opcode == XORI) | (opcode == SLTI) ); + jump_op = ( opcode == J); + + if (memory_op) begin + ex_alu_src_b = 1'b1; // select sign_extend_offset input + ex_dst_reg_sel = 1'b0; // rt + ex_alu_op = 2'b00; // add op + wb_mem_to_reg = 1'b1; // select mem_out + + if ( opcode == LW ) begin + mem_read = 1'b1; + wb_reg_write = 1'b1; + end + else + mem_write = 1'b1; // opcode == SW + + end + + else if (r_type_op) begin + ex_alu_src_b = 1'b0; // select B input + ex_dst_reg_sel = 1'b1; // rd + ex_alu_op = 2'b10; // operaction defined by func code + + wb_mem_to_reg = 1'b0; // alu_out + wb_reg_write = 1'b1; // write result to regfile + end + + else if (immediate_op) begin + ex_alu_src_b = 1'b1; // select sign_extend_offset input + ex_dst_reg_sel = 1'b0; // rt + ex_alu_op = 2'b10; // operation defined by function code + + wb_mem_to_reg = 1'b0; // alu_out + wb_reg_write = 1'b01; + end + + else if (branch_op) begin + if (branch_eq) if_pc_source = 2'b01; // PC <= branch_addr + else if_pc_source = 2'b00; + + end + + else if (jump_op) begin + if_pc_source = 2'b10; // PC <= jump_addr + end + + else begin + // NOP + end + + + end + + +endmodule diff --git a/hdl/dp_memory.v b/hdl/dp_memory.v new file mode 100644 index 0000000..fa7db30 --- /dev/null +++ b/hdl/dp_memory.v @@ -0,0 +1,37 @@ +`timescale 1ns / 1ps + +/** + Dual-port Instrcution/Data memory + */ + +module dp_memory( + input wire clk, + + input wire i_read_en, + input wire [31:0] i_addr, + output wire [31:0] i_instr_out, + + input wire d_read_en, + input wire d_write_en, + input wire [31:0] d_addr, + input wire [31:0] d_write_data, + output wire [31:0] d_data_out + ); + + reg [31:0] mem[0:1023]; + + initial begin + $readmemh("./sw/test.rom", mem); + end + + + always @(posedge clk) begin + if (d_write_en) + mem [d_addr] <= d_write_data; + end + + assign i_instr_out = i_read_en ? mem[i_addr] : 0; + assign d_data_out = d_read_en ? mem[d_addr] : 0; + +endmodule + diff --git a/hdl/ex_stage.v b/hdl/ex_stage.v new file mode 100644 index 0000000..cca87e9 --- /dev/null +++ b/hdl/ex_stage.v @@ -0,0 +1,120 @@ +module ex_stage( + input clk, + input rst, + + input wb_reg_write, + input wb_mem_to_reg, + + input mem_read, + input mem_write, + + input ex_imm_command, + input ex_alu_src_b, + input ex_dst_reg_sel, + input [1:0] ex_alu_op, + + input [31:0] A, + input [31:0] B, + input [31:0] sign_extend_offset, + input [4:0] rt, // target register + input [4:0] rd, // destination register + input [5:0] opcode, + input [1:0] rs_fwd_sel, // forwarding muxes control + input [1:0] rt_fwd_sel, // forwarding muxes control + input [31:0] mem_fwd_val, // forwarding from EX_MEM + input [31:0] wb_fwd_val, // forwarding from WB + + // outputs + output [4:0] ex_dst_reg, + output [5:0] ex_opcode, + + output reg [31:0] EX_MEM_alu_result, + output reg [31:0] EX_MEM_B_value, + output reg [4:0] EX_MEM_dst_reg, + output reg [5:0] EX_MEM_opcode, + output reg EX_MEM_mem_read, + output reg EX_MEM_mem_write, + output reg EX_MEM_wb_reg_write, + output reg EX_MEM_wb_mem_to_reg +); + + + wire [5:0] func_field; // func code field in instruction + wire [5:0] func_code; // func code for ALU control + wire [4:0] alu_ctl; // ALU control lines + + reg [31:0] alu_a_in; + wire [31:0] alu_b_in; + reg[31:0] b_value; + + wire [31:0] alu_result; + wire zero; + + + always @* + begin + case(rs_fwd_sel) + 0: alu_a_in = A; + 1: alu_a_in = mem_fwd_val; + 2: alu_a_in = wb_fwd_val; + endcase + end + + always @* + begin + case(rt_fwd_sel) + 0: b_value = B; + 1: b_value = mem_fwd_val; + 2: b_value = wb_fwd_val; + endcase + end + + assign alu_b_in = ex_alu_src_b ? sign_extend_offset : b_value; + assign func_field = sign_extend_offset [5:0]; // looks wierd, but func code is encoded there + assign func_code = ex_imm_command ? {{2'b10},{~opcode[2] & opcode[1] & ~opcode[0]},opcode[2:0]} : func_field; + assign ex_opcode = opcode; + assign ex_dst_reg = ex_dst_reg_sel ? rd : rt; + + + + alu_ctrl aluctl_inst( + .alu_op (ex_alu_op), + .func_code (func_code), + .alu_ctl (alu_ctl) + ); + + alu alu_inst ( + .alu_ctl (alu_ctl), + .a_in (alu_a_in), + .b_in (alu_b_in), + .result (alu_result), + .zero_flag (zero) + ); + + // EX/MEM Pipeline register + always @(posedge clk) begin + if (rst) + begin + EX_MEM_alu_result <= 0; + EX_MEM_B_value <= 0; + EX_MEM_dst_reg <= 0; + EX_MEM_mem_read <= 0; + EX_MEM_mem_write <= 0; + EX_MEM_wb_reg_write <= 0; + EX_MEM_wb_mem_to_reg <= 0; + end + else + begin + EX_MEM_alu_result <= alu_result; + EX_MEM_B_value <= b_value; + EX_MEM_dst_reg <= ex_dst_reg; + EX_MEM_opcode <= opcode; + EX_MEM_mem_read <= mem_read; + EX_MEM_mem_write <= mem_write; + EX_MEM_wb_reg_write <= wb_reg_write; + EX_MEM_wb_mem_to_reg <= wb_mem_to_reg; + end + end + + +endmodule diff --git a/hdl/forwarding_unit.v b/hdl/forwarding_unit.v new file mode 100644 index 0000000..ab98219 --- /dev/null +++ b/hdl/forwarding_unit.v @@ -0,0 +1,138 @@ +`timescale 1ns / 1ps + +module forwarding_unit + ( + input ex_mem_reg_write, + input mem_wb_reg_write, + input [4:0] ex_mem_dst_reg, + input [4:0] mem_wb_dst_reg, + input [4:0] id_ex_rs, + input [4:0] id_ex_rt, + input [4:0] if_id_rs, + input [4:0] if_id_rt, + + output [1:0] if_rs_forward_control, + output [1:0] id_rt_forward_control, + output [1:0] ex_rs_forward_control, + output [1:0] ex_rt_forward_control + ); + + // tmp signals + wire [3:0] id_fwd_ctrl, ex_fwd_ctrl; + + // encoding for muxes control signals + // general for both forwarding muxes + // 2'b01 - from EX_MEM pipe reg + // 2'b10 - from MEM_WB pipe reg + // 2'b00 - no forwarding + + assign if_rs_forward_control = id_fwd_ctrl[0] ? 2'b01 : id_fwd_ctrl[2] ? 2'b10 : 2'b00; + assign id_rt_forward_control = id_fwd_ctrl[1] ? 2'b01 : id_fwd_ctrl[3] ? 2'b10 : 2'b00; + assign ex_rs_forward_control = ex_fwd_ctrl[0] ? 2'b01 : ex_fwd_ctrl[2] ? 2'b10 : 2'b00; + assign ex_rt_forward_control = ex_fwd_ctrl[1] ? 2'b01 : ex_fwd_ctrl[3] ? 2'b10 : 2'b00; + + base_forwarding_unit ex_forwarding_inst( + .ex_mem_reg_write(ex_mem_reg_write), + .mem_wb_reg_write(mem_wb_reg_write), + .ex_mem_dst_reg(ex_mem_dst_reg), + .mem_wb_dst_reg(mem_wb_dst_reg), + .rs(id_ex_rs), + .rt(id_ex_rt), + .forward_control(ex_fwd_ctrl) + ); + + base_forwarding_unit id_forwarding_inst( + .ex_mem_reg_write(ex_mem_reg_write), + .mem_wb_reg_write(mem_wb_reg_write), + .ex_mem_dst_reg(ex_mem_dst_reg), + .mem_wb_dst_reg(mem_wb_dst_reg), + .rs(if_id_rs), + .rt(if_id_rt), + .forward_control(id_fwd_ctrl) + ); + + +endmodule + + + +/* Generic base logic module to implement forwarding + + Description of forward_control signal: +0000 - no forwarding +0001 - forwarding value from EX_MEM for replace rs value on destination stage. + EX_MEM[Value] -> PIPE_STAGE[rs] + +0010 - forwarding value from EX_MEM for replace rt value on destination stage. + EX_MEM[Value] -> PIPE_STAGE[rt] + +0100 - forwarding value from WB for replace rs value on destination stage. + WB[Value] -> PIPE_STAGE[rs] + +1000 - forwarding value from WB for replace rt value on destination stage. + WB[Value] -> PIPE_STAGE[rt] + +0011 - forwarding value from EX_MEM for replace rs and rt value on destination stage + EX_MEM[Value] -> PIPE_STAGE[rs]; EX_MEM[Value] -> PIPE_STAGE[rt] + +1100 - forwarding value from WB for replace Rs and Rt value on destination stage + WB[Value] -> PIPE_STAGE[rs]; WB[Value] -> PIPE_STAGE[rt] + + +0110 - forwarding value from EX_MEM for replace rt value on destination stage. + EX_MEM[Value] -> PIPE_STAGE[rt] + forwarding value from WB for replace rs value on destination stage. + WB[Value] -> PIPE_STAGE[rs] + +1001 - forwarding value from EX_MEM for replace rs value on destination stage. + EX_MEM[Value] -> PIPE_STAGE[rs] + forwarding value from WB for replace rt value on destination stage. + WB[Value] -> PIPE_STAGE[rt] + */ + +module base_forwarding_unit ( + input ex_mem_reg_write, + input mem_wb_reg_write, + input [4:0] ex_mem_dst_reg, + input [4:0] mem_wb_dst_reg, + input [4:0] rs, + input [4:0] rt, + + output reg [3:0] forward_control +); + + // service signals + reg ex_mem_dst_reg_is_not_zero; + reg mem_wb_dst_reg_is_not_zero; + + always @* + begin + + ex_mem_dst_reg_is_not_zero = |ex_mem_dst_reg; + mem_wb_dst_reg_is_not_zero = |mem_wb_dst_reg; + forward_control = 4'h0; + + if (ex_mem_reg_write & ex_mem_dst_reg_is_not_zero) + begin + if (ex_mem_dst_reg == rs) forward_control[0] = 1'b1; + else forward_control[0] = 1'b0; + + if (ex_mem_dst_reg == rt) forward_control[1] = 1'b1; + else forward_control[1] = 1'b0; + end + else forward_control[1:0] = 2'b00; + + if (mem_wb_reg_write & mem_wb_dst_reg_is_not_zero) + begin + if ((mem_wb_dst_reg == rs) & (ex_mem_dst_reg != rs)) forward_control[2] = 1'b1; + else forward_control[2] = 1'b0; + + if ((mem_wb_dst_reg == rt) & (ex_mem_dst_reg != rt)) forward_control[3] = 1'b1; + else forward_control[3] = 1'b0; + end + else forward_control[3:2] = 2'b00; + + end + + +endmodule diff --git a/hdl/hazard_unit.v b/hdl/hazard_unit.v new file mode 100644 index 0000000..627c162 --- /dev/null +++ b/hdl/hazard_unit.v @@ -0,0 +1,66 @@ +`timescale 1ns / 1ps + +module hazard_unit( + input clk, + input rst, + input [4:0] ex_dst_reg, + input [4:0] mem_dst_reg, + input [4:0] id_rs, + input [4:0] id_rt, + + input [5:0] mem_opcode, + input [5:0] ex_opcode, + input [5:0] id_opcode, + + input id_rt_is_source, + input ex_reg_write, + input mem_reg_write, + + output pc_write, + output if_id_write_en, + output reg hazard_detected +); + + localparam + LW = 6'b100011, + BEQ=6'b000100; + + + assign pc_write = ~hazard_detected; + assign if_id_write_en = ~hazard_detected; + + reg [1:0] coincidence; + + always @* + begin + coincidence = 0; + + if (ex_reg_write && ( (id_rs == ex_dst_reg) | ( (id_rt == ex_dst_reg) && id_rt_is_source))) + coincidence[0] = 1'b1; + else if (mem_reg_write && ( (id_rs == mem_dst_reg) | ( (id_rt == mem_dst_reg) && id_rt_is_source))) + coincidence[1] = 1'b1; + end + + + always @* + begin + hazard_detected = 0; + + if (coincidence [0]) + begin + if ( id_opcode == BEQ && ex_opcode == LW ) + hazard_detected = 1; + else if ( id_opcode == BEQ && ex_opcode != LW) + hazard_detected = 1; + else if ( id_opcode != BEQ && ex_opcode == LW) + hazard_detected = 1; + end + else if (coincidence [1]) + begin + if (id_opcode == BEQ && mem_opcode == LW) + hazard_detected = 1; + end + end + + +endmodule diff --git a/hdl/id_stage.v b/hdl/id_stage.v new file mode 100644 index 0000000..387c420 --- /dev/null +++ b/hdl/id_stage.v @@ -0,0 +1,188 @@ +`timescale 1ns / 1ps +/* + Instruction decode pipeline stage + */ + +module id_stage( + input clk, rst, + input reg_write, + input [4:0] wreg_addr, // write register number + input [31:0] wreg_data, // data to write into regfile + input [31:0] instruction, next_i_addr, // instruction fetched, next instruction address + + // inputs to support forwarding + input [1:0] rs_fwd_sel, rt_fwd_sel, // forwarding control signals + input [31:0] mem_fwd_val, wb_fwd_val, // forwarded data values + + input hazard, + // outputs + output wire [4:0] id_rs, + output wire [4:0] id_rt, + output wire [5:0] id_opcode, + + + output reg [31:0] ID_EX_A, + output reg [31:0] ID_EX_B, + output reg [4:0] ID_EX_rt, + output reg [4:0] ID_EX_rs, + output reg [4:0] ID_EX_rd, + output reg [5:0] ID_EX_opcode, + output reg [31:0] ID_EX_sign_extend_offset, + output reg ID_EX_wb_reg_write, + output reg ID_EX_wb_mem_to_reg, + output reg ID_EX_mem_read, + output reg ID_EX_mem_write, + output reg ID_EX_ex_imm_command, + output reg ID_EX_ex_alu_src_b, + output reg ID_EX_ex_dst_reg_sel, + output reg [1:0] ID_EX_ex_alu_op, + + output [31:0] branch_addr, jump_addr, // branch and jump adresses + output id_rt_is_source, + output [1:0] if_pc_source + ); + + + + + reg [31:0] A, B; + wire [31:0] a_out; + wire [31:0] b_out; + wire [31:0] sign_extend_offset; + + wire ex_imm_command; + wire ex_alu_src_b; + wire ex_dst_reg_sel; + wire [1:0] ex_alu_op; + wire mem_read; + wire mem_write; + wire wb_mem_to_reg; + wire wb_reg_write; + wire is_nop; + wire branch_eq; + + + + regfile regfile_inst + ( + .clk( clk ), + .rst( rst ), + .raddr1( instruction[25:21] ), + .raddr2( instruction[20:16] ), + .waddr( wreg_addr ), + .wdata( wreg_data ), + .w_en( reg_write ), + .rdata1( a_out ), + .rdata2( b_out ) + ); + + + + // Forwarding muxes + + always @* + begin + A = 0; + case (rs_fwd_sel) + 0: A = a_out; + 1: A = mem_fwd_val; + 2: A = wb_fwd_val; + endcase + end + + always @* + begin + B = 0; + case (rt_fwd_sel) + 0: B = b_out; + 1: B = mem_fwd_val; + 2: B = wb_fwd_val; + endcase + end + + + assign sign_extend_offset = { { 16{instruction[15]} }, instruction [15:0]}; + assign branch_addr = next_i_addr + ( sign_extend_offset << 2 ); + assign jump_addr = {next_i_addr[31:28], instruction[25:0], 2'b00 }; + assign branch_eq = ( A == B); + + assign id_rs = instruction[25:21]; + assign id_rt = instruction[20:16]; + assign id_opcode = instruction[31:26]; + + assign is_nop = ~|instruction; + + // Control Unit -- Opcode Decoder + + control cunit_instance ( + .opcode( instruction [31:26] ), + .branch_eq( branch_eq ), + .id_rt_is_source(id_rt_is_source), + .if_pc_source(if_pc_source), + .ex_imm_command(ex_imm_command), + .ex_alu_src_b(ex_alu_src_b), + .ex_dst_reg_sel(ex_dst_reg_sel), + .ex_alu_op(ex_alu_op), + .mem_read(mem_read), + .mem_write(mem_write), + .wb_mem_to_reg(wb_mem_to_reg), + .wb_reg_write(wb_reg_write) + ); + + + // ID/EX Pipeline register + + + always @(posedge clk) begin + if (rst) + begin + ID_EX_A <= 0; + ID_EX_B <= 0; + ID_EX_rt <= 0; + ID_EX_rs <= 0; + ID_EX_rd <= 0; + ID_EX_opcode <= 0; + ID_EX_sign_extend_offset <= 0; + ID_EX_wb_reg_write <= 0; + ID_EX_wb_mem_to_reg <= 0; + ID_EX_mem_read <= 0; + ID_EX_mem_write <= 0; + ID_EX_ex_imm_command <= 0; + ID_EX_ex_alu_src_b <= 0; + ID_EX_ex_dst_reg_sel <= 0; + ID_EX_ex_alu_op <= 0; + end + else + begin + ID_EX_A <= A; + ID_EX_B <= B; + ID_EX_rt <= id_rt; + ID_EX_rs <= id_rs; + ID_EX_rd <= instruction[15:11]; + ID_EX_opcode <= id_opcode; + ID_EX_sign_extend_offset <= sign_extend_offset; + if (is_nop || hazard) begin + ID_EX_wb_reg_write <= 0; + ID_EX_wb_mem_to_reg <= 0; + ID_EX_mem_read <= 0; + ID_EX_mem_write <= 0; + ID_EX_ex_imm_command <= 0; + ID_EX_ex_alu_src_b <= 0; + ID_EX_ex_dst_reg_sel <= 0; + ID_EX_ex_alu_op <= 0; + end + else begin + ID_EX_wb_reg_write <= wb_reg_write; + ID_EX_wb_mem_to_reg <= wb_mem_to_reg; + ID_EX_mem_read <= mem_read; + ID_EX_mem_write <= mem_write; + ID_EX_ex_imm_command <= ex_imm_command; + ID_EX_ex_alu_src_b <= ex_alu_src_b; + ID_EX_ex_dst_reg_sel <= ex_dst_reg_sel; + ID_EX_ex_alu_op <= ex_alu_op; + end + end + end + + +endmodule diff --git a/hdl/if_stage.v b/hdl/if_stage.v new file mode 100644 index 0000000..eda165d --- /dev/null +++ b/hdl/if_stage.v @@ -0,0 +1,77 @@ +`timescale 1ns / 1ps + +/* + Instruction Fetch pipeline stage + */ + +module if_stage( + input clk, rst, + + input if_id_write_en, + input pc_write, + input [1:0] pc_source, + + output i_read_en, + output [31:0] i_addr, + + input [31:0] i_instr_in, + input [31:0] jump_addr, branch_addr, + + output reg [31:0] IF_ID_next_i_addr, + output reg [31:0] IF_ID_instruction + ); + + + reg [31:0] pc_reg, pc_next; // Program counter (PC) + wire [31:0] next_i_addr; + + // logic + assign next_i_addr = pc_reg + 4; + assign i_read_en = 1; + assign i_addr = pc_reg >> 2; + + always @* + begin + pc_next = pc_reg; + + case (pc_source) + 2'b00: pc_next = next_i_addr; + 2'b01: pc_next = branch_addr; + 2'b10: pc_next = jump_addr; + endcase + + end + + always @(posedge clk) + begin + if (rst) + pc_reg <= 0; + else + begin + if (pc_write) + pc_reg <= pc_next; + end + end + + + /* + IF/ID Pipeline register + */ + + always @(posedge clk) begin + if (rst) + begin + IF_ID_next_i_addr <= 0; + IF_ID_instruction <= 0; + end + else + begin + if ( if_id_write_en ) begin + IF_ID_next_i_addr <= pc_reg + 4; + IF_ID_instruction <= i_instr_in; + end + end + end + + +endmodule diff --git a/hdl/mem_stage.v b/hdl/mem_stage.v new file mode 100644 index 0000000..79a211d --- /dev/null +++ b/hdl/mem_stage.v @@ -0,0 +1,59 @@ +`timescale 1ns / 1ps + + +module mem_stage ( + input clk, + input rst, + input mem_read, + input mem_write, + input [31:0] alu_result, + input [31:0] B, + input [4:0] dst_reg, + input wb_reg_write, + input wb_mem_to_reg, + + output reg [4:0] MEM_WB_dst_reg, + output reg MEM_WB_reg_write, + output reg MEM_WB_mem_to_reg, + output reg [31:0] MEM_WB_mem_out, + output reg [31:0] MEM_WB_alu_out, + + // Memory Interface + output d_read_en, + output d_write_en, + output [31:0] d_addr, + output [31:0] d_write_data, + input [31:0] d_data_in + ); + + assign d_read_en = mem_read; + assign d_write_en = mem_write; + assign d_addr = alu_result; + assign d_write_data = B; + + + /* + MEM/WB Pipeline register + */ + + always @(posedge clk) begin + if (rst) + begin + MEM_WB_dst_reg <= 0; + MEM_WB_reg_write <= 0; + MEM_WB_mem_to_reg <= 0; + MEM_WB_mem_out <= 0; + MEM_WB_alu_out <= 0; + end + else + begin + MEM_WB_dst_reg <= dst_reg; + MEM_WB_reg_write <= wb_reg_write; + MEM_WB_mem_to_reg <= wb_mem_to_reg; + MEM_WB_mem_out <= d_data_in; + MEM_WB_alu_out <= alu_result; + end + end + + +endmodule diff --git a/hdl/mips_system.v b/hdl/mips_system.v new file mode 100644 index 0000000..fa01da1 --- /dev/null +++ b/hdl/mips_system.v @@ -0,0 +1,55 @@ +/* + MIPS System: CPU Core + Memory + */ + +module mips_system + ( + input wire clk, + input wire rst, + + output ext_write_en, + output ext_read_en, + output [31:0] ext_addr, + output [31:0] ext_write_data, + input [31:0] ext_data_in + ) ; + + wire i_read_en; + wire [31:0] i_addr; + wire [31:0] i_instr; + wire d_read_en; + wire d_write_en; + wire [31:0] d_addr; + wire [31:0] d_write_data; + wire [31:0] d_read_data; + + pipeline pipeline_inst + ( + .clk(clk), + .rst(rst), + .i_read_en(i_read_en), + .i_addr(i_addr), + .i_instr_in(i_instr), + .d_read_en(d_read_en), + .d_write_en(d_write_en), + .d_addr(d_addr), + .d_write_data(d_write_data), + .d_data_in(d_read_data) + ); + + + dp_memory memory_inst + ( + .clk(clk), + .i_read_en(i_read_en), + .i_addr(i_addr), + .i_instr_out(i_instr), + .d_read_en(d_read_en), + .d_write_en(d_write_en), + .d_addr(d_addr), + .d_write_data(d_write_data), + .d_data_out(d_read_data) + ); + + +endmodule // mips_system diff --git a/hdl/pipeline.v b/hdl/pipeline.v new file mode 100644 index 0000000..01f94da --- /dev/null +++ b/hdl/pipeline.v @@ -0,0 +1,250 @@ +`timescale 1ns / 1ps + +/** + Pipelined CPU + */ + +module pipeline( + input wire clk, + input wire rst, + + output i_read_en, + output [31:0] i_addr, + + input [31:0] i_instr_in, + + output wire d_read_en, + output wire d_write_en, + output wire [31:0] d_addr, + output wire [31:0] d_write_data, + input wire [31:0] d_data_in + ); + + +/* Interconnect wires*/ + wire [1:0] pc_source; + wire pc_write; + wire [31:0] jump_addr; + wire [31:0] branch_addr; + wire [31:0] next_i_addr; + wire [31:0] i_fetched; // fetched instrcution from if + wire if_id_write_en; // write enable for IF/ID pipe reg + + wire [31:0] wreg_data; // data to write into regfile + + wire [4:0] ex_dst_reg; + wire [5:0] ex_opcode; + + wire [4:0] id_rs; + wire [4:0] id_rt; + wire [5:0] id_opcode; + + wire ID_EX_wb_reg_write; + wire ID_EX_wb_mem_to_reg; + wire ID_EX_mem_read; + wire ID_EX_mem_write; + wire ID_EX_ex_imm_command; + wire ID_EX_ex_alu_src_b; + wire ID_EX_ex_dst_reg_sel; + wire [1:0] ID_EX_ex_alu_op; + wire [31:0] ID_EX_A; + wire [31:0] ID_EX_B; + wire [31:0] ID_EX_sign_extend_offset; + wire [4:0] ID_EX_rt; // target register + wire [4:0] ID_EX_rd; // destination register + wire [4:0] ID_EX_rs; // source register + wire [5:0] ID_EX_opcode; + + wire [31:0] EX_MEM_alu_result; + wire [31:0] EX_MEM_B_value; + wire [4:0] EX_MEM_dst_reg; + wire [5:0] EX_MEM_opcode; + wire EX_MEM_mem_read; + wire EX_MEM_mem_write; + wire EX_MEM_wb_reg_write; + wire EX_MEM_wb_mem_to_reg; + + wire [4:0] MEM_WB_dst_reg; + wire MEM_WB_reg_write; + wire MEM_WB_mem_to_reg; + wire [31:0] MEM_WB_mem_out; + wire [31:0] MEM_WB_alu_out; + + wire id_rt_is_source; + wire hazard_detected; + + + // forwarding control signals for muxes + wire [1:0] if_rs_forward_control; + wire [1:0] id_rt_forward_control; + wire [1:0] ex_rs_forward_control; + wire [1:0] ex_rt_forward_control; + + + + if_stage ifetch_inst + ( + .clk ( clk ), + .rst ( rst ), + .if_id_write_en ( if_id_write_en ), + .pc_write ( pc_write ), + .pc_source ( pc_source ), + .i_read_en ( i_read_en ), + .i_addr ( i_addr ), + .i_instr_in ( i_instr_in), + .jump_addr ( jump_addr ), + .branch_addr ( branch_addr ), + .IF_ID_instruction ( i_fetched ), + .IF_ID_next_i_addr ( next_i_addr ) + ); + + + hazard_unit hazard_inst + ( + .clk ( clk ), + .rst ( rst ), + .ex_dst_reg ( ex_dst_reg ), + .mem_dst_reg ( EX_MEM_dst_reg ), + .id_rs ( id_rs ), + .id_rt ( id_rt ), + .mem_opcode ( EX_MEM_opcode ), + .ex_opcode ( ex_opcode ), + .id_opcode ( id_opcode ), + .id_rt_is_source ( id_rt_is_source ), + .ex_reg_write ( ID_EX_wb_reg_write ), + .mem_reg_write ( EX_MEM_wb_reg_write ), + .pc_write ( pc_write ), + .if_id_write_en ( if_id_write_en ), + .hazard_detected ( hazard_detected ) + ); + + forwarding_unit forwarding_inst + ( + .ex_mem_reg_write (EX_MEM_wb_reg_write), + .mem_wb_reg_write (MEM_WB_reg_write), + .ex_mem_dst_reg (EX_MEM_dst_reg), + .mem_wb_dst_reg (MEM_WB_dst_reg), + .id_ex_rs (ID_EX_rs), + .id_ex_rt (ID_EX_rt), + .if_id_rs (id_rs), + .if_id_rt (id_rt), + .if_rs_forward_control ( if_rs_forward_control ), + .id_rt_forward_control ( id_rt_forward_control ), + .ex_rs_forward_control ( ex_rs_forward_control ), + .ex_rt_forward_control ( ex_rt_forward_control ) + ); + + + + id_stage idecode_inst + ( + .clk ( clk ), + .rst ( rst ), + .reg_write ( MEM_WB_reg_write ), + .wreg_addr ( MEM_WB_dst_reg ), // write register number + .wreg_data ( wreg_data ), // data to write into regfile + .instruction ( i_fetched ), + .next_i_addr ( next_i_addr ), // instruction fetched, next instruction address + + .rs_fwd_sel ( if_rs_forward_control ), // forwarding control signals + .rt_fwd_sel ( id_rt_forward_control ), // forwarding control signals + .mem_fwd_val ( EX_MEM_alu_result ), // forwarded data values from MEM + .wb_fwd_val ( wreg_data ), // forwarded data values from WB + + .hazard ( hazard_detected ), + .id_rs( id_rs ), + .id_rt( id_rt ), + .id_opcode( id_opcode ), + + .ID_EX_A ( ID_EX_A ), + .ID_EX_B ( ID_EX_B ), + .ID_EX_rt ( ID_EX_rt ), + .ID_EX_rs ( ID_EX_rs ), + .ID_EX_rd ( ID_EX_rd ), + .ID_EX_opcode ( ID_EX_opcode ), + .ID_EX_sign_extend_offset ( ID_EX_sign_extend_offset ), + .ID_EX_wb_reg_write ( ID_EX_wb_reg_write ), + .ID_EX_wb_mem_to_reg ( ID_EX_wb_mem_to_reg ), + .ID_EX_mem_read ( ID_EX_mem_read ), + .ID_EX_mem_write ( ID_EX_mem_write ), + .ID_EX_ex_imm_command ( ID_EX_ex_imm_command ), + .ID_EX_ex_alu_src_b ( ID_EX_ex_alu_src_b ), + .ID_EX_ex_dst_reg_sel ( ID_EX_ex_dst_reg_sel ), + .ID_EX_ex_alu_op ( ID_EX_ex_alu_op ), + + .branch_addr ( branch_addr ), + .jump_addr ( jump_addr ), + .id_rt_is_source ( id_rt_is_source ), + .if_pc_source ( pc_source ) + ); + + + ex_stage execute_inst + ( + .clk ( clk ), + .rst ( rst ), + .wb_reg_write ( ID_EX_wb_reg_write ), + .wb_mem_to_reg ( ID_EX_wb_mem_to_reg ), + .mem_read ( ID_EX_mem_read ), + .mem_write ( ID_EX_mem_write ), + .ex_imm_command ( ID_EX_ex_imm_command ), + .ex_alu_src_b ( ID_EX_ex_alu_src_b ), + .ex_dst_reg_sel ( ID_EX_ex_dst_reg_sel ), + .ex_alu_op ( ID_EX_ex_alu_op ), + .A ( ID_EX_A ), + .B ( ID_EX_B ), + .sign_extend_offset ( ID_EX_sign_extend_offset ), + .rt ( ID_EX_rt ), // target register + .rd ( ID_EX_rd ), // destination register + .opcode ( ID_EX_opcode ), + .rs_fwd_sel ( ex_rs_forward_control ), // forwarding muxes control + .rt_fwd_sel ( ex_rt_forward_control ), // forwarding muxes control + .mem_fwd_val ( EX_MEM_alu_result ), // forwarding from MEM + .wb_fwd_val ( wreg_data ), // forwarding from WB + .ex_dst_reg ( ex_dst_reg ), + .ex_opcode ( ex_opcode ), + .EX_MEM_alu_result ( EX_MEM_alu_result ), + .EX_MEM_B_value ( EX_MEM_B_value ), + .EX_MEM_dst_reg ( EX_MEM_dst_reg ), + .EX_MEM_opcode ( EX_MEM_opcode ), + .EX_MEM_mem_read ( EX_MEM_mem_read ), + .EX_MEM_mem_write ( EX_MEM_mem_write ), + .EX_MEM_wb_reg_write ( EX_MEM_wb_reg_write ), + .EX_MEM_wb_mem_to_reg ( EX_MEM_wb_mem_to_reg ) + ); + + + mem_stage memstage_inst + ( + .clk ( clk ), + .rst ( rst ), + .mem_read ( EX_MEM_mem_read ), + .mem_write ( EX_MEM_mem_write ), + .alu_result ( EX_MEM_alu_result ), + .B ( EX_MEM_B_value ), + .dst_reg ( EX_MEM_dst_reg ), + .wb_reg_write ( EX_MEM_wb_reg_write ), + .wb_mem_to_reg ( EX_MEM_wb_mem_to_reg ), + .MEM_WB_dst_reg ( MEM_WB_dst_reg ), + .MEM_WB_reg_write ( MEM_WB_reg_write ), + .MEM_WB_mem_to_reg ( MEM_WB_mem_to_reg ), + .MEM_WB_mem_out ( MEM_WB_mem_out ), + .MEM_WB_alu_out ( MEM_WB_alu_out ), + .d_read_en ( d_read_en ), + .d_write_en ( d_write_en ), + .d_addr ( d_addr ), + .d_write_data ( d_write_data ), + .d_data_in ( d_data_in ) + ); + + + wb_stage wb_inst + ( + .mem_to_reg ( MEM_WB_mem_to_reg ), + .mem_out ( MEM_WB_mem_out ), + .alu_out ( MEM_WB_alu_out ), + .write_data ( wreg_data ) + ); + + +endmodule diff --git a/hdl/regfile.v b/hdl/regfile.v new file mode 100644 index 0000000..01219f9 --- /dev/null +++ b/hdl/regfile.v @@ -0,0 +1,40 @@ +`timescale 1ns / 1ps + +/** + Register file: + * 2 asyncrhonous read ports + * 1 synchronous write port + */ +module regfile( + input wire clk, // clock to trigger write + input wire rst, // reset + input wire [4:0] raddr1, raddr2, waddr, // the registers numbers to read or write + input wire [31:0] wdata, // data to write + input wire w_en, // write enable + output wire [31:0] rdata1, rdata2 // the register values read + ); + + + reg [31:0] rf [31:0]; // 32 registers each 32 bits long + + assign rdata1 = rf [raddr1]; + assign rdata2 = rf [raddr2]; + + integer ii; + + initial + begin + for ( ii = 0; ii < 32; ii= ii + 1 ) + rf[ii] = 0; + end + + always @(posedge clk) + begin + if (rst) + rf[0] <= 0; + else + if(w_en) + rf [waddr] <= wdata; + end + +endmodule diff --git a/hdl/testbench.v b/hdl/testbench.v new file mode 100644 index 0000000..6100226 --- /dev/null +++ b/hdl/testbench.v @@ -0,0 +1,73 @@ +`timescale 1ns / 1ps + + +module testbench; + + // Inputs + reg clk; + reg rst; + reg [31:0] ext_data_in; + + // Outputs + wire ext_write_en; + wire ext_read_en; + wire [31:0] ext_addr; + wire [31:0] ext_write_data; + + // Instantiate the Unit Under Test (UUT) + mips_system uut ( + .clk(clk), + .rst(rst), + .ext_write_en(ext_write_en), + .ext_read_en(ext_read_en), + .ext_addr(ext_addr), + .ext_write_data(ext_write_data), + .ext_data_in(ext_data_in) + ); + + initial begin + rst = 1; + ext_data_in = 0; + + // Wait 100 ns for global reset to finish + #100; + rst = 0; + + end // initial begin + + + initial begin + clk = 0; + forever + #10 clk = !clk; + end + + + integer i; + initial begin + + for (i = 0; i < 1000; i=i+1) + @(posedge clk); + + + $stop(); + end + + initial + begin + $display("Trace register $t0"); + @(negedge rst); + + forever + begin + @(posedge clk); + $display("$t0 (REG8) = %x",uut.pipeline_inst.idecode_inst.regfile_inst.rf[8]); + end + + + + end + + +endmodule + diff --git a/hdl/wb_stage.v b/hdl/wb_stage.v new file mode 100644 index 0000000..37cfc38 --- /dev/null +++ b/hdl/wb_stage.v @@ -0,0 +1,11 @@ +`timescale 1ns / 1ps + +module wb_stage( + input mem_to_reg, + input [31:0] mem_out, alu_out, + output [31:0] write_data + ); + + assign write_data = mem_to_reg ? mem_out : alu_out; + +endmodule diff --git a/sw/Makefile b/sw/Makefile new file mode 100644 index 0000000..2207685 --- /dev/null +++ b/sw/Makefile @@ -0,0 +1,22 @@ +CFLAGS = -O2 -Wall -c -s + +GCC_MIPS = mips-sde-elf-gcc $(CFLAGS) +AS_MIPS = mips-sde-elf-as +LD_MIPS = mips-sde-elf-ld +DUMP_MIPS = mips-sde-elf-objdump +COPY_MIPS = mips-sde-elf-objcopy +CONVERT = cat test.vh | perl -pe 's/([\dA-F]{2})\s+([\dA-F]{2})\s+([\dA-F]{2})\s+([\dA-F]{2})/$$1$$2$$3$$4/g;' > test.rom + + +LIBS = + + +all: + $(AS_MIPS) -o test.o test.asm + $(LD_MIPS) -Ttext 0x0 -Tdata 0x200 -eentry -o test.axf test.o + $(DUMP_MIPS) --disassemble test.axf > test.lst + $(COPY_MIPS) -O verilog test.axf test.vh + $(CONVERT) + +clean: + rm -f *.o diff --git a/sw/test.asm b/sw/test.asm new file mode 100644 index 0000000..7712165 --- /dev/null +++ b/sw/test.asm @@ -0,0 +1,19 @@ +.global entry + +.data /* data section*/ + .word 0x0001 + .word 0xFFFF +.text /* code goes to text section*/ +.ent entry +entry: + lw $t0, 0x200 /* t0 = 1*/ + lw $t1, 0x200 /* t1 = 1*/ + add $t0, $t0, $t1 /* t0 = t0 + t1 = 2*/ + add $t0, $t0, 0xB /* t0 = t0 + 0xB == 0xD*/ + sub $t0, $t0, $t1 /* t0 = t0 - $t1 == 0xC*/ + or $t0, $t0, 0x10 /* t0 = t0 | 0x10 == 0x1C*/ + xor $t0, $t0, $t1 /* t0 = t0 ^ t1 == 0x1D*/ + slt $t0, $t0, $t1 /* t0 = t0 < t1 == 0*/ + add $t0, $t0, $t1 /* t0 = t0 + t1 == 1*/ + beq $t0, $t1, entry /* PC = entry if t0 == t1*/ +.end entry |