added multiplexer and demultiplexer

This commit is contained in:
hneemann 2016-03-25 14:32:24 +01:00
parent 7a379e7f68
commit 278fffe42e
14 changed files with 304 additions and 32 deletions

View File

@ -14,6 +14,7 @@ public class AttributeKey<VALUE> {
public static final AttributeKey<String> InputSplit = new AttributeKey<>("Input Splitting", "");
public static final AttributeKey<String> OutputSplit = new AttributeKey<>("Output Splitting", "");
public static final AttributeKey<Integer> Frequency = new AttributeKey<>("Frequency", 1);
public static final AttributeKey<Integer> SelectorBits = new AttributeKey<>("Selector Bits", 1);
private final String name;
private final VALUE def;

View File

@ -21,14 +21,16 @@ public interface Element {
void setInputs(ObservableValue... inputs) throws NodeException;
/**
* When the connections between the elements are build
* When the connections between the elements are build all outputs a collected
* by calling this method. After the interconnection they are set to the inputs
* by calling <code>setInputs()</code>
*
* @return the list of outputs wich are set by this element
*/
ObservableValue[] getOutputs();
/**
* The element has to connect itself to the model.
* The element has to register itself to the model.
*
* @param model the model to register to
*/
@ -40,5 +42,4 @@ public interface Element {
default void init() {
}
;
}

View File

@ -0,0 +1,68 @@
package de.neemann.digital.core.wiring;
import de.neemann.digital.core.Node;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.element.AttributeKey;
import de.neemann.digital.core.element.Element;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
/**
* @author hneemann
*/
public class Demultiplexer extends Node implements Element {
private final int selectorBits;
private final Integer bits;
private final long defaultValue;
private final ObservableValue[] output;
private ObservableValue selector;
private ObservableValue input;
private int oldSelectorValue;
private int selectorValue;
private long value;
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(Demultiplexer.class, "sel", "in")
.addAttribute(AttributeKey.Bits)
.addAttribute(AttributeKey.SelectorBits)
.addAttribute(AttributeKey.Default);
public Demultiplexer(ElementAttributes attributes) {
bits = attributes.get(AttributeKey.Bits);
this.selectorBits = attributes.get(AttributeKey.SelectorBits);
this.defaultValue = attributes.get(AttributeKey.Default);
int outputs = 1 << selectorBits;
output = new ObservableValue[outputs];
for (int i = 0; i < outputs; i++) {
output[i] = new ObservableValue("out_" + i, bits);
output[i].setValue(defaultValue);
}
}
@Override
public ObservableValue[] getOutputs() {
return output;
}
@Override
public void readInputs() throws NodeException {
selectorValue = (int) selector.getValue();
value = input.getValue();
}
@Override
public void writeOutputs() throws NodeException {
output[oldSelectorValue].setValue(defaultValue);
output[selectorValue].setValue(value);
oldSelectorValue = selectorValue;
}
public void setInputs(ObservableValue... inputs) throws NodeException {
selector = inputs[0].addObserver(this).checkBits(selectorBits, this);
input = inputs[1].addObserver(this).checkBits(bits, this);
}
}

View File

@ -4,6 +4,9 @@ import de.neemann.digital.core.BitsException;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.basic.FanIn;
import de.neemann.digital.core.element.AttributeKey;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import java.util.Arrays;
@ -16,17 +19,28 @@ public class Multiplexer extends FanIn {
private ObservableValue selector;
private long value;
public Multiplexer(int dataBits, int selectorBits) {
super(dataBits);
this.selectorBits = selectorBits;
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(Multiplexer.class) {
@Override
public String[] getInputNames(ElementAttributes elementAttributes) {
int size = 1 << elementAttributes.get(AttributeKey.SelectorBits);
String[] names = new String[size + 1];
names[0] = "sel";
for (int i = 0; i < size; i++)
names[i + 1] = "in_" + i;
return names;
}
}
.addAttribute(AttributeKey.Bits)
.addAttribute(AttributeKey.SelectorBits);
public Multiplexer(ElementAttributes attributes) {
super(attributes.get(AttributeKey.Bits));
this.selectorBits = attributes.get(AttributeKey.SelectorBits);
}
@Override
public void readInputs() throws NodeException {
int n = (int) selector.getValue();
if (n >= inputs.size())
throw new NodeException("multiplexerSelectsNotPresentInput", this);
value = inputs.get(n).getValue();
}
@ -37,11 +51,11 @@ public class Multiplexer extends FanIn {
@Override
public void setInputs(ObservableValue... inputs) throws NodeException {
selector = inputs[inputs.length - 1];
selector.addObserver(this);
super.setInputs(Arrays.copyOfRange(inputs, 0, inputs.length - 1));
selector = inputs[0].addObserver(this).checkBits(selectorBits, this);
ObservableValue[] in = Arrays.copyOfRange(inputs, 1, inputs.length);
super.setInputs(in);
if (selector.getBits() != selectorBits)
throw new BitsException("selectorMismatch", this, selector);
if (in.length != (1 << selectorBits))
throw new BitsException("selectorInputCountMismatch", this, selector);
}
}

View File

@ -125,7 +125,7 @@ public class LibrarySelector implements ElementNotFoundNotification {
importedElements.add(description.getName());
return description;
} catch (Exception e) {
new ErrorMessage("error importing model").addCause(e).show();
SwingUtilities.invokeLater(new ErrorMessage("error importing model").addCause(e));
}
return null;
}

View File

@ -58,14 +58,11 @@ public class Circuit implements Drawable {
}
}
public Circuit() {
visualElements = new ArrayList<>();
wires = new ArrayList<>();
}
@Override
public void drawTo(Graphic graphic) {
if (!dotsPresent) {

View File

@ -12,8 +12,10 @@ public class PinOrder implements ElementOrderer.OrderInterface<String> {
private final ArrayList<Entry> entries;
private final ArrayList<VisualElement> elements;
private final Circuit circuit;
public PinOrder(Circuit circuit, String name) {
this.circuit = circuit;
this.elements = circuit.getElements();
entries = new ArrayList<>();
for (int i = 0; i < elements.size(); i++)
@ -47,6 +49,7 @@ public class PinOrder implements ElementOrderer.OrderInterface<String> {
entries.set(i, entries.get(j));
entries.set(j, x);
circuit.modified();
}
public static class Entry {

View File

@ -12,9 +12,7 @@ import de.neemann.digital.core.flipflops.T_FF;
import de.neemann.digital.core.io.Const;
import de.neemann.digital.core.io.In;
import de.neemann.digital.core.io.Out;
import de.neemann.digital.core.wiring.Clock;
import de.neemann.digital.core.wiring.Delay;
import de.neemann.digital.core.wiring.Splitter;
import de.neemann.digital.core.wiring.*;
import java.util.ArrayList;
import java.util.HashMap;
@ -45,6 +43,9 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
add(Out.PROBEDESCRIPTION, "IO");
add(Clock.DESCRIPTION, "IO");
add(Multiplexer.DESCRIPTION, "Mux");
add(Demultiplexer.DESCRIPTION, "Mux");
add(Splitter.DESCRIPTION, "Wires");
add(Const.DESCRIPTION, "Wires");

View File

@ -0,0 +1,55 @@
package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.core.Observer;
import de.neemann.digital.gui.draw.elements.IOState;
import de.neemann.digital.gui.draw.elements.Pin;
import de.neemann.digital.gui.draw.elements.Pins;
import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.graphics.Polygon;
import de.neemann.digital.gui.draw.graphics.Style;
import de.neemann.digital.gui.draw.graphics.Vector;
import static de.neemann.digital.gui.draw.shapes.GenericShape.SIZE;
/**
* @author hneemann
*/
public class DemuxerShape implements Shape {
private final int outputCount;
private Pins pins;
public DemuxerShape(int selectorBits) {
this.outputCount = 1 << selectorBits;
}
@Override
public Pins getPins() {
if (pins == null) {
pins = new Pins();
pins.add(new Pin(new Vector(SIZE, outputCount * SIZE), "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));
} else
for (int i = 0; i < outputCount; i++) {
pins.add(new Pin(new Vector(SIZE * 2, i * SIZE), "out_" + i, Pin.Direction.output));
}
pins.add(new Pin(new Vector(0, (outputCount / 2) * SIZE), "in", Pin.Direction.input));
}
return pins;
}
@Override
public Interactor applyStateMonitor(IOState ioState, Observer guiObserver) {
return null;
}
@Override
public void drawTo(Graphic graphic) {
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);
}
}

View File

@ -0,0 +1,55 @@
package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.core.Observer;
import de.neemann.digital.gui.draw.elements.IOState;
import de.neemann.digital.gui.draw.elements.Pin;
import de.neemann.digital.gui.draw.elements.Pins;
import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.graphics.Polygon;
import de.neemann.digital.gui.draw.graphics.Style;
import de.neemann.digital.gui.draw.graphics.Vector;
import static de.neemann.digital.gui.draw.shapes.GenericShape.SIZE;
/**
* @author hneemann
*/
public class MuxerShape implements Shape {
private final int inputCount;
private Pins pins;
public MuxerShape(int selectorBits) {
this.inputCount = 1 << selectorBits;
}
@Override
public Pins getPins() {
if (pins == null) {
pins = new Pins();
pins.add(new Pin(new Vector(SIZE, inputCount * SIZE), "sel", Pin.Direction.input));
if (inputCount == 2) {
pins.add(new Pin(new Vector(0, 0 * SIZE), "in_0", Pin.Direction.input));
pins.add(new Pin(new Vector(0, 2 * SIZE), "in_1", Pin.Direction.input));
} else
for (int i = 0; i < inputCount; i++) {
pins.add(new Pin(new Vector(0, i * SIZE), "in_" + i, Pin.Direction.input));
}
pins.add(new Pin(new Vector(SIZE * 2, (inputCount / 2) * SIZE), "out", Pin.Direction.output));
}
return pins;
}
@Override
public Interactor applyStateMonitor(IOState ioState, Observer guiObserver) {
return null;
}
@Override
public void drawTo(Graphic graphic) {
graphic.drawPolygon(new Polygon(true)
.add(2, -2)
.add(SIZE * 2 - 2, 3)
.add(SIZE * 2 - 2, inputCount * SIZE - 3)
.add(2, inputCount * SIZE + 2), Style.NORMAL);
}
}

View File

@ -11,9 +11,7 @@ import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.io.Const;
import de.neemann.digital.core.io.In;
import de.neemann.digital.core.io.Out;
import de.neemann.digital.core.wiring.Clock;
import de.neemann.digital.core.wiring.Delay;
import de.neemann.digital.core.wiring.Splitter;
import de.neemann.digital.core.wiring.*;
import de.neemann.digital.gui.draw.library.ElementLibrary;
import java.util.HashMap;
@ -56,6 +54,8 @@ public final class ShapeFactory {
map.put(Out.LEDDESCRIPTION.getName(), attr -> new LEDShape(attr.get(AttributeKey.Label), attr.get(AttributeKey.Color)));
map.put(Out.PROBEDESCRIPTION.getName(), attr -> new ProbeShape(attr.get(AttributeKey.Label)));
map.put(Clock.DESCRIPTION.getName(), attr -> new ClockShape(attr.get(AttributeKey.Label)));
map.put(Multiplexer.DESCRIPTION.getName(), attr -> new MuxerShape(attr.get(AttributeKey.SelectorBits)));
map.put(Demultiplexer.DESCRIPTION.getName(), attr -> new DemuxerShape(attr.get(AttributeKey.SelectorBits)));
map.put(Splitter.DESCRIPTION.getName(), attr -> new SplitterShape(attr.get(AttributeKey.InputSplit), attr.get(AttributeKey.OutputSplit)));

View File

@ -0,0 +1,55 @@
package de.neemann.digital.core.wiring;
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;
/**
* @author hneemann
*/
public class DemultiplexerTest extends TestCase {
public void testDemux() throws Exception {
Model model = new Model();
ObservableValue a = new ObservableValue("a", 4);
ObservableValue sel = new ObservableValue("sel", 2);
Demultiplexer demul = model.add(new Demultiplexer(
new ElementAttributes()
.set(AttributeKey.Bits, 4)
.set(AttributeKey.SelectorBits, 2)));
demul.setInputs(sel, a);
TestExecuter te = new TestExecuter(model).setInputs(a, sel).setOutputs(demul.getOutputs());
te.check(2, 0, 2, 0, 0, 0);
te.check(3, 0, 3, 0, 0, 0);
te.check(3, 1, 0, 3, 0, 0);
te.check(4, 2, 0, 0, 4, 0);
te.check(5, 3, 0, 0, 0, 5);
}
public void testDemuxDefault() throws Exception {
Model model = new Model();
ObservableValue a = new ObservableValue("a", 4);
ObservableValue sel = new ObservableValue("sel", 2);
Demultiplexer demul = model.add(new Demultiplexer(
new ElementAttributes()
.set(AttributeKey.Bits, 4)
.set(AttributeKey.Default, 7)
.set(AttributeKey.SelectorBits, 2)));
demul.setInputs(sel, a);
TestExecuter te = new TestExecuter(model).setInputs(a, sel).setOutputs(demul.getOutputs());
te.check(2, 0, 2, 7, 7, 7);
te.check(3, 0, 3, 7, 7, 7);
te.check(3, 1, 7, 3, 7, 7);
te.check(4, 2, 7, 7, 4, 7);
te.check(5, 3, 7, 7, 7, 5);
}
}

View File

@ -5,6 +5,8 @@ import de.neemann.digital.core.BitsException;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.basic.FanIn;
import de.neemann.digital.core.element.AttributeKey;
import de.neemann.digital.core.element.ElementAttributes;
import junit.framework.TestCase;
/**
@ -19,8 +21,10 @@ public class MultiplexerTest extends TestCase {
ObservableValue c = new ObservableValue("c", 4);
ObservableValue d = new ObservableValue("d", 4);
ObservableValue sel = new ObservableValue("sel", 2);
FanIn out = model.add(new Multiplexer(4, 2));
out.setInputs(a, b, c, d, sel);
FanIn out = model.add(new Multiplexer(
new ElementAttributes().set(AttributeKey.Bits, 4)
.set(AttributeKey.SelectorBits, 2)));
out.setInputs(sel, a, b, c, d);
TestExecuter te = new TestExecuter(model).setInputs(a, b, c, d, sel).setOutputs(out.getOutputs());
@ -37,15 +41,33 @@ public class MultiplexerTest extends TestCase {
ObservableValue c = new ObservableValue("c", 4);
ObservableValue d = new ObservableValue("d", 4);
ObservableValue sel = new ObservableValue("sel", 1);
FanIn out = new Multiplexer(4, 2);
FanIn out = new Multiplexer(
new ElementAttributes().set(AttributeKey.Bits, 4)
.set(AttributeKey.SelectorBits, 2));
try {
out.setInputs(sel, a, b, c, d);
out.setInputs(a, b, c, d, sel);
assertTrue(false);
} catch (BitsException e) {
assertTrue(true);
}
}
public void testMux3() throws Exception {
ObservableValue a = new ObservableValue("a", 4);
ObservableValue b = new ObservableValue("b", 4);
ObservableValue c = new ObservableValue("c", 4);
ObservableValue sel = new ObservableValue("sel", 2);
FanIn out = new Multiplexer(
new ElementAttributes().set(AttributeKey.Bits, 4)
.set(AttributeKey.SelectorBits, 2));
try {
out.setInputs(sel, a, b, c);
assertTrue(false);
} catch (BitsException e) {
assertTrue(true);
}
}
}

View File

@ -63,12 +63,12 @@ public class TestNesting extends TestCase {
ElementLibrary library = new ElementLibrary();
LibrarySelector librarySelector = new LibrarySelector(library);
librarySelector.setFilePath(new File(Resources.getRoot(), "dig"));
ShapeFactory.getInstance().setLibrary(library);
ShapeFactory.getInstance().setLibrary(library); // neded to generate generic shapes
return TestExecuter.createFromFile(file, library);
}
/**
* Nested JK-FF. One from tested model is not used!
* Nested JK-FF. One output from nested model is not used!
*
* @throws Exception
*/
@ -88,11 +88,11 @@ public class TestNesting extends TestCase {
/**
* Imports the same model two times.
* A simple traffic light build with two nested MS-JK flipflops.
* A simple traffic light build with two nested MS-JK flip flops.
*/
public void testMultipleNesting() throws NodeException, PinException, IOException {
TestExecuter te = createTestExecuterForNesting("dig/trafficLight.dig");
te.clockUntil(1, 0, 0); // runs the sequential logic up to the given state
te.clockUntil(1, 0, 0); // runs the sequential logic up to the given state, its necessary because initial state is undefined
// C R Y G
te.check(0, 1, 0, 0); // Red
te.check(1, 1, 0, 0);