mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-15 15:58:41 -04:00
added multiplexer and demultiplexer
This commit is contained in:
parent
7a379e7f68
commit
278fffe42e
@ -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;
|
||||
|
@ -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() {
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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)));
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user