Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions api/steps/dc/01_run_api.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from motia import ApiRequest, ApiResponse, FlowContext, api

from utils.path import get_buckyball_path

config = {
"name": "dc-run-api",
"description": "run Design Compiler synthesis script",
"flows": ["dc"],
"triggers": [api("POST", "/dc/run")],
"enqueues": ["dc.run"],
}


async def handler(request: ApiRequest, ctx: FlowContext) -> ApiResponse:
bbdir = get_buckyball_path()
body = request.body or {}

srcdir = body.get("srcdir")
if not srcdir:
return ApiResponse(
status=400,
body={
"status": "error",
"message": "Missing required parameter: --srcdir",
"example": 'bbdev dc --srcdir arch/ReluBall_1 --top ReluBall',
},
)

data = {
"srcdir": srcdir,
"top": body.get("top"),
"keep_hierarchy": bool(body.get("keep_hierarchy", False)),
"balltype": body.get("balltype"),
"config": body.get("config", "sims.verilator.BuckyballToyVerilatorConfig"),
"output_dir": body.get("output_dir"),
"report_dir": f"{bbdir}/bb-tests/output/dc/reports",
}
await ctx.enqueue({"topic": "dc.run", "data": {**data, "_trace_id": ctx.trace_id}})
return ApiResponse(status=202, body={"trace_id": ctx.trace_id})
133 changes: 133 additions & 0 deletions api/steps/dc/01_run_event.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import os
import shlex
import sys

from motia import FlowContext, queue

# Add the utils directory to the Python path
utils_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
if utils_path not in sys.path:
sys.path.insert(0, utils_path)

from utils.event_common import check_result, get_origin_trace_id
from utils.path import get_buckyball_path
from utils.stream_run import stream_run_logger

config = {
"name": "dc-run",
"description": "run Design Compiler synthesis script",
"flows": ["dc"],
"triggers": [queue("dc.run")],
"enqueues": [],
}


async def handler(input_data: dict, ctx: FlowContext) -> None:
origin_tid = get_origin_trace_id(input_data, ctx)
bbdir = get_buckyball_path()
script_path = f"{bbdir}/evals/run-dc.sh"

srcdir = input_data.get("srcdir")
top = input_data.get("top")
keep_hierarchy = bool(input_data.get("keep_hierarchy", False))
balltype = input_data.get("balltype")
config_name = input_data.get("config", "sims.verilator.BuckyballToyVerilatorConfig")
output_dir = input_data.get("output_dir")

if not srcdir:
success_result, failure_result = await check_result(
ctx,
1,
continue_run=False,
extra_fields={
"task": "dc",
"error": "Missing required parameter: srcdir",
"example": "bbdev dc --srcdir arch/ReluBall_1 --top ReluBall",
},
trace_id=origin_tid,
)
return failure_result

if not os.path.exists(script_path):
success_result, failure_result = await check_result(
ctx,
1,
continue_run=False,
extra_fields={
"task": "dc",
"error": f"DC script not found: {script_path}",
},
trace_id=origin_tid,
)
return failure_result

# Keep compatibility with old manual flow: ensure run-dc.sh is executable.
os.chmod(script_path, os.stat(script_path).st_mode | 0o111)

# Optional integrated pre-step: generate Ball verilog first.
if balltype:
final_output_dir = output_dir or f"{balltype}_1"
verilog_dir = f"{bbdir}/arch/{final_output_dir}"
verilog_cmd = (
f"mill -i __.test.runMain sims.verify.BallTopMain {shlex.quote(str(balltype))} "
"--disable-annotation-unknown --strip-debug-info -O=debug "
f"--split-verilog -o={shlex.quote(verilog_dir)}"
)

verilog_result = stream_run_logger(
cmd=verilog_cmd,
logger=ctx.logger,
cwd=f"{bbdir}/arch",
stdout_prefix="dc verilog",
stderr_prefix="dc verilog",
)

