diff --git a/dv/cosim/cosim.h b/dv/cosim/cosim.h index 4a5c63c75b..c702b5cfce 100644 --- a/dv/cosim/cosim.h +++ b/dv/cosim/cosim.h @@ -74,9 +74,15 @@ class Cosim { // In this case the instruction doesn't retire so no register write occurs (so // `write_reg` must be 0). // + // `expanded_insn_valid` is the current instruction an expanded one + // `expanded_insn` is the 32-bit instruction that is being expanded + // `expanded_insn_last` whether this is the last op of an expanded instruction + // // Returns false if there are any errors; use `get_errors` to obtain details virtual bool step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, - bool sync_trap, bool suppress_reg_write) = 0; + bool sync_trap, bool suppress_reg_write, + bool expanded_insn_valid, uint32_t expanded_insn, + bool expanded_insn_last) = 0; // When more than one of `set_mip`, `set_nmi` or `set_debug_req` is called // before `step` which one takes effect is chosen by the co-simulator. Which @@ -158,6 +164,12 @@ class Cosim { // Clear internal vector of error descriptions virtual void clear_errors() = 0; + // Get a vector of strings describing dbg that have occurred during `step` + virtual const std::vector &get_dbg() = 0; + + // Clear internal vector of dbg descriptions + virtual void clear_dbg() = 0; + // Returns a count of instructions executed by co-simulator and DUT without // failures. virtual unsigned int get_insn_cnt() = 0; diff --git a/dv/cosim/cosim_dpi.cc b/dv/cosim/cosim_dpi.cc index 30a3da74dd..77d19e465c 100644 --- a/dv/cosim/cosim_dpi.cc +++ b/dv/cosim/cosim_dpi.cc @@ -12,11 +12,15 @@ int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg, const svBitVecVal *write_reg_data, const svBitVecVal *pc, - svBit sync_trap, svBit suppress_reg_write) { + svBit sync_trap, svBit suppress_reg_write, + svBit expanded_insn_valid, + const svBitVecVal *expanded_insn, + svBit expanded_insn_last) { assert(cosim); return cosim->step(write_reg[0], write_reg_data[0], pc[0], sync_trap, - suppress_reg_write) + suppress_reg_write, expanded_insn_valid, expanded_insn[0], + expanded_insn_last) ? 1 : 0; } @@ -114,6 +118,28 @@ void riscv_cosim_clear_errors(Cosim *cosim) { cosim->clear_errors(); } +int riscv_cosim_get_num_dbg(Cosim *cosim) { + assert(cosim); + + return cosim->get_dbg().size(); +} + +const char *riscv_cosim_get_dbg(Cosim *cosim, int index) { + assert(cosim); + + if (index >= cosim->get_dbg().size()) { + return nullptr; + } + + return cosim->get_dbg()[index].c_str(); +} + +void riscv_cosim_clear_dbg(Cosim *cosim) { + assert(cosim); + + cosim->clear_dbg(); +} + void riscv_cosim_write_mem_byte(Cosim *cosim, const svBitVecVal *addr, const svBitVecVal *d) { assert(cosim); diff --git a/dv/cosim/cosim_dpi.h b/dv/cosim/cosim_dpi.h index bbadbc5e3c..ff03176b4e 100644 --- a/dv/cosim/cosim_dpi.h +++ b/dv/cosim/cosim_dpi.h @@ -16,7 +16,10 @@ extern "C" { int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg, const svBitVecVal *write_reg_data, const svBitVecVal *pc, - svBit sync_trap, svBit suppress_reg_write); + svBit sync_trap, svBit suppress_reg_write, + svBit expanded_insn_valid, + const svBitVecVal *expanded_insn, + svBit expanded_insn_last); void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *pre_mip, const svBitVecVal *post_mip); void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi); @@ -37,6 +40,9 @@ void riscv_cosim_set_iside_error(Cosim *cosim, svBitVecVal *addr); int riscv_cosim_get_num_errors(Cosim *cosim); const char *riscv_cosim_get_error(Cosim *cosim, int index); void riscv_cosim_clear_errors(Cosim *cosim); +int riscv_cosim_get_num_dbg(Cosim *cosim); +const char *riscv_cosim_get_dbg(Cosim *cosim, int index); +void riscv_cosim_clear_dbg(Cosim *cosim); void riscv_cosim_write_mem_byte(Cosim *cosim, const svBitVecVal *addr, const svBitVecVal *d); unsigned int riscv_cosim_get_insn_cnt(Cosim *cosim); diff --git a/dv/cosim/cosim_dpi.svh b/dv/cosim/cosim_dpi.svh index 35ecd3b8cb..f1781f4a53 100644 --- a/dv/cosim/cosim_dpi.svh +++ b/dv/cosim/cosim_dpi.svh @@ -11,7 +11,8 @@ `define COSIM_DPI_SVH import "DPI-C" function int riscv_cosim_step(chandle cosim_handle, bit [4:0] write_reg, - bit [31:0] write_reg_data, bit [31:0] pc, bit sync_trap, bit suppress_reg_write); + bit [31:0] write_reg_data, bit [31:0] pc, bit sync_trap, bit suppress_reg_write, + bit expanded_insn_valid, bit [15:0] expanded_insn, bit expanded_insn_last); import "DPI-C" function void riscv_cosim_set_mip(chandle cosim_handle, bit [31:0] pre_mip, bit [31:0] post_mip); import "DPI-C" function void riscv_cosim_set_nmi(chandle cosim_handle, bit nmi); @@ -28,6 +29,9 @@ import "DPI-C" function int riscv_cosim_set_iside_error(chandle cosim_handle, bi import "DPI-C" function int riscv_cosim_get_num_errors(chandle cosim_handle); import "DPI-C" function string riscv_cosim_get_error(chandle cosim_handle, int index); import "DPI-C" function void riscv_cosim_clear_errors(chandle cosim_handle); +import "DPI-C" function int riscv_cosim_get_num_dbg(chandle cosim_handle); +import "DPI-C" function string riscv_cosim_get_dbg(chandle cosim_handle, int index); +import "DPI-C" function void riscv_cosim_clear_dbg(chandle cosim_handle); import "DPI-C" function void riscv_cosim_write_mem_byte(chandle cosim_handle, bit [31:0] addr, bit [7:0] d); import "DPI-C" function int unsigned riscv_cosim_get_insn_cnt(chandle cosim_handle); diff --git a/dv/cosim/spike_cosim.cc b/dv/cosim/spike_cosim.cc index daa400709b..b2f1ff3f12 100644 --- a/dv/cosim/spike_cosim.cc +++ b/dv/cosim/spike_cosim.cc @@ -39,7 +39,10 @@ SpikeCosim::SpikeCosim(const std::string &isa_string, uint32_t start_pc, uint32_t pmp_num_regions, uint32_t pmp_granularity, uint32_t mhpm_counter_num, uint32_t dm_start_addr, uint32_t dm_end_addr) - : nmi_mode(false), pending_iside_error(false), insn_cnt(0) { + : nmi_mode(false), + pending_iside_error(false), + insn_cnt(0), + pending_expanded_insn(0) { FILE *log_file = nullptr; if (trace_log_path.length() != 0) { log = std::make_unique(trace_log_path.c_str()); @@ -170,7 +173,9 @@ bool SpikeCosim::backdoor_read_mem(uint32_t addr, size_t len, // processor, and when we call step() again we start executing in the new // context of the trap (trap handler, new MSTATUS, debug rom, etc. etc.) bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, - bool sync_trap, bool suppress_reg_write) { + bool sync_trap, bool suppress_reg_write, + bool expanded_insn_valid, uint32_t expanded_insn, + bool expanded_insn_last) { assert(write_reg < 32); // The DUT has just produced an RVFI item @@ -214,7 +219,16 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, // (If the current step causes a synchronous trap, it will be // recorded against the current pc) initial_spike_pc = (processor->get_state()->pc & 0xffffffff); - processor->step(1); + // Only step Spike if the current instruction is not an expanded one or the + // final operation of an expanded sequence. Spike does not expand + // instructions, so we have to consume a single Spike step over multiple steps + // of Ibex. Since Spike will initiate the memory interface checks, we must + // complete all the steps of the expanded instruction in Ibex before stepping + // Spike. That is why we step Spike on expanded_insn_last and then check that + // all modifications match. + if (!expanded_insn_valid || expanded_insn_last || sync_trap) { + processor->step(1); + } // ISS // - If encountered an async trap, @@ -309,8 +323,16 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, suppressed_write_reg_data); } - if (!check_retired_instr(write_reg, write_reg_data, pc, suppress_reg_write)) { - return false; + if (expanded_insn_valid) { + if (!check_expanded_instr(write_reg, write_reg_data, pc, suppress_reg_write, + expanded_insn, expanded_insn_last)) { + return false; + } + } else { + if (!check_retired_instr(write_reg, write_reg_data, pc, + suppress_reg_write)) { + return false; + } } // Only increment insn_cnt and return true if there are no errors @@ -318,6 +340,151 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, return true; } +bool SpikeCosim::check_expanded_instr(uint32_t write_reg, + uint32_t write_reg_data, uint32_t dut_pc, + bool suppress_reg_write, + uint32_t expanded_insn, + bool expanded_insn_last) { + // Expanded instruction must be set when calling this function + assert(expanded_insn != 0); + + // If it's the first instruction of an expanded sequence, set pending state + // and save the PC. + if (!pending_expanded_insn) { + if (expanded_insn_last) { + // This is the first and last instruction. This should never happen with + // the currently supported expanded instructions + std::stringstream err_str; + err_str << "Error: PC 0x" << std::hex << dut_pc + << ": First and last expanded instruction set simultaneously. " + "This should never happen."; + errors.emplace_back(err_str.str()); + return false; + } + pending_expanded_insn = expanded_insn; + expanded_insn_pc = dut_pc; + } + + // Verify that the PC didn't change + if (dut_pc != expanded_insn_pc) { + std::stringstream err_str; + err_str << "Error: PC 0x" << std::hex << dut_pc + << ": PC changed during expanded instruction. Expected 0x" + << std::hex << expanded_insn_pc; + errors.emplace_back(err_str.str()); + // This is a fatal error, reset state + pending_expanded_insn = 0; + dut_reg_changes.clear(); + return false; + } + + // Push the DUT's register write to the queue for later unless its write to x0 + if (write_reg != 0 && !suppress_reg_write) { + dut_reg_changes[write_reg] = write_reg_data; + } + + if (!expanded_insn_last) { + // This is part of an expanded instruction, but not the last part. + // We just store the state and return true, as we wait for the final + // instruction. The ISS did NOT step yet, so we cannot compare the states + // yet. + return true; + } else { + // This is the final instruction of this sequence. Time to check all + // buffered writes. + + // Check ISS PC vs our saved PC + if ((processor->get_state()->last_inst_pc & 0xffffffff) != + expanded_insn_pc) { + std::stringstream err_str; + err_str << "PC mismatch, DUT retired expanded instruction at: " + << std::hex << expanded_insn_pc + << " , but the ISS retired: " << std::hex + << (processor->get_state()->last_inst_pc & 0xffffffff); + errors.emplace_back(err_str.str()); + pending_expanded_insn = 0; + dut_reg_changes.clear(); + return false; + } + + // Get all ISS changes and a working copy of DUT writes + auto &iss_reg_changes = processor->get_state()->log_reg_write; + bool all_checks_pass = true; + + // For each ISS change, find a matching DUT write. + for (auto iss_reg_change : iss_reg_changes) { + // reg_change.first provides register type in bottom 4 bits, then register + // index above that + // Ignore writes to x0 + if (iss_reg_change.first == 0) + continue; + + // register is GPR + if ((iss_reg_change.first & 0xf) == 0) { + // Find match by register address first + uint32_t iss_write_reg = (iss_reg_change.first >> 4) & 0x1f; + auto dut_reg_change = dut_reg_changes.find(iss_write_reg); + // Check if found + if (dut_reg_change != dut_reg_changes.end()) { + // Perform the regular write check + // dut_reg_change->first is write_reg, dut_reg_change->second is + // write_reg_data + if (!check_gpr_write(iss_reg_change, dut_reg_change->first, + dut_reg_change->second)) { + // Data mismatch --> continue to capture mutliple mismatches but + // eventually fail + all_checks_pass = false; + } + // Consume this write from the map + dut_reg_changes.erase(dut_reg_change); + } else { + // No DUT write found for this ISS register. + std::stringstream err_str; + uint32_t cosim_write_reg_data = iss_reg_change.second.v[0]; + err_str << "PC 0x" << std::hex << expanded_insn_pc + << ": ISS wrote GPR x" << iss_write_reg << " (val 0x" + << std::hex << cosim_write_reg_data + << "), but no matching write was found from the DUT's " + "expanded instructions."; + errors.emplace_back(err_str.str()); + all_checks_pass = false; + } + } else if ((iss_reg_change.first & 0xf) == 4) { + // register is CSR + on_csr_write(iss_reg_change); + } else { + // should never see other types + assert(false); + } + } + + // Make sure there are no DUT writes left over + if (!dut_reg_changes.empty()) { + for (auto &extra_write : dut_reg_changes) { + std::stringstream err_str; + err_str << "PC 0x" << std::hex << expanded_insn_pc + << ": DUT expanded instruction wrote GPR x" << extra_write.first + << " with value 0x" << std::hex << extra_write.second + << ", but this write was not expected by the ISS."; + errors.emplace_back(err_str.str()); + all_checks_pass = false; + } + } + + // This was the last instruction of this expanded instruction. Cleanup state + // and return + pending_expanded_insn = 0; + dut_reg_changes.clear(); + + // Final check for any errors added during the process + if (errors.size() != 0) { + all_checks_pass = false; + } + + return all_checks_pass; + } +} + bool SpikeCosim::check_retired_instr(uint32_t write_reg, uint32_t write_reg_data, uint32_t dut_pc, bool suppress_reg_write) { @@ -333,6 +500,11 @@ bool SpikeCosim::check_retired_instr(uint32_t write_reg, << " , but the ISS retired: " << std::hex << (processor->get_state()->last_inst_pc & 0xffffffff); errors.emplace_back(err_str.str()); + if (pending_expanded_insn) { + err_str << " (while processing expanded instruction at PC 0x" << std::hex + << expanded_insn_pc << ")"; + errors.emplace_back(err_str.str()); + } return false; } @@ -781,6 +953,10 @@ const std::vector &SpikeCosim::get_errors() { return errors; } void SpikeCosim::clear_errors() { errors.clear(); } +const std::vector &SpikeCosim::get_dbg() { return dbg; } + +void SpikeCosim::clear_dbg() { dbg.clear(); } + void SpikeCosim::fixup_csr(int csr_num, uint32_t csr_val) { switch (csr_num) { case CSR_MSTATUS: { diff --git a/dv/cosim/spike_cosim.h b/dv/cosim/spike_cosim.h index 68fd2204fb..ef238d021e 100644 --- a/dv/cosim/spike_cosim.h +++ b/dv/cosim/spike_cosim.h @@ -38,6 +38,7 @@ class SpikeCosim : public simif_t, public Cosim { bus_t bus; std::vector> mems; std::vector errors; + std::vector dbg; bool nmi_mode; typedef struct { @@ -99,6 +100,17 @@ class SpikeCosim : public simif_t, public Cosim { unsigned int insn_cnt; + // Handle expanded instructions + // Set to one once we start processing an expanded instruction. Used to track + // the start of a new expanded instruction. + uint32_t pending_expanded_insn; + // Keep track of the PC of an expanded instruction to ensure it doesn't change + // without completing the expansion and getting a `expanded_insn_last` signal. + uint32_t expanded_insn_pc; + // Keep track of register writes during an expanded instruction to compare + // with the ISS's register changes in the `expanded_insn_last` step. + std::map dut_reg_changes; + public: SpikeCosim(const std::string &isa_string, uint32_t start_pc, uint32_t start_mtvec, const std::string &trace_log_path, @@ -120,10 +132,14 @@ class SpikeCosim : public simif_t, public Cosim { const uint8_t *data_in) override; bool backdoor_read_mem(uint32_t addr, size_t len, uint8_t *data_out) override; bool step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, - bool sync_trap, bool suppress_reg_write) override; + bool sync_trap, bool suppress_reg_write, bool expanded_insn_valid, + uint32_t expanded_insn, bool expanded_insn_last) override; bool check_retired_instr(uint32_t write_reg, uint32_t write_reg_data, uint32_t dut_pc, bool suppress_reg_write); + bool check_expanded_instr(uint32_t write_reg, uint32_t write_reg_data, + uint32_t dut_pc, bool suppress_reg_write, + uint32_t expanded_insn, bool expanded_insn_last); bool check_sync_trap(uint32_t write_reg, uint32_t pc, uint32_t initial_spike_pc); void set_mip(uint32_t pre_mip, uint32_t post_mip) override; @@ -142,6 +158,8 @@ class SpikeCosim : public simif_t, public Cosim { void set_iside_error(uint32_t addr) override; const std::vector &get_errors() override; void clear_errors() override; + const std::vector &get_dbg() override; + void clear_dbg() override; unsigned int get_insn_cnt() override; }; diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv index 7998349d82..76d3ad2f61 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv @@ -163,7 +163,11 @@ class ibex_cosim_scoreboard extends uvm_scoreboard; riscv_cosim_set_ic_scr_key_valid(cosim_handle, rvfi_instr.ic_scr_key_valid); if (!riscv_cosim_step(cosim_handle, rvfi_instr.rd_addr, rvfi_instr.rd_wdata, rvfi_instr.pc, - rvfi_instr.trap, rvfi_instr.rf_wr_suppress)) begin + rvfi_instr.trap, rvfi_instr.rf_wr_suppress, + rvfi_instr.expanded_insn_valid, rvfi_instr.expanded_insn, + rvfi_instr.expanded_insn_last)) begin + // Print the debug before the error to help with diagnosis + `uvm_info(`gfn, get_cosim_dbg_str(rvfi_instr.pc), UVM_LOW) // cosim instruction step doesn't match rvfi captured instruction, report a fatal error // with the details if (cfg.relax_cosim_check) begin @@ -171,6 +175,10 @@ class ibex_cosim_scoreboard extends uvm_scoreboard; end else begin `uvm_fatal(`gfn, get_cosim_error_str()) end + end else begin + if (riscv_cosim_get_num_dbg(cosim_handle) > 0) begin + `uvm_info(`gfn, get_cosim_dbg_str(rvfi_instr.pc), UVM_LOW) + end end end endtask: run_cosim_rvfi @@ -268,8 +276,7 @@ class ibex_cosim_scoreboard extends uvm_scoreboard; bit [31:0] aligned_next_addr; forever begin // Wait for new instruction to appear in ID stage - wait (instr_vif.instr_cb.valid_id && - instr_vif.instr_cb.instr_new_id && + wait (instr_vif.instr_cb.rvfi_id_done && latest_order != instr_vif.instr_cb.rvfi_order_id); latest_order = instr_vif.instr_cb.rvfi_order_id; @@ -320,9 +327,9 @@ class ibex_cosim_scoreboard extends uvm_scoreboard; // Wait for a new instruction or a writeback exception. When a new instruction has entered the // ID stage and we haven't seen a writeback exception we know the instruction associated with the // error just added to the queue isn't getting flushed. - wait (instr_vif.instr_cb.instr_new_id || dut_vif.dut_cb.wb_exception); + wait (instr_vif.instr_cb.rvfi_id_done || dut_vif.dut_cb.wb_exception); - if (!instr_vif.instr_cb.instr_new_id && dut_vif.dut_cb.wb_exception) begin + if (!instr_vif.instr_cb.rvfi_id_done && dut_vif.dut_cb.wb_exception) begin // If we hit a writeback exception without seeing a new instruction then the newly added // error relates to an instruction just flushed from the ID stage so pop it from the // queue. @@ -341,6 +348,16 @@ class ibex_cosim_scoreboard extends uvm_scoreboard; return error; endfunction : get_cosim_error_str + function string get_cosim_dbg_str(bit [31:0] pc); + string dbg = $sformatf("Cosim debug (DUT PC 0x%08x):\n", pc); + for (int i = 0; i < riscv_cosim_get_num_dbg(cosim_handle); ++i) begin + dbg = {dbg, riscv_cosim_get_dbg(cosim_handle, i), "\n"}; + end + riscv_cosim_clear_dbg(cosim_handle); + + return dbg; + endfunction : get_cosim_dbg_str + function void final_phase(uvm_phase phase); super.final_phase(phase); diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv index 0bf50116e7..9638d0dcb4 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_monitor.sv @@ -30,21 +30,24 @@ class ibex_rvfi_monitor extends uvm_monitor; while(!(vif.monitor_cb.valid || vif.monitor_cb.ext_irq_valid)) vif.wait_clks(1); // Read instruction details from RVFI interface - trans_collected = ibex_rvfi_seq_item::type_id::create("trans_collected"); - trans_collected.irq_only = !vif.monitor_cb.valid && vif.monitor_cb.ext_irq_valid; - trans_collected.trap = vif.monitor_cb.trap; - trans_collected.pc = vif.monitor_cb.pc_rdata; - trans_collected.rd_addr = vif.monitor_cb.rd_addr; - trans_collected.rd_wdata = vif.monitor_cb.rd_wdata; - trans_collected.order = vif.monitor_cb.order; - trans_collected.pre_mip = vif.monitor_cb.ext_pre_mip; - trans_collected.post_mip = vif.monitor_cb.ext_post_mip; - trans_collected.nmi = vif.monitor_cb.ext_nmi; - trans_collected.nmi_int = vif.monitor_cb.ext_nmi_int; - trans_collected.debug_req = vif.monitor_cb.ext_debug_req; - trans_collected.rf_wr_suppress = vif.monitor_cb.ext_rf_wr_suppress; - trans_collected.mcycle = vif.monitor_cb.ext_mcycle; - trans_collected.ic_scr_key_valid = vif.monitor_cb.ext_ic_scr_key_valid; + trans_collected = ibex_rvfi_seq_item::type_id::create("trans_collected"); + trans_collected.irq_only = !vif.monitor_cb.valid && vif.monitor_cb.ext_irq_valid; + trans_collected.trap = vif.monitor_cb.trap; + trans_collected.pc = vif.monitor_cb.pc_rdata; + trans_collected.rd_addr = vif.monitor_cb.rd_addr; + trans_collected.rd_wdata = vif.monitor_cb.rd_wdata; + trans_collected.order = vif.monitor_cb.order; + trans_collected.pre_mip = vif.monitor_cb.ext_pre_mip; + trans_collected.post_mip = vif.monitor_cb.ext_post_mip; + trans_collected.nmi = vif.monitor_cb.ext_nmi; + trans_collected.nmi_int = vif.monitor_cb.ext_nmi_int; + trans_collected.debug_req = vif.monitor_cb.ext_debug_req; + trans_collected.rf_wr_suppress = vif.monitor_cb.ext_rf_wr_suppress; + trans_collected.mcycle = vif.monitor_cb.ext_mcycle; + trans_collected.ic_scr_key_valid = vif.monitor_cb.ext_ic_scr_key_valid; + trans_collected.expanded_insn_valid = vif.monitor_cb.ext_expanded_insn_valid; + trans_collected.expanded_insn = vif.monitor_cb.ext_expanded_insn; + trans_collected.expanded_insn_last = vif.monitor_cb.ext_expanded_insn_last; for (int i=0; i < 10; i++) begin trans_collected.mhpmcounters[i] = vif.monitor_cb.ext_mhpmcounters[i]; diff --git a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv index dceba31c47..3f7031887f 100644 --- a/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv +++ b/dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_rvfi_seq_item.sv @@ -21,6 +21,10 @@ class ibex_rvfi_seq_item extends uvm_sequence_item; bit [31:0] mhpmcountersh [10]; bit ic_scr_key_valid; + bit expanded_insn_valid; + bit [15:0] expanded_insn; + bit expanded_insn_last; + `uvm_object_utils_begin(ibex_rvfi_seq_item) `uvm_field_int (trap, UVM_DEFAULT) `uvm_field_int (pc, UVM_DEFAULT) @@ -37,6 +41,9 @@ class ibex_rvfi_seq_item extends uvm_sequence_item; `uvm_field_sarray_int (mhpmcounters, UVM_DEFAULT) `uvm_field_sarray_int (mhpmcountersh, UVM_DEFAULT) `uvm_field_int (ic_scr_key_valid, UVM_DEFAULT) + `uvm_field_int (expanded_insn_valid, UVM_DEFAULT) + `uvm_field_int (expanded_insn, UVM_DEFAULT) + `uvm_field_int (expanded_insn_last, UVM_DEFAULT) `uvm_object_utils_end `uvm_object_new diff --git a/dv/uvm/core_ibex/env/core_ibex_instr_monitor_if.sv b/dv/uvm/core_ibex/env/core_ibex_instr_monitor_if.sv index 08daae43f6..51e437bbd4 100644 --- a/dv/uvm/core_ibex/env/core_ibex_instr_monitor_if.sv +++ b/dv/uvm/core_ibex/env/core_ibex_instr_monitor_if.sv @@ -15,7 +15,7 @@ interface core_ibex_instr_monitor_if #( // ID stage logic reset; logic valid_id; - logic instr_new_id; + logic rvfi_id_done; logic err_id; logic is_compressed_id; logic [15:0] instr_compressed_id; @@ -30,7 +30,7 @@ interface core_ibex_instr_monitor_if #( clocking instr_cb @(posedge clk); input reset; input valid_id; - input instr_new_id; + input rvfi_id_done; input err_id; input is_compressed_id; input instr_compressed_id; diff --git a/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv b/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv index 0199b87f76..b2b0eac1b4 100644 --- a/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv +++ b/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv @@ -40,6 +40,10 @@ interface core_ibex_rvfi_if(input logic clk); logic ext_ic_scr_key_valid; + logic ext_expanded_insn_valid; + logic [15:0] ext_expanded_insn; + logic ext_expanded_insn_last; + clocking monitor_cb @(posedge clk); input reset; input valid; @@ -74,6 +78,9 @@ interface core_ibex_rvfi_if(input logic clk); input ext_mhpmcountersh; input ext_ic_scr_key_valid; input ext_irq_valid; + input ext_expanded_insn_valid; + input ext_expanded_insn; + input ext_expanded_insn_last; endclocking task automatic wait_clks(input int num); diff --git a/dv/uvm/core_ibex/riscv_dv_extension/riscv_core_setting.tpl.sv b/dv/uvm/core_ibex/riscv_dv_extension/riscv_core_setting.tpl.sv index fff0a1af17..c64ce30238 100644 --- a/dv/uvm/core_ibex/riscv_dv_extension/riscv_core_setting.tpl.sv +++ b/dv/uvm/core_ibex/riscv_dv_extension/riscv_core_setting.tpl.sv @@ -53,7 +53,7 @@ bit support_unaligned_load_store = 1'b1; // ISA supported by the processor // TODO: Determine how Ibex RV32B types map to RISCV-DV ISA names -riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C +riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C, RV32ZCB, RV32ZCMP % if ibex_config['RV32B'] == 'ibex_pkg::RV32BNone': }; % else: diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index b4107f41ac..c789f65fe4 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -211,37 +211,40 @@ module core_ibex_tb_top; assign instr_mem_vif.be = 0; assign instr_mem_vif.wdata = 0; // RVFI interface connections - assign rvfi_if.reset = ~rst_n; - assign rvfi_if.valid = dut.rvfi_valid; - assign rvfi_if.order = dut.rvfi_order; - assign rvfi_if.insn = dut.rvfi_insn; - assign rvfi_if.trap = dut.rvfi_trap; - assign rvfi_if.intr = dut.rvfi_intr; - assign rvfi_if.mode = dut.rvfi_mode; - assign rvfi_if.ixl = dut.rvfi_ixl; - assign rvfi_if.rs1_addr = dut.rvfi_rs1_addr; - assign rvfi_if.rs2_addr = dut.rvfi_rs2_addr; - assign rvfi_if.rs1_rdata = dut.rvfi_rs1_rdata; - assign rvfi_if.rs2_rdata = dut.rvfi_rs2_rdata; - assign rvfi_if.rd_addr = dut.rvfi_rd_addr; - assign rvfi_if.rd_wdata = dut.rvfi_rd_wdata; - assign rvfi_if.pc_rdata = dut.rvfi_pc_rdata; - assign rvfi_if.pc_wdata = dut.rvfi_pc_wdata; - assign rvfi_if.mem_addr = dut.rvfi_mem_addr; - assign rvfi_if.mem_rmask = dut.rvfi_mem_rmask; - assign rvfi_if.mem_rdata = dut.rvfi_mem_rdata; - assign rvfi_if.mem_wdata = dut.rvfi_mem_wdata; - assign rvfi_if.ext_pre_mip = dut.rvfi_ext_pre_mip; - assign rvfi_if.ext_post_mip = dut.rvfi_ext_post_mip; - assign rvfi_if.ext_nmi = dut.rvfi_ext_nmi; - assign rvfi_if.ext_nmi_int = dut.rvfi_ext_nmi_int; - assign rvfi_if.ext_debug_req = dut.rvfi_ext_debug_req; - assign rvfi_if.ext_rf_wr_suppress = dut.rvfi_ext_rf_wr_suppress; - assign rvfi_if.ext_mcycle = dut.rvfi_ext_mcycle; - assign rvfi_if.ext_mhpmcounters = dut.rvfi_ext_mhpmcounters; - assign rvfi_if.ext_mhpmcountersh = dut.rvfi_ext_mhpmcountersh; - assign rvfi_if.ext_ic_scr_key_valid = dut.rvfi_ext_ic_scr_key_valid; - assign rvfi_if.ext_irq_valid = dut.rvfi_ext_irq_valid; + assign rvfi_if.reset = ~rst_n; + assign rvfi_if.valid = dut.rvfi_valid; + assign rvfi_if.order = dut.rvfi_order; + assign rvfi_if.insn = dut.rvfi_insn; + assign rvfi_if.trap = dut.rvfi_trap; + assign rvfi_if.intr = dut.rvfi_intr; + assign rvfi_if.mode = dut.rvfi_mode; + assign rvfi_if.ixl = dut.rvfi_ixl; + assign rvfi_if.rs1_addr = dut.rvfi_rs1_addr; + assign rvfi_if.rs2_addr = dut.rvfi_rs2_addr; + assign rvfi_if.rs1_rdata = dut.rvfi_rs1_rdata; + assign rvfi_if.rs2_rdata = dut.rvfi_rs2_rdata; + assign rvfi_if.rd_addr = dut.rvfi_rd_addr; + assign rvfi_if.rd_wdata = dut.rvfi_rd_wdata; + assign rvfi_if.pc_rdata = dut.rvfi_pc_rdata; + assign rvfi_if.pc_wdata = dut.rvfi_pc_wdata; + assign rvfi_if.mem_addr = dut.rvfi_mem_addr; + assign rvfi_if.mem_rmask = dut.rvfi_mem_rmask; + assign rvfi_if.mem_rdata = dut.rvfi_mem_rdata; + assign rvfi_if.mem_wdata = dut.rvfi_mem_wdata; + assign rvfi_if.ext_pre_mip = dut.rvfi_ext_pre_mip; + assign rvfi_if.ext_post_mip = dut.rvfi_ext_post_mip; + assign rvfi_if.ext_nmi = dut.rvfi_ext_nmi; + assign rvfi_if.ext_nmi_int = dut.rvfi_ext_nmi_int; + assign rvfi_if.ext_debug_req = dut.rvfi_ext_debug_req; + assign rvfi_if.ext_rf_wr_suppress = dut.rvfi_ext_rf_wr_suppress; + assign rvfi_if.ext_mcycle = dut.rvfi_ext_mcycle; + assign rvfi_if.ext_mhpmcounters = dut.rvfi_ext_mhpmcounters; + assign rvfi_if.ext_mhpmcountersh = dut.rvfi_ext_mhpmcountersh; + assign rvfi_if.ext_ic_scr_key_valid = dut.rvfi_ext_ic_scr_key_valid; + assign rvfi_if.ext_irq_valid = dut.rvfi_ext_irq_valid; + assign rvfi_if.ext_expanded_insn_valid = dut.rvfi_ext_expanded_insn_valid; + assign rvfi_if.ext_expanded_insn = dut.rvfi_ext_expanded_insn; + assign rvfi_if.ext_expanded_insn_last = dut.rvfi_ext_expanded_insn_last; // Irq interface connections assign irq_vif.reset = ~rst_n; // Dut_if interface connections @@ -274,7 +277,7 @@ module core_ibex_tb_top; // Instruction monitor connections assign instr_monitor_if.reset = ~rst_n; assign instr_monitor_if.valid_id = dut.u_ibex_top.u_ibex_core.id_stage_i.instr_valid_i; - assign instr_monitor_if.instr_new_id = dut.u_ibex_top.u_ibex_core.instr_new_id; + assign instr_monitor_if.rvfi_id_done = dut.u_ibex_top.u_ibex_core.rvfi_id_done; assign instr_monitor_if.err_id = dut.u_ibex_top.u_ibex_core.id_stage_i.controller_i.instr_fetch_err; diff --git a/dv/verilator/simple_system_cosim/ibex_simple_system_cosim_checker.sv b/dv/verilator/simple_system_cosim/ibex_simple_system_cosim_checker.sv index 3d97417970..71317fd38a 100644 --- a/dv/verilator/simple_system_cosim/ibex_simple_system_cosim_checker.sv +++ b/dv/verilator/simple_system_cosim/ibex_simple_system_cosim_checker.sv @@ -63,7 +63,8 @@ module ibex_simple_system_cosim_checker #( if (riscv_cosim_step(cosim_handle, u_top.rvfi_rd_addr, u_top.rvfi_rd_wdata, u_top.rvfi_pc_rdata, u_top.rvfi_trap, - u_top.rvfi_ext_rf_wr_suppress) == 0) + u_top.rvfi_ext_rf_wr_suppress, u_top.rvfi_ext_expanded_insn_valid, + u_top.rvfi_ext_expanded_insn, u_top.rvfi_ext_expanded_insn_last) == 0) begin $display("FAILURE: Co-simulation mismatch at time %t", $time()); for (int i = 0;i < riscv_cosim_get_num_errors(cosim_handle); ++i) begin diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index b7d8d399a4..1d81f97e7d 100644 --- a/vendor/google_riscv-dv.lock.hjson +++ b/vendor/google_riscv-dv.lock.hjson @@ -1,4 +1,4 @@ -// Copyright lowRISC contributors. +// Copyright lowRISC contributors (OpenTitan project). // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 @@ -8,7 +8,7 @@ { upstream: { - url: https://github.com/chipsalliance/riscv-dv - rev: 71666ebacd69266b1abb7cdbad5e1897ce5884e6 + url: https://github.com/SamuelRiedel/riscv-dv + rev: 71ceff7bb7d332fcf8037752ccdec19b33c2d210 } } diff --git a/vendor/google_riscv-dv.vendor.hjson b/vendor/google_riscv-dv.vendor.hjson index ea249598b3..972d9eb5f3 100644 --- a/vendor/google_riscv-dv.vendor.hjson +++ b/vendor/google_riscv-dv.vendor.hjson @@ -6,8 +6,8 @@ target_dir: "google_riscv-dv", upstream: { - url: "https://github.com/chipsalliance/riscv-dv", - rev: "master", + url: "https://github.com/SamuelRiedel/riscv-dv", + rev: "zcmp-extension", }, exclude_from_upstream: [ diff --git a/vendor/google_riscv-dv/.github/workflows/build-spike.yml b/vendor/google_riscv-dv/.github/workflows/build-spike.yml index 442e825e82..59fbfffb34 100644 --- a/vendor/google_riscv-dv/.github/workflows/build-spike.yml +++ b/vendor/google_riscv-dv/.github/workflows/build-spike.yml @@ -36,7 +36,7 @@ jobs: key: ${{ env.cache_name }}_${{ env.cache_date }} restore-keys: ${{ env.cache_name }}_ - - name: Install prerequisities + - name: Install prerequisites if: ${{ steps.cache.outputs.cache-hit != 'true' }} run: | sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ diff --git a/vendor/google_riscv-dv/.github/workflows/run-tests.yml b/vendor/google_riscv-dv/.github/workflows/run-tests.yml index dd93d0cf63..7858a7065c 100644 --- a/vendor/google_riscv-dv/.github/workflows/run-tests.yml +++ b/vendor/google_riscv-dv/.github/workflows/run-tests.yml @@ -22,12 +22,14 @@ jobs: name: Prepare test types run: | python3 -m pip install pyyaml - echo "tests=$(python3 .github/scripts/parse_testlist.py $RISCV_TARGET)" | tee -a $GITHUB_OUTPUT + python3 .github/scripts/parse_testlist.py $RISCV_TARGET > tests.list + echo "tests=$(cat tests.list)" | tee -a $GITHUB_OUTPUT - id: hash name: Prepare files' hash run: | - echo "files-hash=$(sha256sum **/*.sv **/*.py **/*.yml **/*.yaml | cut -d\ -f1 | sha256sum | cut -d\ -f1)" | tee -a $GITHUB_OUTPUT - + sha256sum **/*.sv **/*.py **/*.yaml > file.hash + echo "files-hash=$(cat file.hash | cut -d\ -f1 | sha256sum | cut -d\ -f1)" | tee -a $GITHUB_OUTPUT + generate-code: runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] @@ -39,7 +41,7 @@ jobs: test: ${{ fromJSON(needs.generate-config.outputs.test-types) }} version: [ uvm ] include: - - test: riscv_arithmetic_basic_test + - test: riscv_arithmetic_basic_test version: pyflow env: GHA_EXTERNAL_DISK: additional-tools @@ -89,9 +91,10 @@ jobs: --isa $RISCV_TARGET --mabi ilp32 --steps gen -v -o test 2>&1 | tee test/generate.log - name: Upload Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: + name: generate_code_${{ matrix.test }}_${{ matrix.version }} path: | test/asm_test/*.S @@ -116,7 +119,14 @@ jobs: - uses: actions/checkout@v4 - name: Install dependencies - run: sudo apt-get -qqy update && sudo apt-get -qqy install gcc-riscv64-unknown-elf device-tree-compiler + run: sudo apt-get -qqy update && sudo apt-get -qqy install device-tree-compiler + + - name: Install cross-compiler + shell: bash + run: | + echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null + sudo apt -qqy update && sudo apt -qqy --no-install-recommends install gcc-riscv64-unknown-elf + riscv64-unknown-elf-gcc --version - name: Setup python # python dependencies cannot be properly downloaded with new versions of python @@ -174,9 +184,10 @@ jobs: --isa $RISCV_TARGET --mabi ilp32 --steps gcc_compile,iss_sim -v -o test 2>&1 | tee -a test/generate.log - name: Upload Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: + name: run_tests_log_${{ matrix.test }}_${{ matrix.version }} path: | - test/asm_test/*.log test/*.log + test/**/${{ matrix.test }}*.log diff --git a/vendor/google_riscv-dv/__init__.py b/vendor/google_riscv-dv/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/google_riscv-dv/run.py b/vendor/google_riscv-dv/run.py index b6b8aa0a3b..8477c403ba 100644 --- a/vendor/google_riscv-dv/run.py +++ b/vendor/google_riscv-dv/run.py @@ -124,13 +124,14 @@ def get_generator_cmd(simulator, simulator_yaml, cov, exp, debug_cmd): sys.exit(RET_FAIL) -def parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd): +def parse_iss_yaml(iss, iss_yaml, isa, priv, setting_dir, debug_cmd): """Parse ISS YAML to get the simulation command Args: iss : target ISS used to look up in ISS YAML iss_yaml : ISS configuration file in YAML format isa : ISA variant passed to the ISS + priv: : privilege modes setting_dir : Generator setting directory debug_cmd : Produce the debug cmd log without running @@ -140,6 +141,9 @@ def parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd): logging.info("Processing ISS setup file : {}".format(iss_yaml)) yaml_data = read_yaml(iss_yaml) + # Path to the "yaml" subdirectory + yaml_dir = os.path.dirname(iss_yaml) + # Path to the "scripts" subdirectory my_path = os.path.dirname(os.path.realpath(__file__)) scripts_dir = os.path.join(my_path, "scripts") # Search for matched ISS @@ -166,7 +170,9 @@ def parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd): cmd = re.sub("\", variant, cmd) else: cmd = re.sub("\", isa, cmd) + cmd = re.sub("\", priv, cmd) cmd = re.sub("\", scripts_dir, cmd) + cmd = re.sub("\", yaml_dir, cmd) return cmd logging.error("Cannot find ISS {}".format(iss)) sys.exit(RET_FAIL) @@ -442,7 +448,12 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts, debug_cmd): if 'gen_opts' in test: # Disable compressed instruction if re.search('disable_compressed_instr', test['gen_opts']): - test_isa = re.sub("c", "", test_isa) + # Note that this substitution assumes the cannonical order + # of extensions, i.e. that extensions with preceding + # underscores will be provided after all letter extensions. + # This assumption should hold true, as this is a + # requirement enforced by e.g. gcc + test_isa = re.sub(r"(rv.+?)c", r"\1", test_isa) # If march/mabi is not defined in the test gcc_opts, use the default # setting from the command line. if not re.search('march', cmd): @@ -641,7 +652,7 @@ def run_c_from_dir(c_test_dir, iss_yaml, isa, mabi, gcc_opts, iss, def iss_sim(test_list, output_dir, iss_list, iss_yaml, iss_opts, - isa, setting_dir, timeout_s, debug_cmd): + isa, priv, setting_dir, timeout_s, debug_cmd): """Run ISS simulation with the generated test program Args: @@ -651,13 +662,15 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, iss_opts, iss_yaml : ISS configuration file in YAML format iss_opts : ISS command line options isa : ISA variant passed to the ISS + priv : privilege modes setting_dir : Generator setting directory timeout_s : Timeout limit in seconds debug_cmd : Produce the debug cmd log without running """ for iss in iss_list.split(","): log_dir = ("{}/{}_sim".format(output_dir, iss)) - base_cmd = parse_iss_yaml(iss, iss_yaml, isa, setting_dir, debug_cmd) + base_cmd = parse_iss_yaml(iss, iss_yaml, isa, priv, setting_dir, debug_cmd) + base_cmd += iss_opts logging.info("{} sim log dir: {}".format(iss, log_dir)) run_cmd_output(["mkdir", "-p", log_dir]) for test in test_list: @@ -814,6 +827,8 @@ def parse_args(cwd): command is not specified") parser.add_argument("--isa", type=str, default="", help="RISC-V ISA subset") + parser.add_argument("--priv", type=str, default="m", + help="RISC-V privilege modes enabled in simulation [su]") parser.add_argument("-m", "--mabi", type=str, default="", help="mabi used for compilation", dest="mabi") parser.add_argument("--gen_timeout", type=int, default=360, @@ -1147,7 +1162,7 @@ def main(): if args.steps == "all" or re.match(".*iss_sim.*", args.steps): iss_sim(matched_list, output_dir, args.iss, args.iss_yaml, args.iss_opts, - args.isa, args.core_setting_dir, args.iss_timeout, + args.isa, args.priv, args.core_setting_dir, args.iss_timeout, args.debug) # Compare ISS simulation result diff --git a/vendor/google_riscv-dv/scripts/instr_trace_compare.py b/vendor/google_riscv-dv/scripts/instr_trace_compare.py index b0fd3e88cc..615665381c 100644 --- a/vendor/google_riscv-dv/scripts/instr_trace_compare.py +++ b/vendor/google_riscv-dv/scripts/instr_trace_compare.py @@ -125,6 +125,8 @@ def compare_trace_csv(csv1, csv2, name1, name2, log, instr_trace_2[trace_2_index].gpr, gpr_val_2) if gpr_state_change_2 == 1: + fd.write("Mismatch[{}]:\n[{}] {} : {}\n".format( + mismatch_cnt, trace_1_index, name1,trace.get_trace_string())) fd.write("{} instructions left in trace {}\n".format( len(instr_trace_2) - trace_2_index, name2)) mismatch_cnt += len(instr_trace_2) - trace_2_index diff --git a/vendor/google_riscv-dv/scripts/lib.py b/vendor/google_riscv-dv/scripts/lib.py index 872752f001..a12cbc08be 100644 --- a/vendor/google_riscv-dv/scripts/lib.py +++ b/vendor/google_riscv-dv/scripts/lib.py @@ -88,7 +88,7 @@ def get_env_var(var, debug_cmd=None): return val -def run_cmd(cmd, timeout_s=999, exit_on_error=1, check_return_code=True, +def run_cmd(cmd, timeout_s=3600, exit_on_error=1, check_return_code=True, debug_cmd=None): """Run a command and return output @@ -103,6 +103,12 @@ def run_cmd(cmd, timeout_s=999, exit_on_error=1, check_return_code=True, debug_cmd.write(cmd) debug_cmd.write("\n\n") return + def killgroup(ps): + try: + os.killpg(os.getpgid(ps.pid), signal.SIGTERM) + except AttributeError: #killpg not available on windows + ps.kill() + sys.exit(130) try: ps = subprocess.Popen("exec " + cmd, shell=True, @@ -112,21 +118,17 @@ def run_cmd(cmd, timeout_s=999, exit_on_error=1, check_return_code=True, env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + output = ps.communicate(timeout = timeout_s)[0] except subprocess.CalledProcessError: logging.error(ps.communicate()[0]) sys.exit(RET_FAIL) except KeyboardInterrupt: logging.info("\nExited Ctrl-C from user request.") - sys.exit(130) - try: - output = ps.communicate(timeout=timeout_s)[0] + killgroup(ps) except subprocess.TimeoutExpired: logging.error("Timeout[{}s]: {}".format(timeout_s, cmd)) output = "" - try: - os.killpg(os.getpgid(ps.pid), signal.SIGTERM) - except AttributeError: #killpg not available on windows - ps.kill() + killgroup(ps) rc = ps.returncode if rc and check_return_code and rc > 0: logging.info(output) diff --git a/vendor/google_riscv-dv/scripts/renode_log_to_trace_csv.py b/vendor/google_riscv-dv/scripts/renode_log_to_trace_csv.py index cee4a29ac0..351cf29bda 100644 --- a/vendor/google_riscv-dv/scripts/renode_log_to_trace_csv.py +++ b/vendor/google_riscv-dv/scripts/renode_log_to_trace_csv.py @@ -78,6 +78,10 @@ def process_renode_sim_log(log_name, csv_name): if not line: continue + # We've hit ecall, quit + if line.startswith("ECALL:"): + break + # Skip non-regdump if not line.startswith("REGDUMP:"): continue diff --git a/vendor/google_riscv-dv/scripts/renode_wrapper.py b/vendor/google_riscv-dv/scripts/renode_wrapper.py index 245de92781..16c097f48a 100644 --- a/vendor/google_riscv-dv/scripts/renode_wrapper.py +++ b/vendor/google_riscv-dv/scripts/renode_wrapper.py @@ -8,12 +8,14 @@ REPL_TEMPLATE = """ memory: Memory.MappedMemory @ sysbus 0x80000000 - size: 0x10000 + size: {mem} -cpu: CPU.RiscV32 @ sysbus +cpu: CPU.{cpu_type} @ sysbus cpuType: "{isa}" timeProvider: clint hartId: 0 + {priv_levels} + {additional_cpu_parameters} clint: IRQControllers.CoreLevelInterruptor @ sysbus 0x02000000 [0,1] -> cpu@[3,7] @@ -29,8 +31,9 @@ cpu MaximumBlockSize 1 cpu SetHookAtBlockEnd "print('REGDUMP:' + ','.join(self.GetRegistersValues()))" +cpu InstallCustomInstructionHandlerFromString "00000000000000000000000001110011" "print('ECALL:');" -emulation RunFor "0.000100" +emulation RunFor "0.001" quit """ @@ -69,6 +72,32 @@ def main(): required=True, help="ELF file to run", ) + parser.add_argument( + "--mem-size", + type=str, + default="0x100000", + help="Memory size", + ) + parser.add_argument( + "--cpu-type", + type=str, + default="Riscv32", + help="Renode CPU type", + ) + parser.add_argument( + "--priv", + type=str, + default="", + help="Supported privilege levels", + ) + # Some CPUs might not expose these parameters as configurable + # allow the testing software to ignore/override them if needed + parser.add_argument( + "--additional-cpu-parameters", + type=str, + default="allowUnalignedAccesses: true", + help="Additional CPU parameters", + ) args = parser.parse_args() @@ -77,6 +106,16 @@ def main(): repl = os.path.join(tmpdir, "riscv.repl") resc = os.path.join(tmpdir, "riscv.resc") + priv_levels = "" + if args.priv: + priv_levels += "privilegeLevels: PrivilegeLevels." + if "m" in args.priv: + priv_levels += "Machine" + if "s" in args.priv: + priv_levels += "Supervisor" + if "u" in args.priv: + priv_levels += "User" + params = { "renode": args.renode, "isa": args.isa, @@ -84,6 +123,10 @@ def main(): "repl": repl, "resc": resc, "log": args.log, + "mem": args.mem_size, + "cpu_type": args.cpu_type, + "priv_levels": priv_levels, + "additional_cpu_parameters": args.additional_cpu_parameters, } # Render REPL template diff --git a/vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv b/vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv index 02fdf338a5..a603262fe7 100644 --- a/vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv +++ b/vendor/google_riscv-dv/src/isa/riscv_compressed_instr.sv @@ -33,12 +33,19 @@ class riscv_compressed_instr extends riscv_instr; } // C_ADDI16SP is only valid when rd == SP if (instr_name == C_ADDI16SP) { + rs1 == SP; rd == SP; } if (instr_name inside {C_JR, C_JALR}) { rs2 == ZERO; rs1 != ZERO; } + // These formats potentially have rd == rs1 + if (format inside {CA_FORMAT, CB_FORMAT, CI_FORMAT, CR_FORMAT}) { + if (has_rd && has_rs1) { + rd == rs1; + } + } } constraint imm_val_c { @@ -156,7 +163,13 @@ class riscv_compressed_instr extends riscv_instr; has_rs1 = 1'b0; has_imm = 1'b0; end - CI_FORMAT, CIW_FORMAT: begin + CI_FORMAT: begin + if (instr_name inside {C_LI, C_LUI, C_LWSP, C_NOP, C_EBREAK}) begin + has_rs1 = 1'b0; + end + has_rs2 = 1'b0; + end + CIW_FORMAT: begin has_rs1 = 1'b0; has_rs2 = 1'b0; end @@ -166,7 +179,7 @@ class riscv_compressed_instr extends riscv_instr; has_rd = 1'b0; end CB_FORMAT: begin - if (instr_name != C_ANDI) has_rd = 1'b0; + if (instr_name inside {C_BEQZ, C_BNEZ}) has_rd = 1'b0; has_rs2 = 1'b0; end endcase diff --git a/vendor/google_riscv-dv/src/isa/riscv_instr.sv b/vendor/google_riscv-dv/src/isa/riscv_instr.sv index f44e972a28..229afc9235 100644 --- a/vendor/google_riscv-dv/src/isa/riscv_instr.sv +++ b/vendor/google_riscv-dv/src/isa/riscv_instr.sv @@ -45,6 +45,8 @@ class riscv_instr extends uvm_object; rand riscv_reg_t rs1; rand riscv_reg_t rd; rand bit [31:0] imm; + rand bit [3:0] rlist; + rand int stack_adj; // Helper fields bit [31:0] imm_mask = 32'hFFFF_FFFF; @@ -66,6 +68,8 @@ class riscv_instr extends uvm_object; bit has_rs2 = 1'b1; bit has_rd = 1'b1; bit has_imm = 1'b1; + bit has_rlist = 1'b0; + bit has_stack_adj = 1'b0; constraint imm_c { if (instr_name inside {SLLIW, SRLIW, SRAIW}) { @@ -111,7 +115,8 @@ class riscv_instr extends uvm_object; if (cfg.no_fence && (instr_name inside {FENCE, FENCE_I, SFENCE_VMA})) continue; if ((instr_inst.group inside {supported_isa}) && !(cfg.disable_compressed_instr && - (instr_inst.group inside {RV32C, RV64C, RV32DC, RV32FC, RV128C})) && + (instr_inst.group inside {RV32C, RV64C, RV32DC, RV32FC, RV128C, + RV32ZCB, RV64ZCB, RV32ZCMP, RV64ZCMP})) && !(!cfg.enable_floating_point && (instr_inst.group inside {RV32F, RV64F, RV32D, RV64D})) && !(!cfg.enable_vector_extension && @@ -296,6 +301,7 @@ class riscv_instr extends uvm_object; rs2.rand_mode(has_rs2); rd.rand_mode(has_rd); imm.rand_mode(has_imm); + stack_adj.rand_mode(has_stack_adj); if (category != CSR) begin csr.rand_mode(0); end @@ -586,6 +592,40 @@ class riscv_instr extends uvm_object; return imm_str; endfunction + virtual function string get_rlist(); + // rlist 0-3 are reserved for future extensions + if (rlist < 4 || rlist > 15) begin + `uvm_fatal(`gfn, $sformatf("Unsupported rlist: %0d", rlist)) + end + // Handle the specific cases and use a default for the general pattern. + case(rlist) + 4: return "{ra}"; + 5: return "{ra, s0}"; + 15: return "{ra, s0-s11}"; // The special case for s10/s11 + // The default case handles the general pattern for rlist 6 through 14 + default: return $sformatf("{ra, s0-s%0d}", rlist - 5); + endcase + endfunction + + virtual function riscv_reglist_t get_rlist_as_list(); + case(rlist) + 4: return '{RA}; + 5: return '{RA, S0}; + 6: return '{RA, S0, S1}; + 7: return '{RA, S0, S1, S2}; + 8: return '{RA, S0, S1, S2, S3}; + 9: return '{RA, S0, S1, S2, S3, S4}; + 10: return '{RA, S0, S1, S2, S3, S4, S5}; + 11: return '{RA, S0, S1, S2, S3, S4, S5, S6}; + 12: return '{RA, S0, S1, S2, S3, S4, S5, S6, S7}; + 13: return '{RA, S0, S1, S2, S3, S4, S5, S6, S7, S8}; + 14: return '{RA, S0, S1, S2, S3, S4, S5, S6, S7, S8, S9}; + 15: return '{RA, S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11}; + default: `uvm_fatal(`gfn, $sformatf("Unsupported rlist: %0d", rlist)) + endcase + return '{}; + endfunction + virtual function void clear_unused_label(); if(has_label && !is_branch_target && is_local_numeric_label) begin has_label = 1'b0; @@ -620,6 +660,10 @@ class riscv_instr extends uvm_object; imm_str = $sformatf("%0d", $signed(imm)); endfunction + virtual function int get_imm_val(); + return $signed(imm); + endfunction + `include "isa/riscv_instr_cov.svh" endclass diff --git a/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh b/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh index 6819f3836c..54773de3d1 100644 --- a/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh +++ b/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh @@ -408,6 +408,38 @@ // c.j imm get_val(operands[0], imm); end + CU_FORMAT: begin + rs1 = get_gpr(operands[0]); + rs1_value = get_gpr_state(operands[0]); + end + CLB_FORMAT, CLH_FORMAT: begin + get_val(operands[2], imm); + rs1 = get_gpr(operands[1]); + rs1_value = get_gpr_state(operands[1]); + end + CSB_FORMAT, CSH_FORMAT: begin + rs2 = get_gpr(operands[0]); + rs2_value = get_gpr_state(operands[0]); + get_val(operands[2], imm); + rs1 = get_gpr(operands[1]); + rs1_value = get_gpr_state(operands[1]); + end + CMMV_FORMAT: begin + // cm.mva01s rs1, rs2 + // cm.mvsa01 r1s, r2s + rs1 = get_gpr(operands[0]); + rs1_value = get_gpr_state(operands[0]); + rs2 = get_gpr(operands[1]); + rs2_value = get_gpr_state(operands[1]); + end + CMPP_FORMAT: begin + // cm.push {reg_list}, -stack_adj + // cm.pop {reg_list}, stack_adj + // cm.popret {reg_list}, stack_adj + // cm.popretz {reg_list}, stack_adj + get_val(operands[0], rlist); + get_val(operands[1], stack_adj); + end default: `uvm_fatal(`gfn, $sformatf("Unsupported format %0s", format)) endcase endfunction : update_src_regs diff --git a/vendor/google_riscv-dv/src/isa/riscv_zcb_instr.sv b/vendor/google_riscv-dv/src/isa/riscv_zcb_instr.sv new file mode 100644 index 0000000000..7eb7ce4b69 --- /dev/null +++ b/vendor/google_riscv-dv/src/isa/riscv_zcb_instr.sv @@ -0,0 +1,225 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2023 Frontgrade Gaisler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class riscv_zcb_instr extends riscv_instr; + + // This code is based on the frozen v.1.0.1 code reduction specification. + // Most of the code is copied from the riscv_compressed_instr class. + + constraint rvc_csr_c { + // Registers specified by the three-bit rs1’, rs2’, and rd/rs1’ + if (format inside {CLB_FORMAT, CSB_FORMAT, CLH_FORMAT, CSH_FORMAT, CU_FORMAT, CA_FORMAT}) { + if (has_rs1) { + rs1 inside {[S0:A5]}; + } + if (has_rs2) { + rs2 inside {[S0:A5]}; + } + if (has_rd) { + rd inside {[S0:A5]}; + } + } + // CU_FORMAT and CA_FORMAT has rd == rs1 + if (format inside {CU_FORMAT, CA_FORMAT}) { + if (has_rd && has_rs1) { + rd == rs1; + } + } + } + + `uvm_object_utils(riscv_zcb_instr) + + function new(string name = ""); + super.new(name); + rs1 = S0; + rs2 = S0; + rd = S0; + is_compressed = 1'b1; + endfunction : new + + virtual function void set_imm_len(); + if (format inside {CLB_FORMAT, CSB_FORMAT}) begin + imm_len = 2; + end else if (format inside {CLH_FORMAT, CSH_FORMAT}) begin + imm_len = 1; + end + endfunction : set_imm_len + + virtual function void set_rand_mode(); + case (format) inside + CLB_FORMAT: begin + has_rs2 = 1'b0; + end + CSB_FORMAT: begin + has_rd = 1'b0; + end + CLH_FORMAT: begin + has_rs2 = 1'b0; + end + CSH_FORMAT: begin + has_rd = 1'b0; + end + CU_FORMAT: begin + has_rs2 = 1'b0; + has_imm = 1'b0; + end + CA_FORMAT: begin + has_imm = 1'b0; + end + default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW) + endcase + endfunction + + // Convert the instruction to assembly code + virtual function string convert2asm(string prefix = ""); + string asm_str; + asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN); + case(format) + CLB_FORMAT, CLH_FORMAT: + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name()); + CSB_FORMAT, CSH_FORMAT: + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name()); + CU_FORMAT: + asm_str = $sformatf("%0s%0s", asm_str, rs1.name); + CA_FORMAT: + asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name()); + default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW) + endcase + + if (comment != "") + asm_str = {asm_str, " #",comment}; + return asm_str.tolower(); + endfunction : convert2asm + + // Convert the instruction to assembly code + virtual function string convert2bin(string prefix = ""); + string binary; + case (instr_name) inside + C_LBU: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), imm[0], imm[1], + get_c_gpr(rd), get_c_opcode()}); + C_LHU: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b0, imm[1], + get_c_gpr(rd), get_c_opcode()}); + C_LH: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b1, imm[1], + get_c_gpr(rd), get_c_opcode()}); + C_SB: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), imm[0], imm[1], + get_c_gpr(rs2), get_c_opcode()}); + C_SH: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b0, imm[1], + get_c_gpr(rs2), get_c_opcode()}); + C_ZEXT_B: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11000, + get_c_opcode()}); + C_SEXT_B: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11001, + get_c_opcode()}); + C_ZEXT_H: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11010, + get_c_opcode()}); + C_SEXT_H: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11011, + get_c_opcode()}); + C_ZEXT_W: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11100, + get_c_opcode()}); + C_NOT: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11101, + get_c_opcode()}); + C_MUL: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 2'b10, + get_c_gpr(rs2), get_c_opcode()}); + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + return {prefix, binary}; + endfunction : convert2bin + + // Get opcode for zcb instruction + virtual function bit [1:0] get_c_opcode(); + case (instr_name) inside + C_ZEXT_B, C_SEXT_B, C_ZEXT_H, C_SEXT_H, + C_ZEXT_W, C_NOT, C_MUL : get_c_opcode = 2'b01; + C_LBU, C_LHU, C_LH, C_SB, C_SH : get_c_opcode = 2'b00; + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_c_opcode + + virtual function bit [5:0] get_func6(); + case (instr_name) + C_LBU: get_func6 = 6'b100000; + C_LHU: get_func6 = 6'b100001; + C_LH: get_func6 = 6'b100001; + C_SB: get_func6 = 6'b100010; + C_SH: get_func6 = 6'b100011; + C_ZEXT_B: get_func6 = 6'b100011; + C_SEXT_B: get_func6 = 6'b100111; + C_ZEXT_H: get_func6 = 6'b100111; + C_SEXT_H: get_func6 = 6'b100111; + C_ZEXT_W: get_func6 = 6'b100111; + C_NOT: get_func6 = 6'b100111; + C_MUL: get_func6 = 6'b100111; + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_func6 + + virtual function bit is_supported(riscv_instr_gen_config cfg); + return (cfg.enable_zcb_extension && + // RV32C, RV32Zbb, RV32Zba, M/Zmmul is prerequisites for this extension + (RV32ZBB inside {supported_isa}) && + (RV32C inside {supported_isa}) && + (RV32ZBA inside {supported_isa}) && + ((RV32M inside {supported_isa}) || (RV32ZMMUL inside {supported_isa})) && + ((RV32ZCB inside {supported_isa} || RV64ZCB inside {supported_isa})) && + instr_name inside { + C_ZEXT_B, C_SEXT_B, C_ZEXT_H, C_SEXT_H, C_ZEXT_W, + C_NOT, C_MUL, C_LBU, C_LHU, C_LH, C_SB, C_SH + }); + endfunction : is_supported + + // For coverage + virtual function void update_src_regs(string operands[$]); + case(format) + CU_FORMAT: begin + rs1 = get_gpr(operands[0]); + rs1_value = get_gpr_state(operands[0]); + end + CLB_FORMAT, CLH_FORMAT: begin + get_val(operands[2], imm); + rs1 = get_gpr(operands[1]); + rs1_value = get_gpr_state(operands[1]); + end + CSB_FORMAT, CSH_FORMAT: begin + rs2 = get_gpr(operands[0]); + rs2_value = get_gpr_state(operands[0]); + get_val(operands[2], imm); + rs1 = get_gpr(operands[1]); + rs1_value = get_gpr_state(operands[1]); + end + CA_FORMAT: begin + rs2 = get_gpr(operands[1]); + rs2_value = get_gpr_state(operands[1]); + rs1 = get_gpr(operands[0]); + rs1_value = get_gpr_state(operands[0]); + end + default: ; + endcase + super.update_src_regs(operands); + endfunction : update_src_regs + +endclass : riscv_zcb_instr; diff --git a/vendor/google_riscv-dv/src/isa/riscv_zcmp_instr.sv b/vendor/google_riscv-dv/src/isa/riscv_zcmp_instr.sv new file mode 100644 index 0000000000..81c0c6dc72 --- /dev/null +++ b/vendor/google_riscv-dv/src/isa/riscv_zcmp_instr.sv @@ -0,0 +1,225 @@ +/* + * Copyright 2025 Google LLC + * Copyright 2025 lowRISC CIC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class riscv_zcmp_instr extends riscv_instr; + + constraint rvc_csr_c { + // Solve the stack adjustment first, so we can control the stack size + solve stack_adj before rlist; + if (format == CMPP_FORMAT) { + if (instr_name == CM_PUSH) { + // For PUSH, stack adjustment is negative + stack_adj inside {-16, -32, -48, -64, -80, -96, -112}; + (stack_adj == -16) -> rlist inside {[4:7]}; + (stack_adj == -32) -> rlist inside {[4:11]}; + (stack_adj == -48) -> rlist inside {[4:14]}; + (stack_adj == -64) -> rlist inside {[4:15]}; + (stack_adj == -80) -> rlist inside {[8:15]}; + (stack_adj == -96) -> rlist inside {[12:15]}; + (stack_adj == -112) -> rlist inside {15}; + } else { + // For POP and POPRET, stack adjustment is positive + stack_adj inside {16, 32, 48, 64, 80, 96, 112}; + (rlist inside {[4:7]}) -> stack_adj inside {16, 32, 48, 64}; + (rlist inside {[8:11]}) -> stack_adj inside {32, 48, 64, 80}; + (rlist inside {[12:14]}) -> stack_adj inside {48, 64, 80, 96}; + (rlist == 15) -> stack_adj inside {64, 80, 96, 112}; + } + // rlist can be anything between 4 and 15. 0-3 are reserved for future use. + rlist inside {[4:15]}; + } + if (format == CMMV_FORMAT) { + // Always has rs1 and rs2 and they must be different + rs1 != rs2; + // Those instructions use a special encoding, only S0, S1, S2-S7 are allowed + // which correspond to x8, x9, x18-x23, so the actual registers used are + // {r1sc[2:1]>0,r1sc[2:1]==0,r1sc[2:0]}; + // So for registers beyond x16 we prepend 0x10 to the three LSB + // For the registers x8 and x9 we prepend 0x01 to the three LSB + rs1 inside {S0, S1, [S2:S7]}; + rs2 inside {S0, S1, [S2:S7]}; + } + } + + `uvm_object_utils(riscv_zcmp_instr) + + function new(string name = ""); + super.new(name); + rs1 = S0; + rs2 = S0; + rlist = 4; + is_compressed = 1'b1; + stack_adj = instr_name == CM_PUSH ? -16 : 16; + endfunction : new + + virtual function void set_rand_mode(); + case (format) inside + CMMV_FORMAT : begin + has_imm = 1'b0; + end + CMPP_FORMAT : begin + has_rs1 = 1'b0; + has_rs2 = 1'b0; + has_rd = 1'b0; + has_rlist = 1'b1; + has_imm = 1'b0; + has_stack_adj = 1'b1; + end + default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW) + endcase + endfunction + + // Convert the instruction to assembly code + virtual function string convert2asm(string prefix = ""); + string asm_str; + asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN); + case(format) + CMMV_FORMAT: + asm_str = $sformatf("%0s %0s, %0s", asm_str, rs1.name(), rs2.name()); + CMPP_FORMAT: begin + asm_str = $sformatf("%0s %0s, %0d", asm_str, get_rlist(), get_stack_adj()); + end + default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW) + endcase + + if (comment != "") + asm_str = {asm_str, " #",comment}; + return asm_str.tolower(); + endfunction : convert2asm + + // Convert the instruction to binary code + virtual function string convert2bin(string prefix = ""); + string binary; + case (instr_name) inside + CM_PUSH: + binary = $sformatf( + "0x%4h", {get_func6(), get_func2(), rlist, get_stack_adj_encoding(), get_c_opcode()}); + CM_POP: + binary = $sformatf( + "0x%4h", {get_func6(), get_func2(), rlist, get_stack_adj_encoding(), get_c_opcode()}); + CM_POPRETZ: + binary = $sformatf( + "0x%4h", {get_func6(), get_func2(), rlist, get_stack_adj_encoding(), get_c_opcode()}); + CM_POPRET: + binary = $sformatf( + "0x%4h", {get_func6(), get_func2(), rlist, get_stack_adj_encoding(), get_c_opcode()}); + CM_MVA01S: + binary = $sformatf( + "0x%4h", {get_func6(), get_c_gpr(rs1), get_func2(), get_c_gpr(rs2), get_c_opcode()}); + CM_MVSA01: + binary = $sformatf( + "0x%4h", {get_func6(), get_c_gpr(rs1), get_func2(), get_c_gpr(rs2), get_c_opcode()}); + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + return {prefix, binary}; + endfunction : convert2bin + + // Get opcode for zcmp instruction + virtual function bit [1:0] get_c_opcode(); + case (instr_name) inside + CM_PUSH, CM_POP, CM_POPRETZ, CM_POPRET, CM_MVA01S, CM_MVSA01 : get_c_opcode = 2'b10; + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_c_opcode + + virtual function bit [5:0] get_func6(); + case (instr_name) inside + CM_PUSH: get_func6 = 6'b101110; + CM_POP: get_func6 = 6'b101110; + CM_POPRETZ: get_func6 = 6'b101111; + CM_POPRET: get_func6 = 6'b101111; + CM_MVSA01: get_func6 = 6'b101011; + CM_MVA01S: get_func6 = 6'b101011; + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_func6 + + virtual function bit [1:0] get_func2(); + case (instr_name) inside + CM_PUSH: get_func2 = 2'b00; + CM_POP: get_func2 = 2'b10; + CM_POPRETZ: get_func2 = 2'b00; + CM_POPRET: get_func2 = 2'b10; + CM_MVSA01: get_func2 = 2'b01; + CM_MVA01S: get_func2 = 2'b11; + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_func2 + + virtual function bit is_supported(riscv_instr_gen_config cfg); + `uvm_info(`gfn, "ZCMP Check supported", UVM_LOW) + return (cfg.enable_zcmp_extension && + // RV32C, RV32Zbb, RV32Zba, M/Zmmul is prerequisites for this extension + (RV32C inside {supported_isa} || RV64C inside {supported_isa}) && + (RV32ZCMP inside {supported_isa} || RV64ZCMP inside {supported_isa}) && + instr_name inside { + CM_PUSH, CM_POP, CM_POPRET, CM_POPRETZ, CM_MVA01S, CM_MVSA01 + }); + endfunction : is_supported + + // For coverage + virtual function void update_src_regs(string operands[$]); + case(format) + CMMV_FORMAT: begin + rs1 = get_gpr(operands[0]); + rs1_value = get_gpr_state(operands[0]); + rs2 = get_gpr(operands[1]); + rs2_value = get_gpr_state(operands[1]); + end + CMPP_FORMAT: begin + get_val(operands[0], rlist); + get_val(operands[1], stack_adj); + end + default: ; + endcase + super.update_src_regs(operands); + endfunction : update_src_regs + + virtual function bit [1:0] get_stack_adj_encoding(); + int unsigned stack_adj_base; + int unsigned stack_adj_abs; + bit [1:0] stack_adj_encoding; + if (XLEN == 32) begin + case (rlist) + 4, 5, 6, 7: stack_adj_base = 16; + 8, 9, 10, 11: stack_adj_base = 32; + 12, 13, 14: stack_adj_base = 48; + 15: stack_adj_base = 64; + default: stack_adj_base = 0; + endcase + end else begin + case (rlist) + 4, 5: stack_adj_base = 16; + 6, 7: stack_adj_base = 32; + 8, 9: stack_adj_base = 48; + 10, 11: stack_adj_base = 64; + 12, 13: stack_adj_base = 80; + 14: stack_adj_base = 96; + 15: stack_adj_base = 122; + default: stack_adj_base = 0; + endcase + end + stack_adj_abs = instr_name == CM_PUSH ? -stack_adj : stack_adj; + stack_adj_encoding = (stack_adj_abs - stack_adj_base) / 16; + return stack_adj_encoding; + endfunction + + virtual function int get_stack_adj(); + return stack_adj; + endfunction + +endclass : riscv_zcmp_instr; diff --git a/vendor/google_riscv-dv/src/isa/rv32zcb_instr.sv b/vendor/google_riscv-dv/src/isa/rv32zcb_instr.sv new file mode 100644 index 0000000000..d83fbd806f --- /dev/null +++ b/vendor/google_riscv-dv/src/isa/rv32zcb_instr.sv @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2023 Frontgrade Gaisler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +`DEFINE_ZCB_INSTR(C_LBU, CLB_FORMAT, LOAD, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_LHU, CLH_FORMAT, LOAD, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_LH, CLH_FORMAT, LOAD, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_SB, CSB_FORMAT, STORE, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_SH, CSH_FORMAT, STORE, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_ZEXT_B, CU_FORMAT, ARITHMETIC, RV32ZCB) +`DEFINE_ZCB_INSTR(C_SEXT_B, CU_FORMAT, ARITHMETIC, RV32ZCB) +`DEFINE_ZCB_INSTR(C_ZEXT_H, CU_FORMAT, ARITHMETIC, RV32ZCB) +`DEFINE_ZCB_INSTR(C_SEXT_H, CU_FORMAT, ARITHMETIC, RV32ZCB) +`DEFINE_ZCB_INSTR(C_NOT, CU_FORMAT, LOGICAL, RV32ZCB) +`DEFINE_ZCB_INSTR(C_MUL, CA_FORMAT, ARITHMETIC, RV32ZCB) + diff --git a/vendor/google_riscv-dv/src/isa/rv32zcmp_instr.sv b/vendor/google_riscv-dv/src/isa/rv32zcmp_instr.sv new file mode 100644 index 0000000000..9faf550303 --- /dev/null +++ b/vendor/google_riscv-dv/src/isa/rv32zcmp_instr.sv @@ -0,0 +1,24 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2023 Frontgrade Gaisler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +`DEFINE_ZCMP_INSTR(CM_PUSH, CMPP_FORMAT, STORE, RV32ZCMP) +`DEFINE_ZCMP_INSTR(CM_POP, CMPP_FORMAT, LOAD, RV32ZCMP) +`DEFINE_ZCMP_INSTR(CM_POPRETZ, CMPP_FORMAT, LOAD, RV32ZCMP) +`DEFINE_ZCMP_INSTR(CM_POPRET, CMPP_FORMAT, LOAD, RV32ZCMP) +`DEFINE_ZCMP_INSTR(CM_MVA01S, CMMV_FORMAT, ARITHMETIC, RV32ZCMP) +`DEFINE_ZCMP_INSTR(CM_MVSA01, CMMV_FORMAT, ARITHMETIC, RV32ZCMP) + diff --git a/vendor/google_riscv-dv/src/isa/rv64zcb_instr.sv b/vendor/google_riscv-dv/src/isa/rv64zcb_instr.sv new file mode 100644 index 0000000000..8225b82358 --- /dev/null +++ b/vendor/google_riscv-dv/src/isa/rv64zcb_instr.sv @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2023 Frontgrade Gaisler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +`DEFINE_ZCB_INSTR(C_ZEXT_W, CU_FORMAT, ARITHMETIC, RV64ZCB) diff --git a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv index 4c969241a1..fbcc97c3be 100644 --- a/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv +++ b/vendor/google_riscv-dv/src/riscv_asm_program_gen.sv @@ -459,6 +459,7 @@ class riscv_asm_program_gen extends uvm_object; RV32X, RV64X : misa[MISA_EXT_X] = 1'b1; RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS : ; // No Misa bit for Zb* extensions + RV32ZCB, RV64ZCB, RV32ZCMP, RV64ZCMP : ; // No Misa bit for Zc* extensions default : `uvm_fatal(`gfn, $sformatf("%0s is not yet supported", supported_isa[i].name())) endcase diff --git a/vendor/google_riscv-dv/src/riscv_defines.svh b/vendor/google_riscv-dv/src/riscv_defines.svh index 4d078e164b..39cfd10e1f 100644 --- a/vendor/google_riscv-dv/src/riscv_defines.svh +++ b/vendor/google_riscv-dv/src/riscv_defines.svh @@ -129,3 +129,13 @@ `define DEFINE_ZBS_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ class riscv_``instr_n``_instr extends riscv_zbs_instr; \ `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) + +//Zcb-extension instruction +`define DEFINE_ZCB_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_zcb_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) + +//Zcb-extension instruction +`define DEFINE_ZCMP_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_zcmp_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) diff --git a/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv b/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv index f3bc7080ae..7c3a54f71e 100644 --- a/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv +++ b/vendor/google_riscv-dv/src/riscv_directed_instr_lib.sv @@ -474,7 +474,8 @@ class riscv_int_numeric_corner_stream extends riscv_directed_instr_stream; for (int i = 0; i < num_of_instr; i++) begin riscv_instr instr = riscv_instr::get_rand_instr( .include_category({ARITHMETIC}), - .exclude_group({RV32C, RV64C, RV32F, RV64F, RV32D, RV64D})); + .exclude_group({RV32C, RV64C, RV32ZCB, RV64ZCB, RV32ZCMP, RV64ZCMP, + RV32F, RV64F, RV32D, RV64D})); randomize_gpr(instr); instr_list.push_back(instr); end diff --git a/vendor/google_riscv-dv/src/riscv_illegal_instr.sv b/vendor/google_riscv-dv/src/riscv_illegal_instr.sv index 60ff4b546c..d9977b81fd 100644 --- a/vendor/google_riscv-dv/src/riscv_illegal_instr.sv +++ b/vendor/google_riscv-dv/src/riscv_illegal_instr.sv @@ -213,6 +213,53 @@ class riscv_illegal_instr extends uvm_object; } } + constraint zcb_extension_c { + // zcb adds instructions to the reserved funct6 space 6'b100111 + // this constraint defines the subset of that op-code space which is still + // reserved. Only way to trigger this constraint should be with + // kReservedC0/C1 or by kIllegalCompressedOpcode. Since the reserved + // instructions at c_msb = 3'b100 && c_op = 2'b00 are not added to + // legal_c00_opcode this combination could occur. + if (RV32ZCB inside {supported_isa}) { + if (exception inside {kIllegalCompressedOpcode, kReservedCompressedInstr} + && c_msb == 3'b100) { + if (c_op == 2'b00) { + !(instr_bin[12:10] inside {3'b000, 3'b001, 3'b010, 3'b011}); //load/store + // bits 9:2 don't have any inavlid combinations, hence only bit 12:10 + // can yield an op-code which is reserved. + } else if (c_op == 2'b01 && instr_bin[12:10] == 3'b111) { + // if funct2 = 2'b10 there are no reserved op-codes + !(instr_bin[6:5] inside {2'b10}); //funct2 + if (instr_bin[6:5] == 2'b11) { + if (XLEN == 32){ + // c.zext.w not allowed in 32-bit mode + (instr_bin[4:2] inside {3'b100, 3'b110, 3'b111}); + } else { + // reserved opcodes + (instr_bin[4:2] inside {3'b110, 3'b111}); + } + } + } + } + } + } + + constraint zcmp_extension_c { + // zcmp adds instructions where funct3/c_msb = 3'b101 and c2/c_op = 2'b10 + // Those codes are legal if they match a valid Zcmp instruction + if (RV32ZCMP inside {supported_isa}) { + if (exception inside {kIllegalCompressedOpcode, kReservedCompressedInstr}) { + if (c_op == 2'b10 && c_msb == 3'b101) { + !(instr_bin[12:8] inside {5'b11000, 5'b11010, 5'b11100, 5'b11110}); // push/pop + if (instr_bin[12:10] == 3'b011) { + // double move instructions + !(instr_bin[6:5] inside {2'b01, 2'b11}); + } + } + } + } + } + constraint illegal_compressed_op_c { if (exception == kIllegalCompressedOpcode) { c_op != 2'b01; diff --git a/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv b/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv index badc423d65..d704456eec 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_cover_group.sv @@ -38,6 +38,8 @@ `define SAMPLE_ZBB(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbb_instr) `define SAMPLE_ZBC(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbc_instr) `define SAMPLE_ZBS(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbs_instr) +`define SAMPLE_ZCB(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zcb_instr) +`define SAMPLE_ZCMP(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zcmp_instr) `define INSTR_CG_BEGIN(INSTR_NAME, INSTR_CLASS = riscv_instr) \ covergroup ``INSTR_NAME``_cg with function sample(INSTR_CLASS instr); @@ -433,6 +435,20 @@ cp_rd : coverpoint instr.rd; \ `DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \ +`define ZCB_I_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1 { \ + bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \ + } \ + `DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) + +`define ZCMP_I_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1 { \ + bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \ + } \ + `DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) + `define B_I_INSTR_CG_BEGIN(INSTR_NAME) \ `INSTR_CG_BEGIN(INSTR_NAME, riscv_b_instr) \ cp_rs1 : coverpoint instr.rs1; \ @@ -1646,6 +1662,64 @@ class riscv_instr_cover_group; `CA_INSTR_CG_BEGIN(c_addw) `CG_END + // RV32ZCB + `CL_INSTR_CG_BEGIN(c_lbu) + `CG_END + + `CL_INSTR_CG_BEGIN(c_lhu) + `CG_END + + `CL_INSTR_CG_BEGIN(c_lh) + `CG_END + + `CS_INSTR_CG_BEGIN(c_sb) + `CG_END + + `CS_INSTR_CG_BEGIN(c_sh) + `CG_END + + // Similar to zbb with the exception of which registers can be used + `ZCB_I_INSTR_CG_BEGIN(c_zext_b) + `CG_END + + `ZCB_I_INSTR_CG_BEGIN(c_sext_b) + `CG_END + + `ZCB_I_INSTR_CG_BEGIN(c_zext_h) + `CG_END + + `ZCB_I_INSTR_CG_BEGIN(c_sext_h) + `CG_END + + `ZCB_I_INSTR_CG_BEGIN(c_not) + `CG_END + + `CA_INSTR_CG_BEGIN(c_mul) + `CG_END + + // RV64ZCB + `ZCB_I_INSTR_CG_BEGIN(c_zext_w) + `CG_END + + // TODO This needs more thought and probably different defines per type + `ZCMP_I_INSTR_CG_BEGIN(cm_push) + `CG_END + + `ZCMP_I_INSTR_CG_BEGIN(cm_pop) + `CG_END + + `ZCMP_I_INSTR_CG_BEGIN(cm_popretz) + `CG_END + + `ZCMP_I_INSTR_CG_BEGIN(cm_popret) + `CG_END + + `ZCMP_I_INSTR_CG_BEGIN(cm_mva01s) + `CG_END + + `ZCMP_I_INSTR_CG_BEGIN(cm_mvsa01) + `CG_END + `INSTR_CG_BEGIN(hint) cp_hint : coverpoint instr.binary[15:0] { wildcard bins addi = {16'b0000_1xxx_x000_0001, @@ -2071,6 +2145,29 @@ class riscv_instr_cover_group; bseti_cg = new(); `CG_SELECTOR_END + `CG_SELECTOR_BEGIN(RV32ZCB) + c_lbu_cg = new(); + c_lhu_cg = new(); + c_lh_cg = new(); + c_sb_cg = new(); + c_sh_cg = new(); + c_zext_b_cg = new(); + c_sext_b_cg = new(); + c_zext_h_cg = new(); + c_sext_h_cg = new(); + c_not_cg = new(); + c_mul_cg = new(); + `CG_SELECTOR_END + + `CG_SELECTOR_BEGIN(RV32ZCMP) + cm_push_cg = new(); + cm_pop_cg = new(); + cm_popretz_cg = new(); + cm_popret_cg = new(); + cm_mva01s_cg = new(); + cm_mvsa01_cg = new(); + `CG_SELECTOR_END + `CG_SELECTOR_BEGIN(RV32B) pack_cg = new(); packh_cg = new(); @@ -2118,6 +2215,10 @@ class riscv_instr_cover_group; roriw_cg = new(); `CG_SELECTOR_END + `CG_SELECTOR_BEGIN(RV64ZCB) + c_zext_w_cg = new(); + `CG_SELECTOR_END + `CG_SELECTOR_BEGIN(RV64B) packw_cg = new(); packuw_cg = new(); @@ -2396,6 +2497,25 @@ class riscv_instr_cover_group; BINVI : `SAMPLE_ZBS(binvi_cg, instr) BSET : `SAMPLE_ZBS(bset_cg, instr) BSETI : `SAMPLE_ZBS(bseti_cg, instr) + // RV32ZCB + C_LBU : `SAMPLE_ZCB(c_lbu_cg, instr) + C_LHU : `SAMPLE_ZCB(c_lhu_cg, instr) + C_LH : `SAMPLE_ZCB(c_lh_cg, instr) + C_SB : `SAMPLE_ZCB(c_sb_cg, instr) + C_SH : `SAMPLE_ZCB(c_sh_cg, instr) + C_ZEXT_B : `SAMPLE_ZCB(c_zext_b_cg, instr) + C_SEXT_B : `SAMPLE_ZCB(c_sext_b_cg, instr) + C_ZEXT_H : `SAMPLE_ZCB(c_zext_h_cg, instr) + C_SEXT_H : `SAMPLE_ZCB(c_sext_h_cg, instr) + C_NOT : `SAMPLE_ZCB(c_not_cg, instr) + C_MUL : `SAMPLE_ZCB(c_mul_cg, instr) + // RV32ZCMP + CM_PUSH : `SAMPLE_ZCMP(cm_push_cg, instr) + CM_POP : `SAMPLE_ZCMP(cm_pop_cg, instr) + CM_POPRETZ : `SAMPLE_ZCMP(cm_popretz_cg, instr) + CM_POPRET : `SAMPLE_ZCMP(cm_popret_cg, instr) + CM_MVA01S : `SAMPLE_ZCMP(cm_mva01s_cg, instr) + CM_MVSA01 : `SAMPLE_ZCMP(cm_mvsa01_cg, instr) // RV32B PACK : `SAMPLE_B(pack_cg, instr) PACKH : `SAMPLE_B(packh_cg, instr) @@ -2438,6 +2558,8 @@ class riscv_instr_cover_group; ROLW : `SAMPLE_ZBB(rolw_cg, instr) RORW : `SAMPLE_ZBB(rorw_cg, instr) RORIW : `SAMPLE_ZBB(roriw_cg, instr) + // RV64ZCB + C_ZEXT_W : `SAMPLE_ZCB(c_zext_w_cg, instr) // RV64B PACKW : `SAMPLE_B(packw_cg, instr) PACKUW : `SAMPLE_B(packuw_cg, instr) @@ -2544,8 +2666,8 @@ class riscv_instr_cover_group; if ((instr.group inside {supported_isa}) && (instr.group inside {RV32I, RV32M, RV64M, RV64I, RV32C, RV64C, RVV, RV64B, RV32B, - RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, - RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS})) begin + RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, RV32ZCB, RV32ZCMP, + RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS, RV64ZCB, RV64ZCMP})) begin if (((instr_name inside {URET}) && !support_umode_trap) || ((instr_name inside {SRET, SFENCE_VMA}) && !(SUPERVISOR_MODE inside {supported_privileged_mode})) || diff --git a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv index 0712821e58..4b7cab531c 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_gen_config.sv @@ -264,6 +264,8 @@ class riscv_instr_gen_config extends uvm_object; bit enable_zbb_extension; bit enable_zbc_extension; bit enable_zbs_extension; + bit enable_zcb_extension; + bit enable_zcmp_extension; b_ext_group_t enable_bitmanip_groups[] = {ZBB, ZBS, ZBP, ZBE, ZBF, ZBC, ZBR, ZBM, ZBT, ZB_TMP}; @@ -541,6 +543,8 @@ class riscv_instr_gen_config extends uvm_object; `uvm_field_int(enable_zbb_extension, UVM_DEFAULT) `uvm_field_int(enable_zbc_extension, UVM_DEFAULT) `uvm_field_int(enable_zbs_extension, UVM_DEFAULT) + `uvm_field_int(enable_zcb_extension, UVM_DEFAULT) + `uvm_field_int(enable_zcmp_extension, UVM_DEFAULT) `uvm_field_int(use_push_data_section, UVM_DEFAULT) `uvm_object_utils_end @@ -611,6 +615,8 @@ class riscv_instr_gen_config extends uvm_object; get_bool_arg_value("+enable_zbb_extension=", enable_zbb_extension); get_bool_arg_value("+enable_zbc_extension=", enable_zbc_extension); get_bool_arg_value("+enable_zbs_extension=", enable_zbs_extension); + get_bool_arg_value("+enable_zcb_extension=", enable_zcb_extension); + get_bool_arg_value("+enable_zcmp_extension=", enable_zcmp_extension); cmdline_enum_processor #(b_ext_group_t)::get_array_values("+enable_bitmanip_groups=", 1'b0, enable_bitmanip_groups); if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin @@ -657,6 +663,16 @@ class riscv_instr_gen_config extends uvm_object; enable_zbs_extension = 0; end + + if (!((RV32ZCB inside {supported_isa}) || + (RV64ZCB inside {supported_isa}))) begin + enable_zcb_extension = 0; + end + + if (!((RV32ZCMP inside {supported_isa}) || + (RV64ZCMP inside {supported_isa}))) begin + enable_zcmp_extension = 0; + end vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg"); pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg"); pmp_cfg.rand_mode(pmp_cfg.pmp_randomize); diff --git a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv index 12f248b74e..fd36ea63ce 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_pkg.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_pkg.sv @@ -80,7 +80,7 @@ package riscv_instr_pkg; MACHINE_MODE = 2'b11 } privileged_mode_t; - typedef enum bit [4:0] { + typedef enum bit [5:0] { RV32I, RV64I, RV32M, @@ -108,6 +108,12 @@ package riscv_instr_pkg; RV64ZBB, RV64ZBC, RV64ZBS, + RV32ZCB, + RV64ZCB, + RV32ZCMP, + RV64ZCMP, + RV32ZMMUL, + RV64ZMMUL, RV32X, RV64X } riscv_instr_group_t; @@ -271,6 +277,27 @@ package riscv_instr_pkg; PACKW, PACKUW, XPERM_W, + // RV32ZCB + C_LBU, + C_LHU, + C_LH, + C_SB, + C_SH, + C_ZEXT_B, + C_SEXT_B, + C_ZEXT_H, + C_SEXT_H, + C_NOT, + C_MUL, + // RV64ZCB instructions + C_ZEXT_W, + // RV32ZCMP + CM_PUSH, + CM_POP, + CM_POPRETZ, + CM_POPRET, + CM_MVA01S, + CM_MVSA01, // RV32M instructions MUL, MULH, @@ -665,6 +692,8 @@ package riscv_instr_pkg; S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6 } riscv_reg_t; + typedef riscv_reg_t riscv_reglist_t[$]; + typedef enum bit [4:0] { FT0, FT1, FT2, FT3, FT4, FT5, FT6, FT7, FS0, FS1, FA0, FA1, FA2, FA3, FA4, FA5, FA6, FA7, FS2, FS3, FS4, FS5, FS6, FS7, FS8, FS9, FS10, FS11, FT8, FT9, FT10, FT11 @@ -693,6 +722,14 @@ package riscv_instr_pkg; CS_FORMAT, CSS_FORMAT, CIW_FORMAT, + // Zc compressed instruction format + CLB_FORMAT, + CSB_FORMAT, + CLH_FORMAT, + CSH_FORMAT, + CU_FORMAT, + CMMV_FORMAT, + CMPP_FORMAT, // Vector instruction format VSET_FORMAT, VA_FORMAT, @@ -1535,6 +1572,8 @@ package riscv_instr_pkg; typedef class riscv_zbb_instr; typedef class riscv_zbc_instr; typedef class riscv_zbs_instr; + typedef class riscv_zcb_instr; + typedef class riscv_zcmp_instr; typedef class riscv_b_instr; `include "riscv_instr_gen_config.sv" `include "isa/riscv_instr.sv" @@ -1560,6 +1599,11 @@ package riscv_instr_pkg; `include "isa/rv32zbb_instr.sv" `include "isa/rv32zbc_instr.sv" `include "isa/rv32zbs_instr.sv" + `include "isa/riscv_zcb_instr.sv" + `include "isa/rv32zcb_instr.sv" + `include "isa/rv64zcb_instr.sv" + `include "isa/riscv_zcmp_instr.sv" + `include "isa/rv32zcmp_instr.sv" `include "isa/rv32m_instr.sv" `include "isa/rv64a_instr.sv" `include "isa/rv64b_instr.sv" diff --git a/vendor/google_riscv-dv/src/riscv_instr_stream.sv b/vendor/google_riscv-dv/src/riscv_instr_stream.sv index 9e980da87d..0a7f15fc70 100644 --- a/vendor/google_riscv-dv/src/riscv_instr_stream.sv +++ b/vendor/google_riscv-dv/src/riscv_instr_stream.sv @@ -228,24 +228,36 @@ class riscv_rand_instr_stream extends riscv_instr_stream; end endfunction - function void randomize_instr(output riscv_instr instr, - input bit is_in_debug = 1'b0, - input bit disable_dist = 1'b0, - input riscv_instr_group_t include_group[$] = {}); - riscv_instr_name_t exclude_instr[]; + function void update_excluded_instr(ref riscv_instr_name_t exclude_instr[], + input bit is_in_debug = 1'b0); if ((SP inside {reserved_rd, cfg.reserved_regs}) || ((avail_regs.size() > 0) && !(SP inside {avail_regs}))) begin - exclude_instr = {C_ADDI4SPN, C_ADDI16SP, C_LWSP, C_LDSP}; + exclude_instr = {exclude_instr, C_ADDI4SPN, C_ADDI16SP, C_LWSP, C_LDSP}; end - // Post-process the allowed_instr and exclude_instr lists to handle - // adding ebreak instructions to the debug rom. + if ((A0 inside {reserved_rd, cfg.reserved_regs}) || + (A1 inside {reserved_rd, cfg.reserved_regs}) || + ((avail_regs.size() > 0) && (!(A0 inside {avail_regs}) || !(A1 inside {avail_regs})))) begin + // MVA01S instruction needs both A0 and A1 to be writable + exclude_instr = {exclude_instr, CM_MVA01S}; + end + // Post-process the exclude_instr lists to handle adding ebreak instructions to the debug rom. if (is_in_debug) begin - if (cfg.no_ebreak && cfg.enable_ebreak_in_debug_rom) begin - allowed_instr = {allowed_instr, EBREAK, C_EBREAK}; - end else if (!cfg.no_ebreak && !cfg.enable_ebreak_in_debug_rom) begin + if (!cfg.no_ebreak && !cfg.enable_ebreak_in_debug_rom) begin exclude_instr = {exclude_instr, EBREAK, C_EBREAK}; end end + endfunction + + function void randomize_instr(output riscv_instr instr, + input bit is_in_debug = 1'b0, + input bit disable_dist = 1'b0, + input riscv_instr_group_t include_group[$] = {}); + riscv_instr_name_t exclude_instr[]; + update_excluded_instr(exclude_instr, is_in_debug); + // Post-process the allowed_instr lists to handle adding ebreak instructions to the debug rom. + if (is_in_debug && cfg.no_ebreak && cfg.enable_ebreak_in_debug_rom) begin + allowed_instr = {allowed_instr, EBREAK, C_EBREAK}; + end instr = riscv_instr::get_rand_instr(.include_instr(allowed_instr), .exclude_instr(exclude_instr), .include_group(include_group)); @@ -256,30 +268,48 @@ class riscv_rand_instr_stream extends riscv_instr_stream; function void randomize_gpr(riscv_instr instr); `DV_CHECK_RANDOMIZE_WITH_FATAL(instr, if (avail_regs.size() > 0) { - if (has_rs1) { - rs1 inside {avail_regs}; - } - if (has_rs2) { - rs2 inside {avail_regs}; - } - if (has_rd) { - rd inside {avail_regs}; + if (format == CMMV_FORMAT) { + if (has_rs1 && has_rs2) { + rs2 != rs1; + } + rs1 inside {S0, S1, [S2:S7]}; + rs2 inside {S0, S1, [S2:S7]}; + } else { + if (has_rs1) { + rs1 inside {avail_regs}; + } + if (has_rs2) { + rs2 inside {avail_regs}; + } + if (has_rd) { + rd inside {avail_regs}; + } } } foreach (reserved_rd[i]) { if (has_rd) { rd != reserved_rd[i]; } - if (format == CB_FORMAT) { + if (instr_name == CM_MVSA01) { rs1 != reserved_rd[i]; + rs2 != reserved_rd[i]; + } + if (instr_name == CM_MVA01S) { + A0 != reserved_rd[i]; + A1 != reserved_rd[i]; } } foreach (cfg.reserved_regs[i]) { if (has_rd) { rd != cfg.reserved_regs[i]; } - if (format == CB_FORMAT) { + if (instr_name == CM_MVSA01) { rs1 != cfg.reserved_regs[i]; + rs2 != cfg.reserved_regs[i]; + } + if (instr_name == CM_MVA01S) { + A0 != cfg.reserved_regs[i]; + A1 != cfg.reserved_regs[i]; } } // TODO: Add constraint for CSR, floating point register diff --git a/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv b/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv index cae0873137..6dcbbfdd3d 100644 --- a/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv +++ b/vendor/google_riscv-dv/src/riscv_load_store_instr_lib.sv @@ -119,19 +119,33 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream; // Generate each load/store instruction virtual function void gen_load_store_instr(); - bit enable_compressed_load_store; + bit enable_compressed_load_store, enable_zcb; riscv_instr instr; randomize_avail_regs(); if ((rs1_reg inside {[S0 : A5], SP}) && !cfg.disable_compressed_instr) begin enable_compressed_load_store = 1; end + if ((RV32C inside {riscv_instr_pkg::supported_isa}) && + (RV32ZCB inside {riscv_instr_pkg::supported_isa} && cfg.enable_zcb_extension)) begin + enable_zcb = 1; + end foreach (addr[i]) begin // Assign the allowed load/store instructions based on address alignment // This is done separately rather than a constraint to improve the randomization performance allowed_instr = {LB, LBU, SB}; + if((offset[i] inside {[0:2]}) && enable_compressed_load_store && + enable_zcb && rs1_reg != SP) begin + `uvm_info(`gfn, "Add ZCB byte load/store to allowed instr", UVM_LOW) + allowed_instr = {C_LBU, C_SB}; + end if (!cfg.enable_unaligned_load_store) begin if (addr[i][0] == 1'b0) begin allowed_instr = {LH, LHU, SH, allowed_instr}; + if(((offset[i] == 0) || (offset[i] == 2)) && enable_compressed_load_store && + enable_zcb && rs1_reg != SP) begin + `uvm_info(`gfn, "Add ZCB half-word load/store to allowed instr", UVM_LOW) + allowed_instr = {C_LHU, C_LH, C_SH}; + end end if (addr[i] % 4 == 0) begin allowed_instr = {LW, SW, allowed_instr}; @@ -682,3 +696,269 @@ class riscv_vector_load_store_instr_stream extends riscv_mem_access_stream; endfunction endclass + +// Class to test Zcmp Push/Popret control flow chains +class riscv_zcmp_chain_instr_stream extends riscv_mem_access_stream; + // Number of push/pop blocks in the chain + rand int unsigned num_blocks; + // Execution order of these blocks + int unsigned block_order[]; + + // Track number of chains + static int unsigned chain_cnt = 0; + int unsigned chain_id; + + // Data page to use for stack operations + rand int base; + rand int unsigned data_page_id; + rand int unsigned max_load_store_offset; + + constraint addr_c { + solve data_page_id before max_load_store_offset; + solve max_load_store_offset before base; + data_page_id < max_data_page_id; + foreach (data_page[i]) { + if (i == data_page_id) {max_load_store_offset == data_page[i].size_in_bytes;} + } + base inside {[0 : max_load_store_offset - 1]}; + } + + constraint block_c {num_blocks inside {[1 : 50]};} + + function new(string name = ""); + super.new(name); + // Assign a unique ID to this specific stream instance + chain_id = chain_cnt++; + endfunction + + `uvm_object_utils(riscv_zcmp_chain_instr_stream) + + function void post_randomize(); + // SP cannot be modified by other instructions + if (!(SP inside {reserved_rd})) begin + reserved_rd = {reserved_rd, SP}; + end + setup_chain_order(); + + // Generate the chain of blocks + gen_zcmp_chain(); + // Ensure labels are preserved + foreach (instr_list[i]) begin + if (instr_list[i].label != "") instr_list[i].has_label = 1'b1; + else instr_list[i].has_label = 1'b0; + instr_list[i].atomic = 1'b1; + end + // Initizialize SP to point to a data page + add_rs1_init_la_instr(SP, data_page_id, 0); + // Don't call super here, because it will delete all labels + endfunction + + // Randomize the order in which blocks are executed + virtual function void setup_chain_order(); + block_order = new[num_blocks]; + foreach (block_order[i]) begin + block_order[i] = i; + end + block_order.shuffle(); + endfunction + + // Main generator function + virtual function void gen_zcmp_chain(); + riscv_instr instr; + riscv_instr popret_instr; + string prefix = $sformatf("zcmp_%0d", chain_id); + riscv_instr_name_t exclude_instr[]; + update_excluded_instr(exclude_instr); + + // Save all registers that will be overwritten by our upcoming push/pop chain + // A0 is overwritten by CM.POPRETZ, but cannot be saved by CM.PUSH/POP. + // Save A0 outside the main stack frame (e.g., at SP-120) + instr = riscv_instr::get_instr(ADDI); + instr.rd = SP; + instr.rs1 = SP; + instr.imm_str = "-16"; + instr_list.push_back(instr); + instr = riscv_instr::get_instr(XLEN == 32 ? SW : SD); + instr.rs1 = SP; + instr.rs2 = A0; + instr.imm_str = "0"; + instr_list.push_back(instr); + // Save all the remaining registers overwritten by pop + instr = riscv_instr::get_instr(CM_PUSH); + instr.stack_adj = -112; // Max stack frame + instr.rlist = 15; // All registers + instr_list.push_back(instr); + // Jump to the first block + instr = riscv_instr::get_instr(JAL); + instr.rd = ZERO; // Don't link, just jump + instr.imm_str = $sformatf("%s_%0d", prefix, block_order[0]); + instr.comment = "Bootstrap: Jump to first random block"; + instr_list.push_back(instr); + + // Generate the push/pop blocks + for (int i = 0; i < num_blocks; i++) begin + // Number of random instructions to insert between push/pop + int random_instructions; + // Labels to link blocks + string current_label = $sformatf("%s_%0d", prefix, i); + string next_label; + int next_block_idx = -1; + // Control the stack growth/shrinkage + // Total number of instructions (Push + Pop) + int num_steps; + // Stack size at each step + int stack_size[]; + int max_stack = max_load_store_offset; + int delta; + riscv_instr_name_t final_opcode; + + // Find which block comes after current block 'i' in the execution order + foreach (block_order[k]) begin + if (block_order[k] == i) begin + if (k < num_blocks - 1) begin + next_block_idx = block_order[k+1]; + next_label = $sformatf("%s_%0d", prefix, next_block_idx); + end else begin + // End of chain + next_label = $sformatf("%s_end", prefix); + end + end + end + + // Randomize the stack pointer's path and the number of steps + std::randomize(stack_size, num_steps) with { + // Number of push/pop steps per block + num_steps inside {[2:12]}; + // Include the initial zero depth + stack_size.size() == num_steps + 1; + // Start and stop at zero depth + stack_size[0] == 0; + stack_size[num_steps] == 0; + foreach (stack_size[i]) { + // Stay within stack region + stack_size[i] inside {[-max_stack:0]}; + // Transition Constraints + if (i > 0) { + // Must be 16-byte aligned steps + (stack_size[i] - stack_size[i-1]) % 16 == 0; + // Restrict adjustment size of single push/pop and avoid no-ops (diff==0) + (stack_size[i] - stack_size[i-1]) inside {[-112:-16], [16:112]}; + } + } + }; + + // Loop through all the steps and insert a push or pop instruction. Also sprinkle in some + // random instructions inbetween. Skip the very last pop, since that will be a popret we + // handle specially. + for (int i = 0; i < num_steps - 1; i++) begin + delta = stack_size[i+1] - stack_size[i]; + if (delta < 0) begin + // CM.PUSH (Stack Grows) + instr = riscv_instr::get_instr(CM_PUSH); + `DV_CHECK_RANDOMIZE_WITH_FATAL(instr, stack_adj == delta;) + end else begin + // CM.POP (Stack Shrinks) + instr = riscv_instr::get_instr(CM_POP); + `DV_CHECK_RANDOMIZE_WITH_FATAL(instr, stack_adj == delta;) + end + + // First instruction gets the label to jump to + if (i == 0) begin + instr.label = current_label; + end + + instr_list.push_back(instr); + + // Insert random instructions in between push and pops + random_instructions = $urandom_range(0, 5); + repeat (random_instructions) begin + instr = riscv_instr::get_rand_instr(.include_category({ARITHMETIC, LOGICAL, SHIFT, COMPARE + }), .exclude_instr(exclude_instr)); + `DV_CHECK_RANDOMIZE_WITH_FATAL(instr, + // CRITICAL: Do not touch SP! + if (cfg.reserved_regs.size() > 0 || reserved_rd.size() > 0) { + !(rd inside {cfg.reserved_regs, reserved_rd}); + }, + $sformatf("Cannot randomize instruction %s with constrained registers\n", + instr.convert2asm())) + instr_list.push_back(instr); + end + end + + // Last step is a POPRET/POPRETZ. Randomly choose which: + randcase + 1: final_opcode = CM_POPRET; + 1: final_opcode = CM_POPRETZ; + endcase + delta = stack_size[num_steps] - stack_size[num_steps-1]; + // Do not insert this popret into the instruction stream yet. First, we have to create a + // proper RA address to jump to. However, since we need to know where the POPRET will load the + // RA from (i.e., which rlist and stack_adj it uses), we have to randomize it first. + popret_instr = riscv_instr::get_instr(final_opcode); + `DV_CHECK_RANDOMIZE_WITH_FATAL(popret_instr, stack_adj == delta;) + + // Push the RA with the address of 'next_label' onto the stack at the correct location. The + // following instructiosn are "atomic" because we don't want other instructions to interleave + // between them. + if (next_label != "") begin + riscv_pseudo_instr la_instr_pseudo; + riscv_reg_t temp_reg; + int ra_offset_in_stack; + + // Calculate where RA will be read from by the POPRET instruction. + // For cm.pop {ra, s0-sN}, stack_adj: + // RA is usually at `[SP + stack_adj - XLEN/8*(rlist - 3)]` because we pop rlist-3 registers + // There is one exception, if rlist == 15 (all registers), we pop rlist-2 registers because + // it includes s10 and s11. So adjust accordingly. + ra_offset_in_stack = delta - XLEN / 8 * (popret_instr.rlist - 3); + if (popret_instr.rlist == 15) begin + ra_offset_in_stack = ra_offset_in_stack - XLEN / 8; + end + + // Get a temp reg that isn't reserved and not X0 + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL( + temp_reg, !(temp_reg inside {cfg.reserved_regs, reserved_rd, ZERO});) + + // Load Address of the NEXT block + la_instr_pseudo = riscv_pseudo_instr::type_id::create("la_instr_pseudo"); + la_instr_pseudo.pseudo_instr_name = LA; + la_instr_pseudo.rd = temp_reg; + la_instr_pseudo.imm_str = next_label; + la_instr_pseudo.atomic = 1'b1; + instr_list.push_back(la_instr_pseudo); + + // Overwrite the RA slot on the stack + instr = riscv_instr::get_instr(XLEN == 32 ? SW : SD); + instr.rs1 = SP; + instr.rs2 = temp_reg; + instr.imm_str = $sformatf("%0d", ra_offset_in_stack); + instr.atomic = 1'b1; + instr.comment = "Overwrite saved RA with next block address"; + instr_list.push_back(instr); + end + + // Insert popret at the very end. We already randomized it earlier to place the RA at the correct address. + instr_list.push_back(popret_instr); + end + + // Endpoint of chain: Restore all registers overwritten by push/pop + instr = riscv_instr::get_instr(CM_POP); + instr.stack_adj = 112; // Max stack frame + instr.rlist = 15; // All registers + instr.label = $sformatf("%s_end", prefix); + instr.comment = "End of Zcmp Chain"; + instr_list.push_back(instr); + // Restore A0 from the stack + instr = riscv_instr::get_instr(XLEN == 32 ? LW : LD); + instr.rd = A0; + instr.rs1 = SP; + instr.imm_str = "0"; + instr_list.push_back(instr); + instr = riscv_instr::get_instr(ADDI); + instr.rd = SP; + instr.rs1 = SP; + instr.imm_str = "16"; + instr_list.push_back(instr); + endfunction + +endclass diff --git a/vendor/google_riscv-dv/src/riscv_loop_instr.sv b/vendor/google_riscv-dv/src/riscv_loop_instr.sv index c2fcecc63f..507a5e7503 100644 --- a/vendor/google_riscv-dv/src/riscv_loop_instr.sv +++ b/vendor/google_riscv-dv/src/riscv_loop_instr.sv @@ -113,7 +113,10 @@ class riscv_loop_instr extends riscv_rand_instr_stream; `uvm_object_new function void post_randomize(); + riscv_instr_name_t exclude_instr[]; reserved_rd = {loop_cnt_reg, loop_limit_reg}; + // Figure out which instructions we can no longer use after the loop regs are decided + update_excluded_instr(exclude_instr); // Generate instructions that mixed with the loop instructions initialize_instr_list(num_of_instr_in_loop); gen_instr(1'b1); @@ -144,10 +147,11 @@ class riscv_loop_instr extends riscv_rand_instr_stream; // Branch target instruction, can be anything loop_branch_target_instr[i] = riscv_instr::get_rand_instr( .include_category({ARITHMETIC, LOGICAL, COMPARE}), - .exclude_instr({C_ADDI16SP})); + .exclude_instr(exclude_instr)); `DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_target_instr[i], - if (format == CB_FORMAT) { + if (instr_name == CM_MVSA01) { !(rs1 inside {reserved_rd, cfg.reserved_regs}); + !(rs2 inside {reserved_rd, cfg.reserved_regs}); } if (has_rd) { !(rd inside {reserved_rd, cfg.reserved_regs}); diff --git a/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv b/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv index 7b7dc39b05..029891d287 100644 --- a/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv +++ b/vendor/google_riscv-dv/test/riscv_instr_cov_test.sv @@ -138,8 +138,8 @@ class riscv_instr_cov_test extends uvm_test; instr = riscv_instr::get_instr(instr_name); if ((instr.group inside {RV32I, RV32M, RV32C, RV64I, RV64M, RV64C, RV32F, RV64F, RV32D, RV64D, RV32B, RV64B, - RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, - RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS}) && + RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, RV32ZCB, RV32ZCMP, + RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS, RV64ZCB, RV64ZCMP}) && (instr.group inside {supported_isa})) begin assign_trace_info_to_instr(instr); instr.pre_sample(); diff --git a/vendor/google_riscv-dv/yaml/iss.yaml b/vendor/google_riscv-dv/yaml/iss.yaml index 8a8b662307..1167d7fd92 100644 --- a/vendor/google_riscv-dv/yaml/iss.yaml +++ b/vendor/google_riscv-dv/yaml/iss.yaml @@ -15,7 +15,7 @@ - iss: spike path_var: SPIKE_PATH cmd: > - /spike --log-commits --isa= -l + /spike --log-commits --isa= --priv= --misaligned -l - iss: ovpsim path_var: OVPSIM_PATH @@ -35,9 +35,9 @@ - iss: whisper path_var: WHISPER_ISS cmd: > - --log --xlen --isa + --log --xlen --isa --configfile /whisper.json --iccmrw - iss: renode path_var: RENODE_PATH cmd: > - python3 /renode_wrapper.py --renode "" --elf --isa + python3 /renode_wrapper.py --renode "" --elf --isa --priv= --mem-size 0x80000000 diff --git a/vendor/google_riscv-dv/yaml/whisper.json b/vendor/google_riscv-dv/yaml/whisper.json new file mode 100644 index 0000000000..62551c7c67 --- /dev/null +++ b/vendor/google_riscv-dv/yaml/whisper.json @@ -0,0 +1,7 @@ +{ + "iccm": { + "region": "0", + "size": "0x80000000", + "offset": "0x80000000" + } +} diff --git a/vendor/patches/google_riscv-dv/0004-compiler-flags.patch b/vendor/patches/google_riscv-dv/0004-compiler-flags.patch new file mode 100644 index 0000000000..86816df5d5 --- /dev/null +++ b/vendor/patches/google_riscv-dv/0004-compiler-flags.patch @@ -0,0 +1,55 @@ +--- a/run.py ++++ b/run.py +@@ -951,40 +951,40 @@ def load_config(args, cwd): + args.core_setting_dir = cwd + "/target/" + args.target + if args.target == "rv32imc": + args.mabi = "ilp32" +- args.isa = "rv32imc_zicsr_zifencei" ++ args.isa = "rv32imc" + elif args.target == "rv32imafdc": + args.mabi = "ilp32" +- args.isa = "rv32imafdc_zicsr_zifencei" ++ args.isa = "rv32imafdc" + elif args.target == "rv32imc_sv32": + args.mabi = "ilp32" +- args.isa = "rv32imc_zicsr_zifencei" ++ args.isa = "rv32imc" + elif args.target == "multi_harts": + args.mabi = "ilp32" +- args.isa = "rv32gc_zicsr_zifencei" ++ args.isa = "rv32gc" + elif args.target == "rv32imcb": + args.mabi = "ilp32" +- args.isa = "rv32imcb_zicsr_zifencei" ++ args.isa = "rv32imcb" + elif args.target == "rv32i": + args.mabi = "ilp32" +- args.isa = "rv32i_zicsr_zifencei" ++ args.isa = "rv32i" + elif args.target == "rv64imc": + args.mabi = "lp64" +- args.isa = "rv64imc_zicsr_zifencei" ++ args.isa = "rv64imc" + elif args.target == "rv64imcb": + args.mabi = "lp64" +- args.isa = "rv64imcb_zicsr_zifencei" ++ args.isa = "rv64imcb" + elif args.target == "rv64gc": + args.mabi = "lp64" +- args.isa = "rv64gc_zicsr_zifencei" ++ args.isa = "rv64gc" + elif args.target == "rv64gcv": + args.mabi = "lp64" +- args.isa = "rv64gcv_zicsr_zifencei" ++ args.isa = "rv64gcv" + elif args.target == "ml": + args.mabi = "lp64" +- args.isa = "rv64imc_zicsr_zifencei" ++ args.isa = "rv64imc" + elif args.target == "rv64imafdc": + args.mabi = "lp64" +- args.isa = "rv64imafdc_zicsr_zifencei" ++ args.isa = "rv64imafdc" + else: + sys.exit("Unsupported pre-defined target: {}".format(args.target)) + else: