Skip to content

Commit 5b1dbe9

Browse files
Merge pull request #3 from chipfoundry/cocotb_openframe_support
updates to support openframe verification
2 parents 0111c9f + 7f589d6 commit 5b1dbe9

2 files changed

Lines changed: 68 additions & 17 deletions

File tree

chipfoundry_cli/main.py

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,6 +1915,19 @@ def setup(project_root, repo_owner, repo_name, branch, pdk, caravel_lite,
19151915
# Check if project is initialized (allow dry-run to proceed)
19161916
check_project_initialized(project_root_path, 'setup', dry_run=dry_run)
19171917

1918+
# Read project type from project.json
1919+
project_json_path = project_root_path / '.cf' / 'project.json'
1920+
project_type = 'digital' # default
1921+
if project_json_path.exists():
1922+
try:
1923+
with open(project_json_path, 'r') as f:
1924+
project_data = json.load(f)
1925+
project_type = project_data.get('project', {}).get('type', 'digital')
1926+
except (json.JSONDecodeError, IOError):
1927+
pass # Use default if we can't read it
1928+
1929+
is_openframe = project_type == 'openframe'
1930+
19181931
had_errors = False
19191932

19201933
def _error_text(err):
@@ -1943,7 +1956,8 @@ def maybe_abort_no_space(err, step_label):
19431956
# If in "only" mode, only install what's specified
19441957
# If not in "only" mode, install everything
19451958
install_caravel = only_caravel or not only_mode
1946-
install_mcw = only_mcw or not only_mode
1959+
# MCW is not used for openframe projects
1960+
install_mcw = (only_mcw or not only_mode) and not is_openframe
19471961
install_openlane = only_openlane or not only_mode
19481962
install_pdk = only_pdk or not only_mode
19491963
install_timing = only_timing or not only_mode
@@ -1956,9 +1970,13 @@ def maybe_abort_no_space(err, step_label):
19561970
f"Project directory: [yellow]{project_root}[/yellow]",
19571971
f"Repository: [yellow]{repo_owner}/{repo_name}@{branch}[/yellow]",
19581972
f"PDK: [yellow]{pdk}[/yellow]",
1973+
f"Project type: [yellow]{project_type}[/yellow]",
19591974
f"Caravel variant: [yellow]{'caravel-lite' if caravel_lite else 'caravel'}[/yellow]",
19601975
]
19611976

1977+
if is_openframe:
1978+
config_lines.append("[dim]MCW not needed for openframe projects[/dim]")
1979+
19621980
if only_mode:
19631981
installing = []
19641982
if only_caravel: installing.append("caravel")
@@ -2057,7 +2075,11 @@ def maybe_abort_no_space(err, step_label):
20572075
console.print(f"[dim]{e.stderr}[/dim]")
20582076

20592077
# Step 3: Install Management Core Wrapper
2060-
if install_mcw:
2078+
# Show message if user explicitly requested MCW but project is openframe
2079+
if only_mcw and is_openframe:
2080+
console.print("\n[bold]Step 3:[/bold] Installing Management Core Wrapper...")
2081+
console.print("[yellow]⚠[/yellow] MCW is not used for openframe projects, skipping...")
2082+
elif install_mcw:
20612083
console.print("\n[bold]Step 3:[/bold] Installing Management Core Wrapper...")
20622084
mcw_dir = project_root_path / 'mgmt_core_wrapper'
20632085

@@ -3084,7 +3106,7 @@ def precheck(project_root, disable_lvs, checks, dry_run):
30843106
@click.option('--sim', type=click.Choice(['rtl', 'gl'], case_sensitive=False), default='rtl', help='Simulation type: rtl or gl (gate-level)')
30853107
@click.option('--list', 'list_tests', is_flag=True, help='List all available cocotb tests')
30863108
@click.option('--all', 'run_all', is_flag=True, help='Run all tests')
3087-
@click.option('--tag', help='Test list tag/yaml file (e.g., user_proj_tests)')
3109+
@click.option('--tag', help='Test list tag/yaml file (e.g., all_tests or user_proj_tests)')
30883110
@click.option('--dry-run', is_flag=True, help='Show the configuration without running')
30893111
def verify(test, project_root, sim, list_tests, run_all, tag, dry_run):
30903112
"""Run cocotb verification tests.
@@ -3094,7 +3116,7 @@ def verify(test, project_root, sim, list_tests, run_all, tag, dry_run):
30943116
cf verify counter_la # Run a specific test (RTL)
30953117
cf verify counter_la --sim gl # Run gate-level simulation
30963118
cf verify --all # Run all tests
3097-
cf verify --tag user_proj_tests # Run tests from a yaml list
3119+
cf verify --tag all_tests # Run tests from a yaml list
30983120
"""
30993121
# If .cf/project.json exists in cwd, use it as default project_root
31003122
cwd_root, _ = get_project_json_from_cwd()
@@ -3114,13 +3136,13 @@ def verify(test, project_root, sim, list_tests, run_all, tag, dry_run):
31143136

31153137
project_json_path = project_root_path / '.cf' / 'project.json'
31163138

3139+
# Get project type (needed for openframe flag)
3140+
with open(project_json_path, 'r') as f:
3141+
project_data = json.load(f)
3142+
project_type = project_data.get('project', {}).get('type', 'digital')
3143+
31173144
# Check if GPIO configuration exists (skip check if just listing tests or openframe)
31183145
if not list_tests:
3119-
# Check project type - GPIO config not needed for openframe
3120-
with open(project_json_path, 'r') as f:
3121-
project_data = json.load(f)
3122-
project_type = project_data.get('project', {}).get('type', 'digital')
3123-
31243146
if project_type != 'openframe':
31253147
gpio_config = get_gpio_config_from_project_json(str(project_json_path))
31263148
if not gpio_config or len(gpio_config) == 0:
@@ -3221,13 +3243,19 @@ def verify(test, project_root, sim, list_tests, run_all, tag, dry_run):
32213243

