Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions cocotb_test/testbench.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import argparse
import cocotb_test


class Testbench:
def __init__(self):
self.template_parameter_list = []
self.template_parameters = {}

self.simulator = None
self.toplevel = None
self.module = None
self.work_dir = None
self.python_search = None
self.toplevel_lang = "verilog"
self.verilog_sources = None
self.vhdl_sources = None
self.includes = None
self.defines = None
self.parameters = {}
self.compile_args = None
self.vhdl_compile_args = None
self.verilog_compile_args = None
self.sim_args = None
self.extra_args = None
self.plus_args = None
self.force_compile = False
self.testcase = None
self.sim_build = "sim_build"
self.seed = None
self.extra_env = None
self.compile_only = False
self.waves = None
self.timescale = None
self.gui = False
self.simulation_args = None
self.simulator_kwargs = {}

def add_template_parameter(self, name, val):
self.template_parameter_list.append(name)
self.template_parameters[name] = val

def main(self):
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument("--simulator", default=None, help="specify simulator")
parser.add_argument("--waves", default=False, action="store_true", help="enable waveform dumping")

for name, val in self.template_parameters.items():
parser.add_argument(f"--param_{name.lower()}", default=str(val), metavar=name, help=f"set module parameter {name}")

args = parser.parse_args()

if args.simulator:
self.simulator = args.simulator

if args.waves:
self.waves = True

parameters = {}

for name, val in self.template_parameters.items():
arg_val = getattr(args, f"param_{name.lower()}")
if arg_val is not None:
parameters[name] = arg_val

self.run(parameters=parameters)

def run(self, parameters=None):

sim_parameters = {}

for name in self.template_parameters:
if name in parameters:
val = parameters[name]
else:
val = self.template_parameters[name]

sim_parameters[name] = eval(str(val), {'__builtins__': None}, sim_parameters)

cocotb_test.simulator.run(
simulator=self.simulator,
toplevel=self.toplevel,
module=self.module,
work_dir=self.work_dir,
python_search=self.python_search,
toplevel_lang=self.toplevel_lang,
verilog_sources=self.verilog_sources,
vhdl_sources=self.vhdl_sources,
includes=self.includes,
defines=self.defines,
parameters=sim_parameters,
compile_args=self.compile_args,
vhdl_compile_args=self.vhdl_compile_args,
verilog_compile_args=self.verilog_compile_args,
sim_args=self.sim_args,
extra_args=self.extra_args,
plus_args=self.plus_args,
force_compile=self.force_compile,
testcase=self.testcase,
sim_build=self.sim_build,
seed=self.seed,
extra_env=self.extra_env,
compile_only=self.compile_only,
waves=self.waves,
timescale=self.timescale,
gui=self.gui,
simulation_args=self.simulation_args
)
55 changes: 54 additions & 1 deletion tests/test_parameters.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env python3
from cocotb_test.simulator import run
from cocotb_test.testbench import Testbench
import pytest
import os
import subprocess

import cocotb
from cocotb.triggers import Timer
Expand All @@ -14,12 +17,62 @@ def run_test_paramters(dut):
yield Timer(1)

WIDTH_IN = int(os.environ.get("WIDTH_IN", "8"))
WIDTH_OUT = int(os.environ.get("WIDTH_OUT", "8"))
WIDTH_OUT = int(os.environ.get("WIDTH_OUT", WIDTH_IN))

assert WIDTH_IN == len(dut.data_in)
assert WIDTH_OUT == len(dut.data_out)


tb = Testbench()

dut = "test_parameters"
tb.toplevel = dut
tb.module = os.path.splitext(os.path.basename(__file__))[0]

tb.verilog_sources = [
os.path.join(tests_dir, dut+".v"),
]

tb.add_template_parameter('WIDTH_IN', 8)
tb.add_template_parameter('WIDTH_OUT', 'WIDTH_IN')

tb.python_search = [tests_dir]
tb.includes = [os.path.join(tests_dir, "includes")]
tb.defines = ["DEFINE=1"]

tb.force_compile = True

if __name__ == '__main__':
tb.main()


@pytest.mark.skipif(os.getenv("SIM") == "ghdl", reason="Verilog not supported")
@pytest.mark.parametrize(
"parameters", [{"WIDTH_IN": "8", "WIDTH_OUT": "16"}, {"WIDTH_IN": "16"}]
)
def test_testbench_pytest(request, parameters):
tb.sim_build = os.path.join(tests_dir, "sim_build",
request.node.name.replace('[', '-').replace(']', ''))
tb.extra_env = parameters
tb.run(parameters=parameters)


@pytest.mark.skipif(os.getenv("SIM") == "ghdl", reason="Verilog not supported")
@pytest.mark.parametrize(
"parameters", [{"WIDTH_IN": "8", "WIDTH_OUT": "16"}, {"WIDTH_IN": "16"}]
)
def test_testbench_cli(request, parameters):
env = {}
for name, val in os.environ.items():
env[name] = val
args = [__file__]
for name, val in parameters.items():
args.append(f"--param_{name.lower()}={val}")
env[name] = val
c = subprocess.run(args, env=env)
assert c.returncode == 0


@pytest.mark.skipif(os.getenv("SIM") == "ghdl", reason="Verilog not suported")
@pytest.mark.parametrize(
"parameters", [{"WIDTH_IN": "8", "WIDTH_OUT": "16"}, {"WIDTH_IN": "16"}]
Expand Down
8 changes: 7 additions & 1 deletion tests/test_parameters.v
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@

module test_parameters #(
parameter WIDTH_IN = 8,
parameter WIDTH_OUT = 8
parameter WIDTH_OUT = WIDTH_IN
) (
input [WIDTH_IN-1:0] data_in,
output [WIDTH_OUT-1:0] data_out,
output [`DEFINE-1:0] define_out
);

initial begin
$display("WIDTH_IN: %d", WIDTH_IN);
$display("WIDTH_OUT: %d", WIDTH_OUT);
$display("`DEFINE: %d", `DEFINE);
end

endmodule