refactor: refactor Yosys synthesis flow to support multiple recipes

- Introduced SYNTH_RECIPE variable to select between balanced, area, and speed synthesis recipes.
- Updated Makefile to handle new SYNTH_RECIPE variable and its validation.
- Modified synthesis scripts to utilize the selected recipe, ensuring outputs are directed to the appropriate directories.
- Enhanced documentation to reflect changes in synthesis flow and directory structure.
- Added tests to verify correct behavior of new synthesis recipes and their integration into the regression suite.
- Removed obsolete scripts and configurations related to previous synthesis methods.
This commit is contained in:
maksyuki committed 2026-08-17 08:54:57 +08:00
1 parent 4b8bf938cd
commit 662488d385
23 files changed
+391 -232

No files matched your search

+15 -6
View File
@@ -28,10 +28,11 @@ ifneq ($(origin HAVE_DEBUG),undefined)
$(error HAVE_DEBUG has been removed; the Hazard3 Debug Module is always enabled)
endif
SOC ?= MINI
SIMU ?= VCS
SYNTH ?= NONE
STA ?= NONE
SOC ?= MINI
SIMU ?= VCS
SYNTH ?= NONE
SYNTH_RECIPE ?= balanced
STA ?= NONE
# HW
PDK ?= IHP130
@@ -101,7 +102,11 @@ VARIANT_ROOT := $(abspath $(BUILD_ROOT))/$(VARIANT_ID)
SW_BUILD_DIR := $(VARIANT_ROOT)/sw
SIM_TOOL_NAME := $(shell printf '%s' '$(SIMU)' | tr '[:upper:]' '[:lower:]')
SIM_BUILD_ROOT := $(VARIANT_ROOT)/sim/$(SIM_TOOL_NAME)
ifeq ($(SYNTH_RECIPE),balanced)
SYN_BUILD_ROOT := $(VARIANT_ROOT)/syn/yosys
else
SYN_BUILD_ROOT := $(VARIANT_ROOT)/syn/yosys-$(SYNTH_RECIPE)
endif
STA_BUILD_ROOT := $(VARIANT_ROOT)/sta/opensta
META_DIR := $(VARIANT_ROOT)/meta
ifeq ($(SYNTH),YOSYS)
@@ -113,6 +118,7 @@ endif
VALID_SOC := MINI
VALID_SIMU := VCS VERILATOR IVERILOG
VALID_SYNTH := NONE YOSYS
VALID_SYNTH_RECIPE := balanced area speed
VALID_STA := NONE OPENSTA
VALID_PDK := ICS55 IHP130 SKY130 GF180
VALID_BOOL := YES NO
@@ -128,6 +134,7 @@ endef
$(call validate_value,SOC,$(VALID_SOC))
$(call validate_value,SIMU,$(VALID_SIMU))
$(call validate_value,SYNTH,$(VALID_SYNTH))
$(call validate_value,SYNTH_RECIPE,$(VALID_SYNTH_RECIPE))
$(call validate_value,STA,$(VALID_STA))
$(call validate_value,PDK,$(VALID_PDK))
$(call validate_value,HAVE_PLL,$(VALID_BOOL))
@@ -326,7 +333,8 @@ config:
BUILD_TIMESTAMP '$(BUILD_TIMESTAMP)' VARIANT_ID '$(VARIANT_ID)' VARIANT_ROOT '$(VARIANT_ROOT)' \
JOBS '$(JOBS)' \
SOC '$(SOC)' MGMT_CORE 'HAZARD3' \
SIMU '$(SIMU)' SYNTH '$(SYNTH)' STA '$(STA)' FORMAL '$(FORMAL)' \
SIMU '$(SIMU)' SYNTH '$(SYNTH)' SYNTH_RECIPE '$(SYNTH_RECIPE)' \
STA '$(STA)' FORMAL '$(FORMAL)' \
VCS_USE_LSF '$(VCS_USE_LSF)' PDK '$(PDK)' \
HAVE_PLL '$(HAVE_PLL)' HAVE_SRAM_IF '$(HAVE_SRAM_IF)' \
HAVE_SRAM_MACRO '$(HAVE_SRAM_MACRO)' PDK_BEHAV '$(PDK_BEHAV)' HAVE_SVA '$(HAVE_SVA)' \
@@ -390,7 +398,8 @@ manifest:
$(FLOW_PYTHON) $(ROOT_PATH)/scripts/manifest.py create --root $(ROOT_PATH) \
--lock $(LOCK_FILE) --output $(META_DIR)/manifest.json --profile $(PROFILE_NAME) \
$(foreach var,$(CONFIG_KEY_VARS),--config $(var)=$($(var))) \
--config SIMU=$(SIMU) --config SYNTH=$(SYNTH) --config STA=$(STA)
--config SIMU=$(SIMU) --config SYNTH=$(SYNTH) --config SYNTH_RECIPE=$(SYNTH_RECIPE) \
--config STA=$(STA)
check-warnings:
python3 $(ROOT_PATH)/scripts/analyze_warnings.py check --root $(ROOT_PATH) \
+7
View File
@@ -121,12 +121,19 @@ build/<variant>/
sim/<simulator>/
formal/<proof>/
syn/yosys/
syn/yosys-area/ (optional SYNTH_RECIPE=area)
syn/yosys-speed/ (optional SYNTH_RECIPE=speed)
sta/opensta/
meta/manifest.json
meta/warnings.json
meta/metrics.json
```
The default Yosys recipe writes `syn/yosys/`. Optional `SYNTH_RECIPE=area` and
`SYNTH_RECIPE=speed` jobs write sibling directories; STA, netlist simulation, warning analysis,
and metrics read only `syn/yosys/`. `SYNTH_RECIPE` is a flow selector and does not change the
configuration hash.
Generated filelists and MPW output are flow-local. Make depfiles track expanded RTL sources and
included headers. The shared MPW generator is protected by a file lock. Default tool parallelism is
capped at 16 and can be set with `JOBS=<n>` or `MAX_JOBS=<n>`.
+2 -2
View File
@@ -1,11 +1,11 @@
OPENSTA ?= sta
OPENSTA_THREADS ?= $(JOBS)
OPENSTA_NETLIST ?= $(SYN_BUILD_ROOT)/out/retrosoc_asic_yosys.v
OPENSTA_NETLIST ?= $(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.v
OPENSTA_REPORT ?= $(STA_BUILD_ROOT)/retrosoc_sta.log
OPENSTA_LOG ?= $(STA_BUILD_ROOT)/opensta.log
OPENSTA_METRICS ?= $(STA_BUILD_ROOT)/timing_metrics.rpt
OPENSTA_CONFIG ?= $(SYN_BUILD_ROOT)/out/retrosoc_asic_yosys.config
OPENSTA_CONFIG ?= $(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.config
OPENSTA_SDC ?= $(STA_BUILD_ROOT)/retrosoc_core.sdc
OPENSTA_SDC_GEN := $(ROOT_PATH)/physical/smoke/sta/opensta/generate_sdc.py
OPENSTA_DOMAIN_MAP := $(ROOT_PATH)/rtl/mini/integration/clock_reset_domains.json
-7
View File
@@ -1,7 +0,0 @@
syn:
@mkdir -p .syn_build
@echo "hello"
clean:
rm -rf .syn_build
+20 -1
View File
@@ -2,7 +2,7 @@
This directory contains Yosys synthesis integration, configuration, and source
export tooling. `yosys/` owns the supported open-source synthesis flow;
`tools/` exports flattened source sets; `demo/` contains examples only.
`tools/` exports flattened source sets.
Use a committed profile and run the supported flow:
@@ -10,6 +10,25 @@ Use a committed profile and run the supported flow:
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth
```
`SYNTH_RECIPE` selects the ABC mapping recipe without changing the variant hash:
- `balanced` (default) writes `build/<variant>/syn/yosys/`
- `area` writes `build/<variant>/syn/yosys-area/`
- `speed` writes `build/<variant>/syn/yosys-speed/`
STA, netlist simulation, warning analysis, and metrics consume the default
`syn/yosys/` slot. Nightly IHP130 regression also runs the `area` and `speed`
recipes as synth-only extra jobs.
```sh
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS SYNTH_RECIPE=area synth
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS SYNTH_RECIPE=speed synth
```
The default ABC target period is derived from the `external` STA period in
`rtl/mini/integration/clock_reset_domains.json`. Override it with
`YOSYS_TARGET_PERIOD_PS=<ps>` when needed.
Synthesis outputs are generated below `build/` and must not be committed.
Review warning and metric changes with `make check-warnings check-metrics` for
the affected profile.
@@ -1,70 +0,0 @@
# Copyright (c) 2022 ETH Zurich and University of Bologna.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
#
# Authors:
# - Philippe Sauter <phsauter@iis.ee.ethz.ch>
#
# Optimization script utilizing 'Lazy Mans Synthesis'
# Requires the library of 6-input records (src/rec6Lib...)
# https://people.eecs.berkeley.edu/~alanmi/publications/2012/iccad12_lms.pdf
print_stats
# strash can fix some yosys-convertion edge-cases, good idea to run first
strash
rec_start3 {REC_AIG}
# main optimization iteration:
alias &opt_iter "&st; &if -y -K 6; &syn2; &if -K 6; &st; &b"
# &if -y -K 6; &syn2; &if -K 6, see LMS paper
# &dc2 AIG rewriting (greedy minimization)
# &b balance structure for depth
# &st structural hashing
# &dc compute structural choices
# &nf select choice and map to tech
# &ps print statistics
# mapping iteration
alias &map_iter "&st; &nf {D}; &ps"
# initial mapping iteration
&get -n
echo "Initial network:"
&ps
echo "High effort delay optimization..."
&opt_iter; &opt_iter; &ps;
&opt_iter; &opt_iter; &ps;
&opt_iter; &opt_iter; &ps;
&opt_iter; &opt_iter; &ps;
&put
# according to https://people.eecs.berkeley.edu/~alanmi/abc/
# it can take up to 10-ish iterations for convergence
# in my experience it seems to get 99% there after 5-6 with a lower runtime
&get -n
echo "Opt+mapping Iterations..."
&opt_iter; &map_iter;
&opt_iter; &map_iter;
&opt_iter; &map_iter;
&opt_iter; &map_iter;
&opt_iter; &map_iter;
&opt_iter; &map_iter;
&opt_iter; &map_iter;
&opt_iter; &map_iter;
&put
topo
stime
echo "buffering for delay and fanout..."
buffer -p
echo "resizing cells..."
upsize {D}
dnsize {D}
upsize {D}
dnsize {D}
echo "Final timing:"
stime
@@ -1,10 +0,0 @@
# Copyright (c) 2024 ETH Zurich and University of Bologna.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
#
# Authors:
# - Philippe Sauter <phsauter@iis.ee.ethz.ch>
# set_driving_cell sg13g2_buf_1
set_driving_cell LVT_BUFHDV12
set_load 0.015
@@ -0,0 +1,27 @@
# Copyright (c) 2022 ETH Zurich and University of Bologna.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
#
# -- Adaptable modifications are redistributed under compatible License --
#
# Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
# retroSoC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# Area ABC recipe adapted from OpenROAD-flow-scripts flow/scripts/abc_area.script.
# Source: The-OpenROAD-Project/OpenROAD-flow-scripts, BSD-3-Clause.
strash
dch
map -B 0.9
topo
stime -c
buffer -c
upsize -c
dnsize -c
@@ -0,0 +1,35 @@
# Copyright (c) 2022 ETH Zurich and University of Bologna.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
#
# -- Adaptable modifications are redistributed under compatible License --
#
# Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
# retroSoC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# Balanced ABC recipe adapted from Yosys ABC_COMMAND_CTR (liberty + constr).
# Source: YosysHQ/yosys passes/techmap/abc.cc, ISC license.
strash
&get -n
&fraig -x
&put
scorr
dc2
dretime
strash
&get -n
&dch -f
&nf {D}
&put
buffer
upsize {D}
dnsize {D}
stime -p
@@ -0,0 +1,55 @@
# Copyright (c) 2022 ETH Zurich and University of Bologna.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
#
# -- Adaptable modifications are redistributed under compatible License --
#
# Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
# retroSoC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# Speed ABC recipe adapted from OpenROAD-flow-scripts flow/scripts/abc_speed.script.
# Source: The-OpenROAD-Project/OpenROAD-flow-scripts, BSD-3-Clause.
# Every &nf mapping step receives the shared {D} period constraint.
&get -n
&st
&dch
&nf {D}
&st
&syn2
&if -g -K 6
&synch2
&nf {D}
&st
&syn2
&if -g -K 6
&synch2
&nf {D}
&st
&syn2
&if -g -K 6
&synch2
&nf {D}
&st
&syn2
&if -g -K 6
&synch2
&nf {D}
&st
&syn2
&if -g -K 6
&synch2
&nf {D}
&put
buffer -c
topo
stime -c
upsize -c
dnsize -c
@@ -1,68 +0,0 @@
#!/bin/python
import re
dff_dont_use_list = [
'.*ED.*',
'.*SD.*',
'.*SED.* ',
'.*SND.*',
'.*DX.*',
'.*D.*RSN.*',
'.*LA.*RSN.*',
'.*LAH.*',
'.*LAL.*',
'.*ND.*RSN.*',
]
comp_dont_use_list = [
'.*DEL.*',
'.*AO222.*',
'.*AO33.*',
'.*AOI222.*',
'.*AOI33.*',
'.*OA222.*',
'.*OAI222.*',
'.*OA33.*',
'.*OAI33.*',
'.*CLK.*',
'.*CK.*',
'.*NOR4.*',
'.*V0.* ',
'.*V24.* ',
'.*V20.* ',
'.*222.* ',
'.*33.* ',
'.*32.* ',
'.*FDCAP.*',
'.*PULL.*',
'.*TBUF.*',
'.*F_DIO.*',
'.*IAO22.*',
'LVT_MUX4HDV1',
]
res_dff_dont_use = []
res_comp_dont_use = []
with open('../../S110/scc011ums_hd_lvt_tt_v1p2_25c_basic.lib',
'r',
encoding='utf-8') as fp:
for line in fp:
for cell in dff_dont_use_list:
val = re.match(r'.*cell\((' + cell + ')\)', line)
if val:
res_dff_dont_use.append(val.group(1))
for cell in comp_dont_use_list:
val = re.match(r'.*cell\((' + cell + ')\)', line)
if val:
res_comp_dont_use.append(val.group(1))
with open('dont_use_cell_dff', 'w', encoding='utf-8') as fp:
for v in res_dff_dont_use:
fp.write(f'"{v}" ')
with open('dont_use_cell_comb', 'w', encoding='utf-8') as fp:
for v in res_comp_dont_use:
fp.write(f'"{v}" ')
+3 -4
View File
@@ -16,6 +16,7 @@ set variables {
top_design { TOP_DESIGN "" }
hier_depth { HIER_DEPTH 0 }
period_ps { YOSYS_TARGET_PERIOD_PS 5000 }
synth_recipe { SYNTH_RECIPE "balanced" }
proj_name { PROJ_NAME "" }
build_dir { BUILD "[set dir [pwd]]/out" }
work_dir { WORK "[set dir [pwd]]/WORK" }
@@ -57,14 +58,12 @@ proc envVarValid {var_name} {
proc processAbcScript {abc_script} {
global work_dir period_ps
set src_dir [file join [file dirname [info script]] ../src]
set abc_out_path $work_dir/[file tail $abc_script]
set raw [read -nonewline [open $abc_script r]]
set abc_script_delay [string map -nocase [list "{D}" [subst "-D $period_ps"]] $raw]
set abc_script_recaig [string map -nocase [list "{REC_AIG}" [subst "$src_dir/rec6Lib_final_filtered3_recanon_basilisk.aig"]] $abc_script_delay]
set mapped [string map -nocase [list "{D}" [subst "-D $period_ps"]] $raw]
set abc_out [open $abc_out_path w]
puts -nonewline $abc_out $abc_script_recaig
puts -nonewline $abc_out $mapped
flush $abc_out
close $abc_out
@@ -1,39 +0,0 @@
BEGIN {
IGNORECASE=1
capture = 0
RED = "\033[31m"
YELLOW = "\033[33m"
RESET = "\033[0m"
}
/Executing SLANG frontend/ {
# Start capturing when we find "Executing SLANG frontend"
capture = 1
gsub(/\<Warning[s]*\>/, YELLOW "Warning" RESET)
gsub(/\<Error[s]*\>/, RED "Error" RESET)
print
next
}
capture {
gsub(/\<Warning[s]*\>/, YELLOW "Warning" RESET)
gsub(/\<Error[s]*\>/, RED "Error" RESET)
print
if ($0 ~ /Executing/ && $0 !~ /SLANG frontend/) {
capture = 0
}
}
/Executing/ {
if ($0 ~ /[0-9\.]+ Executing/) {
gsub(/\<Warning[s]*\>/, YELLOW "Warning" RESET)
gsub(/\<Error[s]*\>/, RED "Error" RESET)
print
}
}
/\<Warning[s]*\>|\<Error[s]*\>/ {
gsub(/\<Warning\>/, YELLOW "Warning" RESET)
gsub(/\<Error\>/, RED "Error" RESET)
print
}
@@ -33,6 +33,8 @@ if {$pdk == "IHP130"} {
# for hilomap
set tech_cell_tiehi {sg13g2_tiehi L_HI}
set tech_cell_tielo {sg13g2_tielo L_LO}
set abc_driver sg13g2_buf_4
set abc_load 6.0
} elseif {$pdk == "ICS55"} {
set pdk_dir "$root_dir/physical/pdk/icsprout55-pdk"
set pdk_cells_lib "$root_dir/.cache/retrosoc/pdk/ics55"
@@ -42,6 +44,8 @@ if {$pdk == "IHP130"} {
# for hilomap
set tech_cell_tiehi {TIEHIH7R Z}
set tech_cell_tielo {TIELOH7R Z}
set abc_driver BUFX4H7R
set abc_load 6.0
} elseif {$pdk == "GF180"} {
set pdk_cells_lib "$root_dir/.cache/retrosoc/pdk/gf180"
set tech_cells [list "$pdk_cells_lib/gf180mcu_fd_sc_mcu7t5v0__tt_025C_5v00.lib"]
@@ -50,12 +54,16 @@ if {$pdk == "IHP130"} {
# Keep constants as logic instead of mapping them to an uncharacterized cell.
set tech_cell_tiehi {}
set tech_cell_tielo {}
set abc_driver gf180mcu_fd_sc_mcu7t5v0__buf_4
set abc_load 13.43
} elseif {$pdk == "SKY130"} {
set pdk_cells_lib "$root_dir/.cache/retrosoc/pdk/sky130"
set tech_cells [list "$pdk_cells_lib/sky130_fd_sc_hd__tt_025C_1v80.lib"]
set tech_macros [list]
set tech_cell_tiehi {sky130_fd_sc_hd__conb_1 HI}
set tech_cell_tielo {sky130_fd_sc_hd__conb_1 LO}
set abc_driver sky130_fd_sc_hd__buf_1
set abc_load 5
} else {
error "unsupported PDK for Yosys: $pdk"
}
+16 -17
View File
@@ -21,15 +21,6 @@
set script_dir [file dirname [info script]]
source $script_dir/common.tcl
# constraints file
set abc_constr $script_dir/abc.constr
# ABC script without DFF optimizations
set abc_combinational_script $script_dir/abc-opt.script
# process abc file (written to WORK directory)
set abc_comb_script [processAbcScript $abc_combinational_script]
# read liberty files and prepare some variables
source $script_dir/init_tech.tcl
@@ -141,15 +132,21 @@ yosys tee -q -o "${report_dir}/${proj_name}_pre_tech.json" stat -json -tech cmos
# -----------------------------------------------------------------------------
# mapping to technology
puts "Using combinational-only abc optimizations"
if {$pdk == "S110"} {
yosys dfflibmap {*}$dff_cells_dont_use_args {*}$tech_cells_args
# yosys abc {*}$tech_cells_args -D $period_ps -script $abc_comb_script -constr $abc_constr -showtmp
yosys abc {*}$comb_cells_dont_use_args {*}$tech_cells_args
} else {
yosys dfflibmap {*}$tech_cells_args
yosys abc {*}$tech_cells_args
set abc_script_src $script_dir/abc_${synth_recipe}.script
if {![file exists $abc_script_src]} {
error "unsupported SYNTH_RECIPE: $synth_recipe"
}
set abc_script [processAbcScript $abc_script_src]
set abc_constr $work_dir/abc.constr
set constr_file [open $abc_constr w]
puts $constr_file "set_driving_cell $abc_driver"
puts $constr_file "set_load $abc_load"
close $constr_file
puts "Using SYNTH_RECIPE=$synth_recipe ABC script $abc_script_src (period_ps=$period_ps)"
yosys dfflibmap {*}$tech_cells_args
yosys abc {*}$tech_cells_args -D $period_ps -script $abc_script -constr $abc_constr
yosys clean -purge
@@ -182,5 +179,7 @@ set config_file [open $config_tmp "w"]
puts $config_file "PDK=$pdk"
puts $config_file "SOC=$soc"
puts $config_file "TOP_DESIGN=$top_design"
puts $config_file "SYNTH_RECIPE=$synth_recipe"
puts $config_file "PERIOD_PS=$period_ps"
close $config_file
file rename -force $config_tmp $config
-3
View File
@@ -5,9 +5,6 @@
# Authors:
# - Philippe Sauter <phsauter@iis.ee.ethz.ch>
# target clock-period in pico-seconds
export YOSYS_TARGET_PERIOD_PS := 10000
# modules Yosys will treat as blackboxes
export YOSYS_BLACKBOX_MODULES := "*tc_sram_blackbox*"
+10 -1
View File
@@ -27,6 +27,14 @@ YOSYS_RPT := $(YOSYS_BUILD)/rpt
include $(YOSYS_DIR)/synth_config.mk
ifeq ($(origin YOSYS_TARGET_PERIOD_PS),undefined)
YOSYS_TARGET_PERIOD_PS := $(shell python3 $(ROOT_PATH)/scripts/yosys_period.py \
--domains $(ROOT_PATH)/rtl/mini/integration/clock_reset_domains.json)
ifeq ($(strip $(YOSYS_TARGET_PERIOD_PS)),)
$(error Failed to derive YOSYS_TARGET_PERIOD_PS from the clock/reset inventory)
endif
endif
TOP_DESIGN ?= retrosoc_asic
RTL_NAME ?= retrosoc_asic
SV_FLIST := $(GENERATED_FL_DIR)/yosys.fl
@@ -55,7 +63,8 @@ $(NETLIST): $(SV_FLIST) $(YOSYS_SCRIPTS)
@mkdir -p $(YOSYS_RPT)
python3 $(ROOT_PATH)/scripts/run_flow.py --tool yosys \
--log $(YOSYS_BUILD)/$(RTL_NAME).log --result $(YOSYS_BUILD)/result-synth.json \
--env PDK=$(PDK) --env SOC=$(SOC) \
--env PDK=$(PDK) --env SOC=$(SOC) --env SYNTH_RECIPE=$(SYNTH_RECIPE) \
--env YOSYS_TARGET_PERIOD_PS=$(YOSYS_TARGET_PERIOD_PS) \
--env SV_FLIST=$(SV_FLIST) --env TOP_DESIGN=$(TOP_DESIGN) --env CONFIG=$(NETLIST_CONFIG) \
--env PROJ_NAME=$(RTL_NAME) --env WORK=$(YOSYS_TMP) --env BUILD=$(YOSYS_OUT) \
--env REPORTS=$(YOSYS_RPT) --env NETLIST=$(NETLIST) -- \
+1 -1
View File
@@ -2,7 +2,7 @@ IVERILOG ?= iverilog
VVP ?= vvp
GTKWAVE ?= gtkwave
NETLIST_PATH ?= $(SYN_BUILD_ROOT)/out/retrosoc_asic_yosys.v
NETLIST_PATH ?= $(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.v
POST_PATH ?= $(ROOT_PATH)/physical/sdf/retrosoc_asic.v
SDF_PATH ?= $(ROOT_PATH)/physical/sdf/retrosoc_asic_CTS_MIN.sdf.gz
SDF_SCOPE ?= $(RTL_TOP).u_retrosoc_asic
+3 -3
View File
@@ -10,7 +10,7 @@ VCS_FLOW_PYTHON := $(strip $(VCS_RUNNER) $(PYTHON))
COMP_LOG := -l compile.log
SIM_LOG := -l sim.log
# netlist file path
NETLIST_PATH := -v $(SYN_BUILD_ROOT)/out/retrosoc_asic_yosys.v
NETLIST_PATH := -v $(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.v
POST_PATH := -v $(ROOT_PATH)/physical/sdf/retrosoc_asic.v
SDF_PATH := "$(ROOT_PATH)/physical/sdf/retrosoc_asic_CTS_MIN.sdf.gz"
# testbench filelist
@@ -69,7 +69,7 @@ $(VCS_NETL_SIMV): DIR := $(VCS_NETL_DIR)
$(VCS_NETL_SIMV): FLIST := $(NETLIST_PATH) $(NET_FLIST) $(TB_FLIST)
$(VCS_NETL_SIMV): OPTS := $(TIME_OPTION)
$(VCS_NETL_SIMV): DEPFILE := $(VCS_NETL_DEPFILE)
$(VCS_NETL_SIMV): DEPS_ARGS := $(NET_FLIST) -f $(GENERATED_FL_DIR)/tb.fl --extra $(SYN_BUILD_ROOT)/out/retrosoc_asic_yosys.v
$(VCS_NETL_SIMV): DEPS_ARGS := $(NET_FLIST) -f $(GENERATED_FL_DIR)/tb.fl --extra $(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.v
$(VCS_POST_SIMV): DIR := $(VCS_POST_DIR)
$(VCS_POST_SIMV): FLIST := $(POST_PATH) $(NET_FLIST) $(TB_FLIST)
@@ -101,7 +101,7 @@ $(VCS_BEHV_SIMV) $(VCS_NETL_SIMV) $(VCS_POST_SIMV): $(MPW_VARIANT_STAMP) $(FILEL
$(SIM_TOOL) $(COMMON_OPTS) $(OPTS) $(FLIST) -top $(RTL_TOP) $(COMP_LOG)
$(FLOW_PYTHON) $(RTL_PATH)/script/filelist_deps.py $(DEPS_ARGS) --target $@ --output $(DEPFILE)
$(VCS_NETL_SIMV): $(SYN_BUILD_ROOT)/out/retrosoc_asic_yosys.v
$(VCS_NETL_SIMV): $(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.v
$(VCS_POST_SIMV): $(ROOT_PATH)/physical/sdf/retrosoc_asic.v $(ROOT_PATH)/physical/sdf/retrosoc_asic_CTS_MIN.sdf.gz
sim netsim postsim:
+2
View File
@@ -65,6 +65,8 @@ NIGHTLY_COMMANDS = (
"configs/benchmark/ihp130-hazard3-coremark.mk",
("SIMU=VERILATOR", "HAVE_SVA=YES", "coremark-report"),
),
("configs/ci/ihp130.mk", ("SYNTH=YOSYS", "SYNTH_RECIPE=area", "synth")),
("configs/ci/ihp130.mk", ("SYNTH=YOSYS", "SYNTH_RECIPE=speed", "synth")),
)
PR_PROFILES = ("configs/ci/ihp130.mk",)
SMOKE_PROFILES: tuple[str, ...] = ()
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
"""Derive the Yosys ABC target period from the SoC clock/reset inventory."""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from typing import Any
def require_object(value: Any, field: str) -> dict[str, Any]:
if not isinstance(value, dict):
raise ValueError(f"{field} must be an object")
return value
def require_string(value: Any, field: str) -> str:
if not isinstance(value, str) or not value:
raise ValueError(f"{field} must be a non-empty string")
return value
def period_ps(document: dict[str, Any], domain: str = "external") -> int:
require_string(domain, "domain")
domains = document.get("domains")
if not isinstance(domains, list) or not domains:
raise ValueError("domains must be a non-empty list")
for entry in domains:
item = require_object(entry, "domains entry")
if item.get("name") != domain:
continue
sta = require_object(item.get("sta"), f"domain {domain}.sta")
period_ns = sta.get("period_ns")
if not isinstance(period_ns, (int, float)) or isinstance(period_ns, bool) or period_ns <= 0:
raise ValueError(f"domain {domain}.sta.period_ns must be a positive number")
return round(float(period_ns) * 1000)
raise ValueError(f"domain {domain} is not declared")
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--domains", type=Path, required=True)
parser.add_argument("--domain", default="external")
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
try:
document = require_object(
json.loads(args.domains.read_text(encoding="utf-8")), "domain map"
)
print(period_ps(document, args.domain))
except (OSError, ValueError, json.JSONDecodeError) as error:
print(error, file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
+50
View File
@@ -858,10 +858,60 @@ def test_pdk_pr_regressions_cover_firmware_rtl_and_netlist() -> None:
)
assert any("SIMU=IVERILOG" in values and "sim-asm" in values for values in command_values)
assert any("SYNTH=YOSYS" in values and "synth" in values for values in command_values)
assert not any(
any(value.startswith("SYNTH_RECIPE=") for value in values) for values in command_values
)
assert ("STA=OPENSTA", "sta") in command_values
assert any("SIMU=IVERILOG" in values and "netsim" in values for values in command_values)
def test_nightly_regression_runs_optional_yosys_recipes() -> None:
commands, profiles = select_regression("nightly", "IHP130")
assert commands == NIGHTLY_COMMANDS
assert profiles == ("configs/ci/ihp130.mk",)
assert (
"configs/ci/ihp130.mk",
("SYNTH=YOSYS", "SYNTH_RECIPE=area", "synth"),
) in NIGHTLY_COMMANDS
assert (
"configs/ci/ihp130.mk",
("SYNTH=YOSYS", "SYNTH_RECIPE=speed", "synth"),
) in NIGHTLY_COMMANDS
assert not any(
any(value.startswith("SYNTH_RECIPE=") for value in values) for _, values in PR_COMMANDS
)
nightly = run(
sys.executable,
str(ROOT / "scripts/regress.py"),
"--root",
str(ROOT),
"--suite",
"nightly",
"--pdk",
"IHP130",
"--dry-run",
)
assert "+ make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS SYNTH_RECIPE=area synth" in nightly.stdout
assert "+ make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS SYNTH_RECIPE=speed synth" in nightly.stdout
pr = run(
sys.executable,
str(ROOT / "scripts/regress.py"),
"--root",
str(ROOT),
"--suite",
"pr",
"--pdk",
"IHP130",
"--dry-run",
)
assert "+ make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth" in pr.stdout
assert "SYNTH_RECIPE=area" not in pr.stdout
assert "SYNTH_RECIPE=speed" not in pr.stdout
def test_regression_observations_do_not_block_or_skip_metrics(
monkeypatch, tmp_path: Path, capsys
) -> None:
+74
View File
@@ -0,0 +1,74 @@
"""Tests for Yosys recipe selection and ABC period derivation."""
from __future__ import annotations
import subprocess
import sys
from pathlib import Path
from scripts.yosys_period import period_ps
ROOT = Path(__file__).resolve().parents[1]
DOMAINS = ROOT / "rtl/mini/integration/clock_reset_domains.json"
PERIOD_HELPER = ROOT / "scripts/yosys_period.py"
YOSYS_SCRIPTS = ROOT / "physical/smoke/syn/yosys/script"
def run_period(*args: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, str(PERIOD_HELPER), *args],
text=True,
capture_output=True,
)
def test_yosys_period_rounds_external_sta_period() -> None:
assert period_ps({"domains": [{"name": "external", "sta": {"period_ns": 13.888888889}}]}) == 13889
result = run_period("--domains", str(DOMAINS))
assert result.returncode == 0, result.stderr
assert result.stdout.strip() == "13889"
def test_yosys_period_rejects_unknown_domain() -> None:
result = run_period("--domains", str(DOMAINS), "--domain", "missing")
assert result.returncode != 0
assert "domain missing is not declared" in result.stderr
def test_yosys_recipe_scripts_and_public_slot_are_stable() -> None:
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
yosys_mk = (ROOT / "physical/smoke/syn/yosys/yosys.mk").read_text(encoding="utf-8")
synth_tcl = (YOSYS_SCRIPTS / "synth.tcl").read_text(encoding="utf-8")
opensta = (ROOT / "physical/smoke/sta/opensta/opensta.mk").read_text(encoding="utf-8")
iverilog = (ROOT / "rtl/mini/mk/iverilog.mk").read_text(encoding="utf-8")
vcs = (ROOT / "rtl/mini/mk/vcs.mk").read_text(encoding="utf-8")
assert "SYNTH_RECIPE ?= balanced" in makefile
assert "VALID_SYNTH_RECIPE := balanced area speed" in makefile
assert "syn/yosys-$(SYNTH_RECIPE)" in makefile
assert "CONFIG_KEY_VARS" in makefile
assert "SYNTH_RECIPE" not in makefile.split("CONFIG_KEY_VARS", 1)[1].split("VARIANT_ID", 1)[0]
assert "--env SYNTH_RECIPE=$(SYNTH_RECIPE)" in yosys_mk
assert "--env YOSYS_TARGET_PERIOD_PS=$(YOSYS_TARGET_PERIOD_PS)" in yosys_mk
assert "abc_${synth_recipe}.script" in synth_tcl
assert "yosys abc {*}$tech_cells_args -D $period_ps -script $abc_script -constr $abc_constr" in synth_tcl
assert "S110" not in synth_tcl
assert "$(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.v" in opensta
assert "$(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.v" in iverilog
assert "$(VARIANT_ROOT)/syn/yosys/out/retrosoc_asic_yosys.v" in vcs
assert "SYN_BUILD_ROOT" not in opensta
assert "SYN_BUILD_ROOT" not in iverilog.split("NETLIST_PATH", 1)[1][:200]
assert (YOSYS_SCRIPTS / "abc_balanced.script").read_text(encoding="utf-8").count("&nf {D}") == 1
assert "&nf {D}" not in (YOSYS_SCRIPTS / "abc_area.script").read_text(encoding="utf-8")
assert (YOSYS_SCRIPTS / "abc_speed.script").read_text(encoding="utf-8").count("&nf {D}") == 6
leftover = {
"abc-opt.script",
"abc.constr",
"cell_dont_use.py",
"filter_output.awk",
}
assert leftover.isdisjoint({path.name for path in YOSYS_SCRIPTS.iterdir()})
assert not (ROOT / "physical/smoke/syn/dc").exists()
assert not (ROOT / "physical/smoke/syn/Makefile").exists()