Commit adb54524 by Jessica Hawkwell

added 6 new instructions, had to restructure a bit to support interrupts

1 parent 88a0a581
Pipeline #213 passed
in 1 minute 4 seconds
# project-specific stuffs # project-specific stuffs
*.mem.txt *.mem.*
*.bin
*.kc *.kc
# swap # swap
......
...@@ -6,14 +6,15 @@ import java.io.FileWriter; ...@@ -6,14 +6,15 @@ import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.Future;
import me.felinewith.kcpu.hardware.Kmcu;
import me.felinewith.kcpu.interfaces.IDevice; import me.felinewith.kcpu.interfaces.IDevice;
import me.felinewith.kcpu.interfaces.IMemory; import me.felinewith.kcpu.interfaces.IMemory;
import me.felinewith.kcpu.util.BaseDevice; import me.felinewith.kcpu.util.BaseDevice;
import me.felinewith.kcpu.util.CPUStoppedException; import me.felinewith.kcpu.util.CPUStoppedException;
import me.felinewith.kcpu.util.FakeFuture;
import me.felinewith.kcpu.util.HardwareFinished;
import me.felinewith.kcpu.util.HardwareMemIrq; import me.felinewith.kcpu.util.HardwareMemIrq;
import me.felinewith.kcpu.util.HardwareRecvIrq; import me.felinewith.kcpu.util.HardwareRecvIrq;
...@@ -23,7 +24,7 @@ import me.felinewith.kcpu.util.HardwareRecvIrq; ...@@ -23,7 +24,7 @@ import me.felinewith.kcpu.util.HardwareRecvIrq;
*/ */
public class KBoard extends BaseDevice implements IMemory { public class KBoard extends BaseDevice implements IMemory {
final ThreadPoolExecutor tpe; final ExecutorService es;
IDevice[] devices; IDevice[] devices;
KMemoryRange[] deviceMaps; KMemoryRange[] deviceMaps;
...@@ -35,7 +36,7 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -35,7 +36,7 @@ public class KBoard extends BaseDevice implements IMemory {
Kcpu cpu; Kcpu cpu;
public KBoard() { public KBoard() {
tpe = new ThreadPoolExecutor(16, 32, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(16)); es = Executors.newCachedThreadPool();
memory = new byte[0x010000]; memory = new byte[0x010000];
devices = new IDevice[16]; devices = new IDevice[16];
deviceMaps = new KMemoryRange[16]; deviceMaps = new KMemoryRange[16];
...@@ -48,24 +49,24 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -48,24 +49,24 @@ public class KBoard extends BaseDevice implements IMemory {
public void init() { public void init() {
cpu = new Kcpu(this); logln("CPU up...");
attachDevice(0x8000, cpu);
attachDevice(0x8800, new Kmcu());
//attachMemory(0, 0xff00, new Buffer());
//attachMemory(1, 0x1000, new BootRom());
System.out.println("CPU up...");
Future f = new FakeFuture();
try { try {
while (true) { while (true) {
cpu.workCycle(); // we may have a program wait for an interrupt to finish
Thread.yield(); // we halt here so we don't clobber anything
if (f.isDone()) { f = cpu.workCycle(0); }
} }
} }
catch (CPUStoppedException x) {} catch (CPUStoppedException x) { logln("CPU Stopped: %s", x.getMessage());}
System.err.println("CPU Stopped [zpwr]");
tpe.shutdown(); es.shutdown();
while (!es.isTerminated()) {
// slightly longer wait time here, just to give other threads a chance to quit
try { Thread.sleep(1l); }
catch (InterruptedException x) { Thread.yield(); }
}
int a; int a;
for (a = 0; a <= 0xf; a++) { for (a = 0; a <= 0xf; a++) {
if (devices[a] != null) { if (devices[a] != null) {
...@@ -78,13 +79,12 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -78,13 +79,12 @@ public class KBoard extends BaseDevice implements IMemory {
dumpEverything(); dumpEverything();
} }
@Override public void memIrq(short addr, byte irq) { @Override public Future<HardwareFinished> sendMemIrq(short addr, byte irq) {
short dev = checkDevice(addr); short dev = checkDevice(addr);
short rdev = (short)(0x0f & dev); short rdev = (short)(0x0f & dev);
StackTraceElement[] stes = Thread.currentThread().getStackTrace(); StackTraceElement[] stes = Thread.currentThread().getStackTrace();
StackTraceElement ste = stes[2]; StackTraceElement ste = stes[2];
String className = ste.getClassName(); String className = ste.getClassName();
System.err.format("\t\t%s\n", ste.getClassName());
int sendIrq = 16; int sendIrq = 16;
int a; int a;
for (a = 0; a < 16; a++) { for (a = 0; a < 16; a++) {
...@@ -92,33 +92,41 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -92,33 +92,41 @@ public class KBoard extends BaseDevice implements IMemory {
sendIrq = a; sendIrq = a;
break; break;
} }
if ((memDevs[a] != null) && memDevs[a].getClass().getCanonicalName().equals(className)) {
sendIrq = 0x10 + a;
break;
}
} }
if ( dev == 0x7f ) { devices[0].memIrq(addr, (byte)sendIrq); } if ( dev == 0x7f ) { devices[0].recvMemIrq(addr, (byte)sendIrq); }
else if ( dev <= 0x0f ) { else if ( dev <= 0x0f ) {
short devOff = deviceMaps[rdev].getOffset(); short devOff = deviceMaps[rdev].getOffset();
short devAddr = (short)(addr - devOff); short devAddr = (short)(addr - devOff);
tpe.execute(new HardwareMemIrq(devices[rdev], devAddr, (byte)sendIrq)); return es.submit(new HardwareMemIrq(devices[rdev], devAddr, (byte)sendIrq));
} }
else if ( 0x10 <= dev && dev <= 0x1f ) { else if ( 0x10 <= dev && dev <= 0x1f ) {
short devOff = memDevMaps[rdev].getOffset(); short devOff = memDevMaps[rdev].getOffset();
short devAddr = (short)(addr - devOff); short devAddr = (short)(addr - devOff);
tpe.execute(new HardwareMemIrq(memDevs[rdev], devAddr, (byte)sendIrq)); return es.submit(new HardwareMemIrq(memDevs[rdev], devAddr, (byte)sendIrq));
} }
return new FakeFuture();
} }
@Override public void sendIrq(byte irq) { @Override public Future<HardwareFinished> sendIrq(byte irq) {
if ( irq >= 16 ) { return; } if ( irq >= 16 ) { return super.sendIrq(irq); }
StackTraceElement ste = Thread.currentThread().getStackTrace()[1]; StackTraceElement ste = Thread.currentThread().getStackTrace()[2];
String className = ste.getClassName(); String className = ste.getClassName();
int sendIrq = 16; int sendIrq = 16;
int a; int a;
for (a = 0; a < 16; a++) { for (a = 0; a < 16; a++) {
if (devices[a].getClass().getCanonicalName().equals(className)) { if ((devices[a] != null) && devices[a].getClass().getCanonicalName().equals(className)) {
sendIrq = a; sendIrq = a;
break; break;
} }
} }
if ( devices[irq] != null ) { tpe.execute(new HardwareRecvIrq(devices[irq], (byte)sendIrq)); } if ( devices[irq] != null ) {
return es.submit(new HardwareRecvIrq(devices[irq], (byte)sendIrq));
}
return new FakeFuture();
} }
@Override public short length() { return (short)memory.length; }; @Override public short length() { return (short)memory.length; };
...@@ -133,16 +141,16 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -133,16 +141,16 @@ public class KBoard extends BaseDevice implements IMemory {
else if ( 0x10 <= dev && dev <= 0x1f ) { else if ( 0x10 <= dev && dev <= 0x1f ) {
short devOff = memDevMaps[rdev].getOffset(); short devOff = memDevMaps[rdev].getOffset();
short devAddr = (short)(addr - devOff); short devAddr = (short)(addr - devOff);
return memDevs[rdev].read(devAddr); synchronized (memory) { return memDevs[rdev].read(devAddr); }
} }
return memory[0xffff & addr]; synchronized (memory) { return memory[0xffff & addr]; }
} }
@Override public void write(short addr, byte data) { @Override public void write(short addr, byte data) {
short dev = checkDevice(addr); short dev = checkDevice(addr);
System.err.printf("\tWriting %2x to %04x\n", data, addr); logln("\tWriting %2x to %04x", data, addr);
short rdev = (short)(0x0f & dev); short rdev = (short)(0x0f & dev);
if ( dev == 0x7f ) { memory[0xffff & addr] = data; } if ( dev == 0x7f ) { synchronized (memory) { memory[0xffff & addr] = data; } }
if ( dev <= 0x0f ) { if ( dev <= 0x0f ) {
short devOff = deviceMaps[rdev].getOffset(); short devOff = deviceMaps[rdev].getOffset();
short devAddr = (short)(addr - devOff); short devAddr = (short)(addr - devOff);
...@@ -170,6 +178,7 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -170,6 +178,7 @@ public class KBoard extends BaseDevice implements IMemory {
if ( devices[port] != null ) { return; } if ( devices[port] != null ) { return; }
else if ( deviceMaps[port] != null ) { return; } else if ( deviceMaps[port] != null ) { return; }
if ((port == 0) && (device.getClass().isAssignableFrom(Kcpu.class)) ) { cpu = (Kcpu)device; }
devices[port] = device; devices[port] = device;
deviceMaps[port] = new KMemoryRange(offset, device.length()); deviceMaps[port] = new KMemoryRange(offset, device.length());
...@@ -234,8 +243,10 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -234,8 +243,10 @@ public class KBoard extends BaseDevice implements IMemory {
if ( port >= 0x20 ) { return new KMemoryRange((short)0, (short)0); } if ( port >= 0x20 ) { return new KMemoryRange((short)0, (short)0); }
KMemoryRange kmr; KMemoryRange kmr;
if ( port <= 0x0f ) { kmr = deviceMaps[port]; } if ((port <= 0x0f) && (deviceMaps[port] != null)) { kmr = deviceMaps[port]; }
else { kmr = memDevMaps[(short)(0x0f & port)]; } else if ((0x10 <= port) && (port <= 0x2f) && (memDevMaps[0xf & port] != null)) {
kmr = memDevMaps[(short)(0x0f & port)]; }
else { return new KMemoryRange((short)0, (short)0); }
return new KMemoryRange(kmr.getOffset(), kmr.getLength()); return new KMemoryRange(kmr.getOffset(), kmr.getLength());
} }
public void setDeviceRange(short device, short addr) { public void setDeviceRange(short device, short addr) {
...@@ -277,8 +288,11 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -277,8 +288,11 @@ public class KBoard extends BaseDevice implements IMemory {
dumpMemory(filename, temp); dumpMemory(filename, temp);
} }
public void dumpMemory(String filename, byte[] mem) { public void dumpMemory(String filename, byte[] mem) {
byte[] test = new byte[mem.length];
Arrays.fill(test, (byte)0);
if (Arrays.equals(mem, test)) { return; }
File f = new File(filename.concat(".mem.txt")); File f = new File(filename.concat(".mem.txt"));
try { System.out.println(String.format("Writing %s", f.getCanonicalPath())); } catch (IOException x) {} try { logln("Writing %s", f.getCanonicalPath()); } catch (IOException x) {}
try (FileWriter fw = new FileWriter(f)) { try (FileWriter fw = new FileWriter(f)) {
int max = mem.length; int max = mem.length;
int a; int a;
...@@ -322,7 +336,7 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -322,7 +336,7 @@ public class KBoard extends BaseDevice implements IMemory {
catch (IOException x) {} catch (IOException x) {}
f = new File(filename.concat(".mem.bin")); f = new File(filename.concat(".mem.bin"));
try { System.out.println(String.format("Writing %s", f.getCanonicalPath())); } catch (IOException x) {} try { logln("Writing %s", f.getCanonicalPath()); } catch (IOException x) {}
try (FileOutputStream fos = new FileOutputStream(f)) { try (FileOutputStream fos = new FileOutputStream(f)) {
if (mem.length <= 4096) { if (mem.length <= 4096) {
fos.write(mem); fos.write(mem);
......
...@@ -190,7 +190,7 @@ public class Kasm { ...@@ -190,7 +190,7 @@ public class Kasm {
// replace assembler keywords with numbers // replace assembler keywords with numbers
if (temp.contains("BASE")) { temp = temp.replaceAll("BASE", String.format("%d", BASEaddr)); } if (temp.contains("BASE")) { temp = temp.replaceAll("BASE", String.format("%d", BASEaddr)); }
if (temp.contains("MARK")) { temp = temp.replaceAll("MARK", String.format("%d", mark)); } if (temp.contains("MARK")) { temp = temp.replaceAll("MARK", String.format("%d", pc - mark)); }
Pattern p = Pattern.compile("([0-9a-f]+),([0-9]+)", Pattern.CASE_INSENSITIVE); Pattern p = Pattern.compile("([0-9a-f]+),([0-9]+)", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(temp); Matcher m = p.matcher(temp);
...@@ -299,11 +299,12 @@ public class Kasm { ...@@ -299,11 +299,12 @@ public class Kasm {
byte[] bytes = compileSegment(String.format("jmpu %d", max)); byte[] bytes = compileSegment(String.format("jmpu %d", max));
output.write(bytes, 0, bytes.length); output.write(bytes, 0, bytes.length);
for (a = 0; a < max; a++) { output.write(fill); } for (a = 0; a < max; a++) { output.write(fill); }
pc += output.size(); pc += max;
return output.toByteArray(); return output.toByteArray();
} }
else { else {
opcode = OpDirector.valueOf(parts[0]); try { opcode = OpDirector.valueOf(parts[0]); }
catch (IllegalArgumentException x) { return new byte[0]; }
if (verbose) { log("[%10s] ", opcode.name()); } if (verbose) { log("[%10s] ", opcode.name()); }
writeShort(output, opcode.getOpcode()); writeShort(output, opcode.getOpcode());
......
package me.felinewith.kcpu;
import java.io.PrintStream;
import java.lang.Thread.UncaughtExceptionHandler;
/**
*
* @author jlhawkwell
*/
public class KcpuExceptions implements UncaughtExceptionHandler {
Kcpu c;
PrintStream logger;
public KcpuExceptions(Kcpu cpu, PrintStream ps) {
c = cpu;
logger = ps;
}
@Override public void uncaughtException(Thread t, Throwable e) {
logger.format("[%34s] Uncaught Exception: %s\n%s", t.getName(), e.getClass().getCanonicalName(), e.getMessage());
c.recvIrq((byte)0);
}
}
...@@ -2,6 +2,7 @@ package me.felinewith.kcpu; ...@@ -2,6 +2,7 @@ package me.felinewith.kcpu;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import me.felinewith.kcpu.hardware.Kmcu;
import me.felinewith.kcpu.memory.BootRom; import me.felinewith.kcpu.memory.BootRom;
import me.felinewith.kcpu.memory.Buffer; import me.felinewith.kcpu.memory.Buffer;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
...@@ -18,9 +19,6 @@ import org.apache.commons.cli.ParseException; ...@@ -18,9 +19,6 @@ import org.apache.commons.cli.ParseException;
*/ */
public class Kemulator { public class Kemulator {
public static void main(String[] args) { public static void main(String[] args) {
KBoard kb = new KBoard();
Buffer bb = new Buffer();
if ( args.length != 0 ) { if ( args.length != 0 ) {
for (String s : args) { for (String s : args) {
if (s.equals("-kasm")) { Kasm.main(args); return; } if (s.equals("-kasm")) { Kasm.main(args); return; }
...@@ -30,6 +28,7 @@ public class Kemulator { ...@@ -30,6 +28,7 @@ public class Kemulator {
ArrayList<Option> option = new ArrayList<>(); ArrayList<Option> option = new ArrayList<>();
option.add(Option.builder("b") option.add(Option.builder("b")
.longOpt("bootrom") .longOpt("bootrom")
.desc("Loads a given set of ROMs into the BootRom")
.argName("bootrom") .argName("bootrom")
.hasArg() .hasArg()
.numberOfArgs(8) .numberOfArgs(8)
...@@ -37,6 +36,12 @@ public class Kemulator { ...@@ -37,6 +36,12 @@ public class Kemulator {
); );
option.add(Option.builder("h") option.add(Option.builder("h")
.longOpt("help") .longOpt("help")
.desc("Displays this help")
.build()
);
option.add(Option.builder("v")
.longOpt("verbose")
.desc("Enables verbose output (useful for debugging)")
.build() .build()
); );
...@@ -55,6 +60,7 @@ public class Kemulator { ...@@ -55,6 +60,7 @@ public class Kemulator {
} }
BootRom bootrom = new BootRom(); BootRom bootrom = new BootRom();
boolean verbose = false;
if (line != null) { if (line != null) {
if (line.hasOption("h")) { if (line.hasOption("h")) {
...@@ -69,15 +75,34 @@ public class Kemulator { ...@@ -69,15 +75,34 @@ public class Kemulator {
catch (IOException x) {} catch (IOException x) {}
} }
} }
if (line.hasOption("v")) { verbose = true; }
} }
KBoard kb = new KBoard();
Kcpu cpu = new Kcpu(kb);
Kmcu mcu = new Kmcu();
Buffer bb = new Buffer();
bb.setInputStream(System.in); bb.setInputStream(System.in);
bb.setOutputStream(System.out); bb.setOutputStream(System.out);
if (verbose) {
cpu.setLogger(System.err);
mcu.setLogger(System.err);
bb.setLogger(System.err);
}
kb.attachDevice(0x8000, cpu);
kb.attachDevice(0x8800, mcu);
kb.attachMemory(0xff00, bb); kb.attachMemory(0xff00, bb);
kb.attachMemory(0x1000, bootrom); kb.attachMemory(0x1000, bootrom);
kb.init(); if (verbose) {
kb.init(System.err);
System.err.flush();
}
else { kb.init(); }
System.out.flush(); System.out.flush();
} }
......
package me.felinewith.kcpu.hardware; package me.felinewith.kcpu.hardware;
import java.io.PrintStream;
import java.util.Arrays; import java.util.Arrays;
import me.felinewith.kcpu.hardware.kmcu.KmcuOp; import me.felinewith.kcpu.hardware.kmcu.KmcuOp;
import me.felinewith.kcpu.util.BaseDevice; import me.felinewith.kcpu.util.BaseDevice;
...@@ -11,34 +10,14 @@ import me.felinewith.kcpu.util.Converter; ...@@ -11,34 +10,14 @@ import me.felinewith.kcpu.util.Converter;
* @author jlhawkwell * @author jlhawkwell
*/ */
public class Kmcu extends BaseDevice { public class Kmcu extends BaseDevice {
private static PrintStream outer;
/**
* @return the outer
*/
public static PrintStream getOuter() { return outer; }
/**
* @param aOuter the outer to set
*/
public static void setOuter(PrintStream aOuter) { outer = aOuter; }
private static void log(String format, Object... vals) {
if ( outer == null ) { return; }
outer.print(String.format(format, vals));
}
private static void logln(String format, Object... vals) {
if ( outer == null ) { return; }
outer.println(String.format(format, vals));
}
public Kmcu() { public Kmcu() {
setOuter(System.err);
memory = new byte[0x20]; memory = new byte[0x20];
name = "Kmcp"; name = "Kmcp";
} }
private void workInit(short setting) { private void workInit(short setting) {
synchronized (memory) {
byte[] reg; byte[] reg;
if (setting == 0) { reg = Arrays.copyOfRange(memory, 0, 7); } if (setting == 0) { reg = Arrays.copyOfRange(memory, 0, 7); }
else { reg = Arrays.copyOfRange(memory, 8, 15); } else { reg = Arrays.copyOfRange(memory, 8, 15); }
...@@ -73,6 +52,7 @@ public class Kmcu extends BaseDevice { ...@@ -73,6 +52,7 @@ public class Kmcu extends BaseDevice {
memory[a + c] = reg[c]; memory[a + c] = reg[c];
} }
} }
}
private byte[] performCalc(KmcuOp opcode, byte[] reg) { private byte[] performCalc(KmcuOp opcode, byte[] reg) {
byte[] out = new byte[8]; byte[] out = new byte[8];
...@@ -102,6 +82,7 @@ public class Kmcu extends BaseDevice { ...@@ -102,6 +82,7 @@ public class Kmcu extends BaseDevice {
case COS: out[0] = Converter.double2byte(Math.cos(Converter.byte2double(work[0]))); break; case COS: out[0] = Converter.double2byte(Math.cos(Converter.byte2double(work[0]))); break;
case COSH: out[0] = Converter.double2byte(Math.cosh(Converter.byte2double(work[0]))); break; case COSH: out[0] = Converter.double2byte(Math.cosh(Converter.byte2double(work[0]))); break;
case DIV: case DIV:
if (work[1] == 0) { break; }
out[0] = Converter.float2byte(work[0] / work[1]); out[0] = Converter.float2byte(work[0] / work[1]);
out[4] = Converter.int2byte(work[0] % work[1]); out[4] = Converter.int2byte(work[0] % work[1]);
break; break;
...@@ -185,6 +166,7 @@ public class Kmcu extends BaseDevice { ...@@ -185,6 +166,7 @@ public class Kmcu extends BaseDevice {
case COS: out[0] = Converter.double2short(Math.cos(Converter.short2double(work[0]))); break; case COS: out[0] = Converter.double2short(Math.cos(Converter.short2double(work[0]))); break;
case COSH: out[0] = Converter.double2short(Math.cosh(Converter.short2double(work[0]))); break; case COSH: out[0] = Converter.double2short(Math.cosh(Converter.short2double(work[0]))); break;
case DIV: case DIV:
if (work[1] == 0) { break; }
out[0] = Converter.float2short(work[0] / work[1]); out[0] = Converter.float2short(work[0] / work[1]);
out[1] = Converter.int2short(work[0] % work[1]); out[1] = Converter.int2short(work[0] % work[1]);
break; break;
...@@ -281,6 +263,7 @@ public class Kmcu extends BaseDevice { ...@@ -281,6 +263,7 @@ public class Kmcu extends BaseDevice {
case COS: out[0] = Converter.double2int(Math.cos(Converter.int2double(work[0]))); break; case COS: out[0] = Converter.double2int(Math.cos(Converter.int2double(work[0]))); break;
case COSH: out[0] = Converter.double2int(Math.cosh(Converter.int2double(work[0]))); break; case COSH: out[0] = Converter.double2int(Math.cosh(Converter.int2double(work[0]))); break;
case DIV: case DIV:
if (work[1] == 0) { break; }
out[0] = Converter.float2int(work[0] / work[1]); out[0] = Converter.float2int(work[0] / work[1]);
out[1] = work[0] % work[1]; out[1] = work[0] % work[1];
break; break;
...@@ -381,6 +364,7 @@ public class Kmcu extends BaseDevice { ...@@ -381,6 +364,7 @@ public class Kmcu extends BaseDevice {
case COS: out[0] = Converter.double2float(Math.cos(Converter.float2double(work[0]))); break; case COS: out[0] = Converter.double2float(Math.cos(Converter.float2double(work[0]))); break;
case COSH: out[0] = Converter.double2float(Math.cosh(Converter.float2double(work[0]))); break; case COSH: out[0] = Converter.double2float(Math.cosh(Converter.float2double(work[0]))); break;
case DIV: case DIV:
if (work[1] == 0) { break; }
out[0] = work[0] / work[1]; out[0] = work[0] / work[1];
out[1] = work[0] % work[1]; out[1] = work[0] % work[1];
break; break;
...@@ -460,7 +444,7 @@ public class Kmcu extends BaseDevice { ...@@ -460,7 +444,7 @@ public class Kmcu extends BaseDevice {
return output; return output;
} }
@Override public void memIrq(short addr, byte irq) { @Override public void recvMemIrq(short addr, byte irq) {
if ( 0 <= addr && addr <= memory.length ) { if ( 0 <= addr && addr <= memory.length ) {
workInit((short)0); workInit((short)0);
workInit((short)1); workInit((short)1);
......
package me.felinewith.kcpu.interfaces; package me.felinewith.kcpu.interfaces;
import java.io.PrintStream;
import java.util.concurrent.Future;
import me.felinewith.kcpu.util.HardwareFinished;
/** /**
* *
* @author jlhawkwell * @author jlhawkwell
*/ */
public interface IDevice extends IMemory { public interface IDevice extends IMemory {
public void init(IMemory board); public void init(IMemory board);
public void init(PrintStream logger, IMemory board);
public abstract void sendIrq(byte irq); public Future<HardwareFinished> sendIrq(byte irq);
public abstract void recvIrq(byte irq); public void recvIrq(byte irq);
} }
package me.felinewith.kcpu.interfaces; package me.felinewith.kcpu.interfaces;
import java.io.PrintStream;
import java.util.concurrent.Future;
import me.felinewith.kcpu.util.HardwareFinished;
/** /**
* *
* @author jlhawkwell * @author jlhawkwell
*/ */
public interface IMemory { public interface IMemory {
public abstract short length(); public void init();
public abstract byte read(short addr); public void init(PrintStream logger);
public abstract void write(short addr, byte data); public short length();
public abstract void memIrq(short addr, byte irq); public byte read(short addr);
public void write(short addr, byte data);
public Future<HardwareFinished> sendMemIrq(short addr, byte irq);
public void recvMemIrq(short addr, byte irq);
public void setLogger(PrintStream logger);
public void powerOff(); public void powerOff();
} }
...@@ -31,37 +31,69 @@ public class BootRom extends BaseMemory { ...@@ -31,37 +31,69 @@ public class BootRom extends BaseMemory {
// hardcoding some bootrom // hardcoding some bootrom
//writeBytes(kasm.compileSegment("movs $0 r2")); //writeBytes(kasm.compileSegment("movs $0 r2"));
kasm.compileSegment("mark"); kasm.compileSegment("mark");
writeBytes(kasm.compileSegment("add r0 16")); writeBytes(kasm.compileSegment("add r0 8"));
writeBytes(kasm.compileSegment("add r2 1")); writeBytes(kasm.compileSegment("add r2 1"));
writeBytes(kasm.compileSegment("movs $0 r2")); writeBytes(kasm.compileSegment("movs $0 r2"));
writeBytes(kasm.compileSegment("jdl r0 512 mark")); writeBytes(kasm.compileSegment("jdle r2 30 mark"));
//writeBytes(Kasm.compile("movs r0 0")); writeBytes(kasm.compileSegment("mov r2 2"));
//writeBytes(Kasm.compile("movs r1 0")); writeBytes(kasm.compileSegment("mov r3 0"));
//writeBytes(Kasm.compile("movs r2 0")); kasm.compileSegment("mark");
//writeBytes(Kasm.compile("movs r3 0")); writeBytes(kasm.compileSegment("devp r3"));
writeBytes(kasm.compileSegment("movs ar.2 r0"));
writeBytes(kasm.compileSegment("add r2 8"));
writeBytes(kasm.compileSegment("add r3 1"));
writeBytes(kasm.compileSegment("jdle r3 32 mark"));
writeBytes(kasm.compileSegment("mov r2 4"));
writeBytes(kasm.compileSegment("mov r3 0"));
kasm.compileSegment("mark");
writeBytes(kasm.compileSegment("devp r3"));
writeBytes(kasm.compileSegment("movs ar.2 r1"));
writeBytes(kasm.compileSegment("add r2 8"));
writeBytes(kasm.compileSegment("add r3 1"));
writeBytes(kasm.compileSegment("jdle r3 32 mark"));
writeBytes(kasm.compileSegment("gpc")); writeBytes(kasm.compileSegment("movs r0 1f00,16"));
writeBytes(kasm.compileSegment("mov ff00,16 61,16")); writeBytes(kasm.compileSegment("mov r1 0"));
writeBytes(kasm.compileSegment("irqm ff01,16"));
kasm.compileSegment("mark");
writeBytes(kasm.compileSegment("mov ar.0 ar.1"));
writeBytes(kasm.compileSegment("add r1 1"));
writeBytes(kasm.compileSegment("add r0 1"));
writeBytes(kasm.compileSegment("jdle r1 ff,16 mark"));
writeBytes(kasm.compileSegment("irqm 1f00,16"));
/*writeBytes(kasm.compileSegment("gpc"));
writeBytes(kasm.compileSegment("movs r0 60,16"));
kasm.compileSegment("mark");
writeBytes(kasm.compileSegment("add r0 1"));
writeBytes(kasm.compileSegment("mov ff00,16 r0"));
writeBytes(kasm.compileSegment("irqmh ff01,16"));
writeBytes(kasm.compileSegment("jdl r0 7a,16 mark")); // */
} }
// writable at the start, so smart ROMs can rewrite themselves to rearrange stuff // writable at the start, so smart ROMs can rewrite themselves to rearrange stuff
// useful for moving devices around the address space at boot-time // useful for moving devices around the address space at boot-time
// then a simple program can write a device table into ROM space // then a simple program can write a device table into ROM space
// finally, send an interrupt to the ROM device to lock it // finally, send an interrupt to the ROM device to lock it
@Override public void memIrq(short addr, byte irq) { writable = false; } @Override public void recvMemIrq(short addr, byte irq) {
writable = false;
logln("BootRom locked read-only");
}
@Override public void write(short addr, byte data) { @Override public void write(short addr, byte data) {
if (!writable) { return; } if (!writable) { return; }
super.write(addr, data); super.write(addr, data);
} }
private void writeByte(byte input) { private void writeByte(byte input) {
synchronized (memory) {
memory[writepos] = input; memory[writepos] = input;
writepos++; writepos++;
if ( writepos == memory.length ) { writepos = 0; } if ( writepos == memory.length ) { writepos = 0; }
} }
}
private void writeBytes(byte[] input) { private void writeBytes(byte[] input) {
for (byte b : input) { writeByte(b); } for (byte b : input) { writeByte(b); }
......
...@@ -40,7 +40,8 @@ public class Buffer extends BaseMemory { ...@@ -40,7 +40,8 @@ public class Buffer extends BaseMemory {
bufout = new OutputStreamWriter(stdout); bufout = new OutputStreamWriter(stdout);
} }
@Override public void memIrq(short addr, byte irq) { @Override public void recvMemIrq(short addr, byte irq) {
synchronized (memory) {
short a; short a;
short value; short value;
if (addr <= 0x0f) { if (addr <= 0x0f) {
...@@ -70,8 +71,10 @@ public class Buffer extends BaseMemory { ...@@ -70,8 +71,10 @@ public class Buffer extends BaseMemory {
catch (IOException e) {} catch (IOException e) {}
} }
} }
}
@Override public byte read(short addr) { @Override public byte read(short addr) {
synchronized (memory) {
if (addr >= memory.length) { return (byte)0xff; } if (addr >= memory.length) { return (byte)0xff; }
// input buffer clears when read // input buffer clears when read
if ( addr >= 0x10 ) { if ( addr >= 0x10 ) {
...@@ -81,6 +84,7 @@ public class Buffer extends BaseMemory { ...@@ -81,6 +84,7 @@ public class Buffer extends BaseMemory {
} }
return memory[addr]; return memory[addr];
} }
}
@Override public void write(short addr, byte data) { @Override public void write(short addr, byte data) {
// doing this to prevent programs from clobbering the input buffer // doing this to prevent programs from clobbering the input buffer
......
...@@ -18,6 +18,7 @@ public class BasicMath implements IOpcodeHandler { ...@@ -18,6 +18,7 @@ public class BasicMath implements IOpcodeHandler {
switch (opcode) { switch (opcode) {
case ADD: out = ValueHelper.writeShort(0, ref, out, values, memory, new Integer(va + vb).shortValue()); break; case ADD: out = ValueHelper.writeShort(0, ref, out, values, memory, new Integer(va + vb).shortValue()); break;
case DIV: case DIV:
if (vb == 0) { return out; }
out = ValueHelper.writeShort(0, ref, out, values, memory, new Integer(va / vb).shortValue()); out = ValueHelper.writeShort(0, ref, out, values, memory, new Integer(va / vb).shortValue());
out = ValueHelper.writeShort(1, ref, out, values, memory, new Integer(va % vb).shortValue()); out = ValueHelper.writeShort(1, ref, out, values, memory, new Integer(va % vb).shortValue());
break; break;
......
...@@ -32,11 +32,13 @@ public enum OpDirector { ...@@ -32,11 +32,13 @@ public enum OpDirector {
DEVA(0xff00, "addr; get device at address"), // get device port from address DEVA(0xff00, "addr; get device at address"), // get device port from address
DEVD(0xff01, "port: detach device on port"), // detach device DEVD(0xff01, "port: detach device on port"), // detach device
DEVM(0xff02, "port newaddr: relocate device to address"), // relocate device DEVM(0xff02, "port newaddr: relocate device to address"), // relocate device
DEVP(0x1003, "port: get device address for device on port"), // get device address from port DEVP(0xff03, "port: get device address for device on port"), // get device address from port
// interrupts // interrupts
IRQD(0xff10, "port: send interrupt to port"), // interrupt to port IRQD(0xff10, "port: send interrupt to port"), // interrupt to port
IRQM(0xff11, "addr: send interrupt to memory address"), // interrupt to memory IRQM(0xff11, "addr: send interrupt to memory address"), // interrupt to memory
IRQDH(0xff12, "port: send interrupt to port and halt"),
IRQMH(0xff13, "addr: send interrupt to memory address and halt"),
// jumps // jumps
JMP (0xff18, "Alias of JMPU"), // jump up JMP (0xff18, "Alias of JMPU"), // jump up
......
package me.felinewith.kcpu.util; package me.felinewith.kcpu.util;
import java.io.PrintStream;
import java.util.concurrent.Future;
import me.felinewith.kcpu.interfaces.IDevice; import me.felinewith.kcpu.interfaces.IDevice;
import me.felinewith.kcpu.interfaces.IMemory; import me.felinewith.kcpu.interfaces.IMemory;
...@@ -14,14 +16,19 @@ public abstract class BaseDevice extends BaseMemory implements IDevice { ...@@ -14,14 +16,19 @@ public abstract class BaseDevice extends BaseMemory implements IDevice {
@Override public void init(IMemory system) { @Override public void init(IMemory system) {
board = system; board = system;
init();
}
@Override public void init(PrintStream ps, IMemory system) {
super.init(ps);
init(system);
} }
protected void sendIrq() { protected Future<HardwareFinished> sendIrq() {
int addr = memory.length - 1; int addr = memory.length - 1;
sendIrq(memory[addr]); synchronized (memory) { return sendIrq(memory[addr]); }
} }
@Override public void sendIrq(byte irq) { } @Override public Future<HardwareFinished> sendIrq(byte irq) { return new FakeFuture(); }
@Override public void recvIrq(byte irq) { } @Override public void recvIrq(byte irq) { }
@Override public short length() { return (short)memory.length; } @Override public short length() { return (short)memory.length; }
......
package me.felinewith.kcpu.util; package me.felinewith.kcpu.util;
import java.io.PrintStream;
import java.util.concurrent.Future;
import me.felinewith.kcpu.interfaces.IMemory; import me.felinewith.kcpu.interfaces.IMemory;
/** /**
...@@ -9,24 +11,46 @@ import me.felinewith.kcpu.interfaces.IMemory; ...@@ -9,24 +11,46 @@ import me.felinewith.kcpu.interfaces.IMemory;
public abstract class BaseMemory implements IMemory { public abstract class BaseMemory implements IMemory {
protected byte[] memory; protected byte[] memory;
protected PrintStream logger = null;
protected boolean lastLineWasNewLine = false;
@Override public short length() { @Override public void init() {}
return (short)memory.length; @Override public void init(PrintStream ps) {
logger = ps;
init();
} }
@Override public short length() { return (short)memory.length; }
public final byte read(int addr) { return read((short)addr); } public final byte read(int addr) { return read((short)addr); }
@Override public byte read(short addr) { @Override public byte read(short addr) {
if ( (0xffff & addr) > length() ) { return (byte)0xff; } if ( (0xffff & addr) > length() ) { return (byte)0xff; }
return memory[0xffff & addr]; synchronized (memory) { return memory[0xffff & addr]; }
} }
public final void write(int addr, byte data) { write((short)addr, data); } public final void write(int addr, byte data) { write((short)addr, data); }
@Override public void write(short addr, byte data) { @Override public void write(short addr, byte data) {
if ( (0xffff & addr) > length() ) { return; } if ( (0xffff & addr) > length() ) { return; }
memory[0xffff & addr] = data; synchronized (memory) { memory[0xffff & addr] = data; }
} }
@Override public void memIrq(short addr, byte irq) { } @Override public Future<HardwareFinished> sendMemIrq(short addr, byte irq) { return new FakeFuture(); }
@Override public void recvMemIrq(short addr, byte irq) {}
@Override public void setLogger(PrintStream ps) { logger = ps; }
@Override public void powerOff() { } @Override public void powerOff() { }
protected void log(String format, Object... args) {
if (logger == null) { return; }
if (lastLineWasNewLine) {
logger.format("[%-34s] ", Thread.currentThread().getName());
lastLineWasNewLine = false;
}
logger.format(format, args);
}
protected void logln(String format, Object... args) {
if (logger == null) { return; }
log(format, args);
logger.println();
lastLineWasNewLine = true;
}
} }
package me.felinewith.kcpu.util;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
*
* @author jlhawkwell
*/
public class FakeFuture implements Future<HardwareFinished> {
@Override public boolean cancel(boolean mayInterruptIfRunning) { return false; }
@Override public boolean isCancelled() { return true; }
@Override public boolean isDone() { return true; }
@Override public HardwareFinished get() throws InterruptedException, ExecutionException {
return new HardwareFinished(); }
@Override public HardwareFinished get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return new HardwareFinished();
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package me.felinewith.kcpu.util;
/**
*
* @author jlhawkwell
*/
public class HardwareFinished {
}
package me.felinewith.kcpu.util; package me.felinewith.kcpu.util;
import java.util.TimerTask; import java.util.concurrent.Callable;
import me.felinewith.kcpu.interfaces.IMemory; import me.felinewith.kcpu.interfaces.IMemory;
/** /**
* *
* @author jlhawkwell * @author jlhawkwell
*/ */
public class HardwareMemIrq extends TimerTask { public class HardwareMemIrq implements Callable<HardwareFinished> {
IMemory id; IMemory id;
short a; short a;
...@@ -18,8 +18,10 @@ public class HardwareMemIrq extends TimerTask { ...@@ -18,8 +18,10 @@ public class HardwareMemIrq extends TimerTask {
a = addr; a = addr;
i = irq; i = irq;
} }
@Override public void run() {
Thread.currentThread().setName(String.format("memIRQ-%02x_%04x-%x", i, a, Thread.currentThread().getId() )); @Override public HardwareFinished call() throws Exception {
id.memIrq(a, i); Thread.currentThread().setName(String.format("memIRQ-%02x_%04x-%016x", i, a, Thread.currentThread().getId() ));
id.recvMemIrq(a, i);
return new HardwareFinished();
} }
} }
package me.felinewith.kcpu.util; package me.felinewith.kcpu.util;
import java.util.TimerTask; import java.util.concurrent.Callable;
import me.felinewith.kcpu.interfaces.IDevice; import me.felinewith.kcpu.interfaces.IDevice;
/** /**
* *
* @author jlhawkwell * @author jlhawkwell
*/ */
public class HardwareRecvIrq extends TimerTask { public class HardwareRecvIrq implements Callable<HardwareFinished> {
IDevice id; IDevice id;
byte i; byte i;
...@@ -16,8 +16,10 @@ public class HardwareRecvIrq extends TimerTask { ...@@ -16,8 +16,10 @@ public class HardwareRecvIrq extends TimerTask {
id = device; id = device;
i = irq; i = irq;
} }
@Override public void run() {
Thread.currentThread().setName(String.format("recvIRQ-%02x-%x", i, Thread.currentThread().getId() )); @Override public HardwareFinished call() throws Exception {
Thread.currentThread().setName(String.format("recvIRQ-%02x-%016x", i, Thread.currentThread().getId() ));
id.recvIrq(i); id.recvIrq(i);
return new HardwareFinished();
} }
} }
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!