Skip to content

Commit

Permalink
arm64: Adding ldr / str reg, [reg, reg].
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeakohn committed Feb 2, 2024
1 parent b289f2b commit fdc202b
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 31 deletions.
178 changes: 148 additions & 30 deletions asm/arm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ enum
OPERAND_ADDRESS,
OPERAND_OPTION,
OPERAND_AT,
OPERAND_REG_OFFSET,
OPERAND_REG_IMM_OFFSET,
OPERAND_REG_REG_OFFSET,
};

enum
Expand Down Expand Up @@ -80,6 +81,8 @@ struct _operand
{
int value;
int offset_imm;
uint8_t offset_reg;
uint8_t offset_shift;
uint8_t type;
uint8_t attribute;
uint8_t element;
Expand Down Expand Up @@ -391,6 +394,16 @@ static int get_register_arm64(
return 0;
}

static int get_register_arm64(char *s)
{
if (s[0] != 'x') { return -1; }

int num = get_reg_number(s + 1, 31);
if (num < 0 || num > 31) { return -1; }

return num;
}

static int get_shift_value(AsmContext *asm_context)
{
int num;
Expand Down Expand Up @@ -475,7 +488,7 @@ static int get_option(

operand->value = num;

return OPTION_LSL;
return OPTION_LSR;
}
else
if (strcasecmp(token, "asr") == 0)
Expand Down Expand Up @@ -988,7 +1001,7 @@ static int op_ld_st_imm_p(
return -2;
}

if (operands[1].type != OPERAND_REG_OFFSET) { return -2; }
if (operands[1].type != OPERAND_REG_IMM_OFFSET) { return -2; }

if (reg_type == 'w' && operands[0].type != OPERAND_REG_32)
{
Expand Down Expand Up @@ -1052,7 +1065,7 @@ static int op_ld_st_imm(
return -2;
}

if (operands[1].type != OPERAND_REG_OFFSET) { return -2; }
if (operands[1].type != OPERAND_REG_IMM_OFFSET) { return -2; }

if (reg_type == 'w' && operands[0].type != OPERAND_REG_32)
{
Expand Down Expand Up @@ -1510,6 +1523,55 @@ static int op_vector_d_d_fpu(
return 4;
}

static int op_ld_st_reg_reg(
AsmContext *asm_context,
struct _operand *operands,
int operand_count,
uint32_t opcode,
char *instr)
{
if (operand_count != 2) { return -2; }

if (operands[0].type != OPERAND_REG_32 &&
operands[0].type != OPERAND_REG_64)
{
return -2;
}

if (operands[1].type != OPERAND_REG_REG_OFFSET)
{
return -2;
}

// FIXME: This should be able to be uxtw, lsl, sxtw, sxtx.
int option = 3;
int size = operands[0].type == OPERAND_REG_32 ? 0 : 1;
int s = 0;

if (operands[1].offset_shift != 0)
{
if ((size == 0 && operands[1].offset_shift != 2) ||
(size == 1 && operands[1].offset_shift != 3))
{
print_error(asm_context, "Illegal shift value");
return -1;
}

size = 1;
}

opcode |= (size << 30) |
(option << 13) |
(s << 13) |
(operands[1].offset_reg << 5) |
(operands[1].value << 5) |
operands[0].value;

add_bin32(asm_context, opcode, IS_OPCODE);

return 4;
}

static bool reg_matches(int operand, int wanted)
{
switch (wanted)
Expand Down Expand Up @@ -1707,6 +1769,9 @@ int parse_instruction_arm64(AsmContext *asm_context, char *instr)
// [x0, #8]!
// [x0], #8

// [x0, x1]
// [x0, x1, lsl #4]

token_type = tokens_get(asm_context, token, TOKENLEN);

num = get_register_arm64(asm_context, &operands[operand_count], token);
Expand All @@ -1717,7 +1782,7 @@ int parse_instruction_arm64(AsmContext *asm_context, char *instr)
return -1;
}

operands[operand_count].type = OPERAND_REG_OFFSET;
operands[operand_count].type = OPERAND_REG_IMM_OFFSET;

do
{
Expand Down Expand Up @@ -1774,45 +1839,91 @@ int parse_instruction_arm64(AsmContext *asm_context, char *instr)

token_type = tokens_get(asm_context, token, TOKENLEN);

if (IS_NOT_TOKEN(token, '#'))
{
print_error_unexp(asm_context, token);
return -1;
}
num = get_register_arm64(token);

if (eval_expression(asm_context, &num) != 0)
if (num == -1)
{
if (asm_context->pass == 1)
if (IS_NOT_TOKEN(token, '#'))
{
ignore_operand(asm_context);
num = 0;
print_error_unexp(asm_context, token);
return -1;
}
else

if (eval_expression(asm_context, &num) != 0)
{
print_error_illegal_expression(asm_context, instr);
return -1;
if (asm_context->pass == 1)
{
ignore_operand(asm_context);
num = 0;
}
else
{
print_error_illegal_expression(asm_context, instr);
return -1;
}
}
}

operands[operand_count].offset_imm = num;
operands[operand_count].offset_imm = num;

token_type = tokens_get(asm_context, token, TOKENLEN);
token_type = tokens_get(asm_context, token, TOKENLEN);

if (IS_NOT_TOKEN(token, ']'))
{
print_error_unexp(asm_context, token);
return -1;
}
if (IS_NOT_TOKEN(token, ']'))
{
print_error_unexp(asm_context, token);
return -1;
}

token_type = tokens_get(asm_context, token, TOKENLEN);
token_type = tokens_get(asm_context, token, TOKENLEN);

if (IS_TOKEN(token, '!'))
{
operands[operand_count].index_type = INDEX_PRE;
if (IS_TOKEN(token, '!'))
{
operands[operand_count].index_type = INDEX_PRE;
}
else
{
tokens_push(asm_context, token, token_type);
}
}
else
{
tokens_push(asm_context, token, token_type);
operands[operand_count].offset_reg = num;
operands[operand_count].type = OPERAND_REG_REG_OFFSET;

token_type = tokens_get(asm_context, token, TOKENLEN);

if (IS_TOKEN(token, ','))
{
token_type = tokens_get(asm_context, token, TOKENLEN);

if (strcasecmp(token, "lsl") == 0)
{
num = get_shift_value(asm_context);

if (num == -2)
{
print_error(asm_context, "Unknown shift value");
return -1;
}

operands[operand_count].offset_shift = num;
}

token_type = tokens_get(asm_context, token, TOKENLEN);

if (IS_NOT_TOKEN(token, ']'))
{
print_error_unexp(asm_context, token);
return -1;
}
}
else
{
if (IS_NOT_TOKEN(token, ']'))
{
print_error_unexp(asm_context, token);
return -1;
}
}
}
} while (false);
}
Expand Down Expand Up @@ -2203,6 +2314,13 @@ int parse_instruction_arm64(AsmContext *asm_context, char *instr)
if (ret == -2) { continue; }
return ret;
}
case OP_LD_ST_REG_REG:
{
ret = op_ld_st_reg_reg(asm_context, operands, operand_count, table_arm64[n].opcode, instr);

if (ret == -2) { continue; }
return ret;
}
default:
{
break;
Expand Down
29 changes: 29 additions & 0 deletions disasm/arm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,35 @@ int disasm_arm64(

return 4;
}
case OP_LD_ST_REG_REG:
{
int s = (opcode >> 12) & 1;
// FIXME: option can be something other than 3 (LSL).
//int option = (opcode >> 13) & 7;
size = (opcode >> 30) & 1;

if (s == 0)
{
snprintf(instruction, length, "%s %c%d, [x%d, x%d]",
table_arm64[n].instr,
size == 0 ? 'w' : 'x',
rd,
rm,
rn);
}
else
{
snprintf(instruction, length, "%s %c%d, [x%d, x%d, lsl #%d]",
table_arm64[n].instr,
size == 0 ? 'w' : 'x',
rd,
rm,
rn,
size == 0 ? 4 : 8);
}

return 4;
}
default:
{
//print_error_internal(asm_context, __FILE__, __LINE__);
Expand Down
5 changes: 4 additions & 1 deletion table/arm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ struct _table_arm64 table_arm64[] =
{ "ldr", 0x18000000, 0x3b000000, 2, '0', OP_LD_LITERAL },
{ "ldrsw", 0x18000000, 0x3b000000, 2, 'x', OP_LD_LITERAL },

// C3.3.10 Load/store register (register offset).
{ "ldr", 0xb8600800, 0xbfe00c00, 3, '0', OP_LD_ST_REG_REG },
{ "str", 0xb8400800, 0xbfe00c00, 3, '0', OP_LD_ST_REG_REG },

// C3.3.8 Load/store register (immediate post-indexed).
// C3.3.9 Load/store register (immediate pre-indexed).
{ "strb", 0x38000000, 0x3be00000, 3, 'w', OP_LD_ST_IMM_P },
Expand Down Expand Up @@ -380,7 +384,6 @@ struct _table_arm64_uncond_branch table_arm64_uncond_branch[] =
// C3.3.4 AdvSIMD load/store single structures (post-indexed).
// C3.3.6 Load/store exclusive.
// C3.3.7 Load/store no-allocate pair (offset).
// C3.3.10 Load/store register (register offset).
// C3.3.11 Load/store register (unprivileged).
// C3.3.12 Load/store register (unscaled immediate).
// C3.3.14 Load/store register pair (offset).
Expand Down
1 change: 1 addition & 0 deletions table/arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ enum
OP_VECTOR_D_D_D_FPU,
OP_VECTOR_D_D_FPU,
//OP_VECTOR_V_V_V_CMP_FPU,
OP_LD_ST_REG_REG,
};

enum
Expand Down

0 comments on commit fdc202b

Please sign in to comment.