about summary refs log blame commit diff stats
path: root/awk/retro/vm.awk
blob: cd894c5a5b4744f79119ccbff9a027ef13ffdd16 (plain) (tree)











































































































































































































































































































































































                                                          
#!/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
}