From 8ee40a3d495836d985ab13441fa466e5b0080d91 Mon Sep 17 00:00:00 2001 From: hneemann Date: Tue, 17 Nov 2020 20:51:49 +0100 Subject: [PATCH] if high-z values are used, random bits are created --- src/main/dig/cmos/sram.dig | 6 ++--- .../neemann/digital/core/ObservableValue.java | 22 +++++++++++++++- .../core/wiring/bus/AbstractBusHandler.java | 6 +++-- src/main/resources/lang/lang_de.xml | 3 +-- src/main/resources/lang/lang_en.xml | 2 +- .../digital/core/ObservableValueTest.java | 26 +++++++++++++------ .../digital/core/wiring/BusSplitterTest.java | 13 +++++----- 7 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/main/dig/cmos/sram.dig b/src/main/dig/cmos/sram.dig index 43c62188b..0b8fd8a8a 100644 --- a/src/main/dig/cmos/sram.dig +++ b/src/main/dig/cmos/sram.dig @@ -519,9 +519,9 @@ in der Speichermatrix gespeichert.}} # write all cells to one loop(n,16) -bits(4,n) 0 1 0 -bits(4,n) 1 1 1 -bits(4,n) 0 1 1 +bits(4,n) 0 1 x +bits(4,n) 1 1 x +bits(4,n) 0 1 x end loop # check all cells are one diff --git a/src/main/java/de/neemann/digital/core/ObservableValue.java b/src/main/java/de/neemann/digital/core/ObservableValue.java index f6f2bbf52..59828cc59 100644 --- a/src/main/java/de/neemann/digital/core/ObservableValue.java +++ b/src/main/java/de/neemann/digital/core/ObservableValue.java @@ -9,6 +9,8 @@ import de.neemann.digital.core.element.ElementTypeDescription; import de.neemann.digital.core.element.PinDescription; import de.neemann.digital.lang.Lang; +import java.util.Random; + /** * Represents all signal values in the simulator. * There are some setters to set the value. Each bit of a value can be set to high z state. @@ -29,6 +31,8 @@ public class ObservableValue extends Observable implements PinDescription { private String description; private String pinNumber; private boolean isSwitchPin; + // used to create random bits if high-z values are read + private Random random; /** * Creates a new instance. @@ -122,11 +126,27 @@ public class ObservableValue extends Observable implements PinDescription { } /** - * returns the actual value + * Returns the current value. + * The high-z bits are set to a random value. * * @return the value */ public long getValue() { + if (highZ != 0) { + if (random == null) + random = new Random(); + return value | (random.nextLong() & highZ); + } else + return value; + } + + /** + * Returns the current value + * The high-z bits are set to zero + * + * @return the value + */ + public long getValueHighZIsZero() { return value; } diff --git a/src/main/java/de/neemann/digital/core/wiring/bus/AbstractBusHandler.java b/src/main/java/de/neemann/digital/core/wiring/bus/AbstractBusHandler.java index ec8720160..430054642 100644 --- a/src/main/java/de/neemann/digital/core/wiring/bus/AbstractBusHandler.java +++ b/src/main/java/de/neemann/digital/core/wiring/bus/AbstractBusHandler.java @@ -81,14 +81,16 @@ public abstract class AbstractBusHandler { long highz = -1; for (ObservableValue input : getInputs()) { highz &= input.getHighZ(); - value |= input.getValue(); + value |= input.getValueHighZIsZero(); } // check for a burn condition! for (ObservableValue input : getInputs()) { long bothDefine = ~(highz | input.getHighZ()); - if ((value & bothDefine) != (input.getValue() & bothDefine)) + if ((value & bothDefine) != (input.getValueHighZIsZero() & bothDefine)) { burn = State.burn; + break; + } } switch (getResistor()) { diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 6a67af8c6..3ad04bfb4 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -336,8 +336,7 @@ Dieser Ausgang gibt immer 1 aus. Nicht verbunden Dieses Element kann verwendet werden, um eine Leitung auf High-Z zu - legen. Wird ein Eingang eines Gatters auf High-Z gesetzt, wird dieser Wert vom Simulator wie Null - interpretiert. + legen. Wird ein Eingang eines logischen Gatters auf High-Z gesetzt, ist der gelesene Wert undefiniert. Zu beachten ist, dass es in der Realität in vielen Fällen zu überhöhter Stromaufnahme und gar zu Beschädigungen kommen kann, wenn ein Digitaleingang nicht auf Null oder Eins gesetzt wird, sondern unbeschaltet bleibt. Daher sollte dies Element mit Bedacht eingesetzt werden. diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index 0b9ea195a..bacd3ea54 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -333,7 +333,7 @@ This output always returns 1. Not Connected This component can be used to set a line to High-Z. - If an input of a gate is set to High-Z, the simulator interprets this value as zero. + If an input of a logical gate is set to high-Z, the read value is undefined. Note that in reality in many cases excessive current consumption and even damage can occur if a digital input is not set to zero or one but remains unconnected. Therefore this element should be used with care. diff --git a/src/test/java/de/neemann/digital/core/ObservableValueTest.java b/src/test/java/de/neemann/digital/core/ObservableValueTest.java index c28956e0d..1fb975f2f 100644 --- a/src/test/java/de/neemann/digital/core/ObservableValueTest.java +++ b/src/test/java/de/neemann/digital/core/ObservableValueTest.java @@ -9,6 +9,7 @@ import junit.framework.Assert; import junit.framework.TestCase; /** + * */ public class ObservableValueTest extends TestCase { @@ -52,13 +53,22 @@ public class ObservableValueTest extends TestCase { public void testHighZ() { ObservableValue v = new ObservableValue("z", 4); - check(0, 15, v.set(15, 15)); check(14, 1, v.set(15, 1)); check(12, 3, v.set(15, 3)); + + v.set(15, 15); + long min = 15; + long max = 0; + for (int i = 0; i < 100; i++) { + long val = v.getValue(); + if (val < min) min = val; + if (val > max) max = val; + } + assertTrue(max - min > 8); } private void check(long val, long z, ObservableValue v) { - assertEquals(val, v.getValue()); + assertEquals(val, v.getValue() & ~z); assertEquals(z, v.getHighZ()); } @@ -66,10 +76,10 @@ public class ObservableValueTest extends TestCase { ObservableValue v = new ObservableValue("z", 4) .setToHighZ() .addObserverToValue(Assert::fail); - v.set(0,15); - v.set(1,15); - v.set(2,15); - v.set(3,15); + v.set(0, 15); + v.set(1, 15); + v.set(2, 15); + v.set(3, 15); } public void testChange() { @@ -91,12 +101,12 @@ public class ObservableValueTest extends TestCase { @Override public void hasChanged() { - changed=true; + changed = true; } private boolean isChanged() { final boolean c = changed; - changed=false; + changed = false; return c; } } diff --git a/src/test/java/de/neemann/digital/core/wiring/BusSplitterTest.java b/src/test/java/de/neemann/digital/core/wiring/BusSplitterTest.java index e680ba954..f031c18a1 100644 --- a/src/test/java/de/neemann/digital/core/wiring/BusSplitterTest.java +++ b/src/test/java/de/neemann/digital/core/wiring/BusSplitterTest.java @@ -11,6 +11,7 @@ import de.neemann.digital.core.ObservableValue; import de.neemann.digital.core.element.ElementAttributes; import junit.framework.TestCase; +import static de.neemann.digital.TestExecuter.IGNORE; import static de.neemann.digital.core.ObservableValues.ovs; public class BusSplitterTest extends TestCase { @@ -30,12 +31,12 @@ public class BusSplitterTest extends TestCase { TestExecuter te = new TestExecuter(model).setInputs(oe, d, d0, d1, d2, d3).setOutputs(out.getOutputs()); - te.check(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - te.check(1, 5, 0, 0, 0, 0, 0, 1, 0, 1, 0); - te.check(1, 15, 0, 0, 0, 0, 0, 1, 1, 1, 1); - te.check(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - te.check(0, 0, 1, 0, 1, 0, 5, 0, 0, 0, 0); - te.check(0, 0, 1, 1, 1, 1, 15, 0, 0, 0, 0); + te.checkZ(1, 0, 0, 0, 0, 0, IGNORE, 0, 0, 0, 0); + te.checkZ(1, 5, 0, 0, 0, 0, IGNORE, 1, 0, 1, 0); + te.checkZ(1, 15, 0, 0, 0, 0, IGNORE, 1, 1, 1, 1); + te.checkZ(0, 0, 0, 0, 0, 0, 0, IGNORE, IGNORE, IGNORE, IGNORE); + te.checkZ(0, 0, 1, 0, 1, 0, 5, IGNORE, IGNORE, IGNORE, IGNORE); + te.checkZ(0, 0, 1, 1, 1, 1, 15, IGNORE, IGNORE, IGNORE, IGNORE); } }