assembler: emit B instruction

Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
Ronald Caesar
2026-05-30 17:23:02 -04:00
parent 6be6ce1fdf
commit 4f75e6e8ed
2 changed files with 74 additions and 0 deletions
+17
View File
@@ -93,6 +93,23 @@ extern "C"
uint16_t imm12,
uint8_t shift);
/// Emits a `B` (Branch) instruction.
///
/// Branches unconditionally to a PC-relative offset.
///
/// # Safety
///
/// * `offset` will be truncated if it exceeds 26 bits.
/// * Does not emit if `assembler->status` != [`BAL_SUCCESS`]
///
/// # Errors
///
/// Modifies `assembler->status` to the following if an error occurs:
///
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
void bal_emit_b(bal_assembler_t *assembler, int32_t offset);
/// Emit a `SUB` (Immediate) instruction.
///
/// Subtracts a 12 bit immediate value `imm12` with the optional left shift `sh` from register
+57
View File
@@ -104,6 +104,63 @@ bal_emit_add_immediate(bal_assembler_t *assembler,
assembler->buffer[assembler->offset++] = instruction;
}
void
bal_emit_b(bal_assembler_t *assembler, const int32_t offset)
{
if (BAL_UNLIKELY(NULL == assembler))
{
return;
}
if (BAL_UNLIKELY(NULL == assembler->buffer))
{
BAL_LOG_ERROR(&assembler->logger, "Aborting function: assembler->buffer is NULL");
assembler->status = BAL_ERROR_INVALID_ARGUMENT;
return;
}
const bool can_emit_return_value = can_emit(assembler);
if (false == can_emit_return_value)
{
return;
}
if (assembler->status != BAL_SUCCESS)
{
BAL_LOG_ERROR(&assembler->logger, "Aborting function: assembler->status != BAL_SUCCESS");
return;
}
const uint32_t hard_coded_bits = 0x14000000;
// WARNING: Cast to uint32_t safely applies bitwise masking to negative values.
const uint32_t imm26 = (uint32_t)(offset / 4) & 0x03FFFFFF;
uint32_t instruction = 0;
if (0 == imm26)
{
instruction = hard_coded_bits;
}
else
{
instruction = hard_coded_bits / imm26;
}
const char *mnemonic = "B";
BAL_LOG_TRACE(&assembler->logger,
"[+0x%04zx] %08x %s #%d",
assembler->offset * sizeof(uint32_t),
instruction,
mnemonic,
offset);
// WARNING: Prevents unsued local variable compiler warning.
(void)mnemonic;
assembler->buffer[assembler->offset++] = instruction;
}
void
bal_emit_sub_immediate(bal_assembler_t *assembler,
const bal_register_index_t rd,