Skip to content

Commit bb60e84

Browse files
committed
Update lowrisc_ibex to lowRISC/ibex@66823369
Update code from upstream repository https://github.com/lowRISC/ibex.git to revision 668233699df9ec2a40413e69e0de0a5b10185980 * [dv] Add spurious responses to memory agent (Greg Chadwick) * [dv] Add riscv_ram_intg_test This test injects a fault into different MuBi encoded signals within the prim_ram_1p_scr and prim_ram_1p_adv and checks whether a fatal alert is triggered. (Pascal Nasahl) * [cosim] Clang lint fix (Greg Chadwick) * [dv] Output warning message on problematic MIP changes (Greg Chadwick) * [cosim] Correctly deal with checking top of range memory accesses (Greg Chadwick) * [dv] Update testbench to use new 'pre_val' MIP (Greg Chadwick) * [dv] Fix model mismatches in cases where an access crosses PMP regions (Greg Chadwick) * [dv] Fix exception_stall_instr_cross illegal bins (Greg Chadwick) * [dv] Add riscv_rf_ctrl_intg_test (Greg Chadwick) * [dv] Add cover points for memory interface behaviour (Greg Chadwick) * [dv] Fix race condition in ibex_mem_intf_agent (Greg Chadwick) Signed-off-by: Pirmin Vogel <[email protected]>
1 parent c90f43d commit bb60e84

33 files changed

+781
-121
lines changed

hw/vendor/lowrisc_ibex.lock.hjson

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
upstream:
1010
{
1111
url: https://github.com/lowRISC/ibex.git
12-
rev: d019dccb4b6fb1a580cefabff0391a00bb123ffb
12+
rev: 668233699df9ec2a40413e69e0de0a5b10185980
1313
}
1414
}

hw/vendor/lowrisc_ibex/doc/03_reference/coverage_plan.rst

+11
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,17 @@ The mapping between security countermeasures and coverpoints that demonstrate it
375375
| ICACHE.MEM.INTEGRITY | ``cp_icache_ecc_err`` |
376376
+--------------------------------+-------------------------------------------------------+
377377

378+
Memory Interface Behaviour
379+
^^^^^^^^^^^^^^^^^^^^^^^^^^
380+
Covering different scenarios around timing of memory requests and responses and
381+
related behaviour
382+
383+
* ``cp_dmem_response_latency``/``cp_imem_response_latency`` - Latency of response from request for dmem and imem.
384+
Separated into two bins ``single_cycle`` (immediate response after request) and ``multi_cycle`` (all other latencies).
385+
* ``dmem_req_gnt_valid``/``imem_req_gnt_rvalid`` - Request, grant and rvalid all seen in the same cycle for dmem and imem.
386+
This means a response is seen the same cycle a new request is being granted.
387+
388+
378389
Miscellaneous
379390
^^^^^^^^^^^^^
380391
Various points of interest do not fit into the categories above.

hw/vendor/lowrisc_ibex/dv/cosim/cosim.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ struct DSideAccessInfo {
3535
// `misaligned_first` set to true, there is no second half.
3636
bool misaligned_first;
3737
bool misaligned_second;
38+
39+
bool misaligned_first_saw_error;
40+
41+
bool m_mode_access;
3842
};
3943

4044
class Cosim {
@@ -83,7 +87,7 @@ class Cosim {
8387
//
8488
// At the next call of `step`, the MIP value will take effect (i.e. if it's a
8589
// new interrupt that is enabled it will step straight to that handler).
86-
virtual void set_mip(uint32_t mip) = 0;
90+
virtual void set_mip(uint32_t pre_mip, uint32_t post_mip) = 0;
8791

8892
// Set the state of the NMI (non-maskable interrupt) line.
8993
//

hw/vendor/lowrisc_ibex/dv/cosim/cosim_dpi.cc

+19-12
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
// SPDX-License-Identifier: Apache-2.0
44

5+
#include "cosim_dpi.h"
6+
57
#include <svdpi.h>
8+
69
#include <cassert>
710

811
#include "cosim.h"
9-
#include "cosim_dpi.h"
1012

1113
int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg,
1214
const svBitVecVal *write_reg_data, const svBitVecVal *pc,
@@ -19,10 +21,11 @@ int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg,
1921
: 0;
2022
}
2123

22-
void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *mip) {
24+
void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *pre_mip,
25+
const svBitVecVal *post_mip) {
2326
assert(cosim);
2427

25-
cosim->set_mip(mip[0]);
28+
cosim->set_mip(pre_mip[0], post_mip[0]);
2629
}
2730

