From 2ef1c1b1fca419354920c5487293bc605294904e Mon Sep 17 00:00:00 2001 From: Guillaume Chauvon <94678394+Gchauvon@users.noreply.github.com> Date: Mon, 3 Feb 2025 13:40:02 +0100 Subject: [PATCH] Update ID stage to support ZCMP, ZCMT and CVXIF with Superscalar (#2756) Add support for Superscalar with ZCMP, ZCMT and CVXIF. ZCMP decoder, ZCMT decoder and CVXIF interface driver are using port 0. Standard RVC and 32 bits instruction can take port 0 or 1. --- core/commit_stage.sv | 15 +- core/cvxif_compressed_if_driver.sv | 60 ++-- core/cvxif_fu.sv | 13 +- core/id_stage.sv | 366 +++++++++++++---------- core/include/config_pkg.sv | 2 - core/include/cv32a60x_config_pkg.sv | 4 +- core/issue_stage.sv | 10 +- core/macro_decoder.sv | 6 +- core/zcmt_decoder.sv | 4 +- verif/tb/uvmt/cva6_tb_wrapper.sv | 4 +- verif/tests/custom/cv_xif/cvxif_macros.h | 76 ++++- 11 files changed, 320 insertions(+), 240 deletions(-) diff --git a/core/commit_stage.sv b/core/commit_stage.sv index b717f785aa..d41c6b5a30 100644 --- a/core/commit_stage.sv +++ b/core/commit_stage.sv @@ -301,10 +301,10 @@ module commit_stage end if (CVA6Cfg.NrCommitPorts > 1) begin - - commit_ack_o[1] = 1'b0; - we_gpr_o[1] = 1'b0; - wdata_o[1] = commit_instr_i[1].result; + commit_macro_ack[1] = 1'b0; + commit_ack_o[1] = 1'b0; + we_gpr_o[1] = 1'b0; + wdata_o[1] = commit_instr_i[1].result; // ----------------- // Commit Port 2 @@ -350,10 +350,9 @@ module commit_stage end end if (CVA6Cfg.RVZCMP) begin - if (CVA6Cfg.NrCommitPorts > 1) - commit_macro_ack_o = (commit_instr_i[0].is_macro_instr || commit_instr_i[1].is_macro_instr) ? commit_macro_ack : commit_ack_o; - else - commit_macro_ack_o = (commit_instr_i[0].is_macro_instr) ? commit_macro_ack : commit_ack_o; + for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin + commit_macro_ack_o[i] = commit_instr_i[i].is_macro_instr ? commit_macro_ack[i] : commit_ack_o[i]; + end end else commit_macro_ack_o = commit_ack_o; end diff --git a/core/cvxif_compressed_if_driver.sv b/core/cvxif_compressed_if_driver.sv index 26fdeab85b..ab759f8e4c 100644 --- a/core/cvxif_compressed_if_driver.sv +++ b/core/cvxif_compressed_if_driver.sv @@ -16,24 +16,24 @@ module cvxif_compressed_if_driver #( input logic clk_i, // Asynchronous reset active low - SUBSYSTEM input logic rst_ni, + input logic flush_i, // CVA6 Hart id input logic [CVA6Cfg.XLEN-1:0] hart_id_i, - input logic [CVA6Cfg.NrIssuePorts-1:0] is_compressed_i, - input logic [CVA6Cfg.NrIssuePorts-1:0] is_illegal_i, - input logic [CVA6Cfg.NrIssuePorts-1:0] instruction_valid_i, - input logic [CVA6Cfg.NrIssuePorts-1:0][31:0] instruction_i, + input logic is_compressed_i, + input logic is_illegal_i, + input logic [31:0] instruction_i, - output logic [CVA6Cfg.NrIssuePorts-1:0] is_compressed_o, - output logic [CVA6Cfg.NrIssuePorts-1:0] is_illegal_o, - output logic [CVA6Cfg.NrIssuePorts-1:0][31:0] instruction_o, - input logic stall_i, - output logic [CVA6Cfg.NrIssuePorts-1:0] stall_o, + output logic is_compressed_o, + output logic is_illegal_o, + output logic [31:0] instruction_o, + input logic stall_i, + output logic stall_o, // CVXIF Compressed interface - input logic compressed_ready_i, - input x_compressed_resp_t compressed_resp_i, - output logic compressed_valid_o, - output x_compressed_req_t compressed_req_o + input logic compressed_ready_i, + input x_compressed_resp_t compressed_resp_i, + output logic compressed_valid_o, + output x_compressed_req_t compressed_req_o ); @@ -44,32 +44,22 @@ module cvxif_compressed_if_driver #( compressed_valid_o = 1'b0; compressed_req_o.instr = '0; compressed_req_o.hartid = hart_id_i; - stall_o[0] = stall_i; - stall_o[1] = 1'b0; - if (is_illegal_i[0]) begin - compressed_valid_o = is_illegal_i[0] && instruction_valid_i[0]; - compressed_req_o.instr = instruction_i[0][15:0]; - is_illegal_o[0] = ~compressed_resp_i.accept; - instruction_o[0] = compressed_resp_i.accept ? compressed_resp_i.instr : instruction_i[0]; - is_compressed_o[0] = compressed_resp_i.accept ? 1'b0 : is_compressed_i[0]; + stall_o = stall_i; + if (is_illegal_i) begin + compressed_valid_o = is_illegal_i; + compressed_req_o.instr = instruction_i[15:0]; + is_illegal_o = ~compressed_resp_i.accept; + instruction_o = compressed_resp_i.accept ? compressed_resp_i.instr : instruction_i; + is_compressed_o = compressed_resp_i.accept ? 1'b0 : is_compressed_i; if (~stall_i) begin // Propagate stall from macro decoder or wait for compressed ready if compressed transaction is happening. - // Stall if both instruction are illegal - stall_o[0] = (compressed_valid_o && ~compressed_ready_i); - if (CVA6Cfg.SuperscalarEn) begin - stall_o[1] = is_illegal_i[1]; - end + stall_o = (compressed_valid_o && ~compressed_ready_i); end end - if (CVA6Cfg.SuperscalarEn) begin - if (~is_illegal_i[0] && is_illegal_i[1]) begin // 2nd instruction is illegal - compressed_valid_o = is_illegal_i[1] && instruction_valid_i[1]; - compressed_req_o.instr = instruction_i[1][15:0]; - is_illegal_o[1] = ~compressed_resp_i.accept; - instruction_o[1] = compressed_resp_i.accept ? compressed_resp_i.instr : instruction_i[1]; - is_compressed_o[1] = compressed_resp_i.accept ? 1'b0 : is_compressed_i[1]; - stall_o[1] = (compressed_valid_o && ~compressed_ready_i); - end + if (flush_i) begin + compressed_valid_o = 1'b0; + compressed_req_o.instr = '0; + compressed_req_o.hartid = hart_id_i; end end diff --git a/core/cvxif_fu.sv b/core/cvxif_fu.sv index b191fbff4e..cf6ee15215 100644 --- a/core/cvxif_fu.sv +++ b/core/cvxif_fu.sv @@ -56,7 +56,7 @@ module cvxif_fu assign x_ready_o = 1'b1; // Readyness of cvxif_fu is determined in issue stage by CVXIF issue interface // Result signals - assign x_valid_o = x_illegal_i && x_valid_i ? 1'b1 : result_valid_i; + assign x_valid_o = x_illegal_i || result_valid_i; assign x_result_o = result_i.data; assign x_trans_id_o = x_illegal_i ? x_trans_id_i : result_i.id; assign x_we_o = result_i.we; @@ -64,13 +64,10 @@ module cvxif_fu // Handling of illegal instruction exception always_comb begin - x_exception_o = '0; // No exception in this interface - if (x_illegal_i && x_valid_i) begin - x_exception_o.valid = '1; - x_exception_o.cause = riscv::ILLEGAL_INSTR; - if (CVA6Cfg.TvalEn) - x_exception_o.tval = x_off_instr_i; // TODO Optimization : Set exception in IRO. - end + x_exception_o.valid = x_illegal_i; + x_exception_o.cause = x_illegal_i ? riscv::ILLEGAL_INSTR : '0; + if (CVA6Cfg.TvalEn) + x_exception_o.tval = x_off_instr_i; // TODO Optimization : Set exception in IRO. end endmodule diff --git a/core/id_stage.sv b/core/id_stage.sv index 6500c7ba18..d37554db4f 100644 --- a/core/id_stage.sv +++ b/core/id_stage.sv @@ -86,7 +86,7 @@ module id_stage #( // CVXIF Compressed interface input logic [CVA6Cfg.XLEN-1:0] hart_id_i, input logic compressed_ready_i, - //JVT + //JVT input jvt_t jvt_i, input x_compressed_resp_t compressed_resp_i, output logic compressed_valid_o, @@ -104,30 +104,52 @@ module id_stage #( logic is_ctrl_flow; } issue_struct_t; issue_struct_t [CVA6Cfg.NrIssuePorts-1:0] issue_n, issue_q; + // stall required for ZCMP ZCMT CVXIF + logic [CVA6Cfg.NrIssuePorts-1:0] stall_instr_fetch; logic [CVA6Cfg.NrIssuePorts-1:0] is_control_flow_instr; scoreboard_entry_t [CVA6Cfg.NrIssuePorts-1:0] decoded_instruction; + logic [CVA6Cfg.NrIssuePorts-1:0] decoded_instruction_valid; logic [CVA6Cfg.NrIssuePorts-1:0][31:0] orig_instr; - logic [CVA6Cfg.NrIssuePorts-1:0] is_illegal; - logic [CVA6Cfg.NrIssuePorts-1:0] is_illegal_cmp; - logic [CVA6Cfg.NrIssuePorts-1:0] is_illegal_cvxif, is_illegal_cvxif_zcmp, is_illegal_cvxif_zcmt; - logic [CVA6Cfg.NrIssuePorts-1:0][31:0] instruction; - logic [CVA6Cfg.NrIssuePorts-1:0][31:0] compressed_instr; - logic [CVA6Cfg.NrIssuePorts-1:0][31:0] - instruction_cvxif, instruction_cvxif_zcmp, instruction_cvxif_zcmt; - logic [CVA6Cfg.NrIssuePorts-1:0] is_compressed; - logic [CVA6Cfg.NrIssuePorts-1:0] is_compressed_cmp; - logic [CVA6Cfg.NrIssuePorts-1:0] - is_compressed_cvxif, is_compressed_cvxif_zcmp, is_compressed_cvxif_zcmt; + // Compressed decoder signals + logic [CVA6Cfg.NrIssuePorts-1:0] is_illegal_rvc; + logic [CVA6Cfg.NrIssuePorts-1:0][31:0] instruction_rvc; + logic [CVA6Cfg.NrIssuePorts-1:0] is_compressed_rvc; + logic [CVA6Cfg.NrIssuePorts-1:0] is_zcmt_instr; + logic [CVA6Cfg.NrIssuePorts-1:0] is_macro_instr; + + // CVXIF compressed interface driver signals + // Inputs + logic is_illegal_cvxif_i; + logic [ 31:0] instruction_cvxif_i; + logic is_compressed_cvxif_i; + logic stall_macro_deco; + // Outputs + logic is_illegal_cvxif_o; + logic [ 31:0] instruction_cvxif_o; + logic is_compressed_cvxif_o; + + // ZCMP decoder signals + logic is_illegal_zcmp; + logic [ 31:0] instruction_zcmp; + logic is_compressed_zcmp; + logic stall_macro_deco_zcmp; + logic is_last_macro_instr; + logic is_double_rd_macro_instr; + + // ZCMT decoder signals + logic is_illegal_zcmt; + logic [ 31:0] instruction_zcmt; + logic is_compressed_zcmt; + logic stall_macro_deco_zcmt; + logic [ CVA6Cfg.XLEN-1:0] jump_address; + + // Decoder signals + logic [CVA6Cfg.NrIssuePorts-1:0] is_illegal_deco; + logic [CVA6Cfg.NrIssuePorts-1:0][31:0] instruction_deco; + logic [CVA6Cfg.NrIssuePorts-1:0] is_compressed_deco; - logic [CVA6Cfg.NrIssuePorts-1:0] is_macro_instr_i; - logic [CVA6Cfg.NrIssuePorts-1:0] stall_instr_fetch; - logic stall_macro_deco, stall_macro_deco_zcmp, stall_macro_deco_zcmt; - logic is_last_macro_instr_o; - logic is_double_rd_macro_instr_o; - logic [CVA6Cfg.NrIssuePorts-1:0] is_zcmt_instr; - logic [ CVA6Cfg.XLEN-1:0] jump_address; if (CVA6Cfg.RVC) begin // --------------------------------------------------------- @@ -138,141 +160,139 @@ module id_stage #( .CVA6Cfg(CVA6Cfg) ) compressed_decoder_i ( .instr_i (fetch_entry_i[i].instruction), - .instr_o (compressed_instr[i]), - .illegal_instr_o (is_illegal[i]), - .is_compressed_o (is_compressed[i]), - .is_macro_instr_o(is_macro_instr_i[i]), + .instr_o (instruction_rvc[i]), + .illegal_instr_o (is_illegal_rvc[i]), + .is_compressed_o (is_compressed_rvc[i]), + .is_macro_instr_o(is_macro_instr[i]), .is_zcmt_instr_o (is_zcmt_instr[i]) ); end - if (CVA6Cfg.RVZCMP || (CVA6Cfg.RVZCMT & ~CVA6Cfg.MmuPresent)) begin //MMU should be off when using ZCMT - //sequencial decoder - if (CVA6Cfg.RVZCMP) begin - macro_decoder #( - .CVA6Cfg(CVA6Cfg) - ) macro_decoder_i ( - .instr_i (compressed_instr[0]), - .is_macro_instr_i (is_macro_instr_i[0]), - .clk_i (clk_i), - .rst_ni (rst_ni), - .instr_o (instruction_cvxif_zcmp), - .illegal_instr_i (is_illegal[0]), - .is_compressed_i (is_compressed[0]), - .issue_ack_i (issue_instr_ack_i[0]), - .illegal_instr_o (is_illegal_cvxif_zcmp), - .is_compressed_o (is_compressed_cvxif_zcmp), - .fetch_stall_o (stall_macro_deco_zcmp), - .is_last_macro_instr_o (is_last_macro_instr_o), - .is_double_rd_macro_instr_o(is_double_rd_macro_instr_o) - ); - end - if (CVA6Cfg.RVZCMT) begin - zcmt_decoder #( - .CVA6Cfg(CVA6Cfg), - .dcache_req_i_t(dcache_req_i_t), - .dcache_req_o_t(dcache_req_o_t), - .jvt_t(jvt_t), - .branchpredict_sbe_t(branchpredict_sbe_t) - ) zcmt_decoder_i ( - .instr_i (compressed_instr[0]), - .pc_i (fetch_entry_i[0].address), - .is_zcmt_instr_i(is_zcmt_instr[0]), - .clk_i (clk_i), - .rst_ni (rst_ni), - .instr_o (instruction_cvxif_zcmt), - .illegal_instr_i(is_illegal[0]), - .is_compressed_i(is_compressed[0]), - .illegal_instr_o(is_illegal_cvxif_zcmt), - .is_compressed_o(is_compressed_cvxif_zcmt), - .fetch_stall_o (stall_macro_deco_zcmt), - .jvt_i (jvt_i), - .req_port_i (dcache_req_ports_i), - .req_port_o (dcache_req_ports_o), - .jump_address_o (jump_address) - ); - end else assign jump_address = '0; - assign instruction_cvxif[0] = is_zcmt_instr[0] ? instruction_cvxif_zcmt : instruction_cvxif_zcmp; - assign is_illegal_cvxif[0] = is_zcmt_instr[0] ? is_illegal_cvxif_zcmt : is_illegal_cvxif_zcmp; - assign is_compressed_cvxif[0] = is_zcmt_instr[0] ? is_compressed_cvxif_zcmt : is_compressed_cvxif_zcmp; - assign stall_macro_deco = is_zcmt_instr[0] ? stall_macro_deco_zcmt : stall_macro_deco_zcmp; + if (CVA6Cfg.SuperscalarEn) begin + assign stall_instr_fetch[1] = is_illegal_rvc[1] || is_macro_instr[1] || is_zcmt_instr[1]; + end - if (CVA6Cfg.SuperscalarEn) begin - assign instruction_cvxif[CVA6Cfg.NrIssuePorts-1] = '0; - assign is_illegal_cvxif[CVA6Cfg.NrIssuePorts-1] = '0; - assign is_compressed_cvxif[CVA6Cfg.NrIssuePorts-1] = '0; - end - cvxif_compressed_if_driver #( + if (CVA6Cfg.RVZCMP) begin + macro_decoder #( + .CVA6Cfg(CVA6Cfg) + ) macro_decoder_i ( + .instr_i (instruction_rvc[0]), + .is_macro_instr_i (is_macro_instr[0]), + .clk_i (clk_i), + .rst_ni (rst_ni), + .instr_o (instruction_zcmp), + .illegal_instr_i (is_illegal_rvc[0]), + .is_compressed_i (is_compressed_rvc[0]), + .issue_ack_i (issue_instr_ack_i[0]), + .illegal_instr_o (is_illegal_zcmp), + .is_compressed_o (is_compressed_zcmp), + .fetch_stall_o (stall_macro_deco_zcmp), + .is_last_macro_instr_o (is_last_macro_instr), + .is_double_rd_macro_instr_o(is_double_rd_macro_instr) + ); + end else begin + assign instruction_zcmp = instruction_rvc; + assign is_illegal_zcmp = is_illegal_rvc; + assign is_compressed_zcmp = is_compressed_rvc; + assign stall_macro_deco_zcmp = '0; + assign is_last_macro_instr = '0; + assign is_double_rd_macro_instr = '0; + end + + if (CVA6Cfg.RVZCMT) begin + zcmt_decoder #( .CVA6Cfg(CVA6Cfg), - .x_compressed_req_t(x_compressed_req_t), - .x_compressed_resp_t(x_compressed_resp_t) - ) i_cvxif_compressed_if_driver_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .hart_id_i (hart_id_i), - .is_compressed_i (is_compressed_cvxif), - .is_illegal_i (is_illegal_cvxif), - .instruction_i (instruction_cvxif), - .instruction_valid_i(fetch_entry_valid_i), - .is_compressed_o (is_compressed_cmp), - .is_illegal_o (is_illegal_cmp), - .instruction_o (instruction), - .stall_i (stall_macro_deco), - .stall_o (stall_instr_fetch), - .compressed_ready_i (compressed_ready_i), - .compressed_resp_i (compressed_resp_i), - .compressed_valid_o (compressed_valid_o), - .compressed_req_o (compressed_req_o) + .dcache_req_i_t(dcache_req_i_t), + .dcache_req_o_t(dcache_req_o_t), + .jvt_t(jvt_t), + .branchpredict_sbe_t(branchpredict_sbe_t) + ) zcmt_decoder_i ( + .instr_i (instruction_rvc[0]), + .pc_i (fetch_entry_i[0].address), + .is_zcmt_instr_i(is_zcmt_instr[0]), + .clk_i (clk_i), + .rst_ni (rst_ni), + .instr_o (instruction_zcmt), + .illegal_instr_i(is_illegal_rvc[0]), + .is_compressed_i(is_compressed_rvc[0]), + .illegal_instr_o(is_illegal_zcmt), + .is_compressed_o(is_compressed_zcmt), + .fetch_stall_o (stall_macro_deco_zcmt), + .jvt_i (jvt_i), + .req_port_i (dcache_req_ports_i), + .req_port_o (dcache_req_ports_o), + .jump_address_o (jump_address) ); end else begin + assign instruction_zcmt = instruction_rvc; + assign is_illegal_zcmt = is_illegal_rvc; + assign is_compressed_zcmt = is_compressed_rvc; + assign stall_macro_deco_zcmt = '0; + assign jump_address = '0; + end + + if (CVA6Cfg.RVZCMT) begin + assign instruction_cvxif_i = is_zcmt_instr[0] ? instruction_zcmt : instruction_zcmp; + assign is_illegal_cvxif_i = is_zcmt_instr[0] ? is_illegal_zcmt : is_illegal_zcmp; + assign is_compressed_cvxif_i = is_zcmt_instr[0] ? is_compressed_zcmt : is_compressed_zcmp; + assign stall_macro_deco = is_zcmt_instr[0] ? stall_macro_deco_zcmt : stall_macro_deco_zcmp; + end else begin // Do not instantiate the mux which is not optimized cross-bondaries + assign instruction_cvxif_i = instruction_zcmp; + assign is_illegal_cvxif_i = is_illegal_zcmp; + assign is_compressed_cvxif_i = is_compressed_zcmp; + assign stall_macro_deco = stall_macro_deco_zcmp; + end + + if (CVA6Cfg.CvxifEn) begin cvxif_compressed_if_driver #( .CVA6Cfg(CVA6Cfg), .x_compressed_req_t(x_compressed_req_t), .x_compressed_resp_t(x_compressed_resp_t) ) i_cvxif_compressed_if_driver_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .hart_id_i (hart_id_i), - .is_compressed_i (is_compressed), - .is_illegal_i (is_illegal), - .instruction_valid_i(fetch_entry_valid_i), - .instruction_i (compressed_instr), - .is_compressed_o (is_compressed_cmp), - .is_illegal_o (is_illegal_cmp), - .instruction_o (instruction), - .stall_i (1'b0), - .stall_o (stall_instr_fetch), - .compressed_ready_i (compressed_ready_i), - .compressed_resp_i (compressed_resp_i), - .compressed_valid_o (compressed_valid_o), - .compressed_req_o (compressed_req_o) + .clk_i (clk_i), + .rst_ni (rst_ni), + .flush_i (flush_i), + .hart_id_i (hart_id_i), + .is_compressed_i (is_compressed_cvxif_i), + .is_illegal_i (is_illegal_cvxif_i), + .instruction_i (instruction_cvxif_i), + .is_compressed_o (is_compressed_cvxif_o), + .is_illegal_o (is_illegal_cvxif_o), + .instruction_o (instruction_cvxif_o), + .stall_i (stall_macro_deco), + .stall_o (stall_instr_fetch[0]), + .compressed_ready_i(compressed_ready_i), + .compressed_resp_i (compressed_resp_i), + .compressed_valid_o(compressed_valid_o), + .compressed_req_o (compressed_req_o) ); - assign is_last_macro_instr_o = '0; - assign is_double_rd_macro_instr_o = '0; - assign jump_address = '0; - end - end else begin - for (genvar i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin - assign instruction[i] = fetch_entry_i[i].instruction; + end else begin + assign stall_instr_fetch[0] = stall_macro_deco; end - assign is_illegal_cmp = '0; - assign is_compressed_cmp = '0; - assign is_macro_instr_i = '0; - assign is_zcmt_instr = '0; - assign jump_address = '0; - assign is_last_macro_instr_o = '0; - assign is_double_rd_macro_instr_o = '0; - if (CVA6Cfg.CvxifEn) begin - assign compressed_valid_o = '0; - assign compressed_req_o.instr = '0; - assign compressed_req_o.hartid = hart_id_i; - end // TODO Add else to map x_compressed_if outputs to '0 ? end - assign rvfi_is_compressed_o = is_compressed_cmp; // --------------------------------------------------------- // 2. Decode and emit instruction to issue stage // --------------------------------------------------------- + + always_comb begin + // No CVXIF, No ZCMP, No ZCMT => Connect directly compressed decoder to decoder + is_illegal_deco = is_illegal_rvc; + instruction_deco = instruction_rvc; + is_compressed_deco = is_compressed_rvc; + if (CVA6Cfg.CvxifEn) begin + is_illegal_deco[0] = is_illegal_cvxif_o; + instruction_deco[0] = instruction_cvxif_o; + is_compressed_deco[0] = is_compressed_cvxif_o; + end else if (!CVA6Cfg.CvxifEn && (CVA6Cfg.RVZCMP || CVA6Cfg.RVZCMT)) begin + is_illegal_deco[0] = is_illegal_cvxif_i; + instruction_deco[0] = instruction_cvxif_i; + is_compressed_deco[0] = is_compressed_cvxif_i; + end + end + + assign rvfi_is_compressed_o = is_compressed_rvc; + for (genvar i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin decoder #( .CVA6Cfg(CVA6Cfg), @@ -287,14 +307,14 @@ module id_stage #( .irq_ctrl_i, .irq_i, .pc_i (fetch_entry_i[i].address), - .is_compressed_i (is_compressed_cmp[i]), - .is_macro_instr_i (is_macro_instr_i[i]), + .is_compressed_i (is_compressed_deco[i]), + .is_macro_instr_i (is_macro_instr[i]), .is_zcmt_i (is_zcmt_instr[i]), - .is_last_macro_instr_i (is_last_macro_instr_o), - .is_double_rd_macro_instr_i(is_double_rd_macro_instr_o), + .is_last_macro_instr_i (is_last_macro_instr), + .is_double_rd_macro_instr_i(is_double_rd_macro_instr), .jump_address_i (jump_address), - .is_illegal_i (is_illegal_cmp[i]), - .instruction_i (instruction[i]), + .is_illegal_i (is_illegal_deco[i]), + .instruction_i (instruction_deco[i]), .compressed_instr_i (fetch_entry_i[i].instruction[15:0]), .branch_predict_i (fetch_entry_i[i].branch_predict), .ex_i (fetch_entry_i[i].ex), @@ -317,7 +337,7 @@ module id_stage #( end // ------------------ - // Pipeline Register + // 3. Pipeline Register // ------------------ for (genvar i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin assign issue_entry_o[i] = issue_q[i].sbe; @@ -331,6 +351,12 @@ module id_stage #( always_comb begin issue_n = issue_q; fetch_entry_ready_o = '0; + // instruction is not valid if we stall due to ZCMT or CVXIF + decoded_instruction_valid[0] = (CVA6Cfg.RVZCMT && is_zcmt_instr[0] && stall_macro_deco_zcmt) || + (CVA6Cfg.CvxifEn && is_illegal_cvxif_i && ~stall_macro_deco) && stall_instr_fetch[0] + ? 1'b0 : 1'b1; + // Instruction on port 1 are always valid. It is either 32bits or legal 16bits. + decoded_instruction_valid[1] = ~stall_instr_fetch[1]; // Clear the valid flag if issue has acknowledged the instruction if (issue_instr_ack_i[0]) begin @@ -344,21 +370,36 @@ module id_stage #( if (issue_n[1].valid) begin issue_n[0] = issue_n[1]; issue_n[1].valid = 1'b0; - end else if (fetch_entry_valid_i[0] && !stall_instr_fetch[0]) begin - fetch_entry_ready_o[0] = 1'b1; - issue_n[0] = '{1'b1, decoded_instruction[0], orig_instr[0], is_control_flow_instr[0]}; + end else if (fetch_entry_valid_i[0]) begin + fetch_entry_ready_o[0] = ~stall_instr_fetch[0]; + issue_n[0] = '{ + decoded_instruction_valid[0], + decoded_instruction[0], + orig_instr[0], + is_control_flow_instr[0] + }; end end if (!issue_n[1].valid) begin if (fetch_entry_ready_o[0]) begin - if (fetch_entry_valid_i[1] && !stall_instr_fetch[1]) begin - fetch_entry_ready_o[1] = 1'b1; - issue_n[1] = '{1'b1, decoded_instruction[1], orig_instr[1], is_control_flow_instr[1]}; + if (fetch_entry_valid_i[1]) begin + fetch_entry_ready_o[1] = ~stall_instr_fetch[1]; + issue_n[1] = '{ + decoded_instruction_valid[1], + decoded_instruction[1], + orig_instr[1], + is_control_flow_instr[1] + }; end - end else if (fetch_entry_valid_i[0] && !stall_instr_fetch[0]) begin - fetch_entry_ready_o[0] = 1'b1; - issue_n[1] = '{1'b1, decoded_instruction[0], orig_instr[0], is_control_flow_instr[0]}; + end else if (fetch_entry_valid_i[0]) begin + fetch_entry_ready_o[0] = ~stall_instr_fetch[0]; + issue_n[1] = '{ + decoded_instruction_valid[0], + decoded_instruction[0], + orig_instr[0], + is_control_flow_instr[0] + }; end end @@ -369,22 +410,27 @@ module id_stage #( end end else begin always_comb begin - issue_n = issue_q; + issue_n = issue_q; fetch_entry_ready_o = '0; - + // instruction is not valid if we stall due to ZCMT or CVXIF + decoded_instruction_valid[0] = (CVA6Cfg.RVZCMT && is_zcmt_instr[0] && stall_macro_deco_zcmt) || + (CVA6Cfg.CvxifEn && is_illegal_cvxif_i && ~stall_macro_deco && stall_instr_fetch[0]) + ? 1'b0 : 1'b1; // Clear the valid flag if issue has acknowledged the instruction if (issue_instr_ack_i[0]) issue_n[0].valid = 1'b0; + // TODO: refaire // if we have a space in the register and the fetch is valid, go get it // or the issue stage is currently acknowledging an instruction, which means that we will have space // for a new instruction - if ((!issue_q[0].valid || issue_instr_ack_i[0]) && fetch_entry_valid_i[0]) begin - if (stall_instr_fetch[0]) begin - fetch_entry_ready_o[0] = 1'b0; - end else begin - fetch_entry_ready_o[0] = 1'b1; - end - issue_n[0] = '{1'b1, decoded_instruction[0], orig_instr[0], is_control_flow_instr[0]}; + if (!issue_n[0].valid && fetch_entry_valid_i[0]) begin + fetch_entry_ready_o[0] = ~stall_instr_fetch[0]; + issue_n[0] = '{ + decoded_instruction_valid[0], + decoded_instruction[0], + orig_instr[0], + is_control_flow_instr[0] + }; end // invalidate the pipeline register on a flush @@ -401,5 +447,5 @@ module id_stage #( issue_q <= issue_n; end end -endmodule +endmodule diff --git a/core/include/config_pkg.sv b/core/include/config_pkg.sv index 73f2e3852b..3396088024 100644 --- a/core/include/config_pkg.sv +++ b/core/include/config_pkg.sv @@ -392,14 +392,12 @@ package config_pkg; assert (Cfg.NrCachedRegionRules <= NrMaxRules); assert (Cfg.NrPMPEntries <= 64); assert (!(Cfg.SuperscalarEn && Cfg.RVF)); - assert (!(Cfg.SuperscalarEn && Cfg.RVZCMP)); assert (Cfg.FETCH_WIDTH == 32 || Cfg.FETCH_WIDTH == 64) else $fatal(1, "[frontend] fetch width != not supported"); // Support for disabling MIP.MSIP and MIE.MSIE in Hypervisor and Supervisor mode is not supported // Software Interrupt can be disabled when there is only M machine mode in CVA6. assert (!(Cfg.RVS && !Cfg.SoftwareInterruptEn)); assert (!(Cfg.RVH && !Cfg.SoftwareInterruptEn)); - assert (!(Cfg.SuperscalarEn && Cfg.RVZCMT)); assert (!(Cfg.RVZCMT && ~Cfg.MmuPresent)); // pragma translate_on endfunction diff --git a/core/include/cv32a60x_config_pkg.sv b/core/include/cv32a60x_config_pkg.sv index f29f2dc8e5..d7543d3821 100644 --- a/core/include/cv32a60x_config_pkg.sv +++ b/core/include/cv32a60x_config_pkg.sv @@ -43,9 +43,9 @@ package cva6_config_pkg; RVV: bit'(0), RVC: bit'(1), RVH: bit'(0), - RVZCMT: bit'(1), + RVZCMT: bit'(0), RVZCB: bit'(1), - RVZCMP: bit'(1), + RVZCMP: bit'(0), XFVec: bit'(0), CvxifEn: bit'(1), RVZiCond: bit'(0), diff --git a/core/issue_stage.sv b/core/issue_stage.sv index 68ace5dac6..4ffc5382e8 100644 --- a/core/issue_stage.sv +++ b/core/issue_stage.sv @@ -176,11 +176,11 @@ module issue_stage scoreboard_entry_t [CVA6Cfg.NR_SB_ENTRIES-1:0] sbe; } forwarding_t; - forwarding_t fwd; - scoreboard_entry_t [CVA6Cfg.NrIssuePorts-1:0] issue_instr_sb_iro; - logic [CVA6Cfg.NrIssuePorts-1:0][ 31:0] orig_instr_sb_iro; - logic [CVA6Cfg.NrIssuePorts-1:0] issue_instr_valid_sb_iro; - logic [CVA6Cfg.NrIssuePorts-1:0] issue_ack_iro_sb; + forwarding_t fwd; + scoreboard_entry_t [CVA6Cfg.NrIssuePorts-1:0] issue_instr_sb_iro; + logic [CVA6Cfg.NrIssuePorts-1:0][31:0] orig_instr_sb_iro; + logic [CVA6Cfg.NrIssuePorts-1:0] issue_instr_valid_sb_iro; + logic [CVA6Cfg.NrIssuePorts-1:0] issue_ack_iro_sb; assign issue_instr_o = issue_instr_sb_iro[0]; assign issue_instr_hs_o = issue_instr_valid_sb_iro[0] & issue_ack_iro_sb[0]; diff --git a/core/macro_decoder.sv b/core/macro_decoder.sv index 9824e7d4f8..0d695a3372 100644 --- a/core/macro_decoder.sv +++ b/core/macro_decoder.sv @@ -272,9 +272,9 @@ module macro_decoder #( unique case (state_q) IDLE: begin - if (is_macro_instr_i && issue_ack_i) begin + if (is_macro_instr_i) begin reg_numbers_d = reg_numbers - 1'b1; - state_d = INIT; + state_d = issue_ack_i ? INIT : IDLE; case (macro_instr_type) PUSH: begin offset_d = 12'hFFC + 12'hFFC; @@ -423,7 +423,7 @@ module macro_decoder #( end end INIT: begin - fetch_stall_o = 1'b1; // stall inst fetch + fetch_stall_o = is_macro_instr_i; // stall inst fetch if (issue_ack_i && is_macro_instr_i && macro_instr_type == PUSH) begin if (reg_numbers_q == 4'b0001) begin if (CVA6Cfg.XLEN == 64) begin diff --git a/core/zcmt_decoder.sv b/core/zcmt_decoder.sv index 44f908d12c..c37c11fda5 100644 --- a/core/zcmt_decoder.sv +++ b/core/zcmt_decoder.sv @@ -62,7 +62,7 @@ module zcmt_decoder #( state_d = state_q; illegal_instr_o = 1'b0; is_compressed_o = is_zcmt_instr_i || is_compressed_i; - fetch_stall_o = is_zcmt_instr_i; + fetch_stall_o = '0; jump_address_o = '0; // cache request port @@ -78,6 +78,7 @@ module zcmt_decoder #( unique case (state_q) IDLE: begin + fetch_stall_o = 1'b0; if (is_zcmt_instr_i) begin if (CVA6Cfg.XLEN == 32) begin //It is only target for 32 bit targets in cva6 with No MMU table_address = {jvt_i.base, 6'b000000} + {24'h0, instr_i[7:2], 2'b00}; @@ -85,6 +86,7 @@ module zcmt_decoder #( req_port_o.address_tag = table_address[CVA6Cfg.VLEN-1:10]; // No MMU support state_d = TABLE_JUMP; req_port_o.data_req = 1'b1; + fetch_stall_o = 1'b1; end else illegal_instr_o = 1'b1; // Condition may be extented for 64 bits embedded targets with No MMU end else begin diff --git a/verif/tb/uvmt/cva6_tb_wrapper.sv b/verif/tb/uvmt/cva6_tb_wrapper.sv index fa8250a8e8..708267b960 100644 --- a/verif/tb/uvmt/cva6_tb_wrapper.sv +++ b/verif/tb/uvmt/cva6_tb_wrapper.sv @@ -247,7 +247,9 @@ module cva6_tb_wrapper import uvmt_cva6_pkg::*; #( assign cvxif_if.compressed_valid = cvxif_req.compressed_valid; assign cvxif_if.compressed_req = cvxif_req.compressed_req; assign cvxif_if.issue_valid = cvxif_req.issue_valid; - assign cvxif_if.issue_req = cvxif_req.issue_req; + assign cvxif_if.issue_req.instr = cvxif_req.issue_req.instr; + assign cvxif_if.issue_req.hartid = cvxif_req.issue_req.hartid; + assign cvxif_if.issue_req.id = cvxif_req.issue_req.id; assign cvxif_if.register_valid = cvxif_req.register_valid; assign cvxif_if.register = cvxif_req.register; assign cvxif_if.commit_valid = cvxif_req.commit_valid; diff --git a/verif/tests/custom/cv_xif/cvxif_macros.h b/verif/tests/custom/cv_xif/cvxif_macros.h index be2a692c26..6311442271 100644 --- a/verif/tests/custom/cv_xif/cvxif_macros.h +++ b/verif/tests/custom/cv_xif/cvxif_macros.h @@ -1,4 +1,4 @@ -// Copyright 2021 Thales DIS design services SAS +// Copyright 2022 Thales DIS design services SAS // // Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -8,21 +8,67 @@ // Original Author: Zineb EL KACIMI (zineb.el-kacimi@external.thalesgroup.com) // Contributor : Guillaume Chauvon +# Add user macros, routines in this file -#define LOAD_RS(rs,value) li rs, value -#define COMP_RS(rs1,rs2,rd) xor rd, rs1, rs2 +# Mappings of custom_* mnemonics to .insn pseudo-op of GAS -#define CUS_NOP() .word 0b##0000000##00000####00000##000##00000##1111011 -#define CUS_ADD(rs1,rs2,rd) .word 0b##0000000##rs2####rs1##001##rd##1111011 -#define CUS_ADD_RS1(rs1,rs2,rd) .word 0b##0000001##rs2####rs1##001##rd##1111011 // only use rs1 : rs1 + rs1 => rd -#define CUS_ADD_RS2(rs1,rs2,rd) .word 0b##0000010##rs2####rs1##001##rd##1111011 // only use rs2 : rs2 + rs2 => rd -#define CUS_ADD_MULTI(rs1,rs2,rd) .word 0b##0000011##rs2####rs1##001##rd##1111011 -#define CUS_ADD_RS3_MADD(rs1,rs2,rs3,rd) .word 0b##rs3##00##rs2####rs1##000##rd##1000011 //MADD -#define CUS_ADD_RS3_MSUB(rs1,rs2,rs3,rd) .word 0b##rs3##00##rs2####rs1##000##rd##1000111 //MSUB -#define CUS_ADD_RS3_NMSUB(rs1,rs2,rs3,rd) .word 0b##rs3##00##rs2####rs1##000##rd##1001011 //NMSUB -#define CUS_ADD_RS3_NMADD(rs1,rs2,rs3,rd) .word 0b##rs3##00##rs2####rs1##000##rd##1001111 //NMADD -#define CUS_ADD_RS3_RTYPE(rs1,rs2,rs3) .word 0b##0000100##rs2####rs1##001##rs3##1111011 +# CUS_ADD rd, rs1, rs2 -> .insn r CUSTOM_3, 0x1, 0x0, rd, rs1, rs2 +.macro cus_add rd, rs1, rs2 + .insn r CUSTOM_3, 0x1, 0x0, \rd, \rs1, \rs2 +.endm -#define CUS_CADD(rs1, rs2) .half 0b##111##1##rs1##rs2##00 // -> Extend to CUS_ADD(rs1,rs2,x10) -#define CUS_CNOP() .half 0b##111##0##00000##00000##00 // -> Extend to CUS_NOP +# CUS_NOP -> .insn r CUSTOM_3, 0x0, 0x0, x0, x0, x0 +.macro cus_nop + .insn r CUSTOM_3, 0x0, 0x0, x0, x0, x0 +.endm + +# CUS_DOUBLE_RS1 rd, rs1, rs2 -> .insn r CUSTOM_3, 0x1, 0x1, rd, rs1, rs2 +.macro cus_double_rs1 rd, rs1, rs2 + .insn r CUSTOM_3, 0x1, 0x1, \rd, \rs1, \rs2 +.endm + +# CUS_DOUBLE_RS2 rd, rs1, rs2 -> .insn r CUSTOM_3, 0x1, 0x2, rd, rs1, rs2 +.macro cus_double_rs2 rd, rs1, rs2 + .insn r CUSTOM_3, 0x1, 0x2, \rd, \rs1, \rs2 +.endm + +# CUS_ADD_MULTI rd, rs1, rs2 -> .insn r CUSTOM_3, 0x1, 0x3, rd, rs1, rs2 +.macro cus_add_multi rd, rs1, rs2 + .insn r CUSTOM_3, 0x1, 0x3, \rd, \rs1, \rs2 +.endm + +# CUS_ADD_RS3_MADD rd, rs1, rs2, rs3 -> .insn r MADD, 0x0, 0x0, rd, rs1, rs2, rs3 +.macro cus_add_rs3_madd rd, rs1, rs2, rs3 + .insn r MADD, 0x0, 0x0, \rd, \rs1, \rs2, \rs3 +.endm + +# CUS_ADD_RS3_MSUB rd, rs1, rs2, rs3 -> .insn r MSUB, 0x0, 0x0, rd, rs1, rs2, rs3 +.macro cus_add_rs3_msub rd, rs1, rs2, rs3 + .insn r MSUB, 0x0, 0x0, \rd, \rs1, \rs2, \rs3 +.endm + +# CUS_ADD_RS3_NMADD rd, rs1, rs2, rs3 -> .insn r NMADD, 0x0, 0x0, rd, rs1, rs2, rs3 +.macro cus_add_rs3_nmadd rd, rs1, rs2, rs3 + .insn r NMADD, 0x0, 0x0, \rd, \rs1, \rs2, \rs3 +.endm + +# CUS_ADD_RS3_NMSUB rd, rs1, rs2, rs3 -> .insn r NMSUB, 0x0, 0x0, rd, rs1, rs2, rs3 +.macro cus_add_rs3_nmsub rd, rs1, rs2, rs3 + .insn r NMSUB, 0x0, 0x0, \rd, \rs1, \rs2, \rs3 +.endm + +# CUS_ADD_RS3_RTYPE rs3, rs1, rs2 -> .insn r MADD, 0x1, 0x4, rs3, rs1, rs2 +.macro cus_add_rs3_rtype rs1, rs2, rs3 + .insn r MADD, 0x1, 0x4, \rs3, \rs1, \rs2 +.endm + +# CUS_CNOP -> .insn cr 0x0, 0xe, x0, x0 +.macro cus_cnop + .insn cr 0x0, 0xe, x0, x0 +.endm + +# CUS_CADD rs1, rs2 -> .insn cr 0x0, 0xf, rs1, rs2 +.macro cus_cadd rs1, rs2 + .insn cr 0x0, 0xf, \rs1, \rs2 +.endm \ No newline at end of file