32223244
if dry_run:
32233245
console.print("[bold yellow]Dry run - configuration ready[/bold yellow]\n")
3246+
openframe_flag = " --openframe" if project_type == 'openframe' else ""
32243247
if test:
3225-
console.print(f"Would run: {caravel_cocotb_bin} -t {test} -sim {sim_arg}")
3248+
console.print(f"Would run: {caravel_cocotb_bin} -t {test} -sim {sim_arg}{openframe_flag}")
32263249
elif run_all:
3227-
yaml_file = 'user_proj_tests_gl.yaml' if sim.lower() == 'gl' else 'user_proj_tests.yaml'
3228-
console.print(f"Would run: {caravel_cocotb_bin} -tl user_proj_tests/{yaml_file} -sim {sim_arg}")
3250+
all_tests_yaml = cocotb_dir / ('all_tests_gl.yaml' if sim.lower() == 'gl' else 'all_tests.yaml')
3251+
if all_tests_yaml.exists():
3252+
yaml_path = all_tests_yaml.name
3253+
else:
3254+
yaml_file = 'user_proj_tests_gl.yaml' if sim.lower() == 'gl' else 'user_proj_tests.yaml'
3255+
yaml_path = f'user_proj_tests/{yaml_file}'
3256+
console.print(f"Would run: {caravel_cocotb_bin} -tl {yaml_path} -sim {sim_arg}{openframe_flag}")
32293257
elif tag:
3230-
console.print(f"Would run: {caravel_cocotb_bin} -tl {tag} -sim {sim_arg}")
3258+
console.print(f"Would run: {caravel_cocotb_bin} -tl {tag} -sim {sim_arg}{openframe_flag}")
32313259
return
32323260

32333261
# Prepare environment
@@ -3244,9 +3272,14 @@ def verify(test, project_root, sim, list_tests, run_all, tag, dry_run):
32443272
if test:
32453273
cmd.extend(['-t', test])
32463274
elif run_all:
3247-
# Use the appropriate test list yaml
3248-
yaml_file = 'user_proj_tests_gl.yaml' if sim.lower() == 'gl' else 'user_proj_tests.yaml'
3249-
yaml_path = f'user_proj_tests/{yaml_file}'
3275+
# Look for test list yaml - prefer all_tests.yaml, fall back to user_proj_tests/
3276+
all_tests_yaml = cocotb_dir / ('all_tests_gl.yaml' if sim.lower() == 'gl' else 'all_tests.yaml')
3277+
if all_tests_yaml.exists():
3278+
yaml_path = all_tests_yaml.name
3279+
else:
3280+
# Fall back to legacy user_proj_tests directory
3281+
yaml_file = 'user_proj_tests_gl.yaml' if sim.lower() == 'gl' else 'user_proj_tests.yaml'
3282+
yaml_path = f'user_proj_tests/{yaml_file}'
32503283
cmd.extend(['-tl', yaml_path])
32513284
elif tag:
32523285
# User specified a custom test list
@@ -3270,6 +3303,13 @@ def verify(test, project_root, sim, list_tests, run_all, tag, dry_run):
32703303
if sim.lower() == 'gl':
32713304
cmd.extend(['-sim', 'GL'])
32723305

3306+
# Add openframe flag for openframe projects
3307+
if project_type == 'openframe':
3308+
cmd.append('--openframe')
3309+
3310+
# Add CI flag to disable Docker interactive mode (required when not running in a terminal)
3311+
cmd.append('--CI')
3312+
32733313
# Run cocotb tests
32743314
console.print(f"[cyan]Running cocotb verification...[/cyan]")
32753315

tests/test_verify_command.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Unit tests for cf verify command.
33
"""
4+
import json
45
import pytest
56
from click.testing import CliRunner
67
from chipfoundry_cli.main import main
@@ -20,6 +21,15 @@ def temp_project_dir():
2021
shutil.rmtree(temp_dir)
2122

2223

24+
def _ensure_project_json(project_root: str) -> None:
25+
"""Create minimal .cf/project.json so verify command can read project type."""
26+
cf_dir = Path(project_root) / ".cf"
27+
cf_dir.mkdir(parents=True, exist_ok=True)
28+
project_json = cf_dir / "project.json"
29+
if not project_json.exists():
30+
project_json.write_text(json.dumps({"project": {"type": "digital"}}))
31+
32+
2333
class TestVerifyCommand:
2434
"""Test suite for cf verify command."""
2535

@@ -39,14 +49,15 @@ def test_verify_help(self):
3949

4050
def test_verify_list(self, temp_project_dir):
4151
"""Test verify command with --list flag."""
52+
_ensure_project_json(temp_project_dir)
4253
runner = CliRunner()
4354
result = runner.invoke(main, [
4455
'verify',
4556
'--project-root', temp_project_dir,
4657
'--list'
4758
])
4859

49-
# Command returns 0 even on error, just prints error message
60+
# Command returns 0; with no cocotb dir it prints a message, with cocotb it lists tests
5061
assert result.exit_code == 0
5162
assert 'cocotb' in result.output.lower() or 'list' in result.output.lower()
5263

0 commit comments

Comments
 (0)