321 changes: 320 additions & 1 deletion target/hexagon/imported/mmvec/ext.idef

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions target/hexagon/internal.h
Expand Up @@ -33,6 +33,8 @@

int hexagon_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int hexagon_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
int hexagon_hvx_gdb_read_register(CPUHexagonState *env, GByteArray *mem_buf, int n);
int hexagon_hvx_gdb_write_register(CPUHexagonState *env, uint8_t *mem_buf, int n);

void hexagon_debug_vreg(CPUHexagonState *env, int regnum);
void hexagon_debug_qreg(CPUHexagonState *env, int regnum);
Expand Down
57 changes: 24 additions & 33 deletions target/hexagon/macros.h
Expand Up @@ -44,8 +44,17 @@
reg_field_info[FIELD].offset)

#define SET_USR_FIELD(FIELD, VAL) \
fINSERT_BITS(env->new_value[HEX_REG_USR], reg_field_info[FIELD].width, \
reg_field_info[FIELD].offset, (VAL))
do { \
if (pkt_need_commit) { \
fINSERT_BITS(env->new_value_usr, \
reg_field_info[FIELD].width, \
reg_field_info[FIELD].offset, (VAL)); \
} else { \
fINSERT_BITS(env->gpr[HEX_REG_USR], \
reg_field_info[FIELD].width, \
reg_field_info[FIELD].offset, (VAL)); \
} \
} while (0)
#endif

#ifdef QEMU_GENERATE
Expand Down Expand Up @@ -164,14 +173,14 @@
#define MEM_STORE8(VA, DATA, SLOT) \
MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, SLOT)
#else
#define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, slot, VA))
#define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, slot, VA))
#define MEM_LOAD2s(VA) ((int16_t)mem_load2(env, slot, VA))
#define MEM_LOAD2u(VA) ((uint16_t)mem_load2(env, slot, VA))
#define MEM_LOAD4s(VA) ((int32_t)mem_load4(env, slot, VA))
#define MEM_LOAD4u(VA) ((uint32_t)mem_load4(env, slot, VA))
#define MEM_LOAD8s(VA) ((int64_t)mem_load8(env, slot, VA))
#define MEM_LOAD8u(VA) ((uint64_t)mem_load8(env, slot, VA))
#define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, pkt_has_store_s1, slot, VA))
#define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, pkt_has_store_s1, slot, VA))
#define MEM_LOAD2s(VA) ((int16_t)mem_load2(env, pkt_has_store_s1, slot, VA))
#define MEM_LOAD2u(VA) ((uint16_t)mem_load2(env, pkt_has_store_s1, slot, VA))
#define MEM_LOAD4s(VA) ((int32_t)mem_load4(env, pkt_has_store_s1, slot, VA))
#define MEM_LOAD4u(VA) ((uint32_t)mem_load4(env, pkt_has_store_s1, slot, VA))
#define MEM_LOAD8s(VA) ((int64_t)mem_load8(env, pkt_has_store_s1, slot, VA))
#define MEM_LOAD8u(VA) ((uint64_t)mem_load8(env, pkt_has_store_s1, slot, VA))

#define MEM_STORE1(VA, DATA, SLOT) log_store32(env, VA, DATA, 1, SLOT)
#define MEM_STORE2(VA, DATA, SLOT) log_store32(env, VA, DATA, 2, SLOT)
Expand Down Expand Up @@ -227,12 +236,8 @@ static inline void gen_cancel(uint32_t slot)

#ifdef QEMU_GENERATE
#define fLSBNEW(PVAL) tcg_gen_andi_tl(LSB, (PVAL), 1)
#define fLSBNEW0 tcg_gen_andi_tl(LSB, hex_new_pred_value[0], 1)
#define fLSBNEW1 tcg_gen_andi_tl(LSB, hex_new_pred_value[1], 1)
#else
#define fLSBNEW(PVAL) ((PVAL) & 1)
#define fLSBNEW0 (env->new_pred_value[0] & 1)
#define fLSBNEW1 (env->new_pred_value[1] & 1)
#endif

#ifdef QEMU_GENERATE
Expand Down Expand Up @@ -347,10 +352,6 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)

#define fREAD_LR() (env->gpr[HEX_REG_LR])

#define fWRITE_LR(A) log_reg_write(env, HEX_REG_LR, A)
#define fWRITE_FP(A) log_reg_write(env, HEX_REG_FP, A)
#define fWRITE_SP(A) log_reg_write(env, HEX_REG_SP, A)

#define fREAD_SP() (env->gpr[HEX_REG_SP])
#define fREAD_LC0 (env->gpr[HEX_REG_LC0])
#define fREAD_LC1 (env->gpr[HEX_REG_LC1])
Expand All @@ -375,24 +376,10 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
#define fBRANCH(LOC, TYPE) fWRITE_NPC(LOC)
#define fJUMPR(REGNO, TARGET, TYPE) fBRANCH(TARGET, COF_TYPE_JUMPR)
#define fHINTJR(TARGET) { /* Not modelled in qemu */}
#define fWRITE_LOOP_REGS0(START, COUNT) \
do { \
log_reg_write(env, HEX_REG_LC0, COUNT); \
log_reg_write(env, HEX_REG_SA0, START); \
} while (0)
#define fWRITE_LOOP_REGS1(START, COUNT) \
do { \
log_reg_write(env, HEX_REG_LC1, COUNT); \
log_reg_write(env, HEX_REG_SA1, START);\
} while (0)

#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))
#define fWRITE_P0(VAL) log_pred_write(env, 0, VAL)
#define fWRITE_P1(VAL) log_pred_write(env, 1, VAL)
#define fWRITE_P2(VAL) log_pred_write(env, 2, VAL)
#define fWRITE_P3(VAL) log_pred_write(env, 3, VAL)
#define fPART1(WORK) if (part1) { WORK; return; }
#define fCAST4u(A) ((uint32_t)(A))
#define fCAST4s(A) ((int32_t)(A))
Expand Down Expand Up @@ -661,7 +648,11 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
reg_field_info[FIELD].offset)

#ifdef QEMU_GENERATE
#define fDCZEROA(REG) tcg_gen_mov_tl(hex_dczero_addr, (REG))
#define fDCZEROA(REG) \
do { \
ctx->dczero_addr = tcg_temp_new(); \
tcg_gen_mov_tl(ctx->dczero_addr, (REG)); \
} while (0)
#endif

#define fBRANCH_SPECULATE_STALL(DOTNEWVAL, JUMP_COND, SPEC_DIR, HINTBITNUM, \
Expand Down
9 changes: 8 additions & 1 deletion target/hexagon/mmvec/macros.h
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -346,4 +346,11 @@
#define fUARCH_NOTE_PUMP_2X()

#define IV1DEAD()

#define fGET10BIT(COE, VAL, POS) \
do { \
COE = (sextract32(VAL, 24 + 2 * POS, 2) << 8) | \
extract32(VAL, POS * 8, 8); \
} while (0);

#endif
154 changes: 104 additions & 50 deletions target/hexagon/op_helper.c
Expand Up @@ -52,38 +52,6 @@ G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
do_raise_exception_err(env, excp, 0);
}

void log_reg_write(CPUHexagonState *env, int rnum,
target_ulong val)
{
HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
rnum, val, val);
if (val == env->gpr[rnum]) {
HEX_DEBUG_LOG(" NO CHANGE");
}
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;
}
}

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",
pnum, val, val);

/* Multiple writes to the same preg are and'ed together */
if (env->pred_written & (1 << pnum)) {
env->new_pred_value[pnum] &= val & 0xff;
} else {
env->new_pred_value[pnum] = val & 0xff;
env->pred_written |= 1 << pnum;
}
}

void log_store32(CPUHexagonState *env, target_ulong addr,
target_ulong val, int width, int slot)
{
Expand Down Expand Up @@ -235,14 +203,14 @@ static void print_store(CPUHexagonState *env, int slot)
}

/* This function is a handy place to set a breakpoint */
void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
void HELPER(debug_commit_end)(CPUHexagonState *env, uint32_t this_PC,
int pred_written, int has_st0, int has_st1)
{
bool reg_printed = false;
bool pred_printed = false;
int i;

HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n",
env->this_PC);
HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n", this_PC);
HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);

for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
Expand All @@ -252,18 +220,18 @@ void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
reg_printed = true;
}
HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
i, env->new_value[i], env->new_value[i]);
i, env->gpr[i], env->gpr[i]);
}
}

