On 11/19/2013 06:17 PM, Claudio Fontana wrote:
> Hello all,
> 
> On 09/27/2013 02:48 AM, Alexander Graf wrote:
>> This patch adds emulation support for the adr instruction.
>>
>> Signed-off-by: Alexander Graf <ag...@suse.de>
>> ---
>>  target-arm/translate-a64.c | 24 ++++++++++++++++++++++++
>>  1 file changed, 24 insertions(+)
>>
>> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
>> index bc91324..00eda0f 100644
>> --- a/target-arm/translate-a64.c
>> +++ b/target-arm/translate-a64.c
>> @@ -943,6 +943,27 @@ static void handle_insg(DisasContext *s, uint32_t insn)
>>      simd_st(cpu_reg(rn), freg_offs_d + idx, size);
>>  }
>>  
>> +/* PC relative address calculation */
>> +static void handle_adr(DisasContext *s, uint32_t insn)
>> +{
>> +    int reg = get_reg(insn);
>> +    int is_page = get_bits(insn, 31, 1);
>> +    uint64_t imm;
>> +    uint64_t base;
>> +
>> +    imm = get_sbits(insn, 5, 19) << 2;
>> +    imm |= get_bits(insn, 29, 2);
>> +
>> +    base = s->pc - 4;
>> +    if (is_page) {
>> +        /* ADRP (page based) */
>> +        base &= ~0xFFFULL;
>> +        imm <<= 12;
>> +    }
>> +
>> +    tcg_gen_movi_i64(cpu_reg(reg), base + imm);
>> +}
>> +
> 
> does this work with negative values?
> The spec says to SignExtend:
> 
> if page then
>     imm = SignExtend(immhi:immlo:Zeros(12), 64);
> else
>     imm = SignExtend(immhi:immlo, 64);
> 
> /*...*/
> 
> maybe Michael you know if this is an issue in practice?
> If I want to get a negative PC relative offset, how does this work?
> 
> Claudio


This is a totally untested idea of what I would think/roughly implement:

static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
{
    /*
     * 31 30 29 28 27 26 25 24 23     5 4  0
     * op immlo  1  0  0  0  0   immhi   Rd
     */
    unsigned int page, imm, rd, len; /* op -> page, immhi:immlo -> imm */
    uint64_t base;
    sint64_t offset; /* SignExtend(imm) -> offset */

    page = insn & (1 << 31) ? 1 : 0;
    imm = extract32(insn, 29, 2) + extract32(insn, 5, 19) << 2;
    rd = extract32(insn, 0, 5);

    base = s->pc - 4;
    len = 19 + 2; /* immhi:immlo */
    offset = imm;

    if (page) {
        /* ADRP (page based) */
        base &= ~0xfff;
        len += 12; /* immhi:immlo:Zeros(12) */
        offset <<= 12; /* apply Zeros */
    }

    offset = (offset << (64 - len)) >> (64 - len); /* sign extend */
    tcg_gen_movi_i64(cpu_reg(reg), base + offset);
}

But maybe I am completely off and the original code is perfectly fine..?

C.

> 
> 
>>  /* SIMD ORR */
>>  static void handle_simdorr(DisasContext *s, uint32_t insn)
>>  {
>> @@ -1365,6 +1386,9 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s)
>>              unallocated_encoding(s);
>>          }
>>          break;
>> +    case 0x10:
>> +        handle_adr(s, insn);
>> +        break;
>>      default:
>>          unallocated_encoding(s);
>>          break;
>>
> 


Reply via email to