Skip to content

Commit

Permalink
Implement dynamic addon loading
Browse files Browse the repository at this point in the history
Addons are standalone jars, loaded at runtime. They can be developed
independently of the simulator and can provide some additional functionality.

An example addon is shown in `addons/rand`. When building a jar file,
main class should extend abstract class `sic.sim.addons.Addon`. Only
the methods, needed for functinality of the addon, have to be overriden.

The abstract class Addon currently contains methods for initializing the
addon and some other methods (documented in the source file itself). The
class could be extended at any time (with non-abstract methods) without
breaking any older addons.

Addons can be loaded with `-a path[@params]` command line options.
Parametres are passed to the `load` method of the loaded addon.
  • Loading branch information
Kljunas2 committed Aug 27, 2023
1 parent 18fc7dc commit acb23e8
Show file tree
Hide file tree
Showing 12 changed files with 380 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.idea
SicTools.iml
out
addons/out
/.project
*.class
tests/linker/factorial/factdemo.obj
Expand Down Expand Up @@ -35,4 +36,4 @@ tests/linker/factorial/stack.log
tests/linker/factorial/stack.lst
tests/linker/one2/linked.obj
tests/linker/one2/prog.log
tests/linker/one2/prog.lst
tests/linker/one2/prog.lst
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
OUT = out/make

all: outdir img
all: outdir img addons
javac -encoding UTF-8 -sourcepath src -d "$(OUT)" src/sic/*.java

sim: outdir img
Expand All @@ -15,6 +15,9 @@ asm: outdir
link: outdir
javac -encoding UTF-8 -sourcepath src -d "$(OUT)" src/sic/Link.java

addons: outdir
javac -encoding UTF-8 -sourcepath src -d "$(OUT)" src/sic/sim/addons/*/*.java

jar: all
jar --create --file "$(OUT)/sictools.jar" --manifest MANIFEST.MF -C "$(OUT)" .

Expand Down
21 changes: 21 additions & 0 deletions addons/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
NAME=${name}
# MAIN is the class which extends the abstract class sic.sim.plugins.Plugin.
MAIN="${name}.Main"
OUT=out/make
# SICPATH should be changed if building from a different tree.
# It can also point to sictools.jar file.
SICPATH=../out/make


