--- /dev/null
+package net.mograsim.logic.core.timeline;
+
+import java.util.function.LongSupplier;
+
+public class PauseableTimeFunction implements LongSupplier
+{
+ private boolean paused = false;
+ private long unpausedSysTime = 0, lastPausedInternalTime = 0;
+ private int speedPercentage = 100;
+
+ public void pause()
+ {
+ if (!paused)
+ {
+ lastPausedInternalTime = getAsLong();
+ paused = true;
+ }
+ }
+
+ public void unpause()
+ {
+ if (paused)
+ {
+ paused = false;
+ unpausedSysTime = System.currentTimeMillis();
+ }
+ }
+
+ @Override
+ public long getAsLong()
+ {
+ return paused ? lastPausedInternalTime
+ : lastPausedInternalTime + ((System.currentTimeMillis() - unpausedSysTime) * speedPercentage) / 100;
+ }
+
+ public void setSpeedPercentage(int percentage)
+ {
+ if (!paused)
+ {
+ pause();
+ unpause();
+ }
+ this.speedPercentage = Integer.min(100, Integer.max(percentage, 1));
+ }
+
+ public boolean isPaused()
+ {
+ return paused;
+ }
+
+ public void toggle()
+ {
+ if (paused)
+ unpause();
+ else
+ pause();
+ }
+}
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import net.mograsim.logic.core.timeline.PauseableTimeFunction;
import net.mograsim.logic.core.timeline.Timeline;
//TODO maybe move to logic core?
private final AtomicBoolean shouldBeRunningLive;
private final AtomicBoolean isRunningLive;
+ private final AtomicBoolean isPaused;
private final AtomicLong nextExecSimulTime;
private final Thread simulationThread;
+ PauseableTimeFunction tf;
+
public LogicExecuter(Timeline timeline)
{
this.timeline = timeline;
- timeline.setTimeFunction(System::currentTimeMillis);
+ tf = new PauseableTimeFunction();
+ timeline.setTimeFunction(tf);
shouldBeRunningLive = new AtomicBoolean();
isRunningLive = new AtomicBoolean();
+ isPaused = new AtomicBoolean();
nextExecSimulTime = new AtomicLong();
simulationThread = new Thread(() ->
{
while (shouldBeRunningLive.get())
{
// always execute to keep timeline from "hanging behind" for too long
- long current = System.currentTimeMillis();
+ long current = tf.getAsLong();
timeline.executeUntil(timeline.laterThan(current), current + 10);
long sleepTime;
if (timeline.hasNext())
nextExecSimulTime.set(current + sleepTime);
if (sleepTime > 0)
Thread.sleep(sleepTime);
+
+ synchronized (isPaused)
+ {
+ while (isPaused.get())
+ isPaused.wait();
+ }
}
catch (@SuppressWarnings("unused") InterruptedException e)
{// do nothing; it is normal execution flow to be interrupted
waitForIsRunning(false);
}
+ public void unpauseLiveExecution()
+ {
+ synchronized (isPaused)
+ {
+ tf.unpause();
+ isPaused.set(false);
+ isPaused.notify();
+ }
+ }
+
+ public void pauseLiveExecution()
+ {
+ synchronized (isPaused)
+ {
+ tf.pause();
+ isPaused.set(true);
+ }
+ }
+
+ public boolean isPaused()
+ {
+ return isPaused.get();
+ }
+
+ public void setSpeedPercentage(int percentage)
+ {
+ tf.setSpeedPercentage(percentage);
+ }
+
private void waitForIsRunning(boolean expectedState)
{
while (isRunningLive.get() ^ expectedState)
package net.mograsim.machine.mi;
import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.util.Objects;
-import net.mograsim.machine.MachineRegistry;
-import net.mograsim.machine.MemoryDefinition;
import net.mograsim.machine.mi.parameters.MicroInstructionParameter;
import net.mograsim.machine.mi.parameters.ParameterClassification;
public static void parseMemory(final MicroInstructionMemory memory, String inputPath) throws IOException
{
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputPath))))
+ try (InputStream input = new FileInputStream(inputPath))
{
- parseMemory(memory, reader);
- }
- }
-
- public static MicroInstructionMemory parseMemory(String inputPath) throws IOException
- {
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputPath))))
- {
- return parseMemory(reader);
- }
- }
-
- /**
- * First line must be the machine name, the rest must be in csv format
- */
- public static MicroInstructionMemory parseMemory(BufferedReader input)
- {
- try
- {
- return parseMemory(input.readLine(), input);
- }
- catch (IOException e)
- {
- throw new MicroInstructionMemoryParseException(e);
+ parseMemory(memory, input);
}
}
/**
- * must be in csv format
+ * @param input The input to parse must be in csv format; The stream is closed after being consumed.
+ *
+ * @throws IOException
*/
- public static MicroInstructionMemory parseMemory(String machineName, BufferedReader input)
+ public static MicroInstructionMemory parseMemory(MicroInstructionMemoryDefinition memDef, InputStream input) throws IOException
{
try
{
- MicroInstructionMemoryDefinition def = Objects
- .requireNonNull(MachineRegistry.getMachine(machineName), "Unknown machine: " + machineName)
- .getMicroInstructionMemoryDefinition();
- MicroInstructionMemory memory = new StandardMicroInstructionMemory(def);
+ MicroInstructionMemory memory = new StandardMicroInstructionMemory(memDef);
parseMemory(memory, input);
return memory;
}
}
/**
- * must be in csv format
+ *
+ * @param input The input to parse must be in csv format; The stream is closed after being consumed.
+ *
+ * @throws IOException
*/
- public static void parseMemory(final MicroInstructionMemory memory, BufferedReader input)
+ public static void parseMemory(final MicroInstructionMemory memory, InputStream input) throws IOException
{
- MicroInstructionMemoryDefinition def = memory.getDefinition();
- MicroInstructionDefinition miDef = def.getMicroInstructionDefinition();
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(input)))
+ {
+ MicroInstructionMemoryDefinition def = memory.getDefinition();
+ MicroInstructionDefinition miDef = def.getMicroInstructionDefinition();
- long minAddr = def.getMinimalAddress();
- long maxAddr = def.getMaximalAddress();
+ long minAddr = def.getMinimalAddress();
+ long maxAddr = def.getMaximalAddress();
- String line;
- long i = minAddr;
- try
- {
- for (; i <= maxAddr && input.ready() && !"".equals((line = input.readLine())); i++)
+ String line;
+ long i = minAddr;
+ try
{
- memory.setCell(i, parse(miDef, line));
+ for (; i <= maxAddr && reader.ready() && !"".equals((line = reader.readLine())); i++)
+ {
+ memory.setCell(i, parse(miDef, line));
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
}
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- for (; i <= maxAddr; i++)
- {
- memory.setCell(i, miDef.createDefaultInstruction());
+ for (; i <= maxAddr; i++)
+ {
+ memory.setCell(i, miDef.createDefaultInstruction());
+ }
}
}
/**
* must be in csv format
*/
- public static MicroInstruction parse(MicroInstructionDefinition definition, String path)
+ public static MicroInstruction parse(MicroInstructionDefinition definition, String input)
{
int size = definition.size();
- String[] strings = path.split(",");
+ String[] strings = input.split(",");
if (size != strings.length)
throw new MicroInstructionMemoryParseException("String does not match definition! The number of parameters does not match.");
MicroInstructionParameter[] params = new MicroInstructionParameter[size];
}
}
- public static void write(MicroInstructionMemory memory, String outputPath) throws IOException
- {
- try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(outputPath)))
- {
- write(memory, writer);
- }
- }
-
- public static void write(MicroInstructionMemory memory, String machineName, String outputPath) throws IOException
- {
- try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(outputPath)))
- {
- write(memory, machineName, writer);
- }
- }
-
- public static void write(MicroInstructionMemory memory, OutputStreamWriter output) throws IOException
- {
- MemoryDefinition def = memory.getDefinition();
- long min = def.getMinimalAddress(), max = def.getMaximalAddress() + 1;
- for (long i = min; i < max; i++)
- {
- output.write(toCSV(memory.getCell(i)) + lineSeparator);
- }
- }
-
- public static void write(MicroInstructionMemory memory, String machineName, OutputStreamWriter output) throws IOException
- {
- output.write(machineName + lineSeparator);
- MemoryDefinition def = memory.getDefinition();
- long min = def.getMinimalAddress(), max = def.getMaximalAddress() + 1;
- for (long i = min; i < max; i++)
- {
- output.write(toCSV(memory.getCell(i)) + lineSeparator);
- }
- }
-
private static String toCSV(MicroInstruction inst)
{
int max = inst.getSize() - 1;
sb.append(inst.getParameter(max).toString());
return sb.toString();
}
+
+ public static InputStream write(MicroInstructionMemory memory)
+ {
+ return new InputStream()
+ {
+ long instIndex = memory.getDefinition().getMinimalAddress(), maxAddress = memory.getDefinition().getMaximalAddress();
+ InputStream instStream = new ByteArrayInputStream(new byte[0]);
+
+ @Override
+ public int read() throws IOException
+ {
+ int val = instStream.read();
+ if (val == -1 && instIndex <= maxAddress)
+ {
+ instStream = new ByteArrayInputStream((toCSV(memory.getCell(instIndex++)) + lineSeparator).getBytes());
+ val = instStream.read();
+ }
+ return val;
+ }
+ };
+ }
}
public void bindMicroInstructionMemory(MicroInstructionMemory memory)
{
this.memory = memory;
- this.miDef = memory.getDefinition().getMicroInstructionDefinition();
- setViewerInput(memory);
+ if (memory != null)
+ {
+ this.miDef = memory.getDefinition().getMicroInstructionDefinition();
+ setViewerInput(memory);
+ }
}
private static final String[] HEX_DIGITS = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
package net.mograsim.plugin.tables.mi;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStream;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.IPathEditorInput;
+import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;
private InstructionTableContentProvider provider;
private int highlighted = 0;
private boolean dirty = false;
- private String machineName;
private MicroInstructionMemory memory;
private InstructionTable table;
public void bindMicroInstructionMemory(MicroInstructionMemory memory)
{
this.memory = memory;
- this.memory.registerCellModifiedListener(this);
- this.memory.registerActiveMicroInstructionChangedListener(this);
+ if (memory != null)
+ {
+ this.memory.registerCellModifiedListener(this);
+ this.memory.registerActiveMicroInstructionChangedListener(this);
+ }
if (table != null)
table.bindMicroInstructionMemory(memory);
}
- private void open(String file)
+ private void open(IFile file)
{
- try (BufferedReader bf = new BufferedReader(new FileReader(file)))
+ try
{
- machineName = bf.readLine();
- bindMicroInstructionMemory(MicroInstructionMemoryParser.parseMemory(machineName, bf));
+ bindMicroInstructionMemory(MicroInstructionMemoryParser.parseMemory(
+ MachineContext.getInstance().getMachine().getDefinition().getMicroInstructionMemoryDefinition(), file.getContents()));
}
- catch (IOException | MicroInstructionMemoryParseException e)
+ catch (IOException | MicroInstructionMemoryParseException | CoreException e)
{
e.printStackTrace();
}
}
- private void save(String file)
+ private void save(IFile file, IProgressMonitor progressMonitor)
{
if (memory == null)
{
System.err.println("Failed to write MicroprogrammingMemory to File. No MicroprogrammingMemory assigned.");
return;
}
- try
+ try (InputStream toWrite = MicroInstructionMemoryParser.write(memory))
{
- MicroInstructionMemoryParser.write(memory, machineName, file);
+ file.setContents(toWrite, 0, progressMonitor);
}
- catch (IOException e)
+ catch (IOException | CoreException e)
{
e.printStackTrace();
}
public void doSave(IProgressMonitor progressMonitor)
{
IEditorInput input = getEditorInput();
- if (input instanceof IPathEditorInput)
+ if (input instanceof IFileEditorInput)
{
- IPathEditorInput pathInput = (IPathEditorInput) input;
- save(pathInput.getPath().toOSString());
+ IFileEditorInput pathInput = (IFileEditorInput) input;
+ save(pathInput.getFile(), progressMonitor);
setDirty(false);
}
}
@Override
public void doSaveAs()
{
- openSaveAsDialog();
+// openSaveAsDialog();
}
- private void openSaveAsDialog()
- {
- FileDialog d = new FileDialog(table.getTableViewer().getTable().getShell(), SWT.SAVE);
- d.open();
- String filename = d.getFileName();
- if (!filename.equals(""))
- {
- save(d.getFilterPath() + File.separator + filename);
- setDirty(false);
- }
- }
+// private void openSaveAsDialog()
+// {
+// FileDialog d = new FileDialog(table.getTableViewer().getTable().getShell(), SWT.SAVE);
+// d.open();
+// String filename = d.getFileName();
+// if (!filename.equals(""))
+// {
+// save(d.getFilterPath() + File.separator + filename);
+// setDirty(false);
+// }
+// }
@Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException
{
setSite(site);
setInput(input);
- if (input instanceof IPathEditorInput)
+ if (input instanceof IFileEditorInput)
{
- IPathEditorInput pathInput = (IPathEditorInput) input;
- setPartName(pathInput.getName());
- open(pathInput.getPath().toOSString());
+ IFileEditorInput fileInput = (IFileEditorInput) input;
+ setPartName(fileInput.getName());
+ open(fileInput.getFile());
}
+
}
@Override
@Override
public boolean isSaveAsAllowed()
{
- return true;
+ return false;
}
@Override
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Slider;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
GridLayout layout = new GridLayout(1, true);
parent.setLayout(layout);
+ addSimulationControlWidgets(parent);
+
ui = new LogicUICanvas(parent, SWT.NONE, m.getModel());
ui.addTransformListener((x, y, z) -> part.setDirty(z < 1));
ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
exec.startLiveExecution();
}
+ private void addSimulationControlWidgets(Composite parent)
+ {
+ Composite c = new Composite(parent, SWT.NONE);
+ c.setLayout(new GridLayout(4, false));
+ Button pauseButton = new Button(c, SWT.TOGGLE);
+ pauseButton.setText("Running");
+
+ pauseButton.addListener(SWT.Selection, e ->
+ {
+ if (!pauseButton.getSelection())
+ {
+ pauseButton.setText("Running");
+ exec.unpauseLiveExecution();
+ } else
+ {
+ pauseButton.setText("Paused");
+ exec.pauseLiveExecution();
+ }
+ });
+
+ Label speedLabel = new Label(c, SWT.NONE);
+ speedLabel.setText("Simulation Speed: ");
+
+ Slider slider = new Slider(c, SWT.NONE);
+ slider.setMinimum(1);
+ slider.setMaximum(100 + slider.getThumb());
+ slider.setIncrement(1);
+
+ Label speedPercentageLabel = new Label(c, SWT.NONE);
+ speedPercentageLabel.setText("100%");
+
+ slider.addListener(SWT.Selection, e ->
+ {
+ int selection = slider.getSelection();
+ speedPercentageLabel.setText(selection + "%");
+
+ exec.setSpeedPercentage(slider.getSelection());
+ });
+ slider.setSelection(100);
+
+ c.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL));
+ c.pack();
+ c.setVisible(true);
+ }
+
@Override
public void setFocus()
{