arm-asm: Add b, bl, bx, blx
This commit is contained in:
parent
3b1f06c3b2
commit
b85c3e1595
2 changed files with 67 additions and 0 deletions
60
arm-asm.c
60
arm-asm.c
|
@ -754,6 +754,61 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note: almost dupe of encbranch in arm-gen.c */
|
||||||
|
static uint32_t encbranchoffset(int pos, int addr, int fail)
|
||||||
|
{
|
||||||
|
addr-=pos+8;
|
||||||
|
addr/=4;
|
||||||
|
if(addr>=0x1000000 || addr<-0x1000000) { // FIXME: Is that correct?
|
||||||
|
if(fail)
|
||||||
|
tcc_error("function bigger than 32MB");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return /*not 0x0A000000|*/(addr&0xffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_branch_opcode(TCCState *s1, int token)
|
||||||
|
{
|
||||||
|
int jmp_disp = 0;
|
||||||
|
Operand op;
|
||||||
|
parse_operand(s1, &op);
|
||||||
|
if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N) {
|
||||||
|
jmp_disp = encbranchoffset(ind, op.e.v, 0);
|
||||||
|
if (jmp_disp < -0x800000 || jmp_disp > 0x7fffff) {
|
||||||
|
tcc_error("branch is too far");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (ARM_INSTRUCTION_GROUP(token)) {
|
||||||
|
case TOK_ASM_beq:
|
||||||
|
if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N)
|
||||||
|
asm_emit_opcode(token, (0xa << 24) | (jmp_disp & 0xffffff));
|
||||||
|
else
|
||||||
|
expect("branch target");
|
||||||
|
break;
|
||||||
|
case TOK_ASM_bleq:
|
||||||
|
if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N)
|
||||||
|
asm_emit_opcode(token, (0xb << 24) | (jmp_disp & 0xffffff));
|
||||||
|
else
|
||||||
|
expect("branch target");
|
||||||
|
break;
|
||||||
|
case TOK_ASM_bxeq:
|
||||||
|
if (op.type != OP_REG32)
|
||||||
|
expect("register");
|
||||||
|
else
|
||||||
|
asm_emit_opcode(token, (0x12fff1 << 4) | op.reg);
|
||||||
|
break;
|
||||||
|
case TOK_ASM_blxeq:
|
||||||
|
if (op.type != OP_REG32)
|
||||||
|
expect("register");
|
||||||
|
else
|
||||||
|
asm_emit_opcode(token, (0x12fff3 << 4) | op.reg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
expect("branch instruction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ST_FUNC void asm_opcode(TCCState *s1, int token)
|
ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||||
{
|
{
|
||||||
while (token == TOK_LINEFEED) {
|
while (token == TOK_LINEFEED) {
|
||||||
|
@ -787,6 +842,11 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||||
return asm_nullary_opcode(token);
|
return asm_nullary_opcode(token);
|
||||||
case TOK_ASM_swieq:
|
case TOK_ASM_swieq:
|
||||||
return asm_unary_opcode(s1, token);
|
return asm_unary_opcode(s1, token);
|
||||||
|
case TOK_ASM_beq:
|
||||||
|
case TOK_ASM_bleq:
|
||||||
|
case TOK_ASM_bxeq:
|
||||||
|
case TOK_ASM_blxeq:
|
||||||
|
return asm_branch_opcode(s1, token);
|
||||||
case TOK_ASM_clzeq:
|
case TOK_ASM_clzeq:
|
||||||
case TOK_ASM_sxtbeq:
|
case TOK_ASM_sxtbeq:
|
||||||
case TOK_ASM_sxtheq:
|
case TOK_ASM_sxtheq:
|
||||||
|
|
|
@ -104,6 +104,13 @@
|
||||||
DEF_ASM_CONDED(push)
|
DEF_ASM_CONDED(push)
|
||||||
DEF_ASM_CONDED(pop)
|
DEF_ASM_CONDED(pop)
|
||||||
|
|
||||||
|
/* branches */
|
||||||
|
|
||||||
|
DEF_ASM_CONDED(b)
|
||||||
|
DEF_ASM_CONDED(bl)
|
||||||
|
DEF_ASM_CONDED(bx)
|
||||||
|
DEF_ASM_CONDED(blx)
|
||||||
|
|
||||||
/* data processing instructions; order is important */
|
/* data processing instructions; order is important */
|
||||||
|
|
||||||
DEF_ASM_CONDED(and)
|
DEF_ASM_CONDED(and)
|
||||||
|
|
Loading…
Add table
Reference in a new issue