.PHONY: main
main: outdir
javac -encoding UTF-8 -cp ".:$(SICPATH)" -d "$(OUT)/$(NAME)" $(NAME)/*.java
jar --create --file "$(OUT)/$(NAME).jar" --main-class $(MAIN) -C "$(OUT)/$(NAME)" .

.PHONY: outdir
outdir:
@mkdir -p "$(OUT)"

.PHONY: clean
clean:
rm -rf "$(OUT)"
23 changes: 23 additions & 0 deletions addons/rand/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package rand;

import java.util.Vector;

import sic.sim.addons.Addon;
import sic.sim.Executor;

public class Main extends Addon {
private int device = 3;
public void load(String args) {
System.out.println("Loading rand");
if (args != null) {
device = Integer.parseInt(args);
}
}

@Override
public Vector<AddonDevice> getDevices() {
Vector<AddonDevice> vc = new Vector<AddonDevice>();
vc.add(new Addon.AddonDevice(device, new RandDevice(), true));
return vc;
}
}
14 changes: 14 additions & 0 deletions addons/rand/RandDevice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package rand;

import java.util.Random;

import sic.sim.vm.Device;

public class RandDevice extends Device {
private Random random = new Random();

@Override
public int read() {
return random.nextInt(256);
}
}
31 changes: 31 additions & 0 deletions src/sic/Sim.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
import sic.sim.Executor;
import sic.sim.MainView;
import sic.sim.vm.Machine;
import sic.sim.addons.Addon;
import sic.sim.addons.AddonLoader;

import javax.swing.UIManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Vector;

/**
* Simulator of the SIC/XE computer.
Expand Down Expand Up @@ -49,12 +53,39 @@ public static void main(String[] args) throws Exception {
return;
}

Vector<Addon> addons = new Vector<Addon>();

for (Args.AddonArgs a : processedArgs.getAddons()) {
try {
Addon p = AddonLoader.loadJar(a.path);
p.load(a.pars);
addons.add(p);
} catch (IOException e) {
System.out.printf("cannot open addon file %s%n", a.path);
System.out.println(e);
System.exit(1);
} catch (ClassCastException e) {
System.out.printf("main class of %s does not extend Addon class%n", a.path);
System.exit(1);
}
}

Machine machine = new Machine();
Executor executor = new Executor(machine, processedArgs);
Disassembler disassembler = new Disassembler(new Mnemonics(), machine);

final MainView mainView = new MainView(executor, disassembler, processedArgs);

for (Addon a : addons) {
a.init(executor);
machine.devices.setDevices(a.getDevices());
mainView.addMenuEntries(a.getMenuEntries());
mainView.addTimerTasks(a.getTimerTasks());
mainView.addSettingsPanels(a.getSettingsPanels());
}
mainView.addAddonMenu();
mainView.updateTimerTasks();

if (processedArgs.hasFilename()) mainView.load(new File(processedArgs.getFilename()));

mainView.updateView();
Expand Down
33 changes: 33 additions & 0 deletions src/sic/VM.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
import sic.sim.Executor;
import sic.sim.addons.GraphicalScreen;
import sic.sim.addons.TextualScreen;
import sic.sim.addons.Addon;
import sic.sim.addons.AddonLoader;
import sic.sim.vm.Machine;

import java.io.IOException;
import java.util.*;

/**
Expand All @@ -34,9 +37,36 @@ public static void main(String[] args) throws Exception {
System.exit(0);
}

Vector<Addon> addons = new Vector<Addon>();

for (Args.AddonArgs a : arg.getAddons()) {
try {
Addon p = AddonLoader.loadJar(a.path);
p.load(a.pars);
addons.add(p);
} catch (IOException e) {
System.out.printf("cannot open addon file %s%n", a.path);
System.out.println(e);
System.exit(1);
} catch (ClassCastException e) {
System.out.printf("main class of %s does not extend Addon class%n", a.path);
System.exit(1);
}
}

Machine machine = new Machine();
Executor executor = new Executor(machine, arg);

Vector<TimerTask> timerTasks = new Vector<TimerTask>();
for (Addon a : addons) {
a.init(executor);
machine.devices.setDevices(a.getDevices());
Vector<TimerTask> tasks = a.getTimerTasks();
if (tasks != null) {
timerTasks.addAll(tasks);
}
}

if (arg.hasFilename()) {
String ext = arg.getFileext();
if ("asm".equals(ext)) Loader.loadAsm(machine, arg.getFilename());
Expand All @@ -57,6 +87,9 @@ public static void main(String[] args) throws Exception {
graphicalScreen.toggleView();
}
java.util.Timer timer = new java.util.Timer();
for (TimerTask t : timerTasks) {
timer.schedule(t, 0, 50);
}
TimerTask timerTask = new TimerTask() {
public void run() {
if (textScreen != null) textScreen.updateView();
Expand Down
36 changes: 34 additions & 2 deletions src/sic/sim/Args.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package sic.sim;

import java.util.Vector;

import sic.common.Utils;

/**
Expand Down Expand Up @@ -56,6 +58,8 @@ public class Args extends AbstractCmdLineArgs {
private boolean keyb;
private int keybAddress;

private Vector<AddonArgs> addons = new Vector<AddonArgs>();

public boolean isHelp() {
return help;
}
Expand Down Expand Up @@ -128,6 +132,10 @@ public int getGraphScrFreq() {
return graphScrFreq;
}

public Vector<AddonArgs> getAddons() {
return addons;
}

public static void printArgs() {
System.out.print(
" -help|-h Print help.\n" +
Expand All @@ -137,7 +145,8 @@ public static void printArgs() {
" -stats Print instruction statistics.\n" +
" -text colsxrows Show and resize textual screen.\n" +
" -graph colsxrows[@hz] Show and resize graphical screen.\n" +
" -keyb address Show and set keyboard address.\n");
" -keyb address Show and set keyboard address.\n" +
" -a path[@params] Load addon.\n");
}

int parseFreq(String s) {
Expand Down Expand Up @@ -179,6 +188,17 @@ void parseKeyb(String s){
}
}

void parseAddon(String s) {
int i = s.indexOf('@');
String path = s;
String params = null;
if (i != -1) {
path = s.substring(0, i);
params = s.substring(i + 1);
}
addons.add(new AddonArgs(path, params));
}

void processArgs(String[] args) {
// options
int last = 0;
Expand Down Expand Up @@ -213,6 +233,9 @@ void processArgs(String[] args) {
keyb = true;
parseKeyb(args[++last]);
break;
case "-a":
parseAddon(args[++last]);
break;
}
if (!arg.startsWith("-") || arg.equals("--")) break;
last++;
Expand All @@ -229,4 +252,13 @@ public Args(String[] args) {
processArgs(args);
}

}
public class AddonArgs {
public String path;
public String pars;

public AddonArgs(String path, String pars) {
this.path = path;
this.pars = pars;
}
}
}
55 changes: 53 additions & 2 deletions src/sic/sim/MainView.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import sic.sim.addons.Keyboard;
import sic.sim.addons.TextualScreen;
import sic.sim.views.*;
import sic.sim.addons.Addon;

import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
Expand All @@ -22,6 +23,7 @@
import java.io.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

/**
* TODO: write a short description
Expand All @@ -47,6 +49,11 @@ public class MainView {

private File lastLoadedFile;

private Vector<Addon.MenuEntry> menuEntries = new Vector<Addon.MenuEntry>();
private Vector<Addon.SettingsPanel> settingsPanels = new Vector<Addon.SettingsPanel>();
private Vector<TimerTask> timerTasks = new Vector<TimerTask>();

private Timer timer;

public MainView(final Executor executor, Disassembler disassembler, Args arg) {
this.executor = executor;
Expand Down Expand Up @@ -96,7 +103,7 @@ public MainView(final Executor executor, Disassembler disassembler, Args arg) {
keyboard.toggleView();
}

Timer timer = new Timer();
timer = new Timer();
TimerTask timerTask = new TimerTask() {
public void run() {
if (mainFrame.isVisible() && executor.hasChanged()) {
Expand Down Expand Up @@ -125,6 +132,47 @@ public void updateView() {
watchView.updateView();
}

public void addMenuEntries(Vector<Addon.MenuEntry> entries) {
if (entries == null) {
return;
}
menuEntries.addAll(entries);
}

public void addSettingsPanels(Vector<Addon.SettingsPanel> panels) {
if (panels == null) {
return;
}
settingsPanels.addAll(panels);
}

public void addAddonMenu() {
if (menuEntries.size() <= 0) {
return;
}
JMenuBar mb = mainFrame.getJMenuBar();
JMenu menu = new JMenu("Addons");

for (Addon.MenuEntry e : menuEntries) {
GUI.addMenuItem(menu, e.name, e.keyEvent, e.keyStroke, e.actionListener);
}
mb.add(menu);
}

public void addTimerTasks(Vector<TimerTask> tasks) {
if (tasks == null) {
return;
}
timerTasks.addAll(tasks);
}

public void updateTimerTasks() {
for (TimerTask t : timerTasks) {
System.out.println("scheduling a task");
timer.schedule(t, 0, 50);
}
}

private JMenuBar createMenuBar() {
JMenuBar mb = new JMenuBar();

Expand Down Expand Up @@ -326,7 +374,7 @@ public void loadObj(File file) {
Loader.loadSection(executor.machine, reader);
lastLoadedFile = file;
mainFrame.setTitle(file.getName());
updateView();
updateView();
} catch (FileNotFoundException e1) {
JOptionPane.showMessageDialog(mainFrame, "Error loading object file.");
updateView();
Expand Down Expand Up @@ -392,6 +440,9 @@ private void showSettingsView() {
tabs.addTab("Textual screen", null, textScreen.createSettingsPane(), null);
tabs.addTab("Graphical screen", null, graphScreen.createSettingsPane(), null);
tabs.addTab("Keyboard", null, keyboard.createSettingsPane(), null);
for (Addon.SettingsPanel panel : settingsPanels) {
tabs.addTab(panel.title, null, panel.panel, null);
}
GUI.showInJFrame("Settings", tabs, 0, 0);
}

Expand Down
Loading

0 comments on commit acb23e8

Please sign in to comment.