diff --git a/controller.sv b/controller.sv index 0353b808..b3186ae0 100644 --- a/controller.sv +++ b/controller.sv @@ -82,9 +82,10 @@ module controller output logic data_sign_extension_o, // Sign extension on read data from data memory output logic [1:0] data_reg_offset_o, // Offset in bytes inside register for stores output logic data_req_o, // Request for a transaction to data memory - input logic data_ack_i, // Data memory request-acknowledge input logic data_req_ex_i, // Delayed copy of the data_req_o - input logic data_rvalid_i, // rvalid from data memory + + input logic lsu_ready_ex_i, + input logic lsu_ready_wb_i, // hwloop signals output logic [2:0] hwloop_we_o, // write enable for hwloop regs @@ -173,7 +174,6 @@ module controller logic mult_en; logic [1:0] csr_op; - logic lsu_stall; logic misalign_stall; logic instr_ack_stall; logic load_stall; @@ -1256,9 +1256,6 @@ module controller // Stall because of IF miss assign instr_ack_stall = ~instr_ack_i; - // Stall if TCDM contention has been detected - assign lsu_stall = ~data_ack_i; - assign misalign_stall = data_misaligned_i; assign trap_stall = trap_insn_o; @@ -1284,10 +1281,10 @@ module controller // we unstall the if_stage if the debug unit wants to set a new // pc, so that the new value gets written into current_pc_if and is // used by the instr_core_interface - stall_if_o = instr_ack_stall | load_stall | jr_stall | lsu_stall | misalign_stall | halt_if | (~pc_valid_i) | (jump_in_id_o == `BRANCH_COND); - stall_id_o = instr_ack_stall | load_stall | jr_stall | lsu_stall | misalign_stall | halt_id; - stall_ex_o = instr_ack_stall | lsu_stall | dbg_stall_i; - stall_wb_o = lsu_stall | dbg_stall_i; + stall_if_o = instr_ack_stall | load_stall | jr_stall | (~lsu_ready_ex_i) | (~lsu_ready_wb_i) | misalign_stall | halt_if | (~pc_valid_i) | (jump_in_id_o == `BRANCH_COND); + stall_id_o = instr_ack_stall | load_stall | jr_stall | (~lsu_ready_ex_i) | (~lsu_ready_wb_i) | misalign_stall | halt_id; + stall_ex_o = instr_ack_stall | (~lsu_ready_ex_i) | (~lsu_ready_wb_i) | dbg_stall_i; + stall_wb_o = (~lsu_ready_wb_i) | dbg_stall_i; end diff --git a/id_stage.sv b/id_stage.sv index eeae970b..37c7c25b 100644 --- a/id_stage.sv +++ b/id_stage.sv @@ -108,8 +108,9 @@ module id_stage output logic [1:0] data_reg_offset_ex_o, output logic data_misaligned_ex_o, output logic data_req_ex_o, - input logic data_ack_i, // Grant from data memory - input logic data_rvalid_i, + + input logic lsu_ready_ex_i, + input logic lsu_ready_wb_i, // Interrupt signals input logic irq_i, @@ -575,9 +576,10 @@ module id_stage .data_sign_extension_o ( data_sign_ext_id ), .data_reg_offset_o ( data_reg_offset_id ), .data_req_o ( data_req_id ), - .data_ack_i ( data_ack_i ), .data_req_ex_i ( data_req_ex_o ), - .data_rvalid_i ( data_rvalid_i ), + + .lsu_ready_ex_i ( lsu_ready_ex_i ), + .lsu_ready_wb_i ( lsu_ready_wb_i ), // hwloop signals .hwloop_we_o ( hwloop_we ), diff --git a/load_store_unit.sv b/load_store_unit.sv index 9bb28520..03e27106 100644 --- a/load_store_unit.sv +++ b/load_store_unit.sv @@ -5,6 +5,7 @@ // Engineer: Igor Loi - igor.loi@unibo.it // // // // Additional contributions by: // +// Andreas Traber - atraber@iis.ee.ethz.ch // // // // // // Create Date: 01/07/2014 // @@ -42,7 +43,6 @@ module load_store_unit output logic [31:0] data_rdata_ex_o, // requested data -> to ex stage input logic data_req_ex_i, // data request -> from ex stage - output logic data_ack_int_o, // data ack -> to controller input logic [31:0] operand_a_ex_i, // operand a from RF for address -> from ex stage input logic [31:0] operand_b_ex_i, // operand b from RF for address -> from ex stage input logic addr_useincr_ex_i, // use a + b or just a for address -> from ex stage @@ -61,7 +61,10 @@ module load_store_unit input logic data_rvalid_i, input logic data_gnt_i, - // stall signal + // stall signal + output logic lsu_ready_ex_o, // LSU ready for new data in EX stage + output logic lsu_ready_wb_o, // LSU ready for new data in WB stage + input logic ex_stall_i ); @@ -74,20 +77,14 @@ module load_store_unit logic [1:0] wdata_offset; // mux control for data to be written to memory - // signals for tcdm contention - logic [3:0] data_be, data_be_q; - logic [31:0] data_wdata, data_wdata_q; - logic data_we_q; - logic [31:0] data_addr_q; + logic [3:0] data_be; + logic [31:0] data_wdata; logic misaligned_st; // high if we are currently performing the second part of a misaligned store - logic misaligned_st_q; // register for misaligned_st - logic request_entered; - enum logic [2:0] { IDLE, WAIT_GNT, PENDING_W_EX_STALL_2, PENDING_W_EX_STALL_1, PENDING_WO_EX_STALL} CS, NS; + enum logic [1:0] { IDLE, WAIT_RVALID, WAIT_RVALID_EX_STALL, IDLE_EX_STALL } CS, NS; - logic latch_rdata; logic [31:0] rdata_q; ///////////////////////////////// BE generation //////////////////////////////// @@ -169,7 +166,7 @@ module load_store_unit rdata_offset_q <= '0; data_sign_ext_q <= '0; end - else if (request_entered == 1'b1) // request entered FSM + else if (data_gnt_i == 1'b1) // request was granted, we wait for rvalid and can continue to WB begin data_type_q <= data_type_ex_i; rdata_offset_q <= data_addr_int[1:0]; @@ -177,39 +174,6 @@ module load_store_unit end end - // pipeline gnt signal - always_ff @(posedge clk, negedge rst_n) - begin - if(rst_n == 1'b0) - begin - data_ack_int_o <= 1'b0; - end - else - begin - data_ack_int_o <= ~((data_req_o == 1'b1) & (data_gnt_i == 1'b0)); - end - end - - // FF for not accepted requests - always_ff @(posedge clk, negedge rst_n) - begin - if(rst_n == 1'b0) - begin - data_be_q <= '0; - data_addr_q <= '0; - data_we_q <= '0; - data_wdata_q <= '0; - misaligned_st_q <= 1'b0; - end - else if ((data_req_o == 1'b1) & (data_gnt_i == 1'b0)) // request was not granted - begin - data_be_q <= data_be_o; - data_addr_q <= data_addr_o; - data_we_q <= data_we_o; - data_wdata_q <= data_wdata_o; - misaligned_st_q <= misaligned_st; - end - end //////////////////////////////////////////////////////////////////////// // ____ _ _____ _ _ // @@ -335,7 +299,7 @@ module load_store_unit begin CS <= NS; - if(latch_rdata) + if(data_rvalid_i) begin // if we have detected a misaligned access, and we are // currently doing the first part of this access, then @@ -351,133 +315,112 @@ module load_store_unit end // output to register file - assign data_rdata_ex_o = (latch_rdata == 1'b1) ? data_rdata_ext : rdata_q; + assign data_rdata_ex_o = (data_rvalid_i == 1'b1) ? data_rdata_ext : rdata_q; + assign data_addr_o = data_addr_int; + assign data_wdata_o = data_wdata; + assign data_we_o = data_we_ex_i; + assign data_be_o = data_be; + + assign misaligned_st = data_misaligned_ex_i; // FSM always_comb begin + NS = CS; + data_req_o = 1'b0; - data_we_o = 1'b0; - data_addr_o = data_addr_int; - data_wdata_o = data_wdata; - data_be_o = data_be; - misaligned_st = data_misaligned_ex_i; - latch_rdata = 1'b0; - request_entered = 1'b0; + + lsu_ready_ex_o = 1'b1; + lsu_ready_wb_o = 1'b1; case(CS) + // starts from not active and stays in IDLE until request was granted IDLE: begin - data_req_o = data_req_ex_i; - data_we_o = data_we_ex_i; + data_req_o = data_req_ex_i; - if(data_req_ex_i) - begin - request_entered = 1'b1; + if(data_req_ex_i) begin + lsu_ready_ex_o = 1'b0; + + if(data_gnt_i) begin + lsu_ready_ex_o = 1'b1; - if(data_gnt_i) - begin if(ex_stall_i) - NS = PENDING_W_EX_STALL_1; + NS = WAIT_RVALID_EX_STALL; else - NS = PENDING_WO_EX_STALL; - end - else - begin - if(ex_stall_i) - NS = IDLE; - else - begin - NS = WAIT_GNT; - end + NS = WAIT_RVALID; end end - else - NS = IDLE; end //~ IDLE - WAIT_GNT: + // wait for rvalid in WB stage and send a new request if there is any + WAIT_RVALID: begin - data_req_o = 1'b1; - data_we_o = data_we_q; + lsu_ready_wb_o = 1'b0; - data_addr_o = data_addr_q; - data_be_o = data_be_q; - data_wdata_o = data_wdata_q; - misaligned_st = misaligned_st_q; + data_req_o = data_req_ex_i; - if(data_gnt_i) - begin - NS = PENDING_WO_EX_STALL; + if (data_rvalid_i) begin + // we don't have to wait for anything here as we are the only stall + // source for the WB stage + lsu_ready_wb_o = 1'b1; end - else - begin - NS = WAIT_GNT; - end - end // case: WAIT_GNT - PENDING_WO_EX_STALL: - begin - latch_rdata = ~data_we_o; + if(data_req_ex_i) begin + lsu_ready_ex_o = 1'b0; - data_req_o = data_req_ex_i; - data_we_o = data_we_ex_i; + if(data_gnt_i) begin + lsu_ready_ex_o = 1'b1; - if(data_req_ex_i) - begin - request_entered = 1'b1; - - if(data_gnt_i) - begin if(ex_stall_i) - NS = PENDING_W_EX_STALL_1; + NS = WAIT_RVALID_EX_STALL; else - NS = PENDING_WO_EX_STALL; + NS = WAIT_RVALID; end - else - begin - if(ex_stall_i) - NS = IDLE; - else - NS = WAIT_GNT; + end else begin + // no request, so go to IDLE + NS = IDLE; + end + end + + // wait for rvalid while still in EX stage + // we end up here when there was an EX stall, so in this cycle we just + // wait and don't send new requests + WAIT_RVALID_EX_STALL: + begin + data_req_o = 1'b0; + + if (data_rvalid_i) begin + if (ex_stall_i) begin + // we have to wait until ex_stall is deasserted + NS = IDLE_EX_STALL; + end else begin + // we are done and can go back to idle + // the data is safely stored already + NS = IDLE; end + end else begin + // we didn't yet receive the rvalid, so we check the ex_stall + // signal. If we are no longer stalled we can change to the "normal" + // WAIT_RVALID state + if (~ex_stall_i) + NS = WAIT_RVALID; end - else - NS = IDLE; - end //~PENDING_WO_EX_STALL + end - PENDING_W_EX_STALL_1 : + IDLE_EX_STALL: begin - data_req_o = 1'b0; - - latch_rdata = ~data_we_o; - - if(ex_stall_i) - begin - NS = PENDING_W_EX_STALL_2; - end - else - begin + // wait for us to be unstalled and then change back to IDLE state + if (~ex_stall_i) begin NS = IDLE; end - end //~ PENDING_W_EX_STALL_1 + end - PENDING_W_EX_STALL_2 : - begin - if(ex_stall_i) - begin - NS = PENDING_W_EX_STALL_2; - end - else - begin - NS = IDLE; - end - end //~ PENDING_W_EX_STALL_2 - - default : - begin + default: begin NS = IDLE; + + data_req_o = 1'b0; end endcase end diff --git a/riscv_core.sv b/riscv_core.sv index 5baad467..ccd11be7 100644 --- a/riscv_core.sv +++ b/riscv_core.sv @@ -166,7 +166,9 @@ module riscv_core logic [1:0] data_reg_offset_ex; logic data_req_ex; logic data_misaligned_ex; - logic data_ack_int; + + logic lsu_ready_ex; + logic lsu_ready_wb; // Signals between instruction core interface and pipe (if and id stages) logic instr_req_int; // Id stage asserts a req to instruction core interface @@ -361,8 +363,9 @@ module riscv_core .data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit .data_req_ex_o ( data_req_ex ), // to load store unit .data_misaligned_ex_o ( data_misaligned_ex ), // to load store unit - .data_ack_i ( data_ack_int ), // from load store unit - .data_rvalid_i ( data_r_valid_i ), + + .lsu_ready_ex_i ( lsu_ready_ex ), + .lsu_ready_wb_i ( lsu_ready_wb ), // Interrupt Signals .irq_i ( irq_i ), // incoming interrupts @@ -482,7 +485,6 @@ module riscv_core .data_rdata_ex_o ( regfile_wdata ), .data_req_ex_i ( data_req_ex ), - .data_ack_int_o ( data_ack_int ), // ack used in controller to stall .operand_a_ex_i ( alu_operand_a_ex ), .operand_b_ex_i ( alu_operand_b_ex ), .addr_useincr_ex_i ( useincr_addr_ex ), @@ -492,14 +494,17 @@ module riscv_core //output to data memory .data_req_o ( data_req_o ), + .data_gnt_i ( data_gnt_i ), + .data_rvalid_i ( data_r_valid_i ), + .data_addr_o ( data_addr_o ), .data_we_o ( data_we_o ), - .data_be_o ( data_be_o ), .data_wdata_o ( data_wdata_o ), .data_rdata_i ( data_rdata_i ), - .data_rvalid_i ( data_r_valid_i ), - .data_gnt_i ( data_gnt_i ), + + .lsu_ready_ex_o ( lsu_ready_ex ), + .lsu_ready_wb_o ( lsu_ready_wb ), .ex_stall_i ( stall_ex ) );