Skip to content

Commit

Permalink
Merge pull request svunit#280 from svunit/add-support-for-xilinx-viva…
Browse files Browse the repository at this point in the history
…do-simulator

Add support for Xilinx Vivado Simulator
  • Loading branch information
tudortimi authored Nov 3, 2023
2 parents b1413e7 + 8fd2b41 commit 5b78513
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 14 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,9 @@ qrun.out/

# Verilator
obj_dir/

# Vivado Simulator
xsim.dir/
xvlog.pb
xelab.pb
xsim*.jou
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Add support for Xilinx Vivado (TM) Simulator

### Fixed
- Fix warning in VCS when using `SVUNIT_CLK_GEN


## [3.37.0] - 2023-09-18

### Added
Expand Down
32 changes: 28 additions & 4 deletions bin/runSVUnit
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ clean();

# Extract simulator from PATH if nothing passed as argument
if ($simulator eq "") {
my @sims = qw(xrun irun qrun vsim vcs dsim verilator);
my @sims = qw(xrun irun qrun vsim vcs dsim verilator xsim);
foreach my $sim (@sims) {
if (system("which $sim > /dev/null 2>&1") == 0) {
$simulator = $sim;
Expand All @@ -152,7 +152,7 @@ $simulator =~ s/questa/modelsim/;
$simulator =~ s/ius/irun/;
$simulator =~ s/xcelium/xrun/;

if (not grep { $_ eq $simulator } qw(xrun irun modelsim riviera vcs dsim qrun verilator)) {
if (not grep { $_ eq $simulator } qw(xrun irun modelsim riviera vcs dsim qrun verilator xsim)) {
print("Could not determine simulator. None found on 'PATH' and none specified via command line\n");
usage()
}
Expand All @@ -170,6 +170,9 @@ if ($simulator eq "modelsim" or $simulator eq "riviera") {
} elsif ($simulator eq "verilator") {
$cmd .= "verilator --binary --top-module testrunner";
$cmd .= qq! @compileargs!;
} elsif ($simulator eq "xsim") {
$cmd .= "xvhdl -f $vhdlfile && " if $vhdlfile;
$cmd .= "xvlog --sv --log $vlogfile ";
} else {
$cmd .= "$simulator -l $logfile ";
$cmd .= "-f $vhdlfile " if $vhdlfile;
Expand All @@ -180,6 +183,7 @@ if (defined $uvm) {
$cmd .= " -uvm" if ($simulator eq "xrun" or $simulator eq "irun");
$cmd .= " -ntb_opts uvm" if $simulator eq "vcs";
$cmd .= ' +incdir+$UVM_HOME/src $UVM_HOME/src/uvm.sv -sv_lib $UVM_HOME/src/dpi/libuvm_dpi.so' if $simulator eq "dsim";
$cmd .= " --lib uvm" if $simulator eq "xsim";
push @defines, "RUN_SVUNIT_WITH_UVM";
}

Expand All @@ -191,7 +195,14 @@ foreach (@filelists) {
$cmd .= " -f .svunit.f";

# defines
$cmd .= " +define+" . join " +define+", @defines if (@defines > 0);
if ($simulator ne "xsim") {
$cmd .= " +define+" . join " +define+", @defines if (@defines > 0);
}
else {
if (@defines > 0) {
$cmd .= ' ' . join(' ', map { "--define $_" } @defines);
}
}

if ($simulator eq "modelsim" or $simulator eq "riviera") {
if (!grep(/(^| )(-gui|-c|-i)( |$)/, @simargs)) {
Expand All @@ -205,12 +216,19 @@ if ($simulator eq "modelsim" or $simulator eq "riviera") {
$verilator_simargs .= " +SVUNIT_FILTER=$filter";
}
$cmd .= qq! && obj_dir/Vtestrunner $verilator_simargs 2>&1 | tee $logfile !;
} elsif ($simulator eq "xsim") {
$cmd .= qq! @compileargs && xelab testrunner && xsim @simargs --R --log $logfile testrunner!;
} else {
$cmd .= " @compileargs @simargs -top testrunner";
}

if (defined $filter && $simulator ne "verilator") {
$cmd .= " +SVUNIT_FILTER=$filter";
if ($simulator eq "xsim") {
$cmd .= " --testplusarg SVUNIT_FILTER=$filter";
}
else {
$cmd .= " +SVUNIT_FILTER=$filter";
}
}

my $build_cmd = "buildSVUnit -o $outdir";
Expand Down Expand Up @@ -238,6 +256,12 @@ if (defined $uvm) {
if (system("$build_cmd")) {
exit -1;
}
if ($simulator eq "xsim") {
if (system("sed -i 's/\+incdir+/--include /g' $outdir/.svunit.f")) {
exit -1;
}
}

print $cmd . "\n";
if (system("$cmd")) {
exit INTERNAL_EXECUTION_ERROR;
Expand Down
5 changes: 5 additions & 0 deletions svunit_base/junit-xml/XmlElement.svh
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ class XmlElement;

local function string get_start_tag_contents();
string result = tag;
`ifdef XILINX_SIMULATOR
// XXX WORKAROUND Vivado somehow manages to overwrite `tag` if we assign it to `result`.
// It probably does some dumb referencing, instead of allocating a new string variable.
result = { tag };
`endif
foreach (attributes[i])
result = { result, " ", $sformatf("%s=\"%s\"", i, attributes[i])};
return result;
Expand Down
8 changes: 4 additions & 4 deletions svunit_base/svunit_filter_for_single_pattern.svh
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,27 @@ class filter_for_single_pattern;
for (int i = 0; i < pattern.len(); i++)
if (pattern[i] == ".")
return i;
$fatal(0, error_msg);
`__svunit_fatal(error_msg);
endfunction


