This repository has been archived on 2025-11-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
avm/src/inst.c
Aryadev Chavali 7380dd375a Fixed bug with get_opcode_data_type
Pushed the bits one step too far.
2023-10-16 11:25:52 +01:00

150 lines
3.9 KiB
C

/* Copyright (C) 2023 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: 2023-10-15
* Author: Aryadev Chavali
* Description: Implementation of bytecode for instructions
*/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "./inst.h"
data_type_t get_opcode_data_type(opcode_t opcode)
{
data_type_t type = DATA_TYPE_NIL;
if (OPCODE_IS_TYPE(opcode, OP_TYPE_PUSH))
type = (data_type_t)opcode;
else if (OPCODE_IS_TYPE(opcode, OP_TYPE_PUSH_REGISTER))
type = opcode >> 1;
else if (OPCODE_IS_TYPE(opcode, OP_TYPE_POP))
type = opcode >> 2;
else if (OPCODE_IS_TYPE(opcode, OP_TYPE_MOV))
type = opcode >> 3;
return type;
}
size_t inst_bytecode_size(inst_t inst)
{
size_t size = 1; // for opcode
if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_PUSH))
{
if (inst.opcode == OP_PUSH_BYTE)
++size;
else if (inst.opcode == OP_PUSH_WORD)
size += sizeof(word);
else if (inst.opcode == OP_PUSH_FLOAT)
size += sizeof(f64);
}
else if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_PUSH_REGISTER))
++size;
else if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_POP))
{
// No operand or register so leave as is
}
else if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_MOV))
{
if (inst.opcode == OP_MOV_BYTE)
++size;
else if (inst.opcode == OP_MOV_WORD)
size += sizeof(word);
else if (inst.opcode == OP_MOV_FLOAT)
size += sizeof(f64);
// For the register
++size;
}
return size;
}
void inst_write_bytecode(inst_t inst, darr_t *darr)
{
// Append opcode
darr_append_byte(darr, inst.opcode);
// Then append 0 or more operands
data_type_t to_append = DATA_TYPE_NIL;
if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_PUSH))
to_append = (data_type_t)inst.opcode;
else if (OPCODE_IS_TYPE(inst.opcode, OP_TYPE_PUSH_REGISTER) ||
OPCODE_IS_TYPE(inst.opcode, OP_TYPE_MOV))
to_append = DATA_TYPE_BYTE;
switch (to_append)
{
case DATA_TYPE_NIL:
break;
case DATA_TYPE_BYTE:
darr_append_byte(darr, inst.operand.as_byte);
break;
case DATA_TYPE_WORD:
darr_append_bytes(darr, (byte *)&inst.operand.as_word, sizeof(word));
break;
case DATA_TYPE_FLOAT:
darr_append_bytes(darr, (byte *)&inst.operand.as_float, sizeof(f64));
break;
}
}
data_t read_type_from_darr(darr_t *darr, data_type_t type)
{
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++]);
break;
case DATA_TYPE_WORD:
if (darr->used + sizeof(word) >= darr->available)
// TODO: Error (darr has no space left)
return DWORD(0);
word w = 0;
memcpy(&w, darr->data + darr->used, sizeof(w));
darr->used += sizeof(w);
return DWORD(w);
break;
case DATA_TYPE_FLOAT:
if (darr->used + sizeof(word) >= darr->available)
// TODO: Error (darr has no space left)
return DWORD(0);
f64 f = 0;
memcpy(&f, darr->data + darr->used, sizeof(f));
darr->used += sizeof(f);
return DFLOAT(f);
break;
}
// TODO: Error (unrecognised type)
return DBYTE(0);
}
inst_t inst_read_bytecode(darr_t *darr)
{
if (darr->used >= darr->available)
return (inst_t){0};
inst_t inst = {0};
opcode_t opcode = darr->data[darr->used++];
if (opcode > OP_HALT)
// Translate to NOOP
return inst;
// Read operands
if (OPCODE_IS_TYPE(opcode, OP_TYPE_PUSH))
inst.operand = read_type_from_darr(darr, get_opcode_data_type(opcode));
// Read register (as a byte)
else if (OPCODE_IS_TYPE(opcode, OP_TYPE_PUSH_REGISTER) ||
OPCODE_IS_TYPE(opcode, OP_TYPE_MOV))
inst.operand = read_type_from_darr(darr, DATA_TYPE_BYTE);
// Otherwise opcode doesn't take operands
inst.opcode = opcode;
return inst;
}