2024-12-15 19:30:14 +00:00
|
|
|
#include "assembler.h"
|
|
|
|
|
|
|
|
|
|
#include <blue/core/hash.h>
|
2025-05-14 16:27:22 +01:00
|
|
|
#include <blue/object/hashmap.h>
|
2024-12-15 19:30:14 +00:00
|
|
|
#include <blue/object/number.h>
|
|
|
|
|
#include <blue/object/string.h>
|
|
|
|
|
#include <ivy/asm/bin.h>
|
2024-12-15 22:36:50 +00:00
|
|
|
#include <ivy/asm/instr.h>
|
2025-05-14 16:27:22 +01:00
|
|
|
#include <ivy/asm/lex.h>
|
2024-12-15 19:30:14 +00:00
|
|
|
#include <ivy/ident.h>
|
|
|
|
|
#include <ivy/selector.h>
|
2025-05-14 16:27:22 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
enum label_state {
|
|
|
|
|
LABEL_UNRESOLVED = 0,
|
|
|
|
|
LABEL_RESOLVED,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct label {
|
|
|
|
|
enum label_state l_state;
|
|
|
|
|
b_queue_entry l_entry;
|
|
|
|
|
const struct ivy_asm_token *l_name;
|
|
|
|
|
size_t l_offset;
|
|
|
|
|
};
|
2024-12-15 22:36:50 +00:00
|
|
|
|
2024-12-15 19:30:14 +00:00
|
|
|
struct block_assembler_scope {
|
|
|
|
|
struct assembler_scope s_base;
|
2025-05-14 16:27:22 +01:00
|
|
|
b_hashmap *s_labels;
|
|
|
|
|
b_queue s_label_refs;
|
|
|
|
|
size_t s_text_start;
|
2024-12-15 19:30:14 +00:00
|
|
|
};
|
|
|
|
|
|
2025-05-14 16:27:22 +01:00
|
|
|
static struct label *label_create(enum label_state state)
|
|
|
|
|
{
|
|
|
|
|
struct label *out = malloc(sizeof *out);
|
|
|
|
|
if (!out) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(out, 0x0, sizeof *out);
|
|
|
|
|
|
|
|
|
|
out->l_state = state;
|
|
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void label_destroy(struct label *label)
|
|
|
|
|
{
|
|
|
|
|
free(label);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-15 19:30:14 +00:00
|
|
|
static enum ivy_status init_scope(
|
|
|
|
|
struct ivy_assembler *as, struct assembler_scope *scope,
|
|
|
|
|
const ivy_assembler_attrib_table attrib)
|
|
|
|
|
{
|
|
|
|
|
struct ivy_bin_block header = {0};
|
|
|
|
|
|
2025-05-14 16:27:22 +01:00
|
|
|
struct block_assembler_scope *c = (struct block_assembler_scope *)scope;
|
|
|
|
|
c->s_labels = b_hashmap_create(NULL, NULL);
|
|
|
|
|
c->s_text_start = ivy_assembler_get_ptr(as);
|
|
|
|
|
|
2024-12-15 19:30:14 +00:00
|
|
|
header.b_index = b_i32_htob((uint32_t)attrib[IVY_ASM_ATTRIB_INDEX]);
|
|
|
|
|
assembler_write_data(as, &header, sizeof header);
|
|
|
|
|
|
2025-05-14 16:27:22 +01:00
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct label *get_label(struct block_assembler_scope *scope, const char *name)
|
|
|
|
|
{
|
|
|
|
|
b_hashmap_key key = {
|
|
|
|
|
.key_data = name,
|
|
|
|
|
.key_size = strlen(name),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const b_hashmap_value *v = b_hashmap_get(scope->s_labels, &key);
|
|
|
|
|
if (!v) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return v->value_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum ivy_status resolve_label_refs(
|
|
|
|
|
struct ivy_assembler *as, struct assembler_scope *scope)
|
|
|
|
|
{
|
2024-12-15 22:36:50 +00:00
|
|
|
struct block_assembler_scope *c = (struct block_assembler_scope *)scope;
|
2025-05-14 16:27:22 +01:00
|
|
|
enum ivy_status status = IVY_OK;
|
|
|
|
|
size_t nr_read = 0;
|
2024-12-15 19:30:14 +00:00
|
|
|
|
2025-05-14 16:27:22 +01:00
|
|
|
b_queue_iterator it;
|
|
|
|
|
b_queue_foreach (&it, &c->s_label_refs) {
|
|
|
|
|
struct label *label_ref = b_unbox(struct label, it.entry, l_entry);
|
|
|
|
|
struct label *label_dest = get_label(c, label_ref->l_name->t_str);
|
|
|
|
|
|
|
|
|
|
if (!label_dest) {
|
|
|
|
|
printf("cannot resolve label '%s'\n",
|
|
|
|
|
label_ref->l_name->t_str);
|
|
|
|
|
return IVY_ERR_NO_ENTRY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b_i32 x;
|
|
|
|
|
status = assembler_read_data_at(
|
|
|
|
|
as, &x, label_ref->l_offset, sizeof x, &nr_read);
|
|
|
|
|
|
|
|
|
|
if (status != IVY_OK || nr_read != sizeof x) {
|
|
|
|
|
printf("cannot fix label reference at 0x%zx\n",
|
|
|
|
|
label_ref->l_offset);
|
|
|
|
|
return IVY_ERR_IO_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t instr = b_i32_btoh(x);
|
|
|
|
|
instr = R_SET_D3(instr, label_dest->l_offset);
|
|
|
|
|
x = b_i32_htob(instr);
|
|
|
|
|
|
|
|
|
|
assembler_write_data_at(as, &x, label_ref->l_offset, sizeof x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum ivy_status finish_scope(
|
|
|
|
|
struct ivy_assembler *as, struct assembler_scope *scope)
|
|
|
|
|
{
|
|
|
|
|
return resolve_label_refs(as, scope);
|
2024-12-15 19:30:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum ivy_status put_instr(
|
|
|
|
|
struct ivy_assembler *as, struct assembler_scope *scope,
|
|
|
|
|
const struct ivy_instr *instr)
|
|
|
|
|
{
|
2024-12-15 22:36:50 +00:00
|
|
|
uint32_t v = 0;
|
|
|
|
|
v = R_SET_OPCODE(v, instr->i_op->i_opcode);
|
|
|
|
|
|
|
|
|
|
switch (instr->i_op->i_layout) {
|
|
|
|
|
case IVY_INSTR_X:
|
|
|
|
|
break;
|
|
|
|
|
case IVY_INSTR_D:
|
2025-01-15 17:39:15 +00:00
|
|
|
v |= R_SET_D3(v, instr->i_arg[0]);
|
2024-12-15 22:36:50 +00:00
|
|
|
break;
|
|
|
|
|
case IVY_INSTR_R1:
|
2025-01-15 17:39:15 +00:00
|
|
|
v |= R_SET_R1(v, instr->i_arg[0]);
|
2024-12-15 22:36:50 +00:00
|
|
|
break;
|
|
|
|
|
case IVY_INSTR_R1D:
|
2025-01-15 17:39:15 +00:00
|
|
|
v |= R_SET_R1(v, instr->i_arg[0]);
|
|
|
|
|
v |= R_SET_D2(v, instr->i_arg[1]);
|
2024-12-15 22:36:50 +00:00
|
|
|
break;
|
|
|
|
|
case IVY_INSTR_R2:
|
2025-01-15 17:39:15 +00:00
|
|
|
v |= R_SET_R1(v, instr->i_arg[0]);
|
|
|
|
|
v |= R_SET_R2(v, instr->i_arg[1]);
|
2024-12-15 22:36:50 +00:00
|
|
|
break;
|
|
|
|
|
case IVY_INSTR_R2D:
|
2025-01-15 17:39:15 +00:00
|
|
|
v |= R_SET_R1(v, instr->i_arg[0]);
|
|
|
|
|
v |= R_SET_R2(v, instr->i_arg[1]);
|
|
|
|
|
v |= R_SET_D1(v, instr->i_arg[2]);
|
2024-12-15 22:36:50 +00:00
|
|
|
break;
|
|
|
|
|
case IVY_INSTR_R3:
|
2025-01-15 17:39:15 +00:00
|
|
|
v |= R_SET_R1(v, instr->i_arg[0]);
|
|
|
|
|
v |= R_SET_R2(v, instr->i_arg[1]);
|
|
|
|
|
v |= R_SET_R3(v, instr->i_arg[2]);
|
2024-12-15 22:36:50 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return IVY_ERR_INTERNAL_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b_i32 x = b_i32_htob(v);
|
2024-12-15 19:30:14 +00:00
|
|
|
assembler_write_data(as, &x, sizeof x);
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-14 16:27:22 +01:00
|
|
|
static enum ivy_status put_label(
|
|
|
|
|
struct ivy_assembler *as, struct assembler_scope *scope,
|
|
|
|
|
const struct ivy_asm_token *label_name, size_t label_offset)
|
|
|
|
|
{
|
|
|
|
|
struct block_assembler_scope *c = (struct block_assembler_scope *)scope;
|
|
|
|
|
struct label *label = label_create(LABEL_RESOLVED);
|
|
|
|
|
|
|
|
|
|
label->l_name = label_name;
|
|
|
|
|
label->l_offset = label_offset - c->s_text_start;
|
|
|
|
|
|
|
|
|
|
b_hashmap_key key = {
|
|
|
|
|
.key_data = label_name->t_str,
|
|
|
|
|
.key_size = strlen(label_name->t_str),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
b_hashmap_value value = {
|
|
|
|
|
.value_data = label,
|
|
|
|
|
.value_size = sizeof *label,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (b_hashmap_get(c->s_labels, &key)) {
|
|
|
|
|
return IVY_ERR_NAME_EXISTS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b_status status = b_hashmap_put(c->s_labels, &key, &value);
|
|
|
|
|
|
|
|
|
|
return ivy_status_from_b_status(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum ivy_status put_label_ref(
|
|
|
|
|
struct ivy_assembler *as, struct assembler_scope *scope,
|
|
|
|
|
const struct ivy_asm_token *label_name, size_t ref_offset)
|
|
|
|
|
{
|
|
|
|
|
struct block_assembler_scope *c = (struct block_assembler_scope *)scope;
|
|
|
|
|
struct label *label = label_create(LABEL_UNRESOLVED);
|
|
|
|
|
|
|
|
|
|
label->l_name = label_name;
|
|
|
|
|
label->l_offset = ref_offset;
|
|
|
|
|
|
|
|
|
|
b_queue_push_back(&c->s_label_refs, &label->l_entry);
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-15 19:30:14 +00:00
|
|
|
const struct assembler_scope_type block_scope_type = {
|
|
|
|
|
.s_scope_size = sizeof(struct block_assembler_scope),
|
|
|
|
|
.s_init_scope = init_scope,
|
2025-05-14 16:27:22 +01:00
|
|
|
.s_finish_scope = finish_scope,
|
2024-12-15 19:30:14 +00:00
|
|
|
.s_put_instr = put_instr,
|
2025-05-14 16:27:22 +01:00
|
|
|
.s_put_label = put_label,
|
|
|
|
|
.s_put_label_ref = put_label_ref,
|
2024-12-15 19:30:14 +00:00
|
|
|
};
|