local function void ensure_no_more_dots(string pattern, int unsigned first_dot_idx);
for (int i = first_dot_idx+1; i < pattern.len(); i++)
if (pattern[i] == ".")
$fatal(0, error_msg);
`__svunit_fatal(error_msg);
endfunction


local function void disallow_partial_wildcards(string field_name, string field_value);
if (field_value != "*")
if (str_contains_char(field_value, "*"))
$fatal(0, $sformatf("Partial wildcards in %s names aren't currently supported", field_name));
`__svunit_fatal($sformatf("Partial wildcards in %s names aren't currently supported", field_name));
endfunction


local static function bit str_contains_char(string s, string c);
if (c.len() != 1)
$fatal(0, "Expected a single character");
`__svunit_fatal("Expected a single character");
foreach (s[i])
if (s[i] == c[0])
return 1;
Expand Down
7 changes: 7 additions & 0 deletions svunit_base/svunit_internal_defines.svh
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@


`define __svunit_stringify(s) `"s`"

`define __svunit_fatal(s) \
`ifndef XILINX_SIMULATOR \
$fatal(0, s); \
`else \
$fatal(s); \
`endif
11 changes: 11 additions & 0 deletions svunit_base/uvm-mock/svunit_uvm_test.sv
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class svunit_uvm_test extends uvm_test;
static local bit m_finish_e;

static local bit m_in_pre_reset;
`ifdef XILINX_SIMULATOR
local static event pre_reset_phase_started;
`endif

static local bit m_in_main;

function new(string name = "", uvm_component parent = null);
Expand All @@ -66,7 +70,11 @@ class svunit_uvm_test extends uvm_test;
endfunction