for (i = 0; i < NUM_PREGS; i++) {
if (env->pred_written & (1 << i)) {
if (pred_written & (1 << i)) {
if (!pred_printed) {
HEX_DEBUG_LOG("Predicates written\n");
pred_printed = true;
}
HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
i, env->new_pred_value[i]);
i, env->pred[i]);
}
}

Expand Down Expand Up @@ -384,7 +352,8 @@ uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
}

int64_t HELPER(vacsh_val)(CPUHexagonState *env,
int64_t RxxV, int64_t RssV, int64_t RttV)
int64_t RxxV, int64_t RssV, int64_t RttV,
uint32_t pkt_need_commit)
{
for (int i = 0; i < 4; i++) {
int xv = sextract64(RxxV, i * 16, 16);
Expand Down Expand Up @@ -416,6 +385,87 @@ int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
return PeV;
}

int64_t HELPER(cabacdecbin_val)(int64_t RssV, int64_t RttV)
{
int64_t RddV = 0;
size4u_t state;
size4u_t valMPS;
size4u_t bitpos;
size4u_t range;
size4u_t offset;
size4u_t rLPS;
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);
}
/* 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));
}
return RddV;
}

int32_t HELPER(cabacdecbin_pred)(int64_t RssV, int64_t RttV)
{
int32_t p0 = 0;
size4u_t state;
size4u_t valMPS;
size4u_t bitpos;
size4u_t range;
size4u_t offset;
size4u_t rLPS;
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) {
p0 = valMPS;

}
/* least probable region */
else {
p0 = valMPS ^ 1;
}
return p0;
}

static void probe_store(CPUHexagonState *env, int slot, int mmu_idx,
bool is_predicated)
{
Expand Down Expand Up @@ -516,41 +566,45 @@ void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask)
* If the load is in slot 0 and there is a store in slot1 (that
* wasn't cancelled), we have to do the store first.
*/
static void check_noshuf(CPUHexagonState *env, uint32_t slot,
target_ulong vaddr, int size)
static void check_noshuf(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr, int size)
{
if (slot == 0 && env->pkt_has_store_s1 &&
if (slot == 0 && pkt_has_store_s1 &&
((env->slot_cancelled & (1 << 1)) == 0)) {
HELPER(probe_noshuf_load)(env, vaddr, size, MMU_USER_IDX);
HELPER(commit_store)(env, 1);
}
}

uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
uint8_t mem_load1(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr)
{
uintptr_t ra = GETPC();
check_noshuf(env, slot, vaddr, 1);
check_noshuf(env, pkt_has_store_s1, slot, vaddr, 1);
return cpu_ldub_data_ra(env, vaddr, ra);
}

uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
uint16_t mem_load2(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr)
{
uintptr_t ra = GETPC();
check_noshuf(env, slot, vaddr, 2);
check_noshuf(env, pkt_has_store_s1, slot, vaddr, 2);
return cpu_lduw_data_ra(env, vaddr, ra);
}

uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
uint32_t mem_load4(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr)
{
uintptr_t ra = GETPC();
check_noshuf(env, slot, vaddr, 4);
check_noshuf(env, pkt_has_store_s1, slot, vaddr, 4);
return cpu_ldl_data_ra(env, vaddr, ra);
}

uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr)
uint64_t mem_load8(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr)
{
uintptr_t ra = GETPC();
check_noshuf(env, slot, vaddr, 8);
check_noshuf(env, pkt_has_store_s1, slot, vaddr, 8);
return cpu_ldq_data_ra(env, vaddr, ra);
}

Expand Down
16 changes: 8 additions & 8 deletions target/hexagon/op_helper.h
Expand Up @@ -19,15 +19,15 @@
#define HEXAGON_OP_HELPER_H

/* Misc functions */
void write_new_pc(CPUHexagonState *env, bool pkt_has_multi_cof, target_ulong addr);
uint8_t mem_load1(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr);
uint16_t mem_load2(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr);
uint32_t mem_load4(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr);
uint64_t mem_load8(CPUHexagonState *env, bool pkt_has_store_s1,
uint32_t slot, target_ulong vaddr);

uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);

void log_reg_write(CPUHexagonState *env, int rnum,
target_ulong val);
void log_store64(CPUHexagonState *env, target_ulong addr,
int64_t val, int width, int slot);
void log_store32(CPUHexagonState *env, target_ulong addr,
Expand Down
275 changes: 192 additions & 83 deletions target/hexagon/translate.c

Large diffs are not rendered by default.

52 changes: 45 additions & 7 deletions target/hexagon/translate.h
Expand Up @@ -38,10 +38,12 @@ typedef struct DisasContext {
int reg_log[REG_WRITES_MAX];
int reg_log_idx;
DECLARE_BITMAP(regs_written, TOTAL_PER_THREAD_REGS);
DECLARE_BITMAP(regs_read, TOTAL_PER_THREAD_REGS);
DECLARE_BITMAP(predicated_regs, TOTAL_PER_THREAD_REGS);
int preg_log[PRED_WRITES_MAX];
int preg_log_idx;
DECLARE_BITMAP(pregs_written, NUM_PREGS);
DECLARE_BITMAP(pregs_read, NUM_PREGS);
uint8_t store_width[STORES_MAX];
bool s1_store_processed;
int future_vregs_idx;
Expand All @@ -55,13 +57,22 @@ typedef struct DisasContext {
DECLARE_BITMAP(vregs_select, NUM_VREGS);
DECLARE_BITMAP(predicated_future_vregs, NUM_VREGS);
DECLARE_BITMAP(predicated_tmp_vregs, NUM_VREGS);
DECLARE_BITMAP(vregs_read, NUM_VREGS);
int qreg_log[NUM_QREGS];
int qreg_log_idx;
DECLARE_BITMAP(qregs_read, NUM_QREGS);
bool pre_commit;
bool need_commit;
TCGCond branch_cond;
target_ulong branch_dest;
bool is_tight_loop;
bool need_pkt_has_store_s1;
bool short_circuit;
bool has_hvx_helper;
TCGv new_value[TOTAL_PER_THREAD_REGS];
TCGv new_pred_value[NUM_PREGS];
TCGv pred_written;
TCGv branch_taken;
TCGv dczero_addr;
} DisasContext;

static inline void ctx_log_pred_write(DisasContext *ctx, int pnum)
Expand All @@ -73,6 +84,11 @@ static inline void ctx_log_pred_write(DisasContext *ctx, int pnum)
}
}

static inline void ctx_log_pred_read(DisasContext *ctx, int pnum)
{
set_bit(pnum, ctx->pregs_read);
}

