/*******************************************************************************
* 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.cburch.logisim.std.io;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.SortedMap;
import java.util.TreeMap;
import com.bfh.logisim.designrulecheck.Netlist;
import com.bfh.logisim.designrulecheck.NetlistComponent;
import com.bfh.logisim.fpgagui.FPGAReport;
import com.bfh.logisim.hdlgenerator.AbstractHDLGeneratorFactory;
import com.bfh.logisim.hdlgenerator.FileWriter;
import com.bfh.logisim.settings.Settings;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.Splitter;
import com.cburch.logisim.circuit.Wire;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.EndData;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.instance.StdAttr;
public class PortHDLGeneratorFactory extends AbstractHDLGeneratorFactory {
private class InOutMap {
private Point p;
private Type type;
private int portNb;
public InOutMap(Type type, Point p, int portNb) {
this.p = p;
this.type = type;
this.portNb = portNb;
}
public int getEnd() {
return p.y;
}
public int getPortNb() {
return portNb;
}
public int getSize() {
return (p.y - p.x) + 1;
}
public int getStart() {
return p.x;
}
public Type getType() {
return type;
}
}
private enum Type {
IN, OUT, INOUT
}
private static final String inBusName = "PIO_IN_BUS";
private static final String outBusName = "PIO_OUT_BUS";
private static final String inOutBusName = "PIO_INOUT_BUS";
private HashMap<String, HashMap<Integer, InOutMap>> compMap = new HashMap<String, HashMap<Integer, InOutMap>>();
private Location findEndConnection(Location start, Circuit circ) {
Location newLoc = start;
Collection<Wire> wiresCol = circ.getWires(newLoc);
Iterator<Wire> wires = wiresCol.iterator();
if (wiresCol.size() != 1) {
return null;
}
Wire net = null;
Wire oldNet = null;
while (wires.hasNext()) {
net = wires.next();
if (net != oldNet) {
newLoc = net.getEnd0().equals(newLoc) ? net.getEnd1() : net
.getEnd0();
wiresCol = circ.getWires(newLoc);
wires = wiresCol.iterator();
oldNet = net;
}
}
return newLoc;
}
// #4
@Override
public ArrayList<String> GetArchitecture(Netlist TheNetlist,
AttributeSet attrs, String ComponentName, FPGAReport Reporter,
String HDLType) {
ArrayList<String> Contents = new ArrayList<String>();
if (HDLType.equals(Settings.VHDL)) {
Contents.addAll(FileWriter.getGenerateRemark(ComponentName,
HDLType, TheNetlist.projName()));
Contents.add("");
Contents.add("ARCHITECTURE PlatformIndependent OF "
+ ComponentName.toString() + " IS ");
Contents.add("");
Contents.add("BEGIN");
Contents.add("");
int currentInOutIdx = -1;
for (int i = 0; i < compMap.get(ComponentName).size(); i++) {
if (compMap.get(ComponentName).get(i).getType() == Type.IN) {
if (compMap.get(ComponentName).get(i).getSize() == 1) {
Contents.add(inOutBusName + "_" + currentInOutIdx + "("
+ compMap.get(ComponentName).get(i).getEnd()
+ ")" + " <= " + inBusName + "_" + i + ";");
} else {
Contents.add(inOutBusName + "_" + currentInOutIdx + "("
+ compMap.get(ComponentName).get(i).getEnd()
+ " DOWNTO "
+ compMap.get(ComponentName).get(i).getStart()
+ ")" + " <= " + inBusName + "_" + i + ";");
}
} else if (compMap.get(ComponentName).get(i).getType() == Type.OUT) {
if (compMap.get(ComponentName).get(i).getSize() == 1) {
Contents.add(outBusName + "_" + i + " <= "
+ inOutBusName + "_" + currentInOutIdx + "("
+ compMap.get(ComponentName).get(i).getEnd()
+ ");");
} else {
Contents.add(outBusName + "_" + i + " <= "
+ inOutBusName + "_" + currentInOutIdx + "("
+ compMap.get(ComponentName).get(i).getEnd()
+ " DOWNTO "
+ compMap.get(ComponentName).get(i).getStart()
+ ");");
}
} else if (compMap.get(ComponentName).get(i).getType() == Type.INOUT) {
currentInOutIdx = i;
}
}
Contents.add("");
Contents.add("END PlatformIndependent;");
}
return Contents;
}
private Point getBitRange(byte[] bits, int wireNr) {
int i;
int start = -1;
boolean first = true;
int count = -1;
for (i = 0; i < bits.length; i++) {
if (bits[i] == wireNr) {
if (first) {
first = false;
start = i;
}
count++;
}
}
return new Point(start, start + count);
}
// #8,10,11,13
@Override
public String getComponentStringIdentifier() {
return "PORTIO";
}
// #2
@Override
public ArrayList<String> GetEntity(Netlist TheNetlist, AttributeSet attrs,
String ComponentName, FPGAReport Reporter, String HDLType) {
NetlistComponent ComponentInfo = null;
compMap.put(ComponentName, new HashMap<Integer, InOutMap>());
for (NetlistComponent comp : TheNetlist.GetNormalComponents()) {
if (comp.GetComponent().getAttributeSet().equals(attrs)) {
ComponentInfo = comp;
break;
}
}
int mapIdx = 0;
for (int portNr = 0; portNr < ComponentInfo.GetComponent().getEnds()
.size(); portNr++) {
Location splitterLoc = findEndConnection(ComponentInfo
.GetComponent().getEnd(portNr).getLocation(),
TheNetlist.getCircuit());
if (splitterLoc == null) {
Reporter.AddFatalError("Found 0, 2 or more connections on PortIO's splitter ("
+ ComponentName + ")");
return null;
}
for (Splitter split : TheNetlist.getSplitters()) {
if (split.getLocation().equals(splitterLoc)) { // trouve le
// premier
// splitter du
// Port
compMap.get(ComponentName).put(
mapIdx,
new InOutMap(Type.INOUT, new Point(0, split
.GetEndpoints().length - 1), portNr));
int splitPortNr = 0;
for (EndData end : split.getEnds()) {
if (!end.getLocation().equals(splitterLoc)) { // parcours
// les
// sortie
// du
// splitter
Location compLoc = findEndConnection(
end.getLocation(), TheNetlist.getCircuit());
if (compLoc == null) {
Reporter.AddFatalError("Found 0, 2 or more connections on PortIO's splitter ("
+ ComponentName + ")");
return null;
}
for (Component comp : TheNetlist.getCircuit()
.getNonWires(compLoc)) { // parcours le
// (les?)
// composant
// connecte a la
// sortie du
// splitter
for (EndData port : comp.getEnds()) {
if (port.getLocation().equals(compLoc)) { // trouve
// le
// port
// du
// composant
// relie
// au
// splitter
if (!(comp instanceof Splitter)
&& !(comp instanceof PortIO)) {
if (port.isInput()) {
compMap.get(ComponentName)
.put(mapIdx,
new InOutMap(
Type.OUT,
getBitRange(
split.GetEndpoints(),
splitPortNr),
portNr));
} else if (port.isOutput()) {
compMap.get(ComponentName)
.put(mapIdx,
new InOutMap(
Type.IN,
getBitRange(
split.GetEndpoints(),
splitPortNr),
portNr));
}
} else {
Reporter.AddFatalError("Cannot connect PortIO's splitter to other splitter or PortIO ("
+ ComponentName + ")");
return null;
}
}
}
}
}
mapIdx++;
splitPortNr++;
}
}
}
}
ArrayList<String> Contents = new ArrayList<String>();
Contents.addAll(FileWriter.getGenerateRemark(ComponentName,
Settings.VHDL, TheNetlist.projName()));
Contents.addAll(FileWriter.getExtendedLibrary());
Contents.add("ENTITY " + ComponentName + " IS");
Contents.add(" PORT ( ");
for (int i = 0; i < compMap.get(ComponentName).size(); i++) {
String line = " ";
switch (compMap.get(ComponentName).get(i).getType()) {
case IN:
line += inBusName + "_" + i + " : IN ";
break;
case OUT:
line += outBusName + "_" + i + " : OUT ";
break;
case INOUT:
line += inOutBusName + "_" + i + " : INOUT ";
break;
default:
Reporter.AddFatalError("Found component of unknown type ("
+ compMap.get(ComponentName).get(i).toString() + ")");
}
if (compMap.get(ComponentName).get(i).getSize() == 1) {
line += "std_logic";
} else {
line += "std_logic_vector ("
+ (compMap.get(ComponentName).get(i).getSize() - 1)
+ " DOWNTO 0)";
}
if (i == (compMap.get(ComponentName).size() - 1)) {
line += ")";
}
line += ";";
Contents.add(line);
}
Contents.add("END " + ComponentName + ";");
Contents.add("");
return Contents;
}
// #6
@Override
public SortedMap<String, Integer> GetInOutList(Netlist TheNetlist,
AttributeSet attrs) {
String ComponentName = attrs.getValue(StdAttr.LABEL);
SortedMap<String, Integer> InOuts = new TreeMap<String, Integer>();
for (int i = 0; i < compMap.get(ComponentName).size(); i++) {
if (compMap.get(ComponentName).get(i).getType() == Type.INOUT) {
InOuts.put(inOutBusName + "_" + i, compMap.get(ComponentName)
.get(i).getSize());
}
}
return InOuts;
}
// #5
@Override
public SortedMap<String, Integer> GetInputList(Netlist TheNetlist,
AttributeSet attrs) {
String ComponentName = attrs.getValue(StdAttr.LABEL);
SortedMap<String, Integer> Inputs = new TreeMap<String, Integer>();
for (int i = 0; i < compMap.get(ComponentName).size(); i++) {
if (compMap.get(ComponentName).get(i).getType() == Type.IN) {
Inputs.put(inBusName + "_" + i,
compMap.get(ComponentName).get(i).getSize());
}
}
return Inputs;
}
// #7
@Override
public SortedMap<String, Integer> GetOutputList(Netlist TheNetlist,
AttributeSet attrs) {
String ComponentName = attrs.getValue(StdAttr.LABEL);
SortedMap<String, Integer> Outputs = new TreeMap<String, Integer>();
for (int i = 0; i < compMap.get(ComponentName).size(); i++) {
if (compMap.get(ComponentName).get(i).getType() == Type.OUT) {
Outputs.put(outBusName + "_" + i, compMap.get(ComponentName)
.get(i).getSize());
}
}
return Outputs;
}
// #9,12
@Override
public SortedMap<String, String> GetPortMap(Netlist Nets,
NetlistComponent ComponentInfo, FPGAReport Reporter, String HDLType) {
String ComponentName = ComponentInfo.GetComponent().getAttributeSet()
.getValue(StdAttr.LABEL);
SortedMap<String, String> PortMap = new TreeMap<String, String>();
for (int i = 0; i < compMap.get(ComponentName).size(); i++) {
String key = null;
String name = null;
int start = -1;
int end = -1;
switch (compMap.get(ComponentName).get(i).getType()) {
case IN:
key = inBusName + "_" + i;
name = BusName
+ Integer.toString(Nets.GetNetId(ComponentInfo
.getEnd(compMap.get(ComponentName).get(i)
.getPortNb()).GetConnection((byte) 0)
.GetParrentNet()));
start = compMap.get(ComponentName).get(i).getStart();
end = compMap.get(ComponentName).get(i).getEnd();
break;
case OUT:
key = outBusName + "_" + i;
name = BusName
+ Integer.toString(Nets.GetNetId(ComponentInfo
.getEnd(compMap.get(ComponentName).get(i)
.getPortNb()).GetConnection((byte) 0)
.GetParrentNet()));
start = compMap.get(ComponentName).get(i).getStart();
end = compMap.get(ComponentName).get(i).getEnd();
break;
case INOUT:
key = inOutBusName + "_" + i;
name = LocalInOutBubbleBusname;
start = end = ComponentInfo.GetLocalBubbleInOutStartId();
start += compMap.get(ComponentName).get(i).getStart()
+ compMap.get(ComponentName).get(i).getPortNb() * 32;
end += compMap.get(ComponentName).get(i).getEnd()
+ compMap.get(ComponentName).get(i).getPortNb() * 32;
break;
default:
Reporter.AddFatalError("Found component of unknown type ("
+ compMap.get(ComponentName).get(i).toString() + ")");
}
if (compMap.get(ComponentName).get(i).getSize() == 1) {
PortMap.put(key, name + "(" + end + ")");
} else {
PortMap.put(key, name + "(" + end + " DOWNTO " + start + ")");
}
}
return PortMap;
}
// #1,3
@Override
public String GetSubDir() {
/*
* this method returns the module sub-directory where the HDL code is
* placed
*/
return "io";
}
@Override
public boolean HDLTargetSupported(String HDLType, AttributeSet attrs) {
return HDLType.equals(Settings.VHDL);
}
}