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; package me.felinewith.kcpu;
import java.io.PrintStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.Future;
import me.felinewith.kcpu.interfaces.IMemory; import me.felinewith.kcpu.interfaces.IMemory;
import me.felinewith.kcpu.opcodes.OpDirector; import me.felinewith.kcpu.opcodes.OpDirector;
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.Converter; import me.felinewith.kcpu.util.Converter;
import me.felinewith.kcpu.util.FakeFuture;
import me.felinewith.kcpu.util.HardwareFinished;
import me.felinewith.kcpu.util.helpers.MemHelper; import me.felinewith.kcpu.util.helpers.MemHelper;
import me.felinewith.kcpu.util.helpers.ValueHelper; import me.felinewith.kcpu.util.helpers.ValueHelper;
import me.felinewith.kcpu.util.helpers.ValueType; import me.felinewith.kcpu.util.helpers.ValueType;
...@@ -16,26 +18,6 @@ import me.felinewith.kcpu.util.helpers.ValueType; ...@@ -16,26 +18,6 @@ import me.felinewith.kcpu.util.helpers.ValueType;
* @author jlhawkwell * @author jlhawkwell
*/ */
public class Kcpu extends BaseDevice { public class Kcpu 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));
}
//private byte[] memory; //private byte[] memory;
//private String name; //private String name;
...@@ -43,6 +25,7 @@ public class Kcpu extends BaseDevice { ...@@ -43,6 +25,7 @@ public class Kcpu extends BaseDevice {
short pc; short pc;
short[] registers; short[] registers;
int nopseq;
private KBoard kboard; private KBoard kboard;
Thread initThread; Thread initThread;
...@@ -56,7 +39,7 @@ public class Kcpu extends BaseDevice { ...@@ -56,7 +39,7 @@ public class Kcpu extends BaseDevice {
* 0x0120 : data stack pointer * 0x0120 : data stack pointer
* 0x0122 : pc stack pointer * 0x0122 : pc stack pointer
* 0x0124 ~ unused * 0x0124 ~ unused
* 0x01ff : interrupt (boolean value) * 0x01ff : irq state
*/ */
memory = new byte[0x0200]; memory = new byte[0x0200];
name = "Kcpu"; name = "Kcpu";
...@@ -65,42 +48,75 @@ public class Kcpu extends BaseDevice { ...@@ -65,42 +48,75 @@ public class Kcpu extends BaseDevice {
pc = 0x1000; pc = 0x1000;
registers = new short[4]; registers = new short[4];
nopseq = 0;
} }
@Override public void init(IMemory system) { @Override public void init(IMemory system) { init(); }
initThread = Thread.currentThread();
setOuter(System.err); @Override public void init() { initThread = Thread.currentThread(); }
}
// need to prevent other devices from writing to CPU internals // need to prevent other devices from writing to CPU internals
@Override public void write(short offset, byte data) { } @Override public void write(short offset, byte data) { }
@Override public void recvIrq(byte irq) { @Override synchronized public void recvIrq(byte irq) {
synchronized (initThread) { // synchronized member means only one thread can use it at a time, which exactly what we want
short[] regs = Arrays.copyOf(registers, registers.length); short[] regs = Arrays.copyOf(registers, registers.length);
short counter = pc; short counter = pc;
if (Thread.currentThread().getId() != initThread.getId()) { int intq = 0;
initThread.interrupt(); if (Thread.currentThread().getId() != initThread.getId()) {
regs = Arrays.copyOf(registers, registers.length); logln("Starting IRQ %x : %s", irq, Thread.currentThread().getName());
counter = pc; Thread.currentThread().setUncaughtExceptionHandler(new KcpuExceptions(this, logger));
synchronized(memory) {
memory[memory.length - 1]++;
intq = memory[memory.length - 1];
} }
short start = (short)((irq * 2) + 0x0180); // when the program counter stops moving, we have successfully
pc = Converter.bytes2short(new byte[]{memory[start], memory[start + 1]}); // paused main processor execution
try { int prevpc = 0;
while (true) { workCycle(); Thread.yield(); } while (prevpc != pc) {
logln("\tWaiting: %4x %4x", prevpc, pc);
prevpc = pc;
} }
catch (CPUStoppedException x) {}
if (Thread.currentThread().getId() != initThread.getId()) { regs = Arrays.copyOf(registers, registers.length);
registers = Arrays.copyOf(regs, regs.length); counter = pc;
pc = counter; }
initThread.notify();
short start = (short)((irq * 2) + 0x0180);
synchronized (memory) { pc = Converter.bytes2short(new byte[]{memory[start], memory[start + 1]}); }
try {
while (true) {
workCycle(intq);
Thread.yield();
} }
} }
catch (CPUStoppedException x) {
logln("CPU Stopped: %s", x.getMessage());
//x = null;
}
if (Thread.currentThread().getId() != initThread.getId()) {
registers = Arrays.copyOf(regs, regs.length);
pc = counter;
synchronized (memory) { memory[memory.length - 1]--; }
initThread.notify();
}
} }
public void workCycle() throws CPUStoppedException { synchronized public Future<HardwareFinished> workCycle(int interrupt) throws CPUStoppedException {
synchronized (memory) {
if (memory[memory.length - 1] != interrupt) {
//logln("Whoops! %s", Thread.currentThread().getName());
try { Thread.sleep(1l); }
catch (IllegalMonitorStateException | InterruptedException x) {}
return new FakeFuture();
}
}
if (nopseq == 100) {
nopseq = 0;
throw new CPUStoppedException("nops");
} // die if there are more than 100 nops
if (pc >= 0xfff0) { pc = 0; } if (pc >= 0xfff0) { pc = 0; }
short inst = MemHelper.readShort(pc, kboard); short inst = MemHelper.readShort(pc, kboard);
short ref = MemHelper.readShort(pc + 2, kboard); short ref = MemHelper.readShort(pc + 2, kboard);
...@@ -125,7 +141,7 @@ public class Kcpu extends BaseDevice { ...@@ -125,7 +141,7 @@ public class Kcpu extends BaseDevice {
} }
log("%04x : [%10s] %04x ->", pc, ((od == null)?"nop":od.name()), ref); log("%04x : [%10s] %04x ->", pc, ((od == null)?"nop":od.name()), ref);
log(" %04x %04x %04x %04x ", registers[0], registers[1], registers[2], registers[3]); log(" %04x %04x %04x %04x", registers[0], registers[1], registers[2], registers[3]);
// this works because the value starts counting at 1 // this works because the value starts counting at 1
switch(0x0700 & ref) { switch(0x0700 & ref) {
...@@ -135,73 +151,119 @@ public class Kcpu extends BaseDevice { ...@@ -135,73 +151,119 @@ public class Kcpu extends BaseDevice {
case 0x0300: ref += (ValueType.R.getValue() << 6); case 0x0300: ref += (ValueType.R.getValue() << 6);
} }
if ((0x0700 & ref) >= 0x0100) { log(" %2s.%04x", ValueType.valueOf(ref, 0), values[0]); } if ((0x0700 & ref) >= 0x0100) { log(" : %2s.%04x", ValueType.valueOf(ref, 0), values[0]); }
if ((0x0700 & ref) >= 0x0200) { log(" %2s.%04x", ValueType.valueOf(ref, 1), values[1]); } if ((0x0700 & ref) >= 0x0200) { log(" %2s.%04x", ValueType.valueOf(ref, 1), values[1]); }
if ((0x0700 & ref) >= 0x0300) { log(" %2s.%04x", ValueType.valueOf(ref, 2), values[2]); } if ((0x0700 & ref) >= 0x0300) { log(" %2s.%04x", ValueType.valueOf(ref, 2), values[2]); }
if ((0x0700 & ref) >= 0x0400) { log(" %2s.%04x", ValueType.valueOf(ref, 3), values[3]); } if ((0x0700 & ref) >= 0x0400) { log(" %2s.%04x", ValueType.valueOf(ref, 3), values[3]); }
// bring up the program counter // bring up the program counter
if (od == null) { if (od == null) {
nopseq++;
pc += 12; // inc if nop pc += 12; // inc if nop
logln("\t[X]"); logln("\t[X]");
return; return new FakeFuture();
}
else {
nopseq = 0;
logln("");
} }
else { logln(""); }
pc += 4; pc += 4;
pc += (((0x0700 & ref) >> 8) * 2); pc += (((0x0700 & ref) >> 8) * 2);
if ( od.hasHandler() ) { if ( od.hasHandler() ) {
registers = od.call(pc, ref, registers, values, kboard); registers = od.call(pc, ref, registers, values, kboard);
return; return new FakeFuture();
} }
short data = ValueHelper.readShort(0, ref, registers, values, kboard); short data = ValueHelper.readShort(0, ref, registers, values, kboard);
synchronized (memory) {
short ps_c = Converter.bytes2short(new byte[]{memory[0x0122], memory[0x0123]});
short ps_d = Converter.bytes2short(new byte[]{memory[0x0120], memory[0x0121]});
short base_c = (short)(0x0100 + (ps_c * 2));
short base_d = (short)(ps_d * 2);
byte[] tmp;
// stack manipulation
switch (od) {
case CALL:
if (ps_c == 0x40) { break; }
tmp = Converter.short2bytes(pc);
ps_c++;
base_c = (short)(0x0100 + (ps_c * 2));
memory[base_c] = tmp[0];
memory[base_c + 1] = tmp[1];
break;
case RET:
if (ps_c == 0) { break; }
pc = Converter.bytes2short(new byte[]{memory[base_c], memory[base_c + 1]});
ps_c--;
break;
case PUSH:
if (ps_c == 0x80) { break; }
tmp = Converter.short2bytes(data);
ps_c++;
base_d = (short)(ps_d * 2);
memory[base_d] = tmp[0];
memory[base_d + 1] = tmp[1];
break;
case POP:
if (ps_d != 0) { break; }
registers[0] = Converter.bytes2short(new byte[]{memory[base_d], memory[base_d + 1]});
ps_d--;
break;
}
}
switch (od) { switch (od) {
// device management // device management
case DEVA: registers[0] = kboard.checkDevice(data); return; case DEVA: registers[0] = kboard.checkDevice(data); break;
case DEVD: kboard.detachDevice(data); return; case DEVD: kboard.detachDevice(data); break;
case DEVM: case DEVM:
kboard.setDeviceRange(data, ValueHelper.readShort(1, ref, registers, values, kboard)); kboard.setDeviceRange(data, ValueHelper.readShort(1, ref, registers, values, kboard));
return; break;
case DEVP: case DEVP:
KMemoryRange kmr = kboard.getDeviceRange(data); KMemoryRange kmr = kboard.getDeviceRange(data);
registers[0] = kmr.getOffset(); registers[0] = kmr.getOffset();
registers[1] = kmr.getLength(); registers[1] = kmr.getLength();
return; break;
// interrupts // interrupts
case IRQD: kboard.sendIrq((byte)(0x000f & data)); return; case IRQD: kboard.sendIrq((byte)(0x000f & data)); break;
case IRQM: kboard.memIrq(data, (byte)0); return; case IRQM: kboard.sendMemIrq(data, (byte)0); break;
case IRQDH: case IRQMH:
Future<HardwareFinished> f;
switch(od) {
case IRQDH: f = kboard.sendIrq((byte)(0x000f & data)); break;
case IRQMH: f = kboard.sendMemIrq(data, (byte)0); break;
default: f = new FakeFuture();
}
return f;
case IRET:
if (interrupt != 0) { throw new CPUStoppedException("iret"); }
break;
// jumps // jumps
case JMP: case JMPU: pc = (short)(pc + (0xffff & data)); return; case JMP: case JMPU: pc = (short)(pc + (0xffff & data)); break;
case JMPA: pc = data; return; case JMPA: pc = data; break;
case JMPD: pc = (short)(pc - (0xffff & data)); return; case JMPD: pc = (short)(pc - (0xffff & data)); break;
case GPC: case GPC:
registers[0] = pc; registers[0] = pc;
return; break;
case ZPWR: throw new CPUStoppedException("zpwr"); case ZPWR: throw new CPUStoppedException("zpwr");
} }
short data2 = ValueHelper.readShort(1, ref, registers, values, kboard); short data2 = ValueHelper.readShort(1, ref, registers, values, kboard);
short data3 = ValueHelper.readShort(2, ref, registers, values, kboard); synchronized (memory) {
switch (od) {
case IVEC:
if (data > 0x10) { break; }
byte[] tmp = Converter.short2bytes(data2);
int a = 0x0180 + (data * 2);
memory[a] = tmp[0];
memory[a + 1] = tmp[1];
}
}
switch (od) { switch (od) {
// conditionals
case JE: if (data == data2) { pc += data3; } return;
case JAE: if (data == data2) { pc = data3; } return;
case JDE: if (data == data2) { pc -= data3; } return;
case JG: if (data > data2) { pc += data3; } return;
case JAG: if (data > data2) { pc = data3; } return;
case JDG: if (data > data2) { pc -= data3; } return;
case JL: if (data < data2) { pc += data3; } return;
case JAL: if (data < data2) { pc = data3; } return;
case JDL: if (data < data2) { pc -= data3; } return;
case JGE: if (data >= data2) { pc += data3; } return;
case JAGE: if (data >= data2) { pc = data3; } return;
case JDGE: if (data >= data2) { pc -= data3; } return;
case JLE: if (data <= data2) { pc += data3; } return;
case JALE: if (data <= data2) { pc = data3; } return;
case JDLE: if (data <= data2) { pc -= data3; } return;
case VCMP: case VCMP:
registers[0] = 0; registers[0] = 0;
if (data != data2) { registers[0] += 0x0001; } if (data != data2) { registers[0] += 0x0001; }
...@@ -209,6 +271,26 @@ public class Kcpu extends BaseDevice { ...@@ -209,6 +271,26 @@ public class Kcpu extends BaseDevice {
if (data == data2) { registers[0] += 0x0004; } if (data == data2) { registers[0] += 0x0004; }
if (data <= data2) { registers[0] += 0x0008; } if (data <= data2) { registers[0] += 0x0008; }
} }
}
short data3 = ValueHelper.readShort(2, ref, registers, values, kboard);
switch (od) {
// conditionals
case JE: if (data == data2) { pc += data3; } break;
case JAE: if (data == data2) { pc = data3; } break;
case JDE: if (data == data2) { pc -= data3; } break;
case JG: if (data > data2) { pc += data3; } break;
case JAG: if (data > data2) { pc = data3; } break;
case JDG: if (data > data2) { pc -= data3; } break;
case JL: if (data < data2) { pc += data3; } break;
case JAL: if (data < data2) { pc = data3; } break;
case JDL: if (data < data2) { pc -= data3; } break;
case JGE: if (data >= data2) { pc += data3; } break;
case JAGE: if (data >= data2) { pc = data3; } break;
case JDGE: if (data >= data2) { pc -= data3; } break;
case JLE: if (data <= data2) { pc += data3; } break;
case JALE: if (data <= data2) { pc = data3; } break;
case JDLE: if (data <= data2) { pc -= data3; } break;
}
return new FakeFuture();
}
} }
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,66 +10,47 @@ import me.felinewith.kcpu.util.Converter; ...@@ -11,66 +10,47 @@ 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) {
byte[] reg; synchronized (memory) {
if (setting == 0) { reg = Arrays.copyOfRange(memory, 0, 7); } byte[] reg;
else { reg = Arrays.copyOfRange(memory, 8, 15); } if (setting == 0) { reg = Arrays.copyOfRange(memory, 0, 7); }
else { reg = Arrays.copyOfRange(memory, 8, 15); }
short starts;
switch (setting) { short starts;
case 0: starts = 0x10; break; switch (setting) {
case 1: starts = 0x12; break; case 0: starts = 0x10; break;
default: starts = 0; break; case 1: starts = 0x12; break;
} default: starts = 0; break;
}
byte[] data = {
read(starts), byte[] data = {
read(starts + 1) read(starts),
}; read(starts + 1)
short opcode = Converter.bytes2short(data); };
KmcuOp od = new KmcuOp(opcode); 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, logln("Kmcp : [%10s] %04x -> %04x %04x %04x %04x %04x %04x %04x %04x",
reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7] ((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);
reg = performCalc(od, reg);
int a;
int c; int a;
if (setting == 0) { a = 0; } int c;
else { a = 8; } if (setting == 0) { a = 0; }
else { a = 8; }
for (c = 0; c < 8; c++) {
memory[a + c] = reg[c]; for (c = 0; c < 8; c++) {
memory[a + c] = reg[c];
}
} }
} }
...@@ -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,36 +31,68 @@ public class BootRom extends BaseMemory { ...@@ -31,36 +31,68 @@ 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) {
memory[writepos] = input; synchronized (memory) {
writepos++; memory[writepos] = input;
if ( writepos == memory.length ) { writepos = 0; } writepos++;
if ( writepos == memory.length ) { writepos = 0; }
}
} }
private void writeBytes(byte[] input) { private void writeBytes(byte[] input) {
......
...@@ -40,46 +40,50 @@ public class Buffer extends BaseMemory { ...@@ -40,46 +40,50 @@ 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) {
short a; synchronized (memory) {
short value; short a;
if (addr <= 0x0f) { short value;
try { if (addr <= 0x0f) {
for (a = 0; a <= 0x0f; a++) { try {
if ( memory[a] == 0 ) { break; } for (a = 0; a <= 0x0f; a++) {
bufout.write(memory[a]); if ( memory[a] == 0 ) { break; }
memory[a] = 0; bufout.write(memory[a]);
memory[a] = 0;
}
bufout.flush();
} }
bufout.flush(); catch (IOException x) {}
} }
catch (IOException x) {} if (addr >= 0x10) {
} try {
if (addr >= 0x10) { if ( bufin.ready() ) {
try { byte[] temp = bufin.toString().getBytes(cs);
if ( bufin.ready() ) { int len = temp.length;
byte[] temp = bufin.toString().getBytes(cs);
int len = temp.length; if ( len >= 16) { len = 16; }
for (a = 0; a < len; a++) {
if ( len >= 16) { len = 16; } value = (short)(0x10 + a);
for (a = 0; a < len; a++) { memory[value] = temp[a];
value = (short)(0x10 + a); }
memory[value] = temp[a];
} }
} }
catch (IOException e) {}
} }
catch (IOException e) {}
} }
} }
@Override public byte read(short addr) { @Override public byte read(short addr) {
if (addr >= memory.length) { return (byte)0xff; } synchronized (memory) {
// input buffer clears when read if (addr >= memory.length) { return (byte)0xff; }
if ( addr >= 0x10 ) { // input buffer clears when read
byte b = memory[addr]; if ( addr >= 0x10 ) {
memory[addr] = 0; byte b = memory[addr];
return b; memory[addr] = 0;
return b;
}
return memory[addr];
} }
return memory[addr];
} }
@Override public void write(short addr, byte data) { @Override public void write(short addr, byte data) {
......
...@@ -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!