static inline void ctx_log_reg_write(DisasContext *ctx, int rnum,
bool is_predicated)
{
Expand All @@ -99,6 +115,17 @@ static inline void ctx_log_reg_write_pair(DisasContext *ctx, int rnum,
ctx_log_reg_write(ctx, rnum + 1, is_predicated);
}

static inline void ctx_log_reg_read(DisasContext *ctx, int rnum)
{
set_bit(rnum, ctx->regs_read);
}

static inline void ctx_log_reg_read_pair(DisasContext *ctx, int rnum)
{
ctx_log_reg_read(ctx, rnum);
ctx_log_reg_read(ctx, rnum + 1);
}

intptr_t ctx_future_vreg_off(DisasContext *ctx, int regnum,
int num, bool alloc_ok);
intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnum,
Expand Down Expand Up @@ -139,27 +166,38 @@ static inline void ctx_log_vreg_write_pair(DisasContext *ctx,
ctx_log_vreg_write(ctx, rnum ^ 1, type, is_predicated);
}

static inline void ctx_log_vreg_read(DisasContext *ctx, int rnum)
{
set_bit(rnum, ctx->vregs_read);
}

static inline void ctx_log_vreg_read_pair(DisasContext *ctx, int rnum)
{
ctx_log_vreg_read(ctx, rnum ^ 0);
ctx_log_vreg_read(ctx, rnum ^ 1);
}

static inline void ctx_log_qreg_write(DisasContext *ctx,
int rnum)
{
ctx->qreg_log[ctx->qreg_log_idx] = rnum;
ctx->qreg_log_idx++;
}

static inline void ctx_log_qreg_read(DisasContext *ctx, int qnum)
{
set_bit(qnum, ctx->qregs_read);
}

extern TCGv hex_gpr[TOTAL_PER_THREAD_REGS];
extern TCGv hex_pred[NUM_PREGS];
extern TCGv hex_this_PC;
extern TCGv hex_slot_cancelled;
extern TCGv hex_branch_taken;
extern TCGv hex_new_value[TOTAL_PER_THREAD_REGS];
extern TCGv hex_new_value_usr;
extern TCGv hex_reg_written[TOTAL_PER_THREAD_REGS];
extern TCGv hex_new_pred_value[NUM_PREGS];
extern TCGv hex_pred_written;
extern TCGv hex_store_addr[STORES_MAX];
extern TCGv hex_store_width[STORES_MAX];
extern TCGv hex_store_val32[STORES_MAX];
extern TCGv_i64 hex_store_val64[STORES_MAX];
extern TCGv hex_dczero_addr;
extern TCGv hex_llsc_addr;
extern TCGv hex_llsc_val;
extern TCGv_i64 hex_llsc_val_i64;
Expand Down
16 changes: 12 additions & 4 deletions tests/guest-debug/run-test.py
Expand Up @@ -26,11 +26,12 @@ def get_args():
parser.add_argument("--qargs", help="Qemu arguments for test")
parser.add_argument("--binary", help="Binary to debug",
required=True)
parser.add_argument("--test", help="GDB test script",
required=True)
parser.add_argument("--test", help="GDB test script")
parser.add_argument("--gdb", help="The gdb binary to use",
default=None)
parser.add_argument("--gdb-args", help="Additional gdb arguments")
parser.add_argument("--output", help="A file to redirect output to")
parser.add_argument("--stderr", help="A file to redirect stderr to")

return parser.parse_args()

Expand Down Expand Up @@ -58,6 +59,10 @@ def log(output, msg):
output = open(args.output, "w")
else:
output = None
if args.stderr:
stderr = open(args.stderr, "w")
else:
stderr = None

socket_dir = TemporaryDirectory("qemu-gdbstub")
socket_name = os.path.join(socket_dir.name, "gdbstub.socket")
Expand All @@ -77,20 +82,23 @@ def log(output, msg):

# Now launch gdb with our test and collect the result
gdb_cmd = "%s %s" % (args.gdb, args.binary)
if args.gdb_args:
gdb_cmd += " %s" % (args.gdb_args)
# run quietly and ignore .gdbinit
gdb_cmd += " -q -n -batch"
# disable prompts in case of crash
gdb_cmd += " -ex 'set confirm off'"
# connect to remote
gdb_cmd += " -ex 'target remote %s'" % (socket_name)
# finally the test script itself
gdb_cmd += " -x %s" % (args.test)
if args.test:
gdb_cmd += " -x %s" % (args.test)


sleep(1)
log(output, "GDB CMD: %s" % (gdb_cmd))

result = subprocess.call(gdb_cmd, shell=True, stdout=output)
result = subprocess.call(gdb_cmd, shell=True, stdout=output, stderr=stderr)

# A result of greater than 128 indicates a fatal signal (likely a
# crash due to gdb internal failure). That's a problem for GDB and
Expand Down
21 changes: 21 additions & 0 deletions tests/tcg/hexagon/Makefile.target
Expand Up @@ -45,10 +45,18 @@ HEX_TESTS += fpstuff
HEX_TESTS += overflow
HEX_TESTS += signal_context
HEX_TESTS += reg_mut
HEX_TESTS += read_write_overlap
HEX_TESTS += vector_add_int
HEX_TESTS += scatter_gather
HEX_TESTS += hvx_misc
HEX_TESTS += hvx_histogram
HEX_TESTS += invalid-slots

run-and-check-exception = $(call run-test,$2,$3 2>$2.stderr; \
test $$? -eq 1 && grep -q "exception $(strip $1)" $2.stderr)

run-invalid-slots: invalid-slots
$(call run-and-check-exception, 0x15, $@, $(QEMU) $(QEMU_OPTS) $<)

HEX_TESTS += test_abs
HEX_TESTS += test_bitcnt
Expand Down Expand Up @@ -76,17 +84,30 @@ HEX_TESTS += test_vminh
HEX_TESTS += test_vpmpyh
HEX_TESTS += test_vspliceb

HEX_TESTS += v68_scalar
HEX_TESTS += v68_hvx
HEX_TESTS += v69_hvx
HEX_TESTS += v73_scalar

TESTS += $(HEX_TESTS)

# This test has to be compiled for the -mv67t target
usr: usr.c
$(CC) $(CFLAGS) -mv67t -O2 -Wno-inline-asm -Wno-expansion-to-defined $< -o $@ $(LDFLAGS)

# Build this test with -mv71 to exercise the CABAC instruction
misc: misc.c
$(CC) $(CFLAGS) -mv71 -O2 $< -o $@ $(LDFLAGS)
scatter_gather: CFLAGS += -mhvx
vector_add_int: CFLAGS += -mhvx -fvectorize
hvx_misc: hvx_misc.c hvx_misc.h
hvx_misc: CFLAGS += -mhvx
hvx_histogram: CFLAGS += -mhvx -Wno-gnu-folding-constant
v68_hvx: v68_hvx.c hvx_misc.h v6mpy_ref.c.inc
v68_hvx: CFLAGS += -mhvx -Wno-unused-function
v69_hvx: v69_hvx.c hvx_misc.h
v69_hvx: CFLAGS += -mhvx -Wno-unused-function
v73_scalar: CFLAGS += -Wno-unused-function

hvx_histogram: hvx_histogram.c hvx_histogram_row.S
$(CC) $(CFLAGS) $(CROSS_CC_GUEST_CFLAGS) $^ -o $@ $(LDFLAGS)
54 changes: 54 additions & 0 deletions tests/tcg/hexagon/fpstuff.c
Expand Up @@ -20,6 +20,7 @@
*/

#include <stdio.h>
#include <float.h>

const int FPINVF_BIT = 1; /* Invalid */
const int FPINVF = 1 << FPINVF_BIT;
Expand Down Expand Up @@ -706,6 +707,57 @@ static void check_float2int_convs()
check_fpstatus(usr, FPINVF);
}

static void check_float_consts(void)
{
int res32;
unsigned long long res64;

asm("%0 = sfmake(#%1):neg\n\t" : "=r"(res32) : "i"(0xf));
check32(res32, 0xbc9e0000);

asm("%0 = sfmake(#%1):pos\n\t" : "=r"(res32) : "i"(0xf));
check32(res32, 0x3c9e0000);

asm("%0 = dfmake(#%1):neg\n\t" : "=r"(res64) : "i"(0xf));
check64(res64, 0xbf93c00000000000ULL);

asm("%0 = dfmake(#%1):pos\n\t" : "=r"(res64) : "i"(0xf));
check64(res64, 0x3f93c00000000000ULL);
}

static inline unsigned long long dfmpyll(double x, double y)
{
unsigned long long res64;
asm("%0 = dfmpyll(%1, %2)" : "=r"(res64) : "r"(x), "r"(y));
return res64;
}

static inline unsigned long long dfmpylh(double acc, double x, double y)
{
unsigned long long res64 = *(unsigned long long *)&acc;
asm("%0 += dfmpylh(%1, %2)" : "+r"(res64) : "r"(x), "r"(y));
return res64;
}

static void check_dfmpyxx(void)
{
unsigned long long res64;

res64 = dfmpyll(DBL_MIN, DBL_MIN);
check64(res64, 0ULL);
res64 = dfmpyll(-1.0, DBL_MIN);
check64(res64, 0ULL);
res64 = dfmpyll(DBL_MAX, DBL_MAX);
check64(res64, 0x1fffffffdULL);

res64 = dfmpylh(DBL_MIN, DBL_MIN, DBL_MIN);
check64(res64, 0x10000000000000ULL);
res64 = dfmpylh(-1.0, DBL_MAX, DBL_MIN);
check64(res64, 0xc00fffffffe00000ULL);
res64 = dfmpylh(DBL_MAX, 0.0, -1.0);
check64(res64, 0x7fefffffffffffffULL);
}

int main()
{
check_compare_exception();
Expand All @@ -718,6 +770,8 @@ int main()
check_sffixupd();
check_sffms();
check_float2int_convs();
check_float_consts();
check_dfmpyxx();

puts(err ? "FAIL" : "PASS");
return err ? 1 : 0;
Expand Down
66 changes: 21 additions & 45 deletions tests/tcg/hexagon/hvx_misc.c
Expand Up @@ -342,49 +342,6 @@ static void test_vsubuwsat_dv(void)
check_output_w(__LINE__, 2);
}

