inital commit кек
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.cbe.core;
|
||||
|
||||
public interface Bus {
|
||||
byte read(int address);
|
||||
void write(int address, byte data);
|
||||
int readWord(int address);
|
||||
void writeWord(int address, int value);
|
||||
long clock();
|
||||
long tick();
|
||||
void attach(String deviceName, int baseAddress, int size);
|
||||
ModuleInstance getDevice(String name);
|
||||
void reset();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.cbe.core;
|
||||
|
||||
public final class CbePluginConstants {
|
||||
public static final String MAGIC = "CBE_PLUG";
|
||||
public static final int HEADER_SIZE = 62;
|
||||
|
||||
public static final int OFF_MAGIC = 0;
|
||||
public static final int OFF_VERSION = 8;
|
||||
public static final int OFF_HEADER_SIZE = 12;
|
||||
public static final int OFF_MODULE_TYPE = 16;
|
||||
public static final int OFF_COMPILE_MODE = 17;
|
||||
public static final int OFF_METADATA_OFF = 18;
|
||||
public static final int OFF_METADATA_LEN = 22;
|
||||
public static final int OFF_OPCODE_OFF = 26;
|
||||
public static final int OFF_OPCODE_LEN = 30;
|
||||
public static final int OFF_MICROCODE_OFF = 34;
|
||||
public static final int OFF_MICROCODE_LEN = 38;
|
||||
public static final int OFF_HANDLER_OFF = 42;
|
||||
public static final int OFF_HANDLER_LEN = 46;
|
||||
public static final int OFF_DATA_OFF = 50;
|
||||
public static final int OFF_DATA_LEN = 54;
|
||||
public static final int OFF_CHECKSUM = 58;
|
||||
|
||||
private CbePluginConstants() {}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.cbe.core;
|
||||
|
||||
public enum CompileMode {
|
||||
FULL((byte) 0),
|
||||
HYBRID((byte) 1),
|
||||
PACK_ONLY((byte) 2);
|
||||
|
||||
private final byte id;
|
||||
|
||||
CompileMode(byte id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public byte getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static CompileMode fromId(byte id) {
|
||||
for (CompileMode m : values()) {
|
||||
if (m.id == id) return m;
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown CompileMode id: " + id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.cbe.core;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Instruction {
|
||||
private final int opcode;
|
||||
private final String mnemonic;
|
||||
private final List<Arg> args;
|
||||
private final int cycles;
|
||||
private final List<SemanticOp> semantics;
|
||||
|
||||
public Instruction(int opcode, String mnemonic, List<Arg> args, int cycles, List<SemanticOp> semantics) {
|
||||
this.opcode = opcode;
|
||||
this.mnemonic = mnemonic;
|
||||
this.args = args != null ? Collections.unmodifiableList(args) : Collections.<Arg>emptyList();
|
||||
this.cycles = cycles;
|
||||
this.semantics = semantics != null ? Collections.unmodifiableList(semantics) : Collections.<SemanticOp>emptyList();
|
||||
}
|
||||
|
||||
public int getOpcode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
public String getMnemonic() {
|
||||
return mnemonic;
|
||||
}
|
||||
|
||||
public List<Arg> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public int getCycles() {
|
||||
return cycles;
|
||||
}
|
||||
|
||||
public List<SemanticOp> getSemantics() {
|
||||
return semantics;
|
||||
}
|
||||
|
||||
public static class Arg {
|
||||
private final String name;
|
||||
private final String type;
|
||||
|
||||
public Arg(String name, String type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SemanticOp {
|
||||
private final String operation;
|
||||
private final String from;
|
||||
private final String to;
|
||||
private final String value;
|
||||
private final String condition;
|
||||
private final String result;
|
||||
|
||||
public SemanticOp(String operation, String from, String to, String value, String condition) {
|
||||
this(operation, from, to, value, condition, null);
|
||||
}
|
||||
|
||||
public SemanticOp(String operation, String from, String to, String value, String condition, String result) {
|
||||
this.operation = operation;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.value = value;
|
||||
this.condition = condition;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public String getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public String getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
package com.cbe.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class InstructionExecutor {
|
||||
|
||||
private static final int MASK_8BIT = 0xFF;
|
||||
|
||||
// Pre-computed operation IDs for faster dispatch
|
||||
private static final int OP_NOP = 0;
|
||||
private static final int OP_COPY = 1;
|
||||
private static final int OP_LOAD_IMM = 2;
|
||||
private static final int OP_ADD = 3;
|
||||
private static final int OP_SUB = 4;
|
||||
private static final int OP_CMP = 5;
|
||||
private static final int OP_STORE = 6;
|
||||
private static final int OP_LOAD = 7;
|
||||
private static final int OP_JMP = 8;
|
||||
private static final int OP_JCC = 9;
|
||||
private static final int OP_JMP_IMM = 10;
|
||||
private static final int OP_JCC_IMM = 11;
|
||||
private static final int OP_CALL = 12;
|
||||
private static final int OP_RET = 13;
|
||||
private static final int OP_PUSH = 14;
|
||||
private static final int OP_POP = 15;
|
||||
private static final int OP_INC = 16;
|
||||
|
||||
private static final java.util.HashMap<String, Integer> OP_IDS = new java.util.HashMap<String, Integer>();
|
||||
static {
|
||||
OP_IDS.put("nop", OP_NOP);
|
||||
OP_IDS.put("copy", OP_COPY);
|
||||
OP_IDS.put("load_imm", OP_LOAD_IMM);
|
||||
OP_IDS.put("add", OP_ADD);
|
||||
OP_IDS.put("sub", OP_SUB);
|
||||
OP_IDS.put("cmp", OP_CMP);
|
||||
OP_IDS.put("store", OP_STORE);
|
||||
OP_IDS.put("load", OP_LOAD);
|
||||
OP_IDS.put("jmp", OP_JMP);
|
||||
OP_IDS.put("jcc", OP_JCC);
|
||||
OP_IDS.put("jmp_imm", OP_JMP_IMM);
|
||||
OP_IDS.put("jcc_imm", OP_JCC_IMM);
|
||||
OP_IDS.put("call", OP_CALL);
|
||||
OP_IDS.put("ret", OP_RET);
|
||||
OP_IDS.put("push", OP_PUSH);
|
||||
OP_IDS.put("pop", OP_POP);
|
||||
OP_IDS.put("inc", OP_INC);
|
||||
}
|
||||
|
||||
// Cached spec type: 0=reg, 1=mem[const], 2=arg.X, 3=imm.X, 4=mem[arg.X], 5=$next
|
||||
private static int classifySpec(String spec) {
|
||||
if (spec == null || spec.isEmpty()) return 0;
|
||||
char c = spec.charAt(0);
|
||||
if (c == 'a' && spec.startsWith("arg.")) return 2;
|
||||
if (c == 'i' && spec.startsWith("imm.")) return 3;
|
||||
if (c == 'm' && spec.startsWith("mem[")) {
|
||||
if (spec.endsWith("]")) {
|
||||
if (spec.length() > 5 && spec.charAt(4) == 'a' && spec.startsWith("mem[arg.")) return 4;
|
||||
// Check if it's $next
|
||||
if (spec.equals("mem[$next]")) return 5;
|
||||
return 1; // mem[const]
|
||||
}
|
||||
}
|
||||
if (c == '$' && spec.equals("$next")) return 5;
|
||||
return 0; // reg or numeric literal
|
||||
}
|
||||
|
||||
// Pre-computed spec info for quick operand resolution
|
||||
private static class SpecInfo {
|
||||
final int type; // 0=reg, 1=mem[const], 2=arg.X, 3=imm.X, 4=mem[arg.X], 5=$next
|
||||
final String value; // register name, argument name, or numeric string
|
||||
|
||||
SpecInfo(String spec) {
|
||||
this.type = classifySpec(spec);
|
||||
switch (type) {
|
||||
case 1: this.value = spec.substring(4, spec.length() - 1); break;
|
||||
case 2: this.value = spec.substring(4); break;
|
||||
case 3: this.value = spec.substring(4); break;
|
||||
case 4: this.value = spec.substring(8, spec.length() - 1); break;
|
||||
default: this.value = spec; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<Integer, Instruction> instructionMap;
|
||||
|
||||
// Per-instruction cached spec info
|
||||
private final java.util.HashMap<Instruction, CachedSpecs> specCache;
|
||||
|
||||
private static class CachedSpecs {
|
||||
final int[] opIds;
|
||||
final SpecInfo[] fromSpecs;
|
||||
final SpecInfo[] toSpecs;
|
||||
final SpecInfo[] resultSpecs;
|
||||
final String[] valueSpecs;
|
||||
final String[] conditions;
|
||||
|
||||
CachedSpecs(Instruction inst) {
|
||||
java.util.List<Instruction.SemanticOp> ops = inst.getSemantics();
|
||||
int n = ops.size();
|
||||
opIds = new int[n];
|
||||
fromSpecs = new SpecInfo[n];
|
||||
toSpecs = new SpecInfo[n];
|
||||
resultSpecs = new SpecInfo[n];
|
||||
valueSpecs = new String[n];
|
||||
conditions = new String[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
Instruction.SemanticOp op = ops.get(i);
|
||||
Integer id = OP_IDS.get(op.getOperation());
|
||||
opIds[i] = id != null ? id : -1;
|
||||
fromSpecs[i] = new SpecInfo(op.getFrom());
|
||||
toSpecs[i] = new SpecInfo(op.getTo());
|
||||
resultSpecs[i] = new SpecInfo(op.getResult());
|
||||
valueSpecs[i] = op.getValue();
|
||||
conditions[i] = op.getCondition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InstructionExecutor(Map<Integer, Instruction> instructionMap) {
|
||||
this.instructionMap = instructionMap;
|
||||
this.specCache = new java.util.HashMap<Instruction, CachedSpecs>();
|
||||
}
|
||||
|
||||
public OpcodeResult execute(int opcode, Registers regs, Bus bus, byte[] memory) {
|
||||
Instruction inst = instructionMap.get(opcode);
|
||||
if (inst == null) {
|
||||
throw new IllegalArgumentException("Unknown opcode: 0x" + Integer.toHexString(opcode & 0xFF));
|
||||
}
|
||||
|
||||
// Always 8-bit for TinyCPU
|
||||
int mask = MASK_8BIT;
|
||||
|
||||
CachedSpecs cached = specCache.get(inst);
|
||||
if (cached == null) {
|
||||
cached = new CachedSpecs(inst);
|
||||
specCache.put(inst, cached);
|
||||
}
|
||||
|
||||
for (int i = 0; i < cached.opIds.length; i++) {
|
||||
executeCached(cached, i, regs, bus, memory, mask);
|
||||
}
|
||||
|
||||
return OpcodeResult.ok(inst.getCycles());
|
||||
}
|
||||
|
||||
private void executeCached(CachedSpecs cached, int idx, Registers regs, Bus bus, byte[] memory, int mask) {
|
||||
switch (cached.opIds[idx]) {
|
||||
case OP_NOP:
|
||||
break;
|
||||
case OP_COPY: {
|
||||
int srcVal = resolveValueCached(cached.fromSpecs[idx], regs, memory);
|
||||
writeCached(cached.toSpecs[idx], srcVal & mask, regs, memory);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_IMM: {
|
||||
SpecInfo to = cached.toSpecs[idx];
|
||||
if (to.type != 0 || to.value == null) break;
|
||||
int immValue;
|
||||
String valSpec = cached.valueSpecs[idx];
|
||||
if (valSpec != null && valSpec.equals("$next")) {
|
||||
int nextAddr = regs.read("pc");
|
||||
immValue = nextAddr < memory.length ? (memory[nextAddr] & 0xFF) : 0;
|
||||
regs.write("pc", nextAddr + 1);
|
||||
} else if (valSpec != null) {
|
||||
immValue = Integer.parseInt(valSpec.trim());
|
||||
} else {
|
||||
immValue = 0;
|
||||
}
|
||||
regs.write(to.value, immValue & mask);
|
||||
break;
|
||||
}
|
||||
case OP_ADD: {
|
||||
int srcVal = resolveValueCached(cached.fromSpecs[idx], regs, memory);
|
||||
int dstVal = resolveValueCached(cached.toSpecs[idx], regs, memory);
|
||||
int result = srcVal + dstVal;
|
||||
int masked = result & mask;
|
||||
String dest = cached.resultSpecs[idx].value != null ? cached.resultSpecs[idx].value : cached.toSpecs[idx].value;
|
||||
if (dest != null) regs.write(dest, masked);
|
||||
regs.write("carry", (result != masked) ? 1 : 0);
|
||||
regs.write("zero", (masked == 0) ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
case OP_SUB: {
|
||||
int a = resolveValueCached(cached.fromSpecs[idx], regs, memory);
|
||||
int b = resolveValueCached(cached.toSpecs[idx], regs, memory);
|
||||
int result = a - b;
|
||||
int masked = result & mask;
|
||||
String dest = cached.resultSpecs[idx].value != null ? cached.resultSpecs[idx].value : cached.toSpecs[idx].value;
|
||||
if (dest != null) regs.write(dest, masked);
|
||||
regs.write("carry", (result < 0) ? 1 : 0);
|
||||
regs.write("zero", (masked == 0) ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
case OP_CMP: {
|
||||
int a = resolveValueCached(cached.fromSpecs[idx], regs, memory);
|
||||
int b = resolveValueCached(cached.toSpecs[idx], regs, memory);
|
||||
int result = a - b;
|
||||
regs.write("zero", ((result & mask) == 0) ? 1 : 0);
|
||||
regs.write("carry", (result < 0) ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
case OP_STORE: {
|
||||
int val = resolveValueCached(cached.fromSpecs[idx], regs, memory);
|
||||
int addr = resolveAddressCached(cached.toSpecs[idx], regs, memory);
|
||||
if (addr >= 0 && addr < memory.length) {
|
||||
memory[addr] = (byte) (val & 0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_LOAD: {
|
||||
int addr = resolveAddressCached(cached.fromSpecs[idx], regs, memory);
|
||||
int val = (addr >= 0 && addr < memory.length) ? (memory[addr] & 0xFF) : 0;
|
||||
writeCached(cached.toSpecs[idx], val, regs, memory);
|
||||
break;
|
||||
}
|
||||
case OP_JMP: {
|
||||
int addr = resolveValueCached(cached.toSpecs[idx], regs, memory);
|
||||
regs.write("pc", addr & mask);
|
||||
break;
|
||||
}
|
||||
case OP_JCC: {
|
||||
String cond = cached.conditions[idx];
|
||||
if (cond != null) {
|
||||
int comma = cond.indexOf(',');
|
||||
if (comma > 0) {
|
||||
String flagName = cond.substring(0, comma).trim();
|
||||
int expected = Integer.parseInt(cond.substring(comma + 1).trim());
|
||||
if (regs.read(flagName) == expected) {
|
||||
int addr = resolveValueCached(cached.toSpecs[idx], regs, memory);
|
||||
regs.write("pc", addr & mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_JMP_IMM: {
|
||||
int nextAddr = regs.read("pc");
|
||||
if (nextAddr < memory.length) {
|
||||
regs.write("pc", memory[nextAddr] & 0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_JCC_IMM: {
|
||||
String cond = cached.conditions[idx];
|
||||
int nextAddr = regs.read("pc");
|
||||
if (cond != null && nextAddr < memory.length) {
|
||||
int comma = cond.indexOf(',');
|
||||
if (comma > 0) {
|
||||
String flagName = cond.substring(0, comma).trim();
|
||||
int expected = Integer.parseInt(cond.substring(comma + 1).trim());
|
||||
int immTarget = memory[nextAddr] & 0xFF;
|
||||
if (regs.read(flagName) == expected) {
|
||||
regs.write("pc", immTarget);
|
||||
} else {
|
||||
regs.write("pc", nextAddr + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_CALL: {
|
||||
int retAddr = regs.read("pc");
|
||||
int sp = regs.read("sp");
|
||||
if (sp > 0 && sp < memory.length) {
|
||||
memory[sp - 1] = (byte) (retAddr & 0xFF);
|
||||
regs.write("sp", sp - 1);
|
||||
regs.write("pc", resolveValueCached(cached.toSpecs[idx], regs, memory) & mask);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_RET: {
|
||||
int sp = regs.read("sp");
|
||||
if (sp >= 0 && sp < memory.length) {
|
||||
regs.write("sp", sp + 1);
|
||||
regs.write("pc", memory[sp] & 0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_PUSH: {
|
||||
int sp = regs.read("sp");
|
||||
int val = resolveValueCached(cached.fromSpecs[idx], regs, memory);
|
||||
if (sp > 0 && sp < memory.length) {
|
||||
memory[sp - 1] = (byte) (val & 0xFF);
|
||||
regs.write("sp", sp - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_POP: {
|
||||
int sp = regs.read("sp");
|
||||
if (sp >= 0 && sp < memory.length) {
|
||||
int val = memory[sp] & 0xFF;
|
||||
regs.write("sp", sp + 1);
|
||||
writeCached(cached.toSpecs[idx], val, regs, memory);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_INC: {
|
||||
int val = resolveValueCached(cached.fromSpecs[idx], regs, memory);
|
||||
writeCached(cached.toSpecs[idx], (val + 1) & mask, regs, memory);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown semantic operation: " + cached.opIds[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
private static int resolveAddressCached(SpecInfo spec, Registers regs, byte[] memory) {
|
||||
switch (spec.type) {
|
||||
case 5: { // $next
|
||||
int pc = regs.read("pc");
|
||||
if (pc < memory.length) {
|
||||
regs.write("pc", pc + 1);
|
||||
return memory[pc] & 0xFF;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case 1: // mem[const]
|
||||
return Integer.parseInt(spec.value);
|
||||
case 2: // arg.X
|
||||
return regs.read(spec.value);
|
||||
case 4: // mem[arg.X]
|
||||
return regs.read(spec.value);
|
||||
case 0: // register value as address
|
||||
return regs.read(spec.value);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int resolveValueCached(SpecInfo spec, Registers regs, byte[] memory) {
|
||||
switch (spec.type) {
|
||||
case 0: { // register or numeric literal
|
||||
String v = spec.value;
|
||||
if (v == null || v.isEmpty()) return 0;
|
||||
char c = v.charAt(0);
|
||||
if (c >= '0' && c <= '9') {
|
||||
try { return Integer.parseInt(v); } catch (NumberFormatException e) { return regs.read(v); }
|
||||
}
|
||||
if (c == '-') {
|
||||
try { return Integer.parseInt(v); } catch (NumberFormatException e) { return regs.read(v); }
|
||||
}
|
||||
return regs.read(v);
|
||||
}
|
||||
case 1: // mem[const]
|
||||
return memory[Integer.parseInt(spec.value)] & 0xFF;
|
||||
case 2: // arg.X
|
||||
return regs.read(spec.value);
|
||||
case 3: // imm.X
|
||||
return Integer.parseInt(spec.value);
|
||||
case 4: { // mem[arg.X]
|
||||
int addr = regs.read(spec.value);
|
||||
return addr < memory.length ? (memory[addr] & 0xFF) : 0;
|
||||
}
|
||||
case 5: { // $next
|
||||
int pc = regs.read("pc");
|
||||
if (pc < memory.length) {
|
||||
regs.write("pc", pc + 1);
|
||||
return memory[pc] & 0xFF;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeCached(SpecInfo spec, int value, Registers regs, byte[] memory) {
|
||||
if (spec == null || spec.value == null) return;
|
||||
switch (spec.type) {
|
||||
case 0:
|
||||
regs.write(spec.value, value);
|
||||
break;
|
||||
case 1: // mem[const]
|
||||
memory[Integer.parseInt(spec.value)] = (byte) value;
|
||||
break;
|
||||
case 2: // arg.X
|
||||
regs.write(spec.value, value);
|
||||
break;
|
||||
case 4: { // mem[arg.X]
|
||||
int addr = regs.read(spec.value);
|
||||
if (addr >= 0 && addr < memory.length) memory[addr] = (byte) value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.cbe.core;
|
||||
|
||||
public interface ModuleInstance {
|
||||
ModuleMetadata getMetadata();
|
||||
String getName();
|
||||
void init(Bus bus);
|
||||
void reset();
|
||||
void destroy();
|
||||
OpcodeResult executeOpcode(int opcode, Registers regs, Bus bus);
|
||||
byte[] readData(int bank, int offset, int size);
|
||||
void writeData(int bank, int offset, byte[] data);
|
||||
byte[] getMicrocode(String command);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.cbe.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ModuleMetadata implements Serializable {
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private final String name;
|
||||
private final String arch;
|
||||
private final ModuleType type;
|
||||
private final int version;
|
||||
private final float tdp;
|
||||
private final int maxFrequency; // Hz, 0 = unknown
|
||||
|
||||
public ModuleMetadata(String name, String arch, ModuleType type, int version, float tdp) {
|
||||
this(name, arch, type, version, tdp, 0);
|
||||
}
|
||||
|
||||
public ModuleMetadata(String name, String arch, ModuleType type, int version, float tdp, int maxFrequency) {
|
||||
this.name = name;
|
||||
this.arch = arch;
|
||||
this.type = type;
|
||||
this.version = version;
|
||||
this.tdp = tdp;
|
||||
this.maxFrequency = maxFrequency;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public ModuleType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public float getTdp() {
|
||||
return tdp;
|
||||
}
|
||||
|
||||
public int getMaxFrequency() {
|
||||
return maxFrequency;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.cbe.core;
|
||||
|
||||
public enum ModuleType {
|
||||
CPU((byte) 0),
|
||||
RAM((byte) 1),
|
||||
DISK((byte) 2),
|
||||
GPU((byte) 3),
|
||||
BIOS((byte) 4),
|
||||
KBD((byte) 5),
|
||||
SND((byte) 6),
|
||||
DATA_ONLY((byte) 7);
|
||||
|
||||
private final byte id;
|
||||
|
||||
ModuleType(byte id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public byte getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static ModuleType fromId(byte id) {
|
||||
for (ModuleType t : values()) {
|
||||
if (t.id == id) return t;
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown ModuleType id: " + id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.cbe.core;
|
||||
|
||||
public class OpcodeResult {
|
||||
private final boolean halt;
|
||||
private final int cyclesConsumed;
|
||||
|
||||
public OpcodeResult(boolean halt, int cyclesConsumed) {
|
||||
this.halt = halt;
|
||||
this.cyclesConsumed = cyclesConsumed;
|
||||
}
|
||||
|
||||
public static OpcodeResult ok(int cycles) {
|
||||
return new OpcodeResult(false, cycles);
|
||||
}
|
||||
|
||||
public static OpcodeResult halt(int cycles) {
|
||||
return new OpcodeResult(true, cycles);
|
||||
}
|
||||
|
||||
public boolean isHalt() {
|
||||
return halt;
|
||||
}
|
||||
|
||||
public int getCyclesConsumed() {
|
||||
return cyclesConsumed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.cbe.core;
|
||||
|
||||
/**
|
||||
* POST (Power-On Self-Test) codes.
|
||||
* Each code is a single byte that the system reports as it initializes.
|
||||
*
|
||||
* Layout convention:
|
||||
* 0x0_ = power-on phase
|
||||
* 0x1_ = CPU
|
||||
* 0x2_ = memory
|
||||
* 0x3_ = video
|
||||
* 0x4_ = keyboard
|
||||
* 0x5_ = sound
|
||||
* 0x6_ = disk
|
||||
* 0x7_ = BIOS
|
||||
* 0x8_ = OS / boot
|
||||
* 0xA_ = runtime
|
||||
* 0xE_ = warning
|
||||
* 0xF_ = fatal
|
||||
*
|
||||
* The engine writes the current POST code to the special memory address
|
||||
* {@link #POST_CODE_ADDR}. The GUI reads from there for visualization.
|
||||
*
|
||||
* The COMPONENT_OK bitmask lives in the LED register at {@link #LED_STATUS_ADDR}.
|
||||
*/
|
||||
public enum PostCode {
|
||||
POWER_ON(0x01),
|
||||
CPU_DETECTED(0x10), CPU_OK(0x11), CPU_FAIL(0x12),
|
||||
MEM_DETECTED(0x20), MEM_OK(0x21), MEM_FAIL(0x22),
|
||||
VIDEO_DETECTED(0x30), VIDEO_OK(0x31), VIDEO_FAIL(0x32),
|
||||
KBD_DETECTED(0x40), KBD_OK(0x41), KBD_FAIL(0x42),
|
||||
SND_DETECTED(0x50), SND_OK(0x51), SND_FAIL(0x52),
|
||||
DISK_DETECTED(0x60), DISK_OK(0x61), DISK_FAIL(0x62),
|
||||
BIOS_LOADING(0x70), BIOS_OK(0x71), BIOS_FAIL(0x72),
|
||||
BIOS_CPU(0x73), BIOS_RAM(0x74), BIOS_GPU(0x75),
|
||||
BIOS_KBD(0x76), BIOS_SND(0x77), BIOS_DONE(0x78),
|
||||
BOOT_LOAD(0x80), BOOT_OK(0x81),
|
||||
RUNTIME(0xA0),
|
||||
WARNING(0xE0),
|
||||
FATAL(0xF0);
|
||||
|
||||
public static final int POST_CODE_ADDR = 0xFE; // current POST code
|
||||
public static final int ERROR_CODE_ADDR = 0xFD; // last error code
|
||||
public static final int LED_STATUS_ADDR = 0xFC; // bitmask of components OK
|
||||
public static final int KBD_DATA_ADDR = 0xFB; // KBD: next key (or 0 if none)
|
||||
public static final int KBD_STATUS_ADDR = 0xFA; // KBD: bit0=key available
|
||||
public static final int SND_BEEP_ADDR = 0xF9; // SND: any write triggers beep
|
||||
public static final int BIOS_TRIGGER = 0xF7; // write any value to invoke BIOS diagnostics
|
||||
public static final int BIOS_INFO_BASE = 0xE0; // 16 bytes of BIOS info (0xE0..0xEF)
|
||||
public static final int DEVICE_TABLE_BASE = 0xD0; // 16 bytes device table (0xD0..0xDF)
|
||||
public static final int GPU_OUT_CHAR = 0xC0; // write byte to output char on GPU display
|
||||
public static final int DISK_SECTOR_ADDR = 0xB0; // write sector LBA here to queue a disk read
|
||||
public static final int DISK_READY_ADDR = 0xB1; // read: 1=disk I/O ready, 0=busy
|
||||
public static final int DISK_DATA_BASE = 0xB2; // 256 bytes of disk sector data (0xB2..0xFF)
|
||||
|
||||
// LED bits for the visualizer
|
||||
public static final int LED_PWR = 0x01;
|
||||
public static final int LED_CPU = 0x02;
|
||||
public static final int LED_MEM = 0x04;
|
||||
public static final int LED_VID = 0x08;
|
||||
public static final int LED_KBD = 0x10;
|
||||
public static final int LED_SND = 0x20;
|
||||
public static final int LED_DSK = 0x40;
|
||||
public static final int LED_CLK = 0x80;
|
||||
|
||||
public final int code;
|
||||
|
||||
PostCode(int code) { this.code = code; }
|
||||
|
||||
public static int componentLed(int code) {
|
||||
int hi = (code >> 4) & 0x0F;
|
||||
if (hi == 0x7) {
|
||||
// BIOS codes (0x70-0x7F): map to the component being tested
|
||||
int lo = code & 0x0F;
|
||||
switch (lo) {
|
||||
case 0x3: return LED_CPU; // BIOS_CPU
|
||||
case 0x4: return LED_MEM; // BIOS_RAM
|
||||
case 0x5: return LED_VID; // BIOS_GPU
|
||||
case 0x6: return LED_KBD; // BIOS_KBD
|
||||
case 0x7: return LED_SND; // BIOS_SND
|
||||
case 0x8: return LED_DSK; // BIOS_DONE / boot attempt
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
switch (hi) {
|
||||
case 0x0: return LED_PWR;
|
||||
case 0x1: return LED_CPU;
|
||||
case 0x2: return LED_MEM;
|
||||
case 0x3: return LED_VID;
|
||||
case 0x4: return LED_KBD;
|
||||
case 0x5: return LED_SND;
|
||||
case 0x6: return LED_DSK;
|
||||
case 0x8: return LED_DSK; // BOOT - disk LED
|
||||
case 0xA: return LED_CLK; // runtime
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static String describe(int code) {
|
||||
switch (code) {
|
||||
case 0x00: return "Idle";
|
||||
case 0x01: return "Power on";
|
||||
case 0x10: return "CPU detected";
|
||||
case 0x11: return "CPU OK";
|
||||
case 0x12: return "CPU FAIL";
|
||||
case 0x20: return "Memory detected";
|
||||
case 0x21: return "Memory OK";
|
||||
case 0x22: return "Memory FAIL";
|
||||
case 0x30: return "Video detected";
|
||||
case 0x31: return "Video OK";
|
||||
case 0x32: return "Video FAIL";
|
||||
case 0x40: return "Keyboard detected";
|
||||
case 0x41: return "Keyboard OK";
|
||||
case 0x42: return "Keyboard FAIL";
|
||||
case 0x50: return "Sound detected";
|
||||
case 0x51: return "Sound OK";
|
||||
case 0x52: return "Sound FAIL";
|
||||
case 0x60: return "Disk detected";
|
||||
case 0x61: return "Disk OK";
|
||||
case 0x62: return "Disk FAIL";
|
||||
case 0x70: return "BIOS loading";
|
||||
case 0x71: return "BIOS OK";
|
||||
case 0x72: return "BIOS FAIL";
|
||||
case 0x80: return "Boot loader";
|
||||
case 0x81: return "Boot OK";
|
||||
case 0xA0: return "Runtime";
|
||||
case 0xE0: return "WARNING";
|
||||
case 0xF0: return "FATAL";
|
||||
default: return "Code 0x" + Integer.toHexString(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.cbe.core;
|
||||
|
||||
public interface Registers {
|
||||
int read(String name);
|
||||
void write(String name, int value);
|
||||
java.util.Set<String> names();
|
||||
void reset();
|
||||
}
|
||||
Reference in New Issue
Block a user