Commit 78af4d11 by Jessica Hawkwell

started preliminary support for interrupts, stacks, and function calls

1 parent c44caf9d
Pipeline #211 passed
in 1 minute 8 seconds
# project-specific stuffs # project-specific stuffs
*.mem *.mem.txt
*.bin *.bin
*.kc *.kc
......
...@@ -13,8 +13,9 @@ import me.felinewith.kcpu.hardware.Kmcu; ...@@ -13,8 +13,9 @@ 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.HardwareExec; import me.felinewith.kcpu.util.CPUStoppedException;
import me.felinewith.kcpu.util.HardwareMemIrq; import me.felinewith.kcpu.util.HardwareMemIrq;
import me.felinewith.kcpu.util.HardwareRecvIrq;
/** /**
* *
...@@ -56,45 +57,66 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -56,45 +57,66 @@ public class KBoard extends BaseDevice implements IMemory {
System.out.println("CPU up..."); System.out.println("CPU up...");
while (cpu.workCycle() != 0xff) { try {
Thread.yield(); while (true) {
cpu.workCycle();
Thread.yield();
}
} }
catch (CPUStoppedException x) {}
System.err.println("CPU Stopped [zpwr]"); System.err.println("CPU Stopped [zpwr]");
tpe.shutdown(); tpe.shutdown();
System.err.println("Timers stopped");
int a; int a;
for (a = 0; a <= 0xf; a++) { for (a = 0; a <= 0xf; a++) {
if (devices[a] != null) { if (devices[a] != null) {
devices[a].powerOff(); devices[a].powerOff();
System.err.println(String.format("device %x stopped", a));
} }
if (memDevs[a] != null) { if (memDevs[a] != null) {
memDevs[a].powerOff(); memDevs[a].powerOff();
System.err.println(String.format("memdev %x stopped", a));
} }
} }
dumpEverything(); dumpEverything();
} }
@Override public void memIrq(short addr) { @Override public void memIrq(short addr, byte irq) {
short dev = checkDevice(addr); short dev = checkDevice(addr);
short rdev = (short)(0x0f & dev); short rdev = (short)(0x0f & dev);
if ( dev == 0x7f ) { devices[0].memIrq(addr); } StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
String className = ste.getClassName();
int sendIrq = 16;
int a;
for (a = 0; a < 16; a++) {
if (devices[a].getClass().getCanonicalName().equals(className)) {
sendIrq = a;
break;
}
}
if ( dev == 0x7f ) { devices[0].memIrq(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)); tpe.execute(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)); tpe.execute(new HardwareMemIrq(memDevs[rdev], devAddr, (byte)sendIrq));
} }
} }
@Override public void sendIrq(byte irq) { @Override public void sendIrq(byte irq) {
if ( irq >= 16 ) { return; } if ( irq >= 16 ) { return; }
if ( devices[irq] != null ) { tpe.execute(new HardwareExec(devices[irq])); } StackTraceElement ste = Thread.currentThread().getStackTrace()[1];
String className = ste.getClassName();
int sendIrq = 16;
int a;
for (a = 0; a < 16; a++) {
if (devices[a].getClass().getCanonicalName().equals(className)) {
sendIrq = a;
break;
}
}
if ( devices[irq] != null ) { tpe.execute(new HardwareRecvIrq(devices[irq], (byte)sendIrq)); }
} }
@Override public short length() { return (short)memory.length; }; @Override public short length() { return (short)memory.length; };
...@@ -233,9 +255,6 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -233,9 +255,6 @@ public class KBoard extends BaseDevice implements IMemory {
} }
} }
@Override public void exec() {
}
public void dumpEverything() { public void dumpEverything() {
dumpMemory("system", memory); dumpMemory("system", memory);
int a; int a;
...@@ -256,7 +275,7 @@ public class KBoard extends BaseDevice implements IMemory { ...@@ -256,7 +275,7 @@ 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) {
File f = new File(filename.concat(".mem")); File f = new File(filename.concat(".mem.txt"));
try { System.out.println(String.format("Writing %s", f.getCanonicalPath())); } catch (IOException x) {} try { System.out.println(String.format("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;
......
...@@ -3,18 +3,22 @@ package me.felinewith.kcpu; ...@@ -3,18 +3,22 @@ package me.felinewith.kcpu;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import me.felinewith.kcpu.hardware.kmcu.KmcuOpCodes; import me.felinewith.kcpu.hardware.kmcu.KmcuOpCodes;
import me.felinewith.kcpu.opcodes.OpDirector; import me.felinewith.kcpu.opcodes.OpDirector;
import me.felinewith.kcpu.util.Converter; import me.felinewith.kcpu.util.Converter;
import me.felinewith.kcpu.util.helpers.ValueType;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
...@@ -25,89 +29,259 @@ import org.apache.commons.cli.ParseException; ...@@ -25,89 +29,259 @@ import org.apache.commons.cli.ParseException;
public class Kasm { public class Kasm {
private static PrintStream outer; private static PrintStream outer;
private static boolean verbose = false;
public static void main(String[] args) { public static void main(String[] args) {
setOuter(System.out); setOuter(System.out);
Options opts = new Options(); Options opts = new Options();
opts.addOption("b", "base", true, "Base address for binary"); opts.addOption(Option.builder("b").longOpt("base")
opts.addOption("co", "cpu-opcodes", false, "Displays supported CPU opcodes"); .desc("Program's base address. Emitted code will assume it is loaded to this address.")
opts.addOption("mo", "mcu-opcodes", false, "Displays supported MCU opcodes"); .hasArg(true)
opts.addOption("v", "verbose", false, "Verbose output."); .argName("addr")
opts.addOption("kasm", false, "Ignored."); .numberOfArgs(1)
opts.addOption("help", "Show this help"); .build()
);
opts.addOption(Option.builder("c").longOpt("cpu")
.desc("Displays suppoted CPU opcodes")
.build()
);
opts.addOption(Option.builder("m").longOpt("mcu")
.desc("Displays suported MCU opcodes.")
.build()
);
opts.addOption(Option.builder("v").longOpt("verbose")
.desc("Verbose output.")
.build()
);
opts.addOption(Option.builder().longOpt("kasm")
.desc("This option is ignored.")
.build()
);
opts.addOption(Option.builder("h").longOpt("help")
.desc("Shows this help.")
.build()
);
opts.addOption(Option.builder("o").longOpt("output")
.desc("Filename to use for building a single output file.")
.hasArg()
.argName("file")
.numberOfArgs(1)
.build()
);
String[] files = Arrays.copyOf(args, args.length);
KasmBuilder kb = Kasm.builder();
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new DefaultParser();
try { try {
CommandLine cli = parser.parse(opts, args); CommandLine cli = parser.parse(opts, args);
if (cli.hasOption("help") || cli.hasOption("co") || cli.hasOption("mo")) { if (cli.hasOption("help") || cli.hasOption("c") || cli.hasOption("m")) {
if (cli.hasOption("help")) { if (cli.hasOption("help")) {
HelpFormatter hf = new HelpFormatter(); HelpFormatter hf = new HelpFormatter();
hf.printHelp("kasm [options] [kasm ...]", "", opts,"Non-KASM files may be ignored.", false); hf.printHelp("kasm [options] [kasm ...]", "", opts,"Non-KASM files may be ignored.", false);
} }
if (cli.hasOption("co")) { if (cli.hasOption("cpu")) {
logln("Supported CPU Opcodes:"); logln("Supported CPU Opcodes:");
for (OpDirector oc : OpDirector.values()) { for (OpDirector oc : OpDirector.values()) {
logln("\t[%10s] %s", oc.name(), oc.getDescription()); logln("\t[%10s] %s", oc.name(), oc.getDescription());
} }
logln(""); logln("");
} }
if (cli.hasOption("mo")) { if (cli.hasOption("mcu")) {
logln("Supported MCU Opcodes:"); logln("Supported MCU Opcodes:");
for (KmcuOpCodes oc : KmcuOpCodes.values()) { for (KmcuOpCodes oc : KmcuOpCodes.values()) {
logln("\t%04x -> [%10s]", oc.getOpcode(), oc.name()); logln("\t[%10s] %s", oc.name(), oc.getDescription());
} }
logln(""); logln("");
} }
return; return;
} }
if (cli.hasOption("v")) { verbose = true; } if (cli.hasOption("verbose")) { kb.setVerbose(true); }
if (cli.hasOption("base")) { kb.setBASEaddr(Short.valueOf(cli.getOptionValue("base"))); }
if (cli.hasOption("output")) { kb.setFile(cli.getOptionValue("output")); }
files = cli.getArgs();
} }
catch (ParseException x) { catch (ParseException x) {
logln("Parser error: %s", x.getMessage()); logln("Parser error: %s", x.getMessage());
HelpFormatter hf = new HelpFormatter(); HelpFormatter hf = new HelpFormatter();
hf.printHelp("kasm [options] [kasm files]", "Header",opts,"Footer\nNote: Non-KASM text files may be ignored.", true); hf.printHelp("kasm [options] [kasm files]", "Header", opts,
"Note: Non-KASM text files may be ignored.", true);
return; return;
} }
for (String a : args) { Kasm kasm = kb.build();
for (String a : files) {
if ( a.endsWith(".kasm") ) { if ( a.endsWith(".kasm") ) {
try { assemble(a); } try {
kasm.assemble(a);
kasm.reset();
}
catch (IOException x) {} catch (IOException x) {}
} }
} }
kasm.close();
} }
static void assemble(String filename) throws IOException { assemble(new File(filename));} /**
static void assemble(File file) throws IOException { * @return the outer
File out = new File(file.getCanonicalPath().concat(".kc")); */
public static PrintStream getOuter() { return outer; }
logln("\nInput : %s\nOutput: %s", file.getCanonicalPath(), out.getCanonicalPath()); /**
FileInputStream fis = new FileInputStream(file); * @param aOuter the outer to set
FileOutputStream fos = new FileOutputStream(out); */
public static void setOuter(PrintStream aOuter) { outer = aOuter; }
InputStreamReader isr = new InputStreamReader(fis); private static void log(String format, Object... vals) {
BufferedReader br = new BufferedReader(isr); 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 static KasmBuilder builder() { return new Kasm.KasmBuilder(); }
private short BASEaddr;
private short mark;
private boolean verbose;
private File outFile = null;
private FileOutputStream fileOutputStream = null;
private ByteArrayOutputStream baos;
private short pc;
private Kasm() { }
private Kasm(KasmBuilder builder) {
BASEaddr = builder.BASEaddr;
if (builder.file != null) {
outFile = builder.file;
try { fileOutputStream = new FileOutputStream(outFile); }
catch (IOException x) {}
}
verbose = builder.verbose;
baos = new ByteArrayOutputStream();
}
private String stripType(String input) {
if (input.contains(".")) { return input.substring(input.indexOf('.') + 1); }
switch (input.charAt(0)) {
case 'R': case 'r': case '%': case '$':
return input.substring(1);
}
return input;
}
private short asmType(String input) {
String test = input.toLowerCase();
if (test.startsWith("d.")) { return ValueType.D.getValue(); }
else if (test.startsWith("r") || test.startsWith("r.")) { return ValueType.R.getValue(); }
else if (test.startsWith("%") || test.startsWith("ad.")) { return ValueType.AD.getValue(); }
else if (test.startsWith("$") || test.startsWith("ar.")) { return ValueType.AR.getValue(); }
return ValueType.D.getValue();
}
private short numberize(String input) {
String temp = stripType(input).toUpperCase();
String[] pt;
int tmp;
// remove underscores, which are useful in reading numbers in code
if (temp.contains("_")) { temp = temp.replaceAll("_", ""); }
// 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)); }
Pattern p = Pattern.compile("([0-9a-f]+),([0-9]+)", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(temp);
// convert radix'd numbers
short radix;
while (m.find()) {
radix = Short.valueOf(m.group(2), 10);
tmp = Integer.valueOf(m.group(1), radix);
temp = temp.replace(m.group(), String.format("%d", (short)(0xffff & tmp)));
m.reset(temp);
}
// perform any required math
p = Pattern.compile("([0-9a-f]+)([-+*\\/])([0-9a-f]+)", Pattern.CASE_INSENSITIVE);
m = p.matcher(temp);
while (m.find()) {
switch (m.group(2)) {
case "+":
tmp = Integer.valueOf(m.group(1)) + Integer.valueOf(m.group(3));
temp = temp.replace(m.group(), String.format("%d", (short)(0xffff & tmp)));
break;
case "-":
tmp = Integer.valueOf(m.group(1)) - Integer.valueOf(m.group(3));
temp = temp.replace(m.group(), String.format("%d", (short)(0xffff & tmp)));
break;
case "*":
tmp = Integer.valueOf(m.group(1)) * Integer.valueOf(m.group(3));
temp = temp.replace(m.group(), String.format("%d", (short)(0xffff & tmp)));
break;
case "/":
tmp = Integer.valueOf(m.group(1)) / Integer.valueOf(m.group(3));
temp = temp.replace(m.group(), String.format("%d", (short)(0xffff & tmp)));
break;
}
m.reset(temp);
}
return (short)(0xffff & Integer.valueOf(temp));
}
void assemble(String filename) throws IOException { assemble(new File(filename));}
void assemble(File file) throws IOException {
String fn = file.getCanonicalPath();
fn = fn.substring(0, fn.lastIndexOf('.'));
File out = new File(String.format("%s.kc", fn));
logln("\nInput : %s\nOutput: %s", file.getCanonicalPath(),
(outFile == null)?out.getCanonicalPath():outFile.getCanonicalPath());
readFromFile(file);
sendToFile(out);
}
public void readFromFile(String filename) throws IOException { readFromFile(new File(filename));}
public void readFromFile(File file) throws IOException {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line; String line;
byte[] temp;
int a;
while ((line = br.readLine()) != null) { while ((line = br.readLine()) != null) {
temp = compile(line); compile(line);
fos.write(temp);
} }
fos.flush(); }
fos.close(); public void sendToFile(String filename) throws IOException { sendToFile(new File(filename)); }
public void sendToFile(File file) throws IOException {
if (outFile == null) { baos.writeTo(new FileOutputStream(file)); }
else { baos.writeTo(fileOutputStream); }
baos.reset();
}
br.close(); public void compile(String[] kasm) {
isr.close(); for (String s : kasm) { compile(s); }
fis.close(); }
public void compile(String kasm) {
byte[] temp = compileSegment(kasm);
baos.write(temp, 0, temp.length);
} }
static public byte[] compile(String kasm) { public byte[] compileSegment(String[] kasm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] temp;
for (String s : kasm) {
temp = compileSegment(s);
output.write(temp, 0, temp.length);
}
return output.toByteArray();
}
public byte[] compileSegment(String kasm) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
if ( kasm.startsWith("#") || kasm.startsWith("//") || kasm.length() == 0 ) {} if ( kasm.startsWith("#") || kasm.startsWith("//") || kasm.length() == 0 ) {}
else { else {
if (kasm.contains("#")) { kasm = kasm.substring(0, kasm.indexOf("#") - 1); }
if (kasm.contains("//")) { kasm = kasm.substring(0, kasm.indexOf("//") - 1); }
String[] parts; String[] parts;
OpDirector opcode; OpDirector opcode;
short ref = 0; short ref = 0;
...@@ -116,18 +290,27 @@ public class Kasm { ...@@ -116,18 +290,27 @@ public class Kasm {
else { parts = new String[]{kasm}; } else { parts = new String[]{kasm}; }
parts[0] = parts[0].toUpperCase(); parts[0] = parts[0].toUpperCase();
if (parts[0].equals("FILL")) { if (parts[0].equals("MARK")) { mark = pc; return new byte[0]; }
else if (parts[0].equals("FILL")) {
int a; int a;
int max = numberize(parts[1]); int max = numberize(parts[1]);
byte fill = 0; byte fill = 0;
if (parts.length >= 3) { fill = (byte)numberize(parts[2]); } if (parts.length >= 3) { fill = (byte)(0xff & numberize(parts[2])); }
for (a = 0; a < max; a++) { baos.write(fill); } byte[] bytes = compileSegment(String.format("jmpu %d", max));
return baos.toByteArray(); output.write(bytes, 0, bytes.length);
for (a = 0; a < max; a++) { output.write(fill); }
pc += output.size();
return output.toByteArray();
} }
else { else {
opcode = OpDirector.valueOf(parts[0]); opcode = OpDirector.valueOf(parts[0]);
if (verbose) { log("[%10s] ", opcode.name()); } if (verbose) { log("[%10s] ", opcode.name()); }
writeShort(baos, opcode.getOpcode()); writeShort(output, opcode.getOpcode());
short plen = (short)parts.length;
if (plen >= 5) { plen = 5; }
plen = (short)(2 + (plen * 2));
pc += plen;
if (verbose) { log(" : "); } if (verbose) { log(" : "); }
if (parts.length >= 2) { ref += asmType(parts[1]); } if (parts.length >= 2) { ref += asmType(parts[1]); }
...@@ -140,90 +323,53 @@ public class Kasm { ...@@ -140,90 +323,53 @@ public class Kasm {
else if (parts.length >= 3) { ref += 0x0200; } else if (parts.length >= 3) { ref += 0x0200; }
else if (parts.length >= 2) { ref += 0x0100; } else if (parts.length >= 2) { ref += 0x0100; }
writeShort(baos, ref); writeShort(output, ref);
if (verbose) { log(" -> "); } if (verbose) { log(" -> "); }
if (parts.length >= 2) { writeShort(baos, numberize(parts[1])); } if (parts.length >= 2) { writeShort(output, numberize(parts[1])); }
if (parts.length >= 3) { writeShort(baos, numberize(parts[2])); } if (parts.length >= 3) { writeShort(output, numberize(parts[2])); }
if (parts.length >= 4) { writeShort(baos, numberize(parts[3])); } if (parts.length >= 4) { writeShort(output, numberize(parts[3])); }
if (parts.length >= 5) { writeShort(baos, numberize(parts[4])); } if (parts.length >= 5) { writeShort(output, numberize(parts[4])); }
if (verbose) { logln(""); } if (verbose) { logln(""); }
} }
} }
return baos.toByteArray(); return output.toByteArray();
} }
static void writeShort(ByteArrayOutputStream baos, short value) {
void writeShort(ByteArrayOutputStream output, short value) {
byte[] temp = Converter.short2bytes(value); byte[] temp = Converter.short2bytes(value);
if (verbose) { log("%02x%02x ", temp[0], temp[1]); } if (verbose) { log("%02x%02x ", temp[0], temp[1]); }
baos.write(temp, 0, temp.length); output.write(temp, 0, temp.length);
}
static void writeShort(FileOutputStream fos, short value) throws IOException {
byte[] v = Converter.short2bytes(value);
if (verbose) { log("[%02x%02x]", v[0], v[1]); }
fos.write(v);
} }
static String stripType(String input) { public void reset() { baos.reset(); }
if (asmType(input) == 0) { return input; } public void close() {
return input.substring(1); if (fileOutputStream != null) {
} try { fileOutputStream.close(); }
catch (IOException x) {}
static short asmType(String input) { return asmType(input.charAt(0)); }
static short asmType(char input) {
switch (input) {
case 'r': return 0x01;
case '%': return 0x02;
case '$': return 0x03;
default: return 0x00;
}
}
static short numberize(String input) {
String temp = stripType(input);
String[] pt;
if (temp.contains("_")) { temp = temp.replaceAll("_", ""); }
if (temp.contains(",")) {
pt = temp.split("[,]");
short radix = Short.valueOf(pt[1], 10);
return (short)(0xffff & Integer.valueOf(pt[0], radix));
} }
else { return (short)(0xffff & Integer.valueOf(temp)); }
}
/**
* @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 static KasmBuilder builder() { return new Kasm.KasmBuilder(); }
short BASEaddr;
private Kasm() { }
private Kasm(KasmBuilder builder) {
BASEaddr = builder.BASEaddr;
} }
public static class KasmBuilder { public static class KasmBuilder {
short BASEaddr; short BASEaddr = 0;
boolean verbose = false;
File file = null;
public KasmBuilder() { } public KasmBuilder() { }
public Kasm build() { return new Kasm(this); } public Kasm build() { return new Kasm(this); }
public KasmBuilder setBASEaddr(short BASEaddr) { this.BASEaddr = BASEaddr; return this; } public KasmBuilder setBASEaddr(short BASEaddr) { this.BASEaddr = BASEaddr; return this; }
public KasmBuilder setFile(String file) {
String temp = file;
int t = file.lastIndexOf('.');
if (t == -1) { temp = String.format("%s.kc", file); }
else if (!file.substring(t + 1).equals("kc")) { temp = String.format("%s.kc", file.substring(0, t)); }
return setFile(new File(temp));
}
public KasmBuilder setFile(File file) { this.file = file; return this; }
public KasmBuilder setVerbose(boolean verbose) { this.verbose = verbose; return this; }
} }
} }
package me.felinewith.kcpu; package me.felinewith.kcpu;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.Arrays;
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.Converter;
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;
...@@ -42,9 +45,20 @@ public class Kcpu extends BaseDevice { ...@@ -42,9 +45,20 @@ public class Kcpu extends BaseDevice {
short[] registers; short[] registers;
private KBoard kboard; private KBoard kboard;
Thread initThread;
public Kcpu(KBoard system) { public Kcpu(KBoard system) {
memory = new byte[0x0800]; /**
* memory ranges:
* 0x0000 - 0x00ff : data stack
* 0x0100 - 0x017f : pc stack (return stack)
* 0x0180 - 0x019f : interrupt vectors
* 0x0120 : data stack pointer
* 0x0122 : pc stack pointer
* 0x0124 ~ unused
* 0x01ff : interrupt (boolean value)
*/
memory = new byte[0x0200];
name = "Kcpu"; name = "Kcpu";
settings = new short[6]; settings = new short[6];
kboard = system; kboard = system;
...@@ -54,30 +68,45 @@ public class Kcpu extends BaseDevice { ...@@ -54,30 +68,45 @@ public class Kcpu extends BaseDevice {
} }
@Override public void init(IMemory system) { @Override public void init(IMemory system) {
initThread = Thread.currentThread();
setOuter(System.err); setOuter(System.err);
} }
@Override public void exec() { workCycle(); } // need to prevent other devices from writing to CPU internals
@Override public void write(short offset, byte data) { }
@Override public byte read(short addr) { @Override public void recvIrq(byte irq) {
if ( (0xffff & addr) > length() ) { return (byte)0xff; } synchronized (initThread) {
return memory[0xffff & addr]; short[] regs = Arrays.copyOf(registers, registers.length);
} short counter = pc;
if (Thread.currentThread().getId() != initThread.getId()) {
initThread.interrupt();
regs = Arrays.copyOf(registers, registers.length);
counter = pc;
}
@Override public void write(short offset, byte data) { } short start = (short)((irq * 2) + 0x0180);
@Override public void copy(short addrSrc, short addrDest, IMemory dest) { } pc = Converter.bytes2short(new byte[]{memory[start], memory[start + 1]});
try {
while (true) { workCycle(); Thread.yield(); }
}
catch (CPUStoppedException x) {}
@Override public void memIrq(short addr) { if (Thread.currentThread().getId() != initThread.getId()) {
if (0 <= addr && addr <= memory.length) { exec(); } registers = Arrays.copyOf(regs, regs.length);
pc = counter;
initThread.notify();
}
}
} }
public int workCycle() { public void workCycle() throws CPUStoppedException {
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);
short[] values = new short[4]; short[] values = new short[]{(short)0, (short)1, (short)2, (short)3};
if ((0xffff & inst) == 0xffff){ if ((0xffff & inst) == 0xff1b){
logln("Break!"); log("");
} }
switch (0x0700 & ref) { switch (0x0700 & ref) {
case 0x0700: case 0x0600: case 0x0500: case 0x0700: case 0x0600: case 0x0500:
...@@ -96,8 +125,20 @@ public class Kcpu extends BaseDevice { ...@@ -96,8 +125,20 @@ 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\t\t", registers[0], registers[1], registers[2], registers[3]); // bring up the program counter
if (od == null) { pc += 12; return; } // inc if nop
pc += 4;
pc += (((0x0700 & ref) >> 8) * 2);
// this works because the value starts counting at 1
switch(0x0700 & ref) {
case 0x0000: ref += ValueType.R.getValue();
case 0x0100: ref += (ValueType.R.getValue() << 2);
case 0x0200: ref += (ValueType.R.getValue() << 4);
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]); }
...@@ -105,72 +146,65 @@ public class Kcpu extends BaseDevice { ...@@ -105,72 +146,65 @@ public class Kcpu extends BaseDevice {
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]); }
logln(""); logln("");
if (od == null) { pc += 12; return 0; } // inc if nop
pc += 4;
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 0; return;
} }
short data = ValueHelper.readShort(0, ref, registers, values, kboard); short data = ValueHelper.readShort(0, ref, registers, values, kboard);
switch (od) { switch (od) {
// device management // device management
case DEVA: registers[0] = kboard.checkDevice(data); return 0; case DEVA: registers[0] = kboard.checkDevice(data); return;
case DEVD: kboard.detachDevice(data); return 0; case DEVD: kboard.detachDevice(data); return;
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 0; return;
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 0; return;
// interrupts // interrupts
case IRQD: kboard.sendIrq((byte)(0x000f & data)); return 0; case IRQD: kboard.sendIrq((byte)(0x000f & data)); return;
case IRQM: kboard.memIrq(data); return 0; case IRQM: kboard.memIrq(data, (byte)0); return;
// jumps // jumps
case JMP: pc = (short)(pc + (0xffff & data)); return 0; case JMP: case JMPU: pc = (short)(pc + (0xffff & data)); return;
case JMPA: pc = data; return 0; case JMPA: pc = data; return;
case JMPD: pc = (short)(pc - (0xffff & data)); return 0; case JMPD: pc = (short)(pc - (0xffff & data)); return;
case GPC: case GPC:
registers = ValueHelper.writeShort(0, ref, registers, values, kboard, pc); registers[0] = pc;
return 0; return;
case ZPWR: return 0xff; 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); short data3 = ValueHelper.readShort(2, ref, registers, values, kboard);
switch (od) { switch (od) {
// conditionals // conditionals
case JE: if (data == data2) { pc += data3; } return 0; case JE: if (data == data2) { pc += data3; } return;
case JAE: if (data == data2) { pc = data3; } return 0; case JAE: if (data == data2) { pc = data3; } return;
case JDE: if (data == data2) { pc -= data3; } return 0; case JDE: if (data == data2) { pc -= data3; } return;
case JG: if (data > data2) { pc += data3; } return 0; case JG: if (data > data2) { pc += data3; } return;
case JAG: if (data > data2) { pc = data3; } return 0; case JAG: if (data > data2) { pc = data3; } return;
case JDG: if (data > data2) { pc -= data3; } return 0; case JDG: if (data > data2) { pc -= data3; } return;
case JL: if (data < data2) { pc += data3; } return 0; case JL: if (data < data2) { pc += data3; } return;
case JAL: if (data < data2) { pc = data3; } return 0; case JAL: if (data < data2) { pc = data3; } return;
case JDL: if (data < data2) { pc -= data3; } return 0; case JDL: if (data < data2) { pc -= data3; } return;
case JGE: if (data >= data2) { pc += data3; } return 0; case JGE: if (data >= data2) { pc += data3; } return;
case JAGE: if (data >= data2) { pc = data3; } return 0; case JAGE: if (data >= data2) { pc = data3; } return;
case JDGE: if (data >= data2) { pc -= data3; } return 0; case JDGE: if (data >= data2) { pc -= data3; } return;
case JLE: if (data <= data2) { pc += data3; } return 0; case JLE: if (data <= data2) { pc += data3; } return;
case JALE: if (data <= data2) { pc = data3; } return 0; case JALE: if (data <= data2) { pc = data3; } return;
case JDLE: if (data <= data2) { pc -= data3; } return 0; 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; }
if (data >= data2) { registers[0] += 0x0002; } if (data >= data2) { registers[0] += 0x0002; }
if (data == data2) { registers[0] += 0x0004; } if (data == data2) { registers[0] += 0x0004; }
if (data <= data2) { registers[0] += 0x0008; } if (data <= data2) { registers[0] += 0x0008; }
return 0;
} }
return 0;
} }
} }
...@@ -30,7 +30,7 @@ public class Kemulator { ...@@ -30,7 +30,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")
.argName("bootrom.kc") .argName("bootrom")
.hasArg() .hasArg()
.numberOfArgs(8) .numberOfArgs(8)
.build() .build()
......
package me.felinewith.kcpu.hardware; package me.felinewith.kcpu.hardware;
import me.felinewith.kcpu.hardware.kmcu.KmcuOp;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.Arrays; import java.util.Arrays;
import me.felinewith.kcpu.util.Converter; import me.felinewith.kcpu.hardware.kmcu.KmcuOp;
import me.felinewith.kcpu.util.BaseDevice; import me.felinewith.kcpu.util.BaseDevice;
import me.felinewith.kcpu.util.Converter;
/** /**
* *
...@@ -38,11 +38,6 @@ public class Kmcu extends BaseDevice { ...@@ -38,11 +38,6 @@ public class Kmcu extends BaseDevice {
name = "Kmcp"; name = "Kmcp";
} }
@Override public void exec() {
workInit((short)0);
workInit((short)1);
}
private void workInit(short setting) { private void workInit(short setting) {
byte[] reg; byte[] reg;
if (setting == 0) { reg = Arrays.copyOfRange(memory, 0, 7); } if (setting == 0) { reg = Arrays.copyOfRange(memory, 0, 7); }
...@@ -465,9 +460,15 @@ public class Kmcu extends BaseDevice { ...@@ -465,9 +460,15 @@ public class Kmcu extends BaseDevice {
return output; return output;
} }
@Override public void memIrq(short addr) { @Override public void memIrq(short addr, byte irq) {
if ( 0 <= addr && addr <= memory.length ) { exec(); } if ( 0 <= addr && addr <= memory.length ) {
workInit((short)0);
workInit((short)1);
}
} }
@Override public void sendIrq(byte irq) { } @Override public void recvIrq(byte irq) {
workInit((short)0);
workInit((short)1);
}
} }
...@@ -8,5 +8,5 @@ public interface IDevice extends IMemory { ...@@ -8,5 +8,5 @@ public interface IDevice extends IMemory {
public void init(IMemory board); public void init(IMemory board);
public abstract void sendIrq(byte irq); public abstract void sendIrq(byte irq);
public void exec(); public abstract void recvIrq(byte irq);
} }
...@@ -8,8 +8,7 @@ public interface IMemory { ...@@ -8,8 +8,7 @@ public interface IMemory {
public abstract short length(); public abstract short length();
public abstract byte read(short addr); public abstract byte read(short addr);
public abstract void write(short addr, byte data); public abstract void write(short addr, byte data);
public void copy(short addrSrc, short addrDest, IMemory dest); public abstract void memIrq(short addr, byte irq);
public abstract void memIrq(short addr);
public void powerOff(); public void powerOff();
} }
...@@ -6,6 +6,7 @@ import java.io.FileNotFoundException; ...@@ -6,6 +6,7 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import me.felinewith.kcpu.Kasm; import me.felinewith.kcpu.Kasm;
import me.felinewith.kcpu.Kasm.KasmBuilder;
import me.felinewith.kcpu.util.BaseMemory; import me.felinewith.kcpu.util.BaseMemory;
/** /**
...@@ -15,42 +16,42 @@ import me.felinewith.kcpu.util.BaseMemory; ...@@ -15,42 +16,42 @@ import me.felinewith.kcpu.util.BaseMemory;
public class BootRom extends BaseMemory { public class BootRom extends BaseMemory {
private short writepos; private short writepos;
private short prev;
private short prev2;
private boolean writable; private boolean writable;
public BootRom() { public BootRom() {
writepos = 0; writepos = 0;
prev = 0; writable = true;
prev2 = 0;
writable = false;
memory = new byte[0x1000]; memory = new byte[0x1000];
Arrays.fill(memory, (byte)0xff); Arrays.fill(memory, (byte)0xff);
KasmBuilder kb = Kasm.builder();
kb.setBASEaddr((short)0x1000);
kb.setVerbose(false);
Kasm kasm = kb.build();
// hardcoding some bootrom // hardcoding some bootrom
writeBytes(Kasm.compile("movs $0 r2")); //writeBytes(kasm.compileSegment("movs $0 r2"));
writeBytes(Kasm.compile("add r0 16")); kasm.compileSegment("mark");
writeBytes(Kasm.compile("add r2 1")); writeBytes(kasm.compileSegment("add r0 16"));
writeBytes(Kasm.compile("movs $0 r2")); writeBytes(kasm.compileSegment("add r2 1"));
writeBytes(Kasm.compile("jdl r0 512 22,16")); writeBytes(kasm.compileSegment("movs $0 r2"));
writeBytes(kasm.compileSegment("jdl r0 512 mark"));
//writeBytes(Kasm.compile("movs r0 0")); //writeBytes(Kasm.compile("movs r0 0"));
//writeBytes(Kasm.compile("movs r1 0")); //writeBytes(Kasm.compile("movs r1 0"));
//writeBytes(Kasm.compile("movs r2 0")); //writeBytes(Kasm.compile("movs r2 0"));
//writeBytes(Kasm.compile("movs r3 0")); //writeBytes(Kasm.compile("movs r3 0"));
writeBytes(Kasm.compile("gpc %0300,16")); writeBytes(kasm.compileSegment("gpc"));
writeBytes(Kasm.compile("mov ff00,16 61,16")); writeBytes(kasm.compileSegment("mov ff00,16 61,16"));
writeBytes(Kasm.compile("irqm ff01,16")); writeBytes(kasm.compileSegment("irqm ff01,16"));
} }
@Override public void memIrq(short addr) { // writable at the start, so smart ROMs can rewrite themselves to rearrange stuff
writable = ((prev2 == 0x4b63) && (prev == 0x7075) && (addr == 0x7f)); // useful for moving devices around the address space at boot-time
// then a simple program can write a device table into ROM space
if ((0xff & prev) == 0) { prev += addr; } // finally, send an interrupt to the ROM device to lock it
else if ((0xff00 & prev) == 0) { prev = (short)(prev << 8); prev += addr; } @Override public void memIrq(short addr, byte irq) { writable = false; }
else { prev2 = prev; }
}
@Override public void write(short addr, byte data) { @Override public void write(short addr, byte data) {
if (!writable) { return; } if (!writable) { return; }
......
...@@ -40,7 +40,7 @@ public class Buffer extends BaseMemory { ...@@ -40,7 +40,7 @@ public class Buffer extends BaseMemory {
bufout = new OutputStreamWriter(stdout); bufout = new OutputStreamWriter(stdout);
} }
@Override public void memIrq(short addr) { @Override public void memIrq(short addr, byte irq) {
short a; short a;
short value; short value;
if (addr <= 0x0f) { if (addr <= 0x0f) {
......
package me.felinewith.kcpu.opcodes; package me.felinewith.kcpu.opcodes;
import me.felinewith.kcpu.util.helpers.ValueHelper;
import java.util.Arrays; import java.util.Arrays;
import me.felinewith.kcpu.interfaces.IMemory; import me.felinewith.kcpu.interfaces.IMemory;
import me.felinewith.kcpu.util.helpers.ValueHelper;
/** /**
* *
...@@ -11,8 +11,9 @@ import me.felinewith.kcpu.interfaces.IMemory; ...@@ -11,8 +11,9 @@ import me.felinewith.kcpu.interfaces.IMemory;
public class Memory implements IOpcodeHandler { public class Memory implements IOpcodeHandler {
@Override public short[] opcode(OpDirector opcode, short pc, short ref, short[] regs, short[] values, IMemory memory) { @Override public short[] opcode(OpDirector opcode, short pc, short ref, short[] regs, short[] values, IMemory memory) {
short data;
short[] output = Arrays.copyOf(regs, regs.length); short[] output = Arrays.copyOf(regs, regs.length);
short addr = ValueHelper.readShort(0, ref, output, values, memory);
short data;
switch (opcode) { switch (opcode) {
case MOV: case MOVB: case MOV: case MOVB:
data = ValueHelper.readByte(1, ref, output, values, memory); data = ValueHelper.readByte(1, ref, output, values, memory);
......
...@@ -18,43 +18,59 @@ public enum OpDirector { ...@@ -18,43 +18,59 @@ public enum OpDirector {
MOV (0x0010, Memory.class, "Alias for MOVB"), MOVB(0x0010, Memory.class, "dest value"), MOV (0x0010, Memory.class, "Alias for MOVB"), MOVB(0x0010, Memory.class, "dest value"),
MOVS(0x0011, Memory.class, "dest value"), MOVS(0x0011, Memory.class, "dest value"),
// stack manipulation
PUSH(0x1000, "value: push value to stack"),
POP (0x1001, "pop value off stack"),
CALL(0x1002, "addr: call function at address"),
RET (0x1003, "return from function"),
IRET(0x10f0, "return from interrupt state (does nothing in normal mode)"),
// interrupt vector management
IVEC(0x10f1, "irq addr: set function address for interrupt irq"),
// cpu stuffies // cpu stuffies
DEVA(0xff00, "n0; get device at address n0"), // get device port from address DEVA(0xff00, "addr; get device at address"), // get device port from address
DEVD(0xff01, "n0: detach device on port n0"), // detach device DEVD(0xff01, "port: detach device on port"), // detach device
DEVM(0xff02, "n0 n1: relocate device n0 to address n1"), // relocate device DEVM(0xff02, "port newaddr: relocate device to address"), // relocate device
DEVP(0x1003, "n0: get device address for device on port n0"), // get device address from port DEVP(0x1003, "port: get device address for device on port"), // get device address from port
IRQD(0xff10, "n0: send interrupt to port n0"), // interrupt to port // interrupts
IRQM(0xff11, "n0: send interrupt to memory address n0"), // interrupt to memory IRQD(0xff10, "port: send interrupt to port"), // interrupt to port
IRQM(0xff11, "addr: send interrupt to memory address"), // interrupt to memory
// jumps
JMP (0xff18, "Alias of JMPU"), // jump up JMP (0xff18, "Alias of JMPU"), // jump up
JMPU(0xff18, "n0: jump up n0 addresses"), JMPU(0xff18, "addr: jump up n0 addresses"),
JMPA(0xff19, "n0: jump to address n0"), // jump absolute addr JMPA(0xff19, "addr: jump to address n0"), // jump absolute addr
JMPD(0xff1a, "n0: jump down n0 addresses"), // jump down JMPD(0xff1a, "addr: jump down n0 addresses"), // jump down
GPC (0xff1b, "write instruction pointer"), // get instruction pointer GPC (0xff1b, "write instruction pointer"), // get instruction pointer
// comparisson jumps
JE (0xff20, "Alias of JUE"), // jump if = JE (0xff20, "Alias of JUE"), // jump if =
JUE (0xff20, "n0 n1 n2: jump if n0 == n1, see JMPU"), JUE (0xff20, "n0 n1 addr: jump if n0 == n1, see JMPU"),
JAE (0xff21, "n0 n1 n2: jump if n0 == n1, see JMPA"), JAE (0xff21, "n0 n1 addr: jump if n0 == n1, see JMPA"),
JDE (0xff22, "n0 n1 n2: jump if n0 == n1, see JMPD"), JDE (0xff22, "n0 n1 addr: jump if n0 == n1, see JMPD"),
JG (0xff23, "Alias of JUG"), // jump if > JG (0xff23, "Alias of JUG"), // jump if >
JUG (0xff23, "n0 n1 n2: jump if n0 > n1, see JMPU"), JUG (0xff23, "n0 n1 addr: jump if n0 > n1, see JMPU"),
JAG (0xff24, "n0 n1 n2: jump if n0 > n1, see JMPA"), JAG (0xff24, "n0 n1 addr: jump if n0 > n1, see JMPA"),
JDG (0xff25, "n0 n1 n2: jump if n0 > n1, see JMPD"), JDG (0xff25, "n0 n1 addr: jump if n0 > n1, see JMPD"),
JL (0xff26, "Alias of JUL"), // jump if < JL (0xff26, "Alias of JUL"), // jump if <
JUL (0xff26, "n0 n1 n2: jump if n0 < n1, see JMPU"), JUL (0xff26, "n0 n1 addr: jump if n0 < n1, see JMPU"),
JAL (0xff27, "n0 n1 n2: jump if n0 < n1, see JMPA"), JAL (0xff27, "n0 n1 addr: jump if n0 < n1, see JMPA"),
JDL (0xff28, "n0 n1 n2: jump if n0 < n1, see JMPD"), JDL (0xff28, "n0 n1 addr: jump if n0 < n1, see JMPD"),
JGE (0xff29, "Alias of JUGE"), // jump if >= JGE (0xff29, "Alias of JUGE"), // jump if >=
JUGE(0xff29, "n0 n1 n2: jump if n0 >= n1, see JMPU"), JUGE(0xff29, "n0 n1 addr: jump if n0 >= n1, see JMPU"),
JAGE(0xff2a, "n0 n1 n2: jump if n0 >= n1, see JMPA"), JAGE(0xff2a, "n0 n1 addr: jump if n0 >= n1, see JMPA"),
JDGE(0xff2b, "n0 n1 n2: jump if n0 >= n1, see JMPD"), JDGE(0xff2b, "n0 n1 addr: jump if n0 >= n1, see JMPD"),
JLE (0xff2c, "Alias of JULE"), // jump if <= JLE (0xff2c, "Alias of JULE"), // jump if <=
JULE(0xff2c, "n0 n1 n2: jump if n0 <= n1, see JMPU"), JULE(0xff2c, "n0 n1 addr: jump if n0 <= n1, see JMPU"),
JALE(0xff2d, "n0 n1 n2: jump if n0 <= n1, see JMPA"), JALE(0xff2d, "n0 n1 addr: jump if n0 <= n1, see JMPA"),
JDLE(0xff2e, "n0 n1 n2: jump if n0 <= n1, see JMPD"), JDLE(0xff2e, "n0 n1 addr: jump if n0 <= n1, see JMPD"),
// value compare
VCMP(0xff2f, "n0 n1: performs multiple comparissons of n0 and n1"), VCMP(0xff2f, "n0 n1: performs multiple comparissons of n0 and n1"),
// power
ZPWR(0xffff, "Power off"), // power off ZPWR(0xffff, "Power off"), // power off
; ;
......
...@@ -16,16 +16,13 @@ public abstract class BaseDevice extends BaseMemory implements IDevice { ...@@ -16,16 +16,13 @@ public abstract class BaseDevice extends BaseMemory implements IDevice {
board = system; board = system;
} }
@Override public void memIrq(short addr) {
if ( 0 <= addr && addr <= memory.length ) { exec(); }
}
protected void sendIrq() { protected void sendIrq() {
int addr = memory.length - 1; int addr = memory.length - 1;
sendIrq(memory[addr]); sendIrq(memory[addr]);
} }
@Override public void sendIrq(byte irq) { } @Override public void sendIrq(byte irq) { }
@Override public void recvIrq(byte irq) { }
@Override public short length() { return (short)memory.length; } @Override public short length() { return (short)memory.length; }
......
...@@ -26,13 +26,7 @@ public abstract class BaseMemory implements IMemory { ...@@ -26,13 +26,7 @@ public abstract class BaseMemory implements IMemory {
memory[0xffff & addr] = data; memory[0xffff & addr] = data;
} }
public final void copy(int addrSrc, int addrDest, IMemory dest) { copy((short)addrSrc, (short)addrDest, dest); } @Override public void memIrq(short addr, byte irq) { }
@Override public void copy(short addrSrc, short addrDest, IMemory dest) {
if ( (0xffff & addrSrc) > length() ) { return; }
dest.write(addrDest, read(addrSrc));
}
@Override public void memIrq(short addr) { }
@Override public void powerOff() { } @Override public void powerOff() { }
} }
package me.felinewith.kcpu.util;
/**
*
* @author jlhawkwell
*/
public class CPUStoppedException extends Exception {
/**
* Creates a new instance of <code>CPUStoppedException</code> without detail message.
*/
public CPUStoppedException() {
}
/**
* Constructs an instance of <code>CPUStoppedException</code> with the specified detail message.
*
* @param msg the detail message.
*/
public CPUStoppedException(String msg) {
super(msg);
}
}
package me.felinewith.kcpu.util;
import java.util.TimerTask;
import me.felinewith.kcpu.interfaces.IDevice;
/**
*
* @author jlhawkwell
*/
public class HardwareExec extends TimerTask {
IDevice id;
public HardwareExec(IDevice device) {
id = device;
}
@Override public void run() { id.exec(); }
}
...@@ -11,10 +11,15 @@ public class HardwareMemIrq extends TimerTask { ...@@ -11,10 +11,15 @@ public class HardwareMemIrq extends TimerTask {
IMemory id; IMemory id;
short a; short a;
byte i;
public HardwareMemIrq(IMemory device, short addr) { public HardwareMemIrq(IMemory device, short addr, byte irq) {
id = device; id = device;
a = addr; a = addr;
i = irq;
}
@Override public void run() {
Thread.currentThread().setName(String.format("memIRQ-%02x-%x", id, Thread.currentThread().getId() ));
id.memIrq(a, i);
} }
@Override public void run() { id.memIrq(a); }
} }
...@@ -7,14 +7,17 @@ import me.felinewith.kcpu.interfaces.IDevice; ...@@ -7,14 +7,17 @@ import me.felinewith.kcpu.interfaces.IDevice;
* *
* @author jlhawkwell * @author jlhawkwell
*/ */
public class HardwareSendIrq extends TimerTask { public class HardwareRecvIrq extends TimerTask {
IDevice id; IDevice id;
byte i; byte i;
public HardwareSendIrq(IDevice device, byte irq) { public HardwareRecvIrq(IDevice device, byte irq) {
id = device; id = device;
i = irq; i = irq;
} }
@Override public void run() { id.sendIrq(i); } @Override public void run() {
Thread.currentThread().setName(String.format("recvIRQ-%02x_%02x-%x", id, i, Thread.currentThread().getId() ));
id.recvIrq(i);
}
} }
...@@ -25,6 +25,7 @@ public class ValueHelper { ...@@ -25,6 +25,7 @@ public class ValueHelper {
case 2: cref = (short)(0x0030 & ref); break; case 2: cref = (short)(0x0030 & ref); break;
case 3: cref = (short)(0x00c0 & ref); break; case 3: cref = (short)(0x00c0 & ref); break;
} }
switch (cref) { switch (cref) {
case 0x0000: output = values[pos]; break; case 0x0000: output = values[pos]; break;
case 0x0001: case 0x0004: case 0x0010: case 0x0040: case 0x0001: case 0x0004: case 0x0010: case 0x0040:
...@@ -55,10 +56,14 @@ public class ValueHelper { ...@@ -55,10 +56,14 @@ public class ValueHelper {
case 2: cref = (short)(0x0030 & ref); break; case 2: cref = (short)(0x0030 & ref); break;
case 3: cref = (short)(0x00c0 & ref); break; case 3: cref = (short)(0x00c0 & ref); break;
} }
// short-circuit write to register if position isn't used in the instruction
if (pos > ((0x0f00 & reg) >> 8)) { cref = 1; }
switch (cref) { switch (cref) {
case 0x0000:
case 0x0001: case 0x0004: case 0x0010: case 0x0040: case 0x0001: case 0x0004: case 0x0010: case 0x0040:
output[reg] = data; break; output[reg] = data; break;
case 0x0000:
case 0x0002: case 0x0008: case 0x0020: case 0x0080: case 0x0002: case 0x0008: case 0x0020: case 0x0080:
MemHelper.writeByte(values[pos], data, memory); break; MemHelper.writeByte(values[pos], data, memory); break;
case 0x0003: case 0x000c: case 0x0030: case 0x00c0: case 0x0003: case 0x000c: case 0x0030: case 0x00c0:
...@@ -109,10 +114,16 @@ public class ValueHelper { ...@@ -109,10 +114,16 @@ public class ValueHelper {
case 2: cref = (short)(0x0030 & ref); break; case 2: cref = (short)(0x0030 & ref); break;
case 3: cref = (short)(0x00c0 & ref); break; case 3: cref = (short)(0x00c0 & ref); break;
} }
// short-circuit write to register if position isn't used in the instruction
if (pos > ((0x0f00 & ref) >> 8)) {
cref = 1;
}
switch (cref) { switch (cref) {
case 0x0000:
case 0x0001: case 0x0004: case 0x0010: case 0x0040: case 0x0001: case 0x0004: case 0x0010: case 0x0040:
output[reg] = data; break; output[reg] = data; break;
case 0x0000:
case 0x0002: case 0x0008: case 0x0020: case 0x0080: case 0x0002: case 0x0008: case 0x0020: case 0x0080:
MemHelper.writeShort(values[pos], data, memory); break; MemHelper.writeShort(values[pos], data, memory); break;
case 0x0003: case 0x000c: case 0x0030: case 0x00c0: case 0x0003: case 0x000c: case 0x0030: case 0x00c0:
......
...@@ -10,8 +10,8 @@ public enum ValueType { ...@@ -10,8 +10,8 @@ public enum ValueType {
AD(2), AD(2),
AR(3); AR(3);
int t; short t;
private ValueType(int type) { t = type; } private ValueType(int type) { t = (short)type; }
public static ValueType valueOf(int value, int position) { public static ValueType valueOf(int value, int position) {
int temp = value >> (position * 2); int temp = value >> (position * 2);
...@@ -24,5 +24,5 @@ public enum ValueType { ...@@ -24,5 +24,5 @@ public enum ValueType {
} }
return D; return D;
} }
public int getValue() { return t; } public short getValue() { return t; }
} }
...@@ -2,9 +2,9 @@ movs $0 r2 ...@@ -2,9 +2,9 @@ movs $0 r2
add r0 16 add r0 16
add r2 1 add r2 1
movs $0 r2 movs $0 r2
jdl r0 512 2a,16 jdl r0 512 20,16+a,16
deva 0 deva 0
deva 1 deva 1
gpc gpc
gpc %300,16 gpc %100,16+300,16
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!