static void test_vshuff(void)
{
/* Test that vshuff works when the two operands are the same register */
const uint32_t splat = 0x089be55c;
const uint32_t shuff = 0x454fa926;
MMVector v0, v1;

memset(expect, 0x12, sizeof(MMVector));
memset(output, 0x34, sizeof(MMVector));

asm volatile("v25 = vsplat(%0)\n\t"
"vshuff(v25, v25, %1)\n\t"
"vmem(%2 + #0) = v25\n\t"
: /* no outputs */
: "r"(splat), "r"(shuff), "r"(output)
: "v25", "memory");

/*
* The semantics of Hexagon are the operands are pass-by-value, so create
* two copies of the vsplat result.
*/
for (int i = 0; i < MAX_VEC_SIZE_BYTES / 4; i++) {
v0.uw[i] = splat;
v1.uw[i] = splat;
}
/* Do the vshuff operation */
for (int offset = 1; offset < MAX_VEC_SIZE_BYTES; offset <<= 1) {
if (shuff & offset) {
for (int k = 0; k < MAX_VEC_SIZE_BYTES; k++) {
if (!(k & offset)) {
uint8_t tmp = v0.ub[k];
v0.ub[k] = v1.ub[k + offset];
v1.ub[k + offset] = tmp;
}
}
}
}
/* Put the result in the expect buffer for verification */
expect[0] = v1;

check_output_b(__LINE__, 1);
}

static void test_load_tmp_predicated(void)
{
void *p0 = buffer0;
Expand Down Expand Up @@ -454,6 +411,25 @@ static void test_load_cur_predicated(void)
check_output_w(__LINE__, BUFSIZE);
}

static void test_vcombine(void)
{
for (int i = 0; i < BUFSIZE / 2; i++) {
asm volatile("v2 = vsplat(%0)\n\t"
"v3 = vsplat(%1)\n\t"
"v3:2 = vcombine(v2, v3)\n\t"
"vmem(%2+#0) = v2\n\t"
"vmem(%2+#1) = v3\n\t"
:
: "r"(2 * i), "r"(2 * i + 1), "r"(&output[2 * i])
: "v2", "v3", "memory");
for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
expect[2 * i].w[j] = 2 * i + 1;
expect[2 * i + 1].w[j] = 2 * i;
}
}
check_output_w(__LINE__, BUFSIZE);
}

int main()
{
init_buffers();
Expand Down Expand Up @@ -489,11 +465,11 @@ int main()
test_vadduwsat();
test_vsubuwsat_dv();

test_vshuff();

test_load_tmp_predicated();
test_load_cur_predicated();

test_vcombine();

puts(err ? "FAIL" : "PASS");
return err ? 1 : 0;
}
29 changes: 29 additions & 0 deletions tests/tcg/hexagon/invalid-slots.c
@@ -0,0 +1,29 @@
/*
* Copyright(c) 2023 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/>.
*/

char mem[8] __attribute__((aligned(8)));

int main()
{
asm volatile(
"r0 = #mem\n"
/* Invalid packet (2 instructions at slot 0): */
".word 0xa1804100\n" /* { memw(r0) = r1; */
".word 0x28032804\n" /* r3 = #0; r4 = #0 } */
: : : "r0", "r3", "r4", "memory");
return 0;
}
47 changes: 47 additions & 0 deletions tests/tcg/hexagon/misc.c
Expand Up @@ -18,6 +18,8 @@
#include <stdio.h>
#include <string.h>

#define CORE_HAS_CABAC (__HEXAGON_ARCH__ <= 71)

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
Expand Down Expand Up @@ -245,13 +247,15 @@ static void check(int val, int expect)
}
}

#if CORE_HAS_CABAC
static void check64(long long val, long long expect)
{
if (val != expect) {
printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect);
err++;
}
}
#endif

uint32_t init[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
uint32_t array[10];
Expand Down Expand Up @@ -286,6 +290,7 @@ static long long creg_pair(int x, int y)
return retval;
}

#if CORE_HAS_CABAC
static long long decbin(long long x, long long y, int *pred)
{
long long retval;
Expand All @@ -295,6 +300,7 @@ static long long decbin(long long x, long long y, int *pred)
: "r"(x), "r"(y));
return retval;
}
#endif

/* Check that predicates are auto-and'ed in a packet */
static int auto_and(void)
Expand Down Expand Up @@ -385,11 +391,46 @@ void test_count_trailing_zeros_ones(void)
check(ct1p(0xffffff0fffffffffULL), 36);
}

static inline int dpmpyss_rnd_s0(int x, int y)
{
int res;
asm("%0 = mpy(%1, %2):rnd\n\t" : "=r"(res) : "r"(x), "r"(y));
return res;
}

void test_dpmpyss_rnd_s0(void)
{
check(dpmpyss_rnd_s0(-1, 0x80000000), 1);
check(dpmpyss_rnd_s0(0, 0x80000000), 0);
check(dpmpyss_rnd_s0(1, 0x80000000), 0);
check(dpmpyss_rnd_s0(0x7fffffff, 0x80000000), 0xc0000001);
check(dpmpyss_rnd_s0(0x80000000, -1), 1);
check(dpmpyss_rnd_s0(-1, -1), 0);
check(dpmpyss_rnd_s0(0, -1), 0);
check(dpmpyss_rnd_s0(1, -1), 0);
check(dpmpyss_rnd_s0(0x7fffffff, -1), 0);
check(dpmpyss_rnd_s0(0x80000000, 0), 0);
check(dpmpyss_rnd_s0(-1, 0), 0);
check(dpmpyss_rnd_s0(0, 0), 0);
check(dpmpyss_rnd_s0(1, 0), 0);
check(dpmpyss_rnd_s0(-1, -1), 0);
check(dpmpyss_rnd_s0(0, -1), 0);
check(dpmpyss_rnd_s0(1, -1), 0);
check(dpmpyss_rnd_s0(0x7fffffff, 1), 0);
check(dpmpyss_rnd_s0(0x80000000, 0x7fffffff), 0xc0000001);
check(dpmpyss_rnd_s0(-1, 0x7fffffff), 0);
check(dpmpyss_rnd_s0(0, 0x7fffffff), 0);
check(dpmpyss_rnd_s0(1, 0x7fffffff), 0);
check(dpmpyss_rnd_s0(0x7fffffff, 0x7fffffff), 0x3fffffff);
}

int main()
{
int res;
#if CORE_HAS_CABAC
long long res64;
int pred;
#endif

memcpy(array, init, sizeof(array));
S4_storerhnew_rr(array, 4, 0xffff);
Expand Down Expand Up @@ -505,13 +546,17 @@ int main()
res = test_clrtnew(2, 7);
check(res, 7);

#if CORE_HAS_CABAC
res64 = decbin(0xf0f1f2f3f4f5f6f7LL, 0x7f6f5f4f3f2f1f0fLL, &pred);
check64(res64, 0x357980003700010cLL);
check(pred, 0);

res64 = decbin(0xfLL, 0x1bLL, &pred);
check64(res64, 0x78000100LL);
check(pred, 1);
#else
puts("Skipping cabac tests");
#endif

res = auto_and();
check(res, 0);
Expand All @@ -522,6 +567,8 @@ int main()

test_count_trailing_zeros_ones();

test_dpmpyss_rnd_s0();

puts(err ? "FAIL" : "PASS");
return err;
}
136 changes: 136 additions & 0 deletions tests/tcg/hexagon/read_write_overlap.c
@@ -0,0 +1,136 @@
/*
* Copyright(c) 2023 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 instructions where the semantics write to the destination
* before all the operand reads have been completed.
*
* These instructions are problematic when we short-circuit the
* register writes because the destination and source operands could
* be the same TCGv.
*
* We test by forcing the read and write to be register r7.
*/

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

int err;

static void __check(const char *filename, int line, int x, int expect)
{
if (x != expect) {
printf("ERROR %s:%d - 0x%08x != 0x%08x\n",
filename, line, x, expect);
err++;
}
}

#define check(x, expect) __check(__FILE__, __LINE__, (x), (expect))

#define insert(RES, X, WIDTH, OFFSET) \
asm("r7 = %1\n\t" \
"r7 = insert(r7, #" #WIDTH ", #" #OFFSET ")\n\t" \
"%0 = r7\n\t" \
: "=r"(RES) : "r"(X) : "r7")

static void test_insert(void)
{
uint32_t res;

insert(res, 0x12345678, 8, 1);
check(res, 0x123456f0);
insert(res, 0x12345678, 0, 1);
check(res, 0x12345678);
insert(res, 0x12345678, 20, 16);
check(res, 0x56785678);
}