if verilog_result.returncode != 0:
success_result, failure_result = await check_result(
ctx,
verilog_result.returncode,
continue_run=False,
extra_fields={
"task": "dc",
"error": "Failed to generate pre-DC verilog",
"balltype": balltype,
"config": config_name,
},
trace_id=origin_tid,
)
return failure_result

# If user keeps default-like srcdir, force it to generated dir for consistency.
srcdir = f"arch/{final_output_dir}"

command_parts = ["bash", shlex.quote(script_path), "--srcdir", shlex.quote(str(srcdir))]
if top:
command_parts.extend(["--top", shlex.quote(str(top))])
if keep_hierarchy:
command_parts.append("--keep-hierarchy")

command = " ".join(command_parts)

result = stream_run_logger(
cmd=command,
logger=ctx.logger,
cwd=bbdir,
executable="bash",
stdout_prefix="dc run",
stderr_prefix="dc run",
)

success_result, failure_result = await check_result(
ctx,
result.returncode,
continue_run=False,
extra_fields={
"task": "dc",
"report_dir": input_data.get("report_dir", f"{bbdir}/bb-tests/output/dc/reports"),
"srcdir": srcdir,
"top": top,
},
trace_id=origin_tid,
)

return
30 changes: 30 additions & 0 deletions bbdev
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ WORKFLOW_COMMANDS = {
"flashbitstream": 'Flash bitstream onto AU280. Args: "[--bitstream <path>] [--serial <url>]"',
"runworkload": 'Run workload on AU280. Args: "[--workload <name>] [--board <name>] [--timeout <s>] [--uart <dev>]"',
},
"dc": {
"run": 'Run Design Compiler synthesis. Args: "--srcdir <design_dir> [--top <top_module>] [--keep-hierarchy] [--balltype <type>] [--config <cfg>] [--output-dir <dir>]"',
},
}

ALL_COMMANDS = ["start", "stop"] + list(WORKFLOW_COMMANDS)
Expand Down Expand Up @@ -169,8 +172,21 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
stop_parser = subparsers.add_parser("stop", parents=[common], help="Stop dev server")
stop_parser.add_argument("--all", action="store_true", help="Stop all servers")

# dc direct mode (no --run wrapper):
# bbdev dc --srcdir ... [--top ...] [--keep-hierarchy]
# [--balltype ...] [--config ...] [--output-dir ...]
dc_parser = subparsers.add_parser("dc", parents=[common], help="Run DC synthesis")
dc_parser.add_argument("--srcdir", type=str, required=True, help="Design source directory relative to repo root")
dc_parser.add_argument("--top", type=str, default=None, help="Top module name")
dc_parser.add_argument("--keep-hierarchy", action="store_true", help="Keep hierarchy during compile")
dc_parser.add_argument("--balltype", type=str, default=None, help="Optional Ball type for pre-verilog generation, e.g. ReluBall")
dc_parser.add_argument("--config", type=str, default="sims.verilator.BuckyballToyVerilatorConfig", help="Verilog generation config when --balltype is set")
Comment on lines +177 to +183
dc_parser.add_argument("--output-dir", type=str, default=None, help="Verilog output dir under arch/, e.g. ReluBall_1")

# Build workflow subcommands from WORKFLOW_COMMANDS table
for cmd_name, operations in WORKFLOW_COMMANDS.items():
if cmd_name == "dc":
continue
cmd_parser = subparsers.add_parser(
cmd_name, parents=[common], help=f"{cmd_name} operations"
)
Expand All @@ -193,6 +209,20 @@ def parse_args(argv: list[str]) -> argparse.Namespace:

def extract_command_info(args: argparse.Namespace) -> dict:
"""Extract command, operation, and parsed sub-arguments from argparse Namespace."""
if args.command == "dc":
return {
"command": "dc",
"operation": "run",
"args": {
"srcdir": args.srcdir,
"top": args.top,
"keep_hierarchy": bool(args.keep_hierarchy),
"balltype": args.balltype,
"config": args.config,
"output_dir": args.output_dir,
},
}

result = {"command": args.command, "operation": None, "args": {}}

for attr_name, attr_value in vars(args).items():
Expand Down
Loading