adds a pseudo random number generator, see #598

This commit is contained in:
hneemann 2021-01-02 09:54:00 +01:00
parent b96714d61c
commit 2dab02e0c5
9 changed files with 318 additions and 9 deletions

View File

@ -144,7 +144,7 @@ public class SubstituteLibrary implements LibraryInterface {
c.getAttributes().set(Keys.IS_GENERIC, false);
generify(attr, c);
return ElementLibrary.createCustomDescription(new File(filename), c, library).isSubstitutedBuiltIn();
return ElementLibrary.createCustomDescription(new File(filename), c).isSubstitutedBuiltIn();
}
private void generify(ElementAttributes attr, Circuit circuit) throws IOException {

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2021 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.core.arithmetic;
import de.neemann.digital.core.*;
import de.neemann.digital.core.element.Element;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
import java.util.Random;
import static de.neemann.digital.core.element.PinInfo.input;
/**
* Creates a random number using the Java Random class.
*/
public class PRNG extends Node implements Element {
/**
* The element type description
*/
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(PRNG.class,
input("S"),
input("se"),
input("ne"),
input("C").setClock())
.addAttribute(Keys.ROTATE)
.addAttribute(Keys.BITS)
.addAttribute(Keys.LABEL);
private final ObservableValue output;
private final int bits;
private final long mask;
private final Random random;
private ObservableValue seedVal;
private ObservableValue setVal;
private ObservableValue nextVal;
private ObservableValue clockVal;
private boolean lastClock;
private long value;
/**
* Creates a new instance
*
* @param attributes the elements attributes
*/
public PRNG(ElementAttributes attributes) {
bits = attributes.get(Keys.BITS);
output = new ObservableValue("R", bits).setPinDescription(DESCRIPTION);
// Let Java set the initial seed so that different values are generated each simulation,
// unless a specific seed is set by the user later on.
random = new Random();
mask = Bits.mask(bits);
value = random.nextLong() & mask;
}
@Override
public void readInputs() throws NodeException {
boolean clock = clockVal.getBool();
if (clock && !lastClock) {
// First update seed
if (setVal.getBool())
random.setSeed(seedVal.getValue());
// Then value. This keeps the component well defined in case both 'set' and 'next' inputs are set.
if (nextVal.getBool())
value = random.nextLong() & mask;
}
lastClock = clock;
}
@Override
public void writeOutputs() throws NodeException {
output.setValue(value);
}
@Override
public void setInputs(ObservableValues inputs) throws NodeException {
// Note: could separate bit count for seed input & value output
seedVal = inputs.get(0).checkBits(bits, this);
setVal = inputs.get(1).checkBits(1, this);
nextVal = inputs.get(2).checkBits(1, this);
clockVal = inputs.get(3).addObserverToValue(this).checkBits(1, this);
}
@Override
public ObservableValues getOutputs() {
return output.asList();
}
}

View File

@ -89,9 +89,9 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
private final HashSet<String> isProgrammable = new HashSet<>();
private final ArrayList<LibraryListener> listeners = new ArrayList<>();
private final LibraryNode root;
private final ElementLibraryFolder custom;
private JarComponentManager jarComponentManager;
private ShapeFactory shapeFactory;
private ElementLibraryFolder custom;
private File rootLibraryPath;
private Exception exception;
private long lastRescanTime;
@ -197,7 +197,8 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.add(ROM.DESCRIPTION)
.add(ROMDualPort.DESCRIPTION)
.add(Counter.DESCRIPTION)
.add(CounterPreset.DESCRIPTION))
.add(CounterPreset.DESCRIPTION)
.add(PRNG.DESCRIPTION))
.add(new LibraryNode(Lang.get("lib_arithmetic"))
.add(Add.DESCRIPTION)
.add(Sub.DESCRIPTION)
@ -588,7 +589,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
throw new IOException(Lang.get("err_couldNotFindIncludedFile_N0", file));
}
ElementTypeDescriptionCustom description = createCustomDescription(file, circuit, this);
ElementTypeDescriptionCustom description = createCustomDescription(file, circuit);
description.setShortName(createShortName(file.getName(), circuit.getAttributes().getLabel()));
String descriptionText = Lang.evalMultilingualContent(circuit.getAttributes().get(Keys.DESCRIPTION));
@ -620,11 +621,10 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
*
* @param file the file
* @param circuit the circuit
* @param library the used library
* @return the type description
* @throws PinException PinException
*/
public static ElementTypeDescriptionCustom createCustomDescription(File file, Circuit circuit, ElementLibrary library) throws PinException {
public static ElementTypeDescriptionCustom createCustomDescription(File file, Circuit circuit) throws PinException {
ElementTypeDescriptionCustom d = new ElementTypeDescriptionCustom(file, circuit);
d.setElementFactory(attributes -> new CustomElement(d));
return d;

View File

@ -375,7 +375,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
file = new File(name);
try {
ElementTypeDescriptionCustom description =
ElementLibrary.createCustomDescription(file, circuit, library);
ElementLibrary.createCustomDescription(file, circuit);
description.setShortName(name);
description.setDescription(Lang.evalMultilingualContent(circuit.getAttributes().get(Keys.DESCRIPTION)));
new ElementHelpDialog(Main.this, description, circuit.getAttributes()).setVisible(true);

View File

@ -844,6 +844,19 @@
<string name="elem_BitCount_pin_in">Die 1-Bits in diesem Datenwort werden gezählt.</string>
<string name="elem_BitCount_pin_out">Ausgang mit der Anzahl der gezählten 1-Bits.</string>
<string name="elem_PRNG">Zufallszahlengenerator</string>
<string name="elem_PRNG_tt">Kann verwendet werden um Zufallszahlen zu erzeugen.
Beim Starten der Simulation wird der Generator neu initialisiert, so dass bei jedem Start eine neue
Pseudozufallszahlenfolge erzeugt wird.
Der Generator kann in der laufenden Simulation mit einem definierten SEED-Wert initialisiert werden,
um eine definierte Pseudozufallszahlenfolge erzeugen zu lassen.
</string>
<string name="elem_PRNG_short">PRNG</string>
<string name="elem_PRNG_pin_S">Startwert des Generators</string>
<string name="elem_PRNG_pin_se">Wenn gesetzt wird der Zufallsszahlengenerator bei der nächsten steigenden Taktflanke mit dem neuen Startwert reinitialisiert.</string>
<string name="elem_PRNG_pin_ne">Wenn gesetzt wird bei der nächsten steigenden Taktflanke eine neue Zufallsszahl ausgegeben.</string>
<string name="elem_PRNG_pin_C">Der Takteingang.</string>
<string name="elem_PRNG_pin_R">Ausgabe der Pseudozufallszahl.</string>
<!-- Schalter -->

View File

@ -819,6 +819,19 @@
<string name="elem_BitCount_pin_in">The input which 1-bits are counted.</string>
<string name="elem_BitCount_pin_out">Outputs the number of 1-bits.</string>
<string name="elem_PRNG">Random Nnumber Generator</string>
<string name="elem_PRNG_tt">Can be used to generate random numbers.
When the simulation is started, the generator is reinitialized so that a new pseudo-random number
sequence is generated at each start.
The generator can be initialized in the running simulation with a defined seed value to generate
a defined pseudo-random number sequence.
</string>
<string name="elem_PRNG_short">PRNG</string>
<string name="elem_PRNG_pin_S">New seed value of the generator.</string>
<string name="elem_PRNG_pin_se">If set, the random number generator is reinitialized with the new seed value at the next rising clock edge.</string>
<string name="elem_PRNG_pin_ne">If set, a new random number is output at the next rising clock edge.</string>
<string name="elem_PRNG_pin_C">The clock input.</string>
<string name="elem_PRNG_pin_R">Output of the pseudorandom number.</string>
<!-- Switches -->

View File

@ -50,8 +50,8 @@ public class TestExamples extends TestCase {
*/
public void testTestExamples() throws Exception {
File examples = new File(Resources.getRoot(), "/dig/test");
assertEquals(198, new FileScanner(this::check).scan(examples));
assertEquals(187, testCasesInFiles);
assertEquals(199, new FileScanner(this::check).scan(examples));
assertEquals(188, testCasesInFiles);
}
/**

View File

@ -687,6 +687,16 @@
<elementAttributes/>
<pos x="820" y="940"/>
</visualElement>
<visualElement>
<elementName>PRNG</elementName>
<elementAttributes>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="420" y="1080"/>
</visualElement>
</visualElements>
<wires>
<wire>
@ -737,6 +747,10 @@
<p1 x="700" y="520"/>
<p2 x="800" y="520"/>
</wire>
<wire>
<p1 x="400" y="1160"/>
<p2 x="420" y="1160"/>
</wire>
<wire>
<p1 x="240" y="780"/>
<p2 x="260" y="780"/>
@ -1053,6 +1067,10 @@
<p1 x="220" y="1080"/>
<p2 x="240" y="1080"/>
</wire>
<wire>
<p1 x="380" y="1080"/>
<p2 x="420" y="1080"/>
</wire>
<wire>
<p1 x="240" y="1080"/>
<p2 x="260" y="1080"/>
@ -1169,6 +1187,10 @@
<p1 x="240" y="1100"/>
<p2 x="260" y="1100"/>
</wire>
<wire>
<p1 x="400" y="1100"/>
<p2 x="420" y="1100"/>
</wire>
<wire>
<p1 x="600" y="720"/>
<p2 x="680" y="720"/>
@ -1385,6 +1407,10 @@
<p1 x="1160" y="500"/>
<p2 x="1200" y="500"/>
</wire>
<wire>
<p1 x="400" y="1140"/>
<p2 x="420" y="1140"/>
</wire>
<wire>
<p1 x="1080" y="760"/>
<p2 x="1100" y="760"/>
@ -1681,10 +1707,22 @@
<p1 x="400" y="960"/>
<p2 x="400" y="1020"/>
</wire>
<wire>
<p1 x="400" y="1020"/>
<p2 x="400" y="1100"/>
</wire>
<wire>
<p1 x="400" y="580"/>
<p2 x="400" y="780"/>
</wire>
<wire>
<p1 x="400" y="1100"/>
<p2 x="400" y="1140"/>
</wire>
<wire>
<p1 x="400" y="1140"/>
<p2 x="400" y="1160"/>
</wire>
<wire>
<p1 x="400" y="220"/>
<p2 x="400" y="260"/>
@ -2125,6 +2163,10 @@
<p1 x="380" y="820"/>
<p2 x="380" y="920"/>
</wire>
<wire>
<p1 x="380" y="920"/>
<p2 x="380" y="1080"/>
</wire>
</wires>
<measurementOrdering/>
</circuit>

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="utf-8"?>
<circuit>
<version>1</version>
<attributes/>
<visualElements>
<visualElement>
<elementName>PRNG</elementName>
<elementAttributes>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="460" y="180"/>
</visualElement>
<visualElement>
<elementName>Clock</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>C</string>
</entry>
</elementAttributes>
<pos x="280" y="260"/>
</visualElement>
<visualElement>
<elementName>Const</elementName>
<elementAttributes/>
<pos x="440" y="240"/>
</visualElement>
<visualElement>
<elementName>JK_FF</elementName>
<elementAttributes/>
<pos x="340" y="180"/>
</visualElement>
<visualElement>
<elementName>Ground</elementName>
<elementAttributes/>
<pos x="320" y="240"/>
</visualElement>
<visualElement>
<elementName>VDD</elementName>
<elementAttributes/>
<pos x="320" y="160"/>
</visualElement>
<visualElement>
<elementName>Const</elementName>
<elementAttributes>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="440" y="180"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Y</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="560" y="220"/>
</visualElement>
<visualElement>
<elementName>Testcase</elementName>
<elementAttributes>
<entry>
<string>Testdata</string>
<testData>
<dataString>C Y
c 0xd8
c 0x92
c 0xf0
c 0xdd
c 0x68
c 0x12
c 0x7e
c 0xe4
c 0xfc
</dataString>
</testData>
</entry>
</elementAttributes>
<pos x="360" y="320"/>
</visualElement>
</visualElements>
<wires>
<wire>
<p1 x="440" y="240"/>
<p2 x="460" y="240"/>
</wire>
<wire>
<p1 x="280" y="260"/>
<p2 x="300" y="260"/>
</wire>
<wire>
<p1 x="300" y="260"/>
<p2 x="460" y="260"/>
</wire>
<wire>
<p1 x="320" y="180"/>
<p2 x="340" y="180"/>
</wire>
<wire>
<p1 x="440" y="180"/>
<p2 x="460" y="180"/>
</wire>
<wire>
<p1 x="300" y="200"/>
<p2 x="340" y="200"/>
</wire>
<wire>
<p1 x="400" y="200"/>
<p2 x="460" y="200"/>
</wire>
<wire>
<p1 x="320" y="220"/>
<p2 x="340" y="220"/>
</wire>
<wire>
<p1 x="520" y="220"/>
<p2 x="560" y="220"/>
</wire>
<wire>
<p1 x="320" y="220"/>
<p2 x="320" y="240"/>
</wire>
<wire>
<p1 x="320" y="160"/>
<p2 x="320" y="180"/>
</wire>
<wire>
<p1 x="300" y="200"/>
<p2 x="300" y="260"/>
</wire>
</wires>
<measurementOrdering/>
</circuit>