RVFI based on core state (#151, fix #147)

The RVFI implementation make use of signals from the decoder and
controller to detect the state of the processor.
Especially the signal for a new and retired instruction.
This commit is contained in:
Tobias Wölfel 2019-07-15 15:45:14 +02:00 committed by Tobias Woelfel
parent b8e1f552b4
commit d059979af6
4 changed files with 92 additions and 85 deletions

View file

@ -101,8 +101,6 @@ module ibex_controller (
input logic stall_jump_i,
input logic stall_branch_i,
output logic id_out_valid_o, // ID stage has valid output
// performance monitors
output logic perf_jump_o, // we are executing a jump
// instruction (j, jr, jal, jalr)
@ -533,9 +531,6 @@ module ibex_controller (
// multicycle instr causes an exception for example
assign instr_valid_clear_o = ~stall | halt_id;
// signal that ID stage has valid output
assign id_out_valid_o = ~stall & instr_valid_i & ~special_req;
// update registers
always_ff @(posedge clk_i or negedge rst_ni) begin : update_regs
if (!rst_ni) begin

View file

@ -180,8 +180,6 @@ module ibex_core #(
logic id_in_ready;
logic ex_valid;
logic if_id_pipe_reg_we;
logic lsu_data_valid;
// Signals between instruction core interface and pipe (if and id stages)
@ -216,13 +214,11 @@ module ibex_core #(
logic perf_store;
// for RVFI
logic id_out_valid, unused_id_out_valid; // ID stage has valid output data
logic illegal_insn_id, unused_illegal_insn_id; // ID stage sees an illegal instruction
// RISC-V Formal Interface signals
`ifdef RVFI
logic [31:0] rvfi_insn_opcode;
logic rvfi_valid_int;
logic [31:0] rvfi_insn_id;
logic [4:0] rvfi_rs1_addr_id;
logic [4:0] rvfi_rs2_addr_id;
logic [31:0] rvfi_rs1_data_d;
@ -240,11 +236,6 @@ module ibex_core #(
logic rvfi_rd_we_id;
logic rvfi_insn_new_d;
logic rvfi_insn_new_q;
logic rvfi_insn_clear_d;
logic rvfi_insn_clear_q;
logic rvfi_changed_insn;
logic rvfi_changed_pc;
logic [31:0] rvfi_pc_id_q;
logic [3:0] rvfi_mem_mask_int;
logic [31:0] rvfi_mem_rdata_d;
logic [31:0] rvfi_mem_rdata_q;
@ -336,7 +327,6 @@ module ibex_core #(
// pipeline stalls
.id_in_ready_i ( id_in_ready ),
.if_id_pipe_reg_we_o ( if_id_pipe_reg_we ),
.if_busy_o ( if_busy ),
.perf_imiss_o ( perf_imiss )
@ -389,8 +379,6 @@ module ibex_core #(
.ex_valid_i ( ex_valid ),
.lsu_valid_i ( lsu_data_valid ),
.id_out_valid_o ( id_out_valid ),
.alu_operator_ex_o ( alu_operator_ex ),
.alu_operand_a_ex_o ( alu_operand_a_ex ),
.alu_operand_b_ex_o ( alu_operand_b_ex ),
@ -465,7 +453,6 @@ module ibex_core #(
);
// for RVFI only
assign unused_id_out_valid = id_out_valid;
assign unused_illegal_insn_id = illegal_insn_id;
ibex_ex_block #(
@ -611,33 +598,55 @@ module ibex_core #(
);
`ifdef RVFI
always_ff @(posedge clk) begin
rvfi_halt <= '0;
rvfi_trap <= '0;
rvfi_intr <= irq_ack_o;
rvfi_order <= rst_ni ? rvfi_order + rvfi_valid : '0;
rvfi_insn <= rvfi_insn_opcode;
rvfi_mode <= PRIV_LVL_M;
rvfi_rs1_addr <= rvfi_rs1_addr_id;
rvfi_rs2_addr <= rvfi_rs2_addr_id;
rvfi_pc_rdata <= pc_id;
rvfi_mem_rmask <= rvfi_mem_mask_int;
rvfi_mem_wmask <= data_we_o ? rvfi_mem_mask_int : 4'b0000;
rvfi_valid <= rvfi_valid_int;
rvfi_rs1_rdata <= rvfi_rs1_data_d;
rvfi_rs2_rdata <= rvfi_rs2_data_d;
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_halt <= '0;
rvfi_trap <= '0;
rvfi_intr <= '0;
rvfi_order <= '0;
rvfi_insn <= '0;
rvfi_mode <= '0;
rvfi_rs1_addr <= '0;
rvfi_rs2_addr <= '0;
rvfi_pc_rdata <= '0;
rvfi_pc_wdata <= '0;
rvfi_mem_rmask <= '0;
rvfi_mem_wmask <= '0;
rvfi_valid <= '0;
rvfi_rs1_rdata <= '0;
rvfi_rs2_rdata <= '0;
rvfi_rd_wdata <= '0;
rvfi_rd_addr <= '0;
rvfi_mem_rdata <= '0;
rvfi_mem_wdata <= '0;
rvfi_mem_addr <= '0;
end else begin
rvfi_halt <= '0;
rvfi_trap <= illegal_insn_id;
rvfi_intr <= irq_ack_o;
rvfi_order <= rvfi_order + rvfi_valid;
rvfi_insn <= rvfi_insn_id;
rvfi_mode <= PRIV_LVL_M; // TODO: Update for user mode support
rvfi_rs1_addr <= rvfi_rs1_addr_id;
rvfi_rs2_addr <= rvfi_rs2_addr_id;
rvfi_pc_rdata <= pc_id;
rvfi_pc_wdata <= pc_if;
rvfi_mem_rmask <= rvfi_mem_mask_int;
rvfi_mem_wmask <= data_we_o ? rvfi_mem_mask_int : 4'b0000;
rvfi_valid <= instr_ret;
rvfi_rs1_rdata <= rvfi_rs1_data_d;
rvfi_rs2_rdata <= rvfi_rs2_data_d;
rvfi_rd_wdata <= rvfi_rd_wdata_d;
rvfi_rd_addr <= rvfi_rd_addr_d;
rvfi_mem_rdata <= rvfi_mem_rdata_d;
rvfi_mem_wdata <= rvfi_mem_wdata_d;
rvfi_mem_addr <= rvfi_mem_addr_d;
end
end
assign rvfi_pc_wdata = pc_id;
assign rvfi_rd_wdata = rvfi_rd_wdata_q;
assign rvfi_rd_addr = rvfi_rd_addr_q;
assign rvfi_mem_rdata = rvfi_mem_rdata_q;
assign rvfi_mem_wdata = rvfi_mem_wdata_q;
assign rvfi_mem_addr = rvfi_mem_addr_q;
// Keep the mem data stable for each instruction cycle
always_comb begin
if (rvfi_insn_new_d) begin
if (rvfi_insn_new_d && lsu_data_valid) begin
rvfi_mem_addr_d = alu_adder_result_ex;
rvfi_mem_rdata_d = regfile_wdata_lsu;
rvfi_mem_wdata_d = data_wdata_ex;
@ -647,10 +656,16 @@ module ibex_core #(
rvfi_mem_wdata_d = rvfi_mem_wdata_q;
end
end
always_ff @(posedge clk) begin
rvfi_mem_addr_q <= rvfi_mem_addr_d;
rvfi_mem_rdata_q <= rvfi_mem_rdata_d;
rvfi_mem_wdata_q <= rvfi_mem_wdata_d;
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_mem_addr_q <= '0;
rvfi_mem_rdata_q <= '0;
rvfi_mem_wdata_q <= '0;
end else begin
rvfi_mem_addr_q <= rvfi_mem_addr_d;
rvfi_mem_rdata_q <= rvfi_mem_rdata_d;
rvfi_mem_wdata_q <= rvfi_mem_wdata_d;
end
end
// Byte enable based on data type
always_comb begin
@ -662,19 +677,17 @@ module ibex_core #(
endcase
end
assign rvfi_valid_int = id_out_valid && if_id_pipe_reg_we && !illegal_c_insn_id;
always_comb begin
if (instr_is_compressed_id) begin
rvfi_insn_opcode = {16'b0, instr_rdata_c_id};
rvfi_insn_id = {16'b0, instr_rdata_c_id};
end else begin
rvfi_insn_opcode = instr_rdata_id;
rvfi_insn_id = instr_rdata_id;
end
end
// Source register data are kept stable for each instruction cycle
always_comb begin
if (rvfi_insn_new_d) begin
if (instr_new_id) begin
rvfi_rs1_data_d = rvfi_rs1_data_id;
rvfi_rs2_data_d = rvfi_rs2_data_id;
end else begin
@ -682,9 +695,14 @@ module ibex_core #(
rvfi_rs2_data_d = rvfi_rs2_data_q;
end
end
always_ff @(posedge clk) begin
rvfi_rs1_data_q <= rvfi_rs1_data_d;
rvfi_rs2_data_q <= rvfi_rs2_data_d;
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_rs1_data_q <= '0;
rvfi_rs2_data_q <= '0;
end else begin
rvfi_rs1_data_q <= rvfi_rs1_data_d;
rvfi_rs2_data_q <= rvfi_rs2_data_d;
end
end
// RD write register is refreshed only once per cycle and
@ -694,7 +712,6 @@ module ibex_core #(
if (!rvfi_rd_we_id) begin
rvfi_rd_addr_d = '0;
rvfi_rd_wdata_d = '0;
rvfi_insn_clear_d = 1'b0;
end else begin
rvfi_rd_addr_d = rvfi_rd_addr_id;
if (!rvfi_rd_addr_id) begin
@ -702,43 +719,41 @@ module ibex_core #(
end else begin
rvfi_rd_wdata_d = rvfi_rd_wdata_id;
end
rvfi_insn_clear_d = 1'b1;
end
end else begin
rvfi_rd_addr_d = rvfi_rd_addr_q;
rvfi_rd_wdata_d = rvfi_rd_wdata_q;
rvfi_insn_clear_d = 1'b0;
end
end
always_ff @(posedge clk) begin
rvfi_insn_clear_q <= rvfi_insn_clear_d;
rvfi_rd_addr_q <= rvfi_rd_addr_d;
rvfi_rd_wdata_q <= rvfi_rd_wdata_d;
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_rd_addr_q <= '0;
rvfi_rd_wdata_q <= '0;
end else begin
rvfi_rd_addr_q <= rvfi_rd_addr_d;
rvfi_rd_wdata_q <= rvfi_rd_wdata_d;
end
end
// New instruction signalling based on changes of
// instruction data, program counter and valid signal
always_comb begin
if (rvfi_changed_insn || rvfi_changed_pc || rvfi_valid ) begin
if (instr_new_id) begin
rvfi_insn_new_d = 1'b1;
end else if (rvfi_insn_clear_q) begin
rvfi_insn_new_d = 1'b0;
end else begin
rvfi_insn_new_d = rvfi_insn_new_q;
end
end
always_ff @(posedge clk) begin
rvfi_insn_new_q <= rvfi_insn_new_d;
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_insn_new_q <= 1'b0;
end else begin
if (instr_ret) begin
rvfi_insn_new_q <= 1'b0;
end else begin
rvfi_insn_new_q <= rvfi_insn_new_d;
end
end
end
// Change in instruction code
assign rvfi_changed_insn = rvfi_insn != rvfi_insn_opcode;
// Change in program counter
always_ff @(posedge clk) begin
rvfi_pc_id_q <= pc_id;
end
assign rvfi_changed_pc = rvfi_pc_id_q != pc_id;
`endif
endmodule

View file

@ -70,8 +70,6 @@ module ibex_id_stage #(
// Stalls
input logic ex_valid_i, // EX stage has valid output
input logic lsu_valid_i, // LSU has valid output, or is done
output logic id_out_valid_o, // ID stage is done
// ALU
output ibex_defines::alu_op_e alu_operator_ex_o,
output logic [31:0] alu_operand_a_ex_o,
@ -480,8 +478,6 @@ module ibex_id_stage #(
.stall_jump_i ( stall_jump ),
.stall_branch_i ( stall_branch ),
.id_out_valid_o ( id_out_valid_o ),
// Performance Counters
.perf_jump_o ( perf_jump_o ),
.perf_tbranch_o ( perf_tbranch_o )

View file

@ -77,7 +77,6 @@ module ibex_if_stage #(
// pipeline stall
input logic id_in_ready_i, // ID stage is ready for new instr
output logic if_id_pipe_reg_we_o, // IF-ID pipeline reg write enable
// misc signals
output logic if_busy_o, // IF stage is busy fetching instr
@ -104,6 +103,8 @@ module ibex_if_stage #(
logic [5:0] irq_id;
logic unused_irq_bit;
logic if_id_pipe_reg_we; // IF-ID pipeline reg write enable
logic [7:0] unused_boot_addr;
assign unused_boot_addr = boot_addr_i[7:0];
@ -193,7 +194,7 @@ module ibex_if_stage #(
if (fetch_valid) begin
have_instr = 1'b1;
if (req_i && if_id_pipe_reg_we_o) begin
if (req_i && if_id_pipe_reg_we) begin
fetch_ready = 1'b1;
offset_in_init_d = 1'b0;
end
@ -231,7 +232,7 @@ module ibex_if_stage #(
);
// IF-ID pipeline registers, frozen when the ID stage is stalled
assign if_id_pipe_reg_we_o = have_instr & id_in_ready_i;
assign if_id_pipe_reg_we = have_instr & id_in_ready_i;
always_ff @(posedge clk_i or negedge rst_ni) begin : if_id_pipeline_regs
if (!rst_ni) begin
@ -243,8 +244,8 @@ module ibex_if_stage #(
illegal_c_insn_id_o <= 1'b0;
pc_id_o <= '0;
end else begin
instr_new_id_o <= if_id_pipe_reg_we_o;
if (if_id_pipe_reg_we_o) begin
instr_new_id_o <= if_id_pipe_reg_we;
if (if_id_pipe_reg_we) begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
instr_rdata_c_id_o <= fetch_rdata[15:0];