mirror of
https://github.com/pound-emu/ballistic.git
synced 2026-06-17 04:16:48 -07:00
assembler: emit ADD (Shifted Register) instructions
Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
@@ -95,6 +95,23 @@ extern "C"
|
||||
uint16_t imm12,
|
||||
uint8_t shift);
|
||||
|
||||
/// Emits a `ADD` (Shifted Register) instruction.
|
||||
///
|
||||
/// Adds a register value `rn` and a shifted register `rm`, and writes the result to `rd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `rd`, `rn`, `rm` must be valid registers (0-31).
|
||||
/// * `shift` must be between 0 and 63.
|
||||
/// * `shift_type` must be 0 (LSL), 1 (LSR), or 2 (ASR).
|
||||
/// * Function does not emit instructions if `assembler->status` != [`BAL_SUCCESS`].
|
||||
void bal_emit_add_shifted_register(bal_assembler_t *assembler,
|
||||
bal_register_index_t rd,
|
||||
bal_register_index_t rn,
|
||||
bal_register_index_t rm,
|
||||
uint8_t shift,
|
||||
uint8_t shift_type);
|
||||
|
||||
/// Emits a `B` (Branch) instruction.
|
||||
///
|
||||
/// Branches unconditionally to a PC-relative offset.
|
||||
|
||||
+95
-2
@@ -104,6 +104,98 @@ bal_emit_add_immediate(bal_assembler_t *assembler,
|
||||
assembler->buffer[assembler->offset++] = instruction;
|
||||
}
|
||||
|
||||
void
|
||||
bal_emit_add_shifted_register(bal_assembler_t *assembler,
|
||||
bal_register_index_t rd,
|
||||
bal_register_index_t rn,
|
||||
bal_register_index_t rm,
|
||||
uint8_t shift,
|
||||
uint8_t shift_type)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (BAL_UNLIKELY(assembler->status != BAL_SUCCESS))
|
||||
{
|
||||
BAL_LOG_ERROR(&assembler->logger, "Aborting function: assembler->status != BAL_SUCCESS");
|
||||
return;
|
||||
}
|
||||
|
||||
const bool can_emit_return_value = can_emit(assembler);
|
||||
|
||||
if (BAL_UNLIKELY(false == can_emit_return_value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (BAL_UNLIKELY(rd > 31))
|
||||
{
|
||||
BAL_LOG_ERROR(&assembler->logger, "Rd X%u out of range (0-31).", rd);
|
||||
assembler->status = BAL_ERROR_INVALID_ARGUMENT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (BAL_UNLIKELY(rn > 31))
|
||||
{
|
||||
BAL_LOG_ERROR(&assembler->logger, "Rn X%u out of range (0-31).", rn);
|
||||
assembler->status = BAL_ERROR_INVALID_ARGUMENT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (BAL_UNLIKELY(rm > 31))
|
||||
{
|
||||
BAL_LOG_ERROR(&assembler->logger, "Rm X%u out of range (0-31).", rm);
|
||||
assembler->status = BAL_ERROR_INVALID_ARGUMENT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (BAL_UNLIKELY(shift > 63))
|
||||
{
|
||||
BAL_LOG_ERROR(&assembler->logger, "%u is not a valid shift amount (0-63).", shift);
|
||||
assembler->status = BAL_ERROR_INVALID_ARGUMENT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (BAL_UNLIKELY(shift_type > 2))
|
||||
{
|
||||
BAL_LOG_ERROR(&assembler->logger, "%u is not a valid shift type (0-2).", shift_type);
|
||||
assembler->status = BAL_ERROR_INVALID_ARGUMENT;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t sf = 1U;
|
||||
const uint32_t opcode = 0x0BU;
|
||||
uint32_t instruction = 0;
|
||||
instruction |= sf << 31;
|
||||
instruction |= opcode << 24;
|
||||
instruction |= (uint32_t)shift_type << 22;
|
||||
instruction |= (uint32_t)rm << 16;
|
||||
instruction |= (uint32_t)rn << 5;
|
||||
instruction |= (uint32_t)rd;
|
||||
|
||||
const char *mnemonic = "ADD (Shifted Register)";
|
||||
BAL_LOG_TRACE(&assembler->logger,
|
||||
"[+0X%04zx] %08x %s X%u, X%u, X%u, shift %u",
|
||||
assembler->offset * sizeof(uint32_t),
|
||||
instruction,
|
||||
mnemonic,
|
||||
rd,
|
||||
rn,
|
||||
rm,
|
||||
shift);
|
||||
(void)mnemonic;
|
||||
assembler->buffer[assembler->offset++] = instruction;
|
||||
}
|
||||
|
||||
void
|
||||
bal_emit_b(bal_assembler_t *assembler, const int32_t offset)
|
||||
{
|
||||
@@ -367,8 +459,9 @@ can_emit(bal_assembler_t *assembler)
|
||||
{
|
||||
if (assembler->offset >= assembler->capacity)
|
||||
{
|
||||
BAL_LOG_ERROR(
|
||||
&assembler->logger, "Assembler Overflow. Capacity %zu reached.", assembler->capacity);
|
||||
BAL_LOG_ERROR(&assembler->logger,
|
||||
"Aborting function: Assembler Overflow. Capacity %zu reached.",
|
||||
assembler->capacity);
|
||||
assembler->status = BAL_ERROR_INSTRUCTION_OVERFLOW;
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user