New Lattice iCE40 FPGA development platform // Resolve #480
This commit is contained in:
Executable
+149
@@ -0,0 +1,149 @@
|
||||
"""
|
||||
Build script for lattice ice40 FPGAs
|
||||
latticeice40-builder.py
|
||||
"""
|
||||
import os
|
||||
from os.path import join
|
||||
|
||||
from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default,
|
||||
DefaultEnvironment, Environment, Exit, GetOption,
|
||||
Glob)
|
||||
|
||||
env = DefaultEnvironment()
|
||||
env.Replace(PROGNAME="hardware")
|
||||
env.Append(SIMULNAME="simulation")
|
||||
|
||||
# -- Get the local folder in which the icestorm tools should be installed
|
||||
piopackages_dir = env.subst('$PIOPACKAGES_DIR')
|
||||
bin_dir = join(piopackages_dir, 'toolchain-icestorm', 'bin')
|
||||
|
||||
# -- Add this path to the PATH env variable. First the building tools will be
|
||||
# -- searched in the local PATH. If they are not founde, the global ones will
|
||||
# -- be executed (if installed)
|
||||
env.PrependENVPath('PATH', bin_dir)
|
||||
|
||||
# -- Target name for synthesis
|
||||
TARGET = join(env['BUILD_DIR'], env['PROGNAME'])
|
||||
|
||||
# -- Target name for simulation
|
||||
# TARGET_SIM = join(env['PROJECT_DIR'], env['SIMULNAME'])
|
||||
|
||||
# -- Get a list of all the verilog files in the src folfer, in ASCII, with
|
||||
# -- the full path. All these files are used for the simulation
|
||||
v_nodes = Glob(join(env['PROJECTSRC_DIR'], '*.v'))
|
||||
src_sim = ["{}".format(f) for f in v_nodes]
|
||||
|
||||
# --------- Get the Testbench file (there should be only 1)
|
||||
# -- Create a list with all the files finished in _tb.v. It should contain
|
||||
# -- the test bench
|
||||
list_tb = [f for f in src_sim if f[-5:].upper() == "_TB.V"]
|
||||
|
||||
if len(list_tb) > 1:
|
||||
print "---> WARNING: More than one testbenches used"
|
||||
|
||||
# -- Error checking
|
||||
try:
|
||||
testbench = list_tb[0]
|
||||
|
||||
# -- there is no testbench
|
||||
except IndexError:
|
||||
testbench = None
|
||||
|
||||
if 'sim' in COMMAND_LINE_TARGETS:
|
||||
if testbench is None:
|
||||
print "ERROR!!! NO testbench found for simulation"
|
||||
Exit(1)
|
||||
|
||||
# -- Simulation name
|
||||
testbench_file = os.path.split(testbench)[-1]
|
||||
SIMULNAME, ext = os.path.splitext(testbench_file)
|
||||
else:
|
||||
SIMULNAME = ''
|
||||
|
||||
|
||||
TARGET_SIM = join(env.subst('$BUILD_DIR'), SIMULNAME)
|
||||
|
||||
# -------- Get the synthesis files. They are ALL the files except the
|
||||
# -------- testbench
|
||||
src_synth = [f for f in src_sim if f not in list_tb]
|
||||
|
||||
# -- For debugging
|
||||
print "Testbench: {}".format(testbench)
|
||||
|
||||
# -- Get the PCF file
|
||||
src_dir = env.subst('$PROJECTSRC_DIR')
|
||||
PCFs = join(src_dir, '*.pcf')
|
||||
PCF_list = Glob(PCFs)
|
||||
|
||||
try:
|
||||
PCF = PCF_list[0]
|
||||
except IndexError:
|
||||
print "\n--------> ERROR: no .pcf file found <----------\n"
|
||||
Exit(2)
|
||||
|
||||
# -- Debug
|
||||
print "----> PCF Found: {}".format(PCF)
|
||||
|
||||
# -- Builder 1 (.v --> .blif)
|
||||
synth = Builder(action='yosys -p \"synth_ice40 -blif {}.blif\" \
|
||||
$SOURCES'.format(TARGET),
|
||||
suffix='.blif',
|
||||
src_suffix='.v')
|
||||
|
||||
# -- Builder 2 (.blif --> .asc)
|
||||
pnr = Builder(action='arachne-pnr -d 1k -o $TARGET -p {} \
|
||||
$SOURCE'.format(PCF),
|
||||
suffix='.asc',
|
||||
src_suffix='.blif')
|
||||
|
||||
# -- Builder 3 (.asc --> .bin)
|
||||
bitstream = Builder(action='icepack $SOURCE $TARGET',
|
||||
suffix='.bin',
|
||||
src_suffix='.asc')
|
||||
|
||||
# -- Builder 4 (.asc --> .rpt)
|
||||
time_rpt = Builder(action='icetime -mtr $TARGET $SOURCE',
|
||||
suffix='.rpt',
|
||||
src_suffix='.asc')
|
||||
|
||||
env.Append(BUILDERS={'Synth': synth, 'PnR': pnr, 'Bin': bitstream,
|
||||
'Time': time_rpt})
|
||||
|
||||
blif = env.Synth(TARGET, [src_synth])
|
||||
asc = env.PnR(TARGET, [blif, PCF])
|
||||
binf = env.Bin(TARGET, asc)
|
||||
|
||||
upload = env.Alias('upload', binf, 'iceprog ' + ' $SOURCE')
|
||||
AlwaysBuild(upload)
|
||||
|
||||
# -- Target for calculating the time (.rpt)
|
||||
# rpt = env.Time(asc)
|
||||
t = env.Alias('time', env.Time('time.rpt', asc))
|
||||
|
||||
# -------------------- Simulation ------------------
|
||||
# -- Constructor para generar simulacion: icarus Verilog
|
||||
iverilog = Builder(action='iverilog -o $TARGET $SOURCES ',
|
||||
suffix='.out',
|
||||
src_suffix='.v')
|
||||
|
||||
vcd = Builder(action=' $SOURCE',
|
||||
suffix='.vcd', src_suffix='.out')
|
||||
|
||||
simenv = Environment(BUILDERS={'IVerilog': iverilog, 'VCD': vcd},
|
||||
ENV=os.environ)
|
||||
|
||||
out = simenv.IVerilog(TARGET_SIM, src_sim)
|
||||
vcd_file = simenv.VCD(SIMULNAME, out)
|
||||
|
||||
waves = simenv.Alias('sim', vcd_file, 'gtkwave ' +
|
||||
join(env['PROJECT_DIR'], "{} ".format(vcd_file[0])) +
|
||||
join(env['PROJECTSRC_DIR'], SIMULNAME) +
|
||||
'.gtkw')
|
||||
AlwaysBuild(waves)
|
||||
|
||||
Default([binf])
|
||||
|
||||
# -- These is for cleaning the files generated using the alias targets
|
||||
if GetOption('clean'):
|
||||
env.Default([t])
|
||||
simenv.Default([out, vcd_file])
|
||||
Reference in New Issue
Block a user