Welcome to Mizu’s Documentorial!#
This documentation page is designed less like a direct reference and more like a tutorial.
If you would instead prefer a reference… full generated documentation can be found here.
Programs in Mizu are represented by an array of Opcodes.
-
struct opcode
Type which holds an instruction and (upto) 3 registers for it to act upon.
Note
Since instruction_t is a pointer, this struct will have different sizes on different machines. Thus Mizu binaries are only compatible with machines of the same pointer size and endianness.
Public Functions
-
inline opcode &set_immediate(const uint32_t value)#
Replaces a and b with a u32 immediate value
- Returns:
opcode& this
-
inline opcode &set_immediate_signed(const int32_t value)#
Replaces a and b with a i32 immediate value
- Returns:
opcode& this
-
inline opcode &set_branch_immediate(const int16_t value)#
Replaces b with a i16 immediate value (Used to determine branch offsets)
- Returns:
opcode& this
-
inline opcode &set_immediate_f32(const float value)#
Replaces a and b with a f32 immediate value
- Returns:
opcode& this
-
inline opcode &set_lower_immediate_f64(const double value)#
Replaces a and b with the lower half of an f64 immediate value
- Parameters:
value – the full f64 value
- Returns:
opcode& this
-
inline opcode &set_upper_immediate_f64(const double value)#
Replaces a and b with the upper half of an f64 immediate value
- Parameters:
value – the full f64 value
- Returns:
opcode& this
-
inline opcode &set_immediate(const uint32_t value)#
-
using mizu::instruction_t = void *(*)(struct opcode *pc, uint64_t *registers, struct registers_and_stack *env, uint8_t *sp)
Function pointer type representing the interface every instruction is expected to have
A simple program that loads a number and prints it out might look something like:
#define MIZU_IMPLEMENTATION // Needs to be included in exactly one source (.cpp) file
#include <mizu/instructions.hpp>
const static opcode program[] = { // Const static so that the code winds up in .bss
opcode{load_immediate, registers::t(0)}.set_immediate(40),
opcode{debug_print, 0, registers::t(0)},
opcode{halt}, // Need to explicitly mark the end of execution
};
This code looks up t0 (first temporary) register using Mizu’s register utilities.
-
namespace registers
x0 (zero) is always zero
x1-x20 (t0-t19) are temporary registers which are expected to be saved by the caller if necessary
x21 (ra) is the return address (callee saved)
x22-x256 (a0-a234) are the argument registers (callee saved)
Note
x22/a0 and x23/a1 are the canonical return registers
Functions
-
constexpr reg_t x(std::size_t i)
Generic register lookup
- Parameters:
i – The register’s index
- Returns:
constexpr reg_t associated value to store in an opcode
-
constexpr reg_t t(std::size_t i)
Temporary register lookup
- Parameters:
i – The temporary register’s index
- Returns:
constexpr reg_t associated value to store in an opcode
-
constexpr reg_t a(std::size_t i)
Argument register lookup
- Parameters:
i – The argument register’s index
- Returns:
constexpr reg_t associated value to store in an opcode
Unfortunately these “registers” must be stored in memory, thus before mizu can run a program it must allocate memory for the registers (and the stack).
This memory is cloned for each thread of execution.
Note
All Mizu registers are unsigned 64 bit integers (u64) regardless of host machine.
-
struct registers_and_stack
Type representing holding the registers and stack space for a Mizu program or thread.
Public Functions
Public Members
-
fp::array<uint64_t, memory_size> memory#
Memory used to store the stack and registers
Note
8kB in size by default, MIZU_STACK_SIZE is a tweakble cmake property
-
uint8_t *stack_boundary#
Pointer to the boundary between the stack and the registers
-
uint8_t *stack_bottom#
Pointer to the start (bottom/last byte of) the stack
Note
In Mizu the stack pointer counts down from the last byte of the memory until it hits the stack boundary
-
fp::array<uint64_t, memory_size> memory#
- group Setup_environment
Functions
-
inline void setup_environment(registers_and_stack &env, const opcode *program_start = nullptr, const opcode *program_end = nullptr)#
Configures a new Mizu environment
Note
sets register x0 to zero
- Parameters:
env – the environment to configure
program_start – pointer to the start of the program (defaults to null)
program_end – pointer to the end of the program (defaults to null)
-
inline void setup_environment(registers_and_stack &env, fp::view<const opcode> program)#
Configures a new Mizu environment
Note
sets register x0 to zero
- Parameters:
env – the environment to configure
program – view representing the whole program
-
void fill_stack_bottom(registers_and_stack &env, fp::view<const std::byte> binary)#
Copies the provided
binarydata into the bottom of an environment’s stack.- Parameters:
env – The enviornment to copy data into
binary – The binary data to fill the bottom of its stack with
-
inline void setup_environment(registers_and_stack &env, const opcode *program_start = nullptr, const opcode *program_end = nullptr)#
Once an environment has been setup a program can be started in that environment using:
-
MIZU_START_FROM_ENVIRONMENT(program, env)#
Starts executing the provide program in the provided environment
- Parameters:
program – The program to execute
env – The environment to execute
programin
The following code provides a demonstration of the program initialization process:
{
registers_and_stack environment = {};
setup_environment(environment); // Ensures the pointers within the environment are properly configured
MIZU_START_FROM_ENVIRONMENT(program, env);
}
Instructions#
New instructions (almost) always follow this template:
void* <name> (opcode* pc, uint64_t* registers, registers_and_stack* env, uint8_t* sp) {
// Instruction code goes here
MIZU_NEXT();
}
MIZU_REGISTER_INSTRUCTION(<name>); // Ensures the serialization system is aware of the instruction
The program counter (pc) variable points to the current opcode and provides its out, a, and p parameters which can be used to lookup the relevant register in the registers variable.
The environment includes the memory (registers and stack) as well as pointers to the stack’s start and end, while the stack pointer (sp) variable marks the current top of the stack.
The code to implement the instruction should be written before the MIZU_NEXT macro, which is responsible for handling the flow of control between instructions.
The parameters for the following instructions are described in terms of their opcodes:
out,a, andball represent the relevant members of an opcodebcan sometimes take an explicitly signed value which can be set using the.set_branch_immediate()function.immediaterepresents a value taking the space of bothaandbset using the.set_immediate()function.signed immediaterepresents a value taking the space of bothaandbset using the.set_signed_immediate()function.float immediaterepresents a floating point value taking the space of bothaandbset using.set_immediate_f32().
-
namespace mizu
-
namespace debug
Functions
-
void *breakpoint(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Noop which can be used to add breakpoints into code
-
namespace instructions
-
void *breakpoint(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
-
namespace debug
-
namespace mizu
Functions
-
constexpr uint32_t label2immediate(const fp_string_view label)
Converts a string label to an immediate value
Note
Only the first 4 characters of the label are relevant.
- Parameters:
label – string_view to be converted
- Returns:
constexpr uint32_t the immediate
-
constexpr uint32_t label2immediate(const fp_string label)
Converts a string label to an immediate value
Note
Only the first 4 characters of the label are relevant.
- Parameters:
label – string to be converted
- Returns:
constexpr uint32_t the immediate
-
void *label(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Noop which marks a label that can be found using mizu::find_label and then jumped to using mizu::jump_to
Note
mizu::label2int can convert a string into an immediate for this function
- Parameters:
immediate – Integer label value
-
void *find_label(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Finds the provided label and stores a pointer to it in
outNote
Unlike every other assembly this is a runtime function, time is spent scanning the program to find the label. It is this recommended to cluster these instructions near the beginning of the program where they won’t be executed multiple times.
Note
This function first searches below it in the program then searches above it if the label can’t be found. The closest matching label following these rules will be found if there is any ambiguity.
- Parameters:
out – register to store the label pointer in
immediate – the label to search for
-
void *halt(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Ends execution of the program or thread.
-
void *debug_print(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Prints the value stored in a register in several formats
- Parameters:
a – the register to print the value of
-
void *debug_print_binary(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Prints the value stored in a register in several formats including binary
- Parameters:
a – the register to print the value of
-
void *load_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Stores an immediate value into a register
Note
Since immediate are only 32bit numbers this function sets the bottom 32 bits of our 64 bit registers.
- Parameters:
out – the register to update
immediate – the value to store in
out
-
void *load_upper_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Stores an immediate value into a register shifting it so that its content fills the upper 32bits.
Warning
The load immediate instruction overwrites the entire register, thus it should be called before load_upper_immediate!
- Parameters:
out – the register to update
immediate – the value to store in
out
-
void *convert_to_u64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts a register to a 64 bit integer.
- Parameters:
out – register to store the result in
a – register whose value to convert
-
void *convert_to_u32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts a register to a 32 bit integer.
- Parameters:
out – register to store the result in
a – register whose value to convert
-
void *convert_to_u16(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts a register to a 16 bit integer.
- Parameters:
out – register to store the result in
a – register whose value to convert
-
void *convert_to_u8(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts a register to an 8 bit integer.
- Parameters:
out – register to store the result in
a – register whose value to convert
-
void *stack_load_u64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Loads a 64 bit integer from the stack
- Parameters:
out – register to store the result in
a – register storing an offset to the current stack pointer (defaults to zero bytes)
-
void *stack_store_u64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Copies a 64 bit integer from a register to the stack.
- Parameters:
out – register to store another copy in
a – register storing the value to copy
b – register storing an offset to the current stack pointer (defaults to zero bytes)
-
void *stack_load_u32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Loads a 32 bit integer from the stack
- Parameters:
out – register to store the result in
a – register storing an offset to the current stack pointer (defaults to zero bytes)
-
void *stack_store_u32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Copies a 32 bit integer from a register to the stack.
- Parameters:
out – register to store another copy in
a – register storing the value to copy
b – register storing an offset to the current stack pointer (defaults to zero bytes)
-
void *stack_load_u16(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Loads a 16 bit integer from the stack
- Parameters:
out – register to store the result in
a – register storing an offset to the current stack pointer (defaults to zero bytes)
-
void *stack_store_u16(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Copies a 16 bit integer from a register to the stack.
- Parameters:
out – register to store another copy in
a – register storing the value to copy
b – register storing an offset to the current stack pointer (defaults to zero bytes)
-
void *stack_load_u8(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Loads an 8 bit integer from the stack
- Parameters:
out – register to store the result in
a – register storing an offset to the current stack pointer (defaults to zero bytes)
-
void *stack_store_u8(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Copies a 8 bit integer from a register to the stack.
- Parameters:
out – register to store another copy in
a – register storing the value to copy
b – register storing an offset to the current stack pointer (defaults to zero bytes)
-
void *stack_push(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Subtracts a value from the stack pointer. In other words reserves some additional memory on the stack.
- Parameters:
a – register storing how many bytes to reserve
-
void *stack_push_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Subtracts a value from the stack pointer. In other words reserves some additional memory on the stack.
- Parameters:
immediate – how many bytes to reserve
-
void *stack_pop(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds a value to stack pointer. In other words releases reserved memory on the stack.
- Parameters:
a – register storing how many bytes to release
-
void *stack_pop_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds a value to stack pointer. In other words releases reserved memory on the stack.
- Parameters:
immediate – how many bytes to release
-
void *offset_of_stack_bottom(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Returns the offset needed to load/store to the bottom of the stack
- Parameters:
out – register to store the calculated offset in
a – register storing a signed offset relative to the bottom of the stack
-
void *jump_relative(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Moves the program counter by an offset. If the offset is zero this instruction is executed again. If it is one the next instruction is executed as usual. If it is negative a previous instruction is executed.
Note
ais interpreted as a signed integer, allowing for negative jumps- Parameters:
out – register to store the address of the instruction that should be executed next.
a – register storing how many instructions to jump
-
void *jump_relative_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Moves the program counter by an offset. If the offset is zero this instruction is executed again. If it is one the next instruction is executed as usual. If it is negative a previous instruction is executed.
Note
immediateis interpreted as a signed integer, allowing for negative jumps- Parameters:
out – register to store the address of the instruction that should be executed next.
immediate – how many instructions to jump
-
void *jump_to(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Sets the program counter to a value (usually the output of another jump)
- Parameters:
out – register to store the address of the instruction that should be executed next.
a – register storing the address of the instruction to jump to.
-
void *branch_relative(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Moves the program counter by an offset similar to a jump, however only does so if the condition register is not zero
Note
bis interpreted as a signed integer, allowing for negative jumps- Parameters:
out – register to store the address of the instruction that should be executed next.
a – register storing a condition, zero indicates no jump while any other number indicates that a jump should occur
b – register storing how many instructions to jump
-
void *branch_relative_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Moves the program counter by an offset similar to a jump, however only does so if the condition register is not zero
Note
bis interpreted as a signed integer, allowing for negative jumps- Parameters:
out – register to store the address of the instruction that should be executed next.
a – register storing a condition, zero indicates no jump while any other number indicates that a jump should occur
b – (branch immediate) how many instructions to jump
-
void *branch_to(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Sets the program counter to a value (usually the output of another jump), however only does so if the condition register is not zero
- Parameters:
out – register to store the address of the instruction that should be executed next.
a – register storing a condition, zero indicates no jump while any other number indicates that a jump should occur
b – register storing the address of the instruction to jump to.
-
void *set_if_equal(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if two registers are equal
- Parameters:
out – register to be set to one if
a==bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_not_equal(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if two registers are not equal
- Parameters:
out – register to be set to one if
a!=bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_less(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a register is less than another
- Parameters:
out – register to be set to one if
a<bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_less_signed(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a register is less than another
Note
Both
aandbare treated as being signed- Parameters:
out – register to be set to one if
a==bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_greater_equal(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a register is greater or equal to another
- Parameters:
out – register to be set to one if
a>=bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_greater_equal_signed(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a register is greater or equal to another
Note
Both
aandbare treated as being signed- Parameters:
out – register to be set to one if
a>=bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *add(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds two numbers
- Parameters:
out – register to store
a+bina – register storing first value
b – register storing second value
-
void *subtract(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Subtracts two numbers
- Parameters:
out – register to store
a-bina – register storing first value
b – register storing second value
-
void *multiply(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Multiplies two numbers
- Parameters:
out – register to store
a*bina – register storing first value
b – register storing second value
-
void *divide(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Divides two numbers
- Parameters:
out – register to store
a/bina – register storing first value
b – register storing second value
-
void *modulus(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Finds the remainder of the division of two numbers
- Parameters:
out – register to store
a%bina – register storing first value
b – register storing second value
-
void *shift_left(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Shifts one number left by another
- Parameters:
out – register to store
a<<bina – register storing first value
b – register storing second value
-
void *shift_right_logical(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Shifts one number right by another
- Parameters:
out – register to store
a>>bina – register storing first value
b – register storing second value
-
void *shift_right_arithmetic(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Shifts one number right by another, sign extending it
- Parameters:
out – register to store
a>>bina – register storing first value
b – register storing second value
-
void *bitwise_xor(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Xor’s two numbers
- Parameters:
out – register to store
a^bina – register storing first value
b – register storing second value
-
void *bitwise_and(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
And’s two numbers
- Parameters:
out – register to store
a&bina – register storing first value
b – register storing second value
-
void *bitwise_or(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Or’s two numbers
- Parameters:
out – register to store
a|bina – register storing first value
b – register storing second value
Variables
-
constexpr auto program_end = nullptr
-
namespace instructions
-
constexpr uint32_t label2immediate(const fp_string_view label)
-
namespace mizu
Functions
-
inline uint64_t new_thread(opcode *pc, registers_and_stack *env, uint8_t *sp)
-
inline void delay(std::chrono::microseconds time, opcode *&pc, uint64_t &storage_register)
-
void *fork_relative(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Forks a new thread moving its program counter by an offset relative to the current thread’s program counter. If the offset is zero this instruction is executed again. If it is one the next instruction is executed as usual. If it is negative a previous instruction is executed.
Note
A new set of registers (copied from the current thread) are created for the new thread.
Note
ais interpreted as a signed integer, allowing for negative jumps- Parameters:
out – register to store the thread reference in
a – register storing how many instructions to jump
-
void *fork_relative_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Forks a new thread moving its program counter by an offset relative to the current thread’s program counter. If the offset is zero this instruction is executed again. If it is one the next instruction is executed as usual. If it is negative a previous instruction is executed.
Note
A new set of registers (copied from the current thread) are created for the new thread.
Note
immediateis interpreted as a signed integer, allowing for negative jumps- Parameters:
out – register to store the thread reference in
immediate – how many instructions to jump
-
void *fork_to(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Forks a new thread with its program counter set to a value (usually the output of another jump)
Note
A new set of registers (copied from the current thread) are created for the new thread.
- Parameters:
out – register to store the thread reference in
a – register storing the address of the instruction to jump to.
-
void *join_thread(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Waits for the provided thread to finish and frees its reference
- Parameters:
a – Register storing the thread to wait for
b – Register storing a value to overwrite
awith (defaults to zero)
-
void *sleep_microseconds(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Sleeps the provided number of micro seconds
- Parameters:
a – Register storing the number of microseconds to sleep
-
void *channel_create(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Creates an inter-thread communication channel. This channel can keep a buffer of values or a single value.
Note
Channels send and receive register sized binary blobs.
- Parameters:
out – Register to store the channel reference in
a – Register storing the capacity of the channel buffer (defaults to a single item)
-
void *channel_close(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Closes the provided channel and frees its reference
- Parameters:
a – Register storing the channel to free
b – Register storing a value to overwrite
awith (defaults to zero)
-
void *channel_receive(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Blocks the current thread until there is an item to receive from the channel.
- Parameters:
out – Register to store the binary blob read from the channel in.
a – Register storing the channel to read from.
-
void *channel_send(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Blocks the current thread until the channel has room to receive a new value.
- Parameters:
a – Register storing the channel to send a message to
b – Register storing the binary blob to send to the channel.
-
void *mutex_create(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Creates a read/write lockable mutex
- Parameters:
out – Register to store the mutex reference in
-
void *mutex_free(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Frees a mutex.
- Parameters:
a – Register storing the mutex to free.
b – Register storing a value to overwrite
awith (defaults to zero)
-
void *mutex_write_lock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Blocks the current thread until an exclusive (writing) lock can be taken on the mutex
- Parameters:
a – Register storing the mutex to lock.
-
void *mutex_try_write_lock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Attemps to take an exclusive (writing) lock on the mutex
- Parameters:
out – Register to store weather (1) or not (0) the lock was successfully taken in
a – Register storing the mutex to lock.
-
void *mutex_write_unlock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Releases an exclusive (writing) lock on a mutex so that another thread can lock it.
- Parameters:
a – Register storing the mutex to unlock.
-
void *mutex_read_lock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Blocks the current thread until a shared (reading) lock can be taken on the mutex
Note
any number of threads can take a reading lock at the same time, but only one thread can have a writing lock.
- Parameters:
a – Register storing the mutex to lock.
-
void *mutex_try_read_lock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Attemps to take an shared (reading) lock on the mutex
Note
any number of threads can take a reading lock at the same time, but only one thread can have a writing lock.
- Parameters:
out – Register to store weather (1) or not (0) the lock was successfully taken in
a – Register storing the mutex to lock.
-
void *mutex_read_unlock(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Releases a shared (reading) lock on a mutex so that another thread can lock it.
- Parameters:
a – Register storing the mutex to unlock.
-
namespace instructions
-
inline uint64_t new_thread(opcode *pc, registers_and_stack *env, uint8_t *sp)
-
namespace mizu
-
namespace unsafe
Functions
-
void *allocate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Allocates new memory on the host application heap.
- Parameters:
out – Register in which a pointer to the allocated memory will be stored
a – Register storing how many bytes to allocate
-
void *free_allocated(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Frees an allocation alloacted with allocate.
- Parameters:
a – Register storing the allocation to free
b – Register storing a value to overwrite
awith (defaults to zero)
-
void *allocate_fat_pointer(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Allocates new memory on the host application heap. This memory knows how many element are stored in it.
Note
The total size of this allocation is a * b
- Parameters:
out – Register in which a pointer to the allocated memory will be stored
a – Register storing the size of each element
b – Register storing how many elements there are
-
void *free_fat_pointer(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Frees an allocation alloacted with allocate_fat_pointer.
- Parameters:
a – Register storing the allocation to free
b – Register storing a value to overwrite
awith (defaults to zero)
-
void *pointer_to_stack(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Generates a pointer to memory on Mizu’s stack.
- Parameters:
out – Register to store the pointer in
a – Register storing a (signed) offset from the current stack pointer.
-
void *pointer_to_stack_bottom(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Generates a pointer to memory on the bottom of Mizu’s stack.
- Parameters:
out – Register to store the pointer in
a – Register storing a (signed) offset from the current stack pointer.
-
void *pointer_to_register(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Generates a pointer to one of Mizu’s registers
- Parameters:
a – Register to take a pointer to.
out – Register to store the pointer in
-
void *copy_memory(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Copies memory from one pointer to another
- Parameters:
out – Register storing a pointer that data should be copied to
a – Register storing a pointer that data should be copied from
b – Register storing how many bytes should be copied.
-
void *copy_memory_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Copies memory from one pointer to another
- Parameters:
out – Register storing a pointer that data should be copied to
a – Register storing a pointer that data should be copied from
b – (branch immediate) number of bytes that should be copied
-
void *set_memory(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Sets all of the given memory to the provided byte
- Parameters:
out – Register storing a pointer to what should be overwritten
a – Register storing a u8 to overwrite
outwithb – Register storing how many bytes should be overwritten
-
void *set_memory_immediate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Sets all of the given memory to the provided byte
- Parameters:
out – Register storing a pointer to what should be overwritten
a – Register storing a u8 to overwrite
outwithb – (branch immediate) how many bytes should be overwritten
-
namespace instructions
-
void *allocate(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
-
namespace unsafe
Floating Point Instructions#
-
namespace mizu
Functions
-
template<std::floating_point F>
inline F &float_register(uint64_t *registers, uint16_t index)
-
void *convert_to_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts the provided register into a float register
- Parameters:
out – Register to store the result of the conversion in
a – Register to convert to an f32
-
void *convert_signed_to_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts the provided (signed) register into a float register
- Parameters:
out – Register to store the result of the conversion in
a – Register to convert to an f32
-
void *convert_from_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Truncates the provided float register and stores it in the given register (as an unsigned number)
- Parameters:
out – Register to store the result of the conversion in
a – Float register to convert to a u64
-
void *convert_signed_from_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Truncates the provided float register and stores it in the given register
- Parameters:
out – Register to store the result of the conversion in
a – Float register to convert to an i64
-
void *add_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds two f32 numbers
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to store
a+bina – register storing first value
b – register storing second value
-
void *subtract_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Subtracts two f32 numbers
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to store
a-bina – register storing first value
b – register storing second value
-
void *multiply_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Multiplies two f32 numbers
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to store
a*bina – register storing first value
b – register storing second value
-
void *divide_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Divides two f32 numbers
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to store
a/bina – register storing first value
b – register storing second value
-
void *max_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Finds the max of two f32 numbers
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to store max(
a,b) ina – register storing first value
b – register storing second value
-
void *min_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Finds the min of two f32 numbers
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to store min(
a,b) ina – register storing first value
b – register storing second value
-
void *sqrt_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Finds the square root of a f32 number
- Parameters:
out – register to store sqrt(
a) ina – register storing the value
-
void *set_if_equal_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if two f32 registers are equal
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to be set to one if
a==bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_not_equal_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if two f32 registers are not equal
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to be set to one if
a!=bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_less_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if one f32 register is less than another
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to be set to one if
a<bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_greater_equal_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if one f32 register is greater or equal to another
Note
Both
aandbmust be f32s. If they aren’t they should be converted first- Parameters:
out – register to be set to one if
a>=bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_negative_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a f32 register is negative
- Parameters:
out – register to be set to one if
a< 0 or zero otherwisea – register storing the value to compare
-
void *set_if_positive_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a f32 register is positive
- Parameters:
out – register to be set to one if
a> 0 or zero otherwisea – register storing the value to compare
-
void *set_if_infinity_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a f32 register is an infinity
- Parameters:
out – register to be set to one if
a== +/- infinity or zero otherwisea – register storing the value to compare
-
void *set_if_nan_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a f32 register is nan
- Parameters:
out – register to be set to one if
a== nan or zero otherwisea – register storing the value to compare
-
namespace instructions
-
template<std::floating_point F>
-
namespace mizu
Functions
-
void *convert_f32_to_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts the provided f32 register to an f64 register
- Parameters:
out – Register to store the f64 result in
a – Register storing the f32 to convert
-
void *convert_f64_to_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts the provided f64 register to an f32 register
- Parameters:
out – Register to store the f32 result in
a – Register storing the f64 to convert
-
void *convert_to_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts the provided register into a float register
- Parameters:
out – Register to store the result of the conversion in
a – Register to convert to an f64
-
void *convert_signed_to_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts the provided (signed) register into a float register
- Parameters:
out – Register to store the result of the conversion in
a – Register to convert to an f64
-
void *convert_from_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Truncates the provided float register and stores it in the given register (as an unsigned number)
- Parameters:
out – Register to store the result of the conversion in
a – Float register to convert to a u64
-
void *convert_signed_from_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Truncates the provided float register and stores it in the given register
- Parameters:
out – Register to store the result of the conversion in
a – Float register to convert to an i64
-
void *add_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds two f64 numbers
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to store
a+bina – register storing first value
b – register storing second value
-
void *subtract_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Subtracts two f64 numbers
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to store
a-bina – register storing first value
b – register storing second value
-
void *multiply_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Multiplies two f64 numbers
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to store
a*bina – register storing first value
b – register storing second value
-
void *divide_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Divides two f64 numbers
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to store
a/bina – register storing first value
b – register storing second value
-
void *max_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Finds the max of two f64 numbers
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to store max(
a,b) ina – register storing first value
b – register storing second value
-
void *min_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Finds the min of two f64 numbers
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to store min(
a,b) ina – register storing first value
b – register storing second value
-
void *sqrt_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Finds the square root of a f64 number
- Parameters:
out – register to store sqrt(
a) ina – register storing the value
-
void *set_if_equal_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if two f64 registers are equal
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to be set to one if
a==bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_not_equal_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if two f64 registers are not equal
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to be set to one if
a!=bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_less_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if one f64 register is less than another
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to be set to one if
a<bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_greater_equal_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if one f64 register is greater or equal to another
Note
Both
aandbmust be f64s. If they aren’t they should be converted first- Parameters:
out – register to be set to one if
a>=bor zero otherwisea – register storing the first value to compare
b – register storing the second value to compare
-
void *set_if_negative_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a f64 register is negative
- Parameters:
out – register to be set to one if
a< 0 or zero otherwisea – register storing the value to compare
-
void *set_if_positive_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a f64 register is positive
- Parameters:
out – register to be set to one if
a> 0 or zero otherwisea – register storing the value to compare
-
void *set_if_infinity_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a f64 register is an infinity
- Parameters:
out – register to be set to one if
a== +/- infinity or zero otherwisea – register storing the value to compare
-
void *set_if_nan_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Checks if a f64 register is nan
- Parameters:
out – register to be set to one if
a== nan or zero otherwisea – register storing the value to compare
-
namespace instructions
-
void *convert_f32_to_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
FFI Instructions#
Please note that the FFI instructions aren’t included in the default mizu/instructions header.
To include them please add:
#include <ffi/instructions.hpp>
-
namespace mizu
-
namespace ffi
Functions
-
template<bool has_return>
void *call_impl(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
-
void *push_type_void(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds void to the current type stack.
-
void *push_type_pointer(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds void* to the current type stack.
-
void *push_type_i32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds int32_t to the current type stack.
-
void *push_type_u32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds uint32_t to the current type stack.
-
void *push_type_i64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds int64_t to the current type stack.
-
void *push_type_u64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds uint64_t to the current type stack.
-
void *push_type_f32(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds
floatto the current type stack.
-
void *push_type_f64(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Adds
doubleto the current type stack.
-
void *clear_type_stack(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Clears the current type stack.
-
void *create_interface(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Converts the current type stack into a interface that tells the ffi subsystem what the types of each argument are.
Note
The first type on the stack is interpreted as the return type, any types after that are parameters (that one return type is required! Use push_type_void to indicate no return.)
- Parameters:
out – Register to store the resulting interface in
-
void *free_interface(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Frees the provided interface and overwrites it with the value in
b(defaults to zero)- Parameters:
a – Register storing the interface to free.
b – Register storing the value to overwrite a with (defaults to zero)
-
void *call(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Calls an ffi function, the functions arguments are expected to be in the argument registers (a0, a1, etc…)
- Parameters:
a – Register storing a pointer to the function to call.
b – Register storing the interface defining how the function’s arguments should be interpreted.
-
void *call_with_return(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Calls an ffi function with a returned value, the functions arguments are expected to be in the argument registers (a0, a1, etc…)
- Parameters:
out – Register storing
a – Register storing a pointer to the function to call.
b – Register storing the interface defining how the function’s arguments should be interpreted.
-
void *load_library(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Loads a DLL (or platform equivalent) with the provided path.
Note
most platforms will search some set of library path for the given path
- Parameters:
out – Register to store the resulting library pointer in
a – Register storing a null-terminated c-string pointer representing the path to search for the library.
-
void *load_first_library_that_exists(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Expects a list of null terminated c-string library paths in the first
immediateargument registers. Tries to load each library and stores a pointer to the first to load inout- Parameters:
out – Register to store the resulting library in.
immediate – number of argument (a0, a1, etc…) registers storing paths to search
-
void *load_library_function(opcode *pc, uint64_t *registers, registers_and_stack *env, uint8_t *sp)
Loads a function pointer from a library.
- Parameters:
out – Register to store the resulting function pointer in
a – Register storing a pointer to the library to load the function from.
b – Register storing a null-terminated c-string pointer representing the (mangled) name of the function to load.
-
namespace instructions
-
template<bool has_return>
-
namespace ffi
Serialization#
Once a program has been created it may be useful to save it to a file.
Since different programs will wind up putting the instructions’ functions in different places in memory, when serializing a file it is useful to instead replace those addresses with indices.
Thus Mizu provides a lookup system:
- group Lookup
Functions
-
inline std::optional<detail::id_t> lookup_id(std::string_view name)#
Finds the ID of an instruction by its name
- Parameters:
name – the name of the instruction to find
- Returns:
std::optional<detail::id_t> the id if found or std::nullopt if not
-
inline std::optional<detail::id_t> lookup_id(const fp_string_view name)#
Finds the ID of an instruction by its name
- Parameters:
name – the name of the instruction to find
- Returns:
std::optional<detail::id_t> the id if found or std::nullopt if not
-
inline std::optional<detail::id_t> lookup_id(const fp_string name)#
Finds the ID of an instruction by its name
- Parameters:
name – the name of the instruction to find
- Returns:
std::optional<detail::id_t> the id if found or std::nullopt if not
-
inline std::optional<detail::id_t> lookup_id(mizu::instruction_t ptr)#
Finds the ID of an instruction by its function pointer
- Parameters:
ptr – pointer to the instruction to find
- Returns:
std::optional<detail::id_t> the id if found or std::nullopt if not
-
inline std::optional<mizu::instruction_t> lookup_pointer(detail::id_t id)#
Looks up the function pointer for an instruction based on its ID
- Parameters:
id – The ID to search for
- Returns:
std::optional<mizu::instruction_t> callable function pointer if found or std::nullopt if not
-
inline std::optional<fp_string_view> lookup_name(detail::id_t id)#
Looks up the name of an instruction based on its ID
- Parameters:
id – The ID to search for
- Returns:
std::optional<fp_string_view> view of the instruction’s name if found or std::nullopt if not
-
inline std::optional<mizu::instruction_t> lookup(std::string_view name)#
Finds the function pointer for an instruction by its name
- Parameters:
name – the name of the instruction to find
- Returns:
std::optional<mizu::instruction_t> callable function pointer if found or std::nullopt if not
-
inline std::optional<mizu::instruction_t> lookup(const fp_string_view name)#
Finds the function pointer for an instruction by its name
- Parameters:
name – the name of the instruction to find
- Returns:
std::optional<mizu::instruction_t> callable function pointer if found or std::nullopt if not
-
inline std::optional<mizu::instruction_t> lookup(const fp_string name)#
Finds the function pointer for an instruction by its name
- Parameters:
name – the name of the instruction to find
- Returns:
std::optional<mizu::instruction_t> callable function pointer if found or std::nullopt if not
-
inline std::optional<fp_string_view> lookup(mizu::instruction_t ptr)#
Finds the name for an instruction by its function pointer
- Parameters:
ptr – pointer to the instruction to find
- Returns:
std::optional<fp_string_view> view of the instruction’s name if found or std::nullopt if not
-
inline void release_lookup_data()#
Releases all of the lookup tables used lookup instructions
Note
After lookup is no longer needed (say if the program has been loaded from disk and does not need to be written to disk again) this function can be called to free up memory in constrained scenarios.
-
inline std::optional<detail::id_t> lookup_id(std::string_view name)#
As well as some serialization functions which replace pointers with their identifiers automatically:
-
namespace mizu
Functions
-
inline fp::dynarray<std::byte> to_binary(fp::view<const opcode> _program)
Converts a Mizu
programinto a byte array ready to be written to a file or sent over the network.Note
This function makes no account of different machine endianness or pointer sizes.
- Parameters:
program – The program to serialize
- Returns:
fp::dynarray<std::byte> a dynamically allocated array of bytes representing the serialized program
-
inline fp::dynarray<opcode> from_binary(fp::view<const std::byte> binary)
Converts a blob of
binarydata into a Mizu programNote
This function makes no account of different machine endianness or pointer sizes.
- Parameters:
binary – The binary blob to deserialize
- Returns:
fp::dynarray<opcode> a dynamically allocated Mizu program
-
namespace serialization
-
struct serialization_opcode
- #include <serialize.hpp>
A version of the opcode which has fixed sizes for serialization purposes.
Public Static Functions
-
static inline serialization_opcode from_opcode(const opcode &code)#
-
static inline serialization_opcode from_opcode(const opcode &code)#
-
struct serialization_opcode
-
inline fp::dynarray<std::byte> to_binary(fp::view<const opcode> _program)
These serialization functions also have variants that pack some data into the bottom of the program’s stack and combine the whole thing into a portable format:
-
namespace mizu
Functions
-
inline fp::dynarray<std::byte> to_portable(fp::view<const opcode> program, fp::view<std::byte> data = {nullptr, 0})
Converts a Mizu
programand somedatainto a portable program that can executed anywhereNote
This function makes no account of different machine endianness or pointer sizes.
- Parameters:
program – The program to serialize
data – The data to put at the bottom of the program’s stack
- Returns:
fp::dynarray<std::byte> a dynamically allocated array of bytes representing the serialized program
-
inline fp::dynarray<std::byte> to_portable(fp::view<const opcode> program, registers_and_stack &env)
Converts a Mizu
programand anenvinto a snapshot of a portable program that can executed anywhereNote
This function makes no account of different machine endianness or pointer sizes.
- Parameters:
program – The program to snapshot
env – The program enviornment to snapshot
- Returns:
fp::dynarray<std::byte> a dynamically allocated array of bytes representing the serialized program
-
inline std::pair<fp::dynarray<opcode>, registers_and_stack> from_portable(fp::view<const std::byte> binary)
Converts a blob of
binarydata storing a portable Mizu program and stack data back into a Mizu program.Note
This function makes no account of different machine endianness or pointer sizes.
- Parameters:
binary – The binary blob to deserialize
- Returns:
std::pair<fp::dynarray<opcode>, registers_and_stack> a dynamically allocated Mizu program and its enviornment
-
inline fp::string generate_header_file(fp::view<opcode> program, registers_and_stack &env, fp::string_view extra_includes = fp::string_view::from_cstr(""))
Generates a C++ header file representing the provided Mizu
programandenv.- Parameters:
program – The program to generate a header for.
env – The enviornment the program should begin executing in.
extra_includes – If the program requires extra instruction headers (like SIMD or custom) they should be listed (one per line, including the #include) here
- Returns:
fp::string a string storing the resulting headerfile.
-
namespace portable
-
inline fp::dynarray<std::byte> to_portable(fp::view<const opcode> program, fp::view<std::byte> data = {nullptr, 0})