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
*.mem.txt
*.bin
*.mem.*
*.kc
# swap
......
......@@ -6,14 +6,15 @@ import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import me.felinewith.kcpu.hardware.Kmcu;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import me.felinewith.kcpu.interfaces.IDevice;
import me.felinewith.kcpu.interfaces.IMemory;
import me.felinewith.kcpu.util.BaseDevice;
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.HardwareRecvIrq;
......@@ -23,7 +24,7 @@ import me.felinewith.kcpu.util.HardwareRecvIrq;
*/
public class KBoard extends BaseDevice implements IMemory {
final ThreadPoolExecutor tpe;
final ExecutorService es;
IDevice[] devices;
KMemoryRange[] deviceMaps;
......@@ -35,7 +36,7 @@ public class KBoard extends BaseDevice implements IMemory {
Kcpu cpu;
public KBoard() {
tpe = new ThreadPoolExecutor(16, 32, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(16));
es = Executors.newCachedThreadPool();
memory = new byte[0x010000];
devices = new IDevice[16];
deviceMaps = new KMemoryRange[16];
......@@ -48,24 +49,24 @@ public class KBoard extends BaseDevice implements IMemory {
public void init() {
cpu = new Kcpu(this);
attachDevice(0x8000, cpu);
attachDevice(0x8800, new Kmcu());
//attachMemory(0, 0xff00, new Buffer());
//attachMemory(1, 0x1000, new BootRom());
System.out.println("CPU up...");
logln("CPU up...");
Future f = new FakeFuture();
try {
while (true) {
cpu.workCycle();
Thread.yield();
// we may have a program wait for an interrupt to finish
// we halt here so we don't clobber anything
if (f.isDone()) { f = cpu.workCycle(0); }
}
}
catch (CPUStoppedException x) {}
System.err.println("CPU Stopped [zpwr]");
tpe.shutdown();
catch (CPUStoppedException x) { logln("CPU Stopped: %s", x.getMessage());}
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;
for (a = 0; a <= 0xf; a++) {
if (devices[a] != null) {
......@@ -78,13 +79,12 @@ public class KBoard extends BaseDevice implements IMemory {
dumpEverything();
}
@Override public void memIrq(short addr, byte irq) {
@Override public Future<HardwareFinished> sendMemIrq(short addr, byte irq) {
short dev = checkDevice(addr);
short rdev = (short)(0x0f & dev);
StackTraceElement[] stes = Thread.currentThread().getStackTrace();
StackTraceElement ste = stes[2];
String className = ste.getClassName();
System.err.format("\t\t%s\n", ste.getClassName());
int sendIrq = 16;
int a;
for (a = 0; a < 16; a++) {
......@@ -92,33 +92,41 @@ public class KBoard extends BaseDevice implements IMemory {
sendIrq = a;
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 ) {
short devOff = deviceMaps[rdev].getOffset();
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 ) {
short devOff = memDevMaps[rdev].getOffset();
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) {
if ( irq >= 16 ) { return; }
StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
@Override public Future<HardwareFinished> sendIrq(byte irq) {
if ( irq >= 16 ) { return super.sendIrq(irq); }
StackTraceElement ste = Thread.currentThread().getStackTrace()[2];
String className = ste.getClassName();
int sendIrq = 16;
int 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;
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; };
......@@ -133,16 +141,16 @@ public class KBoard extends BaseDevice implements IMemory {
else if ( 0x10 <= dev && dev <= 0x1f ) {
short devOff = memDevMaps[rdev].getOffset();
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) {
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);
if ( dev == 0x7f ) { memory[0xffff & addr] = data; }
if ( dev == 0x7f ) { synchronized (memory) { memory[0xffff & addr] = data; } }
if ( dev <= 0x0f ) {
short devOff = deviceMaps[rdev].getOffset();
short devAddr = (short)(addr - devOff);
......@@ -170,6 +178,7 @@ public class KBoard extends BaseDevice implements IMemory {
if ( devices[port] != null ) { return; }
else if ( deviceMaps[port] != null ) { return; }
if ((port == 0) && (device.getClass().isAssignableFrom(Kcpu.class)) ) { cpu = (Kcpu)device; }
devices[port] = device;
deviceMaps[port] = new KMemoryRange(offset, device.length());
......@@ -234,8 +243,10 @@ public class KBoard extends BaseDevice implements IMemory {
if ( port >= 0x20 ) { return new KMemoryRange((short)0, (short)0); }
KMemoryRange kmr;
if ( port <= 0x0f ) { kmr = deviceMaps[port]; }
else { kmr = memDevMaps[(short)(0x0f & port)]; }
if ((port <= 0x0f) && (deviceMaps[port] != null)) { kmr = deviceMaps[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());
}
public void setDeviceRange(short device, short addr) {
......@@ -277,8 +288,11 @@ public class KBoard extends BaseDevice implements IMemory {
dumpMemory(filename, temp);
}
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"));
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)) {
int max = mem.length;
int a;
......@@ -322,7 +336,7 @@ public class KBoard extends BaseDevice implements IMemory {
catch (IOException x) {}
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)) {
if (mem.length <= 4096) {
fos.write(mem);
......
......@@ -190,7 +190,7 @@ public class Kasm {
// replace assembler keywords with numbers
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);
Matcher m = p.matcher(temp);
......@@ -299,11 +299,12 @@ public class Kasm {
byte[] bytes = compileSegment(String.format("jmpu %d", max));
output.write(bytes, 0, bytes.length);
for (a = 0; a < max; a++) { output.write(fill); }
pc += output.size();
pc += max;
return output.toByteArray();
}
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()); }
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;
import java.io.IOException;
import java.util.ArrayList;
import me.felinewith.kcpu.hardware.Kmcu;
import me.felinewith.kcpu.memory.BootRom;
import me.felinewith.kcpu.memory.Buffer;
import org.apache.commons.cli.CommandLine;
......@@ -18,9 +19,6 @@ import org.apache.commons.cli.ParseException;
*/
public class Kemulator {
public static void main(String[] args) {
KBoard kb = new KBoard();
Buffer bb = new Buffer();
if ( args.length != 0 ) {
for (String s : args) {
if (s.equals("-kasm")) { Kasm.main(args); return; }
......@@ -30,6 +28,7 @@ public class Kemulator {
ArrayList<Option> option = new ArrayList<>();
option.add(Option.builder("b")
.longOpt("bootrom")
.desc("Loads a given set of ROMs into the BootRom")
.argName("bootrom")
.hasArg()
.numberOfArgs(8)
......@@ -37,6 +36,12 @@ public class Kemulator {
);
option.add(Option.builder("h")
.longOpt("help")
.desc("Displays this help")
.build()
);
option.add(Option.builder("v")
.longOpt("verbose")
.desc("Enables verbose output (useful for debugging)")
.build()
);
......@@ -55,6 +60,7 @@ public class Kemulator {
}
BootRom bootrom = new BootRom();
boolean verbose = false;
if (line != null) {
if (line.hasOption("h")) {
......@@ -69,15 +75,34 @@ public class Kemulator {
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.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(0x1000, bootrom);
kb.init();
if (verbose) {
kb.init(System.err);
System.err.flush();
}
else { kb.init(); }
System.out.flush();
}
......
package me.felinewith.kcpu.hardware;
import java.io.PrintStream;
import java.util.Arrays;
import me.felinewith.kcpu.hardware.kmcu.KmcuOp;
import me.felinewith.kcpu.util.BaseDevice;
......@@ -11,66 +10,47 @@ import me.felinewith.kcpu.util.Converter;
* @author jlhawkwell
*/
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() {
setOuter(System.err);
memory = new byte[0x20];
name = "Kmcp";
}
private void workInit(short setting) {
byte[] reg;
if (setting == 0) { reg = Arrays.copyOfRange(memory, 0, 7); }
else { reg = Arrays.copyOfRange(memory, 8, 15); }
short starts;
switch (setting) {
case 0: starts = 0x10; break;
case 1: starts = 0x12; break;
default: starts = 0; break;
}
byte[] data = {
read(starts),
read(starts + 1)
};
short opcode = Converter.bytes2short(data);
KmcuOp od = new KmcuOp(opcode);
logln("Kmcp : [%10s] %04x -> %04x %04x %04x %04x %04x %04x %04x %04x",
((od.name() == null)?"nop":od.name()), opcode,
reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7]
);
reg = performCalc(od, reg);
int a;
int c;
if (setting == 0) { a = 0; }
else { a = 8; }
for (c = 0; c < 8; c++) {
memory[a + c] = reg[c];
synchronized (memory) {
byte[] reg;
if (setting == 0) { reg = Arrays.copyOfRange(memory, 0, 7); }
else { reg = Arrays.copyOfRange(memory, 8, 15); }
short starts;
switch (setting) {
case 0: starts = 0x10; break;
case 1: starts = 0x12; break;
default: starts = 0; break;
}
byte[] data = {
read(starts),
read(starts + 1)
};
short opcode = Converter.bytes2short(data);
KmcuOp od = new KmcuOp(opcode);
logln("Kmcp : [%10s] %04x -> %04x %04x %04x %04x %04x %04x %04x %04x",
((od.name() == null)?"nop":od.name()), opcode,
reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7]
);
reg = performCalc(od, reg);
int a;
int c;
if (setting == 0) { a = 0; }
else { a = 8; }
for (c = 0; c < 8; c++) {
memory[a + c] = reg[c];
}
}
}
......@@ -102,6 +82,7 @@ public class Kmcu extends BaseDevice {
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 DIV:
if (work[1] == 0) { break; }
out[0] = Converter.float2byte(work[0] / work[1]);
out[4] = Converter.int2byte(work[0] % work[1]);
break;
......@@ -185,6 +166,7 @@ public class Kmcu extends BaseDevice {
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 DIV:
if (work[1] == 0) { break; }
out[0] = Converter.float2short(work[0] / work[1]);
out[1] = Converter.int2short(work[0] % work[1]);
break;
......@@ -281,6 +263,7 @@ public class Kmcu extends BaseDevice {
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 DIV:
if (work[1] == 0) { break; }
out[0] = Converter.float2int(work[0] / work[1]);
out[1] = work[0] % work[1];
break;
......@@ -381,6 +364,7 @@ public class Kmcu extends BaseDevice {
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 DIV:
if (work[1] == 0) { break; }
out[0] = work[0] / work[1];
out[1] = work[0] % work[1];
break;
......@@ -460,7 +444,7 @@ public class Kmcu extends BaseDevice {
return output;
}
@Override public void memIrq(short addr, byte irq) {
@Override public void recvMemIrq(short addr, byte irq) {
if ( 0 <= addr && addr <= memory.length ) {
workInit((short)0);
workInit((short)1);
......
package me.felinewith.kcpu.interfaces;
import java.io.PrintStream;
import java.util.concurrent.Future;
import me.felinewith.kcpu.util.HardwareFinished;
/**
*
* @author jlhawkwell
*/
public interface IDevice extends IMemory {
public void init(IMemory board);
public void init(PrintStream logger, IMemory board);
public abstract void sendIrq(byte irq);
public abstract void recvIrq(byte irq);
public Future<HardwareFinished> sendIrq(byte irq);
public void recvIrq(byte irq);
}
package me.felinewith.kcpu.interfaces;
import java.io.PrintStream;
import java.util.concurrent.Future;
import me.felinewith.kcpu.util.HardwareFinished;
/**
*
* @author jlhawkwell
*/
public interface IMemory {
public abstract short length();
public abstract byte read(short addr);
public abstract void write(short addr, byte data);
public abstract void memIrq(short addr, byte irq);
public void init();
public void init(PrintStream logger);
public short length();
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();
}
......@@ -31,36 +31,68 @@ public class BootRom extends BaseMemory {
// hardcoding some bootrom
//writeBytes(kasm.compileSegment("movs $0 r2"));
kasm.compileSegment("mark");
writeBytes(kasm.compileSegment("add r0 16"));
writeBytes(kasm.compileSegment("add r0 8"));
writeBytes(kasm.compileSegment("add r2 1"));
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.compile("movs r1 0"));
//writeBytes(Kasm.compile("movs r2 0"));
//writeBytes(Kasm.compile("movs r3 0"));
writeBytes(kasm.compileSegment("mov r2 2"));
writeBytes(kasm.compileSegment("mov r3 0"));
kasm.compileSegment("mark");
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("mov ff00,16 61,16"));
writeBytes(kasm.compileSegment("irqm ff01,16"));
writeBytes(kasm.compileSegment("movs r0 1f00,16"));
writeBytes(kasm.compileSegment("mov r1 0"));
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
// useful for moving devices around the address space at boot-time
// then a simple program can write a device table into ROM space
// 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) {
if (!writable) { return; }
super.write(addr, data);
}
private void writeByte(byte input) {
memory[writepos] = input;
writepos++;
if ( writepos == memory.length ) { writepos = 0; }
synchronized (memory) {
memory[writepos] = input;
writepos++;
if ( writepos == memory.length ) { writepos = 0; }
}
}
private void writeBytes(byte[] input) {
......
......@@ -40,46 +40,50 @@ public class Buffer extends BaseMemory {
bufout = new OutputStreamWriter(stdout);
}
@Override public void memIrq(short addr, byte irq) {
short a;
short value;
if (addr <= 0x0f) {
try {
for (a = 0; a <= 0x0f; a++) {
if ( memory[a] == 0 ) { break; }
bufout.write(memory[a]);
memory[a] = 0;
@Override public void recvMemIrq(short addr, byte irq) {
synchronized (memory) {
short a;
short value;
if (addr <= 0x0f) {
try {
for (a = 0; a <= 0x0f; a++) {
if ( memory[a] == 0 ) { break; }
bufout.write(memory[a]);
memory[a] = 0;
}
bufout.flush();
}
bufout.flush();
catch (IOException x) {}
}
catch (IOException x) {}
}
if (addr >= 0x10) {
try {
if ( bufin.ready() ) {
byte[] temp = bufin.toString().getBytes(cs);
int len = temp.length;
if ( len >= 16) { len = 16; }
for (a = 0; a < len; a++) {
value = (short)(0x10 + a);
memory[value] = temp[a];
if (addr >= 0x10) {
try {
if ( bufin.ready() ) {
byte[] temp = bufin.toString().getBytes(cs);
int len = temp.length;
if ( len >= 16) { len = 16; }
for (a = 0; a < len; a++) {
value = (short)(0x10 + a);
memory[value] = temp[a];
}
}
}
catch (IOException e) {}
}
catch (IOException e) {}
}
}
@Override public byte read(short addr) {
if (addr >= memory.length) { return (byte)0xff; }
// input buffer clears when read
if ( addr >= 0x10 ) {
byte b = memory[addr];
memory[addr] = 0;
return b;
synchronized (memory) {
if (addr >= memory.length) { return (byte)0xff; }
// input buffer clears when read
if ( addr >= 0x10 ) {
byte b = memory[addr];
memory[addr] = 0;
return b;
}
return memory[addr];
}
return memory[addr];
}
@Override public void write(short addr, byte data) {
......
......@@ -18,6 +18,7 @@ public class BasicMath implements IOpcodeHandler {
switch (opcode) {
case ADD: out = ValueHelper.writeShort(0, ref, out, values, memory, new Integer(va + vb).shortValue()); break;
case DIV:
if (vb == 0) { return out; }
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());
break;
......
......@@ -32,11 +32,13 @@ public enum OpDirector {
DEVA(0xff00, "addr; get device at address"), // get device port from address
DEVD(0xff01, "port: detach device on port"), // detach 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
IRQD(0xff10, "port: send interrupt to port"), // interrupt to port
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
JMP (0xff18, "Alias of JMPU"), // jump up
......
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.IMemory;
......@@ -14,14 +16,19 @@ public abstract class BaseDevice extends BaseMemory implements IDevice {
@Override public void init(IMemory 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;
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 short length() { return (short)memory.length; }
......
package me.felinewith.kcpu.util;
import java.io.PrintStream;
import java.util.concurrent.Future;
import me.felinewith.kcpu.interfaces.IMemory;
/**
......@@ -9,24 +11,46 @@ import me.felinewith.kcpu.interfaces.IMemory;
public abstract class BaseMemory implements IMemory {
protected byte[] memory;
protected PrintStream logger = null;
protected boolean lastLineWasNewLine = false;
@Override public short length() {
return (short)memory.length;
@Override public void init() {}
@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); }
@Override public byte read(short addr) {
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); }
@Override public void write(short addr, byte data) {
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() { }
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;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import me.felinewith.kcpu.interfaces.IMemory;
/**
*
* @author jlhawkwell
*/
public class HardwareMemIrq extends TimerTask {
public class HardwareMemIrq implements Callable<HardwareFinished> {
IMemory id;
short a;
......@@ -18,8 +18,10 @@ public class HardwareMemIrq extends TimerTask {
a = addr;
i = irq;
}
@Override public void run() {
Thread.currentThread().setName(String.format("memIRQ-%02x_%04x-%x", i, a, Thread.currentThread().getId() ));
id.memIrq(a, i);
@Override public HardwareFinished call() throws Exception {
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;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import me.felinewith.kcpu.interfaces.IDevice;
/**
*
* @author jlhawkwell
*/
public class HardwareRecvIrq extends TimerTask {
public class HardwareRecvIrq implements Callable<HardwareFinished> {
IDevice id;
byte i;
......@@ -16,8 +16,10 @@ public class HardwareRecvIrq extends TimerTask {
id = device;
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);
return new HardwareFinished();
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!