/*
* Copyright (c) 2012, 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.c.hls;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import net.sf.orcc.backends.c.CBackend;
import net.sf.orcc.backends.transform.CastArgFuncCall;
import net.sf.orcc.backends.transform.DisconnectedOutputPortRemoval;
import net.sf.orcc.backends.transform.Multi2MonoToken;
import net.sf.orcc.backends.util.Validator;
import net.sf.orcc.df.Action;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.Connection;
import net.sf.orcc.df.Instance;
import net.sf.orcc.df.Network;
import net.sf.orcc.df.Port;
import net.sf.orcc.df.transform.ArgumentEvaluator;
import net.sf.orcc.df.transform.BroadcastAdder;
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.df.util.NetworkValidator;
import net.sf.orcc.ir.transform.RenameTransformation;
import net.sf.orcc.tools.classifier.Classifier;
import net.sf.orcc.tools.merger.action.ActionMerger;
import net.sf.orcc.util.FilesManager;
import net.sf.orcc.util.OrccAttributes;
import net.sf.orcc.util.OrccLogger;
import net.sf.orcc.util.Result;
/**
* C backend targeting high-level synthesis tools
*
* @author Mariem Abid
* @author Khaled Jerbi
* @author Herve Yviquel
*/
public class HLSBackend extends CBackend {
private String commandPath;
private String vhdlPath;
private final NetworkPrinter networkPrinter;
private final NetworkTestBenchPrinter netTestBenchPrinter;
private final TopVhdlPrinter topVHDLPrinter;
private final BatchCommandPrinter batchCommandPrinter;
private final BatchCommandPrinterLinux batchCommandPrinterLinux;
private final InstancePrinter instancePrinter;
private final InstanceCosimPrinter instanceCosimPrinter;
private final InstancePrinterCast instancePrinterCast;
private final ActorTopVhdlPrinter actorTopVHDLPrinter;
private final ActorNetworkTestBenchPrinter actorNetTestBenchPrinter;
private final UnitaryBatchCommandPrinter unitaryBatchCommandPrinter;
private final UnitaryBatchCommandPrinterLinux unitaryBatchCommandPrinterLinux;
public HLSBackend() {
networkPrinter = new NetworkPrinter();
netTestBenchPrinter = new NetworkTestBenchPrinter();
topVHDLPrinter = new TopVhdlPrinter();
batchCommandPrinter = new BatchCommandPrinter();
batchCommandPrinterLinux = new BatchCommandPrinterLinux();
instancePrinter = new InstancePrinter();
instanceCosimPrinter = new InstanceCosimPrinter();
instancePrinterCast = new InstancePrinterCast();
actorTopVHDLPrinter = new ActorTopVhdlPrinter();
actorNetTestBenchPrinter = new ActorNetworkTestBenchPrinter();
unitaryBatchCommandPrinter = new UnitaryBatchCommandPrinter();
unitaryBatchCommandPrinterLinux = new UnitaryBatchCommandPrinterLinux();
}
@Override
protected Result doLibrariesExtraction() {
Result result = FilesManager.extract("/runtime/HLS/scripts", outputPath);
result.merge(FilesManager.extract("/runtime/common/scripts", outputPath));
String libPath = outputPath + File.separator + "scripts";
// Ensure scripts have execution rights
new File(libPath, "hlsanalyse.py").setExecutable(true);
return Result.newInstance();
}
@Override
protected void doInitializeOptions() {
// Configure paths were files will be generated
srcPath = outputPath + File.separator + "HLSBackend";
commandPath = srcPath + File.separator + "batchCommand";
vhdlPath = srcPath + File.separator + "TopVHDL";
// Load options map into various code generator instances
networkPrinter.setOptions(getOptions());
netTestBenchPrinter.setOptions(getOptions());
topVHDLPrinter.setOptions(getOptions());
batchCommandPrinter.setOptions(getOptions());
batchCommandPrinterLinux.setOptions(getOptions());
instancePrinter.setOptions(getOptions());
instanceCosimPrinter.setOptions(getOptions());
instancePrinterCast.setOptions(getOptions());
actorTopVHDLPrinter.setOptions(getOptions());
actorNetTestBenchPrinter.setOptions(getOptions());
unitaryBatchCommandPrinter.setOptions(getOptions());
unitaryBatchCommandPrinterLinux.setOptions(getOptions());
// Configure the map used in RenameTransformation
final Map<String, String> renameMap = new HashMap<String, String>();
renameMap.put("abs", "abs_my_precious");
renameMap.put("getw", "getw_my_precious");
renameMap.put("index", "index_my_precious");
renameMap.put("max", "max_my_precious");
renameMap.put("min", "min_my_precious");
renameMap.put("select", "select_my_precious");
renameMap.put("OUT", "OUT_my_precious");
renameMap.put("IN", "IN_my_precious");
renameMap.put("bitand", "bitand_my_precious");
// -----------------------------------------------------
// Transformations that will be applied on the Network
// -----------------------------------------------------
networkTransfos.add(new Instantiator(false));
networkTransfos.add(new NetworkFlattener());
if (classify) {
OrccLogger.traceln("Classification of actors...");
networkTransfos.add(new Classifier());
}
if (mergeActors) {
OrccLogger.traceln("Merging of actors...");
networkTransfos.add(new ActionMerger());
}
networkTransfos.add(new BroadcastAdder());
networkTransfos.add(new ArgumentEvaluator());
networkTransfos.add(new DisconnectedOutputPortRemoval());
networkTransfos.add(new UnitImporter());
networkTransfos.add(new RenameTransformation(renameMap));
networkTransfos.add(new TypeResizer(true, true, true, false));
// -----------------------------------------------------
// Transformations that will be applied on Instances
// -----------------------------------------------------
if (mergeActions) {
childrenTransfos.add(new ActionMerger());
}
if (convertMulti2Mono) {
childrenTransfos.add(new Multi2MonoToken());
}
childrenTransfos.add(new DfVisitor<Void>(new CastArgFuncCall()));
}
@Override
protected void doValidate(Network network) {
Validator.checkMinimalFifoSize(network, fifoSize);
new NetworkValidator().doSwitch(network);
}
@Override
protected void beforeGeneration(Network network) {
network.computeTemplateMaps();
}
@Override
protected Result doGenerateNetwork(Network network) {
final Result result = Result.newInstance();
result.merge(FilesManager.writeFile(networkPrinter.fifoSimPackContent(), vhdlPath, "sim_package.vhd"));
result.merge(FilesManager.writeFile(networkPrinter.fifoFileContent(), vhdlPath, "ram_tab.vhd"));
return result;
}
@Override
protected Result doAdditionalGeneration(Network network) {
final Result result = Result.newInstance();
netTestBenchPrinter.setNetwork(network);
topVHDLPrinter.setNetwork(network);
batchCommandPrinter.setNetwork(network);
batchCommandPrinterLinux.setNetwork(network);
result.merge(FilesManager.writeFile(netTestBenchPrinter.getNetworkFileContent(), vhdlPath, network.getName() + "_TopTestBench.vhd"));
result.merge(FilesManager.writeFile(topVHDLPrinter.getNetworkFileContent(), vhdlPath, network.getName() + "Top.vhd"));
result.merge(FilesManager.writeFile(batchCommandPrinter.getNetworkFileContent(), commandPath, "Command.bat"));
result.merge(FilesManager.writeFile(batchCommandPrinterLinux.getNetworkFileContent(), commandPath, "command-linux.sh"));
return result;
}
@Override
protected Result doGenerateInstance(Instance instance) {
instancePrinter.setInstance(instance);
final Result result = Result.newInstance();
result.merge(FilesManager.writeFile(instancePrinter.getFileContent(),
srcPath, instance.getName() + ".cpp"));
result.merge(FilesManager.writeFile(instancePrinter.script(srcPath),
srcPath, "script_" + instance.getName() + ".tcl"));
result.merge(FilesManager.writeFile(instancePrinter.directive(srcPath),
srcPath, "directive_" + instance.getName() + ".tcl"));
return result;
}
@Override
protected Result doAdditionalGeneration(Instance instance) {
instanceCosimPrinter.setInstance(instance);
instancePrinterCast.setInstance(instance);
actorTopVHDLPrinter.setInstance(instance);
actorNetTestBenchPrinter.setInstance(instance);
unitaryBatchCommandPrinter.setInstance(instance);
unitaryBatchCommandPrinterLinux.setInstance(instance);
final Result result = Result.newInstance();
final String instanceName = instance.getName();
result.merge(FilesManager.writeFile(
instanceCosimPrinter.getFileContent(), srcPath, instanceName
+ "TestBench.cpp"));
{
final Actor actor = instance.getActor();
if (actor.hasAttribute(OrccAttributes.DIRECTIVE_DEBUG)) {
for (Action action : actor.getActions()) {
// The base used to form folder and files names
final String base = "cast_" + instanceName + "_tab_"
+ action.getName() + "_read";
result.merge(FilesManager.writeFile(instancePrinterCast
.getFileContentReadDebug(action.getName()),
srcPath, base + ".cpp"));
result.merge(FilesManager.writeFile(
instancePrinterCast.script(srcPath, base), srcPath,
"script_" + base + ".tcl"));
}
}
for (final Port portIn : actor.getInputs()) {
final Connection connIn = instance.getIncomingPortMap().get(portIn);
if (connIn != null) {
// The base used to form folder and files names
final String base = "cast_" + instanceName + "_"
+ connIn.getTargetPort().getName() + "_write";
result.merge(FilesManager.writeFile(
instancePrinterCast.getFileContentWrite(connIn),
srcPath, base + ".cpp"));
result.merge(FilesManager.writeFile(
instancePrinterCast.script(srcPath, base), srcPath,
"script_" + base + ".tcl"));
}
}
for (final Port portOut : actor.getOutputs()) {
final Connection connOut = instance.getOutgoingPortMap()
.get(portOut).get(0);
if (connOut != null) {
// The base used to form folder and files names
final String base = "cast_" + instanceName + "_"
+ connOut.getSourcePort().getName() + "_read";
result.merge(FilesManager.writeFile(
instancePrinterCast.getFileContentRead(connOut),
srcPath, base + ".cpp"));
result.merge(FilesManager.writeFile(
instancePrinterCast.script(srcPath, base), srcPath,
"script_" + base + ".tcl"));
}
}
}
result.merge(FilesManager.writeFile(
actorTopVHDLPrinter.ActorTopFileContent(), srcPath
+ File.separator + instanceName + "TopVHDL",
instanceName + "Top.vhd"));
result.merge(FilesManager.writeFile(
actorNetTestBenchPrinter.actorNetworkFileContent(), srcPath
+ File.separator + instanceName + "TopVHDL",
instanceName + "_TopTestBench.vhd"));
result.merge(FilesManager.writeFile(
unitaryBatchCommandPrinter.getFileContentBatch(), commandPath,
"Command_" + instanceName + ".bat"));
result.merge(FilesManager.writeFile(
unitaryBatchCommandPrinterLinux.getFileContentBatch(),
commandPath, "command-linux_" + instanceName + ".sh"));
return result;
}
}