Simulator compatibility updates

This commit is contained in:
Alex Mykyta
2023-10-22 20:43:34 -07:00
parent d689bb7077
commit b5b1ba790e
29 changed files with 244 additions and 111 deletions

View File

@@ -1,7 +1,7 @@
def pytest_addoption(parser): def pytest_addoption(parser):
parser.addoption( parser.addoption(
"--sim-tool", "--sim-tool",
choices=["questa", "xilinx", "stub", "skip", "auto"], choices=["questa", "xsim", "stub", "skip", "auto"],
default="auto", default="auto",
help=""" help="""
Select the simulator to use. Select the simulator to use.
@@ -12,6 +12,29 @@ def pytest_addoption(parser):
""" """
) )
parser.addoption(
"--gui",
default=False,
action="store_true",
help=""",
Launch sim tool in GUI mode
Only use this option when running a single test
"""
)
parser.addoption(
"--rerun",
default=False,
action="store_true",
help=""",
Re-run simulation in-place without re-exporting regblock
Useful if hand-editing a testcase interactively.
"""
)
parser.addoption( parser.addoption(
"--synth-tool", "--synth-tool",
choices=["vivado", "skip", "auto"], choices=["vivado", "skip", "auto"],

View File

@@ -49,6 +49,13 @@ class BaseTestCase(unittest.TestCase):
def _load_request(self, request): def _load_request(self, request):
self.request = request self.request = request
@property
def rerun(self) -> bool:
"""
Re-run wothout deleting and re-generating prior output directory.
"""
return self.request.config.getoption("--rerun")
def get_testcase_dir(self) -> str: def get_testcase_dir(self) -> str:
class_dir = os.path.dirname(inspect.getfile(self.__class__)) class_dir = os.path.dirname(inspect.getfile(self.__class__))
return class_dir return class_dir
@@ -114,6 +121,9 @@ class BaseTestCase(unittest.TestCase):
) )
def setUp(self) -> None: def setUp(self) -> None:
if self.rerun:
return
# Create fresh build dir # Create fresh build dir
run_dir = self.get_run_dir() run_dir = self.get_run_dir()
if os.path.exists(run_dir): if os.path.exists(run_dir):

View File

