f4pga: yosys TCL wrappers moved from f4pga-arch-defs
Signed-off-by: Unai Martinez-Corral <umartinezcorral@antmicro.com>
This commit is contained in:
parent
0d451747ad
commit
c1c612b575
|
@ -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 = \
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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=[],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)"
|
||||
|
|
|
@ -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'
|
|
@ -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]))
|
|
@ -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)
|
|
@ -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)
|
|
@ -0,0 +1,7 @@
|
|||
yosys -import
|
||||
|
||||
# Clean
|
||||
opt_clean
|
||||
|
||||
# Write EBLIF
|
||||
write_blif -attr -cname -param $::env(OUT_EBLIF)
|
|
@ -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)
|
|
@ -0,0 +1,7 @@
|
|||
yosys -import
|
||||
|
||||
# Clean
|
||||
opt_clean
|
||||
|
||||
# Write EBLIF
|
||||
write_blif -attr -cname -param $::env(OUT_EBLIF)
|
|
@ -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)
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)
|
Loading…
Reference in New Issue