mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-14 23:36:27 -04:00
Merge branch 'master' into newProcessor
# Conflicts: # src/main/java/de/neemann/digital/testing/parser/Parser.java
This commit is contained in:
commit
ee86de0d49
@ -5,16 +5,11 @@
|
||||
*/
|
||||
package de.neemann.digital.testing;
|
||||
|
||||
import de.neemann.digital.core.memory.DataField;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.testing.parser.LineEmitter;
|
||||
import de.neemann.digital.testing.parser.Parser;
|
||||
import de.neemann.digital.testing.parser.ParserException;
|
||||
import de.neemann.digital.testing.parser.VirtualSignal;
|
||||
import de.neemann.digital.testing.parser.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* The test data.
|
||||
@ -24,8 +19,7 @@ public class TestCaseDescription {
|
||||
private transient LineEmitter lines;
|
||||
private transient ArrayList<String> names;
|
||||
private transient ArrayList<VirtualSignal> virtualSignals;
|
||||
private transient DataField program;
|
||||
private transient HashMap<String, Long> signalInit;
|
||||
private transient ModelInitializer modelInitializer;
|
||||
|
||||
|
||||
/**
|
||||
@ -78,8 +72,7 @@ public class TestCaseDescription {
|
||||
lines = tdp.getLines();
|
||||
names = tdp.getNames();
|
||||
virtualSignals = tdp.getVirtualSignals();
|
||||
program = tdp.getProgram();
|
||||
signalInit = tdp.getSignalInit();
|
||||
modelInitializer = tdp.getModelInitializer();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,21 +103,12 @@ public class TestCaseDescription {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the program data or null if not available
|
||||
* @return the model initializer
|
||||
* @throws TestingDataException TestingDataException
|
||||
*/
|
||||
public DataField getProgram() throws TestingDataException {
|
||||
public ModelInitializer getModelInitializer() throws TestingDataException {
|
||||
check();
|
||||
return program;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the signal init values
|
||||
* @throws TestingDataException TestingDataException
|
||||
*/
|
||||
public HashMap<String, Long> getSignalInit() throws TestingDataException {
|
||||
check();
|
||||
return signalInit;
|
||||
return modelInitializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -7,7 +7,6 @@ package de.neemann.digital.testing;
|
||||
|
||||
import de.neemann.digital.core.*;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import de.neemann.digital.core.memory.ProgramMemory;
|
||||
import de.neemann.digital.core.wiring.Clock;
|
||||
import de.neemann.digital.data.Value;
|
||||
import de.neemann.digital.draw.elements.Circuit;
|
||||
@ -21,8 +20,6 @@ import de.neemann.digital.testing.parser.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Runs the test and stores the test results created by a single {@link TestCaseDescription} instance.
|
||||
@ -150,25 +147,7 @@ public class TestExecutor {
|
||||
if (outputs.size() == 0)
|
||||
throw new TestingDataException(Lang.get("err_noTestOutputSignalsDefined"));
|
||||
|
||||
if (testCase.getProgram() != null) {
|
||||
List<Node> nodes = model.findNode(n -> n instanceof ProgramMemory && ((ProgramMemory) n).isProgramMemory());
|
||||
switch (nodes.size()) {
|
||||
case 0:
|
||||
throw new TestingDataException(Lang.get("err_noRomFound"));
|
||||
case 1:
|
||||
((ProgramMemory) nodes.get(0)).setProgramMemory(testCase.getProgram());
|
||||
break;
|
||||
default:
|
||||
throw new TestingDataException(Lang.get("err_multipleRomsFound"));
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Long> r : testCase.getSignalInit().entrySet()) {
|
||||
Signal.Setter signal = model.getSignalSetter(r.getKey());
|
||||
if (signal == null)
|
||||
throw new TestingDataException(Lang.get("err_testSignal_N_notFound", r.getKey()));
|
||||
signal.set(r.getValue(), 0);
|
||||
}
|
||||
testCase.getModelInitializer().init(model);
|
||||
|
||||
model.init();
|
||||
model.addObserver(event -> {
|
||||
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.testing.parser;
|
||||
|
||||
import de.neemann.digital.core.Model;
|
||||
import de.neemann.digital.core.Node;
|
||||
import de.neemann.digital.core.Signal;
|
||||
import de.neemann.digital.core.memory.DataField;
|
||||
import de.neemann.digital.core.memory.ProgramMemory;
|
||||
import de.neemann.digital.core.memory.RAMInterface;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.testing.TestingDataException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Is prepared by the test data parser and then used to initialize the
|
||||
* model for the test.
|
||||
*/
|
||||
public class ModelInitializer {
|
||||
private final ArrayList<ModelInit> inits;
|
||||
|
||||
ModelInitializer() {
|
||||
this.inits = new ArrayList<>();
|
||||
}
|
||||
|
||||
void initSignal(String name, long value) {
|
||||
inits.add(new InitSignal(name, value));
|
||||
}
|
||||
|
||||
void initProgramMemory(DataField memory) {
|
||||
inits.add(new InitProgramMemory(memory));
|
||||
}
|
||||
|
||||
void initMemory(String ramName, int addr, long value) {
|
||||
inits.add(new InitMemory(ramName, addr, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Aplies the init steps to the given model
|
||||
*
|
||||
* @param model the model to initialize
|
||||
* @throws TestingDataException TestingDataException
|
||||
*/
|
||||
public void init(Model model) throws TestingDataException {
|
||||
for (ModelInit mi : inits)
|
||||
mi.init(model);
|
||||
}
|
||||
|
||||
private interface ModelInit {
|
||||
void init(Model model) throws TestingDataException;
|
||||
}
|
||||
|
||||
private static final class InitSignal implements ModelInit {
|
||||
private final String name;
|
||||
private final long value;
|
||||
|
||||
private InitSignal(String name, long value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Model model) throws TestingDataException {
|
||||
Signal.Setter s = model.getSignalSetter(name);
|
||||
if (s == null)
|
||||
throw new TestingDataException(Lang.get("err_testSignal_N_notFound", name));
|
||||
s.set(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class InitProgramMemory implements ModelInit {
|
||||
private final DataField dataField;
|
||||
|
||||
private InitProgramMemory(DataField dataField) {
|
||||
this.dataField = dataField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Model model) throws TestingDataException {
|
||||
List<Node> nodes = model.findNode(n -> n instanceof ProgramMemory && ((ProgramMemory) n).isProgramMemory());
|
||||
switch (nodes.size()) {
|
||||
case 0:
|
||||
throw new TestingDataException(Lang.get("err_noRomFound"));
|
||||
case 1:
|
||||
((ProgramMemory) nodes.get(0)).setProgramMemory(dataField);
|
||||
break;
|
||||
default:
|
||||
throw new TestingDataException(Lang.get("err_multipleRomsFound"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class InitMemory implements ModelInit {
|
||||
private final String memoryName;
|
||||
private final int addr;
|
||||
private final long value;
|
||||
|
||||
private InitMemory(String memoryName, int addr, long value) {
|
||||
this.memoryName = memoryName;
|
||||
this.addr = addr;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Model model) throws TestingDataException {
|
||||
List<Node> nodes = model.findNode(n -> n instanceof RAMInterface && ((RAMInterface) n).getLabel().equals(memoryName));
|
||||
switch (nodes.size()) {
|
||||
case 0:
|
||||
throw new TestingDataException(Lang.get("err_noMemoryFound", memoryName));
|
||||
case 1:
|
||||
((RAMInterface) nodes.get(0)).getMemory().setData(addr, value);
|
||||
break;
|
||||
default:
|
||||
throw new TestingDataException(Lang.get("err_multipleMemoriesFound", memoryName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
package de.neemann.digital.testing.parser;
|
||||
|
||||
import de.neemann.digital.core.Bits;
|
||||
import de.neemann.digital.core.*;
|
||||
import de.neemann.digital.core.memory.DataField;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.data.Value;
|
||||
@ -33,12 +33,11 @@ import java.util.HashMap;
|
||||
public class Parser {
|
||||
|
||||
private final ArrayList<String> names;
|
||||
private final HashMap<String, Long> signalInitMap;
|
||||
private final ModelInitializer modelInit;
|
||||
private final ArrayList<VirtualSignal> virtualSignals;
|
||||
private final Tokenizer tok;
|
||||
private final HashMap<String, Function> functions = new HashMap<>();
|
||||
private LineEmitter emitter;
|
||||
private DataField program;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
@ -51,7 +50,7 @@ public class Parser {
|
||||
functions.put("ite", new IfThenElse());
|
||||
names = new ArrayList<>();
|
||||
virtualSignals = new ArrayList<>();
|
||||
signalInitMap = new HashMap<>();
|
||||
modelInit = new ModelInitializer();
|
||||
tok = new Tokenizer(new BufferedReader(new StringReader(data)));
|
||||
}
|
||||
|
||||
@ -123,11 +122,25 @@ public class Parser {
|
||||
expect(Tokenizer.Token.NUMBER);
|
||||
long n = convToLong(tok.getIdent());
|
||||
expect(Tokenizer.Token.SEMICOLON);
|
||||
signalInitMap.put(sName, sign * n);
|
||||
modelInit.initSignal(sName, sign * n);
|
||||
break;
|
||||
case MEMORY:
|
||||
tok.consume();
|
||||
expect(Tokenizer.Token.IDENT);
|
||||
final String ramName = tok.getIdent();
|
||||
expect(Tokenizer.Token.OPEN);
|
||||
expect(Tokenizer.Token.NUMBER);
|
||||
long addr = convToLong(tok.getIdent());
|
||||
expect(Tokenizer.Token.CLOSE);
|
||||
expect(Tokenizer.Token.EQUAL);
|
||||
expect(Tokenizer.Token.NUMBER);
|
||||
long val = convToLong(tok.getIdent());
|
||||
expect(Tokenizer.Token.SEMICOLON);
|
||||
modelInit.initMemory(ramName, (int) addr, val);
|
||||
break;
|
||||
case PROGRAM:
|
||||
tok.consume();
|
||||
program = parseData();
|
||||
modelInit.initProgramMemory(parseData());
|
||||
break;
|
||||
case DECLARE:
|
||||
tok.consume();
|
||||
@ -283,17 +296,10 @@ public class Parser {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the program data or null if not available
|
||||
* @return the model init actions
|
||||
*/
|
||||
public DataField getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the signal init map
|
||||
*/
|
||||
public HashMap<String, Long> getSignalInit() {
|
||||
return signalInitMap;
|
||||
public ModelInitializer getModelInitializer() {
|
||||
return modelInit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@ public class Tokenizer {
|
||||
enum Token {
|
||||
UNKNOWN, IDENT, AND, OR, XOR, BIN_NOT, OPEN, CLOSE, NUMBER, EOL, EOF, SHIFTLEFT, SHIFTRIGHT, COMMA, EQUAL,
|
||||
ADD, SUB, MUL, GREATER, GREATEREQUAL, SMALER, SMALEREQUAL, DIV, MOD, END, LOOP, REPEAT, BITS, SEMICOLON,
|
||||
LET, LOG_NOT, DECLARE, PROGRAM, INIT, WHILE
|
||||
LET, LOG_NOT, DECLARE, PROGRAM, INIT, MEMORY, WHILE
|
||||
}
|
||||
|
||||
private final static HashMap<String, Token> STATEMENT_MAP = new HashMap<>();
|
||||
@ -32,6 +32,7 @@ public class Tokenizer {
|
||||
STATEMENT_MAP.put("declare", Token.DECLARE);
|
||||
STATEMENT_MAP.put("program", Token.PROGRAM);
|
||||
STATEMENT_MAP.put("init", Token.INIT);
|
||||
STATEMENT_MAP.put("memory", Token.MEMORY);
|
||||
}
|
||||
|
||||
private final Reader in;
|
||||
|
@ -1158,6 +1158,8 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
<string name="err_verilogExporting">Fehler beim Export zu Verilog.</string>
|
||||
<string name="err_noRomFound">Kein Programmspeicher im Modell gefunden! Ein Programmspeicher muss gewählt werden!</string>
|
||||
<string name="err_multipleRomsFound">Mehrere Programmspeicher im Modell gefunden! Es darf nur ein Programmspeicher muss gewählt werden!</string>
|
||||
<string name="err_noMemoryFound">Kein Speicher "{0}" im Modell gefunden!</string>
|
||||
<string name="err_multipleMemoriesFound">Mehrere Speicher "{0}" im Modell gefunden!</string>
|
||||
<string name="err_errorLoadingRomData">Fehler beim Laden des Programmspeichers.</string>
|
||||
<string name="err_parsingSVG">Fehler beim Laden der SVG-Datei.</string>
|
||||
<string name="err_morePinsDefinedInSVGAsNeeded">Die SVG-Datei enthält Pins, die es in der Schaltung nicht gibt.</string>
|
||||
|
@ -1148,6 +1148,8 @@
|
||||
<string name="err_verilogExporting">Error during export to Verilog.</string>
|
||||
<string name="err_noRomFound">No program memory found! The program memory needs to be flagged as such.</string>
|
||||
<string name="err_multipleRomsFound">Multiple program memories found! Only one program memory is allowed.</string>
|
||||
<string name="err_noMemoryFound">No memory "{0}" found in the model!</string>
|
||||
<string name="err_multipleMemoriesFound">Multiple memories "{0}" found in the model!</string>
|
||||
<string name="err_errorLoadingRomData">Error loading the program memory.</string>
|
||||
<string name="err_parsingSVG">Error while reading the SVG file.</string>
|
||||
<string name="err_morePinsDefinedInSVGAsNeeded">The SVG file contains pins that do not exist in the circuit.</string>
|
||||
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.testing.parser;
|
||||
|
||||
import de.neemann.digital.core.Model;
|
||||
import de.neemann.digital.core.ObservableValue;
|
||||
import de.neemann.digital.core.Signal;
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import de.neemann.digital.core.memory.DataField;
|
||||
import de.neemann.digital.core.memory.RAMSinglePort;
|
||||
import de.neemann.digital.testing.TestingDataException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ModelInitializerTest extends TestCase {
|
||||
|
||||
public void test_program() throws IOException, ParserException, TestingDataException {
|
||||
ModelInitializer mi = new Parser("A B Y\n" +
|
||||
"program(1,2,3,4)\n" +
|
||||
"1 1 1").parse().getModelInitializer();
|
||||
|
||||
Model m = new Model();
|
||||
RAMSinglePort ram = m.add(new RAMSinglePort(new ElementAttributes().set(Keys.IS_PROGRAM_MEMORY, true)));
|
||||
|
||||
mi.init(m);
|
||||
|
||||
DataField program = ram.getMemory();
|
||||
assertNotNull(program);
|
||||
assertEquals(4, program.trim());
|
||||
assertEquals(1, program.getDataWord(0));
|
||||
assertEquals(2, program.getDataWord(1));
|
||||
assertEquals(3, program.getDataWord(2));
|
||||
assertEquals(4, program.getDataWord(3));
|
||||
assertEquals(0, program.getDataWord(4));
|
||||
}
|
||||
|
||||
public void test_signal() throws IOException, ParserException, TestingDataException {
|
||||
ModelInitializer mi = new Parser("A B Y\n" +
|
||||
"init s1=5;\n" +
|
||||
"init s2=-1;\n" +
|
||||
"1 1 1").parse().getModelInitializer();
|
||||
|
||||
Model m = new Model();
|
||||
ObservableValue s1 = new ObservableValue("s", 8);
|
||||
ObservableValue s2 = new ObservableValue("s", 8);
|
||||
m.addSignal(new Signal("s1", s1, (value, highZ) -> s1.setValue(value)));
|
||||
m.addSignal(new Signal("s2", s2, (value, highZ) -> s2.setValue(value)));
|
||||
|
||||
mi.init(m);
|
||||
|
||||
assertEquals(5, s1.getValue());
|
||||
assertEquals(-1, s2.getValueSigned());
|
||||
}
|
||||
|
||||
public void test_ram() throws IOException, ParserException, TestingDataException {
|
||||
ModelInitializer mi = new Parser("A B Y\n" +
|
||||
"memory myRam(0)=1;\n" +
|
||||
"memory myRam(1)=2;\n" +
|
||||
"1 1 1").parse().getModelInitializer();
|
||||
|
||||
Model m = new Model();
|
||||
RAMSinglePort ram = m.add(new RAMSinglePort(new ElementAttributes().set(Keys.LABEL, "myRam")));
|
||||
|
||||
mi.init(m);
|
||||
|
||||
DataField ramData = ram.getMemory();
|
||||
assertNotNull(ram);
|
||||
assertEquals(2, ramData.trim());
|
||||
assertEquals(1, ramData.getDataWord(0));
|
||||
assertEquals(2, ramData.getDataWord(1));
|
||||
|
||||
|
||||
m = new Model();
|
||||
m.add(new RAMSinglePort(new ElementAttributes().set(Keys.LABEL, "wrongName")));
|
||||
try {
|
||||
mi.init(m);
|
||||
fail();
|
||||
} catch (TestingDataException e) {
|
||||
assertTrue(e.getMessage().contains("myRam"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,8 +8,13 @@ package de.neemann.digital.testing.parser;
|
||||
import de.neemann.digital.core.Model;
|
||||
import de.neemann.digital.core.ObservableValue;
|
||||
import de.neemann.digital.core.Signal;
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import de.neemann.digital.core.memory.DataField;
|
||||
import de.neemann.digital.core.memory.RAMSinglePort;
|
||||
import de.neemann.digital.core.memory.ROM;
|
||||
import de.neemann.digital.data.Value;
|
||||
import de.neemann.digital.testing.TestingDataException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -193,7 +198,7 @@ public class ParserTest extends TestCase {
|
||||
assertEquals(1, td.getLines().size());
|
||||
}
|
||||
|
||||
public void test_modelInitState() throws IOException, ParserException {
|
||||
public void test_modelSetVar() throws IOException, ParserException {
|
||||
Model model = new Model();
|
||||
model.addOutput(new Signal("A", new ObservableValue("A", 3).setValue(2)));
|
||||
model.addOutput(new Signal("B", new ObservableValue("B", 3).setValue(3)));
|
||||
@ -204,19 +209,4 @@ public class ParserTest extends TestCase {
|
||||
new LineCollector(parser, context);
|
||||
assertEquals(5, context.getVar("a"));
|
||||
}
|
||||
|
||||
public void test_program() throws IOException, ParserException {
|
||||
Parser parser = new Parser("A B Y\n" +
|
||||
"program(1,2,3,4)\n" +
|
||||
"1 1 1").parse();
|
||||
DataField program = parser.getProgram();
|
||||
assertNotNull(program);
|
||||
assertEquals(4, program.trim());
|
||||
assertEquals(1, program.getDataWord(0));
|
||||
assertEquals(2, program.getDataWord(1));
|
||||
assertEquals(3, program.getDataWord(2));
|
||||
assertEquals(4, program.getDataWord(3));
|
||||
assertEquals(0, program.getDataWord(4));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,11 +13,11 @@
|
||||
<entry>
|
||||
<string>Testdata</string>
|
||||
<testData>
|
||||
<dataString>en Out
|
||||
<dataString>en Out R
|
||||
|
||||
init R=1;
|
||||
|
||||
0 1
|
||||
0 1 1
|
||||
</dataString>
|
||||
</testData>
|
||||
</entry>
|
||||
@ -100,11 +100,11 @@ init R=1;
|
||||
<entry>
|
||||
<string>Testdata</string>
|
||||
<testData>
|
||||
<dataString>en Out
|
||||
<dataString>en Out R
|
||||
|
||||
init R=7;
|
||||
|
||||
0 7
|
||||
0 7 7
|
||||
</dataString>
|
||||
</testData>
|
||||
</entry>
|
||||
|
Loading…
x
Reference in New Issue
Block a user