diff --git a/mips_cpu/Makefile b/mips_cpu/Makefile index 4f036d7..dc37c99 100644 --- a/mips_cpu/Makefile +++ b/mips_cpu/Makefile @@ -1,13 +1,7 @@ -.PHONY: clean verilate simulate dump - -s.v: t.v - yosys -s mips_core.ys -l yosys.log -t - -t.v: memory_interfaces.sv mips_core/alu.sv mips_core/branch_controller.sv mips_core/cache_bank.sv mips_core/d_cache.sv mips_core/decoder.sv mips_core/fetch_unit.sv mips_core/forward_unit.sv mips_core/glue_circuits.sv mips_core/hazard_controller.sv mips_core/i_cache.sv mips_core/mips_core.sv mips_core/mips_core.svh mips_core/mips_core_interfaces.sv mips_core/mips_core_pkg.sv mips_core/pipeline_registers.sv mips_core/reg_file.sv mips_cpu_pkg.sv pass_done_interface.sv - ~/Downloads/sv2v-Linux-v0.0.4/sv2v -Imips_core mips_cpu_pkg.sv memory_interfaces.sv pass_done_interface.sv mips_core/*.sv | grep -v import | grep -v "\$$error" | grep -v "\$$stop" | grep -v "\$$fwrite" | grep -v "\$$fflush" > t.v +.PHONY: clean verilate simulate dump wave verilate: - verilator --cc --exe --build --trace-fst -DSIMULATION -Imips_core -f verilator_files --top-module mips_core verilator_main.cpp memory.cpp memory_driver.cpp -Wno-fatal + bash -c "source $(CSE148_TOOLS)/oss-cad-suite/environment && verilator --cc --exe --build --trace-fst -DSIMULATION -Imips_core -f verilator_files --top-module mips_core verilator_main.cpp memory.cpp memory_driver.cpp -Wno-fatal" simulate: obj_dir/Vmips_core @@ -15,6 +9,9 @@ simulate: dump: obj_dir/Vmips_core -d +wave: + gtkwave simx.fst + clean: rm -rf obj_dir/ rm -f *.txt \ No newline at end of file diff --git a/mips_cpu/mips_core.sdc b/mips_cpu/mips_core.sdc deleted file mode 100644 index fe99ac2..0000000 --- a/mips_cpu/mips_core.sdc +++ /dev/null @@ -1,97 +0,0 @@ -create_clock -period 10 -name clk [get_ports clk] -set_input_delay -max -clock clk 1 [get_ports rst_n] -set_input_delay -min -clock clk -1 [get_ports rst_n] -set_output_delay -max -clock clk 1 [get_ports rst_n] -set_output_delay -min -clock clk -1 [get_ports rst_n] -set_input_delay -max -clock clk 1 [get_ports i_cache_read_control_done] -set_input_delay -min -clock clk -1 [get_ports i_cache_read_control_done] -set_output_delay -max -clock clk 1 [get_ports i_cache_read_control_done] -set_output_delay -min -clock clk -1 [get_ports i_cache_read_control_done] -set_input_delay -max -clock clk 1 [get_ports i_cache_read_user_data] -set_input_delay -min -clock clk -1 [get_ports i_cache_read_user_data] -set_output_delay -max -clock clk 1 [get_ports i_cache_read_user_data] -set_output_delay -min -clock clk -1 [get_ports i_cache_read_user_data] -set_input_delay -max -clock clk 1 [get_ports i_cache_read_user_available] -set_input_delay -min -clock clk -1 [get_ports i_cache_read_user_available] -set_output_delay -max -clock clk 1 [get_ports i_cache_read_user_available] -set_output_delay -min -clock clk -1 [get_ports i_cache_read_user_available] -set_input_delay -max -clock clk 1 [get_ports i_cache_read_control_base] -set_input_delay -min -clock clk -1 [get_ports i_cache_read_control_base] -set_output_delay -max -clock clk 1 [get_ports i_cache_read_control_base] -set_output_delay -min -clock clk -1 [get_ports i_cache_read_control_base] -set_input_delay -max -clock clk 1 [get_ports i_cache_read_control_length] -set_input_delay -min -clock clk -1 [get_ports i_cache_read_control_length] -set_output_delay -max -clock clk 1 [get_ports i_cache_read_control_length] -set_output_delay -min -clock clk -1 [get_ports i_cache_read_control_length] -set_input_delay -max -clock clk 1 [get_ports i_cache_read_control_go] -set_input_delay -min -clock clk -1 [get_ports i_cache_read_control_go] -set_output_delay -max -clock clk 1 [get_ports i_cache_read_control_go] -set_output_delay -min -clock clk -1 [get_ports i_cache_read_control_go] -set_input_delay -max -clock clk 1 [get_ports i_cache_read_user_re] -set_input_delay -min -clock clk -1 [get_ports i_cache_read_user_re] -set_output_delay -max -clock clk 1 [get_ports i_cache_read_user_re] -set_output_delay -min -clock clk -1 [get_ports i_cache_read_user_re] -set_input_delay -max -clock clk 1 [get_ports d_cache_write_control_done] -set_input_delay -min -clock clk -1 [get_ports d_cache_write_control_done] -set_output_delay -max -clock clk 1 [get_ports d_cache_write_control_done] -set_output_delay -min -clock clk -1 [get_ports d_cache_write_control_done] -set_input_delay -max -clock clk 1 [get_ports d_cache_write_user_full] -set_input_delay -min -clock clk -1 [get_ports d_cache_write_user_full] -set_output_delay -max -clock clk 1 [get_ports d_cache_write_user_full] -set_output_delay -min -clock clk -1 [get_ports d_cache_write_user_full] -set_input_delay -max -clock clk 1 [get_ports d_cache_write_control_base] -set_input_delay -min -clock clk -1 [get_ports d_cache_write_control_base] -set_output_delay -max -clock clk 1 [get_ports d_cache_write_control_base] -set_output_delay -min -clock clk -1 [get_ports d_cache_write_control_base] -set_input_delay -max -clock clk 1 [get_ports d_cache_write_control_length] -set_input_delay -min -clock clk -1 [get_ports d_cache_write_control_length] -set_output_delay -max -clock clk 1 [get_ports d_cache_write_control_length] -set_output_delay -min -clock clk -1 [get_ports d_cache_write_control_length] -set_input_delay -max -clock clk 1 [get_ports d_cache_write_control_go] -set_input_delay -min -clock clk -1 [get_ports d_cache_write_control_go] -set_output_delay -max -clock clk 1 [get_ports d_cache_write_control_go] -set_output_delay -min -clock clk -1 [get_ports d_cache_write_control_go] -set_input_delay -max -clock clk 1 [get_ports d_cache_write_user_we] -set_input_delay -min -clock clk -1 [get_ports d_cache_write_user_we] -set_output_delay -max -clock clk 1 [get_ports d_cache_write_user_we] -set_output_delay -min -clock clk -1 [get_ports d_cache_write_user_we] -set_input_delay -max -clock clk 1 [get_ports d_cache_write_user_data] -set_input_delay -min -clock clk -1 [get_ports d_cache_write_user_data] -set_output_delay -max -clock clk 1 [get_ports d_cache_write_user_data] -set_output_delay -min -clock clk -1 [get_ports d_cache_write_user_data] -set_input_delay -max -clock clk 1 [get_ports d_cache_read_control_done] -set_input_delay -min -clock clk -1 [get_ports d_cache_read_control_done] -set_output_delay -max -clock clk 1 [get_ports d_cache_read_control_done] -set_output_delay -min -clock clk -1 [get_ports d_cache_read_control_done] -set_input_delay -max -clock clk 1 [get_ports d_cache_read_user_data] -set_input_delay -min -clock clk -1 [get_ports d_cache_read_user_data] -set_output_delay -max -clock clk 1 [get_ports d_cache_read_user_data] -set_output_delay -min -clock clk -1 [get_ports d_cache_read_user_data] -set_input_delay -max -clock clk 1 [get_ports d_cache_read_user_available] -set_input_delay -min -clock clk -1 [get_ports d_cache_read_user_available] -set_output_delay -max -clock clk 1 [get_ports d_cache_read_user_available] -set_output_delay -min -clock clk -1 [get_ports d_cache_read_user_available] -set_input_delay -max -clock clk 1 [get_ports d_cache_read_control_base] -set_input_delay -min -clock clk -1 [get_ports d_cache_read_control_base] -set_output_delay -max -clock clk 1 [get_ports d_cache_read_control_base] -set_output_delay -min -clock clk -1 [get_ports d_cache_read_control_base] -set_input_delay -max -clock clk 1 [get_ports d_cache_read_control_length] -set_input_delay -min -clock clk -1 [get_ports d_cache_read_control_length] -set_output_delay -max -clock clk 1 [get_ports d_cache_read_control_length] -set_output_delay -min -clock clk -1 [get_ports d_cache_read_control_length] -set_input_delay -max -clock clk 1 [get_ports d_cache_read_control_go] -set_input_delay -min -clock clk -1 [get_ports d_cache_read_control_go] -set_output_delay -max -clock clk 1 [get_ports d_cache_read_control_go] -set_output_delay -min -clock clk -1 [get_ports d_cache_read_control_go] -set_input_delay -max -clock clk 1 [get_ports d_cache_read_user_re] -set_input_delay -min -clock clk -1 [get_ports d_cache_read_user_re] -set_output_delay -max -clock clk 1 [get_ports d_cache_read_user_re] -set_output_delay -min -clock clk -1 [get_ports d_cache_read_user_re] -set_input_delay -max -clock clk 1 [get_ports pass_done_value] -set_input_delay -min -clock clk -1 [get_ports pass_done_value] -set_output_delay -max -clock clk 1 [get_ports pass_done_value] -set_output_delay -min -clock clk -1 [get_ports pass_done_value] -set_input_delay -max -clock clk 1 [get_ports pass_done_code] -set_input_delay -min -clock clk -1 [get_ports pass_done_code] -set_output_delay -max -clock clk 1 [get_ports pass_done_code] -set_output_delay -min -clock clk -1 [get_ports pass_done_code] diff --git a/mips_cpu/mips_core.ys b/mips_cpu/mips_core.ys deleted file mode 100644 index 73db046..0000000 --- a/mips_cpu/mips_core.ys +++ /dev/null @@ -1,10 +0,0 @@ -read_liberty -lib /home/zinsser/cse148/FreePDK45/osu_soc/lib/files/gscl45nm.lib -read_liberty -lib /home/zinsser/cse148/baseline/mips_cpu/rams/build/sram_32_16_freepdk45_TT_1p0V_25C.lib -read_verilog t.v -synth -top mips_core -flatten -dfflibmap -liberty /home/zinsser/cse148/FreePDK45/osu_soc/lib/files/gscl45nm.lib -abc -liberty /home/zinsser/cse148/FreePDK45/osu_soc/lib/files/gscl45nm.lib -constr mips_core.constr -D 5000 -opt_clean - -write_verilog -attr2comment s.v -stat -liberty /home/zinsser/cse148/FreePDK45/osu_soc/lib/files/gscl45nm.lib -liberty /home/zinsser/cse148/baseline/mips_cpu/rams/build/sram_32_16_freepdk45_TT_1p0V_25C.lib diff --git a/mips_cpu/mips_core/alu.sv b/mips_cpu/mips_core/alu.sv index aca4b02..d3c3231 100644 --- a/mips_cpu/mips_core/alu.sv +++ b/mips_cpu/mips_core/alu.sv @@ -97,7 +97,12 @@ module alu ( ALUCTL_BGEZ: out.branch_outcome = in.op1 >= signed'(0) ? TAKEN : NOT_TAKEN; ALUCTL_BLTZ: out.branch_outcome = in.op1 < signed'(0) ? TAKEN : NOT_TAKEN; - default: $display("%m (%t) Illegal ALUCTL code %b", $time, in.alu_ctl); + default: + begin + `ifdef SIMULATION + $display("%m (%t) Illegal ALUCTL code %b", $time, in.alu_ctl); + `endif + end endcase end end diff --git a/mips_cpu/mips_core/cache_bank.sv b/mips_cpu/mips_core/cache_bank.sv index 1cec98d..e572e18 100644 --- a/mips_cpu/mips_core/cache_bank.sv +++ b/mips_cpu/mips_core/cache_bank.sv @@ -34,19 +34,24 @@ module cache_bank #(parameter DATA_WIDTH = 32, parameter ADDR_WIDTH = 4)( // the read output (old_data) should be presented at the output port. logic new_data_flag; - // cache_bank_core #(DATA_WIDTH, ADDR_WIDTH) - // BANK_CORE ( - // .clk, .i_we, .i_waddr, .i_raddr, .i_wdata, - // .o_rdata(old_data) - // ); - - // sram_32_16_freepdk45 BANK_CORE ( - sram #(DATA_WIDTH, ADDR_WIDTH) BANK_CORE ( - // Port 0: W - .clk0(clk), .csb0(~i_we), .addr0(i_waddr), .din0(i_wdata), - // Port 1: R - .clk1(clk), .csb1('0), .addr1(i_raddr), .dout1(old_data) - ); + generate + if (ADDR_WIDTH < 4) begin + // OpenRAM requires at least 16 rows + // Use register based structure for shallow RAMs + cache_bank_core #(DATA_WIDTH, ADDR_WIDTH) + BANK_CORE ( + .clk, .i_we, .i_waddr, .i_raddr, .i_wdata, + .o_rdata(old_data) + ); + end else begin + sram #(.DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH)) BANK_CORE ( + // Port 0: W + .clk0(clk), .csb0(~i_we), .addr0(i_waddr), .din0(i_wdata), + // Port 1: R + .clk1(clk), .csb1('0), .addr1(i_raddr), .dout1(old_data) + ); + end + endgenerate assign o_rdata = new_data_flag ? new_data : old_data; @@ -76,65 +81,7 @@ module cache_bank_core #(parameter DATA_WIDTH = 32, parameter ADDR_WIDTH = 4)( end endmodule -module cache_bank_sp #(parameter DATA_WIDTH = 32, parameter ADDR_WIDTH = 4)( - input clk, // Clock - input i_we, // Write enable - input logic [DATA_WIDTH - 1 : 0] i_wdata, // Write data - input logic [ADDR_WIDTH - 1 : 0] i_waddr, i_raddr, // Write/read address - output logic o_rvalid, - output logic [DATA_WIDTH - 1 : 0] o_rdata // Read data -); - - // A register to store new_data - logic [DATA_WIDTH - 1 : 0] new_data; - - // The registered output of cache_bank_core_sp - logic rvalid; - logic [DATA_WIDTH - 1 : 0] rdata; - - // A flag to determine whether the last cycle write data (new_data) or - // the read output (old_data) should be presented at the output port. - logic new_data_flag; - - cache_bank_core_sp #(DATA_WIDTH, ADDR_WIDTH) - BANK_CORE ( - .clk, .i_we, .i_waddr, .i_raddr, .i_wdata, - .o_rvalid(rvalid), - .o_rdata(rdata) - ); - - assign o_rvalid = new_data_flag | rvalid; - assign o_rdata = new_data_flag ? new_data : rdata; - - always_ff @(posedge clk) - begin - new_data <= i_wdata; - new_data_flag <= i_we & (i_raddr == i_waddr); - end -endmodule - -module cache_bank_core_sp #(parameter DATA_WIDTH = 32, parameter ADDR_WIDTH = 4)( - input clk, // Clock - input i_we, // Write enable - input logic [DATA_WIDTH - 1 : 0] i_wdata, // Write data - input logic [ADDR_WIDTH - 1 : 0] i_waddr, i_raddr, // Write/read address - output logic o_rvalid, - output logic [DATA_WIDTH - 1 : 0] o_rdata // Read data -); - localparam DEPTH = 1 << ADDR_WIDTH; - - logic [DATA_WIDTH - 1 : 0] data [DEPTH]; - - always_ff @(posedge clk) - begin - if (i_we) - data[i_waddr] <= i_wdata; - else - o_rdata <= data[i_raddr]; - o_rvalid <= !i_we; - end -endmodule - +`ifdef SIMULATION // OpenRAM SRAM model module sram( // Port 0: W @@ -207,3 +154,4 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; end endmodule +`endif diff --git a/mips_cpu/mips_core/d_cache.sv b/mips_cpu/mips_core/d_cache.sv index 6762c65..b73734b 100644 --- a/mips_cpu/mips_core/d_cache.sv +++ b/mips_cpu/mips_core/d_cache.sv @@ -238,51 +238,30 @@ module d_cache #( always_comb begin + next_state = state; unique case (state) STATE_READY: - begin if (miss) - begin if (valid_bits[i_index] & dirty_bits[i_index]) next_state = STATE_FLUSH_REQUEST; else next_state = STATE_REFILL_REQUEST; - end - else - next_state = state; - end STATE_FLUSH_REQUEST: - begin if (mem_write_address.AWREADY) next_state = STATE_FLUSH_DATA; - else - next_state = state; - end STATE_FLUSH_DATA: - begin if (last_flush_word && mem_write_data.WREADY) next_state = STATE_REFILL_REQUEST; - else - next_state = state; - end STATE_REFILL_REQUEST: - begin if (mem_read_address.ARREADY) next_state = STATE_REFILL_DATA; - else - next_state = state; - end STATE_REFILL_DATA: - begin if (last_refill_word) next_state = STATE_READY; - else - next_state = state; - end endcase end diff --git a/mips_cpu/mips_core/decoder.sv b/mips_cpu/mips_core/decoder.sv index 7083790..2521f7e 100644 --- a/mips_cpu/mips_core/decoder.sv +++ b/mips_cpu/mips_core/decoder.sv @@ -49,7 +49,7 @@ module decoder ( decoder_output_ifc.out out ); - task uses_rs; + task rs; begin // Only set uses_rs if it is not register zero out.uses_rs = |i_inst.data[25:21]; @@ -57,7 +57,7 @@ module decoder ( end endtask - task uses_rt; + task rt; begin // Only set uses_rt if it is not register zero out.uses_rt = |i_inst.data[20:16]; @@ -74,7 +74,7 @@ module decoder ( end endtask - task uses_immediate_raw; + task immediate_raw; input [31:0] immediate; begin out.uses_immediate = 1'b1; @@ -82,19 +82,19 @@ module decoder ( end endtask - task uses_immediate_zero_extend; - uses_immediate_raw(32'(unsigned'(i_inst.data[15:0]))); + task immediate_zero_extend; + immediate_raw(32'(unsigned'(i_inst.data[15:0]))); endtask - task uses_immediate_signed_extend; - uses_immediate_raw(32'(signed'(i_inst.data[15:0]))); + task immediate_signed_extend; + immediate_raw(32'(signed'(i_inst.data[15:0]))); endtask - task uses_immediate_shamt; - uses_immediate_raw(32'(unsigned'(i_inst.data[10:6]))); + task immediate_shamt; + immediate_raw(32'(unsigned'(i_inst.data[10:6]))); endtask - task uses_rw_raw; + task rw_raw; input [4:0] rw; begin // Only set uses_rw if it is not register zero @@ -103,43 +103,43 @@ module decoder ( end endtask - task uses_rw_rtype; - uses_rw_raw(i_inst.data[15:11]); + task rw_rtype; + rw_raw(i_inst.data[15:11]); endtask - task uses_rw_itype; - uses_rw_raw(i_inst.data[20:16]); + task rw_itype; + rw_raw(i_inst.data[20:16]); endtask task typical_rtype; begin - uses_rs(); - uses_rt(); - uses_rw_rtype(); + rs(); + rt(); + rw_rtype(); end endtask task shamt_rtype; begin route_rt_to_rs(); - uses_rw_rtype(); - uses_immediate_shamt(); + rw_rtype(); + immediate_shamt(); end endtask task signed_extend_itype; begin - uses_rs(); - uses_rw_itype(); - uses_immediate_signed_extend(); + rs(); + rw_itype(); + immediate_signed_extend(); end endtask task zero_extend_itype; begin - uses_rs(); - uses_rw_itype(); - uses_immediate_zero_extend(); + rs(); + rw_itype(); + immediate_zero_extend(); end endtask @@ -274,7 +274,7 @@ module decoder ( 6'h08: // jr begin out.alu_ctl = ALUCTL_NOP; // jr does not use alu - uses_rs(); + rs(); out.is_branch_jump = 1'b1; out.is_jump = 1'b1; out.is_jump_reg = 1'b1; @@ -283,9 +283,9 @@ module decoder ( 6'h09: //jalr begin out.alu_ctl = ALUCTL_OR; - uses_rs(); - uses_rw_raw(ra); // jalr always write to ra (31) - uses_immediate_raw(32'(unsigned'(i_pc.pc)) + 8); + rs(); + rw_raw(ra); // jalr always write to ra (31) + immediate_raw(32'(unsigned'(i_pc.pc)) + 8); out.is_branch_jump = 1'b1; out.is_jump = 1'b1; out.is_jump_reg = 1'b1; @@ -293,31 +293,41 @@ module decoder ( 6'h18: // mul begin + `ifdef SIMULTION $error("%m (%t) mul not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end 6'h19: //mulu begin + `ifdef SIMULTION $error("%m (%t) mulu not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end 6'h1a: //div begin + `ifdef SIMULTION $error("%m (%t) div not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end 6'h1b: //divu begin + `ifdef SIMULTION $error("%m (%t) divu not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end default: begin + `ifdef SIMULTION $error("%m (%t) unknown R-type funct code %b. Treated as a NOP. PC=0x%x", $time, i_inst.data[5:0], i_pc.pc); + `endif out.valid = 1'b0; end endcase @@ -368,15 +378,15 @@ module decoder ( 6'h0f: //lui Implemented as 0 | Immediate begin out.alu_ctl = ALUCTL_OR; - uses_rw_itype(); - uses_immediate_raw({i_inst.data[15:0], 16'h0000}); + rw_itype(); + immediate_raw({i_inst.data[15:0], 16'h0000}); end 6'h04: //beq begin out.alu_ctl = ALUCTL_BEQ; - uses_rs(); - uses_rt(); + rs(); + rt(); out.is_branch_jump = 1'b1; out.branch_target = i_pc.pc + `ADDR_WIDTH'd4 + `ADDR_WIDTH'(signed'(i_inst.data[15:0]) << 2); end @@ -384,8 +394,8 @@ module decoder ( 6'h05: //bne begin out.alu_ctl = ALUCTL_BNE; - uses_rs(); - uses_rt(); + rs(); + rt(); out.is_branch_jump = 1'b1; out.branch_target = i_pc.pc + `ADDR_WIDTH'd4 + `ADDR_WIDTH'(signed'(i_inst.data[15:0]) << 2); end @@ -393,8 +403,8 @@ module decoder ( 6'h06: //blez begin out.alu_ctl = ALUCTL_BLEZ; - uses_rs(); - uses_rt(); + rs(); + rt(); out.is_branch_jump = 1'b1; out.branch_target = i_pc.pc + `ADDR_WIDTH'd4 + `ADDR_WIDTH'(signed'(i_inst.data[15:0]) << 2); end @@ -405,8 +415,8 @@ module decoder ( out.alu_ctl = ALUCTL_BGEZ; else out.alu_ctl = ALUCTL_BLTZ; - uses_rs(); - uses_rt(); + rs(); + rt(); out.is_branch_jump = 1'b1; out.branch_target = i_pc.pc + `ADDR_WIDTH'd4 + `ADDR_WIDTH'(signed'(i_inst.data[15:0]) << 2); end @@ -414,8 +424,8 @@ module decoder ( 6'h07: //bgtz begin out.alu_ctl = ALUCTL_BGTZ; - uses_rs(); - uses_rt(); + rs(); + rt(); out.is_branch_jump = 1'b1; out.branch_target = i_pc.pc + `ADDR_WIDTH'd4 + `ADDR_WIDTH'(signed'(i_inst.data[15:0]) << 2); end @@ -431,8 +441,8 @@ module decoder ( 6'h03: // jal begin out.alu_ctl = ALUCTL_OR; - uses_rw_raw(ra); // jal always write to ra (31) - uses_immediate_raw(32'(unsigned'(i_pc.pc)) + 8); + rw_raw(ra); // jal always write to ra (31) + immediate_raw(32'(unsigned'(i_pc.pc)) + 8); out.is_branch_jump = 1'b1; out.is_jump = 1'b1; out.branch_target = {i_inst.data[`ADDR_WIDTH - 3: 0], 2'b00}; @@ -440,25 +450,33 @@ module decoder ( 6'h20: //lb begin + `ifdef SIMULTION $error("%m (%t) lb not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end 6'h24: //lbu begin + `ifdef SIMULTION $error("%m (%t) lbu not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end 6'h21: //lh begin + `ifdef SIMULTION $error("%m (%t) lh not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end 6'h25: //lhu begin + `ifdef SIMULTION $error("%m (%t) lhu not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end @@ -472,13 +490,17 @@ module decoder ( 6'h28: //sb begin + `ifdef SIMULTION $error("%m (%t) sb not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end 6'h29: //sh begin + `ifdef SIMULTION $error("%m (%t) sh not supported. Treated as a NOP. PC=0x%x", $time, i_pc.pc); + `endif out.valid = 1'b0; end @@ -487,9 +509,9 @@ module decoder ( out.alu_ctl = ALUCTL_ADD; out.is_mem_access = 1'b1; out.mem_action = WRITE; - uses_rs(); - uses_rt(); - uses_immediate_signed_extend(); + rs(); + rt(); + immediate_signed_extend(); end 6'h10: //mtc0 @@ -498,24 +520,26 @@ module decoder ( 5'h17: begin out.alu_ctl = ALUCTL_MTC0_PASS; - uses_rt(); + rt(); end 5'h18: begin out.alu_ctl = ALUCTL_MTC0_FAIL; - uses_rt(); + rt(); end 5'h19: begin out.alu_ctl = ALUCTL_MTC0_DONE; - uses_rt(); + rt(); end default: begin + `ifdef SIMULTION $error("%m (%t) unknown MTC0 value 0x%x. Treated as a NOP. PC=0x%x", $time, i_inst.data[15:11], i_pc.pc); + `endif out.valid = 1'b0; end endcase @@ -523,8 +547,9 @@ module decoder ( default: begin + `ifdef SIMULTION $error("%m (%t) unknown opcode %b. Treated as a NOP. PC=0x%x", $time, i_inst.data[31:26], i_pc.pc); - $stop; + `endif out.valid = 1'b0; end endcase diff --git a/mips_cpu/mips_core/i_cache.sv b/mips_cpu/mips_core/i_cache.sv index daac13e..762c377 100644 --- a/mips_cpu/mips_core/i_cache.sv +++ b/mips_cpu/mips_core/i_cache.sv @@ -184,28 +184,17 @@ module i_cache #( always_comb begin + next_state = state; unique case (state) STATE_READY: - begin if (miss) next_state = STATE_REFILL_REQUEST; - else - next_state = state; - end STATE_REFILL_REQUEST: - begin if (mem_read_address.ARREADY) next_state = STATE_REFILL_DATA; - else - next_state = state; - end STATE_REFILL_DATA: - begin if (last_refill_word) next_state = STATE_READY; - else - next_state = state; - end endcase end diff --git a/mips_cpu/rams/.gitignore b/mips_cpu/rams/.gitignore deleted file mode 100644 index 5034363..0000000 --- a/mips_cpu/rams/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -__pycache__/ -build/ \ No newline at end of file diff --git a/mips_cpu/rams/config.py b/mips_cpu/rams/config.py deleted file mode 100644 index dae1a3a..0000000 --- a/mips_cpu/rams/config.py +++ /dev/null @@ -1,29 +0,0 @@ -# Data word size -word_size = 32 -# Number of words in the memory -num_words = 16 - -# Technology to use in $OPENRAM_TECH -tech_name = "freepdk45" - -num_rw_ports = 0 -num_r_ports = 1 -num_w_ports = 1 - -# You can use the technology nominal corner only -nominal_corner_only = True -# Or you can specify particular corners -# Process corners to characterize -# process_corners = ["SS", "TT", "FF"] -# Voltage corners to characterize -# supply_voltages = [ 3.0, 3.3, 3.5 ] -# Temperature corners to characterize -# temperatures = [ 0, 25 100] - -# Output directory for the results -output_path = "build" -# Output file base name -output_name = "sram_{0}_{1}_{2}_analytical".format(word_size,num_words,tech_name) - -# Disable analytical models for full characterization (WARNING: slow!) -# analytical_delay = False diff --git a/mips_cpu/synth/.gitignore b/mips_cpu/synth/.gitignore new file mode 100644 index 0000000..c414527 --- /dev/null +++ b/mips_cpu/synth/.gitignore @@ -0,0 +1,8 @@ +__pycache__/ +build/ +*.json +*.log +*.v +configs.mk +synthesis.ys +timing.sta \ No newline at end of file diff --git a/mips_cpu/synth/Makefile b/mips_cpu/synth/Makefile new file mode 100644 index 0000000..b1a4d0d --- /dev/null +++ b/mips_cpu/synth/Makefile @@ -0,0 +1,45 @@ +.PHONY: clean all rams syn sta + +configs= +ifneq (clean,$(MAKECMDGOALS)) +include configs.mk +endif + +ram_targets=$(configs:%=build/sram_%_freepdk45_analytical_TT_1p0V_25C.lib) + +all: netlist.v + +mips_core.v: ../mips_core/*.sv + $(CSE148_TOOLS)/sv2v-Linux/sv2v -Imips_core ../mips_core/*.sv > $@ + +hierarchy.json: mips_core.v + bash -c "source $(CSE148_TOOLS)/oss-cad-suite/environment && yosys -s hierarchy.ys -l hierarchy.log -t" + +configs.mk synthesis.ys sram.v timing.sta: hierarchy.json generate.py + python3 generate.py + +rams: $(ram_targets) + +build/sram_%_freepdk45_analytical_TT_1p0V_25C.lib : config.py + env RAM_CONFIG="$*" \ + FREEPDK45=$(CSE148_TOOLS)/FreePDK45 \ + OPENRAM_HOME=$(CSE148_TOOLS)/OpenRAM/compiler \ + OPENRAM_TECH=$(CSE148_TOOLS)/OpenRAM/technology \ + $(CSE148_TOOLS)/venv/bin/python3 $(CSE148_TOOLS)/OpenRAM/compiler/openram.py config + +netlist.v: mips_core.v $(ram_targets) synthesis.ys + bash -c "source ~/cse148/oss-cad-suite/environment && yosys -s synthesis.ys -l synthesis.log -t" + +syn: netlist.v + +sta: netlist.v timing.sta $(ram_targets) + $(CSE148_TOOLS)/OpenSTA/app/sta timing.sta + +clean: + rm -rf build + rm -f *.log + rm -f *.json + rm -f *.v + rm -f configs.mk + rm -f synthesis.ys + rm -f timing.sta \ No newline at end of file diff --git a/mips_cpu/synth/config.py b/mips_cpu/synth/config.py new file mode 100644 index 0000000..9c6e49f --- /dev/null +++ b/mips_cpu/synth/config.py @@ -0,0 +1,33 @@ +import os + +word_size, num_words = os.environ["RAM_CONFIG"].split("_") + +# Data word size +word_size = int(word_size) +# Number of words in the memory +num_words = int(num_words) + +# Technology to use in $OPENRAM_TECH +tech_name = "freepdk45" + +num_rw_ports = 0 +num_r_ports = 1 +num_w_ports = 1 + +# You can use the technology nominal corner only +nominal_corner_only = True +# Or you can specify particular corners +# Process corners to characterize +# process_corners = ["SS", "TT", "FF"] +# Voltage corners to characterize +# supply_voltages = [ 3.0, 3.3, 3.5 ] +# Temperature corners to characterize +# temperatures = [ 0, 25 100] + +# Output directory for the results +output_path = "build" +# Output file base name +output_name = "sram_{0}_{1}_{2}_analytical".format(word_size,num_words,tech_name) + +# Disable analytical models for full characterization (WARNING: slow!) +# analytical_delay = False diff --git a/mips_cpu/synth/generate.py b/mips_cpu/synth/generate.py new file mode 100644 index 0000000..8a138ee --- /dev/null +++ b/mips_cpu/synth/generate.py @@ -0,0 +1,100 @@ +import json +import os + +liberty = f"{os.environ['CSE148_TOOLS']}/FreePDK45/osu_soc/lib/files/gscl45nm.lib" + + +def parse_hierarchy(file_name): + with open(file_name) as f: + h = json.load(f) + + configs = set() + for module_name, module in h["modules"].items(): + for cell in module["cells"].values(): + if cell["type"] == "sram": + addr_width = int(cell["parameters"]["ADDR_WIDTH"], 2) + data_width = int(cell["parameters"]["DATA_WIDTH"], 2) + depth = 1 << addr_width + print(f"Found sram {data_width}x{depth} in {module_name}") + configs.add((addr_width, data_width, depth)) + return configs + +def generate_makefile(configs): + with open("configs.mk", "w") as f: + f.write("configs=") + f.write(" ".join(f"{w}_{h}" for _, w, h in configs)) + +def generate_sram_mapping(configs): + with open("sram.v", "w") as f: + f.write(f""" + +module sram( +// Port 0: W + clk0,csb0,addr0,din0, +// Port 1: R + clk1,csb1,addr1,dout1 + ); + + parameter DATA_WIDTH = 32; + parameter ADDR_WIDTH = 4; + + input clk0, csb0; + input [ADDR_WIDTH-1:0] addr0; + input [DATA_WIDTH-1:0] din0; + input clk1, csb1; + input [ADDR_WIDTH-1:0] addr1; + output [DATA_WIDTH-1:0] dout1; + + generate +""") + for a, w, h in configs: + f.write(f""" + if (ADDR_WIDTH == {a} && DATA_WIDTH == {w}) + sram_{w}_{h}_freepdk45_analytical core (.*); +""") + + f.write(""" + endgenerate +endmodule + +""") + +def generate_yosys_script(configs): + with open("synthesis.ys", "w") as f: + f.write(f"read_liberty -lib {liberty}\n") + for _, w, h in configs: + f.write(f"read_liberty -lib build/sram_{w}_{h}_freepdk45_analytical_TT_1p0V_25C.lib\n") + f.write(f""" +read_verilog mips_core.v +read_verilog -sv sram.v +synth -top mips_core -flatten +dfflibmap -liberty {liberty} +abc -liberty {liberty} -constr mips_core.constr -D 5000 +opt_clean + +write_verilog -attr2comment netlist.v +stat -liberty {liberty}""") + for _, w, h in configs: + f.write(f" -liberty build/sram_{w}_{h}_freepdk45_analytical_TT_1p0V_25C.lib") + +def generate_sta_script(configs): + with open("timing.sta", "w") as f: + f.write(f"read_liberty {liberty}\n") + for _, w, h in configs: + f.write(f"read_liberty build/sram_{w}_{h}_freepdk45_analytical_TT_1p0V_25C.lib\n") + f.write(f""" +read_verilog netlist.v +link_design mips_core +read_sdc mips_core.sdc +report_checks +report_clock_min_period -include_port_paths +exit +""") + +if __name__ == "__main__": + configs = parse_hierarchy("hierarchy.json") + + generate_makefile(configs) + generate_sram_mapping(configs) + generate_yosys_script(configs) + generate_sta_script(configs) \ No newline at end of file diff --git a/mips_cpu/synth/hierarchy.ys b/mips_cpu/synth/hierarchy.ys new file mode 100644 index 0000000..6ab7a42 --- /dev/null +++ b/mips_cpu/synth/hierarchy.ys @@ -0,0 +1,5 @@ +read_verilog mips_core.v +blackbox sram +hierarchy -top mips_core +proc +write_json hierarchy.json \ No newline at end of file diff --git a/mips_cpu/synth/mips_core.constr b/mips_cpu/synth/mips_core.constr new file mode 100644 index 0000000..6a0270f --- /dev/null +++ b/mips_cpu/synth/mips_core.constr @@ -0,0 +1,2 @@ +set_driving_cell INVX1 +set_load 0.015 \ No newline at end of file diff --git a/mips_cpu/synth/mips_core.sdc b/mips_cpu/synth/mips_core.sdc new file mode 100644 index 0000000..95591b3 --- /dev/null +++ b/mips_cpu/synth/mips_core.sdc @@ -0,0 +1,5 @@ +create_clock -period 10 -name clk [get_ports clk] +set_input_delay -max -clock clk 1 [all_inputs] +set_input_delay -min -clock clk -1 [all_inputs] +set_output_delay -max -clock clk 1 [all_outputs] +set_output_delay -min -clock clk -1 [all_outputs] diff --git a/mips_cpu/verilator_main.cpp b/mips_cpu/verilator_main.cpp index ffc4bb0..d5832fa 100644 --- a/mips_cpu/verilator_main.cpp +++ b/mips_cpu/verilator_main.cpp @@ -128,7 +128,7 @@ void wb_event(const int addr, const int data) std::cout << "\n!! [" << std::dec << main_time << "] expected write back mismatches" << "\n!! [" << std::dec << main_time << "] expected addr=" << std::hex << expected_addr << " data=" << expected_data - << "\n!! [" << std::dec << main_time << "] actual addr=" << addr + << "\n!! [" << std::dec << main_time << "] actual addr=" << std::hex << addr << " data=" << data << std::endl; std::raise(SIGINT); }