From 49ea08144edb4a26964fecd6d3f087592f769b9f Mon Sep 17 00:00:00 2001 From: hneemann Date: Fri, 11 Mar 2016 23:16:40 +0100 Subject: [PATCH] initial commit --- .gitignore | 72 ++++++ pom.xml | 211 ++++++++++++++++++ .../de/neemann/digital/BitsException.java | 10 + .../java/de/neemann/digital/Listener.java | 8 + src/main/java/de/neemann/digital/Model.java | 80 +++++++ src/main/java/de/neemann/digital/Node.java | 42 ++++ .../de/neemann/digital/NodeException.java | 10 + .../de/neemann/digital/ObservableValue.java | 69 ++++++ .../java/de/neemann/digital/basic/And.java | 24 ++ .../de/neemann/digital/basic/Function.java | 52 +++++ .../java/de/neemann/digital/basic/NAnd.java | 24 ++ .../java/de/neemann/digital/basic/NOr.java | 23 ++ .../java/de/neemann/digital/basic/Not.java | 31 +++ .../java/de/neemann/digital/basic/Or.java | 24 ++ .../java/de/neemann/digital/FlipFlops.java | 58 +++++ .../java/de/neemann/digital/TestExecuter.java | 44 ++++ .../de/neemann/digital/basic/AndTest.java | 29 +++ .../de/neemann/digital/basic/NAndTest.java | 28 +++ .../de/neemann/digital/basic/NOrTest.java | 29 +++ .../java/de/neemann/digital/basic/OrTest.java | 29 +++ 20 files changed, 897 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/de/neemann/digital/BitsException.java create mode 100644 src/main/java/de/neemann/digital/Listener.java create mode 100644 src/main/java/de/neemann/digital/Model.java create mode 100644 src/main/java/de/neemann/digital/Node.java create mode 100644 src/main/java/de/neemann/digital/NodeException.java create mode 100644 src/main/java/de/neemann/digital/ObservableValue.java create mode 100644 src/main/java/de/neemann/digital/basic/And.java create mode 100644 src/main/java/de/neemann/digital/basic/Function.java create mode 100644 src/main/java/de/neemann/digital/basic/NAnd.java create mode 100644 src/main/java/de/neemann/digital/basic/NOr.java create mode 100644 src/main/java/de/neemann/digital/basic/Not.java create mode 100644 src/main/java/de/neemann/digital/basic/Or.java create mode 100644 src/test/java/de/neemann/digital/FlipFlops.java create mode 100644 src/test/java/de/neemann/digital/TestExecuter.java create mode 100644 src/test/java/de/neemann/digital/basic/AndTest.java create mode 100644 src/test/java/de/neemann/digital/basic/NAndTest.java create mode 100644 src/test/java/de/neemann/digital/basic/NOrTest.java create mode 100644 src/test/java/de/neemann/digital/basic/OrTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..eb2057841 --- /dev/null +++ b/.gitignore @@ -0,0 +1,72 @@ +# Created by .ignore support plugin (hsz.mobi) +### Java template +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..f91143d0c --- /dev/null +++ b/pom.xml @@ -0,0 +1,211 @@ + + + 4.0.0 + + de.neemann.digital + digital + 1.0-SNAPSHOT + + + yyyy-MM-dd HH:mm + UTF-8 + 1.7.12 + + + + + + file://${pom.basedir}/_stage + + + + + + + org.codehaus.mojo + cobertura-maven-plugin + 2.7 + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.1 + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.15 + + sun_checks_neemann.xml + + + + + checkstyle + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.2 + + org.umlgraph.doclet.UmlGraphDoc + + org.umlgraph + umlgraph + 5.6 + + -views -all + true + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + + + + + + + + + + + + + junit + junit + 4.0 + test + + + + + + scm:git:file://localhost/${pom.basedir} + + + + \ No newline at end of file diff --git a/src/main/java/de/neemann/digital/BitsException.java b/src/main/java/de/neemann/digital/BitsException.java new file mode 100644 index 000000000..561d57e1a --- /dev/null +++ b/src/main/java/de/neemann/digital/BitsException.java @@ -0,0 +1,10 @@ +package de.neemann.digital; + +/** + * @author hneemann + */ +public class BitsException extends Exception { + public BitsException(String message) { + super(message); + } +} diff --git a/src/main/java/de/neemann/digital/Listener.java b/src/main/java/de/neemann/digital/Listener.java new file mode 100644 index 000000000..d43120270 --- /dev/null +++ b/src/main/java/de/neemann/digital/Listener.java @@ -0,0 +1,8 @@ +package de.neemann.digital; + +/** + * @author hneemann + */ +public interface Listener { + void needsUpdate() throws NodeException; +} diff --git a/src/main/java/de/neemann/digital/Model.java b/src/main/java/de/neemann/digital/Model.java new file mode 100644 index 000000000..79b134b40 --- /dev/null +++ b/src/main/java/de/neemann/digital/Model.java @@ -0,0 +1,80 @@ +package de.neemann.digital; + +import java.util.ArrayList; +import java.util.Collections; + +/** + * @author hneemann + */ +public class Model { + + private ArrayList nodes; + private ArrayList nodesToUpdateAct; + private ArrayList nodesToUpdateNext; + private int version; + private int maxCounter = 1000; + + public Model() { + this.nodes = new ArrayList<>(); + this.nodesToUpdateAct = new ArrayList<>(); + this.nodesToUpdateNext = new ArrayList<>(); + } + + public int getVersion() { + return version; + } + + public T add(T node) { + nodes.add(node); + node.setModel(this); + return node; + } + + public void addToUpdateList(Node node) { + nodesToUpdateNext.add(node); + } + + public void doStep() throws NodeException { + doStep(false); + } + + public void doStep(boolean noise) throws NodeException { + int counter = 0; + while (!nodesToUpdateNext.isEmpty()) { + version++; + // swap lists + ArrayList nl = nodesToUpdateNext; + nodesToUpdateNext = nodesToUpdateAct; + nodesToUpdateAct = nl; + + nodesToUpdateNext.clear(); + + if (noise) { + Collections.shuffle(nodesToUpdateAct); + for (Node n : nodesToUpdateAct) { + n.readInputs(); + n.writeOutputs(); + } + } else { + for (Node n : nodesToUpdateAct) { + n.readInputs(); + } + for (Node n : nodesToUpdateAct) { + n.writeOutputs(); + } + } + if (counter++ > maxCounter) { + throw new NodeException("seemsToOscillate"); + } + } + } + + public void init() throws NodeException { + init(false); + } + + public void init(boolean noise) throws NodeException { + nodesToUpdateNext.addAll(nodes); + doStep(noise); + } +} diff --git a/src/main/java/de/neemann/digital/Node.java b/src/main/java/de/neemann/digital/Node.java new file mode 100644 index 000000000..18d5fe3a7 --- /dev/null +++ b/src/main/java/de/neemann/digital/Node.java @@ -0,0 +1,42 @@ +package de.neemann.digital; + +/** + * @author hneemann + */ +public abstract class Node implements Listener { + + private Model model; + private int version; + + public void setModel(Model model) { + this.model = model; + } + + @Override + public void needsUpdate() throws NodeException { + if (model == null) + throw new NodeException("no model set"); + + if (model.getVersion() != version) { + model.addToUpdateList(this); + version = model.getVersion(); + } + } + + /** + * Only read the input! + * It is not allowed to write to the outputs!!! + * + * @throws NodeException + */ + public abstract void readInputs() throws NodeException; + + /** + * Only write to the output! + * It is not allowed to read from the inputs!!! + * + * @throws NodeException + */ + public abstract void writeOutputs() throws NodeException; + +} diff --git a/src/main/java/de/neemann/digital/NodeException.java b/src/main/java/de/neemann/digital/NodeException.java new file mode 100644 index 000000000..4dcc8b033 --- /dev/null +++ b/src/main/java/de/neemann/digital/NodeException.java @@ -0,0 +1,10 @@ +package de.neemann.digital; + +/** + * @author hneemann + */ +public class NodeException extends Exception { + public NodeException(String message) { + super(message); + } +} diff --git a/src/main/java/de/neemann/digital/ObservableValue.java b/src/main/java/de/neemann/digital/ObservableValue.java new file mode 100644 index 000000000..5df7c7acf --- /dev/null +++ b/src/main/java/de/neemann/digital/ObservableValue.java @@ -0,0 +1,69 @@ +package de.neemann.digital; + +import java.util.ArrayList; + +/** + * @author hneemann + */ +public class ObservableValue { + + private final int bits; + private int value; + private ArrayList listeners; + + public ObservableValue(int bits) { + this.bits = bits; + listeners = new ArrayList<>(); + } + + public void addListener(Listener listener) throws NodeException { + listeners.add(listener); + } + + public void removeListener(Listener listener) { + listeners.remove(listener); + } + + public void hasChanged() throws NodeException { + for (Listener l : listeners) { + l.needsUpdate(); + } + } + + public int getValue() { + return value; + } + + public void setValue(int value) throws NodeException { + if (this.value != value) { + this.value = value; + hasChanged(); + } + } + + public int getBits() { + return bits; + } + + public int getValueBits() { + return getValueBits(value); + } + + public int getValueBits(int value) { + return value & (1 << bits) - 1; + } + + public void checkBits(ObservableValue value) throws BitsException { + if (value.getBits() != bits) { + throw new BitsException("needs " + bits + " bits, found " + value.getBits()); + } + } + + @Override + public String toString() { + return "ObservableValue{" + + "value=" + value + + ", bits=" + bits + + '}'; + } +} diff --git a/src/main/java/de/neemann/digital/basic/And.java b/src/main/java/de/neemann/digital/basic/And.java new file mode 100644 index 000000000..481882954 --- /dev/null +++ b/src/main/java/de/neemann/digital/basic/And.java @@ -0,0 +1,24 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.ObservableValue; + +import java.util.ArrayList; + +/** + * @author hneemann + */ +public class And extends Function { + + public And(int bits) { + super(bits); + } + + @Override + protected int calculate(ArrayList inputs) { + int f = -1; + for (ObservableValue i : inputs) { + f &= i.getValue(); + } + return f; + } +} diff --git a/src/main/java/de/neemann/digital/basic/Function.java b/src/main/java/de/neemann/digital/basic/Function.java new file mode 100644 index 000000000..bdab4e5d6 --- /dev/null +++ b/src/main/java/de/neemann/digital/basic/Function.java @@ -0,0 +1,52 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.BitsException; +import de.neemann.digital.Node; +import de.neemann.digital.NodeException; +import de.neemann.digital.ObservableValue; + +import java.util.ArrayList; + +/** + * @author hneemann + */ +public abstract class Function extends Node { + + private final ArrayList inputs; + private final ObservableValue output; + private int value; + + public Function(int bits) { + output = new ObservableValue(bits); + inputs = new ArrayList<>(); + } + + public Function addInput(ObservableValue value) throws BitsException, NodeException { + output.checkBits(value); + inputs.add(value); + value.addListener(this); + return this; + } + + public void removeInput(ObservableValue value) { + inputs.remove(value); + value.removeListener(this); + } + + public ObservableValue getOutput() { + return output; + } + + + @Override + public void readInputs() throws NodeException { + value = calculate(inputs); + } + + @Override + public void writeOutputs() throws NodeException { + output.setValue(value); + } + + protected abstract int calculate(ArrayList inputs); +} diff --git a/src/main/java/de/neemann/digital/basic/NAnd.java b/src/main/java/de/neemann/digital/basic/NAnd.java new file mode 100644 index 000000000..0b573d218 --- /dev/null +++ b/src/main/java/de/neemann/digital/basic/NAnd.java @@ -0,0 +1,24 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.ObservableValue; + +import java.util.ArrayList; + +/** + * @author hneemann + */ +public class NAnd extends Function { + + public NAnd(int bits) { + super(bits); + } + + @Override + protected int calculate(ArrayList inputs) { + int f = -1; + for (ObservableValue i : inputs) { + f &= i.getValue(); + } + return ~f; + } +} diff --git a/src/main/java/de/neemann/digital/basic/NOr.java b/src/main/java/de/neemann/digital/basic/NOr.java new file mode 100644 index 000000000..095efe3fc --- /dev/null +++ b/src/main/java/de/neemann/digital/basic/NOr.java @@ -0,0 +1,23 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.ObservableValue; + +import java.util.ArrayList; + +/** + * @author hneemann + */ +public class NOr extends Function { + public NOr(int bits) { + super(bits); + } + + @Override + protected int calculate(ArrayList inputs) { + int f = 0; + for (ObservableValue i : inputs) { + f |= i.getValue(); + } + return ~f; + } +} diff --git a/src/main/java/de/neemann/digital/basic/Not.java b/src/main/java/de/neemann/digital/basic/Not.java new file mode 100644 index 000000000..59f77c09e --- /dev/null +++ b/src/main/java/de/neemann/digital/basic/Not.java @@ -0,0 +1,31 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.Node; +import de.neemann.digital.NodeException; +import de.neemann.digital.ObservableValue; + +/** + * @author hneemann + */ +public class Not extends Node { + + private final ObservableValue input; + private final ObservableValue output; + private int value; + + public Not(ObservableValue input) throws NodeException { + this.input = input; + output = new ObservableValue(input.getBits()); + input.addListener(this); + } + + @Override + public void readInputs() throws NodeException { + value = input.getValue(); + } + + @Override + public void writeOutputs() throws NodeException { + output.setValue(~value); + } +} diff --git a/src/main/java/de/neemann/digital/basic/Or.java b/src/main/java/de/neemann/digital/basic/Or.java new file mode 100644 index 000000000..9262222e8 --- /dev/null +++ b/src/main/java/de/neemann/digital/basic/Or.java @@ -0,0 +1,24 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.ObservableValue; + +import java.util.ArrayList; + +/** + * @author hneemann + */ +public class Or extends Function { + + public Or(int bits) { + super(bits); + } + + @Override + protected int calculate(ArrayList inputs) { + int f = 0; + for (ObservableValue i : inputs) { + f |= i.getValue(); + } + return f; + } +} diff --git a/src/test/java/de/neemann/digital/FlipFlops.java b/src/test/java/de/neemann/digital/FlipFlops.java new file mode 100644 index 000000000..d95c13465 --- /dev/null +++ b/src/test/java/de/neemann/digital/FlipFlops.java @@ -0,0 +1,58 @@ +package de.neemann.digital; + +import de.neemann.digital.basic.Function; +import de.neemann.digital.basic.NAnd; +import de.neemann.digital.basic.NOr; +import junit.framework.TestCase; + +/** + * @author hneemann + */ +public class FlipFlops extends TestCase { + + public void testFlipFlopNOr() throws Exception { + ObservableValue r = new ObservableValue(1); + ObservableValue s = new ObservableValue(1); + + Model model = new Model(); + Function a1 = model.add(new NOr(1)).addInput(r); + Function a2 = model.add(new NOr(1)).addInput(s); + + a1.addInput(a2.getOutput()); + a2.addInput(a1.getOutput()); + + TestExecuter sc = new TestExecuter(model, true).setInputs(r, s).setOutputs(a1.getOutput(), a2.getOutput()); + sc.check(0, 1, 1, 0); + sc.check(0, 0, 1, 0); + sc.check(1, 0, 0, 1); + sc.check(0, 0, 0, 1); + sc.check(0, 1, 1, 0); + sc.check(1, 1, 0, 0); // verbotener Zustand!! + r.setValue(0); // gehe aus verbotenem Zustand raus!!! + s.setValue(0); + model.doStep(true); // geht nur mit noise! + + assertTrue((a1.getOutput().getValueBits() == 1 && a2.getOutput().getValueBits() == 0) || // endzustand ist undefiniert! + (a1.getOutput().getValueBits() == 0 && a2.getOutput().getValueBits() == 1)); + } + + public void testFlipFlopNAnd() throws Exception { + ObservableValue r = new ObservableValue(1); + ObservableValue s = new ObservableValue(1); + + Model model = new Model(); + Function a1 = model.add(new NAnd(1)).addInput(r); + Function a2 = model.add(new NAnd(1)).addInput(s); + + a1.addInput(a2.getOutput()); + a2.addInput(a1.getOutput()); + + TestExecuter sc = new TestExecuter(model).setInputs(r, s).setOutputs(a1.getOutput(), a2.getOutput()); + sc.check(1, 0, 0, 1); + sc.check(1, 1, 0, 1); + sc.check(0, 1, 1, 0); + sc.check(1, 1, 1, 0); + sc.check(1, 0, 0, 1); + } + +} \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/TestExecuter.java b/src/test/java/de/neemann/digital/TestExecuter.java new file mode 100644 index 000000000..27728b7b9 --- /dev/null +++ b/src/test/java/de/neemann/digital/TestExecuter.java @@ -0,0 +1,44 @@ +package de.neemann.digital; + +import static org.junit.Assert.assertEquals; + +/** + * @author hneemann + */ +public class TestExecuter { + + private final Model model; + private ObservableValue[] inputs; + private ObservableValue[] outputs; + + public TestExecuter(Model model) throws NodeException { + this(model, false); + } + + public TestExecuter(Model model, boolean noise) throws NodeException { + this.model = model; + model.init(noise); + } + + public TestExecuter setInputs(ObservableValue... values) { + inputs = values; + return this; + } + + public TestExecuter setOutputs(ObservableValue... values) { + outputs = values; + return this; + } + + public void check(int... val) throws NodeException { + for (int i = 0; i < inputs.length; i++) { + inputs[i].setValue(val[i]); + } + model.doStep(); + + for (int i = 0; i < outputs.length; i++) { + assertEquals("Value " + i, outputs[i].getValueBits(val[i + inputs.length]), outputs[i].getValueBits()); + } + } + +} diff --git a/src/test/java/de/neemann/digital/basic/AndTest.java b/src/test/java/de/neemann/digital/basic/AndTest.java new file mode 100644 index 000000000..2ab19bce7 --- /dev/null +++ b/src/test/java/de/neemann/digital/basic/AndTest.java @@ -0,0 +1,29 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.Model; +import de.neemann.digital.ObservableValue; +import de.neemann.digital.TestExecuter; +import junit.framework.TestCase; + +/** + * @author hneemann + */ +public class AndTest extends TestCase { + + public void testAnd() throws Exception { + ObservableValue a = new ObservableValue(1); + ObservableValue b = new ObservableValue(1); + + + Model model = new Model(); + Function and = model.add(new And(1)).addInput(a).addInput(b); + + TestExecuter sc = new TestExecuter(model).setInputs(a, b).setOutputs(and.getOutput()); + sc.check(0, 0, 0); + sc.check(1, 0, 0); + sc.check(0, 1, 0); + sc.check(1, 1, 1); + sc.check(1, 0, 0); + sc.check(0, 1, 0); + } +} \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/basic/NAndTest.java b/src/test/java/de/neemann/digital/basic/NAndTest.java new file mode 100644 index 000000000..db23694ff --- /dev/null +++ b/src/test/java/de/neemann/digital/basic/NAndTest.java @@ -0,0 +1,28 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.Model; +import de.neemann.digital.ObservableValue; +import de.neemann.digital.TestExecuter; +import junit.framework.TestCase; + +/** + * @author hneemann + */ +public class NAndTest extends TestCase { + + public void testAnd() throws Exception { + ObservableValue a = new ObservableValue(1); + ObservableValue b = new ObservableValue(1); + + Model model = new Model(); + Function nand = model.add(new NAnd(1)).addInput(a).addInput(b); + + TestExecuter sc = new TestExecuter(model).setInputs(a, b).setOutputs(nand.getOutput()); + sc.check(0, 0, 1); + sc.check(1, 0, 1); + sc.check(0, 1, 1); + sc.check(1, 1, 0); + sc.check(1, 0, 1); + sc.check(0, 1, 1); + } +} \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/basic/NOrTest.java b/src/test/java/de/neemann/digital/basic/NOrTest.java new file mode 100644 index 000000000..37dd5e2c9 --- /dev/null +++ b/src/test/java/de/neemann/digital/basic/NOrTest.java @@ -0,0 +1,29 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.Model; +import de.neemann.digital.ObservableValue; +import de.neemann.digital.TestExecuter; +import junit.framework.TestCase; + +/** + * @author hneemann + */ +public class NOrTest extends TestCase { + + public void testNOr() throws Exception { + ObservableValue a = new ObservableValue(1); + ObservableValue b = new ObservableValue(1); + + Model model = new Model(); + Function nor = model.add(new NOr(1)).addInput(a).addInput(b); + + TestExecuter sc = new TestExecuter(model).setInputs(a, b).setOutputs(nor.getOutput()); + sc.check(0, 0, 1); + sc.check(1, 0, 0); + sc.check(0, 1, 0); + sc.check(1, 1, 0); + sc.check(1, 0, 0); + sc.check(0, 1, 0); + sc.check(0, 0, 1); + } +} \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/basic/OrTest.java b/src/test/java/de/neemann/digital/basic/OrTest.java new file mode 100644 index 000000000..13e5221aa --- /dev/null +++ b/src/test/java/de/neemann/digital/basic/OrTest.java @@ -0,0 +1,29 @@ +package de.neemann.digital.basic; + +import de.neemann.digital.Model; +import de.neemann.digital.ObservableValue; +import de.neemann.digital.TestExecuter; +import junit.framework.TestCase; + +/** + * @author hneemann + */ +public class OrTest extends TestCase { + + public void testOr() throws Exception { + ObservableValue a = new ObservableValue(1); + ObservableValue b = new ObservableValue(1); + + Model model = new Model(); + Function and = model.add(new Or(1)).addInput(a).addInput(b); + + TestExecuter sc = new TestExecuter(model).setInputs(a, b).setOutputs(and.getOutput()); + sc.check(0, 0, 0); + sc.check(1, 0, 1); + sc.check(0, 1, 1); + sc.check(1, 1, 1); + sc.check(1, 0, 1); + sc.check(0, 1, 1); + sc.check(0, 0, 0); + } +} \ No newline at end of file