Skip to content

Commit

Permalink
Simulate with verilator flag (#442)
Browse files Browse the repository at this point in the history
Closes #85
  • Loading branch information
gussmith23 authored Nov 23, 2024
1 parent e3e43d2 commit 0888e0c
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 28 deletions.
56 changes: 54 additions & 2 deletions bin/main.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
(define-logger lakeroad)
(current-logger lakeroad-logger)

(require racket/runtime-path)
(define-runtime-path HERE ".")

(require rosette
(prefix-in lr: "../racket/language.rkt")
"../racket/utils.rkt"
"../racket/synthesize.rkt"
"../racket/compile-to-json.rkt"
"../racket/circt-comb-operators.rkt"
"../racket/sketches.rkt"
"../racket/architecture-description.rkt"
json
Expand Down Expand Up @@ -100,6 +102,8 @@
(define yices-path (make-parameter #f))
(define cvc4-path (make-parameter #f))
(define boolector-path (make-parameter #f))
(define simulate-with-verilator (make-parameter #f))
(define simulate-with-verilator-args (make-parameter '()))
(define yosys-log-filepath (make-parameter #f))
(define output-smt-path (make-parameter #f))

Expand Down Expand Up @@ -206,8 +210,15 @@
v
"Path to the boolector binary. If not set, Rosette will assume the binary is on your PATH."
(boolector-path v)]
#:once-any
["--simulate-with-verilator"
"If set, Lakeroad will simulate the result of synthesis to validate its correctness."
(simulate-with-verilator #t)]
#:multi
[("--simulate-with-verilator-arg")
v
"Argument to pass through to simulate_with_verilator.py. See the documentation for available flags."
" You can see the available flags by running `simulate_with_verilator.py --help`."
(simulate-with-verilator-args (append (simulate-with-verilator-args) (list v)))]
[("--solver-flag")
v
"Flag to pass to the solver. A string of the form <flag>=<value>. This flag can be specified"
Expand All @@ -216,12 +227,14 @@
(when (hash-has-key? (solver-flags) key)
(error (format "Flag ~a already specified." key)))
(hash-set! (solver-flags) key value))]
#:once-each
[("--instruction")
v
"The instruction to synthesize, written in Rosette bitvector semantics. Use (var <name> <bw>) to"
" indicate a variable. For example, an 8-bit AND is (bvand (var a 8) (var b 8))."
(instruction v)]
[("--module-name") v "Name given to the module produced." (module-name v)]
#:multi
[("--input-signal")
v
"Specify an input to the sketch, using a small domain-specific language. Generally, the inputs to"
Expand Down Expand Up @@ -563,3 +576,42 @@
(output-port))]

[_ (error "Invalid output format.")])])

(when (simulate-with-verilator)
; TODO(@gussmith23): shouldn't use "python3" directly here.
(let*-values
([(path) (build-path HERE "simulate_with_verilator.py")]
[(_) (log-debug "running simulate_with_verilator.py at ~a" path)]
[(out-verilog-filepath) (make-temporary-file "rkttmp~a.v")]
[(_) (with-output-to-file
out-verilog-filepath
(lambda ()
(when (not (system (format "yosys -q -p 'read_json ~a; write_verilog'"
(json-filepath))))
(error "Yosys failed.")))
#:exists 'must-truncate)]
[(args) (list "--verilog_filepath"
(verilog-module-filepath)
"--verilog_filepath"
out-verilog-filepath
"--test_module_name"
(module-name)
"--ground_truth_module_name"
(top-module-name)
"--output_signal"
(format "~a:~a" (verilog-module-out-signal) (verilog-module-out-bitwidth)))]
[(args) (append args
(flatten (map (lambda (port-pair)
(list "--input_signal"
(format "~a:~a" (first port-pair) (second port-pair))))
(ports))))]
[(args) (append args (simulate-with-verilator-args))]
[(sp out in err) (apply subprocess #f #f #f (find-executable-path "python3") path args)]
[(_) (subprocess-wait sp)]
[(return-code) (subprocess-status sp)])
(when (not (equal? return-code 0))
(error (format
"simulate_with_verilator.py failed with return code ~a\n\nstderr:\n~a\n\nstdout:~a"
return-code
(port->string err)
(port->string out))))))
24 changes: 21 additions & 3 deletions bin/simulate_with_verilator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
import sys
from typing import List, Optional, Tuple, Union
import subprocess
import logging

MAX_NUM_TESTS = 2**18

LOGGING_ENV_VAR = "SIMULATE_WITH_VERILOG_LOG_LEVEL"


def simulate_with_verilator(
test_module_name: str,
Expand Down Expand Up @@ -57,12 +60,16 @@ def simulate_with_verilator(
# all. But this will lead to a name collision from Verilator, and until
# there are namespaces in Verilog (how are there not???) this is what we're
# stuck with.
assert test_module_name != ground_truth_module_name, "Modules cannot have the same name."
assert (
test_module_name != ground_truth_module_name
), "Modules cannot have the same name."

if ignore_missing_test_module_file and not all(
[Path(path).exists() for path in verilog_filepaths]
):
missing = list(filter(lambda path: not Path(path).exists(), verilog_filepaths))[0]
missing = list(filter(lambda path: not Path(path).exists(), verilog_filepaths))[
0
]
logging.warning(
f"Required Verilog file {missing} does not exist. " "Skipping simulation."
)
Expand Down Expand Up @@ -183,12 +190,15 @@ def generate_one():
for one_set_of_inputs in all_inputs:
print(" ".join([str(hex(x)) for x in one_set_of_inputs]), file=f)

logging.debug(f"Running make -f {makefile_filepath} in {makefile_filepath.parent}")

# --environment-overrides is a brute-force way to allow users to use CXX=...
# to override the C++ compiler with an environment variable. Overriding
# doesn't normally work due to the issues brought up here:
# https://github.com/verilator/verilator/issues/4549
proc = subprocess.run(
["make", "--environment-overrides", "--always-make", "-f", makefile_filepath], capture_output=True
["make", "--environment-overrides", "--always-make", "-f", makefile_filepath],
capture_output=True,
)
Path(testbench_stdout_log_filepath).write_bytes(proc.stdout)
Path(testbench_stderr_log_filepath).write_bytes(proc.stderr)
Expand Down Expand Up @@ -328,6 +338,10 @@ def generate_one():
default=False,
help="Whether to expect that all outputs are always 0 on all inputs.",
)
parser.add_argument(
"--log_level",
help=f"Provide logging level. Example --loglevel debug, default=no logging. Logging can also be controlled by the {LOGGING_ENV_VAR} environment variable.",
)

args = parser.parse_args()

Expand All @@ -339,6 +353,10 @@ def generate_one():
# Parse something like <signal_name>:<bitwidth> into a tuple.
parse_signal_str = lambda x: (str(x.split(":")[0]), int(x.split(":")[1]))

if args.log_level or os.environ.get(LOGGING_ENV_VAR):
logging.basicConfig(level=args.log_level.upper() if args.log_level else os.environ.get(LOGGING_ENV_VAR))


simulate_with_verilator(
test_module_name=args.test_module_name,
ground_truth_module_name=args.ground_truth_module_name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,15 @@
// RUN: --input-signal 'a:(port a 18):18' \
// RUN: --input-signal 'b:(port b 18):18' \
// RUN: --timeout 120 \
// RUN: > $outfile
// RUN: FileCheck %s < $outfile
// RUN: if [ -z ${LAKEROAD_PRIVATE_DIR+x} ]; then \
// RUN: echo "Warning: LAKEROAD_PRIVATE_DIR is not set. Skipping simulation."; \
// RUN: exit 0; \
// RUN: else \
// RUN: python3 $LAKEROAD_DIR/bin/simulate_with_verilator.py \
// RUN: --test_module_name test_module \
// RUN: --ground_truth_module_name top \
// RUN: --output_signal p:18 \
// RUN: --max_num_tests=10000 \
// RUN: --verilog_filepath $outfile \
// RUN: --verilog_filepath %s \
// RUN: --pipeline_depth 0 \
// RUN: --input_signal a:18 \
// RUN: --input_signal b:18 \
// RUN: --verilator_include_dir "$LAKEROAD_PRIVATE_DIR/intel_cyclone10lp/" \
// RUN: --verilator_extra_arg='-Wno-LATCH' \
// RUN: --verilator_extra_arg='-Wno-INITIALDLY' \
// RUN: --verilator_extra_arg='-Wno-COMBDLY' \
// RUN: --verilator_extra_arg='-Wno-TIMESCALEMOD' \
// RUN: --verilator_extra_arg='-Wno-WIDTH'; \
// RUN: fi
// RUN: --simulate-with-verilator \
// RUN: --simulate-with-verilator-arg "--max_num_tests=10000" \
// RUN: --simulate-with-verilator-arg "--verilator_include_dir=$LAKEROAD_PRIVATE_DIR/intel_cyclone10lp/" \
// RUN: --simulate-with-verilator-arg "--verilator_extra_arg=-Wno-LATCH" \
// RUN: --simulate-with-verilator-arg "--verilator_extra_arg=-Wno-INITIALDLY" \
// RUN: --simulate-with-verilator-arg "--verilator_extra_arg=-Wno-COMBDLY" \
// RUN: --simulate-with-verilator-arg "--verilator_extra_arg=-Wno-TIMESCALEMOD" \
// RUN: --simulate-with-verilator-arg "--verilator_extra_arg=-Wno-WIDTH" \
// RUN: | FileCheck %s


module top(input [17:0] a, b, output [17:0] p);
Expand Down

0 comments on commit 0888e0c

Please sign in to comment.