@@ -95,59 +95,129 @@ interface axi4lite_intf_driver #(
@cb; @cb;
end end
semaphore txn_aw_mutex = new(1); //--------------------------------------------------------------------------
semaphore txn_w_mutex = new(1); typedef struct {
semaphore txn_b_mutex = new(1); logic [1:0] bresp;
semaphore txn_ar_mutex = new(1); } write_response_t;
semaphore txn_r_mutex = new(1);
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data, logic [DATA_WIDTH/8-1:0] strb = '1); class write_request_t;
bit w_before_aw; mailbox #(write_response_t) response_mbx;
w_before_aw = $urandom_range(1,0); logic [ADDR_WIDTH-1:0] addr;
logic [DATA_WIDTH-1:0] data;
logic [DATA_WIDTH/8-1:0] strb;
function new();
this.response_mbx = new();
endfunction
endclass
fork mailbox #(write_request_t) aw_mbx = new();
begin mailbox #(write_request_t) w_mbx = new();
txn_aw_mutex.get(); write_request_t write_queue[$];
// Issue AW transfers
initial forever begin
write_request_t req;
aw_mbx.get(req);
##0; ##0;
if(w_before_aw) repeat($urandom_range(2,0)) @cb; repeat($urandom_range(2,0)) @cb;
cb.AWVALID <= '1; cb.AWVALID <= '1;
cb.AWADDR <= addr; cb.AWADDR <= req.addr;
cb.AWPROT <= '0; cb.AWPROT <= '0;
@(cb); @(cb);
while(cb.AWREADY !== 1'b1) @(cb); while(cb.AWREADY !== 1'b1) @(cb);
cb.AWVALID <= '0; cb.AWVALID <= '0;
txn_aw_mutex.put();
end end
begin // Issue W transfers
txn_w_mutex.get(); initial forever begin
write_request_t req;
w_mbx.get(req);
##0; ##0;
if(!w_before_aw) repeat($urandom_range(2,0)) @cb; repeat($urandom_range(2,0)) @cb;
cb.WVALID <= '1; cb.WVALID <= '1;
cb.WDATA <= data; cb.WDATA <= req.data;
cb.WSTRB <= strb; cb.WSTRB <= req.strb;
@(cb); @(cb);
while(cb.WREADY !== 1'b1) @(cb); while(cb.WREADY !== 1'b1) @(cb);
cb.WVALID <= '0; cb.WVALID <= '0;
cb.WSTRB <= '0; cb.WSTRB <= '0;
txn_w_mutex.put();
end end
begin // Listen for R responses
txn_b_mutex.get(); initial forever begin
@cb; @cb;
while(!(cb.BREADY === 1'b1 && cb.BVALID === 1'b1)) @(cb); while(rst || !(cb.BREADY === 1'b1 && cb.BVALID === 1'b1)) @cb;
assert(!$isunknown(cb.BRESP)) else $error("Read from 0x%0x returned X's on BRESP", addr); if(write_queue.size() != 0) begin
txn_b_mutex.put(); // Can match this response with an existing request.
// Send response to requestor
write_request_t req;
write_response_t resp;
req = write_queue.pop_front();
resp.bresp = cb.BRESP;
req.response_mbx.put(resp);
end else begin
$error("Got unmatched write response");
end end
join end
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data, logic [DATA_WIDTH/8-1:0] strb = '1);
write_request_t req;
write_response_t resp;
req = new();
req.addr = addr;
req.data = data;
req.strb = strb;
aw_mbx.put(req);
w_mbx.put(req);
write_queue.push_back(req);
// Wait for response
req.response_mbx.get(resp);
assert(!$isunknown(resp.bresp)) else $error("Read from 0x%0x returned X's on BRESP", addr);
endtask endtask
task automatic read(logic [ADDR_WIDTH-1:0] addr, output logic [DATA_WIDTH-1:0] data); //--------------------------------------------------------------------------
typedef struct {
logic [DATA_WIDTH-1: 0] rdata;
logic [1:0] rresp;
} read_response_t;
class read_request_t;
mailbox #(read_response_t) response_mbx;
function new();
this.response_mbx = new();
endfunction
endclass
semaphore txn_ar_mutex = new(1);
read_request_t read_queue[$];
// Listen for R responses
initial forever begin
@cb;
while(rst || !(cb.RREADY === 1'b1 && cb.RVALID === 1'b1)) @cb;
if(read_queue.size() != 0) begin
// Can match this response with an existing request.
// Send response to requestor
read_request_t req;
read_response_t resp;
req = read_queue.pop_front();
resp.rdata = cb.RDATA;
resp.rresp = cb.RRESP;
req.response_mbx.put(resp);
end else begin
$error("Got unmatched read response");
end
end
task automatic read(logic [ADDR_WIDTH-1:0] addr, output logic [DATA_WIDTH-1:0] data);
read_request_t req;
read_response_t resp;
fork
begin
txn_ar_mutex.get(); txn_ar_mutex.get();
// Issue read request
##0; ##0;
cb.ARVALID <= '1; cb.ARVALID <= '1;
cb.ARADDR <= addr; cb.ARADDR <= addr;
@@ -155,19 +225,18 @@ interface axi4lite_intf_driver #(
@(cb); @(cb);
while(cb.ARREADY !== 1'b1) @(cb); while(cb.ARREADY !== 1'b1) @(cb);
cb.ARVALID <= '0; cb.ARVALID <= '0;
txn_ar_mutex.put();
end
begin // Push new request into queue
txn_r_mutex.get(); req = new();
@cb; read_queue.push_back(req);
while(!(cb.RREADY === 1'b1 && cb.RVALID === 1'b1)) @(cb); txn_ar_mutex.put();
assert(!$isunknown(cb.RDATA)) else $error("Read from 0x%0x returned X's on RDATA", addr);
assert(!$isunknown(cb.RRESP)) else $error("Read from 0x%0x returned X's on RRESP", addr); // Wait for response
data = cb.RDATA; req.response_mbx.get(resp);
txn_r_mutex.put();
end assert(!$isunknown(resp.rdata)) else $error("Read from 0x%0x returned X's on RDATA", addr);
join assert(!$isunknown(resp.rresp)) else $error("Read from 0x%0x returned X's on RRESP", addr);
data = resp.rdata;
endtask endtask
task automatic assert_read(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] expected_data, logic [DATA_WIDTH-1:0] mask = '1); task automatic assert_read(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] expected_data, logic [DATA_WIDTH-1:0] mask = '1);
@@ -177,6 +246,7 @@ interface axi4lite_intf_driver #(
assert(data == expected_data) else $error("Read from 0x%x returned 0x%x. Expected 0x%x", addr, data, expected_data); assert(data == expected_data) else $error("Read from 0x%x returned 0x%x. Expected 0x%x", addr, data, expected_data);
endtask endtask
//--------------------------------------------------------------------------
initial begin initial begin
reset(); reset();
end end

