diff --git a/Java/src/org/ciyam/at/API.java b/Java/src/org/ciyam/at/API.java
index c012e27..6adecaf 100644
--- a/Java/src/org/ciyam/at/API.java
+++ b/Java/src/org/ciyam/at/API.java
@@ -10,33 +10,33 @@ package org.ciyam.at;
* bits) with the second part being the number of the transaction if applicable (also 32 bits and zero if not applicable).
*
*/
-public interface API {
+public abstract class API {
/** Returns current blockchain's height */
- public int getCurrentBlockHeight();
+ public abstract int getCurrentBlockHeight();
/** Returns block height where AT was created */
- public int getATCreationBlockHeight(MachineState state);
+ public abstract int getATCreationBlockHeight(MachineState state);
/** Returns previous block's height */
- default public int getPreviousBlockHeight() {
+ public int getPreviousBlockHeight() {
return getCurrentBlockHeight() - 1;
}
/** Put previous block's signature hash in A */
- public void putPreviousBlockHashInA(MachineState state);
+ public abstract void putPreviousBlockHashInA(MachineState state);
/** Put next transaction to AT after timestamp in A */
- public void putTransactionAfterTimestampInA(Timestamp timestamp, MachineState state);
+ public abstract void putTransactionAfterTimestampInA(Timestamp timestamp, MachineState state);
/** Return type from transaction in A, or 0xffffffffffffffff if A not valid transaction */
- public long getTypeFromTransactionInA(MachineState state);
+ public abstract long getTypeFromTransactionInA(MachineState state);
/** Return amount from transaction in A, after transaction fees have been deducted, or 0xffffffffffffffff if A not valid transaction */
- public long getAmountFromTransactionInA(MachineState state);
+ public abstract long getAmountFromTransactionInA(MachineState state);
/** Return timestamp from transaction in A, or 0xffffffffffffffff if A not valid transaction */
- public long getTimestampFromTransactionInA(MachineState state);
+ public abstract long getTimestampFromTransactionInA(MachineState state);
/**
* Generate pseudo-random number using transaction in A.
@@ -48,53 +48,92 @@ public interface API {
*
* Returns 0xffffffffffffffff if A not valid transaction.
*/
- public long generateRandomUsingTransactionInA(MachineState state);
+ public abstract long generateRandomUsingTransactionInA(MachineState state);
/** Put 'message' from transaction in A into B */
- public void putMessageFromTransactionInAIntoB(MachineState state);
+ public abstract void putMessageFromTransactionInAIntoB(MachineState state);
/** Put sender/creator address from transaction in A into B */
- public void putAddressFromTransactionInAIntoB(MachineState state);
+ public abstract void putAddressFromTransactionInAIntoB(MachineState state);
/** Put AT's creator's address into B */
- public void putCreatorAddressIntoB(MachineState state);
+ public abstract void putCreatorAddressIntoB(MachineState state);
/** Return AT's current balance */
- public long getCurrentBalance(MachineState state);
+ public abstract long getCurrentBalance(MachineState state);
/** Return AT's previous balance at end of last execution round. Does not include any amounts sent to AT since */
- public long getPreviousBalance(MachineState state);
+ public abstract long getPreviousBalance(MachineState state);
/** Pay passed amount, or current balance if necessary, (fee inclusive) to address in B */
- public void payAmountToB(long value1, MachineState state);
+ public abstract void payAmountToB(long value1, MachineState state);
/** Pay AT's current balance to address in B */
- public void payCurrentBalanceToB(MachineState state);
+ public abstract void payCurrentBalanceToB(MachineState state);
/** Pay AT's previous balance to address in B */
- public void payPreviousBalanceToB(MachineState state);
+ public abstract void payPreviousBalanceToB(MachineState state);
/** Send 'message' in A to address in B */
- public void messageAToB(MachineState state);
+ public abstract void messageAToB(MachineState state);
/**
* Returns minutes of blocks added to 'timestamp'
*
* minutes is converted to rough number of blocks and added to 'timestamp' to create return value.
*/
- public long addMinutesToTimestamp(Timestamp timestamp, long minutes, MachineState state);
+ public abstract long addMinutesToTimestamp(Timestamp timestamp, long minutes, MachineState state);
/** AT has encountered fatal error. Return remaining funds to creator */
- public void onFatalError(MachineState state, ExecutionException e);
+ public abstract void onFatalError(MachineState state, ExecutionException e);
/** Pre-execute checking of param requirements for platform-specific functions */
- public void platformSpecificPreExecuteCheck(short functionCodeValue, int paramCount, boolean returnValueExpected) throws IllegalFunctionCodeException;
+ public abstract void platformSpecificPreExecuteCheck(short functionCodeValue, int paramCount, boolean returnValueExpected)
+ throws IllegalFunctionCodeException;
/**
* Platform-specific function execution
*
* @throws ExecutionException
*/
- public void platformSpecificPostCheckExecute(short functionCodeValue, FunctionData functionData, MachineState state) throws ExecutionException;
+ public abstract void platformSpecificPostCheckExecute(short functionCodeValue, FunctionData functionData, MachineState state) throws ExecutionException;
+
+ /** Convenience method to allow subclasses to access package-scoped MachineState.setIsSleeping */
+ protected void setIsSleeping(MachineState state, boolean isSleeping) {
+ state.setIsSleeping(isSleeping);
+ }
+
+ /** Convenience methods to allow subclasses to access package-scoped a1-a4, b1-b4 variables */
+ protected void setA1(MachineState state, long value) {
+ state.a1 = value;
+ }
+
+ protected void setA2(MachineState state, long value) {
+ state.a2 = value;
+ }
+
+ protected void setA3(MachineState state, long value) {
+ state.a3 = value;
+ }
+
+ protected void setA4(MachineState state, long value) {
+ state.a4 = value;
+ }
+
+ protected void setB1(MachineState state, long value) {
+ state.b1 = value;
+ }
+
+ protected void setB2(MachineState state, long value) {
+ state.b2 = value;
+ }
+
+ protected void setB3(MachineState state, long value) {
+ state.b3 = value;
+ }
+
+ protected void setB4(MachineState state, long value) {
+ state.b4 = value;
+ }
}
diff --git a/Java/src/org/ciyam/at/FunctionCode.java b/Java/src/org/ciyam/at/FunctionCode.java
index 1aa3aeb..c3c4e37 100644
--- a/Java/src/org/ciyam/at/FunctionCode.java
+++ b/Java/src/org/ciyam/at/FunctionCode.java
@@ -31,7 +31,7 @@ public enum FunctionCode {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
String message = String.valueOf(functionData.value1);
- state.logger.echo(message);
+ state.getLogger().echo(message);
}
},
/**
@@ -671,7 +671,7 @@ public enum FunctionCode {
GET_BLOCK_TIMESTAMP(0x0300, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = Timestamp.toLong(state.api.getCurrentBlockHeight(), 0);
+ functionData.returnValue = Timestamp.toLong(state.getAPI().getCurrentBlockHeight(), 0);
}
},
/**
@@ -681,7 +681,7 @@ public enum FunctionCode {
GET_CREATION_TIMESTAMP(0x0301, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = Timestamp.toLong(state.api.getATCreationBlockHeight(state), 0);
+ functionData.returnValue = Timestamp.toLong(state.getAPI().getATCreationBlockHeight(state), 0);
}
},
/**
@@ -691,7 +691,7 @@ public enum FunctionCode {
GET_PREVIOUS_BLOCK_TIMESTAMP(0x0302, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = Timestamp.toLong(state.api.getPreviousBlockHeight(), 0);
+ functionData.returnValue = Timestamp.toLong(state.getAPI().getPreviousBlockHeight(), 0);
}
},
/**
@@ -701,7 +701,7 @@ public enum FunctionCode {
PUT_PREVIOUS_BLOCK_HASH_IN_A(0x0303, 0, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.putPreviousBlockHashInA(state);
+ state.getAPI().putPreviousBlockHashInA(state);
}
},
/**
@@ -712,7 +712,7 @@ public enum FunctionCode {
PUT_TX_AFTER_TIMESTAMP_IN_A(0x0304, 1, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.putTransactionAfterTimestampInA(new Timestamp(functionData.value1), state);
+ state.getAPI().putTransactionAfterTimestampInA(new Timestamp(functionData.value1), state);
}
},
/**
@@ -723,7 +723,7 @@ public enum FunctionCode {
GET_TYPE_FROM_TX_IN_A(0x0305, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = state.api.getTypeFromTransactionInA(state);
+ functionData.returnValue = state.getAPI().getTypeFromTransactionInA(state);
}
},
/**
@@ -734,7 +734,7 @@ public enum FunctionCode {
GET_AMOUNT_FROM_TX_IN_A(0x0306, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = state.api.getAmountFromTransactionInA(state);
+ functionData.returnValue = state.getAPI().getAmountFromTransactionInA(state);
}
},
/**
@@ -745,7 +745,7 @@ public enum FunctionCode {
GET_TIMESTAMP_FROM_TX_IN_A(0x0307, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = state.api.getTimestampFromTransactionInA(state);
+ functionData.returnValue = state.getAPI().getTimestampFromTransactionInA(state);
}
},
/**
@@ -757,15 +757,17 @@ public enum FunctionCode {
GENERATE_RANDOM_USING_TX_IN_A(0x0308, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = state.api.generateRandomUsingTransactionInA(state);
+ functionData.returnValue = state.getAPI().generateRandomUsingTransactionInA(state);
- // If API set isSleeping then rewind program counter ready for being awoken
- if (state.isSleeping) {
- state.programCounter -= 1 + 2 + 4; // EXT_FUN_RET(1) + our function code(2) + address(4)
+ // If API set isSleeping then rewind program counter (actually codeByteBuffer) ready for being awoken
+ if (state.getIsSleeping()) {
+ // EXT_FUN_RET(1) + our function code(2) + address(4)
+ int newPosition = state.codeByteBuffer.position() - MachineState.OPCODE_SIZE - MachineState.FUNCTIONCODE_SIZE - MachineState.ADDRESS_SIZE;
+ state.codeByteBuffer.position(newPosition);
// If specific sleep height not set, default to next block
- if (state.sleepUntilHeight == null)
- state.sleepUntilHeight = state.currentBlockHeight + 1;
+ if (state.getSleepUntilHeight() == null)
+ state.setSleepUntilHeight(state.getCurrentBlockHeight() + 1);
}
}
},
@@ -778,7 +780,7 @@ public enum FunctionCode {
PUT_MESSAGE_FROM_TX_IN_A_INTO_B(0x0309, 0, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.putMessageFromTransactionInAIntoB(state);
+ state.getAPI().putMessageFromTransactionInAIntoB(state);
}
},
/**
@@ -788,7 +790,7 @@ public enum FunctionCode {
PUT_ADDRESS_FROM_TX_IN_A_INTO_B(0x030a, 0, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.putAddressFromTransactionInAIntoB(state);
+ state.getAPI().putAddressFromTransactionInAIntoB(state);
}
},
/**
@@ -798,7 +800,7 @@ public enum FunctionCode {
PUT_CREATOR_INTO_B(0x030b, 0, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.putCreatorAddressIntoB(state);
+ state.getAPI().putCreatorAddressIntoB(state);
}
},
/**
@@ -808,7 +810,7 @@ public enum FunctionCode {
GET_CURRENT_BALANCE(0x0400, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = state.api.getCurrentBalance(state);
+ functionData.returnValue = state.getAPI().getCurrentBalance(state);
}
},
/**
@@ -819,7 +821,7 @@ public enum FunctionCode {
GET_PREVIOUS_BALANCE(0x0401, 0, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = state.api.getPreviousBalance(state);
+ functionData.returnValue = state.getAPI().getPreviousBalance(state);
}
},
/**
@@ -830,7 +832,7 @@ public enum FunctionCode {
PAY_TO_ADDRESS_IN_B(0x0402, 1, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.payAmountToB(functionData.value1, state);
+ state.getAPI().payAmountToB(functionData.value1, state);
}
},
/**
@@ -840,7 +842,7 @@ public enum FunctionCode {
PAY_ALL_TO_ADDRESS_IN_B(0x0403, 0, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.payCurrentBalanceToB(state);
+ state.getAPI().payCurrentBalanceToB(state);
}
},
/**
@@ -851,7 +853,7 @@ public enum FunctionCode {
PAY_PREVIOUS_TO_ADDRESS_IN_B(0x0404, 0, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.payPreviousBalanceToB(state);
+ state.getAPI().payPreviousBalanceToB(state);
}
},
/**
@@ -861,7 +863,7 @@ public enum FunctionCode {
MESSAGE_A_TO_ADDRESS_IN_B(0x0405, 0, false) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.messageAToB(state);
+ state.getAPI().messageAToB(state);
}
},
/**
@@ -871,7 +873,7 @@ public enum FunctionCode {
ADD_MINUTES_TO_TIMESTAMP(0x0406, 2, true) {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- functionData.returnValue = state.api.addMinutesToTimestamp(new Timestamp(functionData.value1), functionData.value2, state);
+ functionData.returnValue = state.getAPI().addMinutesToTimestamp(new Timestamp(functionData.value1), functionData.value2, state);
}
},
/**
@@ -882,12 +884,12 @@ public enum FunctionCode {
API_PASSTHROUGH(0x0500, 0, false) {
@Override
public void preExecuteCheck(int paramCount, boolean returnValueExpected, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.platformSpecificPreExecuteCheck(rawFunctionCode, paramCount, returnValueExpected);
+ state.getAPI().platformSpecificPreExecuteCheck(rawFunctionCode, paramCount, returnValueExpected);
}
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
- state.api.platformSpecificPostCheckExecute(rawFunctionCode, functionData, state);
+ state.getAPI().platformSpecificPostCheckExecute(rawFunctionCode, functionData, state);
}
};
@@ -943,7 +945,7 @@ public enum FunctionCode {
if (functionData.paramCount == 2 && functionData.value2 == null)
throw new IllegalFunctionCodeException("Passed value2 is null but function has paramCount of (" + this.paramCount + ")");
- state.logger.debug("Function \"" + this.name() + "\"");
+ state.getLogger().debug("Function \"" + this.name() + "\"");
postCheckExecute(functionData, state, rawFunctionCode);
}
diff --git a/Java/src/org/ciyam/at/MachineState.java b/Java/src/org/ciyam/at/MachineState.java
index 1175d42..011e1f4 100644
--- a/Java/src/org/ciyam/at/MachineState.java
+++ b/Java/src/org/ciyam/at/MachineState.java
@@ -4,12 +4,21 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
public class MachineState {
/** Header bytes length */
public static final int HEADER_LENGTH = 2 + 2 + 2 + 2 + 2 + 2; // version reserved code data call-stack user-stack
+ /** Size of one OpCode - typically 1 byte (byte) */
+ public static final int OPCODE_SIZE = 1;
+
+ /** Size of one FunctionCode - typically 2 bytes (short) */
+ public static final int FUNCTIONCODE_SIZE = 2;
+
/** Size of value stored in data segment - typically 8 bytes (long) */
public static final int VALUE_SIZE = 8;
@@ -19,162 +28,336 @@ public class MachineState {
/** Maximum value for an address in the code segment */
public static final int MAX_CODE_ADDRESS = 0x1fffffff;
- /** Bytes per code page */
- public static final int CODE_PAGE_SIZE = 1;
+ private static class VersionedConstants {
+ /** Bytes per code page */
+ public final int CODE_PAGE_SIZE;
+ /** Bytes per data page */
+ public final int DATA_PAGE_SIZE;
+ /** Bytes per call stack page */
+ public final int CALL_STACK_PAGE_SIZE;
+ /** Bytes per user stack page */
+ public final int USER_STACK_PAGE_SIZE;
- /** Bytes per data page */
- public static final int DATA_PAGE_SIZE = VALUE_SIZE;
-
- /** Bytes per call stack page */
- public static final int CALL_STACK_PAGE_SIZE = ADDRESS_SIZE;
-
- /** Bytes per user stack page */
- public static final int USER_STACK_PAGE_SIZE = VALUE_SIZE;
-
- /** Program Counter: offset into code to point of current execution */
- public int programCounter;
-
- /** Initial program counter value to use on next block after current block's execution has stopped. 0 by default */
- public int onStopAddress;
-
- /** Program counter value to use if an error occurs during execution. If null upon error, refund all funds to creator and finish */
- public Integer onErrorAddress;
-
- /** Execution for current block has stopped. Continue at current program counter on next/specific block */
- public boolean isSleeping;
-
- /** Block height required to wake from sleeping, or null if not in use */
- public Integer sleepUntilHeight;
-
- /** Execution for current block has stopped. Restart at onStopAddress on next block */
- public boolean isStopped;
-
- /** Execution stopped due to lack of funds for processing. Restart at onStopAddress if frozenBalance increases */
- public boolean isFrozen;
-
- /** Balance at which there were not enough funds, or null if not in use */
- public Long frozenBalance;
-
- /** Execution permanently stopped */
- public boolean isFinished;
-
- /** Execution permanently stopped due to fatal error */
- public boolean hadFatalError;
-
- // 256-bit pseudo-registers
- public long a1;
- public long a2;
- public long a3;
- public long a4;
-
- public long b1;
- public long b2;
- public long b3;
- public long b4;
-
- public int currentBlockHeight;
-
- /** Number of opcodes processed this execution */
- public int steps;
-
- public API api;
- LoggerInterface logger;
-
- public short version;
- public short reserved;
- public short numCodePages;
- public short numDataPages;
- public short numCallStackPages;
- public short numUserStackPages;
-
- public byte[] headerBytes;
-
- public ByteBuffer codeByteBuffer;
- public ByteBuffer dataByteBuffer;
- public ByteBuffer callStackByteBuffer;
- public ByteBuffer userStackByteBuffer;
-
- private class Flags {
- private int flags;
-
- public Flags() {
- flags = 0;
- }
-
- public Flags(int value) {
- this.flags = value;
- }
-
- public void push(boolean flag) {
- flags <<= 1;
- flags |= flag ? 1 : 0;
- }
-
- public boolean pop() {
- boolean result = (flags & 1) != 0;
- flags >>>= 1;
- return result;
- }
-
- public int intValue() {
- return flags;
+ public VersionedConstants(int codePageSize, int dataPageSize, int callStackPageSize, int userStackPageSize) {
+ CODE_PAGE_SIZE = codePageSize;
+ DATA_PAGE_SIZE = dataPageSize;
+ CALL_STACK_PAGE_SIZE = callStackPageSize;
+ USER_STACK_PAGE_SIZE = userStackPageSize;
}
}
+ /** Map of constants (e.g. CODE_PAGE_SIZE) by AT version */
+ private static final Map VERSIONED_CONSTANTS = new HashMap();
+ static {
+ VERSIONED_CONSTANTS.put((short) 1, new VersionedConstants(256, 256, 256, 256));
+ VERSIONED_CONSTANTS.put((short) 3, new VersionedConstants(OPCODE_SIZE, VALUE_SIZE, ADDRESS_SIZE, VALUE_SIZE));
+ }
+
+ // Set during construction
+ public final short version;
+ public final short reserved;
+ public final short numCodePages;
+ public final short numDataPages;
+ public final short numCallStackPages;
+ public final short numUserStackPages;
+
+ private final byte[] headerBytes;
+
+ /** Constants set in effect */
+ private final VersionedConstants constants;
+
+ /** Program Counter: offset into code to point of current execution */
+ private int programCounter;
+
+ /** Initial program counter value to use on next block after current block's execution has stopped. 0 by default */
+ private int onStopAddress;
+
+ /** Program counter value to use if an error occurs during execution. If null upon error, refund all funds to creator and finish */
+ private Integer onErrorAddress;
+
+ /** Execution for current block has stopped. Continue at current program counter on next/specific block */
+ private boolean isSleeping;
+
+ /** Block height required to wake from sleeping, or null if not in use */
+ private Integer sleepUntilHeight;
+
+ /** Execution for current block has stopped. Restart at onStopAddress on next block */
+ private boolean isStopped;
+
+ /** Execution stopped due to lack of funds for processing. Restart at onStopAddress if frozenBalance increases */
+ private boolean isFrozen;
+
+ /** Balance at which there were not enough funds, or null if not in use */
+ private Long frozenBalance;
+
+ /** Execution permanently stopped */
+ private boolean isFinished;
+
+ /** Execution permanently stopped due to fatal error */
+ private boolean hadFatalError;
+
+ // 256-bit pseudo-registers
+ // NOTE: These are package-scope to allow easy access/operations in FunctionCodes.
+ // Outside classes (e.g. unit tests) can use getters
+ /* package */ long a1;
+ /* package */ long a2;
+ /* package */ long a3;
+ /* package */ long a4;
+
+ /* package */ long b1;
+ /* package */ long b2;
+ /* package */ long b3;
+ /* package */ long b4;
+
+ private int currentBlockHeight;
+
+ /** Number of opcodes processed this execution */
+ private int steps;
+
+ private API api;
+ private LoggerInterface logger;
+
+ // NOTE: These are package-scope to allow easy access/operations in Opcode/FunctionCode.
+ /* package */ ByteBuffer codeByteBuffer;
+ /* package */ ByteBuffer dataByteBuffer;
+ /* package */ ByteBuffer callStackByteBuffer;
+ /* package */ ByteBuffer userStackByteBuffer;
+
+ // Constructors
+
/** For internal use when recreating a machine state */
private MachineState(API api, LoggerInterface logger, byte[] headerBytes) {
if (headerBytes.length != HEADER_LENGTH)
throw new IllegalArgumentException("headerBytes length " + headerBytes.length + " incorrect, expected " + HEADER_LENGTH);
this.headerBytes = headerBytes;
- parseHeader();
- this.codeByteBuffer = ByteBuffer.allocate(this.numCodePages * CODE_PAGE_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+ // Parsing header bytes
+ ByteBuffer byteBuffer = ByteBuffer.wrap(this.headerBytes);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
- this.dataByteBuffer = ByteBuffer.allocate(this.numDataPages * DATA_PAGE_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+ this.version = byteBuffer.getShort();
+ if (this.version < 1)
+ throw new IllegalArgumentException("Version must be >= 0");
- this.callStackByteBuffer = ByteBuffer.allocate(this.numCallStackPages * CALL_STACK_PAGE_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+ this.constants = VERSIONED_CONSTANTS.get(this.version);
+ if (this.constants == null)
+ throw new IllegalArgumentException("Version " + this.version + " unsupported");
+
+ this.reserved = byteBuffer.getShort();
+
+ this.numCodePages = byteBuffer.getShort();
+ if (this.numCodePages < 1)
+ throw new IllegalArgumentException("Number of code pages must be > 0");
+
+ this.numDataPages = byteBuffer.getShort();
+ if (this.numDataPages < 1)
+ throw new IllegalArgumentException("Number of data pages must be > 0");
+
+ this.numCallStackPages = byteBuffer.getShort();
+ if (this.numCallStackPages < 0)
+ throw new IllegalArgumentException("Number of call stack pages must be >= 0");
+
+ this.numUserStackPages = byteBuffer.getShort();
+ if (this.numUserStackPages < 0)
+ throw new IllegalArgumentException("Number of user stack pages must be >= 0");
+
+ // Header OK - set up code and data buffers
+ this.codeByteBuffer = ByteBuffer.allocate(this.numCodePages * this.constants.CODE_PAGE_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+ this.dataByteBuffer = ByteBuffer.allocate(this.numDataPages * this.constants.DATA_PAGE_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+
+ // Set up stacks
+ this.callStackByteBuffer = ByteBuffer.allocate(this.numCallStackPages * this.constants.CALL_STACK_PAGE_SIZE).order(ByteOrder.LITTLE_ENDIAN);
this.callStackByteBuffer.position(this.callStackByteBuffer.limit()); // Downward-growing stack, so start at the end
- this.userStackByteBuffer = ByteBuffer.allocate(this.numUserStackPages * USER_STACK_PAGE_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+ this.userStackByteBuffer = ByteBuffer.allocate(this.numUserStackPages * this.constants.USER_STACK_PAGE_SIZE).order(ByteOrder.LITTLE_ENDIAN);
this.userStackByteBuffer.position(this.userStackByteBuffer.limit()); // Downward-growing stack, so start at the end
this.api = api;
- this.currentBlockHeight = api.getCurrentBlockHeight();
+ this.currentBlockHeight = 0;
this.steps = 0;
this.logger = logger;
}
+ /** For creating a new machine state */
+ public MachineState(byte[] creationBytes) {
+ this(null, null, Arrays.copyOfRange(creationBytes, 0, HEADER_LENGTH));
+
+ int expectedLength = HEADER_LENGTH + this.numCodePages * this.constants.CODE_PAGE_SIZE + this.numDataPages + this.constants.DATA_PAGE_SIZE;
+ if (creationBytes.length != expectedLength)
+ throw new IllegalArgumentException("Creation bytes length does not match header values");
+
+ System.arraycopy(creationBytes, HEADER_LENGTH, this.codeByteBuffer.array(), 0, this.numCodePages * this.constants.CODE_PAGE_SIZE);
+
+ System.arraycopy(creationBytes, HEADER_LENGTH + this.numCodePages * this.constants.CODE_PAGE_SIZE, this.dataByteBuffer.array(), 0,
+ this.numDataPages + this.constants.DATA_PAGE_SIZE);
+
+ commonFinalConstruction();
+ }
+
/** For creating a new machine state */
public MachineState(API api, LoggerInterface logger, byte[] headerBytes, byte[] codeBytes, byte[] dataBytes) {
this(api, logger, headerBytes);
- // XXX: Why don't we simply ByteBuffer.wrap(codeBytes) as they're read-only?
- // This would do away with the need to specify numCodePages, save space and provide automatic end-of-code detection during execution thanks to
- // ByteBuffer's BufferUnderflowException
-
- if (codeBytes.length > this.numCodePages * CODE_PAGE_SIZE)
+ if (codeBytes.length > this.numCodePages * this.constants.CODE_PAGE_SIZE)
throw new IllegalArgumentException("Number of code pages too small to hold code bytes");
- if (dataBytes.length > this.numDataPages * DATA_PAGE_SIZE)
+ if (dataBytes.length > this.numDataPages * this.constants.DATA_PAGE_SIZE)
throw new IllegalArgumentException("Number of data pages too small to hold data bytes");
System.arraycopy(codeBytes, 0, this.codeByteBuffer.array(), 0, codeBytes.length);
System.arraycopy(dataBytes, 0, this.dataByteBuffer.array(), 0, dataBytes.length);
+ commonFinalConstruction();
+ }
+
+ private void commonFinalConstruction() {
this.programCounter = 0;
this.onStopAddress = 0;
this.onErrorAddress = null;
this.isSleeping = false;
this.sleepUntilHeight = null;
this.isStopped = false;
- this.isFinished = false;
- this.hadFatalError = false;
this.isFrozen = false;
this.frozenBalance = null;
+ this.isFinished = false;
+ this.hadFatalError = false;
}
+ // Getters / setters
+
+ // NOTE: Many setters have package-scope (i.e. org.ciyam.at only) to allow changes
+ // during execution but not by outside classes.
+
+ public int getProgramCounter() {
+ return this.programCounter;
+ }
+
+ public int getOnStopAddress() {
+ return this.onStopAddress;
+ }
+
+ /* package */ void setOnStopAddress(int address) {
+ this.onStopAddress = address;
+ }
+
+ public Integer getOnErrorAddress() {
+ return this.onErrorAddress;
+ }
+
+ /* package */ void setOnErrorAddress(Integer address) {
+ this.onErrorAddress = address;
+ }
+
+ public boolean getIsSleeping() {
+ return this.isSleeping;
+ }
+
+ /* package */ void setIsSleeping(boolean isSleeping) {
+ this.isSleeping = isSleeping;
+ }
+
+ public Integer getSleepUntilHeight() {
+ return this.sleepUntilHeight;
+ }
+
+ /* package */ void setSleepUntilHeight(Integer address) {
+ this.sleepUntilHeight = address;
+ }
+
+ public boolean getIsStopped() {
+ return this.isStopped;
+ }
+
+ /* package */ void setIsStopped(boolean isStopped) {
+ this.isStopped = isStopped;
+ }
+
+ public boolean getIsFrozen() {
+ return this.isFrozen;
+ }
+
+ /* package */ void setIsFrozen(boolean isFrozen) {
+ this.isFrozen = isFrozen;
+ }
+
+ public Long getFrozenBalance() {
+ return this.frozenBalance;
+ }
+
+ /* package */ void setFrozenBalance(Long frozenBalance) {
+ this.frozenBalance = frozenBalance;
+ }
+
+ public boolean getIsFinished() {
+ return this.isFinished;
+ }
+
+ /* package */ void setIsFinished(boolean isFinished) {
+ this.isFinished = isFinished;
+ }
+
+ public boolean getHadFatalError() {
+ return this.hadFatalError;
+ }
+
+ /* package */ void setHadFatalError(boolean hadFatalError) {
+ this.hadFatalError = hadFatalError;
+ }
+
+ // No corresponding setters due to package-scope - see above
+ public long getA1() {
+ return this.a1;
+ }
+
+ public long getA2() {
+ return this.a2;
+ }
+
+ public long getA3() {
+ return this.a3;
+ }
+
+ public long getA4() {
+ return this.a4;
+ }
+
+ public long getB1() {
+ return this.b1;
+ }
+
+ public long getB2() {
+ return this.b2;
+ }
+
+ public long getB3() {
+ return this.b3;
+ }
+
+ public long getB4() {
+ return this.b4;
+ }
+ // End of package-scope pseudo-registers
+
+ public int getCurrentBlockHeight() {
+ return this.currentBlockHeight;
+ }
+
+ public int getSteps() {
+ return this.steps;
+ }
+
+ public API getAPI() {
+ return this.api;
+ }
+
+ public LoggerInterface getLogger() {
+ return this.logger;
+ }
+
+ // Serialization
+
/** For serializing a machine state */
public byte[] toBytes() {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
@@ -192,13 +375,13 @@ public class MachineState {
// Call stack length (32bit unsigned int)
int callStackLength = this.callStackByteBuffer.limit() - this.callStackByteBuffer.position();
bytes.write(toByteArray(callStackLength));
- // Call stack
+ // Call stack (only the bytes actually in use)
bytes.write(this.callStackByteBuffer.array(), this.callStackByteBuffer.position(), callStackLength);
// User stack length (32bit unsigned int)
int userStackLength = this.userStackByteBuffer.limit() - this.userStackByteBuffer.position();
bytes.write(toByteArray(userStackLength));
- // User stack
+ // User stack (only the bytes actually in use)
bytes.write(this.userStackByteBuffer.array(), this.userStackByteBuffer.position(), userStackLength);
// Actual state
@@ -333,6 +516,34 @@ public class MachineState {
return state;
}
+ /** Class for pushing/popping boolean flags onto/from an int */
+ private class Flags {
+ private int flags;
+
+ public Flags() {
+ flags = 0;
+ }
+
+ public Flags(int value) {
+ this.flags = value;
+ }
+
+ public void push(boolean flag) {
+ flags <<= 1;
+ flags |= flag ? 1 : 0;
+ }
+
+ public boolean pop() {
+ boolean result = (flags & 1) != 0;
+ flags >>>= 1;
+ return result;
+ }
+
+ public int intValue() {
+ return flags;
+ }
+ }
+
/** Convert int to little-endian byte array */
private byte[] toByteArray(int value) {
return new byte[] { (byte) (value), (byte) (value >> 8), (byte) (value >> 16), (byte) (value >> 24) };
@@ -344,32 +555,7 @@ public class MachineState {
(byte) (value >> 48), (byte) (value >> 56) };
}
- private void parseHeader() {
- ByteBuffer byteBuffer = ByteBuffer.wrap(this.headerBytes);
- byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
-
- this.version = byteBuffer.getShort();
- if (this.version < 1)
- throw new IllegalArgumentException("Version must be >= 0");
-
- this.reserved = byteBuffer.getShort();
-
- this.numCodePages = byteBuffer.getShort();
- if (this.numCodePages < 1)
- throw new IllegalArgumentException("Number of code pages must be > 0");
-
- this.numDataPages = byteBuffer.getShort();
- if (this.numDataPages < 1)
- throw new IllegalArgumentException("Number of data pages must be > 0");
-
- this.numCallStackPages = byteBuffer.getShort();
- if (this.numCallStackPages < 0)
- throw new IllegalArgumentException("Number of call stack pages must be >= 0");
-
- this.numUserStackPages = byteBuffer.getShort();
- if (this.numUserStackPages < 0)
- throw new IllegalArgumentException("Number of user stack pages must be >= 0");
- }
+ // Actual execution
public void execute() {
// Set byte buffer position using program counter
@@ -382,6 +568,7 @@ public class MachineState {
this.isFrozen = false;
this.frozenBalance = null;
this.steps = 0;
+ this.currentBlockHeight = api.getCurrentBlockHeight();
while (!this.isSleeping && !this.isStopped && !this.isFinished && !this.isFrozen) {
byte rawOpCode = codeByteBuffer.get();
@@ -393,7 +580,12 @@ public class MachineState {
this.logger.debug("[PC: " + String.format("%04x", this.programCounter) + "] " + nextOpCode.name());
- nextOpCode.execute(codeByteBuffer, dataByteBuffer, userStackByteBuffer, callStackByteBuffer, this);
+ // TODO: Request cost from API, apply cost to balance, etc.
+
+ // At this point, programCounter is BEFORE opcode (and args).
+ nextOpCode.execute(this);
+
+ // Synchronize programCounter with codeByteBuffer in case of JMPs, branches, etc.
this.programCounter = codeByteBuffer.position();
} catch (ExecutionException e) {
this.logger.debug("Error at PC " + String.format("%04x", this.programCounter) + ": " + e.getMessage());
@@ -401,6 +593,8 @@ public class MachineState {
if (this.onErrorAddress == null) {
this.isFinished = true;
this.hadFatalError = true;
+
+ // Ask API to refund remaining funds back to AT's creator
this.api.onFatalError(this, e);
break;
}
@@ -418,7 +612,7 @@ public class MachineState {
}
}
- // public String disassemble(List dataLabels, Map codeLabels) {
+ /** Return disassembly of code bytes */
public String disassemble() throws ExecutionException {
String output = "";
diff --git a/Java/src/org/ciyam/at/OpCode.java b/Java/src/org/ciyam/at/OpCode.java
index 8e69040..3fbfcbb 100644
--- a/Java/src/org/ciyam/at/OpCode.java
+++ b/Java/src/org/ciyam/at/OpCode.java
@@ -2,7 +2,9 @@ package org.ciyam.at;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -26,7 +28,7 @@ import java.util.stream.Collectors;
* $($addr1 + $addr2) means "fetch from address fetched from addr1 plus offset fetched from addr2", i.e. indirect indexed
*
* @see OpCode#valueOf(int)
- * @see OpCode#execute(ByteBuffer, ByteBuffer, ByteBuffer, ByteBuffer, MachineState)
+ * @see OpCode#executeWithParams(MachineState, Object...)
*/
public enum OpCode {
@@ -37,8 +39,7 @@ public enum OpCode {
*/
NOP(0x7f) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) {
+ public void executeWithParams(MachineState state, Object... args) {
// Do nothing
}
},
@@ -49,11 +50,11 @@ public enum OpCode {
*/
SET_VAL(0x01, OpCodeParam.DEST_ADDR, OpCodeParam.VALUE) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = Utils.getCodeValue(codeByteBuffer);
- dataByteBuffer.putLong(address, value);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+ long value = (long) args[1];
+
+ state.dataByteBuffer.putLong(address, value);
}
},
/**
@@ -63,12 +64,12 @@ public enum OpCode {
*/
SET_DAT(0x02, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address1 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address2 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = dataByteBuffer.getLong(address2);
- dataByteBuffer.putLong(address1, value);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address1 = (int) args[0];
+ int address2 = (int) args[1];
+
+ long value = state.dataByteBuffer.getLong(address2);
+ state.dataByteBuffer.putLong(address1, value);
}
},
/**
@@ -78,10 +79,10 @@ public enum OpCode {
*/
CLR_DAT(0x03, OpCodeParam.DEST_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- dataByteBuffer.putLong(address, 0L);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+
+ state.dataByteBuffer.putLong(address, 0L);
}
},
/**
@@ -91,11 +92,11 @@ public enum OpCode {
*/
INC_DAT(0x04, OpCodeParam.DEST_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = dataByteBuffer.getLong(address);
- dataByteBuffer.putLong(address, value + 1);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+
+ long value = state.dataByteBuffer.getLong(address);
+ state.dataByteBuffer.putLong(address, value + 1);
}
},
/**
@@ -105,11 +106,11 @@ public enum OpCode {
*/
DEC_DAT(0x05, OpCodeParam.DEST_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = dataByteBuffer.getLong(address);
- dataByteBuffer.putLong(address, value - 1);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+
+ long value = state.dataByteBuffer.getLong(address);
+ state.dataByteBuffer.putLong(address, value - 1);
}
},
/**
@@ -119,9 +120,8 @@ public enum OpCode {
*/
ADD_DAT(0x06, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> a + b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeDataOperation(state, (a, b) -> a + b, args);
}
},
/**
@@ -131,9 +131,8 @@ public enum OpCode {
*/
SUB_DAT(0x07, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> a - b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeDataOperation(state, (a, b) -> a - b, args);
}
},
/**
@@ -143,9 +142,8 @@ public enum OpCode {
*/
MUL_DAT(0x08, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> a * b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeDataOperation(state, (a, b) -> a * b, args);
}
},
/**
@@ -156,10 +154,9 @@ public enum OpCode {
*/
DIV_DAT(0x09, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
try {
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> a / b);
+ executeDataOperation(state, (a, b) -> a / b, args);
} catch (ArithmeticException e) {
throw new IllegalOperationException("Divide by zero", e);
}
@@ -172,9 +169,8 @@ public enum OpCode {
*/
BOR_DAT(0x0a, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> a | b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeDataOperation(state, (a, b) -> a | b, args);
}
},
/**
@@ -184,9 +180,8 @@ public enum OpCode {
*/
AND_DAT(0x0b, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> a & b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeDataOperation(state, (a, b) -> a & b, args);
}
},
/**
@@ -196,9 +191,8 @@ public enum OpCode {
*/
XOR_DAT(0x0c, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> a ^ b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeDataOperation(state, (a, b) -> a ^ b, args);
}
},
/**
@@ -208,11 +202,11 @@ public enum OpCode {
*/
NOT_DAT(0x0d, OpCodeParam.DEST_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = dataByteBuffer.getLong(address);
- dataByteBuffer.putLong(address, ~value);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+
+ long value = state.dataByteBuffer.getLong(address);
+ state.dataByteBuffer.putLong(address, ~value);
}
},
/**
@@ -222,18 +216,17 @@ public enum OpCode {
*/
SET_IND(0x0e, OpCodeParam.DEST_ADDR, OpCodeParam.INDIRECT_SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address1 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address2 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address1 = (int) args[0];
+ int address2 = (int) args[1];
- long address3 = dataByteBuffer.getLong(address2) * MachineState.VALUE_SIZE;
+ long address3 = state.dataByteBuffer.getLong(address2) * MachineState.VALUE_SIZE;
- if (address3 < 0 || address3 + MachineState.VALUE_SIZE >= dataByteBuffer.limit())
+ if (address3 < 0 || address3 + MachineState.VALUE_SIZE >= state.dataByteBuffer.limit())
throw new InvalidAddressException("Data address out of bounds");
- long value = dataByteBuffer.getLong((int) address3);
- dataByteBuffer.putLong(address1, value);
+ long value = state.dataByteBuffer.getLong((int) address3);
+ state.dataByteBuffer.putLong(address1, value);
}
},
/**
@@ -243,22 +236,21 @@ public enum OpCode {
*/
SET_IDX(0x0f, OpCodeParam.DEST_ADDR, OpCodeParam.INDIRECT_SRC_ADDR_WITH_INDEX, OpCodeParam.INDEX) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address1 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address2 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address3 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address1 = (int) args[0];
+ int address2 = (int) args[1];
+ int address3 = (int) args[2];
- long baseAddress = dataByteBuffer.getLong(address2) * MachineState.VALUE_SIZE;
- long offset = dataByteBuffer.getLong(address3) * MachineState.VALUE_SIZE;
+ long baseAddress = state.dataByteBuffer.getLong(address2) * MachineState.VALUE_SIZE;
+ long offset = state.dataByteBuffer.getLong(address3) * MachineState.VALUE_SIZE;
long newAddress = baseAddress + offset;
- if (newAddress < 0 || newAddress + MachineState.VALUE_SIZE >= dataByteBuffer.limit())
+ if (newAddress < 0 || newAddress + MachineState.VALUE_SIZE >= state.dataByteBuffer.limit())
throw new InvalidAddressException("Data address out of bounds");
- long value = dataByteBuffer.getLong((int) newAddress);
- dataByteBuffer.putLong(address1, value);
+ long value = state.dataByteBuffer.getLong((int) newAddress);
+ state.dataByteBuffer.putLong(address1, value);
}
},
/**
@@ -269,16 +261,16 @@ public enum OpCode {
*/
PSH_DAT(0x10, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = dataByteBuffer.getLong(address);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+
+ long value = state.dataByteBuffer.getLong(address);
try {
// Simulate backwards-walking stack
- int newPosition = userStackByteBuffer.position() - MachineState.VALUE_SIZE;
- userStackByteBuffer.putLong(newPosition, value);
- userStackByteBuffer.position(newPosition);
+ int newPosition = state.userStackByteBuffer.position() - MachineState.VALUE_SIZE;
+ state.userStackByteBuffer.putLong(newPosition, value);
+ state.userStackByteBuffer.position(newPosition);
} catch (IndexOutOfBoundsException | IllegalArgumentException e) {
throw new StackBoundsException("No room on user stack to push data", e);
}
@@ -292,18 +284,17 @@ public enum OpCode {
*/
POP_DAT(0x11, OpCodeParam.DEST_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
try {
- long value = userStackByteBuffer.getLong();
+ long value = state.userStackByteBuffer.getLong();
// Clear old stack entry
- userStackByteBuffer.putLong(userStackByteBuffer.position() - MachineState.VALUE_SIZE, 0L);
+ state.userStackByteBuffer.putLong(state.userStackByteBuffer.position() - MachineState.VALUE_SIZE, 0L);
// Put popped value into data address
- dataByteBuffer.putLong(address, value);
+ state.dataByteBuffer.putLong(address, value);
} catch (BufferUnderflowException e) {
throw new StackBoundsException("Empty user stack from which to pop data", e);
}
@@ -317,20 +308,19 @@ public enum OpCode {
*/
JMP_SUB(0x12, OpCodeParam.CODE_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getCodeAddress(codeByteBuffer);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
try {
// Simulate backwards-walking stack
- int newPosition = callStackByteBuffer.position() - MachineState.ADDRESS_SIZE;
- callStackByteBuffer.putInt(newPosition, codeByteBuffer.position());
- callStackByteBuffer.position(newPosition);
+ int newPosition = state.callStackByteBuffer.position() - MachineState.ADDRESS_SIZE;
+ state.callStackByteBuffer.putInt(newPosition, state.codeByteBuffer.position());
+ state.callStackByteBuffer.position(newPosition);
} catch (IndexOutOfBoundsException | IllegalArgumentException e) {
throw new StackBoundsException("No room on call stack to call subroutine", e);
}
- codeByteBuffer.position(address);
+ state.codeByteBuffer.position(address);
}
},
/**
@@ -341,15 +331,14 @@ public enum OpCode {
*/
RET_SUB(0x13) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
try {
- int returnAddress = callStackByteBuffer.getInt();
+ int returnAddress = state.callStackByteBuffer.getInt();
// Clear old stack entry
- callStackByteBuffer.putInt(callStackByteBuffer.position() - MachineState.ADDRESS_SIZE, 0);
+ state.callStackByteBuffer.putInt(state.callStackByteBuffer.position() - MachineState.ADDRESS_SIZE, 0);
- codeByteBuffer.position(returnAddress);
+ state.codeByteBuffer.position(returnAddress);
} catch (BufferUnderflowException e) {
throw new StackBoundsException("Empty call stack missing return address from subroutine", e);
}
@@ -362,18 +351,17 @@ public enum OpCode {
*/
IND_DAT(0x14, OpCodeParam.INDIRECT_DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address1 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address2 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address1 = (int) args[0];
+ int address2 = (int) args[1];
- long address3 = dataByteBuffer.getLong(address1) * MachineState.VALUE_SIZE;
+ long address3 = state.dataByteBuffer.getLong(address1) * MachineState.VALUE_SIZE;
- if (address3 < 0 || address3 + MachineState.VALUE_SIZE >= dataByteBuffer.limit())
+ if (address3 < 0 || address3 + MachineState.VALUE_SIZE >= state.dataByteBuffer.limit())
throw new InvalidAddressException("Data address out of bounds");
- long value = dataByteBuffer.getLong(address2);
- dataByteBuffer.putLong((int) address3, value);
+ long value = state.dataByteBuffer.getLong(address2);
+ state.dataByteBuffer.putLong((int) address3, value);
}
},
/**
@@ -383,22 +371,21 @@ public enum OpCode {
*/
IDX_DAT(0x15, OpCodeParam.INDIRECT_DEST_ADDR_WITH_INDEX, OpCodeParam.INDEX, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address1 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address2 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address3 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address1 = (int) args[0];
+ int address2 = (int) args[1];
+ int address3 = (int) args[2];
- long baseAddress = dataByteBuffer.getLong(address1) * MachineState.VALUE_SIZE;
- long offset = dataByteBuffer.getLong(address2) * MachineState.VALUE_SIZE;
+ long baseAddress = state.dataByteBuffer.getLong(address1) * MachineState.VALUE_SIZE;
+ long offset = state.dataByteBuffer.getLong(address2) * MachineState.VALUE_SIZE;
long newAddress = baseAddress + offset;
- if (newAddress < 0 || newAddress + MachineState.VALUE_SIZE >= dataByteBuffer.limit())
+ if (newAddress < 0 || newAddress + MachineState.VALUE_SIZE >= state.dataByteBuffer.limit())
throw new InvalidAddressException("Data address out of bounds");
- long value = dataByteBuffer.getLong(address3);
- dataByteBuffer.putLong((int) newAddress, value);
+ long value = state.dataByteBuffer.getLong(address3);
+ state.dataByteBuffer.putLong((int) newAddress, value);
}
},
/**
@@ -408,10 +395,9 @@ public enum OpCode {
*/
MOD_DAT(0x16, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
try {
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> a % b);
+ executeDataOperation(state, (a, b) -> a % b, args);
} catch (ArithmeticException e) {
throw new IllegalOperationException("Divide by zero", e);
}
@@ -426,10 +412,9 @@ public enum OpCode {
private static final long MAX_SHIFT = MachineState.VALUE_SIZE * 8;
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
// If 2nd arg is more than value size (in bits) then return 0 to simulate all bits being shifted out of existence
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> b >= MAX_SHIFT ? 0 : a << b);
+ executeDataOperation(state, (a, b) -> b >= MAX_SHIFT ? 0 : a << b, args);
}
},
/**
@@ -442,10 +427,9 @@ public enum OpCode {
private static final long MAX_SHIFT = MachineState.VALUE_SIZE * 8;
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
// If 2nd arg is more than value size (in bits) then return 0 to simulate all bits being shifted out of existence
- executeDataOperation(codeByteBuffer, dataByteBuffer, (a, b) -> b >= MAX_SHIFT ? 0 : a >>> b);
+ executeDataOperation(state, (a, b) -> b >= MAX_SHIFT ? 0 : a >>> b, args);
}
},
/**
@@ -455,11 +439,10 @@ public enum OpCode {
*/
JMP_ADR(0x1a, OpCodeParam.CODE_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getCodeAddress(codeByteBuffer);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
- codeByteBuffer.position(address);
+ state.codeByteBuffer.position(address);
}
},
/**
@@ -470,22 +453,19 @@ public enum OpCode {
*/
BZR_DAT(0x1b, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int opCodePosition = codeByteBuffer.position() - 1; // i.e. before this OpCode
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+ byte offset = (byte) args[1];
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- byte offset = Utils.getCodeOffset(codeByteBuffer);
+ int branchTarget = state.getProgramCounter() + offset;
- int branchTarget = opCodePosition + offset;
-
- if (branchTarget < 0 || branchTarget >= codeByteBuffer.limit())
+ if (branchTarget < 0 || branchTarget >= state.codeByteBuffer.limit())
throw new InvalidAddressException("branch target out of bounds");
- long value = dataByteBuffer.getLong(address);
+ long value = state.dataByteBuffer.getLong(address);
if (value == 0)
- codeByteBuffer.position(branchTarget);
+ state.codeByteBuffer.position(branchTarget);
}
},
/**
@@ -496,22 +476,19 @@ public enum OpCode {
*/
BNZ_DAT(0x1e, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int opCodePosition = codeByteBuffer.position() - 1; // i.e. before this OpCode
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+ byte offset = (byte) args[1];
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- byte offset = Utils.getCodeOffset(codeByteBuffer);
+ int branchTarget = state.getProgramCounter() + offset;
- int branchTarget = opCodePosition + offset;
-
- if (branchTarget < 0 || branchTarget >= codeByteBuffer.limit())
+ if (branchTarget < 0 || branchTarget >= state.codeByteBuffer.limit())
throw new InvalidAddressException("branch target out of bounds");
- long value = dataByteBuffer.getLong(address);
+ long value = state.dataByteBuffer.getLong(address);
if (value != 0)
- codeByteBuffer.position(branchTarget);
+ state.codeByteBuffer.position(branchTarget);
}
},
/**
@@ -522,9 +499,8 @@ public enum OpCode {
*/
BGT_DAT(0x1f, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeBranchConditional(codeByteBuffer, dataByteBuffer, state, (a, b) -> a > b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeBranchConditional(state, (a, b) -> a > b, args);
}
},
/**
@@ -535,9 +511,8 @@ public enum OpCode {
*/
BLT_DAT(0x20, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeBranchConditional(codeByteBuffer, dataByteBuffer, state, (a, b) -> a < b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeBranchConditional(state, (a, b) -> a < b, args);
}
},
/**
@@ -548,9 +523,8 @@ public enum OpCode {
*/
BGE_DAT(0x21, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeBranchConditional(codeByteBuffer, dataByteBuffer, state, (a, b) -> a >= b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeBranchConditional(state, (a, b) -> a >= b, args);
}
},
/**
@@ -561,9 +535,8 @@ public enum OpCode {
*/
BLE_DAT(0x22, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeBranchConditional(codeByteBuffer, dataByteBuffer, state, (a, b) -> a <= b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeBranchConditional(state, (a, b) -> a <= b, args);
}
},
/**
@@ -574,9 +547,8 @@ public enum OpCode {
*/
BEQ_DAT(0x23, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeBranchConditional(codeByteBuffer, dataByteBuffer, state, (a, b) -> a == b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeBranchConditional(state, (a, b) -> a == b, args);
}
},
/**
@@ -587,9 +559,8 @@ public enum OpCode {
*/
BNE_DAT(0x24, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- executeBranchConditional(codeByteBuffer, dataByteBuffer, state, (a, b) -> a != b);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ executeBranchConditional(state, (a, b) -> a != b, args);
}
},
/**
@@ -600,13 +571,13 @@ public enum OpCode {
*/
SLP_DAT(0x25, OpCodeParam.BLOCK_HEIGHT) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getCodeAddress(codeByteBuffer);
- long value = codeByteBuffer.getLong(address);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
- state.sleepUntilHeight = (int) value;
- state.isSleeping = true;
+ long value = state.codeByteBuffer.getLong(address);
+
+ state.setSleepUntilHeight((int) value);
+ state.setIsSleeping(true);
}
},
/**
@@ -616,13 +587,13 @@ public enum OpCode {
*/
FIZ_DAT(0x26, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = dataByteBuffer.getLong(address);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+
+ long value = state.dataByteBuffer.getLong(address);
if (value == 0)
- state.isFinished = true;
+ state.setIsFinished(true);
}
},
/**
@@ -632,15 +603,14 @@ public enum OpCode {
*/
STZ_DAT(0x27, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = dataByteBuffer.getLong(address);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
+
+ long value = state.dataByteBuffer.getLong(address);
if (value == 0) {
- state.programCounter = state.onStopAddress;
- codeByteBuffer.position(state.onStopAddress);
- state.isStopped = true;
+ state.codeByteBuffer.position(state.getOnStopAddress());
+ state.setIsStopped(true);
}
}
},
@@ -651,9 +621,8 @@ public enum OpCode {
*/
FIN_IMD(0x28) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- state.isFinished = true;
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ state.setIsFinished(true);
}
},
/**
@@ -663,9 +632,8 @@ public enum OpCode {
*/
STP_IMD(0x29) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) {
- state.isStopped = true;
+ public void executeWithParams(MachineState state, Object... args) {
+ state.setIsStopped(true);
}
},
/**
@@ -675,10 +643,9 @@ public enum OpCode {
*/
SLP_IMD(0x2a) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) {
- state.sleepUntilHeight = state.currentBlockHeight + 1;
- state.isSleeping = true;
+ public void executeWithParams(MachineState state, Object... args) {
+ state.setSleepUntilHeight(state.getCurrentBlockHeight() + 1);
+ state.setIsSleeping(true);
}
},
/**
@@ -688,11 +655,10 @@ public enum OpCode {
*/
ERR_ADR(0x2b, OpCodeParam.CODE_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- int address = Utils.getCodeAddress(codeByteBuffer);
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ int address = (int) args[0];
- state.onErrorAddress = address;
+ state.setOnErrorAddress(address);
}
},
/**
@@ -703,9 +669,8 @@ public enum OpCode {
*/
SET_PCS(0x30) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) {
- state.onStopAddress = codeByteBuffer.position();
+ public void executeWithParams(MachineState state, Object... args) {
+ state.setOnStopAddress(state.codeByteBuffer.position());
}
},
/**
@@ -715,9 +680,9 @@ public enum OpCode {
*/
EXT_FUN(0x32, OpCodeParam.FUNC) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- short rawFunctionCode = codeByteBuffer.getShort();
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ short rawFunctionCode = (short) args[0];
+
FunctionCode functionCode = FunctionCode.valueOf(rawFunctionCode);
if (functionCode == null)
@@ -727,7 +692,7 @@ public enum OpCode {
FunctionData functionData = new FunctionData(false);
- executeFunction(codeByteBuffer, functionCode, functionData, state, rawFunctionCode);
+ functionCode.execute(functionData, state, rawFunctionCode);
}
},
/**
@@ -737,9 +702,10 @@ public enum OpCode {
*/
EXT_FUN_DAT(0x33, OpCodeParam.FUNC, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- short rawFunctionCode = codeByteBuffer.getShort();
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ short rawFunctionCode = (short) args[0];
+ int address = (int) args[1];
+
FunctionCode functionCode = FunctionCode.valueOf(rawFunctionCode);
if (functionCode == null)
@@ -747,12 +713,11 @@ public enum OpCode {
functionCode.preExecuteCheck(1, false, state, rawFunctionCode);
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- long value = dataByteBuffer.getLong(address);
+ long value = state.dataByteBuffer.getLong(address);
FunctionData functionData = new FunctionData(value, false);
- executeFunction(codeByteBuffer, functionCode, functionData, state, rawFunctionCode);
+ functionCode.execute(functionData, state, rawFunctionCode);
}
},
/**
@@ -762,9 +727,11 @@ public enum OpCode {
*/
EXT_FUN_DAT_2(0x34, OpCodeParam.FUNC, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- short rawFunctionCode = codeByteBuffer.getShort();
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ short rawFunctionCode = (short) args[0];
+ int address1 = (int) args[1];
+ int address2 = (int) args[2];
+
FunctionCode functionCode = FunctionCode.valueOf(rawFunctionCode);
if (functionCode == null)
@@ -772,15 +739,12 @@ public enum OpCode {
functionCode.preExecuteCheck(2, false, state, rawFunctionCode);
- int address1 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address2 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
-
- long value1 = dataByteBuffer.getLong(address1);
- long value2 = dataByteBuffer.getLong(address2);
+ long value1 = state.dataByteBuffer.getLong(address1);
+ long value2 = state.dataByteBuffer.getLong(address2);
FunctionData functionData = new FunctionData(value1, value2, false);
- executeFunction(codeByteBuffer, functionCode, functionData, state, rawFunctionCode);
+ functionCode.execute(functionData, state, rawFunctionCode);
}
},
/**
@@ -790,9 +754,10 @@ public enum OpCode {
*/
EXT_FUN_RET(0x35, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- short rawFunctionCode = codeByteBuffer.getShort();
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ short rawFunctionCode = (short) args[0];
+ int address = (int) args[1];
+
FunctionCode functionCode = FunctionCode.valueOf(rawFunctionCode);
if (functionCode == null)
@@ -800,16 +765,14 @@ public enum OpCode {
functionCode.preExecuteCheck(0, true, state, rawFunctionCode);
- int address = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
-
FunctionData functionData = new FunctionData(true);
- executeFunction(codeByteBuffer, functionCode, functionData, state, rawFunctionCode);
+ functionCode.execute(functionData, state, rawFunctionCode);
if (functionData.returnValue == null)
throw new ExecutionException("Function failed to return a value as expected of EXT_FUN_RET");
- dataByteBuffer.putLong(address, functionData.returnValue);
+ state.dataByteBuffer.putLong(address, functionData.returnValue);
}
},
/**
@@ -819,9 +782,11 @@ public enum OpCode {
*/
EXT_FUN_RET_DAT(0x36, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- short rawFunctionCode = codeByteBuffer.getShort();
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ short rawFunctionCode = (short) args[0];
+ int address1 = (int) args[1];
+ int address2 = (int) args[2];
+
FunctionCode functionCode = FunctionCode.valueOf(rawFunctionCode);
if (functionCode == null)
@@ -829,19 +794,16 @@ public enum OpCode {
functionCode.preExecuteCheck(1, true, state, rawFunctionCode);
- int address1 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address2 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
-
- long value = dataByteBuffer.getLong(address2);
+ long value = state.dataByteBuffer.getLong(address2);
FunctionData functionData = new FunctionData(value, true);
- executeFunction(codeByteBuffer, functionCode, functionData, state, rawFunctionCode);
+ functionCode.execute(functionData, state, rawFunctionCode);
if (functionData.returnValue == null)
throw new ExecutionException("Function failed to return a value as expected of EXT_FUN_RET_DAT");
- dataByteBuffer.putLong(address1, functionData.returnValue);
+ state.dataByteBuffer.putLong(address1, functionData.returnValue);
}
},
/**
@@ -851,9 +813,12 @@ public enum OpCode {
*/
EXT_FUN_RET_DAT_2(0x37, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR) {
@Override
- public void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException {
- short rawFunctionCode = codeByteBuffer.getShort();
+ public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
+ short rawFunctionCode = (short) args[0];
+ int address1 = (int) args[1];
+ int address2 = (int) args[2];
+ int address3 = (int) args[3];
+
FunctionCode functionCode = FunctionCode.valueOf(rawFunctionCode);
if (functionCode == null)
@@ -862,21 +827,17 @@ public enum OpCode {
functionCode.preExecuteCheck(2, true, state, rawFunctionCode);
- int address1 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address2 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
- int address3 = Utils.getDataAddress(codeByteBuffer, dataByteBuffer);
-
- long value1 = dataByteBuffer.getLong(address2);
- long value2 = dataByteBuffer.getLong(address3);
+ long value1 = state.dataByteBuffer.getLong(address2);
+ long value2 = state.dataByteBuffer.getLong(address3);
FunctionData functionData = new FunctionData(value1, value2, true);
- executeFunction(codeByteBuffer, functionCode, functionData, state, rawFunctionCode);
+ functionCode.execute(functionData, state, rawFunctionCode);
if (functionData.returnValue == null)
throw new ExecutionException("Function failed to return a value as expected of EXT_FUN_RET_DAT_2");
- dataByteBuffer.putLong(address1, functionData.returnValue);
+ state.dataByteBuffer.putLong(address1, functionData.returnValue);
}
};
@@ -896,26 +857,32 @@ public enum OpCode {
}
/**
- * Execute OpCode
+ * Execute OpCode with args fetched from code bytes
*
- * Assumes codeByteBuffer.position() is already placed immediately after opcode.
+ * Assumes codeByteBuffer.position() is already placed immediately after opcode and params.
+ * state.getProgramCounter() is available to return position immediately before opcode and params.
*
- * Updates codeByteBuffer.position() as arguments are fetched, so caller should update state.programCounter using
- * codeByteBuffer.position() on return.
+ * OpCode execution can modify codeByteBuffer.position() in cases like jumps, branches, etc.
*
* Can also modify userStackByteBuffer and various fields of state.
*
* Throws a subclass of ExecutionException on error, e.g. InvalidAddressException.
*
- * @param codeByteBuffer
- * @param dataByteBuffer
- * @param userStackByteBuffer
- * @param callStackByteBuffer
* @param state
+ * @param args
+ *
* @throws ExecutionException
*/
- public abstract void execute(ByteBuffer codeByteBuffer, ByteBuffer dataByteBuffer, ByteBuffer userStackByteBuffer, ByteBuffer callStackByteBuffer,
- MachineState state) throws ExecutionException;
+ public abstract void executeWithParams(MachineState state, Object... args) throws ExecutionException;
+
+ public void execute(MachineState state) throws ExecutionException {
+ List