<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>LogicUI</name>
+ <name>mograsim.logic.ui</name>
<comment></comment>
<projects>
- <project>era.mi</project>
+ <project>mograsim.logic.core</project>
<project>SWTZoomableCanvas</project>
</projects>
<buildSpec>
eclipse.preferences.version=1\r
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true\r
-formatter_profile=_ERA-MI\r
+formatter_profile=_MoGraSim\r
formatter_settings_version=16\r
sp_cleanup.add_default_serial_version_id=true\r
sp_cleanup.add_generated_serial_version_id=false\r
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
-Bundle-Name: LogicUI
-Bundle-SymbolicName: LogicUI;singleton:=true
+Bundle-Name: mograsim.logic.ui
+Bundle-SymbolicName: mograsim.logic.ui;singleton:=true
Bundle-Version: 1.0.0
-Export-Package: era.mi.gui,
- era.mi.gui.examples,
- era.mi.gui.model,
- era.mi.gui.model.components,
- era.mi.gui.model.wires,
- era.mi.gui.modeladapter,
- era.mi.gui.modeladapter.componentadapters
+Export-Package: mograsim.logic.ui,
+ mograsim.logic.ui.examples,
+ mograsim.logic.ui.model,
+ mograsim.logic.ui.model.components,
+ mograsim.logic.ui.model.wires,
+ mograsim.logic.ui.modeladapter,
+ mograsim.logic.ui.modeladapter.componentadapters
Bundle-RequiredExecutionEnvironment: JavaSE-10
Require-Bundle: org.eclipse.swt;bundle-version="3.110.0",
SWTZoomableCanvas;bundle-version="1.0.0";visibility:=reexport,
- era.mi;bundle-version="1.0.0";visibility:=reexport
-Automatic-Module-Name: LogicUI
+ mograsim.logic.core;bundle-version="1.0.0";visibility:=reexport
+Automatic-Module-Name: mograsim.logic.ui
+++ /dev/null
-package era.mi.gui;
-
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Device;
-
-import era.mi.logic.types.ColorDefinition;
-import era.mi.logic.types.ColorDefinition.BuiltInColor;
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-
-//TODO replace with a proper ColorManager
-public class ColorHelper
-{
- public static void executeWithDifferentForeground(GeneralGC gc, ColorDefinition col, Runnable exec)
- {
- executeWithDifferentColor(gc.getDevice(), col, gc::getForeground, gc::setForeground, exec);
- }
-
- public static void executeWithDifferentBackground(GeneralGC gc, ColorDefinition col, Runnable exec)
- {
- executeWithDifferentColor(gc.getDevice(), col, gc::getBackground, gc::setBackground, exec);
- }
-
- private static void executeWithDifferentColor(Device device, ColorDefinition col, Supplier<Color> getColor, Consumer<Color> setColor,
- Runnable exec)
- {
- Color oldColor = getColor.get();
- boolean isNoSystemColor = col.builtInColor == null;
- Color newColor;
- if (isNoSystemColor)
- newColor = new Color(device, col.r, col.g, col.b);
- else
- newColor = device.getSystemColor(ColorHelper.toSWTColorConstant(col.builtInColor));
- setColor.accept(newColor);
-
- exec.run();
-
- setColor.accept(oldColor);
- if (isNoSystemColor)
- newColor.dispose();
- }
-
- public static int toSWTColorConstant(BuiltInColor col)
- {
- switch (col)
- {
- case COLOR_BLACK:
- return SWT.COLOR_BLACK;
- case COLOR_BLUE:
- return SWT.COLOR_BLUE;
- case COLOR_CYAN:
- return SWT.COLOR_CYAN;
- case COLOR_DARK_BLUE:
- return SWT.COLOR_DARK_BLUE;
- case COLOR_DARK_CYAN:
- return SWT.COLOR_DARK_CYAN;
- case COLOR_DARK_GRAY:
- return SWT.COLOR_DARK_GRAY;
- case COLOR_DARK_GREEN:
- return SWT.COLOR_DARK_GREEN;
- case COLOR_DARK_MAGENTA:
- return SWT.COLOR_DARK_MAGENTA;
- case COLOR_DARK_RED:
- return SWT.COLOR_DARK_RED;
- case COLOR_DARK_YELLOW:
- return SWT.COLOR_DARK_YELLOW;
- case COLOR_GRAY:
- return SWT.COLOR_GRAY;
- case COLOR_GREEN:
- return SWT.COLOR_GREEN;
- case COLOR_MAGENTA:
- return SWT.COLOR_MAGENTA;
- case COLOR_RED:
- return SWT.COLOR_RED;
- case COLOR_WHITE:
- return SWT.COLOR_WHITE;
- case COLOR_YELLOW:
- return SWT.COLOR_YELLOW;
- default:
- throw new IllegalArgumentException("Unknown enum constant: " + col);
- }
- }
-
- private ColorHelper()
- {
- throw new UnsupportedOperationException("No instances of ColorHelper");
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-
-import era.mi.logic.timeline.Timeline;
-
-//TODO maybe move to logic core?
-public class LogicExecuter
-{
- // TODO replace with LogicModel when it exists
- private final Timeline timeline;
-
- private final AtomicBoolean shouldBeRunningLive;
- private final AtomicBoolean isRunningLive;
- private final AtomicLong nextExecSimulTime;
- private final Thread simulationThread;
-
- public LogicExecuter(Timeline timeline)
- {
- this.timeline = timeline;
-
- timeline.setTimeFunction(System::currentTimeMillis);
- shouldBeRunningLive = new AtomicBoolean();
- isRunningLive = new AtomicBoolean();
- nextExecSimulTime = new AtomicLong();
- simulationThread = new Thread(() ->
- {
- isRunningLive.set(true);
- synchronized (isRunningLive)
- {
- isRunningLive.notify();
- }
- while (shouldBeRunningLive.get())
- {
- // always execute to keep timeline from "hanging behind" for too long
- long current = System.currentTimeMillis();
- timeline.executeUntil(timeline.laterThan(current), current + 10);
- long sleepTime;
- if (timeline.hasNext())
- sleepTime = timeline.nextEventTime() - current;
- else
- sleepTime = 10000;
- try
- {
- nextExecSimulTime.set(current + sleepTime);
- if (sleepTime > 0)
- Thread.sleep(sleepTime);
- }
- catch (@SuppressWarnings("unused") InterruptedException e)
- {// do nothing; it is normal execution flow to be interrupted
- }
- }
- isRunningLive.set(false);
- synchronized (isRunningLive)
- {
- isRunningLive.notify();
- }
- });
- timeline.addEventAddedListener(event ->
- {
- if (isRunningLive.get())
- if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
- simulationThread.interrupt();
- });
- }
-
- public void executeNextStep()
- {
- timeline.executeNext();
- }
-
- public synchronized void startLiveExecution()
- {
- if (shouldBeRunningLive.get())
- return;
- shouldBeRunningLive.set(true);
- simulationThread.start();
- waitForIsRunning(true);
- }
-
- public synchronized void stopLiveExecution()
- {
- if (!shouldBeRunningLive.get())
- return;
- shouldBeRunningLive.set(false);
- simulationThread.interrupt();
- waitForIsRunning(false);
- }
-
- private void waitForIsRunning(boolean expectedState)
- {
- while (isRunningLive.get() ^ expectedState)
- try
- {
- synchronized (isRunningLive)
- {
- isRunningLive.wait();
- }
- }
- catch (@SuppressWarnings("unused") InterruptedException e)
- {// no need to do anything
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui;\r
-\r
-import java.util.function.Consumer;\r
-\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Event;\r
-\r
-import era.mi.gui.model.ViewModel;\r
-import era.mi.gui.model.components.GUIComponent;\r
-import era.mi.gui.model.wires.GUIWire;\r
-import era.mi.gui.model.wires.Pin;\r
-import net.haspamelodica.swt.helper.gcs.GeneralGC;\r
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;\r
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;\r
-import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;\r
-\r
-/**\r
- * Simulation visualizer canvas.\r
- * \r
- * @author Daniel Kirschten\r
- */\r
-public class LogicUICanvas extends ZoomableCanvas\r
-{\r
- private static final boolean DRAW_PINS = false;\r
-\r
- private final ViewModel model;\r
-\r
- public LogicUICanvas(Composite parent, int style, ViewModel model)\r
- {\r
- super(parent, style);\r
-\r
- this.model = model;\r
-\r
- Consumer<Object> redrawConsumer = o -> redrawThreadsafe();\r
- Consumer<Pin> pinAddedListener = p ->\r
- {\r
- p.addPinMovedListener(redrawConsumer);\r
- redrawThreadsafe();\r
- };\r
- Consumer<Pin> pinRemovedListener = p ->\r
- {\r
- p.removePinMovedListener(redrawConsumer);\r
- redrawThreadsafe();\r
- };\r
- Consumer<? super GUIComponent> componentAddedListener = c ->\r
- {\r
- c.addComponentLookChangedListener(redrawConsumer);\r
- c.addComponentMovedListener(redrawConsumer);\r
- c.addPinAddedListener(pinAddedListener);\r
- c.addPinRemovedListener(pinRemovedListener);\r
- redrawThreadsafe();\r
- };\r
- model.addComponentAddedListener(componentAddedListener);\r
- model.getComponents().forEach(componentAddedListener);\r
- model.addComponentRemovedListener(c ->\r
- {\r
- c.removeComponentLookChangedListener(redrawConsumer);\r
- c.removeComponentMovedListener(redrawConsumer);\r
- c.removePinAddedListener(pinAddedListener);\r
- c.removePinRemovedListener(pinRemovedListener);\r
- redrawThreadsafe();\r
- });\r
- Consumer<? super GUIWire> wireAddedListener = w ->\r
- {\r
- w.addWireLookChangedListener(redrawConsumer);\r
- redrawThreadsafe();\r
- };\r
- model.addWireAddedListener(wireAddedListener);\r
- model.getWires().forEach(wireAddedListener);\r
- model.addWireRemovedListener(w ->\r
- {\r
- w.removeWireLookChangedListener(redrawConsumer);\r
- redrawThreadsafe();\r
- });\r
-\r
- addZoomedRenderer(gc ->\r
- {\r
- gc.setLineWidth(.5);\r
- model.getWires().forEach(w -> w.render(gc));\r
- Rectangle visibleRegion = new Rectangle(offX, offY, gW / zoom, gH / zoom);\r
- model.getComponents().forEach(c -> drawComponent(gc, c, visibleRegion));\r
- });\r
- addListener(SWT.MouseDown, this::mouseDown);\r
- }\r
-\r
- private void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion)\r
- {\r
- component.render(gc, visibleRegion);\r
- if (DRAW_PINS)\r
- {\r
- gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_CYAN));\r
- for (Pin p : component.getPins())\r
- {\r
- Point pos = p.getPos();\r
- gc.fillOval(pos.x - 1, pos.y - 1, 2, 2);\r
- }\r
- }\r
- }\r
-\r
- private void mouseDown(Event e)\r
- {\r
- if (e.button == 1)\r
- {\r
- Point click = displayToWorldCoords(e.x, e.y);\r
- for (GUIComponent component : model.getComponents())\r
- if (component.getBounds().contains(click) && component.clicked(click.x, click.y))\r
- {\r
- redraw();\r
- break;\r
- }\r
- }\r
- }\r
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
-
-/**
- * Standalone simulation visualizer graphical user interface.
- *
- * @author Daniel Kirschten
- */
-public class LogicUIStandaloneGUI
-{
- private final Display display;
- private final Shell shell;
- private final LogicUICanvas ui;
-
- public LogicUIStandaloneGUI(ViewModel model)
- {
- display = new Display();
- shell = new Shell(display);
- shell.setLayout(new FillLayout());
- ui = new LogicUICanvas(shell, SWT.NONE, model);
-
- ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
- userInput.buttonDrag = 3;
- userInput.buttonZoom = 2;
- userInput.enableUserInput();
- new ZoomableCanvasOverlay(ui, null).enableScale();
-
- // TODO don't do this here
- LogicModelParameters params = new LogicModelParameters();
- params.gateProcessTime = 50;
- params.wireTravelTime = 10;
-// timeline = ViewLogicModelAdapter.convert(model, params);
- }
-
- public LogicUICanvas getLogicUICanvas()
- {
- return ui;
- }
-
- /**
- * Opens the UI shell. Returns when the shell is closed.
- */
- public void run()
- {
- shell.open();
- while (!shell.isDisposed())
- if (!display.readAndDispatch())
- display.sleep();
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui;
-
-import java.util.function.Consumer;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import era.mi.gui.modeladapter.ViewLogicModelAdapter;
-import era.mi.logic.timeline.Timeline;
-
-public class SimpleLogicUIStandalone
-{
- public static void executeVisualisation(Consumer<ViewModel> setupViewModel)
- {
- // setup view model
- ViewModel viewModel = new ViewModel();
- setupViewModel.accept(viewModel);
-
- // convert to logic model
- LogicModelParameters params = new LogicModelParameters();
- params.gateProcessTime = 50;
- params.wireTravelTime = 10;
- Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
-
- // initialize UI and executer
- LogicUIStandaloneGUI ui = new LogicUIStandaloneGUI(viewModel);
- LogicExecuter exec = new LogicExecuter(timeline);
-
- // run it
- exec.startLiveExecution();
- ui.run();
- exec.stopLiveExecution();
- }
-
- private SimpleLogicUIStandalone()
- {
- throw new UnsupportedOperationException("No SimpleLogicUIStandalone instances");
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.examples;
-
-import era.mi.gui.SimpleLogicUIStandalone;
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.components.GUIManualSwitch;
-import era.mi.gui.model.components.GUINotGate;
-import era.mi.gui.model.components.GUIOrGate;
-import era.mi.gui.model.wires.GUIWire;
-import era.mi.gui.model.wires.WireCrossPoint;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-
-public class RSLatchExample
-{
- public static void main(String[] args)
- {
- SimpleLogicUIStandalone.executeVisualisation(RSLatchExample::createRSLatchExample);
- }
-
- @SuppressWarnings("unused") // for GUIWires being created
- public static void createRSLatchExample(ViewModel model)
- {
- GUIManualSwitch rIn = new GUIManualSwitch(model);
- rIn.moveTo(100, 100);
- GUIManualSwitch sIn = new GUIManualSwitch(model);
- sIn.moveTo(100, 200);
-
- GUIOrGate or1 = new GUIOrGate(model, 1);
- or1.moveTo(160, 102.5);
- new GUIWire(model, rIn.getOutputPin(), or1.getInputPins().get(0));
-
- GUIOrGate or2 = new GUIOrGate(model, 1);
- or2.moveTo(160, 192.5);
- new GUIWire(model, sIn.getOutputPin(), or2.getInputPins().get(1));
-
- GUINotGate not1 = new GUINotGate(model, 1);
- not1.moveTo(200, 107.5);
- new GUIWire(model, or1.getOutputPin(), not1.getInputPins().get(0));
-
- GUINotGate not2 = new GUINotGate(model, 1);
- not2.moveTo(200, 197.5);
- new GUIWire(model, or2.getOutputPin(), not2.getInputPins().get(0));
-
- WireCrossPoint p1 = new WireCrossPoint(model, 1);
- p1.moveTo(250, 112.5);
- new GUIWire(model, not1.getOutputPin(), p1.getPin());
- new GUIWire(model, p1.getPin(), or2.getInputPins().get(0), new Point(250, 130), new Point(140, 185), new Point(140, 197.5));
-
- WireCrossPoint p2 = new WireCrossPoint(model, 1);
- p2.moveTo(250, 202.5);
- new GUIWire(model, not2.getOutputPin(), p2.getPin());
- new GUIWire(model, p2.getPin(), or1.getInputPins().get(1), new Point(250, 185), new Point(140, 130), new Point(140, 117.5));
-
- WireCrossPoint o1 = new WireCrossPoint(model, 1);
- o1.moveTo(270, 112.5);
- new GUIWire(model, p1.getPin(), o1.getPin());
-
- WireCrossPoint o2 = new WireCrossPoint(model, 1);
- o2.moveTo(270, 202.5);
- new GUIWire(model, p2.getPin(), o2.getPin());
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Consumer;
-
-import era.mi.gui.model.components.GUIComponent;
-import era.mi.gui.model.wires.GUIWire;
-
-public class ViewModel
-{
- private final List<GUIComponent> components;
- private final List<GUIComponent> componentsUnmodifiable;
- private final List<GUIWire> wires;
- private final List<GUIWire> wiresUnmodifiable;
-
- private final List<Consumer<? super GUIComponent>> componentAddedListeners;
- private final List<Consumer<? super GUIComponent>> componentRemovedListeners;
- private final List<Consumer<? super GUIWire>> wireAddedListeners;
- private final List<Consumer<? super GUIWire>> wireRemovedListeners;
-
- public ViewModel()
- {
- components = new ArrayList<>();
- componentsUnmodifiable = Collections.unmodifiableList(components);
- wires = new ArrayList<>();
- wiresUnmodifiable = Collections.unmodifiableList(wires);
-
- componentAddedListeners = new ArrayList<>();
- componentRemovedListeners = new ArrayList<>();
- wireAddedListeners = new ArrayList<>();
- wireRemovedListeners = new ArrayList<>();
- }
-
- /**
- * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application
- * code as it is automatically called in GUIComponent::new.
- */
- public void componentCreated(GUIComponent component)
- {
- if (components.contains(component))
- throw new IllegalStateException("Don't add the same component twice!");
- components.add(component);
- callComponentAddedListeners(component);
- }
-
- /**
- * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from
- * application code as it is automatically called in GUIComponent::destroy.
- */
- public void componentDestroyed(GUIComponent component)
- {
- if (!components.contains(component))
- throw new IllegalStateException("Don't remove the same component twice!");
- components.remove(component);
- callComponentRemovedListeners(component);
- }
-
- /**
- * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application
- * code as it is automatically called in GUIComponent::new.
- */
- public void wireCreated(GUIWire wire)
- {
- if (wires.contains(wire))
- throw new IllegalStateException("Don't add the same wire twice!");
- wires.add(wire);
- callWireAddedListeners(wire);
- }
-
- /**
- * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from
- * application code as it is automatically called in GUIComponent::destroy.
- */
- public void wireDestroyed(GUIWire wire)
- {
- if (!wires.contains(wire))
- throw new IllegalStateException("Don't remove the same wire twice!");
- wires.remove(wire);
- callWireRemovedListeners(wire);
- }
-
- public List<GUIComponent> getComponents()
- {
- return componentsUnmodifiable;
- }
-
- public List<GUIWire> getWires()
- {
- return wiresUnmodifiable;
- }
-
- // @formatter:off
- public void addComponentAddedListener (Consumer<? super GUIComponent> listener){componentAddedListeners .add (listener);}
- public void addComponentRemovedListener (Consumer<? super GUIComponent> listener){componentRemovedListeners.add (listener);}
- public void addWireAddedListener (Consumer<? super GUIWire > listener){wireAddedListeners .add (listener);}
- public void addWireRemovedListener (Consumer<? super GUIWire > listener){wireRemovedListeners .add (listener);}
-
- public void removeComponentAddedListener (Consumer<? super GUIComponent> listener){componentAddedListeners .remove(listener);}
- public void removeComponentRemovedListener(Consumer<? super GUIComponent> listener){componentRemovedListeners.remove(listener);}
- public void removeWireAddedListener (Consumer<? super GUIWire > listener){wireAddedListeners .remove(listener);}
- public void removeWireRemovedListener (Consumer<? super GUIWire > listener){wireRemovedListeners .remove(listener);}
-
- private void callComponentAddedListeners (GUIComponent c) {componentAddedListeners .forEach(l -> l.accept(c));}
- private void callComponentRemovedListeners(GUIComponent c) {componentRemovedListeners.forEach(l -> l.accept(c));}
- private void callWireAddedListeners (GUIWire w ) {wireAddedListeners .forEach(l -> l.accept(w));}
- private void callWireRemovedListeners (GUIWire w ) {wireRemovedListeners .forEach(l -> l.accept(w));}
- // @formatter:on
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.components;
-
-import era.mi.gui.model.ViewModel;
-
-public class GUIAndGate extends SimpleRectangularGUIGate
-{
- public GUIAndGate(ViewModel model, int logicWidth)
- {
- super(model, logicWidth, "&", false);
- setInputCount(2);// TODO make variable
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.components;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Consumer;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.wires.Pin;
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-
-public abstract class GUIComponent
-{
- protected final ViewModel model;
- private final Rectangle bounds;
- private final List<Pin> pins;
- protected final List<Pin> pinsUnmodifiable;
-
- private final List<Consumer<? super GUIComponent>> componentLookChangedListeners;
- private final List<Consumer<? super GUIComponent>> componentMovedListeners;
- private final List<Consumer<? super Pin>> pinAddedListeners;
- private final List<Consumer<? super Pin>> pinRemovedListeners;
-
- public GUIComponent(ViewModel model)
- {
- this.model = model;
- this.bounds = new Rectangle(0, 0, 0, 0);
- this.pins = new ArrayList<>();
- this.pinsUnmodifiable = Collections.unmodifiableList(pins);
-
- this.componentLookChangedListeners = new ArrayList<>();
- this.componentMovedListeners = new ArrayList<>();
- this.pinAddedListeners = new ArrayList<>();
- this.pinRemovedListeners = new ArrayList<>();
-
- model.componentCreated(this);
- }
-
- public void destroy()
- {
- pins.forEach(p -> pinRemovedListeners.forEach(l -> l.accept(p)));
- model.componentDestroyed(this);
- }
-
- public void moveTo(double x, double y)
- {
- bounds.x = x;
- bounds.y = y;
- callComponentMovedListeners();
- }
-
- /**
- * Returns the bounds of this component. Used for calculating which component is clicked.
- */
- public Rectangle getBounds()
- {
- return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
- }
-
- /**
- * Called when this component is clicked. Absolute coordinates of the click are given. Returns true if this component consumed this
- * click.
- */
- @SuppressWarnings({ "static-method", "unused" }) // this method is inteded to be overridden
- public boolean clicked(double x, double y)
- {
- return false;
- }
-
- /**
- * Returns a list of pins of this component.
- */
- public List<Pin> getPins()
- {
- return pinsUnmodifiable;
- }
-
- // @formatter:off
- public void addComponentLookChangedListener (Consumer<? super GUIComponent> listener) {componentLookChangedListeners.add (listener);}
- public void addComponentMovedListener (Consumer<? super GUIComponent> listener) {componentMovedListeners .add (listener);}
- public void addPinAddedListener (Consumer<? super Pin > listener) {pinAddedListeners .add (listener);}
- public void addPinRemovedListener (Consumer<? super Pin > listener) {pinRemovedListeners .add (listener);}
-
- public void removeComponentLookChangedListener(Consumer<? super GUIComponent> listener) {componentLookChangedListeners.remove(listener);}
- public void removeComponentMovedListener (Consumer<? super GUIComponent> listener) {componentMovedListeners .remove(listener);}
- public void removePinAddedListener (Consumer<? super Pin > listener) {pinAddedListeners .remove(listener);}
- public void removePinRemovedListener (Consumer<? super Pin > listener) {pinRemovedListeners .remove(listener);}
-
- protected void callComponentLookChangedListeners( ) {componentLookChangedListeners.forEach(l -> l.accept(this));}
- private void callComponentMovedListeners ( ) {componentMovedListeners .forEach(l -> l.accept(this));}
- private void callPinAddedListeners (Pin p) {pinAddedListeners .forEach(l -> l.accept(p ));}
- private void callPinRemovedListeners (Pin p) {pinRemovedListeners .forEach(l -> l.accept(p ));}
- // @form atter:on
-
- /**
- * Render this component to the given gc.
- */
- public abstract void render(GeneralGC gc, Rectangle visibleRegion);
-
- protected void setSize(double width, double height)
- {
- bounds.width = width;
- bounds.height = height;
- callComponentLookChangedListeners();
- }
-
- protected void addPin(Pin pin)
- {
- pins.add(pin);
- callPinAddedListeners(pin);
- }
-
- protected void removePin(Pin pin)
- {
- pins.remove(pin);
- callPinRemovedListeners(pin);
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.components;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.wires.Pin;
-import era.mi.logic.components.ManualSwitch;
-import era.mi.logic.types.BitVectorFormatter;
-import era.mi.logic.wires.Wire.ReadEnd;
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-
-public class GUIManualSwitch extends GUIComponent
-{
- private static final double width = 20;
- private static final double height = 15;
- private static final double fontHeight = 5;
-
- private final Pin outputPin;
-
- private ManualSwitch logicSwitch;
- private ReadEnd end;
-
- public GUIManualSwitch(ViewModel model)
- {
- super(model);
- setSize(width, height);
- addPin(this.outputPin = new Pin(this, 1, width, height / 2));
- }
-
- @Override
- public void render(GeneralGC gc, Rectangle visibleRegion)
- {
- double posX = getBounds().x;
- double posY = getBounds().y;
-
- gc.drawRectangle(posX, posY, width, height);
- String label = BitVectorFormatter.formatValueAsString(end);
- Font oldFont = gc.getFont();
- Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
- gc.setFont(labelFont);
- Point textExtent = gc.textExtent(label);
- gc.drawText(label, posX + (width - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true);
- gc.setFont(oldFont);
- }
-
- public void setLogicModelBinding(ManualSwitch logicSwitch, ReadEnd end)
- {
- this.logicSwitch = logicSwitch;
- this.end = end;
- // TODO when ManualSwitch supports it, add listeners
- end.addObserver((i, o) -> callComponentLookChangedListeners());
- }
-
- @Override
- public boolean clicked(double x, double y)
- {
- if (logicSwitch != null)
- logicSwitch.toggle();
- return true;
- }
-
- public Pin getOutputPin()
- {
- return outputPin;
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.components;
-
-import era.mi.gui.model.ViewModel;
-
-public class GUINotGate extends SimpleRectangularGUIGate
-{
- public GUINotGate(ViewModel model, int logicWidth)
- {
- super(model, logicWidth, "1", true);
- setInputCount(1);
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.components;
-
-import era.mi.gui.model.ViewModel;
-
-public class GUIOrGate extends SimpleRectangularGUIGate
-{
- public GUIOrGate(ViewModel model, int logicWidth)
- {
- super(model, logicWidth, "\u22651", false);// ">=1"
- setInputCount(2);
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.components;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.wires.MovablePin;
-import era.mi.gui.model.wires.Pin;
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-
-public class SimpleRectangularGUIGate extends GUIComponent
-{
- private static final double width = 20;
- private static final double pinDistance = 10;
- private static final double fontHeight = 5;
- private static final double invertedCircleDiam = 3.5;
-
- private final String label;
- protected final int logicWidth;
- private final boolean isInverted;
- private final double rectWidth;
-
- private MovablePin outputPin;
- private final List<Pin> inputPins;
- private final List<Pin> inputPinsUnmodifiable;
-
- protected SimpleRectangularGUIGate(ViewModel model, int logicWidth, String label, boolean isInverted)
- {
- super(model);
- this.label = label;
- this.logicWidth = logicWidth;
- this.isInverted = isInverted;
- this.rectWidth = width - (isInverted ? invertedCircleDiam : 0);
- this.outputPin = new MovablePin(this, logicWidth, width, 0);
- addPin(outputPin);
- this.inputPins = new ArrayList<>();
- this.inputPinsUnmodifiable = Collections.unmodifiableList(inputPins);
- setInputCount(1);
- }
-
- protected void setInputCount(int inputCount)
- {
- int oldInputCount = inputPins.size();
- setSize(width, inputCount * pinDistance);
- if (oldInputCount > inputCount)
- while (inputPins.size() > inputCount)
- removePin(inputPins.get(inputCount));
- else if (oldInputCount < inputCount)
- for (int i = oldInputCount; i < inputCount; i++)
- {
- Pin pin = new Pin(this, logicWidth, 0, pinDistance / 2 + i * pinDistance);
- inputPins.add(pin);
- addPin(pin);
- }
- outputPin.setRelPos(width, inputCount * pinDistance / 2);
- }
-
- public Pin getOutputPin()
- {
- return outputPin;
- }
-
- public List<Pin> getInputPins()
- {
- return inputPinsUnmodifiable;
- }
-
- @Override
- public void render(GeneralGC gc, Rectangle visibleRegion)
- {
- double posX = getBounds().x;
- double posY = getBounds().y;
-
- double height = inputPins.size() * pinDistance;
- gc.drawRectangle(posX, posY, rectWidth, height);
- Font oldFont = gc.getFont();
- Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
- gc.setFont(labelFont);
- Point textExtent = gc.textExtent(label);
- gc.drawText(label, posX + (rectWidth - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true);
- gc.setFont(oldFont);
- if (isInverted)
- gc.drawOval(posX + rectWidth, posY + (height - invertedCircleDiam) / 2, invertedCircleDiam, invertedCircleDiam);
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.wires;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-
-import era.mi.gui.ColorHelper;
-import era.mi.gui.model.ViewModel;
-import era.mi.logic.types.BitVectorFormatter;
-import era.mi.logic.wires.Wire.ReadEnd;
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-
-public class GUIWire
-{
- private final ViewModel model;
- public final int logicWidth;
- private Pin pin1;
- private Pin pin2;
- private double[] path;
-
- private final List<Consumer<? super GUIWire>> wireLookChangedListeners;
-
- private ReadEnd end;
-
- public GUIWire(ViewModel model, Pin pin1, Pin pin2, Point... path)
- {
- this.model = model;
- this.logicWidth = pin1.logicWidth;
- if (pin2.logicWidth != pin1.logicWidth)
- throw new IllegalArgumentException("Can't connect pins of different logic width");
- this.path = new double[path.length * 2 + 4];
- for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2)
- {
- this.path[dstI + 0] = path[srcI].x;
- this.path[dstI + 1] = path[srcI].y;
- }
-
- this.pin1 = pin1;
- this.pin2 = pin2;
-
- wireLookChangedListeners = new ArrayList<>();
-
- pin1.addPinMovedListener(p -> pin1Moved());
- pin2.addPinMovedListener(p -> pin2Moved());
- pin1Moved();
- pin2Moved();
-
- model.wireCreated(this);
- }
-
- private void pin1Moved()
- {
- Point pos = pin1.getPos();
- this.path[0] = pos.x;
- this.path[1] = pos.y;
- }
-
- private void pin2Moved()
- {
- Point pos = pin2.getPos();
- this.path[this.path.length - 2] = pos.x;
- this.path[this.path.length - 1] = pos.y;
- }
-
- public void destroy()
- {
- model.wireDestroyed(this);
- }
-
- public void render(GeneralGC gc)
- {
- ColorHelper.executeWithDifferentForeground(gc, BitVectorFormatter.formatAsColor(end), () -> gc.drawPolyline(path));
- }
-
- public void setLogicModelBinding(ReadEnd end)
- {
- this.end = end;
- end.addObserver((i, o) -> callWireLookChangedListeners());
- }
-
- public Pin getPin1()
- {
- return pin1;
- }
-
- public Pin getPin2()
- {
- return pin2;
- }
-
- // @formatter:off
- public void addWireLookChangedListener (Consumer<? super GUIWire> listener) {wireLookChangedListeners.add (listener);}
-
- public void removeWireLookChangedListener(Consumer<? super GUIWire> listener) {wireLookChangedListeners.remove(listener);}
-
- private void callWireLookChangedListeners() {wireLookChangedListeners.forEach(l -> l.accept(this));}
- // @formatter:on
-
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.wires;
-
-import era.mi.gui.model.components.GUIComponent;
-
-public class MovablePin extends Pin
-{
- public MovablePin(GUIComponent component, int logicWidth, double relX, double relY)
- {
- super(component, logicWidth, relX, relY);
- }
-
- @Override
- public void setRelPos(double relX, double relY)
- {
- super.setRelPos(relX, relY);
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.wires;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-
-import era.mi.gui.model.components.GUIComponent;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-
-public class Pin
-{
- public final GUIComponent component;
- public final int logicWidth;
-
- protected double relX;
- protected double relY;
-
- private final List<Consumer<? super Pin>> pinMovedListeners;
-
- public Pin(GUIComponent component, int logicWidth, double relX, double relY)
- {
- this.component = component;
- this.logicWidth = logicWidth;
- this.relX = relX;
- this.relY = relY;
-
- this.pinMovedListeners = new ArrayList<>();
-
- component.addComponentMovedListener(c -> callPinMovedListeners());
- }
-
- public double getRelX()
- {
- return relX;
- }
-
- public double getRelY()
- {
- return relY;
- }
-
- public Point getRelPos()
- {
- return new Point(relX, relY);
- }
-
- public Point getPos()
- {
- Rectangle componentBounds = component.getBounds();
- return new Point(relX + componentBounds.x, relY + componentBounds.y);
- }
-
- // @formatter:off
- public void addPinMovedListener (Consumer<? super Pin> listener){pinMovedListeners.add (listener);}
-
- public void removePinMovedListener(Consumer<? super Pin> listener){pinMovedListeners.remove(listener);}
-
- private void callPinMovedListeners() {pinMovedListeners.forEach(l -> l.accept(this));}
- // @formatter:on
-
- protected void setRelPos(double relX, double relY)
- {
- this.relX = relX;
- this.relY = relY;
- callPinMovedListeners();
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.model.wires;
-
-import era.mi.gui.ColorHelper;
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.components.GUIComponent;
-import era.mi.logic.types.BitVectorFormatter;
-import era.mi.logic.wires.Wire.ReadEnd;
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-
-public class WireCrossPoint extends GUIComponent
-{
- private final Pin pin;
-
- private ReadEnd end;
- private final int logicWidth;
-
- public WireCrossPoint(ViewModel model, int logicWidth)
- {
- super(model);
- this.logicWidth = logicWidth;
- setSize(0, 0);
- addPin(this.pin = new Pin(this, logicWidth, 0, 0));
- }
-
- @Override
- public void render(GeneralGC gc, Rectangle visibleRegion)
- {
- Rectangle bounds = getBounds();
- ColorHelper.executeWithDifferentBackground(gc, BitVectorFormatter.formatAsColor(end),
- () -> gc.fillOval(bounds.x - 1, bounds.y - 1, 2, 2));
- }
-
- public void setLogicModelBinding(ReadEnd end)
- {
- this.end = end;
- end.addObserver((i, o) -> callComponentLookChangedListeners());
- }
-
- public int getLogicWidth()
- {
- return logicWidth;
- }
-
- public Pin getPin()
- {
- return pin;
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.modeladapter;
-
-public class LogicModelParameters
-{
- public int wireTravelTime;
- public int gateProcessTime;
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.modeladapter;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.components.GUIAndGate;
-import era.mi.gui.model.components.GUIComponent;
-import era.mi.gui.model.components.GUINotGate;
-import era.mi.gui.model.components.GUIOrGate;
-import era.mi.gui.model.wires.GUIWire;
-import era.mi.gui.model.wires.Pin;
-import era.mi.gui.model.wires.WireCrossPoint;
-import era.mi.gui.modeladapter.componentadapters.ComponentAdapter;
-import era.mi.gui.modeladapter.componentadapters.ManualSwitchAdapter;
-import era.mi.gui.modeladapter.componentadapters.SimpleGateAdapter;
-import era.mi.logic.components.Component;
-import era.mi.logic.components.gates.AndGate;
-import era.mi.logic.components.gates.NotGate;
-import era.mi.logic.components.gates.OrGate;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.wires.Wire;
-import era.mi.logic.wires.Wire.ReadEnd;
-
-public class ViewLogicModelAdapter
-{
- private final static Map<Class<? extends GUIComponent>, ComponentAdapter<? extends GUIComponent>> componentAdapters;
- static
- {
- Set<ComponentAdapter<? extends GUIComponent>> componentAdaptersModifiable = new HashSet<>();
- componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUIOrGate.class, OrGate::new));
- componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUIAndGate.class, AndGate::new));
- componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUINotGate.class, (t, p, o, i) -> new NotGate(t, p, i[0], o)));
- componentAdaptersModifiable.add(new ManualSwitchAdapter());
- // TODO list all "primitive" adapters here
- componentAdapters = Collections.unmodifiableMap(
- componentAdaptersModifiable.stream().collect(Collectors.toMap(ComponentAdapter::getSupportedClass, Function.identity())));
- }
-
- public static Timeline convert(ViewModel viewModel, LogicModelParameters params)
- {
- // TODO replace Timeline with LogicModel as soon as it exists
- Timeline timeline = new Timeline(10);
-
- Map<Pin, Wire> logicWiresPerPin = convertWires(
- viewModel.getComponents().stream().flatMap(component -> component.getPins().stream()).collect(Collectors.toSet()),
- viewModel.getWires(), params, timeline);
- Map<Pin, Wire> logicWiresPerPinUnmodifiable = Collections.unmodifiableMap(logicWiresPerPin);
-
- Map<GUIComponent, Component> oneToOneComponents = new HashMap<>();
- for (GUIComponent guiComp : viewModel.getComponents())
- {
- if (!(guiComp instanceof WireCrossPoint))
- oneToOneComponents.put(guiComp, createAndLinkComponent(timeline, params, guiComp, logicWiresPerPinUnmodifiable,
- componentAdapters.get(guiComp.getClass())));
- else
- {
- WireCrossPoint guiCompCasted = (WireCrossPoint) guiComp;
- guiCompCasted.setLogicModelBinding(logicWiresPerPin.get(guiCompCasted.getPin()).createReadOnlyEnd());
- }
- }
-
- // TODO handle complex components
-
- List<Component> logicComponents = new ArrayList<>();
- logicComponents.addAll(oneToOneComponents.values());
-
- return timeline;
- }
-
- private static Map<Pin, Wire> convertWires(Set<Pin> allPins, List<GUIWire> wires, LogicModelParameters params, Timeline timeline)
- {
- Map<Pin, Set<Pin>> connectedPinGroups = getConnectedPinGroups(allPins, wires);
- Map<Pin, Wire> logicWiresPerPin = createLogicWires(params, timeline, connectedPinGroups);
- setGUIWiresLogicModelBinding(wires, logicWiresPerPin);
- return logicWiresPerPin;
- }
-
- private static Map<Pin, Wire> createLogicWires(LogicModelParameters params, Timeline timeline, Map<Pin, Set<Pin>> connectedPinGroups)
- {
- Map<Pin, Wire> logicWiresPerPin = new HashMap<>();
- Map<Set<Pin>, Wire> logicWiresPerPinGroup = new HashMap<>();
- for (Entry<Pin, Set<Pin>> e : connectedPinGroups.entrySet())
- logicWiresPerPin.put(e.getKey(), logicWiresPerPinGroup.computeIfAbsent(e.getValue(),
- set -> new Wire(timeline, e.getKey().logicWidth, params.wireTravelTime)));
- return logicWiresPerPin;
- }
-
- private static void setGUIWiresLogicModelBinding(List<GUIWire> wires, Map<Pin, Wire> logicWiresPerPin)
- {
- Map<Wire, ReadEnd> guiWireSharedReadEnd = logicWiresPerPin.values().stream().distinct()
- .collect(Collectors.toMap(Function.identity(), Wire::createReadOnlyEnd));
- for (GUIWire guiWire : wires)
- guiWire.setLogicModelBinding(guiWireSharedReadEnd.get(logicWiresPerPin.get(guiWire.getPin1())));
- }
-
- private static Map<Pin, Set<Pin>> getConnectedPinGroups(Set<Pin> allPins, List<GUIWire> wires)
- {
- Map<Pin, Set<Pin>> connectedPinsPerPin = new HashMap<>();
-
- for (Pin p : allPins)
- {
- HashSet<Pin> connectedPins = new HashSet<>();
- connectedPins.add(p);
- connectedPinsPerPin.put(p, connectedPins);
- }
-
- wires.forEach(wire ->
- {
- Pin pin1 = wire.getPin1();
- Pin pin2 = wire.getPin2();
-
- Set<Pin> pin1ConnectedPins = connectedPinsPerPin.get(pin1);
- Set<Pin> pin2ConnectedPins = connectedPinsPerPin.get(pin2);
-
- pin1ConnectedPins.addAll(pin2ConnectedPins);
- pin1ConnectedPins.add(pin1);
- pin1ConnectedPins.add(pin2);
-
- pin2ConnectedPins.forEach(pin -> connectedPinsPerPin.put(pin, pin1ConnectedPins));
- });
- return connectedPinsPerPin;
- }
-
- @SuppressWarnings("unchecked")
- private static <G extends GUIComponent> Component createAndLinkComponent(Timeline timeline, LogicModelParameters params,
- GUIComponent guiComponent, Map<Pin, Wire> logicWiresPerPin, ComponentAdapter<G> adapter)
- {
- if (adapter == null)
- throw new IllegalArgumentException("Unknown component class: " + guiComponent.getClass());
- return adapter.createAndLinkComponent(timeline, params, (G) guiComponent, logicWiresPerPin);
- }
-
- private ViewLogicModelAdapter()
- {
- throw new UnsupportedOperationException("No ViewLogicModelConverter instances");
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.modeladapter.componentadapters;
-
-import java.util.Map;
-
-import era.mi.gui.model.components.GUIComponent;
-import era.mi.gui.model.wires.Pin;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import era.mi.logic.components.Component;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.wires.Wire;
-
-public interface ComponentAdapter<G extends GUIComponent>
-{
- public Class<G> getSupportedClass();
-
- public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G guiComponent,
- Map<Pin, Wire> logicWiresPerPin);
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.modeladapter.componentadapters;
-
-import java.util.Map;
-
-import era.mi.gui.model.components.GUIManualSwitch;
-import era.mi.gui.model.wires.Pin;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import era.mi.logic.components.Component;
-import era.mi.logic.components.ManualSwitch;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.wires.Wire;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public class ManualSwitchAdapter implements ComponentAdapter<GUIManualSwitch>
-{
- @Override
- public Class<GUIManualSwitch> getSupportedClass()
- {
- return GUIManualSwitch.class;
- }
-
- @Override
- public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, GUIManualSwitch guiComponent,
- Map<Pin, Wire> logicWiresPerPin)
- {
- ReadWriteEnd end = logicWiresPerPin.get(guiComponent.getOutputPin()).createReadWriteEnd();
- ManualSwitch manualSwitch = new ManualSwitch(timeline, end);
- guiComponent.setLogicModelBinding(manualSwitch, end);
- return manualSwitch;
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.modeladapter.componentadapters;
-
-import java.util.List;
-import java.util.Map;
-
-import era.mi.gui.model.components.SimpleRectangularGUIGate;
-import era.mi.gui.model.wires.Pin;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import era.mi.logic.components.Component;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.wires.Wire;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public class SimpleGateAdapter<G extends SimpleRectangularGUIGate> implements ComponentAdapter<G>
-{
- private final Class<G> supportedClass;
- private final ComponentConstructor constructor;
-
- public SimpleGateAdapter(Class<G> supportedClass, ComponentConstructor constructor)
- {
- this.supportedClass = supportedClass;
- this.constructor = constructor;
- }
-
- @Override
- public Class<G> getSupportedClass()
- {
- return supportedClass;
- }
-
- @Override
- public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G guiComponent, Map<Pin, Wire> logicWiresPerPin)
- {
- ReadWriteEnd out = logicWiresPerPin.get(guiComponent.getOutputPin()).createReadWriteEnd();
- List<Pin> inputPins = guiComponent.getInputPins();
- ReadEnd[] ins = new ReadEnd[inputPins.size()];
- for (int i = 0; i < inputPins.size(); i++)
- ins[i] = logicWiresPerPin.get(inputPins.get(i)).createReadOnlyEnd();
- return constructor.newComponent(timeline, params.gateProcessTime, out, ins);
- }
-
- public static interface ComponentConstructor
- {
- public Component newComponent(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd[] ins);
- }
-
-}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Device;
+
+import mograsim.logic.core.types.ColorDefinition;
+import mograsim.logic.core.types.ColorDefinition.BuiltInColor;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+
+//TODO replace with a proper ColorManager
+public class ColorHelper
+{
+ public static void executeWithDifferentForeground(GeneralGC gc, ColorDefinition col, Runnable exec)
+ {
+ executeWithDifferentColor(gc.getDevice(), col, gc::getForeground, gc::setForeground, exec);
+ }
+
+ public static void executeWithDifferentBackground(GeneralGC gc, ColorDefinition col, Runnable exec)
+ {
+ executeWithDifferentColor(gc.getDevice(), col, gc::getBackground, gc::setBackground, exec);
+ }
+
+ private static void executeWithDifferentColor(Device device, ColorDefinition col, Supplier<Color> getColor, Consumer<Color> setColor,
+ Runnable exec)
+ {
+ Color oldColor = getColor.get();
+ boolean isNoSystemColor = col.builtInColor == null;
+ Color newColor;
+ if (isNoSystemColor)
+ newColor = new Color(device, col.r, col.g, col.b);
+ else
+ newColor = device.getSystemColor(ColorHelper.toSWTColorConstant(col.builtInColor));
+ setColor.accept(newColor);
+
+ exec.run();
+
+ setColor.accept(oldColor);
+ if (isNoSystemColor)
+ newColor.dispose();
+ }
+
+ public static int toSWTColorConstant(BuiltInColor col)
+ {
+ switch (col)
+ {
+ case COLOR_BLACK:
+ return SWT.COLOR_BLACK;
+ case COLOR_BLUE:
+ return SWT.COLOR_BLUE;
+ case COLOR_CYAN:
+ return SWT.COLOR_CYAN;
+ case COLOR_DARK_BLUE:
+ return SWT.COLOR_DARK_BLUE;
+ case COLOR_DARK_CYAN:
+ return SWT.COLOR_DARK_CYAN;
+ case COLOR_DARK_GRAY:
+ return SWT.COLOR_DARK_GRAY;
+ case COLOR_DARK_GREEN:
+ return SWT.COLOR_DARK_GREEN;
+ case COLOR_DARK_MAGENTA:
+ return SWT.COLOR_DARK_MAGENTA;
+ case COLOR_DARK_RED:
+ return SWT.COLOR_DARK_RED;
+ case COLOR_DARK_YELLOW:
+ return SWT.COLOR_DARK_YELLOW;
+ case COLOR_GRAY:
+ return SWT.COLOR_GRAY;
+ case COLOR_GREEN:
+ return SWT.COLOR_GREEN;
+ case COLOR_MAGENTA:
+ return SWT.COLOR_MAGENTA;
+ case COLOR_RED:
+ return SWT.COLOR_RED;
+ case COLOR_WHITE:
+ return SWT.COLOR_WHITE;
+ case COLOR_YELLOW:
+ return SWT.COLOR_YELLOW;
+ default:
+ throw new IllegalArgumentException("Unknown enum constant: " + col);
+ }
+ }
+
+ private ColorHelper()
+ {
+ throw new UnsupportedOperationException("No instances of ColorHelper");
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import mograsim.logic.core.timeline.Timeline;
+
+//TODO maybe move to logic core?
+public class LogicExecuter
+{
+ // TODO replace with LogicModel when it exists
+ private final Timeline timeline;
+
+ private final AtomicBoolean shouldBeRunningLive;
+ private final AtomicBoolean isRunningLive;
+ private final AtomicLong nextExecSimulTime;
+ private final Thread simulationThread;
+
+ public LogicExecuter(Timeline timeline)
+ {
+ this.timeline = timeline;
+
+ timeline.setTimeFunction(System::currentTimeMillis);
+ shouldBeRunningLive = new AtomicBoolean();
+ isRunningLive = new AtomicBoolean();
+ nextExecSimulTime = new AtomicLong();
+ simulationThread = new Thread(() ->
+ {
+ isRunningLive.set(true);
+ synchronized (isRunningLive)
+ {
+ isRunningLive.notify();
+ }
+ while (shouldBeRunningLive.get())
+ {
+ // always execute to keep timeline from "hanging behind" for too long
+ long current = System.currentTimeMillis();
+ timeline.executeUntil(timeline.laterThan(current), current + 10);
+ long sleepTime;
+ if (timeline.hasNext())
+ sleepTime = timeline.nextEventTime() - current;
+ else
+ sleepTime = 10000;
+ try
+ {
+ nextExecSimulTime.set(current + sleepTime);
+ if (sleepTime > 0)
+ Thread.sleep(sleepTime);
+ }
+ catch (@SuppressWarnings("unused") InterruptedException e)
+ {// do nothing; it is normal execution flow to be interrupted
+ }
+ }
+ isRunningLive.set(false);
+ synchronized (isRunningLive)
+ {
+ isRunningLive.notify();
+ }
+ });
+ timeline.addEventAddedListener(event ->
+ {
+ if (isRunningLive.get())
+ if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
+ simulationThread.interrupt();
+ });
+ }
+
+ public void executeNextStep()
+ {
+ timeline.executeNext();
+ }
+
+ public synchronized void startLiveExecution()
+ {
+ if (shouldBeRunningLive.get())
+ return;
+ shouldBeRunningLive.set(true);
+ simulationThread.start();
+ waitForIsRunning(true);
+ }
+
+ public synchronized void stopLiveExecution()
+ {
+ if (!shouldBeRunningLive.get())
+ return;
+ shouldBeRunningLive.set(false);
+ simulationThread.interrupt();
+ waitForIsRunning(false);
+ }
+
+ private void waitForIsRunning(boolean expectedState)
+ {
+ while (isRunningLive.get() ^ expectedState)
+ try
+ {
+ synchronized (isRunningLive)
+ {
+ isRunningLive.wait();
+ }
+ }
+ catch (@SuppressWarnings("unused") InterruptedException e)
+ {// no need to do anything
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui;\r
+\r
+import java.util.function.Consumer;\r
+\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Event;\r
+\r
+import mograsim.logic.ui.model.ViewModel;\r
+import mograsim.logic.ui.model.components.GUIComponent;\r
+import mograsim.logic.ui.model.wires.GUIWire;\r
+import mograsim.logic.ui.model.wires.Pin;\r
+import net.haspamelodica.swt.helper.gcs.GeneralGC;\r
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;\r
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;\r
+import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;\r
+\r
+/**\r
+ * Simulation visualizer canvas.\r
+ * \r
+ * @author Daniel Kirschten\r
+ */\r
+public class LogicUICanvas extends ZoomableCanvas\r
+{\r
+ private static final boolean DRAW_PINS = false;\r
+\r
+ private final ViewModel model;\r
+\r
+ public LogicUICanvas(Composite parent, int style, ViewModel model)\r
+ {\r
+ super(parent, style);\r
+\r
+ this.model = model;\r
+\r
+ Consumer<Object> redrawConsumer = o -> redrawThreadsafe();\r
+ Consumer<Pin> pinAddedListener = p ->\r
+ {\r
+ p.addPinMovedListener(redrawConsumer);\r
+ redrawThreadsafe();\r
+ };\r
+ Consumer<Pin> pinRemovedListener = p ->\r
+ {\r
+ p.removePinMovedListener(redrawConsumer);\r
+ redrawThreadsafe();\r
+ };\r
+ Consumer<? super GUIComponent> componentAddedListener = c ->\r
+ {\r
+ c.addComponentLookChangedListener(redrawConsumer);\r
+ c.addComponentMovedListener(redrawConsumer);\r
+ c.addPinAddedListener(pinAddedListener);\r
+ c.addPinRemovedListener(pinRemovedListener);\r
+ redrawThreadsafe();\r
+ };\r
+ model.addComponentAddedListener(componentAddedListener);\r
+ model.getComponents().forEach(componentAddedListener);\r
+ model.addComponentRemovedListener(c ->\r
+ {\r
+ c.removeComponentLookChangedListener(redrawConsumer);\r
+ c.removeComponentMovedListener(redrawConsumer);\r
+ c.removePinAddedListener(pinAddedListener);\r
+ c.removePinRemovedListener(pinRemovedListener);\r
+ redrawThreadsafe();\r
+ });\r
+ Consumer<? super GUIWire> wireAddedListener = w ->\r
+ {\r
+ w.addWireLookChangedListener(redrawConsumer);\r
+ redrawThreadsafe();\r
+ };\r
+ model.addWireAddedListener(wireAddedListener);\r
+ model.getWires().forEach(wireAddedListener);\r
+ model.addWireRemovedListener(w ->\r
+ {\r
+ w.removeWireLookChangedListener(redrawConsumer);\r
+ redrawThreadsafe();\r
+ });\r
+\r
+ addZoomedRenderer(gc ->\r
+ {\r
+ gc.setLineWidth(.5);\r
+ model.getWires().forEach(w -> w.render(gc));\r
+ Rectangle visibleRegion = new Rectangle(offX, offY, gW / zoom, gH / zoom);\r
+ model.getComponents().forEach(c -> drawComponent(gc, c, visibleRegion));\r
+ });\r
+ addListener(SWT.MouseDown, this::mouseDown);\r
+ }\r
+\r
+ private void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion)\r
+ {\r
+ component.render(gc, visibleRegion);\r
+ if (DRAW_PINS)\r
+ {\r
+ gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_CYAN));\r
+ for (Pin p : component.getPins())\r
+ {\r
+ Point pos = p.getPos();\r
+ gc.fillOval(pos.x - 1, pos.y - 1, 2, 2);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void mouseDown(Event e)\r
+ {\r
+ if (e.button == 1)\r
+ {\r
+ Point click = displayToWorldCoords(e.x, e.y);\r
+ for (GUIComponent component : model.getComponents())\r
+ if (component.getBounds().contains(click) && component.clicked(click.x, click.y))\r
+ {\r
+ redraw();\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
+
+/**
+ * Standalone simulation visualizer graphical user interface.
+ *
+ * @author Daniel Kirschten
+ */
+public class LogicUIStandaloneGUI
+{
+ private final Display display;
+ private final Shell shell;
+ private final LogicUICanvas ui;
+
+ public LogicUIStandaloneGUI(ViewModel model)
+ {
+ display = new Display();
+ shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+ ui = new LogicUICanvas(shell, SWT.NONE, model);
+
+ ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
+ userInput.buttonDrag = 3;
+ userInput.buttonZoom = 2;
+ userInput.enableUserInput();
+ new ZoomableCanvasOverlay(ui, null).enableScale();
+
+ // TODO don't do this here
+ LogicModelParameters params = new LogicModelParameters();
+ params.gateProcessTime = 50;
+ params.wireTravelTime = 10;
+// timeline = ViewLogicModelAdapter.convert(model, params);
+ }
+
+ public LogicUICanvas getLogicUICanvas()
+ {
+ return ui;
+ }
+
+ /**
+ * Opens the UI shell. Returns when the shell is closed.
+ */
+ public void run()
+ {
+ shell.open();
+ while (!shell.isDisposed())
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui;
+
+import java.util.function.Consumer;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+import mograsim.logic.ui.modeladapter.ViewLogicModelAdapter;
+
+public class SimpleLogicUIStandalone
+{
+ public static void executeVisualisation(Consumer<ViewModel> setupViewModel)
+ {
+ // setup view model
+ ViewModel viewModel = new ViewModel();
+ setupViewModel.accept(viewModel);
+
+ // convert to logic model
+ LogicModelParameters params = new LogicModelParameters();
+ params.gateProcessTime = 50;
+ params.wireTravelTime = 10;
+ Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
+
+ // initialize UI and executer
+ LogicUIStandaloneGUI ui = new LogicUIStandaloneGUI(viewModel);
+ LogicExecuter exec = new LogicExecuter(timeline);
+
+ // run it
+ exec.startLiveExecution();
+ ui.run();
+ exec.stopLiveExecution();
+ }
+
+ private SimpleLogicUIStandalone()
+ {
+ throw new UnsupportedOperationException("No SimpleLogicUIStandalone instances");
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.examples;
+
+import mograsim.logic.ui.SimpleLogicUIStandalone;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.components.GUIManualSwitch;
+import mograsim.logic.ui.model.components.GUINotGate;
+import mograsim.logic.ui.model.components.GUIOrGate;
+import mograsim.logic.ui.model.wires.GUIWire;
+import mograsim.logic.ui.model.wires.WireCrossPoint;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+
+public class RSLatchExample
+{
+ public static void main(String[] args)
+ {
+ SimpleLogicUIStandalone.executeVisualisation(RSLatchExample::createRSLatchExample);
+ }
+
+ @SuppressWarnings("unused") // for GUIWires being created
+ public static void createRSLatchExample(ViewModel model)
+ {
+ GUIManualSwitch rIn = new GUIManualSwitch(model);
+ rIn.moveTo(100, 100);
+ GUIManualSwitch sIn = new GUIManualSwitch(model);
+ sIn.moveTo(100, 200);
+
+ GUIOrGate or1 = new GUIOrGate(model, 1);
+ or1.moveTo(160, 102.5);
+ new GUIWire(model, rIn.getOutputPin(), or1.getInputPins().get(0));
+
+ GUIOrGate or2 = new GUIOrGate(model, 1);
+ or2.moveTo(160, 192.5);
+ new GUIWire(model, sIn.getOutputPin(), or2.getInputPins().get(1));
+
+ GUINotGate not1 = new GUINotGate(model, 1);
+ not1.moveTo(200, 107.5);
+ new GUIWire(model, or1.getOutputPin(), not1.getInputPins().get(0));
+
+ GUINotGate not2 = new GUINotGate(model, 1);
+ not2.moveTo(200, 197.5);
+ new GUIWire(model, or2.getOutputPin(), not2.getInputPins().get(0));
+
+ WireCrossPoint p1 = new WireCrossPoint(model, 1);
+ p1.moveTo(250, 112.5);
+ new GUIWire(model, not1.getOutputPin(), p1.getPin());
+ new GUIWire(model, p1.getPin(), or2.getInputPins().get(0), new Point(250, 130), new Point(140, 185), new Point(140, 197.5));
+
+ WireCrossPoint p2 = new WireCrossPoint(model, 1);
+ p2.moveTo(250, 202.5);
+ new GUIWire(model, not2.getOutputPin(), p2.getPin());
+ new GUIWire(model, p2.getPin(), or1.getInputPins().get(1), new Point(250, 185), new Point(140, 130), new Point(140, 117.5));
+
+ WireCrossPoint o1 = new WireCrossPoint(model, 1);
+ o1.moveTo(270, 112.5);
+ new GUIWire(model, p1.getPin(), o1.getPin());
+
+ WireCrossPoint o2 = new WireCrossPoint(model, 1);
+ o2.moveTo(270, 202.5);
+ new GUIWire(model, p2.getPin(), o2.getPin());
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+import mograsim.logic.ui.model.components.GUIComponent;
+import mograsim.logic.ui.model.wires.GUIWire;
+
+public class ViewModel
+{
+ private final List<GUIComponent> components;
+ private final List<GUIComponent> componentsUnmodifiable;
+ private final List<GUIWire> wires;
+ private final List<GUIWire> wiresUnmodifiable;
+
+ private final List<Consumer<? super GUIComponent>> componentAddedListeners;
+ private final List<Consumer<? super GUIComponent>> componentRemovedListeners;
+ private final List<Consumer<? super GUIWire>> wireAddedListeners;
+ private final List<Consumer<? super GUIWire>> wireRemovedListeners;
+
+ public ViewModel()
+ {
+ components = new ArrayList<>();
+ componentsUnmodifiable = Collections.unmodifiableList(components);
+ wires = new ArrayList<>();
+ wiresUnmodifiable = Collections.unmodifiableList(wires);
+
+ componentAddedListeners = new ArrayList<>();
+ componentRemovedListeners = new ArrayList<>();
+ wireAddedListeners = new ArrayList<>();
+ wireRemovedListeners = new ArrayList<>();
+ }
+
+ /**
+ * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application
+ * code as it is automatically called in GUIComponent::new.
+ */
+ public void componentCreated(GUIComponent component)
+ {
+ if (components.contains(component))
+ throw new IllegalStateException("Don't add the same component twice!");
+ components.add(component);
+ callComponentAddedListeners(component);
+ }
+
+ /**
+ * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from
+ * application code as it is automatically called in GUIComponent::destroy.
+ */
+ public void componentDestroyed(GUIComponent component)
+ {
+ if (!components.contains(component))
+ throw new IllegalStateException("Don't remove the same component twice!");
+ components.remove(component);
+ callComponentRemovedListeners(component);
+ }
+
+ /**
+ * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application
+ * code as it is automatically called in GUIComponent::new.
+ */
+ public void wireCreated(GUIWire wire)
+ {
+ if (wires.contains(wire))
+ throw new IllegalStateException("Don't add the same wire twice!");
+ wires.add(wire);
+ callWireAddedListeners(wire);
+ }
+
+ /**
+ * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from
+ * application code as it is automatically called in GUIComponent::destroy.
+ */
+ public void wireDestroyed(GUIWire wire)
+ {
+ if (!wires.contains(wire))
+ throw new IllegalStateException("Don't remove the same wire twice!");
+ wires.remove(wire);
+ callWireRemovedListeners(wire);
+ }
+
+ public List<GUIComponent> getComponents()
+ {
+ return componentsUnmodifiable;
+ }
+
+ public List<GUIWire> getWires()
+ {
+ return wiresUnmodifiable;
+ }
+
+ // @formatter:off
+ public void addComponentAddedListener (Consumer<? super GUIComponent> listener){componentAddedListeners .add (listener);}
+ public void addComponentRemovedListener (Consumer<? super GUIComponent> listener){componentRemovedListeners.add (listener);}
+ public void addWireAddedListener (Consumer<? super GUIWire > listener){wireAddedListeners .add (listener);}
+ public void addWireRemovedListener (Consumer<? super GUIWire > listener){wireRemovedListeners .add (listener);}
+
+ public void removeComponentAddedListener (Consumer<? super GUIComponent> listener){componentAddedListeners .remove(listener);}
+ public void removeComponentRemovedListener(Consumer<? super GUIComponent> listener){componentRemovedListeners.remove(listener);}
+ public void removeWireAddedListener (Consumer<? super GUIWire > listener){wireAddedListeners .remove(listener);}
+ public void removeWireRemovedListener (Consumer<? super GUIWire > listener){wireRemovedListeners .remove(listener);}
+
+ private void callComponentAddedListeners (GUIComponent c) {componentAddedListeners .forEach(l -> l.accept(c));}
+ private void callComponentRemovedListeners(GUIComponent c) {componentRemovedListeners.forEach(l -> l.accept(c));}
+ private void callWireAddedListeners (GUIWire w ) {wireAddedListeners .forEach(l -> l.accept(w));}
+ private void callWireRemovedListeners (GUIWire w ) {wireRemovedListeners .forEach(l -> l.accept(w));}
+ // @formatter:on
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.components;
+
+import mograsim.logic.ui.model.ViewModel;
+
+public class GUIAndGate extends SimpleRectangularGUIGate
+{
+ public GUIAndGate(ViewModel model, int logicWidth)
+ {
+ super(model, logicWidth, "&", false);
+ setInputCount(2);// TODO make variable
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.components;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.wires.Pin;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+public abstract class GUIComponent
+{
+ protected final ViewModel model;
+ private final Rectangle bounds;
+ private final List<Pin> pins;
+ protected final List<Pin> pinsUnmodifiable;
+
+ private final List<Consumer<? super GUIComponent>> componentLookChangedListeners;
+ private final List<Consumer<? super GUIComponent>> componentMovedListeners;
+ private final List<Consumer<? super Pin>> pinAddedListeners;
+ private final List<Consumer<? super Pin>> pinRemovedListeners;
+
+ public GUIComponent(ViewModel model)
+ {
+ this.model = model;
+ this.bounds = new Rectangle(0, 0, 0, 0);
+ this.pins = new ArrayList<>();
+ this.pinsUnmodifiable = Collections.unmodifiableList(pins);
+
+ this.componentLookChangedListeners = new ArrayList<>();
+ this.componentMovedListeners = new ArrayList<>();
+ this.pinAddedListeners = new ArrayList<>();
+ this.pinRemovedListeners = new ArrayList<>();
+
+ model.componentCreated(this);
+ }
+
+ public void destroy()
+ {
+ pins.forEach(p -> pinRemovedListeners.forEach(l -> l.accept(p)));
+ model.componentDestroyed(this);
+ }
+
+ public void moveTo(double x, double y)
+ {
+ bounds.x = x;
+ bounds.y = y;
+ callComponentMovedListeners();
+ }
+
+ /**
+ * Returns the bounds of this component. Used for calculating which component is clicked.
+ */
+ public Rectangle getBounds()
+ {
+ return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
+ }
+
+ /**
+ * Called when this component is clicked. Absolute coordinates of the click are given. Returns true if this component consumed this
+ * click.
+ */
+ @SuppressWarnings({ "static-method", "unused" }) // this method is inteded to be overridden
+ public boolean clicked(double x, double y)
+ {
+ return false;
+ }
+
+ /**
+ * Returns a list of pins of this component.
+ */
+ public List<Pin> getPins()
+ {
+ return pinsUnmodifiable;
+ }
+
+ // @formatter:off
+ public void addComponentLookChangedListener (Consumer<? super GUIComponent> listener) {componentLookChangedListeners.add (listener);}
+ public void addComponentMovedListener (Consumer<? super GUIComponent> listener) {componentMovedListeners .add (listener);}
+ public void addPinAddedListener (Consumer<? super Pin > listener) {pinAddedListeners .add (listener);}
+ public void addPinRemovedListener (Consumer<? super Pin > listener) {pinRemovedListeners .add (listener);}
+
+ public void removeComponentLookChangedListener(Consumer<? super GUIComponent> listener) {componentLookChangedListeners.remove(listener);}
+ public void removeComponentMovedListener (Consumer<? super GUIComponent> listener) {componentMovedListeners .remove(listener);}
+ public void removePinAddedListener (Consumer<? super Pin > listener) {pinAddedListeners .remove(listener);}
+ public void removePinRemovedListener (Consumer<? super Pin > listener) {pinRemovedListeners .remove(listener);}
+
+ protected void callComponentLookChangedListeners( ) {componentLookChangedListeners.forEach(l -> l.accept(this));}
+ private void callComponentMovedListeners ( ) {componentMovedListeners .forEach(l -> l.accept(this));}
+ private void callPinAddedListeners (Pin p) {pinAddedListeners .forEach(l -> l.accept(p ));}
+ private void callPinRemovedListeners (Pin p) {pinRemovedListeners .forEach(l -> l.accept(p ));}
+ // @form atter:on
+
+ /**
+ * Render this component to the given gc.
+ */
+ public abstract void render(GeneralGC gc, Rectangle visibleRegion);
+
+ protected void setSize(double width, double height)
+ {
+ bounds.width = width;
+ bounds.height = height;
+ callComponentLookChangedListeners();
+ }
+
+ protected void addPin(Pin pin)
+ {
+ pins.add(pin);
+ callPinAddedListeners(pin);
+ }
+
+ protected void removePin(Pin pin)
+ {
+ pins.remove(pin);
+ callPinRemovedListeners(pin);
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.components;
+
+import mograsim.logic.core.components.ManualSwitch;
+import mograsim.logic.core.types.BitVectorFormatter;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.wires.Pin;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+public class GUIManualSwitch extends GUIComponent
+{
+ private static final double width = 20;
+ private static final double height = 15;
+ private static final double fontHeight = 5;
+
+ private final Pin outputPin;
+
+ private ManualSwitch logicSwitch;
+ private ReadEnd end;
+
+ public GUIManualSwitch(ViewModel model)
+ {
+ super(model);
+ setSize(width, height);
+ addPin(this.outputPin = new Pin(this, 1, width, height / 2));
+ }
+
+ @Override
+ public void render(GeneralGC gc, Rectangle visibleRegion)
+ {
+ double posX = getBounds().x;
+ double posY = getBounds().y;
+
+ gc.drawRectangle(posX, posY, width, height);
+ String label = BitVectorFormatter.formatValueAsString(end);
+ Font oldFont = gc.getFont();
+ Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
+ gc.setFont(labelFont);
+ Point textExtent = gc.textExtent(label);
+ gc.drawText(label, posX + (width - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true);
+ gc.setFont(oldFont);
+ }
+
+ public void setLogicModelBinding(ManualSwitch logicSwitch, ReadEnd end)
+ {
+ this.logicSwitch = logicSwitch;
+ this.end = end;
+ // TODO when ManualSwitch supports it, add listeners
+ end.addObserver((i, o) -> callComponentLookChangedListeners());
+ }
+
+ @Override
+ public boolean clicked(double x, double y)
+ {
+ if (logicSwitch != null)
+ logicSwitch.toggle();
+ return true;
+ }
+
+ public Pin getOutputPin()
+ {
+ return outputPin;
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.components;
+
+import mograsim.logic.ui.model.ViewModel;
+
+public class GUINotGate extends SimpleRectangularGUIGate
+{
+ public GUINotGate(ViewModel model, int logicWidth)
+ {
+ super(model, logicWidth, "1", true);
+ setInputCount(1);
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.components;
+
+import mograsim.logic.ui.model.ViewModel;
+
+public class GUIOrGate extends SimpleRectangularGUIGate
+{
+ public GUIOrGate(ViewModel model, int logicWidth)
+ {
+ super(model, logicWidth, "\u22651", false);// ">=1"
+ setInputCount(2);
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.components;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.wires.MovablePin;
+import mograsim.logic.ui.model.wires.Pin;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+public class SimpleRectangularGUIGate extends GUIComponent
+{
+ private static final double width = 20;
+ private static final double pinDistance = 10;
+ private static final double fontHeight = 5;
+ private static final double invertedCircleDiam = 3.5;
+
+ private final String label;
+ protected final int logicWidth;
+ private final boolean isInverted;
+ private final double rectWidth;
+
+ private MovablePin outputPin;
+ private final List<Pin> inputPins;
+ private final List<Pin> inputPinsUnmodifiable;
+
+ protected SimpleRectangularGUIGate(ViewModel model, int logicWidth, String label, boolean isInverted)
+ {
+ super(model);
+ this.label = label;
+ this.logicWidth = logicWidth;
+ this.isInverted = isInverted;
+ this.rectWidth = width - (isInverted ? invertedCircleDiam : 0);
+ this.outputPin = new MovablePin(this, logicWidth, width, 0);
+ addPin(outputPin);
+ this.inputPins = new ArrayList<>();
+ this.inputPinsUnmodifiable = Collections.unmodifiableList(inputPins);
+ setInputCount(1);
+ }
+
+ protected void setInputCount(int inputCount)
+ {
+ int oldInputCount = inputPins.size();
+ setSize(width, inputCount * pinDistance);
+ if (oldInputCount > inputCount)
+ while (inputPins.size() > inputCount)
+ removePin(inputPins.get(inputCount));
+ else if (oldInputCount < inputCount)
+ for (int i = oldInputCount; i < inputCount; i++)
+ {
+ Pin pin = new Pin(this, logicWidth, 0, pinDistance / 2 + i * pinDistance);
+ inputPins.add(pin);
+ addPin(pin);
+ }
+ outputPin.setRelPos(width, inputCount * pinDistance / 2);
+ }
+
+ public Pin getOutputPin()
+ {
+ return outputPin;
+ }
+
+ public List<Pin> getInputPins()
+ {
+ return inputPinsUnmodifiable;
+ }
+
+ @Override
+ public void render(GeneralGC gc, Rectangle visibleRegion)
+ {
+ double posX = getBounds().x;
+ double posY = getBounds().y;
+
+ double height = inputPins.size() * pinDistance;
+ gc.drawRectangle(posX, posY, rectWidth, height);
+ Font oldFont = gc.getFont();
+ Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
+ gc.setFont(labelFont);
+ Point textExtent = gc.textExtent(label);
+ gc.drawText(label, posX + (rectWidth - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true);
+ gc.setFont(oldFont);
+ if (isInverted)
+ gc.drawOval(posX + rectWidth, posY + (height - invertedCircleDiam) / 2, invertedCircleDiam, invertedCircleDiam);
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.wires;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import mograsim.logic.core.types.BitVectorFormatter;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.ui.ColorHelper;
+import mograsim.logic.ui.model.ViewModel;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+
+public class GUIWire
+{
+ private final ViewModel model;
+ public final int logicWidth;
+ private Pin pin1;
+ private Pin pin2;
+ private double[] path;
+
+ private final List<Consumer<? super GUIWire>> wireLookChangedListeners;
+
+ private ReadEnd end;
+
+ public GUIWire(ViewModel model, Pin pin1, Pin pin2, Point... path)
+ {
+ this.model = model;
+ this.logicWidth = pin1.logicWidth;
+ if (pin2.logicWidth != pin1.logicWidth)
+ throw new IllegalArgumentException("Can't connect pins of different logic width");
+ this.path = new double[path.length * 2 + 4];
+ for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2)
+ {
+ this.path[dstI + 0] = path[srcI].x;
+ this.path[dstI + 1] = path[srcI].y;
+ }
+
+ this.pin1 = pin1;
+ this.pin2 = pin2;
+
+ wireLookChangedListeners = new ArrayList<>();
+
+ pin1.addPinMovedListener(p -> pin1Moved());
+ pin2.addPinMovedListener(p -> pin2Moved());
+ pin1Moved();
+ pin2Moved();
+
+ model.wireCreated(this);
+ }
+
+ private void pin1Moved()
+ {
+ Point pos = pin1.getPos();
+ this.path[0] = pos.x;
+ this.path[1] = pos.y;
+ }
+
+ private void pin2Moved()
+ {
+ Point pos = pin2.getPos();
+ this.path[this.path.length - 2] = pos.x;
+ this.path[this.path.length - 1] = pos.y;
+ }
+
+ public void destroy()
+ {
+ model.wireDestroyed(this);
+ }
+
+ public void render(GeneralGC gc)
+ {
+ ColorHelper.executeWithDifferentForeground(gc, BitVectorFormatter.formatAsColor(end), () -> gc.drawPolyline(path));
+ }
+
+ public void setLogicModelBinding(ReadEnd end)
+ {
+ this.end = end;
+ end.addObserver((i, o) -> callWireLookChangedListeners());
+ }
+
+ public Pin getPin1()
+ {
+ return pin1;
+ }
+
+ public Pin getPin2()
+ {
+ return pin2;
+ }
+
+ // @formatter:off
+ public void addWireLookChangedListener (Consumer<? super GUIWire> listener) {wireLookChangedListeners.add (listener);}
+
+ public void removeWireLookChangedListener(Consumer<? super GUIWire> listener) {wireLookChangedListeners.remove(listener);}
+
+ private void callWireLookChangedListeners() {wireLookChangedListeners.forEach(l -> l.accept(this));}
+ // @formatter:on
+
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.wires;
+
+import mograsim.logic.ui.model.components.GUIComponent;
+
+public class MovablePin extends Pin
+{
+ public MovablePin(GUIComponent component, int logicWidth, double relX, double relY)
+ {
+ super(component, logicWidth, relX, relY);
+ }
+
+ @Override
+ public void setRelPos(double relX, double relY)
+ {
+ super.setRelPos(relX, relY);
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.wires;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import mograsim.logic.ui.model.components.GUIComponent;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+public class Pin
+{
+ public final GUIComponent component;
+ public final int logicWidth;
+
+ protected double relX;
+ protected double relY;
+
+ private final List<Consumer<? super Pin>> pinMovedListeners;
+
+ public Pin(GUIComponent component, int logicWidth, double relX, double relY)
+ {
+ this.component = component;
+ this.logicWidth = logicWidth;
+ this.relX = relX;
+ this.relY = relY;
+
+ this.pinMovedListeners = new ArrayList<>();
+
+ component.addComponentMovedListener(c -> callPinMovedListeners());
+ }
+
+ public double getRelX()
+ {
+ return relX;
+ }
+
+ public double getRelY()
+ {
+ return relY;
+ }
+
+ public Point getRelPos()
+ {
+ return new Point(relX, relY);
+ }
+
+ public Point getPos()
+ {
+ Rectangle componentBounds = component.getBounds();
+ return new Point(relX + componentBounds.x, relY + componentBounds.y);
+ }
+
+ // @formatter:off
+ public void addPinMovedListener (Consumer<? super Pin> listener){pinMovedListeners.add (listener);}
+
+ public void removePinMovedListener(Consumer<? super Pin> listener){pinMovedListeners.remove(listener);}
+
+ private void callPinMovedListeners() {pinMovedListeners.forEach(l -> l.accept(this));}
+ // @formatter:on
+
+ protected void setRelPos(double relX, double relY)
+ {
+ this.relX = relX;
+ this.relY = relY;
+ callPinMovedListeners();
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.model.wires;
+
+import mograsim.logic.core.types.BitVectorFormatter;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.ui.ColorHelper;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.components.GUIComponent;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+public class WireCrossPoint extends GUIComponent
+{
+ private final Pin pin;
+
+ private ReadEnd end;
+ private final int logicWidth;
+
+ public WireCrossPoint(ViewModel model, int logicWidth)
+ {
+ super(model);
+ this.logicWidth = logicWidth;
+ setSize(0, 0);
+ addPin(this.pin = new Pin(this, logicWidth, 0, 0));
+ }
+
+ @Override
+ public void render(GeneralGC gc, Rectangle visibleRegion)
+ {
+ Rectangle bounds = getBounds();
+ ColorHelper.executeWithDifferentBackground(gc, BitVectorFormatter.formatAsColor(end),
+ () -> gc.fillOval(bounds.x - 1, bounds.y - 1, 2, 2));
+ }
+
+ public void setLogicModelBinding(ReadEnd end)
+ {
+ this.end = end;
+ end.addObserver((i, o) -> callComponentLookChangedListeners());
+ }
+
+ public int getLogicWidth()
+ {
+ return logicWidth;
+ }
+
+ public Pin getPin()
+ {
+ return pin;
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.modeladapter;
+
+public class LogicModelParameters
+{
+ public int wireTravelTime;
+ public int gateProcessTime;
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.modeladapter;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import mograsim.logic.core.components.Component;
+import mograsim.logic.core.components.gates.AndGate;
+import mograsim.logic.core.components.gates.NotGate;
+import mograsim.logic.core.components.gates.OrGate;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.components.GUIAndGate;
+import mograsim.logic.ui.model.components.GUIComponent;
+import mograsim.logic.ui.model.components.GUINotGate;
+import mograsim.logic.ui.model.components.GUIOrGate;
+import mograsim.logic.ui.model.wires.GUIWire;
+import mograsim.logic.ui.model.wires.Pin;
+import mograsim.logic.ui.model.wires.WireCrossPoint;
+import mograsim.logic.ui.modeladapter.componentadapters.ComponentAdapter;
+import mograsim.logic.ui.modeladapter.componentadapters.ManualSwitchAdapter;
+import mograsim.logic.ui.modeladapter.componentadapters.SimpleGateAdapter;
+
+public class ViewLogicModelAdapter
+{
+ private final static Map<Class<? extends GUIComponent>, ComponentAdapter<? extends GUIComponent>> componentAdapters;
+ static
+ {
+ Set<ComponentAdapter<? extends GUIComponent>> componentAdaptersModifiable = new HashSet<>();
+ componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUIOrGate.class, OrGate::new));
+ componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUIAndGate.class, AndGate::new));
+ componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUINotGate.class, (t, p, o, i) -> new NotGate(t, p, i[0], o)));
+ componentAdaptersModifiable.add(new ManualSwitchAdapter());
+ // TODO list all "primitive" adapters here
+ componentAdapters = Collections.unmodifiableMap(
+ componentAdaptersModifiable.stream().collect(Collectors.toMap(ComponentAdapter::getSupportedClass, Function.identity())));
+ }
+
+ public static Timeline convert(ViewModel viewModel, LogicModelParameters params)
+ {
+ // TODO replace Timeline with LogicModel as soon as it exists
+ Timeline timeline = new Timeline(10);
+
+ Map<Pin, Wire> logicWiresPerPin = convertWires(
+ viewModel.getComponents().stream().flatMap(component -> component.getPins().stream()).collect(Collectors.toSet()),
+ viewModel.getWires(), params, timeline);
+ Map<Pin, Wire> logicWiresPerPinUnmodifiable = Collections.unmodifiableMap(logicWiresPerPin);
+
+ Map<GUIComponent, Component> oneToOneComponents = new HashMap<>();
+ for (GUIComponent guiComp : viewModel.getComponents())
+ {
+ if (!(guiComp instanceof WireCrossPoint))
+ oneToOneComponents.put(guiComp, createAndLinkComponent(timeline, params, guiComp, logicWiresPerPinUnmodifiable,
+ componentAdapters.get(guiComp.getClass())));
+ else
+ {
+ WireCrossPoint guiCompCasted = (WireCrossPoint) guiComp;
+ guiCompCasted.setLogicModelBinding(logicWiresPerPin.get(guiCompCasted.getPin()).createReadOnlyEnd());
+ }
+ }
+
+ // TODO handle complex components
+
+ List<Component> logicComponents = new ArrayList<>();
+ logicComponents.addAll(oneToOneComponents.values());
+
+ return timeline;
+ }
+
+ private static Map<Pin, Wire> convertWires(Set<Pin> allPins, List<GUIWire> wires, LogicModelParameters params, Timeline timeline)
+ {
+ Map<Pin, Set<Pin>> connectedPinGroups = getConnectedPinGroups(allPins, wires);
+ Map<Pin, Wire> logicWiresPerPin = createLogicWires(params, timeline, connectedPinGroups);
+ setGUIWiresLogicModelBinding(wires, logicWiresPerPin);
+ return logicWiresPerPin;
+ }
+
+ private static Map<Pin, Wire> createLogicWires(LogicModelParameters params, Timeline timeline, Map<Pin, Set<Pin>> connectedPinGroups)
+ {
+ Map<Pin, Wire> logicWiresPerPin = new HashMap<>();
+ Map<Set<Pin>, Wire> logicWiresPerPinGroup = new HashMap<>();
+ for (Entry<Pin, Set<Pin>> e : connectedPinGroups.entrySet())
+ logicWiresPerPin.put(e.getKey(), logicWiresPerPinGroup.computeIfAbsent(e.getValue(),
+ set -> new Wire(timeline, e.getKey().logicWidth, params.wireTravelTime)));
+ return logicWiresPerPin;
+ }
+
+ private static void setGUIWiresLogicModelBinding(List<GUIWire> wires, Map<Pin, Wire> logicWiresPerPin)
+ {
+ Map<Wire, ReadEnd> guiWireSharedReadEnd = logicWiresPerPin.values().stream().distinct()
+ .collect(Collectors.toMap(Function.identity(), Wire::createReadOnlyEnd));
+ for (GUIWire guiWire : wires)
+ guiWire.setLogicModelBinding(guiWireSharedReadEnd.get(logicWiresPerPin.get(guiWire.getPin1())));
+ }
+
+ private static Map<Pin, Set<Pin>> getConnectedPinGroups(Set<Pin> allPins, List<GUIWire> wires)
+ {
+ Map<Pin, Set<Pin>> connectedPinsPerPin = new HashMap<>();
+
+ for (Pin p : allPins)
+ {
+ HashSet<Pin> connectedPins = new HashSet<>();
+ connectedPins.add(p);
+ connectedPinsPerPin.put(p, connectedPins);
+ }
+
+ wires.forEach(wire ->
+ {
+ Pin pin1 = wire.getPin1();
+ Pin pin2 = wire.getPin2();
+
+ Set<Pin> pin1ConnectedPins = connectedPinsPerPin.get(pin1);
+ Set<Pin> pin2ConnectedPins = connectedPinsPerPin.get(pin2);
+
+ pin1ConnectedPins.addAll(pin2ConnectedPins);
+ pin1ConnectedPins.add(pin1);
+ pin1ConnectedPins.add(pin2);
+
+ pin2ConnectedPins.forEach(pin -> connectedPinsPerPin.put(pin, pin1ConnectedPins));
+ });
+ return connectedPinsPerPin;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <G extends GUIComponent> Component createAndLinkComponent(Timeline timeline, LogicModelParameters params,
+ GUIComponent guiComponent, Map<Pin, Wire> logicWiresPerPin, ComponentAdapter<G> adapter)
+ {
+ if (adapter == null)
+ throw new IllegalArgumentException("Unknown component class: " + guiComponent.getClass());
+ return adapter.createAndLinkComponent(timeline, params, (G) guiComponent, logicWiresPerPin);
+ }
+
+ private ViewLogicModelAdapter()
+ {
+ throw new UnsupportedOperationException("No ViewLogicModelConverter instances");
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.modeladapter.componentadapters;
+
+import java.util.Map;
+
+import mograsim.logic.core.components.Component;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.ui.model.components.GUIComponent;
+import mograsim.logic.ui.model.wires.Pin;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+
+public interface ComponentAdapter<G extends GUIComponent>
+{
+ public Class<G> getSupportedClass();
+
+ public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G guiComponent,
+ Map<Pin, Wire> logicWiresPerPin);
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.modeladapter.componentadapters;
+
+import java.util.Map;
+
+import mograsim.logic.core.components.Component;
+import mograsim.logic.core.components.ManualSwitch;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+import mograsim.logic.ui.model.components.GUIManualSwitch;
+import mograsim.logic.ui.model.wires.Pin;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+
+public class ManualSwitchAdapter implements ComponentAdapter<GUIManualSwitch>
+{
+ @Override
+ public Class<GUIManualSwitch> getSupportedClass()
+ {
+ return GUIManualSwitch.class;
+ }
+
+ @Override
+ public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, GUIManualSwitch guiComponent,
+ Map<Pin, Wire> logicWiresPerPin)
+ {
+ ReadWriteEnd end = logicWiresPerPin.get(guiComponent.getOutputPin()).createReadWriteEnd();
+ ManualSwitch manualSwitch = new ManualSwitch(timeline, end);
+ guiComponent.setLogicModelBinding(manualSwitch, end);
+ return manualSwitch;
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.ui.modeladapter.componentadapters;
+
+import java.util.List;
+import java.util.Map;
+
+import mograsim.logic.core.components.Component;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+import mograsim.logic.ui.model.components.SimpleRectangularGUIGate;
+import mograsim.logic.ui.model.wires.Pin;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+
+public class SimpleGateAdapter<G extends SimpleRectangularGUIGate> implements ComponentAdapter<G>
+{
+ private final Class<G> supportedClass;
+ private final ComponentConstructor constructor;
+
+ public SimpleGateAdapter(Class<G> supportedClass, ComponentConstructor constructor)
+ {
+ this.supportedClass = supportedClass;
+ this.constructor = constructor;
+ }
+
+ @Override
+ public Class<G> getSupportedClass()
+ {
+ return supportedClass;
+ }
+
+ @Override
+ public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G guiComponent, Map<Pin, Wire> logicWiresPerPin)
+ {
+ ReadWriteEnd out = logicWiresPerPin.get(guiComponent.getOutputPin()).createReadWriteEnd();
+ List<Pin> inputPins = guiComponent.getInputPins();
+ ReadEnd[] ins = new ReadEnd[inputPins.size()];
+ for (int i = 0; i < inputPins.size(); i++)
+ ins[i] = logicWiresPerPin.get(inputPins.get(i)).createReadOnlyEnd();
+ return constructor.newComponent(timeline, params.gateProcessTime, out, ins);
+ }
+
+ public static interface ComponentConstructor
+ {
+ public Component newComponent(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd[] ins);
+ }
+
+}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>\r
<projectDescription>\r
- <name>SampleERCP</name>\r
+ <name>mograsim.rcp</name>\r
<comment></comment>\r
<projects>\r
- <project>LogicUI</project>\r
+ <project>mograsim.rcp</project>\r
</projects>\r
<buildSpec>\r
<buildCommand>\r
eclipse.preferences.version=1\r
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true\r
-formatter_profile=_ERA-MI\r
+formatter_profile=_MoGraSim\r
formatter_settings_version=16\r
org.eclipse.jdt.ui.text.custom_code_templates=\r
sp_cleanup.add_default_serial_version_id=true\r
<?xml version="1.0" encoding="UTF-8"?>\r
<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_6wlLcMgZEeSyMNYR5xypkQ" elementId="Sample.application" bindingContexts="_6wlLecgZEeSyMNYR5xypkQ">\r
- <children xsi:type="basic:TrimmedWindow" xmi:id="_6wlLccgZEeSyMNYR5xypkQ" elementId="Sample.window.main" label="Sample RCP4" iconURI="platform:/plugin/SampleERCP/icons/app/ico_16t.png" width="500" height="400">\r
+ <children xsi:type="basic:TrimmedWindow" xmi:id="_6wlLccgZEeSyMNYR5xypkQ" elementId="Sample.window.main" label="Sample RCP4" iconURI="platform:/plugin/mograsim.rcp/icons/app/ico_16t.png" width="500" height="400">\r
<children xsi:type="basic:PartSashContainer" xmi:id="_6wlLksgZEeSyMNYR5xypkQ" elementId="Sample.partsashcontainer.sample">\r
<children xsi:type="basic:PartStack" xmi:id="_6wlLk8gZEeSyMNYR5xypkQ" elementId="Sample.partstack.sample">\r
- <children xsi:type="basic:Part" xmi:id="_6wlLlMgZEeSyMNYR5xypkQ" elementId="Sample.part.sample" contributionURI="bundleclass://SampleERCP/sampleercp.parts.SamplePart" label="Sample Part" iconURI="platform:/plugin/SampleERCP/icons/home.png"/>\r
- <children xsi:type="basic:Part" xmi:id="_cldhcH1HEema06ZDPR6BSw" elementId="sampleercp.part.logicui" contributionURI="bundleclass://SampleERCP/sampleercp.parts.LogicUIPart" label="LogicUI part"/>\r
+ <children xsi:type="basic:Part" xmi:id="_6wlLlMgZEeSyMNYR5xypkQ" elementId="Sample.part.sample" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.parts.SamplePart" label="Sample Part" iconURI="platform:/plugin/mograsim.rcp/icons/home.png"/>\r
+ <children xsi:type="basic:Part" xmi:id="_cldhcH1HEema06ZDPR6BSw" elementId="mograsim.rcp.part.logicui" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.parts.LogicUIPart" label="LogicUI part"/>\r
</children>\r
<children xsi:type="basic:PartStack" xmi:id="_l2EzYG6wEemo__tDmTCqCQ" elementId="sample.partstack.0">\r
<children xsi:type="basic:Part" xmi:id="_mW1XEG6wEemo__tDmTCqCQ" elementId="sample.part.none" label="None" tooltip="Something"/>\r
</children>\r
<mainMenu xmi:id="_6wlLicgZEeSyMNYR5xypkQ" elementId="org.eclipse.ui.main.menu">\r
<children xsi:type="menu:Menu" xmi:id="_6wlLisgZEeSyMNYR5xypkQ" elementId="file" label="File">\r
- <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLi8gZEeSyMNYR5xypkQ" elementId="Sample.handleditem.file.open" label="Open" iconURI="platform:/plugin/SampleERCP/icons/open_in_app.png" command="_6wlLgMgZEeSyMNYR5xypkQ"/>\r
- <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLjMgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.save" label="Save" iconURI="platform:/plugin/SampleERCP/icons/save_edit.png" command="_6wlLg8gZEeSyMNYR5xypkQ"/>\r
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLi8gZEeSyMNYR5xypkQ" elementId="Sample.handleditem.file.open" label="Open" iconURI="platform:/plugin/mograsim.rcp/icons/open_in_app.png" command="_6wlLgMgZEeSyMNYR5xypkQ"/>\r
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLjMgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.save" label="Save" iconURI="platform:/plugin/mograsim.rcp/icons/save_edit.png" command="_6wlLg8gZEeSyMNYR5xypkQ"/>\r
<children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLjcgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.quit" label="Quit" command="_6wlLfMgZEeSyMNYR5xypkQ"/>\r
</children>\r
<children xsi:type="menu:Menu" xmi:id="_6wlLjsgZEeSyMNYR5xypkQ" elementId="help" label="Help">\r
</mainMenu>\r
<trimBars xmi:id="_6wlLlcgZEeSyMNYR5xypkQ" elementId="Sample.trimbar.top">\r
<children xsi:type="menu:ToolBar" xmi:id="_6wlLlsgZEeSyMNYR5xypkQ" elementId="org.eclipse.ui.main.toolbar">\r
- <children xsi:type="menu:HandledToolItem" xmi:id="_6wlLmMgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.trimbar.top.save" iconURI="platform:/plugin/SampleERCP/icons/save_edit.png" command="_6wlLg8gZEeSyMNYR5xypkQ"/>\r
- <children xsi:type="menu:HandledToolItem" xmi:id="_6wlLl8gZEeSyMNYR5xypkQ" elementId="Sample.handleditem.trimbar.top.open" iconURI="platform:/plugin/SampleERCP/icons/open_in_app.png" command="_6wlLgMgZEeSyMNYR5xypkQ"/>\r
+ <children xsi:type="menu:HandledToolItem" xmi:id="_6wlLmMgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.trimbar.top.save" iconURI="platform:/plugin/mograsim.rcp/icons/save_edit.png" command="_6wlLg8gZEeSyMNYR5xypkQ"/>\r
+ <children xsi:type="menu:HandledToolItem" xmi:id="_6wlLl8gZEeSyMNYR5xypkQ" elementId="Sample.handleditem.trimbar.top.open" iconURI="platform:/plugin/mograsim.rcp/icons/open_in_app.png" command="_6wlLgMgZEeSyMNYR5xypkQ"/>\r
</children>\r
</trimBars>\r
</children>\r
- <handlers xmi:id="_6wlLfcgZEeSyMNYR5xypkQ" elementId="sample.handler.quitCommand" contributionURI="bundleclass://SampleERCP/sampleercp.handlers.QuitHandler" command="_6wlLfMgZEeSyMNYR5xypkQ"/>\r
- <handlers xmi:id="_6wlLgcgZEeSyMNYR5xypkQ" elementId="sample.handler.openCommand" contributionURI="bundleclass://SampleERCP/sampleercp.handlers.OpenHandler" command="_6wlLgMgZEeSyMNYR5xypkQ"/>\r
- <handlers xmi:id="_6wlLhMgZEeSyMNYR5xypkQ" elementId="sample.handler.saveCommand" contributionURI="bundleclass://SampleERCP/sampleercp.handlers.SaveHandler" command="_6wlLg8gZEeSyMNYR5xypkQ"/>\r
- <handlers xmi:id="_6wlLh8gZEeSyMNYR5xypkQ" elementId="sample.handler.aboutCommand" contributionURI="bundleclass://SampleERCP/sampleercp.handlers.AboutHandler" command="_6wlLhsgZEeSyMNYR5xypkQ"/>\r
+ <handlers xmi:id="_6wlLfcgZEeSyMNYR5xypkQ" elementId="sample.handler.quitCommand" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.handlers.QuitHandler" command="_6wlLfMgZEeSyMNYR5xypkQ"/>\r
+ <handlers xmi:id="_6wlLgcgZEeSyMNYR5xypkQ" elementId="sample.handler.openCommand" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.handlers.OpenHandler" command="_6wlLgMgZEeSyMNYR5xypkQ"/>\r
+ <handlers xmi:id="_6wlLhMgZEeSyMNYR5xypkQ" elementId="sample.handler.saveCommand" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.handlers.SaveHandler" command="_6wlLg8gZEeSyMNYR5xypkQ"/>\r
+ <handlers xmi:id="_6wlLh8gZEeSyMNYR5xypkQ" elementId="sample.handler.aboutCommand" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.handlers.AboutHandler" command="_6wlLhsgZEeSyMNYR5xypkQ"/>\r
<bindingTables xmi:id="_6wlLfsgZEeSyMNYR5xypkQ" elementId="Sample.bindingtable" bindingContext="_6wlLecgZEeSyMNYR5xypkQ">\r
<bindings xmi:id="_6wlLf8gZEeSyMNYR5xypkQ" elementId="Sample.keybinding.m1q" keySequence="M1+Q" command="_6wlLfMgZEeSyMNYR5xypkQ"/>\r
<bindings xmi:id="_6wlLgsgZEeSyMNYR5xypkQ" elementId="Sample.keybinding.m1o" keySequence="M1+O" command="_6wlLgMgZEeSyMNYR5xypkQ"/>\r
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
-Bundle-SymbolicName: SampleERCP;singleton:=true
+Bundle-SymbolicName: mograsim.rcp;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.15.200",
org.eclipse.e4.ui.di;bundle-version="1.2.500",
org.eclipse.ui.workbench;bundle-version="3.113.0",
javax.annotation;bundle-version="1.2.0",
- LogicUI,
- era.mi
+ mograsim.logic.ui
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Automatic-Module-Name: Sample
-Export-Package: sampleercp.handlers;uses:="org.eclipse.swt.widgets,org.eclipse.e4.ui.workbench,org.eclipse.e4.ui.workbench.modeling",
- sampleercp.parts;uses:="org.eclipse.swt.widgets",
- sampleercp.splashhandlers
+Export-Package: mograsim.rcp.handlers;uses:="org.eclipse.swt.widgets,org.eclipse.e4.ui.workbench,org.eclipse.e4.ui.workbench.modeling",
+ mograsim.rcp.parts;uses:="org.eclipse.swt.widgets",
+ mograsim.rcp.splashhandlers
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<?pde version="3.5"?>
-
-<product name="Simulator WIP" uid="sample" id="SampleERCP.product" application="org.eclipse.e4.ui.workbench.swt.E4Application" version="1.0.0.qualifier" useFeatures="false" includeLaunchers="true">
-
- <aboutInfo>
- <text>
- Example
- </text>
- </aboutInfo>
-
- <configIni use="default">
- </configIni>
-
- <launcherArgs>
- <programArgs>-clearPersistedState
- </programArgs>
- <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts
- </vmArgsMac>
- </launcherArgs>
-
- <windowImages i16="/SampleERCP/icons/app/ico_16t.png" i32="/SampleERCP/icons/app/ico_32t.png" i48="/SampleERCP/icons/app/ico_48t.png" i64="/SampleERCP/icons/app/ico_64t.png" i128="/SampleERCP/icons/app/ico_128t.png" i256="/SampleERCP/icons/app/ico_256t.png"/>
-
- <splash
- handlerType="extensible" />
- <launcher name="Sample">
- <linux icon="/SampleERCP/icons/app/ico_256t.xpm"/>
- <macosx icon="/SampleERCP/icons/app/ico_256t.icns"/>
- <win useIco="true">
- <ico path="/SampleERCP/icons/app/ico_all.ico"/>
- <bmp/>
- </win>
- </launcher>
-
- <vm>
- <linux include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</linux>
- <macos include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</macos>
- <windows include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</windows>
- </vm>
-
- <license>
- <url>https://www.eclipse.org/legal/epl-2.0/</url>
- <text>
- Copyright (c) 2019 Christian Femers, Daniel Kirschten and Fabian Stemmler
-
-This program and the accompanying materials are made
-available under the terms of the Eclipse Public License 2.0
-which is available at https://www.eclipse.org/legal/epl-2.0/
-
-This Source Code may also be made available under the following Secondary
-Licenses when the conditions for such availability set forth in the Eclipse
-Public License, v. 2.0 are satisfied: GNU General Public License, version 2
-with the GNU Classpath Exception which is
-available at https://www.gnu.org/software/classpath/license.html.
-
-SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
- </text>
- </license>
-
- <plugins>
- <plugin id="LogicUI"/>
- <plugin id="SWTBufferedCanvas"/>
- <plugin id="SWTObjectWrappers"/>
- <plugin id="SWTZoomableCanvas"/>
- <plugin id="SampleERCP"/>
- <plugin id="com.ibm.icu"/>
- <plugin id="era.mi"/>
- <plugin id="javax.annotation"/>
- <plugin id="javax.inject"/>
- <plugin id="javax.servlet"/>
- <plugin id="javax.xml"/>
- <plugin id="org.apache.batik.constants"/>
- <plugin id="org.apache.batik.css"/>
- <plugin id="org.apache.batik.i18n"/>
- <plugin id="org.apache.batik.util"/>
- <plugin id="org.apache.commons.io"/>
- <plugin id="org.apache.commons.jxpath"/>
- <plugin id="org.apache.commons.logging"/>
- <plugin id="org.apache.felix.gogo.runtime"/>
- <plugin id="org.apache.felix.scr"/>
- <plugin id="org.apache.log4j"/>
- <plugin id="org.apache.xmlgraphics"/>
- <plugin id="org.eclipse.ant.core"/>
- <plugin id="org.eclipse.core.commands"/>
- <plugin id="org.eclipse.core.contenttype"/>
- <plugin id="org.eclipse.core.databinding"/>
- <plugin id="org.eclipse.core.databinding.beans"/>
- <plugin id="org.eclipse.core.databinding.observable"/>
- <plugin id="org.eclipse.core.databinding.property"/>
- <plugin id="org.eclipse.core.expressions"/>
- <plugin id="org.eclipse.core.filesystem"/>
- <plugin id="org.eclipse.core.filesystem.win32.x86_64" fragment="true"/>
- <plugin id="org.eclipse.core.jobs"/>
- <plugin id="org.eclipse.core.resources"/>
- <plugin id="org.eclipse.core.resources.win32.x86_64" fragment="true"/>
- <plugin id="org.eclipse.core.runtime"/>
- <plugin id="org.eclipse.core.variables"/>
- <plugin id="org.eclipse.e4.core.commands"/>
- <plugin id="org.eclipse.e4.core.contexts"/>
- <plugin id="org.eclipse.e4.core.di"/>
- <plugin id="org.eclipse.e4.core.di.annotations"/>
- <plugin id="org.eclipse.e4.core.di.extensions"/>
- <plugin id="org.eclipse.e4.core.di.extensions.supplier"/>
- <plugin id="org.eclipse.e4.core.services"/>
- <plugin id="org.eclipse.e4.emf.xpath"/>
- <plugin id="org.eclipse.e4.ui.bindings"/>
- <plugin id="org.eclipse.e4.ui.css.core"/>
- <plugin id="org.eclipse.e4.ui.css.swt"/>
- <plugin id="org.eclipse.e4.ui.css.swt.theme"/>
- <plugin id="org.eclipse.e4.ui.di"/>
- <plugin id="org.eclipse.e4.ui.model.workbench"/>
- <plugin id="org.eclipse.e4.ui.services"/>
- <plugin id="org.eclipse.e4.ui.swt.gtk" fragment="true"/>
- <plugin id="org.eclipse.e4.ui.widgets"/>
- <plugin id="org.eclipse.e4.ui.workbench"/>
- <plugin id="org.eclipse.e4.ui.workbench.addons.swt"/>
- <plugin id="org.eclipse.e4.ui.workbench.renderers.swt"/>
- <plugin id="org.eclipse.e4.ui.workbench.renderers.swt.cocoa" fragment="true"/>
- <plugin id="org.eclipse.e4.ui.workbench.swt"/>
- <plugin id="org.eclipse.e4.ui.workbench3"/>
- <plugin id="org.eclipse.emf.common"/>
- <plugin id="org.eclipse.emf.databinding"/>
- <plugin id="org.eclipse.emf.ecore"/>
- <plugin id="org.eclipse.emf.ecore.change"/>
- <plugin id="org.eclipse.emf.ecore.xmi"/>
- <plugin id="org.eclipse.equinox.app"/>
- <plugin id="org.eclipse.equinox.bidi"/>
- <plugin id="org.eclipse.equinox.common"/>
- <plugin id="org.eclipse.equinox.concurrent"/>
- <plugin id="org.eclipse.equinox.event"/>
- <plugin id="org.eclipse.equinox.preferences"/>
- <plugin id="org.eclipse.equinox.region" fragment="true"/>
- <plugin id="org.eclipse.equinox.registry"/>
- <plugin id="org.eclipse.equinox.supplement"/>
- <plugin id="org.eclipse.equinox.transforms.hook" fragment="true"/>
- <plugin id="org.eclipse.equinox.weaving.hook" fragment="true"/>
- <plugin id="org.eclipse.fx.osgi" fragment="true"/>
- <plugin id="org.eclipse.help"/>
- <plugin id="org.eclipse.jdt.annotation"/>
- <plugin id="org.eclipse.jface"/>
- <plugin id="org.eclipse.jface.databinding"/>
- <plugin id="org.eclipse.osgi"/>
- <plugin id="org.eclipse.osgi.compatibility.state" fragment="true"/>
- <plugin id="org.eclipse.osgi.services"/>
- <plugin id="org.eclipse.osgi.util"/>
- <plugin id="org.eclipse.pde.ds.lib"/>
- <plugin id="org.eclipse.swt"/>
- <plugin id="org.eclipse.swt.cocoa.macosx.x86_64" fragment="true"/>
- <plugin id="org.eclipse.swt.gtk.linux.ppc64le" fragment="true"/>
- <plugin id="org.eclipse.swt.gtk.linux.x86_64" fragment="true"/>
- <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
- <plugin id="org.eclipse.ui"/>
- <plugin id="org.eclipse.ui.cocoa" fragment="true"/>
- <plugin id="org.eclipse.ui.workbench"/>
- <plugin id="org.eclipse.xtext.logging" fragment="true"/>
- <plugin id="org.w3c.css.sac"/>
- <plugin id="org.w3c.dom.events"/>
- <plugin id="org.w3c.dom.smil"/>
- <plugin id="org.w3c.dom.svg"/>
- </plugins>
-
- <configurations>
- <plugin id="org.apache.felix.scr" autoStart="true" startLevel="2" />
- <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="0" />
- <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" />
- <plugin id="org.eclipse.equinox.event" autoStart="true" startLevel="2" />
- <plugin id="org.eclipse.equinox.simpleconfigurator" autoStart="true" startLevel="1" />
- </configurations>
-
- <preferencesInfo>
- <targetfile overwrite="false"/>
- </preferencesInfo>
-
- <cssInfo>
- <file path="/SampleERCP/css/default.css"/>
- </cssInfo>
-
-</product>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?pde version="3.5"?>
+
+<product name="Simulator WIP" uid="sample" id="mograsim.rcp.product" application="org.eclipse.e4.ui.workbench.swt.E4Application" version="1.0.0.qualifier" useFeatures="false" includeLaunchers="true">
+
+ <aboutInfo>
+ <text>
+ Example
+ </text>
+ </aboutInfo>
+
+ <configIni use="default">
+ </configIni>
+
+ <launcherArgs>
+ <programArgs>-clearPersistedState
+ </programArgs>
+ <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts
+ </vmArgsMac>
+ </launcherArgs>
+
+ <windowImages i16="/mograsim.rcp/icons/app/ico_16t.png" i32="/mograsim.rcp/icons/app/ico_32t.png" i48="/mograsim.rcp/icons/app/ico_48t.png" i64="/mograsim.rcp/icons/app/ico_64t.png" i128="/mograsim.rcp/icons/app/ico_128t.png" i256="/mograsim.rcp/icons/app/ico_256t.png"/>
+
+ <splash
+ handlerType="extensible" />
+ <launcher name="Sample">
+ <linux icon="/mograsim.rcp/icons/app/ico_256t.xpm"/>
+ <macosx icon="/mograsim.rcp/icons/app/ico_256t.icns"/>
+ <win useIco="true">
+ <ico path="/mograsim.rcp/icons/app/ico_all.ico"/>
+ <bmp/>
+ </win>
+ </launcher>
+
+
+ <vm>
+ <linux include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</linux>
+ <macos include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</macos>
+ <windows include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</windows>
+ </vm>
+
+ <license>
+ <url>https://www.eclipse.org/legal/epl-2.0/</url>
+ <text>
+ Copyright (c) 2019 Christian Femers, Daniel Kirschten and Fabian Stemmler
+
+This program and the accompanying materials are made
+available under the terms of the Eclipse Public License 2.0
+which is available at https://www.eclipse.org/legal/epl-2.0/
+
+This Source Code may also be made available under the following Secondary
+Licenses when the conditions for such availability set forth in the Eclipse
+Public License, v. 2.0 are satisfied: GNU General Public License, version 2
+with the GNU Classpath Exception which is
+available at https://www.gnu.org/software/classpath/license.html.
+
+SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ </text>
+ </license>
+
+ <plugins>
+ <plugin id="SWTBufferedCanvas"/>
+ <plugin id="SWTObjectWrappers"/>
+ <plugin id="SWTZoomableCanvas"/>
+ <plugin id="com.ibm.icu"/>
+ <plugin id="javax.annotation"/>
+ <plugin id="javax.inject"/>
+ <plugin id="javax.xml"/>
+ <plugin id="mograsim.logic.core"/>
+ <plugin id="mograsim.logic.ui"/>
+ <plugin id="mograsim.rcp"/>
+ <plugin id="org.apache.batik.constants"/>
+ <plugin id="org.apache.batik.css"/>
+ <plugin id="org.apache.batik.i18n"/>
+ <plugin id="org.apache.batik.util"/>
+ <plugin id="org.apache.commons.io"/>
+ <plugin id="org.apache.commons.jxpath"/>
+ <plugin id="org.apache.commons.logging"/>
+ <plugin id="org.apache.xmlgraphics"/>
+ <plugin id="org.eclipse.core.commands"/>
+ <plugin id="org.eclipse.core.contenttype"/>
+ <plugin id="org.eclipse.core.databinding"/>
+ <plugin id="org.eclipse.core.databinding.observable"/>
+ <plugin id="org.eclipse.core.databinding.property"/>
+ <plugin id="org.eclipse.core.expressions"/>
+ <plugin id="org.eclipse.core.jobs"/>
+ <plugin id="org.eclipse.core.runtime"/>
+ <plugin id="org.eclipse.e4.core.commands"/>
+ <plugin id="org.eclipse.e4.core.contexts"/>
+ <plugin id="org.eclipse.e4.core.di"/>
+ <plugin id="org.eclipse.e4.core.di.annotations"/>
+ <plugin id="org.eclipse.e4.core.di.extensions"/>
+ <plugin id="org.eclipse.e4.core.di.extensions.supplier"/>
+ <plugin id="org.eclipse.e4.core.services"/>
+ <plugin id="org.eclipse.e4.emf.xpath"/>
+ <plugin id="org.eclipse.e4.ui.bindings"/>
+ <plugin id="org.eclipse.e4.ui.css.core"/>
+ <plugin id="org.eclipse.e4.ui.css.swt"/>
+ <plugin id="org.eclipse.e4.ui.css.swt.theme"/>
+ <plugin id="org.eclipse.e4.ui.di"/>
+ <plugin id="org.eclipse.e4.ui.model.workbench"/>
+ <plugin id="org.eclipse.e4.ui.services"/>
+ <plugin id="org.eclipse.e4.ui.widgets"/>
+ <plugin id="org.eclipse.e4.ui.workbench"/>
+ <plugin id="org.eclipse.e4.ui.workbench.addons.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench.renderers.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench3"/>
+ <plugin id="org.eclipse.emf.common"/>
+ <plugin id="org.eclipse.emf.ecore"/>
+ <plugin id="org.eclipse.emf.ecore.change"/>
+ <plugin id="org.eclipse.emf.ecore.xmi"/>
+ <plugin id="org.eclipse.equinox.app"/>
+ <plugin id="org.eclipse.equinox.common"/>
+ <plugin id="org.eclipse.equinox.preferences"/>
+ <plugin id="org.eclipse.equinox.region" fragment="true"/>
+ <plugin id="org.eclipse.equinox.registry"/>
+ <plugin id="org.eclipse.equinox.supplement"/>
+ <plugin id="org.eclipse.equinox.transforms.hook" fragment="true"/>
+ <plugin id="org.eclipse.equinox.weaving.hook" fragment="true"/>
+ <plugin id="org.eclipse.help"/>
+ <plugin id="org.eclipse.jface"/>
+ <plugin id="org.eclipse.jface.databinding"/>
+ <plugin id="org.eclipse.osgi"/>
+ <plugin id="org.eclipse.osgi.compatibility.state" fragment="true"/>
+ <plugin id="org.eclipse.osgi.services"/>
+ <plugin id="org.eclipse.osgi.util"/>
+ <plugin id="org.eclipse.swt"/>
+ <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
+ <plugin id="org.eclipse.ui.workbench"/>
+ <plugin id="org.w3c.css.sac"/>
+ <plugin id="org.w3c.dom.events"/>
+ <plugin id="org.w3c.dom.smil"/>
+ <plugin id="org.w3c.dom.svg"/>
+ </plugins>
+
+ <configurations>
+ <plugin id="org.eclipse.equinox.simpleconfigurator" autoStart="true" startLevel="1" />
+ </configurations>
+
+ <preferencesInfo>
+ <targetfile overwrite="false"/>
+ </preferencesInfo>
+
+ <cssInfo>
+ <file path="/mograsim.rcp/css/default.css"/>
+ </cssInfo>
+
+</product>
name="Simulator WIP">\r
<property\r
name="applicationCSS"\r
- value="platform:/plugin/SampleERCP/css/default.css">\r
+ value="platform:/plugin/mograsim.rcp/css/default.css">\r
</property>\r
<property\r
name="appName"\r
<extension\r
point="org.eclipse.ui.splashHandlers">\r
<splashHandler\r
- class="sampleercp.splashHandlers.ExtensibleSplashHandler"\r
- id="sampleercp.splashHandlers.extensible">\r
+ class="mograsim.rcp.splashhandlers.ExtensibleSplashHandler"\r
+ id="mograsim.rcp.splashHandlers.extensible">\r
</splashHandler>\r
<splashHandlerProductBinding\r
- productId="SampleERCP.product"\r
- splashId="sampleercp.splashHandlers.extensible">\r
- </splashHandlerProductBinding>\r
- <splashHandler\r
- class="sampleercp.splashhandlers.ExtensibleSplashHandler"\r
- id="sampleercp.splashHandlers.extensible">\r
- </splashHandler>\r
- <splashHandlerProductBinding\r
- productId="SampleERCP.product"\r
- splashId="sampleercp.splashHandlers.extensible">\r
+ productId="mograsim.rcp.product"\r
+ splashId="mograsim.rcp.splashHandlers.extensible">\r
</splashHandlerProductBinding>\r
</extension>\r
<extension\r
- point="SampleERCP.splashExtension">\r
+ point="mograsim.rcp.splashExtension">\r
<splashExtension\r
icon="icons/af.png"\r
id="af"\r
--- /dev/null
+package mograsim.rcp.handlers;\r
+\r
+import org.eclipse.e4.core.di.annotations.Execute;\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.swt.widgets.Shell;\r
+\r
+public class AboutHandler\r
+{\r
+ @Execute\r
+ public void execute(Shell shell)\r
+ {\r
+ MessageDialog.openInformation(shell, "About", "Sample RCP4");\r
+ }\r
+}\r
--- /dev/null
+package mograsim.rcp.handlers;\r
+\r
+import org.eclipse.e4.core.di.annotations.Execute;\r
+import org.eclipse.swt.widgets.FileDialog;\r
+import org.eclipse.swt.widgets.Shell;\r
+\r
+public class OpenHandler\r
+{\r
+\r
+ @Execute\r
+ public void execute(Shell shell)\r
+ {\r
+ FileDialog dialog = new FileDialog(shell);\r
+ dialog.open();\r
+ }\r
+}\r
--- /dev/null
+package mograsim.rcp.handlers;\r
+\r
+import org.eclipse.e4.core.di.annotations.Execute;\r
+import org.eclipse.e4.ui.workbench.IWorkbench;\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.swt.widgets.Shell;\r
+\r
+public class QuitHandler\r
+{\r
+ @Execute\r
+ public void execute(IWorkbench workbench, Shell shell)\r
+ {\r
+ if (MessageDialog.openConfirm(shell, "Confirmation", "Do you want to exit?"))\r
+ {\r
+ workbench.close();\r
+ }\r
+ }\r
+}\r
--- /dev/null
+package mograsim.rcp.handlers;\r
+\r
+import org.eclipse.e4.core.di.annotations.CanExecute;\r
+import org.eclipse.e4.core.di.annotations.Execute;\r
+import org.eclipse.e4.ui.workbench.modeling.EPartService;\r
+\r
+public class SaveHandler\r
+{\r
+\r
+ @CanExecute\r
+ public boolean canExecute(EPartService partService)\r
+ {\r
+ if (partService != null)\r
+ {\r
+ return !partService.getDirtyParts().isEmpty();\r
+ }\r
+ return false;\r
+ }\r
+\r
+ @Execute\r
+ public void execute(EPartService partService)\r
+ {\r
+ partService.saveAll(false);\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package mograsim.rcp.parts;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.ui.LogicExecuter;
+import mograsim.logic.ui.LogicUICanvas;
+import mograsim.logic.ui.examples.RSLatchExample;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+import mograsim.logic.ui.modeladapter.ViewLogicModelAdapter;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
+
+public class LogicUIPart
+{
+ @Inject
+ private MPart part;
+
+ @PostConstruct
+ public void create(Composite parent)
+ {
+ // setup view model
+ ViewModel viewModel = new ViewModel();
+ RSLatchExample.createRSLatchExample(viewModel);
+
+ // convert to logic model
+ LogicModelParameters params = new LogicModelParameters();
+ params.gateProcessTime = 50;
+ params.wireTravelTime = 10;
+ Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
+
+ // initialize UI
+ LogicUICanvas ui = new LogicUICanvas(parent, SWT.NONE, viewModel);
+ ui.addTransformListener((x, y, z) -> part.setDirty(z < 1));
+ ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
+ userInput.buttonDrag = 3;
+ userInput.buttonZoom = 2;
+ userInput.enableUserInput();
+
+ // initialize executer
+ LogicExecuter exec = new LogicExecuter(timeline);
+
+ // run it
+ exec.startLiveExecution();
+
+ // TODO find a better condition when to stop
+ ui.addDisposeListener(e -> exec.stopLiveExecution());
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.rcp.parts;\r
+\r
+import java.util.Arrays;\r
+import java.util.List;\r
+\r
+import javax.annotation.PostConstruct;\r
+import javax.inject.Inject;\r
+\r
+import org.eclipse.e4.ui.di.Focus;\r
+import org.eclipse.e4.ui.di.Persist;\r
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;\r
+import org.eclipse.jface.viewers.ArrayContentProvider;\r
+import org.eclipse.jface.viewers.TableViewer;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Text;\r
+\r
+public class SamplePart\r
+{\r
+\r
+ private TableViewer tableViewer;\r
+\r
+ @Inject\r
+ private MPart part;\r
+\r
+ @PostConstruct\r
+ public void createComposite(Composite parent)\r
+ {\r
+ parent.setLayout(new GridLayout(1, false));\r
+\r
+ Text txtInput = new Text(parent, SWT.BORDER);\r
+ txtInput.setMessage("Enter text to mark part as dirty");\r
+ txtInput.addModifyListener(e -> part.setDirty(true));\r
+ txtInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\r
+\r
+ tableViewer = new TableViewer(parent);\r
+\r
+ tableViewer.setContentProvider(ArrayContentProvider.getInstance());\r
+ tableViewer.setInput(createInitialDataModel());\r
+ tableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));\r
+ }\r
+\r
+ @Focus\r
+ public void setFocus()\r
+ {\r
+ tableViewer.getTable().setFocus();\r
+ }\r
+\r
+ @Persist\r
+ public void save()\r
+ {\r
+ part.setDirty(false);\r
+ }\r
+\r
+ private static List<String> createInitialDataModel()\r
+ {\r
+ return Arrays.asList("Sample item 1", "Sample item 2", "Sample item 3", "Sample item 4", "Sample item 5");\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package mograsim.rcp.splashhandlers;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+\r
+import org.eclipse.core.runtime.IConfigurationElement;\r
+import org.eclipse.core.runtime.IExtension;\r
+import org.eclipse.core.runtime.Platform;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.eclipse.ui.splash.AbstractSplashHandler;\r
+\r
+/**\r
+ * @since 3.3\r
+ *\r
+ */\r
+public class ExtensibleSplashHandler extends AbstractSplashHandler\r
+{\r
+\r
+ private ArrayList<Image> fImageList;\r
+\r
+ private ArrayList<String> fTooltipList;\r
+\r
+ private static final String F_SPLASH_EXTENSION_ID = "Sample.splashExtension"; // NON-NLS-1\r
+\r
+ private static final String F_ELEMENT_ICON = "icon"; // NON-NLS-1\r
+\r
+ private static final String F_ELEMENT_TOOLTIP = "tooltip"; // NON-NLS-1\r
+\r
+ private static final String F_DEFAULT_TOOLTIP = "Image"; // NON-NLS-1\r
+\r
+ private static final int F_IMAGE_WIDTH = 50;\r
+\r
+ private static final int F_IMAGE_HEIGHT = 50;\r
+\r
+ private static final int F_SPLASH_SCREEN_BEVEL = 5;\r
+\r
+ private Composite fIconPanel;\r
+\r
+ /**\r
+ * \r
+ */\r
+ public ExtensibleSplashHandler()\r
+ {\r
+ fImageList = new ArrayList<>();\r
+ fTooltipList = new ArrayList<>();\r
+ fIconPanel = null;\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see org.eclipse.ui.splash.AbstractSplashHandler#init(org.eclipse.swt.widgets. Shell)\r
+ */\r
+ @Override\r
+ public void init(Shell splash)\r
+ {\r
+ // Store the shell\r
+ super.init(splash);\r
+ // Configure the shell layout\r
+ configureUISplash();\r
+ // Load all splash extensions\r
+ loadSplashExtensions();\r
+ // If no splash extensions were loaded abort the splash handler\r
+ if (!hasSplashExtensions())\r
+ {\r
+ return;\r
+ }\r
+ // Create UI\r
+ createUI();\r
+ // Configure the image panel bounds\r
+ configureUICompositeIconPanelBounds();\r
+ // Enter event loop and prevent the RCP application from\r
+ // loading until all work is done\r
+ doEventLoop();\r
+ }\r
+\r
+ /**\r
+ * @return\r
+ */\r
+ private boolean hasSplashExtensions()\r
+ {\r
+ return !fImageList.isEmpty();\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUI()\r
+ {\r
+ // Create the icon panel\r
+ createUICompositeIconPanel();\r
+ // Create the images\r
+ createUIImages();\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUIImages()\r
+ {\r
+ Iterator<Image> imageIterator = fImageList.iterator();\r
+ Iterator<String> tooltipIterator = fTooltipList.iterator();\r
+ int i = 1;\r
+ int columnCount = ((GridLayout) fIconPanel.getLayout()).numColumns;\r
+ // Create all the images\r
+ // Abort if we run out of columns (left-over images will not fit within\r
+ // the usable splash screen width)\r
+ while (imageIterator.hasNext() && (i <= columnCount))\r
+ {\r
+ Image image = imageIterator.next();\r
+ String tooltip = tooltipIterator.next();\r
+ // Create the image using a label widget\r
+ createUILabel(image, tooltip);\r
+ i++;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param image\r
+ * @param tooltip\r
+ */\r
+ private void createUILabel(Image image, String tooltip)\r
+ {\r
+ // Create the label (no text)\r
+ Label label = new Label(fIconPanel, SWT.NONE);\r
+ label.setImage(image);\r
+ label.setToolTipText(tooltip);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUICompositeIconPanel()\r
+ {\r
+ Shell splash = getSplash();\r
+ // Create the composite\r
+ fIconPanel = new Composite(splash, SWT.NONE);\r
+ // Determine the maximum number of columns that can fit on the splash\r
+ // screen. One 50x50 image per column.\r
+ int maxColumnCount = getUsableSplashScreenWidth() / F_IMAGE_WIDTH;\r
+ // Limit size to the maximum number of columns if the number of images\r
+ // exceed this amount; otherwise, use the exact number of columns\r
+ // required.\r
+ int actualColumnCount = Math.min(fImageList.size(), maxColumnCount);\r
+ // Configure the layout\r
+ GridLayout layout = new GridLayout(actualColumnCount, true);\r
+ layout.horizontalSpacing = 0;\r
+ layout.verticalSpacing = 0;\r
+ layout.marginHeight = 0;\r
+ layout.marginWidth = 0;\r
+ fIconPanel.setLayout(layout);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void configureUICompositeIconPanelBounds()\r
+ {\r
+ // Determine the size of the panel and position it at the bottom-right\r
+ // of the splash screen.\r
+ Point panelSize = fIconPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);\r
+\r
+ int xCoord = getSplash().getSize().x - F_SPLASH_SCREEN_BEVEL - panelSize.x;\r
+ int yCoord = getSplash().getSize().y - F_SPLASH_SCREEN_BEVEL - panelSize.y;\r
+ int xWidth = panelSize.x;\r
+ int yWidth = panelSize.y;\r
+\r
+ fIconPanel.setBounds(xCoord, yCoord, xWidth, yWidth);\r
+ }\r
+\r
+ /**\r
+ * @return\r
+ */\r
+ private int getUsableSplashScreenWidth()\r
+ {\r
+ // Splash screen width minus two graphic border bevel widths\r
+ return getSplash().getSize().x - (F_SPLASH_SCREEN_BEVEL * 2);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void loadSplashExtensions()\r
+ {\r
+ // Get all splash handler extensions\r
+ IExtension[] extensions = Platform.getExtensionRegistry().getExtensionPoint(F_SPLASH_EXTENSION_ID).getExtensions();\r
+ // Process all splash handler extensions\r
+ for (int i = 0; i < extensions.length; i++)\r
+ {\r
+ processSplashExtension(extensions[i]);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param extension\r
+ */\r
+ private void processSplashExtension(IExtension extension)\r
+ {\r
+ // Get all splash handler configuration elements\r
+ IConfigurationElement[] elements = extension.getConfigurationElements();\r
+ // Process all splash handler configuration elements\r
+ for (int j = 0; j < elements.length; j++)\r
+ {\r
+ processSplashElements(elements[j]);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param configurationElement\r
+ */\r
+ private void processSplashElements(IConfigurationElement configurationElement)\r
+ {\r
+ // Attribute: icon\r
+ processSplashElementIcon(configurationElement);\r
+ // Attribute: tooltip\r
+ processSplashElementTooltip(configurationElement);\r
+ }\r
+\r
+ /**\r
+ * @param configurationElement\r
+ */\r
+ private void processSplashElementTooltip(IConfigurationElement configurationElement)\r
+ {\r
+ // Get attribute tooltip\r
+ String tooltip = configurationElement.getAttribute(F_ELEMENT_TOOLTIP);\r
+ // If a tooltip is not defined, give it a default\r
+ if ((tooltip == null) || (tooltip.length() == 0))\r
+ {\r
+ fTooltipList.add(F_DEFAULT_TOOLTIP);\r
+ } else\r
+ {\r
+ fTooltipList.add(tooltip);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param configurationElement\r
+ */\r
+ private void processSplashElementIcon(IConfigurationElement configurationElement)\r
+ {\r
+ // Get attribute icon\r
+ String iconImageFilePath = configurationElement.getAttribute(F_ELEMENT_ICON);\r
+ // Abort if an icon attribute was not specified\r
+ if ((iconImageFilePath == null) || (iconImageFilePath.length() == 0))\r
+ {\r
+ return;\r
+ }\r
+ // Create a corresponding image descriptor\r
+ ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(configurationElement.getNamespaceIdentifier(),\r
+ iconImageFilePath);\r
+ // Abort if no corresponding image was found\r
+ if (descriptor == null)\r
+ {\r
+ return;\r
+ }\r
+ // Create the image\r
+ Image image = descriptor.createImage();\r
+ // Abort if image creation failed\r
+ if (image == null)\r
+ {\r
+ return;\r
+ }\r
+ // Abort if the image does not have dimensions of 50x50\r
+ if ((image.getBounds().width != F_IMAGE_WIDTH) || (image.getBounds().height != F_IMAGE_HEIGHT))\r
+ {\r
+ // Dipose of the image\r
+ image.dispose();\r
+ return;\r
+ }\r
+ // Store the image and tooltip\r
+ fImageList.add(image);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void configureUISplash()\r
+ {\r
+ // Configure layout\r
+ GridLayout layout = new GridLayout(1, true);\r
+ getSplash().setLayout(layout);\r
+ // Force shell to inherit the splash background\r
+ getSplash().setBackgroundMode(SWT.INHERIT_DEFAULT);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void doEventLoop()\r
+ {\r
+ Shell splash = getSplash();\r
+ if (!splash.getDisplay().readAndDispatch())\r
+ {\r
+ splash.getDisplay().sleep();\r
+ }\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see org.eclipse.ui.splash.AbstractSplashHandler#dispose()\r
+ */\r
+ @Override\r
+ public void dispose()\r
+ {\r
+ super.dispose();\r
+ // Check to see if any images were defined\r
+ if ((fImageList == null) || fImageList.isEmpty())\r
+ {\r
+ return;\r
+ }\r
+ // Dispose of all the images\r
+ Iterator<Image> iterator = fImageList.iterator();\r
+ while (iterator.hasNext())\r
+ {\r
+ Image image = iterator.next();\r
+ image.dispose();\r
+ }\r
+ }\r
+}\r
+++ /dev/null
-package sampleercp.handlers;\r
-\r
-import org.eclipse.e4.core.di.annotations.Execute;\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.swt.widgets.Shell;\r
-\r
-public class AboutHandler\r
-{\r
- @Execute\r
- public void execute(Shell shell)\r
- {\r
- MessageDialog.openInformation(shell, "About", "Sample RCP4");\r
- }\r
-}\r
+++ /dev/null
-package sampleercp.handlers;\r
-\r
-import org.eclipse.e4.core.di.annotations.Execute;\r
-import org.eclipse.swt.widgets.FileDialog;\r
-import org.eclipse.swt.widgets.Shell;\r
-\r
-public class OpenHandler\r
-{\r
-\r
- @Execute\r
- public void execute(Shell shell)\r
- {\r
- FileDialog dialog = new FileDialog(shell);\r
- dialog.open();\r
- }\r
-}\r
+++ /dev/null
-package sampleercp.handlers;\r
-\r
-import org.eclipse.e4.core.di.annotations.Execute;\r
-import org.eclipse.e4.ui.workbench.IWorkbench;\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.swt.widgets.Shell;\r
-\r
-public class QuitHandler\r
-{\r
- @Execute\r
- public void execute(IWorkbench workbench, Shell shell)\r
- {\r
- if (MessageDialog.openConfirm(shell, "Confirmation", "Do you want to exit?"))\r
- {\r
- workbench.close();\r
- }\r
- }\r
-}\r
+++ /dev/null
-package sampleercp.handlers;\r
-\r
-import org.eclipse.e4.core.di.annotations.CanExecute;\r
-import org.eclipse.e4.core.di.annotations.Execute;\r
-import org.eclipse.e4.ui.workbench.modeling.EPartService;\r
-\r
-public class SaveHandler\r
-{\r
-\r
- @CanExecute\r
- public boolean canExecute(EPartService partService)\r
- {\r
- if (partService != null)\r
- {\r
- return !partService.getDirtyParts().isEmpty();\r
- }\r
- return false;\r
- }\r
-\r
- @Execute\r
- public void execute(EPartService partService)\r
- {\r
- partService.saveAll(false);\r
- }\r
-}
\ No newline at end of file
+++ /dev/null
-package sampleercp.parts;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-
-import era.mi.gui.LogicExecuter;
-import era.mi.gui.LogicUICanvas;
-import era.mi.gui.examples.RSLatchExample;
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import era.mi.gui.modeladapter.ViewLogicModelAdapter;
-import era.mi.logic.timeline.Timeline;
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
-
-public class LogicUIPart
-{
- @Inject
- private MPart part;
-
- @PostConstruct
- public void create(Composite parent)
- {
- // setup view model
- ViewModel viewModel = new ViewModel();
- RSLatchExample.createRSLatchExample(viewModel);
-
- // convert to logic model
- LogicModelParameters params = new LogicModelParameters();
- params.gateProcessTime = 50;
- params.wireTravelTime = 10;
- Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
-
- // initialize UI
- LogicUICanvas ui = new LogicUICanvas(parent, SWT.NONE, viewModel);
- ui.addTransformListener((x, y, z) -> part.setDirty(z < 1));
- ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
- userInput.buttonDrag = 3;
- userInput.buttonZoom = 2;
- userInput.enableUserInput();
-
- // initialize executer
- LogicExecuter exec = new LogicExecuter(timeline);
-
- // run it
- exec.startLiveExecution();
-
- // TODO find a better condition when to stop
- ui.addDisposeListener(e -> exec.stopLiveExecution());
- }
-}
\ No newline at end of file
+++ /dev/null
-package sampleercp.parts;\r
-\r
-import java.util.Arrays;\r
-import java.util.List;\r
-\r
-import javax.annotation.PostConstruct;\r
-import javax.inject.Inject;\r
-\r
-import org.eclipse.e4.ui.di.Focus;\r
-import org.eclipse.e4.ui.di.Persist;\r
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;\r
-import org.eclipse.jface.viewers.ArrayContentProvider;\r
-import org.eclipse.jface.viewers.TableViewer;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Text;\r
-\r
-public class SamplePart\r
-{\r
-\r
- private TableViewer tableViewer;\r
-\r
- @Inject\r
- private MPart part;\r
-\r
- @PostConstruct\r
- public void createComposite(Composite parent)\r
- {\r
- parent.setLayout(new GridLayout(1, false));\r
-\r
- Text txtInput = new Text(parent, SWT.BORDER);\r
- txtInput.setMessage("Enter text to mark part as dirty");\r
- txtInput.addModifyListener(e -> part.setDirty(true));\r
- txtInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\r
-\r
- tableViewer = new TableViewer(parent);\r
-\r
- tableViewer.setContentProvider(ArrayContentProvider.getInstance());\r
- tableViewer.setInput(createInitialDataModel());\r
- tableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));\r
- }\r
-\r
- @Focus\r
- public void setFocus()\r
- {\r
- tableViewer.getTable().setFocus();\r
- }\r
-\r
- @Persist\r
- public void save()\r
- {\r
- part.setDirty(false);\r
- }\r
-\r
- private static List<String> createInitialDataModel()\r
- {\r
- return Arrays.asList("Sample item 1", "Sample item 2", "Sample item 3", "Sample item 4", "Sample item 5");\r
- }\r
-}
\ No newline at end of file
+++ /dev/null
-package sampleercp.splashhandlers;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Iterator;\r
-\r
-import org.eclipse.core.runtime.IConfigurationElement;\r
-import org.eclipse.core.runtime.IExtension;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.eclipse.jface.resource.ImageDescriptor;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.graphics.Image;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Label;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.ui.plugin.AbstractUIPlugin;\r
-import org.eclipse.ui.splash.AbstractSplashHandler;\r
-\r
-/**\r
- * @since 3.3\r
- *\r
- */\r
-public class ExtensibleSplashHandler extends AbstractSplashHandler\r
-{\r
-\r
- private ArrayList<Image> fImageList;\r
-\r
- private ArrayList<String> fTooltipList;\r
-\r
- private static final String F_SPLASH_EXTENSION_ID = "Sample.splashExtension"; // NON-NLS-1\r
-\r
- private static final String F_ELEMENT_ICON = "icon"; // NON-NLS-1\r
-\r
- private static final String F_ELEMENT_TOOLTIP = "tooltip"; // NON-NLS-1\r
-\r
- private static final String F_DEFAULT_TOOLTIP = "Image"; // NON-NLS-1\r
-\r
- private static final int F_IMAGE_WIDTH = 50;\r
-\r
- private static final int F_IMAGE_HEIGHT = 50;\r
-\r
- private static final int F_SPLASH_SCREEN_BEVEL = 5;\r
-\r
- private Composite fIconPanel;\r
-\r
- /**\r
- * \r
- */\r
- public ExtensibleSplashHandler()\r
- {\r
- fImageList = new ArrayList<>();\r
- fTooltipList = new ArrayList<>();\r
- fIconPanel = null;\r
- }\r
-\r
- /*\r
- * (non-Javadoc)\r
- * \r
- * @see org.eclipse.ui.splash.AbstractSplashHandler#init(org.eclipse.swt.widgets. Shell)\r
- */\r
- @Override\r
- public void init(Shell splash)\r
- {\r
- // Store the shell\r
- super.init(splash);\r
- // Configure the shell layout\r
- configureUISplash();\r
- // Load all splash extensions\r
- loadSplashExtensions();\r
- // If no splash extensions were loaded abort the splash handler\r
- if (!hasSplashExtensions())\r
- {\r
- return;\r
- }\r
- // Create UI\r
- createUI();\r
- // Configure the image panel bounds\r
- configureUICompositeIconPanelBounds();\r
- // Enter event loop and prevent the RCP application from\r
- // loading until all work is done\r
- doEventLoop();\r
- }\r
-\r
- /**\r
- * @return\r
- */\r
- private boolean hasSplashExtensions()\r
- {\r
- return !fImageList.isEmpty();\r
- }\r
-\r
- /**\r
- * \r
- */\r
- private void createUI()\r
- {\r
- // Create the icon panel\r
- createUICompositeIconPanel();\r
- // Create the images\r
- createUIImages();\r
- }\r
-\r
- /**\r
- * \r
- */\r
- private void createUIImages()\r
- {\r
- Iterator<Image> imageIterator = fImageList.iterator();\r
- Iterator<String> tooltipIterator = fTooltipList.iterator();\r
- int i = 1;\r
- int columnCount = ((GridLayout) fIconPanel.getLayout()).numColumns;\r
- // Create all the images\r
- // Abort if we run out of columns (left-over images will not fit within\r
- // the usable splash screen width)\r
- while (imageIterator.hasNext() && (i <= columnCount))\r
- {\r
- Image image = imageIterator.next();\r
- String tooltip = tooltipIterator.next();\r
- // Create the image using a label widget\r
- createUILabel(image, tooltip);\r
- i++;\r
- }\r
- }\r
-\r
- /**\r
- * @param image\r
- * @param tooltip\r
- */\r
- private void createUILabel(Image image, String tooltip)\r
- {\r
- // Create the label (no text)\r
- Label label = new Label(fIconPanel, SWT.NONE);\r
- label.setImage(image);\r
- label.setToolTipText(tooltip);\r
- }\r
-\r
- /**\r
- * \r
- */\r
- private void createUICompositeIconPanel()\r
- {\r
- Shell splash = getSplash();\r
- // Create the composite\r
- fIconPanel = new Composite(splash, SWT.NONE);\r
- // Determine the maximum number of columns that can fit on the splash\r
- // screen. One 50x50 image per column.\r
- int maxColumnCount = getUsableSplashScreenWidth() / F_IMAGE_WIDTH;\r
- // Limit size to the maximum number of columns if the number of images\r
- // exceed this amount; otherwise, use the exact number of columns\r
- // required.\r
- int actualColumnCount = Math.min(fImageList.size(), maxColumnCount);\r
- // Configure the layout\r
- GridLayout layout = new GridLayout(actualColumnCount, true);\r
- layout.horizontalSpacing = 0;\r
- layout.verticalSpacing = 0;\r
- layout.marginHeight = 0;\r
- layout.marginWidth = 0;\r
- fIconPanel.setLayout(layout);\r
- }\r
-\r
- /**\r
- * \r
- */\r
- private void configureUICompositeIconPanelBounds()\r
- {\r
- // Determine the size of the panel and position it at the bottom-right\r
- // of the splash screen.\r
- Point panelSize = fIconPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);\r
-\r
- int xCoord = getSplash().getSize().x - F_SPLASH_SCREEN_BEVEL - panelSize.x;\r
- int yCoord = getSplash().getSize().y - F_SPLASH_SCREEN_BEVEL - panelSize.y;\r
- int xWidth = panelSize.x;\r
- int yWidth = panelSize.y;\r
-\r
- fIconPanel.setBounds(xCoord, yCoord, xWidth, yWidth);\r
- }\r
-\r
- /**\r
- * @return\r
- */\r
- private int getUsableSplashScreenWidth()\r
- {\r
- // Splash screen width minus two graphic border bevel widths\r
- return getSplash().getSize().x - (F_SPLASH_SCREEN_BEVEL * 2);\r
- }\r
-\r
- /**\r
- * \r
- */\r
- private void loadSplashExtensions()\r
- {\r
- // Get all splash handler extensions\r
- IExtension[] extensions = Platform.getExtensionRegistry().getExtensionPoint(F_SPLASH_EXTENSION_ID).getExtensions();\r
- // Process all splash handler extensions\r
- for (int i = 0; i < extensions.length; i++)\r
- {\r
- processSplashExtension(extensions[i]);\r
- }\r
- }\r
-\r
- /**\r
- * @param extension\r
- */\r
- private void processSplashExtension(IExtension extension)\r
- {\r
- // Get all splash handler configuration elements\r
- IConfigurationElement[] elements = extension.getConfigurationElements();\r
- // Process all splash handler configuration elements\r
- for (int j = 0; j < elements.length; j++)\r
- {\r
- processSplashElements(elements[j]);\r
- }\r
- }\r
-\r
- /**\r
- * @param configurationElement\r
- */\r
- private void processSplashElements(IConfigurationElement configurationElement)\r
- {\r
- // Attribute: icon\r
- processSplashElementIcon(configurationElement);\r
- // Attribute: tooltip\r
- processSplashElementTooltip(configurationElement);\r
- }\r
-\r
- /**\r
- * @param configurationElement\r
- */\r
- private void processSplashElementTooltip(IConfigurationElement configurationElement)\r
- {\r
- // Get attribute tooltip\r
- String tooltip = configurationElement.getAttribute(F_ELEMENT_TOOLTIP);\r
- // If a tooltip is not defined, give it a default\r
- if ((tooltip == null) || (tooltip.length() == 0))\r
- {\r
- fTooltipList.add(F_DEFAULT_TOOLTIP);\r
- } else\r
- {\r
- fTooltipList.add(tooltip);\r
- }\r
- }\r
-\r
- /**\r
- * @param configurationElement\r
- */\r
- private void processSplashElementIcon(IConfigurationElement configurationElement)\r
- {\r
- // Get attribute icon\r
- String iconImageFilePath = configurationElement.getAttribute(F_ELEMENT_ICON);\r
- // Abort if an icon attribute was not specified\r
- if ((iconImageFilePath == null) || (iconImageFilePath.length() == 0))\r
- {\r
- return;\r
- }\r
- // Create a corresponding image descriptor\r
- ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(configurationElement.getNamespaceIdentifier(),\r
- iconImageFilePath);\r
- // Abort if no corresponding image was found\r
- if (descriptor == null)\r
- {\r
- return;\r
- }\r
- // Create the image\r
- Image image = descriptor.createImage();\r
- // Abort if image creation failed\r
- if (image == null)\r
- {\r
- return;\r
- }\r
- // Abort if the image does not have dimensions of 50x50\r
- if ((image.getBounds().width != F_IMAGE_WIDTH) || (image.getBounds().height != F_IMAGE_HEIGHT))\r
- {\r
- // Dipose of the image\r
- image.dispose();\r
- return;\r
- }\r
- // Store the image and tooltip\r
- fImageList.add(image);\r
- }\r
-\r
- /**\r
- * \r
- */\r
- private void configureUISplash()\r
- {\r
- // Configure layout\r
- GridLayout layout = new GridLayout(1, true);\r
- getSplash().setLayout(layout);\r
- // Force shell to inherit the splash background\r
- getSplash().setBackgroundMode(SWT.INHERIT_DEFAULT);\r
- }\r
-\r
- /**\r
- * \r
- */\r
- private void doEventLoop()\r
- {\r
- Shell splash = getSplash();\r
- if (!splash.getDisplay().readAndDispatch())\r
- {\r
- splash.getDisplay().sleep();\r
- }\r
- }\r
-\r
- /*\r
- * (non-Javadoc)\r
- * \r
- * @see org.eclipse.ui.splash.AbstractSplashHandler#dispose()\r
- */\r
- @Override\r
- public void dispose()\r
- {\r
- super.dispose();\r
- // Check to see if any images were defined\r
- if ((fImageList == null) || fImageList.isEmpty())\r
- {\r
- return;\r
- }\r
- // Dispose of all the images\r
- Iterator<Image> iterator = fImageList.iterator();\r
- while (iterator.hasNext())\r
- {\r
- Image image = iterator.next();\r
- image.dispose();\r
- }\r
- }\r
-}\r
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>era.mi</name>
+ <name>mograsim.logic.core</name>
<comment></comment>
<projects>
</projects>
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=10
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=10
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
-formatter_profile=_ERA-MI
+formatter_profile=_MoGraSim
formatter_settings_version=16
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
-Bundle-Name: MI
-Bundle-SymbolicName: era.mi
+Bundle-Name: mograsim.logic.core
+Bundle-SymbolicName: mograsim.logic.core
Bundle-Version: 1.0.0.qualifier
-Export-Package: era.mi.logic,
- era.mi.logic.components,
- era.mi.logic.components.gates,
- era.mi.logic.tests,
- era.mi.logic.timeline,
- era.mi.logic.types,
- era.mi.logic.wires
+Export-Package: mograsim.logic.core,
+ mograsim.logic.core.components,
+ mograsim.logic.core.components.gates,
+ mograsim.logic.core.tests,
+ mograsim.logic.core.timeline,
+ mograsim.logic.core.types,
+ mograsim.logic.core.wires
Bundle-RequiredExecutionEnvironment: JavaSE-10
-Automatic-Module-Name: era.mi
+Automatic-Module-Name: mograsim.logic.core
+++ /dev/null
-package era.mi.logic;
-
-import java.util.Arrays;
-
-import era.mi.logic.types.Bit;
-
-public final class Util
-{
-
- @SuppressWarnings("unchecked")
- public static <T> T[] concat(T[]... arrays)
- {
- if (arrays.length == 0)
- throw new IllegalArgumentException("Cannot concatenate 0 arrays.");
-
- int length = 0;
- for (T[] array : arrays)
- length += array.length;
-
- T[] newArray = Arrays.copyOf(arrays[0], length);
- int appendIndex = arrays[0].length;
- for (int i = 1; i < arrays.length; i++)
- {
- System.arraycopy(arrays[i], 0, newArray, appendIndex, arrays[i].length);
- appendIndex += arrays[i].length;
- }
-
- return newArray;
- }
-
-// @SuppressWarnings("unchecked")
-// public static <T> T[][] split(T[] array, int... lengths)
-// {
-// //TODO: implement array split again; This version contains an illegal cast
-// int totalLength = 0;
-// for(int length : lengths)
-// totalLength += length;
-//
-// if(totalLength != array.length)
-// throw new IllegalArgumentException(); //TODO: add proper error message
-//
-// Object[][] newArray = new Object[lengths.length][];
-// int splitIndex = 0;
-// for(int i = 0; i < lengths.length; i++)
-// {
-// System.arraycopy(array, splitIndex, newArray, 0, lengths[i]);
-// splitIndex += lengths[i];
-// }
-//
-// return (T[][]) newArray;
-// }
-
- public static Bit[] and(Bit[] a, Bit[] b)
- {
- return binBitOp(a, b, Bit::and);
- }
-
- public static Bit[] or(Bit[] a, Bit[] b)
- {
- return binBitOp(a, b, Bit::or);
- }
-
- public static Bit[] xor(Bit[] a, Bit[] b)
- {
- return binBitOp(a, b, Bit::xor);
- }
-
- private static Bit[] binBitOp(Bit[] a, Bit[] b, BitOp op)
- {
- if (a.length != b.length)
- throw new IllegalArgumentException("Bit Arrays were not of equal length.");
- Bit[] out = new Bit[a.length];
- for (int i = 0; i < a.length; i++)
- {
- out[i] = op.execute(a[i], b[i]);
- }
- return out;
- }
-
- public static Bit[] not(Bit[] a)
- {
- Bit[] out = new Bit[a.length];
- for (int i = 0; i < a.length; i++)
- {
- out[i] = a[i].not();
- }
- return out;
- }
-
- /**
- * uses the {@link Bit#combineWith(Bit)} method, does not create a new array, the result is stored in the first array.
- *
- * @author Christian Femers
- */
- public static Bit[] combineInto(Bit[] dest, Bit[] addition)
- {
- if (dest.length != addition.length)
- throw new IllegalArgumentException("Bit Arrays were not of equal length.");
- for (int i = 0; i < addition.length; i++)
- {
- dest[i] = dest[i].join(addition[i]);
- }
- return dest;
- }
-
- interface BitOp
- {
- Bit execute(Bit a, Bit b);
- }
-}
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.BitVector;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.WireObserver;\r
-\r
-/**\r
- * A basic component that recomputes all outputs (with a delay), when it is updated.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
-public abstract class BasicComponent extends Component implements WireObserver\r
-{\r
- private int processTime;\r
-\r
- /**\r
- * \r
- * @param processTime Amount of time this component takes to update its outputs. Must be more than 0, otherwise 1 is assumed.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public BasicComponent(Timeline timeline, int processTime)\r
- {\r
- super(timeline);\r
- this.processTime = processTime > 0 ? processTime : 1;\r
- }\r
-\r
- @Override\r
- public void update(ReadEnd initiator, BitVector oldValues)\r
- {\r
- timeline.addEvent(e -> compute(), processTime);\r
- }\r
-\r
- protected abstract void compute();\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.Bit;\r
-import era.mi.logic.types.BitVector;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-public class BitDisplay extends BasicComponent\r
-{\r
- private final ReadEnd in;\r
- private BitVector displayedValue;\r
-\r
- public BitDisplay(Timeline timeline, ReadEnd in)\r
- {\r
- super(timeline, 1);\r
- this.in = in;\r
- in.addObserver(this);\r
- compute();\r
- }\r
-\r
- @Override\r
- protected void compute()\r
- {\r
- displayedValue = in.getValues();\r
- }\r
-\r
- public BitVector getDisplayedValue()\r
- {\r
- return displayedValue;\r
- }\r
-\r
- public boolean isDisplaying(Bit... values)\r
- {\r
- return displayedValue.equals(BitVector.of(values));\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of(in);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of();\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.timeline.TimelineEvent;\r
-import era.mi.logic.timeline.TimelineEventHandler;\r
-import era.mi.logic.types.Bit;\r
-import era.mi.logic.wires.Wire;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-public class Clock extends Component implements TimelineEventHandler\r
-{\r
- private boolean toggle = false;\r
- private ReadWriteEnd out;\r
- private int delta;\r
-\r
- /**\r
- * \r
- * @param out {@link Wire} the clock's impulses are fed into\r
- * @param delta ticks between rising and falling edge\r
- */\r
- public Clock(Timeline timeline, ReadWriteEnd out, int delta)\r
- {\r
- super(timeline);\r
- this.delta = delta;\r
- this.out = out;\r
- addToTimeline();\r
- }\r
-\r
- @Override\r
- public void handle(TimelineEvent e)\r
- {\r
- addToTimeline();\r
- out.feedSignals(toggle ? Bit.ONE : Bit.ZERO);\r
- toggle = !toggle;\r
- }\r
-\r
- public ReadWriteEnd getOut()\r
- {\r
- return out;\r
- }\r
-\r
- private void addToTimeline()\r
- {\r
- timeline.addEvent(this, delta);\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of();\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(out);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-public abstract class Component\r
-{\r
- protected Timeline timeline;\r
-\r
- public Component(Timeline timeline)\r
- {\r
- this.timeline = timeline;\r
- }\r
-\r
- /**\r
- * Returns immutable list of all inputs to the {@link Component} (including e.g. the select bits to a MUX). Intended for visualization\r
- * in the UI.\r
- */\r
- public abstract List<ReadEnd> getAllInputs();\r
-\r
- /**\r
- * Returns immutable list of all outputs to the {@link Component}. Intended for visualization in the UI.\r
- */\r
- public abstract List<ReadWriteEnd> getAllOutputs();\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.BitVector;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-import era.mi.logic.wires.WireObserver;\r
-\r
-public class Connector extends Component implements WireObserver\r
-{\r
- private boolean connected;\r
- private final ReadWriteEnd a;\r
- private final ReadWriteEnd b;\r
-\r
- public Connector(Timeline timeline, ReadWriteEnd a, ReadWriteEnd b)\r
- {\r
- super(timeline);\r
- if (a.length() != b.length())\r
- throw new IllegalArgumentException(String.format("WireArray width does not match: %d, %d", a.length(), b.length()));\r
- this.a = a;\r
- this.b = b;\r
- a.addObserver(this);\r
- b.addObserver(this);\r
- }\r
-\r
- public void connect()\r
- {\r
- connected = true;\r
- update(a);\r
- update(b);\r
- }\r
-\r
- public void disconnect()\r
- {\r
- connected = false;\r
- a.clearSignals();\r
- b.clearSignals();\r
- }\r
-\r
- public void setConnection(boolean connected)\r
- {\r
- if (connected)\r
- connect();\r
- else\r
- disconnect();\r
- }\r
-\r
- @Override\r
- public void update(ReadEnd initiator, BitVector oldValues)\r
- {\r
- if (connected)\r
- timeline.addEvent(e -> update(initiator), 1);\r
- }\r
-\r
- private void update(ReadEnd initiator)\r
- {\r
- if (initiator == a)\r
- b.feedSignals(a.wireValuesExcludingMe());\r
- else\r
- a.feedSignals(b.wireValuesExcludingMe());\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of(a, b);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(a, b);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.wires.Wire;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-/**\r
- * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the\r
- * output.\r
- * \r
- * @author Fabian Stemmler\r
- *\r
- */\r
-public class Demux extends BasicComponent\r
-{\r
- private final ReadEnd select, in;\r
- private final ReadWriteEnd[] outputs;\r
- private final int outputSize;\r
- private int selected = -1;\r
-\r
- /**\r
- * Output {@link Wire}s and in must be of uniform length\r
- * \r
- * @param in Must be of uniform length with all outputs.\r
- * @param select Indexes the output array to which the input is mapped. Must have enough bits to index all outputs.\r
- * @param outputs One of these outputs receives the input signal, depending on the select bits\r
- */\r
- public Demux(Timeline timeline, int processTime, ReadEnd in, ReadEnd select, ReadWriteEnd... outputs)\r
- {\r
- super(timeline, processTime);\r
- outputSize = in.length();\r
-\r
- this.in = in;\r
- this.outputs = outputs;\r
- for (int i = 0; i < this.outputs.length; i++)\r
- {\r
- if (outputs[i].length() != outputSize)\r
- throw new IllegalArgumentException("All DEMUX wire arrays must be of uniform length!");\r
- this.outputs[i] = outputs[i];\r
- }\r
-\r
- this.select = select;\r
- select.addObserver(this);\r
-\r
- int maxInputs = 1 << select.length();\r
- if (this.outputs.length > maxInputs)\r
- throw new IllegalArgumentException("There are more outputs (" + this.outputs.length + ") to the DEMUX than supported by "\r
- + select.length() + " select bits (" + maxInputs + ").");\r
- in.addObserver(this);\r
- }\r
-\r
- @Override\r
- public void compute()\r
- {\r
- int selectValue = select.hasNumericValue() ? (int) select.getUnsignedValue() : -1;\r
- if (selectValue >= outputs.length)\r
- selectValue = -1;\r
-\r
- if (selected != selectValue && selected != -1)\r
- outputs[selected].clearSignals();\r
-\r
- selected = selectValue;\r
-\r
- if (selectValue != -1)\r
- outputs[selectValue].feedSignals(in.getValues());\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of(in, select);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(outputs);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.Bit;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-/**\r
- * This class models a simple on/off (ONE/ZERO) switch for user interaction.\r
- *\r
- * @author Christian Femers\r
- *\r
- */\r
-public class ManualSwitch extends Component\r
-{\r
- private ReadWriteEnd output;\r
- private boolean isOn;\r
-\r
- public ManualSwitch(Timeline timeline, ReadWriteEnd output)\r
- {\r
- super(timeline);\r
- if (output.length() != 1)\r
- throw new IllegalArgumentException("Switch output can be only a single wire");\r
- this.output = output;\r
- }\r
-\r
- public void switchOn()\r
- {\r
- setState(true);\r
- }\r
-\r
- public void switchOff()\r
- {\r
- setState(false);\r
- }\r
-\r
- public void toggle()\r
- {\r
- setState(!isOn);\r
- }\r
-\r
- public void setState(boolean isOn)\r
- {\r
- if (this.isOn == isOn)\r
- return;\r
- this.isOn = isOn;\r
- output.feedSignals(getValue());\r
- }\r
-\r
- public boolean isOn()\r
- {\r
- return isOn;\r
- }\r
-\r
- public Bit getValue()\r
- {\r
- return isOn ? Bit.ONE : Bit.ZERO;\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of();\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(output);\r
- }\r
-\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.BitVector;\r
-import era.mi.logic.wires.Wire;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-import era.mi.logic.wires.WireObserver;\r
-\r
-public class Merger extends Component implements WireObserver\r
-{\r
- private ReadWriteEnd out;\r
- private ReadEnd[] inputs;\r
- private int[] beginningIndex;\r
-\r
- /**\r
- * \r
- * @param union The output of merging n {@link Wire}s into one. Must have length = a1.length() + a2.length() + ... + an.length().\r
- * @param inputs The inputs to be merged into the union\r
- */\r
- public Merger(Timeline timeline, ReadWriteEnd union, ReadEnd... inputs)\r
- {\r
- super(timeline);\r
- this.inputs = inputs;\r
- this.out = union;\r
- this.beginningIndex = new int[inputs.length];\r
-\r
- int length = 0;\r
- for (int i = 0; i < inputs.length; i++)\r
- {\r
- beginningIndex[i] = length;\r
- length += inputs[i].length();\r
- inputs[i].addObserver(this);\r
- }\r
-\r
- if (length != union.length())\r
- throw new IllegalArgumentException(\r
- "The output of merging n WireArrays into one must have length = a1.length() + a2.length() + ... + an.length().");\r
- }\r
-\r
- public ReadEnd getInput(int index)\r
- {\r
- return inputs[index];\r
- }\r
-\r
- public ReadEnd getUnion()\r
- {\r
- return out;\r
- }\r
-\r
- @Override\r
- public void update(ReadEnd initiator, BitVector oldValues)\r
- {\r
- int index = find(initiator);\r
- int beginning = beginningIndex[index];\r
- out.feedSignals(beginning, inputs[index].getValues());\r
- }\r
-\r
- private int find(ReadEnd r)\r
- {\r
- for (int i = 0; i < inputs.length; i++)\r
- if (inputs[i] == r)\r
- return i;\r
- return -1;\r
- }\r
-\r
- public ReadEnd[] getInputs()\r
- {\r
- return inputs.clone();\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of(inputs);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(out);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collections;\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.wires.Wire;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-/**\r
- * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the\r
- * output.\r
- * \r
- * @author Fabian Stemmler\r
- *\r
- */\r
-public class Mux extends BasicComponent\r
-{\r
- private ReadEnd select;\r
- private ReadWriteEnd out;\r
- private ReadEnd[] inputs;\r
- private final int outputSize;\r
-\r
- /**\r
- * Input {@link Wire}s and out must be of uniform length\r
- * \r
- * @param out Must be of uniform length with all inputs.\r
- * @param select Indexes the input array which is to be mapped to the output. Must have enough bits to index all inputs.\r
- * @param inputs One of these inputs is mapped to the output, depending on the select bits\r
- */\r
- public Mux(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd select, ReadEnd... inputs)\r
- {\r
- super(timeline, processTime);\r
- outputSize = out.length();\r
-\r
- this.inputs = inputs.clone();\r
- for (int i = 0; i < this.inputs.length; i++)\r
- {\r
- if (inputs[i].length() != outputSize)\r
- throw new IllegalArgumentException("All MUX wire arrays must be of uniform length!");\r
- inputs[i].addObserver(this);\r
- }\r
-\r
- this.select = select;\r
- select.addObserver(this);\r
-\r
- int maxInputs = 1 << select.length();\r
- if (this.inputs.length > maxInputs)\r
- throw new IllegalArgumentException("There are more inputs (" + this.inputs.length + ") to the MUX than supported by "\r
- + select.length() + " select bits (" + maxInputs + ").");\r
-\r
- this.out = out;\r
- }\r
-\r
- public ReadEnd getOut()\r
- {\r
- return out;\r
- }\r
-\r
- public ReadEnd getSelect()\r
- {\r
- return select;\r
- }\r
-\r
- @Override\r
- public void compute()\r
- {\r
- int selectValue;\r
- if (!select.hasNumericValue() || (selectValue = (int) select.getUnsignedValue()) >= inputs.length)\r
- {\r
- out.clearSignals();\r
- return;\r
- }\r
-\r
- ReadEnd active = inputs[selectValue];\r
- out.feedSignals(active.getValues());\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- ArrayList<ReadEnd> wires = new ArrayList<ReadEnd>(Arrays.asList(inputs));\r
- wires.add(select);\r
- return Collections.unmodifiableList(wires);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(out);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.BitVector;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-import era.mi.logic.wires.WireObserver;\r
-\r
-public class Splitter extends Component implements WireObserver\r
-{\r
- private ReadEnd input;\r
- private ReadWriteEnd[] outputs;\r
-\r
- public Splitter(Timeline timeline, ReadEnd input, ReadWriteEnd... outputs)\r
- {\r
- super(timeline);\r
- this.input = input;\r
- this.outputs = outputs;\r
- input.addObserver(this);\r
- int length = 0;\r
- for (ReadEnd out : outputs)\r
- length += out.length();\r
-\r
- if (input.length() != length)\r
- throw new IllegalArgumentException(\r
- "The input of splitting one into n WireArrays must have length = a1.length() + a2.length() + ... + an.length().");\r
- }\r
-\r
- protected void compute()\r
- {\r
- BitVector inputBits = input.getValues();\r
- int startIndex = 0;\r
- for (int i = 0; i < outputs.length; i++)\r
- {\r
- outputs[i].feedSignals(inputBits.subVector(startIndex, startIndex + outputs[i].length()));\r
- startIndex += outputs[i].length();\r
- }\r
- }\r
-\r
- @Override\r
- public void update(ReadEnd initiator, BitVector oldValues)\r
- {\r
- compute();\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of(input);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(outputs);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.Bit;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-public class TriStateBuffer extends BasicComponent\r
-{\r
- ReadEnd in, enable;\r
- ReadWriteEnd out;\r
-\r
- public TriStateBuffer(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out, ReadEnd enable)\r
- {\r
- super(timeline, processTime);\r
- if (in.length() != out.length())\r
- throw new IllegalArgumentException(\r
- "Tri-state output must have the same amount of bits as the input. Input: " + in.length() + " Output: " + out.length());\r
- if (enable.length() != 1)\r
- throw new IllegalArgumentException("Tri-state enable must have exactly one bit, not " + enable.length() + ".");\r
- this.in = in;\r
- in.addObserver(this);\r
- this.enable = enable;\r
- enable.addObserver(this);\r
- this.out = out;\r
- }\r
-\r
- @Override\r
- protected void compute()\r
- {\r
- if (enable.getValue() == Bit.ONE)\r
- out.feedSignals(in.getValues());\r
- else\r
- out.clearSignals();\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of(in, enable);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(out);\r
- }\r
-\r
-}\r
+++ /dev/null
-package era.mi.logic.components.gates;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.BitVector.BitVectorMutator;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-public class AndGate extends MultiInputGate\r
-{\r
- public AndGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)\r
- {\r
- super(timeline, processTime, BitVectorMutator::and, out, in);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components.gates;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.components.BasicComponent;\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.BitVector.BitVectorMutator;\r
-import era.mi.logic.types.MutationOperation;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-public abstract class MultiInputGate extends BasicComponent\r
-{\r
- protected ReadEnd[] in;\r
- protected ReadWriteEnd out;\r
- protected final int length;\r
- protected MutationOperation op;\r
-\r
- protected MultiInputGate(Timeline timeline, int processTime, MutationOperation op, ReadWriteEnd out, ReadEnd... in)\r
- {\r
- super(timeline, processTime);\r
- this.op = op;\r
- length = out.length();\r
- this.in = in.clone();\r
- if (in.length < 1)\r
- throw new IllegalArgumentException(String.format("Cannot create gate with %d wires.", in.length));\r
- for (ReadEnd w : in)\r
- {\r
- if (w.length() != length)\r
- throw new IllegalArgumentException("All wires connected to the gate must be of uniform length.");\r
- w.addObserver(this);\r
- }\r
- this.out = out;\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of(in);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(out);\r
- }\r
-\r
- @Override\r
- protected void compute()\r
- {\r
- BitVectorMutator mutator = BitVectorMutator.empty();\r
- for (ReadEnd w : in)\r
- op.apply(mutator, w.getValues());\r
- out.feedSignals(mutator.get());\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components.gates;\r
-\r
-import java.util.List;\r
-\r
-import era.mi.logic.components.BasicComponent;\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-public class NotGate extends BasicComponent\r
-{\r
- private ReadEnd in;\r
- private ReadWriteEnd out;\r
-\r
- public NotGate(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out)\r
- {\r
- super(timeline, processTime);\r
- this.in = in;\r
- in.addObserver(this);\r
- this.out = out;\r
- }\r
-\r
- @Override\r
- protected void compute()\r
- {\r
- out.feedSignals(in.getValues().not());\r
- }\r
-\r
- public ReadEnd getIn()\r
- {\r
- return in;\r
- }\r
-\r
- public ReadEnd getOut()\r
- {\r
- return out;\r
- }\r
-\r
- @Override\r
- public List<ReadEnd> getAllInputs()\r
- {\r
- return List.of(in);\r
- }\r
-\r
- @Override\r
- public List<ReadWriteEnd> getAllOutputs()\r
- {\r
- return List.of(out);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components.gates;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.BitVector.BitVectorMutator;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-public class OrGate extends MultiInputGate\r
-{\r
- public OrGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)\r
- {\r
- super(timeline, processTime, BitVectorMutator::or, out, in);\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.components.gates;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.BitVector.BitVectorMutator;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-/**\r
- * Outputs 1 when the number of 1 inputs is odd.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
-public class XorGate extends MultiInputGate\r
-{\r
- public XorGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)\r
- {\r
- super(timeline, processTime, BitVectorMutator::xor, out, in);\r
- }\r
-\r
-}\r
+++ /dev/null
-package era.mi.logic.tests;\r
-\r
-import static org.junit.Assert.assertTrue;\r
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;\r
-import static org.junit.jupiter.api.Assertions.assertEquals;\r
-import static org.junit.jupiter.api.Assertions.fail;\r
-\r
-import java.util.function.LongConsumer;\r
-\r
-import org.junit.jupiter.api.Test;\r
-\r
-import era.mi.logic.components.Connector;\r
-import era.mi.logic.components.Demux;\r
-import era.mi.logic.components.Merger;\r
-import era.mi.logic.components.Mux;\r
-import era.mi.logic.components.Splitter;\r
-import era.mi.logic.components.TriStateBuffer;\r
-import era.mi.logic.components.gates.AndGate;\r
-import era.mi.logic.components.gates.NotGate;\r
-import era.mi.logic.components.gates.OrGate;\r
-import era.mi.logic.components.gates.XorGate;\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.Bit;\r
-import era.mi.logic.types.BitVector;\r
-import era.mi.logic.wires.Wire;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-import era.mi.logic.wires.Wire.ReadWriteEnd;\r
-\r
-class ComponentTest\r
-{\r
- private Timeline t = new Timeline(11);\r
-\r
- @Test\r
- void circuitExampleTest()\r
- {\r
- Wire a = new Wire(t, 1, 1), b = new Wire(t, 1, 1), c = new Wire(t, 1, 10), d = new Wire(t, 2, 1), e = new Wire(t, 1, 1),\r
- f = new Wire(t, 1, 1), g = new Wire(t, 1, 1), h = new Wire(t, 2, 1), i = new Wire(t, 2, 1), j = new Wire(t, 1, 1),\r
- k = new Wire(t, 1, 1);\r
- new AndGate(t, 1, f.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());\r
- new NotGate(t, 1, f.createReadOnlyEnd(), g.createReadWriteEnd());\r
- new Merger(t, h.createReadWriteEnd(), c.createReadOnlyEnd(), g.createReadOnlyEnd());\r
- new Mux(t, 1, i.createReadWriteEnd(), e.createReadOnlyEnd(), h.createReadOnlyEnd(), d.createReadOnlyEnd());\r
- new Splitter(t, i.createReadOnlyEnd(), k.createReadWriteEnd(), j.createReadWriteEnd());\r
-\r
- a.createReadWriteEnd().feedSignals(Bit.ZERO);\r
- b.createReadWriteEnd().feedSignals(Bit.ONE);\r
- c.createReadWriteEnd().feedSignals(Bit.ZERO);\r
- d.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE);\r
- e.createReadWriteEnd().feedSignals(Bit.ZERO);\r
-\r
- t.executeAll();\r
-\r
- assertEquals(Bit.ONE, j.getValue());\r
- assertEquals(Bit.ZERO, k.getValue());\r
- }\r
-\r
- @Test\r
- void splitterTest()\r
- {\r
- t.reset();\r
- Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), in = new Wire(t, 8, 1);\r
- in.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
- new Splitter(t, in.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(), c.createReadWriteEnd());\r
-\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(a.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO);\r
- assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO);\r
- assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE);\r
- }\r
-\r
- @Test\r
- void mergerTest()\r
- {\r
- t.reset();\r
- Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), out = new Wire(t, 8, 1);\r
- a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO);\r
- b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO);\r
- c.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);\r
-\r
- new Merger(t, out.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());\r
-\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
- }\r
-\r
- @Test\r
- void triStateBufferTest()\r
- {\r
- Wire a = new Wire(t, 1, 1), b = new Wire(t, 1, 1), en = new Wire(t, 1, 1), notEn = new Wire(t, 1, 1);\r
- new NotGate(t, 1, en.createReadOnlyEnd(), notEn.createReadWriteEnd());\r
- new TriStateBuffer(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd(), en.createReadOnlyEnd());\r
- new TriStateBuffer(t, 1, b.createReadOnlyEnd(), a.createReadWriteEnd(), notEn.createReadOnlyEnd());\r
-\r
- ReadWriteEnd enI = en.createReadWriteEnd(), aI = a.createReadWriteEnd(), bI = b.createReadWriteEnd();\r
- enI.feedSignals(Bit.ONE);\r
- aI.feedSignals(Bit.ONE);\r
- bI.feedSignals(Bit.Z);\r
-\r
- t.executeAll();\r
-\r
- assertEquals(Bit.ONE, b.getValue());\r
-\r
- bI.feedSignals(Bit.ZERO);\r
-\r
- t.executeAll();\r
-\r
- assertEquals(Bit.X, b.getValue());\r
- assertEquals(Bit.ONE, a.getValue());\r
-\r
- aI.clearSignals();\r
- enI.feedSignals(Bit.ZERO);\r
-\r
- t.executeAll();\r
-\r
- assertEquals(Bit.ZERO, a.getValue());\r
-\r
- }\r
-\r
- @Test\r
- void muxTest()\r
- {\r
- t.reset();\r
- Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), out = new Wire(t, 4, 1);\r
- ReadWriteEnd selectIn = select.createReadWriteEnd();\r
-\r
- selectIn.feedSignals(Bit.ZERO, Bit.ZERO);\r
- a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
- c.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
-\r
- new Mux(t, 1, out.createReadWriteEnd(), select.createReadOnlyEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(),\r
- c.createReadOnlyEnd());\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(out.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
- selectIn.feedSignals(Bit.ZERO, Bit.ONE);\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
-\r
- selectIn.feedSignals(Bit.ONE, Bit.ONE);\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(out.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);\r
-\r
- }\r
-\r
- @Test\r
- void demuxTest()\r
- {\r
- t.reset();\r
- Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), in = new Wire(t, 4, 1);\r
- ReadWriteEnd selectIn = select.createReadWriteEnd();\r
-\r
- selectIn.feedSignals(Bit.ZERO, Bit.ZERO);\r
- in.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
-\r
- new Demux(t, 1, in.createReadOnlyEnd(), select.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(),\r
- c.createReadWriteEnd());\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(a.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
- assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);\r
- assertBitArrayEquals(c.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);\r
- selectIn.feedSignals(Bit.ZERO, Bit.ONE);\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);\r
- assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);\r
- assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
-\r
- selectIn.feedSignals(Bit.ONE, Bit.ONE);\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);\r
- assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);\r
- assertBitArrayEquals(c.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);\r
-\r
- }\r
-\r
- @Test\r
- void andTest()\r
- {\r
- t.reset();\r
- Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);\r
- new AndGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());\r
- a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);\r
- b.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
-\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(c.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ZERO);\r
- }\r
-\r
- @Test\r
- void orTest()\r
- {\r
- t.reset();\r
- Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);\r
- new OrGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());\r
- a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);\r
- b.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
-\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ONE);\r
- }\r
-\r
- @Test\r
- void xorTest()\r
- {\r
- t.reset();\r
- Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2), c = new Wire(t, 3, 1), d = new Wire(t, 3, 1);\r
- new XorGate(t, 1, d.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());\r
- a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);\r
- b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);\r
- c.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);\r
-\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(d.getValues(), Bit.ZERO, Bit.ONE, Bit.ONE);\r
- }\r
-\r
- @Test\r
- void notTest()\r
- {\r
- t.reset();\r
- Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2);\r
- new NotGate(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd());\r
- a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);\r
-\r
- t.executeAll();\r
-\r
- assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO, Bit.ZERO);\r
- }\r
-\r
- @Test\r
- void rsLatchCircuitTest()\r
- {\r
- t.reset();\r
- Wire r = new Wire(t, 1, 1), s = new Wire(t, 1, 1), t1 = new Wire(t, 1, 15), t2 = new Wire(t, 1, 1), q = new Wire(t, 1, 1),\r
- nq = new Wire(t, 1, 1);\r
-\r
- new OrGate(t, 1, t2.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());\r
- new OrGate(t, 1, t1.createReadWriteEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());\r
- new NotGate(t, 1, t2.createReadOnlyEnd(), q.createReadWriteEnd());\r
- new NotGate(t, 1, t1.createReadOnlyEnd(), nq.createReadWriteEnd());\r
-\r
- ReadWriteEnd sIn = s.createReadWriteEnd(), rIn = r.createReadWriteEnd();\r
-\r
- sIn.feedSignals(Bit.ONE);\r
- rIn.feedSignals(Bit.ZERO);\r
-\r
- t.executeAll();\r
-\r
- assertEquals(Bit.ONE, q.getValue());\r
- assertEquals(Bit.ZERO, nq.getValue());\r
-\r
- sIn.feedSignals(Bit.ZERO);\r
-\r
- t.executeAll();\r
- assertEquals(Bit.ONE, q.getValue());\r
- assertEquals(Bit.ZERO, nq.getValue());\r
-\r
- rIn.feedSignals(Bit.ONE);\r
-\r
- t.executeAll();\r
-\r
- assertEquals(Bit.ZERO, q.getValue());\r
- assertEquals(Bit.ONE, nq.getValue());\r
- }\r
-\r
- @Test\r
- void numericValueTest()\r
- {\r
- t.reset();\r
-\r
- Wire a = new Wire(t, 4, 1);\r
- a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE);\r
-\r
- t.executeAll();\r
-\r
- assertEquals(15, a.getUnsignedValue());\r
- assertEquals(-1, a.getSignedValue());\r
- }\r
-\r
- boolean flag = false;\r
-\r
- @Test\r
- void simpleTimelineTest()\r
- {\r
- Timeline t = new Timeline(3);\r
- flag = false;\r
- t.addEvent((e) ->\r
- {\r
- if (!flag)\r
- fail();\r
- flag = false;\r
- }, 15);\r
- t.addEvent((e) ->\r
- {\r
- if (flag)\r
- fail();\r
- flag = true;\r
- }, 10);\r
- t.addEvent((e) ->\r
- {\r
- if (flag)\r
- fail();\r
- flag = true;\r
- }, 20);\r
- t.addEvent((e) ->\r
- {\r
- fail("Only supposed to execute until timestamp 20, not 25");\r
- }, 25);\r
-\r
- t.executeUntil(t.laterThan(20), 100);\r
-\r
- if (!flag)\r
- fail();\r
- }\r
-\r
- @Test\r
- void multipleInputs()\r
- {\r
- t.reset();\r
- Wire w = new Wire(t, 2, 1);\r
- ReadWriteEnd wI1 = w.createReadWriteEnd(), wI2 = w.createReadWriteEnd();\r
- wI1.feedSignals(Bit.ONE, Bit.Z);\r
- wI2.feedSignals(Bit.Z, Bit.X);\r
- t.executeAll();\r
- assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.X);\r
-\r
- wI2.feedSignals(Bit.ZERO, Bit.Z);\r
- t.executeAll();\r
- assertBitArrayEquals(w.getValues(), Bit.X, Bit.Z);\r
-\r
- wI2.feedSignals(Bit.Z, Bit.Z);\r
- t.executeAll();\r
- assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);\r
-\r
- wI2.feedSignals(Bit.ONE, Bit.Z);\r
- ReadEnd rE = w.createReadOnlyEnd();\r
- rE.addObserver((i, oldValues) -> fail("WireEnd notified observer, although value did not change."));\r
- t.executeAll();\r
- rE.close();\r
- wI1.feedSignals(Bit.X, Bit.X);\r
- t.executeAll();\r
- wI1.addObserver((i, oldValues) -> fail("WireEnd notified observer, although it was closed."));\r
- wI1.close();\r
- assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);\r
- }\r
-\r
- @Test\r
- void wireConnections()\r
- {\r
- // Nur ein Experiment, was über mehrere 'passive' Bausteine hinweg passieren würde\r
-\r
- t.reset();\r
-\r
- Wire a = new Wire(t, 1, 2);\r
- Wire b = new Wire(t, 1, 2);\r
- Wire c = new Wire(t, 1, 2);\r
- ReadWriteEnd aI = a.createReadWriteEnd();\r
- ReadWriteEnd bI = b.createReadWriteEnd();\r
- ReadWriteEnd cI = c.createReadWriteEnd();\r
-\r
- TestBitDisplay test = new TestBitDisplay(t, c.createReadOnlyEnd());\r
- TestBitDisplay test2 = new TestBitDisplay(t, a.createReadOnlyEnd());\r
- LongConsumer print = time -> System.out.format("Time %2d\n a: %s\n b: %s\n c: %s\n", time, a, b, c);\r
-\r
- cI.feedSignals(Bit.ONE);\r
- test.assertAfterSimulationIs(print, Bit.ONE);\r
-\r
- cI.feedSignals(Bit.X);\r
- test.assertAfterSimulationIs(print, Bit.X);\r
-\r
- cI.feedSignals(Bit.X);\r
- cI.feedSignals(Bit.Z);\r
- test.assertAfterSimulationIs(print, Bit.Z);\r
-\r
- new Connector(t, b.createReadWriteEnd(), c.createReadWriteEnd()).connect();\r
- test.assertAfterSimulationIs(print, Bit.Z);\r
- System.err.println("ONE");\r
- bI.feedSignals(Bit.ONE);\r
- test.assertAfterSimulationIs(print, Bit.ONE);\r
- System.err.println("ZERO");\r
- bI.feedSignals(Bit.ZERO);\r
- test.assertAfterSimulationIs(print, Bit.ZERO);\r
- System.err.println("Z");\r
- bI.feedSignals(Bit.Z);\r
- test.assertAfterSimulationIs(print, Bit.Z);\r
-\r
- new Connector(t, a.createReadWriteEnd(), b.createReadWriteEnd()).connect();\r
- System.err.println("Z 2");\r
- aI.feedSignals(Bit.Z);\r
- test.assertAfterSimulationIs(print, Bit.Z);\r
- test2.assertAfterSimulationIs(Bit.Z);\r
- System.err.println("ONE 2");\r
- aI.feedSignals(Bit.ONE);\r
- test.assertAfterSimulationIs(print, Bit.ONE);\r
- test2.assertAfterSimulationIs(Bit.ONE);\r
- System.err.println("ZERO 2");\r
- aI.feedSignals(Bit.ZERO);\r
- test.assertAfterSimulationIs(print, Bit.ZERO);\r
- test2.assertAfterSimulationIs(Bit.ZERO);\r
- System.err.println("Z 2 II");\r
- aI.feedSignals(Bit.Z);\r
- test.assertAfterSimulationIs(print, Bit.Z);\r
- test2.assertAfterSimulationIs(Bit.Z);\r
-\r
- System.err.println("No Conflict yet");\r
- bI.feedSignals(Bit.ONE);\r
- test.assertAfterSimulationIs(print, Bit.ONE);\r
- test2.assertAfterSimulationIs(Bit.ONE);\r
- aI.feedSignals(Bit.ONE);\r
- test.assertAfterSimulationIs(print, Bit.ONE);\r
- test2.assertAfterSimulationIs(Bit.ONE);\r
- System.err.println("Conflict");\r
- aI.feedSignals(Bit.ZERO);\r
- test.assertAfterSimulationIs(print, Bit.X);\r
- test2.assertAfterSimulationIs(Bit.X);\r
- aI.feedSignals(Bit.ONE);\r
- test.assertAfterSimulationIs(print, Bit.ONE);\r
- test2.assertAfterSimulationIs(Bit.ONE);\r
- }\r
-\r
- private static void assertBitArrayEquals(BitVector actual, Bit... expected)\r
- {\r
- assertArrayEquals(expected, actual.getBits());\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.tests;\r
-\r
-import java.awt.Color;\r
-import java.awt.Graphics;\r
-import java.awt.Graphics2D;\r
-import java.awt.Rectangle;\r
-import java.awt.RenderingHints;\r
-import java.awt.event.MouseEvent;\r
-import java.awt.event.MouseListener;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-import java.util.Map.Entry;\r
-\r
-import javax.swing.JFrame;\r
-import javax.swing.JPanel;\r
-import javax.swing.WindowConstants;\r
-\r
-import era.mi.logic.components.ManualSwitch;\r
-import era.mi.logic.components.gates.NotGate;\r
-import era.mi.logic.components.gates.OrGate;\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.timeline.Timeline.ExecutionResult;\r
-import era.mi.logic.wires.Wire;\r
-\r
-public class GUITest extends JPanel\r
-{\r
-\r
- private static final long serialVersionUID = 1L;\r
-\r
- private static final int WIRE_DELAY = 40;\r
- private static final int OR_DELAY = 100;\r
- private static final int NOT_DELAY = 100;\r
-\r
- private Timeline t = new Timeline(11);\r
-\r
- Wire r = new Wire(t, 1, WIRE_DELAY);\r
- Wire s = new Wire(t, 1, WIRE_DELAY);\r
- Wire t1 = new Wire(t, 1, WIRE_DELAY);\r
- Wire t2 = new Wire(t, 1, WIRE_DELAY);\r
- Wire q = new Wire(t, 1, WIRE_DELAY);\r
- Wire nq = new Wire(t, 1, WIRE_DELAY);\r
-\r
- ManualSwitch rIn = new ManualSwitch(t, r.createReadWriteEnd());\r
- ManualSwitch sIn = new ManualSwitch(t, s.createReadWriteEnd());\r
-\r
- OrGate or1 = new OrGate(t, OR_DELAY, t2.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());\r
- OrGate or2 = new OrGate(t, OR_DELAY, t1.createReadWriteEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());\r
- NotGate not1 = new NotGate(t, NOT_DELAY, t2.createReadOnlyEnd(), q.createReadWriteEnd());\r
- NotGate not2 = new NotGate(t, NOT_DELAY, t1.createReadOnlyEnd(), nq.createReadWriteEnd());\r
-\r
- Map<ManualSwitch, Rectangle> switchMap = new HashMap<>();\r
-\r
- int height;\r
- int width;\r
- boolean sizeChanged;\r
-\r
- public GUITest()\r
- {\r
- addMouseListener(new MouseListener()\r
- {\r
-\r
- @Override\r
- public void mouseReleased(MouseEvent e)\r
- {\r
- for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())\r
- {\r
- if (dim.getValue().contains(e.getPoint()))\r
- {\r
- dim.getKey().switchOff();\r
- repaint();\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void mousePressed(MouseEvent e)\r
- {\r
- for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())\r
- {\r
- if (dim.getValue().contains(e.getPoint()))\r
- {\r
- dim.getKey().switchOn();\r
- repaint();\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseExited(MouseEvent e)\r
- {\r
- // none\r
- }\r
-\r
- @Override\r
- public void mouseEntered(MouseEvent e)\r
- {\r
- // none\r
- }\r
-\r
- @Override\r
- public void mouseClicked(MouseEvent e)\r
- {\r
- // If you want toggle buttons, use this code instead\r
-// for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet()) {\r
-// if (dim.getValue().contains(e.getPoint())) {\r
-// dim.getKey().toggle();\r
-// repaint();\r
-// }\r
-// }\r
- }\r
- });\r
- }\r
-\r
- public Timeline getTimeline()\r
- {\r
- return t;\r
- };\r
-\r
- @Override\r
- public void paint(Graphics some_g)\r
- {\r
- super.paint(some_g);\r
- Graphics2D g = ((Graphics2D) some_g);\r
- g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);\r
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
- g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);\r
-\r
- checkSizeChange();\r
- adaptFont(g);\r
-\r
- drawWire(g, r, "r", 2, 9, 4, 9);\r
-\r
- drawWire(g, s, "s", 2, 3, 4, 3);\r
-\r
- drawWire(g, t2, "t2", 5, 8.5, 6, 8.5);\r
-\r
- drawWire(g, t1, "t1", 5, 3.5, 6, 3.5);\r
-\r
- drawWire(g, q, "q", 7, 8.5, 9, 8.5);\r
-\r
- drawWire(g, nq, "nq", 7, 3.5, 9, 3.5);\r
-\r
- drawWire(g, q, "", 7.5, 8.5, 7.5, 7.5);\r
- drawWire(g, q, "", 7.5, 7.5, 3, 4.5);\r
- drawWire(g, q, "", 3, 4.5, 3, 4);\r
- drawWire(g, q, "q", 3, 4, 4, 4);\r
-\r
- drawWire(g, nq, "", 7.5, 3.5, 7.5, 4.5);\r
- drawWire(g, nq, "", 7.5, 4.5, 3, 7.5);\r
- drawWire(g, nq, "", 3, 7.5, 3, 8);\r
- drawWire(g, nq, "nq", 3, 8, 4, 8);\r
-\r
- drawSquare(g, 4, 8, "OR");\r
- drawSquare(g, 4, 3, "OR");\r
-\r
- drawSquare(g, 6, 8, "NOT");\r
- drawSquare(g, 6, 3, "NOT");\r
-\r
- drawSwitch(g, rIn, "Switch R", 0.5, 8.25, 2, 9.75);\r
- drawSwitch(g, sIn, "Switch S", 0.5, 2.25, 2, 3.75);\r
-\r
- drawString(g, "Hint: drag the cursor out of the pressed switch to keep it's state", 5, 0, 0.0, 1.0);\r
- }\r
-\r
- private void checkSizeChange()\r
- {\r
- sizeChanged = height != getHeight() || width != getWidth();\r
- if (sizeChanged)\r
- {\r
- height = getHeight();\r
- width = getWidth();\r
- }\r
- }\r
-\r
- private void adaptFont(Graphics g)\r
- {\r
- g.setFont(g.getFont().deriveFont(Math.min(height, width) / 40f));\r
- }\r
-\r
- private void drawString(Graphics g, String s, int x, int y, double anchorX, double anchorY)\r
- {\r
- int h = g.getFontMetrics().getAscent();\r
- int w = g.getFontMetrics().stringWidth(s);\r
- g.drawString(s, x - (int) (w * anchorX), y + (int) (h * anchorY));\r
- }\r
-\r
- private void drawWire(Graphics g, Wire wa, String name, double x1, double y1, double x2, double y2)\r
- {\r
- setTo(g, wa);\r
- g.drawLine(gX(x1), gY(y1), gX(x2), gY(y2));\r
- drawString(g, name, (gX(x1) + gX(x2)) / 2, (gY(y1) + gY(y2)) / 2 - 5, 0, 0);\r
- }\r
-\r
- private void drawSquare(Graphics g, int posX, int posY, String text)\r
- {\r
- int x1 = gX(posX) - 5;\r
- int x2 = gX(posX + 1) + 5;\r
- int y1 = gY(posY) - 5;\r
- int y2 = gY(posY + 1) + 5;\r
-\r
- g.setColor(Color.WHITE);\r
- g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\r
- setBlack(g);\r
- g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\r
- drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);\r
-\r
- }\r
-\r
- private void drawSwitch(Graphics g, ManualSwitch ms, String text, double posX1, double posY1, double posX2, double posY2)\r
- {\r
- int x1 = gX(posX1) - 5;\r
- int x2 = gX(posX2) + 5;\r
- int y1 = gY(posY1) - 5;\r
- int y2 = gY(posY2) + 5;\r
-\r
- if (sizeChanged)\r
- {\r
- Rectangle r = new Rectangle(x1, y1, x2 - x1, y2 - y1);\r
- switchMap.put(ms, r);\r
- }\r
-\r
- g.setColor(ms.isOn() ? Color.getHSBColor(.3f, .5f, 1f) : Color.WHITE);\r
- g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\r
- setBlack(g);\r
- g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\r
- drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);\r
- }\r
-\r
- private static void setBlack(Graphics g)\r
- {\r
- g.setColor(Color.BLACK);\r
- }\r
-\r
- private static void setTo(Graphics g, Wire wa)\r
- {\r
- switch (wa.getValue())\r
- {\r
- case ONE:\r
- g.setColor(Color.GREEN);\r
- break;\r
- case X:\r
- g.setColor(Color.RED);\r
- break;\r
- case Z:\r
- g.setColor(Color.DARK_GRAY);\r
- break;\r
- case ZERO:\r
- g.setColor(Color.BLACK);\r
- break;\r
- case U:\r
- g.setColor(Color.MAGENTA);\r
- break;\r
- default:\r
- throw new IllegalArgumentException();\r
- }\r
- }\r
-\r
- private int gY(double pos)\r
- {\r
- return (int) (pos * height / 11);\r
- }\r
-\r
- private int gX(double pos)\r
- {\r
- return (int) (pos * width / 11) + 50;\r
- }\r
-\r
- public static void main(String[] args)\r
- {\r
- JFrame f = new JFrame("Test circuit 1.0.0");\r
- GUITest gt = new GUITest();\r
- f.add(gt);\r
- f.setSize(800, 600);\r
- f.setLocation(500, 400);\r
- f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);\r
- f.setVisible(true);\r
-\r
- long begin = System.currentTimeMillis();\r
-\r
- long lastFrame = begin;\r
- long updateT = 16;\r
-\r
- while (f.isVisible())\r
- {\r
- ExecutionResult er = gt.getTimeline().executeUntil(gt.getTimeline().laterThan((lastFrame - begin) * 3), lastFrame + 14);\r
-// if (t.hasNext()) \r
-// t.executeNext();\r
- if (er != ExecutionResult.NOTHING_DONE)\r
- gt.repaint(12);\r
- try\r
- {\r
- Thread.sleep(Math.max(updateT - System.currentTimeMillis() + lastFrame, 0));\r
- }\r
- catch (Exception e)\r
- {\r
- e.printStackTrace();\r
- }\r
- lastFrame = System.currentTimeMillis();\r
- }\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.tests;\r
-\r
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;\r
-\r
-import java.util.function.LongConsumer;\r
-\r
-import era.mi.logic.components.BitDisplay;\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.Bit;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-\r
-public final class TestBitDisplay extends BitDisplay\r
-{\r
-\r
- public TestBitDisplay(Timeline timeline, ReadEnd in)\r
- {\r
- super(timeline, in);\r
- }\r
-\r
- public void assertDisplays(Bit... expected)\r
- {\r
- assertArrayEquals(expected, getDisplayedValue().getBits());\r
- }\r
-\r
- public void assertAfterSimulationIs(Bit... expected)\r
- {\r
- timeline.executeAll();\r
- assertDisplays(expected);\r
- }\r
-\r
- public void assertAfterSimulationIs(LongConsumer r, Bit... expected)\r
- {\r
- while (timeline.hasNext())\r
- {\r
- timeline.executeNext();\r
- r.accept(timeline.getSimulationTime());\r
- }\r
- assertDisplays(expected);\r
- }\r
-\r
- @Override\r
- protected void compute()\r
- {\r
- super.compute();\r
- System.out.println("update: value is " + getDisplayedValue());\r
- }\r
-}\r
+++ /dev/null
-package era.mi.logic.timeline;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.PriorityQueue;
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-import java.util.function.LongSupplier;
-
-/**
- * Orders Events by the time they are due to be executed. Can execute Events individually.
- *
- * @author Fabian Stemmler
- *
- */
-public class Timeline
-{
- private PriorityQueue<InnerEvent> events;
- private LongSupplier time;
- private long lastTimeUpdated = 0;
-
- private final List<Consumer<TimelineEvent>> eventAddedListener;
-
- public Timeline(int initCapacity)
- {
- events = new PriorityQueue<InnerEvent>(initCapacity);
-
- eventAddedListener = new ArrayList<>();
- time = () -> lastTimeUpdated;
- }
-
- /**
- * @param timestamp exclusive
- * @return true if the first event is later than the timestamp
- */
- public BooleanSupplier laterThan(long timestamp)
- {
- return () -> timeCmp(events.peek().getTiming(), timestamp) > 0;
- }
-
- public boolean hasNext()
- {
- return !events.isEmpty();
- }
-
- /**
- * Executes all events at the next timestamp, at which there are any
- */
- public void executeNext()
- {
- InnerEvent first = events.peek();
- if (first != null)
- executeUntil(laterThan(first.getTiming()), -1);
- }
-
- public void executeAll()
- {
- while (hasNext())
- executeNext();
- }
-
- /**
- * Executes all events until a given condition is met. The simulation process can be constrained by a real world timestamp.
- *
- * @param condition the condition until which the events are be processed
- * @param stopMillis the System.currentTimeMillis() when simulation definitely needs to stop. A value of -1 means no timeout.
- * @return State of the event execution
- * @formatter:off
- * <code>NOTHING_DONE</code> if the {@link Timeline} was already empty
- * <code>EXEC_OUT_OF_TIME</code> if the given maximum time was reached
- * <code>EXEC_UNTIL_CONDITION</code> if the condition was met
- * <code>EXEC_UNTIL_EMPTY</code> if events were executed until the {@link Timeline} was empty
- * @formatter:on
- * @author Christian Femers, Fabian Stemmler
- */
- public ExecutionResult executeUntil(BooleanSupplier condition, long stopMillis)
- {
- if (events.isEmpty())
- {
- lastTimeUpdated = getSimulationTime();
- return ExecutionResult.NOTHING_DONE;
- }
- int checkStop = 0;
- InnerEvent first = events.peek();
- while (hasNext() && !condition.getAsBoolean())
- {
- events.remove();
- lastTimeUpdated = first.getTiming();
- first.run();
- // Don't check after every run
- checkStop = (checkStop + 1) % 10;
- if (checkStop == 0 && System.currentTimeMillis() >= stopMillis)
- return ExecutionResult.EXEC_OUT_OF_TIME;
- first = events.peek();
- }
- lastTimeUpdated = getSimulationTime();
- return hasNext() ? ExecutionResult.EXEC_UNTIL_EMPTY : ExecutionResult.EXEC_UNTIL_CONDITION;
- }
-
- public void setTimeFunction(LongSupplier time)
- {
- this.time = time;
- }
-
- public long getSimulationTime()
- {
- return time.getAsLong();
- }
-
- public long nextEventTime()
- {
- if (!hasNext())
- return -1;
- return events.peek().getTiming();
- }
-
- public void reset()
- {
- events.clear();
- lastTimeUpdated = 0;
- }
-
- public void addEventAddedListener(Consumer<TimelineEvent> listener)
- {
- eventAddedListener.add(listener);
- }
-
- public void removeEventAddedListener(Consumer<TimelineEvent> listener)
- {
- eventAddedListener.remove(listener);
- }
-
- /**
- * Adds an Event to the {@link Timeline}
- *
- * @param function The {@link TimelineEventHandler} that will be executed, when the {@link InnerEvent} occurs on the timeline.
- * @param relativeTiming The amount of MI ticks in which the {@link InnerEvent} is called, starting from the current time.
- */
- public void addEvent(TimelineEventHandler function, int relativeTiming)
- {
- long timing = getSimulationTime() + relativeTiming;
- TimelineEvent event = new TimelineEvent(timing);
- events.add(new InnerEvent(function, event));
- eventAddedListener.forEach(l -> l.accept(event));
- }
-
- private class InnerEvent implements Runnable, Comparable<InnerEvent>
- {
- private final TimelineEventHandler function;
- private final TimelineEvent event;
-
- /**
- * Creates an {@link InnerEvent}
- *
- * @param function {@link TimelineEventHandler} to be executed when the {@link InnerEvent} occurs
- * @param timing Point in the MI simulation {@link Timeline}, at which the {@link InnerEvent} is executed;
- */
- InnerEvent(TimelineEventHandler function, TimelineEvent event)
- {
- this.function = function;
- this.event = event;
- }
-
- public long getTiming()
- {
- return event.getTiming();
- }
-
- @Override
- public void run()
- {
- function.handle(event);
- }
-
- @Override
- public String toString()
- {
- return event.toString();
- }
-
- @Override
- public int compareTo(InnerEvent o)
- {
- return timeCmp(getTiming(), o.getTiming());
- }
- }
-
- public static int timeCmp(long a, long b)
- {
- return Long.signum(a - b);
- }
-
- @Override
- public String toString()
- {
- return String.format("Simulation time: %s, Last update: %d, Events: %s", getSimulationTime(), lastTimeUpdated, events.toString());
- }
-
- public enum ExecutionResult
- {
- NOTHING_DONE, EXEC_UNTIL_EMPTY, EXEC_UNTIL_CONDITION, EXEC_OUT_OF_TIME
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.logic.timeline;
-
-/**
- * A class that stores all relevant information about an event in the {@link Timeline}. Currently, there is not much relevant information to
- * store.
- *
- * @author Fabian Stemmler
- *
- */
-public class TimelineEvent
-{
- private final long timing;
-
- TimelineEvent(long timing)
- {
- super();
- this.timing = timing;
- }
-
- public long getTiming()
- {
- return timing;
- }
-
- @Override
- public String toString()
- {
- return "timestamp: " + timing;
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.logic.timeline;
-
-@FunctionalInterface
-public interface TimelineEventHandler
-{
- public void handle(TimelineEvent e);
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.logic.types;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * stdlogic according to IEEE 1164
- */
-public enum Bit implements StrictLogicType<Bit>
-{
- U("U"), X("X"), ZERO("0"), ONE("1"), Z("Z");
-
- private final String symbol;
-
- private Bit(String symbol)
- {
- this.symbol = symbol;
- }
-
- @Override
- public Bit and(Bit other)
- {
- return fromTable(AND_TABLE, this, other);
- }
-
- @Override
- public Bit or(Bit other)
- {
- return fromTable(OR_TABLE, this, other);
- }
-
- @Override
- public Bit xor(Bit other)
- {
- return fromTable(XOR_TABLE, this, other);
- }
-
- @Override
- public Bit not()
- {
- switch (this)
- {
- case U:
- return U;
- case ONE:
- return ZERO;
- case ZERO:
- return ONE;
- default:
- return X;
- }
- }
-
- public Bit[] makeArray(int length)
- {
- Bit[] bits = new Bit[length];
- Arrays.fill(bits, this);
- return bits;
- }
-
- public BitVector toVector(int length)
- {
- return BitVector.of(this, length);
- }
-
- @Override
- public Bit join(Bit other)
- {
- return fromTable(JOIN_TABLE, this, other);
- }
-
- @Override
- public String toString()
- {
- return getSymbol();
- }
-
- public String getSymbol()
- {
- return symbol;
- }
-
- public static Bit parse(String s)
- {
- Bit bit = SYMBOL_MAP.get(s);
- Objects.requireNonNull(bit, "No Bit found for symbol " + s);
- return bit;
- }
-
- public static Bit parse(String s, int symbolPosition)
- {
- return parse(s.substring(symbolPosition, symbolPosition + 1));
- }
-
- private static Bit fromTable(Bit[][] table, Bit a, Bit b)
- {
- return table[a.ordinal()][b.ordinal()];
- }
-
- static final Map<String, Bit> SYMBOL_MAP = Map.of(U.symbol, U, X.symbol, X, ZERO.symbol, ZERO, ONE.symbol, ONE, Z.symbol, Z);
-
- // @formatter:off
- private static final Bit[][] JOIN_TABLE =
- { { U, U, U, U, U },
- { U, X, X, X, X },
- { U, X, ZERO, X, ZERO },
- { U, X, X, ONE, ONE },
- { U, X, ZERO, ONE, Z } };
-
- private static final Bit[][] AND_TABLE =
- { { U, U, ZERO, U, U },
- { U, X, ZERO, X, X },
- { ZERO, ZERO, ZERO, ZERO, ZERO },
- { U, X, ZERO, ONE, X },
- { U, X, ZERO, X, X } };
-
- private static final Bit[][] OR_TABLE =
- { { U, U, U, ONE, U },
- { U, X, X, ONE, X },
- { U, X, ZERO, ONE, X },
- { ONE, ONE, ONE, ONE, ONE },
- { U, X, X, ONE, X } };
-
- private static final Bit[][] XOR_TABLE =
- { { U, U, U, U, U },
- { U, X, X, X, X },
- { U, X, ZERO, ONE, X },
- { U, X, ONE, ZERO, X },
- { U, X, X, X, X } };
- // @formatter:on
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.logic.types;
-
-import static java.lang.String.format;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.RandomAccess;
-import java.util.function.BinaryOperator;
-import java.util.function.UnaryOperator;
-
-/**
- * Immutable class representing a {@link Bit}Vector
- *
- *
- * @author Christian Femers
- *
- */
-public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
-{
- private final Bit[] bits;
-
- private BitVector(Bit[] bits)
- {
- this.bits = Objects.requireNonNull(bits);
- }
-
- public static BitVector of(Bit... bits)
- {
- return new BitVector(bits.clone());
- }
-
- public static BitVector of(Bit bit, int length)
- {
- return new BitVector(bit.makeArray(length));
- }
-
- public BitVectorMutator mutator()
- {
- return BitVectorMutator.of(this);
- }
-
- public Bit getBit(int bitIndex)
- {
- return bits[bitIndex];
- }
-
- public Bit[] getBits()
- {
- return bits.clone();
- }
-
- @Override
- public BitVector join(BitVector t)
- {
- checkCompatibility(t);
- return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
- }
-
- @Override
- public BitVector and(BitVector t)
- {
- checkCompatibility(t);
- return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
- }
-
- @Override
- public BitVector or(BitVector t)
- {
- checkCompatibility(t);
- return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
- }
-
- @Override
- public BitVector xor(BitVector t)
- {
- checkCompatibility(t);
- return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
- }
-
- @Override
- public BitVector not()
- {
- return new BitVector(unOp(bits.clone(), Bit::not));
- }
-
- public int length()
- {
- return bits.length;
- }
-
- public BitVector concat(BitVector other)
- {
- Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
- System.arraycopy(other.bits, 0, newBits, length(), other.length());
- return new BitVector(newBits);
- }
-
- public BitVector subVector(int start)
- {
- return new BitVector(Arrays.copyOfRange(bits, start, length()));
- }
-
- public BitVector subVector(int start, int end)
- {
- return new BitVector(Arrays.copyOfRange(bits, start, end));
- }
-
- private void checkCompatibility(BitVector bv)
- {
- if (length() != bv.length())
- throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
- }
-
- static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
- {
- if (dest == null)
- return second.clone();
- for (int i = 0; i < dest.length; i++)
- {
- dest[i] = op.apply(dest[i], second[i]);
- }
- return dest;
- }
-
- static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
- {
- if (dest == null)
- return null;
- for (int i = 0; i < dest.length; i++)
- {
- dest[i] = op.apply(dest[i]);
- }
- return dest;
- }
-
- /**
- * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
- *
- * @author Christian Femers
- */
- @SuppressWarnings("synthetic-access")
- public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
- {
- private Bit[] bits;
-
- private BitVectorMutator(Bit[] bits)
- {
- this.bits = bits;
- }
-
- static BitVectorMutator of(BitVector bv)
- {
- return new BitVectorMutator(bv.getBits());
- }
-
- /**
- * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
- *
- */
- public static BitVectorMutator empty()
- {
- return new BitVectorMutator(null);
- }
-
- /**
- * Produces the resulting, immutable {@link BitVector}<br>
- *
- * @throws IllegalStateException if the mutator is (still) empty
- */
- public BitVector get()
- {
- if (bits == null)
- throw new IllegalStateException("cannot create a BitVector from an empty mutator");
- return new BitVector(bits);
- }
-
- @Override
- public BitVectorMutator join(BitVector t)
- {
- checkCompatibility(t);
- bits = binOp(bits, t.bits, Bit::join);
- return this;
- }
-
- @Override
- public BitVectorMutator and(BitVector t)
- {
- checkCompatibility(t);
- bits = binOp(bits, t.bits, Bit::and);
- return this;
- }
-
- @Override
- public BitVectorMutator or(BitVector t)
- {
- checkCompatibility(t);
- bits = binOp(bits, t.bits, Bit::or);
- return this;
- }
-
- @Override
- public BitVectorMutator xor(BitVector t)
- {
- checkCompatibility(t);
- bits = binOp(bits, t.bits, Bit::xor);
- return this;
- }
-
- @Override
- public BitVectorMutator not()
- {
- unOp(bits, Bit::not);
- return this;
- }
-
- private void checkCompatibility(BitVector bv)
- {
- if (bits != null && bits.length != bv.length())
- throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
- }
- }
-
- /**
- * @see Arrays#hashCode(Object[])
- */
- @Override
- public int hashCode()
- {
- return Arrays.hashCode(bits);
- }
-
- /**
- * Does test for equality of values/content
- *
- * @see Object#equals(Object)
- */
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- return true;
- if (!(obj instanceof BitVector))
- return false;
- BitVector other = (BitVector) obj;
- return Arrays.equals(bits, other.bits);
- }
-
- /**
- * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
- * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
- *
- * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
- *
- * @see Object#equals(Object)
- */
- public boolean equalsWithOffset(BitVector other, int offset)
- {
- if (other == null)
- return false;
- return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
- }
-
- /**
- * All {@link Bit}s symbols concatenated together
- *
- * @see #parse(String)
- */
- @Override
- public String toString()
- {
- StringBuilder sb = new StringBuilder(bits.length);
- for (Bit bit : bits)
- sb.append(bit);
- return sb.toString();
- }
-
- /**
- * Parses a String containing solely {@link Bit} symbols
- *
- * @see #toString()
- */
- public static BitVector parse(String s)
- {
- Bit[] values = new Bit[s.length()];
- for (int i = 0; i < s.length(); i++)
- {
- values[i] = Bit.parse(s, i);
- }
- return new BitVector(values);
- }
-
- @Override
- public Iterator<Bit> iterator()
- {
- return new Iterator<>()
- {
- private int pos = 0;
-
- @Override
- public Bit next()
- {
- if (!hasNext())
- throw new NoSuchElementException();
- return getBit(pos++);
- }
-
- @Override
- public boolean hasNext()
- {
- return pos != length();
- }
- };
- }
-}
+++ /dev/null
-package era.mi.logic.types;
-
-import era.mi.logic.types.ColorDefinition.BuiltInColor;
-import era.mi.logic.wires.Wire.ReadEnd;
-
-public class BitVectorFormatter
-{
- public static String formatValueAsString(ReadEnd end)
- {
- return formatAsString(end == null ? null : end.getValues());
- }
-
- public static String formatAsString(BitVector bitVector)
- {
- if (bitVector == null)
- return "null";
- else
- return bitVector.toString();
- }
-
- public static ColorDefinition formatAsColor(ReadEnd end)
- {
- return formatAsColor(end == null ? null : end.getValues());
- }
-
- public static ColorDefinition formatAsColor(BitVector bitVector)
- {
- // TODO maybe find a color assignment for multiple-bit bit vectors?
- if (bitVector == null || bitVector.length() != 1)
- return new ColorDefinition(BuiltInColor.COLOR_BLACK);
- else
- switch (bitVector.getBit(0))
- {
- case ONE:
- return new ColorDefinition(BuiltInColor.COLOR_GREEN);
- case U:
- return new ColorDefinition(BuiltInColor.COLOR_CYAN);
- case X:
- return new ColorDefinition(BuiltInColor.COLOR_RED);
- case Z:
- return new ColorDefinition(BuiltInColor.COLOR_YELLOW);
- case ZERO:
- return new ColorDefinition(BuiltInColor.COLOR_GRAY);
- default:
- throw new IllegalArgumentException("Unknown enum constant: " + bitVector.getBit(0));
- }
- }
-
- private BitVectorFormatter()
- {
- throw new UnsupportedOperationException("No BitVectorFormatter instances");
- }
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.logic.types;
-
-/**
- * A way to define a color with the possibility to use colors built into the system (called "system colors" in SWT).
- * <p>
- * A {@link ColorDefinition} is defined either by a {@link BuiltInColor} constant, in which case <code>r==g==b==-1</code>, or by red / green
- * / blue components, in which case <code>builtInColor==null</code>
- */
-public class ColorDefinition
-{
- /**
- * The built-in color constant defining this color.
- */
- public final ColorDefinition.BuiltInColor builtInColor;
- /**
- * The red color component defining this color.
- */
- public final int r;
- /**
- * The green color component defining this color.
- */
- public final int g;
- /**
- * The blue color component defining this color.
- */
- public final int b;
-
- public ColorDefinition(ColorDefinition.BuiltInColor col)
- {
- if (col == null)
- throw new IllegalArgumentException("Illegal built-in color: " + col);
- this.builtInColor = col;
- this.r = -1;
- this.g = -1;
- this.b = -1;
- }
-
- public ColorDefinition(int r, int g, int b)
- {
- if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
- throw new IllegalArgumentException("Illegal color components: r=" + r + "; g=" + g + "; b=" + b);
- this.builtInColor = null;
- this.r = r;
- this.g = g;
- this.b = b;
- }
-
- public static enum BuiltInColor
- {
- COLOR_WHITE, COLOR_BLACK, COLOR_RED, COLOR_DARK_RED, COLOR_GREEN, COLOR_DARK_GREEN, COLOR_YELLOW, COLOR_DARK_YELLOW, COLOR_BLUE,
- COLOR_DARK_BLUE, COLOR_MAGENTA, COLOR_DARK_MAGENTA, COLOR_CYAN, COLOR_DARK_CYAN, COLOR_GRAY, COLOR_DARK_GRAY;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.logic.types;
-
-/**
- * Interface for types that support the basic logic operations
- *
- * @author Christian Femers
- *
- * @param <T> the logic type itself, to make the operations closed in T
- * @param <S> the operand type, may be the same as T, see {@link StrictLogicType}
- */
-public interface LogicType<T extends LogicType<T, S>, S>
-{
- /**
- * Determines the result when two signals meet each other directly, also called resolution (IEEE 1164)
- *
- * For example:
- *
- * <pre>
- * 0 joined 0 == 0
- * 1 joined 0 == X
- * 0 joined 1 == X
- * 1 joined 1 == 1
- * </pre>
- *
- * @param t the second logic signal
- * @return the resulting value
- * @author Christian Femers
- */
- T join(S t);
-
- /**
- * Classical logic AND
- *
- * For example:
- *
- * <pre>
- * 0 AND 0 == 0
- * 1 AND 0 == 0
- * 0 AND 1 == 0
- * 1 AND 1 == 1
- * </pre>
- *
- * @param t the second logic signal
- * @return the resulting value
- * @author Christian Femers
- */
- T and(S t);
-
- /**
- * Classical logic OR
- *
- * For example:
- *
- * <pre>
- * 0 OR 0 == 0
- * 1 OR 0 == 1
- * 0 OR 1 == 1
- * 1 OR 1 == 1
- * </pre>
- *
- * @param t the second logic signal
- * @return the resulting value
- * @author Christian Femers
- */
- T or(S t);
-
- /**
- * Classical logic XOR (exclusive OR)
- *
- * For example:
- *
- * <pre>
- * 0 XOR 0 == 0
- * 1 XOR 0 == 1
- * 0 XOR 1 == 1
- * 1 XOR 1 == 0
- * </pre>
- *
- * @param t the second logic signal
- * @return the resulting value
- * @author Christian Femers
- */
- T xor(S t);
-
- /**
- * Classical logic NOT (logical negation)
- *
- * For example:
- *
- * <pre>
- * NOT 0 == 1
- * NOT 1 == 0
- * </pre>
- *
- * @return the resulting value
- * @author Christian Femers
- */
- T not();
-
- /**
- * {@link #and(Object) AND} and then {@link #not() NOT}
- *
- * @author Christian Femers
- */
- default T nand(S t)
- {
- return and(t).not();
- }
-
- /**
- * {@link #or(Object) OR} and then {@link #not() NOT}
- *
- * @author Christian Femers
- */
- default T nor(S t)
- {
- return or(t).not();
- }
-
- /**
- * {@link #xor(Object) XOR} and then {@link #not() NOT}<br>
- * Used to determine equality (alias parity, consistency)
- *
- * @author Christian Femers
- */
- default T xnor(S t)
- {
- return xor(t).not();
- }
-}
+++ /dev/null
-package era.mi.logic.types;
-
-import java.util.function.BiFunction;
-
-import era.mi.logic.types.BitVector.BitVectorMutator;
-
-@FunctionalInterface
-public interface MutationOperation extends BiFunction<BitVectorMutator, BitVector, BitVectorMutator>
-{
- // no changes necessary, only for convenience and readability
-}
+++ /dev/null
-package era.mi.logic.types;
-
-/**
- * Interface for types that support the basic logic operations only among themselves, making it mathematically closed
- *
- * @author Christian Femers
- * @see LogicType
- *
- * @param <T> the logic type itself to make the operations closed
- */
-public interface StrictLogicType<T extends StrictLogicType<T>> extends LogicType<T, T>
-{
- // this is just a matter of type parameters
-}
+++ /dev/null
-package era.mi.logic.wires;\r
-\r
-import static era.mi.logic.types.Bit.U;\r
-import static era.mi.logic.types.Bit.Z;\r
-\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import era.mi.logic.timeline.Timeline;\r
-import era.mi.logic.types.Bit;\r
-import era.mi.logic.types.BitVector;\r
-import era.mi.logic.types.BitVector.BitVectorMutator;\r
-\r
-/**\r
- * Represents an array of wires that can store n bits of information.\r
- * \r
- * @author Fabian Stemmler\r
- *\r
- */\r
-public class Wire\r
-{\r
- private BitVector values;\r
- public final int travelTime;\r
- private List<ReadEnd> attached = new ArrayList<ReadEnd>();\r
- public final int length;\r
- private List<ReadWriteEnd> inputs = new ArrayList<ReadWriteEnd>();\r
- private Timeline timeline;\r
-\r
- public Wire(Timeline timeline, int length, int travelTime)\r
- {\r
- if (length < 1)\r
- throw new IllegalArgumentException(\r
- String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));\r
- this.timeline = timeline;\r
- this.length = length;\r
- this.travelTime = travelTime;\r
- initValues();\r
- }\r
-\r
- private void initValues()\r
- {\r
- values = U.toVector(length);\r
- }\r
-\r
- private void recalculateSingleInput()\r
- {\r
- setNewValues(inputs.get(0).getInputValues());\r
- }\r
-\r
- private void recalculateMultipleInputs()\r
- {\r
- BitVectorMutator mutator = BitVectorMutator.empty();\r
- for (ReadWriteEnd wireArrayEnd : inputs)\r
- mutator.join(wireArrayEnd.getInputValues());\r
- setNewValues(mutator.get());\r
- }\r
-\r
- private void setNewValues(BitVector newValues)\r
- {\r
- if (values.equals(newValues))\r
- return;\r
- BitVector oldValues = values;\r
- values = newValues;\r
- notifyObservers(oldValues);\r
- }\r
-\r
- private void recalculate()\r
- {\r
- switch (inputs.size())\r
- {\r
- case 0:\r
- return;\r
- case 1:\r
- recalculateSingleInput();\r
- break;\r
- default:\r
- recalculateMultipleInputs();\r
- }\r
- }\r
-\r
- /**\r
- * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
- * \r
- * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the same\r
- * value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public boolean hasNumericValue()\r
- {\r
- for (Bit b : values)\r
- {\r
- if (b != Bit.ZERO && b != Bit.ONE)\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- /**\r
- * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
- * \r
- * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public long getUnsignedValue()\r
- {\r
- long val = 0;\r
- long mask = 1;\r
- for (Bit bit : values)\r
- {\r
- switch (bit)\r
- {\r
- default:\r
- case Z:\r
- case X:\r
- return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;\r
- case ONE:\r
- val |= mask;\r
- break;\r
- case ZERO:\r
- }\r
- mask = mask << 1;\r
- }\r
- return val;\r
- }\r
-\r
- /**\r
- * The {@link Wire} is interpreted as a signed integer with n bits.\r
- * \r
- * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public long getSignedValue()\r
- {\r
- long val = getUnsignedValue();\r
- long mask = 1 << (length - 1);\r
- if ((mask & val) != 0)\r
- {\r
- int shifts = 64 - length;\r
- return (val << shifts) >> shifts;\r
- }\r
- return val;\r
- }\r
-\r
- public Bit getValue()\r
- {\r
- return getValue(0);\r
- }\r
-\r
- public Bit getValue(int index)\r
- {\r
- return values.getBit(index);\r
- }\r
-\r
- public BitVector getValues(int start, int end)\r
- {\r
- return values.subVector(start, end);\r
- }\r
-\r
- public BitVector getValues()\r
- {\r
- return values;\r
- }\r
-\r
- /**\r
- * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} is updated.\r
- * \r
- * @param ob The {@link WireObserver} to be notified of changes.\r
- * @return true if the given {@link WireObserver} was not already registered, false otherwise\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- private void attachEnd(ReadEnd end)\r
- {\r
- attached.add(end);\r
- }\r
-\r
- private void detachEnd(ReadEnd end)\r
- {\r
- attached.remove(end);\r
- }\r
-\r
- private void notifyObservers(BitVector oldValues)\r
- {\r
- for (ReadEnd o : attached)\r
- o.update(oldValues);\r
- }\r
-\r
- /**\r
- * Create and register a {@link ReadWriteEnd} object, which is tied to this {@link Wire}. This {@link ReadWriteEnd} can be written to.\r
- */\r
- public ReadWriteEnd createReadWriteEnd()\r
- {\r
- return new ReadWriteEnd();\r
- }\r
-\r
- /**\r
- * Create a {@link ReadEnd} object, which is tied to this {@link Wire}. This {@link ReadEnd} cannot be written to.\r
- */\r
- public ReadEnd createReadOnlyEnd()\r
- {\r
- return new ReadEnd();\r
- }\r
-\r
- private void registerInput(ReadWriteEnd toRegister)\r
- {\r
- inputs.add(toRegister);\r
- }\r
-\r
- /**\r
- * A {@link ReadEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the\r
- * {@link Wire}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs than Z 0\r
- * and 1 turn into X when they are mixed\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public class ReadEnd\r
- {\r
- private List<WireObserver> observers = new ArrayList<WireObserver>();\r
-\r
- private ReadEnd()\r
- {\r
- super();\r
- Wire.this.attachEnd(this);\r
- }\r
-\r
- public void update(BitVector oldValues)\r
- {\r
- for (WireObserver ob : observers)\r
- ob.update(this, oldValues);\r
- }\r
-\r
- /**\r
- * Included for convenient use on {@link Wire}s of length 1.\r
- * \r
- * @return The value of bit 0.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public Bit getValue()\r
- {\r
- return Wire.this.getValue();\r
- }\r
-\r
- /**\r
- * @param index Index of the requested bit.\r
- * @return The value of the indexed bit.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public Bit getValue(int index)\r
- {\r
- return Wire.this.getValue(index);\r
- }\r
-\r
- /**\r
- * @param index Index of the requested bit.\r
- * @return The value of the indexed bit.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public BitVector getValues()\r
- {\r
- return Wire.this.getValues();\r
- }\r
-\r
- /**\r
- * @param start Start of the wanted segment. (inclusive)\r
- * @param end End of the wanted segment. (exclusive)\r
- * @return The values of the segment of {@link Bit}s indexed.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public BitVector getValues(int start, int end)\r
- {\r
- return Wire.this.getValues(start, end);\r
- }\r
-\r
- /**\r
- * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
- * \r
- * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the\r
- * same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public boolean hasNumericValue()\r
- {\r
- return Wire.this.hasNumericValue();\r
- }\r
-\r
- /**\r
- * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
- * \r
- * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public long getUnsignedValue()\r
- {\r
- return Wire.this.getUnsignedValue();\r
- }\r
-\r
- /**\r
- * The {@link Wire} is interpreted as a signed integer with n bits.\r
- * \r
- * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public long getSignedValue()\r
- {\r
- return Wire.this.getSignedValue();\r
- }\r
-\r
- @Override\r
- public String toString()\r
- {\r
- return Wire.this.toString();\r
- }\r
-\r
- public void close()\r
- {\r
- inputs.remove(this);\r
- detachEnd(this);\r
- recalculate();\r
- }\r
-\r
- public int length()\r
- {\r
- return length;\r
- }\r
-\r
- public boolean addObserver(WireObserver ob)\r
- {\r
- return observers.add(ob);\r
- }\r
-\r
- public Wire getWire()\r
- {\r
- return Wire.this;\r
- }\r
- }\r
-\r
- public class ReadWriteEnd extends ReadEnd\r
- {\r
- private boolean open;\r
- private BitVector inputValues;\r
-\r
- private ReadWriteEnd()\r
- {\r
- super();\r
- open = true;\r
- initValues();\r
- registerInput(this);\r
- }\r
-\r
- private void initValues()\r
- {\r
- inputValues = U.toVector(length);\r
- }\r
-\r
- /**\r
- * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.\r
- * \r
- * @param newValues The new values the wires should take on.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public void feedSignals(Bit... newValues)\r
- {\r
- feedSignals(BitVector.of(newValues));\r
- }\r
-\r
- public void feedSignals(BitVector newValues)\r
- {\r
- if (newValues.length() != length)\r
- throw new IllegalArgumentException(\r
- String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));\r
- if (!open)\r
- throw new RuntimeException("Attempted to write to closed WireArrayEnd.");\r
- timeline.addEvent(e -> setValues(newValues), travelTime);\r
- }\r
-\r
- /**\r
- * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.\r
- * \r
- * @param bitVector The new values the wires should take on.\r
- * @param startingBit The first index of the subarray of wires.\r
- * \r
- * @author Fabian Stemmler\r
- */\r
- public void feedSignals(int startingBit, BitVector bitVector)\r
- {\r
- if (!open)\r
- throw new RuntimeException("Attempted to write to closed WireArrayEnd.");\r
- timeline.addEvent(e -> setValues(startingBit, bitVector), travelTime);\r
- }\r
-\r
- private void setValues(int startingBit, BitVector newValues)\r
- {\r
- // index check covered in equals\r
- if (!inputValues.equalsWithOffset(newValues, startingBit))\r
- {\r
- Bit[] vals = inputValues.getBits();\r
- System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());\r
- inputValues = BitVector.of(vals);\r
- Wire.this.recalculate();\r
- }\r
- }\r
-\r
- private void setValues(BitVector newValues)\r
- {\r
- if (inputValues.equals(newValues))\r
- return;\r
- inputValues = newValues;\r
- Wire.this.recalculate();\r
- }\r
-\r
- /**\r
- * @return The value (of bit 0) the {@link ReadEnd} is currently feeding into the associated {@link Wire}.\r
- */\r
- public Bit getInputValue()\r
- {\r
- return getInputValue(0);\r
- }\r
-\r
- /**\r
- * @return The value which the {@link ReadEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.\r
- */\r
- public Bit getInputValue(int index)\r
- {\r
- return inputValues.getBit(index);\r
- }\r
-\r
- /**\r
- * @return A copy (safe to modify) of the values the {@link ReadEnd} is currently feeding into the associated {@link Wire}.\r
- */\r
- public BitVector getInputValues()\r
- {\r
- return getInputValues(0, length);\r
- }\r
-\r
- public BitVector getInputValues(int start, int end)\r
- {\r
- return inputValues.subVector(start, end);\r
- }\r
-\r
- /**\r
- * {@link ReadEnd} now feeds Z into the associated {@link Wire}.\r
- */\r
- public void clearSignals()\r
- {\r
- feedSignals(Z.toVector(length));\r
- }\r
-\r
- public BitVector wireValuesExcludingMe()\r
- {\r
- BitVectorMutator mutator = BitVectorMutator.empty();\r
- for (ReadWriteEnd wireEnd : inputs)\r
- {\r
- if (wireEnd == this)\r
- continue;\r
- mutator.join(wireEnd.inputValues);\r
- }\r
- return mutator.get();\r
- }\r
-\r
- @Override\r
- public String toString()\r
- {\r
- return inputValues.toString();\r
- }\r
- }\r
-\r
- @Override\r
- public String toString()\r
- {\r
- return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), values, inputs);\r
- // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)\r
- }\r
-\r
- public static ReadEnd[] extractEnds(Wire[] w)\r
- {\r
- ReadEnd[] inputs = new ReadEnd[w.length];\r
- for (int i = 0; i < w.length; i++)\r
- inputs[i] = w[i].createReadWriteEnd();\r
- return inputs;\r
- }\r
-}
\ No newline at end of file
+++ /dev/null
-package era.mi.logic.wires;\r
-\r
-import era.mi.logic.types.BitVector;\r
-import era.mi.logic.wires.Wire.ReadEnd;\r
-\r
-public interface WireObserver\r
-{\r
- public void update(ReadEnd initiator, BitVector oldValues);\r
-}\r
--- /dev/null
+package mograsim.logic.core;
+
+import java.util.Arrays;
+
+import mograsim.logic.core.types.Bit;
+
+public final class Util
+{
+
+ @SuppressWarnings("unchecked")
+ public static <T> T[] concat(T[]... arrays)
+ {
+ if (arrays.length == 0)
+ throw new IllegalArgumentException("Cannot concatenate 0 arrays.");
+
+ int length = 0;
+ for (T[] array : arrays)
+ length += array.length;
+
+ T[] newArray = Arrays.copyOf(arrays[0], length);
+ int appendIndex = arrays[0].length;
+ for (int i = 1; i < arrays.length; i++)
+ {
+ System.arraycopy(arrays[i], 0, newArray, appendIndex, arrays[i].length);
+ appendIndex += arrays[i].length;
+ }
+
+ return newArray;
+ }
+
+// @SuppressWarnings("unchecked")
+// public static <T> T[][] split(T[] array, int... lengths)
+// {
+// //TODO: implement array split again; This version contains an illegal cast
+// int totalLength = 0;
+// for(int length : lengths)
+// totalLength += length;
+//
+// if(totalLength != array.length)
+// throw new IllegalArgumentException(); //TODO: add proper error message
+//
+// Object[][] newArray = new Object[lengths.length][];
+// int splitIndex = 0;
+// for(int i = 0; i < lengths.length; i++)
+// {
+// System.arraycopy(array, splitIndex, newArray, 0, lengths[i]);
+// splitIndex += lengths[i];
+// }
+//
+// return (T[][]) newArray;
+// }
+
+ public static Bit[] and(Bit[] a, Bit[] b)
+ {
+ return binBitOp(a, b, Bit::and);
+ }
+
+ public static Bit[] or(Bit[] a, Bit[] b)
+ {
+ return binBitOp(a, b, Bit::or);
+ }
+
+ public static Bit[] xor(Bit[] a, Bit[] b)
+ {
+ return binBitOp(a, b, Bit::xor);
+ }
+
+ private static Bit[] binBitOp(Bit[] a, Bit[] b, BitOp op)
+ {
+ if (a.length != b.length)
+ throw new IllegalArgumentException("Bit Arrays were not of equal length.");
+ Bit[] out = new Bit[a.length];
+ for (int i = 0; i < a.length; i++)
+ {
+ out[i] = op.execute(a[i], b[i]);
+ }
+ return out;
+ }
+
+ public static Bit[] not(Bit[] a)
+ {
+ Bit[] out = new Bit[a.length];
+ for (int i = 0; i < a.length; i++)
+ {
+ out[i] = a[i].not();
+ }
+ return out;
+ }
+
+ /**
+ * uses the {@link Bit#combineWith(Bit)} method, does not create a new array, the result is stored in the first array.
+ *
+ * @author Christian Femers
+ */
+ public static Bit[] combineInto(Bit[] dest, Bit[] addition)
+ {
+ if (dest.length != addition.length)
+ throw new IllegalArgumentException("Bit Arrays were not of equal length.");
+ for (int i = 0; i < addition.length; i++)
+ {
+ dest[i] = dest[i].join(addition[i]);
+ }
+ return dest;
+ }
+
+ interface BitOp
+ {
+ Bit execute(Bit a, Bit b);
+ }
+}
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.BitVector;\r
+import mograsim.logic.core.wires.WireObserver;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+\r
+/**\r
+ * A basic component that recomputes all outputs (with a delay), when it is updated.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+public abstract class BasicComponent extends Component implements WireObserver\r
+{\r
+ private int processTime;\r
+\r
+ /**\r
+ * \r
+ * @param processTime Amount of time this component takes to update its outputs. Must be more than 0, otherwise 1 is assumed.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public BasicComponent(Timeline timeline, int processTime)\r
+ {\r
+ super(timeline);\r
+ this.processTime = processTime > 0 ? processTime : 1;\r
+ }\r
+\r
+ @Override\r
+ public void update(ReadEnd initiator, BitVector oldValues)\r
+ {\r
+ timeline.addEvent(e -> compute(), processTime);\r
+ }\r
+\r
+ protected abstract void compute();\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.Bit;\r
+import mograsim.logic.core.types.BitVector;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class BitDisplay extends BasicComponent\r
+{\r
+ private final ReadEnd in;\r
+ private BitVector displayedValue;\r
+\r
+ public BitDisplay(Timeline timeline, ReadEnd in)\r
+ {\r
+ super(timeline, 1);\r
+ this.in = in;\r
+ in.addObserver(this);\r
+ compute();\r
+ }\r
+\r
+ @Override\r
+ protected void compute()\r
+ {\r
+ displayedValue = in.getValues();\r
+ }\r
+\r
+ public BitVector getDisplayedValue()\r
+ {\r
+ return displayedValue;\r
+ }\r
+\r
+ public boolean isDisplaying(Bit... values)\r
+ {\r
+ return displayedValue.equals(BitVector.of(values));\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of(in);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of();\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.timeline.TimelineEvent;\r
+import mograsim.logic.core.timeline.TimelineEventHandler;\r
+import mograsim.logic.core.types.Bit;\r
+import mograsim.logic.core.wires.Wire;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class Clock extends Component implements TimelineEventHandler\r
+{\r
+ private boolean toggle = false;\r
+ private ReadWriteEnd out;\r
+ private int delta;\r
+\r
+ /**\r
+ * \r
+ * @param out {@link Wire} the clock's impulses are fed into\r
+ * @param delta ticks between rising and falling edge\r
+ */\r
+ public Clock(Timeline timeline, ReadWriteEnd out, int delta)\r
+ {\r
+ super(timeline);\r
+ this.delta = delta;\r
+ this.out = out;\r
+ addToTimeline();\r
+ }\r
+\r
+ @Override\r
+ public void handle(TimelineEvent e)\r
+ {\r
+ addToTimeline();\r
+ out.feedSignals(toggle ? Bit.ONE : Bit.ZERO);\r
+ toggle = !toggle;\r
+ }\r
+\r
+ public ReadWriteEnd getOut()\r
+ {\r
+ return out;\r
+ }\r
+\r
+ private void addToTimeline()\r
+ {\r
+ timeline.addEvent(this, delta);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of();\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(out);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public abstract class Component\r
+{\r
+ protected Timeline timeline;\r
+\r
+ public Component(Timeline timeline)\r
+ {\r
+ this.timeline = timeline;\r
+ }\r
+\r
+ /**\r
+ * Returns immutable list of all inputs to the {@link Component} (including e.g. the select bits to a MUX). Intended for visualization\r
+ * in the UI.\r
+ */\r
+ public abstract List<ReadEnd> getAllInputs();\r
+\r
+ /**\r
+ * Returns immutable list of all outputs to the {@link Component}. Intended for visualization in the UI.\r
+ */\r
+ public abstract List<ReadWriteEnd> getAllOutputs();\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.BitVector;\r
+import mograsim.logic.core.wires.WireObserver;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class Connector extends Component implements WireObserver\r
+{\r
+ private boolean connected;\r
+ private final ReadWriteEnd a;\r
+ private final ReadWriteEnd b;\r
+\r
+ public Connector(Timeline timeline, ReadWriteEnd a, ReadWriteEnd b)\r
+ {\r
+ super(timeline);\r
+ if (a.length() != b.length())\r
+ throw new IllegalArgumentException(String.format("WireArray width does not match: %d, %d", a.length(), b.length()));\r
+ this.a = a;\r
+ this.b = b;\r
+ a.addObserver(this);\r
+ b.addObserver(this);\r
+ }\r
+\r
+ public void connect()\r
+ {\r
+ connected = true;\r
+ update(a);\r
+ update(b);\r
+ }\r
+\r
+ public void disconnect()\r
+ {\r
+ connected = false;\r
+ a.clearSignals();\r
+ b.clearSignals();\r
+ }\r
+\r
+ public void setConnection(boolean connected)\r
+ {\r
+ if (connected)\r
+ connect();\r
+ else\r
+ disconnect();\r
+ }\r
+\r
+ @Override\r
+ public void update(ReadEnd initiator, BitVector oldValues)\r
+ {\r
+ if (connected)\r
+ timeline.addEvent(e -> update(initiator), 1);\r
+ }\r
+\r
+ private void update(ReadEnd initiator)\r
+ {\r
+ if (initiator == a)\r
+ b.feedSignals(a.wireValuesExcludingMe());\r
+ else\r
+ a.feedSignals(b.wireValuesExcludingMe());\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of(a, b);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(a, b);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.wires.Wire;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+/**\r
+ * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the\r
+ * output.\r
+ * \r
+ * @author Fabian Stemmler\r
+ *\r
+ */\r
+public class Demux extends BasicComponent\r
+{\r
+ private final ReadEnd select, in;\r
+ private final ReadWriteEnd[] outputs;\r
+ private final int outputSize;\r
+ private int selected = -1;\r
+\r
+ /**\r
+ * Output {@link Wire}s and in must be of uniform length\r
+ * \r
+ * @param in Must be of uniform length with all outputs.\r
+ * @param select Indexes the output array to which the input is mapped. Must have enough bits to index all outputs.\r
+ * @param outputs One of these outputs receives the input signal, depending on the select bits\r
+ */\r
+ public Demux(Timeline timeline, int processTime, ReadEnd in, ReadEnd select, ReadWriteEnd... outputs)\r
+ {\r
+ super(timeline, processTime);\r
+ outputSize = in.length();\r
+\r
+ this.in = in;\r
+ this.outputs = outputs;\r
+ for (int i = 0; i < this.outputs.length; i++)\r
+ {\r
+ if (outputs[i].length() != outputSize)\r
+ throw new IllegalArgumentException("All DEMUX wire arrays must be of uniform length!");\r
+ this.outputs[i] = outputs[i];\r
+ }\r
+\r
+ this.select = select;\r
+ select.addObserver(this);\r
+\r
+ int maxInputs = 1 << select.length();\r
+ if (this.outputs.length > maxInputs)\r
+ throw new IllegalArgumentException("There are more outputs (" + this.outputs.length + ") to the DEMUX than supported by "\r
+ + select.length() + " select bits (" + maxInputs + ").");\r
+ in.addObserver(this);\r
+ }\r
+\r
+ @Override\r
+ public void compute()\r
+ {\r
+ int selectValue = select.hasNumericValue() ? (int) select.getUnsignedValue() : -1;\r
+ if (selectValue >= outputs.length)\r
+ selectValue = -1;\r
+\r
+ if (selected != selectValue && selected != -1)\r
+ outputs[selected].clearSignals();\r
+\r
+ selected = selectValue;\r
+\r
+ if (selectValue != -1)\r
+ outputs[selectValue].feedSignals(in.getValues());\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of(in, select);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(outputs);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.Bit;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+/**\r
+ * This class models a simple on/off (ONE/ZERO) switch for user interaction.\r
+ *\r
+ * @author Christian Femers\r
+ *\r
+ */\r
+public class ManualSwitch extends Component\r
+{\r
+ private ReadWriteEnd output;\r
+ private boolean isOn;\r
+\r
+ public ManualSwitch(Timeline timeline, ReadWriteEnd output)\r
+ {\r
+ super(timeline);\r
+ if (output.length() != 1)\r
+ throw new IllegalArgumentException("Switch output can be only a single wire");\r
+ this.output = output;\r
+ }\r
+\r
+ public void switchOn()\r
+ {\r
+ setState(true);\r
+ }\r
+\r
+ public void switchOff()\r
+ {\r
+ setState(false);\r
+ }\r
+\r
+ public void toggle()\r
+ {\r
+ setState(!isOn);\r
+ }\r
+\r
+ public void setState(boolean isOn)\r
+ {\r
+ if (this.isOn == isOn)\r
+ return;\r
+ this.isOn = isOn;\r
+ output.feedSignals(getValue());\r
+ }\r
+\r
+ public boolean isOn()\r
+ {\r
+ return isOn;\r
+ }\r
+\r
+ public Bit getValue()\r
+ {\r
+ return isOn ? Bit.ONE : Bit.ZERO;\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of();\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(output);\r
+ }\r
+\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.BitVector;\r
+import mograsim.logic.core.wires.Wire;\r
+import mograsim.logic.core.wires.WireObserver;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class Merger extends Component implements WireObserver\r
+{\r
+ private ReadWriteEnd out;\r
+ private ReadEnd[] inputs;\r
+ private int[] beginningIndex;\r
+\r
+ /**\r
+ * \r
+ * @param union The output of merging n {@link Wire}s into one. Must have length = a1.length() + a2.length() + ... + an.length().\r
+ * @param inputs The inputs to be merged into the union\r
+ */\r
+ public Merger(Timeline timeline, ReadWriteEnd union, ReadEnd... inputs)\r
+ {\r
+ super(timeline);\r
+ this.inputs = inputs;\r
+ this.out = union;\r
+ this.beginningIndex = new int[inputs.length];\r
+\r
+ int length = 0;\r
+ for (int i = 0; i < inputs.length; i++)\r
+ {\r
+ beginningIndex[i] = length;\r
+ length += inputs[i].length();\r
+ inputs[i].addObserver(this);\r
+ }\r
+\r
+ if (length != union.length())\r
+ throw new IllegalArgumentException(\r
+ "The output of merging n WireArrays into one must have length = a1.length() + a2.length() + ... + an.length().");\r
+ }\r
+\r
+ public ReadEnd getInput(int index)\r
+ {\r
+ return inputs[index];\r
+ }\r
+\r
+ public ReadEnd getUnion()\r
+ {\r
+ return out;\r
+ }\r
+\r
+ @Override\r
+ public void update(ReadEnd initiator, BitVector oldValues)\r
+ {\r
+ int index = find(initiator);\r
+ int beginning = beginningIndex[index];\r
+ out.feedSignals(beginning, inputs[index].getValues());\r
+ }\r
+\r
+ private int find(ReadEnd r)\r
+ {\r
+ for (int i = 0; i < inputs.length; i++)\r
+ if (inputs[i] == r)\r
+ return i;\r
+ return -1;\r
+ }\r
+\r
+ public ReadEnd[] getInputs()\r
+ {\r
+ return inputs.clone();\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of(inputs);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(out);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.wires.Wire;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+/**\r
+ * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the\r
+ * output.\r
+ * \r
+ * @author Fabian Stemmler\r
+ *\r
+ */\r
+public class Mux extends BasicComponent\r
+{\r
+ private ReadEnd select;\r
+ private ReadWriteEnd out;\r
+ private ReadEnd[] inputs;\r
+ private final int outputSize;\r
+\r
+ /**\r
+ * Input {@link Wire}s and out must be of uniform length\r
+ * \r
+ * @param out Must be of uniform length with all inputs.\r
+ * @param select Indexes the input array which is to be mapped to the output. Must have enough bits to index all inputs.\r
+ * @param inputs One of these inputs is mapped to the output, depending on the select bits\r
+ */\r
+ public Mux(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd select, ReadEnd... inputs)\r
+ {\r
+ super(timeline, processTime);\r
+ outputSize = out.length();\r
+\r
+ this.inputs = inputs.clone();\r
+ for (int i = 0; i < this.inputs.length; i++)\r
+ {\r
+ if (inputs[i].length() != outputSize)\r
+ throw new IllegalArgumentException("All MUX wire arrays must be of uniform length!");\r
+ inputs[i].addObserver(this);\r
+ }\r
+\r
+ this.select = select;\r
+ select.addObserver(this);\r
+\r
+ int maxInputs = 1 << select.length();\r
+ if (this.inputs.length > maxInputs)\r
+ throw new IllegalArgumentException("There are more inputs (" + this.inputs.length + ") to the MUX than supported by "\r
+ + select.length() + " select bits (" + maxInputs + ").");\r
+\r
+ this.out = out;\r
+ }\r
+\r
+ public ReadEnd getOut()\r
+ {\r
+ return out;\r
+ }\r
+\r
+ public ReadEnd getSelect()\r
+ {\r
+ return select;\r
+ }\r
+\r
+ @Override\r
+ public void compute()\r
+ {\r
+ int selectValue;\r
+ if (!select.hasNumericValue() || (selectValue = (int) select.getUnsignedValue()) >= inputs.length)\r
+ {\r
+ out.clearSignals();\r
+ return;\r
+ }\r
+\r
+ ReadEnd active = inputs[selectValue];\r
+ out.feedSignals(active.getValues());\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ ArrayList<ReadEnd> wires = new ArrayList<ReadEnd>(Arrays.asList(inputs));\r
+ wires.add(select);\r
+ return Collections.unmodifiableList(wires);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(out);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.BitVector;\r
+import mograsim.logic.core.wires.WireObserver;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class Splitter extends Component implements WireObserver\r
+{\r
+ private ReadEnd input;\r
+ private ReadWriteEnd[] outputs;\r
+\r
+ public Splitter(Timeline timeline, ReadEnd input, ReadWriteEnd... outputs)\r
+ {\r
+ super(timeline);\r
+ this.input = input;\r
+ this.outputs = outputs;\r
+ input.addObserver(this);\r
+ int length = 0;\r
+ for (ReadEnd out : outputs)\r
+ length += out.length();\r
+\r
+ if (input.length() != length)\r
+ throw new IllegalArgumentException(\r
+ "The input of splitting one into n WireArrays must have length = a1.length() + a2.length() + ... + an.length().");\r
+ }\r
+\r
+ protected void compute()\r
+ {\r
+ BitVector inputBits = input.getValues();\r
+ int startIndex = 0;\r
+ for (int i = 0; i < outputs.length; i++)\r
+ {\r
+ outputs[i].feedSignals(inputBits.subVector(startIndex, startIndex + outputs[i].length()));\r
+ startIndex += outputs[i].length();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void update(ReadEnd initiator, BitVector oldValues)\r
+ {\r
+ compute();\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of(input);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(outputs);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.Bit;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class TriStateBuffer extends BasicComponent\r
+{\r
+ ReadEnd in, enable;\r
+ ReadWriteEnd out;\r
+\r
+ public TriStateBuffer(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out, ReadEnd enable)\r
+ {\r
+ super(timeline, processTime);\r
+ if (in.length() != out.length())\r
+ throw new IllegalArgumentException(\r
+ "Tri-state output must have the same amount of bits as the input. Input: " + in.length() + " Output: " + out.length());\r
+ if (enable.length() != 1)\r
+ throw new IllegalArgumentException("Tri-state enable must have exactly one bit, not " + enable.length() + ".");\r
+ this.in = in;\r
+ in.addObserver(this);\r
+ this.enable = enable;\r
+ enable.addObserver(this);\r
+ this.out = out;\r
+ }\r
+\r
+ @Override\r
+ protected void compute()\r
+ {\r
+ if (enable.getValue() == Bit.ONE)\r
+ out.feedSignals(in.getValues());\r
+ else\r
+ out.clearSignals();\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of(in, enable);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(out);\r
+ }\r
+\r
+}\r
--- /dev/null
+package mograsim.logic.core.components.gates;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.BitVector.BitVectorMutator;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class AndGate extends MultiInputGate\r
+{\r
+ public AndGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)\r
+ {\r
+ super(timeline, processTime, BitVectorMutator::and, out, in);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components.gates;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.components.BasicComponent;\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.MutationOperation;\r
+import mograsim.logic.core.types.BitVector.BitVectorMutator;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public abstract class MultiInputGate extends BasicComponent\r
+{\r
+ protected ReadEnd[] in;\r
+ protected ReadWriteEnd out;\r
+ protected final int length;\r
+ protected MutationOperation op;\r
+\r
+ protected MultiInputGate(Timeline timeline, int processTime, MutationOperation op, ReadWriteEnd out, ReadEnd... in)\r
+ {\r
+ super(timeline, processTime);\r
+ this.op = op;\r
+ length = out.length();\r
+ this.in = in.clone();\r
+ if (in.length < 1)\r
+ throw new IllegalArgumentException(String.format("Cannot create gate with %d wires.", in.length));\r
+ for (ReadEnd w : in)\r
+ {\r
+ if (w.length() != length)\r
+ throw new IllegalArgumentException("All wires connected to the gate must be of uniform length.");\r
+ w.addObserver(this);\r
+ }\r
+ this.out = out;\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of(in);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(out);\r
+ }\r
+\r
+ @Override\r
+ protected void compute()\r
+ {\r
+ BitVectorMutator mutator = BitVectorMutator.empty();\r
+ for (ReadEnd w : in)\r
+ op.apply(mutator, w.getValues());\r
+ out.feedSignals(mutator.get());\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components.gates;\r
+\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.components.BasicComponent;\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class NotGate extends BasicComponent\r
+{\r
+ private ReadEnd in;\r
+ private ReadWriteEnd out;\r
+\r
+ public NotGate(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out)\r
+ {\r
+ super(timeline, processTime);\r
+ this.in = in;\r
+ in.addObserver(this);\r
+ this.out = out;\r
+ }\r
+\r
+ @Override\r
+ protected void compute()\r
+ {\r
+ out.feedSignals(in.getValues().not());\r
+ }\r
+\r
+ public ReadEnd getIn()\r
+ {\r
+ return in;\r
+ }\r
+\r
+ public ReadEnd getOut()\r
+ {\r
+ return out;\r
+ }\r
+\r
+ @Override\r
+ public List<ReadEnd> getAllInputs()\r
+ {\r
+ return List.of(in);\r
+ }\r
+\r
+ @Override\r
+ public List<ReadWriteEnd> getAllOutputs()\r
+ {\r
+ return List.of(out);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components.gates;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.BitVector.BitVectorMutator;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+public class OrGate extends MultiInputGate\r
+{\r
+ public OrGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)\r
+ {\r
+ super(timeline, processTime, BitVectorMutator::or, out, in);\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.components.gates;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.BitVector.BitVectorMutator;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+/**\r
+ * Outputs 1 when the number of 1 inputs is odd.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+public class XorGate extends MultiInputGate\r
+{\r
+ public XorGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)\r
+ {\r
+ super(timeline, processTime, BitVectorMutator::xor, out, in);\r
+ }\r
+\r
+}\r
--- /dev/null
+package mograsim.logic.core.tests;\r
+\r
+import static org.junit.Assert.assertTrue;\r
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;\r
+import static org.junit.jupiter.api.Assertions.assertEquals;\r
+import static org.junit.jupiter.api.Assertions.fail;\r
+\r
+import java.util.function.LongConsumer;\r
+\r
+import org.junit.jupiter.api.Test;\r
+\r
+import mograsim.logic.core.components.Connector;\r
+import mograsim.logic.core.components.Demux;\r
+import mograsim.logic.core.components.Merger;\r
+import mograsim.logic.core.components.Mux;\r
+import mograsim.logic.core.components.Splitter;\r
+import mograsim.logic.core.components.TriStateBuffer;\r
+import mograsim.logic.core.components.gates.AndGate;\r
+import mograsim.logic.core.components.gates.NotGate;\r
+import mograsim.logic.core.components.gates.OrGate;\r
+import mograsim.logic.core.components.gates.XorGate;\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.Bit;\r
+import mograsim.logic.core.types.BitVector;\r
+import mograsim.logic.core.wires.Wire;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;\r
+\r
+class ComponentTest\r
+{\r
+ private Timeline t = new Timeline(11);\r
+\r
+ @Test\r
+ void circuitExampleTest()\r
+ {\r
+ Wire a = new Wire(t, 1, 1), b = new Wire(t, 1, 1), c = new Wire(t, 1, 10), d = new Wire(t, 2, 1), e = new Wire(t, 1, 1),\r
+ f = new Wire(t, 1, 1), g = new Wire(t, 1, 1), h = new Wire(t, 2, 1), i = new Wire(t, 2, 1), j = new Wire(t, 1, 1),\r
+ k = new Wire(t, 1, 1);\r
+ new AndGate(t, 1, f.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());\r
+ new NotGate(t, 1, f.createReadOnlyEnd(), g.createReadWriteEnd());\r
+ new Merger(t, h.createReadWriteEnd(), c.createReadOnlyEnd(), g.createReadOnlyEnd());\r
+ new Mux(t, 1, i.createReadWriteEnd(), e.createReadOnlyEnd(), h.createReadOnlyEnd(), d.createReadOnlyEnd());\r
+ new Splitter(t, i.createReadOnlyEnd(), k.createReadWriteEnd(), j.createReadWriteEnd());\r
+\r
+ a.createReadWriteEnd().feedSignals(Bit.ZERO);\r
+ b.createReadWriteEnd().feedSignals(Bit.ONE);\r
+ c.createReadWriteEnd().feedSignals(Bit.ZERO);\r
+ d.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE);\r
+ e.createReadWriteEnd().feedSignals(Bit.ZERO);\r
+\r
+ t.executeAll();\r
+\r
+ assertEquals(Bit.ONE, j.getValue());\r
+ assertEquals(Bit.ZERO, k.getValue());\r
+ }\r
+\r
+ @Test\r
+ void splitterTest()\r
+ {\r
+ t.reset();\r
+ Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), in = new Wire(t, 8, 1);\r
+ in.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
+ new Splitter(t, in.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(), c.createReadWriteEnd());\r
+\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(a.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO);\r
+ assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO);\r
+ assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE);\r
+ }\r
+\r
+ @Test\r
+ void mergerTest()\r
+ {\r
+ t.reset();\r
+ Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), out = new Wire(t, 8, 1);\r
+ a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO);\r
+ b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO);\r
+ c.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);\r
+\r
+ new Merger(t, out.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());\r
+\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
+ }\r
+\r
+ @Test\r
+ void triStateBufferTest()\r
+ {\r
+ Wire a = new Wire(t, 1, 1), b = new Wire(t, 1, 1), en = new Wire(t, 1, 1), notEn = new Wire(t, 1, 1);\r
+ new NotGate(t, 1, en.createReadOnlyEnd(), notEn.createReadWriteEnd());\r
+ new TriStateBuffer(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd(), en.createReadOnlyEnd());\r
+ new TriStateBuffer(t, 1, b.createReadOnlyEnd(), a.createReadWriteEnd(), notEn.createReadOnlyEnd());\r
+\r
+ ReadWriteEnd enI = en.createReadWriteEnd(), aI = a.createReadWriteEnd(), bI = b.createReadWriteEnd();\r
+ enI.feedSignals(Bit.ONE);\r
+ aI.feedSignals(Bit.ONE);\r
+ bI.feedSignals(Bit.Z);\r
+\r
+ t.executeAll();\r
+\r
+ assertEquals(Bit.ONE, b.getValue());\r
+\r
+ bI.feedSignals(Bit.ZERO);\r
+\r
+ t.executeAll();\r
+\r
+ assertEquals(Bit.X, b.getValue());\r
+ assertEquals(Bit.ONE, a.getValue());\r
+\r
+ aI.clearSignals();\r
+ enI.feedSignals(Bit.ZERO);\r
+\r
+ t.executeAll();\r
+\r
+ assertEquals(Bit.ZERO, a.getValue());\r
+\r
+ }\r
+\r
+ @Test\r
+ void muxTest()\r
+ {\r
+ t.reset();\r
+ Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), out = new Wire(t, 4, 1);\r
+ ReadWriteEnd selectIn = select.createReadWriteEnd();\r
+\r
+ selectIn.feedSignals(Bit.ZERO, Bit.ZERO);\r
+ a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
+ c.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
+\r
+ new Mux(t, 1, out.createReadWriteEnd(), select.createReadOnlyEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(),\r
+ c.createReadOnlyEnd());\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(out.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
+ selectIn.feedSignals(Bit.ZERO, Bit.ONE);\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
+\r
+ selectIn.feedSignals(Bit.ONE, Bit.ONE);\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(out.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);\r
+\r
+ }\r
+\r
+ @Test\r
+ void demuxTest()\r
+ {\r
+ t.reset();\r
+ Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), in = new Wire(t, 4, 1);\r
+ ReadWriteEnd selectIn = select.createReadWriteEnd();\r
+\r
+ selectIn.feedSignals(Bit.ZERO, Bit.ZERO);\r
+ in.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
+\r
+ new Demux(t, 1, in.createReadOnlyEnd(), select.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(),\r
+ c.createReadWriteEnd());\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(a.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
+ assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);\r
+ assertBitArrayEquals(c.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);\r
+ selectIn.feedSignals(Bit.ZERO, Bit.ONE);\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);\r
+ assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);\r
+ assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);\r
+\r
+ selectIn.feedSignals(Bit.ONE, Bit.ONE);\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);\r
+ assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);\r
+ assertBitArrayEquals(c.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);\r
+\r
+ }\r
+\r
+ @Test\r
+ void andTest()\r
+ {\r
+ t.reset();\r
+ Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);\r
+ new AndGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());\r
+ a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);\r
+ b.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
+\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(c.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ZERO);\r
+ }\r
+\r
+ @Test\r
+ void orTest()\r
+ {\r
+ t.reset();\r
+ Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);\r
+ new OrGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());\r
+ a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);\r
+ b.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);\r
+\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ONE);\r
+ }\r
+\r
+ @Test\r
+ void xorTest()\r
+ {\r
+ t.reset();\r
+ Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2), c = new Wire(t, 3, 1), d = new Wire(t, 3, 1);\r
+ new XorGate(t, 1, d.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());\r
+ a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);\r
+ b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);\r
+ c.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);\r
+\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(d.getValues(), Bit.ZERO, Bit.ONE, Bit.ONE);\r
+ }\r
+\r
+ @Test\r
+ void notTest()\r
+ {\r
+ t.reset();\r
+ Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2);\r
+ new NotGate(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd());\r
+ a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);\r
+\r
+ t.executeAll();\r
+\r
+ assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO, Bit.ZERO);\r
+ }\r
+\r
+ @Test\r
+ void rsLatchCircuitTest()\r
+ {\r
+ t.reset();\r
+ Wire r = new Wire(t, 1, 1), s = new Wire(t, 1, 1), t1 = new Wire(t, 1, 15), t2 = new Wire(t, 1, 1), q = new Wire(t, 1, 1),\r
+ nq = new Wire(t, 1, 1);\r
+\r
+ new OrGate(t, 1, t2.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());\r
+ new OrGate(t, 1, t1.createReadWriteEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());\r
+ new NotGate(t, 1, t2.createReadOnlyEnd(), q.createReadWriteEnd());\r
+ new NotGate(t, 1, t1.createReadOnlyEnd(), nq.createReadWriteEnd());\r
+\r
+ ReadWriteEnd sIn = s.createReadWriteEnd(), rIn = r.createReadWriteEnd();\r
+\r
+ sIn.feedSignals(Bit.ONE);\r
+ rIn.feedSignals(Bit.ZERO);\r
+\r
+ t.executeAll();\r
+\r
+ assertEquals(Bit.ONE, q.getValue());\r
+ assertEquals(Bit.ZERO, nq.getValue());\r
+\r
+ sIn.feedSignals(Bit.ZERO);\r
+\r
+ t.executeAll();\r
+ assertEquals(Bit.ONE, q.getValue());\r
+ assertEquals(Bit.ZERO, nq.getValue());\r
+\r
+ rIn.feedSignals(Bit.ONE);\r
+\r
+ t.executeAll();\r
+\r
+ assertEquals(Bit.ZERO, q.getValue());\r
+ assertEquals(Bit.ONE, nq.getValue());\r
+ }\r
+\r
+ @Test\r
+ void numericValueTest()\r
+ {\r
+ t.reset();\r
+\r
+ Wire a = new Wire(t, 4, 1);\r
+ a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE);\r
+\r
+ t.executeAll();\r
+\r
+ assertEquals(15, a.getUnsignedValue());\r
+ assertEquals(-1, a.getSignedValue());\r
+ }\r
+\r
+ boolean flag = false;\r
+\r
+ @Test\r
+ void simpleTimelineTest()\r
+ {\r
+ Timeline t = new Timeline(3);\r
+ flag = false;\r
+ t.addEvent((e) ->\r
+ {\r
+ if (!flag)\r
+ fail();\r
+ flag = false;\r
+ }, 15);\r
+ t.addEvent((e) ->\r
+ {\r
+ if (flag)\r
+ fail();\r
+ flag = true;\r
+ }, 10);\r
+ t.addEvent((e) ->\r
+ {\r
+ if (flag)\r
+ fail();\r
+ flag = true;\r
+ }, 20);\r
+ t.addEvent((e) ->\r
+ {\r
+ fail("Only supposed to execute until timestamp 20, not 25");\r
+ }, 25);\r
+\r
+ t.executeUntil(t.laterThan(20), 100);\r
+\r
+ if (!flag)\r
+ fail();\r
+ }\r
+\r
+ @Test\r
+ void multipleInputs()\r
+ {\r
+ t.reset();\r
+ Wire w = new Wire(t, 2, 1);\r
+ ReadWriteEnd wI1 = w.createReadWriteEnd(), wI2 = w.createReadWriteEnd();\r
+ wI1.feedSignals(Bit.ONE, Bit.Z);\r
+ wI2.feedSignals(Bit.Z, Bit.X);\r
+ t.executeAll();\r
+ assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.X);\r
+\r
+ wI2.feedSignals(Bit.ZERO, Bit.Z);\r
+ t.executeAll();\r
+ assertBitArrayEquals(w.getValues(), Bit.X, Bit.Z);\r
+\r
+ wI2.feedSignals(Bit.Z, Bit.Z);\r
+ t.executeAll();\r
+ assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);\r
+\r
+ wI2.feedSignals(Bit.ONE, Bit.Z);\r
+ ReadEnd rE = w.createReadOnlyEnd();\r
+ rE.addObserver((i, oldValues) -> fail("WireEnd notified observer, although value did not change."));\r
+ t.executeAll();\r
+ rE.close();\r
+ wI1.feedSignals(Bit.X, Bit.X);\r
+ t.executeAll();\r
+ wI1.addObserver((i, oldValues) -> fail("WireEnd notified observer, although it was closed."));\r
+ wI1.close();\r
+ assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);\r
+ }\r
+\r
+ @Test\r
+ void wireConnections()\r
+ {\r
+ // Nur ein Experiment, was über mehrere 'passive' Bausteine hinweg passieren würde\r
+\r
+ t.reset();\r
+\r
+ Wire a = new Wire(t, 1, 2);\r
+ Wire b = new Wire(t, 1, 2);\r
+ Wire c = new Wire(t, 1, 2);\r
+ ReadWriteEnd aI = a.createReadWriteEnd();\r
+ ReadWriteEnd bI = b.createReadWriteEnd();\r
+ ReadWriteEnd cI = c.createReadWriteEnd();\r
+\r
+ TestBitDisplay test = new TestBitDisplay(t, c.createReadOnlyEnd());\r
+ TestBitDisplay test2 = new TestBitDisplay(t, a.createReadOnlyEnd());\r
+ LongConsumer print = time -> System.out.format("Time %2d\n a: %s\n b: %s\n c: %s\n", time, a, b, c);\r
+\r
+ cI.feedSignals(Bit.ONE);\r
+ test.assertAfterSimulationIs(print, Bit.ONE);\r
+\r
+ cI.feedSignals(Bit.X);\r
+ test.assertAfterSimulationIs(print, Bit.X);\r
+\r
+ cI.feedSignals(Bit.X);\r
+ cI.feedSignals(Bit.Z);\r
+ test.assertAfterSimulationIs(print, Bit.Z);\r
+\r
+ new Connector(t, b.createReadWriteEnd(), c.createReadWriteEnd()).connect();\r
+ test.assertAfterSimulationIs(print, Bit.Z);\r
+ System.err.println("ONE");\r
+ bI.feedSignals(Bit.ONE);\r
+ test.assertAfterSimulationIs(print, Bit.ONE);\r
+ System.err.println("ZERO");\r
+ bI.feedSignals(Bit.ZERO);\r
+ test.assertAfterSimulationIs(print, Bit.ZERO);\r
+ System.err.println("Z");\r
+ bI.feedSignals(Bit.Z);\r
+ test.assertAfterSimulationIs(print, Bit.Z);\r
+\r
+ new Connector(t, a.createReadWriteEnd(), b.createReadWriteEnd()).connect();\r
+ System.err.println("Z 2");\r
+ aI.feedSignals(Bit.Z);\r
+ test.assertAfterSimulationIs(print, Bit.Z);\r
+ test2.assertAfterSimulationIs(Bit.Z);\r
+ System.err.println("ONE 2");\r
+ aI.feedSignals(Bit.ONE);\r
+ test.assertAfterSimulationIs(print, Bit.ONE);\r
+ test2.assertAfterSimulationIs(Bit.ONE);\r
+ System.err.println("ZERO 2");\r
+ aI.feedSignals(Bit.ZERO);\r
+ test.assertAfterSimulationIs(print, Bit.ZERO);\r
+ test2.assertAfterSimulationIs(Bit.ZERO);\r
+ System.err.println("Z 2 II");\r
+ aI.feedSignals(Bit.Z);\r
+ test.assertAfterSimulationIs(print, Bit.Z);\r
+ test2.assertAfterSimulationIs(Bit.Z);\r
+\r
+ System.err.println("No Conflict yet");\r
+ bI.feedSignals(Bit.ONE);\r
+ test.assertAfterSimulationIs(print, Bit.ONE);\r
+ test2.assertAfterSimulationIs(Bit.ONE);\r
+ aI.feedSignals(Bit.ONE);\r
+ test.assertAfterSimulationIs(print, Bit.ONE);\r
+ test2.assertAfterSimulationIs(Bit.ONE);\r
+ System.err.println("Conflict");\r
+ aI.feedSignals(Bit.ZERO);\r
+ test.assertAfterSimulationIs(print, Bit.X);\r
+ test2.assertAfterSimulationIs(Bit.X);\r
+ aI.feedSignals(Bit.ONE);\r
+ test.assertAfterSimulationIs(print, Bit.ONE);\r
+ test2.assertAfterSimulationIs(Bit.ONE);\r
+ }\r
+\r
+ private static void assertBitArrayEquals(BitVector actual, Bit... expected)\r
+ {\r
+ assertArrayEquals(expected, actual.getBits());\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.tests;\r
+\r
+import java.awt.Color;\r
+import java.awt.Graphics;\r
+import java.awt.Graphics2D;\r
+import java.awt.Rectangle;\r
+import java.awt.RenderingHints;\r
+import java.awt.event.MouseEvent;\r
+import java.awt.event.MouseListener;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+\r
+import javax.swing.JFrame;\r
+import javax.swing.JPanel;\r
+import javax.swing.WindowConstants;\r
+\r
+import mograsim.logic.core.components.ManualSwitch;\r
+import mograsim.logic.core.components.gates.NotGate;\r
+import mograsim.logic.core.components.gates.OrGate;\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.timeline.Timeline.ExecutionResult;\r
+import mograsim.logic.core.wires.Wire;\r
+\r
+public class GUITest extends JPanel\r
+{\r
+\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ private static final int WIRE_DELAY = 40;\r
+ private static final int OR_DELAY = 100;\r
+ private static final int NOT_DELAY = 100;\r
+\r
+ private Timeline t = new Timeline(11);\r
+\r
+ Wire r = new Wire(t, 1, WIRE_DELAY);\r
+ Wire s = new Wire(t, 1, WIRE_DELAY);\r
+ Wire t1 = new Wire(t, 1, WIRE_DELAY);\r
+ Wire t2 = new Wire(t, 1, WIRE_DELAY);\r
+ Wire q = new Wire(t, 1, WIRE_DELAY);\r
+ Wire nq = new Wire(t, 1, WIRE_DELAY);\r
+\r
+ ManualSwitch rIn = new ManualSwitch(t, r.createReadWriteEnd());\r
+ ManualSwitch sIn = new ManualSwitch(t, s.createReadWriteEnd());\r
+\r
+ OrGate or1 = new OrGate(t, OR_DELAY, t2.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());\r
+ OrGate or2 = new OrGate(t, OR_DELAY, t1.createReadWriteEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());\r
+ NotGate not1 = new NotGate(t, NOT_DELAY, t2.createReadOnlyEnd(), q.createReadWriteEnd());\r
+ NotGate not2 = new NotGate(t, NOT_DELAY, t1.createReadOnlyEnd(), nq.createReadWriteEnd());\r
+\r
+ Map<ManualSwitch, Rectangle> switchMap = new HashMap<>();\r
+\r
+ int height;\r
+ int width;\r
+ boolean sizeChanged;\r
+\r
+ public GUITest()\r
+ {\r
+ addMouseListener(new MouseListener()\r
+ {\r
+\r
+ @Override\r
+ public void mouseReleased(MouseEvent e)\r
+ {\r
+ for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())\r
+ {\r
+ if (dim.getValue().contains(e.getPoint()))\r
+ {\r
+ dim.getKey().switchOff();\r
+ repaint();\r
+ }\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void mousePressed(MouseEvent e)\r
+ {\r
+ for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())\r
+ {\r
+ if (dim.getValue().contains(e.getPoint()))\r
+ {\r
+ dim.getKey().switchOn();\r
+ repaint();\r
+ }\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void mouseExited(MouseEvent e)\r
+ {\r
+ // none\r
+ }\r
+\r
+ @Override\r
+ public void mouseEntered(MouseEvent e)\r
+ {\r
+ // none\r
+ }\r
+\r
+ @Override\r
+ public void mouseClicked(MouseEvent e)\r
+ {\r
+ // If you want toggle buttons, use this code instead\r
+// for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet()) {\r
+// if (dim.getValue().contains(e.getPoint())) {\r
+// dim.getKey().toggle();\r
+// repaint();\r
+// }\r
+// }\r
+ }\r
+ });\r
+ }\r
+\r
+ public Timeline getTimeline()\r
+ {\r
+ return t;\r
+ };\r
+\r
+ @Override\r
+ public void paint(Graphics some_g)\r
+ {\r
+ super.paint(some_g);\r
+ Graphics2D g = ((Graphics2D) some_g);\r
+ g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);\r
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+ g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);\r
+\r
+ checkSizeChange();\r
+ adaptFont(g);\r
+\r
+ drawWire(g, r, "r", 2, 9, 4, 9);\r
+\r
+ drawWire(g, s, "s", 2, 3, 4, 3);\r
+\r
+ drawWire(g, t2, "t2", 5, 8.5, 6, 8.5);\r
+\r
+ drawWire(g, t1, "t1", 5, 3.5, 6, 3.5);\r
+\r
+ drawWire(g, q, "q", 7, 8.5, 9, 8.5);\r
+\r
+ drawWire(g, nq, "nq", 7, 3.5, 9, 3.5);\r
+\r
+ drawWire(g, q, "", 7.5, 8.5, 7.5, 7.5);\r
+ drawWire(g, q, "", 7.5, 7.5, 3, 4.5);\r
+ drawWire(g, q, "", 3, 4.5, 3, 4);\r
+ drawWire(g, q, "q", 3, 4, 4, 4);\r
+\r
+ drawWire(g, nq, "", 7.5, 3.5, 7.5, 4.5);\r
+ drawWire(g, nq, "", 7.5, 4.5, 3, 7.5);\r
+ drawWire(g, nq, "", 3, 7.5, 3, 8);\r
+ drawWire(g, nq, "nq", 3, 8, 4, 8);\r
+\r
+ drawSquare(g, 4, 8, "OR");\r
+ drawSquare(g, 4, 3, "OR");\r
+\r
+ drawSquare(g, 6, 8, "NOT");\r
+ drawSquare(g, 6, 3, "NOT");\r
+\r
+ drawSwitch(g, rIn, "Switch R", 0.5, 8.25, 2, 9.75);\r
+ drawSwitch(g, sIn, "Switch S", 0.5, 2.25, 2, 3.75);\r
+\r
+ drawString(g, "Hint: drag the cursor out of the pressed switch to keep it's state", 5, 0, 0.0, 1.0);\r
+ }\r
+\r
+ private void checkSizeChange()\r
+ {\r
+ sizeChanged = height != getHeight() || width != getWidth();\r
+ if (sizeChanged)\r
+ {\r
+ height = getHeight();\r
+ width = getWidth();\r
+ }\r
+ }\r
+\r
+ private void adaptFont(Graphics g)\r
+ {\r
+ g.setFont(g.getFont().deriveFont(Math.min(height, width) / 40f));\r
+ }\r
+\r
+ private void drawString(Graphics g, String s, int x, int y, double anchorX, double anchorY)\r
+ {\r
+ int h = g.getFontMetrics().getAscent();\r
+ int w = g.getFontMetrics().stringWidth(s);\r
+ g.drawString(s, x - (int) (w * anchorX), y + (int) (h * anchorY));\r
+ }\r
+\r
+ private void drawWire(Graphics g, Wire wa, String name, double x1, double y1, double x2, double y2)\r
+ {\r
+ setTo(g, wa);\r
+ g.drawLine(gX(x1), gY(y1), gX(x2), gY(y2));\r
+ drawString(g, name, (gX(x1) + gX(x2)) / 2, (gY(y1) + gY(y2)) / 2 - 5, 0, 0);\r
+ }\r
+\r
+ private void drawSquare(Graphics g, int posX, int posY, String text)\r
+ {\r
+ int x1 = gX(posX) - 5;\r
+ int x2 = gX(posX + 1) + 5;\r
+ int y1 = gY(posY) - 5;\r
+ int y2 = gY(posY + 1) + 5;\r
+\r
+ g.setColor(Color.WHITE);\r
+ g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\r
+ setBlack(g);\r
+ g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\r
+ drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);\r
+\r
+ }\r
+\r
+ private void drawSwitch(Graphics g, ManualSwitch ms, String text, double posX1, double posY1, double posX2, double posY2)\r
+ {\r
+ int x1 = gX(posX1) - 5;\r
+ int x2 = gX(posX2) + 5;\r
+ int y1 = gY(posY1) - 5;\r
+ int y2 = gY(posY2) + 5;\r
+\r
+ if (sizeChanged)\r
+ {\r
+ Rectangle r = new Rectangle(x1, y1, x2 - x1, y2 - y1);\r
+ switchMap.put(ms, r);\r
+ }\r
+\r
+ g.setColor(ms.isOn() ? Color.getHSBColor(.3f, .5f, 1f) : Color.WHITE);\r
+ g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\r
+ setBlack(g);\r
+ g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\r
+ drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);\r
+ }\r
+\r
+ private static void setBlack(Graphics g)\r
+ {\r
+ g.setColor(Color.BLACK);\r
+ }\r
+\r
+ private static void setTo(Graphics g, Wire wa)\r
+ {\r
+ switch (wa.getValue())\r
+ {\r
+ case ONE:\r
+ g.setColor(Color.GREEN);\r
+ break;\r
+ case X:\r
+ g.setColor(Color.RED);\r
+ break;\r
+ case Z:\r
+ g.setColor(Color.DARK_GRAY);\r
+ break;\r
+ case ZERO:\r
+ g.setColor(Color.BLACK);\r
+ break;\r
+ case U:\r
+ g.setColor(Color.MAGENTA);\r
+ break;\r
+ default:\r
+ throw new IllegalArgumentException();\r
+ }\r
+ }\r
+\r
+ private int gY(double pos)\r
+ {\r
+ return (int) (pos * height / 11);\r
+ }\r
+\r
+ private int gX(double pos)\r
+ {\r
+ return (int) (pos * width / 11) + 50;\r
+ }\r
+\r
+ public static void main(String[] args)\r
+ {\r
+ JFrame f = new JFrame("Test circuit 1.0.0");\r
+ GUITest gt = new GUITest();\r
+ f.add(gt);\r
+ f.setSize(800, 600);\r
+ f.setLocation(500, 400);\r
+ f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);\r
+ f.setVisible(true);\r
+\r
+ long begin = System.currentTimeMillis();\r
+\r
+ long lastFrame = begin;\r
+ long updateT = 16;\r
+\r
+ while (f.isVisible())\r
+ {\r
+ ExecutionResult er = gt.getTimeline().executeUntil(gt.getTimeline().laterThan((lastFrame - begin) * 3), lastFrame + 14);\r
+// if (t.hasNext()) \r
+// t.executeNext();\r
+ if (er != ExecutionResult.NOTHING_DONE)\r
+ gt.repaint(12);\r
+ try\r
+ {\r
+ Thread.sleep(Math.max(updateT - System.currentTimeMillis() + lastFrame, 0));\r
+ }\r
+ catch (Exception e)\r
+ {\r
+ e.printStackTrace();\r
+ }\r
+ lastFrame = System.currentTimeMillis();\r
+ }\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.tests;\r
+\r
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;\r
+\r
+import java.util.function.LongConsumer;\r
+\r
+import mograsim.logic.core.components.BitDisplay;\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.Bit;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+\r
+public final class TestBitDisplay extends BitDisplay\r
+{\r
+\r
+ public TestBitDisplay(Timeline timeline, ReadEnd in)\r
+ {\r
+ super(timeline, in);\r
+ }\r
+\r
+ public void assertDisplays(Bit... expected)\r
+ {\r
+ assertArrayEquals(expected, getDisplayedValue().getBits());\r
+ }\r
+\r
+ public void assertAfterSimulationIs(Bit... expected)\r
+ {\r
+ timeline.executeAll();\r
+ assertDisplays(expected);\r
+ }\r
+\r
+ public void assertAfterSimulationIs(LongConsumer r, Bit... expected)\r
+ {\r
+ while (timeline.hasNext())\r
+ {\r
+ timeline.executeNext();\r
+ r.accept(timeline.getSimulationTime());\r
+ }\r
+ assertDisplays(expected);\r
+ }\r
+\r
+ @Override\r
+ protected void compute()\r
+ {\r
+ super.compute();\r
+ System.out.println("update: value is " + getDisplayedValue());\r
+ }\r
+}\r
--- /dev/null
+package mograsim.logic.core.timeline;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.LongSupplier;
+
+/**
+ * Orders Events by the time they are due to be executed. Can execute Events individually.
+ *
+ * @author Fabian Stemmler
+ *
+ */
+public class Timeline
+{
+ private PriorityQueue<InnerEvent> events;
+ private LongSupplier time;
+ private long lastTimeUpdated = 0;
+
+ private final List<Consumer<TimelineEvent>> eventAddedListener;
+
+ public Timeline(int initCapacity)
+ {
+ events = new PriorityQueue<InnerEvent>(initCapacity);
+
+ eventAddedListener = new ArrayList<>();
+ time = () -> lastTimeUpdated;
+ }
+
+ /**
+ * @param timestamp exclusive
+ * @return true if the first event is later than the timestamp
+ */
+ public BooleanSupplier laterThan(long timestamp)
+ {
+ return () -> timeCmp(events.peek().getTiming(), timestamp) > 0;
+ }
+
+ public boolean hasNext()
+ {
+ return !events.isEmpty();
+ }
+
+ /**
+ * Executes all events at the next timestamp, at which there are any
+ */
+ public void executeNext()
+ {
+ InnerEvent first = events.peek();
+ if (first != null)
+ executeUntil(laterThan(first.getTiming()), -1);
+ }
+
+ public void executeAll()
+ {
+ while (hasNext())
+ executeNext();
+ }
+
+ /**
+ * Executes all events until a given condition is met. The simulation process can be constrained by a real world timestamp.
+ *
+ * @param condition the condition until which the events are be processed
+ * @param stopMillis the System.currentTimeMillis() when simulation definitely needs to stop. A value of -1 means no timeout.
+ * @return State of the event execution
+ * @formatter:off
+ * <code>NOTHING_DONE</code> if the {@link Timeline} was already empty
+ * <code>EXEC_OUT_OF_TIME</code> if the given maximum time was reached
+ * <code>EXEC_UNTIL_CONDITION</code> if the condition was met
+ * <code>EXEC_UNTIL_EMPTY</code> if events were executed until the {@link Timeline} was empty
+ * @formatter:on
+ * @author Christian Femers, Fabian Stemmler
+ */
+ public ExecutionResult executeUntil(BooleanSupplier condition, long stopMillis)
+ {
+ if (events.isEmpty())
+ {
+ lastTimeUpdated = getSimulationTime();
+ return ExecutionResult.NOTHING_DONE;
+ }
+ int checkStop = 0;
+ InnerEvent first = events.peek();
+ while (hasNext() && !condition.getAsBoolean())
+ {
+ events.remove();
+ lastTimeUpdated = first.getTiming();
+ first.run();
+ // Don't check after every run
+ checkStop = (checkStop + 1) % 10;
+ if (checkStop == 0 && System.currentTimeMillis() >= stopMillis)
+ return ExecutionResult.EXEC_OUT_OF_TIME;
+ first = events.peek();
+ }
+ lastTimeUpdated = getSimulationTime();
+ return hasNext() ? ExecutionResult.EXEC_UNTIL_EMPTY : ExecutionResult.EXEC_UNTIL_CONDITION;
+ }
+
+ public void setTimeFunction(LongSupplier time)
+ {
+ this.time = time;
+ }
+
+ public long getSimulationTime()
+ {
+ return time.getAsLong();
+ }
+
+ public long nextEventTime()
+ {
+ if (!hasNext())
+ return -1;
+ return events.peek().getTiming();
+ }
+
+ public void reset()
+ {
+ events.clear();
+ lastTimeUpdated = 0;
+ }
+
+ public void addEventAddedListener(Consumer<TimelineEvent> listener)
+ {
+ eventAddedListener.add(listener);
+ }
+
+ public void removeEventAddedListener(Consumer<TimelineEvent> listener)
+ {
+ eventAddedListener.remove(listener);
+ }
+
+ /**
+ * Adds an Event to the {@link Timeline}
+ *
+ * @param function The {@link TimelineEventHandler} that will be executed, when the {@link InnerEvent} occurs on the timeline.
+ * @param relativeTiming The amount of MI ticks in which the {@link InnerEvent} is called, starting from the current time.
+ */
+ public void addEvent(TimelineEventHandler function, int relativeTiming)
+ {
+ long timing = getSimulationTime() + relativeTiming;
+ TimelineEvent event = new TimelineEvent(timing);
+ events.add(new InnerEvent(function, event));
+ eventAddedListener.forEach(l -> l.accept(event));
+ }
+
+ private class InnerEvent implements Runnable, Comparable<InnerEvent>
+ {
+ private final TimelineEventHandler function;
+ private final TimelineEvent event;
+
+ /**
+ * Creates an {@link InnerEvent}
+ *
+ * @param function {@link TimelineEventHandler} to be executed when the {@link InnerEvent} occurs
+ * @param timing Point in the MI simulation {@link Timeline}, at which the {@link InnerEvent} is executed;
+ */
+ InnerEvent(TimelineEventHandler function, TimelineEvent event)
+ {
+ this.function = function;
+ this.event = event;
+ }
+
+ public long getTiming()
+ {
+ return event.getTiming();
+ }
+
+ @Override
+ public void run()
+ {
+ function.handle(event);
+ }
+
+ @Override
+ public String toString()
+ {
+ return event.toString();
+ }
+
+ @Override
+ public int compareTo(InnerEvent o)
+ {
+ return timeCmp(getTiming(), o.getTiming());
+ }
+ }
+
+ public static int timeCmp(long a, long b)
+ {
+ return Long.signum(a - b);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("Simulation time: %s, Last update: %d, Events: %s", getSimulationTime(), lastTimeUpdated, events.toString());
+ }
+
+ public enum ExecutionResult
+ {
+ NOTHING_DONE, EXEC_UNTIL_EMPTY, EXEC_UNTIL_CONDITION, EXEC_OUT_OF_TIME
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.core.timeline;
+
+/**
+ * A class that stores all relevant information about an event in the {@link Timeline}. Currently, there is not much relevant information to
+ * store.
+ *
+ * @author Fabian Stemmler
+ *
+ */
+public class TimelineEvent
+{
+ private final long timing;
+
+ TimelineEvent(long timing)
+ {
+ super();
+ this.timing = timing;
+ }
+
+ public long getTiming()
+ {
+ return timing;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "timestamp: " + timing;
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.core.timeline;
+
+@FunctionalInterface
+public interface TimelineEventHandler
+{
+ public void handle(TimelineEvent e);
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.core.types;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * stdlogic according to IEEE 1164
+ */
+public enum Bit implements StrictLogicType<Bit>
+{
+ U("U"), X("X"), ZERO("0"), ONE("1"), Z("Z");
+
+ private final String symbol;
+
+ private Bit(String symbol)
+ {
+ this.symbol = symbol;
+ }
+
+ @Override
+ public Bit and(Bit other)
+ {
+ return fromTable(AND_TABLE, this, other);
+ }
+
+ @Override
+ public Bit or(Bit other)
+ {
+ return fromTable(OR_TABLE, this, other);
+ }
+
+ @Override
+ public Bit xor(Bit other)
+ {
+ return fromTable(XOR_TABLE, this, other);
+ }
+
+ @Override
+ public Bit not()
+ {
+ switch (this)
+ {
+ case U:
+ return U;
+ case ONE:
+ return ZERO;
+ case ZERO:
+ return ONE;
+ default:
+ return X;
+ }
+ }
+
+ public Bit[] makeArray(int length)
+ {
+ Bit[] bits = new Bit[length];
+ Arrays.fill(bits, this);
+ return bits;
+ }
+
+ public BitVector toVector(int length)
+ {
+ return BitVector.of(this, length);
+ }
+
+ @Override
+ public Bit join(Bit other)
+ {
+ return fromTable(JOIN_TABLE, this, other);
+ }
+
+ @Override
+ public String toString()
+ {
+ return getSymbol();
+ }
+
+ public String getSymbol()
+ {
+ return symbol;
+ }
+
+ public static Bit parse(String s)
+ {
+ Bit bit = SYMBOL_MAP.get(s);
+ Objects.requireNonNull(bit, "No Bit found for symbol " + s);
+ return bit;
+ }
+
+ public static Bit parse(String s, int symbolPosition)
+ {
+ return parse(s.substring(symbolPosition, symbolPosition + 1));
+ }
+
+ private static Bit fromTable(Bit[][] table, Bit a, Bit b)
+ {
+ return table[a.ordinal()][b.ordinal()];
+ }
+
+ static final Map<String, Bit> SYMBOL_MAP = Map.of(U.symbol, U, X.symbol, X, ZERO.symbol, ZERO, ONE.symbol, ONE, Z.symbol, Z);
+
+ // @formatter:off
+ private static final Bit[][] JOIN_TABLE =
+ { { U, U, U, U, U },
+ { U, X, X, X, X },
+ { U, X, ZERO, X, ZERO },
+ { U, X, X, ONE, ONE },
+ { U, X, ZERO, ONE, Z } };
+
+ private static final Bit[][] AND_TABLE =
+ { { U, U, ZERO, U, U },
+ { U, X, ZERO, X, X },
+ { ZERO, ZERO, ZERO, ZERO, ZERO },
+ { U, X, ZERO, ONE, X },
+ { U, X, ZERO, X, X } };
+
+ private static final Bit[][] OR_TABLE =
+ { { U, U, U, ONE, U },
+ { U, X, X, ONE, X },
+ { U, X, ZERO, ONE, X },
+ { ONE, ONE, ONE, ONE, ONE },
+ { U, X, X, ONE, X } };
+
+ private static final Bit[][] XOR_TABLE =
+ { { U, U, U, U, U },
+ { U, X, X, X, X },
+ { U, X, ZERO, ONE, X },
+ { U, X, ONE, ZERO, X },
+ { U, X, X, X, X } };
+ // @formatter:on
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.core.types;
+
+import static java.lang.String.format;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.RandomAccess;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * Immutable class representing a {@link Bit}Vector
+ *
+ *
+ * @author Christian Femers
+ *
+ */
+public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
+{
+ private final Bit[] bits;
+
+ private BitVector(Bit[] bits)
+ {
+ this.bits = Objects.requireNonNull(bits);
+ }
+
+ public static BitVector of(Bit... bits)
+ {
+ return new BitVector(bits.clone());
+ }
+
+ public static BitVector of(Bit bit, int length)
+ {
+ return new BitVector(bit.makeArray(length));
+ }
+
+ public BitVectorMutator mutator()
+ {
+ return BitVectorMutator.of(this);
+ }
+
+ public Bit getBit(int bitIndex)
+ {
+ return bits[bitIndex];
+ }
+
+ public Bit[] getBits()
+ {
+ return bits.clone();
+ }
+
+ @Override
+ public BitVector join(BitVector t)
+ {
+ checkCompatibility(t);
+ return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
+ }
+
+ @Override
+ public BitVector and(BitVector t)
+ {
+ checkCompatibility(t);
+ return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
+ }
+
+ @Override
+ public BitVector or(BitVector t)
+ {
+ checkCompatibility(t);
+ return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
+ }
+
+ @Override
+ public BitVector xor(BitVector t)
+ {
+ checkCompatibility(t);
+ return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
+ }
+
+ @Override
+ public BitVector not()
+ {
+ return new BitVector(unOp(bits.clone(), Bit::not));
+ }
+
+ public int length()
+ {
+ return bits.length;
+ }
+
+ public BitVector concat(BitVector other)
+ {
+ Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
+ System.arraycopy(other.bits, 0, newBits, length(), other.length());
+ return new BitVector(newBits);
+ }
+
+ public BitVector subVector(int start)
+ {
+ return new BitVector(Arrays.copyOfRange(bits, start, length()));
+ }
+
+ public BitVector subVector(int start, int end)
+ {
+ return new BitVector(Arrays.copyOfRange(bits, start, end));
+ }
+
+ private void checkCompatibility(BitVector bv)
+ {
+ if (length() != bv.length())
+ throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
+ }
+
+ static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
+ {
+ if (dest == null)
+ return second.clone();
+ for (int i = 0; i < dest.length; i++)
+ {
+ dest[i] = op.apply(dest[i], second[i]);
+ }
+ return dest;
+ }
+
+ static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
+ {
+ if (dest == null)
+ return null;
+ for (int i = 0; i < dest.length; i++)
+ {
+ dest[i] = op.apply(dest[i]);
+ }
+ return dest;
+ }
+
+ /**
+ * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
+ *
+ * @author Christian Femers
+ */
+ @SuppressWarnings("synthetic-access")
+ public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
+ {
+ private Bit[] bits;
+
+ private BitVectorMutator(Bit[] bits)
+ {
+ this.bits = bits;
+ }
+
+ static BitVectorMutator of(BitVector bv)
+ {
+ return new BitVectorMutator(bv.getBits());
+ }
+
+ /**
+ * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
+ *
+ */
+ public static BitVectorMutator empty()
+ {
+ return new BitVectorMutator(null);
+ }
+
+ /**
+ * Produces the resulting, immutable {@link BitVector}<br>
+ *
+ * @throws IllegalStateException if the mutator is (still) empty
+ */
+ public BitVector get()
+ {
+ if (bits == null)
+ throw new IllegalStateException("cannot create a BitVector from an empty mutator");
+ return new BitVector(bits);
+ }
+
+ @Override
+ public BitVectorMutator join(BitVector t)
+ {
+ checkCompatibility(t);
+ bits = binOp(bits, t.bits, Bit::join);
+ return this;
+ }
+
+ @Override
+ public BitVectorMutator and(BitVector t)
+ {
+ checkCompatibility(t);
+ bits = binOp(bits, t.bits, Bit::and);
+ return this;
+ }
+
+ @Override
+ public BitVectorMutator or(BitVector t)
+ {
+ checkCompatibility(t);
+ bits = binOp(bits, t.bits, Bit::or);
+ return this;
+ }
+
+ @Override
+ public BitVectorMutator xor(BitVector t)
+ {
+ checkCompatibility(t);
+ bits = binOp(bits, t.bits, Bit::xor);
+ return this;
+ }
+
+ @Override
+ public BitVectorMutator not()
+ {
+ unOp(bits, Bit::not);
+ return this;
+ }
+
+ private void checkCompatibility(BitVector bv)
+ {
+ if (bits != null && bits.length != bv.length())
+ throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
+ }
+ }
+
+ /**
+ * @see Arrays#hashCode(Object[])
+ */
+ @Override
+ public int hashCode()
+ {
+ return Arrays.hashCode(bits);
+ }
+
+ /**
+ * Does test for equality of values/content
+ *
+ * @see Object#equals(Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof BitVector))
+ return false;
+ BitVector other = (BitVector) obj;
+ return Arrays.equals(bits, other.bits);
+ }
+
+ /**
+ * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
+ * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
+ *
+ * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
+ *
+ * @see Object#equals(Object)
+ */
+ public boolean equalsWithOffset(BitVector other, int offset)
+ {
+ if (other == null)
+ return false;
+ return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
+ }
+
+ /**
+ * All {@link Bit}s symbols concatenated together
+ *
+ * @see #parse(String)
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder(bits.length);
+ for (Bit bit : bits)
+ sb.append(bit);
+ return sb.toString();
+ }
+
+ /**
+ * Parses a String containing solely {@link Bit} symbols
+ *
+ * @see #toString()
+ */
+ public static BitVector parse(String s)
+ {
+ Bit[] values = new Bit[s.length()];
+ for (int i = 0; i < s.length(); i++)
+ {
+ values[i] = Bit.parse(s, i);
+ }
+ return new BitVector(values);
+ }
+
+ @Override
+ public Iterator<Bit> iterator()
+ {
+ return new Iterator<>()
+ {
+ private int pos = 0;
+
+ @Override
+ public Bit next()
+ {
+ if (!hasNext())
+ throw new NoSuchElementException();
+ return getBit(pos++);
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return pos != length();
+ }
+ };
+ }
+}
--- /dev/null
+package mograsim.logic.core.types;
+
+import mograsim.logic.core.types.ColorDefinition.BuiltInColor;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+
+public class BitVectorFormatter
+{
+ public static String formatValueAsString(ReadEnd end)
+ {
+ return formatAsString(end == null ? null : end.getValues());
+ }
+
+ public static String formatAsString(BitVector bitVector)
+ {
+ if (bitVector == null)
+ return "null";
+ else
+ return bitVector.toString();
+ }
+
+ public static ColorDefinition formatAsColor(ReadEnd end)
+ {
+ return formatAsColor(end == null ? null : end.getValues());
+ }
+
+ public static ColorDefinition formatAsColor(BitVector bitVector)
+ {
+ // TODO maybe find a color assignment for multiple-bit bit vectors?
+ if (bitVector == null || bitVector.length() != 1)
+ return new ColorDefinition(BuiltInColor.COLOR_BLACK);
+ else
+ switch (bitVector.getBit(0))
+ {
+ case ONE:
+ return new ColorDefinition(BuiltInColor.COLOR_GREEN);
+ case U:
+ return new ColorDefinition(BuiltInColor.COLOR_CYAN);
+ case X:
+ return new ColorDefinition(BuiltInColor.COLOR_RED);
+ case Z:
+ return new ColorDefinition(BuiltInColor.COLOR_YELLOW);
+ case ZERO:
+ return new ColorDefinition(BuiltInColor.COLOR_GRAY);
+ default:
+ throw new IllegalArgumentException("Unknown enum constant: " + bitVector.getBit(0));
+ }
+ }
+
+ private BitVectorFormatter()
+ {
+ throw new UnsupportedOperationException("No BitVectorFormatter instances");
+ }
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.core.types;
+
+/**
+ * A way to define a color with the possibility to use colors built into the system (called "system colors" in SWT).
+ * <p>
+ * A {@link ColorDefinition} is defined either by a {@link BuiltInColor} constant, in which case <code>r==g==b==-1</code>, or by red / green
+ * / blue components, in which case <code>builtInColor==null</code>
+ */
+public class ColorDefinition
+{
+ /**
+ * The built-in color constant defining this color.
+ */
+ public final ColorDefinition.BuiltInColor builtInColor;
+ /**
+ * The red color component defining this color.
+ */
+ public final int r;
+ /**
+ * The green color component defining this color.
+ */
+ public final int g;
+ /**
+ * The blue color component defining this color.
+ */
+ public final int b;
+
+ public ColorDefinition(ColorDefinition.BuiltInColor col)
+ {
+ if (col == null)
+ throw new IllegalArgumentException("Illegal built-in color: " + col);
+ this.builtInColor = col;
+ this.r = -1;
+ this.g = -1;
+ this.b = -1;
+ }
+
+ public ColorDefinition(int r, int g, int b)
+ {
+ if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
+ throw new IllegalArgumentException("Illegal color components: r=" + r + "; g=" + g + "; b=" + b);
+ this.builtInColor = null;
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ }
+
+ public static enum BuiltInColor
+ {
+ COLOR_WHITE, COLOR_BLACK, COLOR_RED, COLOR_DARK_RED, COLOR_GREEN, COLOR_DARK_GREEN, COLOR_YELLOW, COLOR_DARK_YELLOW, COLOR_BLUE,
+ COLOR_DARK_BLUE, COLOR_MAGENTA, COLOR_DARK_MAGENTA, COLOR_CYAN, COLOR_DARK_CYAN, COLOR_GRAY, COLOR_DARK_GRAY;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.core.types;
+
+/**
+ * Interface for types that support the basic logic operations
+ *
+ * @author Christian Femers
+ *
+ * @param <T> the logic type itself, to make the operations closed in T
+ * @param <S> the operand type, may be the same as T, see {@link StrictLogicType}
+ */
+public interface LogicType<T extends LogicType<T, S>, S>
+{
+ /**
+ * Determines the result when two signals meet each other directly, also called resolution (IEEE 1164)
+ *
+ * For example:
+ *
+ * <pre>
+ * 0 joined 0 == 0
+ * 1 joined 0 == X
+ * 0 joined 1 == X
+ * 1 joined 1 == 1
+ * </pre>
+ *
+ * @param t the second logic signal
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T join(S t);
+
+ /**
+ * Classical logic AND
+ *
+ * For example:
+ *
+ * <pre>
+ * 0 AND 0 == 0
+ * 1 AND 0 == 0
+ * 0 AND 1 == 0
+ * 1 AND 1 == 1
+ * </pre>
+ *
+ * @param t the second logic signal
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T and(S t);
+
+ /**
+ * Classical logic OR
+ *
+ * For example:
+ *
+ * <pre>
+ * 0 OR 0 == 0
+ * 1 OR 0 == 1
+ * 0 OR 1 == 1
+ * 1 OR 1 == 1
+ * </pre>
+ *
+ * @param t the second logic signal
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T or(S t);
+
+ /**
+ * Classical logic XOR (exclusive OR)
+ *
+ * For example:
+ *
+ * <pre>
+ * 0 XOR 0 == 0
+ * 1 XOR 0 == 1
+ * 0 XOR 1 == 1
+ * 1 XOR 1 == 0
+ * </pre>
+ *
+ * @param t the second logic signal
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T xor(S t);
+
+ /**
+ * Classical logic NOT (logical negation)
+ *
+ * For example:
+ *
+ * <pre>
+ * NOT 0 == 1
+ * NOT 1 == 0
+ * </pre>
+ *
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T not();
+
+ /**
+ * {@link #and(Object) AND} and then {@link #not() NOT}
+ *
+ * @author Christian Femers
+ */
+ default T nand(S t)
+ {
+ return and(t).not();
+ }
+
+ /**
+ * {@link #or(Object) OR} and then {@link #not() NOT}
+ *
+ * @author Christian Femers
+ */
+ default T nor(S t)
+ {
+ return or(t).not();
+ }
+
+ /**
+ * {@link #xor(Object) XOR} and then {@link #not() NOT}<br>
+ * Used to determine equality (alias parity, consistency)
+ *
+ * @author Christian Femers
+ */
+ default T xnor(S t)
+ {
+ return xor(t).not();
+ }
+}
--- /dev/null
+package mograsim.logic.core.types;
+
+import java.util.function.BiFunction;
+
+import mograsim.logic.core.types.BitVector.BitVectorMutator;
+
+@FunctionalInterface
+public interface MutationOperation extends BiFunction<BitVectorMutator, BitVector, BitVectorMutator>
+{
+ // no changes necessary, only for convenience and readability
+}
--- /dev/null
+package mograsim.logic.core.types;
+
+/**
+ * Interface for types that support the basic logic operations only among themselves, making it mathematically closed
+ *
+ * @author Christian Femers
+ * @see LogicType
+ *
+ * @param <T> the logic type itself to make the operations closed
+ */
+public interface StrictLogicType<T extends StrictLogicType<T>> extends LogicType<T, T>
+{
+ // this is just a matter of type parameters
+}
--- /dev/null
+package mograsim.logic.core.wires;\r
+\r
+import static mograsim.logic.core.types.Bit.U;\r
+import static mograsim.logic.core.types.Bit.Z;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import mograsim.logic.core.timeline.Timeline;\r
+import mograsim.logic.core.types.Bit;\r
+import mograsim.logic.core.types.BitVector;\r
+import mograsim.logic.core.types.BitVector.BitVectorMutator;\r
+\r
+/**\r
+ * Represents an array of wires that can store n bits of information.\r
+ * \r
+ * @author Fabian Stemmler\r
+ *\r
+ */\r
+public class Wire\r
+{\r
+ private BitVector values;\r
+ public final int travelTime;\r
+ private List<ReadEnd> attached = new ArrayList<ReadEnd>();\r
+ public final int length;\r
+ private List<ReadWriteEnd> inputs = new ArrayList<ReadWriteEnd>();\r
+ private Timeline timeline;\r
+\r
+ public Wire(Timeline timeline, int length, int travelTime)\r
+ {\r
+ if (length < 1)\r
+ throw new IllegalArgumentException(\r
+ String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));\r
+ this.timeline = timeline;\r
+ this.length = length;\r
+ this.travelTime = travelTime;\r
+ initValues();\r
+ }\r
+\r
+ private void initValues()\r
+ {\r
+ values = U.toVector(length);\r
+ }\r
+\r
+ private void recalculateSingleInput()\r
+ {\r
+ setNewValues(inputs.get(0).getInputValues());\r
+ }\r
+\r
+ private void recalculateMultipleInputs()\r
+ {\r
+ BitVectorMutator mutator = BitVectorMutator.empty();\r
+ for (ReadWriteEnd wireArrayEnd : inputs)\r
+ mutator.join(wireArrayEnd.getInputValues());\r
+ setNewValues(mutator.get());\r
+ }\r
+\r
+ private void setNewValues(BitVector newValues)\r
+ {\r
+ if (values.equals(newValues))\r
+ return;\r
+ BitVector oldValues = values;\r
+ values = newValues;\r
+ notifyObservers(oldValues);\r
+ }\r
+\r
+ private void recalculate()\r
+ {\r
+ switch (inputs.size())\r
+ {\r
+ case 0:\r
+ return;\r
+ case 1:\r
+ recalculateSingleInput();\r
+ break;\r
+ default:\r
+ recalculateMultipleInputs();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
+ * \r
+ * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the same\r
+ * value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public boolean hasNumericValue()\r
+ {\r
+ for (Bit b : values)\r
+ {\r
+ if (b != Bit.ZERO && b != Bit.ONE)\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
+ * \r
+ * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public long getUnsignedValue()\r
+ {\r
+ long val = 0;\r
+ long mask = 1;\r
+ for (Bit bit : values)\r
+ {\r
+ switch (bit)\r
+ {\r
+ default:\r
+ case Z:\r
+ case X:\r
+ return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;\r
+ case ONE:\r
+ val |= mask;\r
+ break;\r
+ case ZERO:\r
+ }\r
+ mask = mask << 1;\r
+ }\r
+ return val;\r
+ }\r
+\r
+ /**\r
+ * The {@link Wire} is interpreted as a signed integer with n bits.\r
+ * \r
+ * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public long getSignedValue()\r
+ {\r
+ long val = getUnsignedValue();\r
+ long mask = 1 << (length - 1);\r
+ if ((mask & val) != 0)\r
+ {\r
+ int shifts = 64 - length;\r
+ return (val << shifts) >> shifts;\r
+ }\r
+ return val;\r
+ }\r
+\r
+ public Bit getValue()\r
+ {\r
+ return getValue(0);\r
+ }\r
+\r
+ public Bit getValue(int index)\r
+ {\r
+ return values.getBit(index);\r
+ }\r
+\r
+ public BitVector getValues(int start, int end)\r
+ {\r
+ return values.subVector(start, end);\r
+ }\r
+\r
+ public BitVector getValues()\r
+ {\r
+ return values;\r
+ }\r
+\r
+ /**\r
+ * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} is updated.\r
+ * \r
+ * @param ob The {@link WireObserver} to be notified of changes.\r
+ * @return true if the given {@link WireObserver} was not already registered, false otherwise\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ private void attachEnd(ReadEnd end)\r
+ {\r
+ attached.add(end);\r
+ }\r
+\r
+ private void detachEnd(ReadEnd end)\r
+ {\r
+ attached.remove(end);\r
+ }\r
+\r
+ private void notifyObservers(BitVector oldValues)\r
+ {\r
+ for (ReadEnd o : attached)\r
+ o.update(oldValues);\r
+ }\r
+\r
+ /**\r
+ * Create and register a {@link ReadWriteEnd} object, which is tied to this {@link Wire}. This {@link ReadWriteEnd} can be written to.\r
+ */\r
+ public ReadWriteEnd createReadWriteEnd()\r
+ {\r
+ return new ReadWriteEnd();\r
+ }\r
+\r
+ /**\r
+ * Create a {@link ReadEnd} object, which is tied to this {@link Wire}. This {@link ReadEnd} cannot be written to.\r
+ */\r
+ public ReadEnd createReadOnlyEnd()\r
+ {\r
+ return new ReadEnd();\r
+ }\r
+\r
+ private void registerInput(ReadWriteEnd toRegister)\r
+ {\r
+ inputs.add(toRegister);\r
+ }\r
+\r
+ /**\r
+ * A {@link ReadEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the\r
+ * {@link Wire}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs than Z 0\r
+ * and 1 turn into X when they are mixed\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public class ReadEnd\r
+ {\r
+ private List<WireObserver> observers = new ArrayList<WireObserver>();\r
+\r
+ private ReadEnd()\r
+ {\r
+ super();\r
+ Wire.this.attachEnd(this);\r
+ }\r
+\r
+ public void update(BitVector oldValues)\r
+ {\r
+ for (WireObserver ob : observers)\r
+ ob.update(this, oldValues);\r
+ }\r
+\r
+ /**\r
+ * Included for convenient use on {@link Wire}s of length 1.\r
+ * \r
+ * @return The value of bit 0.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public Bit getValue()\r
+ {\r
+ return Wire.this.getValue();\r
+ }\r
+\r
+ /**\r
+ * @param index Index of the requested bit.\r
+ * @return The value of the indexed bit.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public Bit getValue(int index)\r
+ {\r
+ return Wire.this.getValue(index);\r
+ }\r
+\r
+ /**\r
+ * @param index Index of the requested bit.\r
+ * @return The value of the indexed bit.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public BitVector getValues()\r
+ {\r
+ return Wire.this.getValues();\r
+ }\r
+\r
+ /**\r
+ * @param start Start of the wanted segment. (inclusive)\r
+ * @param end End of the wanted segment. (exclusive)\r
+ * @return The values of the segment of {@link Bit}s indexed.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public BitVector getValues(int start, int end)\r
+ {\r
+ return Wire.this.getValues(start, end);\r
+ }\r
+\r
+ /**\r
+ * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
+ * \r
+ * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the\r
+ * same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public boolean hasNumericValue()\r
+ {\r
+ return Wire.this.hasNumericValue();\r
+ }\r
+\r
+ /**\r
+ * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
+ * \r
+ * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public long getUnsignedValue()\r
+ {\r
+ return Wire.this.getUnsignedValue();\r
+ }\r
+\r
+ /**\r
+ * The {@link Wire} is interpreted as a signed integer with n bits.\r
+ * \r
+ * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public long getSignedValue()\r
+ {\r
+ return Wire.this.getSignedValue();\r
+ }\r
+\r
+ @Override\r
+ public String toString()\r
+ {\r
+ return Wire.this.toString();\r
+ }\r
+\r
+ public void close()\r
+ {\r
+ inputs.remove(this);\r
+ detachEnd(this);\r
+ recalculate();\r
+ }\r
+\r
+ public int length()\r
+ {\r
+ return length;\r
+ }\r
+\r
+ public boolean addObserver(WireObserver ob)\r
+ {\r
+ return observers.add(ob);\r
+ }\r
+\r
+ public Wire getWire()\r
+ {\r
+ return Wire.this;\r
+ }\r
+ }\r
+\r
+ public class ReadWriteEnd extends ReadEnd\r
+ {\r
+ private boolean open;\r
+ private BitVector inputValues;\r
+\r
+ private ReadWriteEnd()\r
+ {\r
+ super();\r
+ open = true;\r
+ initValues();\r
+ registerInput(this);\r
+ }\r
+\r
+ private void initValues()\r
+ {\r
+ inputValues = U.toVector(length);\r
+ }\r
+\r
+ /**\r
+ * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.\r
+ * \r
+ * @param newValues The new values the wires should take on.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public void feedSignals(Bit... newValues)\r
+ {\r
+ feedSignals(BitVector.of(newValues));\r
+ }\r
+\r
+ public void feedSignals(BitVector newValues)\r
+ {\r
+ if (newValues.length() != length)\r
+ throw new IllegalArgumentException(\r
+ String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));\r
+ if (!open)\r
+ throw new RuntimeException("Attempted to write to closed WireArrayEnd.");\r
+ timeline.addEvent(e -> setValues(newValues), travelTime);\r
+ }\r
+\r
+ /**\r
+ * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.\r
+ * \r
+ * @param bitVector The new values the wires should take on.\r
+ * @param startingBit The first index of the subarray of wires.\r
+ * \r
+ * @author Fabian Stemmler\r
+ */\r
+ public void feedSignals(int startingBit, BitVector bitVector)\r
+ {\r
+ if (!open)\r
+ throw new RuntimeException("Attempted to write to closed WireArrayEnd.");\r
+ timeline.addEvent(e -> setValues(startingBit, bitVector), travelTime);\r
+ }\r
+\r
+ private void setValues(int startingBit, BitVector newValues)\r
+ {\r
+ // index check covered in equals\r
+ if (!inputValues.equalsWithOffset(newValues, startingBit))\r
+ {\r
+ Bit[] vals = inputValues.getBits();\r
+ System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());\r
+ inputValues = BitVector.of(vals);\r
+ Wire.this.recalculate();\r
+ }\r
+ }\r
+\r
+ private void setValues(BitVector newValues)\r
+ {\r
+ if (inputValues.equals(newValues))\r
+ return;\r
+ inputValues = newValues;\r
+ Wire.this.recalculate();\r
+ }\r
+\r
+ /**\r
+ * @return The value (of bit 0) the {@link ReadEnd} is currently feeding into the associated {@link Wire}.\r
+ */\r
+ public Bit getInputValue()\r
+ {\r
+ return getInputValue(0);\r
+ }\r
+\r
+ /**\r
+ * @return The value which the {@link ReadEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.\r
+ */\r
+ public Bit getInputValue(int index)\r
+ {\r
+ return inputValues.getBit(index);\r
+ }\r
+\r
+ /**\r
+ * @return A copy (safe to modify) of the values the {@link ReadEnd} is currently feeding into the associated {@link Wire}.\r
+ */\r
+ public BitVector getInputValues()\r
+ {\r
+ return getInputValues(0, length);\r
+ }\r
+\r
+ public BitVector getInputValues(int start, int end)\r
+ {\r
+ return inputValues.subVector(start, end);\r
+ }\r
+\r
+ /**\r
+ * {@link ReadEnd} now feeds Z into the associated {@link Wire}.\r
+ */\r
+ public void clearSignals()\r
+ {\r
+ feedSignals(Z.toVector(length));\r
+ }\r
+\r
+ public BitVector wireValuesExcludingMe()\r
+ {\r
+ BitVectorMutator mutator = BitVectorMutator.empty();\r
+ for (ReadWriteEnd wireEnd : inputs)\r
+ {\r
+ if (wireEnd == this)\r
+ continue;\r
+ mutator.join(wireEnd.inputValues);\r
+ }\r
+ return mutator.get();\r
+ }\r
+\r
+ @Override\r
+ public String toString()\r
+ {\r
+ return inputValues.toString();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public String toString()\r
+ {\r
+ return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), values, inputs);\r
+ // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)\r
+ }\r
+\r
+ public static ReadEnd[] extractEnds(Wire[] w)\r
+ {\r
+ ReadEnd[] inputs = new ReadEnd[w.length];\r
+ for (int i = 0; i < w.length; i++)\r
+ inputs[i] = w[i].createReadWriteEnd();\r
+ return inputs;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package mograsim.logic.core.wires;\r
+\r
+import mograsim.logic.core.types.BitVector;\r
+import mograsim.logic.core.wires.Wire.ReadEnd;\r
+\r
+public interface WireObserver\r
+{\r
+ public void update(ReadEnd initiator, BitVector oldValues);\r
+}\r