~maelkum/viuavm

241b755da0ee740d9a08c6423d8094bc4eb463ab — Marek Marecki 4 months ago 4675c6b
Add AA, AD, and PTR instructions

They will be used to create pointers and allocate memory.

AA - Allocate Automatic

    aa $ptr, $size, <align>

Allocates memory with automatic duration (ie, on stack) and returns
pointer to the allocated memory area. The VM automatically finds a
suitable address to allocate the memory, including requesting a new page
if necessary.

The address parameter (2nd one) is used to specify the requested size.

The offset parameter (3rd one) is used to specify alignment. Alignment
of zero means the most stringent alignment is chosen.

AD - Allocate Dynamic

    ad $ptr, $size, <align>

Allocates memory with dynamic duration (ie, on heap) and returns pointer
to the allocated memory area. The memory is reclaimed automatically
unless the ownership of the pointer is passed to the caller.

The parameters' meaning is the same as for AA.

PTR - PoinTeR

    ptr $ptr, $area, <offset>

Create a pointer to an inside of a memory area allocated by AA or AD.
This makes it easier to address subobjects. However, the since the
offset is only 16 bits wide, the instruction is only able to address the
first 16 KiB of memory in the $area.

ADDIU and ADD instructions can be used to increase the address (the VM
will automatically enforce bounds check to ensure that memory outside
the original area cannot be accessed this way). To facilitate this
analysis put the greedy prefix on PTR instruction and use the arithmetic
instruction immediately afterwards:

    g.ptr $ptr, $area, 0xffff
    addiu $ptr, $ptr, 0x42

Otherwise the pointer arithmetic will be rejected.
M new/include/viua/arch/ins.h => new/include/viua/arch/ins.h +18 -0
@@ 479,6 479,24 @@ struct LM : Instruction {
    LM(viua::arch::ops::M i) : instruction{i}
    {}
};
struct AA : Instruction {
    viua::arch::ops::M instruction;

    AA(viua::arch::ops::M i) : instruction{i}
    {}
};
struct AD : Instruction {
    viua::arch::ops::M instruction;

    AD(viua::arch::ops::M i) : instruction{i}
    {}
};
struct PTR : Instruction {
    viua::arch::ops::M instruction;

    PTR(viua::arch::ops::M i) : instruction{i}
    {}
};
}  // namespace viua::arch::ins

#endif

M new/include/viua/arch/ops.h => new/include/viua/arch/ops.h +8 -2
@@ 306,8 306,11 @@ enum class OPCODE : opcode_type {
    DIVI  = (FORMAT_R | 0x0004),
    DIVIU = (FORMAT_R | 0x0004 | UNSIGNED),

    SM = (FORMAT_M | 0x0001),
    LM = (FORMAT_M | 0x0002),
    SM = (FORMAT_M | 0x0001),   /* Store Memory */
    LM = (FORMAT_M | 0x0002),   /* Load Memory */
    AA = (FORMAT_M | 0x0003),   /* Allocate Automatic */
    AD = (FORMAT_M | 0x0004),   /* Allocate Dynamic */
    PTR = (FORMAT_M | 0x0005),  /* PoinTeR */
};
auto to_string(opcode_type const) -> std::string;
auto parse_opcode(std::string_view) -> opcode_type;


@@ 395,6 398,9 @@ enum class OPCODE_N : opcode_type {
enum class OPCODE_M : opcode_type {
    Make_entry(SM),
    Make_entry(LM),
    Make_entry(AA),
    Make_entry(AD),
    Make_entry(PTR),
};
#undef Make_entry
}  // namespace viua::arch::ops

M new/include/viua/vm/ins.h => new/include/viua/vm/ins.h +3 -0
@@ 116,6 116,9 @@ Work_instruction(SELF);

Work_instruction(SM);
Work_instruction(LM);
Work_instruction(AA);
Work_instruction(AD);
Work_instruction(PTR);

constexpr auto VIUA_TRACE_CYCLES = true;
auto execute(viua::vm::Stack&, viua::arch::instruction_type const* const)

M new/src/arch/ops.cpp => new/src/arch/ops.cpp +12 -0
@@ 430,6 430,12 @@ auto to_string(opcode_type const raw) -> std::string
        return greedy + "sm";
    case OPCODE::LM:
        return greedy + "lm";
    case OPCODE::AA:
        return greedy + "aa";
    case OPCODE::AD:
        return greedy + "ad";
    case OPCODE::PTR:
        return greedy + "ptr";
    }

    return "<unknown>";


@@ 576,6 582,12 @@ auto parse_opcode(std::string_view const raw) -> opcode_type
        return (op | static_cast<opcode_type>(OPCODE::SM));
    } else if (sv == "lm") {
        return (op | static_cast<opcode_type>(OPCODE::LM));
    } else if (sv == "aa") {
        return (op | static_cast<opcode_type>(OPCODE::AA));
    } else if (sv == "ad") {
        return (op | static_cast<opcode_type>(OPCODE::AD));
    } else if (sv == "ptr") {
        return (op | static_cast<opcode_type>(OPCODE::PTR));
    } else {
        throw std::invalid_argument{"viua::arch::ops::parse_opcode: "
                                    + std::string{raw}};

M new/src/vm/ins.cpp => new/src/vm/ins.cpp +12 -0
@@ 211,6 211,9 @@ auto execute(viua::vm::Stack& stack,
#define Work(OP) case OPCODE_M::OP: execute(OP{instruction}, stack, ip); break
            Work(SM);
            Work(LM);
            Work(AA);
            Work(AD);
            Work(PTR);
#undef Work
        }
        break;


@@ 2091,4 2094,13 @@ auto execute(LM const op, Stack& stack, ip_type const ip) -> void
            throw abort_execution{ip, "invalid unit in memory instruction: " + std::to_string(unit)};
    }
}
auto execute(AA const, Stack&, ip_type const) -> void
{
}
auto execute(AD const, Stack&, ip_type const) -> void
{
}
auto execute(PTR const, Stack&, ip_type const) -> void
{
}
}  // namespace viua::vm::ins