Skip to content

Commit

Permalink
Rudimentary upgrades to Yosys+VPR FPGA flow to jumpstart a bigger upg…
Browse files Browse the repository at this point in the history
…rade for future releases
  • Loading branch information
petergrossmann21 committed Jan 16, 2023
1 parent 77f2f47 commit a09746b
Show file tree
Hide file tree
Showing 3 changed files with 325 additions and 2 deletions.
95 changes: 95 additions & 0 deletions siliconcompiler/flows/fpga_yosys_vpr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#fpga_yosys_vpr.py
#Peter Grossmann
#11 January 2023
#$Id$
#$Log$

import siliconcompiler
import re

from siliconcompiler.flows._common import setup_frontend

############################################################################
# DOCS
############################################################################

def make_docs():
'''
A custom FPGA compilation flow for emulating F4PGA's Xilinx RTL to
bitstream flow.
The 'fpga_yosys_vpr' module is an FPGA flow tuned to work with
Yosys + VPR for Xilinx devices supported by F4PGA (i.e. with known good
VPR architecture files).
The following step convention is used in this flow.
* **import**: Sources are collected and packaged for compilation
* **syn**: Synthesize RTL into a device specific netlist with yosys
* **place_route**: FPGA specific placement and routing step with VPR
* **bitstream**: Bitstream generation--NOT YET IMPLEMENTED
* **program**: Program the device--NOT YET IMPLEMENTED
The fpga_yosys_vpr can be configured through the following schema parameters
Schema keypaths:
* ['fpga', 'partname']: Used to select partname to vendor and tool flow
* ['fpga', 'program']: Used to turn on/off HW programming step
'''

chip = siliconcompiler.Chip('<topmodule>')
chip.set('option', 'flow', 'fpga_yosys_vpr')
chip.set('fpga', 'partname', 'xilinx')
setup(chip)

return chip

############################################################################
# Flowgraph Setup
############################################################################
def setup(chip, flowname='fpga_yosys_vpr'):
'''
Setup function for 'fpga_yosys_vpr'
Args:
chip (object): SC Chip object
'''

# Check that fpga arch has been set for vpr flow or partname has been set for others
flow = 'vpr'

#***TO DO: Add something partname-related to help vet that the partname is
# is supported by this flow

# Set FPGA mode if not set
chip.set('option', 'mode', 'fpga')

#Setting up pipeline
flowpipe = ['syn', 'apr']

flowtools = setup_frontend(chip)
for step in flowpipe:
if (step == "syn") :
flowtools.append((step, "yosys"))
elif (step == "apr") :
flowtools.append((step, "vpr"))

# Minimal setup
index = '0'
for step, tool in flowtools:
# Flow
chip.node(flowname, step, tool)
if step != 'import':
chip.edge(flowname, prevstep, step)
# Hard goals
for metric in ('errors','warnings','drvs','unconstrained',
'holdwns','holdtns', 'holdpaths',
'setupwns', 'setuptns', 'setuppaths'):
chip.set('flowgraph', flowname, step, index, 'goal', metric, 0)
# Metrics
for metric in ('luts','dsps','brams','registers',
'pins','peakpower','leakagepower'):
chip.set('flowgraph', flowname, step, index, 'weight', metric, 1.0)
prevstep = step

##################################################
if __name__ == "__main__":
chip = make_docs()
chip.write_flowgraph("fpga_yosys_vpr.png")
25 changes: 24 additions & 1 deletion siliconcompiler/tools/vpr/vpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,30 @@ def setup(chip):

if 'sdc' in chip.getkeys('input'):
options.append(f"--sdc_file {chip.get('input', 'sdc')}")

else :
options.append(f"--timing_analysis off")

#***NOTE: Eventually, I think we want this:
#for rr_graph in chip.get('fpga','rr_graph'):
# options.append(f"--read_rr_graph "+rr_graph)
#
#But for now, implement this to avoid schema changes
rr_graph_files = chip.get('tool', 'vpr', 'var', 'apr', '0', 'rr_graph')
if (len(rr_graph_files) == 1) :
options.append(f"--read_rr_graph "+rr_graph_files[0])

#***NOTE: For real FPGA chips you need to specify the routing channel
# width explicitly. VPR requires an explicit routing channel
# with when --read_rr_graph is used (typically the case for
# real chips). Otherwise VPR performs a binary search for
# the minimum routing channel width that the circuit fits in.
# -PG 1/13/2023
#Given the above, it may be appropriate to couple these variables somehow,
#but --route_chan_width CAN be used by itself.
num_routing_channels = chip.get('tool', 'vpr', 'var', 'apr', '0', 'route_chan_width')
if (len(num_routing_channels) == 1) :
options.append(f"--route_chan_width "+num_routing_channels[0])

