diff --git a/lib/inst.c b/lib/inst.c index 34de15a..eda2fa0 100644 --- a/lib/inst.c +++ b/lib/inst.c @@ -276,36 +276,37 @@ void inst_print(inst_t instruction, FILE *fp) fprintf(fp, ")"); } -size_t inst_bytecode_size(inst_t inst) +size_t opcode_bytecode_size(opcode_t opcode) { static_assert(NUMBER_OF_OPCODES == 98, "inst_bytecode_size: Out of date"); size_t size = 1; // for opcode - if (UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_PUSH)) + if (UNSIGNED_OPCODE_IS_TYPE(opcode, OP_PUSH)) { - if (inst.opcode == OP_PUSH_BYTE) + if (opcode == OP_PUSH_BYTE) ++size; - else if (inst.opcode == OP_PUSH_HWORD) + else if (opcode == OP_PUSH_HWORD) size += HWORD_SIZE; - else if (inst.opcode == OP_PUSH_WORD) + else if (opcode == OP_PUSH_WORD) size += WORD_SIZE; } - else if (UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_PUSH_REGISTER) || - UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_MOV) || - UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_DUP) || - UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_MALLOC) || - UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_MSET) || - UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_MGET) || - UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_JUMP_IF) || - inst.opcode == OP_JUMP_ABS || inst.opcode == OP_CALL) + else if (UNSIGNED_OPCODE_IS_TYPE(opcode, OP_PUSH_REGISTER) || + UNSIGNED_OPCODE_IS_TYPE(opcode, OP_MOV) || + UNSIGNED_OPCODE_IS_TYPE(opcode, OP_DUP) || + UNSIGNED_OPCODE_IS_TYPE(opcode, OP_MALLOC) || + UNSIGNED_OPCODE_IS_TYPE(opcode, OP_MSET) || + UNSIGNED_OPCODE_IS_TYPE(opcode, OP_MGET) || + UNSIGNED_OPCODE_IS_TYPE(opcode, OP_JUMP_IF) || + opcode == OP_JUMP_ABS || opcode == OP_CALL) size += WORD_SIZE; return size; } -void inst_write_bytecode(inst_t inst, darr_t *darr) +size_t inst_write_bytecode(inst_t inst, byte_t *bytes) { static_assert(NUMBER_OF_OPCODES == 98, "inst_write_bytecode: Out of date"); - // Append opcode - darr_append_byte(darr, inst.opcode); + + size_t written = 1; + bytes[0] = inst.opcode; // Then append 0 or more operands data_type_t to_append = DATA_TYPE_NIL; if (UNSIGNED_OPCODE_IS_TYPE(inst.opcode, OP_PUSH)) @@ -325,72 +326,70 @@ void inst_write_bytecode(inst_t inst, darr_t *darr) case DATA_TYPE_NIL: break; case DATA_TYPE_BYTE: - darr_append_byte(darr, inst.operand.as_byte); + bytes[1] = inst.operand.as_byte; + written += 1; break; case DATA_TYPE_HWORD: - darr_ensure_capacity(darr, HWORD_SIZE); - convert_hword_to_bytes(inst.operand.as_hword, darr->data + darr->used); - darr->used += HWORD_SIZE; + convert_hword_to_bytes(inst.operand.as_hword, bytes + 1); + written += HWORD_SIZE; break; case DATA_TYPE_WORD: - darr_ensure_capacity(darr, WORD_SIZE); - convert_word_to_bytes(inst.operand.as_word, darr->data + darr->used); - darr->used += WORD_SIZE; + convert_word_to_bytes(inst.operand.as_word, bytes + 1); + written += WORD_SIZE; break; } + return written; } -void insts_write_bytecode(inst_t *insts, size_t size, darr_t *darr) -{ - for (size_t i = 0; i < size; ++i) - inst_write_bytecode(insts[i], darr); -} - -data_t read_type_from_darr(darr_t *darr, data_type_t type) +bool read_type_from_darr(byte_t *bytes, size_t size, data_type_t type, + data_t *data) { + data_t datum = {0}; switch (type) { case DATA_TYPE_NIL: break; case DATA_TYPE_BYTE: - if (darr->used > darr->available) - // TODO: Error (darr has no space left) - return DBYTE(0); - return DBYTE(darr->data[darr->used++]); + if (size == 0) + return false; + datum = DBYTE(bytes[0]); break; case DATA_TYPE_HWORD: - if (darr->used + HWORD_SIZE > darr->available) - // TODO: Error (darr has no space left) - return DWORD(0); - hword_t u = convert_bytes_to_hword(darr->data + darr->used); - darr->used += HWORD_SIZE; - return DHWORD(u); + if (size < HWORD_SIZE) + return false; + hword_t u = convert_bytes_to_hword(bytes); + datum = DHWORD(u); break; case DATA_TYPE_WORD: - if (darr->used + WORD_SIZE > darr->available) - // TODO: Error (darr has no space left) - return DWORD(0); - word_t w = convert_bytes_to_word(darr->data + darr->used); - darr->used += WORD_SIZE; - return DWORD(w); + if (size < WORD_SIZE) + return false; + word_t w = convert_bytes_to_word(bytes); + datum = DWORD(w); break; + default: + return false; } - // TODO: Error (unrecognised type) - return DBYTE(0); + *data = datum; + return true; } -inst_t inst_read_bytecode(darr_t *darr) +int inst_read_bytecode(inst_t *ptr, byte_t *bytes, size_t size_bytes) { static_assert(NUMBER_OF_OPCODES == 98, "inst_read_bytecode: Out of date"); - if (darr->used >= darr->available) - return (inst_t){0}; - inst_t inst = {0}; - opcode_t opcode = darr->data[darr->used++]; + + opcode_t opcode = *(bytes++); if (opcode > OP_HALT || opcode == NUMBER_OF_OPCODES || opcode < OP_NOOP) - return INST_NOOP; + return READ_ERR_INVALID_OPCODE; + + inst_t inst = {opcode, {0}}; + --size_bytes; + + bool success = true; + // Read operands if (UNSIGNED_OPCODE_IS_TYPE(opcode, OP_PUSH)) - inst.operand = read_type_from_darr(darr, (data_type_t)opcode); + success = read_type_from_darr(bytes, size_bytes, (data_type_t)opcode, + &inst.operand); // Read register (as a byte) else if (UNSIGNED_OPCODE_IS_TYPE(opcode, OP_PUSH_REGISTER) || UNSIGNED_OPCODE_IS_TYPE(opcode, OP_MOV) || @@ -400,111 +399,90 @@ inst_t inst_read_bytecode(darr_t *darr) UNSIGNED_OPCODE_IS_TYPE(opcode, OP_MGET) || UNSIGNED_OPCODE_IS_TYPE(opcode, OP_JUMP_IF) || opcode == OP_JUMP_ABS || opcode == OP_CALL) - inst.operand = read_type_from_darr(darr, DATA_TYPE_WORD); - // Otherwise opcode doesn't take operands - - inst.opcode = opcode; - - return inst; -} - -inst_t *insts_read_bytecode(darr_t *bytes, size_t *ret_size) -{ - *ret_size = 0; - // NOTE: Here we use the darr as a dynamic array of inst_t. - darr_t instructions = {0}; - darr_init(&instructions, sizeof(inst_t)); - while (bytes->used < bytes->available) + success = + read_type_from_darr(bytes, size_bytes, DATA_TYPE_WORD, &inst.operand); + else { - inst_t instruction = inst_read_bytecode(bytes); - darr_append_bytes(&instructions, (byte_t *)&instruction, - sizeof(instruction)); + // Instruction doesn't take operands } - *ret_size = instructions.used / sizeof(inst_t); - return (inst_t *)instructions.data; + + if (success) + { + *ptr = inst; + return (int)(READ_ERR_END) - (int)(size_bytes); + } + else + return READ_ERR_OPERAND_NO_FIT; } -inst_t *insts_read_bytecode_file(FILE *fp, size_t *ret) -{ - darr_t darr = darr_read_file(fp); - inst_t *instructions = insts_read_bytecode(&darr, ret); - free(darr.data); - return instructions; -} - -void insts_write_bytecode_file(inst_t *instructions, size_t size, FILE *fp) -{ - darr_t darr = {0}; - darr_init(&darr, 0); - insts_write_bytecode(instructions, size, &darr); - darr_write_file(&darr, fp); - free(darr.data); -} - -static_assert(sizeof(prog_t) == WORD_SIZE * 2, +static_assert(sizeof(prog_t) == (WORD_SIZE * 2) + sizeof(inst_t *), "prog_{write|read}_* is out of date"); -void prog_write_bytecode(prog_t *program, darr_t *buffer) + +size_t prog_bytecode_size(prog_t program) { + size_t size = WORD_SIZE * 2; + for (size_t i = 0; i < program.count; ++i) + size += opcode_bytecode_size(program.instructions[i].opcode); + return size; +} + +size_t prog_write_bytecode(prog_t program, byte_t *bytes, size_t size_bytes) +{ + if (size_bytes < PROG_HEADER_SIZE || prog_bytecode_size(program) < size_bytes) + return 0; // Write program header i.e. the start and count - word_t start = word_htobc(program->start_address); - darr_append_bytes(buffer, (byte_t *)&start, sizeof(start)); - word_t count = word_htobc(program->count); - darr_append_bytes(buffer, (byte_t *)&count, sizeof(count)); + word_t start = word_htobc(program.start_address); + *(bytes++) = start; + word_t count = word_htobc(program.count); + *(bytes++) = count; // Write instructions - insts_write_bytecode(program->instructions, program->count, buffer); -} - -void prog_append_bytecode(prog_t *program, darr_t *buffer) -{ - insts_write_bytecode(program->instructions, program->count, buffer); -} - -prog_t *prog_read_bytecode(darr_t *buffer) -{ - // TODO: Error (not enough space for program header) - if ((buffer->available - buffer->used) < sizeof(prog_t)) - return NULL; - // Read program header - word_t start_address = convert_bytes_to_word(buffer->data + buffer->used); - buffer->used += sizeof(start_address); - word_t count = convert_bytes_to_word(buffer->data + buffer->used); - buffer->used += sizeof(word_t); - - // TODO: Error (not enough space for program instruction count) - if ((buffer->available - buffer->used) < WORD_SIZE) - return NULL; - - prog_t *program = malloc(sizeof(*program) + (sizeof(inst_t) * count)); - size_t i; - for (i = 0; i < count && (buffer->used < buffer->available); ++i) - program->instructions[i] = inst_read_bytecode(buffer); - - // TODO: Error (Expected more instructions) - if (i < count - 1) + size_t p_iter = 0, b_iter = PROG_HEADER_SIZE; + for (; p_iter < program.count && b_iter < size_bytes; ++p_iter) { - free(program); - return NULL; + size_t written = + inst_write_bytecode(program.instructions[p_iter], bytes + b_iter); + if (written == 0) + return 0; + b_iter += written; } - program->start_address = start_address; - program->count = count; - - return program; + return b_iter; } -void prog_write_file(prog_t *program, FILE *fp) +size_t prog_read_header(prog_t *prog, byte_t *bytes, size_t size_bytes) { - darr_t bytecode = {0}; - prog_write_bytecode(program, &bytecode); - fwrite(bytecode.data, bytecode.used, 1, fp); - free(bytecode.data); + if (size_bytes < PROG_HEADER_SIZE) + return 0; + prog->start_address = convert_bytes_to_word(bytes); + prog->count = convert_bytes_to_word(bytes + WORD_SIZE); + + if (prog->start_address >= prog->count) + return 0; + return PROG_HEADER_SIZE; } -prog_t *prog_read_file(FILE *fp) +read_err_prog_t prog_read_instructions(prog_t *program, size_t *size_bytes_read, + byte_t *bytes, size_t size_bytes) { - darr_t buffer = darr_read_file(fp); - prog_t *p = prog_read_bytecode(&buffer); - free(buffer.data); - return p; + // If no count then must be empty + if (program->count == 0) + return (read_err_prog_t){0}; + + size_t program_iter = 0, byte_iter = 0; + for (; program_iter < program->count && byte_iter < size_bytes; + ++program_iter) + { + inst_t inst = {0}; + int bytes_read = + inst_read_bytecode(&inst, bytes + byte_iter, size_bytes - byte_iter); + if (bytes_read < 0) + return (read_err_prog_t){bytes_read, byte_iter}; + byte_iter += bytes_read; + } + + if (program_iter < program->count) + return (read_err_prog_t){READ_ERR_EXPECTED_MORE, 0}; + *size_bytes_read = byte_iter; + return (read_err_prog_t){0}; } diff --git a/lib/inst.h b/lib/inst.h index 10a2702..3daf50f 100644 --- a/lib/inst.h +++ b/lib/inst.h @@ -13,14 +13,10 @@ #ifndef INST_H #define INST_H -#include -#include - +#include #include #include -const char *opcode_as_cstr(opcode_t); - #define UNSIGNED_OPCODE_IS_TYPE(OPCODE, OP_TYPE) \ (((OPCODE) >= OP_TYPE##_BYTE) && ((OPCODE) <= OP_TYPE##_WORD)) @@ -29,85 +25,224 @@ const char *opcode_as_cstr(opcode_t); #define OPCODE_DATA_TYPE(OPCODE, OP_TYPE) (OPCODE - OP_TYPE##_BYTE) -// OPCODE_DATA_TYPE: opcode_t -> data_type_t. data_type_t acts as -// a map between types and their offsets from the first type of -// instruction. That means for opcode_type A and data_type u, -// OP__BYTE + u = OP__. +typedef enum +{ + OP_NOOP = 0, + + // Dealing with data and registers + OP_PUSH_BYTE, + OP_PUSH_HWORD, + OP_PUSH_WORD, + + OP_POP_BYTE, + OP_POP_HWORD, + OP_POP_WORD, + + OP_PUSH_REGISTER_BYTE, + OP_PUSH_REGISTER_HWORD, + OP_PUSH_REGISTER_WORD, + + OP_MOV_BYTE, + OP_MOV_HWORD, + OP_MOV_WORD, + + OP_DUP_BYTE, + OP_DUP_HWORD, + OP_DUP_WORD, + + // Dealing with the heap + OP_MALLOC_BYTE, + OP_MALLOC_HWORD, + OP_MALLOC_WORD, + + OP_MALLOC_STACK_BYTE, + OP_MALLOC_STACK_HWORD, + OP_MALLOC_STACK_WORD, + + OP_MSET_BYTE, + OP_MSET_HWORD, + OP_MSET_WORD, + + OP_MSET_STACK_BYTE, + OP_MSET_STACK_HWORD, + OP_MSET_STACK_WORD, + + OP_MGET_BYTE, + OP_MGET_HWORD, + OP_MGET_WORD, + + OP_MGET_STACK_BYTE, + OP_MGET_STACK_HWORD, + OP_MGET_STACK_WORD, + + OP_MDELETE, + OP_MSIZE, + + // Boolean operations + OP_NOT_BYTE, + OP_NOT_HWORD, + OP_NOT_WORD, + + OP_OR_BYTE, + OP_OR_HWORD, + OP_OR_WORD, + + OP_AND_BYTE, + OP_AND_HWORD, + OP_AND_WORD, + + OP_XOR_BYTE, + OP_XOR_HWORD, + OP_XOR_WORD, + + OP_EQ_BYTE, + OP_EQ_HWORD, + OP_EQ_WORD, + + // Mathematical operations + OP_PLUS_BYTE, + OP_PLUS_HWORD, + OP_PLUS_WORD, + + OP_SUB_BYTE, + OP_SUB_HWORD, + OP_SUB_WORD, + + OP_MULT_BYTE, + OP_MULT_HWORD, + OP_MULT_WORD, + + // Comparison operations + OP_LT_BYTE, + OP_LT_CHAR, + OP_LT_HWORD, + OP_LT_INT, + OP_LT_WORD, + OP_LT_LONG, + + OP_LTE_BYTE, + OP_LTE_CHAR, + OP_LTE_HWORD, + OP_LTE_INT, + OP_LTE_WORD, + OP_LTE_LONG, + + OP_GT_BYTE, + OP_GT_CHAR, + OP_GT_HWORD, + OP_GT_INT, + OP_GT_WORD, + OP_GT_LONG, + + OP_GTE_BYTE, + OP_GTE_CHAR, + OP_GTE_HWORD, + OP_GTE_INT, + OP_GTE_WORD, + OP_GTE_LONG, + + // Simple I/O + OP_PRINT_BYTE, + OP_PRINT_CHAR, + OP_PRINT_HWORD, + OP_PRINT_INT, + OP_PRINT_WORD, + OP_PRINT_LONG, + + // Program control flow + OP_JUMP_ABS, + OP_JUMP_STACK, + OP_JUMP_IF_BYTE, + OP_JUMP_IF_HWORD, + OP_JUMP_IF_WORD, + + // Subroutines + OP_CALL, + OP_CALL_STACK, + OP_RET, + + // Should not be an opcode + NUMBER_OF_OPCODES, + OP_HALT = 0b11111111, // top of the byte is a HALT +} opcode_t; + +size_t opcode_bytecode_size(opcode_t); +const char *opcode_as_cstr(opcode_t); + +typedef struct +{ + opcode_t opcode; + data_t operand; +} inst_t; + +/** + @brief Serialise an instruction into a byte buffer + + @details Given an instruction and a suitably sized byte buffer, + write the bytecode for the instruction into the buffer. NOTE: This + function does NOT check the bounds of `bytes` i.e. we assume the + caller has created a suitably sized buffer. + + @param[inst] Instruction to serialise + @param[bytes] Buffer to write on + + @return[size_t] Number of bytes written to `bytes`. + */ +size_t inst_write_bytecode(inst_t inst, byte_t *bytes); + +typedef enum +{ + READ_ERR_INVALID_OPCODE = -1, + READ_ERR_OPERAND_NO_FIT = -2, + READ_ERR_EXPECTED_MORE = -3, + READ_ERR_END = -4 +} read_err_t; + +/** + @brief Deserialise an instruction from a bytecode buffer + + @details Given a buffer of bytes, deserialise an instruction, + storing the result in the pointer given. The number of bytes read + in the buffer is returned, which should be opcode_bytecode_size(). + NOTE: If bytes is not suitably sized for the instruction expected + or it is not well formed i.e. not the right schema then a negative + number is returned. + + @param[inst] Pointer to instruction which will store result + @param[bytes] Bytecode buffer to deserialise + @param[size_bytes] Number of bytes in buffer + + @return[int] Number of bytes read. If negative then an error + occurred in deserialisation (either buffer was not suitably sized + or instruction was not well formed) so any result must be + considered invalid. + */ +int inst_read_bytecode(inst_t *inst, byte_t *bytes, size_t size_bytes); void inst_print(inst_t, FILE *); -size_t inst_bytecode_size(inst_t); -void inst_write_bytecode(inst_t, darr_t *); -void insts_write_bytecode(inst_t *, size_t, darr_t *); -// Here the dynamic array is a preloaded buffer of bytes, where -// darr.available is the number of overall bytes and used is the -// cursor (where we are in the buffer). -inst_t inst_read_bytecode(darr_t *); -inst_t *insts_read_bytecode(darr_t *, size_t *); +typedef struct +{ + word_t start_address; + word_t count; + inst_t *instructions; +} prog_t; -void insts_write_bytecode_file(inst_t *, size_t, FILE *); -inst_t *insts_read_bytecode_file(FILE *, size_t *); +#define PROG_HEADER_SIZE (WORD_SIZE * 2) -// Write the entire program as bytecode -void prog_write_bytecode(prog_t *, darr_t *); -// Only append the instructions as bytecode -void prog_append_bytecode(prog_t *, darr_t *); -// Read an entire program as bytecode -prog_t *prog_read_bytecode(darr_t *); +size_t prog_bytecode_size(prog_t); -void prog_write_file(prog_t *, FILE *); -prog_t *prog_read_file(FILE *); +size_t prog_write_bytecode(prog_t program, byte_t *bytes, size_t size_bytes); -#define INST_NOOP ((inst_t){0}) -#define INST_HALT ((inst_t){.opcode = OP_HALT}) +size_t prog_read_header(prog_t *program, byte_t *bytes, size_t size_bytes); -#define INST_PUSH(TYPE, OP) \ - ((inst_t){.opcode = OP_PUSH_##TYPE, .operand = D##TYPE(OP)}) +typedef struct +{ + read_err_t type; + size_t index; +} read_err_prog_t; -#define INST_MOV(TYPE, OP) \ - ((inst_t){.opcode = OP_MOV_##TYPE, .operand = D##TYPE(OP)}) +read_err_prog_t prog_read_instructions(prog_t *program, size_t *size_bytes_read, + byte_t *bytes, size_t size_bytes); -#define INST_POP(TYPE) ((inst_t){.opcode = OP_POP_##TYPE}) - -#define INST_PUSH_REG(TYPE, REG) \ - ((inst_t){.opcode = OP_PUSH_REGISTER_##TYPE, .operand = D##TYPE(REG)}) - -#define INST_DUP(TYPE, OP) \ - ((inst_t){.opcode = OP_DUP_##TYPE, .operand = DWORD(OP)}) - -#define INST_MALLOC(TYPE, OP) \ - ((inst_t){.opcode = OP_MALLOC_##TYPE, .operand = DWORD(OP)}) -#define INST_MALLOC_STACK(TYPE) ((inst_t){.opcode = OP_MALLOC_STACK_##TYPE}) -#define INST_MSET(TYPE, OP) \ - ((inst_t){.opcode = OP_MSET_##TYPE, .operand = DWORD(OP)}) -#define INST_MSET_STACK(TYPE) ((inst_t){.opcode = OP_MSET_STACK_##TYPE}) -#define INST_MGET(TYPE, OP) \ - ((inst_t){.opcode = OP_MGET_##TYPE, .operand = DWORD(OP)}) -#define INST_MGET_STACK(TYPE) ((inst_t){.opcode = OP_MGET_STACK_##TYPE}) -#define INST_MDELETE ((inst_t){.opcode = OP_MDELETE}) -#define INST_MSIZE ((inst_t){.opcode = OP_MSIZE}) - -#define INST_NOT(TYPE) ((inst_t){.opcode = OP_NOT_##TYPE}) -#define INST_OR(TYPE) ((inst_t){.opcode = OP_OR_##TYPE}) -#define INST_AND(TYPE) ((inst_t){.opcode = OP_AND_##TYPE}) -#define INST_XOR(TYPE) ((inst_t){.opcode = OP_XOR_##TYPE}) -#define INST_EQ(TYPE) ((inst_t){.opcode = OP_EQ_##TYPE}) -#define INST_LT(TYPE) ((inst_t){.opcode = OP_LT_##TYPE}) -#define INST_LTE(TYPE) ((inst_t){.opcode = OP_LTE_##TYPE}) -#define INST_GT(TYPE) ((inst_t){.opcode = OP_GT_##TYPE}) -#define INST_GTE(TYPE) ((inst_t){.opcode = OP_GTE_##TYPE}) -#define INST_PLUS(TYPE) ((inst_t){.opcode = OP_PLUS_##TYPE}) -#define INST_SUB(TYPE) ((inst_t){.opcode = OP_SUB_##TYPE}) -#define INST_MULT(TYPE) ((inst_t){.opcode = OP_MULT_##TYPE}) - -#define INST_JUMP_ABS(OP) \ - ((inst_t){.opcode = OP_JUMP_ABS, .operand = DWORD(OP)}) -#define INST_JUMP_STACK ((inst_t){.opcode = OP_JUMP_STACK}) -#define INST_JUMP_IF(TYPE, OP) \ - ((inst_t){.opcode = OP_JUMP_IF_##TYPE, .operand = DWORD(OP)}) -#define INST_CALL(OP) ((inst_t){.opcode = OP_CALL, .operand = DWORD(OP)}) -#define INST_CALL_STACK ((inst_t){.opcode = OP_CALL_STACK}) -#define INST_RET ((inst_t){.opcode = OP_RET}) - -#define INST_PRINT(TYPE) ((inst_t){.opcode = OP_PRINT_##TYPE}) #endif diff --git a/lib/prog.h b/lib/prog.h deleted file mode 100644 index ea47c2c..0000000 --- a/lib/prog.h +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (C) 2024 Aryadev Chavali - - * You may distribute and modify this code under the terms of the - * GPLv2 license. You should have received a copy of the GPLv2 - * license with this file. If not, please write to: - * aryadev@aryadevchavali.com. - - * Created: 2024-04-14 - * Author: Aryadev Chavali - * Description: Structures for both instructions and programs for the - * virtual machine - */ - -#ifndef PROG_H -#define PROG_H - -#include - -typedef enum -{ - OP_NOOP = 0, - - // Dealing with data and registers - OP_PUSH_BYTE, - OP_PUSH_HWORD, - OP_PUSH_WORD, - - OP_POP_BYTE, - OP_POP_HWORD, - OP_POP_WORD, - - OP_PUSH_REGISTER_BYTE, - OP_PUSH_REGISTER_HWORD, - OP_PUSH_REGISTER_WORD, - - OP_MOV_BYTE, - OP_MOV_HWORD, - OP_MOV_WORD, - - OP_DUP_BYTE, - OP_DUP_HWORD, - OP_DUP_WORD, - - // Dealing with the heap - OP_MALLOC_BYTE, - OP_MALLOC_HWORD, - OP_MALLOC_WORD, - - OP_MALLOC_STACK_BYTE, - OP_MALLOC_STACK_HWORD, - OP_MALLOC_STACK_WORD, - - OP_MSET_BYTE, - OP_MSET_HWORD, - OP_MSET_WORD, - - OP_MSET_STACK_BYTE, - OP_MSET_STACK_HWORD, - OP_MSET_STACK_WORD, - - OP_MGET_BYTE, - OP_MGET_HWORD, - OP_MGET_WORD, - - OP_MGET_STACK_BYTE, - OP_MGET_STACK_HWORD, - OP_MGET_STACK_WORD, - - OP_MDELETE, - OP_MSIZE, - - // Boolean operations - OP_NOT_BYTE, - OP_NOT_HWORD, - OP_NOT_WORD, - - OP_OR_BYTE, - OP_OR_HWORD, - OP_OR_WORD, - - OP_AND_BYTE, - OP_AND_HWORD, - OP_AND_WORD, - - OP_XOR_BYTE, - OP_XOR_HWORD, - OP_XOR_WORD, - - OP_EQ_BYTE, - OP_EQ_HWORD, - OP_EQ_WORD, - - // Mathematical operations - OP_PLUS_BYTE, - OP_PLUS_HWORD, - OP_PLUS_WORD, - - OP_SUB_BYTE, - OP_SUB_HWORD, - OP_SUB_WORD, - - OP_MULT_BYTE, - OP_MULT_HWORD, - OP_MULT_WORD, - - // Comparison operations - OP_LT_BYTE, - OP_LT_CHAR, - OP_LT_HWORD, - OP_LT_INT, - OP_LT_WORD, - OP_LT_LONG, - - OP_LTE_BYTE, - OP_LTE_CHAR, - OP_LTE_HWORD, - OP_LTE_INT, - OP_LTE_WORD, - OP_LTE_LONG, - - OP_GT_BYTE, - OP_GT_CHAR, - OP_GT_HWORD, - OP_GT_INT, - OP_GT_WORD, - OP_GT_LONG, - - OP_GTE_BYTE, - OP_GTE_CHAR, - OP_GTE_HWORD, - OP_GTE_INT, - OP_GTE_WORD, - OP_GTE_LONG, - - // Simple I/O - OP_PRINT_BYTE, - OP_PRINT_CHAR, - OP_PRINT_HWORD, - OP_PRINT_INT, - OP_PRINT_WORD, - OP_PRINT_LONG, - - // Program control flow - OP_JUMP_ABS, - OP_JUMP_STACK, - OP_JUMP_IF_BYTE, - OP_JUMP_IF_HWORD, - OP_JUMP_IF_WORD, - - // Subroutines - OP_CALL, - OP_CALL_STACK, - OP_RET, - - // Should not be an opcode - NUMBER_OF_OPCODES, - OP_HALT = 0b11111111, // top of the byte is a HALT -} opcode_t; - -typedef struct -{ - opcode_t opcode; - data_t operand; -} inst_t; - -typedef struct -{ - word_t start_address; - word_t count; - inst_t instructions[]; -} prog_t; - -#endif