View File

@@ -14,7 +14,7 @@ module external_block #(
output logic [WIDTH-1:0] rd_data, output logic [WIDTH-1:0] rd_data,
output logic wr_ack output logic wr_ack
); );
timeunit 1ns; timeunit 1ps;
timeprecision 1ps; timeprecision 1ps;
localparam ADDR_SHIFT = $clog2(WIDTH/8); localparam ADDR_SHIFT = $clog2(WIDTH/8);

View File

@@ -13,7 +13,7 @@ module external_reg #(
output logic [WIDTH-1:0] rd_data, output logic [WIDTH-1:0] rd_data,
output logic wr_ack output logic wr_ack
); );
timeunit 1ns; timeunit 1ps;
timeprecision 1ps; timeprecision 1ps;
logic [SUBWORDS-1:0][WIDTH-1:0] value; logic [SUBWORDS-1:0][WIDTH-1:0] value;
@@ -69,6 +69,7 @@ initial begin
#1ns; #1ns;
if(!rst && req) begin if(!rst && req) begin
$info("got request");
if(req_is_wr) do_write(req, wr_data, wr_biten); if(req_is_wr) do_write(req, wr_data, wr_biten);
else do_read(req); else do_read(req);
end end

View File

@@ -76,6 +76,7 @@ class SimTestCase(BaseTestCase):
super().setUp() super().setUp()
# Create testbench from template # Create testbench from template
if not self.rerun:
self._generate_tb() self._generate_tb()
simulator = simulator_cls(self) simulator = simulator_cls(self)

View File

@@ -3,13 +3,13 @@ import functools
from .base import Simulator from .base import Simulator
from .questa import Questa from .questa import Questa
from .xilinx import Xilinx from .xilinx import XilinxXSIM
from .stub import StubSimulator from .stub import StubSimulator
ALL_SIMULATORS: List[Simulator] ALL_SIMULATORS: List[Simulator]
ALL_SIMULATORS = [ ALL_SIMULATORS = [
Questa, Questa,
Xilinx, XilinxXSIM,
StubSimulator, StubSimulator,
] ]

View File

@@ -13,6 +13,10 @@ class Simulator:
def __init__(self, testcase: 'SimTestCase' = None) -> None: def __init__(self, testcase: 'SimTestCase' = None) -> None:
self.testcase = testcase self.testcase = testcase
@property
def gui_mode(self) -> bool:
return self.testcase.request.config.getoption("--gui")
@property @property
def tb_files(self) -> List[str]: def tb_files(self) -> List[str]:
files = [] files = []

View File

@@ -48,14 +48,21 @@ class Questa(Simulator):
"vsim", "-quiet", "vsim", "-quiet",
"-voptargs=+acc", "-voptargs=+acc",
"-msgmode", "both", "-msgmode", "both",
"-do", "set WildcardFilter [lsearch -not -all -inline $WildcardFilter Memory]",
"-do", "log -r /*;",
"-do", "run -all; exit;",
"-c",
"-l", "%s.log" % test_name, "-l", "%s.log" % test_name,
"-wlf", "%s.wlf" % test_name, "-wlf", "%s.wlf" % test_name,
"tb", "tb",
"-do", "set WildcardFilter [lsearch -not -all -inline $WildcardFilter Memory]",
"-do", "log -r /*;",
] ]
if self.gui_mode:
cmd.append("-i")
else:
cmd.extend([
"-do", "run -all; exit;",
"-c",
])
for plusarg in plusargs: for plusarg in plusargs:
cmd.append("+" + plusarg) cmd.append("+" + plusarg)
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)