threads = chip.get('tool', tool, 'threads', step, index)
options.append(f"--num_workers {threads}")

Expand Down
207 changes: 206 additions & 1 deletion siliconcompiler/tools/yosys/syn_fpga.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,219 @@ set job_name [dict get $sc_cfg option jobname]
set step [dict get $sc_cfg arg step]
set index [dict get $sc_cfg arg index]

set sc_memmap_techlib "None"
set sc_mem_techlib "None"
set sc_lut_techlib "None"
set sc_dsp_techlib "None"
set sc_flop_techlib "None"
set sc_syn_lut_size 6
#if {[string match {ebrick*} $sc_partname]} {
# set sc_memmap_techlib [dict get $sc_cfg tool $sc_tool memmap_techlib]
# set sc_mem_techlib [dict get $sc_cfg tool $sc_tool mem_techlib]
# set sc_lut_techlib [dict get $sc_cfg tool $sc_tool lut_techlib]
# set sc_dsp_techlib [dict get $sc_cfg tool $sc_tool dsp_techlib]
# set sc_flop_techlib [dict get $sc_cfg tool $sc_tool flop_techlib]
#
# #set sc_syn_lut_size 4
# set sc_syn_lut_size [dict get $sc_cfg tool $sc_tool lut_size]
#}

#TODO: add logic that remaps yosys built in name based on part number

# Run this first to handle module instantiations in generate blocks -- see
# comment in syn_asic.tcl for longer explanation.
yosys hierarchy -top $sc_design

#***NOTE: There are over a dozen customized synthesis routines in yosys
# for different FPGA families. The level of maturity and the
# range of parts supported by each varies significantly: some
# are experimental, some support only one part, others are mature,
# and the Xilinx and Intel setups specifically have -family flags
# to select different parts within those companies' product
# portfolios.
# As of 1/13/2023, what's here is a best-effort first stab at getting
# all of the commands exercised in a first-order fashion and defining
# part number strings that could be used to specify each supported
# part number. Where available, part number prefixes have been gleaned
# from DigiKey so that there is a correspondence here between
# real product part numbers and the if/else statement selecting a
# synthesis command. It will be necessary to do some vetting and
# decide what to really support and what to omit based on the yosys
# support (or the place and route support) being too skimpy.
# -PG 1/13/2023

