diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2018-06-22 15:11:53 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-07-02 13:08:21 +0100 |
commit | 14055ad0e5908cd4aec1e745c92b916afd0f08d3 (patch) | |
tree | 8e6ec6d5201560bdf14aa3eb60df054564e3584f | |
parent | 6bfdbf02e90d1e53b9aee9a22459c6d1bdaa9966 (diff) |
risugen: add reg_plus_imm_pl and reg_plus_imm_vl address helpers
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20180622141205.16306-11-alex.bennee@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | risugen_arm.pm | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/risugen_arm.pm b/risugen_arm.pm index 485e94e..696bf5f 100644 --- a/risugen_arm.pm +++ b/risugen_arm.pm @@ -306,6 +306,52 @@ sub write_mov_ri($$) } } +sub write_addpl_rri($$$) +{ + my ($rd, $rn, $imm) = @_; + die "write_addpl: invalid operation for this arch.\n" if (!$is_aarch64); + + insn32(0x04605000 | ($rn << 16) | (($imm & 0x3f) << 5) | $rd); +} + +sub write_addvl_rri($$$) +{ + my ($rd, $rn, $imm) = @_; + die "write_addvl: invalid operation for this arch.\n" if (!$is_aarch64); + + insn32(0x04205000 | ($rn << 16) | (($imm & 0x3f) << 5) | $rd); +} + +sub write_rdvl_ri($$) +{ + my ($rd, $imm) = @_; + die "write_rdvl: invalid operation for this arch.\n" if (!$is_aarch64); + + insn32(0x04bf5000 | (($imm & 0x3f) << 5) | $rd); +} + +sub write_madd_rrrr($$$$) +{ + my ($rd, $rn, $rm, $ra) = @_; + die "write_madd: invalid operation for this arch.\n" if (!$is_aarch64); + + insn32(0x9b000000 | ($rm << 16) | ($ra << 10) | ($rn << 5) | $rd); +} + +sub write_msub_rrrr($$$$) +{ + my ($rd, $rn, $rm, $ra) = @_; + die "write_msub: invalid operation for this arch.\n" if (!$is_aarch64); + + insn32(0x9b008000 | ($rm << 16) | ($ra << 10) | ($rn << 5) | $rd); +} + +sub write_mul_rrr($$$) +{ + my ($rd, $rn, $rm) = @_; + write_madd_rrrr($rd, $rn, $rm, 31); +} + # write random fp value of passed precision (1=single, 2=double, 4=quad) sub write_random_fpreg_var($) { @@ -767,6 +813,86 @@ sub reg_plus_imm($$@) return $base; } +sub reg_plus_imm_pl($$@) +{ + # Handle reg + immediate addressing mode + my ($base, $imm, @trashed) = @_; + if ($imm == 0) { + return reg($base, @trashed); + } + write_get_offset(); + + # Now r0 is the address we want to do the access to, + # so set the basereg by doing the inverse of the + # addressing mode calculation, ie base = r0 - imm + # + # Note that addpl has a 6-bit immediate, but ldr has a 9-bit + # immediate, so we need to be able to support larger immediates. + + if (-$imm >= -32 && -$imm <= 31) { + write_addpl_rri($base, 0, -$imm); + } else { + # We borrow r1 and r2 as a temporaries (not a problem + # as long as we don't leave anything in a register + # which depends on the location of the memory block) + write_mov_ri(1, 0); + write_mov_ri(2, $imm); + write_addpl_rri(1, 1, 1); + write_msub_rrrr($base, 1, 2, 0); + } + if (grep $_ == $base, @trashed) { + return -1; + } + return $base; +} + +sub reg_plus_imm_vl($$@) +{ + # The usual address formulation is + # elements = VL DIV esize + # mbytes = msize DIV 8 + # addr = base + imm * elements * mbytes + # Here we compute + # scale = log2(esize / msize) + # base + (imm * VL) >> scale + my ($base, $imm, $scale, @trashed) = @_; + if ($imm == 0) { + return reg($base, @trashed); + } + write_get_offset(); + + # Now r0 is the address we want to do the access to, + # so set the basereg by doing the inverse of the + # addressing mode calculation, ie base = r0 - imm + # + # Note that rdvl/addvl have a 6-bit immediate, but ldr has a 9-bit + # immediate, so we need to be able to support larger immediates. + + use integer; + my $mul = 1 << $scale; + my $imm_div = $imm / $mul; + + if ($imm == $imm_div * $mul && -$imm_div >= -32 && -$imm_div <= 31) { + write_addvl_rri($base, 0, -$imm_div); + } elsif ($imm >= -32 && $imm <= 31) { + write_rdvl_ri(1, $imm); + write_sub_rrrs($base, 0, 1, $SHIFT_ASR, $scale); + } else { + write_rdvl_ri(1, 1); + write_mov_ri(2, $imm); + if ($scale == 0) { + write_msub_rrrr($base, 1, 2, 0); + } else { + write_mul_rrr(1, 1, 2); + write_sub_rrrs($base, 0, 1, $SHIFT_ASR, $scale); + } + } + if (grep $_ == $base, @trashed) { + return -1; + } + return $base; +} + sub reg_minus_imm($$@) { my ($base, $imm, @trashed) = @_; |