-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
320 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
test.vvp | ||
test_*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
.PHONY: lint test wave clean | ||
|
||
lint: | ||
verilator --lint-only pcie_msi_intr.sv | ||
iverilog -g2012 -t null tb.sv pcie_msi_intr.sv | ||
|
||
test.vvp: pcie_msi_intr.sv tb.sv | ||
iverilog -g2012 -o $@ $^ | ||
|
||
test: test.vvp | ||
python3 test.py -v | ||
|
||
wave: $(TEST)/wave.fst test.gtkw | ||
gtkwave --save test.gtkw --dump=$< | ||
sed -i '/^\[dumpfile/d' test.gtkw | ||
sed -i '/^\[savefile/d' test.gtkw | ||
sed -i '/^\[\*]/d' test.gtkw | ||
|
||
clean: | ||
\rm -f test.vvp | ||
\rm -fr test_*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
module tb; | ||
|
||
logic [4:0] app_msi_num; | ||
logic app_msi_req; | ||
logic app_msi_ack; | ||
logic clk; | ||
logic reset; | ||
logic [7:0] irq; | ||
|
||
initial begin | ||
$from_myhdl(clk, reset, irq, app_msi_ack); | ||
$to_myhdl(app_msi_num, app_msi_req); | ||
end | ||
|
||
pcie_msi_intr dut( | ||
.app_int_sts(), | ||
.app_msi_num(app_msi_num), | ||
.app_msi_req(app_msi_req), | ||
.app_msi_tc(), | ||
.app_int_ack(1'b0), | ||
.app_msi_ack(app_msi_ack), | ||
.clk(clk), | ||
.reset(reset), | ||
.irq(irq)); | ||
|
||
initial begin | ||
$dumpfile("wave.fst"); | ||
$dumpvars(0, tb); | ||
end | ||
endmodule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
[timestart] 0 | ||
[size] 2201 1199 | ||
[pos] -1 -1 | ||
*-13.840914 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 | ||
[treeopen] tb. | ||
[sst_width] 213 | ||
[signals_width] 219 | ||
[sst_expanded] 1 | ||
[sst_vpaned_height] 362 | ||
@28 | ||
tb.dut.clk | ||
tb.dut.reset | ||
@22 | ||
tb.dut.irq[7:0] | ||
@200 | ||
- | ||
@22 | ||
tb.dut.irq_pending[31:0] | ||
tb.dut.irq_clear[31:0] | ||
@200 | ||
- | ||
@28 | ||
tb.dut.app_msi_req | ||
tb.dut.app_msi_ack | ||
@23 | ||
tb.dut.app_msi_num[4:0] | ||
@200 | ||
- | ||
@28 | ||
tb.dut.app_msi_tc[2:0] | ||
tb.dut.app_int_ack | ||
tb.dut.app_int_sts | ||
[pattern_trace] 1 | ||
[pattern_trace] 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
#/usr/bin/env/python3 | ||
"""Testbench for PCIe MSI generation.""" | ||
|
||
import logging as log | ||
import os | ||
import unittest | ||
|
||
import myhdl | ||
|
||
def testcase(*blocks): | ||
"""Runs a decorated function as a block in MyHDL. | ||
Arguments: | ||
*blocks: Any argument given is a function to create other blocks | ||
""" | ||
def inner(func): | ||
def block(self): | ||
def run_and_stop(): | ||
yield from func(self) | ||
raise myhdl.StopSimulation | ||
insts = [x(self, func) for x in blocks] + [run_and_stop()] | ||
sim = myhdl.Simulation(insts) | ||
sim.run(quiet=1) | ||
return block | ||
return inner | ||
|
||
class Test(unittest.TestCase): | ||
"""Collection of PCIe MSI test cases""" | ||
|
||
# pylint: disable=too-many-instance-attributes | ||
def setUp(self): | ||
# To HDL | ||
self.clk = myhdl.Signal(bool(0)) | ||
self.rst = myhdl.Signal(bool(0)) | ||
self.irq = myhdl.Signal(myhdl.intbv()[8:]) | ||
self.msi_ack = myhdl.Signal(bool(0)) | ||
# From HDL | ||
self.msi_num = myhdl.Signal(myhdl.intbv()[5:]) | ||
self.msi_req = myhdl.Signal(bool(0)) | ||
|
||
# === MyHDL instances === | ||
# MyHDL instances that can be enable to co-execute alongside the test case | ||
# These are processes that may or may not be included depending on if that | ||
# signal is required for a particular test case. | ||
# dutgen and clkgen is probably always required. | ||
|
||
def clkgen(self, unused_test): | ||
@myhdl.always(myhdl.delay(2)) | ||
def block(): | ||
# pylint: disable=multiple-statements | ||
self.clk.next = not self.clk | ||
return block | ||
|
||
def dutgen(self, test): | ||
"""Cosimulation of actual Verilog code""" | ||
# This is because icarus does not allow changing the dumpfile in | ||
# a nice way | ||
oldpath = os.getcwd() | ||
newpath = os.path.join(oldpath, test.__name__) | ||
os.makedirs(newpath, exist_ok=True) | ||
os.chdir(newpath) | ||
ret = myhdl.Cosimulation( | ||
"vvp -m myhdl ../test.vvp -fst", | ||
# To HDL | ||
clk=self.clk, | ||
reset=self.rst, | ||
irq=self.irq, | ||
app_msi_ack=self.msi_ack, | ||
# From HDL | ||
app_msi_num=self.msi_num, | ||
app_msi_req=self.msi_req) | ||
os.chdir(oldpath) | ||
return ret | ||
|
||
# === End of MyHDL instances === | ||
def reset(self): | ||
yield myhdl.delay(10) | ||
self.rst.next = 1 | ||
yield myhdl.delay(10) | ||
self.rst.next = 0 | ||
yield myhdl.delay(10) | ||
|
||
@testcase(clkgen, dutgen) | ||
def test_single_irq(self): | ||
"""Test sending an interrupt.""" | ||
yield from self.reset() | ||
yield myhdl.delay(10) | ||
self.irq.next |= 1 << 5 | ||
yield self.msi_req.posedge, myhdl.delay(1000) | ||
if not self.msi_req: | ||
raise Exception("Timeout waiting for app_msi_req") | ||
self.irq.next = 0 | ||
yield self.clk.posedge | ||
self.assertEqual(self.msi_num, 0x5) | ||
self.msi_ack.next = 1 | ||
yield self.clk.posedge | ||
self.msi_ack.next = 0 | ||
yield self.clk.negedge | ||
if self.msi_req: | ||
raise Exception("Expected cleared app_msi_req 1 cycle after ack") | ||
# Expect no more events | ||
yield self.msi_req.posedge, myhdl.delay(100) | ||
if self.msi_req: | ||
raise Exception("Got unexpected secondary MSI") | ||
yield myhdl.delay(10) | ||
|
||
@testcase(clkgen, dutgen) | ||
def test_continuous_irq(self): | ||
"""Test sending a continuous interrupt.""" | ||
yield from self.reset() | ||
yield myhdl.delay(10) | ||
self.irq.next |= 1 << 5 | ||
yield self.msi_req.posedge, myhdl.delay(1000) | ||
if not self.msi_req: | ||
raise Exception("Timeout waiting for app_msi_req") | ||
yield self.clk.posedge | ||
self.assertEqual(self.msi_num, 0x5) | ||
self.msi_ack.next = 1 | ||
yield self.clk.posedge | ||
self.msi_ack.next = 0 | ||
yield self.clk.negedge | ||
if self.msi_req: | ||
raise Exception("Expected cleared app_msi_req 1 cycle after ack") | ||
# Expect no more events | ||
yield self.msi_req.posedge, myhdl.delay(100) | ||
if self.msi_req: | ||
raise Exception("Got unexpected secondary MSI") | ||
yield myhdl.delay(10) | ||
|
||
@testcase(clkgen, dutgen) | ||
def test_multiple_irq(self): | ||
"""Test sending multiple interrupts.""" | ||
yield from self.reset() | ||
yield myhdl.delay(10) | ||
self.irq.next |= 1 << 0 | 1 << 2 | 1 << 3 | ||
yield self.msi_req.posedge, myhdl.delay(1000) | ||
if not self.msi_req: | ||
raise Exception("Timeout waiting for app_msi_req") | ||
self.irq.next = 0 | ||
for ei in [0, 2, 3]: | ||
yield self.clk.posedge | ||
self.assertEqual(self.msi_num, ei) | ||
self.msi_ack.next = 1 | ||
yield self.clk.posedge | ||
self.msi_ack.next = 0 | ||
yield self.clk.negedge | ||
if self.msi_req: | ||
raise Exception("Expected cleared app_msi_req 1 cycle after ack") | ||
yield myhdl.delay(10) | ||
|
||
if __name__ == '__main__': | ||
os.chdir(os.path.dirname(os.path.abspath(__file__))) | ||
log.basicConfig( | ||
level=log.DEBUG, | ||
format='[%(asctime)-15s] %(funcName)-15s %(levelname)-8s %(message)s') | ||
unittest.main() |