#!/usr/bin/awk -f
# Constants
BEGIN {
IMAGE_SIZE = 524288 # Amount of simulated RAM
DATA_DEPTH = 8192 # Depth of data stack
ADDRESS_DEPTH = 32768 # Depth of the stacks
# Initialize stacks
data_sp = 0
addr_sp = 0
# VM state
ip = 0
# Opcode definitions
OP_NOP = 0
OP_LIT = 1
OP_DUP = 2
OP_DROP = 3
OP_SWAP = 4
OP_PUSH = 5
OP_POP = 6
OP_JUMP = 7
OP_CALL = 8
OP_CCALL = 9
OP_RETURN = 10
OP_EQ = 11
OP_NEQ = 12
OP_LT = 13
OP_GT = 14
OP_FETCH = 15
OP_STORE = 16
OP_ADD = 17
OP_SUB = 18
OP_MUL = 19
OP_DIVMOD = 20
OP_AND = 21
OP_OR = 22
OP_XOR = 23
OP_SHIFT = 24
OP_ZERO_EXIT = 25
OP_HALT = 26
OP_IE = 27
OP_IQ = 28
OP_II = 29
}
# Stack operations
function stack_push(stack_name, value) {
if (stack_name == "data") {
data_sp++
data_stack[data_sp] = value
} else if (stack_name == "addr") {
addr_sp++
addr_stack[addr_sp] = value
}
}
function stack_pop(stack_name) {
if (stack_name == "data") {
if (data_sp > 0) {
value = data_stack[data_sp]
data_sp--
return value
}
} else if (stack_name == "addr") {
if (addr_sp > 0) {
value = addr_stack[addr_sp]
addr_sp--
return value
}
}
return 0
}
function stack_tos(stack_name) {
if (stack_name == "data" && data_sp > 0) {
return data_stack[data_sp]
}
return 0
}
function stack_nos(stack_name) {
if (stack_name == "data" && data_sp > 1) {
return data_stack[data_sp - 1]
}
return 0
}
# Bitwise operation implementations
function bitwise_and(x, y, i, result, a, b) {
result = 0
for (i = 0; i < 32; i++) {
a = int(x / (2 ^ i)) % 2
b = int(y / (2 ^ i)) % 2
if (a == 1 && b == 1)
result += 2 ^ i
}
return result
}
function bitwise_or(x, y, i, result, a, b) {
result = 0
for (i = 0; i < 32; i++) {
a = int(x / (2 ^ i)) % 2
b = int(y / (2 ^ i)) % 2
if (a == 1 || b == 1)
result += 2 ^ i
}
return result
}
function bitwise_xor(x, y, i, result, a, b) {
result = 0
for (i = 0; i < 32; i++) {
a = int(x / (2 ^ i)) % 2
b = int(y / (2 ^ i)) % 2
if (a != b)
result += 2 ^ i
}
return result
}
function lshift(x, n) {
return int(x * (2 ^ n))
}
function rshift(x, n) {
return int(x / (2 ^ n))
}
# VM instruction implementations
function process_opcode(opcode) {
if (opcode == OP_NOP) {
return
}
else if (opcode == OP_LIT) {
ip++
stack_push("data", image[ip])
}
else if (opcode == OP_DUP) {
stack_push("data", stack_tos("data"))
}
else if (opcode == OP_DROP) {
stack_pop("data")
}
else if (opcode == OP_SWAP) {
temp = stack_pop("data")
temp2 = stack_pop("data")
stack_push("data", temp)
stack_push("data", temp2)
}
else if (opcode == OP_PUSH) {
stack_push("addr", stack_pop("data"))
}
else if (opcode == OP_POP) {
stack_push("data", stack_pop("addr"))
}
else if (opcode == OP_JUMP) {
ip = stack_pop("data") - 1
}
else if (opcode == OP_CALL) {
stack_push("addr", ip)
ip = stack_pop("data") - 1
}
else if (opcode == OP_CCALL) {
a = stack_pop("data")
b = stack_pop("data")
if (b != 0) {
stack_push("addr", ip)
ip = a - 1
}
}
else if (opcode == OP_RETURN) {
ip = stack_pop("addr")
}
else if (opcode == OP_EQ) {
a = stack_pop("data")
b = stack_pop("data")
stack_push("data", (b == a) ? -1 : 0)
}
else if (opcode == OP_NEQ) {
a = stack_pop("data")
b = stack_pop("data")
stack_push("data", (b != a) ? -1 : 0)
}
else if (opcode == OP_LT) {
a = stack_pop("data")
b = stack_pop("data")
stack_push("data", (b < a) ? -1 : 0)
}
else if (opcode == OP_GT) {
a = stack_pop("data")
b = stack_pop("data")
stack_push("data", (b > a) ? -1 : 0)
}
else if (opcode == OP_FETCH) {
x = stack_pop("data")
if (x == -1)
stack_push("data", data_sp)
else if (x == -2)
stack_push("data", addr_sp)
else if (x == -3)
stack_push("data", IMAGE_SIZE)
else if (x == -4)
stack_push("data", -2147483648)
else if (x == -5)
stack_push("data", 2147483647)
else
stack_push("data", image[x])
}
else if (opcode == OP_STORE) {
addr = stack_pop("data")
value = stack_pop("data")
image[addr] = value
}
else if (opcode == OP_ADD) {
x = stack_pop("data")
y = stack_pop("data")
stack_push("data", x + y)
}
else if (opcode == OP_SUB) {
x = stack_pop("data")
y = stack_pop("data")
stack_push("data", y - x)
}
else if (opcode == OP_MUL) {
x = stack_pop("data")
y = stack_pop("data")
stack_push("data", y * x)
}
else if (opcode == OP_DIVMOD) {
b = stack_pop("data")
a = stack_pop("data")
if (b == 0) {
ip = 0
data_sp = 0
addr_sp = 0
} else {
x = abs(b)
y = abs(a)
q = int(y / x)
r = y % x
if (a < 0 && b < 0)
r = r * -1
if (a > 0 && b < 0)
q = q * -1
if (a < 0 && b > 0) {
r = r * -1
q = q * -1
}
stack_push("data", r)
stack_push("data", q)
}
}
else if (opcode == OP_AND) {
x = stack_pop("data")
y = stack_pop("data")
stack_push("data", bitwise_and(x, y))
}
else if (opcode == OP_OR) {
x = stack_pop("data")
y = stack_pop("data")
stack_push("data", bitwise_or(x, y))
}
else if (opcode == OP_XOR) {
x = stack_pop("data")
y = stack_pop("data")
stack_push("data", bitwise_xor(x, y))
}
else if (opcode == OP_SHIFT) {
x = stack_pop("data")
y = stack_pop("data")
if (x < 0)
stack_push("data", lshift(y, -x))
else
stack_push("data", rshift(y, x))
}
else if (opcode == OP_ZERO_EXIT) {
if (stack_tos("data") == 0) {
stack_pop("data")
ip = stack_pop("addr")
}
}
else if (opcode == OP_HALT) {
ip = IMAGE_SIZE
}
check_stack()
}
# Helper functions
function abs(x) {
return x < 0 ? -x : x
}
function check_stack() {
if (data_sp < 0 || addr_sp < 0 ||
data_sp > DATA_DEPTH || addr_sp > ADDRESS_DEPTH) {
ip = 0
data_sp = 0
addr_sp = 0
}
}
function process_packed_opcodes(packed) {
ops[0] = bitwise_and(packed, 255)
ops[1] = bitwise_and(rshift(packed, 8), 255)
ops[2] = bitwise_and(rshift(packed, 16), 255)
ops[3] = bitwise_and(rshift(packed, 24), 255)
for (i = 0; i < 4; i++) {
if (ops[i] != 0) {
process_opcode(ops[i])
}
}
}
# Main execution function
function execute(offset) {
addr_sp = 1
ip = offset
while (ip < IMAGE_SIZE) {
opcode = image[ip]
process_packed_opcodes(opcode)
if (addr_sp == 0)
ip = IMAGE_SIZE
ip++
}
}
# String handling functions
function string_inject(str, buffer, i, len) {
len = length(str)
for (i = 1; i <= len; i++) {
image[buffer + i - 1] = ord(substr(str, i, 1))
image[buffer + i] = 0
}
}
function string_extract(at, str, i) {
str = ""
i = at
while (image[i] != 0) {
str = str chr(image[i])
i++
}
return str
}
# Initialize VM
BEGIN {
prepare_vm()
}
function prepare_vm() {
ip = 0
data_sp = 0
addr_sp = 0
}