diff --git a/Lang/src/main/java/chipmunk/compiler/assembler/Operands.java b/Lang/src/main/java/chipmunk/compiler/assembler/Operands.java index 4ce3604..aba224c 100644 --- a/Lang/src/main/java/chipmunk/compiler/assembler/Operands.java +++ b/Lang/src/main/java/chipmunk/compiler/assembler/Operands.java @@ -25,14 +25,27 @@ public class Operands { protected Stack types = new Stack<>(); + protected final int reserved; + + public Operands(){ + this(0); + } + + public Operands(int reserved){ + this.reserved = reserved; + } public Operand push(HVMType type){ types.push(type); - return new Operand(types.size() - 1, type); + return new Operand(calculateRegister(), type); } public Operand pop(){ - return new Operand(types.size() - 1, types.pop()); + return new Operand(calculateRegister(), types.pop()); + } + + private int calculateRegister(){ + return reserved + types.size() - 1; } } diff --git a/Lang/src/main/java/chipmunk/runtime/hvm/CClass.java b/Lang/src/main/java/chipmunk/runtime/hvm/CClass.java new file mode 100644 index 0000000..1569870 --- /dev/null +++ b/Lang/src/main/java/chipmunk/runtime/hvm/CClass.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 MyWorld, LLC + * All rights reserved. + * + * This file is part of Chipmunk. + * + * Chipmunk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chipmunk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chipmunk. If not, see . + */ + +package chipmunk.runtime.hvm; + +public class CClass { + + protected CField[] fields; + protected CField[] shared; + protected CMethod[] methods; + protected long storagePtr; + +} diff --git a/Lang/src/main/java/chipmunk/runtime/hvm/CField.java b/Lang/src/main/java/chipmunk/runtime/hvm/CField.java new file mode 100644 index 0000000..173987f --- /dev/null +++ b/Lang/src/main/java/chipmunk/runtime/hvm/CField.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 MyWorld, LLC + * All rights reserved. + * + * This file is part of Chipmunk. + * + * Chipmunk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chipmunk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chipmunk. If not, see . + */ + +package chipmunk.runtime.hvm; + +public record CField(int offset, int flags, CType pType, String name) { + + public int calculateAddress(long pointer){ + return (int) pointer + offset; + } + +} diff --git a/Lang/src/main/java/chipmunk/runtime/hvm/CFlags.java b/Lang/src/main/java/chipmunk/runtime/hvm/CFlags.java new file mode 100644 index 0000000..b021384 --- /dev/null +++ b/Lang/src/main/java/chipmunk/runtime/hvm/CFlags.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 MyWorld, LLC + * All rights reserved. + * + * This file is part of Chipmunk. + * + * Chipmunk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chipmunk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chipmunk. If not, see . + */ + +package chipmunk.runtime.hvm; + +public class CFlags { + + public static final int SHARED = 0b001; + public static final int FINAL = 0b010; + public static final int TRAIT = 0b100; + + public static int combine(int... flags){ + var combined = 0; + for(var f : flags){ + combined |= f; + } + return combined; + } + + public static boolean isSet(int flags, int flag){ + return (flags & flag) != 0; + } +} diff --git a/Lang/src/main/java/chipmunk/runtime/hvm/CMethod.java b/Lang/src/main/java/chipmunk/runtime/hvm/CMethod.java new file mode 100644 index 0000000..bfdd341 --- /dev/null +++ b/Lang/src/main/java/chipmunk/runtime/hvm/CMethod.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 MyWorld, LLC + * All rights reserved. + * + * This file is part of Chipmunk. + * + * Chipmunk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chipmunk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chipmunk. If not, see . + */ + +package chipmunk.runtime.hvm; + +public record CMethod(int address, int flags, String name /* TODO - signature*/) {} diff --git a/Lang/src/main/java/chipmunk/runtime/hvm/CType.java b/Lang/src/main/java/chipmunk/runtime/hvm/CType.java new file mode 100644 index 0000000..aecb435 --- /dev/null +++ b/Lang/src/main/java/chipmunk/runtime/hvm/CType.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 MyWorld, LLC + * All rights reserved. + * + * This file is part of Chipmunk. + * + * Chipmunk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chipmunk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chipmunk. If not, see . + */ + +package chipmunk.runtime.hvm; + +public enum CType { + INT(32), LONG(64), FLOAT(32), DOUBLE(64); + private final int width; + + CType(int width){ + this.width = width; + } + + public int bitWidth(){ + return width; + } +} diff --git a/Lang/src/main/java/chipmunk/runtime/hvm/Memory.java b/Lang/src/main/java/chipmunk/runtime/hvm/Memory.java new file mode 100644 index 0000000..e9116b1 --- /dev/null +++ b/Lang/src/main/java/chipmunk/runtime/hvm/Memory.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 MyWorld, LLC + * All rights reserved. + * + * This file is part of Chipmunk. + * + * Chipmunk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chipmunk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chipmunk. If not, see . + */ + +package chipmunk.runtime.hvm; + +import myworld.hummingbird.HummingbirdVM; + +public class Memory { + + public static long read(long pointer, CType type, HummingbirdVM vm){ + return switch (type){ + case INT, FLOAT -> vm.memory.getInt((int)pointer); + case LONG, DOUBLE -> vm.memory.getLong((int)pointer); + }; + } + + public static void write(long pointer, long value, CType type, HummingbirdVM vm){ + switch (type){ + case INT, FLOAT -> vm.memory.putInt((int) pointer, (int) value); + case LONG, DOUBLE -> vm.memory.putLong((int) pointer, value); + } + } + + public static long readField(long pointer, int field, CClass type, HummingbirdVM vm){ + var f = type.fields[field]; + return read(f.calculateAddress(pointer), f.pType(), vm); + } + + public static void writeField(long pointer, long value, int field, CClass type, HummingbirdVM vm){ + var f = type.fields[field]; + var addr = f.calculateAddress(pointer); + write(f.calculateAddress(addr), value, f.pType(), vm); + } + + // TODO - support shared fields in memory model + +} diff --git a/Lang/src/main/java/chipmunk/runtime/hvm/TypeName.java b/Lang/src/main/java/chipmunk/runtime/hvm/TypeName.java new file mode 100644 index 0000000..774657c --- /dev/null +++ b/Lang/src/main/java/chipmunk/runtime/hvm/TypeName.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 MyWorld, LLC + * All rights reserved. + * + * This file is part of Chipmunk. + * + * Chipmunk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chipmunk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chipmunk. If not, see . + */ + +package chipmunk.runtime.hvm; + +public record TypeName(String module, String name) {} diff --git a/Lang/src/main/java/chipmunk/vm/hvm/HvmCompiler.java b/Lang/src/main/java/chipmunk/vm/hvm/HvmCompiler.java index e1f27dc..4082084 100644 --- a/Lang/src/main/java/chipmunk/vm/hvm/HvmCompiler.java +++ b/Lang/src/main/java/chipmunk/vm/hvm/HvmCompiler.java @@ -37,7 +37,6 @@ public class HvmCompiler { public ChipmunkModule compileModule(BinaryModule module){ var builder = Executable.builder(); - var operands = new Operands(); // For now assume we have a single method with no arguments module.getNamespace().getEntries().forEach(e -> { @@ -47,9 +46,13 @@ public ChipmunkModule compileModule(BinaryModule module){ var method = module.getNamespace().getEntries().get(2).getBinaryMethod(); var constants = method.getConstantPool(); var code = method.getCode(); + + var operands = new Operands(method.getArgCount() + method.getLocalCount()); + var ip = 0; while(ip < code.length){ switch (code[ip]){ + // Arithmetic case PUSH -> ip = push(builder, constants, operands, code, ip); case ADD -> ip = add(builder, operands, ip); case MUL -> ip = mul(builder, operands, ip); @@ -61,6 +64,17 @@ public ChipmunkModule compileModule(BinaryModule module){ case DEC -> ip = dec(builder, operands, ip); case POS -> ip = pos(builder, operands, ip); case NEG -> ip = neg(builder, operands, ip); + + // Bitwise + case BXOR -> ip = bxor(builder, operands, ip); + case BAND -> ip = band(builder, operands, ip); + case BOR -> ip = bor(builder, operands, ip); + case BNEG -> ip = bneg(builder, operands, ip); + case LSHIFT -> ip = lshift(builder, operands, ip); + case RSHIFT -> ip = rshift(builder, operands, ip); + case URSHIFT -> ip = urshift(builder, operands, ip); + + // Flow control case RETURN -> ip = _return(builder, operands, ip); default -> { throw new IllegalArgumentException("Unknown opcode 0x%02X".formatted(code[ip])); @@ -274,6 +288,82 @@ private int neg(Executable.Builder builder, Operands operands, int ip){ return ip + 1; } + private int bxor(Executable.Builder builder, Operands operands, int ip){ + var b = operands.pop(); + var a = operands.pop(); + + // Disregard operand types - treat everything as a long + builder.appendOpcode(Opcodes.BXOR(a.register(), a.register(), b.register())); + operands.push(LONG); + + return ip + 1; + } + + private int band(Executable.Builder builder, Operands operands, int ip){ + var b = operands.pop(); + var a = operands.pop(); + + // Disregard operand types - treat everything as a long + builder.appendOpcode(Opcodes.BAND(a.register(), a.register(), b.register())); + operands.push(LONG); + + return ip + 1; + } + + private int bor(Executable.Builder builder, Operands operands, int ip){ + var b = operands.pop(); + var a = operands.pop(); + + // Disregard operand types - treat everything as a long + builder.appendOpcode(Opcodes.BOR(a.register(), a.register(), b.register())); + operands.push(LONG); + + return ip + 1; + } + + private int bneg(Executable.Builder builder, Operands operands, int ip){ + var a = operands.pop(); + + // Disregard operand types - treat everything as a long + builder.appendOpcode(Opcodes.BNOT(a.register(), a.register())); + operands.push(LONG); + + return ip + 1; + } + + private int lshift(Executable.Builder builder, Operands operands, int ip){ + var b = operands.pop(); + var a = operands.pop(); + + // Disregard operand types - treat everything as a long + builder.appendOpcode(Opcodes.BLSHIFT(a.register(), a.register(), b.register())); + operands.push(LONG); + + return ip + 1; + } + + private int rshift(Executable.Builder builder, Operands operands, int ip){ + var b = operands.pop(); + var a = operands.pop(); + + // Disregard operand types - treat everything as a long + builder.appendOpcode(Opcodes.BSRSHIFT(a.register(), a.register(), b.register())); + operands.push(LONG); + + return ip + 1; + } + + private int urshift(Executable.Builder builder, Operands operands, int ip){ + var b = operands.pop(); + var a = operands.pop(); + + // Disregard operand types - treat everything as a long + builder.appendOpcode(Opcodes.BURSHIFT(a.register(), a.register(), b.register())); + operands.push(LONG); + + return ip + 1; + } + private int _return(Executable.Builder builder, Operands operands, int ip){ var op = operands.pop(); builder.appendOpcode(Opcodes.RETURN(op.register()));