Minor cleanups.
Finish the rest of the hexagon integer instructions. -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmCOuVkdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV9fPwf+LWjCR4/zBWLb6Irj SmpL4Ev+LQaMjFyiDV1U5wM17vOw9fTwM5CFofxkOHbv94uMd4hFD2E2o3ajfVqN 2GvZJBebEWt4WboglIOq7n1SGp4BEIfmqklz3MwuNBVgOM7QNta55UoJd+d0ScoS Clxx/Tu92iqE3ksiMwVsvw2v4BaT0FU8FlkpNeKeTOswWVWsUg16mzEKHZSa+hjW lFTWW7MUxJgrf4yQ7XwfrU6+VSMhstnSFDVqUaNkJnBnaEzhkEWPpHLiNUJWAUqo E14s+QoEO4kdPFO2OqwH5TrARh+IzDjABTWDIOEpGIPGetlOQRcnx+vFyS+n3S6T XVNedQ== =t+/4 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth-gitlab/tags/pull-hex-20210502' into staging Minor cleanups. Finish the rest of the hexagon integer instructions. # gpg: Signature made Sun 02 May 2021 15:38:17 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth-gitlab/tags/pull-hex-20210502: (31 commits) Hexagon (target/hexagon) CABAC decode bin Hexagon (target/hexagon) load into shifted register instructions Hexagon (target/hexagon) load and unpack bytes instructions Hexagon (target/hexagon) bit reverse (brev) addressing Hexagon (target/hexagon) circular addressing Hexagon (target/hexagon) add A4_addp_c/A4_subp_c Hexagon (target/hexagon) add A6_vminub_RdP Hexagon (target/hexagon) add A5_ACS (vacsh) Hexagon (target/hexagon) add F2_sfinvsqrta Hexagon (target/hexagon) add F2_sfrecipa instruction Hexagon (target/hexagon) compile all debug code Hexagon (target/hexagon) move QEMU_GENERATE to only be on during macros.h Hexagon (target/hexagon) cleanup reg_field_info definition Hexagon (target/hexagon) cleanup ternary operators in semantics Hexagon (target/hexagon) use softfloat for float-to-int conversions Hexagon (target/hexagon) replace float32_mul_pow2 with float32_scalbn Hexagon (target/hexagon) use softfloat default NaN and tininess Hexagon (target/hexagon) change type of softfloat_roundingmodes Hexagon (target/hexagon) remove unused carry_from_add64 function Hexagon (target/hexagon) change variables from int to bool when appropriate ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
15106f7dc3
@ -145,6 +145,9 @@ static FloatParts parts_default_nan(float_status *status)
|
||||
#elif defined(TARGET_HPPA)
|
||||
/* snan_bit_is_one, set msb-1. */
|
||||
frac = 1ULL << (DECOMPOSED_BINARY_POINT - 2);
|
||||
#elif defined(TARGET_HEXAGON)
|
||||
sign = 1;
|
||||
frac = ~0ULL;
|
||||
#else
|
||||
/* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
|
||||
* S390, SH4, TriCore, and Xtensa. I cannot find documentation
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
void cpu_loop(CPUHexagonState *env)
|
||||
{
|
||||
CPUState *cs = CPU(hexagon_env_get_cpu(env));
|
||||
CPUState *cs = env_cpu(env);
|
||||
int trapnr, signum, sigcode;
|
||||
target_ulong sigaddr;
|
||||
target_ulong syscallnum;
|
||||
|
@ -27,6 +27,97 @@
|
||||
#define SF_MANTBITS 23
|
||||
#define float32_nan make_float32(0xffffffff)
|
||||
|
||||
/*
|
||||
* These three tables are used by the cabacdecbin instruction
|
||||
*/
|
||||
const uint8_t rLPS_table_64x4[64][4] = {
|
||||
{128, 176, 208, 240},
|
||||
{128, 167, 197, 227},
|
||||
{128, 158, 187, 216},
|
||||
{123, 150, 178, 205},
|
||||
{116, 142, 169, 195},
|
||||
{111, 135, 160, 185},
|
||||
{105, 128, 152, 175},
|
||||
{100, 122, 144, 166},
|
||||
{95, 116, 137, 158},
|
||||
{90, 110, 130, 150},
|
||||
{85, 104, 123, 142},
|
||||
{81, 99, 117, 135},
|
||||
{77, 94, 111, 128},
|
||||
{73, 89, 105, 122},
|
||||
{69, 85, 100, 116},
|
||||
{66, 80, 95, 110},
|
||||
{62, 76, 90, 104},
|
||||
{59, 72, 86, 99},
|
||||
{56, 69, 81, 94},
|
||||
{53, 65, 77, 89},
|
||||
{51, 62, 73, 85},
|
||||
{48, 59, 69, 80},
|
||||
{46, 56, 66, 76},
|
||||
{43, 53, 63, 72},
|
||||
{41, 50, 59, 69},
|
||||
{39, 48, 56, 65},
|
||||
{37, 45, 54, 62},
|
||||
{35, 43, 51, 59},
|
||||
{33, 41, 48, 56},
|
||||
{32, 39, 46, 53},
|
||||
{30, 37, 43, 50},
|
||||
{29, 35, 41, 48},
|
||||
{27, 33, 39, 45},
|
||||
{26, 31, 37, 43},
|
||||
{24, 30, 35, 41},
|
||||
{23, 28, 33, 39},
|
||||
{22, 27, 32, 37},
|
||||
{21, 26, 30, 35},
|
||||
{20, 24, 29, 33},
|
||||
{19, 23, 27, 31},
|
||||
{18, 22, 26, 30},
|
||||
{17, 21, 25, 28},
|
||||
{16, 20, 23, 27},
|
||||
{15, 19, 22, 25},
|
||||
{14, 18, 21, 24},
|
||||
{14, 17, 20, 23},
|
||||
{13, 16, 19, 22},
|
||||
{12, 15, 18, 21},
|
||||
{12, 14, 17, 20},
|
||||
{11, 14, 16, 19},
|
||||
{11, 13, 15, 18},
|
||||
{10, 12, 15, 17},
|
||||
{10, 12, 14, 16},
|
||||
{9, 11, 13, 15},
|
||||
{9, 11, 12, 14},
|
||||
{8, 10, 12, 14},
|
||||
{8, 9, 11, 13},
|
||||
{7, 9, 11, 12},
|
||||
{7, 9, 10, 12},
|
||||
{7, 8, 10, 11},
|
||||
{6, 8, 9, 11},
|
||||
{6, 7, 9, 10},
|
||||
{6, 7, 8, 9},
|
||||
{2, 2, 2, 2}
|
||||
};
|
||||
|
||||
const uint8_t AC_next_state_MPS_64[64] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||
51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
|
||||
61, 62, 62, 63
|
||||
};
|
||||
|
||||
|
||||
const uint8_t AC_next_state_LPS_64[64] = {
|
||||
0, 0, 1, 2, 2, 4, 4, 5, 6, 7,
|
||||
8, 9, 9, 11, 11, 12, 13, 13, 15, 15,
|
||||
16, 16, 18, 18, 19, 19, 21, 21, 22, 22,
|
||||
23, 24, 24, 25, 26, 26, 27, 27, 28, 29,
|
||||
29, 30, 30, 30, 31, 32, 32, 33, 33, 33,
|
||||
34, 34, 35, 35, 35, 36, 36, 36, 37, 37,
|
||||
37, 38, 38, 63
|
||||
};
|
||||
|
||||
#define BITS_MASK_8 0x5555555555555555ULL
|
||||
#define PAIR_MASK_8 0x3333333333333333ULL
|
||||
#define NYBL_MASK_8 0x0f0f0f0f0f0f0f0fULL
|
||||
@ -76,19 +167,6 @@ uint64_t deinterleave(uint64_t src)
|
||||
return myeven | (myodd << 32);
|
||||
}
|
||||
|
||||
uint32_t carry_from_add64(uint64_t a, uint64_t b, uint32_t c)
|
||||
{
|
||||
uint64_t tmpa, tmpb, tmpc;
|
||||
tmpa = fGETUWORD(0, a);
|
||||
tmpb = fGETUWORD(0, b);
|
||||
tmpc = tmpa + tmpb + c;
|
||||
tmpa = fGETUWORD(1, a);
|
||||
tmpb = fGETUWORD(1, b);
|
||||
tmpc = tmpa + tmpb + fGETUWORD(1, tmpc);
|
||||
tmpc = fGETUWORD(1, tmpc);
|
||||
return tmpc;
|
||||
}
|
||||
|
||||
int32_t conv_round(int32_t a, int n)
|
||||
{
|
||||
int64_t val;
|
||||
@ -108,7 +186,7 @@ int32_t conv_round(int32_t a, int n)
|
||||
|
||||
/* Floating Point Stuff */
|
||||
|
||||
static const int softfloat_roundingmodes[] = {
|
||||
static const FloatRoundMode softfloat_roundingmodes[] = {
|
||||
float_round_nearest_even,
|
||||
float_round_to_zero,
|
||||
float_round_down,
|
||||
@ -156,12 +234,6 @@ void arch_fpop_end(CPUHexagonState *env)
|
||||
}
|
||||
}
|
||||
|
||||
static float32 float32_mul_pow2(float32 a, uint32_t p, float_status *fp_status)
|
||||
{
|
||||
float32 b = make_float32((SF_BIAS + p) << SF_MANTBITS);
|
||||
return float32_mul(a, b, fp_status);
|
||||
}
|
||||
|
||||
int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust,
|
||||
float_status *fp_status)
|
||||
{
|
||||
@ -200,12 +272,13 @@ int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust,
|
||||
/* or put Inf in num fixup? */
|
||||
uint8_t RsV_sign = float32_is_neg(RsV);
|
||||
uint8_t RtV_sign = float32_is_neg(RtV);
|
||||
/* Check that RsV is NOT infinite before we overwrite it */
|
||||
if (!float32_is_infinity(RsV)) {
|
||||
float_raise(float_flag_divbyzero, fp_status);
|
||||
}
|
||||
RsV = infinite_float32(RsV_sign ^ RtV_sign);
|
||||
RtV = float32_one;
|
||||
RdV = float32_one;
|
||||
if (float32_is_infinity(RsV)) {
|
||||
float_raise(float_flag_divbyzero, fp_status);
|
||||
}
|
||||
} else if (float32_is_infinity(RtV)) {
|
||||
RsV = make_float32(0x80000000 & (RsV ^ RtV));
|
||||
RtV = float32_one;
|
||||
@ -230,22 +303,22 @@ int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust,
|
||||
if ((n_exp - d_exp + SF_BIAS) <= SF_MANTBITS) {
|
||||
/* Near quotient underflow / inexact Q */
|
||||
PeV = 0x80;
|
||||
RtV = float32_mul_pow2(RtV, -64, fp_status);
|
||||
RsV = float32_mul_pow2(RsV, 64, fp_status);
|
||||
RtV = float32_scalbn(RtV, -64, fp_status);
|
||||
RsV = float32_scalbn(RsV, 64, fp_status);
|
||||
} else if ((n_exp - d_exp + SF_BIAS) > (SF_MAXEXP - 24)) {
|
||||
/* Near quotient overflow */
|
||||
PeV = 0x40;
|
||||
RtV = float32_mul_pow2(RtV, 32, fp_status);
|
||||
RsV = float32_mul_pow2(RsV, -32, fp_status);
|
||||
RtV = float32_scalbn(RtV, 32, fp_status);
|
||||
RsV = float32_scalbn(RsV, -32, fp_status);
|
||||
} else if (n_exp <= SF_MANTBITS + 2) {
|
||||
RtV = float32_mul_pow2(RtV, 64, fp_status);
|
||||
RsV = float32_mul_pow2(RsV, 64, fp_status);
|
||||
RtV = float32_scalbn(RtV, 64, fp_status);
|
||||
RsV = float32_scalbn(RsV, 64, fp_status);
|
||||
} else if (d_exp <= 1) {
|
||||
RtV = float32_mul_pow2(RtV, 32, fp_status);
|
||||
RsV = float32_mul_pow2(RsV, 32, fp_status);
|
||||
RtV = float32_scalbn(RtV, 32, fp_status);
|
||||
RsV = float32_scalbn(RsV, 32, fp_status);
|
||||
} else if (d_exp > 252) {
|
||||
RtV = float32_mul_pow2(RtV, -32, fp_status);
|
||||
RsV = float32_mul_pow2(RsV, -32, fp_status);
|
||||
RtV = float32_scalbn(RtV, -32, fp_status);
|
||||
RsV = float32_scalbn(RsV, -32, fp_status);
|
||||
}
|
||||
RdV = 0;
|
||||
ret = 1;
|
||||
@ -265,7 +338,7 @@ int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust,
|
||||
int r_exp;
|
||||
int ret = 0;
|
||||
RsV = *Rs;
|
||||
if (float32_is_infinity(RsV)) {
|
||||
if (float32_is_any_nan(RsV)) {
|
||||
if (extract32(RsV, 22, 1) == 0) {
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
}
|
||||
@ -287,7 +360,7 @@ int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust,
|
||||
/* Basic checks passed */
|
||||
r_exp = float32_getexp(RsV);
|
||||
if (r_exp <= 24) {
|
||||
RsV = float32_mul_pow2(RsV, 64, fp_status);
|
||||
RsV = float32_scalbn(RsV, 64, fp_status);
|
||||
PeV = 0xe0;
|
||||
}
|
||||
RdV = 0;
|
||||
@ -298,3 +371,41 @@ int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust,
|
||||
*adjust = PeV;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const uint8_t recip_lookup_table[128] = {
|
||||
0x0fe, 0x0fa, 0x0f6, 0x0f2, 0x0ef, 0x0eb, 0x0e7, 0x0e4,
|
||||
0x0e0, 0x0dd, 0x0d9, 0x0d6, 0x0d2, 0x0cf, 0x0cc, 0x0c9,
|
||||
0x0c6, 0x0c2, 0x0bf, 0x0bc, 0x0b9, 0x0b6, 0x0b3, 0x0b1,
|
||||
0x0ae, 0x0ab, 0x0a8, 0x0a5, 0x0a3, 0x0a0, 0x09d, 0x09b,
|
||||
0x098, 0x096, 0x093, 0x091, 0x08e, 0x08c, 0x08a, 0x087,
|
||||
0x085, 0x083, 0x080, 0x07e, 0x07c, 0x07a, 0x078, 0x075,
|
||||
0x073, 0x071, 0x06f, 0x06d, 0x06b, 0x069, 0x067, 0x065,
|
||||
0x063, 0x061, 0x05f, 0x05e, 0x05c, 0x05a, 0x058, 0x056,
|
||||
0x054, 0x053, 0x051, 0x04f, 0x04e, 0x04c, 0x04a, 0x049,
|
||||
0x047, 0x045, 0x044, 0x042, 0x040, 0x03f, 0x03d, 0x03c,
|
||||
0x03a, 0x039, 0x037, 0x036, 0x034, 0x033, 0x032, 0x030,
|
||||
0x02f, 0x02d, 0x02c, 0x02b, 0x029, 0x028, 0x027, 0x025,
|
||||
0x024, 0x023, 0x021, 0x020, 0x01f, 0x01e, 0x01c, 0x01b,
|
||||
0x01a, 0x019, 0x017, 0x016, 0x015, 0x014, 0x013, 0x012,
|
||||
0x011, 0x00f, 0x00e, 0x00d, 0x00c, 0x00b, 0x00a, 0x009,
|
||||
0x008, 0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x000,
|
||||
};
|
||||
|
||||
const uint8_t invsqrt_lookup_table[128] = {
|
||||
0x069, 0x066, 0x063, 0x061, 0x05e, 0x05b, 0x059, 0x057,
|
||||
0x054, 0x052, 0x050, 0x04d, 0x04b, 0x049, 0x047, 0x045,
|
||||
0x043, 0x041, 0x03f, 0x03d, 0x03b, 0x039, 0x037, 0x036,
|
||||
0x034, 0x032, 0x030, 0x02f, 0x02d, 0x02c, 0x02a, 0x028,
|
||||
0x027, 0x025, 0x024, 0x022, 0x021, 0x01f, 0x01e, 0x01d,
|
||||
0x01b, 0x01a, 0x019, 0x017, 0x016, 0x015, 0x014, 0x012,
|
||||
0x011, 0x010, 0x00f, 0x00d, 0x00c, 0x00b, 0x00a, 0x009,
|
||||
0x008, 0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x001,
|
||||
0x0fe, 0x0fa, 0x0f6, 0x0f3, 0x0ef, 0x0eb, 0x0e8, 0x0e4,
|
||||
0x0e1, 0x0de, 0x0db, 0x0d7, 0x0d4, 0x0d1, 0x0ce, 0x0cb,
|
||||
0x0c9, 0x0c6, 0x0c3, 0x0c0, 0x0be, 0x0bb, 0x0b8, 0x0b6,
|
||||
0x0b3, 0x0b1, 0x0af, 0x0ac, 0x0aa, 0x0a8, 0x0a5, 0x0a3,
|
||||
0x0a1, 0x09f, 0x09d, 0x09b, 0x099, 0x097, 0x095, 0x093,
|
||||
0x091, 0x08f, 0x08d, 0x08b, 0x089, 0x087, 0x086, 0x084,
|
||||
0x082, 0x080, 0x07f, 0x07d, 0x07b, 0x07a, 0x078, 0x077,
|
||||
0x075, 0x074, 0x072, 0x071, 0x06f, 0x06e, 0x06c, 0x06b,
|
||||
};
|
||||
|
@ -20,9 +20,12 @@
|
||||
|
||||
#include "qemu/int128.h"
|
||||
|
||||
extern const uint8_t rLPS_table_64x4[64][4];
|
||||
extern const uint8_t AC_next_state_MPS_64[64];
|
||||
extern const uint8_t AC_next_state_LPS_64[64];
|
||||
|
||||
uint64_t interleave(uint32_t odd, uint32_t even);
|
||||
uint64_t deinterleave(uint64_t src);
|
||||
uint32_t carry_from_add64(uint64_t a, uint64_t b, uint32_t c);
|
||||
int32_t conv_round(int32_t a, int n);
|
||||
void arch_fpop_start(CPUHexagonState *env);
|
||||
void arch_fpop_end(CPUHexagonState *env);
|
||||
@ -31,4 +34,8 @@ int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd,
|
||||
int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust,
|
||||
float_status *fp_status);
|
||||
|
||||
extern const uint8_t recip_lookup_table[128];
|
||||
|
||||
extern const uint8_t invsqrt_lookup_table[128];
|
||||
|
||||
#endif
|
||||
|
@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "fpu/softfloat.h"
|
||||
#include "macros.h"
|
||||
#include "conv_emu.h"
|
||||
|
||||
#define LL_MAX_POS 0x7fffffffffffffffULL
|
||||
#define MAX_POS 0x7fffffffU
|
||||
|
||||
static uint64_t conv_f64_to_8u_n(float64 in, int will_negate,
|
||||
float_status *fp_status)
|
||||
{
|
||||
uint8_t sign = float64_is_neg(in);
|
||||
if (float64_is_infinity(in)) {
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
if (float64_is_neg(in)) {
|
||||
return 0ULL;
|
||||
} else {
|
||||
return ~0ULL;
|
||||
}
|
||||
}
|
||||
if (float64_is_any_nan(in)) {
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
return ~0ULL;
|
||||
}
|
||||
if (float64_is_zero(in)) {
|
||||
return 0;
|
||||
}
|
||||
if (sign) {
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
return 0;
|
||||
}
|
||||
if (float64_lt(in, float64_half, fp_status)) {
|
||||
/* Near zero, captures large fracshifts, denorms, etc */
|
||||
float_raise(float_flag_inexact, fp_status);
|
||||
switch (get_float_rounding_mode(fp_status)) {
|
||||
case float_round_down:
|
||||
if (will_negate) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
case float_round_up:
|
||||
if (!will_negate) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0; /* nearest or towards zero */
|
||||
}
|
||||
}
|
||||
return float64_to_uint64(in, fp_status);
|
||||
}
|
||||
|
||||
static void clr_float_exception_flags(uint8_t flag, float_status *fp_status)
|
||||
{
|
||||
uint8_t flags = fp_status->float_exception_flags;
|
||||
flags &= ~flag;
|
||||
set_float_exception_flags(flags, fp_status);
|
||||
}
|
||||
|
||||
static uint32_t conv_df_to_4u_n(float64 fp64, int will_negate,
|
||||
float_status *fp_status)
|
||||
{
|
||||
uint64_t tmp;
|
||||
tmp = conv_f64_to_8u_n(fp64, will_negate, fp_status);
|
||||
if (tmp > 0x00000000ffffffffULL) {
|
||||
clr_float_exception_flags(float_flag_inexact, fp_status);
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
return ~0U;
|
||||
}
|
||||
return (uint32_t)tmp;
|
||||
}
|
||||
|
||||
uint64_t conv_df_to_8u(float64 in, float_status *fp_status)
|
||||
{
|
||||
return conv_f64_to_8u_n(in, 0, fp_status);
|
||||
}
|
||||
|
||||
uint32_t conv_df_to_4u(float64 in, float_status *fp_status)
|
||||
{
|
||||
return conv_df_to_4u_n(in, 0, fp_status);
|
||||
}
|
||||
|
||||
int64_t conv_df_to_8s(float64 in, float_status *fp_status)
|
||||
{
|
||||
uint8_t sign = float64_is_neg(in);
|
||||
uint64_t tmp;
|
||||
if (float64_is_any_nan(in)) {
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
return -1;
|
||||
}
|
||||
if (sign) {
|
||||
float64 minus_fp64 = float64_abs(in);
|
||||
tmp = conv_f64_to_8u_n(minus_fp64, 1, fp_status);
|
||||
} else {
|
||||
tmp = conv_f64_to_8u_n(in, 0, fp_status);
|
||||
}
|
||||
if (tmp > (LL_MAX_POS + sign)) {
|
||||
clr_float_exception_flags(float_flag_inexact, fp_status);
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
tmp = (LL_MAX_POS + sign);
|
||||
}
|
||||
if (sign) {
|
||||
return -tmp;
|
||||
} else {
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t conv_df_to_4s(float64 in, float_status *fp_status)
|
||||
{
|
||||
uint8_t sign = float64_is_neg(in);
|
||||
uint64_t tmp;
|
||||
if (float64_is_any_nan(in)) {
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
return -1;
|
||||
}
|
||||
if (sign) {
|
||||
float64 minus_fp64 = float64_abs(in);
|
||||
tmp = conv_f64_to_8u_n(minus_fp64, 1, fp_status);
|
||||
} else {
|
||||
tmp = conv_f64_to_8u_n(in, 0, fp_status);
|
||||
}
|
||||
if (tmp > (MAX_POS + sign)) {
|
||||
clr_float_exception_flags(float_flag_inexact, fp_status);
|
||||
float_raise(float_flag_invalid, fp_status);
|
||||
tmp = (MAX_POS + sign);
|
||||
}
|
||||
if (sign) {
|
||||
return -tmp;
|
||||
} else {
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t conv_sf_to_8u(float32 in, float_status *fp_status)
|
||||
{
|
||||
float64 fp64 = float32_to_float64(in, fp_status);
|
||||
return conv_df_to_8u(fp64, fp_status);
|
||||
}
|
||||
|
||||
uint32_t conv_sf_to_4u(float32 in, float_status *fp_status)
|
||||
{
|
||||
float64 fp64 = float32_to_float64(in, fp_status);
|
||||
return conv_df_to_4u(fp64, fp_status);
|
||||
}
|
||||
|
||||
int64_t conv_sf_to_8s(float32 in, float_status *fp_status)
|
||||
{
|
||||
float64 fp64 = float32_to_float64(in, fp_status);
|
||||
return conv_df_to_8s(fp64, fp_status);
|
||||
}
|
||||
|
||||
int32_t conv_sf_to_4s(float32 in, float_status *fp_status)
|
||||
{
|
||||
float64 fp64 = float32_to_float64(in, fp_status);
|
||||
return conv_df_to_4s(fp64, fp_status);
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HEXAGON_CONV_EMU_H
|
||||
#define HEXAGON_CONV_EMU_H
|
||||
|
||||
uint64_t conv_sf_to_8u(float32 in, float_status *fp_status);
|
||||
uint32_t conv_sf_to_4u(float32 in, float_status *fp_status);
|
||||
int64_t conv_sf_to_8s(float32 in, float_status *fp_status);
|
||||
int32_t conv_sf_to_4s(float32 in, float_status *fp_status);
|
||||
|
||||
uint64_t conv_df_to_8u(float64 in, float_status *fp_status);
|
||||
uint32_t conv_df_to_4u(float64 in, float_status *fp_status);
|
||||
int64_t conv_df_to_8s(float64 in, float_status *fp_status);
|
||||
int32_t conv_df_to_4s(float64 in, float_status *fp_status);
|
||||
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "fpu/softfloat-helpers.h"
|
||||
|
||||
static void hexagon_v67_cpu_init(Object *obj)
|
||||
{
|
||||
@ -69,10 +70,9 @@ const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = {
|
||||
* stacks at different locations. This is used to compensate so the diff is
|
||||
* cleaner.
|
||||
*/
|
||||
static inline target_ulong adjust_stack_ptrs(CPUHexagonState *env,
|
||||
target_ulong addr)
|
||||
static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr)
|
||||
{
|
||||
HexagonCPU *cpu = container_of(env, HexagonCPU, env);
|
||||
HexagonCPU *cpu = env_archcpu(env);
|
||||
target_ulong stack_adjust = cpu->lldb_stack_adjust;
|
||||
target_ulong stack_start = env->stack_start;
|
||||
target_ulong stack_size = 0x10000;
|
||||
@ -88,7 +88,7 @@ static inline target_ulong adjust_stack_ptrs(CPUHexagonState *env,
|
||||
}
|
||||
|
||||
/* HEX_REG_P3_0 (aka C4) is an alias for the predicate registers */
|
||||
static inline target_ulong read_p3_0(CPUHexagonState *env)
|
||||
static target_ulong read_p3_0(CPUHexagonState *env)
|
||||
{
|
||||
int32_t control_reg = 0;
|
||||
int i;
|
||||
@ -116,7 +116,7 @@ static void print_reg(FILE *f, CPUHexagonState *env, int regnum)
|
||||
|
||||
static void hexagon_dump(CPUHexagonState *env, FILE *f)
|
||||
{
|
||||
HexagonCPU *cpu = container_of(env, HexagonCPU, env);
|
||||
HexagonCPU *cpu = env_archcpu(env);
|
||||
|
||||
if (cpu->lldb_compat) {
|
||||
/*
|
||||
@ -206,8 +206,12 @@ static void hexagon_cpu_reset(DeviceState *dev)
|
||||
CPUState *cs = CPU(dev);
|
||||
HexagonCPU *cpu = HEXAGON_CPU(cs);
|
||||
HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(cpu);
|
||||
CPUHexagonState *env = &cpu->env;
|
||||
|
||||
mcc->parent_reset(dev);
|
||||
|
||||
set_default_nan_mode(1, &env->fp_status);
|
||||
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
|
||||
}
|
||||
|
||||
static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info)
|
||||
|
@ -127,11 +127,6 @@ typedef struct HexagonCPU {
|
||||
target_ulong lldb_stack_adjust;
|
||||
} HexagonCPU;
|
||||
|
||||
static inline HexagonCPU *hexagon_env_get_cpu(CPUHexagonState *env)
|
||||
{
|
||||
return container_of(env, HexagonCPU, env);
|
||||
}
|
||||
|
||||
#include "cpu_bits.h"
|
||||
|
||||
#define cpu_signal_handler cpu_hexagon_signal_handler
|
||||
|
@ -47,7 +47,7 @@ static inline uint32_t iclass_bits(uint32_t encoding)
|
||||
return iclass;
|
||||
}
|
||||
|
||||
static inline int is_packet_end(uint32_t endocing)
|
||||
static inline bool is_packet_end(uint32_t endocing)
|
||||
{
|
||||
uint32_t bits = parse_bits(endocing);
|
||||
return ((bits == 0x3) || (bits == 0x0));
|
||||
|
@ -48,8 +48,8 @@ enum {
|
||||
DEF_REGMAP(R_16, 16, 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23)
|
||||
DEF_REGMAP(R__8, 8, 0, 2, 4, 6, 16, 18, 20, 22)
|
||||
|
||||
#define DECODE_MAPPED_REG(REGNO, NAME) \
|
||||
insn->regno[REGNO] = DECODE_REGISTER_##NAME[insn->regno[REGNO]];
|
||||
#define DECODE_MAPPED_REG(OPNUM, NAME) \
|
||||
insn->regno[OPNUM] = DECODE_REGISTER_##NAME[insn->regno[OPNUM]];
|
||||
|
||||
typedef struct {
|
||||
const struct DectreeTable *table_link;
|
||||
@ -340,8 +340,8 @@ static void decode_split_cmpjump(Packet *pkt)
|
||||
if (GET_ATTRIB(pkt->insn[i].opcode, A_NEWCMPJUMP)) {
|
||||
last = pkt->num_insns;
|
||||
pkt->insn[last] = pkt->insn[i]; /* copy the instruction */
|
||||
pkt->insn[last].part1 = 1; /* last instruction does the CMP */
|
||||
pkt->insn[i].part1 = 0; /* existing instruction does the JUMP */
|
||||
pkt->insn[last].part1 = true; /* last insn does the CMP */
|
||||
pkt->insn[i].part1 = false; /* existing insn does the JUMP */
|
||||
pkt->num_insns++;
|
||||
}
|
||||
}
|
||||
@ -354,7 +354,7 @@ static void decode_split_cmpjump(Packet *pkt)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int decode_opcode_can_jump(int opcode)
|
||||
static bool decode_opcode_can_jump(int opcode)
|
||||
{
|
||||
if ((GET_ATTRIB(opcode, A_JUMP)) ||
|
||||
(GET_ATTRIB(opcode, A_CALL)) ||
|
||||
@ -362,15 +362,15 @@ static inline int decode_opcode_can_jump(int opcode)
|
||||
(opcode == J2_pause)) {
|
||||
/* Exception to A_JUMP attribute */
|
||||
if (opcode == J4_hintjumpr) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int decode_opcode_ends_loop(int opcode)
|
||||
static bool decode_opcode_ends_loop(int opcode)
|
||||
{
|
||||
return GET_ATTRIB(opcode, A_HWLOOP0_END) ||
|
||||
GET_ATTRIB(opcode, A_HWLOOP1_END);
|
||||
@ -383,9 +383,9 @@ static void decode_set_insn_attr_fields(Packet *pkt)
|
||||
int numinsns = pkt->num_insns;
|
||||
uint16_t opcode;
|
||||
|
||||
pkt->pkt_has_cof = 0;
|
||||
pkt->pkt_has_endloop = 0;
|
||||
pkt->pkt_has_dczeroa = 0;
|
||||
pkt->pkt_has_cof = false;
|
||||
pkt->pkt_has_endloop = false;
|
||||
pkt->pkt_has_dczeroa = false;
|
||||
|
||||
for (i = 0; i < numinsns; i++) {
|
||||
opcode = pkt->insn[i].opcode;
|
||||
@ -394,14 +394,14 @@ static void decode_set_insn_attr_fields(Packet *pkt)
|
||||
}
|
||||
|
||||
if (GET_ATTRIB(opcode, A_DCZEROA)) {
|
||||
pkt->pkt_has_dczeroa = 1;
|
||||
pkt->pkt_has_dczeroa = true;
|
||||
}
|
||||
|
||||
if (GET_ATTRIB(opcode, A_STORE)) {
|
||||
if (pkt->insn[i].slot == 0) {
|
||||
pkt->pkt_has_store_s0 = 1;
|
||||
pkt->pkt_has_store_s0 = true;
|
||||
} else {
|
||||
pkt->pkt_has_store_s1 = 1;
|
||||
pkt->pkt_has_store_s1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,9 +422,9 @@ static void decode_set_insn_attr_fields(Packet *pkt)
|
||||
*/
|
||||
static void decode_shuffle_for_execution(Packet *packet)
|
||||
{
|
||||
int changed = 0;
|
||||
bool changed = false;
|
||||
int i;
|
||||
int flag; /* flag means we've seen a non-memory instruction */
|
||||
bool flag; /* flag means we've seen a non-memory instruction */
|
||||
int n_mems;
|
||||
int last_insn = packet->num_insns - 1;
|
||||
|
||||
@ -437,7 +437,7 @@ static void decode_shuffle_for_execution(Packet *packet)
|
||||
}
|
||||
|
||||
do {
|
||||
changed = 0;
|
||||
changed = false;
|
||||
/*
|
||||
* Stores go last, must not reorder.
|
||||
* Cannot shuffle stores past loads, either.
|
||||
@ -445,13 +445,13 @@ static void decode_shuffle_for_execution(Packet *packet)
|
||||
* then a store, shuffle the store to the front. Don't shuffle
|
||||
* stores wrt each other or a load.
|
||||
*/
|
||||
for (flag = n_mems = 0, i = last_insn; i >= 0; i--) {
|
||||
for (flag = false, n_mems = 0, i = last_insn; i >= 0; i--) {
|
||||
int opcode = packet->insn[i].opcode;
|
||||
|
||||
if (flag && GET_ATTRIB(opcode, A_STORE)) {
|
||||
decode_send_insn_to(packet, i, last_insn - n_mems);
|
||||
n_mems++;
|
||||
changed = 1;
|
||||
changed = true;
|
||||
} else if (GET_ATTRIB(opcode, A_STORE)) {
|
||||
n_mems++;
|
||||
} else if (GET_ATTRIB(opcode, A_LOAD)) {
|
||||
@ -466,7 +466,7 @@ static void decode_shuffle_for_execution(Packet *packet)
|
||||
* a .new value
|
||||
*/
|
||||
} else {
|
||||
flag = 1;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,7 +474,7 @@ static void decode_shuffle_for_execution(Packet *packet)
|
||||
continue;
|
||||
}
|
||||
/* Compares go first, may be reordered wrt each other */
|
||||
for (flag = 0, i = 0; i < last_insn + 1; i++) {
|
||||
for (flag = false, i = 0; i < last_insn + 1; i++) {
|
||||
int opcode = packet->insn[i].opcode;
|
||||
|
||||
if ((strstr(opcode_wregs[opcode], "Pd4") ||
|
||||
@ -483,7 +483,7 @@ static void decode_shuffle_for_execution(Packet *packet)
|
||||
/* This should be a compare (not a store conditional) */
|
||||
if (flag) {
|
||||
decode_send_insn_to(packet, i, 0);
|
||||
changed = 1;
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
} else if (GET_ATTRIB(opcode, A_IMPLICIT_WRITES_P3) &&
|
||||
@ -495,18 +495,18 @@ static void decode_shuffle_for_execution(Packet *packet)
|
||||
*/
|
||||
if (flag) {
|
||||
decode_send_insn_to(packet, i, 0);
|
||||
changed = 1;
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
} else if (GET_ATTRIB(opcode, A_IMPLICIT_WRITES_P0) &&
|
||||
!GET_ATTRIB(opcode, A_NEWCMPJUMP)) {
|
||||
if (flag) {
|
||||
decode_send_insn_to(packet, i, 0);
|
||||
changed = 1;
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
flag = 1;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
@ -543,7 +543,7 @@ static void decode_apply_extenders(Packet *packet)
|
||||
int i;
|
||||
for (i = 0; i < packet->num_insns; i++) {
|
||||
if (GET_ATTRIB(packet->insn[i].opcode, A_IT_EXTENDER)) {
|
||||
packet->insn[i + 1].extension_valid = 1;
|
||||
packet->insn[i + 1].extension_valid = true;
|
||||
apply_extender(packet, i + 1, packet->insn[i].immed[0]);
|
||||
}
|
||||
}
|
||||
@ -764,7 +764,7 @@ static void decode_add_endloop_insn(Insn *insn, int loopnum)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int decode_parsebits_is_loopend(uint32_t encoding32)
|
||||
static bool decode_parsebits_is_loopend(uint32_t encoding32)
|
||||
{
|
||||
uint32_t bits = parse_bits(encoding32);
|
||||
return bits == 0x2;
|
||||
@ -775,8 +775,11 @@ decode_set_slot_number(Packet *pkt)
|
||||
{
|
||||
int slot;
|
||||
int i;
|
||||
int hit_mem_insn = 0;
|
||||
int hit_duplex = 0;
|
||||
bool hit_mem_insn = false;
|
||||
bool hit_duplex = false;
|
||||
bool slot0_found = false;
|
||||
bool slot1_found = false;
|
||||
int slot1_iidx = 0;
|
||||
|
||||
/*
|
||||
* The slots are encoded in reverse order
|
||||
@ -801,7 +804,7 @@ decode_set_slot_number(Packet *pkt)
|
||||
if ((GET_ATTRIB(pkt->insn[i].opcode, A_MEMLIKE) ||
|
||||
GET_ATTRIB(pkt->insn[i].opcode, A_MEMLIKE_PACKET_RULES)) &&
|
||||
!hit_mem_insn) {
|
||||
hit_mem_insn = 1;
|
||||
hit_mem_insn = true;
|
||||
pkt->insn[i].slot = 0;
|
||||
continue;
|
||||
}
|
||||
@ -818,7 +821,7 @@ decode_set_slot_number(Packet *pkt)
|
||||
for (i = pkt->num_insns - 1; i >= 0; i--) {
|
||||
/* First subinsn always goes to slot 0 */
|
||||
if (GET_ATTRIB(pkt->insn[i].opcode, A_SUBINSN) && !hit_duplex) {
|
||||
hit_duplex = 1;
|
||||
hit_duplex = true;
|
||||
pkt->insn[i].slot = 0;
|
||||
continue;
|
||||
}
|
||||
@ -830,13 +833,10 @@ decode_set_slot_number(Packet *pkt)
|
||||
}
|
||||
|
||||
/* Fix the exceptions - slot 1 is never empty, always aligns to slot 0 */
|
||||
int slot0_found = 0;
|
||||
int slot1_found = 0;
|
||||
int slot1_iidx = 0;
|
||||
for (i = pkt->num_insns - 1; i >= 0; i--) {
|
||||
/* Is slot0 used? */
|
||||
if (pkt->insn[i].slot == 0) {
|
||||
int is_endloop = (pkt->insn[i].opcode == J2_endloop01);
|
||||
bool is_endloop = (pkt->insn[i].opcode == J2_endloop01);
|
||||
is_endloop |= (pkt->insn[i].opcode == J2_endloop0);
|
||||
is_endloop |= (pkt->insn[i].opcode == J2_endloop1);
|
||||
|
||||
@ -845,17 +845,17 @@ decode_set_slot_number(Packet *pkt)
|
||||
* slot0 for endloop
|
||||
*/
|
||||
if (!is_endloop) {
|
||||
slot0_found = 1;
|
||||
slot0_found = true;
|
||||
}
|
||||
}
|
||||
/* Is slot1 used? */
|
||||
if (pkt->insn[i].slot == 1) {
|
||||
slot1_found = 1;
|
||||
slot1_found = true;
|
||||
slot1_iidx = i;
|
||||
}
|
||||
}
|
||||
/* Is slot0 empty and slot1 used? */
|
||||
if ((slot0_found == 0) && (slot1_found == 1)) {
|
||||
if ((!slot0_found) && slot1_found) {
|
||||
/* Then push it to slot0 */
|
||||
pkt->insn[slot1_iidx].slot = 0;
|
||||
}
|
||||
@ -873,7 +873,7 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
|
||||
{
|
||||
int num_insns = 0;
|
||||
int words_read = 0;
|
||||
int end_of_packet = 0;
|
||||
bool end_of_packet = false;
|
||||
int new_insns = 0;
|
||||
uint32_t encoding32;
|
||||
|
||||
@ -890,7 +890,7 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
|
||||
* decode works
|
||||
*/
|
||||
if (pkt->insn[num_insns].opcode == A4_ext) {
|
||||
pkt->insn[num_insns + 1].extension_valid = 1;
|
||||
pkt->insn[num_insns + 1].extension_valid = true;
|
||||
}
|
||||
num_insns += new_insns;
|
||||
words_read++;
|
||||
@ -913,7 +913,7 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
|
||||
decode_add_endloop_insn(&pkt->insn[pkt->num_insns++], 0);
|
||||
}
|
||||
if (words_read >= 3) {
|
||||
uint32_t has_loop0, has_loop1;
|
||||
bool has_loop0, has_loop1;
|
||||
has_loop0 = decode_parsebits_is_loopend(words[0]);
|
||||
has_loop1 = decode_parsebits_is_loopend(words[1]);
|
||||
if (has_loop0 && has_loop1) {
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "qemu/int128.h"
|
||||
#include "fpu/softfloat.h"
|
||||
#include "macros.h"
|
||||
#include "conv_emu.h"
|
||||
#include "fma_emu.h"
|
||||
|
||||
#define DF_INF_EXP 0x7ff
|
||||
@ -64,7 +63,7 @@ typedef union {
|
||||
};
|
||||
} Float;
|
||||
|
||||
static inline uint64_t float64_getmant(float64 f64)
|
||||
static uint64_t float64_getmant(float64 f64)
|
||||
{
|
||||
Double a = { .i = f64 };
|
||||
if (float64_is_normal(f64)) {
|
||||
@ -91,7 +90,7 @@ int32_t float64_getexp(float64 f64)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline uint64_t float32_getmant(float32 f32)
|
||||
static uint64_t float32_getmant(float32 f32)
|
||||
{
|
||||
Float a = { .i = f32 };
|
||||
if (float32_is_normal(f32)) {
|
||||
@ -118,17 +117,17 @@ int32_t float32_getexp(float32 f32)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline uint32_t int128_getw0(Int128 x)
|
||||
static uint32_t int128_getw0(Int128 x)
|
||||
{
|
||||
return int128_getlo(x);
|
||||
}
|
||||
|
||||
static inline uint32_t int128_getw1(Int128 x)
|
||||
static uint32_t int128_getw1(Int128 x)
|
||||
{
|
||||
return int128_getlo(x) >> 32;
|
||||
}
|
||||
|
||||
static inline Int128 int128_mul_6464(uint64_t ai, uint64_t bi)
|
||||
static Int128 int128_mul_6464(uint64_t ai, uint64_t bi)
|
||||
{
|
||||
Int128 a, b;
|
||||
uint64_t pp0, pp1a, pp1b, pp1s, pp2;
|
||||
@ -152,7 +151,7 @@ static inline Int128 int128_mul_6464(uint64_t ai, uint64_t bi)
|
||||
return int128_make128(ret_low, pp2 + (pp1s >> 32));
|
||||
}
|
||||
|
||||
static inline Int128 int128_sub_borrow(Int128 a, Int128 b, int borrow)
|
||||
static Int128 int128_sub_borrow(Int128 a, Int128 b, int borrow)
|
||||
{
|
||||
Int128 ret = int128_sub(a, b);
|
||||
if (borrow != 0) {
|
||||
@ -170,7 +169,7 @@ typedef struct {
|
||||
uint8_t sticky;
|
||||
} Accum;
|
||||
|
||||
static inline void accum_init(Accum *p)
|
||||
static void accum_init(Accum *p)
|
||||
{
|
||||
p->mant = int128_zero();
|
||||
p->exp = 0;
|
||||
@ -180,7 +179,7 @@ static inline void accum_init(Accum *p)
|
||||
p->sticky = 0;
|
||||
}
|
||||
|
||||
static inline Accum accum_norm_left(Accum a)
|
||||
static Accum accum_norm_left(Accum a)
|
||||
{
|
||||
a.exp--;
|
||||
a.mant = int128_lshift(a.mant, 1);
|
||||
@ -190,6 +189,7 @@ static inline Accum accum_norm_left(Accum a)
|
||||
return a;
|
||||
}
|
||||
|
||||
/* This function is marked inline for performance reasons */
|
||||
static inline Accum accum_norm_right(Accum a, int amt)
|
||||
{
|
||||
if (amt > 130) {
|
||||
@ -226,7 +226,7 @@ static inline Accum accum_norm_right(Accum a, int amt)
|
||||
*/
|
||||
static Accum accum_add(Accum a, Accum b);
|
||||
|
||||
static inline Accum accum_sub(Accum a, Accum b, int negate)
|
||||
static Accum accum_sub(Accum a, Accum b, int negate)
|
||||
{
|
||||
Accum ret;
|
||||
accum_init(&ret);
|
||||
@ -329,7 +329,7 @@ static Accum accum_add(Accum a, Accum b)
|
||||
}
|
||||
|
||||
/* Return an infinity with requested sign */
|
||||
static inline float64 infinite_float64(uint8_t sign)
|
||||
static float64 infinite_float64(uint8_t sign)
|
||||
{
|
||||
if (sign) {
|
||||
return make_float64(DF_MINUS_INF);
|
||||
@ -339,7 +339,7 @@ static inline float64 infinite_float64(uint8_t sign)
|
||||
}
|
||||
|
||||
/* Return a maximum finite value with requested sign */
|
||||
static inline float64 maxfinite_float64(uint8_t sign)
|
||||
static float64 maxfinite_float64(uint8_t sign)
|
||||
{
|
||||
if (sign) {
|
||||
return make_float64(DF_MINUS_MAXF);
|
||||
@ -349,7 +349,7 @@ static inline float64 maxfinite_float64(uint8_t sign)
|
||||
}
|
||||
|
||||
/* Return a zero value with requested sign */
|
||||
static inline float64 zero_float64(uint8_t sign)
|
||||
static float64 zero_float64(uint8_t sign)
|
||||
{
|
||||
if (sign) {
|
||||
return make_float64(0x8000000000000000);
|
||||
@ -369,7 +369,7 @@ float32 infinite_float32(uint8_t sign)
|
||||
}
|
||||
|
||||
/* Return a maximum finite value with the requested sign */
|
||||
static inline float32 maxfinite_float32(uint8_t sign)
|
||||
static float32 maxfinite_float32(uint8_t sign)
|
||||
{
|
||||
if (sign) {
|
||||
return make_float32(SF_MINUS_MAXF);
|
||||
@ -379,7 +379,7 @@ static inline float32 maxfinite_float32(uint8_t sign)
|
||||
}
|
||||
|
||||
/* Return a zero value with requested sign */
|
||||
static inline float32 zero_float32(uint8_t sign)
|
||||
static float32 zero_float32(uint8_t sign)
|
||||
{
|
||||
if (sign) {
|
||||
return make_float32(0x80000000);
|
||||
@ -389,7 +389,7 @@ static inline float32 zero_float32(uint8_t sign)
|
||||
}
|
||||
|
||||
#define GEN_XF_ROUND(SUFFIX, MANTBITS, INF_EXP, INTERNAL_TYPE) \
|
||||
static inline SUFFIX accum_round_##SUFFIX(Accum a, float_status * fp_status) \
|
||||
static SUFFIX accum_round_##SUFFIX(Accum a, float_status * fp_status) \
|
||||
{ \
|
||||
if ((int128_gethi(a.mant) == 0) && (int128_getlo(a.mant) == 0) \
|
||||
&& ((a.guard | a.round | a.sticky) == 0)) { \
|
||||
@ -526,8 +526,8 @@ static bool is_inf_prod(float64 a, float64 b)
|
||||
(float64_is_infinity(b) && is_finite(a) && (!float64_is_zero(a))));
|
||||
}
|
||||
|
||||
static inline float64 special_fma(float64 a, float64 b, float64 c,
|
||||
float_status *fp_status)
|
||||
static float64 special_fma(float64 a, float64 b, float64 c,
|
||||
float_status *fp_status)
|
||||
{
|
||||
float64 ret = make_float64(0);
|
||||
|
||||
@ -586,8 +586,8 @@ static inline float64 special_fma(float64 a, float64 b, float64 c,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static inline float32 special_fmaf(float32 a, float32 b, float32 c,
|
||||
float_status *fp_status)
|
||||
static float32 special_fmaf(float32 a, float32 b, float32 c,
|
||||
float_status *fp_status)
|
||||
{
|
||||
float64 aa, bb, cc;
|
||||
aa = float32_to_float64(a, fp_status);
|
||||
|
@ -37,7 +37,10 @@
|
||||
* _sp stack pointer relative r0 = memw(r29+#12)
|
||||
* _ap absolute set r0 = memw(r1=##variable)
|
||||
* _pr post increment register r0 = memw(r1++m1)
|
||||
* _pbr post increment bit reverse r0 = memw(r1++m1:brev)
|
||||
* _pi post increment immediate r0 = memb(r1++#1)
|
||||
* _pci post increment circular immediate r0 = memw(r1++#4:circ(m0))
|
||||
* _pcr post increment circular register r0 = memw(r1++I:circ(m0))
|
||||
*/
|
||||
|
||||
/* Macros for complex addressing modes */
|
||||
@ -51,12 +54,32 @@
|
||||
fEA_REG(RxV); \
|
||||
fPM_M(RxV, MuV); \
|
||||
} while (0)
|
||||
#define GET_EA_pbr \
|
||||
do { \
|
||||
gen_helper_fbrev(EA, RxV); \
|
||||
tcg_gen_add_tl(RxV, RxV, MuV); \
|
||||
} while (0)
|
||||
#define GET_EA_pi \
|
||||
do { \
|
||||
fEA_REG(RxV); \
|
||||
fPM_I(RxV, siV); \
|
||||
} while (0)
|
||||
|
||||
#define GET_EA_pci \
|
||||
do { \
|
||||
TCGv tcgv_siV = tcg_const_tl(siV); \
|
||||
tcg_gen_mov_tl(EA, RxV); \
|
||||
gen_helper_fcircadd(RxV, RxV, tcgv_siV, MuV, \
|
||||
hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
tcg_temp_free(tcgv_siV); \
|
||||
} while (0)
|
||||
#define GET_EA_pcr(SHIFT) \
|
||||
do { \
|
||||
TCGv ireg = tcg_temp_new(); \
|
||||
tcg_gen_mov_tl(EA, RxV); \
|
||||
gen_read_ireg(ireg, MuV, (SHIFT)); \
|
||||
gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
tcg_temp_free(ireg); \
|
||||
} while (0)
|
||||
|
||||
/* Instructions with multiple definitions */
|
||||
#define fGEN_TCG_LOAD_AP(RES, SIZE, SIGN) \
|
||||
@ -80,19 +103,229 @@
|
||||
#define fGEN_TCG_L4_loadrd_ap(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_AP(RddV, 8, u)
|
||||
|
||||
#define fGEN_TCG_L2_loadrub_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrb_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadruh_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrh_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadri_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrd_pci(SHORTCODE) SHORTCODE
|
||||
|
||||
#define fGEN_TCG_LOAD_pcr(SHIFT, LOAD) \
|
||||
do { \
|
||||
TCGv ireg = tcg_temp_new(); \
|
||||
tcg_gen_mov_tl(EA, RxV); \
|
||||
gen_read_ireg(ireg, MuV, SHIFT); \
|
||||
gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
LOAD; \
|
||||
tcg_temp_free(ireg); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_L2_loadrub_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, u, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadrb_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, s, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadruh_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, u, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadrh_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, s, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadri_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(2, fLOAD(1, 4, u, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadrd_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(3, fLOAD(1, 8, u, EA, RddV))
|
||||
|
||||
#define fGEN_TCG_L2_loadrub_pr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrub_pbr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrub_pi(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrb_pr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrb_pi(SHORTCODE) SHORTCODE;
|
||||
#define fGEN_TCG_L2_loadrb_pbr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrb_pi(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadruh_pr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadruh_pi(SHORTCODE) SHORTCODE;
|
||||
#define fGEN_TCG_L2_loadruh_pbr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadruh_pi(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrh_pr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrh_pbr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrh_pi(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadri_pr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadri_pbr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadri_pi(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrd_pr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrd_pbr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrd_pi(SHORTCODE) SHORTCODE
|
||||
|
||||
/*
|
||||
* These instructions load 2 bytes and places them in
|
||||
* two halves of the destination register.
|
||||
* The GET_EA macro determines the addressing mode.
|
||||
* The SIGN argument determines whether to zero-extend or
|
||||
* sign-extend.
|
||||
*/
|
||||
#define fGEN_TCG_loadbXw2(GET_EA, SIGN) \
|
||||
do { \
|
||||
TCGv tmp = tcg_temp_new(); \
|
||||
TCGv byte = tcg_temp_new(); \
|
||||
GET_EA; \
|
||||
fLOAD(1, 2, u, EA, tmp); \
|
||||
tcg_gen_movi_tl(RdV, 0); \
|
||||
for (int i = 0; i < 2; i++) { \
|
||||
gen_set_half(i, RdV, gen_get_byte(byte, i, tmp, (SIGN))); \
|
||||
} \
|
||||
tcg_temp_free(tmp); \
|
||||
tcg_temp_free(byte); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_L2_loadbzw2_io(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), false)
|
||||
#define fGEN_TCG_L4_loadbzw2_ur(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), false)
|
||||
#define fGEN_TCG_L2_loadbsw2_io(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), true)
|
||||
#define fGEN_TCG_L4_loadbsw2_ur(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), true)
|
||||
#define fGEN_TCG_L4_loadbzw2_ap(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_ap, false)
|
||||
#define fGEN_TCG_L2_loadbzw2_pr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pr, false)
|
||||
#define fGEN_TCG_L2_loadbzw2_pbr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pbr, false)
|
||||
#define fGEN_TCG_L2_loadbzw2_pi(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pi, false)
|
||||
#define fGEN_TCG_L4_loadbsw2_ap(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_ap, true)
|
||||
#define fGEN_TCG_L2_loadbsw2_pr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pr, true)
|
||||
#define fGEN_TCG_L2_loadbsw2_pbr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pbr, true)
|
||||
#define fGEN_TCG_L2_loadbsw2_pi(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pi, true)
|
||||
#define fGEN_TCG_L2_loadbzw2_pci(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pci, false)
|
||||
#define fGEN_TCG_L2_loadbsw2_pci(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pci, true)
|
||||
#define fGEN_TCG_L2_loadbzw2_pcr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pcr(1), false)
|
||||
#define fGEN_TCG_L2_loadbsw2_pcr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw2(GET_EA_pcr(1), true)
|
||||
|
||||
/*
|
||||
* These instructions load 4 bytes and places them in
|
||||
* four halves of the destination register pair.
|
||||
* The GET_EA macro determines the addressing mode.
|
||||
* The SIGN argument determines whether to zero-extend or
|
||||
* sign-extend.
|
||||
*/
|
||||
#define fGEN_TCG_loadbXw4(GET_EA, SIGN) \
|
||||
do { \
|
||||
TCGv tmp = tcg_temp_new(); \
|
||||
TCGv byte = tcg_temp_new(); \
|
||||
GET_EA; \
|
||||
fLOAD(1, 4, u, EA, tmp); \
|
||||
tcg_gen_movi_i64(RddV, 0); \
|
||||
for (int i = 0; i < 4; i++) { \
|
||||
gen_set_half_i64(i, RddV, gen_get_byte(byte, i, tmp, (SIGN))); \
|
||||
} \
|
||||
tcg_temp_free(tmp); \
|
||||
tcg_temp_free(byte); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_L2_loadbzw4_io(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), false)
|
||||
#define fGEN_TCG_L4_loadbzw4_ur(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), false)
|
||||
#define fGEN_TCG_L2_loadbsw4_io(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), true)
|
||||
#define fGEN_TCG_L4_loadbsw4_ur(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), true)
|
||||
#define fGEN_TCG_L2_loadbzw4_pci(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pci, false)
|
||||
#define fGEN_TCG_L2_loadbsw4_pci(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pci, true)
|
||||
#define fGEN_TCG_L2_loadbzw4_pcr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pcr(2), false)
|
||||
#define fGEN_TCG_L2_loadbsw4_pcr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pcr(2), true)
|
||||
#define fGEN_TCG_L4_loadbzw4_ap(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_ap, false)
|
||||
#define fGEN_TCG_L2_loadbzw4_pr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pr, false)
|
||||
#define fGEN_TCG_L2_loadbzw4_pbr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pbr, false)
|
||||
#define fGEN_TCG_L2_loadbzw4_pi(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pi, false)
|
||||
#define fGEN_TCG_L4_loadbsw4_ap(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_ap, true)
|
||||
#define fGEN_TCG_L2_loadbsw4_pr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pr, true)
|
||||
#define fGEN_TCG_L2_loadbsw4_pbr(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pbr, true)
|
||||
#define fGEN_TCG_L2_loadbsw4_pi(SHORTCODE) \
|
||||
fGEN_TCG_loadbXw4(GET_EA_pi, true)
|
||||
|
||||
/*
|
||||
* These instructions load a half word, shift the destination right by 16 bits
|
||||
* and place the loaded value in the high half word of the destination pair.
|
||||
* The GET_EA macro determines the addressing mode.
|
||||
*/
|
||||
#define fGEN_TCG_loadalignh(GET_EA) \
|
||||
do { \
|
||||
TCGv tmp = tcg_temp_new(); \
|
||||
TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \
|
||||
GET_EA; \
|
||||
fLOAD(1, 2, u, EA, tmp); \
|
||||
tcg_gen_extu_i32_i64(tmp_i64, tmp); \
|
||||
tcg_gen_shri_i64(RyyV, RyyV, 16); \
|
||||
tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 48, 16); \
|
||||
tcg_temp_free(tmp); \
|
||||
tcg_temp_free_i64(tmp_i64); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_L4_loadalignh_ur(SHORTCODE) \
|
||||
fGEN_TCG_loadalignh(fEA_IRs(UiV, RtV, uiV))
|
||||
#define fGEN_TCG_L2_loadalignh_io(SHORTCODE) \
|
||||
fGEN_TCG_loadalignh(fEA_RI(RsV, siV))
|
||||
#define fGEN_TCG_L2_loadalignh_pci(SHORTCODE) \
|
||||
fGEN_TCG_loadalignh(GET_EA_pci)
|
||||
#define fGEN_TCG_L2_loadalignh_pcr(SHORTCODE) \
|
||||
fGEN_TCG_loadalignh(GET_EA_pcr(1))
|
||||
#define fGEN_TCG_L4_loadalignh_ap(SHORTCODE) \
|
||||
fGEN_TCG_loadalignh(GET_EA_ap)
|
||||
#define fGEN_TCG_L2_loadalignh_pr(SHORTCODE) \
|
||||
fGEN_TCG_loadalignh(GET_EA_pr)
|
||||
#define fGEN_TCG_L2_loadalignh_pbr(SHORTCODE) \
|
||||
fGEN_TCG_loadalignh(GET_EA_pbr)
|
||||
#define fGEN_TCG_L2_loadalignh_pi(SHORTCODE) \
|
||||
fGEN_TCG_loadalignh(GET_EA_pi)
|
||||
|
||||
/* Same as above, but loads a byte instead of half word */
|
||||
#define fGEN_TCG_loadalignb(GET_EA) \
|
||||
do { \
|
||||
TCGv tmp = tcg_temp_new(); \
|
||||
TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \
|
||||
GET_EA; \
|
||||
fLOAD(1, 1, u, EA, tmp); \
|
||||
tcg_gen_extu_i32_i64(tmp_i64, tmp); \
|
||||
tcg_gen_shri_i64(RyyV, RyyV, 8); \
|
||||
tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 56, 8); \
|
||||
tcg_temp_free(tmp); \
|
||||
tcg_temp_free_i64(tmp_i64); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_L2_loadalignb_io(SHORTCODE) \
|
||||
fGEN_TCG_loadalignb(fEA_RI(RsV, siV))
|
||||
#define fGEN_TCG_L4_loadalignb_ur(SHORTCODE) \
|
||||
fGEN_TCG_loadalignb(fEA_IRs(UiV, RtV, uiV))
|
||||
#define fGEN_TCG_L2_loadalignb_pci(SHORTCODE) \
|
||||
fGEN_TCG_loadalignb(GET_EA_pci)
|
||||
#define fGEN_TCG_L2_loadalignb_pcr(SHORTCODE) \
|
||||
fGEN_TCG_loadalignb(GET_EA_pcr(0))
|
||||
#define fGEN_TCG_L4_loadalignb_ap(SHORTCODE) \
|
||||
fGEN_TCG_loadalignb(GET_EA_ap)
|
||||
#define fGEN_TCG_L2_loadalignb_pr(SHORTCODE) \
|
||||
fGEN_TCG_loadalignb(GET_EA_pr)
|
||||
#define fGEN_TCG_L2_loadalignb_pbr(SHORTCODE) \
|
||||
fGEN_TCG_loadalignb(GET_EA_pbr)
|
||||
#define fGEN_TCG_L2_loadalignb_pi(SHORTCODE) \
|
||||
fGEN_TCG_loadalignb(GET_EA_pi)
|
||||
|
||||
/*
|
||||
* Predicated loads
|
||||
* Here is a primer to understand the tag names
|
||||
@ -195,6 +428,191 @@
|
||||
#define fGEN_TCG_S4_stored_locked(SHORTCODE) \
|
||||
do { SHORTCODE; READ_PREG(PdV, PdN); } while (0)
|
||||
|
||||
#define fGEN_TCG_STORE(SHORTCODE) \
|
||||
do { \
|
||||
TCGv HALF = tcg_temp_new(); \
|
||||
TCGv BYTE = tcg_temp_new(); \
|
||||
SHORTCODE; \
|
||||
tcg_temp_free(HALF); \
|
||||
tcg_temp_free(BYTE); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_STORE_pcr(SHIFT, STORE) \
|
||||
do { \
|
||||
TCGv ireg = tcg_temp_new(); \
|
||||
TCGv HALF = tcg_temp_new(); \
|
||||
TCGv BYTE = tcg_temp_new(); \
|
||||
tcg_gen_mov_tl(EA, RxV); \
|
||||
gen_read_ireg(ireg, MuV, SHIFT); \
|
||||
gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
STORE; \
|
||||
tcg_temp_free(ireg); \
|
||||
tcg_temp_free(HALF); \
|
||||
tcg_temp_free(BYTE); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_S2_storerb_pbr(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerb_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerb_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, RtV)))
|
||||
|
||||
#define fGEN_TCG_S2_storerh_pbr(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerh_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerh_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, RtV)))
|
||||
|
||||
#define fGEN_TCG_S2_storerf_pbr(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerf_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerf_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(1, RtV)))
|
||||
|
||||
#define fGEN_TCG_S2_storeri_pbr(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storeri_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storeri_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, RtV))
|
||||
|
||||
#define fGEN_TCG_S2_storerd_pbr(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerd_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerd_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(3, fSTORE(1, 8, EA, RttV))
|
||||
|
||||
#define fGEN_TCG_S2_storerbnew_pbr(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerbnew_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerbnew_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, NtN)))
|
||||
|
||||
#define fGEN_TCG_S2_storerhnew_pbr(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerhnew_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerhnew_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, NtN)))
|
||||
|
||||
#define fGEN_TCG_S2_storerinew_pbr(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerinew_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerinew_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, NtN))
|
||||
|
||||
/*
|
||||
* Mathematical operations with more than one definition require
|
||||
* special handling
|
||||
*/
|
||||
#define fGEN_TCG_A5_ACS(SHORTCODE) \
|
||||
do { \
|
||||
gen_helper_vacsh_pred(PeV, cpu_env, RxxV, RssV, RttV); \
|
||||
gen_helper_vacsh_val(RxxV, cpu_env, RxxV, RssV, RttV); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Approximate reciprocal
|
||||
* r3,p1 = sfrecipa(r0, r1)
|
||||
*
|
||||
* The helper packs the 2 32-bit results into a 64-bit value,
|
||||
* so unpack them into the proper results.
|
||||
*/
|
||||
#define fGEN_TCG_F2_sfrecipa(SHORTCODE) \
|
||||
do { \
|
||||
TCGv_i64 tmp = tcg_temp_new_i64(); \
|
||||
gen_helper_sfrecipa(tmp, cpu_env, RsV, RtV); \
|
||||
tcg_gen_extrh_i64_i32(RdV, tmp); \
|
||||
tcg_gen_extrl_i64_i32(PeV, tmp); \
|
||||
tcg_temp_free_i64(tmp); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Approximation of the reciprocal square root
|
||||
* r1,p0 = sfinvsqrta(r0)
|
||||
*
|
||||
* The helper packs the 2 32-bit results into a 64-bit value,
|
||||
* so unpack them into the proper results.
|
||||
*/
|
||||
#define fGEN_TCG_F2_sfinvsqrta(SHORTCODE) \
|
||||
do { \
|
||||
TCGv_i64 tmp = tcg_temp_new_i64(); \
|
||||
gen_helper_sfinvsqrta(tmp, cpu_env, RsV); \
|
||||
tcg_gen_extrh_i64_i32(RdV, tmp); \
|
||||
tcg_gen_extrl_i64_i32(PeV, tmp); \
|
||||
tcg_temp_free_i64(tmp); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Add or subtract with carry.
|
||||
* Predicate register is used as an extra input and output.
|
||||
* r5:4 = add(r1:0, r3:2, p1):carry
|
||||
*/
|
||||
#define fGEN_TCG_A4_addp_c(SHORTCODE) \
|
||||
do { \
|
||||
TCGv_i64 carry = tcg_temp_new_i64(); \
|
||||
TCGv_i64 zero = tcg_const_i64(0); \
|
||||
tcg_gen_extu_i32_i64(carry, PxV); \
|
||||
tcg_gen_andi_i64(carry, carry, 1); \
|
||||
tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \
|
||||
tcg_gen_add2_i64(RddV, carry, RddV, carry, RttV, zero); \
|
||||
tcg_gen_extrl_i64_i32(PxV, carry); \
|
||||
gen_8bitsof(PxV, PxV); \
|
||||
tcg_temp_free_i64(carry); \
|
||||
tcg_temp_free_i64(zero); \
|
||||
} while (0)
|
||||
|
||||
/* r5:4 = sub(r1:0, r3:2, p1):carry */
|
||||
#define fGEN_TCG_A4_subp_c(SHORTCODE) \
|
||||
do { \
|
||||
TCGv_i64 carry = tcg_temp_new_i64(); \
|
||||
TCGv_i64 zero = tcg_const_i64(0); \
|
||||
TCGv_i64 not_RttV = tcg_temp_new_i64(); \
|
||||
tcg_gen_extu_i32_i64(carry, PxV); \
|
||||
tcg_gen_andi_i64(carry, carry, 1); \
|
||||
tcg_gen_not_i64(not_RttV, RttV); \
|
||||
tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \
|
||||
tcg_gen_add2_i64(RddV, carry, RddV, carry, not_RttV, zero); \
|
||||
tcg_gen_extrl_i64_i32(PxV, carry); \
|
||||
gen_8bitsof(PxV, PxV); \
|
||||
tcg_temp_free_i64(carry); \
|
||||
tcg_temp_free_i64(zero); \
|
||||
tcg_temp_free_i64(not_RttV); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Compare each of the 8 unsigned bytes
|
||||
* The minimum is placed in each byte of the destination.
|
||||
* Each bit of the predicate is set true if the bit from the first operand
|
||||
* is greater than the bit from the second operand.
|
||||
* r5:4,p1 = vminub(r1:0, r3:2)
|
||||
*/
|
||||
#define fGEN_TCG_A6_vminub_RdP(SHORTCODE) \
|
||||
do { \
|
||||
TCGv left = tcg_temp_new(); \
|
||||
TCGv right = tcg_temp_new(); \
|
||||
TCGv tmp = tcg_temp_new(); \
|
||||
tcg_gen_movi_tl(PeV, 0); \
|
||||
tcg_gen_movi_i64(RddV, 0); \
|
||||
for (int i = 0; i < 8; i++) { \
|
||||
gen_get_byte_i64(left, i, RttV, false); \
|
||||
gen_get_byte_i64(right, i, RssV, false); \
|
||||
tcg_gen_setcond_tl(TCG_COND_GT, tmp, left, right); \
|
||||
tcg_gen_deposit_tl(PeV, PeV, tmp, i, 1); \
|
||||
tcg_gen_umin_tl(tmp, left, right); \
|
||||
gen_set_byte_i64(i, RddV, tmp); \
|
||||
} \
|
||||
tcg_temp_free(left); \
|
||||
tcg_temp_free(right); \
|
||||
tcg_temp_free(tmp); \
|
||||
} while (0)
|
||||
|
||||
/* Floating point */
|
||||
#define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \
|
||||
gen_helper_conv_sf2df(RddV, cpu_env, RsV)
|
||||
|
@ -316,7 +316,7 @@ def genptr_dst_write(f, tag, regtype, regid):
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "P"):
|
||||
if (regid in {"d", "e", "x"}):
|
||||
f.write(" gen_log_pred_write(%s%sN, %s%sV);\n" % \
|
||||
f.write(" gen_log_pred_write(ctx, %s%sN, %s%sV);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
f.write(" ctx_log_pred_write(ctx, %s%sN);\n" % \
|
||||
(regtype, regid))
|
||||
|
@ -15,7 +15,6 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define QEMU_GENERATE
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
@ -24,7 +23,9 @@
|
||||
#include "insn.h"
|
||||
#include "opcodes.h"
|
||||
#include "translate.h"
|
||||
#define QEMU_GENERATE /* Used internally by macros.h */
|
||||
#include "macros.h"
|
||||
#undef QEMU_GENERATE
|
||||
#include "gen_tcg.h"
|
||||
|
||||
static inline TCGv gen_read_preg(TCGv pred, uint8_t num)
|
||||
@ -35,20 +36,24 @@ static inline TCGv gen_read_preg(TCGv pred, uint8_t num)
|
||||
|
||||
static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
|
||||
{
|
||||
TCGv one = tcg_const_tl(1);
|
||||
TCGv zero = tcg_const_tl(0);
|
||||
TCGv slot_mask = tcg_temp_new();
|
||||
|
||||
tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero,
|
||||
val, hex_new_value[rnum]);
|
||||
#if HEX_DEBUG
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum], slot_mask, zero,
|
||||
one, hex_reg_written[rnum]);
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
/*
|
||||
* Do this so HELPER(debug_commit_end) will know
|
||||
*
|
||||
* Note that slot_mask indicates the value is not written
|
||||
* (i.e., slot was cancelled), so we create a true/false value before
|
||||
* or'ing with hex_reg_written[rnum].
|
||||
*/
|
||||
tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero);
|
||||
tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask);
|
||||
}
|
||||
|
||||
tcg_temp_free(one);
|
||||
tcg_temp_free(zero);
|
||||
tcg_temp_free(slot_mask);
|
||||
}
|
||||
@ -56,45 +61,44 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
|
||||
static inline void gen_log_reg_write(int rnum, TCGv val)
|
||||
{
|
||||
tcg_gen_mov_tl(hex_new_value[rnum], val);
|
||||
#if HEX_DEBUG
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movi_tl(hex_reg_written[rnum], 1);
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movi_tl(hex_reg_written[rnum], 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot)
|
||||
{
|
||||
TCGv val32 = tcg_temp_new();
|
||||
TCGv one = tcg_const_tl(1);
|
||||
TCGv zero = tcg_const_tl(0);
|
||||
TCGv slot_mask = tcg_temp_new();
|
||||
|
||||
tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot);
|
||||
/* Low word */
|
||||
tcg_gen_extrl_i64_i32(val32, val);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero,
|
||||
val32, hex_new_value[rnum]);
|
||||
#if HEX_DEBUG
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum],
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum],
|
||||
slot_mask, zero,
|
||||
one, hex_reg_written[rnum]);
|
||||
#endif
|
||||
|
||||
val32, hex_new_value[rnum]);
|
||||
/* High word */
|
||||
tcg_gen_extrh_i64_i32(val32, val);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum + 1],
|
||||
slot_mask, zero,
|
||||
val32, hex_new_value[rnum + 1]);
|
||||
#if HEX_DEBUG
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum + 1],
|
||||
slot_mask, zero,
|
||||
one, hex_reg_written[rnum + 1]);
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
/*
|
||||
* Do this so HELPER(debug_commit_end) will know
|
||||
*
|
||||
* Note that slot_mask indicates the value is not written
|
||||
* (i.e., slot was cancelled), so we create a true/false value before
|
||||
* or'ing with hex_reg_written[rnum].
|
||||
*/
|
||||
tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero);
|
||||
tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask);
|
||||
tcg_gen_or_tl(hex_reg_written[rnum + 1], hex_reg_written[rnum + 1],
|
||||
slot_mask);
|
||||
}
|
||||
|
||||
tcg_temp_free(val32);
|
||||
tcg_temp_free(one);
|
||||
tcg_temp_free(zero);
|
||||
tcg_temp_free(slot_mask);
|
||||
}
|
||||
@ -103,33 +107,41 @@ static void gen_log_reg_write_pair(int rnum, TCGv_i64 val)
|
||||
{
|
||||
/* Low word */
|
||||
tcg_gen_extrl_i64_i32(hex_new_value[rnum], val);
|
||||
#if HEX_DEBUG
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movi_tl(hex_reg_written[rnum], 1);
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movi_tl(hex_reg_written[rnum], 1);
|
||||
}
|
||||
|
||||
/* High word */
|
||||
tcg_gen_extrh_i64_i32(hex_new_value[rnum + 1], val);
|
||||
#if HEX_DEBUG
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1);
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_log_pred_write(int pnum, TCGv val)
|
||||
static inline void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
|
||||
{
|
||||
TCGv zero = tcg_const_tl(0);
|
||||
TCGv base_val = tcg_temp_new();
|
||||
TCGv and_val = tcg_temp_new();
|
||||
TCGv pred_written = tcg_temp_new();
|
||||
|
||||
/* Multiple writes to the same preg are and'ed together */
|
||||
tcg_gen_andi_tl(base_val, val, 0xff);
|
||||
tcg_gen_and_tl(and_val, base_val, hex_new_pred_value[pnum]);
|
||||
tcg_gen_andi_tl(pred_written, hex_pred_written, 1 << pnum);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, hex_new_pred_value[pnum],
|
||||
pred_written, zero,
|
||||
and_val, base_val);
|
||||
|
||||
/*
|
||||
* Section 6.1.3 of the Hexagon V67 Programmer's Reference Manual
|
||||
*
|
||||
* Multiple writes to the same preg are and'ed together
|
||||
* If this is the first predicate write in the packet, do a
|
||||
* straight assignment. Otherwise, do an and.
|
||||
*/
|
||||
if (!test_bit(pnum, ctx->pregs_written)) {
|
||||
tcg_gen_mov_tl(hex_new_pred_value[pnum], base_val);
|
||||
} else {
|
||||
tcg_gen_and_tl(hex_new_pred_value[pnum],
|
||||
hex_new_pred_value[pnum], base_val);
|
||||
}
|
||||
tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pnum);
|
||||
|
||||
tcg_temp_free(zero);
|
||||
@ -254,6 +266,61 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
|
||||
}
|
||||
}
|
||||
|
||||
static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
|
||||
{
|
||||
if (sign) {
|
||||
tcg_gen_sextract_tl(result, src, N * 8, 8);
|
||||
} else {
|
||||
tcg_gen_extract_tl(result, src, N * 8, 8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
|
||||
{
|
||||
TCGv_i64 res64 = tcg_temp_new_i64();
|
||||
if (sign) {
|
||||
tcg_gen_sextract_i64(res64, src, N * 8, 8);
|
||||
} else {
|
||||
tcg_gen_extract_i64(res64, src, N * 8, 8);
|
||||
}
|
||||
tcg_gen_extrl_i64_i32(result, res64);
|
||||
tcg_temp_free_i64(res64);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
|
||||
{
|
||||
if (sign) {
|
||||
tcg_gen_sextract_tl(result, src, N * 16, 16);
|
||||
} else {
|
||||
tcg_gen_extract_tl(result, src, N * 16, 16);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void gen_set_half(int N, TCGv result, TCGv src)
|
||||
{
|
||||
tcg_gen_deposit_tl(result, result, src, N * 16, 16);
|
||||
}
|
||||
|
||||
static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
|
||||
{
|
||||
TCGv_i64 src64 = tcg_temp_new_i64();
|
||||
tcg_gen_extu_i32_i64(src64, src);
|
||||
tcg_gen_deposit_i64(result, result, src64, N * 16, 16);
|
||||
tcg_temp_free_i64(src64);
|
||||
}
|
||||
|
||||
static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
|
||||
{
|
||||
TCGv_i64 src64 = tcg_temp_new_i64();
|
||||
tcg_gen_extu_i32_i64(src64, src);
|
||||
tcg_gen_deposit_i64(result, result, src64, N * 8, 8);
|
||||
tcg_temp_free_i64(src64);
|
||||
}
|
||||
|
||||
static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index)
|
||||
{
|
||||
tcg_gen_qemu_ld32u(dest, vaddr, mem_index);
|
||||
@ -327,5 +394,85 @@ static inline void gen_store_conditional8(CPUHexagonState *env,
|
||||
tcg_gen_movi_tl(hex_llsc_addr, ~0);
|
||||
}
|
||||
|
||||
static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
|
||||
{
|
||||
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
|
||||
tcg_gen_movi_tl(hex_store_width[slot], width);
|
||||
tcg_gen_mov_tl(hex_store_val32[slot], src);
|
||||
}
|
||||
|
||||
static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
gen_store32(vaddr, src, 1, slot);
|
||||
ctx->store_width[slot] = 1;
|
||||
}
|
||||
|
||||
static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
TCGv tmp = tcg_const_tl(src);
|
||||
gen_store1(cpu_env, vaddr, tmp, ctx, slot);
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
|
||||
static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
gen_store32(vaddr, src, 2, slot);
|
||||
ctx->store_width[slot] = 2;
|
||||
}
|
||||
|
||||
static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
TCGv tmp = tcg_const_tl(src);
|
||||
gen_store2(cpu_env, vaddr, tmp, ctx, slot);
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
|
||||
static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
gen_store32(vaddr, src, 4, slot);
|
||||
ctx->store_width[slot] = 4;
|
||||
}
|
||||
|
||||
static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
TCGv tmp = tcg_const_tl(src);
|
||||
gen_store4(cpu_env, vaddr, tmp, ctx, slot);
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
|
||||
static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
|
||||
tcg_gen_movi_tl(hex_store_width[slot], 8);
|
||||
tcg_gen_mov_i64(hex_store_val64[slot], src);
|
||||
ctx->store_width[slot] = 8;
|
||||
}
|
||||
|
||||
static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
TCGv_i64 tmp = tcg_const_i64(src);
|
||||
gen_store8(cpu_env, vaddr, tmp, ctx, slot);
|
||||
tcg_temp_free_i64(tmp);
|
||||
}
|
||||
|
||||
static TCGv gen_8bitsof(TCGv result, TCGv value)
|
||||
{
|
||||
TCGv zero = tcg_const_tl(0);
|
||||
TCGv ones = tcg_const_tl(0xff);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero);
|
||||
tcg_temp_free(zero);
|
||||
tcg_temp_free(ones);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#include "tcg_funcs_generated.c.inc"
|
||||
#include "tcg_func_table_generated.c.inc"
|
||||
|
@ -19,13 +19,16 @@
|
||||
#include "helper_protos_generated.h.inc"
|
||||
|
||||
DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_RETURN, noreturn, env, i32)
|
||||
#if HEX_DEBUG
|
||||
DEF_HELPER_1(debug_start_packet, void, env)
|
||||
DEF_HELPER_FLAGS_3(debug_check_store_width, TCG_CALL_NO_WG, void, env, int, int)
|
||||
DEF_HELPER_FLAGS_3(debug_commit_end, TCG_CALL_NO_WG, void, env, int, int)
|
||||
#endif
|
||||
DEF_HELPER_2(commit_store, void, env, int)
|
||||
DEF_HELPER_FLAGS_4(fcircadd, TCG_CALL_NO_RWG_SE, s32, s32, s32, s32, s32)
|
||||
DEF_HELPER_FLAGS_1(fbrev, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_3(sfrecipa, i64, env, f32, f32)
|
||||
DEF_HELPER_2(sfinvsqrta, i64, env, f32)
|
||||
DEF_HELPER_4(vacsh_val, s64, env, s64, s64, s64)
|
||||
DEF_HELPER_FLAGS_4(vacsh_pred, TCG_CALL_NO_RWG_SE, s32, env, s64, s64, s64)
|
||||
|
||||
/* Floating point */
|
||||
DEF_HELPER_2(conv_sf2df, f64, env, f32)
|
||||
@ -38,21 +41,21 @@ DEF_HELPER_2(conv_ud2sf, f32, env, s64)
|
||||
DEF_HELPER_2(conv_ud2df, f64, env, s64)
|
||||
DEF_HELPER_2(conv_d2sf, f32, env, s64)
|
||||
DEF_HELPER_2(conv_d2df, f64, env, s64)
|
||||
DEF_HELPER_2(conv_sf2uw, s32, env, f32)
|
||||
DEF_HELPER_2(conv_sf2uw, i32, env, f32)
|
||||
DEF_HELPER_2(conv_sf2w, s32, env, f32)
|
||||
DEF_HELPER_2(conv_sf2ud, s64, env, f32)
|
||||
DEF_HELPER_2(conv_sf2ud, i64, env, f32)
|
||||
DEF_HELPER_2(conv_sf2d, s64, env, f32)
|
||||
DEF_HELPER_2(conv_df2uw, s32, env, f64)
|
||||
DEF_HELPER_2(conv_df2uw, i32, env, f64)
|
||||
DEF_HELPER_2(conv_df2w, s32, env, f64)
|
||||
DEF_HELPER_2(conv_df2ud, s64, env, f64)
|
||||
DEF_HELPER_2(conv_df2ud, i64, env, f64)
|
||||
DEF_HELPER_2(conv_df2d, s64, env, f64)
|
||||
DEF_HELPER_2(conv_sf2uw_chop, s32, env, f32)
|
||||
DEF_HELPER_2(conv_sf2uw_chop, i32, env, f32)
|
||||
DEF_HELPER_2(conv_sf2w_chop, s32, env, f32)
|
||||
DEF_HELPER_2(conv_sf2ud_chop, s64, env, f32)
|
||||
DEF_HELPER_2(conv_sf2ud_chop, i64, env, f32)
|
||||
DEF_HELPER_2(conv_sf2d_chop, s64, env, f32)
|
||||
DEF_HELPER_2(conv_df2uw_chop, s32, env, f64)
|
||||
DEF_HELPER_2(conv_df2uw_chop, i32, env, f64)
|
||||
DEF_HELPER_2(conv_df2w_chop, s32, env, f64)
|
||||
DEF_HELPER_2(conv_df2ud_chop, s64, env, f64)
|
||||
DEF_HELPER_2(conv_df2ud_chop, i64, env, f64)
|
||||
DEF_HELPER_2(conv_df2d_chop, s64, env, f64)
|
||||
DEF_HELPER_3(sfadd, f32, env, f32, f32)
|
||||
DEF_HELPER_3(sfsub, f32, env, f32, f32)
|
||||
|
@ -53,10 +53,6 @@ SlotMask find_iclass_slots(Opcode opcode, int itype)
|
||||
(opcode == Y2_isync) ||
|
||||
(opcode == J2_pause) || (opcode == J4_hintjumpr)) {
|
||||
return SLOTS_2;
|
||||
} else if ((itype == ICLASS_V2LDST) && (GET_ATTRIB(opcode, A_STORE))) {
|
||||
return SLOTS_01;
|
||||
} else if ((itype == ICLASS_V2LDST) && (!GET_ATTRIB(opcode, A_STORE))) {
|
||||
return SLOTS_01;
|
||||
} else if (GET_ATTRIB(opcode, A_CRSLOT23)) {
|
||||
return SLOTS_23;
|
||||
} else if (GET_ATTRIB(opcode, A_RESTRICT_PREFERSLOT0)) {
|
||||
|
@ -153,6 +153,21 @@ Q6INSN(A2_subp,"Rdd32=sub(Rtt32,Rss32)",ATTRIBS(),
|
||||
"Sub",
|
||||
{ RddV=RttV-RssV;})
|
||||
|
||||
/* 64-bit with carry */
|
||||
|
||||
Q6INSN(A4_addp_c,"Rdd32=add(Rss32,Rtt32,Px4):carry",ATTRIBS(),"Add with Carry",
|
||||
{
|
||||
RddV = RssV + RttV + fLSBOLD(PxV);
|
||||
PxV = f8BITSOF(fCARRY_FROM_ADD(RssV,RttV,fLSBOLD(PxV)));
|
||||
})
|
||||
|
||||
Q6INSN(A4_subp_c,"Rdd32=sub(Rss32,Rtt32,Px4):carry",ATTRIBS(),"Sub with Carry",
|
||||
{
|
||||
RddV = RssV + ~RttV + fLSBOLD(PxV);
|
||||
PxV = f8BITSOF(fCARRY_FROM_ADD(RssV,~RttV,fLSBOLD(PxV)));
|
||||
})
|
||||
|
||||
|
||||
/* NEG and ABS */
|
||||
|
||||
Q6INSN(A2_negsat,"Rd32=neg(Rs32):sat",ATTRIBS(),
|
||||
@ -1240,6 +1255,35 @@ MINMAX(uw,WORD,UWORD,2)
|
||||
#undef VMINORMAX3
|
||||
|
||||
|
||||
Q6INSN(A5_ACS,"Rxx32,Pe4=vacsh(Rss32,Rtt32)",ATTRIBS(),
|
||||
"Add Compare and Select elements of two vectors, record the maximums and the decisions ",
|
||||
{
|
||||
fHIDE(int i;)
|
||||
fHIDE(int xv;)
|
||||
fHIDE(int sv;)
|
||||
fHIDE(int tv;)
|
||||
for (i = 0; i < 4; i++) {
|
||||
xv = (int) fGETHALF(i,RxxV);
|
||||
sv = (int) fGETHALF(i,RssV);
|
||||
tv = (int) fGETHALF(i,RttV);
|
||||
xv = xv + tv; //assumes 17bit datapath
|
||||
sv = sv - tv; //assumes 17bit datapath
|
||||
fSETBIT(i*2, PeV, (xv > sv));
|
||||
fSETBIT(i*2+1,PeV, (xv > sv));
|
||||
fSETHALF(i, RxxV, fSATH(fMAX(xv,sv)));
|
||||
}
|
||||
})
|
||||
|
||||
Q6INSN(A6_vminub_RdP,"Rdd32,Pe4=vminub(Rtt32,Rss32)",ATTRIBS(),
|
||||
"Vector minimum of bytes, records minimum and decision vector",
|
||||
{
|
||||
fHIDE(int i;)
|
||||
for (i = 0; i < 8; i++) {
|
||||
fSETBIT(i, PeV, (fGETUBYTE(i,RttV) > fGETUBYTE(i,RssV)));
|
||||
fSETBYTE(i,RddV,fMIN(fGETUBYTE(i,RttV),fGETUBYTE(i,RssV)));
|
||||
}
|
||||
})
|
||||
|
||||
/**********************************************/
|
||||
/* Vector Min/Max */
|
||||
/**********************************************/
|
||||
|
@ -198,11 +198,11 @@ Q6INSN(C4_or_orn,"Pd4=or(Ps4,or(Pt4,!Pu4))",ATTRIBS(A_CRSLOT23),
|
||||
|
||||
Q6INSN(C2_any8,"Pd4=any8(Ps4)",ATTRIBS(A_CRSLOT23),
|
||||
"Logical ANY of low 8 predicate bits",
|
||||
{ PsV ? (PdV=0xff) : (PdV=0x00); })
|
||||
{ PdV = (PsV ? 0xff : 0x00); })
|
||||
|
||||
Q6INSN(C2_all8,"Pd4=all8(Ps4)",ATTRIBS(A_CRSLOT23),
|
||||
"Logical ALL of low 8 predicate bits",
|
||||
{ (PsV==0xff) ? (PdV=0xff) : (PdV=0x00); })
|
||||
{ PdV = (PsV == 0xff ? 0xff : 0x00); })
|
||||
|
||||
Q6INSN(C2_vitpack,"Rd32=vitpack(Ps4,Pt4)",ATTRIBS(),
|
||||
"Pack the odd and even bits of two predicate registers",
|
||||
@ -212,7 +212,7 @@ Q6INSN(C2_vitpack,"Rd32=vitpack(Ps4,Pt4)",ATTRIBS(),
|
||||
|
||||
Q6INSN(C2_mux,"Rd32=mux(Pu4,Rs32,Rt32)",ATTRIBS(),
|
||||
"Scalar MUX",
|
||||
{ (fLSBOLD(PuV)) ? (RdV=RsV):(RdV=RtV); })
|
||||
{ RdV = (fLSBOLD(PuV) ? RsV : RtV); })
|
||||
|
||||
|
||||
Q6INSN(C2_cmovenewit,"if (Pu4.new) Rd32=#s12",ATTRIBS(A_ARCHV2),
|
||||
@ -269,18 +269,18 @@ Q6INSN(C2_ccombinewf,"if (!Pu4) Rdd32=combine(Rs32,Rt32)",ATTRIBS(A_ARCHV2),
|
||||
|
||||
Q6INSN(C2_muxii,"Rd32=mux(Pu4,#s8,#S8)",ATTRIBS(A_ARCHV2),
|
||||
"Scalar MUX immediates",
|
||||
{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=siV):(RdV=SiV); })
|
||||
{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? siV : SiV); })
|
||||
|
||||
|
||||
|
||||
Q6INSN(C2_muxir,"Rd32=mux(Pu4,Rs32,#s8)",ATTRIBS(A_ARCHV2),
|
||||
"Scalar MUX register immediate",
|
||||
{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=RsV):(RdV=siV); })
|
||||
{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? RsV : siV); })
|
||||
|
||||
|
||||
Q6INSN(C2_muxri,"Rd32=mux(Pu4,#s8,Rs32)",ATTRIBS(A_ARCHV2),
|
||||
"Scalar MUX register immediate",
|
||||
{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=siV):(RdV=RsV); })
|
||||
{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? siV : RsV); })
|
||||
|
||||
|
||||
|
||||
|
@ -294,12 +294,14 @@ DEF_CLASS32(ICLASS_LD" ---- -------- PP------ --------",LD)
|
||||
|
||||
|
||||
DEF_CLASS32(ICLASS_LD" 0--- -------- PP------ --------",LD_ADDR_ROFFSET)
|
||||
DEF_CLASS32(ICLASS_LD" 100- -------- PP----0- --------",LD_ADDR_POST_CIRC_IMMED)
|
||||
DEF_CLASS32(ICLASS_LD" 101- -------- PP00---- --------",LD_ADDR_POST_IMMED)
|
||||
DEF_CLASS32(ICLASS_LD" 101- -------- PP01---- --------",LD_ADDR_ABS_UPDATE_V4)
|
||||
DEF_CLASS32(ICLASS_LD" 101- -------- PP1----- --------",LD_ADDR_POST_IMMED_PRED_V2)
|
||||
DEF_CLASS32(ICLASS_LD" 110- -------- PP-0---- 0-------",LD_ADDR_POST_REG)
|
||||
DEF_CLASS32(ICLASS_LD" 110- -------- PP-1---- --------",LD_ADDR_ABS_PLUS_REG_V4)
|
||||
DEF_CLASS32(ICLASS_LD" 100- -------- PP----1- --------",LD_ADDR_POST_CREG_V2)
|
||||
DEF_CLASS32(ICLASS_LD" 111- -------- PP------ 0-------",LD_ADDR_POST_BREV_REG)
|
||||
DEF_CLASS32(ICLASS_LD" 111- -------- PP------ 1-------",LD_ADDR_PRED_ABS_V4)
|
||||
|
||||
DEF_FIELD32(ICLASS_LD" !!!- -------- PP------ --------",LD_Amode,"Amode")
|
||||
@ -308,18 +310,24 @@ DEF_FIELD32(ICLASS_LD" ---- --!----- PP------ --------",LD_UN,"Unsigned")
|
||||
|
||||
#define STD_LD_ENC(TAG,OPC) \
|
||||
DEF_ENC32(L2_load##TAG##_io, ICLASS_LD" 0 ii "OPC" sssss PPiiiiii iiiddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pci, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--0i iiiddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pi, ICLASS_LD" 1 01 "OPC" xxxxx PP00---i iiiddddd")\
|
||||
DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--ddddd")\
|
||||
DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--ddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pbr, ICLASS_LD" 1 11 "OPC" xxxxx PPu0---- 0--ddddd")
|
||||
|
||||
|
||||
#define STD_LDX_ENC(TAG,OPC) \
|
||||
DEF_ENC32(L2_load##TAG##_io, ICLASS_LD" 0 ii "OPC" sssss PPiiiiii iiiyyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pci, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--0i iiiyyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pi, ICLASS_LD" 1 01 "OPC" xxxxx PP00---i iiiyyyyy")\
|
||||
DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIyyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--yyyyy")\
|
||||
DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIyyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--yyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pbr, ICLASS_LD" 1 11 "OPC" xxxxx PPu0---- 0--yyyyy")
|
||||
|
||||
|
||||
#define STD_PLD_ENC(TAG,OPC) \
|
||||
@ -334,6 +342,15 @@ DEF_ENC32(L4_pload##TAG##fnew_abs,ICLASS_LD" 1 11 "OPC" iiiii PP111tti 1--ddd
|
||||
|
||||
|
||||
/* 0 000 misc: dealloc,loadw_locked,dcfetch */
|
||||
STD_LD_ENC(bzw4,"0 101")
|
||||
STD_LD_ENC(bzw2,"0 011")
|
||||
|
||||
STD_LD_ENC(bsw4,"0 111")
|
||||
STD_LD_ENC(bsw2,"0 001")
|
||||
|
||||
STD_LDX_ENC(alignh,"0 010")
|
||||
STD_LDX_ENC(alignb,"0 100")
|
||||
|
||||
STD_LD_ENC(rb, "1 000")
|
||||
STD_LD_ENC(rub, "1 001")
|
||||
STD_LD_ENC(rh, "1 010")
|
||||
@ -351,6 +368,7 @@ STD_PLD_ENC(rd, "1 110") /* note dest reg field LSB=0, 1 is reserved */
|
||||
|
||||
DEF_CLASS32( ICLASS_LD" 0--0 000----- PP------ --------",LD_MISC)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 0--0 000----- PP------ --------",LD_ADDR_ROFFSET)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 1000 000----- PP------ --------",LD_ADDR_POST_CIRC_IMMED)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 1010 000----- PP------ --------",LD_ADDR_POST_IMMED)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 1100 000----- PP------ --------",LD_ADDR_POST_REG)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 1110 000----- PP------ --------",LD_ADDR_POST_REG)
|
||||
@ -397,6 +415,7 @@ DEF_FIELD32(ICLASS_ST" ---! !!------ PP------ --------",ST_Type,"Type")
|
||||
DEF_FIELD32(ICLASS_ST" ---- --!----- PP------ --------",ST_UN,"Unsigned")
|
||||
|
||||
DEF_CLASS32(ICLASS_ST" 0--1 -------- PP------ --------",ST_ADDR_ROFFSET)
|
||||
DEF_CLASS32(ICLASS_ST" 1001 -------- PP------ ------0-",ST_ADDR_POST_CIRC_IMMED)
|
||||
DEF_CLASS32(ICLASS_ST" 1011 -------- PP0----- 0-----0-",ST_ADDR_POST_IMMED)
|
||||
DEF_CLASS32(ICLASS_ST" 1011 -------- PP0----- 1-------",ST_ADDR_ABS_UPDATE_V4)
|
||||
DEF_CLASS32(ICLASS_ST" 1011 -------- PP1----- --------",ST_ADDR_POST_IMMED_PRED_V2)
|
||||
@ -404,6 +423,7 @@ DEF_CLASS32(ICLASS_ST" 1111 -------- PP------ 1-------",ST_ADDR_PRED_ABS_V4)
|
||||
DEF_CLASS32(ICLASS_ST" 1101 -------- PP------ 0-------",ST_ADDR_POST_REG)
|
||||
DEF_CLASS32(ICLASS_ST" 1101 -------- PP------ 1-------",ST_ADDR_ABS_PLUS_REG_V4)
|
||||
DEF_CLASS32(ICLASS_ST" 1001 -------- PP------ ------1-",ST_ADDR_POST_CREG_V2)
|
||||
DEF_CLASS32(ICLASS_ST" 1111 -------- PP------ 0-------",ST_ADDR_POST_BREV_REG)
|
||||
DEF_CLASS32(ICLASS_ST" 0--0 1------- PP------ --------",ST_MISC_STORELIKE)
|
||||
DEF_CLASS32(ICLASS_ST" 1--0 0------- PP------ --------",ST_MISC_BUSOP)
|
||||
DEF_CLASS32(ICLASS_ST" 0--0 0------- PP------ --------",ST_MISC_CACHEOP)
|
||||
@ -411,10 +431,13 @@ DEF_CLASS32(ICLASS_ST" 0--0 0------- PP------ --------",ST_MISC_CACHEOP)
|
||||
|
||||
#define STD_ST_ENC(TAG,OPC,SRC) \
|
||||
DEF_ENC32(S2_store##TAG##_io, ICLASS_ST" 0 ii "OPC" sssss PPi"SRC" iiiiiiii")\
|
||||
DEF_ENC32(S2_store##TAG##_pci, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0iiii-0-")\
|
||||
DEF_ENC32(S2_store##TAG##_pi, ICLASS_ST" 1 01 "OPC" xxxxx PP0"SRC" 0iiii-0-")\
|
||||
DEF_ENC32(S4_store##TAG##_ap, ICLASS_ST" 1 01 "OPC" eeeee PP0"SRC" 1-IIIIII")\
|
||||
DEF_ENC32(S2_store##TAG##_pr, ICLASS_ST" 1 10 "OPC" xxxxx PPu"SRC" 0-------")\
|
||||
DEF_ENC32(S4_store##TAG##_ur, ICLASS_ST" 1 10 "OPC" uuuuu PPi"SRC" 1iIIIIII")\
|
||||
DEF_ENC32(S2_store##TAG##_pcr, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0-----1-")\
|
||||
DEF_ENC32(S2_store##TAG##_pbr, ICLASS_ST" 1 11 "OPC" xxxxx PPu"SRC" 0-------")
|
||||
|
||||
|
||||
#define STD_PST_ENC(TAG,OPC,SRC) \
|
||||
@ -1017,6 +1040,8 @@ MPY_ENC(M7_dcmpyiwc_acc, "1010","xxxxx","1","0","1","0","10")
|
||||
|
||||
|
||||
|
||||
MPY_ENC(A5_ACS, "1010","xxxxx","0","1","0","1","ee")
|
||||
MPY_ENC(A6_vminub_RdP, "1010","ddddd","0","1","1","1","ee")
|
||||
/*
|
||||
*/
|
||||
|
||||
@ -1028,6 +1053,7 @@ MPY_ENC(F2_sfmin, "1011","ddddd","0","0","0","1","01")
|
||||
MPY_ENC(F2_sfmpy, "1011","ddddd","0","0","1","0","00")
|
||||
MPY_ENC(F2_sffixupn, "1011","ddddd","0","0","1","1","00")
|
||||
MPY_ENC(F2_sffixupd, "1011","ddddd","0","0","1","1","01")
|
||||
MPY_ENC(F2_sfrecipa, "1011","ddddd","1","1","1","1","ee")
|
||||
|
||||
DEF_FIELDROW_DESC32(ICLASS_M" 1100 -------- PP------ --------","[#12] Rd=(Rs,Rt)")
|
||||
DEF_FIELD32(ICLASS_M" 1100 -------- PP------ --!-----",Mc_tH,"Rt is High") /*Rt high */
|
||||
@ -1641,6 +1667,7 @@ SH2_RR_ENC(F2_conv_sf2w, "1011","100","-","000","ddddd")
|
||||
SH2_RR_ENC(F2_conv_sf2uw_chop, "1011","011","-","001","ddddd")
|
||||
SH2_RR_ENC(F2_conv_sf2w_chop, "1011","100","-","001","ddddd")
|
||||
SH2_RR_ENC(F2_sffixupr, "1011","101","-","000","ddddd")
|
||||
SH2_RR_ENC(F2_sfinvsqrta, "1011","111","-","0ee","ddddd")
|
||||
|
||||
|
||||
DEF_FIELDROW_DESC32(ICLASS_S2op" 1100 -------- PP------ --------","[#12] Rd=(Rs,#u6)")
|
||||
@ -1740,11 +1767,14 @@ SH_RRR_ENC(S4_vxsubaddh, "0001","01-","-","110","ddddd")
|
||||
SH_RRR_ENC(S4_vxaddsubhr, "0001","11-","-","00-","ddddd")
|
||||
SH_RRR_ENC(S4_vxsubaddhr, "0001","11-","-","01-","ddddd")
|
||||
SH_RRR_ENC(S4_extractp_rp, "0001","11-","-","10-","ddddd")
|
||||
SH_RRR_ENC(S2_cabacdecbin, "0001","11-","-","11-","ddddd") /* implicit P0 write */
|
||||
|
||||
|
||||
DEF_FIELDROW_DESC32(ICLASS_S3op" 0010 -------- PP------ --------","[#2] Rdd=(Rss,Rtt,Pu)")
|
||||
SH_RRR_ENC(S2_valignrb, "0010","0--","-","-uu","ddddd")
|
||||
SH_RRR_ENC(S2_vsplicerb, "0010","100","-","-uu","ddddd")
|
||||
SH_RRR_ENC(A4_addp_c, "0010","110","-","-xx","ddddd")
|
||||
SH_RRR_ENC(A4_subp_c, "0010","111","-","-xx","ddddd")
|
||||
|
||||
|
||||
DEF_FIELDROW_DESC32(ICLASS_S3op" 0011 -------- PP------ --------","[#3] Rdd=(Rss,Rt)")
|
||||
|
@ -146,6 +146,22 @@ Q6INSN(F2_sfimm_n,"Rd32=sfmake(#u10):neg",ATTRIBS(),
|
||||
})
|
||||
|
||||
|
||||
Q6INSN(F2_sfrecipa,"Rd32,Pe4=sfrecipa(Rs32,Rt32)",ATTRIBS(),
|
||||
"Reciprocal Approximation for Division",
|
||||
{
|
||||
fHIDE(int idx;)
|
||||
fHIDE(int adjust;)
|
||||
fHIDE(int mant;)
|
||||
fHIDE(int exp;)
|
||||
if (fSF_RECIP_COMMON(RsV,RtV,RdV,adjust)) {
|
||||
PeV = adjust;
|
||||
idx = (RtV >> 16) & 0x7f;
|
||||
mant = (fSF_RECIP_LOOKUP(idx) << 15) | 1;
|
||||
exp = fSF_BIAS() - (fSF_GETEXP(RtV) - fSF_BIAS()) - 1;
|
||||
RdV = fMAKESF(fGETBIT(31,RtV),exp,mant);
|
||||
}
|
||||
})
|
||||
|
||||
Q6INSN(F2_sffixupn,"Rd32=sffixupn(Rs32,Rt32)",ATTRIBS(),
|
||||
"Fix Up Numerator",
|
||||
{
|
||||
@ -162,6 +178,22 @@ Q6INSN(F2_sffixupd,"Rd32=sffixupd(Rs32,Rt32)",ATTRIBS(),
|
||||
RdV = RtV;
|
||||
})
|
||||
|
||||
Q6INSN(F2_sfinvsqrta,"Rd32,Pe4=sfinvsqrta(Rs32)",ATTRIBS(),
|
||||
"Reciprocal Square Root Approximation",
|
||||
{
|
||||
fHIDE(int idx;)
|
||||
fHIDE(int adjust;)
|
||||
fHIDE(int mant;)
|
||||
fHIDE(int exp;)
|
||||
if (fSF_INVSQRT_COMMON(RsV,RdV,adjust)) {
|
||||
PeV = adjust;
|
||||
idx = (RsV >> 17) & 0x7f;
|
||||
mant = (fSF_INVSQRT_LOOKUP(idx) << 15);
|
||||
exp = fSF_BIAS() - ((fSF_GETEXP(RsV) - fSF_BIAS()) >> 1) - 1;
|
||||
RdV = fMAKESF(fGETBIT(31,RsV),exp,mant);
|
||||
}
|
||||
})
|
||||
|
||||
Q6INSN(F2_sffixupr,"Rd32=sffixupr(Rs32)",ATTRIBS(),
|
||||
"Fix Up Radicand",
|
||||
{
|
||||
|
@ -25,7 +25,10 @@ Q6INSN(L2_##TAG##_io, OPER"(Rs32+#s11:"SHFT")", ATTRIB,DESCR,{fIMMEXT(
|
||||
Q6INSN(L4_##TAG##_ur, OPER"(Rt32<<#u2+#U6)", ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IRs(UiV,RtV,uiV); SEMANTICS;})\
|
||||
Q6INSN(L4_##TAG##_ap, OPER"(Re32=#U6)", ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IMM(UiV); SEMANTICS; ReV=UiV; })\
|
||||
Q6INSN(L2_##TAG##_pr, OPER"(Rx32++Mu2)", ATTRIB,DESCR,{fEA_REG(RxV); fPM_M(RxV,MuV); SEMANTICS;})\
|
||||
Q6INSN(L2_##TAG##_pbr, OPER"(Rx32++Mu2:brev)", ATTRIB,DESCR,{fEA_BREVR(RxV); fPM_M(RxV,MuV); SEMANTICS;})\
|
||||
Q6INSN(L2_##TAG##_pi, OPER"(Rx32++#s4:"SHFT")", ATTRIB,DESCR,{fEA_REG(RxV); fPM_I(RxV,siV); SEMANTICS;})\
|
||||
Q6INSN(L2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))",ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRI(RxV,siV,MuV); SEMANTICS;})\
|
||||
Q6INSN(L2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))", ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<<SCALE,MuV); SEMANTICS;})
|
||||
|
||||
/* The set of 32-bit load instructions */
|
||||
STD_LD_AMODES(loadrub,"Rd32=memub","Load Unsigned Byte",ATTRIBS(A_LOAD),"0",fLOAD(1,1,u,EA,RdV),0)
|
||||
@ -35,6 +38,68 @@ STD_LD_AMODES(loadrh, "Rd32=memh", "Load signed Half integer",ATTRIBS(A_LOAD),"1
|
||||
STD_LD_AMODES(loadri, "Rd32=memw", "Load Word",ATTRIBS(A_LOAD),"2",fLOAD(1,4,u,EA,RdV),2)
|
||||
STD_LD_AMODES(loadrd, "Rdd32=memd","Load Double integer",ATTRIBS(A_LOAD),"3",fLOAD(1,8,u,EA,RddV),3)
|
||||
|
||||
/* These instructions do a load an unpack */
|
||||
STD_LD_AMODES(loadbzw2, "Rd32=memubh", "Load Bytes and Vector Zero-Extend (unpack)",
|
||||
ATTRIBS(A_LOAD),"1",
|
||||
{fHIDE(size2u_t tmpV; int i;)
|
||||
fLOAD(1,2,u,EA,tmpV);
|
||||
for (i=0;i<2;i++) {
|
||||
fSETHALF(i,RdV,fGETUBYTE(i,tmpV));
|
||||
}
|
||||
},1)
|
||||
|
||||
STD_LD_AMODES(loadbzw4, "Rdd32=memubh", "Load Bytes and Vector Zero-Extend (unpack)",
|
||||
ATTRIBS(A_LOAD),"2",
|
||||
{fHIDE(size4u_t tmpV; int i;)
|
||||
fLOAD(1,4,u,EA,tmpV);
|
||||
for (i=0;i<4;i++) {
|
||||
fSETHALF(i,RddV,fGETUBYTE(i,tmpV));
|
||||
}
|
||||
},2)
|
||||
|
||||
|
||||
|
||||
/* These instructions do a load an unpack */
|
||||
STD_LD_AMODES(loadbsw2, "Rd32=membh", "Load Bytes and Vector Sign-Extend (unpack)",
|
||||
ATTRIBS(A_LOAD),"1",
|
||||
{fHIDE(size2u_t tmpV; int i;)
|
||||
fLOAD(1,2,u,EA,tmpV);
|
||||
for (i=0;i<2;i++) {
|
||||
fSETHALF(i,RdV,fGETBYTE(i,tmpV));
|
||||
}
|
||||
},1)
|
||||
|
||||
STD_LD_AMODES(loadbsw4, "Rdd32=membh", "Load Bytes and Vector Sign-Extend (unpack)",
|
||||
ATTRIBS(A_LOAD),"2",
|
||||
{fHIDE(size4u_t tmpV; int i;)
|
||||
fLOAD(1,4,u,EA,tmpV);
|
||||
for (i=0;i<4;i++) {
|
||||
fSETHALF(i,RddV,fGETBYTE(i,tmpV));
|
||||
}
|
||||
},2)
|
||||
|
||||
|
||||
|
||||
STD_LD_AMODES(loadalignh, "Ryy32=memh_fifo", "Load Half-word into shifted vector",
|
||||
ATTRIBS(A_LOAD),"1",
|
||||
{
|
||||
fHIDE(size8u_t tmpV;)
|
||||
fLOAD(1,2,u,EA,tmpV);
|
||||
RyyV = (((size8u_t)RyyV)>>16)|(tmpV<<48);
|
||||
},1)
|
||||
|
||||
|
||||
STD_LD_AMODES(loadalignb, "Ryy32=memb_fifo", "Load byte into shifted vector",
|
||||
ATTRIBS(A_LOAD),"0",
|
||||
{
|
||||
fHIDE(size8u_t tmpV;)
|
||||
fLOAD(1,1,u,EA,tmpV);
|
||||
RyyV = (((size8u_t)RyyV)>>8)|(tmpV<<56);
|
||||
},0)
|
||||
|
||||
|
||||
|
||||
|
||||
/* The set of addressing modes standard to all Store instructions */
|
||||
#define STD_ST_AMODES(TAG,DEST,OPER,DESCR,ATTRIB,SHFT,SEMANTICS,SCALE)\
|
||||
Q6INSN(S2_##TAG##_io, OPER"(Rs32+#s11:"SHFT")="DEST, ATTRIB,DESCR,{fIMMEXT(siV); fEA_RI(RsV,siV); SEMANTICS; })\
|
||||
@ -42,6 +107,9 @@ Q6INSN(S2_##TAG##_pi, OPER"(Rx32++#s4:"SHFT")="DEST, ATTRIB,DESCR,{fEA_REG(
|
||||
Q6INSN(S4_##TAG##_ap, OPER"(Re32=#U6)="DEST, ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IMM(UiV); SEMANTICS; ReV=UiV; })\
|
||||
Q6INSN(S2_##TAG##_pr, OPER"(Rx32++Mu2)="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_M(RxV,MuV); SEMANTICS; })\
|
||||
Q6INSN(S4_##TAG##_ur, OPER"(Ru32<<#u2+#U6)="DEST, ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IRs(UiV,RuV,uiV); SEMANTICS;})\
|
||||
Q6INSN(S2_##TAG##_pbr, OPER"(Rx32++Mu2:brev)="DEST, ATTRIB,DESCR,{fEA_BREVR(RxV); fPM_M(RxV,MuV); SEMANTICS; })\
|
||||
Q6INSN(S2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRI(RxV,siV,MuV); SEMANTICS;})\
|
||||
Q6INSN(S2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<<SCALE,MuV); SEMANTICS;})
|
||||
|
||||
|
||||
/* The set of 32-bit store instructions */
|
||||
|
@ -92,6 +92,21 @@ DEF_MACRO(
|
||||
/* attribs */
|
||||
)
|
||||
|
||||
|
||||
DEF_MACRO(
|
||||
fINSERT_RANGE,
|
||||
{
|
||||
int offset=LOWBIT;
|
||||
int width=HIBIT-LOWBIT+1;
|
||||
/* clear bits where new bits go */
|
||||
INREG &= ~(((fCONSTLL(1)<<width)-1)<<offset);
|
||||
/* OR in new bits */
|
||||
INREG |= ((INVAL & ((fCONSTLL(1)<<width)-1)) << offset);
|
||||
},
|
||||
/* attribs */
|
||||
)
|
||||
|
||||
|
||||
DEF_MACRO(
|
||||
f8BITSOF,
|
||||
( (VAL) ? 0xff : 0x00),
|
||||
@ -276,6 +291,12 @@ DEF_MACRO(
|
||||
/* Read and Write Implicit Regs */
|
||||
/*************************************/
|
||||
|
||||
DEF_MACRO(
|
||||
fREAD_IREG, /* read modifier register */
|
||||
(fSXTN(11,64,(((VAL) & 0xf0000000)>>21) | ((VAL>>17)&0x7f) )), /* behavior */
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fREAD_LR, /* read link register */
|
||||
(READ_RREG(REG_LR)), /* behavior */
|
||||
@ -306,6 +327,12 @@ DEF_MACRO(
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fREAD_CSREG, /* read CS register */
|
||||
(READ_RREG(REG_CSA+N)), /* behavior */
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fREAD_LC0, /* read loop count */
|
||||
(READ_RREG(REG_LC0)), /* behavior */
|
||||
@ -806,6 +833,12 @@ DEF_MACRO(
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fEA_BREVR, /* Calculate EA with bit reversed bottom of REGISTER */
|
||||
EA=fbrev(REG),
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fEA_GPI, /* Calculate EA with Global Poitner + Immediate */
|
||||
do { EA=fREAD_GP()+IMM; fGP_DOCHKPAGECROSS(fREAD_GP(),EA); } while (0),
|
||||
@ -824,6 +857,20 @@ DEF_MACRO(
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fPM_CIRI, /* Post Modify Register using Circular arithmetic by Immediate */
|
||||
do { fcirc_add(REG,siV,MuV); } while (0),
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fPM_CIRR, /* Post Modify Register using Circular arithmetic by register */
|
||||
do { fcirc_add(REG,VAL,MuV); } while (0),
|
||||
()
|
||||
)
|
||||
|
||||
|
||||
|
||||
DEF_MACRO(
|
||||
fSCALE, /* scale by N */
|
||||
(((size8s_t)(A))<<N),
|
||||
|
@ -1029,6 +1029,53 @@ Q6INSN(S4_clbpaddi,"Rd32=add(clb(Rss32),#s6)",ATTRIBS(A_ARCHV2),
|
||||
{ RdV = (fMAX(fCL1_8(RssV),fCL1_8(~RssV)))+siV;})
|
||||
|
||||
|
||||
|
||||
Q6INSN(S2_cabacdecbin,"Rdd32=decbin(Rss32,Rtt32)",ATTRIBS(A_ARCHV3),"CABAC decode bin",
|
||||
{
|
||||
fHIDE(size4u_t state;)
|
||||
fHIDE(size4u_t valMPS;)
|
||||
fHIDE(size4u_t bitpos;)
|
||||
fHIDE(size4u_t range;)
|
||||
fHIDE(size4u_t offset;)
|
||||
fHIDE(size4u_t rLPS;)
|
||||
fHIDE(size4u_t rMPS;)
|
||||
|
||||
state = fEXTRACTU_RANGE( fGETWORD(1,RttV) ,5,0);
|
||||
valMPS = fEXTRACTU_RANGE( fGETWORD(1,RttV) ,8,8);
|
||||
bitpos = fEXTRACTU_RANGE( fGETWORD(0,RttV) ,4,0);
|
||||
range = fGETWORD(0,RssV);
|
||||
offset = fGETWORD(1,RssV);
|
||||
|
||||
/* calculate rLPS */
|
||||
range <<= bitpos;
|
||||
offset <<= bitpos;
|
||||
rLPS = rLPS_table_64x4[state][ (range >>29)&3];
|
||||
rLPS = rLPS << 23; /* left aligned */
|
||||
|
||||
/* calculate rMPS */
|
||||
rMPS= (range&0xff800000) - rLPS;
|
||||
|
||||
/* most probable region */
|
||||
if (offset < rMPS) {
|
||||
RddV = AC_next_state_MPS_64[state];
|
||||
fINSERT_RANGE(RddV,8,8,valMPS);
|
||||
fINSERT_RANGE(RddV,31,23,(rMPS>>23));
|
||||
fSETWORD(1,RddV,offset);
|
||||
fWRITE_P0(valMPS);
|
||||
|
||||
|
||||
}
|
||||
/* least probable region */
|
||||
else {
|
||||
RddV = AC_next_state_LPS_64[state];
|
||||
fINSERT_RANGE(RddV,8,8,((!state)?(1-valMPS):(valMPS)));
|
||||
fINSERT_RANGE(RddV,31,23,(rLPS>>23));
|
||||
fSETWORD(1,RddV,(offset-rMPS));
|
||||
fWRITE_P0((valMPS^1));
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Q6INSN(S2_clb,"Rd32=clb(Rs32)",ATTRIBS(),
|
||||
"Count leading bits", {RdV = fMAX(fCL1_4(RsV),fCL1_4(~RsV));})
|
||||
|
||||
|
@ -40,14 +40,15 @@ struct Instruction {
|
||||
|
||||
uint32_t iclass:6;
|
||||
uint32_t slot:3;
|
||||
uint32_t part1:1; /*
|
||||
uint32_t which_extended:1; /* If has an extender, which immediate */
|
||||
uint32_t new_value_producer_slot:4;
|
||||
|
||||
bool part1; /*
|
||||
* cmp-jumps are split into two insns.
|
||||
* set for the compare and clear for the jump
|
||||
*/
|
||||
uint32_t extension_valid:1; /* Has a constant extender attached */
|
||||
uint32_t which_extended:1; /* If has an extender, which immediate */
|
||||
uint32_t is_endloop:1; /* This is an end of loop */
|
||||
uint32_t new_value_producer_slot:4;
|
||||
bool extension_valid; /* Has a constant extender attached */
|
||||
bool is_endloop; /* This is an end of loop */
|
||||
int32_t immed[IMMEDS_MAX]; /* immediate field */
|
||||
};
|
||||
|
||||
@ -58,13 +59,13 @@ struct Packet {
|
||||
uint16_t encod_pkt_size_in_bytes;
|
||||
|
||||
/* Pre-decodes about COF */
|
||||
uint32_t pkt_has_cof:1; /* Has any change-of-flow */
|
||||
uint32_t pkt_has_endloop:1;
|
||||
bool pkt_has_cof; /* Has any change-of-flow */
|
||||
bool pkt_has_endloop;
|
||||
|
||||
uint32_t pkt_has_dczeroa:1;
|
||||
bool pkt_has_dczeroa;
|
||||
|
||||
uint32_t pkt_has_store_s0:1;
|
||||
uint32_t pkt_has_store_s1:1;
|
||||
bool pkt_has_store_s0;
|
||||
bool pkt_has_store_s1;
|
||||
|
||||
Insn insn[INSTRUCTIONS_MAX];
|
||||
};
|
||||
|
@ -22,11 +22,12 @@
|
||||
* Change HEX_DEBUG to 1 to turn on debugging output
|
||||
*/
|
||||
#define HEX_DEBUG 0
|
||||
#if HEX_DEBUG
|
||||
#define HEX_DEBUG_LOG(...) qemu_log(__VA_ARGS__)
|
||||
#else
|
||||
#define HEX_DEBUG_LOG(...) do { } while (0)
|
||||
#endif
|
||||
#define HEX_DEBUG_LOG(...) \
|
||||
do { \
|
||||
if (HEX_DEBUG) { \
|
||||
qemu_log(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int hexagon_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||
int hexagon_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
@ -133,6 +133,38 @@
|
||||
CHECK_NOSHUF; \
|
||||
tcg_gen_qemu_ld64(DST, VA, ctx->mem_idx); \
|
||||
} while (0)
|
||||
|
||||
#define MEM_STORE1_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_INT(X), \
|
||||
gen_store1i, \
|
||||
__builtin_choose_expr(TYPE_TCGV(X), \
|
||||
gen_store1, (void)0))
|
||||
#define MEM_STORE1(VA, DATA, SLOT) \
|
||||
MEM_STORE1_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
|
||||
|
||||
#define MEM_STORE2_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_INT(X), \
|
||||
gen_store2i, \
|
||||
__builtin_choose_expr(TYPE_TCGV(X), \
|
||||
gen_store2, (void)0))
|
||||
#define MEM_STORE2(VA, DATA, SLOT) \
|
||||
MEM_STORE2_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
|
||||
|
||||
#define MEM_STORE4_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_INT(X), \
|
||||
gen_store4i, \
|
||||
__builtin_choose_expr(TYPE_TCGV(X), \
|
||||
gen_store4, (void)0))
|
||||
#define MEM_STORE4(VA, DATA, SLOT) \
|
||||
MEM_STORE4_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
|
||||
|
||||
#define MEM_STORE8_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_INT(X), \
|
||||
gen_store8i, \
|
||||
__builtin_choose_expr(TYPE_TCGV_I64(X), \
|
||||
gen_store8, (void)0))
|
||||
#define MEM_STORE8(VA, DATA, SLOT) \
|
||||
MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
|
||||
#else
|
||||
#define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, slot, VA))
|
||||
#define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, slot, VA))
|
||||
@ -190,6 +222,13 @@ static inline void gen_pred_cancel(TCGv pred, int slot_num)
|
||||
(((HIBIT) - (LOWBIT) + 1) ? \
|
||||
extract64((INREG), (LOWBIT), ((HIBIT) - (LOWBIT) + 1)) : \
|
||||
0LL)
|
||||
#define fINSERT_RANGE(INREG, HIBIT, LOWBIT, INVAL) \
|
||||
do { \
|
||||
int width = ((HIBIT) - (LOWBIT) + 1); \
|
||||
INREG = (width >= 0 ? \
|
||||
deposit64((INREG), (LOWBIT), width, (INVAL)) : \
|
||||
INREG); \
|
||||
} while (0)
|
||||
|
||||
#define f8BITSOF(VAL) ((VAL) ? 0xff : 0x00)
|
||||
|
||||
@ -285,6 +324,39 @@ static inline void gen_logical_not(TCGv dest, TCGv src)
|
||||
|
||||
#define fPCALIGN(IMM) IMM = (IMM & ~PCALIGN_MASK)
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
|
||||
{
|
||||
/*
|
||||
* Section 2.2.4 of the Hexagon V67 Programmer's Reference Manual
|
||||
*
|
||||
* The "I" value from a modifier register is divided into two pieces
|
||||
* LSB bits 23:17
|
||||
* MSB bits 31:28
|
||||
* The value is signed
|
||||
*
|
||||
* At the end we shift the result according to the shift argument
|
||||
*/
|
||||
TCGv msb = tcg_temp_new();
|
||||
TCGv lsb = tcg_temp_new();
|
||||
|
||||
tcg_gen_extract_tl(lsb, val, 17, 7);
|
||||
tcg_gen_sari_tl(msb, val, 21);
|
||||
tcg_gen_deposit_tl(result, msb, lsb, 0, 7);
|
||||
|
||||
tcg_gen_shli_tl(result, result, shift);
|
||||
|
||||
tcg_temp_free(msb);
|
||||
tcg_temp_free(lsb);
|
||||
|
||||
return result;
|
||||
}
|
||||
#define fREAD_IREG(VAL, SHIFT) gen_read_ireg(ireg, (VAL), (SHIFT))
|
||||
#else
|
||||
#define fREAD_IREG(VAL) \
|
||||
(fSXTN(11, 64, (((VAL) & 0xf0000000) >> 21) | ((VAL >> 17) & 0x7f)))
|
||||
#endif
|
||||
|
||||
#define fREAD_LR() (READ_REG(HEX_REG_LR))
|
||||
|
||||
#define fWRITE_LR(A) WRITE_RREG(HEX_REG_LR, A)
|
||||
@ -341,8 +413,6 @@ static inline void gen_logical_not(TCGv dest, TCGv src)
|
||||
#define fWRITE_LC0(VAL) WRITE_RREG(HEX_REG_LC0, VAL)
|
||||
#define fWRITE_LC1(VAL) WRITE_RREG(HEX_REG_LC1, VAL)
|
||||
|
||||
#define fCARRY_FROM_ADD(A, B, C) carry_from_add64(A, B, C)
|
||||
|
||||
#define fSET_OVERFLOW() SET_USR_FIELD(USR_OVF, 1)
|
||||
#define fSET_LPCFG(VAL) SET_USR_FIELD(USR_LPCFG, (VAL))
|
||||
#define fGET_LPCFG (GET_USR_FIELD(USR_LPCFG))
|
||||
@ -402,6 +472,21 @@ static inline void gen_logical_not(TCGv dest, TCGv src)
|
||||
#define fCAST8S_16S(A) (int128_exts64(A))
|
||||
#define fCAST16S_8S(A) (int128_getlo(A))
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fEA_RI(REG, IMM) tcg_gen_addi_tl(EA, REG, IMM)
|
||||
#define fEA_RRs(REG, REG2, SCALE) \
|
||||
do { \
|
||||
TCGv tmp = tcg_temp_new(); \
|
||||
tcg_gen_shli_tl(tmp, REG2, SCALE); \
|
||||
tcg_gen_add_tl(EA, REG, tmp); \
|
||||
tcg_temp_free(tmp); \
|
||||
} while (0)
|
||||
#define fEA_IRs(IMM, REG, SCALE) \
|
||||
do { \
|
||||
tcg_gen_shli_tl(EA, REG, SCALE); \
|
||||
tcg_gen_addi_tl(EA, EA, IMM); \
|
||||
} while (0)
|
||||
#else
|
||||
#define fEA_RI(REG, IMM) \
|
||||
do { \
|
||||
EA = REG + IMM; \
|
||||
@ -414,12 +499,21 @@ static inline void gen_logical_not(TCGv dest, TCGv src)
|
||||
do { \
|
||||
EA = IMM + (REG << SCALE); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fEA_IMM(IMM) tcg_gen_movi_tl(EA, IMM)
|
||||
#define fEA_REG(REG) tcg_gen_mov_tl(EA, REG)
|
||||
#define fEA_BREVR(REG) gen_helper_fbrev(EA, REG)
|
||||
#define fPM_I(REG, IMM) tcg_gen_addi_tl(REG, REG, IMM)
|
||||
#define fPM_M(REG, MVAL) tcg_gen_add_tl(REG, REG, MVAL)
|
||||
#define fPM_CIRI(REG, IMM, MVAL) \
|
||||
do { \
|
||||
TCGv tcgv_siV = tcg_const_tl(siV); \
|
||||
gen_helper_fcircadd(REG, REG, tcgv_siV, MuV, \
|
||||
hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
tcg_temp_free(tcgv_siV); \
|
||||
} while (0)
|
||||
#else
|
||||
#define fEA_IMM(IMM) do { EA = (IMM); } while (0)
|
||||
#define fEA_REG(REG) do { EA = (REG); } while (0)
|
||||
@ -496,23 +590,43 @@ static inline void gen_logical_not(TCGv dest, TCGv src)
|
||||
gen_load_locked##SIZE##SIGN(DST, EA, ctx->mem_idx);
|
||||
#endif
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, insn->slot)
|
||||
#else
|
||||
#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, slot)
|
||||
#endif
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fSTORE_LOCKED(NUM, SIZE, EA, SRC, PRED) \
|
||||
gen_store_conditional##SIZE(env, ctx, PdN, PRED, EA, SRC);
|
||||
#endif
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define GETBYTE_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_TCGV(X), \
|
||||
gen_get_byte, \
|
||||
__builtin_choose_expr(TYPE_TCGV_I64(X), \
|
||||
gen_get_byte_i64, (void)0))
|
||||
#define fGETBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, true)
|
||||
#define fGETUBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, false)
|
||||
#else
|
||||
#define fGETBYTE(N, SRC) ((int8_t)((SRC >> ((N) * 8)) & 0xff))
|
||||
#define fGETUBYTE(N, SRC) ((uint8_t)((SRC >> ((N) * 8)) & 0xff))
|
||||
#endif
|
||||
|
||||
#define fSETBYTE(N, DST, VAL) \
|
||||
do { \
|
||||
DST = (DST & ~(0x0ffLL << ((N) * 8))) | \
|
||||
(((uint64_t)((VAL) & 0x0ffLL)) << ((N) * 8)); \
|
||||
} while (0)
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fGETHALF(N, SRC) gen_get_half(HALF, N, SRC, true)
|
||||
#define fGETUHALF(N, SRC) gen_get_half(HALF, N, SRC, false)
|
||||
#else
|
||||
#define fGETHALF(N, SRC) ((int16_t)((SRC >> ((N) * 16)) & 0xffff))
|
||||
#define fGETUHALF(N, SRC) ((uint16_t)((SRC >> ((N) * 16)) & 0xffff))
|
||||
#endif
|
||||
#define fSETHALF(N, DST, VAL) \
|
||||
do { \
|
||||
DST = (DST & ~(0x0ffffLL << ((N) * 16))) | \
|
||||
|
@ -173,7 +173,6 @@ hexagon_ss.add(files(
|
||||
'printinsn.c',
|
||||
'arch.c',
|
||||
'fma_emu.c',
|
||||
'conv_emu.c',
|
||||
))
|
||||
|
||||
target_arch += {'hexagon': hexagon_ss}
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "arch.h"
|
||||
#include "hex_arch_types.h"
|
||||
#include "fma_emu.h"
|
||||
#include "conv_emu.h"
|
||||
|
||||
#define SF_BIAS 127
|
||||
#define SF_MANTBITS 23
|
||||
@ -35,7 +34,7 @@ static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
|
||||
uint32_t exception,
|
||||
uintptr_t pc)
|
||||
{
|
||||
CPUState *cs = CPU(hexagon_env_get_cpu(env));
|
||||
CPUState *cs = env_cpu(env);
|
||||
qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
|
||||
cs->exception_index = exception;
|
||||
cpu_loop_exit_restore(cs, pc);
|
||||
@ -46,8 +45,8 @@ void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
|
||||
do_raise_exception_err(env, excp, 0);
|
||||
}
|
||||
|
||||
static inline void log_reg_write(CPUHexagonState *env, int rnum,
|
||||
target_ulong val, uint32_t slot)
|
||||
static void log_reg_write(CPUHexagonState *env, int rnum,
|
||||
target_ulong val, uint32_t slot)
|
||||
{
|
||||
HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
|
||||
rnum, val, val);
|
||||
@ -57,14 +56,13 @@ static inline void log_reg_write(CPUHexagonState *env, int rnum,
|
||||
HEX_DEBUG_LOG("\n");
|
||||
|
||||
env->new_value[rnum] = val;
|
||||
#if HEX_DEBUG
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
env->reg_written[rnum] = 1;
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
env->reg_written[rnum] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void log_pred_write(CPUHexagonState *env, int pnum,
|
||||
target_ulong val)
|
||||
static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
|
||||
{
|
||||
HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
|
||||
" (0x" TARGET_FMT_lx ")\n",
|
||||
@ -79,8 +77,8 @@ static inline void log_pred_write(CPUHexagonState *env, int pnum,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void log_store32(CPUHexagonState *env, target_ulong addr,
|
||||
target_ulong val, int width, int slot)
|
||||
static void log_store32(CPUHexagonState *env, target_ulong addr,
|
||||
target_ulong val, int width, int slot)
|
||||
{
|
||||
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
|
||||
", %" PRId32 " [0x08%" PRIx32 "])\n",
|
||||
@ -90,8 +88,8 @@ static inline void log_store32(CPUHexagonState *env, target_ulong addr,
|
||||
env->mem_log_stores[slot].data32 = val;
|
||||
}
|
||||
|
||||
static inline void log_store64(CPUHexagonState *env, target_ulong addr,
|
||||
int64_t val, int width, int slot)
|
||||
static void log_store64(CPUHexagonState *env, target_ulong addr,
|
||||
int64_t val, int width, int slot)
|
||||
{
|
||||
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
|
||||
", %" PRId64 " [0x016%" PRIx64 "])\n",
|
||||
@ -101,7 +99,7 @@ static inline void log_store64(CPUHexagonState *env, target_ulong addr,
|
||||
env->mem_log_stores[slot].data64 = val;
|
||||
}
|
||||
|
||||
static inline void write_new_pc(CPUHexagonState *env, target_ulong addr)
|
||||
static void write_new_pc(CPUHexagonState *env, target_ulong addr)
|
||||
{
|
||||
HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
|
||||
|
||||
@ -119,7 +117,6 @@ static inline void write_new_pc(CPUHexagonState *env, target_ulong addr)
|
||||
}
|
||||
}
|
||||
|
||||
#if HEX_DEBUG
|
||||
/* Handy place to set a breakpoint */
|
||||
void HELPER(debug_start_packet)(CPUHexagonState *env)
|
||||
{
|
||||
@ -130,14 +127,12 @@ void HELPER(debug_start_packet)(CPUHexagonState *env)
|
||||
env->reg_written[i] = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int32_t new_pred_value(CPUHexagonState *env, int pnum)
|
||||
static int32_t new_pred_value(CPUHexagonState *env, int pnum)
|
||||
{
|
||||
return env->new_pred_value[pnum];
|
||||
}
|
||||
|
||||
#if HEX_DEBUG
|
||||
/* Checks for bookkeeping errors between disassembly context and runtime */
|
||||
void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
|
||||
{
|
||||
@ -147,7 +142,6 @@ void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
|
||||
{
|
||||
@ -173,7 +167,6 @@ void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
|
||||
}
|
||||
}
|
||||
|
||||
#if HEX_DEBUG
|
||||
static void print_store(CPUHexagonState *env, int slot)
|
||||
{
|
||||
if (!(env->slot_cancelled & (1 << slot))) {
|
||||
@ -257,35 +250,26 @@ void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
|
||||
env->gpr[HEX_REG_QEMU_INSN_CNT]);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
|
||||
{
|
||||
int32_t length = M & 0x0001ffff;
|
||||
uint32_t new_ptr = RxV + offset;
|
||||
uint32_t start_addr = CS;
|
||||
uint32_t end_addr = start_addr + length;
|
||||
|
||||
if (new_ptr >= end_addr) {
|
||||
new_ptr -= length;
|
||||
} else if (new_ptr < start_addr) {
|
||||
new_ptr += length;
|
||||
}
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
|
||||
{
|
||||
int32_t K_const = (M >> 24) & 0xf;
|
||||
int32_t length = M & 0x1ffff;
|
||||
int32_t mask = (1 << (K_const + 2)) - 1;
|
||||
int32_t K_const = sextract32(M, 24, 4);
|
||||
int32_t length = sextract32(M, 0, 17);
|
||||
uint32_t new_ptr = RxV + offset;
|
||||
uint32_t start_addr = RxV & (~mask);
|
||||
uint32_t end_addr = start_addr | length;
|
||||
uint32_t start_addr;
|
||||
uint32_t end_addr;
|
||||
|
||||
if (K_const == 0 && length >= 4) {
|
||||
return fcircadd_v4(RxV, offset, M, CS);
|
||||
start_addr = CS;
|
||||
end_addr = start_addr + length;
|
||||
} else {
|
||||
/*
|
||||
* Versions v3 and earlier used the K value to specify a power-of-2 size
|
||||
* 2^(K+2) that is greater than the buffer length
|
||||
*/
|
||||
int32_t mask = (1 << (K_const + 2)) - 1;
|
||||
start_addr = RxV & (~mask);
|
||||
end_addr = start_addr | length;
|
||||
}
|
||||
|
||||
if (new_ptr >= end_addr) {
|
||||
@ -297,24 +281,103 @@ int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hexagon FP operations return ~0 insteat of NaN
|
||||
* The hex_check_sfnan/hex_check_dfnan functions perform this check
|
||||
*/
|
||||
static float32 hex_check_sfnan(float32 x)
|
||||
uint32_t HELPER(fbrev)(uint32_t addr)
|
||||
{
|
||||
if (float32_is_any_nan(x)) {
|
||||
return make_float32(0xFFFFFFFFU);
|
||||
}
|
||||
return x;
|
||||
/*
|
||||
* Bit reverse the low 16 bits of the address
|
||||
*/
|
||||
return deposit32(addr, 0, 16, revbit16(addr));
|
||||
}
|
||||
|
||||
static float64 hex_check_dfnan(float64 x)
|
||||
static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
|
||||
{
|
||||
if (float64_is_any_nan(x)) {
|
||||
return make_float64(0xFFFFFFFFFFFFFFFFULL);
|
||||
return make_float32(
|
||||
((sign & 1) << 31) |
|
||||
((exp & 0xff) << SF_MANTBITS) |
|
||||
(mant & ((1 << SF_MANTBITS) - 1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* sfrecipa, sfinvsqrta have two 32-bit results
|
||||
* r0,p0=sfrecipa(r1,r2)
|
||||
* r0,p0=sfinvsqrta(r1)
|
||||
*
|
||||
* Since helpers can only return a single value, we pack the two results
|
||||
* into a 64-bit value.
|
||||
*/
|
||||
uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
||||
{
|
||||
int32_t PeV = 0;
|
||||
float32 RdV;
|
||||
int idx;
|
||||
int adjust;
|
||||
int mant;
|
||||
int exp;
|
||||
|
||||
arch_fpop_start(env);
|
||||
if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
|
||||
PeV = adjust;
|
||||
idx = (RtV >> 16) & 0x7f;
|
||||
mant = (recip_lookup_table[idx] << 15) | 1;
|
||||
exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
|
||||
RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
|
||||
}
|
||||
return x;
|
||||
arch_fpop_end(env);
|
||||
return ((uint64_t)RdV << 32) | PeV;
|
||||
}
|
||||
|
||||
uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int PeV = 0;
|
||||
float32 RdV;
|
||||
int idx;
|
||||
int adjust;
|
||||
int mant;
|
||||
int exp;
|
||||
|
||||
arch_fpop_start(env);
|
||||
if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
|
||||
PeV = adjust;
|
||||
idx = (RsV >> 17) & 0x7f;
|
||||
mant = (invsqrt_lookup_table[idx] << 15);
|
||||
exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
|
||||
RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return ((uint64_t)RdV << 32) | PeV;
|
||||
}
|
||||
|
||||
int64_t HELPER(vacsh_val)(CPUHexagonState *env,
|
||||
int64_t RxxV, int64_t RssV, int64_t RttV)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int xv = sextract64(RxxV, i * 16, 16);
|
||||
int sv = sextract64(RssV, i * 16, 16);
|
||||
int tv = sextract64(RttV, i * 16, 16);
|
||||
int max;
|
||||
xv = xv + tv;
|
||||
sv = sv - tv;
|
||||
max = xv > sv ? xv : sv;
|
||||
/* Note that fSATH can set the OVF bit in usr */
|
||||
RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
|
||||
}
|
||||
return RxxV;
|
||||
}
|
||||
|
||||
int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
|
||||
int64_t RxxV, int64_t RssV, int64_t RttV)
|
||||
{
|
||||
int32_t PeV = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int xv = sextract64(RxxV, i * 16, 16);
|
||||
int sv = sextract64(RssV, i * 16, 16);
|
||||
int tv = sextract64(RttV, i * 16, 16);
|
||||
xv = xv + tv;
|
||||
sv = sv - tv;
|
||||
PeV = deposit32(PeV, i * 2, 1, (xv > sv));
|
||||
PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
|
||||
}
|
||||
return PeV;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -332,8 +395,8 @@ static void check_noshuf(CPUHexagonState *env, uint32_t slot)
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
|
||||
target_ulong vaddr)
|
||||
static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
|
||||
target_ulong vaddr)
|
||||
{
|
||||
uint8_t retval;
|
||||
check_noshuf(env, slot);
|
||||
@ -341,8 +404,8 @@ static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
|
||||
target_ulong vaddr)
|
||||
static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
|
||||
target_ulong vaddr)
|
||||
{
|
||||
uint16_t retval;
|
||||
check_noshuf(env, slot);
|
||||
@ -350,8 +413,8 @@ static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
|
||||
target_ulong vaddr)
|
||||
static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
|
||||
target_ulong vaddr)
|
||||
{
|
||||
uint32_t retval;
|
||||
check_noshuf(env, slot);
|
||||
@ -359,8 +422,8 @@ static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
|
||||
target_ulong vaddr)
|
||||
static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
|
||||
target_ulong vaddr)
|
||||
{
|
||||
uint64_t retval;
|
||||
check_noshuf(env, slot);
|
||||
@ -374,7 +437,6 @@ float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
|
||||
float64 out_f64;
|
||||
arch_fpop_start(env);
|
||||
out_f64 = float32_to_float64(RsV, &env->fp_status);
|
||||
out_f64 = hex_check_dfnan(out_f64);
|
||||
arch_fpop_end(env);
|
||||
return out_f64;
|
||||
}
|
||||
@ -384,7 +446,6 @@ float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
|
||||
float32 out_f32;
|
||||
arch_fpop_start(env);
|
||||
out_f32 = float64_to_float32(RssV, &env->fp_status);
|
||||
out_f32 = hex_check_sfnan(out_f32);
|
||||
arch_fpop_end(env);
|
||||
return out_f32;
|
||||
}
|
||||
@ -394,7 +455,6 @@ float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = uint32_to_float32(RsV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -404,7 +464,6 @@ float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
|
||||
float64 RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = uint32_to_float64(RsV, &env->fp_status);
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -414,7 +473,6 @@ float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = int32_to_float32(RsV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -424,7 +482,6 @@ float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
|
||||
float64 RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = int32_to_float64(RsV, &env->fp_status);
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -434,7 +491,6 @@ float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = uint64_to_float32(RssV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -444,7 +500,6 @@ float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
|
||||
float64 RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = uint64_to_float64(RssV, &env->fp_status);
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -454,7 +509,6 @@ float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = int64_to_float32(RssV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -464,16 +518,21 @@ float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
|
||||
float64 RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = int64_to_float64(RssV, &env->fp_status);
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
int32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
|
||||
uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int32_t RdV;
|
||||
uint32_t RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = conv_sf_to_4u(RsV, &env->fp_status);
|
||||
/* Hexagon checks the sign before rounding */
|
||||
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RdV = 0;
|
||||
} else {
|
||||
RdV = float32_to_uint32(RsV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -482,16 +541,28 @@ int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int32_t RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = conv_sf_to_4s(RsV, &env->fp_status);
|
||||
/* Hexagon returns -1 for NaN */
|
||||
if (float32_is_any_nan(RsV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RdV = -1;
|
||||
} else {
|
||||
RdV = float32_to_int32(RsV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
|
||||
int64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
|
||||
uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int64_t RddV;
|
||||
uint64_t RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = conv_sf_to_8u(RsV, &env->fp_status);
|
||||
/* Hexagon checks the sign before rounding */
|
||||
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RddV = 0;
|
||||
} else {
|
||||
RddV = float32_to_uint64(RsV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -500,16 +571,28 @@ int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int64_t RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = conv_sf_to_8s(RsV, &env->fp_status);
|
||||
/* Hexagon returns -1 for NaN */
|
||||
if (float32_is_any_nan(RsV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RddV = -1;
|
||||
} else {
|
||||
RddV = float32_to_int64(RsV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
int32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
|
||||
uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
|
||||
{
|
||||
int32_t RdV;
|
||||
uint32_t RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = conv_df_to_4u(RssV, &env->fp_status);
|
||||
/* Hexagon checks the sign before rounding */
|
||||
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RdV = 0;
|
||||
} else {
|
||||
RdV = float64_to_uint32(RssV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -518,16 +601,28 @@ int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
|
||||
{
|
||||
int32_t RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = conv_df_to_4s(RssV, &env->fp_status);
|
||||
/* Hexagon returns -1 for NaN */
|
||||
if (float64_is_any_nan(RssV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RdV = -1;
|
||||
} else {
|
||||
RdV = float64_to_int32(RssV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
|
||||
int64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
|
||||
uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
|
||||
{
|
||||
int64_t RddV;
|
||||
uint64_t RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = conv_df_to_8u(RssV, &env->fp_status);
|
||||
/* Hexagon checks the sign before rounding */
|
||||
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RddV = 0;
|
||||
} else {
|
||||
RddV = float64_to_uint64(RssV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -536,17 +631,28 @@ int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
|
||||
{
|
||||
int64_t RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = conv_df_to_8s(RssV, &env->fp_status);
|
||||
/* Hexagon returns -1 for NaN */
|
||||
if (float64_is_any_nan(RssV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RddV = -1;
|
||||
} else {
|
||||
RddV = float64_to_int64(RssV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
int32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
|
||||
uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int32_t RdV;
|
||||
uint32_t RdV;
|
||||
arch_fpop_start(env);
|
||||
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
|
||||
RdV = conv_sf_to_4u(RsV, &env->fp_status);
|
||||
/* Hexagon checks the sign before rounding */
|
||||
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RdV = 0;
|
||||
} else {
|
||||
RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -555,18 +661,28 @@ int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int32_t RdV;
|
||||
arch_fpop_start(env);
|
||||
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
|
||||
RdV = conv_sf_to_4s(RsV, &env->fp_status);
|
||||
/* Hexagon returns -1 for NaN */
|
||||
if (float32_is_any_nan(RsV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RdV = -1;
|
||||
} else {
|
||||
RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
|
||||
int64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
|
||||
uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int64_t RddV;
|
||||
uint64_t RddV;
|
||||
arch_fpop_start(env);
|
||||
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
|
||||
RddV = conv_sf_to_8u(RsV, &env->fp_status);
|
||||
/* Hexagon checks the sign before rounding */
|
||||
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RddV = 0;
|
||||
} else {
|
||||
RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -575,18 +691,28 @@ int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
|
||||
{
|
||||
int64_t RddV;
|
||||
arch_fpop_start(env);
|
||||
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
|
||||
RddV = conv_sf_to_8s(RsV, &env->fp_status);
|
||||
/* Hexagon returns -1 for NaN */
|
||||
if (float32_is_any_nan(RsV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RddV = -1;
|
||||
} else {
|
||||
RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
|
||||
int32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
|
||||
uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
|
||||
{
|
||||
int32_t RdV;
|
||||
uint32_t RdV;
|
||||
arch_fpop_start(env);
|
||||
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
|
||||
RdV = conv_df_to_4u(RssV, &env->fp_status);
|
||||
/* Hexagon checks the sign before rounding */
|
||||
if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RdV = 0;
|
||||
} else {
|
||||
RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -595,18 +721,28 @@ int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
|
||||
{
|
||||
int32_t RdV;
|
||||
arch_fpop_start(env);
|
||||
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
|
||||
RdV = conv_df_to_4s(RssV, &env->fp_status);
|
||||
/* Hexagon returns -1 for NaN */
|
||||
if (float64_is_any_nan(RssV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RdV = -1;
|
||||
} else {
|
||||
RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
|
||||
int64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
|
||||
uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
|
||||
{
|
||||
int64_t RddV;
|
||||
uint64_t RddV;
|
||||
arch_fpop_start(env);
|
||||
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
|
||||
RddV = conv_df_to_8u(RssV, &env->fp_status);
|
||||
/* Hexagon checks the sign before rounding */
|
||||
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RddV = 0;
|
||||
} else {
|
||||
RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -615,8 +751,13 @@ int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
|
||||
{
|
||||
int64_t RddV;
|
||||
arch_fpop_start(env);
|
||||
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
|
||||
RddV = conv_df_to_8s(RssV, &env->fp_status);
|
||||
/* Hexagon returns -1 for NaN */
|
||||
if (float64_is_any_nan(RssV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
RddV = -1;
|
||||
} else {
|
||||
RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
|
||||
}
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -626,7 +767,6 @@ float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = float32_add(RsV, RtV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -636,7 +776,6 @@ float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = float32_sub(RsV, RtV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -688,7 +827,6 @@ float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = float32_maxnum(RsV, RtV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -698,7 +836,6 @@ float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = float32_minnum(RsV, RtV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -765,7 +902,6 @@ float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
||||
float64 RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = float64_add(RssV, RttV, &env->fp_status);
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -775,7 +911,6 @@ float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
||||
float64 RddV;
|
||||
arch_fpop_start(env);
|
||||
RddV = float64_sub(RssV, RttV, &env->fp_status);
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -788,7 +923,6 @@ float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
||||
if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
}
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -801,7 +935,6 @@ float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
||||
if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
|
||||
float_raise(float_flag_invalid, &env->fp_status);
|
||||
}
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
arch_fpop_end(env);
|
||||
return RddV;
|
||||
}
|
||||
@ -877,7 +1010,6 @@ float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
||||
float32 RdV;
|
||||
arch_fpop_start(env);
|
||||
RdV = internal_mpyf(RsV, RtV, &env->fp_status);
|
||||
RdV = hex_check_sfnan(RdV);
|
||||
arch_fpop_end(env);
|
||||
return RdV;
|
||||
}
|
||||
@ -887,7 +1019,6 @@ float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
|
||||
{
|
||||
arch_fpop_start(env);
|
||||
RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
|
||||
RxV = hex_check_sfnan(RxV);
|
||||
arch_fpop_end(env);
|
||||
return RxV;
|
||||
}
|
||||
@ -919,7 +1050,6 @@ float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
|
||||
RxV = check_nan(RxV, RsV, &env->fp_status);
|
||||
RxV = check_nan(RxV, RtV, &env->fp_status);
|
||||
tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
|
||||
tmp = hex_check_sfnan(tmp);
|
||||
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
||||
RxV = tmp;
|
||||
}
|
||||
@ -934,12 +1064,11 @@ float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
|
||||
arch_fpop_start(env);
|
||||
neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
|
||||
RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
|
||||
RxV = hex_check_sfnan(RxV);
|
||||
arch_fpop_end(env);
|
||||
return RxV;
|
||||
}
|
||||
|
||||
static inline bool is_inf_prod(int32_t a, int32_t b)
|
||||
static bool is_inf_prod(int32_t a, int32_t b)
|
||||
{
|
||||
return (float32_is_infinity(a) && float32_is_infinity(b)) ||
|
||||
(float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
|
||||
@ -949,8 +1078,8 @@ static inline bool is_inf_prod(int32_t a, int32_t b)
|
||||
float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
|
||||
float32 RsV, float32 RtV)
|
||||
{
|
||||
int infinp;
|
||||
int infminusinf;
|
||||
bool infinp;
|
||||
bool infminusinf;
|
||||
float32 tmp;
|
||||
|
||||
arch_fpop_start(env);
|
||||
@ -965,7 +1094,6 @@ float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
|
||||
RxV = check_nan(RxV, RsV, &env->fp_status);
|
||||
RxV = check_nan(RxV, RtV, &env->fp_status);
|
||||
tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
|
||||
tmp = hex_check_sfnan(tmp);
|
||||
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
||||
RxV = tmp;
|
||||
}
|
||||
@ -983,8 +1111,8 @@ float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
|
||||
float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
|
||||
float32 RsV, float32 RtV)
|
||||
{
|
||||
int infinp;
|
||||
int infminusinf;
|
||||
bool infinp;
|
||||
bool infminusinf;
|
||||
float32 tmp;
|
||||
|
||||
arch_fpop_start(env);
|
||||
@ -1000,7 +1128,6 @@ float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
|
||||
RxV = check_nan(RxV, RtV, &env->fp_status);
|
||||
float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
|
||||
tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
|
||||
tmp = hex_check_sfnan(tmp);
|
||||
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
||||
RxV = tmp;
|
||||
}
|
||||
@ -1024,13 +1151,11 @@ float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
||||
float64_is_normal(RttV)) {
|
||||
RddV = float64_mul(RssV, make_float64(0x4330000000000000),
|
||||
&env->fp_status);
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
} else if (float64_is_denormal(RttV) &&
|
||||
(float64_getexp(RssV) >= 512) &&
|
||||
float64_is_normal(RssV)) {
|
||||
RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
|
||||
&env->fp_status);
|
||||
RddV = hex_check_dfnan(RddV);
|
||||
} else {
|
||||
RddV = RssV;
|
||||
}
|
||||
@ -1043,7 +1168,6 @@ float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
|
||||
{
|
||||
arch_fpop_start(env);
|
||||
RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
|
||||
RxxV = hex_check_dfnan(RxxV);
|
||||
arch_fpop_end(env);
|
||||
return RxxV;
|
||||
}
|
||||
|
@ -18,10 +18,9 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "reg_fields.h"
|
||||
|
||||
const RegField reg_field_info[] = {
|
||||
const RegField reg_field_info[NUM_REG_FIELDS] = {
|
||||
#define DEF_REG_FIELD(TAG, START, WIDTH) \
|
||||
{ START, WIDTH },
|
||||
#include "reg_fields_def.h.inc"
|
||||
{ 0, 0 }
|
||||
#undef DEF_REG_FIELD
|
||||
};
|
||||
|
@ -23,8 +23,6 @@ typedef struct {
|
||||
int width;
|
||||
} RegField;
|
||||
|
||||
extern const RegField reg_field_info[];
|
||||
|
||||
enum {
|
||||
#define DEF_REG_FIELD(TAG, START, WIDTH) \
|
||||
TAG,
|
||||
@ -33,4 +31,6 @@ enum {
|
||||
#undef DEF_REG_FIELD
|
||||
};
|
||||
|
||||
extern const RegField reg_field_info[NUM_REG_FIELDS];
|
||||
|
||||
#endif
|
||||
|
@ -35,9 +35,7 @@ TCGv hex_this_PC;
|
||||
TCGv hex_slot_cancelled;
|
||||
TCGv hex_branch_taken;
|
||||
TCGv hex_new_value[TOTAL_PER_THREAD_REGS];
|
||||
#if HEX_DEBUG
|
||||
TCGv hex_reg_written[TOTAL_PER_THREAD_REGS];
|
||||
#endif
|
||||
TCGv hex_new_pred_value[NUM_PREGS];
|
||||
TCGv hex_pred_written;
|
||||
TCGv hex_store_addr[STORES_MAX];
|
||||
@ -54,19 +52,42 @@ static const char * const hexagon_prednames[] = {
|
||||
"p0", "p1", "p2", "p3"
|
||||
};
|
||||
|
||||
void gen_exception(int excp)
|
||||
static void gen_exception_raw(int excp)
|
||||
{
|
||||
TCGv_i32 helper_tmp = tcg_const_i32(excp);
|
||||
gen_helper_raise_exception(cpu_env, helper_tmp);
|
||||
tcg_temp_free_i32(helper_tmp);
|
||||
}
|
||||
|
||||
void gen_exception_debug(void)
|
||||
static void gen_exec_counters(DisasContext *ctx)
|
||||
{
|
||||
gen_exception(EXCP_DEBUG);
|
||||
tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT],
|
||||
hex_gpr[HEX_REG_QEMU_PKT_CNT], ctx->num_packets);
|
||||
tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_INSN_CNT],
|
||||
hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns);
|
||||
}
|
||||
|
||||
static void gen_end_tb(DisasContext *ctx)
|
||||
{
|
||||
gen_exec_counters(ctx);
|
||||
tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC);
|
||||
if (ctx->base.singlestep_enabled) {
|
||||
gen_exception_raw(EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
}
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_exception_end_tb(DisasContext *ctx, int excp)
|
||||
{
|
||||
gen_exec_counters(ctx);
|
||||
tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC);
|
||||
gen_exception_raw(excp);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
}
|
||||
|
||||
#if HEX_DEBUG
|
||||
#define PACKET_BUFFER_LEN 1028
|
||||
static void print_pkt(Packet *pkt)
|
||||
{
|
||||
@ -75,10 +96,12 @@ static void print_pkt(Packet *pkt)
|
||||
HEX_DEBUG_LOG("%s", buf->str);
|
||||
g_string_free(buf, true);
|
||||
}
|
||||
#define HEX_DEBUG_PRINT_PKT(pkt) print_pkt(pkt)
|
||||
#else
|
||||
#define HEX_DEBUG_PRINT_PKT(pkt) /* nothing */
|
||||
#endif
|
||||
#define HEX_DEBUG_PRINT_PKT(pkt) \
|
||||
do { \
|
||||
if (HEX_DEBUG) { \
|
||||
print_pkt(pkt); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int read_packet_words(CPUHexagonState *env, DisasContext *ctx,
|
||||
uint32_t words[])
|
||||
@ -88,8 +111,8 @@ static int read_packet_words(CPUHexagonState *env, DisasContext *ctx,
|
||||
|
||||
memset(words, 0, PACKET_WORDS_MAX * sizeof(uint32_t));
|
||||
for (nwords = 0; !found_end && nwords < PACKET_WORDS_MAX; nwords++) {
|
||||
words[nwords] = cpu_ldl_code(env,
|
||||
ctx->base.pc_next + nwords * sizeof(uint32_t));
|
||||
words[nwords] =
|
||||
translator_ldl(env, ctx->base.pc_next + nwords * sizeof(uint32_t));
|
||||
found_end = is_packet_end(words[nwords]);
|
||||
}
|
||||
if (!found_end) {
|
||||
@ -148,17 +171,18 @@ static void gen_start_packet(DisasContext *ctx, Packet *pkt)
|
||||
ctx->reg_log_idx = 0;
|
||||
bitmap_zero(ctx->regs_written, TOTAL_PER_THREAD_REGS);
|
||||
ctx->preg_log_idx = 0;
|
||||
bitmap_zero(ctx->pregs_written, NUM_PREGS);
|
||||
for (i = 0; i < STORES_MAX; i++) {
|
||||
ctx->store_width[i] = 0;
|
||||
}
|
||||
tcg_gen_movi_tl(hex_pkt_has_store_s1, pkt->pkt_has_store_s1);
|
||||
ctx->s1_store_processed = 0;
|
||||
ctx->s1_store_processed = false;
|
||||
|
||||
#if HEX_DEBUG
|
||||
/* Handy place to set a breakpoint before the packet executes */
|
||||
gen_helper_debug_start_packet(cpu_env);
|
||||
tcg_gen_movi_tl(hex_this_PC, ctx->base.pc_next);
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
/* Handy place to set a breakpoint before the packet executes */
|
||||
gen_helper_debug_start_packet(cpu_env);
|
||||
tcg_gen_movi_tl(hex_this_PC, ctx->base.pc_next);
|
||||
}
|
||||
|
||||
/* Initialize the runtime state for packet semantics */
|
||||
if (need_pc(pkt)) {
|
||||
@ -185,7 +209,7 @@ static void mark_implicit_reg_write(DisasContext *ctx, Insn *insn,
|
||||
int attrib, int rnum)
|
||||
{
|
||||
if (GET_ATTRIB(insn->opcode, attrib)) {
|
||||
int is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC);
|
||||
bool is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC);
|
||||
if (is_predicated && !is_preloaded(ctx, rnum)) {
|
||||
tcg_gen_mov_tl(hex_new_value[rnum], hex_gpr[rnum]);
|
||||
}
|
||||
@ -202,7 +226,7 @@ static void mark_implicit_pred_write(DisasContext *ctx, Insn *insn,
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_implicit_writes(DisasContext *ctx, Insn *insn)
|
||||
static void mark_implicit_reg_writes(DisasContext *ctx, Insn *insn)
|
||||
{
|
||||
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_FP, HEX_REG_FP);
|
||||
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SP, HEX_REG_SP);
|
||||
@ -211,7 +235,10 @@ static void mark_implicit_writes(DisasContext *ctx, Insn *insn)
|
||||
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA0, HEX_REG_SA0);
|
||||
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_LC1, HEX_REG_LC1);
|
||||
mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1);
|
||||
}
|
||||
|
||||
static void mark_implicit_pred_writes(DisasContext *ctx, Insn *insn)
|
||||
{
|
||||
mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P0, 0);
|
||||
mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P1, 1);
|
||||
mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P2, 2);
|
||||
@ -222,11 +249,11 @@ static void gen_insn(CPUHexagonState *env, DisasContext *ctx,
|
||||
Insn *insn, Packet *pkt)
|
||||
{
|
||||
if (insn->generate) {
|
||||
mark_implicit_writes(ctx, insn);
|
||||
mark_implicit_reg_writes(ctx, insn);
|
||||
insn->generate(env, ctx, insn, pkt);
|
||||
mark_implicit_pred_writes(ctx, insn);
|
||||
} else {
|
||||
gen_exception(HEX_EXCP_INVALID_OPCODE);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
gen_exception_end_tb(ctx, HEX_EXCP_INVALID_OPCODE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,10 +307,11 @@ static void gen_pred_writes(DisasContext *ctx, Packet *pkt)
|
||||
for (i = 0; i < ctx->preg_log_idx; i++) {
|
||||
int pred_num = ctx->preg_log[i];
|
||||
tcg_gen_mov_tl(hex_pred[pred_num], hex_new_pred_value[pred_num]);
|
||||
#if HEX_DEBUG
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pred_num);
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
/* Do this so HELPER(debug_commit_end) will know */
|
||||
tcg_gen_ori_tl(hex_pred_written, hex_pred_written,
|
||||
1 << pred_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,20 +320,16 @@ static void gen_pred_writes(DisasContext *ctx, Packet *pkt)
|
||||
tcg_temp_free(pval);
|
||||
}
|
||||
|
||||
#if HEX_DEBUG
|
||||
static inline void gen_check_store_width(DisasContext *ctx, int slot_num)
|
||||
static void gen_check_store_width(DisasContext *ctx, int slot_num)
|
||||
{
|
||||
TCGv slot = tcg_const_tl(slot_num);
|
||||
TCGv check = tcg_const_tl(ctx->store_width[slot_num]);
|
||||
gen_helper_debug_check_store_width(cpu_env, slot, check);
|
||||
tcg_temp_free(slot);
|
||||
tcg_temp_free(check);
|
||||
if (HEX_DEBUG) {
|
||||
TCGv slot = tcg_const_tl(slot_num);
|
||||
TCGv check = tcg_const_tl(ctx->store_width[slot_num]);
|
||||
gen_helper_debug_check_store_width(cpu_env, slot, check);
|
||||
tcg_temp_free(slot);
|
||||
tcg_temp_free(check);
|
||||
}
|
||||
}
|
||||
#define HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num) \
|
||||
gen_check_store_width(ctx, slot_num)
|
||||
#else
|
||||
#define HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num) /* nothing */
|
||||
#endif
|
||||
|
||||
static bool slot_is_predicated(Packet *pkt, int slot_num)
|
||||
{
|
||||
@ -330,7 +354,7 @@ void process_store(DisasContext *ctx, Packet *pkt, int slot_num)
|
||||
if (slot_num == 1 && ctx->s1_store_processed) {
|
||||
return;
|
||||
}
|
||||
ctx->s1_store_processed = 1;
|
||||
ctx->s1_store_processed = true;
|
||||
|
||||
if (is_predicated) {
|
||||
TCGv cancelled = tcg_temp_new();
|
||||
@ -355,25 +379,25 @@ void process_store(DisasContext *ctx, Packet *pkt, int slot_num)
|
||||
*/
|
||||
switch (ctx->store_width[slot_num]) {
|
||||
case 1:
|
||||
HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num);
|
||||
gen_check_store_width(ctx, slot_num);
|
||||
tcg_gen_qemu_st8(hex_store_val32[slot_num],
|
||||
hex_store_addr[slot_num],
|
||||
ctx->mem_idx);
|
||||
break;
|
||||
case 2:
|
||||
HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num);
|
||||
gen_check_store_width(ctx, slot_num);
|
||||
tcg_gen_qemu_st16(hex_store_val32[slot_num],
|
||||
hex_store_addr[slot_num],
|
||||
ctx->mem_idx);
|
||||
break;
|
||||
case 4:
|
||||
HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num);
|
||||
gen_check_store_width(ctx, slot_num);
|
||||
tcg_gen_qemu_st32(hex_store_val32[slot_num],
|
||||
hex_store_addr[slot_num],
|
||||
ctx->mem_idx);
|
||||
break;
|
||||
case 8:
|
||||
HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num);
|
||||
gen_check_store_width(ctx, slot_num);
|
||||
tcg_gen_qemu_st64(hex_store_val64[slot_num],
|
||||
hex_store_addr[slot_num],
|
||||
ctx->mem_idx);
|
||||
@ -451,14 +475,6 @@ static void update_exec_counters(DisasContext *ctx, Packet *pkt)
|
||||
ctx->num_insns += num_real_insns;
|
||||
}
|
||||
|
||||
static void gen_exec_counters(DisasContext *ctx)
|
||||
{
|
||||
tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT],
|
||||
hex_gpr[HEX_REG_QEMU_PKT_CNT], ctx->num_packets);
|
||||
tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_INSN_CNT],
|
||||
hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns);
|
||||
}
|
||||
|
||||
static void gen_commit_packet(DisasContext *ctx, Packet *pkt)
|
||||
{
|
||||
gen_reg_writes(ctx);
|
||||
@ -466,8 +482,7 @@ static void gen_commit_packet(DisasContext *ctx, Packet *pkt)
|
||||
process_store_log(ctx, pkt);
|
||||
process_dczeroa(ctx, pkt);
|
||||
update_exec_counters(ctx, pkt);
|
||||
#if HEX_DEBUG
|
||||
{
|
||||
if (HEX_DEBUG) {
|
||||
TCGv has_st0 =
|
||||
tcg_const_tl(pkt->pkt_has_store_s0 && !pkt->pkt_has_dczeroa);
|
||||
TCGv has_st1 =
|
||||
@ -479,10 +494,9 @@ static void gen_commit_packet(DisasContext *ctx, Packet *pkt)
|
||||
tcg_temp_free(has_st0);
|
||||
tcg_temp_free(has_st1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pkt->pkt_has_cof) {
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
gen_end_tb(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,8 +509,7 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
|
||||
|
||||
nwords = read_packet_words(env, ctx, words);
|
||||
if (!nwords) {
|
||||
gen_exception(HEX_EXCP_INVALID_PACKET);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -509,8 +522,7 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
|
||||
gen_commit_packet(ctx, &pkt);
|
||||
ctx->base.pc_next += pkt.encod_pkt_size_in_bytes;
|
||||
} else {
|
||||
gen_exception(HEX_EXCP_INVALID_PACKET);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET);
|
||||
}
|
||||
}
|
||||
|
||||
@ -540,9 +552,7 @@ static bool hexagon_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
|
||||
{
|
||||
DisasContext *ctx = container_of(dcbase, DisasContext, base);
|
||||
|
||||
tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
gen_exception_debug();
|
||||
gen_exception_end_tb(ctx, EXCP_DEBUG);
|
||||
/*
|
||||
* The address covered by the breakpoint must be included in
|
||||
* [tb->pc, tb->pc + tb->size) in order to for it to be
|
||||
@ -589,14 +599,10 @@ static void hexagon_tr_translate_packet(DisasContextBase *dcbase, CPUState *cpu)
|
||||
* The CPU log is used to compare against LLDB single stepping,
|
||||
* so end the TLB after every packet.
|
||||
*/
|
||||
HexagonCPU *hex_cpu = container_of(env, HexagonCPU, env);
|
||||
HexagonCPU *hex_cpu = env_archcpu(env);
|
||||
if (hex_cpu->lldb_compat && qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
|
||||
ctx->base.is_jmp = DISAS_TOO_MANY;
|
||||
}
|
||||
#if HEX_DEBUG
|
||||
/* When debugging, only put one packet per TB */
|
||||
ctx->base.is_jmp = DISAS_TOO_MANY;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -609,19 +615,12 @@ static void hexagon_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
gen_exec_counters(ctx);
|
||||
tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next);
|
||||
if (ctx->base.singlestep_enabled) {
|
||||
gen_exception_debug();
|
||||
gen_exception_raw(EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
}
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
gen_exec_counters(ctx);
|
||||
tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC);
|
||||
if (ctx->base.singlestep_enabled) {
|
||||
gen_exception_debug();
|
||||
} else {
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@ -654,9 +653,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
|
||||
|
||||
#define NAME_LEN 64
|
||||
static char new_value_names[TOTAL_PER_THREAD_REGS][NAME_LEN];
|
||||
#if HEX_DEBUG
|
||||
static char reg_written_names[TOTAL_PER_THREAD_REGS][NAME_LEN];
|
||||
#endif
|
||||
static char new_pred_value_names[NUM_PREGS][NAME_LEN];
|
||||
static char store_addr_names[STORES_MAX][NAME_LEN];
|
||||
static char store_width_names[STORES_MAX][NAME_LEN];
|
||||
@ -669,11 +666,11 @@ void hexagon_translate_init(void)
|
||||
|
||||
opcode_init();
|
||||
|
||||
#if HEX_DEBUG
|
||||
if (!qemu_logfile) {
|
||||
qemu_set_log(qemu_loglevel);
|
||||
if (HEX_DEBUG) {
|
||||
if (!qemu_logfile) {
|
||||
qemu_set_log(qemu_loglevel);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
|
||||
hex_gpr[i] = tcg_global_mem_new(cpu_env,
|
||||
@ -685,13 +682,13 @@ void hexagon_translate_init(void)
|
||||
offsetof(CPUHexagonState, new_value[i]),
|
||||
new_value_names[i]);
|
||||
|
||||
#if HEX_DEBUG
|
||||
snprintf(reg_written_names[i], NAME_LEN, "reg_written_%s",
|
||||
hexagon_regnames[i]);
|
||||
hex_reg_written[i] = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUHexagonState, reg_written[i]),
|
||||
reg_written_names[i]);
|
||||
#endif
|
||||
if (HEX_DEBUG) {
|
||||
snprintf(reg_written_names[i], NAME_LEN, "reg_written_%s",
|
||||
hexagon_regnames[i]);
|
||||
hex_reg_written[i] = tcg_global_mem_new(cpu_env,
|
||||
offsetof(CPUHexagonState, reg_written[i]),
|
||||
reg_written_names[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NUM_PREGS; i++) {
|
||||
hex_pred[i] = tcg_global_mem_new(cpu_env,
|
||||
|
@ -34,17 +34,16 @@ typedef struct DisasContext {
|
||||
DECLARE_BITMAP(regs_written, TOTAL_PER_THREAD_REGS);
|
||||
int preg_log[PRED_WRITES_MAX];
|
||||
int preg_log_idx;
|
||||
DECLARE_BITMAP(pregs_written, NUM_PREGS);
|
||||
uint8_t store_width[STORES_MAX];
|
||||
uint8_t s1_store_processed;
|
||||
bool s1_store_processed;
|
||||
} DisasContext;
|
||||
|
||||
static inline void ctx_log_reg_write(DisasContext *ctx, int rnum)
|
||||
{
|
||||
#if HEX_DEBUG
|
||||
if (test_bit(rnum, ctx->regs_written)) {
|
||||
HEX_DEBUG_LOG("WARNING: Multiple writes to r%d\n", rnum);
|
||||
}
|
||||
#endif
|
||||
ctx->reg_log[ctx->reg_log_idx] = rnum;
|
||||
ctx->reg_log_idx++;
|
||||
set_bit(rnum, ctx->regs_written);
|
||||
@ -60,6 +59,7 @@ static inline void ctx_log_pred_write(DisasContext *ctx, int pnum)
|
||||
{
|
||||
ctx->preg_log[ctx->preg_log_idx] = pnum;
|
||||
ctx->preg_log_idx++;
|
||||
set_bit(pnum, ctx->pregs_written);
|
||||
}
|
||||
|
||||
static inline bool is_preloaded(DisasContext *ctx, int num)
|
||||
@ -86,8 +86,5 @@ extern TCGv hex_llsc_addr;
|
||||
extern TCGv hex_llsc_val;
|
||||
extern TCGv_i64 hex_llsc_val_i64;
|
||||
|
||||
void gen_exception(int excp);
|
||||
void gen_exception_debug(void);
|
||||
|
||||
void process_store(DisasContext *ctx, Packet *pkt, int slot_num);
|
||||
#endif
|
||||
|
@ -28,6 +28,7 @@ endif
|
||||
|
||||
|
||||
CFLAGS += -Wno-incompatible-pointer-types -Wno-undefined-internal
|
||||
CFLAGS += -fno-unroll-loops
|
||||
|
||||
HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon
|
||||
VPATH += $(HEX_SRC)
|
||||
@ -39,7 +40,12 @@ HEX_TESTS = first
|
||||
HEX_TESTS += misc
|
||||
HEX_TESTS += preg_alias
|
||||
HEX_TESTS += dual_stores
|
||||
HEX_TESTS += multi_result
|
||||
HEX_TESTS += mem_noshuf
|
||||
HEX_TESTS += circ
|
||||
HEX_TESTS += brev
|
||||
HEX_TESTS += load_unpack
|
||||
HEX_TESTS += load_align
|
||||
HEX_TESTS += atomics
|
||||
HEX_TESTS += fpstuff
|
||||
|
||||
|
190
tests/tcg/hexagon/brev.c
Normal file
190
tests/tcg/hexagon/brev.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int err;
|
||||
|
||||
#define NBITS 8
|
||||
#define SIZE (1 << NBITS)
|
||||
|
||||
long long dbuf[SIZE] __attribute__((aligned(1 << 16))) = {0};
|
||||
int wbuf[SIZE] __attribute__((aligned(1 << 16))) = {0};
|
||||
short hbuf[SIZE] __attribute__((aligned(1 << 16))) = {0};
|
||||
unsigned char bbuf[SIZE] __attribute__((aligned(1 << 16))) = {0};
|
||||
|
||||
/*
|
||||
* We use the C preporcessor to deal with the combinations of types
|
||||
*/
|
||||
|
||||
#define BREV_LOAD(SZ, RES, ADDR, INC) \
|
||||
__asm__( \
|
||||
"m0 = %2\n\t" \
|
||||
"%0 = mem" #SZ "(%1++m0:brev)\n\t" \
|
||||
: "=r"(RES), "+r"(ADDR) \
|
||||
: "r"(INC) \
|
||||
: "m0")
|
||||
|
||||
#define BREV_LOAD_b(RES, ADDR, INC) \
|
||||
BREV_LOAD(b, RES, ADDR, INC)
|
||||
#define BREV_LOAD_ub(RES, ADDR, INC) \
|
||||
BREV_LOAD(ub, RES, ADDR, INC)
|
||||
#define BREV_LOAD_h(RES, ADDR, INC) \
|
||||
BREV_LOAD(h, RES, ADDR, INC)
|
||||
#define BREV_LOAD_uh(RES, ADDR, INC) \
|
||||
BREV_LOAD(uh, RES, ADDR, INC)
|
||||
#define BREV_LOAD_w(RES, ADDR, INC) \
|
||||
BREV_LOAD(w, RES, ADDR, INC)
|
||||
#define BREV_LOAD_d(RES, ADDR, INC) \
|
||||
BREV_LOAD(d, RES, ADDR, INC)
|
||||
|
||||
#define BREV_STORE(SZ, PART, ADDR, VAL, INC) \
|
||||
__asm__( \
|
||||
"m0 = %2\n\t" \
|
||||
"mem" #SZ "(%0++m0:brev) = %1" PART "\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(VAL), "r"(INC) \
|
||||
: "m0", "memory")
|
||||
|
||||
#define BREV_STORE_b(ADDR, VAL, INC) \
|
||||
BREV_STORE(b, "", ADDR, VAL, INC)
|
||||
#define BREV_STORE_h(ADDR, VAL, INC) \
|
||||
BREV_STORE(h, "", ADDR, VAL, INC)
|
||||
#define BREV_STORE_f(ADDR, VAL, INC) \
|
||||
BREV_STORE(h, ".H", ADDR, VAL, INC)
|
||||
#define BREV_STORE_w(ADDR, VAL, INC) \
|
||||
BREV_STORE(w, "", ADDR, VAL, INC)
|
||||
#define BREV_STORE_d(ADDR, VAL, INC) \
|
||||
BREV_STORE(d, "", ADDR, VAL, INC)
|
||||
|
||||
#define BREV_STORE_NEW(SZ, ADDR, VAL, INC) \
|
||||
__asm__( \
|
||||
"m0 = %2\n\t" \
|
||||
"{\n\t" \
|
||||
" r5 = %1\n\t" \
|
||||
" mem" #SZ "(%0++m0:brev) = r5.new\n\t" \
|
||||
"}\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(VAL), "r"(INC) \
|
||||
: "r5", "m0", "memory")
|
||||
|
||||
#define BREV_STORE_bnew(ADDR, VAL, INC) \
|
||||
BREV_STORE_NEW(b, ADDR, VAL, INC)
|
||||
#define BREV_STORE_hnew(ADDR, VAL, INC) \
|
||||
BREV_STORE_NEW(h, ADDR, VAL, INC)
|
||||
#define BREV_STORE_wnew(ADDR, VAL, INC) \
|
||||
BREV_STORE_NEW(w, ADDR, VAL, INC)
|
||||
|
||||
int bitreverse(int x)
|
||||
{
|
||||
int result = 0;
|
||||
int i;
|
||||
for (i = 0; i < NBITS; i++) {
|
||||
result <<= 1;
|
||||
result |= x & 1;
|
||||
x >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int sext8(int x)
|
||||
{
|
||||
return (x << 24) >> 24;
|
||||
}
|
||||
|
||||
void check(int i, long long result, long long expect)
|
||||
{
|
||||
if (result != expect) {
|
||||
printf("ERROR(%d): 0x%04llx != 0x%04llx\n", i, result, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_BREV_LOAD(SZ, TYPE, BUF, SHIFT, EXP) \
|
||||
do { \
|
||||
p = BUF; \
|
||||
for (i = 0; i < SIZE; i++) { \
|
||||
TYPE result; \
|
||||
BREV_LOAD_##SZ(result, p, 1 << (SHIFT - NBITS)); \
|
||||
check(i, result, EXP); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TEST_BREV_STORE(SZ, TYPE, BUF, VAL, SHIFT) \
|
||||
do { \
|
||||
p = BUF; \
|
||||
memset(BUF, 0xff, sizeof(BUF)); \
|
||||
for (i = 0; i < SIZE; i++) { \
|
||||
BREV_STORE_##SZ(p, (TYPE)(VAL), 1 << (SHIFT - NBITS)); \
|
||||
} \
|
||||
for (i = 0; i < SIZE; i++) { \
|
||||
check(i, BUF[i], bitreverse(i)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TEST_BREV_STORE_NEW(SZ, BUF, SHIFT) \
|
||||
do { \
|
||||
p = BUF; \
|
||||
memset(BUF, 0xff, sizeof(BUF)); \
|
||||
for (i = 0; i < SIZE; i++) { \
|
||||
BREV_STORE_##SZ(p, i, 1 << (SHIFT - NBITS)); \
|
||||
} \
|
||||
for (i = 0; i < SIZE; i++) { \
|
||||
check(i, BUF[i], bitreverse(i)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* We'll set high_half[i] = i << 16 for use in the .H form of store
|
||||
* which stores from the high half of the word.
|
||||
*/
|
||||
int high_half[SIZE];
|
||||
|
||||
int main()
|
||||
{
|
||||
void *p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SIZE; i++) {
|
||||
bbuf[i] = bitreverse(i);
|
||||
hbuf[i] = bitreverse(i);
|
||||
wbuf[i] = bitreverse(i);
|
||||
dbuf[i] = bitreverse(i);
|
||||
high_half[i] = i << 16;
|
||||
}
|
||||
|
||||
TEST_BREV_LOAD(b, int, bbuf, 16, sext8(i));
|
||||
TEST_BREV_LOAD(ub, int, bbuf, 16, i);
|
||||
TEST_BREV_LOAD(h, int, hbuf, 15, i);
|
||||
TEST_BREV_LOAD(uh, int, hbuf, 15, i);
|
||||
TEST_BREV_LOAD(w, int, wbuf, 14, i);
|
||||
TEST_BREV_LOAD(d, long long, dbuf, 13, i);
|
||||
|
||||
TEST_BREV_STORE(b, int, bbuf, i, 16);
|
||||
TEST_BREV_STORE(h, int, hbuf, i, 15);
|
||||
TEST_BREV_STORE(f, int, hbuf, high_half[i], 15);
|
||||
TEST_BREV_STORE(w, int, wbuf, i, 14);
|
||||
TEST_BREV_STORE(d, long long, dbuf, i, 13);
|
||||
|
||||
TEST_BREV_STORE_NEW(bnew, bbuf, 16);
|
||||
TEST_BREV_STORE_NEW(hnew, hbuf, 15);
|
||||
TEST_BREV_STORE_NEW(wnew, wbuf, 14);
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err ? 1 : 0;
|
||||
}
|
486
tests/tcg/hexagon/circ.c
Normal file
486
tests/tcg/hexagon/circ.c
Normal file
@ -0,0 +1,486 @@
|
||||
/*
|
||||
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define DEBUG 0
|
||||
#define DEBUG_PRINTF(...) \
|
||||
do { \
|
||||
if (DEBUG) { \
|
||||
printf(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define NBYTES (1 << 8)
|
||||
#define NHALFS (NBYTES / sizeof(short))
|
||||
#define NWORDS (NBYTES / sizeof(int))
|
||||
#define NDOBLS (NBYTES / sizeof(long long))
|
||||
|
||||
long long dbuf[NDOBLS] __attribute__((aligned(1 << 12))) = {0};
|
||||
int wbuf[NWORDS] __attribute__((aligned(1 << 12))) = {0};
|
||||
short hbuf[NHALFS] __attribute__((aligned(1 << 12))) = {0};
|
||||
unsigned char bbuf[NBYTES] __attribute__((aligned(1 << 12))) = {0};
|
||||
|
||||
/*
|
||||
* We use the C preporcessor to deal with the combinations of types
|
||||
*/
|
||||
|
||||
#define INIT(BUF, N) \
|
||||
void init_##BUF(void) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < N; i++) { \
|
||||
BUF[i] = i; \
|
||||
} \
|
||||
} \
|
||||
|
||||
INIT(bbuf, NBYTES)
|
||||
INIT(hbuf, NHALFS)
|
||||
INIT(wbuf, NWORDS)
|
||||
INIT(dbuf, NDOBLS)
|
||||
|
||||
/*
|
||||
* Macros for performing circular load
|
||||
* RES result
|
||||
* ADDR address
|
||||
* START start address of buffer
|
||||
* LEN length of buffer (in bytes)
|
||||
* INC address increment (in bytes for IMM, elements for REG)
|
||||
*/
|
||||
#define CIRC_LOAD_IMM(SIZE, RES, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %3\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"cs0 = %2\n\t" \
|
||||
"%0 = mem" #SIZE "(%1++#" #INC ":circ(M0))\n\t" \
|
||||
: "=r"(RES), "+r"(ADDR) \
|
||||
: "r"(START), "r"(LEN) \
|
||||
: "r4", "m0", "cs0")
|
||||
#define CIRC_LOAD_IMM_b(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(b, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_ub(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(ub, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_h(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(h, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_uh(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(uh, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_w(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(w, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_d(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(d, RES, ADDR, START, LEN, INC)
|
||||
|
||||
/*
|
||||
* The mreg has the following pieces
|
||||
* mreg[31:28] increment[10:7]
|
||||
* mreg[27:24] K value (used Hexagon v3 and earlier)
|
||||
* mreg[23:17] increment[6:0]
|
||||
* mreg[16:0] circular buffer length
|
||||
*/
|
||||
static int build_mreg(int inc, int K, int len)
|
||||
{
|
||||
return ((inc & 0x780) << 21) |
|
||||
((K & 0xf) << 24) |
|
||||
((inc & 0x7f) << 17) |
|
||||
(len & 0x1ffff);
|
||||
}
|
||||
|
||||
#define CIRC_LOAD_REG(SIZE, RES, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %2\n\t" \
|
||||
"m1 = r4\n\t" \
|
||||
"cs1 = %3\n\t" \
|
||||
"%0 = mem" #SIZE "(%1++I:circ(M1))\n\t" \
|
||||
: "=r"(RES), "+r"(ADDR) \
|
||||
: "r"(build_mreg((INC), 0, (LEN))), \
|
||||
"r"(START) \
|
||||
: "r4", "m1", "cs1")
|
||||
#define CIRC_LOAD_REG_b(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(b, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_ub(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(ub, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_h(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(h, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_uh(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(uh, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_w(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(w, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_d(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(d, RES, ADDR, START, LEN, INC)
|
||||
|
||||
/*
|
||||
* Macros for performing circular store
|
||||
* VAL value to store
|
||||
* ADDR address
|
||||
* START start address of buffer
|
||||
* LEN length of buffer (in bytes)
|
||||
* INC address increment (in bytes for IMM, elements for REG)
|
||||
*/
|
||||
#define CIRC_STORE_IMM(SIZE, PART, VAL, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %3\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"cs0 = %1\n\t" \
|
||||
"mem" #SIZE "(%0++#" #INC ":circ(M0)) = %2" PART "\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(START), "r"(VAL), "r"(LEN) \
|
||||
: "r4", "m0", "cs0", "memory")
|
||||
#define CIRC_STORE_IMM_b(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(b, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_h(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(h, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_f(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(h, ".H", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_w(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(w, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_d(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(d, "", VAL, ADDR, START, LEN, INC)
|
||||
|
||||
#define CIRC_STORE_NEW_IMM(SIZE, VAL, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %3\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"cs0 = %1\n\t" \
|
||||
"{\n\t" \
|
||||
" r5 = %2\n\t" \
|
||||
" mem" #SIZE "(%0++#" #INC ":circ(M0)) = r5.new\n\t" \
|
||||
"}\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(START), "r"(VAL), "r"(LEN) \
|
||||
: "r4", "r5", "m0", "cs0", "memory")
|
||||
#define CIRC_STORE_IMM_bnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_IMM(b, VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_hnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_IMM(h, VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_wnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_IMM(w, VAL, ADDR, START, LEN, INC)
|
||||
|
||||
#define CIRC_STORE_REG(SIZE, PART, VAL, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %1\n\t" \
|
||||
"m1 = r4\n\t" \
|
||||
"cs1 = %2\n\t" \
|
||||
"mem" #SIZE "(%0++I:circ(M1)) = %3" PART "\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(build_mreg((INC), 0, (LEN))), \
|
||||
"r"(START), \
|
||||
"r"(VAL) \
|
||||
: "r4", "m1", "cs1", "memory")
|
||||
#define CIRC_STORE_REG_b(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(b, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_h(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(h, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_f(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(h, ".H", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_w(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(w, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_d(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(d, "", VAL, ADDR, START, LEN, INC)
|
||||
|
||||
#define CIRC_STORE_NEW_REG(SIZE, VAL, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %1\n\t" \
|
||||
"m1 = r4\n\t" \
|
||||
"cs1 = %2\n\t" \
|
||||
"{\n\t" \
|
||||
" r5 = %3\n\t" \
|
||||
" mem" #SIZE "(%0++I:circ(M1)) = r5.new\n\t" \
|
||||
"}\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(build_mreg((INC), 0, (LEN))), \
|
||||
"r"(START), \
|
||||
"r"(VAL) \
|
||||
: "r4", "r5", "m1", "cs1", "memory")
|
||||
#define CIRC_STORE_REG_bnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_REG(b, VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_hnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_REG(h, VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_wnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_REG(w, VAL, ADDR, START, LEN, INC)
|
||||
|
||||
|
||||
int err;
|
||||
|
||||
/* We'll test increments +1 and -1 */
|
||||
void check_load(int i, long long result, int inc, int size)
|
||||
{
|
||||
int expect = (i * inc);
|
||||
while (expect >= size) {
|
||||
expect -= size;
|
||||
}
|
||||
while (expect < 0) {
|
||||
expect += size;
|
||||
}
|
||||
if (result != expect) {
|
||||
printf("ERROR(%d): %lld != %d\n", i, result, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_LOAD_IMM(SZ, TYPE, BUF, BUFSIZE, INC, FMT) \
|
||||
void circ_test_load_imm_##SZ(void) \
|
||||
{ \
|
||||
TYPE *p = (TYPE *)BUF; \
|
||||
int size = 10; \
|
||||
int i; \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
TYPE element; \
|
||||
CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), (INC)); \
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
|
||||
i, p, element); \
|
||||
check_load(i, element, ((INC) / (int)sizeof(TYPE)), size); \
|
||||
} \
|
||||
p = (TYPE *)BUF; \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
TYPE element; \
|
||||
CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), -(INC)); \
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
|
||||
i, p, element); \
|
||||
check_load(i, element, (-(INC) / (int)sizeof(TYPE)), size); \
|
||||
} \
|
||||
}
|
||||
|
||||
TEST_LOAD_IMM(b, char, bbuf, NBYTES, 1, d)
|
||||
TEST_LOAD_IMM(ub, unsigned char, bbuf, NBYTES, 1, d)
|
||||
TEST_LOAD_IMM(h, short, hbuf, NHALFS, 2, d)
|
||||
TEST_LOAD_IMM(uh, unsigned short, hbuf, NHALFS, 2, d)
|
||||
TEST_LOAD_IMM(w, int, wbuf, NWORDS, 4, d)
|
||||
TEST_LOAD_IMM(d, long long, dbuf, NDOBLS, 8, lld)
|
||||
|
||||
#define TEST_LOAD_REG(SZ, TYPE, BUF, BUFSIZE, FMT) \
|
||||
void circ_test_load_reg_##SZ(void) \
|
||||
{ \
|
||||
TYPE *p = (TYPE *)BUF; \
|
||||
int size = 13; \
|
||||
int i; \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
TYPE element; \
|
||||
CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), 1); \
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
|
||||
i, p, element); \
|
||||
check_load(i, element, 1, size); \
|
||||
} \
|
||||
p = (TYPE *)BUF; \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
TYPE element; \
|
||||
CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), -1); \
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
|
||||
i, p, element); \
|
||||
check_load(i, element, -1, size); \
|
||||
} \
|
||||
}
|
||||
|
||||
TEST_LOAD_REG(b, char, bbuf, NBYTES, d)
|
||||
TEST_LOAD_REG(ub, unsigned char, bbuf, NBYTES, d)
|
||||
TEST_LOAD_REG(h, short, hbuf, NHALFS, d)
|
||||
TEST_LOAD_REG(uh, unsigned short, hbuf, NHALFS, d)
|
||||
TEST_LOAD_REG(w, int, wbuf, NWORDS, d)
|
||||
TEST_LOAD_REG(d, long long, dbuf, NDOBLS, lld)
|
||||
|
||||
/* The circular stores will wrap around somewhere inside the buffer */
|
||||
#define CIRC_VAL(SZ, TYPE, BUFSIZE) \
|
||||
TYPE circ_val_##SZ(int i, int inc, int size) \
|
||||
{ \
|
||||
int mod = BUFSIZE % size; \
|
||||
int elem = i * inc; \
|
||||
if (elem < 0) { \
|
||||
if (-elem <= size - mod) { \
|
||||
return (elem + BUFSIZE - mod); \
|
||||
} else { \
|
||||
return (elem + BUFSIZE + size - mod); \
|
||||
} \
|
||||
} else if (elem < mod) {\
|
||||
return (elem + BUFSIZE - mod); \
|
||||
} else { \
|
||||
return (elem + BUFSIZE - size - mod); \
|
||||
} \
|
||||
}
|
||||
|
||||
CIRC_VAL(b, unsigned char, NBYTES)
|
||||
CIRC_VAL(h, short, NHALFS)
|
||||
CIRC_VAL(w, int, NWORDS)
|
||||
CIRC_VAL(d, long long, NDOBLS)
|
||||
|
||||
/*
|
||||
* Circular stores should only write to the first "size" elements of the buffer
|
||||
* the remainder of the elements should have BUF[i] == i
|
||||
*/
|
||||
#define CHECK_STORE(SZ, BUF, BUFSIZE, FMT) \
|
||||
void check_store_##SZ(int inc, int size) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < size; i++) { \
|
||||
DEBUG_PRINTF(#BUF "[%3d] = 0x%02" #FMT ", guess = 0x%02" #FMT "\n", \
|
||||
i, BUF[i], circ_val_##SZ(i, inc, size)); \
|
||||
if (BUF[i] != circ_val_##SZ(i, inc, size)) { \
|
||||
printf("ERROR(%3d): 0x%02" #FMT " != 0x%02" #FMT "\n", \
|
||||
i, BUF[i], circ_val_##SZ(i, inc, size)); \
|
||||
err++; \
|
||||
} \
|
||||
} \
|
||||
for (i = size; i < BUFSIZE; i++) { \
|
||||
if (BUF[i] != i) { \
|
||||
printf("ERROR(%3d): 0x%02" #FMT " != 0x%02x\n", i, BUF[i], i); \
|
||||
err++; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
CHECK_STORE(b, bbuf, NBYTES, x)
|
||||
CHECK_STORE(h, hbuf, NHALFS, x)
|
||||
CHECK_STORE(w, wbuf, NWORDS, x)
|
||||
CHECK_STORE(d, dbuf, NDOBLS, llx)
|
||||
|
||||
#define CIRC_TEST_STORE_IMM(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT, INC) \
|
||||
void circ_test_store_imm_##SZ(void) \
|
||||
{ \
|
||||
unsigned int size = 27; \
|
||||
TYPE *p = BUF; \
|
||||
TYPE val = 0; \
|
||||
int i; \
|
||||
init_##BUF(); \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), INC); \
|
||||
val++; \
|
||||
} \
|
||||
check_store_##CHK(((INC) / (int)sizeof(TYPE)), size); \
|
||||
p = BUF; \
|
||||
val = 0; \
|
||||
init_##BUF(); \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), \
|
||||
-(INC)); \
|
||||
val++; \
|
||||
} \
|
||||
check_store_##CHK((-(INC) / (int)sizeof(TYPE)), size); \
|
||||
}
|
||||
|
||||
CIRC_TEST_STORE_IMM(b, b, unsigned char, bbuf, NBYTES, 0, 1)
|
||||
CIRC_TEST_STORE_IMM(h, h, short, hbuf, NHALFS, 0, 2)
|
||||
CIRC_TEST_STORE_IMM(f, h, short, hbuf, NHALFS, 16, 2)
|
||||
CIRC_TEST_STORE_IMM(w, w, int, wbuf, NWORDS, 0, 4)
|
||||
CIRC_TEST_STORE_IMM(d, d, long long, dbuf, NDOBLS, 0, 8)
|
||||
CIRC_TEST_STORE_IMM(bnew, b, unsigned char, bbuf, NBYTES, 0, 1)
|
||||
CIRC_TEST_STORE_IMM(hnew, h, short, hbuf, NHALFS, 0, 2)
|
||||
CIRC_TEST_STORE_IMM(wnew, w, int, wbuf, NWORDS, 0, 4)
|
||||
|
||||
#define CIRC_TEST_STORE_REG(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT) \
|
||||
void circ_test_store_reg_##SZ(void) \
|
||||
{ \
|
||||
TYPE *p = BUF; \
|
||||
unsigned int size = 19; \
|
||||
TYPE val = 0; \
|
||||
int i; \
|
||||
init_##BUF(); \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), 1); \
|
||||
val++; \
|
||||
} \
|
||||
check_store_##CHK(1, size); \
|
||||
p = BUF; \
|
||||
val = 0; \
|
||||
init_##BUF(); \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), -1); \
|
||||
val++; \
|
||||
} \
|
||||
check_store_##CHK(-1, size); \
|
||||
}
|
||||
|
||||
CIRC_TEST_STORE_REG(b, b, unsigned char, bbuf, NBYTES, 0)
|
||||
CIRC_TEST_STORE_REG(h, h, short, hbuf, NHALFS, 0)
|
||||
CIRC_TEST_STORE_REG(f, h, short, hbuf, NHALFS, 16)
|
||||
CIRC_TEST_STORE_REG(w, w, int, wbuf, NWORDS, 0)
|
||||
CIRC_TEST_STORE_REG(d, d, long long, dbuf, NDOBLS, 0)
|
||||
CIRC_TEST_STORE_REG(bnew, b, unsigned char, bbuf, NBYTES, 0)
|
||||
CIRC_TEST_STORE_REG(hnew, h, short, hbuf, NHALFS, 0)
|
||||
CIRC_TEST_STORE_REG(wnew, w, int, wbuf, NWORDS, 0)
|
||||
|
||||
/* Test the old scheme used in Hexagon V3 */
|
||||
static void circ_test_v3(void)
|
||||
{
|
||||
int *p = wbuf;
|
||||
int size = 15;
|
||||
int K = 4; /* 64 bytes */
|
||||
int element;
|
||||
int i;
|
||||
|
||||
init_wbuf();
|
||||
|
||||
for (i = 0; i < NWORDS; i++) {
|
||||
__asm__(
|
||||
"r4 = %2\n\t"
|
||||
"m1 = r4\n\t"
|
||||
"%0 = memw(%1++I:circ(M1))\n\t"
|
||||
: "=r"(element), "+r"(p)
|
||||
: "r"(build_mreg(1, K, size * sizeof(int)))
|
||||
: "r4", "m1");
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2d\n", i, p, element);
|
||||
check_load(i, element, 1, size);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
init_bbuf();
|
||||
init_hbuf();
|
||||
init_wbuf();
|
||||
init_dbuf();
|
||||
|
||||
DEBUG_PRINTF("NBYTES = %d\n", NBYTES);
|
||||
DEBUG_PRINTF("Address of dbuf = 0x%p\n", dbuf);
|
||||
DEBUG_PRINTF("Address of wbuf = 0x%p\n", wbuf);
|
||||
DEBUG_PRINTF("Address of hbuf = 0x%p\n", hbuf);
|
||||
DEBUG_PRINTF("Address of bbuf = 0x%p\n", bbuf);
|
||||
|
||||
circ_test_load_imm_b();
|
||||
circ_test_load_imm_ub();
|
||||
circ_test_load_imm_h();
|
||||
circ_test_load_imm_uh();
|
||||
circ_test_load_imm_w();
|
||||
circ_test_load_imm_d();
|
||||
|
||||
circ_test_load_reg_b();
|
||||
circ_test_load_reg_ub();
|
||||
circ_test_load_reg_h();
|
||||
circ_test_load_reg_uh();
|
||||
circ_test_load_reg_w();
|
||||
circ_test_load_reg_d();
|
||||
|
||||
circ_test_store_imm_b();
|
||||
circ_test_store_imm_h();
|
||||
circ_test_store_imm_f();
|
||||
circ_test_store_imm_w();
|
||||
circ_test_store_imm_d();
|
||||
circ_test_store_imm_bnew();
|
||||
circ_test_store_imm_hnew();
|
||||
circ_test_store_imm_wnew();
|
||||
|
||||
circ_test_store_reg_b();
|
||||
circ_test_store_reg_h();
|
||||
circ_test_store_reg_f();
|
||||
circ_test_store_reg_w();
|
||||
circ_test_store_reg_d();
|
||||
circ_test_store_reg_bnew();
|
||||
circ_test_store_reg_hnew();
|
||||
circ_test_store_reg_wnew();
|
||||
|
||||
circ_test_v3();
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err ? 1 : 0;
|
||||
}
|
@ -37,10 +37,12 @@ const int SF_NaN = 0x7fc00000;
|
||||
const int SF_NaN_special = 0x7f800001;
|
||||
const int SF_ANY = 0x3f800000;
|
||||
const int SF_HEX_NAN = 0xffffffff;
|
||||
const int SF_small_neg = 0xab98fba8;
|
||||
|
||||
const long long DF_NaN = 0x7ff8000000000000ULL;
|
||||
const long long DF_ANY = 0x3f80000000000000ULL;
|
||||
const long long DF_HEX_NAN = 0xffffffffffffffffULL;
|
||||
const long long DF_small_neg = 0xbd731f7500000000ULL;
|
||||
|
||||
int err;
|
||||
|
||||
@ -248,6 +250,87 @@ static void check_dfminmax(void)
|
||||
check_fpstatus(usr, FPINVF);
|
||||
}
|
||||
|
||||
static void check_recip_exception(void)
|
||||
{
|
||||
int result;
|
||||
int usr;
|
||||
|
||||
/*
|
||||
* Check that sfrecipa doesn't set status bits when
|
||||
* a NaN with bit 22 non-zero is passed
|
||||
*/
|
||||
asm (CLEAR_FPSTATUS
|
||||
"%0,p0 = sfrecipa(%2, %3)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY)
|
||||
: "r2", "p0", "usr");
|
||||
check32(result, SF_HEX_NAN);
|
||||
check_fpstatus(usr, 0);
|
||||
|
||||
asm (CLEAR_FPSTATUS
|
||||
"%0,p0 = sfrecipa(%2, %3)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(result), "=r"(usr) : "r"(SF_ANY), "r"(SF_NaN)
|
||||
: "r2", "p0", "usr");
|
||||
check32(result, SF_HEX_NAN);
|
||||
check_fpstatus(usr, 0);
|
||||
|
||||
asm (CLEAR_FPSTATUS
|
||||
"%0,p0 = sfrecipa(%2, %2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(result), "=r"(usr) : "r"(SF_NaN)
|
||||
: "r2", "p0", "usr");
|
||||
check32(result, SF_HEX_NAN);
|
||||
check_fpstatus(usr, 0);
|
||||
|
||||
/*
|
||||
* Check that sfrecipa doesn't set status bits when
|
||||
* a NaN with bit 22 zero is passed
|
||||
*/
|
||||
asm (CLEAR_FPSTATUS
|
||||
"%0,p0 = sfrecipa(%2, %3)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(result), "=r"(usr) : "r"(SF_NaN_special), "r"(SF_ANY)
|
||||
: "r2", "p0", "usr");
|
||||
check32(result, SF_HEX_NAN);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm (CLEAR_FPSTATUS
|
||||
"%0,p0 = sfrecipa(%2, %3)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(result), "=r"(usr) : "r"(SF_ANY), "r"(SF_NaN_special)
|
||||
: "r2", "p0", "usr");
|
||||
check32(result, SF_HEX_NAN);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm (CLEAR_FPSTATUS
|
||||
"%0,p0 = sfrecipa(%2, %2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(result), "=r"(usr) : "r"(SF_NaN_special)
|
||||
: "r2", "p0", "usr");
|
||||
check32(result, SF_HEX_NAN);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
/*
|
||||
* Check that sfrecipa properly sets divid-by-zero
|
||||
*/
|
||||
asm (CLEAR_FPSTATUS
|
||||
"%0,p0 = sfrecipa(%2, %3)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(result), "=r"(usr) : "r"(0x885dc960), "r"(0x80000000)
|
||||
: "r2", "p0", "usr");
|
||||
check32(result, 0x3f800000);
|
||||
check_fpstatus(usr, FPDBZF);
|
||||
|
||||
asm (CLEAR_FPSTATUS
|
||||
"%0,p0 = sfrecipa(%2, %3)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(result), "=r"(usr) : "r"(0x7f800000), "r"(SF_ZERO)
|
||||
: "r2", "p0", "usr");
|
||||
check32(result, 0x3f800000);
|
||||
check_fpstatus(usr, 0);
|
||||
}
|
||||
|
||||
static void check_canonical_NaN(void)
|
||||
{
|
||||
int sf_result;
|
||||
@ -358,12 +441,171 @@ static void check_canonical_NaN(void)
|
||||
check_fpstatus(usr, 0);
|
||||
}
|
||||
|
||||
static void check_invsqrta(void)
|
||||
{
|
||||
int result;
|
||||
int predval;
|
||||
|
||||
asm volatile("%0,p0 = sfinvsqrta(%2)\n\t"
|
||||
"%1 = p0\n\t"
|
||||
: "+r"(result), "=r"(predval)
|
||||
: "r"(0x7f800000)
|
||||
: "p0");
|
||||
check32(result, 0xff800000);
|
||||
check32(predval, 0x0);
|
||||
}
|
||||
|
||||
static void check_float2int_convs()
|
||||
{
|
||||
int res32;
|
||||
long long res64;
|
||||
int usr;
|
||||
|
||||
/*
|
||||
* Check that the various forms of float-to-unsigned
|
||||
* check sign before rounding
|
||||
*/
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_sf2uw(%2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res32), "=r"(usr) : "r"(SF_small_neg)
|
||||
: "r2", "usr");
|
||||
check32(res32, 0);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_sf2uw(%2):chop\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res32), "=r"(usr) : "r"(SF_small_neg)
|
||||
: "r2", "usr");
|
||||
check32(res32, 0);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_sf2ud(%2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res64), "=r"(usr) : "r"(SF_small_neg)
|
||||
: "r2", "usr");
|
||||
check64(res64, 0);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_sf2ud(%2):chop\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res64), "=r"(usr) : "r"(SF_small_neg)
|
||||
: "r2", "usr");
|
||||
check64(res64, 0);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_df2uw(%2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res32), "=r"(usr) : "r"(DF_small_neg)
|
||||
: "r2", "usr");
|
||||
check32(res32, 0);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_df2uw(%2):chop\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res32), "=r"(usr) : "r"(DF_small_neg)
|
||||
: "r2", "usr");
|
||||
check32(res32, 0);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_df2ud(%2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res64), "=r"(usr) : "r"(DF_small_neg)
|
||||
: "r2", "usr");
|
||||
check64(res64, 0);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_df2ud(%2):chop\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res64), "=r"(usr) : "r"(DF_small_neg)
|
||||
: "r2", "usr");
|
||||
check64(res64, 0);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
/*
|
||||
* Check that the various forms of float-to-signed return -1 for NaN
|
||||
*/
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_sf2w(%2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res32), "=r"(usr) : "r"(SF_NaN)
|
||||
: "r2", "usr");
|
||||
check32(res32, -1);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_sf2w(%2):chop\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res32), "=r"(usr) : "r"(SF_NaN)
|
||||
: "r2", "usr");
|
||||
check32(res32, -1);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_sf2d(%2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res64), "=r"(usr) : "r"(SF_NaN)
|
||||
: "r2", "usr");
|
||||
check64(res64, -1);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_sf2d(%2):chop\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res64), "=r"(usr) : "r"(SF_NaN)
|
||||
: "r2", "usr");
|
||||
check64(res64, -1);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_df2w(%2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res32), "=r"(usr) : "r"(DF_NaN)
|
||||
: "r2", "usr");
|
||||
check32(res32, -1);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_df2w(%2):chop\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res32), "=r"(usr) : "r"(DF_NaN)
|
||||
: "r2", "usr");
|
||||
check32(res32, -1);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_df2d(%2)\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res64), "=r"(usr) : "r"(DF_NaN)
|
||||
: "r2", "usr");
|
||||
check64(res64, -1);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
|
||||
asm(CLEAR_FPSTATUS
|
||||
"%0 = convert_df2d(%2):chop\n\t"
|
||||
"%1 = usr\n\t"
|
||||
: "=r"(res64), "=r"(usr) : "r"(DF_NaN)
|
||||
: "r2", "usr");
|
||||
check64(res64, -1);
|
||||
check_fpstatus(usr, FPINVF);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
check_compare_exception();
|
||||
check_sfminmax();
|
||||
check_dfminmax();
|
||||
check_recip_exception();
|
||||
check_canonical_NaN();
|
||||
check_invsqrta();
|
||||
check_float2int_convs();
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err ? 1 : 0;
|
||||
|
415
tests/tcg/hexagon/load_align.c
Normal file
415
tests/tcg/hexagon/load_align.c
Normal file
@ -0,0 +1,415 @@
|
||||
/*
|
||||
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Test load align instructions
|
||||
*
|
||||
* Example
|
||||
* r1:0 = memh_fifo(r1+#0)
|
||||
* loads a half word from memory, shifts the destination register
|
||||
* right by one half word and inserts the loaded value into the high
|
||||
* half word of the destination.
|
||||
*
|
||||
* There are 8 addressing modes and byte and half word variants, for a
|
||||
* total of 16 instructions to test
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int err;
|
||||
|
||||
char buf[16] __attribute__((aligned(1 << 16)));
|
||||
|
||||
void init_buf(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++) {
|
||||
buf[i] = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void __check(int line, long long result, long long expect)
|
||||
{
|
||||
if (result != expect) {
|
||||
printf("ERROR at line %d: 0x%016llx != 0x%016llx\n",
|
||||
line, result, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
#define check(RES, EXP) __check(__LINE__, RES, EXP)
|
||||
|
||||
void __checkp(int line, void *p, void *expect)
|
||||
{
|
||||
if (p != expect) {
|
||||
printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _io addressing mode (addr + offset)
|
||||
*/
|
||||
#define LOAD_io(SZ, RES, ADDR, OFF) \
|
||||
__asm__( \
|
||||
"%0 = mem" #SZ "_fifo(%1+#" #OFF ")\n\t" \
|
||||
: "+r"(RES) \
|
||||
: "r"(ADDR))
|
||||
#define LOAD_io_b(RES, ADDR, OFF) \
|
||||
LOAD_io(b, RES, ADDR, OFF)
|
||||
#define LOAD_io_h(RES, ADDR, OFF) \
|
||||
LOAD_io(h, RES, ADDR, OFF)
|
||||
|
||||
#define TEST_io(NAME, SZ, SIZE, EXP1, EXP2, EXP3, EXP4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
long long result = ~0LL; \
|
||||
LOAD_io_##SZ(result, buf, 0 * (SIZE)); \
|
||||
check(result, (EXP1)); \
|
||||
LOAD_io_##SZ(result, buf, 1 * (SIZE)); \
|
||||
check(result, (EXP2)); \
|
||||
LOAD_io_##SZ(result, buf, 2 * (SIZE)); \
|
||||
check(result, (EXP3)); \
|
||||
LOAD_io_##SZ(result, buf, 3 * (SIZE)); \
|
||||
check(result, (EXP4)); \
|
||||
}
|
||||
|
||||
TEST_io(loadalignb_io, b, 1,
|
||||
0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
|
||||
0x030201ffffffffffLL, 0x04030201ffffffffLL)
|
||||
TEST_io(loadalignh_io, h, 2,
|
||||
0x0201ffffffffffffLL, 0x04030201ffffffffLL,
|
||||
0x060504030201ffffLL, 0x0807060504030201LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _ur addressing mode (index << offset + base)
|
||||
*/
|
||||
#define LOAD_ur(SZ, RES, SHIFT, IDX) \
|
||||
__asm__( \
|
||||
"%0 = mem" #SZ "_fifo(%1<<#" #SHIFT " + ##buf)\n\t" \
|
||||
: "+r"(RES) \
|
||||
: "r"(IDX))
|
||||
#define LOAD_ur_b(RES, SHIFT, IDX) \
|
||||
LOAD_ur(b, RES, SHIFT, IDX)
|
||||
#define LOAD_ur_h(RES, SHIFT, IDX) \
|
||||
LOAD_ur(h, RES, SHIFT, IDX)
|
||||
|
||||
#define TEST_ur(NAME, SZ, SHIFT, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
long long result = ~0LL; \
|
||||
LOAD_ur_##SZ(result, (SHIFT), 0); \
|
||||
check(result, (RES1)); \
|
||||
LOAD_ur_##SZ(result, (SHIFT), 1); \
|
||||
check(result, (RES2)); \
|
||||
LOAD_ur_##SZ(result, (SHIFT), 2); \
|
||||
check(result, (RES3)); \
|
||||
LOAD_ur_##SZ(result, (SHIFT), 3); \
|
||||
check(result, (RES4)); \
|
||||
}
|
||||
|
||||
TEST_ur(loadalignb_ur, b, 1,
|
||||
0x01ffffffffffffffLL, 0x0301ffffffffffffLL,
|
||||
0x050301ffffffffffLL, 0x07050301ffffffffLL)
|
||||
TEST_ur(loadalignh_ur, h, 1,
|
||||
0x0201ffffffffffffLL, 0x04030201ffffffffLL,
|
||||
0x060504030201ffffLL, 0x0807060504030201LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _ap addressing mode (addr = base)
|
||||
*/
|
||||
#define LOAD_ap(SZ, RES, PTR, ADDR) \
|
||||
__asm__( \
|
||||
"%0 = mem" #SZ "_fifo(%1 = ##" #ADDR ")\n\t" \
|
||||
: "+r"(RES), "=r"(PTR))
|
||||
#define LOAD_ap_b(RES, PTR, ADDR) \
|
||||
LOAD_ap(b, RES, PTR, ADDR)
|
||||
#define LOAD_ap_h(RES, PTR, ADDR) \
|
||||
LOAD_ap(h, RES, PTR, ADDR)
|
||||
|
||||
#define TEST_ap(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
long long result = ~0LL; \
|
||||
void *ptr; \
|
||||
LOAD_ap_##SZ(result, ptr, (buf + 0 * (SIZE))); \
|
||||
check(result, (RES1)); \
|
||||
checkp(ptr, &buf[0 * (SIZE)]); \
|
||||
LOAD_ap_##SZ(result, ptr, (buf + 1 * (SIZE))); \
|
||||
check(result, (RES2)); \
|
||||
checkp(ptr, &buf[1 * (SIZE)]); \
|
||||
LOAD_ap_##SZ(result, ptr, (buf + 2 * (SIZE))); \
|
||||
check(result, (RES3)); \
|
||||
checkp(ptr, &buf[2 * (SIZE)]); \
|
||||
LOAD_ap_##SZ(result, ptr, (buf + 3 * (SIZE))); \
|
||||
check(result, (RES4)); \
|
||||
checkp(ptr, &buf[3 * (SIZE)]); \
|
||||
}
|
||||
|
||||
TEST_ap(loadalignb_ap, b, 1,
|
||||
0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
|
||||
0x030201ffffffffffLL, 0x04030201ffffffffLL)
|
||||
TEST_ap(loadalignh_ap, h, 2,
|
||||
0x0201ffffffffffffLL, 0x04030201ffffffffLL,
|
||||
0x060504030201ffffLL, 0x0807060504030201LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _rp addressing mode (addr ++ modifer-reg)
|
||||
*/
|
||||
#define LOAD_pr(SZ, RES, PTR, INC) \
|
||||
__asm__( \
|
||||
"m0 = %2\n\t" \
|
||||
"%0 = mem" #SZ "_fifo(%1++m0)\n\t" \
|
||||
: "+r"(RES), "+r"(PTR) \
|
||||
: "r"(INC) \
|
||||
: "m0")
|
||||
#define LOAD_pr_b(RES, PTR, INC) \
|
||||
LOAD_pr(b, RES, PTR, INC)
|
||||
#define LOAD_pr_h(RES, PTR, INC) \
|
||||
LOAD_pr(h, RES, PTR, INC)
|
||||
|
||||
#define TEST_pr(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
long long result = ~0LL; \
|
||||
void *ptr = buf; \
|
||||
LOAD_pr_##SZ(result, ptr, (SIZE)); \
|
||||
check(result, (RES1)); \
|
||||
checkp(ptr, &buf[1 * (SIZE)]); \
|
||||
LOAD_pr_##SZ(result, ptr, (SIZE)); \
|
||||
check(result, (RES2)); \
|
||||
checkp(ptr, &buf[2 * (SIZE)]); \
|
||||
LOAD_pr_##SZ(result, ptr, (SIZE)); \
|
||||
check(result, (RES3)); \
|
||||
checkp(ptr, &buf[3 * (SIZE)]); \
|
||||
LOAD_pr_##SZ(result, ptr, (SIZE)); \
|
||||
check(result, (RES4)); \
|
||||
checkp(ptr, &buf[4 * (SIZE)]); \
|
||||
}
|
||||
|
||||
TEST_pr(loadalignb_pr, b, 1,
|
||||
0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
|
||||
0x030201ffffffffffLL, 0x04030201ffffffffLL)
|
||||
TEST_pr(loadalignh_pr, h, 2,
|
||||
0x0201ffffffffffffLL, 0x04030201ffffffffLL,
|
||||
0x060504030201ffffLL, 0x0807060504030201LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _pbr addressing mode (addr ++ modifer-reg:brev)
|
||||
*/
|
||||
#define LOAD_pbr(SZ, RES, PTR) \
|
||||
__asm__( \
|
||||
"r4 = #(1 << (16 - 3))\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"%0 = mem" #SZ "_fifo(%1++m0:brev)\n\t" \
|
||||
: "+r"(RES), "+r"(PTR) \
|
||||
: \
|
||||
: "r4", "m0")
|
||||
#define LOAD_pbr_b(RES, PTR) \
|
||||
LOAD_pbr(b, RES, PTR)
|
||||
#define LOAD_pbr_h(RES, PTR) \
|
||||
LOAD_pbr(h, RES, PTR)
|
||||
|
||||
#define TEST_pbr(NAME, SZ, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
long long result = ~0LL; \
|
||||
void *ptr = buf; \
|
||||
LOAD_pbr_##SZ(result, ptr); \
|
||||
check(result, (RES1)); \
|
||||
LOAD_pbr_##SZ(result, ptr); \
|
||||
check(result, (RES2)); \
|
||||
LOAD_pbr_##SZ(result, ptr); \
|
||||
check(result, (RES3)); \
|
||||
LOAD_pbr_##SZ(result, ptr); \
|
||||
check(result, (RES4)); \
|
||||
}
|
||||
|
||||
TEST_pbr(loadalignb_pbr, b,
|
||||
0x01ffffffffffffffLL, 0x0501ffffffffffffLL,
|
||||
0x030501ffffffffffLL, 0x07030501ffffffffLL)
|
||||
TEST_pbr(loadalignh_pbr, h,
|
||||
0x0201ffffffffffffLL, 0x06050201ffffffffLL,
|
||||
0x040306050201ffffLL, 0x0807040306050201LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _pi addressing mode (addr ++ inc)
|
||||
*/
|
||||
#define LOAD_pi(SZ, RES, PTR, INC) \
|
||||
__asm__( \
|
||||
"%0 = mem" #SZ "_fifo(%1++#" #INC ")\n\t" \
|
||||
: "+r"(RES), "+r"(PTR))
|
||||
#define LOAD_pi_b(RES, PTR, INC) \
|
||||
LOAD_pi(b, RES, PTR, INC)
|
||||
#define LOAD_pi_h(RES, PTR, INC) \
|
||||
LOAD_pi(h, RES, PTR, INC)
|
||||
|
||||
#define TEST_pi(NAME, SZ, INC, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
long long result = ~0LL; \
|
||||
void *ptr = buf; \
|
||||
LOAD_pi_##SZ(result, ptr, (INC)); \
|
||||
check(result, (RES1)); \
|
||||
checkp(ptr, &buf[1 * (INC)]); \
|
||||
LOAD_pi_##SZ(result, ptr, (INC)); \
|
||||
check(result, (RES2)); \
|
||||
checkp(ptr, &buf[2 * (INC)]); \
|
||||
LOAD_pi_##SZ(result, ptr, (INC)); \
|
||||
check(result, (RES3)); \
|
||||
checkp(ptr, &buf[3 * (INC)]); \
|
||||
LOAD_pi_##SZ(result, ptr, (INC)); \
|
||||
check(result, (RES4)); \
|
||||
checkp(ptr, &buf[4 * (INC)]); \
|
||||
}
|
||||
|
||||
TEST_pi(loadalignb_pi, b, 1,
|
||||
0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
|
||||
0x030201ffffffffffLL, 0x04030201ffffffffLL)
|
||||
TEST_pi(loadalignh_pi, h, 2,
|
||||
0x0201ffffffffffffLL, 0x04030201ffffffffLL,
|
||||
0x060504030201ffffLL, 0x0807060504030201LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _pci addressing mode (addr ++ inc:circ)
|
||||
*/
|
||||
#define LOAD_pci(SZ, RES, PTR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %3\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"cs0 = %2\n\t" \
|
||||
"%0 = mem" #SZ "_fifo(%1++#" #INC ":circ(m0))\n\t" \
|
||||
: "+r"(RES), "+r"(PTR) \
|
||||
: "r"(START), "r"(LEN) \
|
||||
: "r4", "m0", "cs0")
|
||||
#define LOAD_pci_b(RES, PTR, START, LEN, INC) \
|
||||
LOAD_pci(b, RES, PTR, START, LEN, INC)
|
||||
#define LOAD_pci_h(RES, PTR, START, LEN, INC) \
|
||||
LOAD_pci(h, RES, PTR, START, LEN, INC)
|
||||
|
||||
#define TEST_pci(NAME, SZ, LEN, INC, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
long long result = ~0LL; \
|
||||
void *ptr = buf; \
|
||||
LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES1)); \
|
||||
checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \
|
||||
LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES2)); \
|
||||
checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \
|
||||
LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES3)); \
|
||||
checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \
|
||||
LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES4)); \
|
||||
checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \
|
||||
}
|
||||
|
||||
TEST_pci(loadalignb_pci, b, 2, 1,
|
||||
0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
|
||||
0x010201ffffffffffLL, 0x02010201ffffffffLL)
|
||||
TEST_pci(loadalignh_pci, h, 4, 2,
|
||||
0x0201ffffffffffffLL, 0x04030201ffffffffLL,
|
||||
0x020104030201ffffLL, 0x0403020104030201LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _pcr addressing mode (addr ++ I:circ(modifier-reg))
|
||||
*/
|
||||
#define LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %2\n\t" \
|
||||
"m1 = r4\n\t" \
|
||||
"cs1 = %3\n\t" \
|
||||
"%0 = mem" #SZ "_fifo(%1++I:circ(m1))\n\t" \
|
||||
: "+r"(RES), "+r"(PTR) \
|
||||
: "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \
|
||||
"r"(START) \
|
||||
: "r4", "m1", "cs1")
|
||||
#define LOAD_pcr_b(RES, PTR, START, LEN, INC) \
|
||||
LOAD_pcr(b, RES, PTR, START, LEN, INC)
|
||||
#define LOAD_pcr_h(RES, PTR, START, LEN, INC) \
|
||||
LOAD_pcr(h, RES, PTR, START, LEN, INC)
|
||||
|
||||
#define TEST_pcr(NAME, SZ, SIZE, LEN, INC, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
long long result = ~0LL; \
|
||||
void *ptr = buf; \
|
||||
LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES1)); \
|
||||
checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \
|
||||
LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES2)); \
|
||||
checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \
|
||||
LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES3)); \
|
||||
checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \
|
||||
LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES4)); \
|
||||
checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \
|
||||
}
|
||||
|
||||
TEST_pcr(loadalignb_pcr, b, 1, 2, 1,
|
||||
0x01ffffffffffffffLL, 0x0201ffffffffffffLL,
|
||||
0x010201ffffffffffLL, 0x02010201ffffffffLL)
|
||||
TEST_pcr(loadalignh_pcr, h, 2, 4, 1,
|
||||
0x0201ffffffffffffLL, 0x04030201ffffffffLL,
|
||||
0x020104030201ffffLL, 0x0403020104030201LL)
|
||||
|
||||
int main()
|
||||
{
|
||||
init_buf();
|
||||
|
||||
test_loadalignb_io();
|
||||
test_loadalignh_io();
|
||||
|
||||
test_loadalignb_ur();
|
||||
test_loadalignh_ur();
|
||||
|
||||
test_loadalignb_ap();
|
||||
test_loadalignh_ap();
|
||||
|
||||
test_loadalignb_pr();
|
||||
test_loadalignh_pr();
|
||||
|
||||
test_loadalignb_pbr();
|
||||
test_loadalignh_pbr();
|
||||
|
||||
test_loadalignb_pi();
|
||||
test_loadalignh_pi();
|
||||
|
||||
test_loadalignb_pci();
|
||||
test_loadalignh_pci();
|
||||
|
||||
test_loadalignb_pcr();
|
||||
test_loadalignh_pcr();
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err ? 1 : 0;
|
||||
}
|
474
tests/tcg/hexagon/load_unpack.c
Normal file
474
tests/tcg/hexagon/load_unpack.c
Normal file
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Test load unpack instructions
|
||||
*
|
||||
* Example
|
||||
* r0 = memubh(r1+#0)
|
||||
* loads a half word from memory and zero-extends the 2 bytes to form a word
|
||||
*
|
||||
* For each addressing mode, there are 4 tests
|
||||
* bzw2 unsigned 2 elements
|
||||
* bsw2 signed 2 elements
|
||||
* bzw4 unsigned 4 elements
|
||||
* bsw4 signed 4 elements
|
||||
* There are 8 addressing modes, for a total of 32 instructions to test
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int err;
|
||||
|
||||
char buf[16] __attribute__((aligned(1 << 16)));
|
||||
|
||||
void init_buf(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++) {
|
||||
int sign = i % 2 == 0 ? 0x80 : 0;
|
||||
buf[i] = sign | (i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void __check(int line, long long result, long long expect)
|
||||
{
|
||||
if (result != expect) {
|
||||
printf("ERROR at line %d: 0x%08llx != 0x%08llx\n",
|
||||
line, result, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
#define check(RES, EXP) __check(__LINE__, RES, EXP)
|
||||
|
||||
void __checkp(int line, void *p, void *expect)
|
||||
{
|
||||
if (p != expect) {
|
||||
printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _io addressing mode (addr + offset)
|
||||
*/
|
||||
#define BxW_LOAD_io(SZ, RES, ADDR, OFF) \
|
||||
__asm__( \
|
||||
"%0 = mem" #SZ "(%1+#" #OFF ")\n\t" \
|
||||
: "=r"(RES) \
|
||||
: "r"(ADDR))
|
||||
#define BxW_LOAD_io_Z(RES, ADDR, OFF) \
|
||||
BxW_LOAD_io(ubh, RES, ADDR, OFF)
|
||||
#define BxW_LOAD_io_S(RES, ADDR, OFF) \
|
||||
BxW_LOAD_io(bh, RES, ADDR, OFF)
|
||||
|
||||
#define TEST_io(NAME, TYPE, SIGN, SIZE, EXT, EXP1, EXP2, EXP3, EXP4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
TYPE result; \
|
||||
init_buf(); \
|
||||
BxW_LOAD_io_##SIGN(result, buf, 0 * (SIZE)); \
|
||||
check(result, (EXP1) | (EXT)); \
|
||||
BxW_LOAD_io_##SIGN(result, buf, 1 * (SIZE)); \
|
||||
check(result, (EXP2) | (EXT)); \
|
||||
BxW_LOAD_io_##SIGN(result, buf, 2 * (SIZE)); \
|
||||
check(result, (EXP3) | (EXT)); \
|
||||
BxW_LOAD_io_##SIGN(result, buf, 3 * (SIZE)); \
|
||||
check(result, (EXP4) | (EXT)); \
|
||||
}
|
||||
|
||||
|
||||
TEST_io(loadbzw2_io, int, Z, 2, 0x00000000,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00080087)
|
||||
TEST_io(loadbsw2_io, int, S, 2, 0x0000ff00,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00080087)
|
||||
TEST_io(loadbzw4_io, long long, Z, 4, 0x0000000000000000LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
TEST_io(loadbsw4_io, long long, S, 4, 0x0000ff000000ff00LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _ur addressing mode (index << offset + base)
|
||||
*/
|
||||
#define BxW_LOAD_ur(SZ, RES, SHIFT, IDX) \
|
||||
__asm__( \
|
||||
"%0 = mem" #SZ "(%1<<#" #SHIFT " + ##buf)\n\t" \
|
||||
: "=r"(RES) \
|
||||
: "r"(IDX))
|
||||
#define BxW_LOAD_ur_Z(RES, SHIFT, IDX) \
|
||||
BxW_LOAD_ur(ubh, RES, SHIFT, IDX)
|
||||
#define BxW_LOAD_ur_S(RES, SHIFT, IDX) \
|
||||
BxW_LOAD_ur(bh, RES, SHIFT, IDX)
|
||||
|
||||
#define TEST_ur(NAME, TYPE, SIGN, SHIFT, EXT, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
TYPE result; \
|
||||
init_buf(); \
|
||||
BxW_LOAD_ur_##SIGN(result, (SHIFT), 0); \
|
||||
check(result, (RES1) | (EXT)); \
|
||||
BxW_LOAD_ur_##SIGN(result, (SHIFT), 1); \
|
||||
check(result, (RES2) | (EXT)); \
|
||||
BxW_LOAD_ur_##SIGN(result, (SHIFT), 2); \
|
||||
check(result, (RES3) | (EXT)); \
|
||||
BxW_LOAD_ur_##SIGN(result, (SHIFT), 3); \
|
||||
check(result, (RES4) | (EXT)); \
|
||||
} \
|
||||
|
||||
TEST_ur(loadbzw2_ur, int, Z, 1, 0x00000000,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00080087)
|
||||
TEST_ur(loadbsw2_ur, int, S, 1, 0x0000ff00,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00080087)
|
||||
TEST_ur(loadbzw4_ur, long long, Z, 2, 0x0000000000000000LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
TEST_ur(loadbsw4_ur, long long, S, 2, 0x0000ff000000ff00LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _ap addressing mode (addr = base)
|
||||
*/
|
||||
#define BxW_LOAD_ap(SZ, RES, PTR, ADDR) \
|
||||
__asm__( \
|
||||
"%0 = mem" #SZ "(%1 = ##" #ADDR ")\n\t" \
|
||||
: "=r"(RES), "=r"(PTR))
|
||||
#define BxW_LOAD_ap_Z(RES, PTR, ADDR) \
|
||||
BxW_LOAD_ap(ubh, RES, PTR, ADDR)
|
||||
#define BxW_LOAD_ap_S(RES, PTR, ADDR) \
|
||||
BxW_LOAD_ap(bh, RES, PTR, ADDR)
|
||||
|
||||
#define TEST_ap(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
TYPE result; \
|
||||
void *ptr; \
|
||||
init_buf(); \
|
||||
BxW_LOAD_ap_##SIGN(result, ptr, (buf + 0 * (SIZE))); \
|
||||
check(result, (RES1) | (EXT)); \
|
||||
checkp(ptr, &buf[0 * (SIZE)]); \
|
||||
BxW_LOAD_ap_##SIGN(result, ptr, (buf + 1 * (SIZE))); \
|
||||
check(result, (RES2) | (EXT)); \
|
||||
checkp(ptr, &buf[1 * (SIZE)]); \
|
||||
BxW_LOAD_ap_##SIGN(result, ptr, (buf + 2 * (SIZE))); \
|
||||
check(result, (RES3) | (EXT)); \
|
||||
checkp(ptr, &buf[2 * (SIZE)]); \
|
||||
BxW_LOAD_ap_##SIGN(result, ptr, (buf + 3 * (SIZE))); \
|
||||
check(result, (RES4) | (EXT)); \
|
||||
checkp(ptr, &buf[3 * (SIZE)]); \
|
||||
}
|
||||
|
||||
TEST_ap(loadbzw2_ap, int, Z, 2, 0x00000000,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00080087)
|
||||
TEST_ap(loadbsw2_ap, int, S, 2, 0x0000ff00,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00080087)
|
||||
TEST_ap(loadbzw4_ap, long long, Z, 4, 0x0000000000000000LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
TEST_ap(loadbsw4_ap, long long, S, 4, 0x0000ff000000ff00LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _rp addressing mode (addr ++ modifer-reg)
|
||||
*/
|
||||
#define BxW_LOAD_pr(SZ, RES, PTR, INC) \
|
||||
__asm__( \
|
||||
"m0 = %2\n\t" \
|
||||
"%0 = mem" #SZ "(%1++m0)\n\t" \
|
||||
: "=r"(RES), "+r"(PTR) \
|
||||
: "r"(INC) \
|
||||
: "m0")
|
||||
#define BxW_LOAD_pr_Z(RES, PTR, INC) \
|
||||
BxW_LOAD_pr(ubh, RES, PTR, INC)
|
||||
#define BxW_LOAD_pr_S(RES, PTR, INC) \
|
||||
BxW_LOAD_pr(bh, RES, PTR, INC)
|
||||
|
||||
#define TEST_pr(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
TYPE result; \
|
||||
void *ptr = buf; \
|
||||
init_buf(); \
|
||||
BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
|
||||
check(result, (RES1) | (EXT)); \
|
||||
checkp(ptr, &buf[1 * (SIZE)]); \
|
||||
BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
|
||||
check(result, (RES2) | (EXT)); \
|
||||
checkp(ptr, &buf[2 * (SIZE)]); \
|
||||
BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
|
||||
check(result, (RES3) | (EXT)); \
|
||||
checkp(ptr, &buf[3 * (SIZE)]); \
|
||||
BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
|
||||
check(result, (RES4) | (EXT)); \
|
||||
checkp(ptr, &buf[4 * (SIZE)]); \
|
||||
}
|
||||
|
||||
TEST_pr(loadbzw2_pr, int, Z, 2, 0x00000000,
|
||||
0x00020081, 0x0040083, 0x00060085, 0x00080087)
|
||||
TEST_pr(loadbsw2_pr, int, S, 2, 0x0000ff00,
|
||||
0x00020081, 0x0040083, 0x00060085, 0x00080087)
|
||||
TEST_pr(loadbzw4_pr, long long, Z, 4, 0x0000000000000000LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
TEST_pr(loadbsw4_pr, long long, S, 4, 0x0000ff000000ff00LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _pbr addressing mode (addr ++ modifer-reg:brev)
|
||||
*/
|
||||
#define BxW_LOAD_pbr(SZ, RES, PTR) \
|
||||
__asm__( \
|
||||
"r4 = #(1 << (16 - 3))\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"%0 = mem" #SZ "(%1++m0:brev)\n\t" \
|
||||
: "=r"(RES), "+r"(PTR) \
|
||||
: \
|
||||
: "r4", "m0")
|
||||
#define BxW_LOAD_pbr_Z(RES, PTR) \
|
||||
BxW_LOAD_pbr(ubh, RES, PTR)
|
||||
#define BxW_LOAD_pbr_S(RES, PTR) \
|
||||
BxW_LOAD_pbr(bh, RES, PTR)
|
||||
|
||||
#define TEST_pbr(NAME, TYPE, SIGN, EXT, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
TYPE result; \
|
||||
void *ptr = buf; \
|
||||
init_buf(); \
|
||||
BxW_LOAD_pbr_##SIGN(result, ptr); \
|
||||
check(result, (RES1) | (EXT)); \
|
||||
BxW_LOAD_pbr_##SIGN(result, ptr); \
|
||||
check(result, (RES2) | (EXT)); \
|
||||
BxW_LOAD_pbr_##SIGN(result, ptr); \
|
||||
check(result, (RES3) | (EXT)); \
|
||||
BxW_LOAD_pbr_##SIGN(result, ptr); \
|
||||
check(result, (RES4) | (EXT)); \
|
||||
}
|
||||
|
||||
TEST_pbr(loadbzw2_pbr, int, Z, 0x00000000,
|
||||
0x00020081, 0x00060085, 0x00040083, 0x00080087)
|
||||
TEST_pbr(loadbsw2_pbr, int, S, 0x0000ff00,
|
||||
0x00020081, 0x00060085, 0x00040083, 0x00080087)
|
||||
TEST_pbr(loadbzw4_pbr, long long, Z, 0x0000000000000000LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x0006008500040083LL, 0x000a008900080087LL)
|
||||
TEST_pbr(loadbsw4_pbr, long long, S, 0x0000ff000000ff00LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x0006008500040083LL, 0x000a008900080087LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _pi addressing mode (addr ++ inc)
|
||||
*/
|
||||
#define BxW_LOAD_pi(SZ, RES, PTR, INC) \
|
||||
__asm__( \
|
||||
"%0 = mem" #SZ "(%1++#" #INC ")\n\t" \
|
||||
: "=r"(RES), "+r"(PTR))
|
||||
#define BxW_LOAD_pi_Z(RES, PTR, INC) \
|
||||
BxW_LOAD_pi(ubh, RES, PTR, INC)
|
||||
#define BxW_LOAD_pi_S(RES, PTR, INC) \
|
||||
BxW_LOAD_pi(bh, RES, PTR, INC)
|
||||
|
||||
#define TEST_pi(NAME, TYPE, SIGN, INC, EXT, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
TYPE result; \
|
||||
void *ptr = buf; \
|
||||
init_buf(); \
|
||||
BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
|
||||
check(result, (RES1) | (EXT)); \
|
||||
checkp(ptr, &buf[1 * (INC)]); \
|
||||
BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
|
||||
check(result, (RES2) | (EXT)); \
|
||||
checkp(ptr, &buf[2 * (INC)]); \
|
||||
BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
|
||||
check(result, (RES3) | (EXT)); \
|
||||
checkp(ptr, &buf[3 * (INC)]); \
|
||||
BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
|
||||
check(result, (RES4) | (EXT)); \
|
||||
checkp(ptr, &buf[4 * (INC)]); \
|
||||
}
|
||||
|
||||
TEST_pi(loadbzw2_pi, int, Z, 2, 0x00000000,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00080087)
|
||||
TEST_pi(loadbsw2_pi, int, S, 2, 0x0000ff00,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00080087)
|
||||
TEST_pi(loadbzw4_pi, long long, Z, 4, 0x0000000000000000LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
TEST_pi(loadbsw4_pi, long long, S, 4, 0x0000ff000000ff00LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x000c008b000a0089LL, 0x0010008f000e008dLL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _pci addressing mode (addr ++ inc:circ)
|
||||
*/
|
||||
#define BxW_LOAD_pci(SZ, RES, PTR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %3\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"cs0 = %2\n\t" \
|
||||
"%0 = mem" #SZ "(%1++#" #INC ":circ(m0))\n\t" \
|
||||
: "=r"(RES), "+r"(PTR) \
|
||||
: "r"(START), "r"(LEN) \
|
||||
: "r4", "m0", "cs0")
|
||||
#define BxW_LOAD_pci_Z(RES, PTR, START, LEN, INC) \
|
||||
BxW_LOAD_pci(ubh, RES, PTR, START, LEN, INC)
|
||||
#define BxW_LOAD_pci_S(RES, PTR, START, LEN, INC) \
|
||||
BxW_LOAD_pci(bh, RES, PTR, START, LEN, INC)
|
||||
|
||||
#define TEST_pci(NAME, TYPE, SIGN, LEN, INC, EXT, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
TYPE result; \
|
||||
void *ptr = buf; \
|
||||
init_buf(); \
|
||||
BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES1) | (EXT)); \
|
||||
checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \
|
||||
BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES2) | (EXT)); \
|
||||
checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \
|
||||
BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES3) | (EXT)); \
|
||||
checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \
|
||||
BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES4) | (EXT)); \
|
||||
checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \
|
||||
}
|
||||
|
||||
TEST_pci(loadbzw2_pci, int, Z, 6, 2, 0x00000000,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00020081)
|
||||
TEST_pci(loadbsw2_pci, int, S, 6, 2, 0x0000ff00,
|
||||
0x00020081, 0x00040083, 0x00060085, 0x00020081)
|
||||
TEST_pci(loadbzw4_pci, long long, Z, 8, 4, 0x0000000000000000LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL)
|
||||
TEST_pci(loadbsw4_pci, long long, S, 8, 4, 0x0000ff000000ff00LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* _pcr addressing mode (addr ++ I:circ(modifier-reg))
|
||||
*/
|
||||
#define BxW_LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %2\n\t" \
|
||||
"m1 = r4\n\t" \
|
||||
"cs1 = %3\n\t" \
|
||||
"%0 = mem" #SZ "(%1++I:circ(m1))\n\t" \
|
||||
: "=r"(RES), "+r"(PTR) \
|
||||
: "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \
|
||||
"r"(START) \
|
||||
: "r4", "m1", "cs1")
|
||||
#define BxW_LOAD_pcr_Z(RES, PTR, START, LEN, INC) \
|
||||
BxW_LOAD_pcr(ubh, RES, PTR, START, LEN, INC)
|
||||
#define BxW_LOAD_pcr_S(RES, PTR, START, LEN, INC) \
|
||||
BxW_LOAD_pcr(bh, RES, PTR, START, LEN, INC)
|
||||
|
||||
#define TEST_pcr(NAME, TYPE, SIGN, SIZE, LEN, INC, \
|
||||
EXT, RES1, RES2, RES3, RES4) \
|
||||
void test_##NAME(void) \
|
||||
{ \
|
||||
TYPE result; \
|
||||
void *ptr = buf; \
|
||||
init_buf(); \
|
||||
BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES1) | (EXT)); \
|
||||
checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \
|
||||
BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES2) | (EXT)); \
|
||||
checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \
|
||||
BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES3) | (EXT)); \
|
||||
checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \
|
||||
BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
|
||||
check(result, (RES4) | (EXT)); \
|
||||
checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \
|
||||
}
|
||||
|
||||
TEST_pcr(loadbzw2_pcr, int, Z, 2, 8, 2, 0x00000000,
|
||||
0x00020081, 0x00060085, 0x00020081, 0x00060085)
|
||||
TEST_pcr(loadbsw2_pcr, int, S, 2, 8, 2, 0x0000ff00,
|
||||
0x00020081, 0x00060085, 0x00020081, 0x00060085)
|
||||
TEST_pcr(loadbzw4_pcr, long long, Z, 4, 8, 1, 0x0000000000000000LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL)
|
||||
TEST_pcr(loadbsw4_pcr, long long, S, 4, 8, 1, 0x0000ff000000ff00LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL,
|
||||
0x0004008300020081LL, 0x0008008700060085LL)
|
||||
|
||||
int main()
|
||||
{
|
||||
test_loadbzw2_io();
|
||||
test_loadbsw2_io();
|
||||
test_loadbzw4_io();
|
||||
test_loadbsw4_io();
|
||||
|
||||
test_loadbzw2_ur();
|
||||
test_loadbsw2_ur();
|
||||
test_loadbzw4_ur();
|
||||
test_loadbsw4_ur();
|
||||
|
||||
test_loadbzw2_ap();
|
||||
test_loadbsw2_ap();
|
||||
test_loadbzw4_ap();
|
||||
test_loadbsw4_ap();
|
||||
|
||||
test_loadbzw2_pr();
|
||||
test_loadbsw2_pr();
|
||||
test_loadbzw4_pr();
|
||||
test_loadbsw4_pr();
|
||||
|
||||
test_loadbzw2_pbr();
|
||||
test_loadbsw2_pbr();
|
||||
test_loadbzw4_pbr();
|
||||
test_loadbsw4_pbr();
|
||||
|
||||
test_loadbzw2_pi();
|
||||
test_loadbsw2_pi();
|
||||
test_loadbzw4_pi();
|
||||
test_loadbsw4_pi();
|
||||
|
||||
test_loadbzw2_pci();
|
||||
test_loadbsw2_pci();
|
||||
test_loadbzw4_pci();
|
||||
test_loadbsw4_pci();
|
||||
|
||||
test_loadbzw2_pcr();
|
||||
test_loadbsw2_pcr();
|
||||
test_loadbzw4_pcr();
|
||||
test_loadbsw4_pcr();
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err ? 1 : 0;
|
||||
}
|
@ -231,6 +231,14 @@ static void check(int val, int expect)
|
||||
}
|
||||
}
|
||||
|
||||
static void check64(long long val, long long expect)
|
||||
{
|
||||
if (val != expect) {
|
||||
printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t init[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
uint32_t array[10];
|
||||
|
||||
@ -264,8 +272,36 @@ static long long creg_pair(int x, int y)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static long long decbin(long long x, long long y, int *pred)
|
||||
{
|
||||
long long retval;
|
||||
asm ("%0 = decbin(%2, %3)\n\t"
|
||||
"%1 = p0\n\t"
|
||||
: "=r"(retval), "=r"(*pred)
|
||||
: "r"(x), "r"(y));
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Check that predicates are auto-and'ed in a packet */
|
||||
static int auto_and(void)
|
||||
{
|
||||
int retval;
|
||||
asm ("r5 = #1\n\t"
|
||||
"{\n\t"
|
||||
" p0 = cmp.eq(r1, #1)\n\t"
|
||||
" p0 = cmp.eq(r1, #2)\n\t"
|
||||
"}\n\t"
|
||||
"%0 = p0\n\t"
|
||||
: "=r"(retval)
|
||||
:
|
||||
: "r5", "p0");
|
||||
return retval;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
long long res64;
|
||||
int pred;
|
||||
|
||||
memcpy(array, init, sizeof(array));
|
||||
S4_storerhnew_rr(array, 4, 0xffff);
|
||||
@ -375,6 +411,17 @@ int main()
|
||||
res = test_clrtnew(2, 7);
|
||||
check(res, 7);
|
||||
|
||||
res64 = decbin(0xf0f1f2f3f4f5f6f7LL, 0x7f6f5f4f3f2f1f0fLL, &pred);
|
||||
check64(res64, 0x357980003700010cLL);
|
||||
check(pred, 0);
|
||||
|
||||
res64 = decbin(0xfLL, 0x1bLL, &pred);
|
||||
check64(res64, 0x78000100LL);
|
||||
check(pred, 1);
|
||||
|
||||
res = auto_and();
|
||||
check(res, 0);
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err;
|
||||
}
|
||||
|
282
tests/tcg/hexagon/multi_result.c
Normal file
282
tests/tcg/hexagon/multi_result.c
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int sfrecipa(int Rs, int Rt, int *pred_result)
|
||||
{
|
||||
int result;
|
||||
int predval;
|
||||
|
||||
asm volatile("%0,p0 = sfrecipa(%2, %3)\n\t"
|
||||
"%1 = p0\n\t"
|
||||
: "+r"(result), "=r"(predval)
|
||||
: "r"(Rs), "r"(Rt)
|
||||
: "p0");
|
||||
*pred_result = predval;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int sfinvsqrta(int Rs, int *pred_result)
|
||||
{
|
||||
int result;
|
||||
int predval;
|
||||
|
||||
asm volatile("%0,p0 = sfinvsqrta(%2)\n\t"
|
||||
"%1 = p0\n\t"
|
||||
: "+r"(result), "=r"(predval)
|
||||
: "r"(Rs)
|
||||
: "p0");
|
||||
*pred_result = predval;
|
||||
return result;
|
||||
}
|
||||
|
||||
static long long vacsh(long long Rxx, long long Rss, long long Rtt,
|
||||
int *pred_result, int *ovf_result)
|
||||
{
|
||||
long long result = Rxx;
|
||||
int predval;
|
||||
int usr;
|
||||
|
||||
/*
|
||||
* This instruction can set bit 0 (OVF/overflow) in usr
|
||||
* Clear the bit first, then return that bit to the caller
|
||||
*/
|
||||
asm volatile("r2 = usr\n\t"
|
||||
"r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */
|
||||
"usr = r2\n\t"
|
||||
"%0,p0 = vacsh(%3, %4)\n\t"
|
||||
"%1 = p0\n\t"
|
||||
"%2 = usr\n\t"
|
||||
: "+r"(result), "=r"(predval), "=r"(usr)
|
||||
: "r"(Rss), "r"(Rtt)
|
||||
: "r2", "p0", "usr");
|
||||
*pred_result = predval;
|
||||
*ovf_result = (usr & 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
static long long vminub(long long Rtt, long long Rss,
|
||||
int *pred_result)
|
||||
{
|
||||
long long result;
|
||||
int predval;
|
||||
|
||||
asm volatile("%0,p0 = vminub(%2, %3)\n\t"
|
||||
"%1 = p0\n\t"
|
||||
: "=r"(result), "=r"(predval)
|
||||
: "r"(Rtt), "r"(Rss)
|
||||
: "p0");
|
||||
*pred_result = predval;
|
||||
return result;
|
||||
}
|
||||
|
||||
static long long add_carry(long long Rss, long long Rtt,
|
||||
int pred_in, int *pred_result)
|
||||
{
|
||||
long long result;
|
||||
int predval = pred_in;
|
||||
|
||||
asm volatile("p0 = %1\n\t"
|
||||
"%0 = add(%2, %3, p0):carry\n\t"
|
||||
"%1 = p0\n\t"
|
||||
: "=r"(result), "+r"(predval)
|
||||
: "r"(Rss), "r"(Rtt)
|
||||
: "p0");
|
||||
*pred_result = predval;
|
||||
return result;
|
||||
}
|
||||
|
||||
static long long sub_carry(long long Rss, long long Rtt,
|
||||
int pred_in, int *pred_result)
|
||||
{
|
||||
long long result;
|
||||
int predval = pred_in;
|
||||
|
||||
asm volatile("p0 = !cmp.eq(%1, #0)\n\t"
|
||||
"%0 = sub(%2, %3, p0):carry\n\t"
|
||||
"%1 = p0\n\t"
|
||||
: "=r"(result), "+r"(predval)
|
||||
: "r"(Rss), "r"(Rtt)
|
||||
: "p0");
|
||||
*pred_result = predval;
|
||||
return result;
|
||||
}
|
||||
|
||||
int err;
|
||||
|
||||
static void check_ll(long long val, long long expect)
|
||||
{
|
||||
if (val != expect) {
|
||||
printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
static void check(int val, int expect)
|
||||
{
|
||||
if (val != expect) {
|
||||
printf("ERROR: 0x%08x != 0x%08x\n", val, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_p(int val, int expect)
|
||||
{
|
||||
if (val != expect) {
|
||||
printf("ERROR: 0x%02x != 0x%02x\n", val, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_sfrecipa()
|
||||
{
|
||||
int res;
|
||||
int pred_result;
|
||||
|
||||
res = sfrecipa(0x04030201, 0x05060708, &pred_result);
|
||||
check(res, 0x59f38001);
|
||||
check_p(pred_result, 0x00);
|
||||
}
|
||||
|
||||
static void test_sfinvsqrta()
|
||||
{
|
||||
int res;
|
||||
int pred_result;
|
||||
|
||||
res = sfinvsqrta(0x04030201, &pred_result);
|
||||
check(res, 0x4d330000);
|
||||
check_p(pred_result, 0xe0);
|
||||
|
||||
res = sfinvsqrta(0x0, &pred_result);
|
||||
check(res, 0x3f800000);
|
||||
check_p(pred_result, 0x0);
|
||||
}
|
||||
|
||||
static void test_vacsh()
|
||||
{
|
||||
long long res64;
|
||||
int pred_result;
|
||||
int ovf_result;
|
||||
|
||||
res64 = vacsh(0x0004000300020001LL,
|
||||
0x0001000200030004LL,
|
||||
0x0000000000000000LL, &pred_result, &ovf_result);
|
||||
check_ll(res64, 0x0004000300030004LL);
|
||||
check_p(pred_result, 0xf0);
|
||||
check(ovf_result, 0);
|
||||
|
||||
res64 = vacsh(0x0004000300020001LL,
|
||||
0x0001000200030004LL,
|
||||
0x000affff000d0000LL, &pred_result, &ovf_result);
|
||||
check_ll(res64, 0x000e0003000f0004LL);
|
||||
check_p(pred_result, 0xcc);
|
||||
check(ovf_result, 0);
|
||||
|
||||
res64 = vacsh(0x00047fff00020001LL,
|
||||
0x00017fff00030004LL,
|
||||
0x000a0fff000d0000LL, &pred_result, &ovf_result);
|
||||
check_ll(res64, 0x000e7fff000f0004LL);
|
||||
check_p(pred_result, 0xfc);
|
||||
check(ovf_result, 1);
|
||||
|
||||
res64 = vacsh(0x0004000300020001LL,
|
||||
0x0001000200030009LL,
|
||||
0x000affff000d0001LL, &pred_result, &ovf_result);
|
||||
check_ll(res64, 0x000e0003000f0008LL);
|
||||
check_p(pred_result, 0xcc);
|
||||
check(ovf_result, 0);
|
||||
}
|
||||
|
||||
static void test_vminub()
|
||||
{
|
||||
long long res64;
|
||||
int pred_result;
|
||||
|
||||
res64 = vminub(0x0807060504030201LL,
|
||||
0x0102030405060708LL,
|
||||
&pred_result);
|
||||
check_ll(res64, 0x0102030404030201LL);
|
||||
check_p(pred_result, 0xf0);
|
||||
|
||||
res64 = vminub(0x0802060405030701LL,
|
||||
0x0107030504060208LL,
|
||||
&pred_result);
|
||||
check_ll(res64, 0x0102030404030201LL);
|
||||
check_p(pred_result, 0xaa);
|
||||
}
|
||||
|
||||
static void test_add_carry()
|
||||
{
|
||||
long long res64;
|
||||
int pred_result;
|
||||
|
||||
res64 = add_carry(0x0000000000000000LL,
|
||||
0xffffffffffffffffLL,
|
||||
1, &pred_result);
|
||||
check_ll(res64, 0x0000000000000000LL);
|
||||
check_p(pred_result, 0xff);
|
||||
|
||||
res64 = add_carry(0x0000000100000000LL,
|
||||
0xffffffffffffffffLL,
|
||||
0, &pred_result);
|
||||
check_ll(res64, 0x00000000ffffffffLL);
|
||||
check_p(pred_result, 0xff);
|
||||
|
||||
res64 = add_carry(0x0000000100000000LL,
|
||||
0xffffffffffffffffLL,
|
||||
0, &pred_result);
|
||||
check_ll(res64, 0x00000000ffffffffLL);
|
||||
check_p(pred_result, 0xff);
|
||||
}
|
||||
|
||||
static void test_sub_carry()
|
||||
{
|
||||
long long res64;
|
||||
int pred_result;
|
||||
|
||||
res64 = sub_carry(0x0000000000000000LL,
|
||||
0x0000000000000000LL,
|
||||
1, &pred_result);
|
||||
check_ll(res64, 0x0000000000000000LL);
|
||||
check_p(pred_result, 0xff);
|
||||
|
||||
res64 = sub_carry(0x0000000100000000LL,
|
||||
0x0000000000000000LL,
|
||||
0, &pred_result);
|
||||
check_ll(res64, 0x00000000ffffffffLL);
|
||||
check_p(pred_result, 0xff);
|
||||
|
||||
res64 = sub_carry(0x0000000100000000LL,
|
||||
0x0000000000000000LL,
|
||||
0, &pred_result);
|
||||
check_ll(res64, 0x00000000ffffffffLL);
|
||||
check_p(pred_result, 0xff);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_sfrecipa();
|
||||
test_sfinvsqrta();
|
||||
test_vacsh();
|
||||
test_vminub();
|
||||
test_add_carry();
|
||||
test_sub_carry();
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err;
|
||||
}
|
Loading…
Reference in New Issue
Block a user