mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
Add simulation for RISC-V compliance testing
This adds a Verilator simulation of Ibex for use in RISC-V Compliance Testing. In addition to ibex itself, the simulation contains a RAM and a memory-mapped helper module for the test software to interact with the outside world. The test framework uses this to dump a "test signature", which is written to a certain part of the memory, and to end the simulation. (In the future, this could be extended to include printf() like functionality.)
This commit is contained in:
parent
b72f5db6bd
commit
24a9c64bf1
8 changed files with 782 additions and 0 deletions
67
dv/riscv_compliance/README.md
Normal file
67
dv/riscv_compliance/README.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
Ibex simulation for RISC-V Compliance Testing
|
||||
=============================================
|
||||
|
||||
This directory contains a compiled simulation of Ibex to be used as target
|
||||
in the [RISC-V Compliance Test](https://github.com/riscv/riscv-compliance).
|
||||
In addition to Ibex itself, it contains a 64 kB RAM and a memory-mapped helper
|
||||
module to interact with the software, e.g. to dump out the test signature and to
|
||||
end the simulation.
|
||||
|
||||
The simulation is designed for Verilator, but can be adapted to other simulators
|
||||
if needed.
|
||||
|
||||
How to run RISC-V Compliance on Ibex
|
||||
------------------------------------
|
||||
|
||||
0. Check your prerequisites
|
||||
To compile the simulation and run the compliance test suite you need to
|
||||
have the following tools installed:
|
||||
- Verilator
|
||||
- fusesoc
|
||||
- srecord (for `srec_cat`)
|
||||
- A RV32 compiler
|
||||
|
||||
On Ubuntu/Debian, install the required tools like this:
|
||||
|
||||
```sh
|
||||
sudo apt-get install srecord python3-pip
|
||||
pip3 install --user -U fusesoc
|
||||
```
|
||||
|
||||
We recommend installing Verilator from source as versions from Linux distributions are often outdated.
|
||||
See https://www.veripool.org/projects/verilator/wiki/Installing for installation instructions.
|
||||
|
||||
1. Build a simulation of Ibex
|
||||
|
||||
```sh
|
||||
cd $IBEX_REPO_BASE
|
||||
fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_riscv_compliance --RV32M=0 --RV32E=0
|
||||
```
|
||||
|
||||
You can use the two compile-time options `--RV32M` and `--RV32E` to
|
||||
enable/disable the M and E ISA extensions, respectively.
|
||||
|
||||
You can now find the compiled simulation at `build/lowrisc_ibex_ibex_riscv_compliance_0.1/sim-verilator/Vibex_riscv_compliance`.
|
||||
|
||||
2. Get the RISC-V Compliance test suite
|
||||
|
||||
The compliance test suite currently needs workarounds for Ibex.
|
||||
Get a modified version of it.
|
||||
|
||||
```
|
||||
git clone https://github.com/imphil/riscv-compliance.git
|
||||
cd riscv-compliance
|
||||
git checkout ibex
|
||||
```
|
||||
|
||||
|
||||
3. Run the test suite
|
||||
```sh
|
||||
cd $RISCV_COMPLIANCE_REPO_BASE
|
||||
export RISCV_TARGET=ibex
|
||||
export RISCV_ISA=rv32i
|
||||
export RISCV_PREFIX=riscv32-unknown-elf-
|
||||
export TARGET_SIM=path/to/your/Vibex_riscv_compliance
|
||||
make clean
|
||||
make
|
||||
```
|
93
dv/riscv_compliance/ibex_riscv_compliance.cc
Normal file
93
dv/riscv_compliance/ibex_riscv_compliance.cc
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "Vibex_riscv_compliance.h"
|
||||
#include "verilated_toplevel.h"
|
||||
#include "verilator_sim_ctrl.h"
|
||||
|
||||
VERILATED_TOPLEVEL(ibex_riscv_compliance)
|
||||
|
||||
ibex_riscv_compliance* top;
|
||||
VerilatorSimCtrl* simctrl;
|
||||
|
||||
static void SignalHandler(int sig) {
|
||||
if (!simctrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
simctrl->RequestStop();
|
||||
break;
|
||||
case SIGUSR1:
|
||||
if (simctrl->TracingEnabled()) {
|
||||
simctrl->TraceOff();
|
||||
} else {
|
||||
simctrl->TraceOn();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupSignalHandler() {
|
||||
struct sigaction sigIntHandler;
|
||||
|
||||
sigIntHandler.sa_handler = SignalHandler;
|
||||
sigemptyset(&sigIntHandler.sa_mask);
|
||||
sigIntHandler.sa_flags = 0;
|
||||
|
||||
sigaction(SIGINT, &sigIntHandler, NULL);
|
||||
sigaction(SIGUSR1, &sigIntHandler, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current simulation time
|
||||
*
|
||||
* Called by $time in Verilog, converts to double, to match what SystemC does
|
||||
*/
|
||||
double sc_time_stamp() { return simctrl->GetTime(); }
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int retcode;
|
||||
top = new ibex_riscv_compliance;
|
||||
simctrl = new VerilatorSimCtrl(top, top->IO_CLK, top->IO_RST_N,
|
||||
VerilatorSimCtrlFlags::ResetPolarityNegative);
|
||||
|
||||
SetupSignalHandler();
|
||||
|
||||
if (!simctrl->ParseCommandArgs(argc, argv, retcode)) {
|
||||
goto free_return;
|
||||
}
|
||||
|
||||
std::cout << "Simulation of Ibex" << std::endl
|
||||
<< "==================" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
if (simctrl->TracingPossible()) {
|
||||
std::cout << "Tracing can be toggled by sending SIGUSR1 to this process:"
|
||||
<< std::endl
|
||||
<< "$ kill -USR1 " << getpid() << std::endl;
|
||||
}
|
||||
|
||||
// Initialize RAM
|
||||
simctrl->InitRam("TOP.ibex_riscv_compliance.u_ram");
|
||||
|
||||
simctrl->Run();
|
||||
simctrl->PrintStatistics();
|
||||
|
||||
if (simctrl->TracingEverEnabled()) {
|
||||
std::cout << std::endl
|
||||
<< "You can view the simulation traces by calling" << std::endl
|
||||
<< "$ gtkwave " << simctrl->GetSimulationFileName() << std::endl;
|
||||
}
|
||||
|
||||
free_return:
|
||||
delete top;
|
||||
delete simctrl;
|
||||
return retcode;
|
||||
}
|
65
dv/riscv_compliance/ibex_riscv_compliance.core
Normal file
65
dv/riscv_compliance/ibex_riscv_compliance.core
Normal file
|
@ -0,0 +1,65 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:ibex:ibex_riscv_compliance:0.1"
|
||||
description: "Ibex simulation for RISC-V compliance testing (using Verilator)"
|
||||
filesets:
|
||||
files_sim_verilator:
|
||||
depend:
|
||||
- lowrisc:dv_verilator:simutil_verilator
|
||||
- lowrisc:ibex:ibex_core
|
||||
|
||||
files:
|
||||
- rtl/ibex_riscv_compliance.sv
|
||||
- ibex_riscv_compliance.cc: { file_type: cppSource }
|
||||
- rtl/prim_clock_gating.sv
|
||||
- rtl/ram_1p.sv
|
||||
- rtl/bus.sv
|
||||
- rtl/riscv_testutil.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
parameters:
|
||||
RV32M:
|
||||
datatype: int
|
||||
paramtype: vlogparam
|
||||
default: 1
|
||||
description: Enable the M ISA extension (hardware multiply/divide) [0/1]
|
||||
RV32E:
|
||||
datatype: int
|
||||
paramtype: vlogparam
|
||||
default: 0
|
||||
description: Enable the E ISA extension (reduced register set) [0/1]
|
||||
|
||||
targets:
|
||||
sim:
|
||||
default_tool: verilator
|
||||
filesets:
|
||||
- files_sim_verilator
|
||||
parameters:
|
||||
- RV32M
|
||||
- RV32E
|
||||
toplevel: ibex_riscv_compliance
|
||||
tools:
|
||||
verilator:
|
||||
mode: cc
|
||||
verilator_options:
|
||||
# Disabling tracing reduces compile times by multiple times, but doesn't have a
|
||||
# huge influence on runtime performance. (Based on early observations.)
|
||||
- '--trace'
|
||||
- '--trace-fst' # this requires -DVM_TRACE_FMT_FST in CFLAGS below!
|
||||
- '--trace-structs'
|
||||
- '--trace-params'
|
||||
- '--trace-max-array 1024'
|
||||
# compiler flags
|
||||
#
|
||||
# -O
|
||||
# Optimization levels have a large impact on the runtime performance of the
|
||||
# simulation model. -O2 and -O3 are pretty similar, -Os is slower than -O2/-O3
|
||||
- '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -g -O0"'
|
||||
- '-LDFLAGS "-pthread -lutil"'
|
||||
- "-Wall"
|
||||
- "-Wno-PINCONNECTEMPTY"
|
||||
# XXX: Cleanup all warnings and remove this option
|
||||
# (or make it more fine-grained at least)
|
||||
- "-Wno-fatal"
|
120
dv/riscv_compliance/rtl/bus.sv
Normal file
120
dv/riscv_compliance/rtl/bus.sv
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* Simplistic Ibex bus implementation
|
||||
*
|
||||
* This module is designed for demo and simulation purposes, do not use it in
|
||||
* a real-world system.
|
||||
*
|
||||
* This implementation doesn't handle the full bus protocol, but makes the
|
||||
* following simplifying assumptions.
|
||||
*
|
||||
* - All devices (slaves) must respond in the next cycle after the request.
|
||||
* - Host (master) arbitration is strictly priority based.
|
||||
*/
|
||||
module bus #(
|
||||
parameter NrDevices,
|
||||
parameter NrHosts,
|
||||
parameter DataWidth = 32,
|
||||
parameter AddressWidth = 32
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
// Hosts (masters)
|
||||
input host_req_i [NrHosts],
|
||||
output logic host_gnt_o [NrHosts],
|
||||
|
||||
input [AddressWidth-1:0] host_addr_i [NrHosts],
|
||||
input host_we_i [NrHosts],
|
||||
input [ DataWidth/8-1:0] host_be_i [NrHosts],
|
||||
input [ DataWidth-1:0] host_wdata_i [NrHosts],
|
||||
output logic host_rvalid_o [NrHosts],
|
||||
output logic [ DataWidth-1:0] host_rdata_o [NrHosts],
|
||||
output logic host_err_o [NrHosts],
|
||||
|
||||
// Devices (slaves)
|
||||
output logic device_req_o [NrDevices],
|
||||
|
||||
output logic [AddressWidth-1:0] device_addr_o [NrDevices],
|
||||
output logic device_we_o [NrDevices],
|
||||
output logic [ DataWidth/8-1:0] device_be_o [NrDevices],
|
||||
output logic [ DataWidth-1:0] device_wdata_o [NrDevices],
|
||||
input device_rvalid_i [NrDevices],
|
||||
input [ DataWidth-1:0] device_rdata_i [NrDevices],
|
||||
input device_err_i [NrDevices],
|
||||
|
||||
// Device address map
|
||||
input [AddressWidth-1:0] cfg_device_addr_base [NrDevices],
|
||||
input [AddressWidth-1:0] cfg_device_addr_mask [NrDevices]
|
||||
);
|
||||
|
||||
logic [$clog2(NrHosts)-1:0] host_sel_req, host_sel_resp;
|
||||
logic [$clog2(NrDevices)-1:0] device_sel_req, device_sel_resp;
|
||||
|
||||
// Master select prio arbiter
|
||||
always_comb begin
|
||||
for (integer host = NrHosts - 1; host >= 0; host = host - 1) begin
|
||||
if (host_req_i[host]) begin
|
||||
host_sel_req = $clog2(NrHosts)'(host);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Device select
|
||||
always_comb begin
|
||||
for (integer device = 0; device < NrDevices; device = device + 1) begin
|
||||
if ((host_addr_i[host_sel_req] & cfg_device_addr_mask[device])
|
||||
== cfg_device_addr_base[device]) begin
|
||||
device_sel_req = $clog2(NrDevices)'(device);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
host_sel_resp <= '0;
|
||||
device_sel_resp <= '0;
|
||||
end else begin
|
||||
// Responses are always expected 1 cycle after the request
|
||||
device_sel_resp <= device_sel_req;
|
||||
host_sel_resp <= host_sel_req;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
for (integer device = 0; device < NrDevices; device = device + 1) begin
|
||||
if ($clog2(NrDevices)'(device) == device_sel_req) begin
|
||||
device_req_o[device] = host_req_i[host_sel_req];
|
||||
device_we_o[device] = host_we_i[host_sel_req];
|
||||
device_addr_o[device] = host_addr_i[host_sel_req];
|
||||
device_wdata_o[device] = host_wdata_i[host_sel_req];
|
||||
device_be_o[device] = host_be_i[host_sel_req];
|
||||
end else begin
|
||||
device_req_o[device] = 1'b0;
|
||||
device_we_o[device] = 1'b0;
|
||||
device_addr_o[device] = 'b0;
|
||||
device_wdata_o[device] = 'b0;
|
||||
device_be_o[device] = 'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
for (integer host = 0; host < NrHosts; host = host + 1) begin
|
||||
if ($clog2(NrHosts)'(host) == host_sel_resp) begin
|
||||
host_rvalid_o[host] = device_rvalid_i[device_sel_resp];
|
||||
host_err_o[host] = device_err_i[device_sel_resp];
|
||||
host_rdata_o[host] = device_rdata_i[device_sel_resp];
|
||||
end else begin
|
||||
host_gnt_o[host] = 1'b0;
|
||||
host_rvalid_o[host] = 1'b0;
|
||||
host_err_o[host] = 1'b0;
|
||||
host_rdata_o[host] = 'b0;
|
||||
end
|
||||
end
|
||||
host_gnt_o[host_sel_req] = host_req_i[host_sel_req];
|
||||
end
|
||||
endmodule
|
185
dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
Normal file
185
dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
Normal file
|
@ -0,0 +1,185 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* Ibex simulation to run the RISC-V compliance test on
|
||||
*
|
||||
* This is a toplevel wrapper for Ibex with helpers to run the RISC-V compliance
|
||||
* test. It is designed for Verilator, but should equally work for other
|
||||
* simulators (if the top-level clk and rst ports are replaced with a generated
|
||||
* clock).
|
||||
*/
|
||||
module ibex_riscv_compliance (
|
||||
input IO_CLK,
|
||||
input IO_RST_N
|
||||
);
|
||||
|
||||
parameter bit RV32E = 0;
|
||||
parameter bit RV32M = 1;
|
||||
|
||||
logic clk_sys, rst_sys_n;
|
||||
|
||||
assign clk_sys = IO_CLK;
|
||||
assign rst_sys_n = IO_RST_N;
|
||||
|
||||
typedef enum {
|
||||
TestUtilHost,
|
||||
CoreI,
|
||||
CoreD
|
||||
} bus_host_e;
|
||||
|
||||
typedef enum {
|
||||
Ram,
|
||||
TestUtilDevice
|
||||
} bus_device_e;
|
||||
|
||||
localparam NrDevices = 2;
|
||||
localparam NrHosts = 3;
|
||||
|
||||
// host and device signals
|
||||
logic host_req [NrHosts];
|
||||
logic host_gnt [NrHosts];
|
||||
logic [31:0] host_addr [NrHosts];
|
||||
logic host_we [NrHosts];
|
||||
logic [ 3:0] host_be [NrHosts];
|
||||
logic [31:0] host_wdata [NrHosts];
|
||||
logic host_rvalid [NrHosts];
|
||||
logic [31:0] host_rdata [NrHosts];
|
||||
logic host_err [NrHosts];
|
||||
|
||||
// devices (slaves)
|
||||
logic device_req [NrDevices];
|
||||
logic [31:0] device_addr [NrDevices];
|
||||
logic device_we [NrDevices];
|
||||
logic [ 3:0] device_be [NrDevices];
|
||||
logic [31:0] device_wdata [NrDevices];
|
||||
logic device_rvalid [NrDevices];
|
||||
logic [31:0] device_rdata [NrDevices];
|
||||
logic device_err [NrDevices];
|
||||
|
||||
// Device address mapping
|
||||
logic [31:0] cfg_device_addr_base [NrDevices];
|
||||
logic [31:0] cfg_device_addr_mask [NrDevices];
|
||||
assign cfg_device_addr_base[Ram] = 32'h0;
|
||||
assign cfg_device_addr_mask[Ram] = ~32'hFFFF; // 64 kB
|
||||
assign cfg_device_addr_base[TestUtilDevice] = 32'h20000;
|
||||
assign cfg_device_addr_mask[TestUtilDevice] = ~32'h3FF; // 1 kB
|
||||
|
||||
|
||||
bus #(
|
||||
.NrDevices (NrDevices),
|
||||
.NrHosts (NrHosts ),
|
||||
.DataWidth (32 ),
|
||||
.AddressWidth(32 )
|
||||
) u_bus (
|
||||
.clk_i (clk_sys),
|
||||
.rst_ni (rst_sys_n),
|
||||
|
||||
.host_req_i (host_req ),
|
||||
.host_gnt_o (host_gnt ),
|
||||
.host_addr_i (host_addr ),
|
||||
.host_we_i (host_we ),
|
||||
.host_be_i (host_be ),
|
||||
.host_wdata_i (host_wdata ),
|
||||
.host_rvalid_o (host_rvalid ),
|
||||
.host_rdata_o (host_rdata ),
|
||||
.host_err_o (host_err ),
|
||||
|
||||
.device_req_o (device_req ),
|
||||
.device_addr_o (device_addr ),
|
||||
.device_we_o (device_we ),
|
||||
.device_be_o (device_be ),
|
||||
.device_wdata_o (device_wdata ),
|
||||
.device_rvalid_i (device_rvalid),
|
||||
.device_rdata_i (device_rdata ),
|
||||
.device_err_i (device_err ),
|
||||
|
||||
.cfg_device_addr_base,
|
||||
.cfg_device_addr_mask
|
||||
);
|
||||
|
||||
ibex_core #(
|
||||
.DmHaltAddr(32'h00000000),
|
||||
.DmExceptionAddr(32'h00000000),
|
||||
.RV32E(RV32E),
|
||||
.RV32M(RV32M)
|
||||
) u_core (
|
||||
.clk_i (clk_sys),
|
||||
.rst_ni (rst_sys_n),
|
||||
|
||||
.test_en_i ('b0),
|
||||
|
||||
.core_id_i (4'b0),
|
||||
.cluster_id_i (6'b0),
|
||||
// First instruction executed is at 0x0 + 0x80
|
||||
.boot_addr_i (32'h00000000),
|
||||
|
||||
.instr_req_o (host_req[CoreI]),
|
||||
.instr_gnt_i (host_gnt[CoreI]),
|
||||
.instr_rvalid_i (host_rvalid[CoreI]),
|
||||
.instr_addr_o (host_addr[CoreI]),
|
||||
.instr_rdata_i (host_rdata[CoreI]),
|
||||
|
||||
.data_req_o (host_req[CoreD]),
|
||||
.data_gnt_i (host_gnt[CoreD]),
|
||||
.data_rvalid_i (host_rvalid[CoreD]),
|
||||
.data_we_o (host_we[CoreD]),
|
||||
.data_be_o (host_be[CoreD]),
|
||||
.data_addr_o (host_addr[CoreD]),
|
||||
.data_wdata_o (host_wdata[CoreD]),
|
||||
.data_rdata_i (host_rdata[CoreD]),
|
||||
.data_err_i (host_err[CoreD]),
|
||||
|
||||
.irq_software_i (1'b0),
|
||||
.irq_timer_i (1'b0),
|
||||
.irq_external_i (1'b0),
|
||||
.irq_fast_i (15'b0),
|
||||
.irq_nm_i (1'b0),
|
||||
|
||||
.debug_req_i ('b0),
|
||||
|
||||
.fetch_enable_i ('b1)
|
||||
);
|
||||
|
||||
// SRAM block for instruction and data storage
|
||||
ram_1p #(
|
||||
.Depth(64*1024/4)
|
||||
) u_ram (
|
||||
.clk_i (clk_sys),
|
||||
.rst_ni (rst_sys_n),
|
||||
.req_i (device_req[Ram]),
|
||||
.we_i (device_we[Ram]),
|
||||
.be_i (device_be[Ram]),
|
||||
.addr_i (device_addr[Ram]),
|
||||
.wdata_i (device_wdata[Ram]),
|
||||
.rvalid_o (device_rvalid[Ram]),
|
||||
.rdata_o (device_rdata[Ram])
|
||||
);
|
||||
|
||||
// RISC-V test utility, used by the RISC-V compliance test to interact with
|
||||
// the simulator.
|
||||
riscv_testutil
|
||||
u_riscv_testutil(
|
||||
.clk_i (clk_sys),
|
||||
.rst_ni (rst_sys_n),
|
||||
|
||||
// Device port
|
||||
.dev_req_i (device_req[TestUtilDevice]),
|
||||
.dev_we_i (device_we[TestUtilDevice]),
|
||||
.dev_addr_i (device_addr[TestUtilDevice]),
|
||||
.dev_wdata_i (device_wdata[TestUtilDevice]),
|
||||
.dev_rvalid_o (device_rvalid[TestUtilDevice]),
|
||||
.dev_rdata_o (device_rdata[TestUtilDevice]),
|
||||
.dev_be_i (device_be[TestUtilDevice]),
|
||||
.dev_err_o (device_err[TestUtilDevice]),
|
||||
|
||||
// Host port
|
||||
.host_req_o (host_req[TestUtilHost]),
|
||||
.host_gnt_i (host_gnt[TestUtilHost]),
|
||||
.host_rvalid_i (host_rvalid[TestUtilHost]),
|
||||
.host_addr_o (host_addr[TestUtilHost]),
|
||||
.host_rdata_i (host_rdata[TestUtilHost])
|
||||
);
|
||||
|
||||
endmodule
|
24
dv/riscv_compliance/rtl/prim_clock_gating.sv
Normal file
24
dv/riscv_compliance/rtl/prim_clock_gating.sv
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Dummy clock gating module
|
||||
|
||||
module prim_clock_gating (
|
||||
input clk_i,
|
||||
input en_i,
|
||||
input test_en_i,
|
||||
output logic clk_o
|
||||
);
|
||||
|
||||
logic clk_en;
|
||||
|
||||
always_latch begin
|
||||
if (clk_i == 1'b0) begin
|
||||
clk_en <= en_i | test_en_i;
|
||||
end
|
||||
end
|
||||
|
||||
assign clk_o = clk_i & clk_en;
|
||||
|
||||
endmodule
|
70
dv/riscv_compliance/rtl/ram_1p.sv
Normal file
70
dv/riscv_compliance/rtl/ram_1p.sv
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* Single-port RAM with 1 cycle read/write delay, 32 bit words
|
||||
*/
|
||||
module ram_1p #(
|
||||
parameter int Depth = 128
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input req_i,
|
||||
input we_i,
|
||||
input [ 3:0] be_i,
|
||||
input [31:0] addr_i,
|
||||
input [31:0] wdata_i,
|
||||
output logic rvalid_o,
|
||||
output logic [31:0] rdata_o
|
||||
);
|
||||
|
||||
localparam int Aw = $clog2(Depth);
|
||||
|
||||
logic [31:0] mem [Depth];
|
||||
|
||||
logic [Aw-1:0] addr_idx;
|
||||
assign addr_idx = addr_i[Aw-1+2:2];
|
||||
logic [31-Aw:0] unused_addr_parts;
|
||||
assign unused_addr_parts = {addr_i[31:Aw+2], addr_i[1:0]};
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (req_i) begin
|
||||
if (we_i) begin
|
||||
for (int i = 0; i < 4; i = i + 1) begin
|
||||
if (be_i[i] == 1'b1) begin
|
||||
mem[addr_idx][i*8 +: 8] <= wdata_i[i*8 +: 8];
|
||||
end
|
||||
end
|
||||
end
|
||||
rdata_o <= mem[addr_idx];
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
rvalid_o <= '0;
|
||||
end else begin
|
||||
rvalid_o <= req_i;
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef VERILATOR
|
||||
export "DPI-C" task simutil_verilator_memload;
|
||||
|
||||
task simutil_verilator_memload;
|
||||
input string file;
|
||||
$readmemh(file, mem);
|
||||
endtask
|
||||
`endif
|
||||
|
||||
`ifdef SRAM_INIT_FILE
|
||||
localparam MEM_FILE = `"`SRAM_INIT_FILE`";
|
||||
initial begin
|
||||
$display("Initializing SRAM from %s", MEM_FILE);
|
||||
$readmemh(MEM_FILE, mem);
|
||||
end
|
||||
`endif
|
||||
endmodule
|
||||
|
158
dv/riscv_compliance/rtl/riscv_testutil.sv
Normal file
158
dv/riscv_compliance/rtl/riscv_testutil.sv
Normal file
|
@ -0,0 +1,158 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* RISC-V Compliance Test helper module (simulation only)
|
||||
*
|
||||
* This module lets the RISC-V compliance test software interact with the
|
||||
* "outside world".
|
||||
*
|
||||
* It consists of a bus device and a bus host.
|
||||
*
|
||||
* Through the bus device, the software can interact with the outside world and
|
||||
* configure this module. The following registers are supported:
|
||||
* 0x0: read the signature and halt the execution
|
||||
* 0x4: set the signature start address
|
||||
* 0x8: set the signature end address
|
||||
*
|
||||
* When register 0x0 is written with an arbitrary value, the test signature is
|
||||
* read through the bus device, and written to STDOUT, prefixed with
|
||||
* "SIGNATURE: ".
|
||||
*/
|
||||
module riscv_testutil (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
// bus device (slave) interface
|
||||
input dev_req_i,
|
||||
input dev_we_i,
|
||||
input [31:0] dev_addr_i,
|
||||
input [31:0] dev_wdata_i,
|
||||
input [ 3:0] dev_be_i,
|
||||
|
||||
output logic dev_rvalid_o,
|
||||
output logic [31:0] dev_rdata_o,
|
||||
output logic dev_err_o,
|
||||
|
||||
// bus host (master) interface
|
||||
output logic host_req_o,
|
||||
input host_gnt_i,
|
||||
input host_rvalid_i,
|
||||
output logic [31:0] host_addr_o,
|
||||
input [31:0] host_rdata_i
|
||||
);
|
||||
// ======= Bus device for interaction with software ======= //
|
||||
|
||||
localparam ADDR_HALT = 0;
|
||||
localparam ADDR_SET_BEGIN_SIGNATURE = 4;
|
||||
localparam ADDR_SET_END_SIGNATURE = 8;
|
||||
|
||||
// 1 kB address space for this peripheral
|
||||
logic [21:0] unused_addr;
|
||||
assign unused_addr = dev_addr_i[31:10];
|
||||
|
||||
logic [31:0] begin_signature_addr_d, begin_signature_addr_q;
|
||||
logic [31:0] end_signature_addr_d, end_signature_addr_q;
|
||||
|
||||
logic read_signature_and_terminate;
|
||||
always_comb begin
|
||||
read_signature_and_terminate = 1'b0;
|
||||
begin_signature_addr_d = begin_signature_addr_q;
|
||||
end_signature_addr_d = end_signature_addr_q;
|
||||
|
||||
if (dev_we_i && dev_req_i) begin
|
||||
case (dev_addr_i[9:0])
|
||||
ADDR_HALT: begin
|
||||
read_signature_and_terminate = 1'b1;
|
||||
end
|
||||
ADDR_SET_BEGIN_SIGNATURE: begin
|
||||
begin_signature_addr_d = dev_wdata_i;
|
||||
end
|
||||
ADDR_SET_END_SIGNATURE: begin
|
||||
end_signature_addr_d = dev_wdata_i;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i) begin
|
||||
begin_signature_addr_q <= begin_signature_addr_d;
|
||||
end_signature_addr_q <= end_signature_addr_d;
|
||||
end
|
||||
|
||||
// all responses are in the next cycle
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
dev_rvalid_o <= 1'b0;
|
||||
end else begin
|
||||
dev_rvalid_o <= dev_req_i;
|
||||
end
|
||||
end
|
||||
|
||||
// only word writes are supported
|
||||
assign dev_err_o = (~dev_we_i | dev_be_i != 4'hf) & dev_req_i;
|
||||
assign dev_rdata_o = 32'h0;
|
||||
|
||||
|
||||
// ======= FSM: Read signature from memory and dump it to STDOUT ======= //
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
WAIT, READ, READ_FINISH, TERMINATE
|
||||
} readsig_state_e;
|
||||
|
||||
readsig_state_e state_q, state_d;
|
||||
|
||||
logic [31:0] read_addr_d, read_addr_q;
|
||||
always_comb begin
|
||||
state_d = state_q;
|
||||
host_req_o = 1'b0;
|
||||
|
||||
unique case (state_q)
|
||||
WAIT: begin
|
||||
if (read_signature_and_terminate) begin
|
||||
$display("Reading signature from 0x%x to 0x%x",
|
||||
begin_signature_addr_q, end_signature_addr_q);
|
||||
state_d = READ;
|
||||
read_addr_d = begin_signature_addr_q;
|
||||
end
|
||||
end
|
||||
|
||||
READ: begin
|
||||
host_req_o = 1'b1;
|
||||
host_addr_o = read_addr_q;
|
||||
if (host_gnt_i) begin
|
||||
read_addr_d = read_addr_q + 4;
|
||||
if (read_addr_d == end_signature_addr_q) begin
|
||||
state_d = READ_FINISH;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
READ_FINISH: begin
|
||||
if (host_rvalid_i) begin
|
||||
state_d = TERMINATE;
|
||||
end
|
||||
end
|
||||
|
||||
TERMINATE: begin
|
||||
$display("Terminating simulation by software request.");
|
||||
$finish;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
state_q <= WAIT;
|
||||
read_addr_q <= 0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
read_addr_q <= read_addr_d;
|
||||
|
||||
if (host_rvalid_i) begin
|
||||
$display("SIGNATURE: 0x%x", host_rdata_i);
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
Loading…
Add table
Add a link
Reference in a new issue