static inline uint32_t insert_rp(uint32_t x, uint32_t width, uint32_t offset)
{
uint64_t width_offset = (uint64_t)width << 32 | offset;
uint32_t res;
asm("r7 = %1\n\t"
"r7 = insert(r7, %2)\n\t"
"%0 = r7\n\t"
: "=r"(res) : "r"(x), "r"(width_offset) : "r7");
return res;

}

static void test_insert_rp(void)
{
check(insert_rp(0x12345678, 8, 1), 0x123456f0);
check(insert_rp(0x12345678, 63, 8), 0x34567878);
check(insert_rp(0x12345678, 127, 8), 0x34567878);
check(insert_rp(0x12345678, 8, 24), 0x78345678);
check(insert_rp(0x12345678, 8, 63), 0x12345678);
check(insert_rp(0x12345678, 8, 64), 0x00000000);
}

static inline uint32_t asr_r_svw_trun(uint64_t x, uint32_t y)
{
uint32_t res;
asm("r7 = %2\n\t"
"r7 = vasrw(%1, r7)\n\t"
"%0 = r7\n\t"
: "=r"(res) : "r"(x), "r"(y) : "r7");
return res;
}

static void test_asr_r_svw_trun(void)
{
check(asr_r_svw_trun(0x1111111122222222ULL, 5),
0x88881111);
check(asr_r_svw_trun(0x1111111122222222ULL, 63),
0x00000000);
check(asr_r_svw_trun(0x1111111122222222ULL, 64),
0x00000000);
check(asr_r_svw_trun(0x1111111122222222ULL, 127),
0x22224444);
check(asr_r_svw_trun(0x1111111122222222ULL, 128),
0x11112222);
check(asr_r_svw_trun(0xffffffff22222222ULL, 128),
0xffff2222);
}

static inline uint32_t swiz(uint32_t x)
{
uint32_t res;
asm("r7 = %1\n\t"
"r7 = swiz(r7)\n\t"
"%0 = r7\n\t"
: "=r"(res) : "r"(x) : "r7");
return res;
}

static void test_swiz(void)
{
check(swiz(0x11223344), 0x44332211);
}

int main()
{
test_insert();
test_insert_rp();
test_asr_r_svw_trun();
test_swiz();

puts(err ? "FAIL" : "PASS");
return err ? EXIT_FAILURE : EXIT_SUCCESS;
}
90 changes: 90 additions & 0 deletions tests/tcg/hexagon/v68_hvx.c
@@ -0,0 +1,90 @@
/*
* Copyright(c) 2022-2023 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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>

int err;

#include "hvx_misc.h"

MMVector v6mpy_buffer0[BUFSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES)));
MMVector v6mpy_buffer1[BUFSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES)));

static void init_v6mpy_buffers(void)
{
int counter0 = 0;
int counter1 = 17;
for (int i = 0; i < BUFSIZE; i++) {
for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
v6mpy_buffer0[i].w[j] = counter0++;
v6mpy_buffer1[i].w[j] = counter1++;
}
}
}

int v6mpy_ref[BUFSIZE][MAX_VEC_SIZE_BYTES / 4] = {
#include "v6mpy_ref.c.inc"
};

static void test_v6mpy(void)
{
void *p00 = buffer0;
void *p01 = v6mpy_buffer0;
void *p10 = buffer1;
void *p11 = v6mpy_buffer1;
void *pout = output;

memset(expect, 0xff, sizeof(expect));
memset(output, 0xff, sizeof(expect));

for (int i = 0; i < BUFSIZE; i++) {
asm("v2 = vmem(%0 + #0)\n\t"
"v3 = vmem(%1 + #0)\n\t"
"v4 = vmem(%2 + #0)\n\t"
"v5 = vmem(%3 + #0)\n\t"
"v5:4.w = v6mpy(v5:4.ub, v3:2.b, #1):v\n\t"
"vmem(%4 + #0) = v4\n\t"
: : "r"(p00), "r"(p01), "r"(p10), "r"(p11), "r"(pout)
: "v2", "v3", "v4", "v5", "memory");
p00 += sizeof(MMVector);
p01 += sizeof(MMVector);
p10 += sizeof(MMVector);
p11 += sizeof(MMVector);
pout += sizeof(MMVector);

for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
expect[i].w[j] = v6mpy_ref[i][j];
}
}

check_output_w(__LINE__, BUFSIZE);
}

int main()
{
init_buffers();
init_v6mpy_buffers();

test_v6mpy();

puts(err ? "FAIL" : "PASS");
return err ? 1 : 0;
}
186 changes: 186 additions & 0 deletions tests/tcg/hexagon/v68_scalar.c
@@ -0,0 +1,186 @@
/*
* Copyright(c) 2023 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 <stdbool.h>
#include <stdint.h>

/*
* Test the scalar core instructions that are new in v68
*/

int err;

static int buffer32[] = { 1, 2, 3, 4 };
static long long buffer64[] = { 5, 6, 7, 8 };

static void __check32(int line, uint32_t result, uint32_t expect)
{
if (result != expect) {
printf("ERROR at line %d: 0x%08x != 0x%08x\n",
line, result, expect);
err++;
}
}

#define check32(RES, EXP) __check32(__LINE__, RES, EXP)

static void __check64(int line, uint64_t result, uint64_t expect)
{
if (result != expect) {
printf("ERROR at line %d: 0x%016llx != 0x%016llx\n",
line, result, expect);
err++;
}
}

#define check64(RES, EXP) __check64(__LINE__, RES, EXP)

static inline int loadw_aq(int *p)
{
int res;
asm volatile("%0 = memw_aq(%1)\n\t"
: "=r"(res) : "r"(p));
return res;
}

static void test_loadw_aq(void)
{
int res;

res = loadw_aq(&buffer32[0]);
check32(res, 1);
res = loadw_aq(&buffer32[1]);
check32(res, 2);
}

static inline long long loadd_aq(long long *p)
{
long long res;
asm volatile("%0 = memd_aq(%1)\n\t"
: "=r"(res) : "r"(p));
return res;
}

static void test_loadd_aq(void)
{
long long res;

res = loadd_aq(&buffer64[2]);
check64(res, 7);
res = loadd_aq(&buffer64[3]);
check64(res, 8);
}

static inline void release_at(int *p)
{
asm volatile("release(%0):at\n\t"
: : "r"(p));
}

static void test_release_at(void)
{
release_at(&buffer32[2]);
check64(buffer32[2], 3);
release_at(&buffer32[3]);
check64(buffer32[3], 4);
}

static inline void release_st(int *p)
{
asm volatile("release(%0):st\n\t"
: : "r"(p));
}

static void test_release_st(void)
{
release_st(&buffer32[2]);
check64(buffer32[2], 3);
release_st(&buffer32[3]);
check64(buffer32[3], 4);
}

static inline void storew_rl_at(int *p, int val)
{
asm volatile("memw_rl(%0):at = %1\n\t"
: : "r"(p), "r"(val) : "memory");
}

static void test_storew_rl_at(void)
{
storew_rl_at(&buffer32[2], 9);
check64(buffer32[2], 9);
storew_rl_at(&buffer32[3], 10);
check64(buffer32[3], 10);
}

static inline void stored_rl_at(long long *p, long long val)
{
asm volatile("memd_rl(%0):at = %1\n\t"
: : "r"(p), "r"(val) : "memory");
}

static void test_stored_rl_at(void)
{
stored_rl_at(&buffer64[2], 11);
check64(buffer64[2], 11);
stored_rl_at(&buffer64[3], 12);
check64(buffer64[3], 12);
}

static inline void storew_rl_st(int *p, int val)
{
asm volatile("memw_rl(%0):st = %1\n\t"
: : "r"(p), "r"(val) : "memory");
}

static void test_storew_rl_st(void)
{
storew_rl_st(&buffer32[0], 13);
check64(buffer32[0], 13);
storew_rl_st(&buffer32[1], 14);
check64(buffer32[1], 14);
}

static inline void stored_rl_st(long long *p, long long val)
{
asm volatile("memd_rl(%0):st = %1\n\t"
: : "r"(p), "r"(val) : "memory");
}

static void test_stored_rl_st(void)
{
stored_rl_st(&buffer64[0], 15);
check64(buffer64[0], 15);
stored_rl_st(&buffer64[1], 15);
check64(buffer64[1], 15);
}

