Skip to content

Commit c4cdcfd

Browse files
committed
Add build, run and check subcommands to sim command
1 parent d748ec0 commit c4cdcfd

File tree

3 files changed

+83
-3
lines changed

3 files changed

+83
-3
lines changed

chipflow_lib/config_models.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# SPDX-License-Identifier: BSD-2-Clause
22
from enum import Enum
3+
from pathlib import Path
34
from typing import Dict, Optional, Any, List, Annotated
45

56
from pydantic import (
@@ -62,6 +63,9 @@ class CompilerConfig(BaseModel):
6263
class SoftwareConfig(BaseModel):
6364
riscv: CompilerConfig = CompilerConfig(cpu="baseline_rv32-a-c-d", abi="ilp32")
6465

66+
class TestConfig(BaseModel):
67+
event_reference: Path
68+
6569
class ChipFlowConfig(BaseModel):
6670
"""Root configuration for chipflow.toml."""
6771
project_name: str
@@ -71,7 +75,7 @@ class ChipFlowConfig(BaseModel):
7175
simulation: SimulationConfig = SimulationConfig()
7276
software: SoftwareConfig = SoftwareConfig()
7377
clock_domains: Optional[List[str]] = None
74-
78+
test: Optional[TestConfig] = None
7579

7680
class Config(BaseModel):
7781
"""Root configuration model for chipflow.toml."""
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import json
2+
from pathlib import Path
3+
4+
from .. import ChipFlowError
5+
6+
def compare_events(gold: Path, gate: Path):
7+
with open(gold, "r") as f:
8+
gold = json.load(f)
9+
with open(gate, "r") as f:
10+
gate = json.load(f)
11+
if len(gold["events"]) != len(gate["events"]):
12+
raise ChipFlowError(f"Simulator check failed! Event mismatch: {len(gold['events'])} events in reference, {len(gate['events'])} in test output")
13+
for ev_gold, ev_gate in zip(gold["events"], gate["events"]):
14+
if ev_gold["peripheral"] != ev_gate["peripheral"] or \
15+
ev_gold["event"] != ev_gate["event"] or \
16+
ev_gold["payload"] != ev_gate["payload"]:
17+
raise ChipFlowError(f"Simulator check failed! Reference event {ev_gold} mismatches test event {ev_gate}")
18+
19+
return True
20+

chipflow_lib/steps/sim.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import os
1+
import inspect
22
import importlib.resources
33
import logging
4+
import os
5+
import subprocess
46

57
from contextlib import contextmanager
68
from pathlib import Path
@@ -12,8 +14,10 @@
1214
from amaranth import Module
1315

1416
from . import StepBase, _wire_up_ports
17+
from ._json_compare import compare_events
1518
from .. import ChipFlowError, _ensure_chipflow_root
16-
from ..platforms._utils import top_components
19+
from ..cli import run
20+
from ..platforms._utils import top_components, load_pinlock
1721
from ..platforms.sim import VARIABLES, TASKS, DOIT_CONFIG, SimPlatform
1822

1923

@@ -75,7 +79,34 @@ def __init__(self, config):
7579
self._platform = SimPlatform(config)
7680
self._config = config
7781

82+
def build_cli_parser(self, parser):
83+
action_argument = parser.add_subparsers(dest="action")
84+
action_argument.add_parser(
85+
"build", help=inspect.getdoc(self.build).splitlines()[0]) # type: ignore
86+
action_argument.add_parser(
87+
"run", help=inspect.getdoc(self.run).splitlines()[0]) # type: ignore
88+
action_argument.add_parser(
89+
"check", help=inspect.getdoc(self.check).splitlines()[0]) # type: ignore
90+
91+
def run_cli(self, args):
92+
load_pinlock() # check pinlock first so we error cleanly
93+
94+
match (args.action):
95+
case "build":
96+
self.build(args)
97+
case "run":
98+
self.run(args)
99+
case "check":
100+
self.check(args)
101+
102+
@property
103+
def sim_dir(self):
104+
return _ensure_chipflow_root() / 'build' / 'sim'
105+
78106
def build(self, *args):
107+
"""
108+
Builds the simulation model for the design
109+
"""
79110
print("Building simulation...")
80111
m = Module()
81112
self._platform.instantiate_ports(m)
@@ -107,3 +138,28 @@ def build(self, *args):
107138
context[k] = v.format(**context)
108139
if DoitMain(ContextTaskLoader(DOIT_CONFIG, TASKS, context)).run(["build_sim"]) !=0:
109140
raise ChipFlowError("Failed building simulator")
141+
142+
def run(self, *args):
143+
"""
144+
Run the simulation. Will ensure that the simulation and the software are both built.
145+
"""
146+
run(["software"])
147+
self.build(args)
148+
result = subprocess.run([self.sim_dir / "sim_soc"], cwd=self.sim_dir)
149+
150+
if result.returncode != 0:
151+
raise ChipFlowError("Simulation failed")
152+
153+
def check(self, *args):
154+
"""
155+
Run the simulation and check events against reference (tests/events_reference.json). Will ensure that the simulation and the software are both built.
156+
"""
157+
if not self._config.chipflow.test:
158+
raise ChipFlowError("No [chipflow.test] section found in configuration")
159+
if not self._config.chipflow.test.event_reference:
160+
raise ChipFlowError("No event_reference configuration found in [chipflow.test]")
161+
162+
self.run(args)
163+
compare_events(self._config.chipflow.test.event_reference, self.sim_dir / "events.json")
164+
print("Integration test passed sucessfully")
165+

0 commit comments

Comments
 (0)