View File

@@ -5,17 +5,17 @@ import shutil
from .base import Simulator from .base import Simulator
class Xilinx(Simulator): class XilinxXSIM(Simulator):
""" """
Don't bother using the Xilinx simulator... Its buggy and extraordinarily slow. Avoid using the Xilinx simulator... Its buggy and extraordinarily slow.
As observed in v2023.2: As observed in v2023.2:
- clocking block assignments do not seem to actually simulate correctly. - Clocking block assignments to struct members do not simulate correctly.
assignment statements get ignored or the values get mangled. assignment statements get lost.
- Streaming operators have all sorts of limitations. https://support.xilinx.com/s/question/0D54U00007ZIGfXSAX/xsim-bug-xsim-does-not-simulate-struct-assignments-in-clocking-blocks-correctly?language=en_US
- Streaming bit-swap within a conditional returns a corrupted value
Keeping this here in case someday it works better... https://support.xilinx.com/s/question/0D54U00007ZIIBPSA5/xsim-bug-xsim-corrupts-value-of-signal-that-is-bitswapped-within-a-conditional-operator?language=en_US
""" """
name = "xilinx" name = "xsim"
@classmethod @classmethod
def is_installed(cls) -> bool: def is_installed(cls) -> bool:
@@ -30,7 +30,7 @@ class Xilinx(Simulator):
"xvlog", "--sv", "xvlog", "--sv",
"--log", "compile.log", "--log", "compile.log",
"--include", os.path.join(os.path.dirname(__file__), ".."), "--include", os.path.join(os.path.dirname(__file__), ".."),
"--define", "XSIM", "--define", "XILINX_XSIM",
] ]
cmd.extend(self.tb_files) cmd.extend(self.tb_files)
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
@@ -38,7 +38,7 @@ class Xilinx(Simulator):
cmd = [ cmd = [
"xelab", "xelab",
"--log", "elaborate.log", "--log", "elaborate.log",
"--timescale", "1ns/1ps", "--timescale", "1ps/1ps",
"--debug", "all", "--debug", "all",
"tb", "tb",
] ]
@@ -50,13 +50,17 @@ class Xilinx(Simulator):
test_name = self.testcase.request.node.name test_name = self.testcase.request.node.name
# call vsim # call xsim
cmd = [ cmd = ["xsim"]
"xsim", if self.gui_mode:
"--R", cmd.append("--gui")
else:
cmd.append("-R")
cmd.extend([
"--log", "%s.log" % test_name, "--log", "%s.log" % test_name,
"tb", "tb",
] ])
for plusarg in plusargs: for plusarg in plusargs:
cmd.append("--testplusarg") cmd.append("--testplusarg")

View File

