# Make sure we are run in the background NICE = nice -n 19 # Command to initialize the Xilinx environment # (Feel free to change to the 64 bit version if necessary.) XILINX_INIT = source /sw/xilinx/ise_11.1i/ISE/settings32.sh; #XILINX_INIT = source /extra/ise_11.1/ISE/settings32.sh; # Beginning of Xilinx part # Xilinx default options # Fix the path by inserting ../.. if the path is relative. If absolute, do nothing fixpath2 = $(shell echo "$(1)" | sed 's,^\([^/]\),../../\1,') # Fix the path by inserting ../ if the path is relative. If absolute, do nothing fixpath1 = $(shell echo "$(1)" | sed 's,^\([^/]\),../\1,') # Reverses the order of all arguments given to the function. reverse_order = $(if $(1), $(word $(words $(1)),$(1)) $(call reverse_order,$(wordlist 2,$(words $(1)),dummy $(1))),$(1)) # Needed for modelsim compilation of VHDL files T_REV=$(call reverse_order,$(T)) S_REV=$(call reverse_order,$(S)) # This rule is responsible for creating the XST synthesis script and # the PRJ file containing the name of the files we want to synthesize .PRECIOUS: $(PROJNAME)-synthdir/%.scr $(PROJNAME)-synthdir/%.prj %.ncd $(PROJNAME)-synthdir/%.ngc $(PROJNAME)-synthdir/%.ngd $(PROJNAME)-synthdir/%_map.ncd $(PROJNAME)-synthdir/%.ncd $(PROJNAME)-synthdir/%.edf %.ncd %.bit $(PROJNAME)-synthdir/synth/design.scr: $(S) @echo @echo '*** Creating synthesis scripts ***' @echo mkdir -p $(@D) # We first create the project file @rm -f $@.tmp @echo "set -tmpdir tmpdir" > $@.tmp @echo "run -ifn design.prj" >> $@.tmp @echo "-ofn design.ngc" >> $@.tmp # The following lines finds the first specified synthesizable file, # removes the file extension by using sed and then removing the # directory part of the file by using basename. This is then used as # our top module! echo "-top $$(basename $$(echo $(firstword $(S)) | sed 's/\..*$$//'))" >> $@.tmp echo "-p $(PART)" >> $@.tmp echo $(XST_OPT) >> $@.tmp # First enter all Verilog files into the project file, then all VHDL files rm -f $(@D)/design.prj touch $(@D)/design.prj $(foreach i,$(filter %.v,$(S)), echo 'verilog work "$(call fixpath2,$(i))"' >> $(@D)/design.prj;) $(foreach i,$(filter %.vhd,$(S)), echo 'vhdl work "$(call fixpath2,$(i))"' >> $(@D)/design.prj;) $(foreach i,$(filter %.vhdl,$(S)), echo 'vhdl work "$(call fixpath2,$(i))"' >> $(@D)/design.prj;) mv $@.tmp $@ # Synthesize the design based on the synthesis script # Clean out temporary directories to be sure no stale data is left... $(PROJNAME)-synthdir/synth/design.ngc: $(PROJNAME)-synthdir/synth/design.scr @echo @echo '*** Synthesizing ***' @echo rm -rf $(@D)/tmpdir mkdir -p $(@D)/tmpdir rm -rf $(@D)/xst mkdir -p $(@D)/xst cd $(@D); $(XILINX_INIT) xst -ifn design.scr -ofn design.syr $(PROJNAME)-synthdir/synth/design_postsynth.vhd: $(PROJNAME)-synthdir/synth/design.ngc @echo @echo '*** Creating post synthesis netlist $* ***' @echo $(XILINX_INIT) netgen -w -ofmt vhdl $(@D)/design.ngc $@ # This is the default rule for NGDBuild when we are not trying to override our TIMESPEC $(PROJNAME)-synthdir/layoutdefault/design.ngd: $(PROJNAME)-synthdir/synth/design.ngc $(U) @echo @echo '*** Producing NGD file ***' @echo rm -rf $(@D)/_ngo mkdir -p $(@D)/_ngo # Running ngdbuild without any UCF file if [ "$(U)" == "" ]; then \ cd $(@D); $(XILINX_INIT) ngdbuild -sd . -dd _ngo -nt timestamp -p $(PART) ../synth/design.ngc design.ngd;\ else\ cd $(@D); $(XILINX_INIT) ngdbuild -sd . -dd _ngo -nt timestamp -p $(PART) -uc $(call fixpath2,$(U)) ../synth/design.ngc design.ngd;\ fi # This is the rule for NGDBuild when we are trying to override the TIMESPEC when using a project.fmax rule $(PROJNAME)-synthdir/layout%/design.ngd: $(PROJNAME)-synthdir/synth/design.ngc $(U) @echo @echo '*** Producing NGD file ***' @echo rm -rf $(@D)/_ngo mkdir -p $(@D)/_ngo @if [ "$(U)" == "" ]; then \ echo 'Cannot synthesize to a specific MHz without a UCF file'; false; \ fi # At this point we try to override the default time constraint! @if ! [ $$(grep -i TIMESPEC $(U) | wc -l) -eq 1 ]; then echo The script can only handle one timespec for now.;false;fi @if ! egrep -q '^TIMESPEC ".*" *= *PERIOD *".*" *[0-9\.]+ *ns *HIGH *50 *% *;' $(U);then\ echo 'TIMESPEC line in UCF must be in the following format: TIMESPEC "name" = PERIOD 4.5 ns HIGH 50%;';\ false;\ fi sed 's/^\(TIMESPEC *".*" *= *PERIOD *".*"\) *[0-9\.]\+ *ns *HIGH *50 *%; *$$/\1 $* HIGH 50%;/' < $(U) > $(@D)/design.ucf @echo "*** UCF file setup for timespec $* ***" cd $(@D); $(XILINX_INIT) ngdbuild -sd . -dd _ngo -nt timestamp -p $(PART) -uc design.ucf ../synth/design.ngc design.ngd # Map a design into the FPGA components $(PROJNAME)-synthdir/layout%/design_map.ncd $(PROJNAME)-synthdir/layout%/design.pcf: $(PROJNAME)-synthdir/layout%/design.ngd @echo @echo '*** Mapping design ***' @echo cd $(@D);$(XILINX_INIT) map -detail -u -p $(PART) -pr b -c 100 -o design_map.ncd design.ngd design.pcf # Rule for placing and routing a design $(PROJNAME)-synthdir/layout%/design.ncd: $(PROJNAME)-synthdir/layout%/design_map.ncd $(PROJNAME)-synthdir/layout%/design.pcf @echo @echo '*** Routing design ***' @echo cd $(@D); $(XILINX_INIT) par -nopad -w -ol high -t 1 design_map.ncd design.ncd design.pcf $(PROJNAME)-synthdir/layoutdefault/design_postpar.vhd: $(PROJNAME)-synthdir/layoutdefault/design.ncd @echo @echo '*** Creating post place and route netlist $* ***' @echo $(XILINX_INIT) netgen -w -ofmt vhdl $(@D)/design.ncd $@ $(PROJNAME)-synthdir/layout%/design.twr: $(PROJNAME)-synthdir/layout%/design.ncd @echo @echo '*** Running static timing analysis ***' @echo cd $(@D); $(XILINX_INIT) trce -v 1000 design.ncd design.pcf $(PROJNAME)-synthdir/layoutdefault/design.xdl: work $(PROJNAME)-synthdir/layoutdefault/design.ncd @echo @echo '*** Creating XDL netlist ***' @echo cd $(@D); $(XILINX_INIT) xdl -w -ncd2xdl design.ncd $(PROJNAME)-synthdir/layoutdefault/design.bit: $(PROJNAME)-synthdir/layoutdefault/design.ncd cd $(@D); bitgen -w design.ncd # Duplicate the layout dependencies a couple of time with different # timespecs to enable parallel make to investigate several different # timing specs simultaneously on multi processor machines. # # Warning: You may have a limited amount of licenses for ISE! expandtimespec = $(shell echo 'scale=5;for(i=0;i<7;i+=1){$(1)-i*0.1;print " "}'|bc) $(PROJNAME)-synthdir/fmax.rpt: $(foreach i,$(call expandtimespec,$(TIMESPEC)),$(PROJNAME)-synthdir/layout$(i)/design.twr) @echo @echo '*** Maximum frequencies follow ***' @echo grep MHz $(PROJNAME)-synthdir/layout*/design.twr work: vlib work # TODO: Don't recompile all files all the time! # (Re)compile all files used for the testbench SIMTBFILES: work $(T_REV) $(if $(filter %.vhd,$(T_REV)), vcom +acc $(foreach i, $(filter %.vhd, $(T_REV)), $(i))) $(if $(filter %.vhdl,$(T_REV)), vcom +acc $(foreach i, $(filter %.vhdl, $(T_REV)), $(i))) $(if $(filter %.v,$(T_REV)), vlog +acc $(foreach i, $(filter %.v, $(T_REV)), $(i))) SIMSYNTHFILES: work $(S_REV) echo $(S_REV) echo $(filter %.vhd,$(S_REV)) $(if $(filter %.vhd,$(S_REV)), vcom +acc $(foreach i, $(filter %.vhd, $(S_REV)), $(i))) $(if $(filter %.vhdl,$(S_REV)), vcom +acc $(foreach i, $(filter %.vhdl, $(S_REV)), $(i))) $(if $(filter %.v,$(S_REV)), vlog +acc $(foreach i, $(filter %.v, $(S_REV)), $(i))) SIMFILES: SIMSYNTHFILES SIMTBFILES SIM: SIMFILES vsim -L work $$(basename $$(echo $(firstword $(T)) | sed 's/\..*$$//')) -L unisim SIMC: SIMFILES vsim -L work $$(basename $$(echo $(firstword $(T)) | sed 's/\..*$$//')) -L unisim -c -do 'run -a;quit -f' SYNTHSIM: work $(PROJNAME)-synthdir/synth/design_postsynth.vhd SIMTBFILES vcom +acc $(PROJNAME)-synthdir/synth/design_postsynth.vhd vsim -L unisim $$(basename $$(echo $(firstword $(T)) | sed 's/\..*$$//')) SYNTHSIMC: work $(PROJNAME)-synthdir/synth/design_postsynth.vhd SIMTBFILES vcom +acc $(PROJNAME)-synthdir/synth/design_postsynth.vhd vsim -L unisim $$(basename $$(echo $(firstword $(T)) | sed 's/\..*$$//')) -c -do 'run -a; quit -f' # TODO: Don't recompile all files all the time! PARSIM: work $(PROJNAME)-synthdir/layoutdefault/design_postpar.vhd SIMTBFILES vcom +acc $(PROJNAME)-synthdir/layoutdefault/design_postpar.vhd cp $(PROJNAME)-synthdir/layoutdefault/design_postpar.sdf . vsim -sdfmax /uut=$(PROJNAME)-synthdir/layoutdefault/design_postpar.sdf -L simprim $$(basename $$(echo $(firstword $(T)) | sed 's/\..*$$//')) # TODO: Don't recompile all files all the time! PARSIMC: work $(PROJNAME)-synthdir/layoutdefault/design_postpar.vhd SIMTBFILES vcom +acc $(PROJNAME)-synthdir/layoutdefault/design_postpar.vhd vsim -sdfmax /uut=$(PROJNAME)-synthdir/layoutdefault/design_postpar.sdf -L simprim $$(basename $$(echo $(firstword $(T)) | sed 's/\..*$$//')) -c -do 'run -a; quit -f' # TODO: Don't recompile all files all the time! POWERSIM: work $(PROJNAME)-synthdir/layoutdefault/design_postpar.vhd SIMTBFILES vcom +acc $(PROJNAME)-synthdir/layoutdefault/design_postpar.vhd vsim -sdfmax /uut=$(PROJNAME)-synthdir/layoutdefault/design_postpar.sdf -do 'vcd file activity.vcd;vcd add -r -internal -in -out uut/*; vcd on;run -a;vcd off;vcd flush;quit -f' -c -L simprim $$(basename $$(echo $(firstword $(T)) | sed 's/\..*$$//')) $(XILINX_INIT) xpwr -v -a -s activity.vcd $(PROJNAME)-synthdir/layoutdefault/design.ncd # The rules below are the only rules that are expected to actually be # called by a normal user of this makefile. %.bitgen: $(NICE) $(MAKE) -f xst.mk $*-synthdir/layoutdefault/design.bit PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" %.fmax: $(NICE) $(MAKE) -f xst.mk $*-synthdir/fmax.rpt PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" TIMESPEC=$(TIMESPEC) %.route: $(NICE) $(MAKE) -f xst.mk $*-synthdir/layoutdefault/design.ncd PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" %.synth: $(NICE) $(MAKE) -f xst.mk $*-synthdir/synth/design.ngc PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" %.timing: $(NICE) $(MAKE) -f xst.mk $*-synthdir/layoutdefault/design.twr PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" %.sim: $(NICE) $(MAKE) -f xst.mk SIM PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.simc: $(NICE) $(MAKE) -f xst.mk SIMC PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.simfiles: $(NICE) $(MAKE) -f xst.mk SIMFILES PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.synthsim: $(NICE) $(MAKE) -f xst.mk SYNTHSIM PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.parsim: $(NICE) $(MAKE) -f xst.mk PARSIM PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.synthsimc: $(NICE) $(MAKE) -f xst.mk SYNTHSIMC PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.parsimc: $(NICE) $(MAKE) -f xst.mk PARSIMC PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.powersim: $(NICE) $(MAKE) -f xst.mk POWERSIM PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.xdl: $(NICE) $(MAKE) -f xst.mk $*-synthdir/layoutdefault/design.xdl PROJNAME="$*" S="$(S)" U="$(U)" XST_OPT="$(XST_OPT)" PART="$(PART)" T="$(T)" %.clean: rm -rf "$*-synthdir" "$*-simdir"