diff --git a/src/main/java/de/neemann/digital/builder/BuilderCollector.java b/src/main/java/de/neemann/digital/builder/BuilderCollector.java index 9f8798375..9ec80146b 100644 --- a/src/main/java/de/neemann/digital/builder/BuilderCollector.java +++ b/src/main/java/de/neemann/digital/builder/BuilderCollector.java @@ -80,4 +80,12 @@ public class BuilderCollector implements BuilderInterface { return registered; } + /** + * Removes an output. + * + * @param name the output to remove + */ + public void removeOutput(String name) { + outputs.remove(name); + } } diff --git a/src/main/java/de/neemann/digital/builder/Gal16v8/BuilderCollectorGAL.java b/src/main/java/de/neemann/digital/builder/Gal16v8/BuilderCollectorGAL.java new file mode 100644 index 000000000..7bf2a6505 --- /dev/null +++ b/src/main/java/de/neemann/digital/builder/Gal16v8/BuilderCollectorGAL.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 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.builder.Gal16v8; + +import de.neemann.digital.analyse.expression.Expression; +import de.neemann.digital.builder.BuilderCollector; +import de.neemann.digital.builder.BuilderException; +import de.neemann.digital.builder.PinMap; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; + +/** + * Used to avoid a double cell allocation if the output of a ff is used as a autput of the state machine. + * This is the case if a Moore machine is build where the state equals the output. + * Sometimes this kind of state machines is called a Medwedew machine. + */ +public class BuilderCollectorGAL extends BuilderCollector { + private final PinMap pinMap; + private HashSet sequentialVars; + private boolean doubleCellUsageFixed = false; + + /** + * Creates a new instance + * + * @param pinMap the used pinMap. Is required to handle aliases correctly + */ + public BuilderCollectorGAL(PinMap pinMap) { + this.pinMap = pinMap; + sequentialVars = new HashSet<>(); + } + + @Override + public BuilderCollector addCombinatorial(String name, Expression expression) throws BuilderException { + checkOpen(); + return super.addCombinatorial(name, expression); + } + + @Override + public BuilderCollector addSequential(String name, Expression expression) throws BuilderException { + checkOpen(); + sequentialVars.add(name); + return super.addSequential(name, expression); + } + + private void checkOpen() { + if (doubleCellUsageFixed) + throw new RuntimeException("wrong BuilderCollectorGAL usage!"); + } + + private void fixDoubleCellUsage() { + if (!doubleCellUsageFixed) { + + super.getCombinatorial().entrySet().removeIf(c -> { + if (pinMap.isSimpleAlias(c.getKey(), c.getValue(), sequentialVars)) { + removeOutput(c.getKey()); + return true; + } + return false; + }); + + doubleCellUsageFixed = true; + } + } + + @Override + public ArrayList getOutputs() { + fixDoubleCellUsage(); + return super.getOutputs(); + } + + @Override + public ArrayList getInputs() { + fixDoubleCellUsage(); + return super.getInputs(); + } + + @Override + public Map getCombinatorial() { + fixDoubleCellUsage(); + return super.getCombinatorial(); + } + + @Override + public Map getRegistered() { + fixDoubleCellUsage(); + return super.getRegistered(); + } +} diff --git a/src/main/java/de/neemann/digital/builder/Gal16v8/CuplExporter.java b/src/main/java/de/neemann/digital/builder/Gal16v8/CuplExporter.java index ce97ee9a5..2994a2c34 100644 --- a/src/main/java/de/neemann/digital/builder/Gal16v8/CuplExporter.java +++ b/src/main/java/de/neemann/digital/builder/Gal16v8/CuplExporter.java @@ -84,7 +84,7 @@ public class CuplExporter implements ExpressionExporter { this.date = date; this.devName = devName; this.pinMap = pinMap; - builder = new CuplBuilder(); + builder = new CuplBuilder(pinMap); cleanNameBuilder = new CleanNameBuilder(builder); } @@ -228,14 +228,15 @@ public class CuplExporter implements ExpressionExporter { protected void sequentialWritten(Writer out, String name) throws IOException { } - private final class CuplBuilder extends BuilderCollector { + private static final class CuplBuilder extends BuilderCollectorGAL { private final NotAllowedVariablesVisitor notAllowedVariablesVisitor = new NotAllowedVariablesVisitor(); + private CuplBuilder(PinMap pinMap) { + super(pinMap); + } + @Override public BuilderCollector addCombinatorial(String name, Expression expression) throws BuilderException { - if (pinMap.isSimpleAlias(name, expression)) - return this; // ignore simple variables! - expression.traverse(notAllowedVariablesVisitor); notAllowedVariablesVisitor.check(name); return super.addCombinatorial(name, expression); diff --git a/src/main/java/de/neemann/digital/builder/Gal16v8/Gal16v8JEDECExporter.java b/src/main/java/de/neemann/digital/builder/Gal16v8/Gal16v8JEDECExporter.java index 4fb532034..73495b9a5 100644 --- a/src/main/java/de/neemann/digital/builder/Gal16v8/Gal16v8JEDECExporter.java +++ b/src/main/java/de/neemann/digital/builder/Gal16v8/Gal16v8JEDECExporter.java @@ -5,9 +5,11 @@ */ package de.neemann.digital.builder.Gal16v8; -import de.neemann.digital.analyse.expression.Expression; import de.neemann.digital.analyse.expression.Variable; -import de.neemann.digital.builder.*; +import de.neemann.digital.builder.BuilderCollector; +import de.neemann.digital.builder.ExpressionExporter; +import de.neemann.digital.builder.PinMap; +import de.neemann.digital.builder.PinMapException; import de.neemann.digital.builder.jedec.FuseMap; import de.neemann.digital.builder.jedec.FuseMapFiller; import de.neemann.digital.builder.jedec.FuseMapFillerException; @@ -43,18 +45,10 @@ public class Gal16v8JEDECExporter implements ExpressionExporter sequentialVars) { if (expression instanceof Variable) { String al = ((Variable) expression).getIdentifier(); + if (sequentialVars != null && !sequentialVars.contains(al)) + return false; + HashSet found = null; for (HashSet s : alias) if (s.contains(name) || s.contains(al)) { diff --git a/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerJK.java b/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerJK.java index bd4b050c6..d23603c88 100644 --- a/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerJK.java +++ b/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerJK.java @@ -57,7 +57,7 @@ public class ExpressionListenerJK implements ExpressionListener { } /** - * If the name belogs to a sequential state var, the state vars name is returned. + * If the name belongs to a sequential state var, the state vars name is returned. * Otherwise a null is returned * * @param name the name of the variable diff --git a/src/test/java/de/neemann/digital/builder/Gal16v8/Gal16V8CuplExporterTest.java b/src/test/java/de/neemann/digital/builder/Gal16v8/Gal16V8CuplExporterTest.java index 907c61e3c..5f45e0054 100644 --- a/src/test/java/de/neemann/digital/builder/Gal16v8/Gal16V8CuplExporterTest.java +++ b/src/test/java/de/neemann/digital/builder/Gal16v8/Gal16V8CuplExporterTest.java @@ -5,12 +5,30 @@ */ package de.neemann.digital.builder.Gal16v8; +import de.neemann.digital.analyse.*; import de.neemann.digital.analyse.expression.Constant; import de.neemann.digital.analyse.expression.Expression; +import de.neemann.digital.analyse.expression.ExpressionException; import de.neemann.digital.analyse.expression.Variable; +import de.neemann.digital.analyse.expression.format.FormatterException; +import de.neemann.digital.analyse.expression.modify.ExpressionModifier; +import de.neemann.digital.builder.PinMapException; +import de.neemann.digital.core.BacktrackException; +import de.neemann.digital.core.Model; +import de.neemann.digital.core.NodeException; +import de.neemann.digital.draw.elements.Circuit; +import de.neemann.digital.draw.elements.PinException; +import de.neemann.digital.draw.library.ElementLibrary; +import de.neemann.digital.draw.library.ElementNotFoundException; +import de.neemann.digital.draw.model.ModelCreator; +import de.neemann.digital.draw.shapes.ShapeFactory; +import de.neemann.digital.gui.components.table.BuilderExpressionCreator; +import de.neemann.digital.gui.components.table.ExpressionCreator; +import de.neemann.digital.gui.components.table.ExpressionListenerStore; +import de.neemann.digital.integration.Resources; import junit.framework.TestCase; -import java.io.ByteArrayOutputStream; +import java.io.*; import java.util.Date; import static de.neemann.digital.analyse.expression.Not.not; @@ -18,6 +36,7 @@ import static de.neemann.digital.analyse.expression.Operation.and; import static de.neemann.digital.analyse.expression.Operation.or; /** + * CUPL builder tests */ public class Gal16V8CuplExporterTest extends TestCase { @@ -133,4 +152,84 @@ public class Gal16V8CuplExporterTest extends TestCase { } } + public void testCuplWorkFlow() throws IOException, ElementNotFoundException, PinException, NodeException, AnalyseException, BacktrackException, PinMapException, ExpressionException, FormatterException { + String cupl = createCupl("dig/GAL/Medwedew.dig"); + + assertEquals("Name test ;\r\n" + + "PartNo 00 ;\r\n" + + "Date unknownDate ;\r\n" + + "Revision 01 ;\r\n" + + "Designer nn ;\r\n" + + "Company unknown ;\r\n" + + "Assembly None ;\r\n" + + "Location unknown ;\r\n" + + "Device g16v8a ;\r\n" + + "\r\n" + + "/* inputs */\r\n" + + "PIN 1 = CLK;\r\n" + + "\r\n" + + "/* outputs */\r\n" + + "PIN 15 = Q_3n;\r\n" + + "PIN 16 = Q_2n;\r\n" + + "PIN 17 = Q_1n;\r\n" + + "PIN 18 = Q_0n;\r\n" + + "\r\n" + + "/* sequential logic */\r\n" + + "Q_0n.D = !Q_0n;\r\n" + + "Q_1n.D = (Q_0n & !Q_1n) # (!Q_0n & Q_1n);\r\n" + + "Q_2n.D = (Q_0n & Q_1n & !Q_2n) # (!Q_0n & Q_2n) # (!Q_1n & Q_2n);\r\n" + + "Q_3n.D = (Q_0n & Q_1n & Q_2n & !Q_3n) # (!Q_0n & Q_3n) # (!Q_1n & Q_3n) # (!Q_2n & Q_3n);\r\n", cupl); + } + + public void testCuplWorkFlowPassThrough() throws IOException, ElementNotFoundException, PinException, NodeException, AnalyseException, BacktrackException, PinMapException, ExpressionException, FormatterException { + String cupl = createCupl("dig/GAL/PassThrough.dig"); + + assertEquals("Name test ;\r\n" + + "PartNo 00 ;\r\n" + + "Date unknownDate ;\r\n" + + "Revision 01 ;\r\n" + + "Designer nn ;\r\n" + + "Company unknown ;\r\n" + + "Assembly None ;\r\n" + + "Location unknown ;\r\n" + + "Device g16v8a ;\r\n" + + "\r\n" + + "/* inputs */\r\n" + + "PIN 1 = CLK;\r\n" + + "PIN 3 = A;\r\n" + + "\r\n" + + "/* outputs */\r\n" + + "PIN 16 = Yn;\r\n" + + "PIN 15 = X;\r\n" + + "\r\n" + + "/* sequential logic */\r\n" + + "Yn.D = A;\r\n" + + "\r\n" + + "/* combinatorial logic */\r\n" + + "X = A;\r\n", cupl); + } + + + private String createCupl(String filename) throws IOException, PinException, NodeException, ElementNotFoundException, BacktrackException, AnalyseException, ExpressionException, FormatterException, PinMapException { + File f = new File(Resources.getRoot(), filename); + ElementLibrary library = new ElementLibrary(); + Circuit c = Circuit.loadCircuit(f, new ShapeFactory(library)); + Model model = new ModelCreator(c, new SubstituteLibrary(library)).createModel(false); + TruthTable t = new ModelAnalyser(model).analyse(); + + ExpressionListenerStore expressions = new ExpressionListenerStore(null); + new ExpressionCreator(t).create(expressions); + + CuplExporter cuplExporter = new CuplExporter("nn", null); + cuplExporter.setProjectName("test"); + final ModelAnalyserInfo modelAnalyzerInfo = t.getModelAnalyzerInfo(); + if (modelAnalyzerInfo != null) + cuplExporter.getPinMapping().addAll(modelAnalyzerInfo.getPins()); + new BuilderExpressionCreator(cuplExporter.getBuilder(), ExpressionModifier.IDENTITY).create(expressions); + + StringWriter str = new StringWriter(); + cuplExporter.writeTo(str); + return str.toString(); + } + } diff --git a/src/test/java/de/neemann/digital/builder/PinMapTest.java b/src/test/java/de/neemann/digital/builder/PinMapTest.java index 5b9c89c82..9c9d5dafc 100644 --- a/src/test/java/de/neemann/digital/builder/PinMapTest.java +++ b/src/test/java/de/neemann/digital/builder/PinMapTest.java @@ -8,7 +8,12 @@ package de.neemann.digital.builder; import de.neemann.digital.analyse.expression.Variable; import junit.framework.TestCase; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; + /** + * */ public class PinMapTest extends TestCase { @@ -131,7 +136,7 @@ public class PinMapTest extends TestCase { public void testAlias() throws PinMapException { pinMap.assignPin("A", 4); - assertTrue(pinMap.isSimpleAlias("B", new Variable("A"))); + assertTrue(pinMap.isSimpleAlias("B", new Variable("A"), null)); assertEquals(4, pinMap.getOutputFor("A")); assertEquals(4, pinMap.getOutputFor("B")); @@ -139,14 +144,14 @@ public class PinMapTest extends TestCase { public void testAliasSwap() throws PinMapException { pinMap.assignPin("A", 4); - assertTrue(pinMap.isSimpleAlias("A", new Variable("B"))); + assertTrue(pinMap.isSimpleAlias("A", new Variable("B"), null)); assertEquals(4, pinMap.getOutputFor("A")); assertEquals(4, pinMap.getOutputFor("B")); } public void testAliasReverseOrder() throws PinMapException { - assertTrue(pinMap.isSimpleAlias("B", new Variable("A"))); + assertTrue(pinMap.isSimpleAlias("B", new Variable("A"), null)); pinMap.assignPin("A", 4); assertEquals(4, pinMap.getOutputFor("A")); @@ -156,12 +161,27 @@ public class PinMapTest extends TestCase { public void testAliasInput() throws PinMapException { pinMap.assignPin("A", 2); - assertTrue(pinMap.isSimpleAlias("B", new Variable("A"))); + assertTrue(pinMap.isSimpleAlias("B", new Variable("A"), null)); assertEquals(2, pinMap.getInputFor("A")); assertEquals(2, pinMap.getInputFor("B")); } + public void testAliasSequential() throws PinMapException { + pinMap.assignPin("A", 4); + assertFalse(pinMap.isSimpleAlias("B", new Variable("A"), new HashSet<>())); + + assertEquals(4, pinMap.getOutputFor("A")); + assertEquals(5, pinMap.getOutputFor("B")); + } + + public void testAliasSequential2() throws PinMapException { + pinMap.assignPin("A", 4); + assertTrue(pinMap.isSimpleAlias("B", new Variable("A"), new HashSet<>(Collections.singletonList("A")))); + + assertEquals(4, pinMap.getOutputFor("A")); + assertEquals(4, pinMap.getOutputFor("B")); + } public void testToString() throws PinMapException { pinMap.assignPin("A", 1); diff --git a/src/test/resources/dig/GAL/Medwedew.dig b/src/test/resources/dig/GAL/Medwedew.dig new file mode 100644 index 000000000..73931bfff --- /dev/null +++ b/src/test/resources/dig/GAL/Medwedew.dig @@ -0,0 +1,864 @@ + + + 1 + + + + Tunnel + + + Inputs + 1 + + + NetName + Q_3^n + + + + + + D_FF + + + Label + Q_3^n + + + Inputs + 1 + + + + + + Or + + + Inputs + 4 + + + + + + And + + + Inputs + 4 + + + + + + And + + + + + And + + + + + And + + + + + Tunnel + + + Inputs + 1 + + + NetName + Q_2^n + + + + + + D_FF + + + Label + Q_2^n + + + Inputs + 1 + + + + + + Or + + + Inputs + 3 + + + + + + And + + + Inputs + 3 + + + + + + And + + + + + And + + + + + Tunnel + + + Inputs + 1 + + + NetName + Q_1^n + + + + + + D_FF + + + Label + Q_1^n + + + Inputs + 1 + + + + + + Or + + + + + And + + + + + And + + + + + Tunnel + + + Inputs + 1 + + + NetName + Q_0^n + + + + + + D_FF + + + Label + Q_0^n + + + Inputs + 1 + + + + + + Tunnel + + + rotation + + + + NetName + Q_3^n + + + + + + Not + + + rotation + + + + + + + Tunnel + + + rotation + + + + NetName + Q_2^n + + + + + + Not + + + rotation + + + + + + + Tunnel + + + rotation + + + + NetName + Q_1^n + + + + + + Not + + + rotation + + + + + + + Tunnel + + + rotation + + + + NetName + Q_0^n + + + + + + Not + + + rotation + + + + + + + Clock + + + runRealTime + true + + + rotation + + + + Label + C + + + Frequency + 2 + + + + + + Tunnel + + + rotation + + + + NetName + Q_3^n + + + + + + Out + + + Label + Q_3 + + + pinNumber + 15 + + + + + + Tunnel + + + rotation + + + + NetName + Q_2^n + + + + + + Out + + + Label + Q_2 + + + pinNumber + 16 + + + + + + Tunnel + + + rotation + + + + NetName + Q_1^n + + + + + + Out + + + Label + Q_1 + + + pinNumber + 17 + + + + + + Tunnel + + + rotation + + + + NetName + Q_0^n + + + + + + Out + + + Label + Q_0 + + + pinNumber + 18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/dig/GAL/PassThrough.dig b/src/test/resources/dig/GAL/PassThrough.dig new file mode 100644 index 000000000..adb985c47 --- /dev/null +++ b/src/test/resources/dig/GAL/PassThrough.dig @@ -0,0 +1,94 @@ + + + 1 + + + + D_FF + + + + + In + + + Label + A + + + pinNumber + 3 + + + + + + Clock + + + + + Out + + + Label + Y + + + pinNumber + 16 + + + + + + Out + + + Label + X + + + pinNumber + 15 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file