mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
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:
23 files changed
+391
-232
No files matched your search
@@ -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) \
|
||||
|
||||
@@ -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>`.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
|
||||
syn:
|
||||
@mkdir -p .syn_build
|
||||
@echo "hello"
|
||||
|
||||
clean:
|
||||
rm -rf .syn_build
|
||||
@@ -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}" ')
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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*"
|
||||
|
||||
|
||||
@@ -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) -- \
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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, ...] = ()
|
||||
|
||||
Executable
+63
@@ -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())
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
Reference in new issue
Block a user