some useful options for vcd converter, some docs
This commit is contained in:
1 parent
c7c9655b3a
commit
45ab484641
3 files changed
+58
-21
No files matched your search
@@ -38,7 +38,11 @@ jpeg_rtl_sim: $(JPEG_CORE_VVP)
|
|||||||
# picorv32 targets
|
# picorv32 targets
|
||||||
#
|
#
|
||||||
|
|
||||||
picorv32_rtl_sim:
|
test_vcd:
|
||||||
make -C picorv32 test_vcd
|
make -C picorv32 test_vcd
|
||||||
cp picorv32/testbench.vcd picorv32.vcd
|
|
||||||
|
|
||||||
|
test_ez_vcd:
|
||||||
|
make -C picorv32 test_ez_vcd
|
||||||
|
|
||||||
|
testbench.npy:
|
||||||
|
./picorv32_vcd_import.py picorv32/testbench.vcd testbench.npy
|
||||||
@@ -18,18 +18,33 @@ If `nix` is not installed, follow this [guide](https://librelane.readthedocs.io/
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Compile jpeg decoder core using `iverilog` and run RTL simulation of the jpeg decoder core using `vvp`:
|
Compile jpeg decoder core using `iverilog` and run RTL simulation of the jpeg decoder core using `vvp`:
|
||||||
|
|
||||||
```
|
```
|
||||||
nix develop
|
nix develop
|
||||||
make
|
make
|
||||||
uv run jpeg_core_tb_run_plasma.py
|
uv run jpeg_core_tb_run_plasma.py
|
||||||
```
|
```
|
||||||
|
Call `uv run jpeg_core_tb_run_plasma.py --help` for more options.
|
||||||
|
|
||||||
Load synthesized circuits and display statistics (example code):
|
Load synthesized circuits and display statistics (example code):
|
||||||
|
|
||||||
```
|
```
|
||||||
uv run load_sky130_circuits.py
|
uv run load_sky130_circuits.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Works also outside a `nix develop` shell if [uv](https://docs.astral.sh/uv/) is installed on the base system. The script demonstrates how to obtain synthesized netlists via nix derivations [published in this github repository](https://github.com/s-holst/benchmark-circuits). These circuits along with layout and timings are built on-demand (using LibreLane) if not yet available in local nix store.
|
Run picorv32's built-in testbench (generate `picorv32/testbench.vcd`):
|
||||||
|
```
|
||||||
|
make test_vcd
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```
|
||||||
|
make test_ez_vcd
|
||||||
|
```
|
||||||
|
|
||||||
|
Import generated VCD with kyupy and convert it to a pattern file for later fault simulation:
|
||||||
|
```
|
||||||
|
uv run picorv32_vcd_import.py picorv32/testbench.vcd patterns.npy
|
||||||
|
```
|
||||||
|
Call `uv run picorv32_vcd_import.py --help` for more options.
|
||||||
|
|
||||||
|
|
||||||
|
Some `uv` commands work also outside a `nix develop` shell if [uv](https://docs.astral.sh/uv/) is installed on the base system. The script demonstrates how to obtain synthesized netlists via nix derivations [published in this github repository](https://github.com/s-holst/benchmark-circuits). These circuits along with layout and timings are built on-demand (using LibreLane) if not yet available in local nix store.
|
||||||
|
|
||||||
+34
-16
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
import argparse
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
@@ -10,6 +12,19 @@ from kyupy.techlib import SKY130
|
|||||||
from kyupy.logic_sim import LogicSim4V
|
from kyupy.logic_sim import LogicSim4V
|
||||||
|
|
||||||
|
|
||||||
|
def path_for(circuit: str):
|
||||||
|
import subprocess
|
||||||
|
return Path(subprocess.check_output(
|
||||||
|
["nix", "build", "--print-out-paths", "--no-link",
|
||||||
|
f"github:s-holst/benchmark-circuits#{circuit}" ],
|
||||||
|
text=True,
|
||||||
|
).strip())
|
||||||
|
|
||||||
|
|
||||||
|
def verilog_nl_path_for(circuit: str):
|
||||||
|
return next(path_for(circuit).glob("*/nl/*.nl.v"))
|
||||||
|
|
||||||
|
|
||||||
def check_conflicts(patterns1, patterns2, names):
|
def check_conflicts(patterns1, patterns2, names):
|
||||||
conflicts = (patterns1 != patterns2) & (patterns1 != logic.UNKNOWN) & (patterns1 != logic.UNASSIGNED) & (patterns2 != logic.UNKNOWN) & (patterns2 != logic.UNASSIGNED)
|
conflicts = (patterns1 != patterns2) & (patterns1 != logic.UNKNOWN) & (patterns1 != logic.UNASSIGNED) & (patterns2 != logic.UNKNOWN) & (patterns2 != logic.UNASSIGNED)
|
||||||
if conflicts.sum() > 0:
|
if conflicts.sum() > 0:
|
||||||
@@ -20,7 +35,7 @@ def check_conflicts(patterns1, patterns2, names):
|
|||||||
assert conflicts.sum() == 0, "incompatible patterns"
|
assert conflicts.sum() == 0, "incompatible patterns"
|
||||||
|
|
||||||
|
|
||||||
def propagate_and_check(sim: LogicSim4V, patterns: np.ndarray, node2name: dict):
|
def sim_and_check(sim: LogicSim4V, patterns: np.ndarray, node2name: dict):
|
||||||
responses = np.full_like(patterns, logic.UNASSIGNED)
|
responses = np.full_like(patterns, logic.UNASSIGNED)
|
||||||
sim.simulate(patterns, responses)
|
sim.simulate(patterns, responses)
|
||||||
#to_image(np.concatenate([patterns, responses]), 'pat_res.png')
|
#to_image(np.concatenate([patterns, responses]), 'pat_res.png')
|
||||||
@@ -61,15 +76,17 @@ def find_name(c, n):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser(description='Imports a VCD file from PicoRV32 simulation into kyupy, simulates a few cycles and save the patterns as npy file for later fault simulation.')
|
||||||
parser.add_argument('dut', type=str, help='verilog file with unit under test (uut)')
|
parser.add_argument('vcd', type=str, help='input vcd file')
|
||||||
parser.add_argument('vcd', type=str, help='vcd file to process')
|
parser.add_argument('npy', type=str, help='output pattern file in npy format')
|
||||||
|
parser.add_argument('-c', type=int, default=16, help='number of clock cycles to re-simulate for filling unknowns')
|
||||||
|
parser.add_argument('-n', type=int, default=0, help='number of patterns to convert (default 0=all)')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
c = verilog.load(args.dut, tlib=SKY130)
|
c = verilog.load(verilog_nl_path_for("picorv32-sky130"), tlib=SKY130)
|
||||||
log.info(f'circuit: {c}')
|
log.info(f'circuit: {c}')
|
||||||
c.resolve_tlib_cells(tlib=SKY130)
|
c.resolve_tlib_cells(tlib=SKY130)
|
||||||
s_locs = {} #{n.name: l for l, n in enumerate(c.s_nodes)}
|
s_locs = {}
|
||||||
name2node = {}
|
name2node = {}
|
||||||
node2name = {}
|
node2name = {}
|
||||||
|
|
||||||
@@ -97,7 +114,7 @@ def main():
|
|||||||
locs.append(-1)
|
locs.append(-1)
|
||||||
return locs
|
return locs
|
||||||
|
|
||||||
def var_locs_picorv(var: vcd.Var):
|
def var_locs(var: vcd.Var):
|
||||||
if var.scope.name in ['uut', 'picorv32_core', 'pcpi_mul', 'pcpi_div']:
|
if var.scope.name in ['uut', 'picorv32_core', 'pcpi_mul', 'pcpi_div']:
|
||||||
if var.reference.startswith('cpu_state'): # FSM got re-coded during synthesis
|
if var.reference.startswith('cpu_state'): # FSM got re-coded during synthesis
|
||||||
return []
|
return []
|
||||||
@@ -122,13 +139,14 @@ def main():
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
def step_filter(time, values, var_map):
|
def step_filter(time, values, var_map):
|
||||||
clk_val = values[clk_loc]
|
if args.n > 0 and time is not None and time >= (args.n*10000):
|
||||||
return clk_val == 0 and time < 100e6
|
return False
|
||||||
|
return values[clk_loc] == 0
|
||||||
|
|
||||||
sim = LogicSim4V(c, sims=1024)
|
sim = LogicSim4V(c, sims=10240, c_reuse=True, strip_forks=True)
|
||||||
log.info(f'sim: {sim}')
|
log.info(f'sim: {sim}')
|
||||||
|
|
||||||
v = vcd.load(args.vcd, var_locs=var_locs_picorv, step_filter=step_filter, s_len=sim.s_len)
|
v = vcd.load(args.vcd, var_locs=var_locs, step_filter=step_filter, s_len=sim.s_len)
|
||||||
log.info(f'vcd: {v}')
|
log.info(f'vcd: {v}')
|
||||||
|
|
||||||
unknown_pi = 0
|
unknown_pi = 0
|
||||||
@@ -146,12 +164,12 @@ def main():
|
|||||||
log.info(f'Total bits unassigned: {(v.data == logic.UNASSIGNED).sum()} unknown: {(v.data == logic.UNKNOWN).sum()}')
|
log.info(f'Total bits unassigned: {(v.data == logic.UNASSIGNED).sum()} unknown: {(v.data == logic.UNKNOWN).sum()}')
|
||||||
|
|
||||||
merged = v.data
|
merged = v.data
|
||||||
np.save('testbench_orig.npy', merged)
|
for i in range(args.c):
|
||||||
for i in range(30):
|
merged = sim_and_check(sim, merged, node2name)
|
||||||
merged = propagate_and_check(sim, merged, node2name)
|
log.info(f'Cycle[{i}] total bits unassigned: {(merged == logic.UNASSIGNED).sum()} unknown: {(merged == logic.UNKNOWN).sum()}')
|
||||||
log.info(f'PropCycle[{i}] total bits unassigned: {(merged == logic.UNASSIGNED).sum()} unknown: {(merged == logic.UNKNOWN).sum()}')
|
|
||||||
|
|
||||||
np.save('testbench_prop.npy', merged)
|
log.info(f'Writing {args.npy}')
|
||||||
|
np.save(args.npy, merged)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in new issue
Block a user