Files
PeakRDL-regblock/tests/lib/cpuifs/passthrough/passthrough_driver.sv
sbaillou d69af23be5 Error response for unmapped address or forbidden read/write access (#168)
* feat: add ability to enable error output on the cpuif, when decoding errors occur (generate_cpuif_err in API).

* fix: move signal to new place (after automatic vers)

* feat: add info about new api (generate_cpuif_err)

* fix: repair readback with latency

* Adding generate_cpuif_err argument to peakrdl-regblock to generate cpuif error response, when the address is decoded incorrectly

* add sw rd or/and wr attribure error response related and add error respone for external mem

* add sw rd or/and wr error response test

* add sw rd or/and wr error response for external register test and fix generation of rtl logic for external register

* add sw rd or/and wr error response for external mem test

* add sw rd or/and wr error response for apb3 imterfaces driver

* add error response test for APB4, AXI4Lite and Avalon interfaces

* rename --generate_cpuif_err to --generate-cpuif-err

* style: minor typo fixes and test clean-up

* refactor: move expected error check inside write/read functions

* feat: add error response check to OBI testbench interface

* feat: split generate-cpuif-err option into err-if-bad-addr and err-if-bad-rw options

* feat: add err_if_bad_addr/rw to cfg_schema

* feat: extend cpuif_err_rsp test to cover all combinations of bad_addr/bad_rw

* style: lint fixes

* fix: removed redundant if node.external condition to help coverage

* Fix dangling hwif_in signals in testcase

---------

Co-authored-by: Denis Trifonov <d.trifonov@yadro.com>
Co-authored-by: Dominik Tanous <tanous@kandou.com>
Co-authored-by: Sebastien Baillou <baillou@kandou.com>
Co-authored-by: Alex Mykyta <amykyta3@users.noreply.github.com>
2025-10-25 18:22:15 -07:00

126 lines
4.3 KiB
Systemverilog

interface passthrough_driver #(
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 32
)(
input wire clk,
input wire rst,
output logic m_cpuif_req,
output logic m_cpuif_req_is_wr,
output logic [ADDR_WIDTH-1:0] m_cpuif_addr,
output logic [DATA_WIDTH-1:0] m_cpuif_wr_data,
output logic [DATA_WIDTH-1:0] m_cpuif_wr_biten,
input wire m_cpuif_req_stall_wr,
input wire m_cpuif_req_stall_rd,
input wire m_cpuif_rd_ack,
input wire m_cpuif_rd_err,
input wire [DATA_WIDTH-1:0] m_cpuif_rd_data,
input wire m_cpuif_wr_ack,
input wire m_cpuif_wr_err
);
timeunit 1ps;
timeprecision 1ps;
default clocking cb @(posedge clk);
default input #1step output #1;
output m_cpuif_req;
output m_cpuif_req_is_wr;
output m_cpuif_addr;
output m_cpuif_wr_data;
output m_cpuif_wr_biten;
input m_cpuif_req_stall_wr;
input m_cpuif_req_stall_rd;
input m_cpuif_rd_ack;
input m_cpuif_rd_err;
input m_cpuif_rd_data;
input m_cpuif_wr_ack;
input m_cpuif_wr_err;
endclocking
task automatic reset();
cb.m_cpuif_req <= '0;
cb.m_cpuif_req_is_wr <= '0;
cb.m_cpuif_addr <= '0;
cb.m_cpuif_wr_data <= '0;
cb.m_cpuif_wr_biten <= '0;
endtask
semaphore txn_req_mutex = new(1);
semaphore txn_resp_mutex = new(1);
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data, logic [DATA_WIDTH-1:0] biten = {DATA_WIDTH{1'b1}}, logic expects_err = 1'b0);
fork
begin
// Initiate transfer
txn_req_mutex.get();
##0;
cb.m_cpuif_req <= '1;
cb.m_cpuif_req_is_wr <= '1;
cb.m_cpuif_addr <= addr;
cb.m_cpuif_wr_data <= data;
cb.m_cpuif_wr_biten <= biten;
@(cb);
while(cb.m_cpuif_req_stall_wr !== 1'b0) @(cb);
reset();
txn_req_mutex.put();
end
begin
// Wait for response
txn_resp_mutex.get();
@cb;
while(cb.m_cpuif_wr_ack !== 1'b1) @(cb);
assert(cb.m_cpuif_wr_err == expects_err) else $error("Error write response to 0x%x returned 0x%x. Expected 0x%x", addr, cb.m_cpuif_wr_err, expects_err);
txn_resp_mutex.put();
end
join
endtask
task automatic read(logic [ADDR_WIDTH-1:0] addr, output logic [DATA_WIDTH-1:0] data, input logic expects_err = 1'b0);
fork
begin
// Initiate transfer
txn_req_mutex.get();
##0;
cb.m_cpuif_req <= '1;
cb.m_cpuif_req_is_wr <= '0;
cb.m_cpuif_addr <= addr;
@(cb);
while(cb.m_cpuif_req_stall_rd !== 1'b0) @(cb);
reset();
txn_req_mutex.put();
end
begin
// Wait for response
txn_resp_mutex.get();
@cb;
while(cb.m_cpuif_rd_ack !== 1'b1) @(cb);
assert(!$isunknown(cb.m_cpuif_rd_data)) else $error("Read from 0x%0x returned X's on m_cpuif_rd_data", addr);
assert(cb.m_cpuif_rd_err == expects_err) else $error("Error read response from 0x%x returned 0x%x. Expected 0x%x", addr, cb.m_cpuif_rd_err, expects_err);
data = cb.m_cpuif_rd_data;
txn_resp_mutex.put();
end
join
endtask
task automatic assert_read(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] expected_data, logic [DATA_WIDTH-1:0] mask = {DATA_WIDTH{1'b1}}, input logic expects_err = 1'b0);
logic [DATA_WIDTH-1:0] data;
read(addr, data, expects_err);
data &= mask;
assert(data == expected_data) else $error("Read from 0x%x returned 0x%x. Expected 0x%x", addr, data, expected_data);
endtask
initial begin
reset();
end
initial forever begin
@cb;
if(!rst) assert(!$isunknown(cb.m_cpuif_rd_ack)) else $error("Saw X on m_cpuif_rd_ack!");
if(!rst) assert(!$isunknown(cb.m_cpuif_wr_ack)) else $error("Saw X on m_cpuif_wr_ack!");
end
endinterface