static task wait_for_ready();
`ifndef XILINX_SIMULATOR
@(posedge m_in_pre_reset);
`else
@(pre_reset_phase_started);
`endif
endtask

static function bit is_running();
Expand All @@ -80,6 +88,9 @@ class svunit_uvm_test extends uvm_test;
task pre_reset_phase(uvm_phase phase);
phase.raise_objection(null);
m_in_pre_reset = 1;
`ifdef XILINX_SIMULATOR
-> pre_reset_phase_started;
`endif
if (!m_start_e) @m_start;
m_start_e = 0;
phase.drop_objection(null);
Expand Down
9 changes: 6 additions & 3 deletions test/test_frmwrk.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
# Need a possibility to remove tools from PATH, otherwise we can't test
def get_path_without_sims():
paths = os.environ['PATH'].split(os.path.pathsep)
for sim_name in ['xrun', 'dsim', 'vsim', "qrun", "verilator"]:
for sim_name in ['xrun', 'dsim', 'vsim', "qrun", "verilator", 'xsim']:
sim = shutil.which(sim_name)
if sim:
paths = list(filter(lambda p: p != os.path.dirname(sim), paths))
paths = list(filter(lambda p: pathlib.Path(p) != pathlib.Path(sim).parent, paths))
return os.path.pathsep.join(paths)


Expand Down Expand Up @@ -425,13 +425,16 @@ def test_frmwrk_32(tmpdir):
assert return_code == 255


@pytest.mark.parametrize("sim", ["xrun", "irun", "vsim", "vcs", "qrun", "verilator"])
@pytest.mark.parametrize("sim", ["xrun", "irun", "vsim", "vcs", "qrun", "verilator", "xsim"])
def test_called_without_simulator__extract_sim_if_on_path(sim, tmpdir, monkeypatch):
with tmpdir.as_cwd():
fake_tool(sim)
if (sim == 'vsim'):
fake_tool('vlib')
fake_tool('vlog')
if sim == 'xsim':
fake_tool('xvlog')
fake_tool('xelab')
monkeypatch.setenv('PATH', get_path_without_sims())
monkeypatch.setenv('PATH', '.', prepend=os.pathsep)

Expand Down
12 changes: 10 additions & 2 deletions test/test_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ def test_sim_4(datafiles, simulator):
@all_available_simulators()
def test_sim_5(datafiles, simulator):
with datafiles.as_cwd():
subprocess.check_call(['runSVUnit', '-s', simulator, '-r', '+JOKES +DUD=4', '--r_arg', '+BOZO'])
if simulator != 'xsim':
subprocess.check_call(['runSVUnit', '-s', simulator, '-r', '+JOKES +DUD=4', '--r_arg', '+BOZO'])
else:
subprocess.check_call(['runSVUnit', '-s', simulator, '-r', '--testplusarg JOKES --testplusarg DUD=4', '--r_arg', '--testplusarg BOZO'])

expect_testrunner_pass('run.log')

Expand All @@ -103,7 +106,10 @@ def test_sim_5(datafiles, simulator):
@all_available_simulators()
def test_sim_6(datafiles, simulator):
with datafiles.as_cwd():
subprocess.check_call(['runSVUnit', '-s', simulator, '-c', '+define+JOKES +define+DUD=4', '--c_arg', '+define+BOZO'])
if simulator != 'xsim':
subprocess.check_call(['runSVUnit', '-s', simulator, '-c', '+define+JOKES +define+DUD=4', '--c_arg', '+define+BOZO'])
else:
subprocess.check_call(['runSVUnit', '-s', simulator, '-c', '--define JOKES --define DUD=4', '--c_arg', '--define BOZO'])

expect_testrunner_pass('run.log')

Expand Down Expand Up @@ -186,6 +192,8 @@ def test_sim_12(datafiles, simulator):
@all_files_in_dir('sim_13')
@all_available_simulators()
def test_sim_13(datafiles, simulator):
if simulator == 'xsim':
pytest.skip(f"'Timeout set in `svunit.f` by `+define+` incompatible with `xvlog`")
with datafiles.as_cwd():
subprocess.check_call(['runSVUnit', '-s', simulator])

Expand Down
2 changes: 2 additions & 0 deletions test/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ def test_util_clk_reset(datafiles, simulator):
# TODO Fix code to work in Verilator
if simulator == 'verilator':
pytest.skip("Verilator issues a lot of lint warnings for this code")
if simulator == 'xsim':
pytest.skip(f"'Include directory added in `svunit.f` by `+incdir+` incompatible with `xvlog`")
with datafiles.as_cwd():
subprocess.check_call(['runSVUnit', '-s', simulator])
expect_testrunner_pass('run.log')
2 changes: 2 additions & 0 deletions test/test_wavedrom.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ def test_wavedrom_0(datafiles):
def test_wavedrom_1(datafiles, simulator):
if simulator == 'verilator':
pytest.skip(f"'Generated code has mismatching lengths and other lint warnings")
if simulator == 'xsim':
pytest.skip(f"'Wavedrom code isn't handled by `buildSVUnit`, but by `svunit.f` incompatible with `xvlog`")
with datafiles.as_cwd():
subprocess.check_call(['runSVUnit', '-s', simulator, '-w'])
expect_testrunner_pass('run.log')
4 changes: 3 additions & 1 deletion test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ def all_available_simulators():
simulators.append('qrun')
if shutil.which('verilator'):
simulators.append('verilator')
if shutil.which('xsim'):
simulators.append('xsim')

if not simulators:
warnings.warn('None of irun, modelsim, vcs, dsim, qrun or verilator are in your path. You need at least 1 simulator to regress svunit-code!')
warnings.warn('None of irun, modelsim, vcs, dsim, qrun, verilator or xsim are in your path. You need at least 1 simulator to regress svunit-code!')

return pytest.mark.parametrize("simulator", simulators)

Expand Down

0 comments on commit 5b78513

Please sign in to comment.