int main()
{
test_loadw_aq();
test_loadd_aq();
test_release_at();
test_release_st();
test_storew_rl_at();
test_stored_rl_at();
test_storew_rl_st();
test_stored_rl_st();

puts(err ? "FAIL" : "PASS");
return err ? 1 : 0;
}
318 changes: 318 additions & 0 deletions tests/tcg/hexagon/v69_hvx.c
@@ -0,0 +1,318 @@
/*
* Copyright(c) 2023 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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>

int err;

#include "hvx_misc.h"

#define fVROUND(VAL, SHAMT) \
((VAL) + (((SHAMT) > 0) ? (1LL << ((SHAMT) - 1)) : 0))

#define fVSATUB(VAL) \
((((VAL) & 0xffLL) == (VAL)) ? \
(VAL) : \
((((int32_t)(VAL)) < 0) ? 0 : 0xff))

#define fVSATUH(VAL) \
((((VAL) & 0xffffLL) == (VAL)) ? \
(VAL) : \
((((int32_t)(VAL)) < 0) ? 0 : 0xffff))

static void test_vasrvuhubrndsat(void)
{
void *p0 = buffer0;
void *p1 = buffer1;
void *pout = output;

memset(expect, 0xaa, sizeof(expect));
memset(output, 0xbb, sizeof(output));

for (int i = 0; i < BUFSIZE / 2; i++) {
asm("v4 = vmem(%0 + #0)\n\t"
"v5 = vmem(%0 + #1)\n\t"
"v6 = vmem(%1 + #0)\n\t"
"v5.ub = vasr(v5:4.uh, v6.ub):rnd:sat\n\t"
"vmem(%2) = v5\n\t"
: : "r"(p0), "r"(p1), "r"(pout)
: "v4", "v5", "v6", "memory");
p0 += sizeof(MMVector) * 2;
p1 += sizeof(MMVector);
pout += sizeof(MMVector);

for (int j = 0; j < MAX_VEC_SIZE_BYTES / 2; j++) {
int shamt;
uint8_t byte0;
uint8_t byte1;

shamt = buffer1[i].ub[2 * j + 0] & 0x7;
byte0 = fVSATUB(fVROUND(buffer0[2 * i + 0].uh[j], shamt) >> shamt);
shamt = buffer1[i].ub[2 * j + 1] & 0x7;
byte1 = fVSATUB(fVROUND(buffer0[2 * i + 1].uh[j], shamt) >> shamt);
expect[i].uh[j] = (byte1 << 8) | (byte0 & 0xff);
}
}

check_output_h(__LINE__, BUFSIZE / 2);
}

static void test_vasrvuhubsat(void)
{
void *p0 = buffer0;
void *p1 = buffer1;
void *pout = output;

memset(expect, 0xaa, sizeof(expect));
memset(output, 0xbb, sizeof(output));

for (int i = 0; i < BUFSIZE / 2; i++) {
asm("v4 = vmem(%0 + #0)\n\t"
"v5 = vmem(%0 + #1)\n\t"
"v6 = vmem(%1 + #0)\n\t"
"v5.ub = vasr(v5:4.uh, v6.ub):sat\n\t"
"vmem(%2) = v5\n\t"
: : "r"(p0), "r"(p1), "r"(pout)
: "v4", "v5", "v6", "memory");
p0 += sizeof(MMVector) * 2;
p1 += sizeof(MMVector);
pout += sizeof(MMVector);

for (int j = 0; j < MAX_VEC_SIZE_BYTES / 2; j++) {
int shamt;
uint8_t byte0;
uint8_t byte1;

shamt = buffer1[i].ub[2 * j + 0] & 0x7;
byte0 = fVSATUB(buffer0[2 * i + 0].uh[j] >> shamt);
shamt = buffer1[i].ub[2 * j + 1] & 0x7;
byte1 = fVSATUB(buffer0[2 * i + 1].uh[j] >> shamt);
expect[i].uh[j] = (byte1 << 8) | (byte0 & 0xff);
}
}

check_output_h(__LINE__, BUFSIZE / 2);
}

static void test_vasrvwuhrndsat(void)
{
void *p0 = buffer0;
void *p1 = buffer1;
void *pout = output;

memset(expect, 0xaa, sizeof(expect));
memset(output, 0xbb, sizeof(output));

for (int i = 0; i < BUFSIZE / 2; i++) {
asm("v4 = vmem(%0 + #0)\n\t"
"v5 = vmem(%0 + #1)\n\t"
"v6 = vmem(%1 + #0)\n\t"
"v5.uh = vasr(v5:4.w, v6.uh):rnd:sat\n\t"
"vmem(%2) = v5\n\t"
: : "r"(p0), "r"(p1), "r"(pout)
: "v4", "v5", "v6", "memory");
p0 += sizeof(MMVector) * 2;
p1 += sizeof(MMVector);
pout += sizeof(MMVector);

for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
int shamt;
uint16_t half0;
uint16_t half1;

shamt = buffer1[i].uh[2 * j + 0] & 0xf;
half0 = fVSATUH(fVROUND(buffer0[2 * i + 0].w[j], shamt) >> shamt);
shamt = buffer1[i].uh[2 * j + 1] & 0xf;
half1 = fVSATUH(fVROUND(buffer0[2 * i + 1].w[j], shamt) >> shamt);
expect[i].w[j] = (half1 << 16) | (half0 & 0xffff);
}
}

check_output_w(__LINE__, BUFSIZE / 2);
}

static void test_vasrvwuhsat(void)
{
void *p0 = buffer0;
void *p1 = buffer1;
void *pout = output;

memset(expect, 0xaa, sizeof(expect));
memset(output, 0xbb, sizeof(output));

for (int i = 0; i < BUFSIZE / 2; i++) {
asm("v4 = vmem(%0 + #0)\n\t"
"v5 = vmem(%0 + #1)\n\t"
"v6 = vmem(%1 + #0)\n\t"
"v5.uh = vasr(v5:4.w, v6.uh):sat\n\t"
"vmem(%2) = v5\n\t"
: : "r"(p0), "r"(p1), "r"(pout)
: "v4", "v5", "v6", "memory");
p0 += sizeof(MMVector) * 2;
p1 += sizeof(MMVector);
pout += sizeof(MMVector);

for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
int shamt;
uint16_t half0;
uint16_t half1;

shamt = buffer1[i].uh[2 * j + 0] & 0xf;
half0 = fVSATUH(buffer0[2 * i + 0].w[j] >> shamt);
shamt = buffer1[i].uh[2 * j + 1] & 0xf;
half1 = fVSATUH(buffer0[2 * i + 1].w[j] >> shamt);
expect[i].w[j] = (half1 << 16) | (half0 & 0xffff);
}
}

check_output_w(__LINE__, BUFSIZE / 2);
}

static void test_vassign_tmp(void)
{
void *p0 = buffer0;
void *pout = output;

memset(expect, 0xaa, sizeof(expect));
memset(output, 0xbb, sizeof(output));

for (int i = 0; i < BUFSIZE; i++) {
/*
* Assign into v12 as .tmp, then use it in the next packet
* Should get the new value within the same packet and
* the old value in the next packet
*/
asm("v3 = vmem(%0 + #0)\n\t"
"r1 = #1\n\t"
"v12 = vsplat(r1)\n\t"
"r1 = #2\n\t"
"v13 = vsplat(r1)\n\t"
"{\n\t"
" v12.tmp = v13\n\t"
" v4.w = vadd(v12.w, v3.w)\n\t"
"}\n\t"
"v4.w = vadd(v4.w, v12.w)\n\t"
"vmem(%1 + #0) = v4\n\t"
: : "r"(p0), "r"(pout)
: "r1", "v3", "v4", "v12", "v13", "memory");
p0 += sizeof(MMVector);
pout += sizeof(MMVector);

for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
expect[i].w[j] = buffer0[i].w[j] + 3;
}
}

check_output_w(__LINE__, BUFSIZE);
}

