improved exception handling in the cycle detector

This commit is contained in:
hneemann 2018-01-27 18:15:52 +01:00
parent 4a405cfb5e
commit 0400e40ba1
6 changed files with 25 additions and 26 deletions

View File

@ -7,7 +7,7 @@ HEAD, planned as v0.17
- Added an "export to zip" function.
- If an input or output is several bits wide, all pin numbers can be specified by a comma-separated list.
- Added a chapter "First Steps" to the documentation.
- The model analyzer now detects circles and creates an error message if a circle is detected.
- The model analyzer now detects cycles and creates an error message if a cycle is detected.
- Bug fixes
- Splitter, BarrelShifter and Comparator now are working with 64 bit.
- fixed a bug in library IC 74198

View File

@ -10,22 +10,25 @@ import java.util.HashMap;
import java.util.HashSet;
/**
* Helper to check a circuit for circles
* Helper to check a circuit for cycles.
* A cycle is a situation where a gate input depends somehow on one of its outputs.
* If a cycle is detected an exception is thrown.
*/
public final class CircleDetector {
public final class CycleDetector {
private CircleDetector() {
private CycleDetector() {
}
/**
* Returns true if the circuit has circles.
* Checks a circuit for circles.
* If a circle is detected, en exception is thrown.
*
* @param values the input signals of the circuit
* @return if the circuit has circles
* @throws BacktrackException BacktrackException
* @throws PinException PinException
* @throws CycleException is thrown if a circle is detected
*/
public static boolean hasCircles(ArrayList<Signal> values) throws BacktrackException, PinException {
public static void checkForCycles(ArrayList<Signal> values) throws BacktrackException, PinException, CycleException {
HashMap<NodeInterface, Node> nodes = new HashMap<>();
HashSet<ObservableValue> visited = new HashSet<>();
@ -35,12 +38,7 @@ public final class CircleDetector {
traverse(root, s.getValue(), nodes, visited);
}
try {
checkForCircles(nodes.values());
return false;
} catch (CircleException e) {
return true;
}
checkGraphForCycles(nodes.values());
}
private static void traverse(Node parent, ObservableValue val, HashMap<NodeInterface, Node> nodes, HashSet<ObservableValue> visited) throws PinException, BacktrackException {
@ -83,7 +81,7 @@ public final class CircleDetector {
}
}
private static void checkForCircles(Collection<Node> nodes) throws CircleException {
private static void checkGraphForCycles(Collection<Node> nodes) throws CycleException {
ArrayList<Node> remaining = new ArrayList<>(nodes);
int layer = 1;
@ -104,12 +102,15 @@ public final class CircleDetector {
}
if (ableToPlace.isEmpty())
throw new CircleException();
throw new CycleException();
remaining.removeAll(ableToPlace);
}
}
private static class CircleException extends Exception {
final static class CycleException extends AnalyseException {
private CycleException() {
super(Lang.get("err_circuitHasCycles"));
}
}
}

View File

@ -362,8 +362,7 @@ public class ModelAnalyser {
for (Signal s : outputs)
getModelAnalyzerInfo().addPinNumber(s);
if (CircleDetector.hasCircles(inputs))
throw new AnalyseException(Lang.get("err_circuitHasCircles"));
CycleDetector.checkForCycles(inputs);
DependencyAnalyser da = new DependencyAnalyser(this);
long steps = da.getRequiredSteps(this);

View File

@ -804,7 +804,7 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="err_tableHasToManyResultColumns">Die Tabelle hat zu viele Spalten!</string>
<string name="err_errorExportingZip">Fehler beim Schreiben der ZIP-Datei.</string>
<string name="err_moreThanOneFastClock">Es ist nur ein Taktelement mit hoher Frequenz erlaubt.</string>
<string name="err_circuitHasCircles">Die Schaltung enthält Zyklen und kann daher nicht analysiert werden.</string>
<string name="err_circuitHasCycles">Die Schaltung enthält Zyklen und kann daher nicht analysiert werden.</string>
<string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Anzahl der Adress-Bits, die verwendet werden.</string>

View File

@ -800,7 +800,7 @@ The names of the variables may not be unique.</string>
<string name="err_tableHasToManyResultColumns">The table has too many columns!</string>
<string name="err_errorExportingZip">Error writing the zip file.</string>
<string name="err_moreThanOneFastClock">Only one clock component with high frequency is allowed.</string>
<string name="err_circuitHasCircles">The circuit contains circles. It's not possible to analyze such a circuit.</string>
<string name="err_circuitHasCycles">The circuit contains cycles. It's not possible to analyze such a circuit.</string>
<string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Number of address bits used.</string>

View File

@ -2,10 +2,9 @@ package de.neemann.digital.analyse;
import de.neemann.digital.core.Model;
import de.neemann.digital.integration.ToBreakRunner;
import de.neemann.digital.lang.Lang;
import junit.framework.TestCase;
public class CircleDetectorTest extends TestCase {
public class CycleDetectorTest extends TestCase {
private static final String[] nameTableSequential = {
"D.dig",
@ -61,10 +60,10 @@ public class CircleDetectorTest extends TestCase {
for (String name : nameTableSequential) {
Model model = new ToBreakRunner("../../main/dig/sequential/" + name, false).getModel();
try {
TruthTable tt = new ModelAnalyser(model).analyse();
new ModelAnalyser(model).analyse();
fail();
} catch (AnalyseException e) {
assertTrue(e.getMessage().contains(Lang.get("err_circuitHasCircles")));
} catch (CycleDetector.CycleException e) {
assertTrue(true);
}
}
}
@ -72,7 +71,7 @@ public class CircleDetectorTest extends TestCase {
public void testCirclesOk() throws Exception {
for (String name : nameTableCombinatorial) {
Model model = new ToBreakRunner("../../main/dig/combinatorial/" + name, false).getModel();
TruthTable tt = new ModelAnalyser(model).analyse();
new ModelAnalyser(model).analyse();
}
}