{
public Modeldff12(LogicModelModifiable model, String name)
{
- super(model, "dff12", name, "D flip flop\n12 bits");
+ super(model, "dff12", name, "D flip flop\n12 bits", false);
setSize(40, 20);
addPin(new Pin(model, this, "D", 12, PinUsage.INPUT, 20, 20), Position.TOP);
addPin(new Pin(model, this, "C", 1, PinUsage.INPUT, 0, 10), Position.RIGHT);
addPin(new Pin(model, this, "Y", 12, PinUsage.OUTPUT, 20, 0), Position.BOTTOM);
+
+ init();
}
@Override
{
public Modeldff4_finewe(LogicModelModifiable model, String name)
{
- super(model, "dff4_finewe", name, "D flip flop\n4 bits");
+ super(model, "dff4_finewe", name, "D flip flop\n4 bits", false);
setSize(35, 90);
addPin(new Pin(model, this, "C", 1, PinUsage.INPUT, 0, 5), Position.RIGHT);
addPin(new Pin(model, this, "_WE1", 1, PinUsage.INPUT, 0, 15), Position.RIGHT);
addPin(new Pin(model, this, "Q2", 1, PinUsage.OUTPUT, 35, 15), Position.LEFT);
addPin(new Pin(model, this, "Q3", 1, PinUsage.OUTPUT, 35, 25), Position.LEFT);
addPin(new Pin(model, this, "Q4", 1, PinUsage.OUTPUT, 35, 35), Position.LEFT);
+
+ init();
}
@Override
{
public Modelinc12(LogicModelModifiable model, String name)
{
- super(model, "inc12", name, "Incrementer");
+ super(model, "inc12", name, "Incrementer", false);
setSize(40, 20);
addPin(new Pin(model, this, "A", 12, PinUsage.INPUT, 20, 20), Position.TOP);
addPin(new Pin(model, this, "CI", 1, PinUsage.INPUT, 40, 10), Position.LEFT);
addPin(new Pin(model, this, "Y", 12, PinUsage.OUTPUT, 20, 0), Position.BOTTOM);
+
+ init();
}
@Override
{
public Modelnor12(LogicModelModifiable model, String name)
{
- super(model, "nor12", name, "=0");
+ super(model, "nor12", name, "=0", false);
setSize(35, 20);
addPin(new Pin(model, this, "D", 12, PinUsage.INPUT, 0, 10), Position.RIGHT);
addPin(new Pin(model, this, "Y", 1, PinUsage.OUTPUT, 35, 10), Position.LEFT);
+
+ init();
}
@Override
{
public Modelram5_12(LogicModelModifiable model, String name)
{
- super(model, "ram5_12", name, "RAM\n5 x 12 Bit");
+ super(model, "ram5_12", name, "RAM\n5 x 12 Bit", false);
setSize(40, 40);
addPin(new Pin(model, this, "A", 3, PinUsage.INPUT, 10, 0), Position.BOTTOM);
addPin(new Pin(model, this, "B", 3, PinUsage.INPUT, 30, 0), Position.BOTTOM);
addPin(new Pin(model, this, "C", 1, PinUsage.INPUT, 0, 15), Position.RIGHT);
addPin(new Pin(model, this, "Y", 12, PinUsage.OUTPUT, 0, 30), Position.RIGHT);
addPin(new Pin(model, this, "D", 12, PinUsage.INPUT, 20, 40), Position.TOP);
+
+ init();
}
@Override
{
public Modelsel4_12(LogicModelModifiable model, String name)
{
- super(model, "sel4_12", name, "4-way SEL\n12 bit");
+ super(model, "sel4_12", name, "4-way SEL\n12 bit", false);
setSize(80, 40);
addPin(new Pin(model, this, "SA", 1, PinUsage.INPUT, 0, 5), Position.RIGHT);
addPin(new Pin(model, this, "SB", 1, PinUsage.INPUT, 0, 15), Position.RIGHT);
addPin(new Pin(model, this, "C", 12, PinUsage.INPUT, 50, 0), Position.BOTTOM);
addPin(new Pin(model, this, "D", 12, PinUsage.INPUT, 70, 0), Position.BOTTOM);
addPin(new Pin(model, this, "Y", 12, PinUsage.OUTPUT, 40, 40), Position.TOP);
+
+ init();
}
@Override
{
public ModelAm2904RegCTInstrDecode(LogicModelModifiable model, String name)
{
- super(model, "Am2904RegCTInstrDecode", name, "Instruction\ndecode");
+ super(model, "Am2904RegCTInstrDecode", name, "Instruction\ndecode", false);
setSize(80, 80);
addPin(new Pin(model, this, "I12-11", 2, PinUsage.INPUT, 0, 30), Position.RIGHT);
addPin(new Pin(model, this, "I5-0", 6, PinUsage.INPUT, 0, 50), Position.RIGHT);
// 1110: MC
// 1111: _MC
addPin(new Pin(model, this, "C0_MUX", 4, PinUsage.OUTPUT, 70, 80), Position.TOP);
+
+ init();
}
@Override
{
public ModelAm2904ShiftInstrDecode(LogicModelModifiable model, String name)
{
- super(model, "Am2904ShiftInstrDecode", name, "Shift \ninstruction\ndecode");
+ super(model, "Am2904ShiftInstrDecode", name, "Shift \ninstruction\ndecode", false);
setSize(60, 80);
addPin(new Pin(model, this, "I", 5, PinUsage.INPUT, 0, 25), Position.RIGHT);
addPin(new Pin(model, this, "_SE", 1, PinUsage.INPUT, 0, 55), Position.RIGHT);
// 1x: SIOn
addPin(new Pin(model, this, "MC_MUX", 2, PinUsage.OUTPUT, 60, 65), Position.LEFT);
addPin(new Pin(model, this, "MC_EN", 1, PinUsage.OUTPUT, 60, 75), Position.LEFT);
+
+ init();
}
@Override
{
public ModelAm2910InstrPLA(LogicModelModifiable model, String name)
{
- super(model, "Am2910InstrPLA", name, "Instr.\nPLA");
+ super(model, "Am2910InstrPLA", name, "Instr.\nPLA", false);
setSize(30, 85);
addPin(new Pin(model, this, "PASS", 1, PinUsage.INPUT, 0, 5), Position.RIGHT);
addPin(new Pin(model, this, "I", 4, PinUsage.INPUT, 0, 20), Position.RIGHT);
addPin(new Pin(model, this, "YmuPC", 1, PinUsage.OUTPUT, 30, 55), Position.LEFT);
addPin(new Pin(model, this, "STKI0", 1, PinUsage.OUTPUT, 30, 65), Position.LEFT);
addPin(new Pin(model, this, "STKI1", 1, PinUsage.OUTPUT, 30, 75), Position.LEFT);
+
+ init();
}
@Override
{
public ModelAm2910RegCntr(LogicModelModifiable model, String name)
{
- super(model, "Am2910RegCntr", name, "Register/\nCounter");
+ super(model, "Am2910RegCntr", name, "Register/\nCounter", false);
setSize(40, 40);
addPin(new Pin(model, this, "D", 12, PinUsage.INPUT, 20, 0), Position.BOTTOM);
addPin(new Pin(model, this, "_RLD", 1, PinUsage.INPUT, 0, 5), Position.RIGHT);
addPin(new Pin(model, this, "DEC", 1, PinUsage.INPUT, 0, 30), Position.RIGHT);
addPin(new Pin(model, this, "C", 1, PinUsage.INPUT, 40, 20), Position.LEFT);
addPin(new Pin(model, this, "Y", 12, PinUsage.OUTPUT, 20, 40), Position.TOP);
+
+ init();
}
@Override
{
public ModelAm2910SP(LogicModelModifiable model, String name)
{
- super(model, "Am2910SP", name, "Stack\npointer");
+ super(model, "Am2910SP", name, "Stack\npointer", false);
setSize(40, 30);
addPin(new Pin(model, this, "STKI0", 1, PinUsage.INPUT, 0, 5), Position.RIGHT);
addPin(new Pin(model, this, "STKI1", 1, PinUsage.INPUT, 0, 15), Position.RIGHT);
addPin(new Pin(model, this, "A", 3, PinUsage.OUTPUT, 10, 30), Position.TOP);
addPin(new Pin(model, this, "B", 3, PinUsage.OUTPUT, 30, 30), Position.TOP);
addPin(new Pin(model, this, "_FULL", 1, PinUsage.OUTPUT, 40, 15), Position.LEFT);
+
+ init();
}
@Override
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import org.eclipse.swt.SWT;
*/
public class LogicUICanvas extends ZoomableCanvas
{
- private static final boolean OPEN_DEBUG_SETHIGHLEVELSTATE_SHELL = false;
+ private static final boolean OPEN_DEBUG_SETHIGHLEVELSTATE_SHELL = true;
private final LogicModel model;
Combo componentSelector = new Combo(debugShell, SWT.DROP_DOWN | SWT.READ_ONLY);
componentSelector.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
List<ModelComponent> componentsByItemIndex = new ArrayList<>();
- Consumer<? super ModelComponent> compsChanged = c -> recalculateComponentSelector(componentsByItemIndex, componentSelector, model);
- model.addComponentAddedListener(compsChanged);
- model.addComponentRemovedListener(compsChanged);
- debugShell.addListener(SWT.Dispose, e ->
+ List<LogicModel> models = new ArrayList<>();
+ AtomicBoolean recalculateQueued = new AtomicBoolean();
+ AtomicReference<Consumer<? super ModelComponent>> compAdded = new AtomicReference<>();
+ AtomicReference<Consumer<? super ModelComponent>> compRemoved = new AtomicReference<>();
+ compAdded.set(c -> compsChanged(compAdded.get(), compRemoved.get(), c, models, componentsByItemIndex, componentSelector, model,
+ recalculateQueued, true));
+ compRemoved.set(c -> compsChanged(compAdded.get(), compRemoved.get(), c, models, componentsByItemIndex, componentSelector, model,
+ recalculateQueued, false));
+ iterateModelTree(compAdded.get(), compRemoved.get(), model, models, true);
+ debugShell.addListener(SWT.Dispose, e -> models.forEach(m ->
{
- model.removeComponentAddedListener(compsChanged);
- model.removeComponentRemovedListener(compsChanged);
- });
- recalculateComponentSelector(componentsByItemIndex, componentSelector, model);
+ m.removeComponentAddedListener(compAdded.get());
+ m.removeComponentRemovedListener(compRemoved.get());
+ }));
+ queueRecalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model);
new Label(debugShell, SWT.NONE).setText("Target state ID: ");
Text stateIDText = new Text(debugShell, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
stateIDText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
debugShell.open();
}
- private void recalculateComponentSelector(List<ModelComponent> componentsByItemIndex, Combo componentSelector, LogicModel model)
+ private void compsChanged(Consumer<? super ModelComponent> compAdded, Consumer<? super ModelComponent> compRemoved, ModelComponent c,
+ List<LogicModel> models, List<ModelComponent> componentsByItemIndex, Combo componentSelector, LogicModel model,
+ AtomicBoolean recalculateQueued, boolean add)
+ {
+ iterateSubmodelTree(compAdded, compRemoved, c, models, add);
+ queueRecalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model);
+ }
+
+ private void iterateSubmodelTree(Consumer<? super ModelComponent> compAdded, Consumer<? super ModelComponent> compRemoved,
+ ModelComponent c, List<LogicModel> models, boolean add)
+ {
+ if (c instanceof SubmodelComponent)
+ iterateModelTree(compAdded, compRemoved, ((SubmodelComponent) c).submodel, models, add);
+ }
+
+ private void iterateModelTree(Consumer<? super ModelComponent> compAdded, Consumer<? super ModelComponent> compRemoved,
+ LogicModel model, List<LogicModel> models, boolean add)
+ {
+ if (add ^ models.contains(model))
+ {
+ if (add)
+ {
+ models.add(model);
+ model.addComponentAddedListener(compAdded);
+ model.addComponentRemovedListener(compRemoved);
+ } else
+ {
+ models.remove(model);
+ model.removeComponentAddedListener(compAdded);
+ model.removeComponentRemovedListener(compRemoved);
+ }
+ for (ModelComponent c : model.getComponentsByName().values())
+ iterateSubmodelTree(compAdded, compRemoved, c, models, add);
+ }
+ }
+
+ private void queueRecalculateComponentSelector(AtomicBoolean recalculateQueued, List<ModelComponent> componentsByItemIndex,
+ Combo componentSelector, LogicModel model)
+ {
+ if (recalculateQueued.compareAndSet(false, true))
+ getDisplay().asyncExec(() -> recalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model));
+ }
+
+ private void recalculateComponentSelector(AtomicBoolean recalculateQueued, List<ModelComponent> componentsByItemIndex,
+ Combo componentSelector, LogicModel model)
{
+ recalculateQueued.set(false);
componentsByItemIndex.clear();
componentSelector.setItems();
addComponentSelectorItems(componentsByItemIndex, "", componentSelector, model);
}
- private void addComponentSelectorItems(List<ModelComponent> componentsByItemIndex, String base, Combo componentSelector, LogicModel model)
+ private void addComponentSelectorItems(List<ModelComponent> componentsByItemIndex, String base, Combo componentSelector,
+ LogicModel model)
{
model.getComponentsByName().values().stream().sorted((c1, c2) -> c1.name.compareTo(c2.name)).forEach(c ->
{
// creation and destruction
public ModelComponent(LogicModelModifiable model, String name)
+ {
+ this(model, name, true);
+ }
+
+ /**
+ * Creates a new {@link ModelComponent} and, if <code>callInit</code>, initializes the component (See {@link #init()}).<br>
+ * If <code>callInit==false</code>, make sure to call {@link #init()}!
+ *
+ * @author Daniel Kirschten
+ */
+ protected ModelComponent(LogicModelModifiable model, String name, boolean callInit)
{
this.model = model;
this.name = name == null ? model.getDefaultComponentName(this) : name;
this.pinAddedListeners = new ArrayList<>();
this.pinRemovedListeners = new ArrayList<>();
- // TODO this will crash the high level state debug shell because submodel is not yet set.
- // The same problem exists in LogicModelModifiable.getDefaultComponentName; see there
+ if (callInit)
+ init();
+ }
+
+ /**
+ * Initializes this component. This method should be called exactly once in this component's constructor.<br>
+ * Currently, this method only registers this component in the model.
+ */
+ protected void init()
+ {
model.componentCreated(this, this::destroyed);
}
public ModelAndGate(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, "AndGate", "&", false, logicWidth, name);
+ super(model, "AndGate", "&", false, logicWidth, name, false);
setInputCount(2);// TODO make variable
+ init();
}
static
public ModelBitDisplay(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, name);
+ super(model, name, false);
this.logicWidth = logicWidth;
logicObs = (i) -> model.requestRedraw();
setSize(width, height);
addPin(this.inputPin = new Pin(model, this, "", logicWidth, PinUsage.INPUT, 0, height / 2));
+
+ init();
}
@Override
public ModelClock(LogicModelModifiable model, ModelClockParams params, String name)
{
- super(model, name);
+ super(model, name, false);
this.params = params;
logicObs = (i) -> model.requestRedraw();
this.outputPin = new Pin(model, this, "", 1, PinUsage.OUTPUT, oc.newX(width, height / 2), oc.newY(width, height / 2));
addPin(outputPin);
+
+ init();
}
@Override
public ModelFixedOutput(LogicModelModifiable model, BitVector bits, String name)
{
- super(model, name);
+ super(model, name, false);
this.bits = bits;
setSize(width, height);
addPin(new Pin(model, this, "out", bits.length(), PinUsage.OUTPUT, width, height / 2));
+
+ init();
}
@Override
public ModelManualSwitch(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, name);
+ super(model, name, false);
this.logicWidth = logicWidth;
logicObs = (i) -> model.requestRedraw();
setSize(width, height);
addPin(this.outputPin = new Pin(model, this, "", logicWidth, PinUsage.OUTPUT, width, height / 2));
+
+ init();
}
@Override
public ModelMerger(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, name);
+ super(model, name, false);
this.logicWidth = logicWidth;
setSize(width, (logicWidth - 1) * heightPerPin);
double inputHeight = (logicWidth - 1) * heightPerPin;
addPin(new Pin(model, this, "I" + i, 1, PinUsage.TRISTATE, 0, inputHeight));
addPin(this.outputPin = new Pin(model, this, "O", logicWidth, PinUsage.TRISTATE, width, (logicWidth - 1) * heightPerPin / 2));
inputEnds = new ReadEnd[logicWidth];
+
+ init();
}
@Override
public ModelNandGate(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, "NandGate", "&", true, logicWidth, name);
+ super(model, "NandGate", "&", true, logicWidth, name, false);
setInputCount(2);// TODO make variable
+ init();
}
static
public ModelNotGate(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, "NotGate", "1", true, logicWidth, name);
+ super(model, "NotGate", "1", true, logicWidth, name, false);
setInputCount(1);
+ init();
}
static
{
- LogicCoreAdapter
- .addComponentAdapter(new SimpleGateAdapter<>(ModelNotGate.class, (t, p, o, i) -> new CoreNotGate(t, p, i[0], o)));
+ LogicCoreAdapter.addComponentAdapter(new SimpleGateAdapter<>(ModelNotGate.class, (t, p, o, i) -> new CoreNotGate(t, p, i[0], o)));
IndirectModelComponentCreator.setComponentSupplier(ModelNotGate.class.getCanonicalName(),
(m, p, n) -> new ModelNotGate(m, p.getAsInt(), n));
}
public ModelOrGate(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, "OrGate", "\u22651", false, logicWidth, name);// ">=1"
+ super(model, "OrGate", "\u22651", false, logicWidth, name, false);// ">=1"
setInputCount(2);
+ init();
}
static
public ModelSplitter(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, name);
+ super(model, name, false);
this.logicWidth = logicWidth;
setSize(width, (logicWidth - 1) * heightPerPin);
addPin(this.inputPin = new Pin(model, this, "I", logicWidth, PinUsage.TRISTATE, 0, (logicWidth - 1) * heightPerPin / 2));
for (int i = 0; i < logicWidth; i++, outputHeight -= 10)
addPin(new Pin(model, this, "O" + i, 1, PinUsage.TRISTATE, width, outputHeight));
outputEnds = new ReadEnd[logicWidth];
+
+ init();
}
@Override
public ModelTextComponent(LogicModelModifiable model, String text, String name)
{
- super(model, name);
+ super(model, name, false);
this.text = text;
// If size is unset, it defaults to 0, which could prohibit this component from being rendered, which would prohibit the size being
// set to a better guess
setSize(1, 1);
+
+ init();
}
@Override
public ModelTriStateBuffer(LogicModelModifiable model, ModelTriStateBufferParams params, String name)
{
- super(model, name);
+ super(model, name, false);
this.params = params;
oc = new OrientationCalculator(params.orientation, width, height);
addPin(input);
addPin(output);
addPin(enable);
+
+ init();
}
public final Pin getInputPin()
// creation and destruction
- public SimpleRectangularHardcodedModelComponent(LogicModelModifiable model, String id, String name, String centerText)
+ public SimpleRectangularHardcodedModelComponent(LogicModelModifiable model, String id, String name, String centerText, boolean callInit)
{
- super(model, name);
+ super(model, name, false);
this.id = id;
this.outlineRenderer = new DefaultOutlineRenderer(this);
CenteredTextParams centeredTextParams = new CenteredTextParams();
recalculate.run();
}
});
+
+ if (callInit)
+ init();
}
// pins
protected SimpleRectangularModelGate(LogicModelModifiable model, String id, String label, boolean isInverted, int logicWidth,
String name)
{
- super(model, name);
+ this(model, id, label, isInverted, logicWidth, name, true);
+ }
+
+ protected SimpleRectangularModelGate(LogicModelModifiable model, String id, String label, boolean isInverted, int logicWidth,
+ String name, boolean callInit)
+ {
+ super(model, name, false);
this.id = id;
this.label = label;
this.logicWidth = logicWidth;
addPin(outputPin);
this.inputPins = new ArrayList<>();
setInputCount(1);
+
+ if (callInit)
+ init();
}
protected void setInputCount(int inputCount)
public SimpleRectangularSubmodelComponent(LogicModelModifiable model, int logicWidth, String label, String name)
{
- super(model, name);
+ this(model, logicWidth, label, name, true);
+ }
+
+ protected SimpleRectangularSubmodelComponent(LogicModelModifiable model, int logicWidth, String label, String name, boolean callInit)
+ {
+ super(model, name, false);
this.label = label;
this.logicWidth = logicWidth;
this.inputPinNames = new ArrayList<>();
rendererParams.pinLabelMargin = pinNameMargin;
setSymbolRenderer(new SimpleRectangularLikeSymbolRenderer(this, rendererParams));
setOutlineRenderer(new DefaultOutlineRenderer(this));
+
+ if (callInit)
+ init();
}
protected void setInputPins(String... pinNames)
public SubmodelComponent(LogicModelModifiable model, String name)
{
- super(model, name);
+ this(model, name, true);
+ }
+
+ protected SubmodelComponent(LogicModelModifiable model, String name, boolean callInit)
+ {
+ super(model, name, false);
this.submodelModifiable = new LogicModelModifiable();
this.submodel = submodelModifiable;
this.submodelPins = new HashMap<>();
model.removeRedrawHandlerChangedListener(redrawHandlerChangedListener);
});
submodelModifiable.setRedrawHandler(model.getRedrawHandler());
+
+ if (callInit)
+ init();
}
// pins
{
public SubmodelInterface(LogicModelModifiable model, String name)
{
- super(model, name);
+ super(model, name, true);
}
@Override
public ModelWireCrossPoint(LogicModelModifiable model, int logicWidth, String name)
{
- super(model, name);
+ super(model, name, false);
this.logicWidth = logicWidth;
logicObs = (i) -> model.requestRedraw();
setSize(CIRCLE_DIAM, CIRCLE_DIAM);
addPin(this.pin = new Pin(model, this, "", logicWidth, PinUsage.TRISTATE, CIRCLE_RADIUS, CIRCLE_RADIUS));
+
+ init();
}
// pins
public DeserializedSubmodelComponent(LogicModelModifiable model, String name, String idForSerializingOverride,
JsonElement paramsForSerializingOverride)
{
- super(model, name);
+ super(model, name, false);
this.idForSerializingOverride = idForSerializingOverride;
this.paramsForSerializingOverride = paramsForSerializingOverride;
+ init();
}
@Override
public ModelMemoryWA(LogicModelModifiable model, MainMemoryDefinition definition, String name)
{
- super(model, name);
+ super(model, name,false);
this.definition = definition;
CenteredTextParams renderer1Params = new CenteredTextParams();
addPin(addrPin = new Pin(model, this, "A", definition.getMemoryAddressBits(), PinUsage.INPUT, 0, 10));
addPin(dataPin = new Pin(model, this, "D", definition.getCellWidth(), PinUsage.TRISTATE, 0, 30));
addPin(rWPin = new Pin(model, this, "RW", 1, PinUsage.INPUT, 0, 50));
+
+ init();
}
public Pin getAddressPin()