Simulator compatibility updates
This commit is contained in:
@@ -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"],
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -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 = []
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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 %}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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 %}
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user