Skip to content
Draft
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
13 changes: 13 additions & 0 deletions linker/slashkit/core/command_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,14 @@ def populate_argument_parser(cls, ap: argparse.ArgumentParser):
ap.add_argument("--out-dir", required=True, type=Path,
help="The resource directory to install the artifacts to. "
+ "If you have checked out the SLASH repository, this would be linker/slashkit/resources")
ap.add_argument("--ignore-timing-failure", action="store_true",
help="Install static shell artifacts even when timing failed (WNS < 0 or WHS < 0).")

def __init__(self, args: argparse.Namespace):
super().__init__(args)

self._ignore_timing_failure: bool = args.ignore_timing_failure

self._build_dir: Path = args.build_dir.expanduser().resolve()
if self._build_dir.is_dir():
shutil.rmtree(self._build_dir)
Expand Down Expand Up @@ -409,3 +413,12 @@ def aved_ref(self) -> str:
@property
def out_dir(self) -> Path:
return self._out_dir

@property
def ignore_timing_failure(self) -> bool:
return self._ignore_timing_failure

@property
def noninteractive(self) -> bool:
value = os.getenv("SLASH_NONINTERACTIVE", "")
return value not in ("", "0", "false", "False", "no", "No")
8 changes: 8 additions & 0 deletions linker/slashkit/emit/hw/project_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from slashkit.emit.metadata.report_util import convert_report_utilization_to_xml
from slashkit.emit.render import export_package
from slashkit.core.command_config import LinkerConfiguration, InstallerConfiguration, CommandConfiguration
from slashkit.emit.metadata.timing_freq import require_static_shell_timing_or_confirm

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -385,6 +386,13 @@ def install_static_shell(config: InstallerConfiguration) -> None:

create_build_project(config)

require_static_shell_timing_or_confirm(
build_dir=config.build_dir,
project_name=config.project_name,
ignore_failure=config.ignore_timing_failure,
noninteractive=config.noninteractive,
)