if {[string match {ice*} $sc_partname]} {
yosys synth_ice40 -top $sc_design -json "${sc_design}_netlist.json"
} elseif { [string match {xc7*} $sc_partname] } {
#TODO: Xilinx family support is theoretically pretty broad; need
# to break this out. Currently supporting 7 series FPGAs only
yosys synth_xilinx -family xc7 -top ${sc_design}
} elseif { [string match {speedster*} $sc_partname] } {
#***NOTE: This appears to support the Speedster 22i specifically;
# unknown whether it would also work with Speedster 7t
# series, but safer guess is that it doesn't.
#TODO need a better part number string for this
yosys synth_achronix -top ${sc_design}
} elseif { [string match {al*} $sc_partname] } {
#TODO: Figure out support for AL3 series vs AL4 series (Eagle)
# the tech maps maybe support both but it's tough to tell
# without a deep dive
yosys synth_anlogic -top ${sc_design}
} elseif { [string match {xc2c*} $sc_partname] } {
#Xilinx CoolRunner-2 CPLDs. Note that these are
#old-school parts that don't use LUTs, mapping logic
#to an AND-OR plance instead. Do we want to support these?
yosys synth_coolrunner2 -top ${sc_design}
} elseif { [string match {lfe5*} $sc_partname] } {
#Lattice ECP5
yosys synth_ecp5 -top ${sc_design}
} elseif { [string match {t*} $sc_partname] } {
#TODO: determine how this supports Trion vs. Titanum FPGAs
# and come up with a less generic string match
yosys synth_efinix -top ${sc_design}
} elseif { [string match {ccgm*} $sc_partname] } {
#Cologne Chip seems to only have one GateMate part for
#now, so presumably this supports it
yosys synth_gatemate -top ${sc_design}
} elseif { [string match {gw*} $sc_partname] } {
#TODO: Determine which gowin parts are actually supported
yosys synth_gowin -top ${sc_design}
} elseif { [string match {xc7*} $sc_partname] } {
#This is listed as still experimental; we may wish
#to drop it
yosys synth_intel -top ${sc_design}
} elseif { [string match {xc7*} $sc_partname] } {
#This is a bundle for the Cyclone-V, Cyclone-10
yosys synth_intel_alm -top ${sc_design}
} elseif { [string match {lcmxo2*} $sc_partname] } {
#Lattice Mach-XO2; note this is a bit older part;
#they are up to the Mach-XO5 now
yosys synth_machxo2 -top ${sc_design}
} elseif { [string match {lfcpnx*} $sc_partname] } {
#***NOTE: Nexus is Lattice's term for a platform within which
# a few FPGA parts might be deployed. The most recent
# Nexus platform FPGA is the Certus-Pro whose part names
# are matched here. Others may need to be grandfathered in,
# depending on what technology mapping Yosys actually supports
# with this command
yosys synth_nexus -top ${sc_design}
} elseif { [string match {ql3p*} $sc_partname] } {
#QuickLogic PolarPro-3
yosys synth_quicklogic -top ${sc_design}
} elseif { [string match {m2s*} $sc_partname] } {
#Microchip/Microsemi/Actel SmartFusion 2
yosys synth_sf2 -top ${sc_design}
} else {
yosys script "${build_dir}/${sc_design}/${job_name}/${step}/${index}/inputs/vpr_yosyslib/synthesis.ys"
#yosys script "${build_dir}/${sc_design}/${job_name}/${step}/${index}/inputs/vpr_yosyslib/synthesis.ys"
#Match VPR reference flow's hierarchy check, including their comments

#Here are the notes from the VPR developers
# These commands follow the generic `synth'
# command script inside Yosys
# The -libdir argument allows Yosys to search the current
# directory for any definitions to modules it doesn't know
# about, such as hand-instantiated (not inferred) memories
#***NOTE: Removed -libdir as it's nonsensical with the
# use case of this script -PG 1/11/2023
yosys hierarchy -check -auto-top

#Rename top level module to match selected design name;
#This allows us to enforce some naming consistency in
#automated flows
#***NOTE: because rename is a Tcl keyword the yosys -import
# trick doesn't work
yosys rename -top ${sc_design}

yosys proc
#select -module ${sc_design}
#flatten -wb
#flatten

#Match the optimization passes of the VTR reference yosys flow
yosys opt_expr
yosys opt_clean
yosys check
yosys opt -nodffe -nosdff
yosys fsm
yosys opt
yosys wreduce
yosys peepopt
yosys opt_clean
yosys share
yosys opt
yosys memory -nomap
yosys opt -full

#Do our own thing from here
yosys techmap -map +/techmap.v

#***TO DO: Figure out how to deal with this in an SC-compatible way
if { $sc_flop_techlib eq "None" } {
yosys dfflegalize -cell \$_DFF_P_ 01 -cell \$_DFF_P??_ 01
}

#opt
#opt_clean

#Perform preliminary buffer insertion before passing to ABC to help reduce
#the overhead of final buffer insertion downstream
yosys insbuf

yosys abc -lut $sc_syn_lut_size -dff
#abc -script $env(FPGA_ARCHITECT_ROOT)/test/scripts/fpgaa_abc_flow.scr

#***TO DO: Wrap this in a verbosity flag
#yosys write_verilog -noexpr -selected ${sc_design}_abc.v

#Clean up the design before buffer insertion to avoid blowing up the design
#size with that step
#opt
#clean

yosys flatten
yosys clean

#***NOTE: If you flatten after this step instead of before Yosys barfs,
# would be nice to have a deeper understanding of why that is
# -PG 1/16/2023
set sc_memmap_techlib [ dict get $sc_cfg tool $sc_tool var $sc_step $sc_index memmap ]
if { $sc_memmap_techlib ne "None" } {
yosys memory_libmap -lib $sc_memmap_techlib
#***HACK: Eliminate $reduce_or with this mapping here
# until we have a cleaner solution
yosys simplemap
}

#if { $map_buffers == 1 } {
#insbuf -buf $buffer_name $buf_input_name $buf_output_name
#}

#***NOTE: hilomap needs to happen before tech mapping so that
# we can run the hierarchy check and prevent the tiecell
# library from being treated like part of the design
# -PG 1/3/2023
#if { $tiecells == 1 } {
#hilomap -hicell $tiehi_cell $tiehi_output_name -locell $tielo_cell $tielo_output_name
#}

########################################################
# Technology Mapping
########################################################
if [dict exists $sc_cfg tool $sc_tool var $sc_step $sc_index techmap ] {
set sc_techmap [ dict get $sc_cfg tool $sc_tool var $sc_step $sc_index techmap ]
foreach mapfile $sc_techmap {
yosys techmap -map $mapfile
}
}

#***NOTE: Can't do a hierarchy check here as the techmap results
# get flagged
#***TO DO: Review why this might have been in the flow during
# previous development phases and revisit what if anything to
# do going forward -PG 12/23/2022
#hierarchy -check -purge_lib

yosys clean

yosys stat
}

0 comments on commit a09746b

Please sign in to comment.