From ccc588735ce88a9f8fc95b140ef1ebf3ea0386bf Mon Sep 17 00:00:00 2001 From: hneemann Date: Sun, 20 Mar 2016 22:07:10 +0100 Subject: [PATCH] splitter is working completely --- .../neemann/digital/core/ObservableValue.java | 3 + .../neemann/digital/core/wiring/Splitter.java | 100 +++++++++++------- .../java/de/neemann/digital/gui/Main.java | 1 + .../digital/core/wiring/SplitterTest1.java | 12 +++ .../digital/core/wiring/SplitterTest2.java | 4 + .../digital/core/wiring/SplitterTestMix.java | 76 +++++++++++++ 6 files changed, 158 insertions(+), 38 deletions(-) create mode 100644 src/test/java/de/neemann/digital/core/wiring/SplitterTestMix.java diff --git a/src/main/java/de/neemann/digital/core/ObservableValue.java b/src/main/java/de/neemann/digital/core/ObservableValue.java index e5eeff499..08e782e8e 100644 --- a/src/main/java/de/neemann/digital/core/ObservableValue.java +++ b/src/main/java/de/neemann/digital/core/ObservableValue.java @@ -104,4 +104,7 @@ public class ObservableValue extends Value { return name; } + public int observerCount() { + return observers.size(); + } } diff --git a/src/main/java/de/neemann/digital/core/wiring/Splitter.java b/src/main/java/de/neemann/digital/core/wiring/Splitter.java index 334d25064..42bf57ac6 100644 --- a/src/main/java/de/neemann/digital/core/wiring/Splitter.java +++ b/src/main/java/de/neemann/digital/core/wiring/Splitter.java @@ -56,18 +56,18 @@ public class Splitter implements Element { Port inPort = inPorts.getPort(i); if (inPort.getBits() != inputs[i].getBits()) throw new BitsException("splitterBitsMismatch", inputs[i]); - registerObserversFor(inPort); } + + for (Port out : outPorts) + fillOutput(out); } - private void registerObserversFor(Port in) throws NodeException { - Observer observer = outPorts.getSingleTargetObserver(in, inputs, outputs); - if (observer != null) { - inputs[in.number].addObserver(observer); - return; - } + private void fillOutput(Port out) throws NodeException { + for (Port in : inPorts) { + if (in.getPos() + in.getBits() <= out.getPos() || out.getPos() + out.getBits() <= in.getPos()) + continue; // this input is not needed to fill out!!! - for (Port out : outPorts) { + // out is filled completely by this single input value! if (out.getPos() >= in.getPos() && out.getPos() + out.getBits() <= in.getPos() + in.getBits()) { @@ -80,7 +80,61 @@ public class Splitter implements Element { outValue.setValue(inValue.getValue() >> bitPos); } }); + break; // done!! out is completely filled! } + + // complete in value needs to be copied to a part of the output + if (out.getPos() <= in.getPos() && in.getPos() + in.getBits() <= out.getPos() + out.getBits()) { + final int bitPos = in.getPos() - out.getPos(); + final long mask = ~(((1L << in.bits) - 1) << bitPos); + final ObservableValue inValue = inputs[in.number]; + final ObservableValue outValue = outputs[out.number]; + inputs[in.number].addObserver(new Observer() { + @Override + public void hasChanged() { + long in = inValue.getValue(); + long out = outValue.getValue(); + outValue.setValue((out & mask) | (in << bitPos)); + } + }); + continue; // done with this input, its completely copied to the output! + } + + // If this point is reached, a part of the input needs to be copied to a part of the output! + + // upper part of input needs to be copied to the lower part of the output + if (in.getPos() < out.getPos()) { + final int bitsToCopy = in.getPos() + in.getBits() - out.getPos(); + final long mask = ~((1L << bitsToCopy) - 1); + final int shift = out.getPos() - in.getPos(); + final ObservableValue inValue = inputs[in.number]; + final ObservableValue outValue = outputs[out.number]; + inputs[in.number].addObserver(new Observer() { + @Override + public void hasChanged() { + long in = inValue.getValue(); + long out = outValue.getValue(); + outValue.setValue((out & mask) | (in >> shift)); + } + }); + continue; + } + + // lower part of input needs to be copied to the upper part of the output + final int bitsToCopy = out.getPos() + out.getBits() - in.getPos(); + final int shift = in.getPos() - out.getPos(); + final long mask = ~(((1L << bitsToCopy) - 1) << shift); + final ObservableValue inValue = inputs[in.number]; + final ObservableValue outValue = outputs[out.number]; + inputs[in.number].addObserver(new Observer() { + @Override + public void hasChanged() { + long in = inValue.getValue(); + long out = outValue.getValue(); + outValue.setValue((out & mask) | (in << shift)); + } + }); + } } @@ -138,36 +192,6 @@ public class Splitter implements Element { return ports.get(i); } - /** - * Checks if there is a single out target port for the input port - * - * @param inPort - * @param inputs - * @param outputs - */ - public Observer getSingleTargetObserver(Port inPort, ObservableValue[] inputs, ObservableValue[] outputs) { - int pos = inPort.getPos(); - int bits = inPort.getBits(); - - for (Port outPort : ports) { - if (outPort.getPos() <= pos && pos + bits <= outPort.getPos() + outPort.getBits()) { - final int bitPos = pos - outPort.getPos(); - final int mask = ~(((1 << inPort.bits) - 1) << bitPos); - final ObservableValue inValue = inputs[inPort.number]; - final ObservableValue outValue = outputs[outPort.number]; - return new Observer() { - @Override - public void hasChanged() { - long in = inValue.getValue(); - long out = outValue.getValue(); - outValue.setValue((out & mask) | (in << bitPos)); - } - }; - } - } - return null; - } - @Override public Iterator iterator() { return ports.iterator(); diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index 3c494767e..80e4368b6 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -215,6 +215,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave { model.init(); } catch (Exception e1) { new ErrorMessage("error creating model").addCause(e1).show(Main.this); + circuitComponent.setModeAndReset(CircuitComponent.Mode.part); } } diff --git a/src/test/java/de/neemann/digital/core/wiring/SplitterTest1.java b/src/test/java/de/neemann/digital/core/wiring/SplitterTest1.java index b8ce3d329..3d1df4690 100644 --- a/src/test/java/de/neemann/digital/core/wiring/SplitterTest1.java +++ b/src/test/java/de/neemann/digital/core/wiring/SplitterTest1.java @@ -22,6 +22,10 @@ public class SplitterTest1 extends TestCase { .set(AttributeKey.OutputSplit, "4")); splitter.setInputs(a, b, c, d); + assertEquals(1, a.observerCount()); + assertEquals(1, b.observerCount()); + assertEquals(1, c.observerCount()); + assertEquals(1, d.observerCount()); ObservableValue[] outputs = splitter.getOutputs(); assertEquals(1, outputs.length); @@ -50,6 +54,10 @@ public class SplitterTest1 extends TestCase { .set(AttributeKey.OutputSplit, "16")); splitter.setInputs(a, b, c, d); + assertEquals(1, a.observerCount()); + assertEquals(1, b.observerCount()); + assertEquals(1, c.observerCount()); + assertEquals(1, d.observerCount()); ObservableValue[] outputs = splitter.getOutputs(); assertEquals(1, outputs.length); @@ -77,6 +85,10 @@ public class SplitterTest1 extends TestCase { .set(AttributeKey.OutputSplit, "8,8")); splitter.setInputs(a, b, c, d); + assertEquals(1, a.observerCount()); + assertEquals(1, b.observerCount()); + assertEquals(1, c.observerCount()); + assertEquals(1, d.observerCount()); ObservableValue[] outputs = splitter.getOutputs(); assertEquals(2, outputs.length); diff --git a/src/test/java/de/neemann/digital/core/wiring/SplitterTest2.java b/src/test/java/de/neemann/digital/core/wiring/SplitterTest2.java index 689b5ccdf..a782b6875 100644 --- a/src/test/java/de/neemann/digital/core/wiring/SplitterTest2.java +++ b/src/test/java/de/neemann/digital/core/wiring/SplitterTest2.java @@ -19,6 +19,7 @@ public class SplitterTest2 extends TestCase { .set(AttributeKey.OutputSplit, "1,1,1,1")); splitter.setInputs(a); + assertEquals(4, a.observerCount()); ObservableValue[] outputs = splitter.getOutputs(); assertEquals(4, outputs.length); @@ -40,6 +41,7 @@ public class SplitterTest2 extends TestCase { .set(AttributeKey.OutputSplit, "4,4,4,4")); splitter.setInputs(a); + assertEquals(4, a.observerCount()); ObservableValue[] outputs = splitter.getOutputs(); assertEquals(4, outputs.length); @@ -65,6 +67,8 @@ public class SplitterTest2 extends TestCase { .set(AttributeKey.OutputSplit, "4,4,4,4")); splitter.setInputs(a, b); + assertEquals(2, a.observerCount()); + assertEquals(2, b.observerCount()); ObservableValue[] outputs = splitter.getOutputs(); assertEquals(4, outputs.length); diff --git a/src/test/java/de/neemann/digital/core/wiring/SplitterTestMix.java b/src/test/java/de/neemann/digital/core/wiring/SplitterTestMix.java new file mode 100644 index 000000000..5690c3614 --- /dev/null +++ b/src/test/java/de/neemann/digital/core/wiring/SplitterTestMix.java @@ -0,0 +1,76 @@ +package de.neemann.digital.core.wiring; + +import de.neemann.digital.TestExecuter; +import de.neemann.digital.core.ObservableValue; +import de.neemann.digital.core.element.AttributeKey; +import de.neemann.digital.core.element.ElementAttributes; +import junit.framework.TestCase; + +/** + * @author hneemann + */ +public class SplitterTestMix extends TestCase { + + public void test1() throws Exception { + ObservableValue a = new ObservableValue("a", 8); + ObservableValue b = new ObservableValue("b", 8); + + Splitter splitter = new Splitter(new ElementAttributes() + .set(AttributeKey.InputSplit, "8,8") + .set(AttributeKey.OutputSplit, "4,12")); + + splitter.setInputs(a, b); + assertEquals(2, a.observerCount()); + assertEquals(1, b.observerCount()); + + ObservableValue[] outputs = splitter.getOutputs(); + assertEquals(2, outputs.length); + + TestExecuter sc = new TestExecuter().setInputs(a, b).setOutputsOf(splitter); + sc.check(0x00, 0x00, 0x0, 0x000); + + sc.check(0x01, 0x00, 0x1, 0x000); + sc.check(0x10, 0x00, 0x0, 0x001); + sc.check(0x00, 0x01, 0x0, 0x010); + sc.check(0x00, 0x10, 0x0, 0x100); + + sc.check(0x0f, 0x00, 0xf, 0x000); + sc.check(0xf0, 0x00, 0x0, 0x00f); + sc.check(0x00, 0x0f, 0x0, 0x0f0); + sc.check(0x00, 0xf0, 0x0, 0xf00); + + sc.check(0xc0, 0xab, 0x0, 0xabc); + } + + public void test2() throws Exception { + ObservableValue a = new ObservableValue("a", 8); + ObservableValue b = new ObservableValue("b", 8); + + Splitter splitter = new Splitter(new ElementAttributes() + .set(AttributeKey.InputSplit, "8,8") + .set(AttributeKey.OutputSplit, "12,4")); + + splitter.setInputs(a, b); + assertEquals(1, a.observerCount()); + assertEquals(2, b.observerCount()); + + ObservableValue[] outputs = splitter.getOutputs(); + assertEquals(2, outputs.length); + + TestExecuter sc = new TestExecuter().setInputs(a, b).setOutputsOf(splitter); + sc.check(0x00, 0x00, 0x000, 0x0); + + sc.check(0x01, 0x00, 0x001, 0x0); + sc.check(0x10, 0x00, 0x010, 0x0); + sc.check(0x00, 0x01, 0x100, 0x0); + sc.check(0x00, 0x10, 0x000, 0x1); + + sc.check(0x0f, 0x00, 0x00f, 0x0); + sc.check(0xf0, 0x00, 0x0f0, 0x0); + sc.check(0x00, 0x0f, 0xf00, 0x0); + sc.check(0x00, 0xf0, 0x000, 0xf); + + sc.check(0xbc, 0xda, 0xabc, 0xd); + } + +} \ No newline at end of file