diff --git a/src/main/dig/Ampel_Einfach.dig b/src/main/dig/Ampel_Einfach.dig
index 9fd767583..d9ff8bde4 100644
--- a/src/main/dig/Ampel_Einfach.dig
+++ b/src/main/dig/Ampel_Einfach.dig
@@ -20,7 +20,7 @@
Z_1
-
+
0
@@ -100,23 +100,31 @@
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -140,16 +148,12 @@
-
-
-
-
-
+
-
+
@@ -164,7 +168,7 @@
-
+
@@ -172,15 +176,11 @@
-
-
+
+
-
-
-
-
-
+
@@ -188,7 +188,11 @@
-
+
+
+
+
+
diff --git a/src/main/dig/Ampel_MSJK.dig b/src/main/dig/Ampel_MSJK.dig
index 8cc03d444..beb22404f 100644
--- a/src/main/dig/Ampel_MSJK.dig
+++ b/src/main/dig/Ampel_MSJK.dig
@@ -10,7 +10,7 @@
Const
-
+
0
@@ -72,19 +72,19 @@
Clock
-
+
0
Or
-
+
0
Not
-
+
0
@@ -95,13 +95,13 @@
Feuer
-
+
0
MS-JK.dig
-
+
0
@@ -113,37 +113,37 @@
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -153,32 +153,36 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
+
+
+
+
@@ -189,19 +193,19 @@
-
+
-
+
-
-
+
+
-
+
@@ -209,16 +213,20 @@
-
-
+
+
-
+
+
+
+
+
-
-
+
+
\ No newline at end of file
diff --git a/src/main/dig/Ampel_TJK.dig b/src/main/dig/Ampel_TJK.dig
index 21f802292..0393bb55f 100644
--- a/src/main/dig/Ampel_TJK.dig
+++ b/src/main/dig/Ampel_TJK.dig
@@ -10,7 +10,7 @@
Const
-
+
0
@@ -72,19 +72,19 @@
Clock
-
+
0
Or
-
+
0
Not
-
+
0
@@ -95,13 +95,13 @@
Feuer
-
+
0
T-JK.dig
-
+
0
@@ -113,37 +113,37 @@
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -153,32 +153,36 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
+
+
+
+
@@ -189,19 +193,27 @@
-
+
-
+
+
+
+
+
-
-
+
+
-
+
+
+
+
+
@@ -209,16 +221,12 @@
-
-
+
+
-
+
-
-
-
-
\ No newline at end of file
diff --git a/src/main/java/de/neemann/digital/core/ObservableValue.java b/src/main/java/de/neemann/digital/core/ObservableValue.java
index f1385047e..0240d277f 100644
--- a/src/main/java/de/neemann/digital/core/ObservableValue.java
+++ b/src/main/java/de/neemann/digital/core/ObservableValue.java
@@ -12,6 +12,7 @@ public class ObservableValue extends Value {
private final ArrayList observers;
private final String name;
private final long mask;
+ private final boolean supportsHighZ;
public ObservableValue(String name, int bits) {
this(name, bits, false);
@@ -22,6 +23,7 @@ public class ObservableValue extends Value {
mask = (1L << bits) - 1;
this.name = name;
observers = new ArrayList<>();
+ supportsHighZ = highZ;
}
public ObservableValue addObserver(Observer observer) {
@@ -137,4 +139,16 @@ public class ObservableValue extends Value {
public int observerCount() {
return observers.size();
}
+
+ public boolean supportsHighZ() {
+ return supportsHighZ;
+ }
+
+ public boolean isHighZIgnoreBurn() {
+ return highZ;
+ }
+
+ public long getValueIgnoreBurn() {
+ return value;
+ }
}
diff --git a/src/main/java/de/neemann/digital/core/memory/DataField.java b/src/main/java/de/neemann/digital/core/memory/DataField.java
index f7c45d80f..aad49c1e0 100644
--- a/src/main/java/de/neemann/digital/core/memory/DataField.java
+++ b/src/main/java/de/neemann/digital/core/memory/DataField.java
@@ -2,10 +2,7 @@ package de.neemann.digital.core.memory;
import de.neemann.digital.lang.Lang;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
+import java.io.*;
import java.util.Arrays;
/**
@@ -32,7 +29,11 @@ public class DataField {
}
public DataField(File file) throws IOException {
- try (BufferedReader br = new BufferedReader(new FileReader(file))) {
+ this(new FileReader(file));
+ }
+
+ public DataField(Reader reader) throws IOException {
+ try (BufferedReader br = new BufferedReader(reader)) {
data = new long[1024];
String header = br.readLine();
if (header == null || !header.equals("v2.0 raw"))
diff --git a/src/main/java/de/neemann/digital/core/wiring/DataBus.java b/src/main/java/de/neemann/digital/core/wiring/DataBus.java
index 4254f0bf1..4864d1bf7 100644
--- a/src/main/java/de/neemann/digital/core/wiring/DataBus.java
+++ b/src/main/java/de/neemann/digital/core/wiring/DataBus.java
@@ -36,6 +36,8 @@ public class DataBus {
if (bits != b)
throw new PinException(Lang.get("err_notAllOutputsSameBits"), net);
}
+ if (!o.supportsHighZ())
+ throw new PinException(Lang.get("err_notAllOutputsSupportHighZ"), net);
}
commonOut = new CommonObservableValue(bits);
diff --git a/src/main/java/de/neemann/digital/gui/draw/elements/Pin.java b/src/main/java/de/neemann/digital/gui/draw/elements/Pin.java
index 8e8fd0f7e..a41771e93 100644
--- a/src/main/java/de/neemann/digital/gui/draw/elements/Pin.java
+++ b/src/main/java/de/neemann/digital/gui/draw/elements/Pin.java
@@ -13,6 +13,7 @@ public class Pin {
private final String name;
private final Direction direction;
private ObservableValue value;
+ private ObservableValue readerValue; // reader for bidirectional pins
public Pin(Vector pos, Pin pin) {
this(pos, pin.name, pin.direction);
@@ -44,5 +45,13 @@ public class Pin {
this.value = value;
}
+ public ObservableValue getReaderValue() {
+ return readerValue;
+ }
+
+ public void setReaderValue(ObservableValue readerValue) {
+ this.readerValue = readerValue;
+ }
+
public enum Direction {input, output, both}
}
diff --git a/src/main/java/de/neemann/digital/gui/draw/graphics/Style.java b/src/main/java/de/neemann/digital/gui/draw/graphics/Style.java
index ec04c79d5..aa031fdff 100644
--- a/src/main/java/de/neemann/digital/gui/draw/graphics/Style.java
+++ b/src/main/java/de/neemann/digital/gui/draw/graphics/Style.java
@@ -67,9 +67,9 @@ public class Style {
public static Style getWireStyle(ObservableValue value) {
if (value == null || value.getBits() > 1) return WIRE;
- if (value.isHighZ()) return WIRE_HIGHZ;
+ if (value.isHighZIgnoreBurn()) return WIRE_HIGHZ;
- if (value.getValue() == 1) return WIRE_HIGH;
+ if (value.getValueIgnoreBurn() == 1) return WIRE_HIGH;
else return WIRE_LOW;
}
}
diff --git a/src/main/java/de/neemann/digital/gui/draw/model/ModelEntry.java b/src/main/java/de/neemann/digital/gui/draw/model/ModelEntry.java
index 1f72ac121..bd06beec6 100644
--- a/src/main/java/de/neemann/digital/gui/draw/model/ModelEntry.java
+++ b/src/main/java/de/neemann/digital/gui/draw/model/ModelEntry.java
@@ -4,9 +4,11 @@ import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.Observer;
import de.neemann.digital.core.element.Element;
+import de.neemann.digital.core.wiring.Splitter;
import de.neemann.digital.gui.draw.elements.*;
import de.neemann.digital.lang.Lang;
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -48,6 +50,18 @@ public class ModelEntry {
inputs[i] = value;
}
+
+ ArrayList bidirect = null;
+ for (Pin p : pins) {
+ if (p.getDirection() == Pin.Direction.both) {
+ if (bidirect == null)
+ bidirect = new ArrayList<>();
+ bidirect.add(p.getReaderValue());
+ }
+ }
+ if (bidirect != null)
+ inputs = Splitter.combine(inputs, bidirect.toArray(new ObservableValue[bidirect.size()]));
+
element.setInputs(inputs);
}
ioState = new IOState(inputs, element.getOutputs());
diff --git a/src/main/java/de/neemann/digital/gui/draw/model/Net.java b/src/main/java/de/neemann/digital/gui/draw/model/Net.java
index 380cd0bf3..c767337d0 100644
--- a/src/main/java/de/neemann/digital/gui/draw/model/Net.java
+++ b/src/main/java/de/neemann/digital/gui/draw/model/Net.java
@@ -97,6 +97,9 @@ public class Net {
for (Pin i : inputs)
i.setValue(value);
+ for (Pin o : outputs) // set also the reader for bidirectional pins
+ o.setReaderValue(value);
+
if (bindWiresToValues && wires != null)
for (Wire w : wires)
w.setValue(value);
diff --git a/src/main/java/de/neemann/digital/gui/draw/shapes/DemuxerShape.java b/src/main/java/de/neemann/digital/gui/draw/shapes/DemuxerShape.java
index 05c4434ab..671da713d 100644
--- a/src/main/java/de/neemann/digital/gui/draw/shapes/DemuxerShape.java
+++ b/src/main/java/de/neemann/digital/gui/draw/shapes/DemuxerShape.java
@@ -18,19 +18,21 @@ public class DemuxerShape implements Shape {
private final int outputCount;
private final boolean hasInput;
private final boolean flip;
+ private final int height;
private Pins pins;
public DemuxerShape(int selectorBits, boolean hasInput, boolean flip) {
this.hasInput = hasInput;
this.flip = flip;
- this.outputCount = 1 << selectorBits;
+ outputCount = 1 << selectorBits;
+ height = hasInput || (outputCount <= 2) ? outputCount * SIZE : (outputCount - 1) * SIZE;
}
@Override
public Pins getPins() {
if (pins == null) {
pins = new Pins();
- pins.add(new Pin(new Vector(SIZE, flip ? 0 : outputCount * SIZE), "sel", Pin.Direction.input));
+ pins.add(new Pin(new Vector(SIZE, flip ? 0 : height), "sel", Pin.Direction.input));
if (outputCount == 2) {
pins.add(new Pin(new Vector(SIZE * 2, 0 * SIZE), "out_0", Pin.Direction.output));
pins.add(new Pin(new Vector(SIZE * 2, 2 * SIZE), "out_1", Pin.Direction.output));
@@ -54,7 +56,7 @@ public class DemuxerShape implements Shape {
graphic.drawPolygon(new Polygon(true)
.add(2, 3)
.add(SIZE * 2 - 2, -2)
- .add(SIZE * 2 - 2, outputCount * SIZE + 2)
- .add(2, outputCount * SIZE - 3), Style.NORMAL);
+ .add(SIZE * 2 - 2, height + 2)
+ .add(2, height - 3), Style.NORMAL);
}
}
diff --git a/src/main/resources/lang/lang_de.properties b/src/main/resources/lang/lang_de.properties
index dffeb4155..d00375758 100644
--- a/src/main/resources/lang/lang_de.properties
+++ b/src/main/resources/lang/lang_de.properties
@@ -50,12 +50,15 @@ err_duplicateElement_N=Doppeltes Element {0}
err_element_N_notFound=Element {0} nicht gefunden
err_spitterDefSyntaxError=Fehler in der Definition {0} eines Splitters
err_noShapeFoundFor_N=Es wurde kein Diagramm für {0} gefunden.
+err_invalidFileFormat=Ung\u00FCltiges Dateiformat
err_readOfHighZ=Lesen einer hochohmigen Leitung
+err_notAllOutputsSameBits=Es haben nicht alle Ausg\u00E4nge die gleiche Bitbreite
+err_notAllOutputsSupportHighZ=Wenn mehrere Ausg\u00E4nge verbunden sind, m\u00FCssen alle Tri-State Ausg\u00E4nge sein
attr_dialogTitle=Eigenschaften
msg_errorEditingValue=Fehler bei der Eingabe eines Wertes
msg_color=Farbe
-msg_errorImportingModel=Fehler beim Import eins Modells
-msg_errorCreatingModel=Fehler beim Erzeugen eines Modells
+msg_errorImportingModel=Fehler beim Import eines Modells
+msg_errorCreatingModel=Fehler beim Erzeugen des Modells
msg_errorWritingFile=Fehler beim Schreiben einer Datei
msg_errorReadingFile=Fehler beim Lesen einer Datei
msg_errorCalculatingStep=Fehler beim Berechnen eines Schrittes
diff --git a/src/main/resources/lang/lang_en.properties b/src/main/resources/lang/lang_en.properties
index 6ec628f90..40fdda999 100644
--- a/src/main/resources/lang/lang_en.properties
+++ b/src/main/resources/lang/lang_en.properties
@@ -53,6 +53,7 @@ err_noShapeFoundFor_N=No shape found for Element {0}
err_invalidFileFormat=Invalid file format
err_readOfHighZ=Read of high Z value
err_notAllOutputsSameBits=Not all connected outputs have the same bit count
+err_notAllOutputsSupportHighZ=If multiple outputs are connected together, all of them have to be three-state outputs
attr_dialogTitle=Attributes
msg_errorEditingValue=Error editing a atribute value
msg_color=Color
diff --git a/src/test/java/de/neemann/digital/core/memory/CounterTest.java b/src/test/java/de/neemann/digital/core/memory/CounterTest.java
new file mode 100644
index 000000000..db93f07cd
--- /dev/null
+++ b/src/test/java/de/neemann/digital/core/memory/CounterTest.java
@@ -0,0 +1,36 @@
+package de.neemann.digital.core.memory;
+
+import de.neemann.digital.TestExecuter;
+import de.neemann.digital.core.Model;
+import de.neemann.digital.core.ObservableValue;
+import de.neemann.digital.core.element.ElementAttributes;
+import junit.framework.TestCase;
+
+/**
+ * @author hneemann
+ */
+public class CounterTest extends TestCase {
+
+ public void testCounter() throws Exception {
+ ObservableValue clk = new ObservableValue("clk", 1);
+ ObservableValue clr = new ObservableValue("clr", 1);
+
+ Model model = new Model();
+ Counter out = model.add(new Counter(
+ new ElementAttributes()
+ .setBits(8)));
+ out.setInputs(clk, clr);
+
+ TestExecuter sc = new TestExecuter(model).setInputs(clk, clr).setOutputs(out.getOutputs());
+ sc.check(0, 0, 0);
+ sc.check(1, 0, 1);
+ sc.check(0, 0, 1);
+ sc.check(1, 0, 2);
+ sc.check(0, 0, 2);
+ sc.check(1, 0, 3);
+ sc.check(0, 0, 3);
+ sc.check(0, 1, 0);
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/de/neemann/digital/core/memory/DataFieldTest.java b/src/test/java/de/neemann/digital/core/memory/DataFieldTest.java
index 34d960ded..87c87ddb0 100644
--- a/src/test/java/de/neemann/digital/core/memory/DataFieldTest.java
+++ b/src/test/java/de/neemann/digital/core/memory/DataFieldTest.java
@@ -2,6 +2,8 @@ package de.neemann.digital.core.memory;
import junit.framework.TestCase;
+import java.io.StringReader;
+
/**
* @author hneemann
*/
@@ -25,4 +27,13 @@ public class DataFieldTest extends TestCase {
assertEquals(1, data.getData(30));
}
+ public void testLoad() throws Exception {
+ String data = "v2.0 raw\n0\n10\nAA\nFF";
+ DataField df = new DataField(new StringReader(data));
+ assertEquals(4, df.size());
+ assertEquals(0x00, df.getData(0));
+ assertEquals(0x10, df.getData(1));
+ assertEquals(0xAA, df.getData(2));
+ assertEquals(0xFF, df.getData(3));
+ }
}
\ No newline at end of file
diff --git a/src/test/java/de/neemann/digital/core/memory/RAMDualPortTest.java b/src/test/java/de/neemann/digital/core/memory/RAMDualPortTest.java
new file mode 100644
index 000000000..4846fcd4b
--- /dev/null
+++ b/src/test/java/de/neemann/digital/core/memory/RAMDualPortTest.java
@@ -0,0 +1,42 @@
+package de.neemann.digital.core.memory;
+
+import de.neemann.digital.TestExecuter;
+import de.neemann.digital.core.Model;
+import de.neemann.digital.core.ObservableValue;
+import de.neemann.digital.core.element.AttributeKey;
+import de.neemann.digital.core.element.ElementAttributes;
+import junit.framework.TestCase;
+
+import static de.neemann.digital.TestExecuter.HIGHZ;
+
+/**
+ * @author hneemann
+ */
+public class RAMDualPortTest extends TestCase {
+
+ public void testRAM() throws Exception {
+ ObservableValue a = new ObservableValue("a", 4);
+ ObservableValue d = new ObservableValue("d", 4);
+ ObservableValue str = new ObservableValue("str", 1);
+ ObservableValue clk = new ObservableValue("clk", 1);
+ ObservableValue ld = new ObservableValue("ld", 1);
+
+ Model model = new Model();
+ RAMDualPort out = model.add(new RAMDualPort(
+ new ElementAttributes()
+ .set(AttributeKey.AddrBits, 4)
+ .setBits(4)));
+ out.setInputs(a, d, str, clk, ld);
+
+ TestExecuter sc = new TestExecuter(model).setInputs(a, d, str, clk, ld).setOutputs(out.getOutputs());
+ // A D ST C LD
+ sc.check(0, 0, 0, 0, 0, HIGHZ); // def
+ sc.check(0, 5, 1, 1, 0, HIGHZ); // st 0->5
+ sc.check(0, 0, 0, 0, 0, HIGHZ); // def
+ sc.check(1, 9, 1, 1, 0, HIGHZ); // st 1->9
+ sc.check(0, 0, 0, 0, 1, 5); // rd 5
+ sc.check(1, 0, 0, 0, 1, 9); // rd 5
+ }
+
+
+}
\ No newline at end of file