f4pga: yosys TCL wrappers moved from f4pga-arch-defs

Signed-off-by: Unai Martinez-Corral <umartinezcorral@antmicro.com>
This commit is contained in:
Unai Martinez-Corral 2022-08-06 00:23:59 +02:00
parent 0d451747ad
commit c1c612b575
16 changed files with 650 additions and 13 deletions

View File

@ -75,6 +75,8 @@ install_dir = environ.get("F4PGA_INSTALL_DIR", "/usr/local")
ROOT = Path(__file__).resolve().parent
FPGA_FAM = environ.get('FPGA_FAM', 'xc7')
if FPGA_FAM not in ['xc7', 'eos-s3', 'qlf_k4n8']:
raise(Exception(f"Unsupported FPGA_FAM <{FPGA_FAM}>!"))
bin_dir_path = str(Path(sys_argv[0]).resolve().parent.parent)
share_dir_path = \

View File

@ -22,6 +22,7 @@ from pathlib import Path
from f4pga.common import decompose_depname, get_verbosity_level, sub as common_sub
from f4pga.module import Module, ModuleContext
from f4pga.wrappers.tcl import get_script_path as get_tcl_wrapper_path
def yosys_setup_tcl_env(tcl_env_def):
@ -100,16 +101,19 @@ class SynthModule(Module):
tcl_env = yosys_setup_tcl_env(ctx.values.yosys_tcl_env) \
if ctx.values.yosys_tcl_env else {}
split_inouts = Path(tcl_env["UTILS_PATH"]) / 'split_inouts.py'
synth_tcl = Path(ctx.values.tcl_scripts) / 'synth.tcl'
conv_tcl = Path(ctx.values.tcl_scripts) / 'conv.tcl'
if get_verbosity_level() >= 2:
yield f'Synthesizing sources: {ctx.takes.sources}...'
else:
yield f'Synthesizing sources...'
yosys_synth(str(synth_tcl), tcl_env, ctx.takes.sources,
ctx.values.read_verilog_args, ctx.outputs.synth_log)
yosys_synth(
str(get_tcl_wrapper_path('synth')),
tcl_env,
ctx.takes.sources,
ctx.values.read_verilog_args,
ctx.outputs.synth_log
)
yield f'Splitting in/outs...'
common_sub('python3', str(split_inouts), '-i', ctx.outputs.json, '-o',
@ -120,7 +124,11 @@ class SynthModule(Module):
wfptr.write('')
yield f'Converting...'
yosys_conv(str(conv_tcl), tcl_env, ctx.outputs.synth_json)
yosys_conv(
str(get_tcl_wrapper_path('conv')),
tcl_env,
ctx.outputs.synth_json
)
def __init__(self, params):
self.name = 'synthesize'

View File

@ -83,7 +83,8 @@ setuptools_setup(
packages=[
"f4pga",
"f4pga.common_modules",
"f4pga.wrappers.sh"
"f4pga.wrappers.sh",
"f4pga.wrappers.tcl"
],
package_dir={"f4pga": "."},
package_data={
@ -93,6 +94,12 @@ setuptools_setup(
'f4pga.wrappers.sh': [
'xc7/*.f4pga.sh',
'quicklogic/*.f4pga.sh'
],
'f4pga.wrappers.tcl': [
'xc7/*.f4pga.tcl',
'eos-s3/*.f4pga.tcl',
'qlf_k4n8/*.f4pga.tcl',
'ice40/*.f4pga.tcl',
]
},
classifiers=[],

View File

@ -25,6 +25,7 @@ from pathlib import Path
from shutil import which
from subprocess import check_call
from f4pga import FPGA_FAM
python3 = which('python3')
@ -32,9 +33,7 @@ f4pga_environ = environ.copy()
ROOT = Path(__file__).resolve().parent
FPGA_FAM = f4pga_environ.get('FPGA_FAM', 'xc7')
isQuickLogic = FPGA_FAM == 'eos-s3'
isQuickLogic = FPGA_FAM != 'xc7'
SH_SUBDIR = 'quicklogic' if isQuickLogic else FPGA_FAM
F4PGA_INSTALL_DIR = f4pga_environ.get('F4PGA_INSTALL_DIR')
@ -433,6 +432,7 @@ while true; do
done
if [ -z $DEVICE ]; then echo "Please provide device name"; exit 1; fi
if [ -z $FASM ]; then echo "Please provide an input FASM file name"; exit 1; fi
if [ ! -f "$FASM" ]; then echo "File <$FASM> does not exist!"; exit 1; fi
if [ -z $BIT ]; then echo "Please provide an output bistream file name"; exit 1; fi
""" + f"""
if [[ "$DEVICE" =~ ^(qlf_k4n8.*)$ ]]; then

View File

@ -123,8 +123,8 @@ PINMAPCSV="pinmap_${PART}.csv"
export TECHMAP_PATH="${F4PGA_SHARE_DIR}/techmaps/${FAMILY}"
SYNTH_TCL_PATH="${F4PGA_SHARE_DIR}/scripts/${FAMILY}/synth.tcl"
CONV_TCL_PATH="${F4PGA_SHARE_DIR}/scripts/${FAMILY}/conv.tcl"
SYNTH_TCL_PATH="$(python3 -m f4pga.wrappers.tcl synth "${FAMILY}")"
CONV_TCL_PATH="$(python3 -m f4pga.wrappers.tcl conv "${FAMILY}")"
export USE_ROI="FALSE"
export OUT_JSON=$TOP.json

View File

@ -21,7 +21,7 @@ set -e
export TECHMAP_PATH="${F4PGA_SHARE_DIR}"/techmaps/xc7_vpr/techmap
export UTILS_PATH="${F4PGA_SHARE_DIR}"/scripts
SYNTH_TCL_PATH=${UTILS_PATH}/xc7/synth.tcl
SYNTH_TCL_PATH="$(python3 -m f4pga.wrappers.tcl synth)"
VERILOG_FILES=()
XDC_FILES=()
@ -140,4 +140,4 @@ else
fi
python3 ${UTILS_PATH}/split_inouts.py -i ${OUT_JSON} -o ${SYNTH_JSON}
yosys -p "read_json $SYNTH_JSON; tcl ${UTILS_PATH}/xc7/conv.tcl"
yosys -p "read_json $SYNTH_JSON; tcl $(python3 -m f4pga.wrappers.tcl conv)"

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2022 F4PGA Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
# TCL scripts moved from f4pga-arch-defs
from pathlib import Path
from f4pga import FPGA_FAM
ROOT = Path(__file__).resolve().parent
ARCHS = {
'xc7': [
'artix7',
'artix7_100t',
'artix7_200t',
'zynq7',
'zynq7_z020',
'spartan7'
],
'eos-s3': [
'ql-s3',
'pp3'
]
}
def get_script_path(arg, arch = None):
if arch is None:
arch = FPGA_FAM
for key, val in ARCHS.items():
if arch in val:
arch = key
break
if arch not in [
'xc7',
'eos-s3',
'qlf_k4n8',
'ice40'
]:
raise(Exception(f"Unsupported arch <{arch}>!"))
if arg not in ['synth', 'conv']:
raise Exception(f'Unknown tcl wrapper <{arg}>!')
return ROOT / arch / f'{arg}.f4pga.tcl'

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2022 F4PGA Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
from sys import argv as sys_argv
from f4pga.wrappers.tcl import get_script_path
if __name__ == '__main__':
print(get_script_path(sys_argv[1], sys_argv[2]) if len(sys_argv)>2 else get_script_path(sys_argv[1]))

View File

@ -0,0 +1,11 @@
yosys -import
# Clean
opt_clean
# Write EBLIF
write_blif -attr -cname -param \
-true VCC VCC \
-false GND GND \
-undef VCC VCC \
$::env(OUT_EBLIF)

View File

@ -0,0 +1,183 @@
yosys -import
plugin -i ql-iob
plugin -i ql-qlf
yosys -import
# Read VPR cells library
read_verilog -lib -specify $::env(TECHMAP_PATH)/cells_sim.v
# Read device specific cells library
read_verilog -lib -specify $::env(DEVICE_CELLS_SIM)
# Synthesize
synth_quicklogic -family pp3
# Optimize the netlist by adaptively splitting cells that fit into C_FRAG into
# smaller that can fit into F_FRAG.
proc max {a b} {
if {$a > $b} {
return $a
} else {
return $b
}
}
proc min {a b} {
if {$a < $b} {
return $a
} else {
return $b
}
}
# Returns the required number of C_FRAGs to fit the design
proc get_used_c_frag {} {
set used_c_frag [get_count -cells t:mux8x0 t:LUT4 t:logic_cell_macro]
set used_t_frag [get_count -cells t:mux4x0 t:LUT2 t:LUT3]
set used_c_frag_for_t_frag [expr int(ceil($used_t_frag / 2.0))]
return [expr $used_c_frag + $used_c_frag_for_t_frag]
}
# Returns the required number of F_FRAGs to fit the design
proc get_used_f_frag {} {
return [get_count -cells t:inv t:mux2x0 t:LUT1 t:logic_cell_macro]
}
# Load the plugin that allows to retrieve cell count
yosys plugin -i design_introspection
yosys -import
# Maximum number of LOGIC cells in the device
set max_logic 891
# Target number of LOGIC cells. This is less than max to allow the VPR
# packet to have more freedom.
set target_logic [expr int($max_logic * 0.90)]
puts "PACK: Optimizing for target of $target_logic/$max_logic LOGIC cells"
# LUT3 -> mux2x0 (replace)
set used_c_frag [get_used_c_frag]
if {$used_c_frag > $target_logic} {
puts "PACK: Device overfitted $used_c_frag / $target_logic"
# Update
set required_frags [expr 2 * ($used_c_frag - $target_logic)]
set used_f_frag [get_used_f_frag]
set free_f_frag [expr $target_logic - $used_f_frag]
# Try converting LUT3 to mux2x0
if {$free_f_frag > 0} {
puts "PACK: Replacing at most $free_f_frag LUT3 with mux2x0"
set sel_count [min $required_frags $free_f_frag]
yosys techmap -map $::env(TECHMAP_PATH)/lut3tomux2.v t:LUT3 %R$sel_count
}
}
# LUT2 -> mux2x0 (replace)
set used_c_frag [get_used_c_frag]
if {$used_c_frag > $target_logic} {
puts "PACK: Device overfitted $used_c_frag / $target_logic"
# Update
set required_frags [expr 2 * ($used_c_frag - $target_logic)]
set used_f_frag [get_used_f_frag]
set free_f_frag [expr $target_logic - $used_f_frag]
# Try converting LUT2 to mux2x0
if {$free_f_frag > 0} {
puts "PACK: Replacing at most $free_f_frag LUT2 with mux2x0"
set sel_count [min $required_frags $free_f_frag]
yosys techmap -map $::env(TECHMAP_PATH)/lut2tomux2.v t:LUT2 %R$sel_count
}
}
# Split mux4x0
set used_c_frag [get_used_c_frag]
if {$used_c_frag > $target_logic} {
puts "PACK: Device overfitted $used_c_frag / $target_logic"
# Update
set required_frags [expr 2 * ($used_c_frag - $target_logic)]
set used_f_frag [get_used_f_frag]
set free_f_frag [expr $target_logic - $used_f_frag]
# Try converting mux4x0 to 3x mux2x0
if {$free_f_frag >= 3} {
puts "PACK: Splitting at most $free_f_frag mux4x0 to 3x mux2x0"
set sel_count [min $required_frags [expr int(floor($free_f_frag / 3.0))]]
# If there are not enough mux4x0 then map some LUT2 to them (these are
# actually equivalent)
set mux4_count [get_count -cells t:mux4x0]
if {$mux4_count < $sel_count} {
set map_count [expr $sel_count - $mux4_count]
puts "PACK: Replacing at most $map_count LUT2 with mux4x0"
yosys techmap -map $::env(TECHMAP_PATH)/lut2tomux4.v t:LUT2 %R$map_count
}
yosys techmap -map $::env(TECHMAP_PATH)/mux4tomux2.v t:mux4x0 %R$sel_count
}
}
# Split mux8x0
set used_c_frag [get_used_c_frag]
if {$used_c_frag > $target_logic} {
puts "PACK: Device overfitted $used_c_frag / $target_logic"
# Update
set required_frags [expr 2 * ($used_c_frag - $target_logic)]
set used_f_frag [get_used_f_frag]
set free_f_frag [expr $target_logic - $used_f_frag]
# Try converting mux8x0 to 7x mux2x0
if {$free_f_frag >= 7} {
puts "PACK: Splitting at most $free_f_frag mux8x0 to 7x mux2x0"
set sel_count [min $required_frags [expr int(floor($free_f_frag / 7.0))]]
yosys techmap -map $::env(TECHMAP_PATH)/mux8tomux2.v t:mux8x0 %R$sel_count
}
}
# Final check
set used_c_frag [get_used_c_frag]
if {$used_c_frag > $target_logic} {
puts "PACK: Device overfitted $used_c_frag / $target_logic. No more optimization possible!"
}
stat
# Assing parameters to IO cells basing on constraints and package pinmap
if { $::env(PCF_FILE) != "" && $::env(PINMAP_FILE) != ""} {
quicklogic_iob $::env(PCF_FILE) $::env(PINMAP_FILE)
}
# Write a pre-mapped design
write_verilog $::env(OUT_SYNTH_V).premap.v
# Select all logic_0 and logic_1 and apply the techmap to them first. This is
# necessary for constant connection detection in the subsequent techmaps.
select -set consts t:logic_0 t:logic_1
techmap -map $::env(TECHMAP_PATH)/cells_map.v @consts
# Map to the VPR cell library
techmap -map $::env(TECHMAP_PATH)/cells_map.v
# Map to the device specific VPR cell library
techmap -map $::env(DEVICE_CELLS_MAP)
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
stat
# Write output JSON, fixup cell names using an external Python script
write_json $::env(OUT_JSON).org.json
exec $::env(PYTHON3) $::env(UTILS_PATH)/yosys_fixup_cell_names.py $::env(OUT_JSON).org.json $::env(OUT_JSON)
# Read the fixed JSON back and write verilog
design -reset
read_json $::env(OUT_JSON)
write_verilog $::env(OUT_SYNTH_V)

View File

@ -0,0 +1,7 @@
yosys -import
# Clean
opt_clean
# Write EBLIF
write_blif -attr -cname -param $::env(OUT_EBLIF)

View File

@ -0,0 +1,29 @@
yosys -import
proc clean_processes {} {
proc_clean
proc_rmdead
proc_prune
proc_init
proc_arst
proc_mux
proc_dlatch
proc_dff
proc_memwr
proc_clean
}
synth_ice40 -nocarry
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
# TODO: remove this as soon as new VTR master+wip is pushed: https://github.com/SymbiFlow/vtr-verilog-to-routing/pull/525
attrmap -remove hdlname
setundef -zero -params
clean_processes
write_json $::env(OUT_JSON)
write_verilog $::env(OUT_SYNTH_V)

View File

@ -0,0 +1,7 @@
yosys -import
# Clean
opt_clean
# Write EBLIF
write_blif -attr -cname -param $::env(OUT_EBLIF)

View File

@ -0,0 +1,32 @@
yosys -import
# Load the QuickLogic qlf_k4n8 support plugin. Note that this is only temporary
# until support for the device is merged into the upstream Yosys
plugin -i ql-qlf
yosys -import
# Read VPR cells library
read_verilog -lib $::env(TECHMAP_PATH)/cells_sim.v
# Synthesize
if {[info exists ::env(SYNTH_OPTS)]} {
synth_quicklogic -family qlf_k4n8 $::env(SYNTH_OPTS)
} else {
synth_quicklogic -family qlf_k4n8
}
# Write a pre-mapped design
write_verilog $::env(OUT_SYNTH_V).premap.v
# Map to the VPR cell library
techmap -map $::env(TECHMAP_PATH)/cells_map.v
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
stat
write_json $::env(OUT_JSON)
write_verilog $::env(OUT_SYNTH_V)

View File

@ -0,0 +1,20 @@
yosys -import
# Clean
opt_clean
# Designs that directly tie OPAD's to constants cannot use the dedicate
# constant network as an artifact of the way the ROI is configured.
# Until the ROI is removed, enable designs to selectively disable the dedicated
# constant network.
if { [info exists ::env(USE_LUT_CONSTANTS)] } {
write_blif -attr -cname -param \
$::env(OUT_EBLIF)
} else {
write_blif -attr -cname -param \
-true VCC VCC \
-false GND GND \
-undef VCC VCC \
$::env(OUT_EBLIF)
}

View File

@ -0,0 +1,245 @@
yosys -import
plugin -i xdc
plugin -i fasm
plugin -i params
plugin -i sdc
plugin -i design_introspection
# Import the commands from the plugins to the tcl interpreter
yosys -import
# Update the CLKOUT[0-5]_PHASE and CLKOUT[0-5]_DUTY_CYCLE parameter values.
# Due to the fact that Yosys doesn't support floating parameter values
# i.e. treats them as strings, the parameter values need to be multiplied by 1000
# for the PLL registers to have correct values calculated during techmapping.
proc multiply_param { cell param_name multiplier } {
set param_value [getparam $param_name $cell]
if {$param_value ne ""} {
set new_param_value [expr int(round([expr $param_value * $multiplier]))]
setparam -set $param_name $new_param_value $cell
puts "Updated parameter $param_name of cell $cell from $param_value to $new_param_value"
}
}
proc update_pll_and_mmcm_params {} {
foreach cell [selection_to_tcl_list "t:PLLE2_ADV"] {
multiply_param $cell "CLKFBOUT_PHASE" 1000
for {set output 0} {$output < 6} {incr output} {
multiply_param $cell "CLKOUT${output}_PHASE" 1000
multiply_param $cell "CLKOUT${output}_DUTY_CYCLE" 100000
}
}
foreach cell [selection_to_tcl_list "t:MMCME2_ADV"] {
multiply_param $cell "CLKFBOUT_PHASE" 1000
for {set output 0} {$output < 7} {incr output} {
multiply_param $cell "CLKOUT${output}_PHASE" 1000
multiply_param $cell "CLKOUT${output}_DUTY_CYCLE" 100000
}
multiply_param $cell "CLKFBOUT_MULT_F" 1000
multiply_param $cell "CLKOUT0_DIVIDE_F" 1000
}
}
proc clean_processes {} {
proc_clean
proc_rmdead
proc_prune
proc_init
proc_arst
proc_mux
proc_dlatch
proc_dff
proc_memwr
proc_clean
}
# -flatten is used to ensure that the output eblif has only one module.
# Some of symbiflow expects eblifs with only one module.
#
# To solve the carry chain congestion at the output, the synthesis step
# needs to be executed two times.
# abc9 seems to cause troubles if called multiple times in the flow, therefore
# it gets called only at the last synthesis step
#
# Do not infer IOBs for targets that use a ROI.
if { $::env(USE_ROI) == "TRUE" } {
synth_xilinx -flatten -nosrl -noclkbuf -nodsp -noiopad -nowidelut
} else {
# Read Yosys baseline library first.
read_verilog -lib -specify +/xilinx/cells_sim.v
read_verilog -lib +/xilinx/cells_xtra.v
# Overwrite some models (e.g. IBUF with more parameters)
read_verilog -lib $::env(TECHMAP_PATH)/iobs.v
# TODO: This should eventually end up in upstream Yosys
# as models such as FD are not currently supported
# as being used in old FPGAs (e.g. Spartan6)
# Read in unsupported models
read_verilog -lib $::env(TECHMAP_PATH)/retarget.v
if { [info exists ::env(TOP)] && $::env(TOP) != "" } {
hierarchy -check -top $::env(TOP)
} else {
hierarchy -check -auto-top
}
# Start flow after library reading
synth_xilinx -flatten -nosrl -noclkbuf -nodsp -iopad -nowidelut -run prepare:check
}
# Check that post-synthesis cells match libraries.
hierarchy -check
if { [info exists ::env(INPUT_XDC_FILES)] && $::env(INPUT_XDC_FILES) != "" } {
read_xdc -part_json $::env(PART_JSON) {*}$::env(INPUT_XDC_FILES)
write_fasm -part_json $::env(PART_JSON) $::env(OUT_FASM_EXTRA)
# Perform clock propagation based on the information from the XDC commands
propagate_clocks
}
update_pll_and_mmcm_params
# Write the SDC file
#
# Note that write_sdc and the SDC plugin holds live pointers to RTLIL objects.
# If Yosys mutates those objects (e.g. destroys them), the SDC plugin will
# segfault.
write_sdc -include_propagated_clocks $::env(OUT_SDC)
write_verilog $::env(OUT_SYNTH_V).premap.v
# Look for connections OSERDESE2.OQ -> OBUFDS.I. Annotate OBUFDS with a parameter
# indicating that it is connected to an OSERDESE2
select -set obufds t:OSERDESE2 %co2:+\[OQ,I\] t:OBUFDS t:OBUFTDS %u %i
setparam -set HAS_OSERDES 1 @obufds
# Map Xilinx tech library to 7-series VPR tech library.
read_verilog -specify -lib $::env(TECHMAP_PATH)/cells_sim.v
# Convert congested CARRY4 outputs to LUTs.
#
# This is required because VPR cannot reliably resolve SLICE[LM] output
# congestion when both O and CO outputs are used. For this reason if both O
# and CO outputs are used, the CO output is computed using a LUT.
#
# Ideally VPR would resolve the congestion in one of the following ways:
#
# - If either O or CO are registered in a FF, then no output
# congestion exists if the O or CO FF is packed into the same cluster.
# The register output will used the [ABCD]Q output, and the unregistered
# output will used the [ABCD]MUX.
#
# - If neither the O or CO are registered in a FF, then the [ABCD]Q output
# can still be used if the FF is placed into "transparent latch" mode.
# VPR can express this edge, but because using a FF in "transparent latch"
# mode requires running specific CE and SR signals connected to constants,
# VPR cannot easily (or at all) express this packing situation.
#
# VPR's packer in theory could be expanded to express this kind of
# situation.
#
# CLE Row
#
# +--------------------------------------------------------------------------+
# | |
# | |
# | +---+ |
# | | + |
# | | + |
# | +-------->+ O + |
# | CO CHAIN | | + |
# | | | +---------------------> xMUX
# | ^ | +---->+ CO + |
# | | | | | + |
# | | | | | + |
# | +---------+----------+ | | | + |
# | | | | | +---+ |
# | | CARRY ROW | | | |
# | +--->+ S O +--------+ | xOUTMUX |
# | | | | | |
# | | | + | |
# | +--->+ DI CO +-------+o+--+ |
# | | CI CHAIN | + | |
# | | | | | |
# | +---------+----------+ | | xFFMUX |
# | ^ | | |
# | | | | +---+ |
# | + | | | + |
# | | + | + +-----------+ |
# | +--+o+--->+ O + | | |
# | + | + | xFF | |
# | | | +->--D---- Q +------> xQ
# | | | + | | |
# | +---->+ CO + | | |
# | | + +-----------+ |
# | | + |
# | +---+ |
# | |
# | |
# +--------------------------------------------------------------------------+
#
techmap -map $::env(TECHMAP_PATH)/carry_map.v
clean_processes
write_json $::env(OUT_JSON).carry_fixup.json
exec $::env(PYTHON3) $::env(UTILS_PATH)/fix_xc7_carry.py < $::env(OUT_JSON).carry_fixup.json > $::env(OUT_JSON).carry_fixup_out.json
design -push
read_json $::env(OUT_JSON).carry_fixup_out.json
techmap -map $::env(TECHMAP_PATH)/clean_carry_map.v
# Re-read baseline libraries
read_verilog -lib -specify +/xilinx/cells_sim.v
read_verilog -lib +/xilinx/cells_xtra.v
read_verilog -specify -lib $::env(TECHMAP_PATH)/cells_sim.v
if { $::env(USE_ROI) != "TRUE" } {
read_verilog -lib $::env(TECHMAP_PATH)/iobs.v
}
# Re-run optimization flow to absorb carry modifications
hierarchy -check
write_ilang $::env(OUT_JSON).pre_abc9.ilang
if { $::env(USE_ROI) == "TRUE" } {
synth_xilinx -flatten -abc9 -nosrl -noclkbuf -nodsp -noiopad -nowidelut -run map_ffs:check
} else {
synth_xilinx -flatten -abc9 -nosrl -noclkbuf -nodsp -iopad -nowidelut -run map_ffs:check
}
write_ilang $::env(OUT_JSON).post_abc9.ilang
# Either the JSON bounce or ABC9 pass causes the CARRY4_VPR CIN/CYINIT pins
# to have 0's when unused. As a result VPR will attempt to route a 0 to those
# ports. However this is not generally possible or desirable.
#
# $::env(TECHMAP_PATH)/cells_map.v has a simple techmap pass where these
# unused ports are removed. In theory yosys's "rmports" would work here, but
# it does not.
chtype -map CARRY4_VPR CARRY4_FIX
techmap -map $::env(TECHMAP_PATH)/cells_map.v
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
# net.
opt_expr -undriven
opt_clean
setundef -zero -params
stat
# TODO: remove this as soon as new VTR master+wip is pushed: https://github.com/SymbiFlow/vtr-verilog-to-routing/pull/525
attrmap -remove hdlname
# Write the design in JSON format.
clean_processes
write_json $::env(OUT_JSON)
# Write the design in Verilog format.
write_verilog $::env(OUT_SYNTH_V)