2831
void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi) {
@@ -66,17 +69,21 @@ void riscv_cosim_notify_dside_access(Cosim *cosim, svBit store,
6669
svBitVecVal *addr, svBitVecVal *data,
6770
svBitVecVal *be, svBit error,
6871
svBit misaligned_first,
69-
svBit misaligned_second) {
72+
svBit misaligned_second,
73+
svBit misaligned_first_saw_error,
74+
svBit m_mode_access) {
7075
assert(cosim);
7176

72-
cosim->notify_dside_access(
73-
DSideAccessInfo{.store = store != 0,
74-
.data = data[0],
75-
.addr = addr[0],
76-
.be = be[0],
77-
.error = error != 0,
78-
.misaligned_first = misaligned_first != 0,
79-
.misaligned_second = misaligned_second != 0});
77+
cosim->notify_dside_access(DSideAccessInfo{
78+
.store = store != 0,
79+
.data = data[0],
80+
.addr = addr[0],
81+
.be = be[0],
82+
.error = error != 0,
83+
.misaligned_first = misaligned_first != 0,
84+
.misaligned_second = misaligned_second != 0,
85+
.misaligned_first_saw_error = misaligned_first_saw_error != 0,
86+
.m_mode_access = m_mode_access != 0});
8087
}
8188

8289
void riscv_cosim_set_iside_error(Cosim *cosim, svBitVecVal *addr) {

hw/vendor/lowrisc_ibex/dv/cosim/cosim_dpi.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
#include <stdint.h>
99
#include <svdpi.h>
1010

11+
#include "cosim.h"
12+
1113
// This adapts the C++ interface of the `Cosim` class to be used via DPI. See
1214
// the documentation in cosim.h for further details
1315

1416
extern "C" {
1517
int riscv_cosim_step(Cosim *cosim, const svBitVecVal *write_reg,
1618
const svBitVecVal *write_reg_data, const svBitVecVal *pc,
1719
svBit sync_trap, svBit suppress_reg_write);
18-
void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *mip);
20+
void riscv_cosim_set_mip(Cosim *cosim, const svBitVecVal *pre_mip,
21+
const svBitVecVal *post_mip);
1922
void riscv_cosim_set_nmi(Cosim *cosim, svBit nmi);
2023
void riscv_cosim_set_nmi_int(Cosim *cosim, svBit nmi_int);
2124
void riscv_cosim_set_debug_req(Cosim *cosim, svBit debug_req);
@@ -27,7 +30,9 @@ void riscv_cosim_notify_dside_access(Cosim *cosim, svBit store,
2730
svBitVecVal *addr, svBitVecVal *data,
2831
svBitVecVal *be, svBit error,
2932
svBit misaligned_first,
30-
svBit misaligned_second);
33+
svBit misaligned_second,
34+
svBit misaligned_first_saw_error,
35+
svBit m_mode_access);
3136
void riscv_cosim_set_iside_error(Cosim *cosim, svBitVecVal *addr);
3237
int riscv_cosim_get_num_errors(Cosim *cosim);
3338
const char *riscv_cosim_get_error(Cosim *cosim, int index);

hw/vendor/lowrisc_ibex/dv/cosim/cosim_dpi.svh

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
import "DPI-C" function int riscv_cosim_step(chandle cosim_handle, bit [4:0] write_reg,
1414
bit [31:0] write_reg_data, bit [31:0] pc, bit sync_trap, bit suppress_reg_write);
15-
import "DPI-C" function void riscv_cosim_set_mip(chandle cosim_handle, bit [31:0] mip);
15+
import "DPI-C" function void riscv_cosim_set_mip(chandle cosim_handle, bit [31:0] pre_mip,
16+
bit [31:0] post_mip);
1617
import "DPI-C" function void riscv_cosim_set_nmi(chandle cosim_handle, bit nmi);
1718
import "DPI-C" function void riscv_cosim_set_nmi_int(chandle cosim_handle, bit nmi_int);
1819
import "DPI-C" function void riscv_cosim_set_debug_req(chandle cosim_handle, bit debug_req);
@@ -22,7 +23,7 @@ import "DPI-C" function void riscv_cosim_set_csr(chandle cosim_handle, int csr_i
2223
import "DPI-C" function void riscv_cosim_set_ic_scr_key_valid(chandle cosim_handle, bit valid);
2324
import "DPI-C" function void riscv_cosim_notify_dside_access(chandle cosim_handle, bit store,
2425
bit [31:0] addr, bit [31:0] data, bit [3:0] be, bit error, bit misaligned_first,
25-
bit misaligned_second);
26+
bit misaligned_second, bit misaligned_first_saw_error, bit m_mode_access);
2627
import "DPI-C" function int riscv_cosim_set_iside_error(chandle cosim_handle, bit [31:0] addr);
2728
import "DPI-C" function int riscv_cosim_get_num_errors(chandle cosim_handle);
2829
import "DPI-C" function string riscv_cosim_get_error(chandle cosim_handle, int index);

hw/vendor/lowrisc_ibex/dv/cosim/spike_cosim.cc

+93-32
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@
33
// SPDX-License-Identifier: Apache-2.0
44

55
#include "spike_cosim.h"
6+
7+
#include <cassert>
8+
#include <iostream>
9+
#include <sstream>
10+
611
#include "riscv/config.h"
712
#include "riscv/decode.h"
813
#include "riscv/devices.h"
914
#include "riscv/log_file.h"
15+
#include "riscv/mmu.h"
1016
#include "riscv/processor.h"
1117
#include "riscv/simif.h"
1218

13-
#include <cassert>
14-
#include <iostream>
15-
#include <sstream>
16-
1719
// For a short time, we're going to support building against version
1820
// ibex-cosim-v0.2 (20a886c) and also ibex-cosim-v0.3 (9af9730). Unfortunately,
1921
// they've got different APIs and spike doesn't expose a version string.
@@ -83,26 +85,24 @@ bool SpikeCosim::mmio_load(reg_t addr, size_t len, uint8_t *bytes) {
8385
bool dut_error = false;
8486

8587
// Incoming access may be an iside or dside access. Use PC to help determine
86-
// which.
87-
uint32_t pc = processor->get_state()->pc;
88+
// which. PC is 64 bits in spike, we only care about the bottom 32-bit so mask
89+
// off the top bits.
90+
uint64_t pc = processor->get_state()->pc & 0xffffffff;
8891
uint32_t aligned_addr = addr & 0xfffffffc;
8992

9093
if (pending_iside_error && (aligned_addr == pending_iside_err_addr)) {
9194
// Check if the incoming access is subject to an iside error, in which case
9295
// assume it's an iside access and produce an error.
9396
pending_iside_error = false;
9497
dut_error = true;
95-
} else if (addr < pc || addr >= (pc + 8)) {
98+
} else {
9699
// Spike may attempt to access up to 8-bytes from the PC when fetching, so
97-
// only check as a dside access when it falls outside that range.
98-
99-
// Otherwise check if the aligned PC matches with the aligned address or an
100-
// incremented aligned PC (to capture the unaligned 4-byte instruction
101-
// case). Assume a successful iside access if either of these checks are
102-
// true, otherwise assume a dside access and check against DUT dside
103-
// accesses. If the RTL produced a bus error for the access, or the
104-
// checking failed produce a memory fault in spike.
105-
dut_error = (check_mem_access(false, addr, len, bytes) != kCheckMemOk);
100+
// only check as a dside access when it falls outside that range
101+
bool in_iside_range = (addr >= pc && addr < pc + 8);
102+
103+
if (!in_iside_range) {
104+
dut_error = (check_mem_access(false, addr, len, bytes) != kCheckMemOk);
105+
}
106106
}
107107

108108
return !(bus_error || dut_error);
@@ -261,8 +261,8 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc,
261261
if (pending_sync_exception) {
262262
if (!sync_trap) {
263263
std::stringstream err_str;
264-
err_str << "Synchronous trap was expected at ISS PC: "
265-
<< std::hex << processor->get_state()->pc
264+
err_str << "Synchronous trap was expected at ISS PC: " << std::hex
265+
<< processor->get_state()->pc
266266
<< " but the DUT didn't report one at PC " << pc;
267267
errors.emplace_back(err_str.str());
268268
return false;
@@ -294,9 +294,8 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc,
294294

295295
if (pending_iside_error) {
296296
std::stringstream err_str;
297-
err_str << "DUT generated an iside error for address: "
298-
<< std::hex << pending_iside_err_addr
299-
<< " but the ISS didn't produce one";
297+
err_str << "DUT generated an iside error for address: " << std::hex
298+
<< pending_iside_err_addr << " but the ISS didn't produce one";
300299
errors.emplace_back(err_str.str());
301300
return false;
302301
}
@@ -329,8 +328,8 @@ bool SpikeCosim::check_retired_instr(uint32_t write_reg,
329328
if ((processor->get_state()->last_inst_pc & 0xffffffff) != dut_pc) {
330329
std::stringstream err_str;
331330
err_str << "PC mismatch, DUT retired : " << std::hex << dut_pc
332-
<< " , but the ISS retired: "
333-
<< std::hex << processor->get_state()->last_inst_pc;
331+
<< " , but the ISS retired: " << std::hex
332+
<< processor->get_state()->last_inst_pc;
334333
errors.emplace_back(err_str.str());
335334
return false;
336335
}
@@ -385,18 +384,17 @@ bool SpikeCosim::check_retired_instr(uint32_t write_reg,
385384
return true;
386385
}
387386

388-
bool SpikeCosim::check_sync_trap(uint32_t write_reg,
389-
uint32_t dut_pc, uint32_t initial_spike_pc) {
387+
bool SpikeCosim::check_sync_trap(uint32_t write_reg, uint32_t dut_pc,
388+
uint32_t initial_spike_pc) {
390389
// Check if an synchronously-trapping instruction matches
391390
// between Spike and the DUT.
392391

393392
// Check that both spike and DUT trapped on the same pc
394393
if (initial_spike_pc != dut_pc) {
395394
std::stringstream err_str;
396-
err_str << "PC mismatch at synchronous trap, DUT at pc: "
397-
<< std::hex << dut_pc
398-
<< "while ISS pc is at : "
399-
<< std::hex << initial_spike_pc;
395+
err_str << "PC mismatch at synchronous trap, DUT at pc: " << std::hex
396+
<< dut_pc << "while ISS pc is at : " << std::hex
397+
<< initial_spike_pc;
400398
errors.emplace_back(err_str.str());
401399
return false;
402400
}
@@ -411,6 +409,12 @@ bool SpikeCosim::check_sync_trap(uint32_t write_reg,
411409
return false;
412410
}
413411

412+
if ((processor->get_state()->mcause->read() == 0x5) ||
413+
(processor->get_state()->mcause->read() == 0x7)) {
414+
// We have a load or store access fault, apply fixup for misaligned accesses
415+
misaligned_pmp_fixup();
416+
}
417+
414418
// If we see an internal NMI, that means we receive an extra memory intf item.
415419
// Deleting that is necessary since next Load/Store would fail otherwise.
416420
if (processor->get_state()->mcause->read() == 0xFFFFFFE0) {
@@ -577,11 +581,12 @@ void SpikeCosim::initial_proc_setup(uint32_t start_pc, uint32_t start_mtvec,
577581
}
578582
}
579583

580-
void SpikeCosim::set_mip(uint32_t mip) {
581-
uint32_t new_mip = mip;
584+
void SpikeCosim::set_mip(uint32_t pre_mip, uint32_t post_mip) {
585+
uint32_t new_mip = pre_mip;
582586
uint32_t old_mip = processor->get_state()->mip->read();
583587

584-
processor->get_state()->mip->write_with_mask(0xffffffff, mip);
588+
processor->get_state()->mip->write_with_mask(0xffffffff, post_mip);
589+
processor->get_state()->mip->write_pre_val(pre_mip);
585590

586591
if (processor->get_state()->debug_mode ||
587592
(processor->halt_request == processor_t::HR_REGULAR) ||
@@ -619,6 +624,62 @@ void SpikeCosim::early_interrupt_handle() {
619624
}
620625
}
621626

627+
// Ibex splits misaligned accesses into two separate requests. They
628+
// independently undergo PMP access checks. It is possible for one to fail (so
629+
// no request produced for that half of the access) whilst the other successed
630+
// (producing a request for that half of the access).
631+
//
632+
// Spike splits misaligned accesses up into bytes and will apply PMP access
633+
// checks byte by byte in a linear order. As soon as a byte sees a PMP
634+
// permission failure the rest of the misaligned access is aborted.
635+
//
636+
// This results in mismatches as in some misaligned access cases Ibex will
637+
// produce a request and spike will not.
638+
//
639+
// This fixup detects this condition and removes the Ibex access from
640+
// pending_dside_accesses to avoid a mismatch. This removed access is checked
641+
// against PMP using the spike MMU to check spike agrees it passes PMP checks.
642+
//
643+
// There may be a better way to handle this (e.g. altering spike behaviour to
644+
// match Ibex) so for now a warning is generated in fixup cases so they can be
645+
// easily identified.
646+
void SpikeCosim::misaligned_pmp_fixup() {
647+
if (pending_dside_accesses.size() != 0) {
648+
auto &top_pending_access = pending_dside_accesses.front();
649+
auto &top_pending_access_info = top_pending_access.dut_access_info;
650+
651+
// If top access is the second half of a misaligned access where the first
652+
// half saw an error we have the PMP fixup case
653+
if (top_pending_access_info.misaligned_second &&
654+
top_pending_access_info.misaligned_first_saw_error) {
655+
mmu_t *mmu = processor->get_mmu();
656+
657+
// Check if the second half of the access (which Ibex produces a request
658+
// for and spike does not) passes PMP
659+
if (!mmu->pmp_ok(top_pending_access_info.addr, 4,
660+
top_pending_access_info.store ? STORE : LOAD,
661+
top_pending_access_info.m_mode_access ? PRV_M : PRV_U)) {
662+
// Raise an error if the second half shouldn't have passed PMP
663+
std::stringstream err_str;
664+
err_str << "Saw second half of a misaligned access which not have "
665+
<< "generated a memory request as it does not pass a PMP check,"
666+
<< " address: " << std::hex << top_pending_access_info.addr;
667+
errors.emplace_back(err_str.str());
668+
} else {
669+
// Output warning on stdout so we're aware which tests this is happening
670+
// in
671+
std::cout << "WARNING: Cosim dropping second half of misaligned access "
672+
<< "as first half saw an error and second half passed PMP "
673+
<< "check, address: " << std::hex
674+
<< top_pending_access_info.addr << std::endl;
675+
std::cout << std::dec;
676+
677+
pending_dside_accesses.erase(pending_dside_accesses.begin());
678+
}
679+
}
680+
}
681+
}
682+
622683
void SpikeCosim::set_nmi(bool nmi) {
623684
if (nmi && !nmi_mode && !processor->get_state()->debug_mode &&
624685
processor->halt_request != processor_t::HR_REGULAR) {

hw/vendor/lowrisc_ibex/dv/cosim/spike_cosim.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class SpikeCosim : public simif_t, public Cosim {
9595

9696
void early_interrupt_handle();
9797

98+
void misaligned_pmp_fixup();
99+
98100
unsigned int insn_cnt;
99101

100102
public:
@@ -123,7 +125,7 @@ class SpikeCosim : public simif_t, public Cosim {
123125
uint32_t dut_pc, bool suppress_reg_write);
124126
bool check_sync_trap(uint32_t write_reg, uint32_t pc,
125127
uint32_t initial_spike_pc);
126-
void set_mip(uint32_t mip) override;
128+
void set_mip(uint32_t pre_mip, uint32_t post_mip) override;
127129
void set_nmi(bool nmi) override;
128130
void set_nmi_int(bool nmi_int) override;
129131
void set_debug_req(bool debug_req) override;

0 commit comments

Comments
 (0)