HVX is a set of wide vector instructions. Machine state includes vector registers (VRegs) vector predicate registers (QRegs) temporary registers for packet semantics store buffer (masked stores and scatter/gather)
Signed-off-by: Taylor Simpson <tsimp...@quicinc.com> --- target/hexagon/cpu.c | 51 +++++++++++++++++++++++++- target/hexagon/cpu.h | 42 +++++++++++++++++++++ target/hexagon/insn.h | 16 ++++++++ target/hexagon/internal.h | 2 + target/hexagon/mmvec/mmvec.h | 87 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 target/hexagon/mmvec/mmvec.h diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 26bf987..e149a79 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -104,6 +104,39 @@ static void print_reg(FILE *f, CPUHexagonState *env, int regnum) : env->gpr[regnum]); } +static void print_vreg(FILE *f, CPUHexagonState *env, int regnum) +{ + int i; + fprintf(f, " v%d = (", regnum); + fprintf(f, "0x%02x", env->VRegs[regnum].ub[MAX_VEC_SIZE_BYTES - 1]); + for (i = MAX_VEC_SIZE_BYTES - 2; i >= 0; i--) { + fprintf(f, ", 0x%02x", env->VRegs[regnum].ub[i]); + } + fprintf(f, ")\n"); +} + +void hexagon_debug_vreg(CPUHexagonState *env, int regnum) +{ + print_vreg(stdout, env, regnum); +} + +static void print_qreg(FILE *f, CPUHexagonState *env, int regnum) +{ + int i; + fprintf(f, " q%d = (", regnum); + fprintf(f, ", 0x%02x", + env->QRegs[regnum].ub[MAX_VEC_SIZE_BYTES / 8 - 1]); + for (i = MAX_VEC_SIZE_BYTES / 8 - 2; i >= 0; i--) { + fprintf(f, ", 0x%02x", env->QRegs[regnum].ub[i]); + } + fprintf(f, ")\n"); +} + +void hexagon_debug_qreg(CPUHexagonState *env, int regnum) +{ + print_qreg(stdout, env, regnum); +} + static void hexagon_dump(CPUHexagonState *env, FILE *f) { static target_ulong last_pc; @@ -148,6 +181,22 @@ static void hexagon_dump(CPUHexagonState *env, FILE *f) print_reg(f, env, HEX_REG_CS1); #endif fprintf(f, "}\n"); + +/* + * The HVX register dump takes up a ton of space in the log + * Don't print it unless it is needed + */ +#define DUMP_HVX 0 +#if DUMP_HVX + fprintf(f, "Vector Registers = {\n"); + for (i = 0; i < NUM_VREGS; i++) { + print_vreg(f, env, i); + } + for (i = 0; i < NUM_QREGS; i++) { + print_qreg(f, env, i); + } + fprintf(f, "}\n"); +#endif } static void hexagon_dump_state(CPUState *cs, FILE *f, int flags) @@ -273,7 +322,7 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data) cc->gdb_core_xml_file = "hexagon-core.xml"; 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; #ifdef CONFIG_TCG diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index bb3fcd5..3217ba2 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -30,6 +30,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 #ifdef CONFIG_USER_ONLY @@ -42,6 +43,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" @@ -60,6 +62,19 @@ struct MemLog { uint64_t data64; }; +typedef struct { + target_ulong va; + int size; + mmvector_t mask; + mmvector_t data; +} vstorelog_t; + +typedef struct { + unsigned char cdata[256]; + uint32_t range; + uint8_t format; +} mem_access_info_t; + #define EXEC_STATUS_OK 0x0000 #define EXEC_STATUS_STOP 0x0002 #define EXEC_STATUS_REPLAY 0x0010 @@ -72,6 +87,9 @@ struct MemLog { #define CLEAR_EXCEPTION (env->status &= (~EXEC_STATUS_EXCEPTION)) #define SET_EXCEPTION (env->status |= EXEC_STATUS_EXCEPTION) +/* This needs to be large enough for all the reads and writes in a packet */ +#define TEMP_VECTORS_MAX 25 + struct CPUHexagonState { target_ulong gpr[TOTAL_PER_THREAD_REGS]; target_ulong pred[NUM_PREGS]; @@ -110,6 +128,30 @@ struct CPUHexagonState { target_ulong is_gather_store_insn; target_ulong gather_issued; + + mmvector_t VRegs[NUM_VREGS]; + mmvector_t future_VRegs[NUM_VREGS]; + mmvector_t tmp_VRegs[NUM_VREGS]; + + VRegMask VRegs_updated_tmp; + VRegMask VRegs_updated; + VRegMask VRegs_select; + + mmqreg_t QRegs[NUM_QREGS]; + mmqreg_t future_QRegs[NUM_QREGS]; + QRegMask QRegs_updated; + + vstorelog_t vstore[VSTORES_MAX]; + uint8_t store_pending[VSTORES_MAX]; + uint8_t vstore_pending[VSTORES_MAX]; + uint8_t vtcm_pending; + vtcm_storelog_t vtcm_log; + mem_access_info_t mem_access[SLOTS_MAX]; + + int status; + + mmvector_t temp_vregs[TEMP_VECTORS_MAX]; + mmqreg_t temp_qregs[TEMP_VECTORS_MAX]; }; #define HEXAGON_CPU_CLASS(klass) \ diff --git a/target/hexagon/insn.h b/target/hexagon/insn.h index 10be165..7456f11 100644 --- a/target/hexagon/insn.h +++ b/target/hexagon/insn.h @@ -49,12 +49,16 @@ struct Instruction { size4u_t is_dcfetch:1; /* Has an A_DCFETCH attribute */ size4u_t is_load:1; /* Has A_LOAD attribute */ size4u_t is_store:1; /* Has A_STORE attribute */ + size4u_t is_vmem_ld:1; /* Has an A_LOAD and an A_VMEM attribute */ + size4u_t is_vmem_st:1; /* Has an A_STORE and an A_VMEM attribute */ + size4u_t is_scatgath:1; /* Has an A_CVI_GATHER or A_CVI_SCATTER attr */ size4u_t is_memop:1; /* Has A_MEMOP attribute */ size4u_t is_dealloc:1; /* Is a dealloc return or dealloc frame */ size4u_t is_aia:1; /* Is a post increment */ size4u_t is_endloop:1; /* This is an end of loop */ size4u_t is_2nd_jump:1; /* This is the second jump of a dual-jump packet */ size4u_t new_value_producer_slot:4; + size4u_t hvx_resource:8; size4s_t immed[IMMEDS_MAX]; /* immediate field */ }; @@ -121,10 +125,22 @@ struct Packet { /* Misc */ size8u_t num_rops:4; /* Num risc ops in the packet */ + size8u_t pkt_has_vtcm_access:1; /* Is a vmem access going to VTCM */ size8u_t pkt_access_count:2; /* Is a vmem access going to VTCM */ size8u_t pkt_ldaccess_l2:2; /* vmem ld access to l2 */ size8u_t pkt_ldaccess_vtcm:2; /* vmem ld access to vtcm */ + /* Count the types of HVX instructions */ + size8u_t pkt_hvx_va:4; + size8u_t pkt_hvx_vx:4; + size8u_t pkt_hvx_vp:4; + size8u_t pkt_hvx_vs:4; + size8u_t pkt_hvx_all:4; + size8u_t pkt_hvx_none:4; + + size8u_t pkt_has_hvx:1; + size8u_t pkt_has_extension:1; + insn_t insn[INSTRUCTIONS_MAX]; }; diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h index 56fb372..062f47b 100644 --- a/target/hexagon/internal.h +++ b/target/hexagon/internal.h @@ -39,6 +39,8 @@ extern int hexagon_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); extern int hexagon_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +extern void hexagon_debug_vreg(CPUHexagonState *env, int regnum); +extern void hexagon_debug_qreg(CPUHexagonState *env, int regnum); extern void hexagon_debug(CPUHexagonState *env); #if COUNT_HEX_HELPERS diff --git a/target/hexagon/mmvec/mmvec.h b/target/hexagon/mmvec/mmvec.h new file mode 100644 index 0000000..19c607e --- /dev/null +++ b/target/hexagon/mmvec/mmvec.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MMVEC_H +#define MMVEC_H + +#define MAX_VEC_SIZE_LOGBYTES 7 +#define MAX_VEC_SIZE_BYTES (1 << MAX_VEC_SIZE_LOGBYTES) + +#define NUM_VREGS 32 +#define NUM_QREGS 4 + +typedef uint32_t VRegMask; /* at least NUM_VREGS bits */ +typedef uint32_t QRegMask; /* at least NUM_QREGS bits */ + +#define VECTOR_SIZE_BYTE (fVECSIZE()) + +typedef union { + uint64_t ud[MAX_VEC_SIZE_BYTES / 8]; + int64_t d[MAX_VEC_SIZE_BYTES / 8]; + uint32_t uw[MAX_VEC_SIZE_BYTES / 4]; + int32_t w[MAX_VEC_SIZE_BYTES / 4]; + uint16_t uh[MAX_VEC_SIZE_BYTES / 2]; + int16_t h[MAX_VEC_SIZE_BYTES / 2]; + uint8_t ub[MAX_VEC_SIZE_BYTES / 1]; + int8_t b[MAX_VEC_SIZE_BYTES / 1]; +} mmvector_t; + +typedef union { + uint64_t ud[2 * MAX_VEC_SIZE_BYTES / 8]; + int64_t d[2 * MAX_VEC_SIZE_BYTES / 8]; + uint32_t uw[2 * MAX_VEC_SIZE_BYTES / 4]; + int32_t w[2 * MAX_VEC_SIZE_BYTES / 4]; + uint16_t uh[2 * MAX_VEC_SIZE_BYTES / 2]; + int16_t h[2 * MAX_VEC_SIZE_BYTES / 2]; + uint8_t ub[2 * MAX_VEC_SIZE_BYTES / 1]; + int8_t b[2 * MAX_VEC_SIZE_BYTES / 1]; + mmvector_t v[2]; +} mmvector_pair_t; + +typedef union { + uint64_t ud[MAX_VEC_SIZE_BYTES / 8 / 8]; + int64_t d[MAX_VEC_SIZE_BYTES / 8 / 8]; + uint32_t uw[MAX_VEC_SIZE_BYTES / 4 / 8]; + int32_t w[MAX_VEC_SIZE_BYTES / 4 / 8]; + uint16_t uh[MAX_VEC_SIZE_BYTES / 2 / 8]; + int16_t h[MAX_VEC_SIZE_BYTES / 2 / 8]; + uint8_t ub[MAX_VEC_SIZE_BYTES / 1 / 8]; + int8_t b[MAX_VEC_SIZE_BYTES / 1 / 8]; +} mmqreg_t; + +typedef struct { + mmvector_t data; + mmvector_t mask; + mmvector_pair_t offsets; + int size; + target_ulong va_base; + target_ulong va[MAX_VEC_SIZE_BYTES]; + int oob_access; + int op; + int op_size; +} vtcm_storelog_t; + + +/* Types of vector register assignment */ +typedef enum { + EXT_DFL, /* Default */ + EXT_NEW, /* New - value used in the same packet */ + EXT_TMP /* Temp - value used but not stored to register */ +} vector_dst_type_t; + +#endif + -- 2.7.4