static void test_vcombine_tmp(void)
{
void *p0 = buffer0;
void *p1 = buffer1;
void *pout = output;

memset(expect, 0xaa, sizeof(expect));
memset(output, 0xbb, sizeof(output));

for (int i = 0; i < BUFSIZE; i++) {
/*
* Combine into v13:12 as .tmp, then use it in the next packet
* Should get the new value within the same packet and
* the old value in the next packet
*/
asm("v3 = vmem(%0 + #0)\n\t"
"r1 = #1\n\t"
"v12 = vsplat(r1)\n\t"
"r1 = #2\n\t"
"v13 = vsplat(r1)\n\t"
"r1 = #3\n\t"
"v14 = vsplat(r1)\n\t"
"r1 = #4\n\t"
"v15 = vsplat(r1)\n\t"
"{\n\t"
" v13:12.tmp = vcombine(v15, v14)\n\t"
" v4.w = vadd(v12.w, v3.w)\n\t"
" v16 = v13\n\t"
"}\n\t"
"v4.w = vadd(v4.w, v12.w)\n\t"
"v4.w = vadd(v4.w, v13.w)\n\t"
"v4.w = vadd(v4.w, v16.w)\n\t"
"vmem(%2 + #0) = v4\n\t"
: : "r"(p0), "r"(p1), "r"(pout)
: "r1", "v3", "v4", "v12", "v13", "v14", "v15", "v16", "memory");
p0 += sizeof(MMVector);
p1 += sizeof(MMVector);
pout += sizeof(MMVector);

for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
expect[i].w[j] = buffer0[i].w[j] + 10;
}
}

check_output_w(__LINE__, BUFSIZE);
}

static void test_vmpyuhvs(void)
{
void *p0 = buffer0;
void *p1 = buffer1;
void *pout = output;

memset(expect, 0xaa, sizeof(expect));
memset(output, 0xbb, sizeof(output));

for (int i = 0; i < BUFSIZE; i++) {
asm("v4 = vmem(%0 + #0)\n\t"
"v5 = vmem(%1 + #0)\n\t"
"v4.uh = vmpy(V4.uh, v5.uh):>>16\n\t"
"vmem(%2) = v4\n\t"
: : "r"(p0), "r"(p1), "r"(pout)
: "v4", "v5", "memory");
p0 += sizeof(MMVector);
p1 += sizeof(MMVector);
pout += sizeof(MMVector);

for (int j = 0; j < MAX_VEC_SIZE_BYTES / 2; j++) {
expect[i].uh[j] = (buffer0[i].uh[j] * buffer1[i].uh[j]) >> 16;
}
}

check_output_h(__LINE__, BUFSIZE);
}

int main()
{
init_buffers();

test_vasrvuhubrndsat();
test_vasrvuhubsat();
test_vasrvwuhrndsat();
test_vasrvwuhsat();

test_vassign_tmp();
test_vcombine_tmp();

test_vmpyuhvs();

puts(err ? "FAIL" : "PASS");
return err ? 1 : 0;
}
161 changes: 161 additions & 0 deletions tests/tcg/hexagon/v6mpy_ref.c.inc
@@ -0,0 +1,161 @@
/*
* Copyright(c) 2021-2023 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/>.
*/

{ 0xffffee11, 0xfffffcca, 0xffffc1b3, 0xffffd0cc,
0xffffe215, 0xfffff58e, 0xffffaf37, 0xffffc310,
0xffffd919, 0xfffff152, 0xffff9fbb, 0xffffb854,
0xffffd31d, 0xfffff016, 0xffff933f, 0xffffb098,
0xffffd021, 0xfffff1da, 0xffff89c3, 0xffffabdc,
0xffffd025, 0xfffff69e, 0xffff8347, 0xffffaa20,
0xffffd329, 0xfffffe62, 0xffff7fcb, 0xffffab64,
0xffffd92d, 0x00000926, 0xffff7f4f, 0xffffafa8,
},
{ 0xffffe231, 0x000016ea, 0xffff81d3, 0xffffb6ec,
0xffffee35, 0x000027ae, 0xffff8757, 0xffffc130,
0xfffffd39, 0x00003b72, 0xffff8fdb, 0xffffce74,
0x00000f3d, 0x00005236, 0xffff9b5f, 0xffffdeb8,
0x00002441, 0x00006bfa, 0xffffa9e3, 0xfffff1fc,
0x00003c45, 0x000088be, 0xffffbb67, 0x00000840,
0x00005749, 0x0000a882, 0xffffcfeb, 0xffffe684,
0x0000494d, 0x00009a46, 0xffffb16f, 0x000002c8,
},
{ 0xfffff351, 0x0000440a, 0xffff4af3, 0xffff9c0c,
0xffffef55, 0x000044ce, 0xffff4077, 0xffff9650,
0xffffee59, 0x00004892, 0xffff38fb, 0xffff9394,
0xfffff05d, 0x00004f56, 0xffff347f, 0xffff93d8,
0xfffff561, 0x0000591a, 0xffff3303, 0xffff971c,
0xfffffd65, 0x000065de, 0xffff3487, 0xffff9d60,
0x00000869, 0x000075a2, 0xffff390b, 0xffffa6a4,
0x0000166d, 0x00008866, 0xffff408f, 0xffffb2e8,
},
{ 0x00002771, 0x00009e2a, 0xffff4b13, 0xffffc22c,
0x00003b75, 0x0000b6ee, 0xffff5897, 0xffffd470,
0x00005279, 0x0000d2b2, 0xffff691b, 0xffffe9b4,
0x00006c7d, 0x0000f176, 0xffff7c9f, 0x000001f8,
0x00008981, 0x0001133a, 0xffff9323, 0x00001d3c,
0x0000a985, 0x000137fe, 0xffffaca7, 0x00003b80,
0x0000cc89, 0x00015fc2, 0xffffc92b, 0xffffe1c4,
0x0000868d, 0x00011986, 0xffff72af, 0x00000608,
},
{ 0xfffff891, 0x00008b4a, 0xfffed433, 0xffff674c,
0xfffffc95, 0x0000940e, 0xfffed1b7, 0xffff6990,
0x00000399, 0x00009fd2, 0xfffed23b, 0xffff6ed4,
0x00000d9d, 0x0000ae96, 0xfffed5bf, 0xffff7718,
0x00001aa1, 0x0000c05a, 0xfffedc43, 0xffff825c,
0x00002aa5, 0x0000d51e, 0xfffee5c7, 0xffff90a0,
0x00003da9, 0x0000ece2, 0xfffef24b, 0xffffa1e4,
0x000053ad, 0x000107a6, 0xffff01cf, 0xffffb628,
},
{ 0x00006cb1, 0x0001256a, 0xffff1453, 0xffffcd6c,
0x000088b5, 0x0001462e, 0xffff29d7, 0xffffe7b0,
0x0000a7b9, 0x000169f2, 0xffff425b, 0x000004f4,
0x0000c9bd, 0x000190b6, 0xffff5ddf, 0x00002538,
0x0000eec1, 0x0001ba7a, 0xffff7c63, 0x0000487c,
0x000116c5, 0x0001e73e, 0xffff9de7, 0x00006ec0,
0x000141c9, 0x00021702, 0xffffc26b, 0xffffdd04,
0x0000c3cd, 0x000198c6, 0xffff33ef, 0x00000948,
},
{ 0xfffffdd1, 0x0000d28a, 0xfffe5d73, 0xffff328c,
0x000009d5, 0x0000e34e, 0xfffe62f7, 0xffff3cd0,
0x000018d9, 0x0000f712, 0xfffe6b7b, 0xffff4a14,
0x00002add, 0x00010dd6, 0xfffe76ff, 0xffff5a58,
0x00003fe1, 0x0001279a, 0xfffe8583, 0xffff6d9c,
0x000057e5, 0x0001445e, 0xfffe9707, 0xffff83e0,
0x000072e9, 0x00016422, 0xfffeab8b, 0xffff9d24,
0x000090ed, 0x000186e6, 0xfffec30f, 0xffffb968,
},
{ 0x0000b1f1, 0x0001acaa, 0xfffedd93, 0xffffd8ac,
0x0000d5f5, 0x0001d56e, 0xfffefb17, 0xfffffaf0,
0x0000fcf9, 0x00020132, 0xffff1b9b, 0x00002034,
0x000126fd, 0x00022ff6, 0xffff3f1f, 0x00008b36,
0x000093c3, 0x00009d80, 0x00009d6d, 0x0000a78a,
0x0000b4d7, 0x0000c354, 0x0000b801, 0x0000c6de,
0x0000d4eb, 0x0000e828, 0x0000d195, 0xffffea32,
0x00000fff, 0x000022fc, 0xfffffc29, 0x00000f86,
},
{ 0xffffee13, 0xfffffcd0, 0xffffc1bd, 0xffffd0da,
0xffffe327, 0xfffff6a4, 0xffffb051, 0xffffc42e,
0xffffd73b, 0xffffef78, 0xffff9de5, 0xffffb682,
0xffffd24f, 0xffffef4c, 0xffff9279, 0xffffafd6,
0xffffd063, 0xfffff220, 0xffff8a0d, 0xffffac2a,
0xffffd177, 0xfffff7f4, 0xffff84a1, 0xffffab7e,
0xffffd18b, 0xfffffcc8, 0xffff7e35, 0xffffa9d2,
0xffffd89f, 0x0000089c, 0xffff7ec9, 0xffffaf26,
},
{ 0xffffe2b3, 0x00001770, 0xffff825d, 0xffffb77a,
0xffffefc7, 0x00002944, 0xffff88f1, 0xffffc2ce,
0xfffffbdb, 0x00003a18, 0xffff8e85, 0xffffcd22,
0x00000eef, 0x000051ec, 0xffff9b19, 0xffffde76,
0x00002503, 0x00006cc0, 0xffffaaad, 0xfffff2ca,
0x00003e17, 0x00008a94, 0xffffbd41, 0x00000a1e,
0x0000562b, 0x0000a768, 0xffffced5, 0xffffe572,
0x0000493f, 0x00009a3c, 0xffffb169, 0x000002c6,
},
{ 0xfffff353, 0x00004410, 0xffff4afd, 0xffff9c1a,
0xfffff067, 0x000045e4, 0xffff4191, 0xffff976e,
0xffffec7b, 0x000046b8, 0xffff3725, 0xffff91c2,
0xffffef8f, 0x00004e8c, 0xffff33b9, 0xffff9316,
0xfffff5a3, 0x00005960, 0xffff334d, 0xffff976a,
0xfffffeb7, 0x00006734, 0xffff35e1, 0xffff9ebe,
0x000006cb, 0x00007408, 0xffff3775, 0xffffa512,
0x000015df, 0x000087dc, 0xffff4009, 0xffffb266,
},
{ 0x000027f3, 0x00009eb0, 0xffff4b9d, 0xffffc2ba,
0x00003d07, 0x0000b884, 0xffff5a31, 0xffffd60e,
0x0000511b, 0x0000d158, 0xffff67c5, 0xffffe862,
0x00006c2f, 0x0000f12c, 0xffff7c59, 0x000001b6,
0x00008a43, 0x00011400, 0xffff93ed, 0x00001e0a,
0x0000ab57, 0x000139d4, 0xffffae81, 0x00003d5e,
0x0000cb6b, 0x00015ea8, 0xffffc815, 0xffffe0b2,
0x0000867f, 0x0001197c, 0xffff72a9, 0x00000606,
},
{ 0xfffff893, 0x00008b50, 0xfffed43d, 0xffff675a,
0xfffffda7, 0x00009524, 0xfffed2d1, 0xffff6aae,
0x000001bb, 0x00009df8, 0xfffed065, 0xffff6d02,
0x00000ccf, 0x0000adcc, 0xfffed4f9, 0xffff7656,
0x00001ae3, 0x0000c0a0, 0xfffedc8d, 0xffff82aa,
0x00002bf7, 0x0000d674, 0xfffee721, 0xffff91fe,
0x00003c0b, 0x0000eb48, 0xfffef0b5, 0xffffa052,
0x0000531f, 0x0001071c, 0xffff0149, 0xffffb5a6,
},
{ 0x00006d33, 0x000125f0, 0xffff14dd, 0xffffcdfa,
0x00008a47, 0x000147c4, 0xffff2b71, 0xffffe94e,
0x0000a65b, 0x00016898, 0xffff4105, 0x000003a2,
0x0000c96f, 0x0001906c, 0xffff5d99, 0x000024f6,
0x0000ef83, 0x0001bb40, 0xffff7d2d, 0x0000494a,
0x00011897, 0x0001e914, 0xffff9fc1, 0x0000709e,
0x000140ab, 0x000215e8, 0xffffc155, 0xffffdbf2,
0x0000c3bf, 0x000198bc, 0xffff33e9, 0x00000946,
},
{ 0xfffffdd3, 0x0000d290, 0xfffe5d7d, 0xffff329a,
0x00000ae7, 0x0000e464, 0xfffe6411, 0xffff3dee,
0x000016fb, 0x0000f538, 0xfffe69a5, 0xffff4842,
0x00002a0f, 0x00010d0c, 0xfffe7639, 0xffff5996,
0x00004023, 0x000127e0, 0xfffe85cd, 0xffff6dea,
0x00005937, 0x000145b4, 0xfffe9861, 0xffff853e,
0x0000714b, 0x00016288, 0xfffea9f5, 0xffff9b92,
0x0000905f, 0x0001865c, 0xfffec289, 0xffffb8e6,
},
{ 0x0000b273, 0x0001ad30, 0xfffede1d, 0xffffd93a,
0x0000d787, 0x0001d704, 0xfffefcb1, 0xfffffc8e,
0x0000fb9b, 0x0001ffd8, 0xffff1a45, 0x00001ee2,
0x000126af, 0x00022fac, 0xffff3ed9, 0x00008af4,
0x00009485, 0x00009e46, 0x00009e37, 0x0000a858,
0x0000b6a9, 0x0000c52a, 0x0000b9db, 0x0000c8bc,
0x0000d3cd, 0x0000e70e, 0x0000d07f, 0xffffe920,
0x00000ff1, 0x000022f2, 0xfffffc23, 0x00000f84,
},
96 changes: 96 additions & 0 deletions tests/tcg/hexagon/v73_scalar.c
@@ -0,0 +1,96 @@
/*
* Copyright(c) 2023 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 <stdbool.h>
#include <stdint.h>

/*
* Test the scalar core instructions that are new in v73
*/

