mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
feat: enhance LibreLane flow with on-chip SRAM support and OpenSTA integration
This commit is contained in:
8 files changed
+239
-43
No files matched your search
@@ -22,6 +22,7 @@ LIBRELANE_KLAYOUT_PATH := $(LIBRELANE_PDK_ROOT)/$(LIBRELANE_PDK)/libs.tech/kla
|
||||
LIBRELANE_BONDPAD_SCRIPT := $(LIBRELANE_PDK_ROOT)/$(LIBRELANE_PDK)/libs.tech/klayout/tech/scripts/bondpad.py
|
||||
LIBRELANE_PDN := $(LIBRELANE_FLOW_ROOT)/pdn_cfg.tcl
|
||||
LIBRELANE_SRAM_VH := $(LIBRELANE_FLOW_ROOT)/sram_blackboxes.vh
|
||||
LIBRELANE_STA_REPORT_LIMIT := $(LIBRELANE_FLOW_ROOT)/sta_report_limit.tcl
|
||||
LIBRELANE_CLOCK_DOMAINS := $(ROOT_PATH)/rtl/mini/integration/clock_reset_domains.json
|
||||
LIBRELANE_PIN_MAP := $(ROOT_PATH)/rtl/mini/pin_map/pin_map.json
|
||||
LIBRELANE_TRACKED_RTL := $(shell git -C $(ROOT_PATH) ls-files \
|
||||
@@ -29,6 +30,7 @@ LIBRELANE_TRACKED_RTL := $(shell git -C $(ROOT_PATH) ls-files \
|
||||
|
||||
LIBRELANE_SOURCE_PYTHON ?= /usr/bin/python3
|
||||
LIBRELANE_PYTHON ?= python3
|
||||
LIBRELANE_COMMAND := $(LIBRELANE_PYTHON) -m librelane
|
||||
# LibreLane 3.0.5 writes 1000 expanded paths per group at every mid-PnR STA.
|
||||
# Final multi-corner RCX STA remains mandatory; skip only the redundant reports.
|
||||
LIBRELANE_MID_PNR_SKIP ?= --skip OpenROAD.STAMidPNR
|
||||
@@ -51,6 +53,7 @@ LIBRELANE_FEATURE_ARGS := \
|
||||
|
||||
LIBRELANE_CONFIG_DEPS := $(LIBRELANE_RTL) $(LIBRELANE_SDC) \
|
||||
$(LIBRELANE_PDN) $(LIBRELANE_SRAM_VH) \
|
||||
$(LIBRELANE_STA_REPORT_LIMIT) \
|
||||
$(LIBRELANE_FLOW_ROOT)/scripts/generate_chip_config.py
|
||||
ifeq ($(LIBRELANE_TARGET),chip)
|
||||
LIBRELANE_CONFIG_DEPS += $(LIBRELANE_BONDPAD_GDS) $(LIBRELANE_BONDPAD_LEF)
|
||||
@@ -106,8 +109,10 @@ $(LIBRELANE_CONFIG): $(LIBRELANE_CONFIG_DEPS)
|
||||
--pdn $(LIBRELANE_PDN) --bondpad-gds $(LIBRELANE_BONDPAD_GDS) \
|
||||
--bondpad-lef $(LIBRELANE_BONDPAD_LEF) --sram-vh $(LIBRELANE_SRAM_VH) \
|
||||
--ext-clk-hz $(EXT_CLK_HZ) --aud-clk-hz $(AUD_CLK_HZ) \
|
||||
$(if $(filter YES,$(HAVE_PLL)),--have-pll) --target $(LIBRELANE_TARGET) \
|
||||
--output $@
|
||||
--sram-size-kib $(SRAM_SIZE_KIB) \
|
||||
$(if $(filter YES,$(HAVE_PLL)),--have-pll) \
|
||||
$(if $(filter YES,$(HAVE_SRAM_MACRO)),--have-sram-macro) \
|
||||
--target $(LIBRELANE_TARGET) --output $@
|
||||
|
||||
librelane-input: $(LIBRELANE_CONFIG)
|
||||
|
||||
@@ -123,7 +128,7 @@ librelane-doctor: $(LIBRELANE_DOCTOR_RESULT)
|
||||
librelane-run: librelane-doctor manifest
|
||||
$(FLOW_PYTHON) $(ROOT_PATH)/scripts/run_flow.py --tool librelane \
|
||||
--log $(LIBRELANE_LOG) --result $(LIBRELANE_RESULT) --cwd $(LIBRELANE_RUN_ROOT) -- \
|
||||
librelane $(LIBRELANE_CONFIG) --manual-pdk --pdk $(LIBRELANE_PDK) \
|
||||
$(LIBRELANE_COMMAND) $(LIBRELANE_CONFIG) --manual-pdk --pdk $(LIBRELANE_PDK) \
|
||||
--pdk-root $(LIBRELANE_PDK_ROOT) --scl $(LIBRELANE_SCL) --pad $(LIBRELANE_PAD) \
|
||||
--run-tag $(LIBRELANE_RUN_TAG) --overwrite --jobs $(JOBS) $(LIBRELANE_MID_PNR_SKIP) \
|
||||
--condensed --hide-progress-bar --save-views-to $(LIBRELANE_FINAL_DIR)
|
||||
@@ -137,13 +142,13 @@ librelane-core:
|
||||
+$(MAKE) LIBRELANE_TARGET=core librelane-run
|
||||
|
||||
librelane-openroad: librelane-doctor
|
||||
cd $(LIBRELANE_RUN_ROOT) && librelane $(LIBRELANE_CONFIG) --manual-pdk \
|
||||
cd $(LIBRELANE_RUN_ROOT) && $(LIBRELANE_COMMAND) $(LIBRELANE_CONFIG) --manual-pdk \
|
||||
--pdk $(LIBRELANE_PDK) --pdk-root $(LIBRELANE_PDK_ROOT) \
|
||||
--scl $(LIBRELANE_SCL) --pad $(LIBRELANE_PAD) \
|
||||
--run-tag $(LIBRELANE_RUN_TAG) --last-run --flow OpenInOpenROAD
|
||||
|
||||
librelane-klayout: librelane-doctor
|
||||
cd $(LIBRELANE_RUN_ROOT) && librelane $(LIBRELANE_CONFIG) --manual-pdk \
|
||||
cd $(LIBRELANE_RUN_ROOT) && $(LIBRELANE_COMMAND) $(LIBRELANE_CONFIG) --manual-pdk \
|
||||
--pdk $(LIBRELANE_PDK) --pdk-root $(LIBRELANE_PDK_ROOT) \
|
||||
--scl $(LIBRELANE_SCL) --pad $(LIBRELANE_PAD) \
|
||||
--run-tag $(LIBRELANE_RUN_TAG) --last-run --flow OpenInKLayout
|
||||
|
||||
@@ -6,6 +6,7 @@ source $::env(SCRIPTS_DIR)/openroad/common/io.tcl
|
||||
source $::env(SCRIPTS_DIR)/openroad/common/set_global_connections.tcl
|
||||
set_global_connections
|
||||
|
||||
# Use the PDK-native alternating routing directions (H/V/H/V/H).
|
||||
set secondary_supplies []
|
||||
foreach vdd $::env(VDD_NETS) gnd $::env(GND_NETS) {
|
||||
if {$vdd != $::env(VDD_NET)} {
|
||||
@@ -94,7 +95,8 @@ add_pdn_stripe \
|
||||
-pitch $::env(PDN_VPITCH) \
|
||||
-offset $::env(PDN_VOFFSET) \
|
||||
-spacing $::env(PDN_VSPACING) \
|
||||
-starts_with POWER
|
||||
-starts_with POWER \
|
||||
-extend_to_core_ring
|
||||
|
||||
add_pdn_stripe \
|
||||
-grid stdcell_grid \
|
||||
@@ -103,21 +105,31 @@ add_pdn_stripe \
|
||||
-pitch $::env(PDN_HPITCH) \
|
||||
-offset $::env(PDN_HOFFSET) \
|
||||
-spacing $::env(PDN_HSPACING) \
|
||||
-starts_with POWER
|
||||
-starts_with POWER \
|
||||
-extend_to_core_ring
|
||||
|
||||
add_pdn_connect \
|
||||
# The top-metal ring uses -add_connect below, which owns the TopMetal1/TopMetal2 vias.
|
||||
|
||||
# Basilisk's IHP130 topology uses a low-metal ring to collect standard-cell
|
||||
# rails, plus a separate top-metal ring for the pad-facing mesh.
|
||||
add_pdn_ring \
|
||||
-grid stdcell_grid \
|
||||
-layers "$::env(PDN_VERTICAL_LAYER) $::env(PDN_HORIZONTAL_LAYER)"
|
||||
-layers "Metal2 Metal3" \
|
||||
-widths "0.52 0.52" \
|
||||
-spacings "0.8 0.8" \
|
||||
-core_offsets "1.6 1.6" \
|
||||
-starts_with POWER \
|
||||
-add_connect
|
||||
|
||||
if {$::env(PDN_ENABLE_RAILS) == 1} {
|
||||
add_pdn_stripe \
|
||||
-grid stdcell_grid \
|
||||
-layer $::env(PDN_RAIL_LAYER) \
|
||||
-width $::env(PDN_RAIL_WIDTH) \
|
||||
-followpins
|
||||
add_pdn_connect \
|
||||
-grid stdcell_grid \
|
||||
-layers "$::env(PDN_RAIL_LAYER) $::env(PDN_VERTICAL_LAYER)"
|
||||
-followpins \
|
||||
-extend_to_core_ring
|
||||
add_pdn_connect -grid stdcell_grid -layers "Metal1 Metal2"
|
||||
add_pdn_connect -grid stdcell_grid -layers "Metal1 Metal3"
|
||||
}
|
||||
|
||||
if {$::env(PDN_CORE_RING) == 1} {
|
||||
@@ -126,41 +138,55 @@ if {$::env(PDN_CORE_RING) == 1} {
|
||||
-layers "$::env(PDN_VERTICAL_LAYER) $::env(PDN_HORIZONTAL_LAYER)" \
|
||||
-widths "$::env(PDN_CORE_RING_VWIDTH) $::env(PDN_CORE_RING_HWIDTH)" \
|
||||
-spacings "$::env(PDN_CORE_RING_VSPACING) $::env(PDN_CORE_RING_HSPACING)" \
|
||||
-core_offset "$::env(PDN_CORE_RING_VOFFSET) $::env(PDN_CORE_RING_HOFFSET)" \
|
||||
-connect_to_pads
|
||||
-core_offsets "$::env(PDN_CORE_RING_VOFFSET) $::env(PDN_CORE_RING_HOFFSET)" \
|
||||
-connect_to_pads \
|
||||
-connect_to_pad_layers TopMetal2 \
|
||||
-add_connect
|
||||
}
|
||||
|
||||
define_pdn_grid \
|
||||
-macro \
|
||||
-default \
|
||||
-name macro_default \
|
||||
-starts_with POWER \
|
||||
-halo "$::env(PDN_HORIZONTAL_HALO) $::env(PDN_VERTICAL_HALO)"
|
||||
|
||||
add_pdn_connect \
|
||||
-grid macro_default \
|
||||
-layers "$::env(PDN_VERTICAL_LAYER) $::env(PDN_HORIZONTAL_LAYER)"
|
||||
|
||||
set packet_ram_instances [list \
|
||||
u_retrosoc.u_apb4_periph.u_apb4_usb2.u_link_domain.u_packet_store.u_packet_ram.u_packet_ram.u_data_high \
|
||||
u_retrosoc.u_apb4_periph.u_apb4_usb2.u_link_domain.u_packet_store.u_packet_ram.u_packet_ram.u_data_low \
|
||||
u_retrosoc.u_apb4_periph.u_apb4_usb2.u_link_domain.u_packet_store.u_packet_ram.u_packet_ram.u_ecc]
|
||||
set sram_cells [list \
|
||||
RM_IHPSG13_1P_4096x16_c3_bm_bist \
|
||||
RM_IHPSG13_1P_4096x8_c3_bm_bist \
|
||||
RM_IHPSG13_1P_1024x32_c2_bm_bist]
|
||||
|
||||
define_pdn_grid \
|
||||
-macro \
|
||||
-instances $packet_ram_instances \
|
||||
-cells $sram_cells \
|
||||
-name packet_ram_grid \
|
||||
-grid_over_boundary \
|
||||
-voltage_domains CORE \
|
||||
-starts_with POWER
|
||||
|
||||
add_pdn_ring \
|
||||
-grid packet_ram_grid \
|
||||
-layers "Metal2 Metal3" \
|
||||
-widths "0.52 0.52" \
|
||||
-spacings "0.8 0.8" \
|
||||
-core_offsets "1.6 1.6" \
|
||||
-starts_with POWER \
|
||||
-add_connect
|
||||
|
||||
add_pdn_stripe \
|
||||
-grid packet_ram_grid \
|
||||
-layer Metal4 \
|
||||
-width 0.52 \
|
||||
-pitch 20.0 \
|
||||
-offset 2.0 \
|
||||
-spacing 0.8 \
|
||||
-starts_with POWER
|
||||
|
||||
add_pdn_stripe \
|
||||
-grid packet_ram_grid \
|
||||
-layer Metal5 \
|
||||
-width 2.81 \
|
||||
-layer TopMetal1 \
|
||||
-width 2.5 \
|
||||
-pitch 11.24 \
|
||||
-offset 2.81 \
|
||||
-spacing 2.81 \
|
||||
-nets "VSS VDD" \
|
||||
-starts_with POWER
|
||||
|
||||
add_pdn_connect -grid packet_ram_grid -layers "Metal4 Metal5"
|
||||
add_pdn_connect -grid packet_ram_grid -layers "Metal2 TopMetal1"
|
||||
add_pdn_connect -grid packet_ram_grid -layers "Metal3 TopMetal1"
|
||||
add_pdn_connect -grid packet_ram_grid -layers "Metal3 Metal4"
|
||||
add_pdn_connect -grid packet_ram_grid -layers "Metal4 TopMetal1"
|
||||
add_pdn_connect -grid packet_ram_grid -layers "Metal5 TopMetal1"
|
||||
add_pdn_connect -grid packet_ram_grid -layers "TopMetal1 TopMetal2"
|
||||
@@ -19,6 +19,7 @@ from scripts.setup_helpers import atomic_write # noqa: E402
|
||||
|
||||
|
||||
EXPECTED_LIBRELANE_VERSION = "LibreLane v3.0.5"
|
||||
EXPECTED_OPENSTA_VERSION = "3.0.0"
|
||||
EXPECTED_SIGNAL_PADS = 109
|
||||
|
||||
|
||||
@@ -37,18 +38,29 @@ def main() -> int:
|
||||
errors: list[str] = []
|
||||
details: dict[str, object] = {}
|
||||
|
||||
for tool in ("librelane", "klayout"):
|
||||
for tool in ("librelane", "klayout", "sta"):
|
||||
path = shutil.which(tool)
|
||||
details[f"{tool}_path"] = path
|
||||
if path is None:
|
||||
errors.append(f"required tool is missing: {tool}")
|
||||
|
||||
if shutil.which("librelane") is not None:
|
||||
version = command_output(["librelane", "--version"]).splitlines()[0]
|
||||
version = command_output(
|
||||
[sys.executable, "-m", "librelane", "--version"]
|
||||
).splitlines()[0]
|
||||
details["librelane_version"] = version
|
||||
if version != EXPECTED_LIBRELANE_VERSION:
|
||||
errors.append(f"expected {EXPECTED_LIBRELANE_VERSION}, found {version or '<empty>'}")
|
||||
|
||||
if shutil.which("sta") is not None:
|
||||
version = command_output(["sta", "-version"])
|
||||
details["opensta_version"] = version
|
||||
if version != EXPECTED_OPENSTA_VERSION:
|
||||
errors.append(
|
||||
f"expected OpenSTA {EXPECTED_OPENSTA_VERSION}, "
|
||||
f"found {version or '<empty>'}"
|
||||
)
|
||||
|
||||
lock = json.loads(args.lock.read_text(encoding="utf-8"))
|
||||
expected_pdk_revision = lock["sources"]["pdk_ihp130"]["revision"]
|
||||
details["locked_pdk_revision"] = expected_pdk_revision
|
||||
|
||||
@@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -44,6 +45,19 @@ SRAM_INSTANCES = {
|
||||
}
|
||||
|
||||
|
||||
def onchip_sram_instances(capacity_kib: int) -> dict[str, tuple[list[int], str]]:
|
||||
if capacity_kib <= 0 or capacity_kib % 4 != 0:
|
||||
raise ValueError("SRAM_SIZE_KIB must be a positive multiple of 4")
|
||||
count = capacity_kib // 4
|
||||
return {
|
||||
f"u_retrosoc.u_onchip_ram.gen_memory.gen_bank[{index}].u_ram.u_mem": (
|
||||
[2000 + (index % 4) * 500, 500 + (index // 4) * 750],
|
||||
"N",
|
||||
)
|
||||
for index in range(count)
|
||||
}
|
||||
|
||||
|
||||
def config_path(path: Path, base: Path) -> str:
|
||||
return f"dir::{os.path.relpath(path.resolve(), base.resolve())}"
|
||||
|
||||
@@ -141,17 +155,34 @@ def build_config(args: argparse.Namespace) -> dict[str, object]:
|
||||
|
||||
config_dir = args.output.resolve().parent
|
||||
sram_header = config_path(args.sram_vh, config_dir)
|
||||
active_sram_instances = dict(SRAM_INSTANCES)
|
||||
if getattr(args, "have_sram_macro", False):
|
||||
active_sram_instances["RM_IHPSG13_1P_1024x32_c2_bm_bist"] = onchip_sram_instances(
|
||||
getattr(args, "sram_size_kib", 32)
|
||||
)
|
||||
macros = {
|
||||
master: macro_config(master, instances, sram_header)
|
||||
for master, instances in SRAM_INSTANCES.items()
|
||||
for master, instances in active_sram_instances.items()
|
||||
}
|
||||
macro_hooks: list[str] = []
|
||||
for instances in SRAM_INSTANCES.values():
|
||||
for instances in active_sram_instances.values():
|
||||
for instance in instances:
|
||||
bracket_start = instance.find("[")
|
||||
if bracket_start >= 0:
|
||||
bracket_end = instance.index("]", bracket_start)
|
||||
instance_pattern = (
|
||||
re.escape(instance[:bracket_start])
|
||||
+ ".*"
|
||||
+ instance[bracket_start + 1 : bracket_end]
|
||||
+ ".*"
|
||||
+ re.escape(instance[bracket_end + 1 :])
|
||||
)
|
||||
else:
|
||||
instance_pattern = re.escape(instance)
|
||||
macro_hooks.extend(
|
||||
[
|
||||
f"{instance} VDD VSS VDDARRAY! VSS!",
|
||||
f"{instance} VDD VSS VDD! VSS!",
|
||||
f"{instance_pattern} VDD VSS VDDARRAY! VSS!",
|
||||
f"{instance_pattern} VDD VSS VDD! VSS!",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -164,10 +195,17 @@ def build_config(args: argparse.Namespace) -> dict[str, object]:
|
||||
"SYNTH_HIERARCHY_MODE": "deferred_flatten",
|
||||
"YOSYS_LOG_LEVEL": "WARNING",
|
||||
"SYNTH_STRATEGY": "AREA 3",
|
||||
"RUN_POST_GPL_DESIGN_REPAIR": False,
|
||||
"RUN_CTS": False,
|
||||
"RUN_POST_CTS_RESIZER_TIMING": False,
|
||||
"EXTRA_EXCLUDED_CELLS": ["sg13g2_IOPad*"],
|
||||
"PRIMARY_GDSII_STREAMOUT_TOOL": "klayout",
|
||||
"PNR_SDC_FILE": config_path(args.sdc, config_dir),
|
||||
"SIGNOFF_SDC_FILE": config_path(args.sdc, config_dir),
|
||||
"FALLBACK_SDC": config_path(args.sdc, config_dir),
|
||||
"STA_EXTRA_CORNER_TCL_FILE": config_path(
|
||||
ROOT / "physical/librelane/sta_report_limit.tcl", config_dir
|
||||
),
|
||||
"CLOCK_PORT": list(CLOCK_PORTS),
|
||||
"CLOCK_PERIOD": 1_000_000_000 / args.ext_clk_hz,
|
||||
"VDD_NETS": ["VDD"],
|
||||
@@ -179,6 +217,7 @@ def build_config(args: argparse.Namespace) -> dict[str, object]:
|
||||
"PDN_CORE_RING_VSPACING": 5,
|
||||
"PDN_CORE_RING_HSPACING": 5,
|
||||
"PDN_ENABLE_PINS": True,
|
||||
"ERROR_ON_PDN_VIOLATIONS": True,
|
||||
"PDN_CFG": config_path(args.pdn, config_dir),
|
||||
"MACROS": macros,
|
||||
"PDN_MACRO_CONNECTIONS": macro_hooks,
|
||||
@@ -216,7 +255,7 @@ def build_config(args: argparse.Namespace) -> dict[str, object]:
|
||||
"PAD_WEST": pad_sides["WEST"],
|
||||
"DIE_AREA": [0, 0, 8000, 8000],
|
||||
"CORE_AREA": [365, 365, 7635, 7635],
|
||||
"PL_TARGET_DENSITY_PCT": 30,
|
||||
"PL_TARGET_DENSITY_PCT": 45,
|
||||
"PDN_CORE_RING_CONNECT_TO_PADS": True,
|
||||
"PAD_CFG": config_path(ROOT / "physical/librelane/pad_cfg.tcl", config_dir),
|
||||
"PAD_BONDPAD_NAME": "bondpad_70x70",
|
||||
@@ -247,6 +286,8 @@ def main() -> int:
|
||||
parser.add_argument("--ext-clk-hz", type=positive_integer, required=True)
|
||||
parser.add_argument("--aud-clk-hz", type=positive_integer, required=True)
|
||||
parser.add_argument("--have-pll", action="store_true")
|
||||
parser.add_argument("--have-sram-macro", action="store_true")
|
||||
parser.add_argument("--sram-size-kib", type=positive_integer, default=32)
|
||||
parser.add_argument("--target", choices=("chip", "core"), default="chip")
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -138,7 +138,6 @@ def render(args: argparse.Namespace) -> str:
|
||||
"set_clock_uncertainty -setup 0.2 $all_retrosoc_clocks",
|
||||
"set_clock_uncertainty -hold 0.1 $all_retrosoc_clocks",
|
||||
"set_clock_transition 0.1 $all_retrosoc_clocks",
|
||||
"set_propagated_clock $all_retrosoc_clocks",
|
||||
"set_timing_derate -early 0.95",
|
||||
"set_timing_derate -late 1.05",
|
||||
"set_max_fanout 10 [current_design]",
|
||||
|
||||
@@ -45,3 +45,26 @@ module RM_IHPSG13_1P_4096x8_c3_bm_bist (
|
||||
input wire [ 7:0] A_BIST_BM
|
||||
);
|
||||
endmodule
|
||||
|
||||
|
||||
(* blackbox *)
|
||||
module RM_IHPSG13_1P_1024x32_c2_bm_bist (
|
||||
input wire A_CLK,
|
||||
input wire A_MEN,
|
||||
input wire A_WEN,
|
||||
input wire A_REN,
|
||||
input wire [ 9:0] A_ADDR,
|
||||
input wire [31:0] A_DIN,
|
||||
input wire A_DLY,
|
||||
output wire [31:0] A_DOUT,
|
||||
input wire [31:0] A_BM,
|
||||
input wire A_BIST_CLK,
|
||||
input wire A_BIST_EN,
|
||||
input wire A_BIST_MEN,
|
||||
input wire A_BIST_WEN,
|
||||
input wire A_BIST_REN,
|
||||
input wire [ 9:0] A_BIST_ADDR,
|
||||
input wire [31:0] A_BIST_DIN,
|
||||
input wire [31:0] A_BIST_BM
|
||||
);
|
||||
endmodule
|
||||
@@ -0,0 +1,35 @@
|
||||
# LibreLane 3.0.5 hard-codes 1000 expanded paths per clock group. Cap only
|
||||
# report enumeration; worst-slack/TNS analysis still covers the full graph.
|
||||
set ::retrosoc_sta_group_path_count 10
|
||||
puts "\[INFO\] OpenSTA executable: [info nameofexecutable]"
|
||||
rename report_checks ::retrosoc_report_checks
|
||||
proc report_checks {args} {
|
||||
set count_index [lsearch -exact $args -group_path_count]
|
||||
if {$count_index >= 0} {
|
||||
set value_index [expr {$count_index + 1}]
|
||||
if {$value_index < [llength $args]} {
|
||||
lset args $value_index $::retrosoc_sta_group_path_count
|
||||
}
|
||||
} else {
|
||||
lappend args -group_path_count $::retrosoc_sta_group_path_count
|
||||
}
|
||||
uplevel 1 [list ::retrosoc_report_checks {*}$args]
|
||||
}
|
||||
|
||||
rename report_check_types ::retrosoc_report_check_types
|
||||
proc report_check_types {args} {
|
||||
set violator_index [lsearch -exact $args -violators]
|
||||
if {$violator_index >= 0} {
|
||||
set args [lreplace $args $violator_index $violator_index]
|
||||
}
|
||||
uplevel 1 [list ::retrosoc_report_check_types {*}$args]
|
||||
}
|
||||
|
||||
rename report_parasitic_annotation ::retrosoc_report_parasitic_annotation
|
||||
proc report_parasitic_annotation {args} {
|
||||
set detail_index [lsearch -exact $args -report_unannotated]
|
||||
if {$detail_index >= 0} {
|
||||
set args [lreplace $args $detail_index $detail_index]
|
||||
}
|
||||
uplevel 1 [list ::retrosoc_report_parasitic_annotation {*}$args]
|
||||
}
|
||||
@@ -61,6 +61,7 @@ def test_chip_config_places_every_signal_and_power_pad_once(tmp_path: Path) -> N
|
||||
assert "u_sdram_dq15_io_pad.u_sg13g2_IOPadInOut4mA" in sides["west"]
|
||||
assert config["DIE_AREA"] == [0, 0, 8000, 8000]
|
||||
assert config["CORE_AREA"] == [365, 365, 7635, 7635]
|
||||
assert config["PL_TARGET_DENSITY_PCT"] == 45
|
||||
assert config["USE_SLANG"] is True
|
||||
assert config["SLANG_ARGUMENTS"] == ["--keep-hierarchy"]
|
||||
assert config["VERILOG_POWER_DEFINE"] is None
|
||||
@@ -74,10 +75,18 @@ def test_chip_config_places_every_signal_and_power_pad_once(tmp_path: Path) -> N
|
||||
]
|
||||
assert config["YOSYS_LOG_LEVEL"] == "WARNING"
|
||||
assert config["SYNTH_STRATEGY"] == "AREA 3"
|
||||
assert config["RUN_POST_GPL_DESIGN_REPAIR"] is False
|
||||
assert config["RUN_CTS"] is False
|
||||
assert config["RUN_POST_CTS_RESIZER_TIMING"] is False
|
||||
assert config["EXTRA_EXCLUDED_CELLS"] == ["sg13g2_IOPad*"]
|
||||
assert config["VDD_NETS"] == ["VDD"]
|
||||
assert config["GND_NETS"] == ["VSS"]
|
||||
assert config["PAD_CFG"].endswith("physical/librelane/pad_cfg.tcl")
|
||||
assert config["PDN_ENABLE_PINS"] is True
|
||||
assert config["ERROR_ON_PDN_VIOLATIONS"] is True
|
||||
assert config["STA_EXTRA_CORNER_TCL_FILE"].endswith(
|
||||
"physical/librelane/sta_report_limit.tcl"
|
||||
)
|
||||
assert set(config["MACROS"]) == {
|
||||
"RM_IHPSG13_1P_4096x16_c3_bm_bist",
|
||||
"RM_IHPSG13_1P_4096x8_c3_bm_bist",
|
||||
@@ -107,6 +116,27 @@ def test_core_config_uses_a_padless_classic_flow(tmp_path: Path) -> None:
|
||||
}
|
||||
|
||||
|
||||
def test_chip_config_includes_configured_onchip_sram_banks(tmp_path: Path) -> None:
|
||||
module = load_module(
|
||||
"retrosoc_librelane_sram_config", FLOW_ROOT / "scripts/generate_chip_config.py"
|
||||
)
|
||||
arguments = chip_arguments(tmp_path)
|
||||
arguments.have_sram_macro = True
|
||||
arguments.sram_size_kib = 32
|
||||
config = module.build_config(arguments)
|
||||
|
||||
macro = config["MACROS"]["RM_IHPSG13_1P_1024x32_c2_bm_bist"]
|
||||
assert len(macro["instances"]) == 8
|
||||
assert "u_retrosoc.u_onchip_ram.gen_memory.gen_bank[0].u_ram.u_mem" in macro["instances"]
|
||||
assert "u_retrosoc.u_onchip_ram.gen_memory.gen_bank[7].u_ram.u_mem" in macro["instances"]
|
||||
assert any(
|
||||
"gen_bank.*0.*\\.u_ram" in connection
|
||||
for connection in config["PDN_MACRO_CONNECTIONS"]
|
||||
)
|
||||
blackboxes = (FLOW_ROOT / "sram_blackboxes.vh").read_text(encoding="utf-8")
|
||||
assert "module RM_IHPSG13_1P_1024x32_c2_bm_bist" in blackboxes
|
||||
|
||||
|
||||
def test_chip_sdc_is_pad_aware_and_does_not_false_path_all_io(tmp_path: Path) -> None:
|
||||
module = load_module("retrosoc_librelane_sdc", FLOW_ROOT / "scripts/generate_sdc.py")
|
||||
arguments = SimpleNamespace(
|
||||
@@ -123,6 +153,7 @@ def test_chip_sdc_is_pad_aware_and_does_not_false_path_all_io(tmp_path: Path) ->
|
||||
assert "u_rcu.u_sys_clk_buf.u_sg13g2_buf_1/X" in sdc
|
||||
assert "create_generated_clock -name clk_system" in sdc
|
||||
assert "set_clock_groups -name retrosoc_async -asynchronous" in sdc
|
||||
assert "set_propagated_clock" not in sdc
|
||||
assert "set_input_delay -max" in sdc
|
||||
assert "set_output_delay -max" in sdc
|
||||
assert "set_false_path -from $reset_ext_rst_n_i_pad" in sdc
|
||||
@@ -157,6 +188,7 @@ def test_librelane_flow_exposes_core_and_chip_targets() -> None:
|
||||
assert "librelane-core:" in makefile
|
||||
assert "librelane-core-package:" in makefile
|
||||
assert "LIBRELANE_TARGET ?= chip" in makefile
|
||||
assert "LIBRELANE_COMMAND := $(LIBRELANE_PYTHON) -m librelane" in makefile
|
||||
assert "--skip OpenROAD.STAMidPNR" in makefile
|
||||
assert "--librelane-safe" in makefile
|
||||
assert "librelane-all" not in makefile
|
||||
@@ -164,6 +196,8 @@ def test_librelane_flow_exposes_core_and_chip_targets() -> None:
|
||||
ihp_filelist = (ROOT / "rtl/filelist/pdk_ihp130.fl").read_text(encoding="utf-8")
|
||||
assert ihp_filelist.index("sg13g2_udp.v") < ihp_filelist.index("sg13g2_stdcell.v")
|
||||
assert lock["sources"]["pdk_ihp130"]["revision"] == ("970a7688e7dcce2a6172797df9ef47bde2f60f9f")
|
||||
doctor = (FLOW_ROOT / "scripts/doctor.py").read_text(encoding="utf-8")
|
||||
assert 'EXPECTED_OPENSTA_VERSION = "3.0.0"' in doctor
|
||||
|
||||
|
||||
def test_bondpad_lef_matches_the_generated_master_contract() -> None:
|
||||
@@ -175,6 +209,20 @@ def test_bondpad_lef_matches_the_generated_master_contract() -> None:
|
||||
assert "SITE sg13g2_ioSite" in lef
|
||||
|
||||
|
||||
def test_sta_report_wrapper_caps_only_expanded_path_enumeration() -> None:
|
||||
wrapper = (FLOW_ROOT / "sta_report_limit.tcl").read_text(encoding="utf-8")
|
||||
assert "set ::retrosoc_sta_group_path_count 10" in wrapper
|
||||
assert "OpenSTA executable" in wrapper
|
||||
assert "rename report_checks ::retrosoc_report_checks" in wrapper
|
||||
assert "lsearch -exact $args -group_path_count" in wrapper
|
||||
assert "lappend args -group_path_count" in wrapper
|
||||
assert "rename report_check_types ::retrosoc_report_check_types" in wrapper
|
||||
assert "lsearch -exact $args -violators" in wrapper
|
||||
assert "rename report_parasitic_annotation" in wrapper
|
||||
assert "lsearch -exact $args -report_unannotated" in wrapper
|
||||
assert "::retrosoc_report_checks" in wrapper
|
||||
|
||||
|
||||
def test_pdn_connects_all_ihp_pad_power_rails() -> None:
|
||||
pdn = (FLOW_ROOT / "pdn_cfg.tcl").read_text(encoding="utf-8")
|
||||
|
||||
@@ -187,6 +235,13 @@ def test_pdn_connects_all_ihp_pad_power_rails() -> None:
|
||||
assert "odb::dbITerm_connect $iterm $net" in pdn
|
||||
assert "set stdcell_grid_args [list]" in pdn
|
||||
assert '-pins "$::env(PDN_VERTICAL_LAYER) $::env(PDN_HORIZONTAL_LAYER)"' in pdn
|
||||
assert "odb::dbTechLayer_setDirection" not in pdn
|
||||
assert "Metal4 HORIZONTAL" not in pdn
|
||||
assert '-layers "Metal2 Metal3"' in pdn
|
||||
assert "-extend_to_core_ring" in pdn
|
||||
assert "-connect_to_pad_layers TopMetal2" in pdn
|
||||
assert '-layers "Metal3 Metal4"' in pdn
|
||||
assert "-layer Metal4" in pdn
|
||||
assert "-net $::env(VDD_NET) -inst_pattern .* -pin_pattern vdd -power" in pdn
|
||||
assert "-net $::env(GND_NET) -inst_pattern .* -pin_pattern vss -ground" in pdn
|
||||
assert "-net IOVDD -inst_pattern .* -pin_pattern iovdd -power" in pdn
|
||||
|
||||
Reference in new issue
Block a user