/*
* Copyright (c) 2011, IRISA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IRISA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.backends.llvm.tta;
import static net.sf.orcc.backends.BackendsConstants.FPGA_CONFIGURATION;
import static net.sf.orcc.backends.BackendsConstants.FPGA_DEFAULT_CONFIGURATION;
import java.io.File;
import net.sf.orcc.backends.BackendsConstants;
import net.sf.orcc.backends.llvm.aot.LLVMBackend;
import net.sf.orcc.backends.llvm.transform.ListInitializer;
import net.sf.orcc.backends.llvm.transform.TemplateInfoComputing;
import net.sf.orcc.backends.llvm.tta.architecture.Design;
import net.sf.orcc.backends.llvm.tta.architecture.Processor;
import net.sf.orcc.backends.llvm.tta.architecture.util.ArchitectureBuilder;
import net.sf.orcc.backends.llvm.tta.transform.ComplexHwOpDetector;
import net.sf.orcc.backends.llvm.tta.transform.PrintRemoval;
import net.sf.orcc.backends.llvm.tta.transform.StringTransformation;
import net.sf.orcc.backends.transform.CastAdder;
import net.sf.orcc.backends.transform.DisconnectedOutputPortRemoval;
import net.sf.orcc.backends.transform.EmptyBlockRemover;
import net.sf.orcc.backends.transform.InstPhiTransformation;
import net.sf.orcc.backends.transform.ShortCircuitTransformation;
import net.sf.orcc.backends.transform.ssa.ConstantPropagator;
import net.sf.orcc.backends.transform.ssa.CopyPropagator;
import net.sf.orcc.backends.util.Alignable;
import net.sf.orcc.backends.util.BroadcastMapper;
import net.sf.orcc.backends.util.FPGA;
import net.sf.orcc.backends.util.Mapping;
import net.sf.orcc.backends.util.Validator;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.Network;
import net.sf.orcc.df.transform.BroadcastAdder;
import net.sf.orcc.df.transform.BroadcastRemover;
import net.sf.orcc.df.transform.FifoSizePropagator;
import net.sf.orcc.df.transform.Instantiator;
import net.sf.orcc.df.transform.NetworkFlattener;
import net.sf.orcc.df.transform.TypeResizer;
import net.sf.orcc.df.transform.UnitImporter;
import net.sf.orcc.df.util.DfVisitor;
import net.sf.orcc.graph.util.Dota;
import net.sf.orcc.ir.CfgNode;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.transform.BlockCombine;
import net.sf.orcc.ir.transform.ControlFlowAnalyzer;
import net.sf.orcc.ir.transform.DeadCodeElimination;
import net.sf.orcc.ir.transform.DeadGlobalElimination;
import net.sf.orcc.ir.transform.DeadVariableRemoval;
import net.sf.orcc.ir.transform.RenameTransformation;
import net.sf.orcc.ir.transform.SSATransformation;
import net.sf.orcc.ir.transform.SSAVariableRenamer;
import net.sf.orcc.ir.transform.TacTransformation;
import net.sf.orcc.tools.classifier.Classifier;
import net.sf.orcc.tools.merger.action.ActionMerger;
import net.sf.orcc.tools.merger.actor.ActorMerger;
import net.sf.orcc.util.FilesManager;
import net.sf.orcc.util.OrccLogger;
import net.sf.orcc.util.Result;
import net.sf.orcc.util.Void;
/**
* TTA back-end.
*
* @author Herve Yviquel
*
*/
public class TTABackend extends LLVMBackend {
private String actorsPath;
private ArchitectureBuilder architectureBuilder;
private Design design;
private FPGA fpga;
private HwDesignPrinter hwDesignPrinter;
private HwProcessorPrinter hwProcessorPrinter;
private HwProjectPrinter hwProjectPrinter;
private HwTestbenchPrinter hwTestbenchPrinter;
private PyDesignPrinter pyDesignPrinter;
private SwActorPrinter swActorPrinter;
private SwProcessorPrinter swProcessorPrinter;
private TceDesignPrinter tceDesignPrinter;
private TceProcessorPrinter tceProcessorPrinter;
private Dota dota;
private boolean importXcfFile;
private File xcfFile;
public TTABackend() {
super();
hwDesignPrinter = new HwDesignPrinter();
hwProcessorPrinter = new HwProcessorPrinter();
hwProjectPrinter = new HwProjectPrinter();
hwTestbenchPrinter = new HwTestbenchPrinter();
pyDesignPrinter = new PyDesignPrinter();
swActorPrinter = new SwActorPrinter();
swProcessorPrinter = new SwProcessorPrinter();
tceDesignPrinter = new TceDesignPrinter();
tceProcessorPrinter = new TceProcessorPrinter();
dota = new Dota();
architectureBuilder = new ArchitectureBuilder();
}
@Override
protected void doInitializeOptions() {
fpga = FPGA.builder(getOption(FPGA_CONFIGURATION,
FPGA_DEFAULT_CONFIGURATION));
importXcfFile = getOption(BackendsConstants.IMPORT_XCF, false);
if (importXcfFile) {
xcfFile = new File(getOption(BackendsConstants.XCF_FILE, ""));
}
// Configure the options used in code generation
swActorPrinter.setOptions(getOptions());
architectureBuilder.setOptions(getOptions());
// Create the directory tree
actorsPath = outputPath + File.separator + "actors";
// -----------------------------------------------------
// Transformations that will be applied on the Network
// -----------------------------------------------------
if (mergeActors) {
networkTransfos.add(new FifoSizePropagator(fifoSize));
networkTransfos.add(new BroadcastAdder());
}
networkTransfos.add(new ComplexHwOpDetector());
networkTransfos.add(new UnitImporter());
networkTransfos.add(new Instantiator(true));
networkTransfos.add(new NetworkFlattener());
if (classify) {
networkTransfos.add(new Classifier());
}
if (mergeActions) {
networkTransfos.add(new ActionMerger());
}
if (mergeActors) {
networkTransfos.add(new ActorMerger());
}
if (!debug) {
networkTransfos.add(new PrintRemoval());
}
networkTransfos.add(new DisconnectedOutputPortRemoval());
if (mergeActors) {
networkTransfos.add(new BroadcastRemover());
}
networkTransfos.add(new DfVisitor<Expression>(
new ShortCircuitTransformation()));
networkTransfos.add(new TypeResizer(true, true, false, true));
networkTransfos.add(new DfVisitor<Void>(new SSATransformation()));
networkTransfos.add(new StringTransformation());
networkTransfos.add(new RenameTransformation(this.renameMap));
networkTransfos.add(new DfVisitor<Expression>(new TacTransformation()));
networkTransfos.add(new DeadGlobalElimination());
networkTransfos.add(new DfVisitor<Void>(new DeadCodeElimination()));
networkTransfos.add(new DfVisitor<Void>(new DeadVariableRemoval()));
networkTransfos.add(new DfVisitor<Void>(new CopyPropagator()));
networkTransfos.add(new DfVisitor<Void>(new ConstantPropagator()));
networkTransfos.add(new DfVisitor<Void>(new InstPhiTransformation()));
networkTransfos.add(new DfVisitor<Expression>(
new CastAdder(false, true)));
networkTransfos.add(new DfVisitor<Void>(new EmptyBlockRemover()));
networkTransfos.add(new DfVisitor<Void>(new BlockCombine()));
networkTransfos.add(new DfVisitor<CfgNode>(new ControlFlowAnalyzer()));
networkTransfos.add(new DfVisitor<Void>(new ListInitializer()));
networkTransfos.add(new DfVisitor<Void>(new TemplateInfoComputing()));
// computes names of local variables
networkTransfos.add(new DfVisitor<Void>(new SSAVariableRenamer()));
}
@Override
protected Result doGenerateNetwork(Network network) {
// Do nothing
return Result.newInstance();
}
@Override
protected void doValidate(Network network) {
// FIXME: Allow native ports in top level checking
// Validator.checkTopLevel(network);
Validator.checkMinimalFifoSize(network, fifoSize);
if (mergeActors) {
BroadcastMapper broadcastMapper = new BroadcastMapper();
broadcastMapper.prepareBroadcastMapping(network);
}
// Configuration before the code generation
// FIXME: Make it in better place
// Compute the actor mapping from a xcf file or from the user interface
Mapping computedMapping;
if (importXcfFile) {
computedMapping = new Mapping(network, xcfFile);
} else {
computedMapping = new Mapping(network, mapping);
}
network.computeTemplateMaps();
// Update alignment information
Alignable.setAlignability(network);
if (!debug) {
OrccLogger.noticeln("All calls to printing functions are"
+ " removed for performance purpose.");
} else {
OrccLogger.noticeln("A noticeable deterioration in "
+ "performance could appear due to printing call.");
}
// Build the design from the mapping
design = architectureBuilder.build(network, computedMapping);
}
@Override
protected Result doAdditionalGeneration(Network network) {
final Result result = Result.newInstance();
OrccLogger.traceln("Design generation...");
hwProcessorPrinter.setFpga(fpga);
tceProcessorPrinter.setHwDb(design.getHardwareDatabase());
swProcessorPrinter.setOptions(getOptions());
for (Processor tta : design.getProcessors()) {
String processorPath = outputPath + File.separator + tta.getName();
// Print VHDL description
result.merge(FilesManager.writeFile(
hwProcessorPrinter.getVhdl(tta), processorPath,
tta.getName() + ".vhd"));
// Print high-level description
result.merge(FilesManager.writeFile(
tceProcessorPrinter.getAdf(tta), processorPath,
tta.getName() + ".adf"));
result.merge(FilesManager.writeFile(
tceProcessorPrinter.getIdf(tta), processorPath,
tta.getName() + ".idf"));
// Print assembly code of actor-scheduler
result.merge(FilesManager.writeFile(
swProcessorPrinter.getContent(tta), processorPath,
tta.getName() + ".ll"));
}
// Create HDL project
hwDesignPrinter.setFpga(fpga);
result.merge(FilesManager.writeFile(hwDesignPrinter.getVhdl(design),
outputPath, "top.vhd"));
hwProjectPrinter.setFpga(fpga);
if (fpga.isAltera()) {
result.merge(FilesManager.writeFile(
hwProjectPrinter.getQcf(design), outputPath, "top.qsf"));
result.merge(FilesManager.writeFile(
hwProjectPrinter.getQpf(design), outputPath, "top.qpf"));
} else {
result.merge(FilesManager.writeFile(
hwProjectPrinter.getUcf(design), outputPath, "top.ucf"));
result.merge(FilesManager.writeFile(
hwProjectPrinter.getXise(design), outputPath, "top.xise"));
}
hwTestbenchPrinter.setFpga(fpga);
result.merge(FilesManager.writeFile(hwTestbenchPrinter.getVhdl(design),
outputPath, "top_tb.vhd"));
result.merge(FilesManager.writeFile(hwTestbenchPrinter.getWave(design),
outputPath, "wave.do"));
result.merge(FilesManager.writeFile(hwTestbenchPrinter.getTcl(design),
outputPath, "top.tcl"));
// Create TCE project
String pyPath = outputPath + File.separator + "informations_";
FilesManager.writeFile("", pyPath,"__init__.py");
pyDesignPrinter.setFpga(fpga);
result.merge(FilesManager.writeFile(pyDesignPrinter.getPython(design),
pyPath, "informations.py"));
tceDesignPrinter.setOptions(getOptions());
tceDesignPrinter.setPath(outputPath);
result.merge(FilesManager.writeFile(tceDesignPrinter.getPndf(design),
outputPath, "top.pndf"));
result.merge(FilesManager.writeFile(dota.dot(design), outputPath, "top.dot"));
return result;
}
@Override
protected Result doLibrariesExtraction() {
Result result = FilesManager.extract("/runtime/TTA/libs", outputPath);
result.merge(FilesManager.extract("/runtime/common/scripts", outputPath));
// Will be used later to execute the scripts
String libPath = outputPath + File.separator + "libs";
// Ensure scripts have execution rights
new File(libPath, "ttanetgen").setExecutable(true);
new File(libPath, "ttaanalyse.py").setExecutable(true);
new File(libPath, "ttamergehtml.py").setExecutable(true);
new File(libPath, "ttamergecsv.py").setExecutable(true);
new File(libPath, "ttamerge.py").setExecutable(true);
// TODO: This renaming will become useless when the TTA specific scripts
// will be moved into the right folder (/runtime/TTA/scripts) and
// extracted under <path>/scripts
new File(outputPath, "scripts").renameTo(new File(outputPath, "libs/common"));
return result;
}
@Override
protected Result doGenerateActor(Actor actor) {
swActorPrinter.setProcessor(design.getActorToProcessorMap().get(actor));
swActorPrinter.setActor(actor);
return FilesManager.writeFile(swActorPrinter.getContent(), actorsPath,
actor.getName() + ".ll");
}
}