int err;

static void __check32(int line, uint32_t result, uint32_t expect)
{
if (result != expect) {
printf("ERROR at line %d: 0x%08x != 0x%08x\n",
line, result, expect);
err++;
}
}

#define check32(RES, EXP) __check32(__LINE__, RES, EXP)

static void __check64(int line, uint64_t result, uint64_t expect)
{
if (result != expect) {
printf("ERROR at line %d: 0x%016llx != 0x%016llx\n",
line, result, expect);
err++;
}
}

#define check64(RES, EXP) __check64(__LINE__, RES, EXP)

static bool my_func_called;

static void my_func(void)
{
my_func_called = true;
}

static inline void callrh(void *func)
{
asm volatile("callrh %0\n\t"
: : "r"(func)
/* Mark the caller-save registers as clobbered */
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
"r10", "r11", "r12", "r13", "r14", "r15", "r28",
"p0", "p1", "p2", "p3");
}

static void test_callrh(void)
{
my_func_called = false;
callrh(&my_func);
check32(my_func_called, true);
}

static void test_jumprh(void)
{
uint32_t res;
asm ("%0 = #5\n\t"
"r0 = ##1f\n\t"
"jumprh r0\n\t"
"%0 = #3\n\t"
"jump 2f\n\t"
"1:\n\t"
"%0 = #1\n\t"
"2:\n\t"
: "=r"(res) : : "r0");
check32(res, 1);
}

int main()
{
test_callrh();
test_jumprh();

puts(err ? "FAIL" : "PASS");
return err ? 1 : 0;
}
16 changes: 15 additions & 1 deletion tests/tcg/multiarch/system/Makefile.softmmu-target
Expand Up @@ -27,6 +27,20 @@ run-gdbstub-memory: memory
"-monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \
--bin $< --test $(MULTIARCH_SRC)/gdbstub/memory.py, \
softmmu gdbstub support)

run-gdbstub-untimely-packet: hello
$(call run-test, $@, $(GDB_SCRIPT) \
--gdb $(HAVE_GDB_BIN) \
--gdb-args "-ex 'set debug remote 1'" \
--output untimely-packet.gdb.out \
--stderr untimely-packet.gdb.err \
--qemu $(QEMU) \
--bin $< --qargs \
"-monitor none -display none -chardev file$(COMMA)path=untimely-packet.out$(COMMA)id=output $(QEMU_OPTS)", \
"softmmu gdbstub untimely packets")
$(call quiet-command, \
(! grep -Fq 'Packet instead of Ack, ignoring it' untimely-packet.gdb.err), \
"GREP", "file untimely-packet.gdb.err")
else
run-gdbstub-%:
$(call skip-test, "gdbstub test $*", "no guest arch support")
Expand All @@ -36,4 +50,4 @@ run-gdbstub-%:
$(call skip-test, "gdbstub test $*", "need working gdb")
endif

MULTIARCH_RUNS += run-gdbstub-memory
MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-untimely-packet