Skip to content

Commit 28f27df

Browse files
committed
Implements initial Questa simulation tool plugin.
1 parent 6601d54 commit 28f27df

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

hammer/sim/questa/__init__.py

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# hammer-vlsi plugin for Questa
2+
3+
from hammer.vlsi import HammerSimTool, DummyHammerTool, HammerToolStep, deepdict
4+
from hammer.config import HammerJSONEncoder
5+
6+
import hammer.tech as hammer_tech
7+
from hammer.tech import HammerTechnologyUtils
8+
9+
from typing import Dict, List, Any, Optional
10+
from decimal import Decimal
11+
12+
import os
13+
import json
14+
15+
class Questa(HammerSimTool, DummyHammerTool):
16+
17+
# Simulation steps
18+
@property
19+
def steps(self) -> List[HammerToolStep]:
20+
return self.make_steps_from_methods([
21+
self.qhsim
22+
])
23+
24+
# Main simulation method
25+
def qhsim(self) -> bool:
26+
# Get Hammer settings
27+
tb_name = self.get_setting("sim.inputs.tb_name") # testbench main module
28+
tb_dut = self.get_setting("sim.inputs.tb_dut") # DUT instance name in testbench
29+
defines = self.get_setting("sim.inputs.defines") # macro definitions
30+
timescale = self.get_setting("sim.inputs.timescale") # timescale setup
31+
input_files_list = self.get_setting("sim.inputs.input_files") # input HDL files
32+
top_module = self.get_setting("sim.inputs.top_module") # DUT module name
33+
timing_annotated = self.get_setting("sim.inputs.timing_annotated") # using SDF
34+
wave_file = self.get_setting("sim.inputs.wave_file") # waveform format setup file
35+
vlog_args = self.get_setting("sim.inputs.vlog_args") # custom vlog arguments
36+
vopt_args = self.get_setting("sim.inputs.vopt_args") # custom vopt arguments
37+
vsim_args = self.get_setting("sim.inputs.vsim_args") # custom vsim arguments
38+
no_gui = self.get_setting("sim.inputs.no_gui") # do not open GUI
39+
questa_bin = self.get_setting("sim.questa.questa_bin") # Questa binary file
40+
# Create a Questa command file
41+
do_file = f"{self.run_dir}/{tb_name}.do"
42+
f = open(do_file, "w+")
43+
# Create the working library
44+
lib_name = f"work_{tb_name}"
45+
lib_dir = f"{self.run_dir}/{lib_name}"
46+
f.write("# Create the working library\n")
47+
f.write(f"rm -rf {lib_dir}\n")
48+
f.write(f"vlib {lib_dir}\n")
49+
f.write(f"vmap {lib_name} {lib_dir}\n") # potentially redundant
50+
# Compile the design units
51+
defines_list = [f"+define+{x}" for x in defines]
52+
defines_string = " ".join(defines_list)
53+
for i in range(len(input_files_list)): # converting relative paths to absolute
54+
if (input_files_list[i][0] != '/'):
55+
input_files_list[i] = os.getcwd() + '/' + input_files_list[i]
56+
input_files_string = " ".join(input_files_list)
57+
if self.level.is_gatelevel(): # add Verilog models of standard cells
58+
verilog_models_list = self.get_verilog_models()
59+
verilog_models_string = " ".join(verilog_models_list)
60+
input_files_string += ' ' + verilog_models_string
61+
f.write("# Compile the design units\n")
62+
f.write(f"vlog -work {lib_name} {defines_string} -timescale {timescale} \
63+
{input_files_string} {vlog_args}\n")
64+
# Optimize the design
65+
sdf_args = "-nosdf +notimingchecks"
66+
if timing_annotated:
67+
sdf_corner = self.get_setting("sim.inputs.sdf_corner")
68+
# Convert relative paths to absolute (if needed)
69+
if self.sdf_file: # if SDF file is specified in input .yml
70+
self.sdf_file = self.sdf_file if self.sdf_file[0] == '/' else os.getcwd() + '/' + self.sdf_file
71+
# Generate SDF-related arguments
72+
sdf_args = f" +sdf_verbose -sdf{sdf_corner} /{tb_name}/{tb_dut}={self.sdf_file}"
73+
f.write("# Optimize the design\n")
74+
f.write(f"vopt -debugdb -work {lib_name} -timescale {timescale} \
75+
{sdf_args} +acc {tb_name} -o opt_{tb_name} {vopt_args}\n")
76+
# Load the design
77+
f.write("# Load the design\n")
78+
f.write(f"vsim -debugDB -work {lib_name} opt_{tb_name} {vsim_args}\n")
79+
# Add waves
80+
f.write("# Add waves\n")
81+
if wave_file: # if waveform setup file is specified in input .yml
82+
wave_file = wave_file if wave_file[0] == '/' else "../../" + wave_file
83+
f.write(f"do {wave_file}\n")
84+
else:
85+
f.write(f"add wave -group TB -internal {tb_name}/*\n") # a group of all TB signals
86+
f.write(f"add wave -ports {tb_dut}/*\n") # DUT ports displayed individually
87+
f.write(f"add wave -group INT -r -internal {tb_dut}/*\n") # a group of internal DUT signal
88+
# Log simulation data
89+
f.write("# Log simulation data\n")
90+
f.write("log -r *\n") # potentially redundant
91+
# Run simulation (if enabled)
92+
if self.get_setting("sim.inputs.execute_sim"):
93+
f.write("# Run simulation\n")
94+
f.write("run -all\n")
95+
else:
96+
self.logger.warning("Not running any simulations because sim.inputs.execute_sim is unset.")
97+
# Close the Questa command file
98+
f.close()
99+
# Run Questa simulation
100+
args = [questa_bin]
101+
if no_gui:
102+
args.append("-c") # do not open GUI
103+
args.append("-do")
104+
args.append(f"{do_file}")
105+
self.run_executable(args, cwd=self.run_dir)
106+
return True
107+
108+
# Fill output json file
109+
def fill_outputs(self) -> bool:
110+
self.output_waveforms = []
111+
self.output_saifs = []
112+
self.output_top_module = self.top_module
113+
self.output_tb_name = self.get_setting("sim.inputs.tb_name")
114+
self.output_tb_dut = self.get_setting("sim.inputs.tb_dut")
115+
self.output_level = self.get_setting("sim.inputs.level")
116+
return True
117+
118+
# Get verilog models of standard cells
119+
def get_verilog_models(self) -> List[str]:
120+
verilog_sim_files = self.technology.read_libs([hammer_tech.filters.verilog_sim_filter],
121+
hammer_tech.HammerTechnologyUtils.to_plain_item)
122+
return verilog_sim_files
123+
124+
def tool_config_prefix(self) -> str:
125+
return "sim.questa"
126+
127+
tool = Questa

hammer/sim/questa/defaults.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
sim.questa:
2+
# Tool version
3+
version: "24.1std"
4+
# Installation path
5+
questa_home: "${mentor.mentor_home}/intelFPGA/${sim.questa.version}"
6+
questa_home_meta: lazysubst
7+
# Executable
8+
questa_bin: "qhsim"
9+
questa_bin_meta: lazysubst
10+
11+
# Default sim.inputs options
12+
sim.inputs:
13+
sdf_corner: max
14+
wave_file: null
15+
no_gui: null
16+
vlog_args: ""
17+
vopt_args: ""
18+
vsim_args: ""

0 commit comments

Comments
 (0)