Initial tt2 support. not production ready!

This commit is contained in:
hneemann 2017-03-03 17:44:21 +01:00
parent ace69a0088
commit a9ab9c0f16
3 changed files with 463 additions and 0 deletions

View File

@ -0,0 +1,353 @@
package de.neemann.digital.builder.tt2;
import de.neemann.digital.analyse.expression.Expression;
import de.neemann.digital.analyse.expression.Not;
import de.neemann.digital.analyse.expression.Operation;
import de.neemann.digital.analyse.expression.Variable;
import de.neemann.digital.builder.*;
import de.neemann.digital.builder.jedec.FuseMapFillerException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.*;
/**
* Exporter for the tt2 format needed by the ATF15xx fitters from ATMEL.
* Created by hneemann on 03.03.17.
*/
public class TT2Exporter implements ExpressionExporter<TT2Exporter> {
private BuilderCollector builder;
private PinMap pinMap;
private int clockPin;
private String name;
private String device;
private OutputStreamWriter writer;
private HashMap<String, Integer> varIndexMap;
private HashMap<String, Integer> outIndexMap;
private TreeMap<ProdInput, StateSet> termMap;
private ArrayList<String> inputs;
private ArrayList<String> outputs;
/**
* Creates a new instance
*/
public TT2Exporter() {
builder = new BuilderCollector();
pinMap = new PinMap();
device = "f1502plcc44";
name = "unknown";
clockPin = 43;
}
@Override
public BuilderInterface getBuilder() {
return builder;
}
/**
* Sets the pin connected to the clock of the ff
*
* @param clockPin the pin number
* @return this for chained calls
*/
public TT2Exporter setClockPin(int clockPin) {
this.clockPin = clockPin;
return this;
}
/**
* Sets the project name used
*
* @param name the project name
* @return this for chained calls
*/
public TT2Exporter setName(String name) {
this.name = name;
return this;
}
/**
* Sets the device name used
*
* @param device the device name
* @return this for chained calls
*/
public TT2Exporter setDevice(String device) {
this.device = device;
return this;
}
@Override
public PinMap getPinMapping() {
return pinMap;
}
@Override
public void writeTo(OutputStream out) throws FuseMapFillerException, IOException, PinMapException {
writeTo(new OutputStreamWriter(out, "ISO-8859-1"));
}
private void writeTo(OutputStreamWriter writer) throws IOException, FuseMapFillerException, PinMapException {
createProductTerms();
this.writer = writer;
line("#$ TOOL CUPL");
line("# Berkeley PLA format generated using Digital");
line("#$ TITLE " + name);
line("#$ MODULE " + name);
line("#$ JEDECFILE " + name);
line("#$ DEVICE " + device);
line("#$ PINS " + getPins());
line(".i " + inputs.size());
line(".o " + outputs.size());
line(".type f");
line(".ilb " + strList(inputs));
line(".ob " + strList(outputs));
line(".phase " + getPhase());
line(".p " + termMap.size());
for (Map.Entry<ProdInput, StateSet> e : termMap.entrySet())
line(e.getKey() + " " + e.getValue());
line(".e");
writer.close();
}
private void createProductTerms() throws FuseMapFillerException {
inputs = builder.getInputs();
varIndexMap = new HashMap<>();
int i = 0;
for (String name : inputs) {
varIndexMap.put(name, i);
i++;
}
ProdInput clkIn = null;
if (!builder.getRegistered().isEmpty()) {
int clk = inputs.size();
inputs.add("CLK");
varIndexMap.put("CLK", i);
i++;
for (String reg : builder.getRegistered().keySet()) {
inputs.add(reg + ".Q");
varIndexMap.put(reg, i);
i++;
}
clkIn = new ProdInput(inputs.size());
clkIn.set(clk, 1);
}
ArrayList<Integer> clkInList = new ArrayList<Integer>();
outputs = new ArrayList<>();
outIndexMap = new HashMap<>();
i = 0;
for (String name : builder.getOutputs()) {
if (builder.getRegistered().containsKey(name)) {
outIndexMap.put(name + ".REG", i++);
outputs.add(name + ".REG");
outIndexMap.put(name + ".AR", i++);
outputs.add(name + ".AR");
clkInList.add(i);
outIndexMap.put(name + ".C", i++);
outputs.add(name + ".C");
} else {
outIndexMap.put(name, i++);
outputs.add(name);
}
}
termMap = new TreeMap<>();
if (!builder.getRegistered().isEmpty()) { // connect clock and ar
StateSet clk = new StateSet(outputs.size());
for (int c : clkInList)
clk.set(c, 1);
termMap.put(clkIn, clk);
// AR
termMap.put(new ProdInput(inputs.size()), new StateSet(outputs.size()));
}
for (Map.Entry<String, Expression> e : builder.getCombinatorial().entrySet())
addExpression(e.getKey(), e.getValue());
for (Map.Entry<String, Expression> e : builder.getRegistered().entrySet())
addExpression(e.getKey() + ".REG", e.getValue());
}
private void addExpression(String name, Expression expression) throws FuseMapFillerException {
if (expression instanceof Operation.Or) {
Operation.Or or = (Operation.Or) expression;
for (Expression e : or.getExpressions())
addProdFor(name, e);
} else
addProdFor(name, expression);
}
private void addProdFor(String name, Expression e) throws FuseMapFillerException {
ProdInput pt = new ProdInput(getInputCount());
if (e instanceof Operation.And) {
Operation.And and = (Operation.And) e;
for (Expression z : and.getExpressions())
pt.add(z);
} else
pt.add(e);
StateSet o = termMap.computeIfAbsent(pt, k -> new StateSet(getOutputCount()));
o.set(getOutNum(name));
}
private String strList(ArrayList<String> pins) {
StringBuilder sb = new StringBuilder();
for (String p : pins) {
if (sb.length() > 0)
sb.append(" ");
sb.append(p);
}
return sb.toString();
}
private void line(String s) throws IOException {
writer.write(s);
writer.write("\r\n");
}
private int getInputCount() {
return varIndexMap.size();
}
private int getVarNum(String identifier) throws FuseMapFillerException {
final Integer i = varIndexMap.get(identifier);
if (i == null)
throw new FuseMapFillerException("ident " + identifier + " not found!");
return i;
}
private int getOutputCount() {
return outIndexMap.size();
}
private int getOutNum(String identifier) {
return outIndexMap.get(identifier);
}
private String getPhase() {
StringBuilder sb = new StringBuilder(getOutputCount());
for (int i = 0; i < getOutputCount(); i++)
sb.append("1");
return sb.toString();
}
private String getPins() throws PinMapException {
StringBuilder sb = new StringBuilder();
int numPins = builder.getInputs().size() + builder.getOutputs().size();
if (!builder.getRegistered().isEmpty())
numPins++;
sb.append(numPins);
for (String i : builder.getInputs()) {
int p = pinMap.getInputFor(i);
sb.append(" ").append(i).append("+:").append(p);
}
if (!builder.getRegistered().isEmpty())
sb.append(" CLK+:").append(clockPin);
for (String o : builder.getOutputs()) {
int p = pinMap.getInputFor(o);
sb.append(" ").append(o).append("+:").append(p);
}
return sb.toString();
}
private static class StateSet implements Comparable<StateSet> {
private final int[] state;
private StateSet(int outputCount) {
state = new int[outputCount];
}
void setAllToUnused() {
Arrays.fill(state, 2);
}
private void set(int i) {
set(i, 1);
}
void set(int i, int value) {
state[i] = value;
}
@Override
public int compareTo(StateSet stateSet) {
for (int i = 0; i < state.length; i++) {
int c = Integer.compare(state[i], stateSet.state[i]);
if (c != 0)
return c;
}
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StateSet stateSet = (StateSet) o;
return Arrays.equals(state, stateSet.state);
}
@Override
public int hashCode() {
return Arrays.hashCode(state);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(state.length);
for (int i : state)
switch (i) {
case 0:
sb.append("0");
break;
case 1:
sb.append("1");
break;
default:
sb.append("-");
}
return sb.toString();
}
}
private final class ProdInput extends StateSet {
private ProdInput(int inputCount) {
super(inputCount);
setAllToUnused();
}
public void add(Expression z) throws FuseMapFillerException {
if (z instanceof Not)
add(((Not) z).getExpression(), true);
else
add(z, false);
}
private void add(Expression var, boolean invers) throws FuseMapFillerException {
if (var instanceof Variable) {
set(getVarNum(((Variable) var).getIdentifier()), invers ? 0 : 1);
} else
throw new FuseMapFillerException("invalid Expression");
}
}
}

