/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.bfh.logisim.hdlgenerator;
import java.util.ArrayList;
import java.util.SortedMap;
import java.util.TreeMap;
import com.bfh.logisim.designrulecheck.CorrectLabel;
import com.bfh.logisim.designrulecheck.Netlist;
import com.bfh.logisim.designrulecheck.NetlistComponent;
import com.bfh.logisim.fpgagui.FPGAReport;
import com.bfh.logisim.fpgagui.MappableResourcesContainer;
import com.bfh.logisim.settings.Settings;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.std.io.PortIO;
import com.cburch.logisim.std.io.ReptarLocalBus;
import com.cburch.logisim.std.wiring.ClockHDLGeneratorFactory;
import com.cburch.logisim.std.wiring.Pin;
public class ToplevelHDLGeneratorFactory extends AbstractHDLGeneratorFactory {
private long FpgaClockFrequency;
private double TickFrequency;
private Circuit MyCircuit;
private MappableResourcesContainer MyIOComponents;
// private boolean useFPGAClock;
public ToplevelHDLGeneratorFactory(long FPGAClock, double TickClock,
Circuit TopLevel, MappableResourcesContainer IOComponents) {
FpgaClockFrequency = FPGAClock;
TickFrequency = TickClock;
MyCircuit = TopLevel;
MyIOComponents = IOComponents;
// this.useFPGAClock = useFPGAClock;
}
@Override
public ArrayList<String> GetComponentDeclarationSection(Netlist TheNetlist,
AttributeSet attrs) {
ArrayList<String> Components = new ArrayList<String>();
int NrOfClockTrees = TheNetlist.NumberOfClockTrees();
if (NrOfClockTrees > 0) {
TickComponentHDLGeneratorFactory Ticker = new TickComponentHDLGeneratorFactory(
FpgaClockFrequency, TickFrequency/* , useFPGAClock */);
Components
.addAll(Ticker.GetComponentInstantiation(TheNetlist, null,
Ticker.getComponentStringIdentifier(),
Settings.VHDL/* , false */));
HDLGeneratorFactory ClockWorker = TheNetlist
.GetAllClockSources()
.get(0)
.getFactory()
.getHDLGenerator(
Settings.VHDL,
TheNetlist.GetAllClockSources().get(0).getAttributeSet());
Components.addAll(ClockWorker
.GetComponentInstantiation(
TheNetlist,
TheNetlist.GetAllClockSources().get(0)
.getAttributeSet(),
TheNetlist
.GetAllClockSources()
.get(0)
.getFactory()
.getHDLName(
TheNetlist.GetAllClockSources()
.get(0).getAttributeSet()),
Settings.VHDL/* , false */));
}
CircuitHDLGeneratorFactory Worker = new CircuitHDLGeneratorFactory(
MyCircuit);
// boolean hasLB = false;
// for(NetlistComponent comp : TheNetlist.GetNormalComponents()){
// if(comp.GetComponent().getFactory() instanceof ReptarLocalBus){
// hasLB = true;
// break;
// }
// }
Components.addAll(Worker.GetComponentInstantiation(TheNetlist, null,
CorrectLabel.getCorrectLabel(MyCircuit.getName()),
Settings.VHDL/* , hasLB */));
return Components;
}
@Override
public String getComponentStringIdentifier() {
return FPGAToplevelName;
}
@Override
public SortedMap<String, Integer> GetInOutList(Netlist TheNetlist,
AttributeSet attrs) {
SortedMap<String, Integer> InOut = new TreeMap<String, Integer>();
for (int NrOfInOut = 0; NrOfInOut < MyIOComponents
.GetNrOfToplevelInOutPins(); NrOfInOut++) {
InOut.put(
HDLGeneratorFactory.FPGAInOutPinName + "_"
+ Integer.toString(NrOfInOut), 1);
}
return InOut;
}
@Override
public SortedMap<String, Integer> GetInputList(Netlist TheNetlist,
AttributeSet attrs) {
SortedMap<String, Integer> Inputs = new TreeMap<String, Integer>();
int NrOfClockTrees = TheNetlist.NumberOfClockTrees();
/* First we instantiate the Clock tree busses when present */
if (NrOfClockTrees > 0 || TheNetlist.RequiresGlobalClockConnection()) {
Inputs.put(TickComponentHDLGeneratorFactory.FPGAClock, 1);
}
for (int NrOfInputs = 0; NrOfInputs < MyIOComponents
.GetNrOfToplevelInputPins(); NrOfInputs++) {
Inputs.put(
HDLGeneratorFactory.FPGAInputPinName + "_"
+ Integer.toString(NrOfInputs), 1);
}
return Inputs;
}
@Override
public ArrayList<String> GetModuleFunctionality(Netlist TheNetlist,
AttributeSet attrs, FPGAReport Reporter, String HDLType) {
ArrayList<String> Contents = new ArrayList<String>();
int NrOfClockTrees = TheNetlist.NumberOfClockTrees();
String Preamble = (HDLType.equals(Settings.VHDL)) ? "" : "assign ";
String BracketOpen = (HDLType.equals(Settings.VHDL)) ? "(" : "[";
String BracketClose = (HDLType.equals(Settings.VHDL)) ? ")" : "]";
String AssignOperator = (HDLType.equals(Settings.VHDL)) ? " <= "
: " = ";
String NotOperator = (HDLType.equals(Settings.VHDL)) ? "NOT " : "~";
StringBuffer Temp = new StringBuffer();
/* First we process all pins */
Contents.addAll(MakeRemarkBlock(
"Here all signal adaptations are performed", 3, HDLType));
for (ArrayList<String> CompId : MyIOComponents.GetComponents()) {
if (MyIOComponents.GetComponent(CompId).GetComponent().getFactory() instanceof Pin) {
Component ThisPin = MyIOComponents.GetComponent(CompId)
.GetComponent();
ArrayList<String> MyMaps = MyIOComponents
.GetMapNamesList(CompId);
if (MyMaps == null) {
Reporter.AddFatalError("Component has no map information, bizar! "
+ CompId.toString());
return Contents;
}
int PinPinId = 0;
for (int MapOffset = 0; MapOffset < MyMaps.size(); MapOffset++) {
String map = MyMaps.get(MapOffset);
int InputId = MyIOComponents.GetFPGAInputPinId(map);
int OutputId = MyIOComponents.GetFPGAOutputPinId(map);
int NrOfPins = MyIOComponents.GetNrOfPins(map);
boolean Invert = MyIOComponents.RequiresToplevelInversion(
CompId, map);
for (int PinId = 0; PinId < NrOfPins; PinId++) {
Temp.setLength(0);
Temp.append(" " + Preamble);
if (InputId >= 0) {
Temp.append("s_"
+ CorrectLabel.getCorrectLabel(ThisPin
.getAttributeSet().getValue(
StdAttr.LABEL)));
if (ThisPin.getEnd(0).getWidth().getWidth() > 1) {
Temp.append(BracketOpen + PinPinId
+ BracketClose);
}
PinPinId++;
Temp.append(AssignOperator);
if (Invert) {
Temp.append(NotOperator);
}
Temp.append(HDLGeneratorFactory.FPGAInputPinName);
Temp.append("_" + Integer.toString(InputId + PinId));
Temp.append(";");
Contents.add(Temp.toString());
}
if (OutputId >= 0) {
Temp.append(HDLGeneratorFactory.FPGAOutputPinName);
Temp.append("_"
+ Integer.toString(OutputId + PinId));
Temp.append(AssignOperator);
if (Invert) {
Temp.append(NotOperator);
}
Temp.append("s_"
+ CorrectLabel.getCorrectLabel(ThisPin
.getAttributeSet().getValue(
StdAttr.LABEL)));
if (ThisPin.getEnd(0).getWidth().getWidth() > 1) {
Temp.append(BracketOpen + PinPinId
+ BracketClose);
}
PinPinId++;
Temp.append(";");
Contents.add(Temp.toString());
}
}
}
}
}
/* Now we process the bubbles */
Contents.addAll(MakeRemarkBlock(
"Here all inlined adaptations are performed", 3, HDLType));
for (ArrayList<String> CompId : MyIOComponents.GetComponents()) {
if (!(MyIOComponents.GetComponent(CompId).GetComponent()
.getFactory() instanceof Pin)
&& !(MyIOComponents.GetComponent(CompId).GetComponent()
.getFactory() instanceof PortIO)
&& !(MyIOComponents.GetComponent(CompId).GetComponent()
.getFactory() instanceof ReptarLocalBus)) {
HDLGeneratorFactory Generator = MyIOComponents
.GetComponent(CompId)
.GetComponent()
.getFactory()
.getHDLGenerator(
HDLType,
MyIOComponents.GetComponent(CompId)
.GetComponent().getAttributeSet());
if (Generator == null) {
Reporter.AddError("No generator for component "
+ CompId.toString());
} else {
Contents.addAll(Generator.GetInlinedCode(HDLType, CompId,
Reporter, MyIOComponents));
}
} else if (MyIOComponents.GetComponent(CompId).GetComponent()
.getFactory() instanceof ReptarLocalBus) {
((ReptarLocalBus) MyIOComponents.GetComponent(CompId)
.GetComponent().getFactory())
.setMapInfo(MyIOComponents);
} else if (MyIOComponents.GetComponent(CompId).GetComponent()
.getFactory() instanceof PortIO) {
((PortIO) MyIOComponents.GetComponent(CompId).GetComponent()
.getFactory()).setMapInfo(MyIOComponents);
}
}
if (NrOfClockTrees > 0) {
Contents.addAll(MakeRemarkBlock(
"Here the clock tree components are defined", 3, HDLType));
TickComponentHDLGeneratorFactory Ticker = new TickComponentHDLGeneratorFactory(
FpgaClockFrequency, TickFrequency/* , useFPGAClock */);
Contents.addAll(Ticker.GetComponentMap(null, (long) 0, null,
Reporter, "", HDLType));
long index = 0;
for (Component Clockgen : TheNetlist.GetAllClockSources()) {
NetlistComponent ThisClock = new NetlistComponent(Clockgen);
Contents.addAll(Clockgen
.getFactory()
.getHDLGenerator(HDLType,
ThisClock.GetComponent().getAttributeSet())
.GetComponentMap(TheNetlist, index++, ThisClock,
Reporter, "Bla", HDLType));
}
}
Contents.add("");
/* Here the map is performed */
Contents.addAll(MakeRemarkBlock(
"Here the toplevel component is connected", 3, HDLType));
CircuitHDLGeneratorFactory DUT = new CircuitHDLGeneratorFactory(
MyCircuit);
Contents.addAll(DUT.GetComponentMap(TheNetlist, (long) 0, null,
Reporter, CorrectLabel.getCorrectLabel(MyCircuit.getName()),
HDLType));
return Contents;
}
@Override
public SortedMap<String, Integer> GetOutputList(Netlist TheNetlist,
AttributeSet attrs) {
SortedMap<String, Integer> Outputs = new TreeMap<String, Integer>();
int k = 0;
for (int NrOfOutputs = 0; NrOfOutputs < MyIOComponents
.GetNrOfToplevelOutputPins(); NrOfOutputs++) {
if (MyIOComponents
.GetFPGAOutputPinId(MyIOComponents.currentBoardName
+ ":/LocalBus") > -1
&& (NrOfOutputs == MyIOComponents
.GetFPGAOutputPinId(MyIOComponents.currentBoardName
+ ":/LocalBus") || NrOfOutputs == MyIOComponents
.GetFPGAOutputPinId(MyIOComponents.currentBoardName
+ ":/LocalBus") + 1)) {
Outputs.put("FPGA_LB_OUT_" + Integer.toString(k), 1);
k++;
} else {
Outputs.put(HDLGeneratorFactory.FPGAOutputPinName + "_"
+ Integer.toString(NrOfOutputs), 1);
}
}
return Outputs;
}
@Override
public String GetSubDir() {
/*
* this method returns the module directory where the HDL code needs to
* be placed
*/
return "toplevel";
}
@Override
public SortedMap<String, Integer> GetWireList(AttributeSet attrs,
Netlist Nets) {
SortedMap<String, Integer> Wires = new TreeMap<String, Integer>();
int NrOfClockTrees = Nets.NumberOfClockTrees();
int NrOfInputBubbles = Nets.NumberOfInputBubbles();
int NrOfInOutBubbles = Nets.NumberOfInOutBubbles();
int NrOfOutputBubbles = Nets.NumberOfOutputBubbles();
int NrOfInputPorts = Nets.NumberOfInputPorts();
int NrOfInOutPorts = Nets.NumberOfInOutPorts();
int NrOfOutputPorts = Nets.NumberOfOutputPorts();
if (NrOfClockTrees > 0) {
Wires.put(TickComponentHDLGeneratorFactory.FPGATick, 1);
for (int clockBus = 0; clockBus < NrOfClockTrees; clockBus++) {
Wires.put("s_" + ClockTreeName + Integer.toString(clockBus),
ClockHDLGeneratorFactory.NrOfClockBits);
}
}
if (NrOfInputBubbles > 0) {
if (NrOfInputBubbles > 1) {
Wires.put("s_LOGISIM_INPUT_BUBBLES", NrOfInputBubbles);
} else {
Wires.put("s_LOGISIM_INPUT_BUBBLES", 0);
}
}
if (NrOfInOutBubbles > 0) {
if (NrOfInOutBubbles > 1) {
Wires.put("s_LOGISIM_INOUT_BUBBLES", NrOfInOutBubbles);
} else {
Wires.put("s_LOGISIM_INOUT_BUBBLES", 0);
}
}
if (NrOfOutputBubbles > 0) {
if (NrOfOutputBubbles > 1) {
Wires.put("s_LOGISIM_OUTPUT_BUBBLES", NrOfOutputBubbles);
} else {
Wires.put("s_LOGISIM_OUTPUT_BUBBLES", 0);
}
}
if (NrOfInputPorts > 0) {
for (int input = 0; input < NrOfInputPorts; input++) {
String SName = "s_"
+ CorrectLabel.getCorrectLabel(Nets.GetInputPin(input)
.GetComponent().getAttributeSet()
.getValue(StdAttr.LABEL));
int NrOfBits = Nets.GetInputPin(input).GetComponent().getEnd(0)
.getWidth().getWidth();
Wires.put(SName, NrOfBits);
}
}
if (NrOfInOutPorts > 0) {
for (int inout = 0; inout < NrOfInOutPorts; inout++) {
String SName = "s_"
+ CorrectLabel.getCorrectLabel(Nets.GetInOutPin(inout)
.GetComponent().getAttributeSet()
.getValue(StdAttr.LABEL));
int NrOfBits = Nets.GetInOutPin(inout).GetComponent().getEnd(0)
.getWidth().getWidth();
Wires.put(SName, NrOfBits);
}
}
if (NrOfOutputPorts > 0) {
for (int output = 0; output < NrOfOutputPorts; output++) {
String SName = "s_"
+ CorrectLabel.getCorrectLabel(Nets
.GetOutputPin(output).GetComponent()
.getAttributeSet().getValue(StdAttr.LABEL));
int NrOfBits = Nets.GetOutputPin(output).GetComponent()
.getEnd(0).getWidth().getWidth();
Wires.put(SName, NrOfBits);
}
}
return Wires;
}
@Override
public boolean HDLTargetSupported(String HDLType, AttributeSet attrs) {
return true;
}
}