@@ -1,8 +1,10 @@
{% sv_line_anchor %} {% sv_line_anchor %}
module tb; module tb;
timeunit 1ns; timeunit 10ps;
timeprecision 1ps; timeprecision 1ps;
`define bitswap(x) ($bits(x))'({<<{x}})
logic rst = '1; logic rst = '1;
logic clk = '0; logic clk = '0;
initial forever begin initial forever begin

View File

@@ -1,6 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xilinx"} incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -1,6 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xilinx"} incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -145,8 +145,8 @@
.req(hwif_out.wide_ro_reg.req), .req(hwif_out.wide_ro_reg.req),
.req_is_wr(hwif_out.wide_ro_reg.req_is_wr), .req_is_wr(hwif_out.wide_ro_reg.req_is_wr),
.wr_data(64'b0), .wr_data(32'b0),
.wr_biten(64'b0), .wr_biten(32'b0),
.rd_ack(hwif_in.wide_ro_reg.rd_ack), .rd_ack(hwif_in.wide_ro_reg.rd_ack),
.rd_data(hwif_in.wide_ro_reg.rd_data), .rd_data(hwif_in.wide_ro_reg.rd_data),
.wr_ack() .wr_ack()

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -24,8 +24,8 @@
disable fork; disable fork;
cpuif.write('h0, 'd0); cpuif.write('h0, 'd0);
force dut.field_storage.r1.f1.value[3] = 1'b1; assign dut.field_storage.r1.f1.value = 16'd1;
release dut.field_storage.r1.f1.value[3]; deassign dut.field_storage.r1.f1.value;
@cb; @cb;
@cb; @cb;
assert(cb.parity_error == 1'b1); assert(cb.parity_error == 1'b1);

View File

@@ -36,7 +36,7 @@
wait fork; wait fork;
// Mix read/writes // Mix read/writes
for(int i=0; i<64; i++) begin for(int i=0; i<8; i++) begin
fork fork
automatic int i_fk = i; automatic int i_fk = i;
begin begin

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -71,13 +71,13 @@
cpuif.assert_read('h3000, 'h4DEAB000); cpuif.assert_read('h3000, 'h4DEAB000);
// rw_reg_lsb0 // rw_reg_lsb0
`ifndef XSIM `ifndef XILINX_XSIM
// Xilinx simulator has poor support for streaming operators. Skip // Skip due to xsim bug simulating internal RTL - bitswap inside conditional corrupts data
cpuif.assert_read('h3004, 0); cpuif.assert_read('h3004, 0);
cpuif.write('h3004, 'h4DEAB000); cpuif.write('h3004, 'h4DEAB000);
@cb; @cb;
assert({<<{cb.hwif_out.rw_reg_lsb0.f1.value}} == 8'hAB); assert(`bitswap(cb.hwif_out.rw_reg_lsb0.f1.value) == 8'hAB);
assert({<<{cb.hwif_out.rw_reg_lsb0.f2.value}} == 11'h4DE); assert(`bitswap(cb.hwif_out.rw_reg_lsb0.f2.value) == 11'h4DE);
cpuif.assert_read('h3004, 'h4DEAB000); cpuif.assert_read('h3004, 'h4DEAB000);
`endif `endif
{% endblock %} {% endblock %}

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -50,10 +50,10 @@
cpuif.write('h14, 'h9ABC); cpuif.write('h14, 'h9ABC);
cpuif.write('h16, 'hDEF1); cpuif.write('h16, 'hDEF1);
@cb; @cb;
assert({<<{cb.hwif_out.rw_reg1_lsb0.f1.value}} == 8'h34); assert(`bitswap(cb.hwif_out.rw_reg1_lsb0.f1.value) == 8'h34);
assert({<<{cb.hwif_out.rw_reg1_lsb0.f2.value}} == 3'h1); assert(`bitswap(cb.hwif_out.rw_reg1_lsb0.f2.value) == 3'h1);
assert({<<{cb.hwif_out.rw_reg1_lsb0.f3.value}} == 1'h1); assert(`bitswap(cb.hwif_out.rw_reg1_lsb0.f3.value) == 1'h1);
assert({<<{cb.hwif_out.rw_reg1_lsb0.f4.value}} == 8'h9A); assert(`bitswap(cb.hwif_out.rw_reg1_lsb0.f4.value) == 8'h9A);
cpuif.assert_read('h10, 'h1034); cpuif.assert_read('h10, 'h1034);
cpuif.assert_read('h12, 'h0000); cpuif.assert_read('h12, 'h0000);
cpuif.assert_read('h14, 'h9A10); cpuif.assert_read('h14, 'h9A10);
@@ -67,8 +67,8 @@
cpuif.write('h1C, 'h9ABC); cpuif.write('h1C, 'h9ABC);
cpuif.write('h1E, 'hDEF1); cpuif.write('h1E, 'hDEF1);
@cb; @cb;
assert({<<{cb.hwif_out.rw_reg2_lsb0.f1.value}} == 4'h8); assert(`bitswap(cb.hwif_out.rw_reg2_lsb0.f1.value) == 4'h8);
assert({<<{cb.hwif_out.rw_reg2_lsb0.f2.value}} == 16'hDEF1); assert(`bitswap(cb.hwif_out.rw_reg2_lsb0.f2.value) == 16'hDEF1);
cpuif.assert_read('h18, 'h0000); cpuif.assert_read('h18, 'h0000);
cpuif.assert_read('h1A, 'h0008); cpuif.assert_read('h1A, 'h0008);
cpuif.assert_read('h1C, 'h0000); cpuif.assert_read('h1C, 'h0000);

