Skip to content

Commit f6316f6

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

File tree

3 files changed

+84
-5
lines changed

3 files changed

+84
-5
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: Path, gate_path: Path):
7+
with open(gold_path, "r") as f:
8+
gold = json.load(f)
9+
with open(gate_path, "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: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
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
6-
from pathlib import Path
78

89
from doit.cmd_base import TaskLoader2, loader
910
from doit.doit_cmd import DoitMain
@@ -12,8 +13,10 @@
1213
from amaranth import Module
1314

1415
from . import StepBase, _wire_up_ports
16+
from ._json_compare import compare_events
1517
from .. import ChipFlowError, _ensure_chipflow_root
16-
from ..platforms._utils import top_components
18+
from ..cli import run
19+
from ..platforms._utils import top_components, load_pinlock
1720
from ..platforms.sim import VARIABLES, TASKS, DOIT_CONFIG, SimPlatform
1821

1922

@@ -75,7 +78,34 @@ def __init__(self, config):
7578
self._platform = SimPlatform(config)
7679
self._config = config
7780

81+
def build_cli_parser(self, parser):
82+
action_argument = parser.add_subparsers(dest="action")
83+
action_argument.add_parser(
84+
"build", help=inspect.getdoc(self.build).splitlines()[0]) # type: ignore
85+
action_argument.add_parser(
86+
"run", help=inspect.getdoc(self.run).splitlines()[0]) # type: ignore
87+
action_argument.add_parser(
88+
"check", help=inspect.getdoc(self.check).splitlines()[0]) # type: ignore
89+
90+
def run_cli(self, args):
91+
load_pinlock() # check pinlock first so we error cleanly
92+
93+
match (args.action):
94+
case "build":
95+
self.build(args)
96+
case "run":
97+
self.run(args)
98+
case "check":
99+
self.check(args)
100+
101+
@property
102+
def sim_dir(self):
103+
return _ensure_chipflow_root() / 'build' / 'sim'
104+
78105
def build(self, *args):
106+
"""
107+
Builds the simulation model for the design
108+
"""
79109
print("Building simulation...")
80110
m = Module()
81111
self._platform.instantiate_ports(m)
@@ -94,7 +124,7 @@ def build(self, *args):
94124

95125
#FIXME: common source for build dir
96126
self._platform.build(m, top)
97-
with common() as common_dir, source() as source_dir, runtime() as runtime_dir:
127+
with common() as common_dir, runtime() as runtime_dir:
98128
context = {
99129
"COMMON_DIR": common_dir,
100130
"SOURCE_DIR": source_dir,
@@ -107,3 +137,28 @@ def build(self, *args):
107137
context[k] = v.format(**context)
108138
if DoitMain(ContextTaskLoader(DOIT_CONFIG, TASKS, context)).run(["build_sim"]) !=0:
109139
raise ChipFlowError("Failed building simulator")
140+
141+
def run(self, *args):
142+
"""
143+
Run the simulation. Will ensure that the simulation and the software are both built.
144+
"""
145+
run(["software"])
146+
self.build(args)
147+
result = subprocess.run([self.sim_dir / "sim_soc"], cwd=self.sim_dir)
148+
149+
if result.returncode != 0:
150+
raise ChipFlowError("Simulation failed")
151+
152+
def check(self, *args):
153+
"""
154+
Run the simulation and check events against reference (tests/events_reference.json). Will ensure that the simulation and the software are both built.
155+
"""
156+
if not self._config.chipflow.test:
157+
raise ChipFlowError("No [chipflow.test] section found in configuration")
158+
if not self._config.chipflow.test.event_reference:
159+
raise ChipFlowError("No event_reference configuration found in [chipflow.test]")
160+
161+
self.run(args)
162+
compare_events(self._config.chipflow.test.event_reference, self.sim_dir / "events.json")
163+
print("Integration test passed sucessfully")
164+

0 commit comments

Comments
 (0)