impl_dir = config.build_dir / "slash.runs" / "impl_1"
dcp_sources = (
impl_dir / "top_wrapper_routed_bb.dcp",
Expand Down
100 changes: 93 additions & 7 deletions linker/slashkit/emit/metadata/timing_freq.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import logging
import math
import os
import sys
from pathlib import Path
import re
from typing import Optional
Expand All @@ -31,9 +32,10 @@
logger = logging.getLogger(__name__)

HW_BUILD_DIR_ENV_KEYS = ("SLASH_HW_BUILD_DIR", "slash_hw_build_dir")
_FLOAT_RE = re.compile(r"[-+]?\d+(?:\.\d+)?")


def extract_design_wns_ns(report_text: str) -> Optional[float]:
def _find_design_timing_summary_row(report_text: str) -> Optional[list[float]]:
if not report_text:
return None

Expand All @@ -60,16 +62,100 @@ def extract_design_wns_ns(report_text: str) -> Optional[float]:
continue
if set(line) <= {"-", " "}:
continue
m = re.match(r"^[-+]?\d+(?:\.\d+)?", line)
if m:
try:
return float(m.group(0))
except ValueError:
return None
values = [float(m.group(0)) for m in _FLOAT_RE.finditer(line)]
if values:
return values

return None


def extract_design_timing_slacks_ns(report_text: str) -> Optional[tuple[float, float]]:
values = _find_design_timing_summary_row(report_text)
if values is None or len(values) < 3:
return None
return values[0], values[2]


def extract_design_wns_ns(report_text: str) -> Optional[float]:
slacks = extract_design_timing_slacks_ns(report_text)
if slacks is None:
return None
return slacks[0]


def design_timing_met(wns_ns: float, whs_ns: float) -> bool:
return wns_ns >= 0 and whs_ns >= 0


def find_static_shell_timing_report(build_dir: Path, project_name: str) -> Optional[Path]:
path = build_dir / f"report_timing_{project_name}.txt"
if path.is_file():
return path
return None


def require_static_shell_timing_or_confirm(
*,
build_dir: Path,
project_name: str,
ignore_failure: bool,
noninteractive: bool,
) -> None:
timing_report = find_static_shell_timing_report(build_dir, project_name)
if timing_report is None:
raise RuntimeError(
f"Static shell timing report not found: {build_dir / f'report_timing_{project_name}.txt'}"
)

report_text = timing_report.read_text(encoding="utf-8", errors="replace")
slacks = extract_design_timing_slacks_ns(report_text)
if slacks is None:
raise RuntimeError(
f"Could not parse WNS/WHS from static shell timing report: {timing_report}"
)

wns_ns, whs_ns = slacks
if design_timing_met(wns_ns, whs_ns):
logger.info(
"Static shell timing met: WNS(ns)=%.3f, WHS(ns)=%.3f (%s)",
wns_ns,
whs_ns,
timing_report,
)
return

print("ERROR: Static shell timing failed.", file=sys.stderr)
print(f" WNS(ns)={wns_ns:.3f}", file=sys.stderr)
print(f" WHS(ns)={whs_ns:.3f}", file=sys.stderr)
print(f" Report: {timing_report}", file=sys.stderr)

if ignore_failure:
logger.warning(
"Proceeding despite static shell timing failure (--ignore-timing-failure)"
)
return

if noninteractive:
raise RuntimeError(
"Static shell timing failed and SLASH_NONINTERACTIVE is set; "
"use --ignore-timing-failure to override"
)

if sys.stdin.isatty():
answer = input(
"Proceed with install/packaging anyway? [y/N] ").strip().lower()
if answer in ("y", "yes"):
logger.warning(
"User confirmed install despite static shell timing failure")
return
raise SystemExit(1)

raise RuntimeError(
"Static shell timing failed and no interactive terminal is available; "
"use --ignore-timing-failure to override"
)


def compute_max_freq_hz_from_wns(wns_ns: float, base_freq_hz: int = 400_000_000) -> Optional[int]:
if base_freq_hz <= 0:
return None
Expand Down
10 changes: 8 additions & 2 deletions linker/slashkit/resources/base/constraints/impl.xdc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

create_pblock pblock_slash
add_cells_to_pblock [get_pblocks pblock_slash] [get_cells -quiet [list top_i/slash]]
resize_pblock [get_pblocks pblock_slash] -add {SLICE_X28Y716:SLICE_X351Y879 SLICE_X48Y620:SLICE_X351Y715 SLICE_X244Y575:SLICE_X351Y619 SLICE_X84Y575:SLICE_X163Y619 SLICE_X244Y574:SLICE_X323Y574}
resize_pblock [get_pblocks pblock_slash] -add {SLICE_X28Y716:SLICE_X351Y879 SLICE_X48Y620:SLICE_X351Y715 SLICE_X244Y575:SLICE_X351Y619 SLICE_X84Y575:SLICE_X163Y619 SLICE_X244Y574:SLICE_X323Y574 SLICE_X28Y716:SLICE_X351Y898}
resize_pblock [get_pblocks pblock_slash] -add {BUFG_FABRIC_X4Y144:BUFG_FABRIC_X4Y239 BUFG_FABRIC_X3Y168:BUFG_FABRIC_X3Y239 BUFG_FABRIC_X0Y144:BUFG_FABRIC_X2Y239}
resize_pblock [get_pblocks pblock_slash] -add {BUFG_PS_X2Y48:BUFG_PS_X2Y59}
resize_pblock [get_pblocks pblock_slash] -add {DSP58_CPLX_X0Y310:DSP58_CPLX_X11Y439 DSP58_CPLX_X8Y287:DSP58_CPLX_X11Y309 DSP58_CPLX_X0Y287:DSP58_CPLX_X3Y309}
Expand Down Expand Up @@ -70,5 +70,11 @@ set_property NOC_HIGH_ID_MIN 49 [get_pblocks pblock_service_layer]
set_property NOC_HIGH_ID_MAX 48 [get_pblocks pblock_slash]
set_property NOC_HIGH_ID_MIN 31 [get_pblocks pblock_slash]

create_pblock pblock_dfx_decoupler
add_cells_to_pblock [get_pblocks pblock_dfx_decoupler] [get_cells -hierarchical -filter {NAME =~ *static_region/dfx_decoupler_0* && IS_PRIMITIVE}]
add_cells_to_pblock [get_pblocks pblock_dfx_decoupler] [get_cells top_i/static_region/dfx_decoupler_0]
resize_pblock [get_pblocks pblock_dfx_decoupler] -add {SLICE_X16Y899:SLICE_X379Y903}
set_property IS_SOFT FALSE [get_pblocks pblock_dfx_decoupler]

#set_false_path -reset_path -from [get_pins {top_i/static_region/clk_rst_shell/proc_sys_reset_0/U0/ACTIVE_LOW_PR_OUT_DFF[0].FDRE_PER_N/C}]
#set_false_path -reset_path -from [get_pins {top_i/static_region/clk_rst_shell/proc_sys_reset_1/U0/ACTIVE_LOW_PR_OUT_DFF[0].FDRE_PER_N/C}]
#set_false_path -reset_path -from [get_pins {top_i/static_region/clk_rst_shell/proc_sys_reset_1/U0/ACTIVE_LOW_PR_OUT_DFF[0].FDRE_PER_N/C}]
6 changes: 5 additions & 1 deletion linker/slashkit/resources/base/scripts/build_project.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ proc build_project {{proj_name "user"} {jobs 14}} {

# Parent impl run remains 'impl_1'
set_property PR_CONFIGURATION config_1 [get_runs impl_1]
set_property strategy Congestion_SSI_SpreadLogic_high [get_runs impl_1]
set_property strategy Performance_NetDelay_high [get_runs impl_1]
set_property STEPS.OPT_DESIGN.TCL.POST [get_files *opt.post.tcl] [get_runs impl_1]
set_property STEPS.PLACE_DESIGN.TCL.PRE [get_files *place.pre.tcl] [get_runs impl_1]
set_property STEPS.WRITE_DEVICE_IMAGE.TCL.PRE [get_files *write_device_image.pre.tcl] [get_runs impl_1]
Expand All @@ -42,6 +42,10 @@ proc build_project {{proj_name "user"} {jobs 14}} {
launch_runs impl_1 -to_step write_bitstream -jobs $jobs
wait_on_run impl_1
open_run impl_1

set timing_report_file [file join [file normalize [pwd]] "report_timing_${proj_name}.txt"]
report_timing_summary -delay_type min_max -check_timing_verbose -max_paths 1 -input_pins -routable_nets -file $timing_report_file
puts "TIMING REPORT: $timing_report_file"

set impl_output_dir [get_property DIRECTORY [current_run]]
write_abstract_shell -cell top_i/slash -force [file join $impl_output_dir "static_shell_slash.dcp"]
Expand Down
Loading
Loading