View File

@ -0,0 +1,8 @@
/**
* Generator for the OpenABLE Truth Table (tt) format.
* Used to create the input files for the ATF15xx Fitters provided by ATMEL.
* These fitters then are used to create the needed JEDEC files.
* <p>
* Created by hneemann on 03.03.17.
*/
package de.neemann.digital.builder.tt2;

View File

@ -0,0 +1,102 @@
package de.neemann.digital.builder.tt2;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import static de.neemann.digital.analyse.expression.Not.not;
import static de.neemann.digital.analyse.expression.Operation.and;
import static de.neemann.digital.analyse.expression.Operation.or;
import static de.neemann.digital.analyse.expression.Variable.v;
/**
* Created by hneemann on 03.03.17.
*/
public class TT2ExporterTest extends TestCase {
public void testCombinatorial() throws Exception {
TT2Exporter tt2 = new TT2Exporter();
tt2.getPinMapping().setAvailBidirectional(4,5,6,8,20,21);
tt2.getBuilder().addCombinatorial("Y", and(v("A"), v("B")));
tt2.getBuilder().addCombinatorial("X", or(v("A1"), v("B1")));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tt2.writeTo(baos);
assertEquals("#$ TOOL CUPL\r\n" +
"# Berkeley PLA format generated using Digital\r\n" +
"#$ TITLE unknown\r\n" +
"#$ MODULE unknown\r\n" +
"#$ JEDECFILE unknown\r\n" +
"#$ DEVICE f1502plcc44\r\n" +
"#$ PINS 6 A+:4 A1+:5 B+:6 B1+:8 Y+:20 X+:21\r\n" +
".i 4\r\n" +
".o 2\r\n" +
".type f\r\n" +
".ilb A A1 B B1\r\n" +
".ob Y X\r\n" +
".phase 11\r\n" +
".p 3\r\n" +
"1-1- 10\r\n" +
"-1-- 01\r\n" +
"---1 01\r\n" +
".e\r\n",baos.toString());
}
public void testSequential() throws Exception {
TT2Exporter tt2 = new TT2Exporter();
tt2.getPinMapping().setAvailBidirectional(4,5,6,8,20,21);
tt2.getBuilder().addSequential("Yn", and(v("A"), not(v("Yn"))));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tt2.writeTo(baos);
assertEquals("#$ TOOL CUPL\r\n" +
"# Berkeley PLA format generated using Digital\r\n" +
"#$ TITLE unknown\r\n" +
"#$ MODULE unknown\r\n" +
"#$ JEDECFILE unknown\r\n" +
"#$ DEVICE f1502plcc44\r\n" +
"#$ PINS 3 A+:4 CLK+:43 Yn+:5\r\n" +
".i 3\r\n" +
".o 3\r\n" +
".type f\r\n" +
".ilb A CLK Yn.Q\r\n" +
".ob Yn.REG Yn.AR Yn.C\r\n" +
".phase 111\r\n" +
".p 3\r\n" +
"1-0 100\r\n" +
"-1- 001\r\n" +
"--- 000\r\n" +
".e\r\n",baos.toString());
}
public void testSequential2() throws Exception {
TT2Exporter tt2 = new TT2Exporter();
tt2.getPinMapping().setAvailBidirectional(4,5,6,8,20,21);
tt2.getBuilder().addSequential("Yn", and(v("A"), not(v("Yn"))));
tt2.getBuilder().addSequential("Xn", or(v("B"), not(v("Xn"))));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tt2.writeTo(baos);
assertEquals("#$ TOOL CUPL\r\n" +
"# Berkeley PLA format generated using Digital\r\n" +
"#$ TITLE unknown\r\n" +
"#$ MODULE unknown\r\n" +
"#$ JEDECFILE unknown\r\n" +
"#$ DEVICE f1502plcc44\r\n" +
"#$ PINS 5 A+:4 B+:5 CLK+:43 Yn+:6 Xn+:8\r\n" +
".i 5\r\n" +
".o 6\r\n" +
".type f\r\n" +
".ilb A B CLK Xn.Q Yn.Q\r\n" +
".ob Yn.REG Yn.AR Yn.C Xn.REG Xn.AR Xn.C\r\n" +
".phase 111111\r\n" +
".p 5\r\n" +
"1---0 100000\r\n" +
"-1--- 000100\r\n" +
"--1-- 001001\r\n" +
"---0- 000100\r\n" +
"----- 000000\r\n" +
".e\r\n",baos.toString());
}
}