-
Notifications
You must be signed in to change notification settings - Fork 655
Add Zcb and Zcmp extensions #2324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
64cf445
b73ebbf
df69b37
5d81041
5b062c5
1f53bcb
b937304
09ea07c
722ea41
9484da6
77fe555
6cbaded
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,7 +39,8 @@ 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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I think the indentation is missing a couple of spaces here. |
||
FILE *log_file = nullptr; | ||
if (trace_log_path.length() != 0) { | ||
log = std::make_unique<log_file_t>(trace_log_path.c_str()); | ||
|
@@ -170,7 +171,8 @@ 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, | ||
uint32_t expanded_insn) { | ||
assert(write_reg < 32); | ||
|
||
// The DUT has just produced an RVFI item | ||
|
@@ -214,7 +216,12 @@ 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. Spike | ||
// does not expand instructions, so we have to consume a single Spike step | ||
// over multiple steps of Ibex. | ||
Comment on lines
+220
to
+221
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it makes sense to explicitly say that we're stepping spike at the last step in Ibex? |
||
if (pending_expanded_insn == 0) { | ||
processor->step(1); | ||
} | ||
|
||
// ISS | ||
// - If encountered an async trap, | ||
|
@@ -309,18 +316,102 @@ 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) { | ||
if (!check_expanded_instr(write_reg, write_reg_data, pc, suppress_reg_write, | ||
expanded_insn)) { | ||
return false; | ||
} | ||
} else { | ||
if (!check_retired_instr(write_reg, write_reg_data, pc, suppress_reg_write, | ||
expanded_insn)) { | ||
return false; | ||
} | ||
} | ||
|
||
// Only increment insn_cnt and return true if there are no errors | ||
insn_cnt++; | ||
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) { | ||
// If this is the first step of an expanded instruction, set up our expectations. | ||
if (!pending_expanded_insn) { | ||
pending_expanded_insn = expanded_insn; | ||
expanded_insn_pc = dut_pc; | ||
expanded_reg_changes.clear(); | ||
|
||
// The ISS has just stepped once for the entire expanded instruction. | ||
// We now collect all the GPR changes it produced and store them in a map | ||
auto ®_changes = processor->get_state()->log_reg_write; | ||
for (auto reg_change : reg_changes) { | ||
// Check if it's a GPR write (type 0) | ||
if ((reg_change.first & 0xf) == 0) { | ||
uint32_t iss_write_reg = (reg_change.first >> 4) & 0x1f; | ||
// Ignore writes to x0 | ||
if (iss_write_reg == 0) { | ||
continue; | ||
} | ||
uint32_t iss_write_data = reg_change.second.v[0]; | ||
expanded_reg_changes[iss_write_reg] = iss_write_data; | ||
} | ||
} | ||
} | ||
|
||
// TODO: We have to deal with suppressed writes here too | ||
if (suppress_reg_write) { | ||
return true; | ||
} | ||
|
||
// If the DUT did not write a register, this is a valid micro-op (e.g., a | ||
// memory access or intermediate calculation). There is nothing to check. | ||
if (write_reg == 0) { | ||
return true; | ||
} | ||
|
||
// The DUT wrote a register. Check if it matches one of our expectations. | ||
auto reg_change = expanded_reg_changes.find(write_reg); | ||
|
||
// DUT wrote, but ISS didn't | ||
if (reg_change == expanded_reg_changes.end()) { | ||
std::stringstream err_str; | ||
err_str << "Expanded instruction at PC 0x" << std::hex << expanded_insn_pc | ||
<< ": DUT wrote to x" << std::dec << write_reg | ||
<< ", which was not an expected register write for this sequence."; | ||
errors.emplace_back(err_str.str()); | ||
return false; | ||
} | ||
|
||
// The register index matches. Now check if the data matches. | ||
uint32_t expected_data = reg_change->second; | ||
if (write_reg_data != expected_data) { | ||
std::stringstream err_str; | ||
err_str << "Expanded instruction at PC 0x" << std::hex << expanded_insn_pc | ||
<< ": Data mismatch for register x" << std::dec << write_reg | ||
<< ". DUT wrote: 0x" << std::hex << write_reg_data | ||
<< ", but ISS expected: 0x" << expected_data; | ||
errors.emplace_back(err_str.str()); | ||
return false; | ||
} | ||
|
||
// Match is perfect. Remove this from our set of expectations. | ||
expanded_reg_changes.erase(reg_change); | ||
|
||
if(expanded_reg_changes.empty()) { | ||
// All expected register writes have been matched. Clear the pending state. | ||
pending_expanded_insn = 0; | ||
expanded_insn_pc = 0; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
bool SpikeCosim::check_retired_instr(uint32_t write_reg, | ||
uint32_t write_reg_data, uint32_t dut_pc, | ||
bool suppress_reg_write) { | ||
bool suppress_reg_write, | ||
uint32_t expanded_insn) { | ||
// Check the retired instruction and all of its side-effects match those from | ||
// the DUT | ||
|
||
|
@@ -333,6 +424,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; | ||
} | ||
|
||
|
@@ -355,7 +451,7 @@ bool SpikeCosim::check_retired_instr(uint32_t write_reg, | |
assert(!gpr_write_seen); | ||
|
||
if (!suppress_reg_write && | ||
!check_gpr_write(reg_change, write_reg, write_reg_data)) { | ||
!check_gpr_write(reg_change, write_reg, write_reg_data, expanded_insn)) { | ||
return false; | ||
} | ||
|
||
|
@@ -433,7 +529,8 @@ bool SpikeCosim::check_sync_trap(uint32_t write_reg, uint32_t dut_pc, | |
} | ||
|
||
bool SpikeCosim::check_gpr_write(const commit_log_reg_t::value_type ®_change, | ||
uint32_t write_reg, uint32_t write_reg_data) { | ||
uint32_t write_reg, uint32_t write_reg_data, | ||
uint32_t expanded_insn) { | ||
uint32_t cosim_write_reg = (reg_change.first >> 4) & 0x1f; | ||
|
||
if (write_reg == 0) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -163,7 +163,7 @@ | |
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)) begin | ||
Check warning on line 166 in dv/uvm/core_ibex/common/ibex_cosim_agent/ibex_cosim_scoreboard.sv
|
||
// cosim instruction step doesn't match rvfi captured instruction, report a fatal error | ||
// with the details | ||
if (cfg.relax_cosim_check) begin | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: To go in this order, I think the sentence needs a comma: "Internally, they expand ...". (Similarly for the move box below)