mirror of https://github.com/llvm/circt.git
[lit] RTL simulation script with Verilator and Questa support (#334)
* [Tests] [Questa] If found, provide feature and path * Abstraction script and moving existing test * Default sim * Passing default simulator through env var * Adding default driver.sv * Various bug fixes * Argparse wasn't working properly * Don't touch files in test/ * Creating a default for commercial simulation * Making circt-rtl-sim a tool not a util script * Removing old comment * Adding 'rtl-sim' feature and renaming 'comsim' to 'ieee-sim'
This commit is contained in:
parent
4377c178ca
commit
c9ccc4de01
|
@ -128,6 +128,27 @@ else()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# If Questa hasn't been explicitly disabled, find it.
|
||||||
|
option(QUESTA_DISABLE "Disable the Questa simulation tests.")
|
||||||
|
if (QUESTA_DISABLE)
|
||||||
|
message(STATUS "Disabling Questa tests.")
|
||||||
|
else()
|
||||||
|
if (EXISTS ${QUESTA_PATH})
|
||||||
|
message(STATUS "Setting Questa path to ${QUESTA_PATH}.")
|
||||||
|
else()
|
||||||
|
# Search for Questa's `vsim` command.
|
||||||
|
find_program(QUESTA_PATH "vsim")
|
||||||
|
if(EXISTS ${QUESTA_PATH})
|
||||||
|
# Then strip the filename.
|
||||||
|
get_filename_component(QUESTA_PATH ${QUESTA_PATH} DIRECTORY)
|
||||||
|
message(STATUS "Found Questa at ${QUESTA_PATH}.")
|
||||||
|
else()
|
||||||
|
set(QUESTA_PATH "")
|
||||||
|
message(STATUS "Did not find Questa.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# If Yosys hasn't been explicitly disabled, find it.
|
# If Yosys hasn't been explicitly disabled, find it.
|
||||||
option(YOSYS_DISABLE "Disable the yosys tests.")
|
option(YOSYS_DISABLE "Disable the yosys tests.")
|
||||||
if (YOSYS_DISABLE)
|
if (YOSYS_DISABLE)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
set(CIRCT_INTEGRATION_TEST_DEPENDS
|
set(CIRCT_INTEGRATION_TEST_DEPENDS
|
||||||
FileCheck count not
|
FileCheck count not
|
||||||
circt-opt
|
circt-opt
|
||||||
circt-translate)
|
circt-translate
|
||||||
|
circt-rtl-sim
|
||||||
|
firtool)
|
||||||
|
|
||||||
# If ESI Cosim is available to build then enable its tests.
|
# If ESI Cosim is available to build then enable its tests.
|
||||||
if (TARGET EsiCosimDpiServer)
|
if (TARGET EsiCosimDpiServer)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import Cosim_DpiPkg::*;
|
import Cosim_DpiPkg::*;
|
||||||
|
|
||||||
module main(
|
module top(
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
input logic clk,
|
input logic clk,
|
||||||
input logic rstn
|
input logic rstn
|
||||||
|
|
|
@ -45,7 +45,7 @@ class CosimTestRunner:
|
||||||
self.runs = list()
|
self.runs = list()
|
||||||
self.sources = list()
|
self.sources = list()
|
||||||
self.cppSources = list()
|
self.cppSources = list()
|
||||||
self.top = "main"
|
self.top = "top"
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
"""Parse a test file. Look for comments we recognize anywhere in the
|
"""Parse a test file. Look for comments we recognize anywhere in the
|
||||||
|
@ -77,20 +77,19 @@ class CosimTestRunner:
|
||||||
|
|
||||||
# Assemble a list of sources (RTL and C++), applying the defaults and
|
# Assemble a list of sources (RTL and C++), applying the defaults and
|
||||||
# path rules.
|
# path rules.
|
||||||
|
cfg = self.test.config
|
||||||
if len(self.sources) == 0:
|
if len(self.sources) == 0:
|
||||||
sources = [self.file]
|
sources = [self.file]
|
||||||
else:
|
else:
|
||||||
sources = [(src if os.path.isabs(src) else os.path.join(
|
sources = [(src if os.path.isabs(src) else os.path.join(
|
||||||
self.srcdir, src)) for src in self.sources]
|
self.srcdir, src)) for src in self.sources]
|
||||||
if len(self.cppSources) == 0:
|
if len(self.cppSources) == 0:
|
||||||
cppSources = [os.path.join(
|
cppSources = [os.path.join(cfg.circt_tools_dir, "driver.cpp")]
|
||||||
os.path.dirname(__file__), "..", "driver.cpp")]
|
|
||||||
else:
|
else:
|
||||||
cppSources = [(src if os.path.isabs(src) else os.path.join(
|
cppSources = [(src if os.path.isabs(src) else os.path.join(
|
||||||
self.srcdir, src)) for src in self.cppSources]
|
self.srcdir, src)) for src in self.cppSources]
|
||||||
|
|
||||||
# Include the cosim DPI SystemVerilog files.
|
# Include the cosim DPI SystemVerilog files.
|
||||||
cfg = self.test.config
|
|
||||||
cosimInclude = os.path.join(
|
cosimInclude = os.path.join(
|
||||||
cfg.circt_include_dir, "circt", "Dialect", "ESI", "cosim")
|
cfg.circt_include_dir, "circt", "Dialect", "ESI", "cosim")
|
||||||
sources.insert(0, os.path.join(cosimInclude, "Cosim_DpiPkg.sv"))
|
sources.insert(0, os.path.join(cosimInclude, "Cosim_DpiPkg.sv"))
|
||||||
|
@ -167,7 +166,7 @@ class CosimTestRunner:
|
||||||
simEnv = os.environ.copy()
|
simEnv = os.environ.copy()
|
||||||
simEnv["COSIM_PORT"] = str(port)
|
simEnv["COSIM_PORT"] = str(port)
|
||||||
simProc = subprocess.Popen(
|
simProc = subprocess.Popen(
|
||||||
[f"{self.execdir}/obj_dir/V{self.top}", "--cycles", "-1"],
|
[f"{self.execdir}/obj_dir/V{self.top}"],
|
||||||
stdout=simStdout, stderr=simStderr, cwd=self.execdir,
|
stdout=simStdout, stderr=simStderr, cwd=self.execdir,
|
||||||
env=simEnv)
|
env=simEnv)
|
||||||
# Wait a set amount of time for the simulation to start accepting
|
# Wait a set amount of time for the simulation to start accepting
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// REQUIRES: verilator
|
// REQUIRES: verilator
|
||||||
// RUN: circt-translate %s -emit-verilog -verify-diagnostics > %t1.sv
|
// RUN: circt-translate %s -emit-verilog -verify-diagnostics > %t1.sv
|
||||||
// RUN: verilator --cc --top-module main -sv %t1.sv --build --exe %S/../driver.cpp
|
// RUN: circt-rtl-sim.py %t1.sv --cycles 8 2>&1 | FileCheck %s
|
||||||
// RUN: ./obj_dir/Vmain --cycles 8 2>&1 | FileCheck %s
|
|
||||||
|
|
||||||
module {
|
module {
|
||||||
// The RTL dialect doesn't have any sequential constructs yet. So don't do
|
// The RTL dialect doesn't have any sequential constructs yet. So don't do
|
||||||
// much.
|
// much.
|
||||||
rtl.module @main(%clk: i1, %rstn: i1) {
|
rtl.module @top(%clk: i1, %rstn: i1) {
|
||||||
%c1 = rtl.instance "aaa" @AAA () : () -> (i1)
|
%c1 = rtl.instance "aaa" @AAA () : () -> (i1)
|
||||||
%c1Shl = rtl.instance "shl" @shl (%c1) : (i1) -> (i1)
|
%c1Shl = rtl.instance "shl" @shl (%c1) : (i1) -> (i1)
|
||||||
sv.alwaysat_posedge %clk {
|
sv.alwaysat_posedge %clk {
|
||||||
|
@ -34,4 +33,8 @@ module {
|
||||||
// CHECK-NEXT: tick
|
// CHECK-NEXT: tick
|
||||||
// CHECK-NEXT: tick
|
// CHECK-NEXT: tick
|
||||||
// CHECK-NEXT: tick
|
// CHECK-NEXT: tick
|
||||||
// CHECK-NEXT: [driver] Ending simulation at tick #17
|
// CHECK-NEXT: tick
|
||||||
|
// CHECK-NEXT: tick
|
||||||
|
// CHECK-NEXT: tick
|
||||||
|
// CHECK-NEXT: tick
|
||||||
|
// CHECK-NEXT: [driver] Ending simulation at tick #25
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// REQUIRES: verilator
|
// REQUIRES: verilator
|
||||||
// RUN: circt-translate %s -emit-verilog -verify-diagnostics > %t1.sv && verilator --lint-only --top-module AB %t1.sv
|
// RUN: circt-translate %s -emit-verilog -verify-diagnostics > %t1.sv
|
||||||
|
// RUN: verilator --lint-only --top-module AB %t1.sv
|
||||||
|
|
||||||
module {
|
module {
|
||||||
rtl.module @B(%a: i1 { rtl.inout }) -> (i1 {rtl.name = "b"}, i1 {rtl.name = "c"}) {
|
rtl.module @B(%a: i1 { rtl.inout }) -> (i1 {rtl.name = "b"}, i1 {rtl.name = "c"}) {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
// REQUIRES: ieee-sim
|
||||||
|
// RUN: circt-rtl-sim.py --sim %ieee-sim --cycles 2 %s
|
||||||
|
|
||||||
|
module top(
|
||||||
|
input clk,
|
||||||
|
input rstn
|
||||||
|
);
|
||||||
|
|
||||||
|
always@(posedge clk)
|
||||||
|
if (rstn)
|
||||||
|
$display("tock");
|
||||||
|
// CHECK: tock
|
||||||
|
// CHECK-NEXT: tock
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,15 @@
|
||||||
|
// REQUIRES: verilator
|
||||||
|
// RUN: circt-rtl-sim.py --cycles 2 %s | FileCheck %s
|
||||||
|
|
||||||
|
module top(
|
||||||
|
input clk,
|
||||||
|
input rstn
|
||||||
|
);
|
||||||
|
|
||||||
|
always@(posedge clk)
|
||||||
|
if (rstn)
|
||||||
|
$display("tock");
|
||||||
|
// CHECK: tock
|
||||||
|
// CHECK-NEXT: tock
|
||||||
|
|
||||||
|
endmodule
|
|
@ -64,7 +64,8 @@ tool_dirs = [config.circt_tools_dir,
|
||||||
tools = [
|
tools = [
|
||||||
'circt-opt',
|
'circt-opt',
|
||||||
'circt-translate',
|
'circt-translate',
|
||||||
'firtool'
|
'firtool',
|
||||||
|
'circt-rtl-sim.py'
|
||||||
]
|
]
|
||||||
|
|
||||||
# Enable yosys if it has been detected.
|
# Enable yosys if it has been detected.
|
||||||
|
@ -78,6 +79,24 @@ if config.verilator_path != "":
|
||||||
tool_dirs.append(os.path.dirname(config.verilator_path))
|
tool_dirs.append(os.path.dirname(config.verilator_path))
|
||||||
tools.append('verilator')
|
tools.append('verilator')
|
||||||
config.available_features.add('verilator')
|
config.available_features.add('verilator')
|
||||||
|
config.available_features.add('rtl-sim')
|
||||||
|
llvm_config.with_environment(
|
||||||
|
'VERILATOR_PATH', config.verilator_path)
|
||||||
|
|
||||||
|
# Enable Questa if it has been detected.
|
||||||
|
if config.questa_path != "":
|
||||||
|
config.available_features.add('questa')
|
||||||
|
config.available_features.add('ieee-sim')
|
||||||
|
config.available_features.add('rtl-sim')
|
||||||
|
llvm_config.with_environment(
|
||||||
|
'LM_LICENSE_FILE', os.environ['LM_LICENSE_FILE'])
|
||||||
|
|
||||||
|
# When we add support for other simulators, we'll have to figure out which
|
||||||
|
# one should be the default and modify this appropriately.
|
||||||
|
config.substitutions.append(
|
||||||
|
('%questa', os.path.join(config.questa_path, "vsim")))
|
||||||
|
config.substitutions.append(
|
||||||
|
('%ieee-sim', os.path.join(config.questa_path, "vsim")))
|
||||||
|
|
||||||
# Enable ESI cosim tests if they have been built.
|
# Enable ESI cosim tests if they have been built.
|
||||||
if config.esi_cosim_path != "":
|
if config.esi_cosim_path != "":
|
||||||
|
|
|
@ -40,6 +40,7 @@ config.verilator_path = "@VERILATOR_PATH@"
|
||||||
config.esi_cosim_path = "@ESI_COSIM_PATH@"
|
config.esi_cosim_path = "@ESI_COSIM_PATH@"
|
||||||
config.timeout = "@CIRCT_INTEGRATION_TIMEOUT@"
|
config.timeout = "@CIRCT_INTEGRATION_TIMEOUT@"
|
||||||
config.yosys_path = "@YOSYS_PATH@"
|
config.yosys_path = "@YOSYS_PATH@"
|
||||||
|
config.questa_path = "@QUESTA_PATH@"
|
||||||
|
|
||||||
# Support substitution of the tools_dir with user parameters. This is
|
# Support substitution of the tools_dir with user parameters. This is
|
||||||
# used when we can't determine the tool dir at configuration time.
|
# used when we can't determine the tool dir at configuration time.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
add_subdirectory(circt-opt)
|
add_subdirectory(circt-opt)
|
||||||
|
add_subdirectory(circt-rtl-sim)
|
||||||
add_subdirectory(circt-translate)
|
add_subdirectory(circt-translate)
|
||||||
add_subdirectory(handshake-runner)
|
add_subdirectory(handshake-runner)
|
||||||
add_subdirectory(firtool)
|
add_subdirectory(firtool)
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# ===- CMakeLists.txt - Simulation driver cmake ---------------*- cmake -*-===//
|
||||||
|
#
|
||||||
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
# ===-----------------------------------------------------------------------===//
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ===-----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
set(SOURCES circt-rtl-sim.py driver.cpp driver.sv)
|
||||||
|
foreach(file IN ITEMS ${SOURCES})
|
||||||
|
configure_file(${file} ${CIRCT_TOOLS_DIR}/${file})
|
||||||
|
endforeach()
|
||||||
|
add_custom_target(circt-rtl-sim SOURCES ${SOURCES})
|
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# ===- circt-rtl-sim.py - CIRCT simulation driver -------------*- python -*-===//
|
||||||
|
#
|
||||||
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
# ===-----------------------------------------------------------------------===//
|
||||||
|
#
|
||||||
|
# Script to drive CIRCT simulation tests.
|
||||||
|
#
|
||||||
|
# ===-----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
ThisFileDir = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
class Questa:
|
||||||
|
"""Run and compile funcs for Questasim."""
|
||||||
|
|
||||||
|
DefaultDriver = "driver.sv"
|
||||||
|
|
||||||
|
def __init__(self, path, args):
|
||||||
|
if os.path.exists(path) and os.path.isfile(path):
|
||||||
|
self.path = os.path.dirname(path)
|
||||||
|
else:
|
||||||
|
self.path = path
|
||||||
|
self.args = args
|
||||||
|
|
||||||
|
def compile(self, sources):
|
||||||
|
vlog = os.path.join(self.path, "vlog")
|
||||||
|
return subprocess.run([vlog, "-sv"] + sources)
|
||||||
|
|
||||||
|
def run(self, cycles, simargs):
|
||||||
|
if self.args.no_default_driver:
|
||||||
|
top = self.args.top
|
||||||
|
else:
|
||||||
|
top = "driver"
|
||||||
|
|
||||||
|
vsim = os.path.join(self.path, "vsim")
|
||||||
|
# Note: vsim exit codes say nothing about the test run's pass/fail even if
|
||||||
|
# $fatal is encountered in the simulation.
|
||||||
|
cmd = [vsim, top, "-batch", "-do", "run -all"]
|
||||||
|
if cycles >= 0:
|
||||||
|
cmd.append(f"+cycles={cycles}")
|
||||||
|
return subprocess.run(cmd + simargs.split())
|
||||||
|
|
||||||
|
|
||||||
|
class Verilator:
|
||||||
|
"""Run and compile funcs for Verilator."""
|
||||||
|
|
||||||
|
DefaultDriver = "driver.cpp"
|
||||||
|
|
||||||
|
def __init__(self, args):
|
||||||
|
if "VERILATOR_PATH" in os.environ:
|
||||||
|
self.verilator = os.environ["VERILATOR_PATH"]
|
||||||
|
else:
|
||||||
|
self.verilator = args.sim
|
||||||
|
self.top = args.top
|
||||||
|
|
||||||
|
def compile(self, sources):
|
||||||
|
return subprocess.run([self.verilator, "--cc", "--top-module", self.top,
|
||||||
|
"-sv", "--build", "--exe"] + sources)
|
||||||
|
|
||||||
|
def run(self, cycles, args):
|
||||||
|
exe = os.path.join("obj_dir", "V" + self.top)
|
||||||
|
cmd = [exe]
|
||||||
|
if cycles >= 0:
|
||||||
|
cmd.append(f"--cycles")
|
||||||
|
cmd.append(str(cycles))
|
||||||
|
cmd += args.split()
|
||||||
|
print(f"Running: {cmd}")
|
||||||
|
sys.stdout.flush()
|
||||||
|
return subprocess.run(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def __main__(args):
|
||||||
|
defaultSim = ""
|
||||||
|
if "DEFAULT_SIM" in os.environ:
|
||||||
|
defaultSim = os.environ["DEFAULT_SIM"]
|
||||||
|
|
||||||
|
argparser = argparse.ArgumentParser(
|
||||||
|
description="RTL simulation runner for CIRCT")
|
||||||
|
|
||||||
|
argparser.add_argument("--sim", type=str, default="verilator",
|
||||||
|
help="Name of the RTL simulator (if in PATH) to use" +
|
||||||
|
" or path to an executable.")
|
||||||
|
argparser.add_argument("--no-compile", dest="no_compile", action='store_true',
|
||||||
|
help="Don't compile the simulation.")
|
||||||
|
argparser.add_argument("--no-run", dest="no_run", action='store_true',
|
||||||
|
help="Don't run the simulation.")
|
||||||
|
argparser.add_argument("--top", type=str, default="top",
|
||||||
|
help="Name of top module to run.")
|
||||||
|
argparser.add_argument("--simargs", type=str, default="",
|
||||||
|
help="Simulation arguments string.")
|
||||||
|
argparser.add_argument("--no-default-driver", dest="no_default_driver", action='store_true',
|
||||||
|
help="Do not use the standard top module/drivers.")
|
||||||
|
argparser.add_argument("--cycles", type=int, default=-1,
|
||||||
|
help="Number of cycles to run the simulator. " +
|
||||||
|
" -1 means don't stop.")
|
||||||
|
|
||||||
|
argparser.add_argument("sources", nargs="+",
|
||||||
|
help="The list of source files to be included.")
|
||||||
|
|
||||||
|
if len(args) <= 1:
|
||||||
|
argparser.print_help()
|
||||||
|
return
|
||||||
|
args = argparser.parse_args(args[1:])
|
||||||
|
|
||||||
|
# Break up simulator string
|
||||||
|
simParts = os.path.split(args.sim)
|
||||||
|
simName = simParts[1]
|
||||||
|
|
||||||
|
if simName in ["questa", "vsim", "vlog", "vopt"]:
|
||||||
|
sim = Questa(simParts[0], args)
|
||||||
|
|
||||||
|
elif simName == "verilator":
|
||||||
|
sim = Verilator(args)
|
||||||
|
else:
|
||||||
|
print(f"Could not determine simulator from '{args.sim}'",
|
||||||
|
file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if not args.no_default_driver:
|
||||||
|
args.sources.append(os.path.join(ThisFileDir, sim.DefaultDriver))
|
||||||
|
|
||||||
|
if not args.no_compile:
|
||||||
|
rc = sim.compile(args.sources)
|
||||||
|
if rc.returncode != 0:
|
||||||
|
return rc
|
||||||
|
if not args.no_run:
|
||||||
|
rc = sim.run(args.cycles, args.simargs)
|
||||||
|
return rc.returncode
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(__main__(sys.argv))
|
|
@ -5,7 +5,7 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "Vmain.h"
|
#include "Vtop.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include "verilated_vcd_c.h"
|
#include "verilated_vcd_c.h"
|
||||||
|
@ -30,11 +30,13 @@ int main(int argc, char **argv) {
|
||||||
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
||||||
|
|
||||||
size_t numCyclesToRun = 0;
|
size_t numCyclesToRun = 0;
|
||||||
|
bool runForever = true;
|
||||||
// Search the command line args for those we are sensitive to.
|
// Search the command line args for those we are sensitive to.
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
if (std::string(argv[i]) == "--cycles") {
|
if (std::string(argv[i]) == "--cycles") {
|
||||||
if (i + 1 < argc) {
|
if (i + 1 < argc) {
|
||||||
numCyclesToRun = std::strtoull(argv[++i], nullptr, 10);
|
numCyclesToRun = std::strtoull(argv[++i], nullptr, 10);
|
||||||
|
runForever = false;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "--cycles must be followed by number of cycles."
|
std::cerr << "--cycles must be followed by number of cycles."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
@ -44,7 +46,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the simulated module's C++ model.
|
// Construct the simulated module's C++ model.
|
||||||
auto &dut = *new Vmain();
|
auto &dut = *new Vtop();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerilatedVcdC *tfp = new VerilatedVcdC;
|
VerilatedVcdC *tfp = new VerilatedVcdC;
|
||||||
Verilated::traceEverOn(true);
|
Verilated::traceEverOn(true);
|
||||||
|
@ -59,7 +61,7 @@ int main(int argc, char **argv) {
|
||||||
dut.clk = 0;
|
dut.clk = 0;
|
||||||
|
|
||||||
// Run for a few cycles with reset held.
|
// Run for a few cycles with reset held.
|
||||||
for (timeStamp = 0; timeStamp < 10 && !Verilated::gotFinish(); timeStamp++) {
|
for (timeStamp = 0; timeStamp < 8 && !Verilated::gotFinish(); timeStamp++) {
|
||||||
dut.eval();
|
dut.eval();
|
||||||
dut.clk = !dut.clk;
|
dut.clk = !dut.clk;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -71,7 +73,8 @@ int main(int argc, char **argv) {
|
||||||
dut.rstn = 1;
|
dut.rstn = 1;
|
||||||
|
|
||||||
// Run for the specified number of cycles out of reset.
|
// Run for the specified number of cycles out of reset.
|
||||||
for (; timeStamp <= (numCyclesToRun * 2) && !Verilated::gotFinish() &&
|
vluint64_t endTime = timeStamp + (numCyclesToRun * 2);
|
||||||
|
for (; (runForever || timeStamp <= endTime) && !Verilated::gotFinish() &&
|
||||||
!stopSimulation;
|
!stopSimulation;
|
||||||
timeStamp++) {
|
timeStamp++) {
|
||||||
dut.eval();
|
dut.eval();
|
|
@ -0,0 +1,57 @@
|
||||||
|
//===- driver.sv - Standard SystemVerilog testbench driver ----------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Contains the top module driver for our standard simulation tests. It makes
|
||||||
|
// the following assumptions/demands:
|
||||||
|
//
|
||||||
|
// - The testbench module is called 'top'.
|
||||||
|
// - It exposes a pin named 'clk' (for the clock).
|
||||||
|
// - It exposes a pin named 'rstn' (for the reset signal).
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
module driver();
|
||||||
|
|
||||||
|
logic clk = 0;
|
||||||
|
logic rstn = 0;
|
||||||
|
|
||||||
|
top top (
|
||||||
|
.clk(clk),
|
||||||
|
.rstn(rstn)
|
||||||
|
);
|
||||||
|
|
||||||
|
always begin
|
||||||
|
// A clock period is #4.
|
||||||
|
clk = ~clk;
|
||||||
|
#2;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
int cycles;
|
||||||
|
|
||||||
|
$display("[driver] Starting simulation");
|
||||||
|
|
||||||
|
rstn = 0;
|
||||||
|
// Hold in reset for 4 cycles.
|
||||||
|
@(posedge clk);
|
||||||
|
@(posedge clk);
|
||||||
|
@(posedge clk);
|
||||||
|
@(posedge clk);
|
||||||
|
rstn = 1;
|
||||||
|
|
||||||
|
if ($value$plusargs ("cycles=%d", cycles)) begin
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < cycles; i++) begin
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
$display("[driver] Ending simulation at tick #%0d", $time);
|
||||||
|
$finish();
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
Loading…
Reference in New Issue