mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/quic/tags/pull-hex-20211103' into staging
This series adds support for the Hexagon Vector eXtensions (HVX) These instructions are documented here https://developer.qualcomm.com/downloads/qualcomm-hexagon-v66-hvx-programmer-s-reference-manual Hexagon HVX is a wide vector engine with 128 byte vectors. See patch 01 Hexagon HVX README for more information. *** Changes in v2 *** Remove HVX tests from makefile to avoid need for toolchain upgrade # gpg: Signature made Wed 03 Nov 2021 05:14:44 PM EDT # gpg: using RSA key 7B0244FB12DE4422 # gpg: Good signature from "Taylor Simpson (Rock on) <tsimpson@quicinc.com>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 3635 C788 CE62 B91F D4C5 9AB4 7B02 44FB 12DE 4422 * remotes/quic/tags/pull-hex-20211103: (30 commits) Hexagon HVX (tests/tcg/hexagon) histogram test Hexagon HVX (tests/tcg/hexagon) scatter_gather test Hexagon HVX (tests/tcg/hexagon) hvx_misc test Hexagon HVX (tests/tcg/hexagon) vector_add_int test Hexagon HVX (target/hexagon) import instruction encodings Hexagon HVX (target/hexagon) instruction decoding Hexagon HVX (target/hexagon) import semantics Hexagon HVX (target/hexagon) helper overrides - vector stores Hexagon HVX (target/hexagon) helper overrides - vector loads Hexagon HVX (target/hexagon) helper overrides - vector splat and abs Hexagon HVX (target/hexagon) helper overrides - vector compares Hexagon HVX (target/hexagon) helper overrides - vector logical ops Hexagon HVX (target/hexagon) helper overrides - vector max/min Hexagon HVX (target/hexagon) helper overrides - vector shifts Hexagon HVX (target/hexagon) helper overrides - vector add & sub Hexagon HVX (target/hexagon) helper overrides - vector assign & cmov Hexagon HVX (target/hexagon) helper overrides for histogram instructions Hexagon HVX (target/hexagon) helper overrides infrastructure Hexagon HVX (target/hexagon) TCG generation Hexagon HVX (target/hexagon) helper functions ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
+80
-1
@@ -1,9 +1,13 @@
|
||||
Hexagon is Qualcomm's very long instruction word (VLIW) digital signal
|
||||
processor(DSP).
|
||||
processor(DSP). We also support Hexagon Vector eXtensions (HVX). HVX
|
||||
is a wide vector coprocessor designed for high performance computer vision,
|
||||
image processing, machine learning, and other workloads.
|
||||
|
||||
The following versions of the Hexagon core are supported
|
||||
Scalar core: v67
|
||||
https://developer.qualcomm.com/downloads/qualcomm-hexagon-v67-programmer-s-reference-manual
|
||||
HVX extension: v66
|
||||
https://developer.qualcomm.com/downloads/qualcomm-hexagon-v66-hvx-programmer-s-reference-manual
|
||||
|
||||
We presented an overview of the project at the 2019 KVM Forum.
|
||||
https://kvmforum2019.sched.com/event/Tmwc/qemu-hexagon-automatic-translation-of-the-isa-manual-pseudcode-to-tiny-code-instructions-of-a-vliw-architecture-niccolo-izzo-revng-taylor-simpson-qualcomm-innovation-center
|
||||
@@ -124,6 +128,71 @@ There are also cases where we brute force the TCG code generation.
|
||||
Instructions with multiple definitions are examples. These require special
|
||||
handling because qemu helpers can only return a single value.
|
||||
|
||||
For HVX vectors, the generator behaves slightly differently. The wide vectors
|
||||
won't fit in a TCGv or TCGv_i64, so we pass TCGv_ptr variables to pass the
|
||||
address to helper functions. Here's an example for an HVX vector-add-word
|
||||
istruction.
|
||||
static void generate_V6_vaddw(
|
||||
CPUHexagonState *env,
|
||||
DisasContext *ctx,
|
||||
Insn *insn,
|
||||
Packet *pkt)
|
||||
{
|
||||
const int VdN = insn->regno[0];
|
||||
const intptr_t VdV_off =
|
||||
ctx_future_vreg_off(ctx, VdN, 1, true);
|
||||
TCGv_ptr VdV = tcg_temp_local_new_ptr();
|
||||
tcg_gen_addi_ptr(VdV, cpu_env, VdV_off);
|
||||
const int VuN = insn->regno[1];
|
||||
const intptr_t VuV_off =
|
||||
vreg_src_off(ctx, VuN);
|
||||
TCGv_ptr VuV = tcg_temp_local_new_ptr();
|
||||
const int VvN = insn->regno[2];
|
||||
const intptr_t VvV_off =
|
||||
vreg_src_off(ctx, VvN);
|
||||
TCGv_ptr VvV = tcg_temp_local_new_ptr();
|
||||
tcg_gen_addi_ptr(VuV, cpu_env, VuV_off);
|
||||
tcg_gen_addi_ptr(VvV, cpu_env, VvV_off);
|
||||
TCGv slot = tcg_constant_tl(insn->slot);
|
||||
gen_helper_V6_vaddw(cpu_env, VdV, VuV, VvV, slot);
|
||||
tcg_temp_free(slot);
|
||||
gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
|
||||
ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
|
||||
tcg_temp_free_ptr(VdV);
|
||||
tcg_temp_free_ptr(VuV);
|
||||
tcg_temp_free_ptr(VvV);
|
||||
}
|
||||
|
||||
Notice that we also generate a variable named <operand>_off for each operand of
|
||||
the instruction. This makes it easy to override the instruction semantics with
|
||||
functions from tcg-op-gvec.h. Here's the override for this instruction.
|
||||
#define fGEN_TCG_V6_vaddw(SHORTCODE) \
|
||||
tcg_gen_gvec_add(MO_32, VdV_off, VuV_off, VvV_off, \
|
||||
sizeof(MMVector), sizeof(MMVector))
|
||||
|
||||
Finally, we notice that the override doesn't use the TCGv_ptr variables, so
|
||||
we don't generate them when an override is present. Here is what we generate
|
||||
when the override is present.
|
||||
static void generate_V6_vaddw(
|
||||
CPUHexagonState *env,
|
||||
DisasContext *ctx,
|
||||
Insn *insn,
|
||||
Packet *pkt)
|
||||
{
|
||||
const int VdN = insn->regno[0];
|
||||
const intptr_t VdV_off =
|
||||
ctx_future_vreg_off(ctx, VdN, 1, true);
|
||||
const int VuN = insn->regno[1];
|
||||
const intptr_t VuV_off =
|
||||
vreg_src_off(ctx, VuN);
|
||||
const int VvN = insn->regno[2];
|
||||
const intptr_t VvV_off =
|
||||
vreg_src_off(ctx, VvN);
|
||||
fGEN_TCG_V6_vaddw({ fHIDE(int i;) fVFOREACH(32, i) { VdV.w[i] = VuV.w[i] + VvV.w[i] ; } });
|
||||
gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
|
||||
ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
|
||||
}
|
||||
|
||||
In addition to instruction semantics, we use a generator to create the decode
|
||||
tree. This generation is also a two step process. The first step is to run
|
||||
target/hexagon/gen_dectree_import.c to produce
|
||||
@@ -140,6 +209,7 @@ runtime information for each thread and contains stuff like the GPR and
|
||||
predicate registers.
|
||||
|
||||
macros.h
|
||||
mmvec/macros.h
|
||||
|
||||
The Hexagon arch lib relies heavily on macros for the instruction semantics.
|
||||
This is a great advantage for qemu because we can override them for different
|
||||
@@ -203,6 +273,15 @@ During runtime, the following fields in CPUHexagonState (see cpu.h) are used
|
||||
pred_written boolean indicating if predicate was written
|
||||
mem_log_stores record of the stores (indexed by slot)
|
||||
|
||||
For Hexagon Vector eXtensions (HVX), the following fields are used
|
||||
VRegs Vector registers
|
||||
future_VRegs Registers to be stored during packet commit
|
||||
tmp_VRegs Temporary registers *not* stored during commit
|
||||
VRegs_updated Mask of predicated vector writes
|
||||
QRegs Q (vector predicate) registers
|
||||
future_QRegs Registers to be stored during packet commit
|
||||
QRegs_updated Mask of predicated vector writes
|
||||
|
||||
*** Debugging ***
|
||||
|
||||
You can turn on a lot of debugging by changing the HEX_DEBUG macro to 1 in
|
||||
|
||||
@@ -41,6 +41,27 @@ DEF_ATTRIB(STORE, "Stores to memory", "", "")
|
||||
DEF_ATTRIB(MEMLIKE, "Memory-like instruction", "", "")
|
||||
DEF_ATTRIB(MEMLIKE_PACKET_RULES, "follows Memory-like packet rules", "", "")
|
||||
|
||||
/* V6 Vector attributes */
|
||||
DEF_ATTRIB(CVI, "Executes on the HVX extension", "", "")
|
||||
|
||||
DEF_ATTRIB(CVI_NEW, "New value memory instruction executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VM, "Memory instruction executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VP, "Permute instruction executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VP_VS, "Double vector permute/shft insn executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VX, "Multiply instruction executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VX_DV, "Double vector multiply insn executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VS, "Shift instruction executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VS_VX, "Permute/shift and multiply insn executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VA, "ALU instruction executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_VA_DV, "Double vector alu instruction executes on HVX", "", "")
|
||||
DEF_ATTRIB(CVI_4SLOT, "Consumes all the vector execution resources", "", "")
|
||||
DEF_ATTRIB(CVI_TMP, "Transient Memory Load not written to register", "", "")
|
||||
DEF_ATTRIB(CVI_GATHER, "CVI Gather operation", "", "")
|
||||
DEF_ATTRIB(CVI_SCATTER, "CVI Scatter operation", "", "")
|
||||
DEF_ATTRIB(CVI_SCATTER_RELEASE, "CVI Store Release for scatter", "", "")
|
||||
DEF_ATTRIB(CVI_TMP_DST, "CVI instruction that doesn't write a register", "", "")
|
||||
DEF_ATTRIB(CVI_SLOT23, "Can execute in slot 2 or slot 3 (HVX)", "", "")
|
||||
|
||||
|
||||
/* Change-of-flow attributes */
|
||||
DEF_ATTRIB(JUMP, "Jump-type instruction", "", "")
|
||||
@@ -87,6 +108,7 @@ DEF_ATTRIB(HWLOOP1_END, "Ends HW loop1", "", "")
|
||||
DEF_ATTRIB(DCZEROA, "dczeroa type", "", "")
|
||||
DEF_ATTRIB(ICFLUSHOP, "icflush op type", "", "")
|
||||
DEF_ATTRIB(DCFLUSHOP, "dcflush op type", "", "")
|
||||
DEF_ATTRIB(L2FLUSHOP, "l2flush op type", "", "")
|
||||
DEF_ATTRIB(DCFETCH, "dcfetch type", "", "")
|
||||
|
||||
DEF_ATTRIB(L2FETCH, "Instruction is l2fetch type", "", "")
|
||||
|
||||
+75
-5
@@ -59,7 +59,7 @@ const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = {
|
||||
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
|
||||
"sa0", "lc0", "sa1", "lc1", "p3_0", "c5", "m0", "m1",
|
||||
"usr", "pc", "ugp", "gp", "cs0", "cs1", "c14", "c15",
|
||||
"c16", "c17", "c18", "c19", "pkt_cnt", "insn_cnt", "c22", "c23",
|
||||
"c16", "c17", "c18", "c19", "pkt_cnt", "insn_cnt", "hvx_cnt", "c23",
|
||||
"c24", "c25", "c26", "c27", "c28", "c29", "c30", "c31",
|
||||
};
|
||||
|
||||
@@ -113,7 +113,66 @@ static void print_reg(FILE *f, CPUHexagonState *env, int regnum)
|
||||
hexagon_regnames[regnum], value);
|
||||
}
|
||||
|
||||
static void hexagon_dump(CPUHexagonState *env, FILE *f)
|
||||
static void print_vreg(FILE *f, CPUHexagonState *env, int regnum,
|
||||
bool skip_if_zero)
|
||||
{
|
||||
if (skip_if_zero) {
|
||||
bool nonzero_found = false;
|
||||
for (int i = 0; i < MAX_VEC_SIZE_BYTES; i++) {
|
||||
if (env->VRegs[regnum].ub[i] != 0) {
|
||||
nonzero_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!nonzero_found) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fprintf(f, " v%d = ( ", regnum);
|
||||
qemu_fprintf(f, "0x%02x", env->VRegs[regnum].ub[MAX_VEC_SIZE_BYTES - 1]);
|
||||
for (int i = MAX_VEC_SIZE_BYTES - 2; i >= 0; i--) {
|
||||
qemu_fprintf(f, ", 0x%02x", env->VRegs[regnum].ub[i]);
|
||||
}
|
||||
qemu_fprintf(f, " )\n");
|
||||
}
|
||||
|
||||
void hexagon_debug_vreg(CPUHexagonState *env, int regnum)
|
||||
{
|
||||
print_vreg(stdout, env, regnum, false);
|
||||
}
|
||||
|
||||
static void print_qreg(FILE *f, CPUHexagonState *env, int regnum,
|
||||
bool skip_if_zero)
|
||||
{
|
||||
if (skip_if_zero) {
|
||||
bool nonzero_found = false;
|
||||
for (int i = 0; i < MAX_VEC_SIZE_BYTES / 8; i++) {
|
||||
if (env->QRegs[regnum].ub[i] != 0) {
|
||||
nonzero_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!nonzero_found) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fprintf(f, " q%d = ( ", regnum);
|
||||
qemu_fprintf(f, "0x%02x",
|
||||
env->QRegs[regnum].ub[MAX_VEC_SIZE_BYTES / 8 - 1]);
|
||||
for (int i = MAX_VEC_SIZE_BYTES / 8 - 2; i >= 0; i--) {
|
||||
qemu_fprintf(f, ", 0x%02x", env->QRegs[regnum].ub[i]);
|
||||
}
|
||||
qemu_fprintf(f, " )\n");
|
||||
}
|
||||
|
||||
void hexagon_debug_qreg(CPUHexagonState *env, int regnum)
|
||||
{
|
||||
print_qreg(stdout, env, regnum, false);
|
||||
}
|
||||
|
||||
static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags)
|
||||
{
|
||||
HexagonCPU *cpu = env_archcpu(env);
|
||||
|
||||
@@ -159,6 +218,17 @@ static void hexagon_dump(CPUHexagonState *env, FILE *f)
|
||||
print_reg(f, env, HEX_REG_CS1);
|
||||
#endif
|
||||
qemu_fprintf(f, "}\n");
|
||||
|
||||
if (flags & CPU_DUMP_FPU) {
|
||||
qemu_fprintf(f, "Vector Registers = {\n");
|
||||
for (int i = 0; i < NUM_VREGS; i++) {
|
||||
print_vreg(f, env, i, true);
|
||||
}
|
||||
for (int i = 0; i < NUM_QREGS; i++) {
|
||||
print_qreg(f, env, i, true);
|
||||
}
|
||||
qemu_fprintf(f, "}\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void hexagon_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
@@ -166,12 +236,12 @@ static void hexagon_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
HexagonCPU *cpu = HEXAGON_CPU(cs);
|
||||
CPUHexagonState *env = &cpu->env;
|
||||
|
||||
hexagon_dump(env, f);
|
||||
hexagon_dump(env, f, flags);
|
||||
}
|
||||
|
||||
void hexagon_debug(CPUHexagonState *env)
|
||||
{
|
||||
hexagon_dump(env, stdout);
|
||||
hexagon_dump(env, stdout, CPU_DUMP_FPU);
|
||||
}
|
||||
|
||||
static void hexagon_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
@@ -269,7 +339,7 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data)
|
||||
cc->set_pc = hexagon_cpu_set_pc;
|
||||
cc->gdb_read_register = hexagon_gdb_read_register;
|
||||
cc->gdb_write_register = hexagon_gdb_write_register;
|
||||
cc->gdb_num_core_regs = TOTAL_PER_THREAD_REGS;
|
||||
cc->gdb_num_core_regs = TOTAL_PER_THREAD_REGS + NUM_VREGS + NUM_QREGS;
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
cc->disas_set_info = hexagon_cpu_disas_set_info;
|
||||
cc->tcg_ops = &hexagon_tcg_ops;
|
||||
|
||||
+33
-2
@@ -26,6 +26,7 @@ typedef struct CPUHexagonState CPUHexagonState;
|
||||
#include "qemu-common.h"
|
||||
#include "exec/cpu-defs.h"
|
||||
#include "hex_regs.h"
|
||||
#include "mmvec/mmvec.h"
|
||||
|
||||
#define NUM_PREGS 4
|
||||
#define TOTAL_PER_THREAD_REGS 64
|
||||
@@ -34,6 +35,7 @@ typedef struct CPUHexagonState CPUHexagonState;
|
||||
#define STORES_MAX 2
|
||||
#define REG_WRITES_MAX 32
|
||||
#define PRED_WRITES_MAX 5 /* 4 insns + endloop */
|
||||
#define VSTORES_MAX 2
|
||||
|
||||
#define TYPE_HEXAGON_CPU "hexagon-cpu"
|
||||
|
||||
@@ -52,6 +54,13 @@ typedef struct {
|
||||
uint64_t data64;
|
||||
} MemLog;
|
||||
|
||||
typedef struct {
|
||||
target_ulong va;
|
||||
int size;
|
||||
DECLARE_BITMAP(mask, MAX_VEC_SIZE_BYTES) QEMU_ALIGNED(16);
|
||||
MMVector data QEMU_ALIGNED(16);
|
||||
} VStoreLog;
|
||||
|
||||
#define EXEC_STATUS_OK 0x0000
|
||||
#define EXEC_STATUS_STOP 0x0002
|
||||
#define EXEC_STATUS_REPLAY 0x0010
|
||||
@@ -64,6 +73,9 @@ typedef struct {
|
||||
#define CLEAR_EXCEPTION (env->status &= (~EXEC_STATUS_EXCEPTION))
|
||||
#define SET_EXCEPTION (env->status |= EXEC_STATUS_EXCEPTION)
|
||||
|
||||
/* Maximum number of vector temps in a packet */
|
||||
#define VECTOR_TEMPS_MAX 4
|
||||
|
||||
struct CPUHexagonState {
|
||||
target_ulong gpr[TOTAL_PER_THREAD_REGS];
|
||||
target_ulong pred[NUM_PREGS];
|
||||
@@ -97,8 +109,27 @@ struct CPUHexagonState {
|
||||
target_ulong llsc_val;
|
||||
uint64_t llsc_val_i64;
|
||||
|
||||
target_ulong is_gather_store_insn;
|
||||
target_ulong gather_issued;
|
||||
MMVector VRegs[NUM_VREGS] QEMU_ALIGNED(16);
|
||||
MMVector future_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16);
|
||||
MMVector tmp_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16);
|
||||
|
||||
VRegMask VRegs_updated;
|
||||
|
||||
MMQReg QRegs[NUM_QREGS] QEMU_ALIGNED(16);
|
||||
MMQReg future_QRegs[NUM_QREGS] QEMU_ALIGNED(16);
|
||||
QRegMask QRegs_updated;
|
||||
|
||||
/* Temporaries used within instructions */
|
||||
MMVectorPair VuuV QEMU_ALIGNED(16);
|
||||
MMVectorPair VvvV QEMU_ALIGNED(16);
|
||||
MMVectorPair VxxV QEMU_ALIGNED(16);
|
||||
MMVector vtmp QEMU_ALIGNED(16);
|
||||
MMQReg qtmp QEMU_ALIGNED(16);
|
||||
|
||||
VStoreLog vstore[VSTORES_MAX];
|
||||
target_ulong vstore_pending[VSTORES_MAX];
|
||||
bool vtcm_pending;
|
||||
VTCMStoreLog vtcm_log;
|
||||
};
|
||||
|
||||
#define HEXAGON_CPU_CLASS(klass) \
|
||||
|
||||
+26
-2
@@ -22,6 +22,7 @@
|
||||
#include "decode.h"
|
||||
#include "insn.h"
|
||||
#include "printinsn.h"
|
||||
#include "mmvec/decode_ext_mmvec.h"
|
||||
|
||||
#define fZXTN(N, M, VAL) ((VAL) & ((1LL << (N)) - 1))
|
||||
|
||||
@@ -46,6 +47,7 @@ enum {
|
||||
/* Name Num Table */
|
||||
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)
|
||||
DEF_REGMAP(R_8, 8, 0, 1, 2, 3, 4, 5, 6, 7)
|
||||
|
||||
#define DECODE_MAPPED_REG(OPNUM, NAME) \
|
||||
insn->regno[OPNUM] = DECODE_REGISTER_##NAME[insn->regno[OPNUM]];
|
||||
@@ -157,6 +159,9 @@ static void decode_ext_init(void)
|
||||
for (i = EXT_IDX_noext; i < EXT_IDX_noext_AFTER; i++) {
|
||||
ext_trees[i] = &dectree_table_DECODE_EXT_EXT_noext;
|
||||
}
|
||||
for (i = EXT_IDX_mmvec; i < EXT_IDX_mmvec_AFTER; i++) {
|
||||
ext_trees[i] = &dectree_table_DECODE_EXT_EXT_mmvec;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@@ -566,8 +571,12 @@ static void decode_remove_extenders(Packet *packet)
|
||||
|
||||
static SlotMask get_valid_slots(const Packet *pkt, unsigned int slot)
|
||||
{
|
||||
return find_iclass_slots(pkt->insn[slot].opcode,
|
||||
pkt->insn[slot].iclass);
|
||||
if (GET_ATTRIB(pkt->insn[slot].opcode, A_EXTENSION)) {
|
||||
return mmvec_ext_decode_find_iclass_slots(pkt->insn[slot].opcode);
|
||||
} else {
|
||||
return find_iclass_slots(pkt->insn[slot].opcode,
|
||||
pkt->insn[slot].iclass);
|
||||
}
|
||||
}
|
||||
|
||||
#define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT) /* NOTHING */
|
||||
@@ -728,6 +737,11 @@ decode_insns_tablewalk(Insn *insn, const DectreeTable *table,
|
||||
}
|
||||
decode_op(insn, opc, encoding);
|
||||
return 1;
|
||||
} else if (table->table[i].type == DECTREE_EXTSPACE) {
|
||||
/*
|
||||
* For now, HVX will be the only coproc
|
||||
*/
|
||||
return decode_insns_tablewalk(insn, ext_trees[EXT_IDX_mmvec], encoding);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -874,6 +888,7 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
|
||||
int words_read = 0;
|
||||
bool end_of_packet = false;
|
||||
int new_insns = 0;
|
||||
int i;
|
||||
uint32_t encoding32;
|
||||
|
||||
/* Initialize */
|
||||
@@ -901,6 +916,11 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
|
||||
return 0;
|
||||
}
|
||||
pkt->encod_pkt_size_in_bytes = words_read * 4;
|
||||
pkt->pkt_has_hvx = false;
|
||||
for (i = 0; i < num_insns; i++) {
|
||||
pkt->pkt_has_hvx |=
|
||||
GET_ATTRIB(pkt->insn[i].opcode, A_CVI);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for :endloop in the parse bits
|
||||
@@ -931,6 +951,10 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
|
||||
decode_set_slot_number(pkt);
|
||||
decode_fill_newvalue_regno(pkt);
|
||||
|
||||
if (pkt->pkt_has_hvx) {
|
||||
mmvec_ext_decode_checks(pkt, disas_only);
|
||||
}
|
||||
|
||||
if (!disas_only) {
|
||||
decode_shuffle_for_execution(pkt);
|
||||
decode_split_cmpjump(pkt);
|
||||
|
||||
@@ -40,6 +40,11 @@ const char * const opcode_names[] = {
|
||||
* Q6INSN(A2_add,"Rd32=add(Rs32,Rt32)",ATTRIBS(),
|
||||
* "Add 32-bit registers",
|
||||
* { RdV=RsV+RtV;})
|
||||
* HVX instructions have the following form
|
||||
* EXTINSN(V6_vinsertwr, "Vx32.w=vinsert(Rt32)",
|
||||
* ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VX,A_CVI_LATE),
|
||||
* "Insert Word Scalar into Vector",
|
||||
* VxV.uw[0] = RtV;)
|
||||
*/
|
||||
const char * const opcode_syntax[XX_LAST_OPCODE] = {
|
||||
#define Q6INSN(TAG, BEH, ATTRIBS, DESCR, SEM) \
|
||||
@@ -105,6 +110,14 @@ static const char *get_opcode_enc(int opcode)
|
||||
|
||||
static const char *get_opcode_enc_class(int opcode)
|
||||
{
|
||||
const char *tmp = opcode_encodings[opcode].encoding;
|
||||
if (tmp == NULL) {
|
||||
const char *test = "V6_"; /* HVX */
|
||||
const char *name = opcode_names[opcode];
|
||||
if (strncmp(name, test, strlen(test)) == 0) {
|
||||
return "EXT_mmvec";
|
||||
}
|
||||
}
|
||||
return opcode_enc_class_names[opcode_encodings[opcode].enc_class];
|
||||
}
|
||||
|
||||
|
||||
@@ -48,12 +48,26 @@ def gen_helper_arg_pair(f,regtype,regid,regno):
|
||||
if regno >= 0 : f.write(", ")
|
||||
f.write("int64_t %s%sV" % (regtype,regid))
|
||||
|
||||
def gen_helper_arg_ext(f,regtype,regid,regno):
|
||||
if regno > 0 : f.write(", ")
|
||||
f.write("void *%s%sV_void" % (regtype,regid))
|
||||
|
||||
def gen_helper_arg_ext_pair(f,regtype,regid,regno):
|
||||
if regno > 0 : f.write(", ")
|
||||
f.write("void *%s%sV_void" % (regtype,regid))
|
||||
|
||||
def gen_helper_arg_opn(f,regtype,regid,i,tag):
|
||||
if (hex_common.is_pair(regid)):
|
||||
gen_helper_arg_pair(f,regtype,regid,i)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_arg_ext_pair(f,regtype,regid,i)
|
||||
else:
|
||||
gen_helper_arg_pair(f,regtype,regid,i)
|
||||
elif (hex_common.is_single(regid)):
|
||||
if hex_common.is_old_val(regtype, regid, tag):
|
||||
gen_helper_arg(f,regtype,regid,i)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_arg_ext(f,regtype,regid,i)
|
||||
else:
|
||||
gen_helper_arg(f,regtype,regid,i)
|
||||
elif hex_common.is_new_val(regtype, regid, tag):
|
||||
gen_helper_arg_new(f,regtype,regid,i)
|
||||
else:
|
||||
@@ -72,25 +86,67 @@ def gen_helper_dest_decl_pair(f,regtype,regid,regno,subfield=""):
|
||||
f.write(" int64_t %s%sV%s = 0;\n" % \
|
||||
(regtype,regid,subfield))
|
||||
|
||||
def gen_helper_dest_decl_ext(f,regtype,regid):
|
||||
if (regtype == "Q"):
|
||||
f.write(" /* %s%sV is *(MMQReg *)(%s%sV_void) */\n" % \
|
||||
(regtype,regid,regtype,regid))
|
||||
else:
|
||||
f.write(" /* %s%sV is *(MMVector *)(%s%sV_void) */\n" % \
|
||||
(regtype,regid,regtype,regid))
|
||||
|
||||
def gen_helper_dest_decl_ext_pair(f,regtype,regid,regno):
|
||||
f.write(" /* %s%sV is *(MMVectorPair *))%s%sV_void) */\n" % \
|
||||
(regtype,regid,regtype, regid))
|
||||
|
||||
def gen_helper_dest_decl_opn(f,regtype,regid,i):
|
||||
if (hex_common.is_pair(regid)):
|
||||
gen_helper_dest_decl_pair(f,regtype,regid,i)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_dest_decl_ext_pair(f,regtype,regid, i)
|
||||
else:
|
||||
gen_helper_dest_decl_pair(f,regtype,regid,i)
|
||||
elif (hex_common.is_single(regid)):
|
||||
gen_helper_dest_decl(f,regtype,regid,i)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_dest_decl_ext(f,regtype,regid)
|
||||
else:
|
||||
gen_helper_dest_decl(f,regtype,regid,i)
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
|
||||
def gen_helper_src_var_ext(f,regtype,regid):
|
||||
if (regtype == "Q"):
|
||||
f.write(" /* %s%sV is *(MMQReg *)(%s%sV_void) */\n" % \
|
||||
(regtype,regid,regtype,regid))
|
||||
else:
|
||||
f.write(" /* %s%sV is *(MMVector *)(%s%sV_void) */\n" % \
|
||||
(regtype,regid,regtype,regid))
|
||||
|
||||
def gen_helper_src_var_ext_pair(f,regtype,regid,regno):
|
||||
f.write(" /* %s%sV%s is *(MMVectorPair *)(%s%sV%s_void) */\n" % \
|
||||
(regtype,regid,regno,regtype,regid,regno))
|
||||
|
||||
def gen_helper_return(f,regtype,regid,regno):
|
||||
f.write(" return %s%sV;\n" % (regtype,regid))
|
||||
|
||||
def gen_helper_return_pair(f,regtype,regid,regno):
|
||||
f.write(" return %s%sV;\n" % (regtype,regid))
|
||||
|
||||
def gen_helper_dst_write_ext(f,regtype,regid):
|
||||
return
|
||||
|
||||
def gen_helper_dst_write_ext_pair(f,regtype,regid):
|
||||
return
|
||||
|
||||
def gen_helper_return_opn(f, regtype, regid, i):
|
||||
if (hex_common.is_pair(regid)):
|
||||
gen_helper_return_pair(f,regtype,regid,i)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_dst_write_ext_pair(f,regtype,regid)
|
||||
else:
|
||||
gen_helper_return_pair(f,regtype,regid,i)
|
||||
elif (hex_common.is_single(regid)):
|
||||
gen_helper_return(f,regtype,regid,i)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_dst_write_ext(f,regtype,regid)
|
||||
else:
|
||||
gen_helper_return(f,regtype,regid,i)
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
|
||||
@@ -129,14 +185,20 @@ def gen_helper_function(f, tag, tagregs, tagimms):
|
||||
% (tag, tag))
|
||||
else:
|
||||
## The return type of the function is the type of the destination
|
||||
## register
|
||||
## register (if scalar)
|
||||
i=0
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_written(regid)):
|
||||
if (hex_common.is_pair(regid)):
|
||||
gen_helper_return_type_pair(f,regtype,regid,i)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
continue
|
||||
else:
|
||||
gen_helper_return_type_pair(f,regtype,regid,i)
|
||||
elif (hex_common.is_single(regid)):
|
||||
gen_helper_return_type(f,regtype,regid,i)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
continue
|
||||
else:
|
||||
gen_helper_return_type(f,regtype,regid,i)
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
i += 1
|
||||
@@ -145,16 +207,37 @@ def gen_helper_function(f, tag, tagregs, tagimms):
|
||||
f.write("void")
|
||||
f.write(" HELPER(%s)(CPUHexagonState *env" % tag)
|
||||
|
||||
## Arguments include the vector destination operands
|
||||
i = 1
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_written(regid)):
|
||||
if (hex_common.is_pair(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_arg_ext_pair(f,regtype,regid,i)
|
||||
else:
|
||||
continue
|
||||
elif (hex_common.is_single(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_arg_ext(f,regtype,regid,i)
|
||||
else:
|
||||
# This is the return value of the function
|
||||
continue
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
i += 1
|
||||
|
||||
## Arguments to the helper function are the source regs and immediates
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_read(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype) and
|
||||
hex_common.is_readwrite(regid)):
|
||||
continue
|
||||
gen_helper_arg_opn(f,regtype,regid,i,tag)
|
||||
i += 1
|
||||
for immlett,bits,immshift in imms:
|
||||
gen_helper_arg_imm(f,immlett)
|
||||
i += 1
|
||||
|
||||
if hex_common.need_slot(tag):
|
||||
if i > 0: f.write(", ")
|
||||
f.write("uint32_t slot")
|
||||
@@ -173,6 +256,17 @@ def gen_helper_function(f, tag, tagregs, tagimms):
|
||||
gen_helper_dest_decl_opn(f,regtype,regid,i)
|
||||
i += 1
|
||||
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_read(regid)):
|
||||
if (hex_common.is_pair(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_src_var_ext_pair(f,regtype,regid,i)
|
||||
elif (hex_common.is_single(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_helper_src_var_ext(f,regtype,regid)
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
|
||||
if 'A_FPOP' in hex_common.attribdict[tag]:
|
||||
f.write(' arch_fpop_start(env);\n');
|
||||
|
||||
@@ -192,11 +286,12 @@ def main():
|
||||
hex_common.read_semantics_file(sys.argv[1])
|
||||
hex_common.read_attribs_file(sys.argv[2])
|
||||
hex_common.read_overrides_file(sys.argv[3])
|
||||
hex_common.read_overrides_file(sys.argv[4])
|
||||
hex_common.calculate_attribs()
|
||||
tagregs = hex_common.get_tagregs()
|
||||
tagimms = hex_common.get_tagimms()
|
||||
|
||||
with open(sys.argv[4], 'w') as f:
|
||||
with open(sys.argv[5], 'w') as f:
|
||||
for tag in hex_common.tags:
|
||||
## Skip the priv instructions
|
||||
if ( "A_PRIV" in hex_common.attribdict[tag] ) :
|
||||
|
||||
@@ -94,19 +94,33 @@ def gen_helper_prototype(f, tag, tagregs, tagimms):
|
||||
f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag))
|
||||
|
||||
## Generate the qemu DEF_HELPER type for each result
|
||||
## Iterate over this list twice
|
||||
## - Emit the scalar result
|
||||
## - Emit the vector result
|
||||
i=0
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_written(regid)):
|
||||
gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i)
|
||||
if (not hex_common.is_hvx_reg(regtype)):
|
||||
gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i)
|
||||
i += 1
|
||||
|
||||
## Put the env between the outputs and inputs
|
||||
f.write(', env' )
|
||||
i += 1
|
||||
|
||||
# Second pass
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_written(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i)
|
||||
i += 1
|
||||
|
||||
## Generate the qemu type for each input operand (regs and immediates)
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_read(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype) and
|
||||
hex_common.is_readwrite(regid)):
|
||||
continue
|
||||
gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i)
|
||||
i += 1
|
||||
for immlett,bits,immshift in imms:
|
||||
@@ -121,11 +135,12 @@ def main():
|
||||
hex_common.read_semantics_file(sys.argv[1])
|
||||
hex_common.read_attribs_file(sys.argv[2])
|
||||
hex_common.read_overrides_file(sys.argv[3])
|
||||
hex_common.read_overrides_file(sys.argv[4])
|
||||
hex_common.calculate_attribs()
|
||||
tagregs = hex_common.get_tagregs()
|
||||
tagimms = hex_common.get_tagimms()
|
||||
|
||||
with open(sys.argv[4], 'w') as f:
|
||||
with open(sys.argv[5], 'w') as f:
|
||||
for tag in hex_common.tags:
|
||||
## Skip the priv instructions
|
||||
if ( "A_PRIV" in hex_common.attribdict[tag] ) :
|
||||
|
||||
@@ -44,6 +44,11 @@ int main(int argc, char *argv[])
|
||||
* Q6INSN(A2_add,"Rd32=add(Rs32,Rt32)",ATTRIBS(),
|
||||
* "Add 32-bit registers",
|
||||
* { RdV=RsV+RtV;})
|
||||
* HVX instructions have the following form
|
||||
* EXTINSN(V6_vinsertwr, "Vx32.w=vinsert(Rt32)",
|
||||
* ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VX),
|
||||
* "Insert Word Scalar into Vector",
|
||||
* VxV.uw[0] = RtV;)
|
||||
*/
|
||||
#define Q6INSN(TAG, BEH, ATTRIBS, DESCR, SEM) \
|
||||
do { \
|
||||
@@ -59,8 +64,23 @@ int main(int argc, char *argv[])
|
||||
")\n", \
|
||||
#TAG, STRINGIZE(ATTRIBS)); \
|
||||
} while (0);
|
||||
#define EXTINSN(TAG, BEH, ATTRIBS, DESCR, SEM) \
|
||||
do { \
|
||||
fprintf(outfile, "SEMANTICS( \\\n" \
|
||||
" \"%s\", \\\n" \
|
||||
" %s, \\\n" \
|
||||
" \"\"\"%s\"\"\" \\\n" \
|
||||
")\n", \
|
||||
#TAG, STRINGIZE(BEH), STRINGIZE(SEM)); \
|
||||
fprintf(outfile, "ATTRIBUTES( \\\n" \
|
||||
" \"%s\", \\\n" \
|
||||
" \"%s\" \\\n" \
|
||||
")\n", \
|
||||
#TAG, STRINGIZE(ATTRIBS)); \
|
||||
} while (0);
|
||||
#include "imported/allidefs.def"
|
||||
#undef Q6INSN
|
||||
#undef EXTINSN
|
||||
|
||||
/*
|
||||
* Process the macro definitions
|
||||
@@ -81,6 +101,19 @@ int main(int argc, char *argv[])
|
||||
")\n", \
|
||||
#MNAME, STRINGIZE(BEH), STRINGIZE(ATTRS));
|
||||
#include "imported/macros.def"
|
||||
#undef DEF_MACRO
|
||||
|
||||
/*
|
||||
* Process the macros for HVX
|
||||
*/
|
||||
#define DEF_MACRO(MNAME, BEH, ATTRS) \
|
||||
fprintf(outfile, "MACROATTRIB( \\\n" \
|
||||
" \"%s\", \\\n" \
|
||||
" \"\"\"%s\"\"\", \\\n" \
|
||||
" \"%s\" \\\n" \
|
||||
")\n", \
|
||||
#MNAME, STRINGIZE(BEH), STRINGIZE(ATTRS));
|
||||
#include "imported/allext_macros.def"
|
||||
#undef DEF_MACRO
|
||||
|
||||
fclose(outfile);
|
||||
|
||||
+244
-13
@@ -119,10 +119,95 @@ def genptr_decl(f, tag, regtype, regid, regno):
|
||||
(regtype, regid, regtype, regid))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "V"):
|
||||
if (regid in {"dd"}):
|
||||
f.write(" const int %s%sN = insn->regno[%d];\n" %\
|
||||
(regtype, regid, regno))
|
||||
f.write(" const intptr_t %s%sV_off =\n" %\
|
||||
(regtype, regid))
|
||||
if (hex_common.is_tmp_result(tag)):
|
||||
f.write(" ctx_tmp_vreg_off(ctx, %s%sN, 2, true);\n" % \
|
||||
(regtype, regid))
|
||||
else:
|
||||
f.write(" ctx_future_vreg_off(ctx, %s%sN," % \
|
||||
(regtype, regid))
|
||||
f.write(" 2, true);\n")
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" tcg_gen_addi_ptr(%s%sV, cpu_env, %s%sV_off);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
elif (regid in {"uu", "vv", "xx"}):
|
||||
f.write(" const int %s%sN = insn->regno[%d];\n" % \
|
||||
(regtype, regid, regno))
|
||||
f.write(" const intptr_t %s%sV_off =\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" offsetof(CPUHexagonState, %s%sV);\n" % \
|
||||
(regtype, regid))
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" tcg_gen_addi_ptr(%s%sV, cpu_env, %s%sV_off);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
elif (regid in {"s", "u", "v", "w"}):
|
||||
f.write(" const int %s%sN = insn->regno[%d];\n" % \
|
||||
(regtype, regid, regno))
|
||||
f.write(" const intptr_t %s%sV_off =\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" vreg_src_off(ctx, %s%sN);\n" % \
|
||||
(regtype, regid))
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \
|
||||
(regtype, regid))
|
||||
elif (regid in {"d", "x", "y"}):
|
||||
f.write(" const int %s%sN = insn->regno[%d];\n" % \
|
||||
(regtype, regid, regno))
|
||||
f.write(" const intptr_t %s%sV_off =\n" % \
|
||||
(regtype, regid))
|
||||
if (hex_common.is_tmp_result(tag)):
|
||||
f.write(" ctx_tmp_vreg_off(ctx, %s%sN, 1, true);\n" % \
|
||||
(regtype, regid))
|
||||
else:
|
||||
f.write(" ctx_future_vreg_off(ctx, %s%sN," % \
|
||||
(regtype, regid))
|
||||
f.write(" 1, true);\n");
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" tcg_gen_addi_ptr(%s%sV, cpu_env, %s%sV_off);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "Q"):
|
||||
if (regid in {"d", "e", "x"}):
|
||||
f.write(" const int %s%sN = insn->regno[%d];\n" % \
|
||||
(regtype, regid, regno))
|
||||
f.write(" const intptr_t %s%sV_off =\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" offsetof(CPUHexagonState,\n")
|
||||
f.write(" future_QRegs[%s%sN]);\n" % \
|
||||
(regtype, regid))
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" tcg_gen_addi_ptr(%s%sV, cpu_env, %s%sV_off);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
elif (regid in {"s", "t", "u", "v"}):
|
||||
f.write(" const int %s%sN = insn->regno[%d];\n" % \
|
||||
(regtype, regid, regno))
|
||||
f.write(" const intptr_t %s%sV_off =\n" %\
|
||||
(regtype, regid))
|
||||
f.write(" offsetof(CPUHexagonState, QRegs[%s%sN]);\n" % \
|
||||
(regtype, regid))
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \
|
||||
(regtype, regid))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
|
||||
def genptr_decl_new(f,regtype,regid,regno):
|
||||
def genptr_decl_new(f, tag, regtype, regid, regno):
|
||||
if (regtype == "N"):
|
||||
if (regid in {"s", "t"}):
|
||||
f.write(" TCGv %s%sN = hex_new_value[insn->regno[%d]];\n" % \
|
||||
@@ -135,6 +220,21 @@ def genptr_decl_new(f,regtype,regid,regno):
|
||||
(regtype, regid, regno))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "O"):
|
||||
if (regid == "s"):
|
||||
f.write(" const intptr_t %s%sN_num = insn->regno[%d];\n" % \
|
||||
(regtype, regid, regno))
|
||||
if (hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" const intptr_t %s%sN_off =\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" ctx_future_vreg_off(ctx, %s%sN_num," % \
|
||||
(regtype, regid))
|
||||
f.write(" 1, true);\n")
|
||||
else:
|
||||
f.write(" TCGv %s%sN = tcg_constant_tl(%s%sN_num);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
|
||||
@@ -145,7 +245,7 @@ def genptr_decl_opn(f, tag, regtype, regid, toss, numregs, i):
|
||||
if hex_common.is_old_val(regtype, regid, tag):
|
||||
genptr_decl(f,tag, regtype, regid, i)
|
||||
elif hex_common.is_new_val(regtype, regid, tag):
|
||||
genptr_decl_new(f,regtype,regid,i)
|
||||
genptr_decl_new(f, tag, regtype, regid, i)
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
else:
|
||||
@@ -159,7 +259,7 @@ def genptr_decl_imm(f,immlett):
|
||||
f.write(" int %s = insn->immed[%d];\n" % \
|
||||
(hex_common.imm_name(immlett), i))
|
||||
|
||||
def genptr_free(f,regtype,regid,regno):
|
||||
def genptr_free(f, tag, regtype, regid, regno):
|
||||
if (regtype == "R"):
|
||||
if (regid in {"dd", "ss", "tt", "xx", "yy"}):
|
||||
f.write(" tcg_temp_free_i64(%s%sV);\n" % (regtype, regid))
|
||||
@@ -182,33 +282,51 @@ def genptr_free(f,regtype,regid,regno):
|
||||
elif (regtype == "M"):
|
||||
if (regid != "u"):
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "V"):
|
||||
if (regid in {"dd", "uu", "vv", "xx", \
|
||||
"d", "s", "u", "v", "w", "x", "y"}):
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" tcg_temp_free_ptr(%s%sV);\n" % \
|
||||
(regtype, regid))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "Q"):
|
||||
if (regid in {"d", "e", "s", "t", "u", "v", "x"}):
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" tcg_temp_free_ptr(%s%sV);\n" % \
|
||||
(regtype, regid))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
|
||||
def genptr_free_new(f,regtype,regid,regno):
|
||||
def genptr_free_new(f, tag, regtype, regid, regno):
|
||||
if (regtype == "N"):
|
||||
if (regid not in {"s", "t"}):
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "P"):
|
||||
if (regid not in {"t", "u", "v"}):
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "O"):
|
||||
if (regid != "s"):
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
|
||||
def genptr_free_opn(f,regtype,regid,i,tag):
|
||||
if (hex_common.is_pair(regid)):
|
||||
genptr_free(f,regtype,regid,i)
|
||||
genptr_free(f, tag, regtype, regid, i)
|
||||
elif (hex_common.is_single(regid)):
|
||||
if hex_common.is_old_val(regtype, regid, tag):
|
||||
genptr_free(f,regtype,regid,i)
|
||||
genptr_free(f, tag, regtype, regid, i)
|
||||
elif hex_common.is_new_val(regtype, regid, tag):
|
||||
genptr_free_new(f,regtype,regid,i)
|
||||
genptr_free_new(f, tag, regtype, regid, i)
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
|
||||
def genptr_src_read(f,regtype,regid):
|
||||
def genptr_src_read(f, tag, regtype, regid):
|
||||
if (regtype == "R"):
|
||||
if (regid in {"ss", "tt", "xx", "yy"}):
|
||||
f.write(" tcg_gen_concat_i32_i64(%s%sV, hex_gpr[%s%sN],\n" % \
|
||||
@@ -238,6 +356,47 @@ def genptr_src_read(f,regtype,regid):
|
||||
elif (regtype == "M"):
|
||||
if (regid != "u"):
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "V"):
|
||||
if (regid in {"uu", "vv", "xx"}):
|
||||
f.write(" tcg_gen_gvec_mov(MO_64, %s%sV_off,\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" vreg_src_off(ctx, %s%sN),\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" sizeof(MMVector), sizeof(MMVector));\n")
|
||||
f.write(" tcg_gen_gvec_mov(MO_64,\n")
|
||||
f.write(" %s%sV_off + sizeof(MMVector),\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" vreg_src_off(ctx, %s%sN ^ 1),\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" sizeof(MMVector), sizeof(MMVector));\n")
|
||||
elif (regid in {"s", "u", "v", "w"}):
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" tcg_gen_addi_ptr(%s%sV, cpu_env, %s%sV_off);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
elif (regid in {"x", "y"}):
|
||||
f.write(" tcg_gen_gvec_mov(MO_64, %s%sV_off,\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" vreg_src_off(ctx, %s%sN),\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" sizeof(MMVector), sizeof(MMVector));\n")
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" tcg_gen_addi_ptr(%s%sV, cpu_env, %s%sV_off);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "Q"):
|
||||
if (regid in {"s", "t", "u", "v"}):
|
||||
if (not hex_common.skip_qemu_helper(tag)):
|
||||
f.write(" tcg_gen_addi_ptr(%s%sV, cpu_env, %s%sV_off);\n" % \
|
||||
(regtype, regid, regtype, regid))
|
||||
elif (regid in {"x"}):
|
||||
f.write(" tcg_gen_gvec_mov(MO_64, %s%sV_off,\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" offsetof(CPUHexagonState, QRegs[%s%sN]),\n" % \
|
||||
(regtype, regid))
|
||||
f.write(" sizeof(MMQReg), sizeof(MMQReg));\n")
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
|
||||
@@ -248,15 +407,18 @@ def genptr_src_read_new(f,regtype,regid):
|
||||
elif (regtype == "P"):
|
||||
if (regid not in {"t", "u", "v"}):
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "O"):
|
||||
if (regid != "s"):
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
|
||||
def genptr_src_read_opn(f,regtype,regid,tag):
|
||||
if (hex_common.is_pair(regid)):
|
||||
genptr_src_read(f,regtype,regid)
|
||||
genptr_src_read(f, tag, regtype, regid)
|
||||
elif (hex_common.is_single(regid)):
|
||||
if hex_common.is_old_val(regtype, regid, tag):
|
||||
genptr_src_read(f,regtype,regid)
|
||||
genptr_src_read(f, tag, regtype, regid)
|
||||
elif hex_common.is_new_val(regtype, regid, tag):
|
||||
genptr_src_read_new(f,regtype,regid)
|
||||
else:
|
||||
@@ -331,11 +493,68 @@ def genptr_dst_write(f, tag, regtype, regid):
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
|
||||
def genptr_dst_write_ext(f, tag, regtype, regid, newv="EXT_DFL"):
|
||||
if (regtype == "V"):
|
||||
if (regid in {"dd", "xx", "yy"}):
|
||||
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
|
||||
is_predicated = "true"
|
||||
else:
|
||||
is_predicated = "false"
|
||||
f.write(" gen_log_vreg_write_pair(ctx, %s%sV_off, %s%sN, " % \
|
||||
(regtype, regid, regtype, regid))
|
||||
f.write("%s, insn->slot, %s);\n" % \
|
||||
(newv, is_predicated))
|
||||
f.write(" ctx_log_vreg_write_pair(ctx, %s%sN, %s,\n" % \
|
||||
(regtype, regid, newv))
|
||||
f.write(" %s);\n" % (is_predicated))
|
||||
elif (regid in {"d", "x", "y"}):
|
||||
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
|
||||
is_predicated = "true"
|
||||
else:
|
||||
is_predicated = "false"
|
||||
f.write(" gen_log_vreg_write(ctx, %s%sV_off, %s%sN, %s, " % \
|
||||
(regtype, regid, regtype, regid, newv))
|
||||
f.write("insn->slot, %s);\n" % \
|
||||
(is_predicated))
|
||||
f.write(" ctx_log_vreg_write(ctx, %s%sN, %s, %s);\n" % \
|
||||
(regtype, regid, newv, is_predicated))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
elif (regtype == "Q"):
|
||||
if (regid in {"d", "e", "x"}):
|
||||
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
|
||||
is_predicated = "true"
|
||||
else:
|
||||
is_predicated = "false"
|
||||
f.write(" gen_log_qreg_write(%s%sV_off, %s%sN, %s, " % \
|
||||
(regtype, regid, regtype, regid, newv))
|
||||
f.write("insn->slot, %s);\n" % (is_predicated))
|
||||
f.write(" ctx_log_qreg_write(ctx, %s%sN, %s);\n" % \
|
||||
(regtype, regid, is_predicated))
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
else:
|
||||
print("Bad register parse: ", regtype, regid)
|
||||
|
||||
def genptr_dst_write_opn(f,regtype, regid, tag):
|
||||
if (hex_common.is_pair(regid)):
|
||||
genptr_dst_write(f, tag, regtype, regid)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
if (hex_common.is_tmp_result(tag)):
|
||||
genptr_dst_write_ext(f, tag, regtype, regid, "EXT_TMP")
|
||||
else:
|
||||
genptr_dst_write_ext(f, tag, regtype, regid)
|
||||
else:
|
||||
genptr_dst_write(f, tag, regtype, regid)
|
||||
elif (hex_common.is_single(regid)):
|
||||
genptr_dst_write(f, tag, regtype, regid)
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
if (hex_common.is_new_result(tag)):
|
||||
genptr_dst_write_ext(f, tag, regtype, regid, "EXT_NEW")
|
||||
if (hex_common.is_tmp_result(tag)):
|
||||
genptr_dst_write_ext(f, tag, regtype, regid, "EXT_TMP")
|
||||
else:
|
||||
genptr_dst_write_ext(f, tag, regtype, regid, "EXT_DFL")
|
||||
else:
|
||||
genptr_dst_write(f, tag, regtype, regid)
|
||||
else:
|
||||
print("Bad register parse: ",regtype,regid,toss,numregs)
|
||||
|
||||
@@ -406,13 +625,24 @@ def gen_tcg_func(f, tag, regs, imms):
|
||||
## If there is a scalar result, it is the return type
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_written(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype)):
|
||||
continue
|
||||
gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i)
|
||||
i += 1
|
||||
if (i > 0): f.write(", ")
|
||||
f.write("cpu_env")
|
||||
i=1
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_written(regid)):
|
||||
if (not hex_common.is_hvx_reg(regtype)):
|
||||
continue
|
||||
gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i)
|
||||
i += 1
|
||||
for regtype,regid,toss,numregs in regs:
|
||||
if (hex_common.is_read(regid)):
|
||||
if (hex_common.is_hvx_reg(regtype) and
|
||||
hex_common.is_readwrite(regid)):
|
||||
continue
|
||||
gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i)
|
||||
i += 1
|
||||
for immlett,bits,immshift in imms:
|
||||
@@ -445,11 +675,12 @@ def main():
|
||||
hex_common.read_semantics_file(sys.argv[1])
|
||||
hex_common.read_attribs_file(sys.argv[2])
|
||||
hex_common.read_overrides_file(sys.argv[3])
|
||||
hex_common.read_overrides_file(sys.argv[4])
|
||||
hex_common.calculate_attribs()
|
||||
tagregs = hex_common.get_tagregs()
|
||||
tagimms = hex_common.get_tagimms()
|
||||
|
||||
with open(sys.argv[4], 'w') as f:
|
||||
with open(sys.argv[5], 'w') as f:
|
||||
f.write("#ifndef HEXAGON_TCG_FUNCS_H\n")
|
||||
f.write("#define HEXAGON_TCG_FUNCS_H\n\n")
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,13 +19,16 @@
|
||||
#include "cpu.h"
|
||||
#include "internal.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "tcg/tcg-op-gvec.h"
|
||||
#include "insn.h"
|
||||
#include "opcodes.h"
|
||||
#include "translate.h"
|
||||
#define QEMU_GENERATE /* Used internally by macros.h */
|
||||
#include "macros.h"
|
||||
#include "mmvec/macros.h"
|
||||
#undef QEMU_GENERATE
|
||||
#include "gen_tcg.h"
|
||||
#include "gen_tcg_hvx.h"
|
||||
|
||||
static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
|
||||
{
|
||||
@@ -165,6 +168,9 @@ static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num,
|
||||
} else if (reg_num == HEX_REG_QEMU_INSN_CNT) {
|
||||
tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_INSN_CNT],
|
||||
ctx->num_insns);
|
||||
} else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
|
||||
tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT],
|
||||
ctx->num_hvx_insns);
|
||||
} else {
|
||||
tcg_gen_mov_tl(dest, hex_gpr[reg_num]);
|
||||
}
|
||||
@@ -191,6 +197,12 @@ static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num,
|
||||
tcg_gen_concat_i32_i64(dest, pkt_cnt, insn_cnt);
|
||||
tcg_temp_free(pkt_cnt);
|
||||
tcg_temp_free(insn_cnt);
|
||||
} else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
|
||||
TCGv hvx_cnt = tcg_temp_new();
|
||||
tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT],
|
||||
ctx->num_hvx_insns);
|
||||
tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]);
|
||||
tcg_temp_free(hvx_cnt);
|
||||
} else {
|
||||
tcg_gen_concat_i32_i64(dest,
|
||||
hex_gpr[reg_num],
|
||||
@@ -226,6 +238,9 @@ static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num,
|
||||
if (reg_num == HEX_REG_QEMU_INSN_CNT) {
|
||||
ctx->num_insns = 0;
|
||||
}
|
||||
if (reg_num == HEX_REG_QEMU_HVX_CNT) {
|
||||
ctx->num_hvx_insns = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +262,9 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
|
||||
ctx->num_packets = 0;
|
||||
ctx->num_insns = 0;
|
||||
}
|
||||
if (reg_num == HEX_REG_QEMU_HVX_CNT) {
|
||||
ctx->num_hvx_insns = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,5 +464,175 @@ static TCGv gen_8bitsof(TCGv result, TCGv value)
|
||||
return result;
|
||||
}
|
||||
|
||||
static intptr_t vreg_src_off(DisasContext *ctx, int num)
|
||||
{
|
||||
intptr_t offset = offsetof(CPUHexagonState, VRegs[num]);
|
||||
|
||||
if (test_bit(num, ctx->vregs_select)) {
|
||||
offset = ctx_future_vreg_off(ctx, num, 1, false);
|
||||
}
|
||||
if (test_bit(num, ctx->vregs_updated_tmp)) {
|
||||
offset = ctx_tmp_vreg_off(ctx, num, 1, false);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void gen_log_vreg_write(DisasContext *ctx, intptr_t srcoff, int num,
|
||||
VRegWriteType type, int slot_num,
|
||||
bool is_predicated)
|
||||
{
|
||||
TCGLabel *label_end = NULL;
|
||||
intptr_t dstoff;
|
||||
|
||||
if (is_predicated) {
|
||||
TCGv cancelled = tcg_temp_local_new();
|
||||
label_end = gen_new_label();
|
||||
|
||||
/* Don't do anything if the slot was cancelled */
|
||||
tcg_gen_extract_tl(cancelled, hex_slot_cancelled, slot_num, 1);
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, cancelled, 0, label_end);
|
||||
tcg_temp_free(cancelled);
|
||||
}
|
||||
|
||||
if (type != EXT_TMP) {
|
||||
dstoff = ctx_future_vreg_off(ctx, num, 1, true);
|
||||
tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
|
||||
sizeof(MMVector), sizeof(MMVector));
|
||||
tcg_gen_ori_tl(hex_VRegs_updated, hex_VRegs_updated, 1 << num);
|
||||
} else {
|
||||
dstoff = ctx_tmp_vreg_off(ctx, num, 1, false);
|
||||
tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
|
||||
sizeof(MMVector), sizeof(MMVector));
|
||||
}
|
||||
|
||||
if (is_predicated) {
|
||||
gen_set_label(label_end);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_log_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num,
|
||||
VRegWriteType type, int slot_num,
|
||||
bool is_predicated)
|
||||
{
|
||||
gen_log_vreg_write(ctx, srcoff, num ^ 0, type, slot_num, is_predicated);
|
||||
srcoff += sizeof(MMVector);
|
||||
gen_log_vreg_write(ctx, srcoff, num ^ 1, type, slot_num, is_predicated);
|
||||
}
|
||||
|
||||
static void gen_log_qreg_write(intptr_t srcoff, int num, int vnew,
|
||||
int slot_num, bool is_predicated)
|
||||
{
|
||||
TCGLabel *label_end = NULL;
|
||||
intptr_t dstoff;
|
||||
|
||||
if (is_predicated) {
|
||||
TCGv cancelled = tcg_temp_local_new();
|
||||
label_end = gen_new_label();
|
||||
|
||||
/* Don't do anything if the slot was cancelled */
|
||||
tcg_gen_extract_tl(cancelled, hex_slot_cancelled, slot_num, 1);
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, cancelled, 0, label_end);
|
||||
tcg_temp_free(cancelled);
|
||||
}
|
||||
|
||||
dstoff = offsetof(CPUHexagonState, future_QRegs[num]);
|
||||
tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMQReg), sizeof(MMQReg));
|
||||
|
||||
if (is_predicated) {
|
||||
tcg_gen_ori_tl(hex_QRegs_updated, hex_QRegs_updated, 1 << num);
|
||||
gen_set_label(label_end);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src,
|
||||
bool aligned)
|
||||
{
|
||||
TCGv_i64 tmp = tcg_temp_new_i64();
|
||||
if (aligned) {
|
||||
tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1));
|
||||
}
|
||||
for (int i = 0; i < sizeof(MMVector) / 8; i++) {
|
||||
tcg_gen_qemu_ld64(tmp, src, ctx->mem_idx);
|
||||
tcg_gen_addi_tl(src, src, 8);
|
||||
tcg_gen_st_i64(tmp, cpu_env, dstoff + i * 8);
|
||||
}
|
||||
tcg_temp_free_i64(tmp);
|
||||
}
|
||||
|
||||
static void gen_vreg_store(DisasContext *ctx, Insn *insn, Packet *pkt,
|
||||
TCGv EA, intptr_t srcoff, int slot, bool aligned)
|
||||
{
|
||||
intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
|
||||
intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
|
||||
|
||||
if (is_gather_store_insn(insn, pkt)) {
|
||||
TCGv sl = tcg_constant_tl(slot);
|
||||
gen_helper_gather_store(cpu_env, EA, sl);
|
||||
return;
|
||||
}
|
||||
|
||||
tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
|
||||
if (aligned) {
|
||||
tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
|
||||
~((int32_t)sizeof(MMVector) - 1));
|
||||
} else {
|
||||
tcg_gen_mov_tl(hex_vstore_addr[slot], EA);
|
||||
}
|
||||
tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
|
||||
|
||||
/* Copy the data to the vstore buffer */
|
||||
tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
|
||||
/* Set the mask to all 1's */
|
||||
tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL);
|
||||
}
|
||||
|
||||
static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
|
||||
intptr_t bitsoff, int slot, bool invert)
|
||||
{
|
||||
intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
|
||||
intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
|
||||
|
||||
tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
|
||||
tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
|
||||
~((int32_t)sizeof(MMVector) - 1));
|
||||
tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
|
||||
|
||||
/* Copy the data to the vstore buffer */
|
||||
tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
|
||||
/* Copy the mask */
|
||||
tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg));
|
||||
if (invert) {
|
||||
tcg_gen_gvec_not(MO_64, maskoff, maskoff,
|
||||
sizeof(MMQReg), sizeof(MMQReg));
|
||||
}
|
||||
}
|
||||
|
||||
static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff)
|
||||
{
|
||||
TCGv_i64 tmp = tcg_temp_new_i64();
|
||||
TCGv_i64 word = tcg_temp_new_i64();
|
||||
TCGv_i64 bits = tcg_temp_new_i64();
|
||||
TCGv_i64 mask = tcg_temp_new_i64();
|
||||
TCGv_i64 zero = tcg_constant_i64(0);
|
||||
TCGv_i64 ones = tcg_constant_i64(~0);
|
||||
|
||||
for (int i = 0; i < sizeof(MMVector) / 8; i++) {
|
||||
tcg_gen_ld_i64(tmp, cpu_env, srcoff + i * 8);
|
||||
tcg_gen_movi_i64(mask, 0);
|
||||
|
||||
for (int j = 0; j < 8; j += size) {
|
||||
tcg_gen_extract_i64(word, tmp, j * 8, size * 8);
|
||||
tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero);
|
||||
tcg_gen_deposit_i64(mask, mask, bits, j, size);
|
||||
}
|
||||
|
||||
tcg_gen_st8_i64(mask, cpu_env, dstoff + i);
|
||||
}
|
||||
tcg_temp_free_i64(tmp);
|
||||
tcg_temp_free_i64(word);
|
||||
tcg_temp_free_i64(bits);
|
||||
tcg_temp_free_i64(mask);
|
||||
}
|
||||
|
||||
#include "tcg_funcs_generated.c.inc"
|
||||
#include "tcg_func_table_generated.c.inc"
|
||||
|
||||
@@ -23,6 +23,8 @@ 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)
|
||||
DEF_HELPER_2(commit_store, void, env, int)
|
||||
DEF_HELPER_3(gather_store, void, env, i32, int)
|
||||
DEF_HELPER_1(commit_hvx_stores, void, env)
|
||||
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)
|
||||
@@ -90,4 +92,18 @@ DEF_HELPER_4(sffms_lib, f32, env, f32, f32, f32)
|
||||
DEF_HELPER_3(dfmpyfix, f64, env, f64, f64)
|
||||
DEF_HELPER_4(dfmpyhh, f64, env, f64, f64, f64)
|
||||
|
||||
/* Histogram instructions */
|
||||
DEF_HELPER_1(vhist, void, env)
|
||||
DEF_HELPER_1(vhistq, void, env)
|
||||
DEF_HELPER_1(vwhist256, void, env)
|
||||
DEF_HELPER_1(vwhist256q, void, env)
|
||||
DEF_HELPER_1(vwhist256_sat, void, env)
|
||||
DEF_HELPER_1(vwhist256q_sat, void, env)
|
||||
DEF_HELPER_1(vwhist128, void, env)
|
||||
DEF_HELPER_1(vwhist128q, void, env)
|
||||
DEF_HELPER_2(vwhist128m, void, env, s32)
|
||||
DEF_HELPER_2(vwhist128qm, void, env, s32)
|
||||
|
||||
DEF_HELPER_2(probe_pkt_scalar_store_s0, void, env, int)
|
||||
DEF_HELPER_2(probe_hvx_stores, void, env, int)
|
||||
DEF_HELPER_3(probe_pkt_scalar_hvx_stores, void, env, int, int)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define HEXAGON_ARCH_TYPES_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "mmvec/mmvec.h"
|
||||
#include "qemu/int128.h"
|
||||
|
||||
/*
|
||||
@@ -35,4 +36,8 @@ typedef uint64_t size8u_t;
|
||||
typedef int64_t size8s_t;
|
||||
typedef Int128 size16s_t;
|
||||
|
||||
typedef MMVector mmvector_t;
|
||||
typedef MMVectorPair mmvector_pair_t;
|
||||
typedef MMQReg mmqret_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -145,6 +145,9 @@ def compute_tag_immediates(tag):
|
||||
## P predicate register
|
||||
## R GPR register
|
||||
## M modifier register
|
||||
## Q HVX predicate vector
|
||||
## V HVX vector register
|
||||
## O HVX new vector register
|
||||
## regid can be one of the following
|
||||
## d, e destination register
|
||||
## dd destination register pair
|
||||
@@ -180,6 +183,9 @@ def is_readwrite(regid):
|
||||
def is_scalar_reg(regtype):
|
||||
return regtype in "RPC"
|
||||
|
||||
def is_hvx_reg(regtype):
|
||||
return regtype in "VQ"
|
||||
|
||||
def is_old_val(regtype, regid, tag):
|
||||
return regtype+regid+'V' in semdict[tag]
|
||||
|
||||
@@ -203,6 +209,13 @@ def need_ea(tag):
|
||||
def skip_qemu_helper(tag):
|
||||
return tag in overrides.keys()
|
||||
|
||||
def is_tmp_result(tag):
|
||||
return ('A_CVI_TMP' in attribdict[tag] or
|
||||
'A_CVI_TMP_DST' in attribdict[tag])
|
||||
|
||||
def is_new_result(tag):
|
||||
return ('A_CVI_NEW' in attribdict[tag])
|
||||
|
||||
def imm_name(immlett):
|
||||
return "%siV" % immlett
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ enum {
|
||||
/* Use reserved control registers for qemu execution counts */
|
||||
HEX_REG_QEMU_PKT_CNT = 52,
|
||||
HEX_REG_QEMU_INSN_CNT = 53,
|
||||
HEX_REG_QEMU_HVX_CNT = 54,
|
||||
HEX_REG_UTIMERLO = 62,
|
||||
HEX_REG_UTIMERHI = 63,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Top level file for all instruction set extensions
|
||||
*/
|
||||
#define EXTNAME mmvec
|
||||
#define EXTSTR "mmvec"
|
||||
#include "mmvec/ext.idef"
|
||||
#undef EXTNAME
|
||||
#undef EXTSTR
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Top level file for all instruction set extensions
|
||||
*/
|
||||
#define EXTNAME mmvec
|
||||
#define EXTSTR "mmvec"
|
||||
#include "mmvec/macros.def"
|
||||
#undef EXTNAME
|
||||
#undef EXTSTR
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define EXTNAME mmvec
|
||||
#include "mmvec/encode_ext.def"
|
||||
#undef EXTNAME
|
||||
@@ -28,3 +28,4 @@
|
||||
#include "shift.idef"
|
||||
#include "system.idef"
|
||||
#include "subinsns.idef"
|
||||
#include "allext.idef"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user