mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-22 11:55:15 -04:00
Merge branch 'master' into treeSearch
This commit is contained in:
commit
b4cbe8d9e0
@ -2,7 +2,9 @@ Release Notes
|
||||
|
||||
HEAD, planned as v0.27
|
||||
|
||||
- Added fixed point and floating point number formats
|
||||
- Added fixed point and floating point number formats.
|
||||
- Added a CSV truth table export and import.
|
||||
- Added 74299
|
||||
- Refactoring of the expression format setting.
|
||||
CAUTION: All the general settings are maybe lost at restart!
|
||||
To avoid this, open the .digital.cfg file and remove the <entry>
|
||||
|
1843
src/main/dig/lib/DIL Chips/74xx/shift register/74299.dig
Normal file
1843
src/main/dig/lib/DIL Chips/74xx/shift register/74299.dig
Normal file
File diff suppressed because it is too large
Load Diff
179
src/main/java/de/neemann/digital/analyse/CSVImporter.java
Normal file
179
src/main/java/de/neemann/digital/analyse/CSVImporter.java
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.analyse;
|
||||
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Used to read a CSV file
|
||||
*/
|
||||
public final class CSVImporter {
|
||||
|
||||
private CSVImporter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a CSV file
|
||||
*
|
||||
* @param file the file
|
||||
* @return the truth table
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public static TruthTable readCSV(File file) throws IOException {
|
||||
return readCSV(new FileReader(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a CSV file
|
||||
*
|
||||
* @param csv the string to read
|
||||
* @return the truth table
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public static TruthTable readCSV(String csv) throws IOException {
|
||||
return readCSV(new StringReader(csv));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a CSV file
|
||||
*
|
||||
* @param csv the reader
|
||||
* @return the truth table
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public static TruthTable readCSV(Reader csv) throws IOException {
|
||||
BufferedReader r = new BufferedReader(csv);
|
||||
TruthTable tt = readHeader(r);
|
||||
|
||||
while (true) {
|
||||
String line = r.readLine();
|
||||
if (line == null)
|
||||
return tt;
|
||||
line = line.trim();
|
||||
if (!line.isEmpty())
|
||||
parseLine(tt, line);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static TruthTable readHeader(BufferedReader r) throws IOException {
|
||||
String header;
|
||||
do {
|
||||
header = r.readLine();
|
||||
} while (header != null && header.length() == 0);
|
||||
|
||||
if (header == null)
|
||||
throw new IOException(Lang.get("err_csvNoHeaderFound"));
|
||||
|
||||
ArrayList<Variable> vars = new ArrayList<>();
|
||||
|
||||
TruthTable tt = null;
|
||||
for (String ss : header.split(",")) {
|
||||
String h = ss.trim();
|
||||
if (h.isEmpty())
|
||||
tt = new TruthTable(vars);
|
||||
else {
|
||||
if (tt == null)
|
||||
vars.add(new Variable(h));
|
||||
else
|
||||
tt.addResult(h, new BoolTableByteArray(1 << vars.size()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (tt == null || tt.getResultCount() == 0)
|
||||
throw new IOException(Lang.get("err_csvNoOutputValuesFound"));
|
||||
|
||||
return tt;
|
||||
}
|
||||
|
||||
private static void parseLine(TruthTable tt, String line) throws IOException {
|
||||
int resNum = tt.getResultCount();
|
||||
int varNum = tt.getVars().size();
|
||||
int mask = 1 << (varNum - 1);
|
||||
ArrayList<Integer> dc = new ArrayList<>();
|
||||
int row = 0;
|
||||
int rCol = 0;
|
||||
Generator generator = null;
|
||||
for (String ss : line.split(",")) {
|
||||
String e = ss.trim().toLowerCase();
|
||||
if (e.isEmpty())
|
||||
generator = new Generator(row, dc);
|
||||
else {
|
||||
if (generator == null) {
|
||||
if (mask == 0)
|
||||
throw new IOException(Lang.get("err_csvToManyValues"));
|
||||
if (e.equals("1"))
|
||||
row |= mask;
|
||||
else if (e.equals("x"))
|
||||
dc.add(mask);
|
||||
mask = mask >> 1;
|
||||
} else {
|
||||
if (rCol >= resNum)
|
||||
throw new IOException(Lang.get("err_csvToManyValues"));
|
||||
if (e.equals("1"))
|
||||
generator.addCol(rCol);
|
||||
rCol++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mask != 0)
|
||||
throw new IOException(Lang.get("err_csvNotEnoughValues"));
|
||||
|
||||
if (generator != null)
|
||||
generator.applyTo(tt);
|
||||
}
|
||||
|
||||
private static final class Generator {
|
||||
private final int row;
|
||||
private final ArrayList<Integer> dc;
|
||||
private final ArrayList<Integer> cols;
|
||||
|
||||
private Generator(int row, ArrayList<Integer> dc) {
|
||||
this.row = row;
|
||||
this.dc = dc;
|
||||
cols = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addCol(int rCol) {
|
||||
cols.add(rCol);
|
||||
}
|
||||
|
||||
public void applyTo(TruthTable tt) {
|
||||
if (cols.isEmpty())
|
||||
return;
|
||||
|
||||
int vars = tt.getVars().size();
|
||||
|
||||
if (dc.isEmpty())
|
||||
for (int col : cols)
|
||||
tt.setValue(row, vars + col, 1);
|
||||
else {
|
||||
int dcRows = 1 << dc.size();
|
||||
for (int i = 0; i < dcRows; i++) {
|
||||
int r = row;
|
||||
int bitMask = 1;
|
||||
for (int orMask : dc) {
|
||||
if ((i & bitMask) != 0)
|
||||
r = r | orMask;
|
||||
bitMask *= 2;
|
||||
}
|
||||
|
||||
for (int col : cols)
|
||||
tt.setValue(r, vars + col, 1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -14,8 +14,6 @@ import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
|
||||
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.undo.Copyable;
|
||||
|
||||
import java.io.*;
|
||||
@ -41,9 +39,13 @@ public class TruthTable implements Copyable<TruthTable> {
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public static TruthTable readFromFile(File filename) throws IOException {
|
||||
XStream xStream = getxStream();
|
||||
try (InputStream in = new FileInputStream(filename)) {
|
||||
return (TruthTable) xStream.fromXML(in);
|
||||
if (filename.getName().toLowerCase().endsWith(".csv"))
|
||||
return CSVImporter.readCSV(filename);
|
||||
else {
|
||||
XStream xStream = getxStream();
|
||||
try (InputStream in = new FileInputStream(filename)) {
|
||||
return (TruthTable) xStream.fromXML(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,45 +63,6 @@ public class TruthTable implements Copyable<TruthTable> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the table as hex file to be loaded in a ROM or LUT element.
|
||||
*
|
||||
* @param filename filename
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void saveHex(File filename) throws IOException {
|
||||
if (results.size() > 63)
|
||||
throw new IOException(Lang.get("err_tableHasToManyResultColumns"));
|
||||
|
||||
try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), StandardCharsets.UTF_8))) {
|
||||
saveHex(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the table as hex file to be loaded in a ROM or LUT element.
|
||||
*
|
||||
* @param writer the filename to use
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void saveHex(Writer writer) throws IOException {
|
||||
writer.write("v2.0 raw\n");
|
||||
int count = results.get(0).getValues().size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
long val = 0;
|
||||
long mask = 1;
|
||||
for (Result r : results) {
|
||||
ThreeStateValue v = r.getValues().get(i);
|
||||
if (v == ThreeStateValue.one)
|
||||
val |= mask;
|
||||
mask *= 2;
|
||||
}
|
||||
writer.write(Long.toHexString(val));
|
||||
writer.write('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static XStream getxStream() {
|
||||
XStream xStream = new XStreamValid();
|
||||
xStream.alias("truthTable", TruthTable.class);
|
||||
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.analyse.format;
|
||||
|
||||
import de.neemann.digital.analyse.TruthTable;
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
|
||||
import de.neemann.digital.core.Bits;
|
||||
|
||||
/**
|
||||
* Exports a table in LogicFriday format
|
||||
*/
|
||||
public class TruthTableFormatterCSV implements TruthTableFormatter {
|
||||
|
||||
@Override
|
||||
public String format(TruthTable truthTable) throws ExpressionException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String n : truthTable.getVarNames())
|
||||
sb.append(n).append(",");
|
||||
for (String n : truthTable.getResultNames())
|
||||
sb.append(',').append(n);
|
||||
sb.append('\n');
|
||||
|
||||
export(sb, truthTable);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void export(StringBuilder sb, TruthTable truthTable) {
|
||||
int vars = truthTable.getVars().size();
|
||||
for (int r = 0; r < truthTable.getRows(); r++) {
|
||||
long m = Bits.up(1, vars - 1);
|
||||
for (int c = 0; c < vars; c++) {
|
||||
if ((r & m) == 0)
|
||||
sb.append('0');
|
||||
else
|
||||
sb.append('1');
|
||||
sb.append(',');
|
||||
m = m >> 1;
|
||||
}
|
||||
for (int c = 0; c < truthTable.getResultCount(); c++) {
|
||||
ThreeStateValue v = truthTable.getResult(c).get(r);
|
||||
sb.append(',').append(v.toString());
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Helmut Neemann
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.analyse.format;
|
||||
|
||||
import de.neemann.digital.analyse.TruthTable;
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
/**
|
||||
* Formats a truth table
|
||||
*/
|
||||
public class TruthTableFormatterHex implements TruthTableFormatter {
|
||||
|
||||
@Override
|
||||
public String format(TruthTable truthTable) throws ExpressionException {
|
||||
if (truthTable.getResultCount() > 63)
|
||||
throw new ExpressionException(Lang.get("err_tableHasToManyResultColumns"));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("v2.0 raw\n");
|
||||
|
||||
int count = truthTable.getResult(0).size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
long val = 0;
|
||||
long mask = 1;
|
||||
for (int j = 0; j < truthTable.getResultCount(); j++) {
|
||||
ThreeStateValue v = truthTable.getResult(j).get(i);
|
||||
if (v == ThreeStateValue.one)
|
||||
val |= mask;
|
||||
mask *= 2;
|
||||
}
|
||||
sb.append(Long.toHexString(val));
|
||||
sb.append('\n');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -145,10 +145,14 @@ public final class Bits {
|
||||
if (str.indexOf(':') >= 0)
|
||||
return decodeFixed(str);
|
||||
if (str.indexOf('.') > -1) {
|
||||
if (str.endsWith("d") || str.endsWith("D"))
|
||||
return Double.doubleToLongBits(Double.parseDouble(str.substring(0, str.length() - 1)));
|
||||
else
|
||||
return Float.floatToIntBits(Float.parseFloat(str));
|
||||
try {
|
||||
if (str.endsWith("d") || str.endsWith("D"))
|
||||
return Double.doubleToLongBits(Double.parseDouble(str.substring(0, str.length() - 1)));
|
||||
else
|
||||
return Float.floatToIntBits(Float.parseFloat(str));
|
||||
} catch (java.lang.NumberFormatException e) {
|
||||
throw new NumberFormatException(str, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int p = 0;
|
||||
|
@ -499,9 +499,17 @@ public enum IntFormat {
|
||||
|
||||
switch (inValue.getBits()) {
|
||||
case 32:
|
||||
return Float.toString(Float.intBitsToFloat((int) inValue.getValue()));
|
||||
float f = Float.intBitsToFloat((int) inValue.getValue());
|
||||
if (Float.isFinite(f))
|
||||
return Float.toString(f);
|
||||
else
|
||||
return HEX_FORMATTER.formatToEdit(inValue);
|
||||
case 64:
|
||||
return Double.longBitsToDouble(inValue.getValue()) + "d";
|
||||
double d = Double.longBitsToDouble(inValue.getValue());
|
||||
if (Double.isFinite(d))
|
||||
return d + "d";
|
||||
else
|
||||
return HEX_FORMATTER.formatToEdit(inValue);
|
||||
default:
|
||||
return HEX_FORMATTER.formatToEdit(inValue);
|
||||
}
|
||||
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.gui.components.table;
|
||||
|
||||
import de.neemann.digital.analyse.expression.*;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Exports a CSV table containing only the prime implicants
|
||||
*/
|
||||
public class ExpressionListenerCSVCondensed implements ExpressionListener {
|
||||
private final ArrayList<Result> results;
|
||||
private final HashSet<String> names;
|
||||
private final VariableVisitor variables;
|
||||
private StringBuilder str;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public ExpressionListenerCSVCondensed() {
|
||||
results = new ArrayList<>();
|
||||
names = new HashSet<>();
|
||||
variables = new VariableVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resultFound(String name, Expression expression) throws FormatterException, ExpressionException {
|
||||
if (!names.contains(name)) {
|
||||
names.add(name);
|
||||
results.add(new Result(name, expression, results.size()));
|
||||
expression.traverse(variables);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws FormatterException, ExpressionException {
|
||||
str = new StringBuilder();
|
||||
for (Variable var : variables.getVariables())
|
||||
str.append(var.getIdentifier()).append(",");
|
||||
for (Result r : results)
|
||||
str.append(",").append(r.name);
|
||||
str.append("\n");
|
||||
|
||||
for (Result r : results)
|
||||
r.createString(str, variables.getVariables(), results.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
private static final class Result {
|
||||
private final String name;
|
||||
private final Expression expression;
|
||||
private final int number;
|
||||
|
||||
private Result(String name, Expression expression, int number) {
|
||||
this.name = name;
|
||||
this.expression = expression;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public void createString(StringBuilder sb, Collection<Variable> variables, int results) throws ExpressionException {
|
||||
if (expression instanceof Operation.Or) {
|
||||
ArrayList<Expression> o = ((Operation.Or) expression).getExpressions();
|
||||
for (Expression e : o)
|
||||
addPrime(sb, e, variables, results);
|
||||
} else
|
||||
addPrime(sb, expression, variables, results);
|
||||
}
|
||||
|
||||
private void addPrime(StringBuilder sb, Expression and, Collection<Variable> variables, int results) throws ExpressionException {
|
||||
if (and instanceof Operation.And)
|
||||
addAnd(sb, and, variables, results);
|
||||
else if (and instanceof Variable)
|
||||
addVar(sb, ((Variable) and).getIdentifier(), variables, results, false);
|
||||
else if (and instanceof Not && ((Not) and).getExpression() instanceof Variable)
|
||||
addVar(sb, ((Variable) (((Not) and).getExpression())).getIdentifier(), variables, results, true);
|
||||
else
|
||||
throw new ExpressionException("invalid expression");
|
||||
}
|
||||
|
||||
private void addVar(StringBuilder sb, String identifier, Collection<Variable> variables, int results, boolean invert) {
|
||||
for (Variable var : variables) {
|
||||
if (var.getIdentifier().endsWith(identifier)) {
|
||||
if (invert)
|
||||
sb.append("0,");
|
||||
else
|
||||
sb.append("1,");
|
||||
} else
|
||||
sb.append("X,");
|
||||
}
|
||||
|
||||
for (int i = 0; i < results; i++) {
|
||||
if (i == number)
|
||||
sb.append(",1");
|
||||
else
|
||||
sb.append(",0");
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
private void addAnd(StringBuilder sb, Expression and, Collection<Variable> variables, int results) throws ExpressionException {
|
||||
HashSet<String> v = new HashSet<>();
|
||||
HashSet<String> nv = new HashSet<>();
|
||||
if (and instanceof Operation.And) {
|
||||
Operation.And a = (Operation.And) and;
|
||||
for (Expression va : a.getExpressions()) {
|
||||
Expression var = va;
|
||||
HashSet<String> map = v;
|
||||
if (var instanceof Not) {
|
||||
map = nv;
|
||||
var = ((Not) var).getExpression();
|
||||
}
|
||||
if (var instanceof Variable)
|
||||
map.add(((Variable) var).getIdentifier());
|
||||
else
|
||||
throw new ExpressionException("invalid expression");
|
||||
}
|
||||
} else
|
||||
throw new ExpressionException("invalid expression");
|
||||
|
||||
for (Variable var : variables) {
|
||||
if (v.contains(var.getIdentifier()))
|
||||
sb.append("1,");
|
||||
else if (nv.contains(var.getIdentifier()))
|
||||
sb.append("0,");
|
||||
else
|
||||
sb.append("X,");
|
||||
}
|
||||
|
||||
for (int i = 0; i < results; i++) {
|
||||
if (i == number)
|
||||
sb.append(",1");
|
||||
else
|
||||
sb.append(",0");
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
import de.neemann.digital.analyse.expression.modify.*;
|
||||
import de.neemann.digital.analyse.format.TruthTableFormatter;
|
||||
import de.neemann.digital.analyse.format.TruthTableFormatterCSV;
|
||||
import de.neemann.digital.analyse.format.TruthTableFormatterHex;
|
||||
import de.neemann.digital.analyse.format.TruthTableFormatterTestCase;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
|
||||
import de.neemann.digital.builder.ATF150x.ATFDevice;
|
||||
@ -60,7 +62,9 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -373,6 +377,7 @@ public class TableDialog extends JDialog {
|
||||
JFileChooser fc = new MyFileChooser();
|
||||
if (TableDialog.this.filename != null)
|
||||
fc.setSelectedFile(SaveAsHelper.checkSuffix(TableDialog.this.filename, "tru"));
|
||||
fc.setFileFilter(new FileNameExtensionFilter(Lang.get("msg_truthTableCSV"), "csv"));
|
||||
fc.setFileFilter(new FileNameExtensionFilter(Lang.get("msg_truthTable"), "tru"));
|
||||
if (fc.showOpenDialog(TableDialog.this) == JFileChooser.APPROVE_OPTION) {
|
||||
try {
|
||||
@ -437,22 +442,29 @@ public class TableDialog extends JDialog {
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_table_createFunctionFixture_tt")).createJMenuItem());
|
||||
|
||||
fileMenu.add(new ToolTipAction(Lang.get("menu_table_exportHex")) {
|
||||
JMenu export = new JMenu(Lang.get("menu_export"));
|
||||
fileMenu.add(export);
|
||||
export.add(new FileExportActionConfirm(Lang.get("menu_table_exportHex"), "hex") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int res = JOptionPane.OK_OPTION;
|
||||
if (undoManager.getActual().getVars().size() > 20)
|
||||
res = JOptionPane.showConfirmDialog(TableDialog.this, Lang.get("msg_tableHasManyRowsConfirm"));
|
||||
if (res == JOptionPane.OK_OPTION) {
|
||||
JFileChooser fc = new MyFileChooser();
|
||||
if (TableDialog.this.filename != null)
|
||||
fc.setSelectedFile(SaveAsHelper.checkSuffix(TableDialog.this.filename, "hex"));
|
||||
new SaveAsHelper(TableDialog.this, fc, "hex")
|
||||
.checkOverwrite(file -> undoManager.getActual().saveHex(file));
|
||||
}
|
||||
protected String getString() throws ExpressionException {
|
||||
return new TruthTableFormatterHex().format(undoManager.getActual());
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_table_exportHex_tt")).createJMenuItem());
|
||||
|
||||
export.add(new FileExportAction(Lang.get("menu_table_exportCSVCondensed"), "csv") {
|
||||
@Override
|
||||
protected String getString() throws FormatterException, ExpressionException {
|
||||
ExpressionListenerCSVCondensed expressionListener = new ExpressionListenerCSVCondensed();
|
||||
lastGeneratedExpressions.replayTo(expressionListener);
|
||||
expressionListener.close();
|
||||
return expressionListener.toString();
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_table_exportCSVCondensed_tt")).createJMenuItem());
|
||||
export.add(new FileExportActionConfirm(Lang.get("menu_table_exportCSV"), "csv") {
|
||||
@Override
|
||||
protected String getString() throws ExpressionException {
|
||||
return new TruthTableFormatterCSV().format(undoManager.getActual());
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_table_exportCSV_tt")).createJMenuItem());
|
||||
|
||||
createJK = new JCheckBoxMenuItem(Lang.get("menu_table_JK"));
|
||||
createJK.addActionListener(e -> calculateExpressions());
|
||||
@ -998,4 +1010,55 @@ public class TableDialog extends JDialog {
|
||||
|
||||
abstract ExpressionListener createExpressionListener() throws ExpressionException;
|
||||
}
|
||||
|
||||
private abstract class FileExportAction extends ToolTipAction {
|
||||
private final String suffix;
|
||||
|
||||
private FileExportAction(String name, String suffix) {
|
||||
super(name);
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (confirmExport()) {
|
||||
JFileChooser fc = new MyFileChooser();
|
||||
if (TableDialog.this.filename != null)
|
||||
fc.setSelectedFile(SaveAsHelper.checkSuffix(TableDialog.this.filename, suffix));
|
||||
new SaveAsHelper(TableDialog.this, fc, suffix)
|
||||
.checkOverwrite(file -> {
|
||||
try {
|
||||
try (Writer w = new FileWriter(file)) {
|
||||
w.write(getString());
|
||||
}
|
||||
} catch (FormatterException | ExpressionException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean confirmExport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract String getString() throws FormatterException, ExpressionException;
|
||||
}
|
||||
|
||||
private abstract class FileExportActionConfirm extends FileExportAction {
|
||||
|
||||
private FileExportActionConfirm(String name, String suffix) {
|
||||
super(name, suffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean confirmExport() {
|
||||
int res = JOptionPane.OK_OPTION;
|
||||
if (undoManager.getActual().getVars().size() > 20)
|
||||
res = JOptionPane.showConfirmDialog(TableDialog.this, Lang.get("msg_tableHasManyRowsConfirm"));
|
||||
return res == JOptionPane.OK_OPTION;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ public class Tokenizer {
|
||||
boolean wasChar = true;
|
||||
do {
|
||||
c = readChar();
|
||||
if (isNumberChar(c) || isHexChar(c) || c == 'x' || c == 'X') {
|
||||
if (isNumberChar(c) || isHexChar(c) || c == 'x' || c == 'X' || c == ':' || c == '.') {
|
||||
builder.append((char) c);
|
||||
} else {
|
||||
unreadChar(c);
|
||||
|
@ -1216,6 +1216,11 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
<string name="err_ROM_noFileGivenToLoad">Es ist kein Dateiname für das automatische Neuladen verfügbar!</string>
|
||||
<string name="err_virtualSignal_N_DeclaredTwiceInLine_N">Virtuelles Signal {0} doppelt definiert in Zeile {1}!</string>
|
||||
|
||||
<string name="err_csvNoHeaderFound">Kein Header gefunden!</string>
|
||||
<string name="err_csvNoOutputValuesFound">Keine Ausganswerte gefunden!</string>
|
||||
<string name="err_csvNotEnoughValues">Nicht genug Werte in einer Zeile!</string>
|
||||
<string name="err_csvToManyValues">Zu viel Werte in einer Zeile!</string>
|
||||
|
||||
<string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
|
||||
<string name="key_AddrBits_tt">Anzahl der Adress-Bits, die verwendet werden.</string>
|
||||
<string name="key_Bits">Daten-Bits</string>
|
||||
@ -1835,8 +1840,12 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
rein kombinatorisch ist!
|
||||
</string>
|
||||
|
||||
<string name="menu_table_exportHex">Erzeuge HEX</string>
|
||||
<string name="menu_table_exportHex">HEX</string>
|
||||
<string name="menu_table_exportHex_tt">Die HEX-Datei kann in ein ROM oder eine LUT geladen werden.</string>
|
||||
<string name="menu_table_exportCSV">CSV</string>
|
||||
<string name="menu_table_exportCSV_tt">Eine CSV Datei, welche die komplette Warheitstabelle enthält.</string>
|
||||
<string name="menu_table_exportCSVCondensed">CSV, Primimplikanten</string>
|
||||
<string name="menu_table_exportCSVCondensed_tt">Eine CSV Datei, welche nur die Primimplikanten enthält.</string>
|
||||
<string name="menu_table_new">Neu</string>
|
||||
<string name="menu_table_new_combinatorial">Kombinatorisch</string>
|
||||
<string name="menu_table_new_sequential">Automat</string>
|
||||
@ -2059,6 +2068,7 @@ Stellen Sie sicher, dass der Flash-Vorgang abgeschlossen ist, bevor Sie diesen D
|
||||
<string name="msg_testPassed_N">{0} Testzeilen überprüft</string>
|
||||
<string name="msg_testFile">Testdatei</string>
|
||||
<string name="msg_truthTable">Wahrheitstabelle</string>
|
||||
<string name="msg_truthTableCSV">Comma Separated Values, CSV</string>
|
||||
<string name="msg_errorImportingSvg">Fehler beim Import der SVG-Datei.</string>
|
||||
<string name="msg_errorCreatingSvgTemplate">Fehler beim Erzeugen der SVG-Datei.</string>
|
||||
<string name="msg_couldNotCreateStats">Statistik konnte nicht erzeugt werden.</string>
|
||||
|
@ -1203,6 +1203,11 @@
|
||||
<string name="err_ROM_noFileGivenToLoad">There is no file name available for the automatic reload!</string>
|
||||
<string name="err_virtualSignal_N_DeclaredTwiceInLine_N">Virtual signal {0} declared twice in line {1}!</string>
|
||||
|
||||
<string name="err_csvNoHeaderFound">No header found!</string>
|
||||
<string name="err_csvNoOutputValuesFound">No output values found!</string>
|
||||
<string name="err_csvNotEnoughValues">Not enough values in one line!</string>
|
||||
<string name="err_csvToManyValues">Too many values in one line!</string>
|
||||
|
||||
<string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
|
||||
<string name="key_AddrBits_tt">Number of address bits used.</string>
|
||||
<string name="key_Bits">Data Bits</string>
|
||||
@ -1822,8 +1827,12 @@
|
||||
purely combinatorial!
|
||||
</string>
|
||||
|
||||
<string name="menu_table_exportHex">Export HEX</string>
|
||||
<string name="menu_table_exportHex">HEX</string>
|
||||
<string name="menu_table_exportHex_tt">You can load the HEX file to a ROM or a LUT.</string>
|
||||
<string name="menu_table_exportCSV">CSV</string>
|
||||
<string name="menu_table_exportCSV_tt">A CSV file containing the complete truth table.</string>
|
||||
<string name="menu_table_exportCSVCondensed">CSV, prime implicants</string>
|
||||
<string name="menu_table_exportCSVCondensed_tt">A CSV file containing only the prime implicants.</string>
|
||||
<string name="menu_table_new">New</string>
|
||||
<string name="menu_table_new_combinatorial">Combinatorial</string>
|
||||
<string name="menu_table_new_sequential">Sequential</string>
|
||||
@ -2054,6 +2063,7 @@
|
||||
<string name="msg_testPassed_N">{0} test rows passed</string>
|
||||
<string name="msg_testFile">File Tested</string>
|
||||
<string name="msg_truthTable">Truth Table</string>
|
||||
<string name="msg_truthTableCSV">Comma Separated Values, CSV</string>
|
||||
<string name="msg_errorImportingSvg">Error while importing the SVG file.</string>
|
||||
<string name="msg_errorCreatingSvgTemplate">Error creating the SVG template.</string>
|
||||
<string name="msg_couldNotCreateStats">Statistics could not be created.</string>
|
||||
|
195
src/test/java/de/neemann/digital/analyse/CSVImporterTest.java
Normal file
195
src/test/java/de/neemann/digital/analyse/CSVImporterTest.java
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.analyse;
|
||||
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
|
||||
import de.neemann.digital.gui.components.table.ExpressionListenerCSVCondensed;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CSVImporterTest extends TestCase {
|
||||
|
||||
public void testSimple() throws IOException {
|
||||
TruthTable tt = CSVImporter.readCSV("A,B,,Y\n0,0,,0\n0,1,,0\n1,0,,0\n1,1,,1");
|
||||
assertNotNull(tt);
|
||||
|
||||
ArrayList<Variable> vars = tt.getVars();
|
||||
assertEquals(2, vars.size());
|
||||
assertEquals("A", vars.get(0).getIdentifier());
|
||||
assertEquals("B", vars.get(1).getIdentifier());
|
||||
assertEquals(1, tt.getResultCount());
|
||||
assertEquals("Y", tt.getResultName(0));
|
||||
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(0));
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(1));
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(2));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(3));
|
||||
}
|
||||
|
||||
public void testDC() throws IOException {
|
||||
TruthTable tt = CSVImporter.readCSV("A,B,,Y,X\nx,x,,1,0\n1,x,,0,1");
|
||||
assertNotNull(tt);
|
||||
|
||||
ArrayList<Variable> vars = tt.getVars();
|
||||
assertEquals(2, vars.size());
|
||||
assertEquals("A", vars.get(0).getIdentifier());
|
||||
assertEquals("B", vars.get(1).getIdentifier());
|
||||
assertEquals(2, tt.getResultCount());
|
||||
assertEquals("Y", tt.getResultName(0));
|
||||
assertEquals("X", tt.getResultName(1));
|
||||
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(0));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(1));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(2));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(3));
|
||||
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(1).get(0));
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(1).get(1));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(1).get(2));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(1).get(3));
|
||||
}
|
||||
|
||||
public void testDC2() throws IOException {
|
||||
TruthTable tt = CSVImporter.readCSV("A,B,C,,Y\nx,1,x,,1\n");
|
||||
assertNotNull(tt);
|
||||
|
||||
ArrayList<Variable> vars = tt.getVars();
|
||||
assertEquals(3, vars.size());
|
||||
assertEquals("A", vars.get(0).getIdentifier());
|
||||
assertEquals("B", vars.get(1).getIdentifier());
|
||||
assertEquals("C", vars.get(2).getIdentifier());
|
||||
assertEquals(1, tt.getResultCount());
|
||||
assertEquals("Y", tt.getResultName(0));
|
||||
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(0));
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(1));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(2));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(3));
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(4));
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(5));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(6));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(7));
|
||||
}
|
||||
|
||||
public void testMultiplePrimeUsages() throws IOException {
|
||||
TruthTable tt = CSVImporter.readCSV("A,B,,Y,X\n1,1,,1,1\n1,0,,0,1\n0,1,,0,1");
|
||||
assertNotNull(tt);
|
||||
|
||||
ArrayList<Variable> vars = tt.getVars();
|
||||
assertEquals(2, vars.size());
|
||||
assertEquals("A", vars.get(0).getIdentifier());
|
||||
assertEquals("B", vars.get(1).getIdentifier());
|
||||
assertEquals(2, tt.getResultCount());
|
||||
assertEquals("Y", tt.getResultName(0));
|
||||
assertEquals("X", tt.getResultName(1));
|
||||
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(0));
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(1));
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(0).get(2));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(0).get(3));
|
||||
|
||||
assertEquals(ThreeStateValue.zero, tt.getResult(1).get(0));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(1).get(1));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(1).get(2));
|
||||
assertEquals(ThreeStateValue.one, tt.getResult(1).get(3));
|
||||
}
|
||||
|
||||
public void testBug1() throws IOException {
|
||||
TruthTable tt = CSVImporter.readCSV("A,B,,Y,X,Z\n1,1,,1,1,1\n1,0,,0,1,1\n0,1,,0,1,1");
|
||||
assertNotNull(tt);
|
||||
|
||||
try {
|
||||
CSVImporter.readCSV("A,B,,Y,X,Z\n1,1,,1,1,1\n1,0,,0,1,1,1\n0,1,,0,1,1");
|
||||
fail();
|
||||
} catch (IOException e) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testIncomplete() {
|
||||
try {
|
||||
CSVImporter.readCSV("\n\n");
|
||||
fail();
|
||||
} catch (IOException e) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
CSVImporter.readCSV("A,B,Y,X\n1,");
|
||||
fail();
|
||||
} catch (IOException e) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
CSVImporter.readCSV("A,B,Y,,\n1,");
|
||||
fail();
|
||||
} catch (IOException e) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
CSVImporter.readCSV("A,B,,Y,X\n1,");
|
||||
fail();
|
||||
} catch (IOException e) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
CSVImporter.readCSV("A,B,,Y,X\n1,1,1");
|
||||
fail();
|
||||
} catch (IOException e) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
CSVImporter.readCSV("A,B,,Y,X\n1,1,,1,1,1");
|
||||
fail();
|
||||
} catch (IOException e) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testAdder() throws Exception {
|
||||
loopTest("A_0,A_1,B_0,B_1,,S_1,S_0,C\n" +
|
||||
"1,0,1,0,,1,0,0\n" +
|
||||
"1,1,1,1,,1,0,0\n" +
|
||||
"0,0,X,1,,1,0,0\n" +
|
||||
"0,1,X,0,,1,0,0\n" +
|
||||
"X,0,0,1,,1,0,0\n" +
|
||||
"X,1,0,0,,1,0,0\n" +
|
||||
"0,X,1,X,,0,1,0\n" +
|
||||
"1,X,0,X,,0,1,0\n" +
|
||||
"1,X,1,1,,0,0,1\n" +
|
||||
"1,1,1,X,,0,0,1\n" +
|
||||
"X,1,X,1,,0,0,1\n");
|
||||
}
|
||||
|
||||
public void testAndOr() throws Exception {
|
||||
loopTest("A,B,,X,Y\n" +
|
||||
"1,1,,1,0\n" +
|
||||
"1,X,,0,1\n" +
|
||||
"X,1,,0,1\n");
|
||||
}
|
||||
|
||||
private void loopTest(String csv) throws Exception {
|
||||
TruthTable tt = CSVImporter.readCSV(csv);
|
||||
|
||||
ExpressionListenerCSVCondensed elCSV = new ExpressionListenerCSVCondensed();
|
||||
for (int i = 0; i < tt.getResultCount(); i++) {
|
||||
MinimizerInterface mi = new MinimizerQuineMcCluskey();
|
||||
mi.minimize(tt.getVars(), tt.getResult(i), tt.getResultName(i), elCSV);
|
||||
}
|
||||
elCSV.close();
|
||||
|
||||
assertEquals(csv, elCSV.toString());
|
||||
|
||||
}
|
||||
}
|
@ -38,52 +38,4 @@ public class TruthTableTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testHexExportSingle() throws Exception {
|
||||
ArrayList<Variable> vars = Variable.vars(3);
|
||||
TruthTable t = new TruthTable(vars).addResult();
|
||||
BoolTableByteArray result = (BoolTableByteArray) t.getResult(0);
|
||||
for (int i = 0; i < t.getRows(); i++) {
|
||||
result.set(i, i % 2);
|
||||
}
|
||||
StringWriter w = new StringWriter();
|
||||
t.saveHex(w);
|
||||
w.close();
|
||||
|
||||
assertEquals("v2.0 raw\n" +
|
||||
"0\n" +
|
||||
"1\n" +
|
||||
"0\n" +
|
||||
"1\n" +
|
||||
"0\n" +
|
||||
"1\n" +
|
||||
"0\n" +
|
||||
"1\n", w.toString());
|
||||
}
|
||||
|
||||
public void testHexExportTwo() throws Exception {
|
||||
ArrayList<Variable> vars = Variable.vars(3);
|
||||
TruthTable t = new TruthTable(vars).addResult();
|
||||
BoolTableByteArray result = (BoolTableByteArray) t.getResult(0);
|
||||
for (int i = 0; i < t.getRows(); i++) {
|
||||
result.set(i, i % 2);
|
||||
}
|
||||
t.addResult();
|
||||
result = (BoolTableByteArray) t.getResult(1);
|
||||
for (int i = 0; i < t.getRows(); i++) {
|
||||
result.set(i, (i + 1) % 2);
|
||||
}
|
||||
StringWriter w = new StringWriter();
|
||||
t.saveHex(w);
|
||||
w.close();
|
||||
|
||||
assertEquals("v2.0 raw\n" +
|
||||
"2\n" +
|
||||
"1\n" +
|
||||
"2\n" +
|
||||
"1\n" +
|
||||
"2\n" +
|
||||
"1\n" +
|
||||
"2\n" +
|
||||
"1\n", w.toString());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.analyse.format;
|
||||
|
||||
import de.neemann.digital.analyse.TruthTable;
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TruthTableFormatterCSVTest extends TestCase {
|
||||
|
||||
public void testSimple() throws ExpressionException {
|
||||
TruthTable tt = new TruthTable(2);
|
||||
tt.addResult("X", new BoolTableByteArray(new byte[]{0, 1, 1, 1}));
|
||||
tt.addResult("Y", new BoolTableByteArray(new byte[]{0, 0, 0, 1}));
|
||||
String res = new TruthTableFormatterCSV().format(tt);
|
||||
|
||||
assertEquals("A,B,,X,Y\n" +
|
||||
"0,0,,0,0\n" +
|
||||
"0,1,,1,0\n" +
|
||||
"1,0,,1,0\n" +
|
||||
"1,1,,1,1\n", res);
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.analyse.format;
|
||||
|
||||
import de.neemann.digital.analyse.TruthTable;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class TruthTableFormatterHexTest extends TestCase {
|
||||
|
||||
public void testHexExportSingle() throws Exception {
|
||||
ArrayList<Variable> vars = Variable.vars(3);
|
||||
TruthTable t = new TruthTable(vars).addResult();
|
||||
BoolTableByteArray result = (BoolTableByteArray) t.getResult(0);
|
||||
for (int i = 0; i < t.getRows(); i++) {
|
||||
result.set(i, i % 2);
|
||||
}
|
||||
String hex = new TruthTableFormatterHex().format(t);
|
||||
|
||||
assertEquals("v2.0 raw\n" +
|
||||
"0\n" +
|
||||
"1\n" +
|
||||
"0\n" +
|
||||
"1\n" +
|
||||
"0\n" +
|
||||
"1\n" +
|
||||
"0\n" +
|
||||
"1\n", hex);
|
||||
}
|
||||
|
||||
public void testHexExportTwo() throws Exception {
|
||||
ArrayList<Variable> vars = Variable.vars(3);
|
||||
TruthTable t = new TruthTable(vars).addResult();
|
||||
BoolTableByteArray result = (BoolTableByteArray) t.getResult(0);
|
||||
for (int i = 0; i < t.getRows(); i++) {
|
||||
result.set(i, i % 2);
|
||||
}
|
||||
t.addResult();
|
||||
result = (BoolTableByteArray) t.getResult(1);
|
||||
for (int i = 0; i < t.getRows(); i++) {
|
||||
result.set(i, (i + 1) % 2);
|
||||
}
|
||||
|
||||
String hex = new TruthTableFormatterHex().format(t);
|
||||
|
||||
assertEquals("v2.0 raw\n" +
|
||||
"2\n" +
|
||||
"1\n" +
|
||||
"2\n" +
|
||||
"1\n" +
|
||||
"2\n" +
|
||||
"1\n" +
|
||||
"2\n" +
|
||||
"1\n", hex);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Helmut Neemann
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.gui.components.table;
|
||||
|
||||
import de.neemann.digital.analyse.CSVImporter;
|
||||
import de.neemann.digital.analyse.TruthTable;
|
||||
import de.neemann.digital.analyse.expression.*;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
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;
|
||||
|
||||
public class ExpressionListenerCSVCondensedTest extends TestCase {
|
||||
Variable a = new Variable("A");
|
||||
Variable b = new Variable("B");
|
||||
Variable c = new Variable("C");
|
||||
|
||||
public void testSimple() throws FormatterException, ExpressionException, IOException {
|
||||
Expression expression = or(and(a, b), c);
|
||||
|
||||
assertEquals("A,B,C,,Y\n" +
|
||||
"1,1,X,,1\n" +
|
||||
"X,X,1,,1\n", create(expression));
|
||||
}
|
||||
|
||||
public void testNot() throws FormatterException, ExpressionException, IOException {
|
||||
Expression expression = or(and(a, not(b)), not(c));
|
||||
|
||||
assertEquals("A,B,C,,Y\n" +
|
||||
"1,0,X,,1\n" +
|
||||
"X,X,0,,1\n", create(expression));
|
||||
}
|
||||
|
||||
public void testTwo() throws FormatterException, ExpressionException, IOException {
|
||||
Expression e1 = new NamedExpression("Y", or(and(a, b), c));
|
||||
Expression e2 = new NamedExpression("X", a);
|
||||
|
||||
assertEquals("A,B,C,,Y,X\n" +
|
||||
"1,1,X,,1,0\n" +
|
||||
"X,X,1,,1,0\n" +
|
||||
"1,X,X,,0,1\n", create(e1, e2));
|
||||
}
|
||||
|
||||
public void testXor() throws FormatterException, ExpressionException, IOException {
|
||||
Expression expression = or(
|
||||
and(not(a), not(b), c),
|
||||
and(not(a), b, not(c)),
|
||||
and(a, not(b), not(c)),
|
||||
and(a, b, c)
|
||||
);
|
||||
|
||||
assertEquals("A,B,C,,Y\n" +
|
||||
"0,0,1,,1\n" +
|
||||
"0,1,0,,1\n" +
|
||||
"1,0,0,,1\n" +
|
||||
"1,1,1,,1\n", create(expression));
|
||||
}
|
||||
|
||||
private String create(Expression... expressions) throws FormatterException, ExpressionException, IOException {
|
||||
ExpressionListenerCSVCondensed el = new ExpressionListenerCSVCondensed();
|
||||
|
||||
for (Expression e : expressions) {
|
||||
String name = "Y";
|
||||
if (e instanceof NamedExpression) {
|
||||
NamedExpression ne = (NamedExpression) e;
|
||||
name = ne.getName();
|
||||
e = ne.getExpression();
|
||||
}
|
||||
el.resultFound(name, e);
|
||||
}
|
||||
el.close();
|
||||
String s = el.toString();
|
||||
loopCheck(s, expressions);
|
||||
return s;
|
||||
}
|
||||
|
||||
private void loopCheck(String csv, Expression[] expressions) throws IOException, ExpressionException {
|
||||
TruthTable tt = CSVImporter.readCSV(csv);
|
||||
for (int e = 0; e < expressions.length; e++) {
|
||||
ArrayList<Variable> vars = tt.getVars();
|
||||
int count = 1 << vars.size();
|
||||
ContextFiller cf = new ContextFiller(vars);
|
||||
for (int i = 0; i < count; i++) {
|
||||
cf.setContextTo(i);
|
||||
boolean expected = expressions[e].calculate(cf);
|
||||
ThreeStateValue found = tt.getResult(e).get(i);
|
||||
assertEquals(ThreeStateValue.value(expected), found);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -40,8 +40,8 @@ public class TestExamples extends TestCase {
|
||||
*/
|
||||
public void testDistExamples() throws Exception {
|
||||
File examples = new File(Resources.getRoot().getParentFile().getParentFile(), "/main/dig");
|
||||
assertEquals(315, new FileScanner(this::check).scan(examples));
|
||||
assertEquals(500, testCasesInFiles);
|
||||
assertEquals(316, new FileScanner(this::check).scan(examples));
|
||||
assertEquals(502, testCasesInFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1220,14 +1220,13 @@ public class TestInGUI extends TestCase {
|
||||
xMin -= loc.x + SIZE * 5;
|
||||
yMin -= loc.y + SIZE * 2;
|
||||
|
||||
boolean firstWire = true;
|
||||
for (Wire w : circuit.getWires()) {
|
||||
guiTester.mouseClickNow(w.p1.x - xMin, w.p1.y - yMin, InputEvent.BUTTON1_DOWN_MASK);
|
||||
if (w.p1.x != w.p2.x && w.p1.y != w.p2.y)
|
||||
guiTester.typeNow("typed d");
|
||||
|
||||
guiTester.mouseClickNow(w.p2.x - xMin, w.p2.y - yMin, InputEvent.BUTTON1_DOWN_MASK);
|
||||
Thread.sleep(50);
|
||||
guiTester.mouseClickNow(w.p2.x - xMin, w.p2.y - yMin, InputEvent.BUTTON3_DOWN_MASK);
|
||||
if (firstWire) { // Draw first wire twice! Sometimes the first wire is lost and i can't figure out why!
|
||||
firstWire = false; // This is a dirty hack!
|
||||
drawWire(guiTester, xMin, yMin, w);
|
||||
}
|
||||
drawWire(guiTester, xMin, yMin, w);
|
||||
}
|
||||
|
||||
for (VisualElement v : circuit.getElements()) {
|
||||
@ -1240,6 +1239,16 @@ public class TestInGUI extends TestCase {
|
||||
Thread.sleep(400);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawWire(GuiTester guiTester, int xMin, int yMin, Wire w) throws InterruptedException {
|
||||
guiTester.mouseClickNow(w.p1.x - xMin, w.p1.y - yMin, InputEvent.BUTTON1_DOWN_MASK);
|
||||
if (w.p1.x != w.p2.x && w.p1.y != w.p2.y)
|
||||
guiTester.typeNow("typed d");
|
||||
|
||||
guiTester.mouseClickNow(w.p2.x - xMin, w.p2.y - yMin, InputEvent.BUTTON1_DOWN_MASK);
|
||||
Thread.sleep(50);
|
||||
guiTester.mouseClickNow(w.p2.x - xMin, w.p2.y - yMin, InputEvent.BUTTON3_DOWN_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
private static Point getCircuitPos(Main main) {
|
||||
|
@ -50,21 +50,27 @@ public class ParserTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testHex() throws IOException, ParserException {
|
||||
Parser parser = new Parser("A B\n0 0xff").parse();
|
||||
LineCollector td = new LineCollector(parser);
|
||||
assertEquals(2, td.getNames().size());
|
||||
|
||||
assertEquals(1, td.getLines().size());
|
||||
|
||||
assertEquals(0, td.getLines().get(0).getValue(0).getValue());
|
||||
assertEquals(Value.Type.NORMAL, td.getLines().get(0).getValue(0).getType());
|
||||
|
||||
assertEquals(255, td.getLines().get(0).getValue(1).getValue());
|
||||
assertEquals(Value.Type.NORMAL, td.getLines().get(0).getValue(1).getType());
|
||||
checkValueParser("A B\n0 0xff", 255);
|
||||
}
|
||||
|
||||
public void testBin() throws IOException, ParserException {
|
||||
Parser parser = new Parser("A B\n0 0b11111111").parse();
|
||||
checkValueParser("A B\n0 0b11111111", 255);
|
||||
}
|
||||
|
||||
public void testFixed() throws IOException, ParserException {
|
||||
checkValueParser("A B\n0 0.5:4", 8);
|
||||
}
|
||||
|
||||
public void testFloat() throws IOException, ParserException {
|
||||
checkValueParser("A B\n0 0.5", Float.floatToIntBits(0.5f));
|
||||
}
|
||||
|
||||
public void testDouble() throws IOException, ParserException {
|
||||
checkValueParser("A B\n0 0.5d", Double.doubleToLongBits(0.5));
|
||||
}
|
||||
|
||||
void checkValueParser(String s, long val) throws IOException, ParserException {
|
||||
Parser parser = new Parser(s).parse();
|
||||
LineCollector td = new LineCollector(parser);
|
||||
assertEquals(2, td.getNames().size());
|
||||
|
||||
@ -73,7 +79,7 @@ public class ParserTest extends TestCase {
|
||||
assertEquals(0, td.getLines().get(0).getValue(0).getValue());
|
||||
assertEquals(Value.Type.NORMAL, td.getLines().get(0).getValue(0).getType());
|
||||
|
||||
assertEquals(255, td.getLines().get(0).getValue(1).getValue());
|
||||
assertEquals(val, td.getLines().get(0).getValue(1).getValue());
|
||||
assertEquals(Value.Type.NORMAL, td.getLines().get(0).getValue(1).getType());
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user