View File

@@ -1,5 +1,6 @@
from ..lib.sim_testcase import SimTestCase from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
def test_dut(self): def test_dut(self):
self.run_test() self.run_test()

View File

@@ -69,7 +69,7 @@
assert(cb.hwif_out.reg1_msb0.f1.value == 0); assert(cb.hwif_out.reg1_msb0.f1.value == 0);
cpuif.write('hE, 'hDEF1); cpuif.write('hE, 'hDEF1);
@cb; @cb; @cb; @cb;
assert({<<{cb.hwif_out.reg1_msb0.f1.value}} == 64'hDEF19ABC56781234); assert(`bitswap(cb.hwif_out.reg1_msb0.f1.value) == 64'hDEF19ABC56781234);
cpuif.assert_read('h8, 'h1234); cpuif.assert_read('h8, 'h1234);
cpuif.assert_read('hA, 'h5678); cpuif.assert_read('hA, 'h5678);
cpuif.assert_read('hC, 'h9ABC); cpuif.assert_read('hC, 'h9ABC);
@@ -104,8 +104,8 @@
assert(cb.hwif_out.reg2_msb0.f2.value == 0); assert(cb.hwif_out.reg2_msb0.f2.value == 0);
cpuif.write('h16, 'hAA12); cpuif.write('h16, 'hAA12);
@cb; @cb; @cb; @cb;
assert({<<{cb.hwif_out.reg2_msb0.f1.value}} == 12'h234); assert(`bitswap(cb.hwif_out.reg2_msb0.f1.value) == 12'h234);
assert({<<{cb.hwif_out.reg2_msb0.f2.value}} == 4'h1); assert(`bitswap(cb.hwif_out.reg2_msb0.f2.value) == 4'h1);
cpuif.assert_read('h14, 'h3400); cpuif.assert_read('h14, 'h3400);
cpuif.assert_read('h16, 'h0012); cpuif.assert_read('h16, 'h0012);
@@ -281,7 +281,7 @@
cpuif.assert_read('hA, 'h0200); cpuif.assert_read('hA, 'h0200);
cpuif.assert_read('hC, 'h0070); cpuif.assert_read('hC, 'h0070);
cpuif.assert_read('hE, 'h0002); cpuif.assert_read('hE, 'h0002);
assert({<<{cb.hwif_out.reg1_msb0.f1.value}} == 'h0002_0070_0200_A000); assert(`bitswap(cb.hwif_out.reg1_msb0.f1.value) == 'h0002_0070_0200_A000);
// Check that strobes are cumulative // Check that strobes are cumulative
cpuif.write('h8, 'h0030, 'h00F0); cpuif.write('h8, 'h0030, 'h00F0);
@@ -297,7 +297,7 @@
cpuif.assert_read('hA, 'h0278); cpuif.assert_read('hA, 'h0278);
cpuif.assert_read('hC, 'hA07D); cpuif.assert_read('hC, 'hA07D);
cpuif.assert_read('hE, 'hAF02); cpuif.assert_read('hE, 'hAF02);
assert({<<{cb.hwif_out.reg1_msb0.f1.value}} == 'hAF02_A07D_0278_A230); assert(`bitswap(cb.hwif_out.reg1_msb0.f1.value) == 'hAF02_A07D_0278_A230);
{% endblock %} {% endblock %}

View File

@@ -2,6 +2,8 @@ from ..lib.sim_testcase import SimTestCase
from ..lib.cpuifs.passthrough import Passthrough from ..lib.cpuifs.passthrough import Passthrough
class Test(SimTestCase): class Test(SimTestCase):
incompatible_sim_tools = {"xsim"} # due to cb struct assignment bug
cpuif = Passthrough() # test with bit strobes cpuif = Passthrough() # test with bit strobes
def test_dut(self): def test_dut(self):