* [PATCH v5 00/35] Hexagon system emulation, Part 1/3
@ 2026-03-11 3:48 Brian Cain
2026-03-11 3:48 ` [PATCH v5 01/35] docs: Add hexagon sysemu docs Brian Cain
` (34 more replies)
0 siblings, 35 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo
This is Part 1 of the hexagon system emulation (sysemu) patch series,
providing the foundational target infrastructure needed for full-system
emulation of the Qualcomm Hexagon DSP.
Changes since v4:
- Moved lock infrastructure (hex_lock_state_t enum, lock fields,
CPU_INTERRUPT_*_UNLOCK) and TLB lock macros into "Add stubs for
modify_ssr/get_exe_mode" where they are first used
- Renamed "Add locks, id, next_PC to state" to "Add cpu modes, mmu
indices, next_PC to state" to reflect remaining content
- Removed hvx_contexts field and hvx-contexts property from this
series
- Used G_GNUC_UNUSED instead of (void) casts to suppress
unused-variable warnings for sysemu source register numbers
in hex_common.py
Previous versions:
v4: https://lore.kernel.org/qemu-devel/20260309144822.877695-1-brian.cain@oss.qualcomm.com/
v3: https://lore.kernel.org/qemu-devel/20260227203627.932864-1-brian.cain@oss.qualcomm.com/
v2: https://lore.kernel.org/qemu-devel/20250902034715.1947718-1-brian.cain@oss.qualcomm.com/
v1: https://lore.kernel.org/qemu-devel/20250301052628.1011210-1-brian.cain@oss.qualcomm.com/
Brian Cain (35):
docs: Add hexagon sysemu docs
docs/system: Add hexagon CPU emulation
target/hexagon: Fix badva reference, delete CAUSE
target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof
target/hexagon: Handle system/guest registers in gen_analyze_funcs.py
and hex_common.py
target/hexagon: Suppress unused-variable warnings for sysemu source
regs
target/hexagon: Make gen_exception_end_tb non-static
target/hexagon: Switch to tag_ignore(), generate via
get_{user,sys}_tags()
target/hexagon: Add privilege check, use tag_ignore()
target/hexagon: Add a placeholder fp exception
target/hexagon: Add guest, system reg number defs
target/hexagon: Add guest, system reg number state
target/hexagon: Add TCG values for sreg, greg
target/hexagon: Add guest/sys reg writes to DisasContext
target/hexagon: Add imported macro, attr defs for sysemu
target/hexagon: Add new macro definitions for sysemu
target/hexagon: Add handlers for guest/sysreg r/w
target/hexagon: Add placeholder greg/sreg r/w helpers
target/hexagon: Add vmstate representation
target/hexagon: Make A_PRIV, "J2_trap*" insts need_env()
target/hexagon: Define register fields for system regs
target/hexagon: Implement do_raise_exception()
target/hexagon: Add system reg insns
target/hexagon: Add sysemu TCG overrides
target/hexagon: Add implicit attributes to sysemu macros
target/hexagon: Add TCG overrides for int handler insts
target/hexagon: Add TCG overrides for thread ctl
target/hexagon: Add TCG overrides for rte, nmi
target/hexagon: Add sreg_{read,write} helpers
target/hexagon: Add cpu modes, mmu indices, next_PC to state
hw/hexagon: Introduce hexagon TLB device
target/hexagon: Add stubs for modify_ssr/get_exe_mode
target/hexagon: Add clear_wait_mode() definition
target/hexagon: Define f{S,G}ET_FIELD macros
target/hexagon: Add hex_interrupts support
MAINTAINERS | 3 +
docs/devel/hexagon-sys.rst | 112 ++++++
docs/devel/index-internals.rst | 1 +
docs/system/hexagon/cdsp.rst | 12 +
docs/system/hexagon/emulation.rst | 15 +
docs/system/target-hexagon.rst | 103 +++++
docs/system/targets.rst | 1 +
include/hw/hexagon/hexagon_tlb.h | 45 +++
target/hexagon/cpu-param.h | 4 +
target/hexagon/cpu.h | 72 +++-
target/hexagon/cpu_bits.h | 75 +++-
target/hexagon/cpu_helper.h | 21 ++
target/hexagon/gen_tcg.h | 9 +
target/hexagon/gen_tcg_sys.h | 102 +++++
target/hexagon/helper.h | 22 ++
target/hexagon/hex_interrupts.h | 15 +
target/hexagon/hex_mmu.h | 25 ++
target/hexagon/hex_regs.h | 117 ++++++
target/hexagon/internal.h | 18 +
target/hexagon/macros.h | 35 +-
target/hexagon/sys_macros.h | 240 ++++++++++++
target/hexagon/translate.h | 43 +++
target/hexagon/attribs_def.h.inc | 49 ++-
target/hexagon/reg_fields_def.h.inc | 96 +++++
hw/hexagon/hexagon_tlb.c | 463 +++++++++++++++++++++++
linux-user/hexagon/cpu_loop.c | 16 +
target/hexagon/arch.c | 5 +
target/hexagon/cpu.c | 56 ++-
target/hexagon/cpu_helper.c | 85 +++++
target/hexagon/genptr.c | 151 ++++++++
target/hexagon/hex_interrupts.c | 375 ++++++++++++++++++
target/hexagon/hex_mmu.c | 277 ++++++++++++++
target/hexagon/machine.c | 32 ++
target/hexagon/op_helper.c | 144 ++++++-
target/hexagon/translate.c | 30 +-
target/hexagon/gen_analyze_funcs.py | 14 +-
target/hexagon/gen_helper_funcs.py | 26 +-
target/hexagon/gen_helper_protos.py | 23 +-
target/hexagon/gen_idef_parser_funcs.py | 2 +
target/hexagon/gen_op_attribs.py | 2 +-
target/hexagon/gen_opcodes_def.py | 5 +-
target/hexagon/gen_tcg_funcs.py | 35 +-
target/hexagon/hex_common.py | 181 ++++++++-
target/hexagon/imported/encode_pp.def | 128 ++++++-
target/hexagon/imported/macros.def | 482 +++++++++++++++++++++++-
target/hexagon/imported/system.idef | 244 +++++++++++-
target/hexagon/meson.build | 13 +-
47 files changed, 3914 insertions(+), 110 deletions(-)
create mode 100644 docs/devel/hexagon-sys.rst
create mode 100644 docs/system/hexagon/cdsp.rst
create mode 100644 docs/system/hexagon/emulation.rst
create mode 100644 docs/system/target-hexagon.rst
create mode 100644 include/hw/hexagon/hexagon_tlb.h
create mode 100644 target/hexagon/cpu_helper.h
create mode 100644 target/hexagon/gen_tcg_sys.h
create mode 100644 target/hexagon/hex_interrupts.h
create mode 100644 target/hexagon/hex_mmu.h
create mode 100644 target/hexagon/sys_macros.h
create mode 100644 hw/hexagon/hexagon_tlb.c
create mode 100644 target/hexagon/cpu_helper.c
create mode 100644 target/hexagon/hex_interrupts.c
create mode 100644 target/hexagon/hex_mmu.c
create mode 100644 target/hexagon/machine.c
mode change 100755 => 100644 target/hexagon/imported/macros.def
--
2.34.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v5 01/35] docs: Add hexagon sysemu docs
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:48 ` [PATCH v5 02/35] docs/system: Add hexagon CPU emulation Brian Cain
` (33 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain,
Pierrick Bouvier
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
MAINTAINERS | 3 +
docs/devel/hexagon-sys.rst | 112 +++++++++++++++++++++++++++++++++
docs/devel/index-internals.rst | 1 +
docs/system/hexagon/cdsp.rst | 12 ++++
docs/system/target-hexagon.rst | 102 ++++++++++++++++++++++++++++++
docs/system/targets.rst | 1 +
6 files changed, 231 insertions(+)
create mode 100644 docs/devel/hexagon-sys.rst
create mode 100644 docs/system/hexagon/cdsp.rst
create mode 100644 docs/system/target-hexagon.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index a53317ff263..17d1d93d595 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -253,6 +253,9 @@ F: disas/hexagon.c
F: configs/targets/hexagon-linux-user/default.mak
F: docker/dockerfiles/debian-hexagon-cross.docker
F: gdb-xml/hexagon*.xml
+F: docs/system/target-hexagon.rst
+F: docs/system/hexagon/
+F: docs/devel/hexagon-sys.rst
T: git https://github.com/quic/qemu.git hex-next
Hexagon idef-parser
diff --git a/docs/devel/hexagon-sys.rst b/docs/devel/hexagon-sys.rst
new file mode 100644
index 00000000000..92ebc32dce8
--- /dev/null
+++ b/docs/devel/hexagon-sys.rst
@@ -0,0 +1,112 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+.. _Hexagon-System-arch:
+
+Hexagon System Architecture
+===========================
+
+The hexagon architecture has some unique elements which are described here.
+
+Interrupts
+----------
+When interrupts arrive at a Hexagon DSP core, they are priority-steered to
+be handled by an eligible hardware thread with the lowest priority.
+
+Memory
+------
+Each hardware thread has an ``SSR.ASID`` field that contains its Address
+Space Identifier. This value is catenated with a 32-bit virtual address -
+the MMU can then resolve this extended virtual address to a physical address.
+
+TLBs
+----
+The format of a TLB entry is shown below.
+
+.. note::
+ The Small Core DSPs have a different TLB format which is not yet
+ supported.
+
+.. admonition:: Diagram
+
+ .. code:: text
+
+ 6 5 4 3
+ 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |v|g|x|A|A| | |
+ |a|l|P|1|0| ASID | Virtual Page |
+ |l|b| | | | | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ 3 2 1 0
+ 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | | | | | | | |
+ |x|w|r|u|Cacheab| Physical Page |S|
+ | | | | | | | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+* ASID: the address-space identifier
+* A1, A0: the behavior of these cache line attributes are not modeled by QEMU.
+* xP: the extra-physical bit is the most significant physical address bit.
+* S: the S bit and the LSBs of the physical page indicate the page size
+* val: this is the 'valid' bit, when set it indicates that page matching
+ should consider this entry.
+
+.. list-table:: Page sizes
+ :widths: 25 25 50
+ :header-rows: 1
+
+ * - S-bit
+ - Phys page LSBs
+ - Page size
+ * - 1
+ - N/A
+ - 4kb
+ * - 0
+ - 0b1
+ - 16kb
+ * - 0
+ - 0b10
+ - 64kb
+ * - 0
+ - 0b100
+ - 256kb
+ * - 0
+ - 0b1000
+ - 1MB
+ * - 0
+ - 0b10000
+ - 4MB
+ * - 0
+ - 0b100000
+ - 16MB
+
+* glb: if the global bit is set, the ASID is not considered when matching
+ TLBs.
+* Cacheab: the cacheability attributes of TLBs are not modeled, these bits
+ are ignored.
+* RWX: read-, write-, execute-, enable bits. Indicates if user programs
+ are permitted to read/write/execute the given page.
+* U: indicates if user programs can access this page.
+
+Scheduler
+---------
+The Hexagon system architecture has a feature to assist the guest OS
+task scheduler. The guest OS can enable this feature by setting
+``SCHEDCFG.EN``. The ``BESTWAIT`` register is programmed by the guest OS
+to indicate the priority of the highest priority task waiting to run on a
+hardware thread. The reschedule interrupt is triggered when any hardware
+thread's priority in ``STID.PRIO`` is worse than the ``BESTWAIT``. When
+it is triggered, the ``BESTWAIT.PRIO`` value is reset to 0x1ff.
+
+HVX Coprocessor
+---------------
+The Supervisor Status Register field ``SSR.XA`` binds a DSP hardware thread
+to one of the eight possible HVX contexts. The guest OS is responsible for
+managing this resource.
+
+.. seealso::
+
+ ``target/hexagon/README`` in the QEMU source tree for more info about Hexagon.
diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst
index 7a0678cbdd3..0471db80645 100644
--- a/docs/devel/index-internals.rst
+++ b/docs/devel/index-internals.rst
@@ -14,6 +14,7 @@ Details about QEMU's various subsystems including how to add features to them.
block-coroutine-wrapper
clocks
ebpf_rss
+ hexagon-sys
migration/index
multi-process
reset
diff --git a/docs/system/hexagon/cdsp.rst b/docs/system/hexagon/cdsp.rst
new file mode 100644
index 00000000000..237529273cb
--- /dev/null
+++ b/docs/system/hexagon/cdsp.rst
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+Compute DSP
+===========
+
+A Hexagon CDSP is designed as a computation offload device for an SoC. The
+``V66G_1024`` machine contains:
+
+* L2VIC interrupt controller
+* QTimer timer device
+
+This machine will support any Hexagon CPU, but will default to ``v66``.
diff --git a/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst
new file mode 100644
index 00000000000..5f7084a6a08
--- /dev/null
+++ b/docs/system/target-hexagon.rst
@@ -0,0 +1,102 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+.. _Hexagon-System-emulator:
+
+Hexagon System emulator
+-----------------------
+
+Use the ``qemu-system-hexagon`` executable to simulate a 32-bit Hexagon
+machine.
+
+Hexagon Machines
+================
+
+Hexagon DSPs are suited to various functions and generally appear in a
+"DSP subsystem" of a larger system-on-chip (SoC).
+
+Hexagon DSPs are often included in a subsystem that looks like the diagram
+below. Instructions are loaded into DDR before the DSP is brought out of
+reset and the first instructions are fetched from DDR via the EVB/reset vector.
+
+In a real system, a TBU/SMMU would normally arbitrate AXI accesses but
+we don't have a need to model that for QEMU.
+
+Hexagon DSP cores use simultaneous multithreading (SMT) with as many as 8
+hardware threads.
+
+.. admonition:: Diagram
+
+ .. code:: text
+
+ AHB (local) bus AXI (global) bus
+ │ │
+ │ │
+ ┌─────────┐ │ ┌─────────────────┐ │
+ │ L2VIC ├──┤ │ │ │
+ │ ├──┼───────► ├───────┤
+ └─────▲───┘ │ │ Hexagon DSP │ │
+ │ │ │ │ │ ┌─────┐
+ │ │ │ N threads │ │ │ DDR │
+ │ ├───────┤ │ │ │ │
+ ┌────┴──┐ │ │ │ ├────────┤ │
+ │QTimer ├───┤ │ │ │ │ │
+ │ │ │ │ │ │ │ │
+ └───────┘ │ │ ┌─────────┐ │ │ │ │
+ │ │ ┌─────────┐│ │ │ │ │
+ ┌───────┐ │ │ │ HVX xM ││ │ │ │ │
+ │QDSP6SS├───┤ │ │ │┘ │ │ │ │
+ └───────┘ │ │ └─────────┘ │ │ └─────┘
+ │ │ │ │
+ ┌───────┐ │ └─────────────────┘ │
+ │ CSR ├───┤
+ └───────┘ │ ┌──────┐ ┌───────────┐
+ │ │ TCM │ │ VTCM │
+ │ │ │ │
+ └──────┘ │ │
+ │ │
+ │ │
+ │ │
+ └───────────┘
+
+Components
+----------
+Other than l2vic and HVX, the components below are not implemented in QEMU.
+
+* L2VIC: the L2 vectored interrupt controller. Supports 1024 input
+ interrupts, edge- or level-triggered. The core ISA has system registers
+ ``VID``, ``VID1`` which read through to the L2VIC device.
+* QTimer: ARMSSE-based programmable timer device. Its interrupts are
+ wired to the L2VIC. System registers ``TIMER``, ``UTIMER`` read
+ through to the QTimer device.
+* QDSP6SS: DSP subsystem features, accessible to the entire SoC, including
+ DSP NMI, watchdog, reset, etc.
+* CSR: Configuration/Status Registers.
+* TCM: DSP-exclusive tightly-coupled memory. This memory can be used for
+ DSPs when isolated from DDR and in some bootstrapping modes.
+* VTCM: DSP-exclusive vector tightly-coupled memory. This memory is accessed
+ by some HVX instructions.
+* HVX: the vector coprocessor supports 64 and 128-byte vector registers.
+ 64-byte mode is not implemented in QEMU.
+
+
+Bootstrapping
+-------------
+Hexagon systems do not generally have access to a block device. So, for
+QEMU the typical use case involves loading a binary or ELF file into memory
+and executing from the indicated start address::
+
+ $ qemu-system-hexagon -kernel ./prog -append 'arg1 arg2'
+
+Semihosting
+-----------
+Hexagon supports a semihosting interface similar to other architectures'.
+The ``trap0`` instruction can activate these semihosting calls so that the
+guest software can access the host console and filesystem. Semihosting
+is not yet implemented in QEMU hexagon.
+
+
+Hexagon Features
+================
+.. toctree::
+ hexagon/cdsp
+
diff --git a/docs/system/targets.rst b/docs/system/targets.rst
index 5b12858b216..5ebdd0f7fea 100644
--- a/docs/system/targets.rst
+++ b/docs/system/targets.rst
@@ -30,3 +30,4 @@ Contents:
target-sparc64
target-i386
target-xtensa
+ target-hexagon
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 02/35] docs/system: Add hexagon CPU emulation
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
2026-03-11 3:48 ` [PATCH v5 01/35] docs: Add hexagon sysemu docs Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:48 ` [PATCH v5 03/35] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
` (32 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain,
Pierrick Bouvier
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
docs/system/hexagon/emulation.rst | 15 +++++++++++++++
docs/system/target-hexagon.rst | 1 +
2 files changed, 16 insertions(+)
create mode 100644 docs/system/hexagon/emulation.rst
diff --git a/docs/system/hexagon/emulation.rst b/docs/system/hexagon/emulation.rst
new file mode 100644
index 00000000000..36f54f058af
--- /dev/null
+++ b/docs/system/hexagon/emulation.rst
@@ -0,0 +1,15 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+.. _Hexagon Emulation:
+
+Hexagon CPU architecture support
+================================
+
+QEMU's TCG emulation includes support for v65, v66, v67, v68, v69, v71, v73.
+It also has support for the following architecture extensions:
+
+- HVX (Hexagon Vector eXtensions)
+
+For information on the specifics of the HVX extension, please refer
+to the `Qualcomm Hexagon V73 HVX Programmer's Reference Manual
+<https://docs.qualcomm.com/bundle/publicresource/80-N2040-53.pdf>`_.
diff --git a/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst
index 5f7084a6a08..416b8f7be76 100644
--- a/docs/system/target-hexagon.rst
+++ b/docs/system/target-hexagon.rst
@@ -98,5 +98,6 @@ is not yet implemented in QEMU hexagon.
Hexagon Features
================
.. toctree::
+ hexagon/emulation
hexagon/cdsp
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 03/35] target/hexagon: Fix badva reference, delete CAUSE
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
2026-03-11 3:48 ` [PATCH v5 01/35] docs: Add hexagon sysemu docs Brian Cain
2026-03-11 3:48 ` [PATCH v5 02/35] docs/system: Add hexagon CPU emulation Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:48 ` [PATCH v5 04/35] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
` (31 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
The BADVA reg is referred to with the wrong identifier. The
CAUSE reg field of SSR is not yet modeled, we will dump
the SSR in a subsequent commit.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
---
target/hexagon/cpu.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 58a22ee41f2..e61ac10fbf3 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -117,6 +117,14 @@ static void print_reg(FILE *f, CPUHexagonState *env, int regnum)
hexagon_regnames[regnum], value);
}
+#ifndef CONFIG_USER_ONLY
+static void print_t_sreg(FILE *f, const CPUHexagonState *env, int regnum)
+{
+ qemu_fprintf(f, " %s = 0x" TARGET_FMT_lx "\n",
+ hexagon_sregnames[regnum], env->t_sreg[regnum]);
+}
+#endif
+
static void print_vreg(FILE *f, CPUHexagonState *env, int regnum,
bool skip_if_zero)
{
@@ -216,8 +224,7 @@ static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags)
qemu_fprintf(f, " cs0 = 0x00000000\n");
qemu_fprintf(f, " cs1 = 0x00000000\n");
#else
- print_reg(f, env, HEX_REG_CAUSE);
- print_reg(f, env, HEX_REG_BADVA);
+ print_t_sreg(f, env, HEX_SREG_BADVA);
print_reg(f, env, HEX_REG_CS0);
print_reg(f, env, HEX_REG_CS1);
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 04/35] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (2 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 03/35] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:48 ` [PATCH v5 05/35] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
` (30 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
---
target/hexagon/hex_common.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index c0e9f26aebe..002afcdb9e3 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -247,7 +247,9 @@ def need_next_PC(tag):
def need_pkt_has_multi_cof(tag):
- return "A_COF" in attribdict[tag]
+ if attribdict[tag] & {"A_JUMP", "A_CALL"}:
+ return tag != "J4_hintjumpr"
+ return False
def need_pkt_need_commit(tag):
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 05/35] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (3 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 04/35] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:48 ` [PATCH v5 06/35] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
` (29 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Add register classes for guest (G) and system (S) registers to
hex_common.py, and update gen_analyze_funcs.py to handle them.
Guest and system registers can only appear once per packet (one
transfer instruction each), so there is no read-after-write hazard
to detect during the analyze phase. Source classes (GuestSource,
GuestPairSource, SystemSource, SystemPairSource) provide a no-op
analyze_read() since these register reads do not need tracking.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/gen_analyze_funcs.py | 14 ++-
target/hexagon/hex_common.py | 152 ++++++++++++++++++++++++++++
2 files changed, 164 insertions(+), 2 deletions(-)
diff --git a/target/hexagon/gen_analyze_funcs.py b/target/hexagon/gen_analyze_funcs.py
index fdefd5b4b36..44bb22ed927 100755
--- a/target/hexagon/gen_analyze_funcs.py
+++ b/target/hexagon/gen_analyze_funcs.py
@@ -22,7 +22,6 @@
import string
import hex_common
-
##
## Generate the code to analyze the instruction
## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;}
@@ -42,6 +41,13 @@ def gen_analyze_func(f, tag, regs, imms):
f.write(f"static void analyze_{tag}(DisasContext *ctx)\n")
f.write("{\n")
+ if hex_common.tag_ignore(tag):
+ f.write("}\n\n")
+ return
+
+ if hex_common.is_sysemu_tag(tag):
+ f.write("#ifndef CONFIG_USER_ONLY\n")
+
f.write(" Insn *insn G_GNUC_UNUSED = ctx->insn;\n")
if (hex_common.is_hvx_insn(tag)):
if hex_common.has_hvx_helper(tag):
@@ -58,7 +64,8 @@ def gen_analyze_func(f, tag, regs, imms):
for regno, register in enumerate(regs):
reg_type, reg_id = register
reg = hex_common.get_register(tag, reg_type, reg_id)
- reg.decl_reg_num(f, regno)
+ if reg.is_read() or reg.is_written():
+ reg.decl_reg_num(f, regno)
## Analyze the register reads
for regno, register in enumerate(regs):
@@ -78,6 +85,9 @@ def gen_analyze_func(f, tag, regs, imms):
f.write(" mark_implicit_writes(ctx);\n")
+ if hex_common.is_sysemu_tag(tag):
+ f.write("#endif /* !CONFIG_USER_ONLY */\n")
+
f.write("}\n\n")
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index 002afcdb9e3..ceb4b6812d6 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -33,6 +33,41 @@
overrides = {} # tags with helper overrides
idef_parser_enabled = {} # tags enabled for idef-parser
+
+def is_sysemu_tag(tag):
+ return bool(attribdict[tag] & {"A_PRIV", "A_GUEST"})
+
+
+def tag_ignore(tag):
+ tag_skips = (
+ "Y6_diag",
+ "Y6_diag0",
+ "Y6_diag1",
+ )
+ attr_skips = {
+ "A_FAKEINSN",
+ "A_MAPPING",
+ "A_CONDMAPPING",
+ }
+ return tag in tag_skips or attribdict[tag] & attr_skips
+
+
+def get_sys_tags():
+ return sorted(
+ tag for tag in frozenset(tags) if is_sysemu_tag(tag)
+ )
+
+
+def get_user_tags():
+ return sorted(
+ tag for tag in frozenset(tags) if not is_sysemu_tag(tag)
+ )
+
+
+def get_all_tags():
+ return get_user_tags() + get_sys_tags()
+
+
# We should do this as a hash for performance,
# but to keep order let's keep it as a list.
def uniquify(seq):
@@ -369,12 +404,16 @@ def helper_proto_type(self):
return "s32"
def helper_arg_type(self):
return "int32_t"
+ def is_pair(self):
+ return False
class Pair(Scalar):
def helper_proto_type(self):
return "s64"
def helper_arg_type(self):
return "int64_t"
+ def is_pair(self):
+ return True
class Hvx:
def is_scalar_reg(self):
@@ -1010,6 +1049,109 @@ def analyze_write(self, f, tag, regno):
ctx_log_qreg_write(ctx, {self.reg_num}, insn_has_hvx_helper);
"""))
+class GuestRegister(Register):
+ pass
+
+class GuestDest(GuestRegister, Single, Dest):
+ def decl_tcg(self, f, tag, regno):
+ self.decl_reg_num(f, regno)
+ f.write(code_fmt(f"""\
+ TCGv_i32 {self.reg_tcg()} = tcg_temp_new_i32();
+ """))
+ def gen_write(self, f, tag):
+ f.write(code_fmt(f"""\
+ gen_log_greg_write(ctx, {self.reg_num}, {self.reg_tcg()});
+ """))
+ def analyze_write(self, f, tag, regno):
+ f.write(code_fmt(f"""\
+ ctx_log_greg_write(ctx, {self.reg_num});
+ """))
+
+class GuestSource(GuestRegister, Single, OldSource):
+ def decl_tcg(self, f, tag, regno):
+ self.decl_reg_num(f, regno)
+ f.write(code_fmt(f"""\
+ TCGv_i32 {self.reg_tcg()} = tcg_temp_new_i32();
+ gen_read_greg({self.reg_tcg()}, {self.reg_num});
+ """))
+ def analyze_read(self, f, regno):
+ pass
+
+class GuestPairDest(GuestRegister, Pair, Dest):
+ def decl_tcg(self, f, tag, regno):
+ self.decl_reg_num(f, regno)
+ f.write(code_fmt(f"""\
+ TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64();
+ """))
+ def gen_write(self, f, tag):
+ f.write(code_fmt(f"""\
+ gen_log_greg_write_pair(ctx, {self.reg_num}, {self.reg_tcg()});
+ """))
+ def analyze_write(self, f, tag, regno):
+ f.write(code_fmt(f"""\
+ ctx_log_greg_write_pair(ctx, {self.reg_num});
+ """))
+
+class GuestPairSource(GuestRegister, Pair, OldSource):
+ def decl_tcg(self, f, tag, regno):
+ self.decl_reg_num(f, regno)
+ f.write(code_fmt(f"""\
+ TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64();
+ gen_read_greg_pair({self.reg_tcg()}, {self.reg_num});
+ """))
+ def analyze_read(self, f, regno):
+ pass
+
+class SystemDest(Register, Single, Dest):
+ def decl_tcg(self, f, tag, regno):
+ self.decl_reg_num(f, regno)
+ f.write(code_fmt(f"""\
+ TCGv_i32 {self.reg_tcg()} = tcg_temp_new_i32();
+ """))
+ def gen_write(self, f, tag):
+ f.write(code_fmt(f"""\
+ gen_log_sreg_write(ctx, {self.reg_num}, {self.reg_tcg()});
+ """))
+ def analyze_write(self, f, tag, regno):
+ f.write(code_fmt(f"""\
+ ctx_log_sreg_write(ctx, {self.reg_num});
+ """))
+
+class SystemSource(Register, Single, OldSource):
+ def decl_tcg(self, f, tag, regno):
+ self.decl_reg_num(f, regno)
+ f.write(code_fmt(f"""\
+ TCGv_i32 {self.reg_tcg()} = tcg_temp_new_i32();
+ gen_read_sreg({self.reg_tcg()}, {self.reg_num});
+ """))
+ def analyze_read(self, f, regno):
+ pass
+
+class SystemPairDest(Register, Pair, Dest):
+ def decl_tcg(self, f, tag, regno):
+ self.decl_reg_num(f, regno)
+ f.write(code_fmt(f"""\
+ TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64();
+ """))
+ def gen_write(self, f, tag):
+ f.write(code_fmt(f"""\
+ gen_log_sreg_write_pair(ctx, {self.reg_num}, {self.reg_tcg()});
+ """))
+ def analyze_write(self, f, tag, regno):
+ f.write(code_fmt(f"""\
+ ctx_log_sreg_write_pair(ctx, {self.reg_num});
+ """))
+
+class SystemPairSource(Register, Pair, OldSource):
+ def decl_tcg(self, f, tag, regno):
+ self.decl_reg_num(f, regno)
+ f.write(code_fmt(f"""\
+ TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64();
+ gen_read_sreg_pair({self.reg_tcg()}, {self.reg_num});
+ """))
+ def analyze_read(self, f, regno):
+ pass
+
def init_registers():
regs = {
GprDest("R", "d"),
@@ -1056,6 +1198,16 @@ def init_registers():
QRegSource("Q", "u"),
QRegSource("Q", "v"),
QRegReadWrite("Q", "x"),
+
+ # system regs
+ GuestDest("G", "d"),
+ GuestSource("G", "s"),
+ GuestPairDest("G", "dd"),
+ GuestPairSource("G", "ss"),
+ SystemDest("S", "d"),
+ SystemSource("S", "s"),
+ SystemPairDest("S", "dd"),
+ SystemPairSource("S", "ss"),
}
for reg in regs:
registers[f"{reg.regtype}{reg.regid}"] = reg
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 06/35] target/hexagon: Suppress unused-variable warnings for sysemu source regs
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (4 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 05/35] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-12 21:03 ` Taylor Simpson
2026-03-11 3:48 ` [PATCH v5 07/35] target/hexagon: Make gen_exception_end_tb non-static Brian Cain
` (28 subsequent siblings)
34 siblings, 1 reply; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo
The analyze_read() methods on GuestSource, GuestPairSource,
SystemSource, and SystemPairSource were no-ops because these
source registers do not need read-tracking in the analyze phase.
However, gen_analyze_funcs.py unconditionally declares the
register-number variable (e.g. GsN) via decl_reg_num() for all
registers that are read or written. When building with
hexagon-softmmu, the generated analyze function bodies are
compiled (outside the #ifndef CONFIG_USER_ONLY guard), and the
declared-but-unreferenced register-number variable triggers
-Werror=unused-variable under both gcc and clang.
Emit a (void) cast on the register number from analyze_read() to
suppress the warning.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/hex_common.py | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index ceb4b6812d6..1daf7239fc4 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -1068,6 +1068,10 @@ def analyze_write(self, f, tag, regno):
"""))
class GuestSource(GuestRegister, Single, OldSource):
+ def decl_reg_num(self, f, regno):
+ f.write(code_fmt(f"""\
+ const int {self.reg_num} G_GNUC_UNUSED = insn->regno[{regno}];
+ """))
def decl_tcg(self, f, tag, regno):
self.decl_reg_num(f, regno)
f.write(code_fmt(f"""\
@@ -1093,6 +1097,10 @@ def analyze_write(self, f, tag, regno):
"""))
class GuestPairSource(GuestRegister, Pair, OldSource):
+ def decl_reg_num(self, f, regno):
+ f.write(code_fmt(f"""\
+ const int {self.reg_num} G_GNUC_UNUSED = insn->regno[{regno}];
+ """))
def decl_tcg(self, f, tag, regno):
self.decl_reg_num(f, regno)
f.write(code_fmt(f"""\
@@ -1118,6 +1126,10 @@ def analyze_write(self, f, tag, regno):
"""))
class SystemSource(Register, Single, OldSource):
+ def decl_reg_num(self, f, regno):
+ f.write(code_fmt(f"""\
+ const int {self.reg_num} G_GNUC_UNUSED = insn->regno[{regno}];
+ """))
def decl_tcg(self, f, tag, regno):
self.decl_reg_num(f, regno)
f.write(code_fmt(f"""\
@@ -1143,6 +1155,10 @@ def analyze_write(self, f, tag, regno):
"""))
class SystemPairSource(Register, Pair, OldSource):
+ def decl_reg_num(self, f, regno):
+ f.write(code_fmt(f"""\
+ const int {self.reg_num} G_GNUC_UNUSED = insn->regno[{regno}];
+ """))
def decl_tcg(self, f, tag, regno):
self.decl_reg_num(f, regno)
f.write(code_fmt(f"""\
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 07/35] target/hexagon: Make gen_exception_end_tb non-static
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (5 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 06/35] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:48 ` [PATCH v5 08/35] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain via qemu development
` (27 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/translate.h | 2 ++
target/hexagon/translate.c | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index b37cb492381..2804e08ce57 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -282,6 +282,8 @@ extern TCGv hex_vstore_addr[VSTORES_MAX];
extern TCGv hex_vstore_size[VSTORES_MAX];
extern TCGv hex_vstore_pending[VSTORES_MAX];
+void hex_gen_exception_end_tb(DisasContext *ctx, int excp);
+
void process_store(DisasContext *ctx, int slot_num);
FIELD(PROBE_PKT_SCALAR_STORE_S0, MMU_IDX, 0, 2)
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 8a223f6e13e..18b38c285ed 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -189,7 +189,7 @@ static void gen_end_tb(DisasContext *ctx)
ctx->base.is_jmp = DISAS_NORETURN;
}
-static void gen_exception_end_tb(DisasContext *ctx, int excp)
+void hex_gen_exception_end_tb(DisasContext *ctx, int excp)
{
gen_exec_counters(ctx);
tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->next_PC);
@@ -590,7 +590,7 @@ static void gen_insn(DisasContext *ctx)
ctx->insn->generate(ctx);
mark_store_width(ctx);
} else {
- gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_OPCODE);
+ hex_gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_OPCODE);
}
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 08/35] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags()
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (6 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 07/35] target/hexagon: Make gen_exception_end_tb non-static Brian Cain
@ 2026-03-11 3:48 ` Brian Cain via qemu development
2026-03-11 3:48 ` [PATCH v5 09/35] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
` (26 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain via qemu development @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/gen_helper_funcs.py | 26 ++++++++++---------------
target/hexagon/gen_helper_protos.py | 23 +++++++++++-----------
target/hexagon/gen_idef_parser_funcs.py | 2 ++
target/hexagon/gen_op_attribs.py | 2 +-
target/hexagon/gen_opcodes_def.py | 5 ++++-
5 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py
index 6206104424c..1629ebc0e1a 100755
--- a/target/hexagon/gen_helper_funcs.py
+++ b/target/hexagon/gen_helper_funcs.py
@@ -104,29 +104,23 @@ def main():
tagimms = hex_common.get_tagimms()
with open(args.out, "w") as f:
- for tag in hex_common.tags:
- ## Skip the priv instructions
- if "A_PRIV" in hex_common.attribdict[tag]:
- continue
- ## Skip the guest instructions
- if "A_GUEST" in hex_common.attribdict[tag]:
- continue
- ## Skip the floating point instructions
- if "A_FPOP" in hex_common.attribdict[tag]:
- continue
- ## Skip the diag instructions
- if tag == "Y6_diag":
- continue
- if tag == "Y6_diag0":
- continue
- if tag == "Y6_diag1":
+ for tag in hex_common.get_user_tags():
+ if hex_common.tag_ignore(tag):
continue
if hex_common.skip_qemu_helper(tag):
continue
if hex_common.is_idef_parser_enabled(tag):
continue
+ gen_helper_function(f, tag, tagregs, tagimms)
+ f.write("#if !defined(CONFIG_USER_ONLY)\n")
+ for tag in hex_common.get_sys_tags():
+ if hex_common.skip_qemu_helper(tag):
+ continue
+ if hex_common.is_idef_parser_enabled(tag):
+ continue
gen_helper_function(f, tag, tagregs, tagimms)
+ f.write("#endif\n")
if __name__ == "__main__":
diff --git a/target/hexagon/gen_helper_protos.py b/target/hexagon/gen_helper_protos.py
index 77f8e0a6a32..59c8bdd05c0 100755
--- a/target/hexagon/gen_helper_protos.py
+++ b/target/hexagon/gen_helper_protos.py
@@ -59,27 +59,28 @@ def main():
tagimms = hex_common.get_tagimms()
with open(args.out, "w") as f:
- for tag in hex_common.tags:
- ## Skip the priv instructions
- if "A_PRIV" in hex_common.attribdict[tag]:
+ for tag in hex_common.get_user_tags():
+ if hex_common.tag_ignore(tag):
continue
- ## Skip the guest instructions
- if "A_GUEST" in hex_common.attribdict[tag]:
- continue
- ## Skip the diag instructions
- if tag == "Y6_diag":
- continue
- if tag == "Y6_diag0":
+
+ if hex_common.skip_qemu_helper(tag):
continue
- if tag == "Y6_diag1":
+ if hex_common.is_idef_parser_enabled(tag):
continue
+ gen_helper_prototype(f, tag, tagregs, tagimms)
+
+ f.write("#if !defined(CONFIG_USER_ONLY)\n")
+ for tag in hex_common.get_sys_tags():
+ if hex_common.tag_ignore(tag):
+ continue
if hex_common.skip_qemu_helper(tag):
continue
if hex_common.is_idef_parser_enabled(tag):
continue
gen_helper_prototype(f, tag, tagregs, tagimms)
+ f.write("#endif\n")
if __name__ == "__main__":
diff --git a/target/hexagon/gen_idef_parser_funcs.py b/target/hexagon/gen_idef_parser_funcs.py
index 2f6e826f76d..32bce9b0028 100644
--- a/target/hexagon/gen_idef_parser_funcs.py
+++ b/target/hexagon/gen_idef_parser_funcs.py
@@ -60,6 +60,8 @@ def main():
f.write('#include "macros.h.inc"\n\n')
for tag in hex_common.tags:
+ if hex_common.tag_ignore(tag):
+ continue
## Skip the priv instructions
if "A_PRIV" in hex_common.attribdict[tag]:
continue
diff --git a/target/hexagon/gen_op_attribs.py b/target/hexagon/gen_op_attribs.py
index bbbb02df3a2..94dd1f876b2 100755
--- a/target/hexagon/gen_op_attribs.py
+++ b/target/hexagon/gen_op_attribs.py
@@ -38,7 +38,7 @@ def main():
## Generate all the attributes associated with each instruction
##
with open(args.out, "w") as f:
- for tag in hex_common.tags:
+ for tag in hex_common.get_all_tags():
f.write(
f"OP_ATTRIB({tag},ATTRIBS("
f'{",".join(sorted(hex_common.attribdict[tag]))}))\n'
diff --git a/target/hexagon/gen_opcodes_def.py b/target/hexagon/gen_opcodes_def.py
index 94a19ff412e..17ba3f9db95 100755
--- a/target/hexagon/gen_opcodes_def.py
+++ b/target/hexagon/gen_opcodes_def.py
@@ -37,7 +37,10 @@ def main():
## Generate a list of all the opcodes
##
with open(args.out, "w") as f:
- for tag in hex_common.tags:
+ for tag in hex_common.get_user_tags():
+ f.write(f"OPCODE({tag}),\n")
+
+ for tag in hex_common.get_sys_tags():
f.write(f"OPCODE({tag}),\n")
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 09/35] target/hexagon: Add privilege check, use tag_ignore()
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (7 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 08/35] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain via qemu development
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:48 ` [PATCH v5 10/35] target/hexagon: Add a placeholder fp exception Brian Cain
` (25 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo,
Laurent Vivier, Pierrick Bouvier
Add system event and cause code definitions needed for exception
handling in sysemu mode. Add privilege checks that raise exceptions
for guest/supervisor-only instructions executed without appropriate
privilege.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 10 +++++
target/hexagon/cpu_bits.h | 75 +++++++++++++++++++++++++++++----
linux-user/hexagon/cpu_loop.c | 16 +++++++
target/hexagon/cpu.c | 1 +
target/hexagon/translate.c | 8 ++++
target/hexagon/gen_tcg_funcs.py | 35 +++++++++------
6 files changed, 123 insertions(+), 22 deletions(-)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 85afd592778..937194e460e 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -44,6 +44,15 @@
#define MMU_USER_IDX 0
+#define HEXAGON_CPU_IRQ_0 0
+#define HEXAGON_CPU_IRQ_1 1
+#define HEXAGON_CPU_IRQ_2 2
+#define HEXAGON_CPU_IRQ_3 3
+#define HEXAGON_CPU_IRQ_4 4
+#define HEXAGON_CPU_IRQ_5 5
+#define HEXAGON_CPU_IRQ_6 6
+#define HEXAGON_CPU_IRQ_7 7
+
typedef struct {
target_ulong va;
uint32_t width;
@@ -76,6 +85,7 @@ typedef struct {
typedef struct CPUArchState {
target_ulong gpr[TOTAL_PER_THREAD_REGS];
target_ulong pred[NUM_PREGS];
+ uint32_t cause_code;
/* For comparing with LLDB on target - see adjust_stack_ptrs function */
target_ulong last_pc_dumped;
diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h
index 19beca81c0c..91e9da09e03 100644
--- a/target/hexagon/cpu_bits.h
+++ b/target/hexagon/cpu_bits.h
@@ -24,20 +24,77 @@
#define PCALIGN_MASK (PCALIGN - 1)
enum hex_event {
- HEX_EVENT_NONE = -1,
- HEX_EVENT_TRAP0 = 0x008,
+ HEX_EVENT_NONE = -1,
+ HEX_EVENT_RESET = 0x0,
+ HEX_EVENT_IMPRECISE = 0x1,
+ HEX_EVENT_PRECISE = 0x2,
+ HEX_EVENT_TLB_MISS_X = 0x4,
+ HEX_EVENT_TLB_MISS_RW = 0x6,
+ HEX_EVENT_TRAP0 = 0x8,
+ HEX_EVENT_TRAP1 = 0x9,
+ HEX_EVENT_FPTRAP = 0xb,
+ HEX_EVENT_DEBUG = 0xc,
+ HEX_EVENT_INT0 = 0x10,
+ HEX_EVENT_INT1 = 0x11,
+ HEX_EVENT_INT2 = 0x12,
+ HEX_EVENT_INT3 = 0x13,
+ HEX_EVENT_INT4 = 0x14,
+ HEX_EVENT_INT5 = 0x15,
+ HEX_EVENT_INT6 = 0x16,
+ HEX_EVENT_INT7 = 0x17,
+ HEX_EVENT_INT8 = 0x18,
+ HEX_EVENT_INT9 = 0x19,
+ HEX_EVENT_INTA = 0x1a,
+ HEX_EVENT_INTB = 0x1b,
+ HEX_EVENT_INTC = 0x1c,
+ HEX_EVENT_INTD = 0x1d,
+ HEX_EVENT_INTE = 0x1e,
+ HEX_EVENT_INTF = 0x1f,
};
enum hex_cause {
HEX_CAUSE_NONE = -1,
- HEX_CAUSE_TRAP0 = 0x172,
- HEX_CAUSE_FETCH_NO_UPAGE = 0x012,
- HEX_CAUSE_INVALID_PACKET = 0x015,
- HEX_CAUSE_INVALID_OPCODE = 0x015,
+ HEX_CAUSE_RESET = 0x000,
+ HEX_CAUSE_BIU_PRECISE = 0x001,
+ HEX_CAUSE_UNSUPPORTED_HVX_64B = 0x002, /* QEMU-specific */
+ HEX_CAUSE_DOUBLE_EXCEPT = 0x003,
+ HEX_CAUSE_TRAP0 = 0x008,
+ HEX_CAUSE_TRAP1 = 0x009,
+ HEX_CAUSE_FETCH_NO_XPAGE = 0x011,
+ HEX_CAUSE_FETCH_NO_UPAGE = 0x012,
+ HEX_CAUSE_INVALID_PACKET = 0x015,
+ HEX_CAUSE_INVALID_OPCODE = 0x015, /* alias: same cause as INVALID_PACKET */
+ HEX_CAUSE_NO_COPROC_ENABLE = 0x016,
+ HEX_CAUSE_NO_COPROC2_ENABLE = 0x018,
+ HEX_CAUSE_PRIV_USER_NO_GINSN = 0x01a,
+ HEX_CAUSE_PRIV_USER_NO_SINSN = 0x01b,
HEX_CAUSE_REG_WRITE_CONFLICT = 0x01d,
- HEX_CAUSE_PC_NOT_ALIGNED = 0x01e,
- HEX_CAUSE_PRIV_NO_UREAD = 0x024,
- HEX_CAUSE_PRIV_NO_UWRITE = 0x025,
+ HEX_CAUSE_PC_NOT_ALIGNED = 0x01e,
+ HEX_CAUSE_MISALIGNED_LOAD = 0x020,
+ HEX_CAUSE_MISALIGNED_STORE = 0x021,
+ HEX_CAUSE_PRIV_NO_READ = 0x022,
+ HEX_CAUSE_PRIV_NO_WRITE = 0x023,
+ HEX_CAUSE_PRIV_NO_UREAD = 0x024,
+ HEX_CAUSE_PRIV_NO_UWRITE = 0x025,
+ HEX_CAUSE_COPROC_LDST = 0x026,
+ HEX_CAUSE_STACK_LIMIT = 0x027,
+ HEX_CAUSE_VWCTRL_WINDOW_MISS = 0x029,
+ HEX_CAUSE_IMPRECISE_NMI = 0x043,
+ HEX_CAUSE_IMPRECISE_MULTI_TLB_MATCH = 0x044,
+ HEX_CAUSE_TLBMISSX_CAUSE_NORMAL = 0x060,
+ HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE = 0x061,
+ HEX_CAUSE_TLBMISSRW_CAUSE_READ = 0x070,
+ HEX_CAUSE_TLBMISSRW_CAUSE_WRITE = 0x071,
+ HEX_CAUSE_DEBUG_SINGLESTEP = 0x80,
+ HEX_CAUSE_FPTRAP_CAUSE_BADFLOAT = 0x0bf,
+ HEX_CAUSE_INT0 = 0x0c0,
+ HEX_CAUSE_INT1 = 0x0c1,
+ HEX_CAUSE_INT2 = 0x0c2,
+ HEX_CAUSE_INT3 = 0x0c3,
+ HEX_CAUSE_INT4 = 0x0c4,
+ HEX_CAUSE_INT5 = 0x0c5,
+ HEX_CAUSE_INT6 = 0x0c6,
+ HEX_CAUSE_INT7 = 0x0c7,
};
#define PACKET_WORDS_MAX 4
diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c
index 9464246e9e3..9f54c7b3f96 100644
--- a/linux-user/hexagon/cpu_loop.c
+++ b/linux-user/hexagon/cpu_loop.c
@@ -22,6 +22,7 @@
#include "qemu.h"
#include "user-internals.h"
#include "user/cpu_loop.h"
+#include "target/hexagon/internal.h"
#include "signal-common.h"
#include "internal.h"
@@ -60,6 +61,21 @@ void cpu_loop(CPUHexagonState *env)
env->gpr[0] = ret;
}
break;
+ case HEX_EVENT_PRECISE:
+ switch (env->cause_code) {
+ case HEX_CAUSE_PRIV_USER_NO_GINSN:
+ case HEX_CAUSE_PRIV_USER_NO_SINSN:
+ case HEX_CAUSE_INVALID_PACKET:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
+ env->gpr[HEX_REG_PC]);
+ break;
+ default:
+ EXCP_DUMP(env, "\nqemu: unhandled CPU precise exception "
+ "cause code 0x%x - aborting\n",
+ env->cause_code);
+ exit(EXIT_FAILURE);
+ }
+ break;
case HEX_CAUSE_PC_NOT_ALIGNED:
force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
env->gpr[HEX_REG_R31]);
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index e61ac10fbf3..1f172404608 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -306,6 +306,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
/* Default NaN value: sign bit set, all frac bits set */
set_float_default_nan_pattern(0b11111111, &env->fp_status);
+ env->cause_code = HEX_EVENT_NONE;
}
static void hexagon_cpu_disas_set_info(const CPUState *cs,
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 18b38c285ed..571ba9cae41 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -65,6 +65,10 @@ TCGv hex_vstore_addr[VSTORES_MAX];
TCGv hex_vstore_size[VSTORES_MAX];
TCGv hex_vstore_pending[VSTORES_MAX];
+#ifndef CONFIG_USER_ONLY
+TCGv_i32 hex_cause_code;
+#endif
+
static const char * const hexagon_prednames[] = {
"p0", "p1", "p2", "p3"
};
@@ -1153,4 +1157,8 @@ void hexagon_translate_init(void)
offsetof(CPUHexagonState, vstore_pending[i]),
vstore_pending_names[i]);
}
+#ifndef CONFIG_USER_ONLY
+ hex_cause_code = tcg_global_mem_new(tcg_env,
+ offsetof(CPUHexagonState, cause_code), "cause_code");
+#endif
}
diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py
index 87b7f10d7fd..d91bbcf1dc8 100755
--- a/target/hexagon/gen_tcg_funcs.py
+++ b/target/hexagon/gen_tcg_funcs.py
@@ -21,7 +21,7 @@
import re
import string
import hex_common
-
+from textwrap import dedent
##
## Generate the TCG code to call the helper
@@ -49,6 +49,18 @@ def gen_tcg_func(f, tag, regs, imms):
f.write(" Insn *insn G_GNUC_UNUSED = ctx->insn;\n")
+ if "A_PRIV" in hex_common.attribdict[tag]:
+ f.write(dedent("""\
+#ifdef CONFIG_USER_ONLY
+ hex_gen_exception_end_tb(ctx, HEX_CAUSE_PRIV_USER_NO_SINSN);
+#else
+"""))
+ if "A_GUEST" in hex_common.attribdict[tag]:
+ f.write(dedent("""\
+#ifdef CONFIG_USER_ONLY
+ hex_gen_exception_end_tb(ctx, HEX_CAUSE_PRIV_USER_NO_GINSN);
+#else
+"""))
if hex_common.need_ea(tag):
f.write(" TCGv EA G_GNUC_UNUSED = tcg_temp_new();\n")
@@ -100,6 +112,11 @@ def gen_tcg_func(f, tag, regs, imms):
if reg.is_written():
reg.gen_write(f, tag)
+ if (
+ "A_PRIV" in hex_common.attribdict[tag]
+ or "A_GUEST" in hex_common.attribdict[tag]
+ ):
+ f.write("#endif /* CONFIG_USER_ONLY */\n")
f.write("}\n\n")
@@ -124,18 +141,10 @@ def main():
f.write('#include "idef-generated-emitter.h.inc"\n\n')
for tag in hex_common.tags:
- ## Skip the priv instructions
- if "A_PRIV" in hex_common.attribdict[tag]:
- continue
- ## Skip the guest instructions
- if "A_GUEST" in hex_common.attribdict[tag]:
- continue
- ## Skip the diag instructions
- if tag == "Y6_diag":
- continue
- if tag == "Y6_diag0":
- continue
- if tag == "Y6_diag1":
+ if hex_common.tag_ignore(tag):
+ f.write(f"static void generate_{tag}"
+ f"(DisasContext *ctx)\n")
+ f.write("{\n}\n\n")
continue
gen_def_tcg_func(f, tag, tagregs, tagimms)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 10/35] target/hexagon: Add a placeholder fp exception
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (8 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 09/35] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:48 ` [PATCH v5 11/35] target/hexagon: Add guest, system reg number defs Brian Cain
` (24 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/arch.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c
index e17e714a6ac..0a400bf7a77 100644
--- a/target/hexagon/arch.c
+++ b/target/hexagon/arch.c
@@ -208,6 +208,11 @@ void arch_fpop_start(CPUHexagonState *env)
* model it in qemu user mode.
*/
#define RAISE_FP_EXCEPTION do {} while (0)
+#else
+ /*
+ * To be implemented.
+ */
+#define RAISE_FP_EXCEPTION do { g_assert_not_reached(); } while (0)
#endif
#define SOFTFLOAT_TEST_FLAG(FLAG, MYF, MYE) \
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 11/35] target/hexagon: Add guest, system reg number defs
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (9 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 10/35] target/hexagon: Add a placeholder fp exception Brian Cain
@ 2026-03-11 3:48 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 12/35] target/hexagon: Add guest, system reg number state Brian Cain
` (23 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:48 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
---
target/hexagon/cpu.h | 7 +++
target/hexagon/hex_regs.h | 117 ++++++++++++++++++++++++++++++++++++++
2 files changed, 124 insertions(+)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 937194e460e..3825de43ee7 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -20,6 +20,13 @@
#include "fpu/softfloat-types.h"
+#ifndef CONFIG_USER_ONLY
+#define NUM_GREGS 32
+#define GREG_WRITES_MAX 2
+#define NUM_SREGS 64
+#define SREG_WRITES_MAX 2
+#endif
+
#include "cpu-qom.h"
#include "exec/cpu-common.h"
#include "exec/cpu-defs.h"
diff --git a/target/hexagon/hex_regs.h b/target/hexagon/hex_regs.h
index bddfc28021c..214b7b8fde8 100644
--- a/target/hexagon/hex_regs.h
+++ b/target/hexagon/hex_regs.h
@@ -81,4 +81,121 @@ enum {
HEX_REG_UTIMERHI = 63,
};
+#ifndef CONFIG_USER_ONLY
+
+#define HEX_GREG_VALUES \
+ DECL_HEX_GREG(G0, 0) \
+ DECL_HEX_GREG(GELR, 0) \
+ DECL_HEX_GREG(G1, 1) \
+ DECL_HEX_GREG(GSR, 1) \
+ DECL_HEX_GREG(G2, 2) \
+ DECL_HEX_GREG(GOSP, 2) \
+ DECL_HEX_GREG(G3, 3) \
+ DECL_HEX_GREG(GBADVA, 3) \
+ DECL_HEX_GREG(GCYCLE_1T, 10) \
+ DECL_HEX_GREG(GCYCLE_2T, 11) \
+ DECL_HEX_GREG(GCYCLE_3T, 12) \
+ DECL_HEX_GREG(GCYCLE_4T, 13) \
+ DECL_HEX_GREG(GCYCLE_5T, 14) \
+ DECL_HEX_GREG(GCYCLE_6T, 15) \
+ DECL_HEX_GREG(GPMUCNT4, 16) \
+ DECL_HEX_GREG(GPMUCNT5, 17) \
+ DECL_HEX_GREG(GPMUCNT6, 18) \
+ DECL_HEX_GREG(GPMUCNT7, 19) \
+ DECL_HEX_GREG(GPCYCLELO, 24) \
+ DECL_HEX_GREG(GPCYCLEHI, 25) \
+ DECL_HEX_GREG(GPMUCNT0, 26) \
+ DECL_HEX_GREG(GPMUCNT1, 27) \
+ DECL_HEX_GREG(GPMUCNT2, 28) \
+ DECL_HEX_GREG(GPMUCNT3, 29) \
+ DECL_HEX_GREG_DONE
+
+#define DECL_HEX_GREG_DONE
+#define DECL_HEX_GREG(name, val) HEX_GREG_ ##name = val,
+enum hex_greg {
+ HEX_GREG_VALUES
+};
+#undef DECL_HEX_GREG
+#undef DECL_HEX_GREG_DONE
+
+#define DECL_HEX_GREG_DONE 0
+#define DECL_HEX_GREG(_, val) (1 << val) |
+static inline bool greg_implemented(enum hex_greg greg)
+{
+#if NUM_GREGS > 32
+#error "NUM_GREGS too large for greg_implemented(): update `impl_bitmap`"
+#endif
+ static int32_t impl_bitmap = HEX_GREG_VALUES;
+ return impl_bitmap & (1 << greg);
+}
+#undef DECL_HEX_GREG
+#undef DECL_HEX_GREG_DONE
+
+#endif /* CONFIG_USER_ONLY */
+
+#ifndef CONFIG_USER_ONLY
+enum {
+ HEX_SREG_SGP0 = 0,
+ HEX_SREG_SGP1 = 1,
+ HEX_SREG_STID = 2,
+ HEX_SREG_ELR = 3,
+ HEX_SREG_BADVA0 = 4,
+ HEX_SREG_BADVA1 = 5,
+ HEX_SREG_SSR = 6,
+ HEX_SREG_CCR = 7,
+ HEX_SREG_HTID = 8,
+ HEX_SREG_BADVA = 9,
+ HEX_SREG_IMASK = 10,
+ HEX_SREG_GEVB = 11,
+ HEX_SREG_GLB_START = 16,
+ HEX_SREG_EVB = 16,
+ HEX_SREG_MODECTL = 17,
+ HEX_SREG_SYSCFG = 18,
+ HEX_SREG_IPENDAD = 20,
+ HEX_SREG_VID = 21,
+ HEX_SREG_VID1 = 22,
+ HEX_SREG_BESTWAIT = 23,
+ HEX_SREG_IEL = 24,
+ HEX_SREG_SCHEDCFG = 25,
+ HEX_SREG_IAHL = 26,
+ HEX_SREG_CFGBASE = 27,
+ HEX_SREG_DIAG = 28,
+ HEX_SREG_REV = 29,
+ HEX_SREG_PCYCLELO = 30,
+ HEX_SREG_PCYCLEHI = 31,
+ HEX_SREG_ISDBST = 32,
+ HEX_SREG_ISDBCFG0 = 33,
+ HEX_SREG_ISDBCFG1 = 34,
+ HEX_SREG_LIVELOCK = 35,
+ HEX_SREG_BRKPTPC0 = 36,
+ HEX_SREG_BRKPTCFG0 = 37,
+ HEX_SREG_BRKPTPC1 = 38,
+ HEX_SREG_BRKPTCFG1 = 39,
+ HEX_SREG_ISDBMBXIN = 40,
+ HEX_SREG_ISDBMBXOUT = 41,
+ HEX_SREG_ISDBEN = 42,
+ HEX_SREG_ISDBGPR = 43,
+ HEX_SREG_PMUCNT4 = 44,
+ HEX_SREG_PMUCNT5 = 45,
+ HEX_SREG_PMUCNT6 = 46,
+ HEX_SREG_PMUCNT7 = 47,
+ HEX_SREG_PMUCNT0 = 48,
+ HEX_SREG_PMUCNT1 = 49,
+ HEX_SREG_PMUCNT2 = 50,
+ HEX_SREG_PMUCNT3 = 51,
+ HEX_SREG_PMUEVTCFG = 52,
+ HEX_SREG_PMUSTID0 = 53,
+ HEX_SREG_PMUEVTCFG1 = 54,
+ HEX_SREG_PMUSTID1 = 55,
+ HEX_SREG_TIMERLO = 56,
+ HEX_SREG_TIMERHI = 57,
+ HEX_SREG_PMUCFG = 58,
+ HEX_SREG_S59 = 59,
+ HEX_SREG_S60 = 60,
+ HEX_SREG_S61 = 61,
+ HEX_SREG_S62 = 62,
+ HEX_SREG_S63 = 63,
+};
+#endif /* !CONFIG_USER_ONLY */
+
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 12/35] target/hexagon: Add guest, system reg number state
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (10 preceding siblings ...)
2026-03-11 3:48 ` [PATCH v5 11/35] target/hexagon: Add guest, system reg number defs Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 13/35] target/hexagon: Add TCG values for sreg, greg Brian Cain
` (22 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 11 +++++++++++
target/hexagon/cpu.c | 5 +++++
2 files changed, 16 insertions(+)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 3825de43ee7..3562965c88a 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -99,6 +99,17 @@ typedef struct CPUArchState {
target_ulong stack_start;
uint8_t slot_cancelled;
+
+#ifndef CONFIG_USER_ONLY
+ /* Some system registers are per thread and some are global. */
+ uint32_t t_sreg[NUM_SREGS];
+
+ uint32_t greg[NUM_GREGS];
+ uint32_t wait_next_pc;
+
+ /* This alias of CPUState.cpu_index is used by imported sources: */
+ uint32_t threadId;
+#endif
target_ulong new_value_usr;
MemLog mem_log_stores[STORES_MAX];
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 1f172404608..6fabfaad6d2 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -306,6 +306,11 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
/* Default NaN value: sign bit set, all frac bits set */
set_float_default_nan_pattern(0b11111111, &env->fp_status);
+#ifndef CONFIG_USER_ONLY
+ memset(env->t_sreg, 0, sizeof(uint32_t) * NUM_SREGS);
+ memset(env->greg, 0, sizeof(uint32_t) * NUM_GREGS);
+ env->wait_next_pc = 0;
+#endif
env->cause_code = HEX_EVENT_NONE;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 13/35] target/hexagon: Add TCG values for sreg, greg
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (11 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 12/35] target/hexagon: Add guest, system reg number state Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 14/35] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
` (21 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/translate.h | 5 +++++
target/hexagon/translate.c | 16 ++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 2804e08ce57..40d365f4250 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -281,6 +281,11 @@ extern TCGv_i64 hex_llsc_val_i64;
extern TCGv hex_vstore_addr[VSTORES_MAX];
extern TCGv hex_vstore_size[VSTORES_MAX];
extern TCGv hex_vstore_pending[VSTORES_MAX];
+#ifndef CONFIG_USER_ONLY
+extern TCGv_i32 hex_greg[NUM_GREGS];
+extern TCGv_i32 hex_t_sreg[NUM_SREGS];
+#endif
+
void hex_gen_exception_end_tb(DisasContext *ctx, int excp);
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 571ba9cae41..cd6affa2f49 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -66,6 +66,8 @@ TCGv hex_vstore_size[VSTORES_MAX];
TCGv hex_vstore_pending[VSTORES_MAX];
#ifndef CONFIG_USER_ONLY
+TCGv_i32 hex_greg[NUM_GREGS];
+TCGv_i32 hex_t_sreg[NUM_SREGS];
TCGv_i32 hex_cause_code;
#endif
@@ -1099,6 +1101,20 @@ void hexagon_translate_init(void)
opcode_init();
+#ifndef CONFIG_USER_ONLY
+ for (i = 0; i < NUM_GREGS; i++) {
+ hex_greg[i] = tcg_global_mem_new_i32(tcg_env,
+ offsetof(CPUHexagonState, greg[i]),
+ hexagon_gregnames[i]);
+ }
+ for (i = 0; i < NUM_SREGS; i++) {
+ if (i < HEX_SREG_GLB_START) {
+ hex_t_sreg[i] = tcg_global_mem_new_i32(tcg_env,
+ offsetof(CPUHexagonState, t_sreg[i]),
+ hexagon_sregnames[i]);
+ }
+ }
+#endif
for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
hex_gpr[i] = tcg_global_mem_new(tcg_env,
offsetof(CPUHexagonState, gpr[i]),
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 14/35] target/hexagon: Add guest/sys reg writes to DisasContext
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (12 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 13/35] target/hexagon: Add TCG values for sreg, greg Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 15/35] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
` (20 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/translate.h | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 40d365f4250..7e528379db6 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -40,6 +40,14 @@ typedef struct DisasContext {
DECLARE_BITMAP(regs_written, TOTAL_PER_THREAD_REGS);
DECLARE_BITMAP(predicated_regs, TOTAL_PER_THREAD_REGS);
bool implicit_usr_write;
+#ifndef CONFIG_USER_ONLY
+ int greg_log[GREG_WRITES_MAX];
+ int greg_log_idx;
+ int sreg_log[SREG_WRITES_MAX];
+ int sreg_log_idx;
+ TCGv_i32 t_sreg_new_value[NUM_SREGS];
+ TCGv_i32 greg_new_value[NUM_GREGS];
+#endif
int preg_log[PRED_WRITES_MAX];
int preg_log_idx;
DECLARE_BITMAP(pregs_written, NUM_PREGS);
@@ -80,6 +88,34 @@ typedef struct DisasContext {
bool is_gather_store_insn(DisasContext *ctx);
+#ifndef CONFIG_USER_ONLY
+static inline void ctx_log_greg_write(DisasContext *ctx, int rnum)
+{
+ assert(rnum <= HEX_GREG_G3);
+ ctx->greg_log[ctx->greg_log_idx] = rnum;
+ ctx->greg_log_idx++;
+}
+
+static inline void ctx_log_greg_write_pair(DisasContext *ctx, int rnum)
+{
+ assert(!(rnum % 2));
+ ctx_log_greg_write(ctx, rnum);
+ ctx_log_greg_write(ctx, rnum + 1);
+}
+
+static inline void ctx_log_sreg_write(DisasContext *ctx, int rnum)
+{
+ ctx->sreg_log[ctx->sreg_log_idx] = rnum;
+ ctx->sreg_log_idx++;
+}
+
+static inline void ctx_log_sreg_write_pair(DisasContext *ctx, int rnum)
+{
+ ctx_log_sreg_write(ctx, rnum);
+ ctx_log_sreg_write(ctx, rnum + 1);
+}
+#endif
+
static inline void ctx_log_pred_write(DisasContext *ctx, int pnum)
{
if (!test_bit(pnum, ctx->pregs_written)) {
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 15/35] target/hexagon: Add imported macro, attr defs for sysemu
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (13 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 14/35] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 16/35] target/hexagon: Add new macro definitions " Brian Cain
` (19 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/attribs_def.h.inc | 49 ++-
target/hexagon/imported/macros.def | 482 ++++++++++++++++++++++++++++-
2 files changed, 518 insertions(+), 13 deletions(-)
mode change 100755 => 100644 target/hexagon/imported/macros.def
diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc
index 9e3a05f8828..06ab826b49f 100644
--- a/target/hexagon/attribs_def.h.inc
+++ b/target/hexagon/attribs_def.h.inc
@@ -52,6 +52,9 @@ DEF_ATTRIB(REGWRSIZE_4B, "Memory width is 4 bytes", "", "")
DEF_ATTRIB(REGWRSIZE_8B, "Memory width is 8 bytes", "", "")
DEF_ATTRIB(MEMLIKE, "Memory-like instruction", "", "")
DEF_ATTRIB(MEMLIKE_PACKET_RULES, "follows Memory-like packet rules", "", "")
+DEF_ATTRIB(CACHEOP, "Cache operation", "", "")
+DEF_ATTRIB(COPBYADDRESS, "Cache operation by address", "", "")
+DEF_ATTRIB(COPBYIDX, "Cache operation by index", "", "")
DEF_ATTRIB(RELEASE, "Releases a lock", "", "")
DEF_ATTRIB(ACQUIRE, "Acquires a lock", "", "")
@@ -101,23 +104,44 @@ DEF_ATTRIB(ROPS_3, "Compound instruction worth 3 RISC-ops", "", "")
/* access to implicit registers */
DEF_ATTRIB(IMPLICIT_WRITES_LR, "Writes the link register", "", "UREG.LR")
+DEF_ATTRIB(IMPLICIT_READS_LR, "Reads the link register", "UREG.LR", "")
+DEF_ATTRIB(IMPLICIT_READS_LC0, "Reads loop count for loop 0", "UREG.LC0", "")
+DEF_ATTRIB(IMPLICIT_READS_LC1, "Reads loop count for loop 1", "UREG.LC1", "")
+DEF_ATTRIB(IMPLICIT_READS_SA0, "Reads start address for loop 0", "UREG.SA0", "")
+DEF_ATTRIB(IMPLICIT_READS_SA1, "Reads start address for loop 1", "UREG.SA1", "")
+DEF_ATTRIB(IMPLICIT_WRITES_PC, "Writes the program counter", "", "UREG.PC")
+DEF_ATTRIB(IMPLICIT_READS_PC, "Reads the program counter", "UREG.PC", "")
DEF_ATTRIB(IMPLICIT_WRITES_SP, "Writes the stack pointer", "", "UREG.SP")
+DEF_ATTRIB(IMPLICIT_READS_SP, "Reads the stack pointer", "UREG.SP", "")
DEF_ATTRIB(IMPLICIT_WRITES_FP, "Writes the frame pointer", "", "UREG.FP")
+DEF_ATTRIB(IMPLICIT_READS_FP, "Reads the frame pointer", "UREG.FP", "")
+DEF_ATTRIB(IMPLICIT_WRITES_GP, "Writes the GP register", "", "UREG.GP")
+DEF_ATTRIB(IMPLICIT_READS_GP, "Reads the GP register", "UREG.GP", "")
DEF_ATTRIB(IMPLICIT_WRITES_LC0, "Writes loop count for loop 0", "", "UREG.LC0")
DEF_ATTRIB(IMPLICIT_WRITES_LC1, "Writes loop count for loop 1", "", "UREG.LC1")
DEF_ATTRIB(IMPLICIT_WRITES_SA0, "Writes start addr for loop 0", "", "UREG.SA0")
DEF_ATTRIB(IMPLICIT_WRITES_SA1, "Writes start addr for loop 1", "", "UREG.SA1")
+DEF_ATTRIB(IMPLICIT_WRITES_R00, "Writes Register 0", "", "UREG.R00")
DEF_ATTRIB(IMPLICIT_WRITES_P0, "Writes Predicate 0", "", "UREG.P0")
DEF_ATTRIB(IMPLICIT_WRITES_P1, "Writes Predicate 1", "", "UREG.P1")
DEF_ATTRIB(IMPLICIT_WRITES_P2, "Writes Predicate 1", "", "UREG.P2")
DEF_ATTRIB(IMPLICIT_WRITES_P3, "May write Predicate 3", "", "UREG.P3")
-DEF_ATTRIB(IMPLICIT_READS_PC, "Reads the PC register", "", "")
-DEF_ATTRIB(IMPLICIT_READS_P0, "Reads the P0 register", "", "")
-DEF_ATTRIB(IMPLICIT_READS_P1, "Reads the P1 register", "", "")
-DEF_ATTRIB(IMPLICIT_READS_P2, "Reads the P2 register", "", "")
-DEF_ATTRIB(IMPLICIT_READS_P3, "Reads the P3 register", "", "")
+DEF_ATTRIB(IMPLICIT_READS_R00, "Reads Register 0", "UREG.R00", "")
+DEF_ATTRIB(IMPLICIT_READS_P0, "Reads Predicate 0", "UREG.P0", "")
+DEF_ATTRIB(IMPLICIT_READS_P1, "Reads Predicate 1", "UREG.P1", "")
+DEF_ATTRIB(IMPLICIT_READS_P3, "Reads Predicate 3", "UREG.P3", "")
+DEF_ATTRIB(IMPLICIT_READS_Q3, "Reads Vector Predicate 3", "UREG.Q3", "")
+DEF_ATTRIB(IMPLICIT_READS_CS, "Reads the CS/M register", "UREG.CS", "")
DEF_ATTRIB(IMPLICIT_WRITES_USR, "May write USR", "", "")
-DEF_ATTRIB(IMPLICIT_READS_SP, "Reads the SP register", "", "")
+DEF_ATTRIB(IMPLICIT_WRITES_CCR, "Writes CCR register", "", "UREG.CCR")
+DEF_ATTRIB(IMPLICIT_WRITES_GOSP, "Writes GOSP register", "", "UREG.GOSP")
+DEF_ATTRIB(IMPLICIT_WRITES_SSR, "Writes SSR register", "", "UREG.SSR")
+DEF_ATTRIB(IMPLICIT_WRITES_SGP0, "Writes SGP0 register", "", "UREG.SGP0")
+DEF_ATTRIB(IMPLICIT_WRITES_SGP1, "Writes SGP1 register", "", "UREG.SGP1")
+DEF_ATTRIB(IMPLICIT_WRITES_IMASK_ANYTHREAD,
+ "Writes IMASK for any thread", "", "")
+DEF_ATTRIB(IMPLICIT_WRITES_STID_PRIO_ANYTHREAD,
+ "Writes STID priority for any thread", "", "")
DEF_ATTRIB(COMMUTES, "The operation is communitive", "", "")
DEF_ATTRIB(DEALLOCRET, "dealloc_return", "", "")
DEF_ATTRIB(DEALLOCFRAME, "deallocframe", "", "")
@@ -137,9 +161,15 @@ DEF_ATTRIB(RESTRICT_SLOT3ONLY, "Must execute on slot3", "", "")
DEF_ATTRIB(RESTRICT_NOSLOT1, "No slot 1 instruction in parallel", "", "")
DEF_ATTRIB(RESTRICT_PREFERSLOT0, "Try to encode into slot 0", "", "")
DEF_ATTRIB(RESTRICT_PACKET_AXOK, "May exist with A-type or X-type", "", "")
+DEF_ATTRIB(RESTRICT_SINGLE_MEM_FIRST, "Single memory op must be first", "", "")
+DEF_ATTRIB(RESTRICT_SLOT1_AOK, "Slot 1 is allowed", "", "")
DEF_ATTRIB(ICOP, "Instruction cache op", "", "")
+DEF_ATTRIB(EXCEPTION_SWI, "Software interrupt exception", "", "")
+DEF_ATTRIB(DMA, "DMA instruction", "", "")
+DEF_ATTRIB(NO_TIMING_LOG, "Does not get logged to the timing model", "", "")
+
DEF_ATTRIB(HWLOOP0_END, "Ends HW loop0", "", "")
DEF_ATTRIB(HWLOOP1_END, "Ends HW loop1", "", "")
DEF_ATTRIB(RET_TYPE, "return type", "", "")
@@ -151,6 +181,10 @@ DEF_ATTRIB(DCFETCH, "dcfetch type", "", "")
DEF_ATTRIB(L2FETCH, "Instruction is l2fetch type", "", "")
+DEF_ATTRIB(DCTAGOP, "Data cache tag operation", "", "")
+DEF_ATTRIB(ICTAGOP, "Instruction cache tag operation", "", "")
+DEF_ATTRIB(L2TAGOP, "L2 cache tag operation", "", "")
+
DEF_ATTRIB(ICINVA, "icinva", "", "")
DEF_ATTRIB(DCCLEANINVA, "dccleaninva", "", "")
@@ -166,6 +200,9 @@ DEF_ATTRIB(NOTE_LATEPRED, "The predicate can not be used as a .new", "", "")
DEF_ATTRIB(NOTE_NVSLOT0, "Can execute only in slot 0 (ST)", "", "")
DEF_ATTRIB(NOTE_NOVP, "Cannot be paired with a HVX permute instruction", "", "")
DEF_ATTRIB(NOTE_VA_UNARY, "Combined with HVX ALU op (must be unary)", "", "")
+DEF_ATTRIB(NOTE_SLOT1_AOK, "Slot 1 is allowed", "", "")
+DEF_ATTRIB(NOTE_GUEST, "Guest mode instruction", "", "")
+DEF_ATTRIB(NOTE_BADTAG_UNDEF, "Bad tag results in undefined behavior", "", "")
/* V6 MMVector Notes for Documentation */
DEF_ATTRIB(NOTE_SHIFT_RESOURCE, "Uses the HVX shift resource.", "", "")
diff --git a/target/hexagon/imported/macros.def b/target/hexagon/imported/macros.def
old mode 100755
new mode 100644
index 4bbcfdd5e19..13eb13c71f7
--- a/target/hexagon/imported/macros.def
+++ b/target/hexagon/imported/macros.def
@@ -353,6 +353,12 @@ DEF_MACRO(
()
)
+DEF_MACRO(
+ fREAD_SSR, /* read SSR register */
+ (READ_RREG(REG_SSR)), /* behavior */
+ ()
+)
+
DEF_MACRO(
fWRITE_LR, /* write lr */
WRITE_RREG(REG_LR,A), /* behavior */
@@ -371,12 +377,36 @@ DEF_MACRO(
(A_IMPLICIT_WRITES_SP)
)
+DEF_MACRO(
+ fWRITE_GOSP, /* write gosp */
+ WRITE_RREG(REG_GOSP,A), /* behavior */
+ (A_IMPLICIT_WRITES_GOSP)
+)
+
DEF_MACRO(
fREAD_SP, /* read stack pointer */
(READ_RREG(REG_SP)), /* behavior */
()
)
+DEF_MACRO(
+ fREAD_GOSP, /* read guest other stack pointer */
+ (READ_RREG(REG_GOSP)), /* behavior */
+ ()
+)
+
+DEF_MACRO(
+ fREAD_GELR, /* read guest other stack pointer */
+ (READ_RREG(REG_GELR)), /* behavior */
+ ()
+)
+
+DEF_MACRO(
+ fREAD_GEVB, /* read guest other stack pointer */
+ (READ_RREG(REG_GEVB)), /* behavior */
+ ()
+)
+
DEF_MACRO(
fREAD_CSREG, /* read CS register */
(READ_RREG(REG_CSA+N)), /* behavior */
@@ -570,6 +600,11 @@ DEF_MACRO(
WRITE_PREG(3,VAL), /* behavior */
(A_IMPLICIT_WRITES_P3)
)
+DEF_MACRO(
+ fWRITE_P3_LATE, /* write Predicate 0 */
+ {WRITE_PREG(3,VAL); fHIDE(MARK_LATE_PRED_WRITE(3))} , /* behavior */
+ (A_IMPLICIT_WRITES_P3,A_RESTRICT_LATEPRED)
+)
DEF_MACRO(
fPART1, /* write Predicate 0 */
@@ -660,6 +695,7 @@ DEF_MACRO(
((size8s_t)((size2s_t)(A))),
/* optional attributes */
)
+
DEF_MACRO(
fCAST2_8u, /* macro name */
((size8u_t)((size2u_t)(A))),
@@ -1532,18 +1568,137 @@ DEF_MACRO(fECHO,
/* OS interface and stop/wait */
/********************************************/
+DEF_MACRO(RUNNABLE_THREADS_MAX,
+ /* */,
+ ()
+)
+
+DEF_MACRO(THREAD_IS_ON,
+ ((PROC->arch_proc_options->thread_enable_mask>>TNUM) & 0x1),
+ ()
+)
+
+DEF_MACRO(THREAD_EN_MASK,
+ ((PROC->arch_proc_options->thread_enable_mask)),
+ ()
+)
+
+
+
+DEF_MACRO(READ_IMASK,
+ /* */,
+ ()
+)
+DEF_MACRO(WRITE_IMASK,
+ /* */,
+ (A_IMPLICIT_WRITES_IMASK_ANYTHREAD)
+)
+
+
+DEF_MACRO(WRITE_PRIO,
+ /* */,
+ (A_IMPLICIT_WRITES_STID_PRIO_ANYTHREAD)
+)
+
+
+DEF_MACRO(DO_IASSIGNW,
+ /* */,
+ (A_IMPLICIT_WRITES_IMASK_ANYTHREAD)
+)
+
+
+
+
+DEF_MACRO(fDO_NMI,
+ /* */,
+)
+
+DEF_MACRO(fDO_TRACE,
+ /* */,
+)
+
+DEF_MACRO(DO_IASSIGNR,
+ /* */,
+ ()
+)
+
+DEF_MACRO(DO_SWI,
+ /* */,
+ (A_EXCEPTION_SWI)
+)
+
+DEF_MACRO(DO_CSWI,
+ LOG_GLOBAL_REG_WRITE(REG_IPEND,GLOBAL_REG_READ(REG_IPEND) & ~((REG) & GLOBAL_REG_READ(REG_IEL)));,
+ ()
+)
+
+DEF_MACRO(DO_CIAD,
+ sys_ciad(thread,VAL); LOG_GLOBAL_REG_WRITE(REG_IAD,GLOBAL_REG_READ(REG_IAD) & ~(VAL));,
+ (A_EXCEPTION_SWI)
+)
+
+DEF_MACRO(DO_SIAD,
+ sys_siad(thread,VAL); LOG_GLOBAL_REG_WRITE(REG_IAD,GLOBAL_REG_READ(REG_IAD) | (VAL));,
+ (A_EXCEPTION_SWI)
+)
+
+DEF_MACRO(fBREAK,
+ /* */,
+ ()
+)
+
DEF_MACRO(fPAUSE,
{sys_pause(thread, insn->slot, IMM);},
()
)
+
DEF_MACRO(fTRAP,
- warn("Trap NPC=%x ",fREAD_NPC());
- warn("Trap exception, PCYCLE=%lld TYPE=%d NPC=%x IMM=0x%x",thread->processor_ptr->pstats[pcycles],TRAPTYPE,fREAD_NPC(),IMM);
- register_trap_exception(thread,fREAD_NPC(),TRAPTYPE,IMM);,
+ /* */,
+ (A_EXCEPTION_SWI)
+)
+
+DEF_MACRO(fCLEAR_RTE_EX,
+ /* */,
+ ()
+)
+
+DEF_MACRO(fTLB_LOCK_AVAILABLE,
+ (fREAD_GLOBAL_REG_FIELD(SYSCONF,SYSCFG_TLBLOCK) == 0),
()
)
+DEF_MACRO(fK0_LOCK_AVAILABLE,
+ (fREAD_GLOBAL_REG_FIELD(SYSCONF,SYSCFG_K0LOCK) == 0),
+ ()
+)
+
+DEF_MACRO(fSET_TLB_LOCK,
+ {
+ if (fTLB_LOCK_AVAILABLE()) {
+ fLOG_GLOBAL_REG_FIELD(SYSCONF,SYSCFG_TLBLOCK,1);
+ } else {
+ sys_waiting_for_tlb_lock(thread);
+ }
+ },
+ ()
+)
+
+DEF_MACRO(fSET_K0_LOCK,
+ /* */,
+ ()
+)
+
+DEF_MACRO(fCLEAR_TLB_LOCK,
+ /* */,
+ ()
+)
+
+DEF_MACRO(fCLEAR_K0_LOCK,
+ /* */,
+ ()
+)
+
DEF_MACRO(fALIGN_REG_FIELD_VALUE,
((VAL)<<reg_field_info[FIELD].offset),
/* */
@@ -1554,6 +1709,24 @@ DEF_MACRO(fGET_REG_FIELD_MASK,
/* */
)
+DEF_MACRO(fLOG_REG_FIELD,
+ LOG_MASKED_REG_WRITE(thread,REG_##REG,
+ fALIGN_REG_FIELD_VALUE(FIELD,VAL),
+ fGET_REG_FIELD_MASK(FIELD)),
+ ()
+)
+
+DEF_MACRO(fWRITE_GLOBAL_REG_FIELD,
+ /* */,
+)
+
+DEF_MACRO(fLOG_GLOBAL_REG_FIELD,
+ LOG_MASKED_GLOBAL_REG_WRITE(REG_##REG,
+ fALIGN_REG_FIELD_VALUE(FIELD,VAL),
+ fGET_REG_FIELD_MASK(FIELD)),
+ ()
+)
+
DEF_MACRO(fREAD_REG_FIELD,
fEXTRACTU_BITS(thread->Regs[REG_##REG],
reg_field_info[FIELD].width,
@@ -1561,6 +1734,11 @@ DEF_MACRO(fREAD_REG_FIELD,
/* ATTRIBS */
)
+DEF_MACRO(fREAD_GLOBAL_REG_FIELD,
+ /* */,
+ /* ATTRIBS */
+)
+
DEF_MACRO(fGET_FIELD,
fEXTRACTU_BITS(VAL,
reg_field_info[FIELD].width,
@@ -1576,6 +1754,174 @@ DEF_MACRO(fSET_FIELD,
/* ATTRIBS */
)
+DEF_MACRO(fSET_RUN_MODE_NOW,
+ /* */,
+)
+
+DEF_MACRO(fIN_DEBUG_MODE,
+ (thread->debug_mode || (fREAD_GLOBAL_REG_FIELD(ISDBST,ISDBST_DEBUGMODE) & 1<<TNUM)),
+ ()
+)
+DEF_MACRO(fIN_DEBUG_MODE_NO_ISDB,
+ (thread->debug_mode),
+ ()
+)
+
+
+DEF_MACRO(fIN_DEBUG_MODE_WARN,
+ {
+ if (fREAD_GLOBAL_REG_FIELD(ISDBST,ISDBST_DEBUGMODE) & 1<<TNUM)
+ warn("In ISDB debug mode, but TB told me to step normally");
+ },
+ ()
+)
+
+DEF_MACRO(fCLEAR_RUN_MODE,
+ {fLOG_GLOBAL_REG_FIELD(MODECTL,MODECTL_E,
+ fREAD_GLOBAL_REG_FIELD(MODECTL,MODECTL_E) & ~(1<<(TNUM)))},
+ /* NOTHING */
+)
+
+DEF_MACRO(fCLEAR_RUN_MODE_NOW,
+ /* */,
+ /* NOTHING */
+)
+
+DEF_MACRO(fGET_RUN_MODE,
+ /* */,
+)
+
+DEF_MACRO(fSET_WAIT_MODE,
+ {fLOG_GLOBAL_REG_FIELD(MODECTL,MODECTL_W,
+ fREAD_GLOBAL_REG_FIELD(MODECTL,MODECTL_W) | 1<<(TNUM))},
+ /* NOTHING */
+)
+
+DEF_MACRO(fCLEAR_WAIT_MODE,
+ /* */,
+)
+
+DEF_MACRO(fGET_WAIT_MODE,
+ /* */,
+)
+
+
+DEF_MACRO(fRESET_THREAD,
+ register_reset_interrupt(T,NUM),
+)
+
+DEF_MACRO(fREAD_CURRENT_EVB,
+ (GLOBAL_REG_READ(REG_EVB)),
+ /* nothing */
+)
+
+DEF_MACRO(fREAD_ELR,
+ READ_RREG(REG_ELR),
+ ()
+)
+
+DEF_MACRO(fPOW2_HELP_ROUNDUP,
+ ((VAL) | ((VAL) >> 1) | ((VAL) >> 2) | ((VAL) >> 4) | ((VAL) >> 8) | ((VAL) >> 16)),
+ ()
+)
+
+DEF_MACRO(fPOW2_ROUNDUP,
+ fPOW2_HELP_ROUNDUP((VAL)-1)+1,
+ ()
+)
+
+DEF_MACRO(fTLB_IDXMASK,
+ /* */,
+ ()
+)
+
+DEF_MACRO(fTLB_NONPOW2WRAP,
+ /* */,
+ /* ATTRIBS */
+)
+
+DEF_MACRO(fTLBW,
+ /* */,
+ /* ATTRIBS */
+)
+
+DEF_MACRO(fTLB_ENTRY_OVERLAP,
+ fHIDE( (sys_check_overlap(thread,VALUE)!=-2) ),
+ /* ATTRIBS */
+)
+
+DEF_MACRO(fTLB_ENTRY_OVERLAP_IDX,
+ fHIDE(sys_check_overlap(thread,VALUE)),
+ /* ATTRIBS */
+)
+
+
+DEF_MACRO(fTLBR,
+ TLB_REG_READ(fTLB_NONPOW2WRAP(fTLB_IDXMASK(INDEX))),
+ /* ATTRIBS */
+)
+
+DEF_MACRO(fTLBP,
+ tlb_lookup(thread,((TLBHI)>>12),((TLBHI)<<12),1),
+ /* attribs */
+)
+
+
+
+DEF_MACRO(READ_SGP0,
+ READ_RREG(REG_SGP),
+ ()
+)
+
+DEF_MACRO(READ_SGP1,
+ READ_RREG(REG_SGP+1),
+ ()
+)
+
+DEF_MACRO(READ_SGP10,
+ READ_RREG_PAIR(REG_SGP),
+ ()
+)
+
+DEF_MACRO(READ_UGP,
+ READ_RREG(REG_UGP),
+)
+
+DEF_MACRO(WRITE_SGP0,
+ WRITE_RREG(REG_SGP,VAL),
+ (A_IMPLICIT_WRITES_SGP0)
+)
+
+DEF_MACRO(WRITE_SGP1,
+ WRITE_RREG(REG_SGP+1,VAL),
+ (A_IMPLICIT_WRITES_SGP1)
+)
+
+DEF_MACRO(WRITE_SGP10,
+ WRITE_RREG_PAIR(REG_SGP,VAL),
+ (A_IMPLICIT_WRITES_SGP0,A_IMPLICIT_WRITES_SGP1)
+)
+
+DEF_MACRO(WRITE_UGP,
+ WRITE_RREG(REG_UGP,VAL),
+)
+
+DEF_MACRO(fSTART,
+ /* */,
+ ()
+)
+
+DEF_MACRO(fRESUME,
+ fLOG_GLOBAL_REG_FIELD(MODECTL,MODECTL_W,
+ fREAD_GLOBAL_REG_FIELD(MODECTL,MODECTL_W) & (~(REG))),
+ ()
+)
+
+DEF_MACRO(fGET_TNUM,
+ thread->threadId,
+ ()
+)
+
/********************************************/
/* Cache Management */
/********************************************/
@@ -1602,19 +1948,49 @@ DEF_MACRO(fISYNC,
)
+DEF_MACRO(fICFETCH,
+ ,
+ ()
+)
+
DEF_MACRO(fDCFETCH,
sys_dcfetch(thread, (REG), insn->slot),
(A_MEMLIKE)
)
DEF_MACRO(fICINVA,
- {
- arch_internal_flush(thread->processor_ptr, 0, 0xffffffff);
- sys_icinva(thread, (REG),insn->slot);
- },
+ /* */,
(A_ICINVA)
)
+DEF_MACRO(fDCTAGR,
+ ({DST=sys_dctagr(thread, INDEX, insn->slot,DSTREGNO);})/* FIXME */,
+ ()
+)
+
+DEF_MACRO(fDCTAGW,
+ (sys_dctagw(thread, INDEX, PART2, insn->slot)),
+ ()
+)
+DEF_MACRO(fICTAGR,
+ ({DST=sys_ictagr(thread, INDEX, insn->slot,REGNO);}),
+ ()
+)
+
+DEF_MACRO(fICDATAR,
+ ({DST=sys_icdatar(thread, INDEX, insn->slot);}),
+ ()
+)
+
+DEF_MACRO(fICTAGW,
+ (sys_ictagw(thread, INDEX, PART2, insn->slot)),
+ ()
+)
+DEF_MACRO(fICDATAW,
+ ({ fHIDE(); }),
+ ()
+)
+
DEF_MACRO(fL2FETCH,
sys_l2fetch(thread, ADDR,HEIGHT,WIDTH,STRIDE,FLAGS, insn->slot),
(A_MEMLIKE,A_L2FETCH)
@@ -1635,6 +2011,12 @@ DEF_MACRO(fDCZEROA,
(A_MEMLIKE)
)
+DEF_MACRO(fDCINVA,
+ sys_dcinva(thread, (REG)),
+ (A_MEMLIKE)
+)
+
+
DEF_MACRO(fCHECKFORPRIV,
{sys_check_privs(thread); if (EXCEPTION_DETECTED) return; },
()
@@ -1645,6 +2027,16 @@ DEF_MACRO(fCHECKFORGUEST,
()
)
+DEF_MACRO(fTAKEN_INTERRUPT_EDGECLEAR,
+ { proc->global_regs[REG_IPEND] &= ~(INT_NUMTOMASK(intnum) & proc->global_regs[REG_IEL]); },
+ ()
+)
+
+DEF_MACRO(fSET_IAD,
+ /* */,
+ ()
+)
+
DEF_MACRO(fBRANCH_SPECULATE_STALL,
{
sys_speculate_branch_stall(thread, insn->slot, JUMP_COND(JUMP_PRED_SET),
@@ -1664,3 +2056,79 @@ DEF_MACRO(IV1DEAD,
,
()
)
+
+DEF_MACRO(fIN_MONITOR_MODE,
+ sys_in_monitor_mode(thread),
+ ()
+)
+
+DEF_MACRO(fIN_USER_MODE,
+ sys_in_user_mode(thread),
+ ()
+)
+
+DEF_MACRO(fIN_GUEST_MODE,
+ sys_in_guest_mode(thread),
+ ()
+)
+
+DEF_MACRO(fGRE_ENABLED,
+ fREAD_REG_FIELD(CCR,CCR_GRE),
+ ()
+)
+
+DEF_MACRO(fGTE_ENABLED,
+ fREAD_REG_FIELD(CCR,CCR_GRE),
+ ()
+)
+
+DEF_MACRO(fTRAP1_VIRTINSN,
+ ((fIN_GUEST_MODE())
+ && (fGRE_ENABLED())
+ && ( ((IMM) == 1)
+ || ((IMM) == 3)
+ || ((IMM) == 4)
+ || ((IMM) == 6))),
+ ()
+)
+
+DEF_MACRO(fVIRTINSN_RTE,
+ do {
+ thread->trap1_info = TRAP1_VIRTINSN_RTE;
+ fLOG_REG_FIELD(SSR,SSR_SS,fREAD_REG_FIELD(GSR,GSR_SS));
+ fLOG_REG_FIELD(CCR,CCR_GIE,fREAD_REG_FIELD(GSR,GSR_IE));
+ fLOG_REG_FIELD(SSR,SSR_GM,!fREAD_REG_FIELD(GSR,GSR_UM));
+ fBRANCH((fREAD_GELR() & -4),COF_TYPE_RTE);
+ fINTERNAL_CLEAR_SAMEPAGE();
+ } while (0),
+ (A_IMPLICIT_WRITES_CCR,A_IMPLICIT_WRITES_SSR)
+)
+
+DEF_MACRO(fVIRTINSN_SETIE,
+ do {
+ fLOG_REG_FIELD(CCR,CCR_GIE,(REG) & 1);
+ REG = fREAD_REG_FIELD(CCR,CCR_GIE);
+ thread->trap1_info = TRAP1_VIRTINSN_SETIE;
+ } while (0),
+ (A_IMPLICIT_WRITES_CCR)
+)
+
+DEF_MACRO(fVIRTINSN_GETIE,
+ {
+ thread->trap1_info = TRAP1_VIRTINSN_GETIE;
+ REG = fREAD_REG_FIELD(CCR,CCR_GIE);
+ },
+ ()
+)
+
+DEF_MACRO(fVIRTINSN_SPSWAP,
+ do {
+ if (fREAD_REG_FIELD(GSR,GSR_UM)) {
+ size4u_t TEMP = REG;
+ REG = fREAD_GOSP();
+ fWRITE_GOSP(TEMP);
+ thread->trap1_info = TRAP1_VIRTINSN_SPSWAP;
+ }
+ } while (0),
+ (A_IMPLICIT_WRITES_GOSP)
+)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 16/35] target/hexagon: Add new macro definitions for sysemu
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (14 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 15/35] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 17/35] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
` (18 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Also: add nop TCG overrides for break, unpause, fetchbo; add TCG
override for dczeroa_nt (non-temporal variant of dczeroa).
break: this hardware breakpoint instruction is used with the in-silicon
debugger feature, this is not modeled.
unpause: this instruction is used to resume hardware threads that are
stalled by pause instructions. pause is modeled as a nop, or in RR
mode as an EXCP_YIELD. This instruction is safe to ignore.
Since prefetch functions are not modeled, fetchbo is safe to ignore.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/gen_tcg.h | 9 ++
target/hexagon/macros.h | 25 +++-
target/hexagon/sys_macros.h | 237 ++++++++++++++++++++++++++++++++++++
target/hexagon/op_helper.c | 4 +
4 files changed, 274 insertions(+), 1 deletion(-)
create mode 100644 target/hexagon/sys_macros.h
diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h
index 7b96dab9185..bd04386d860 100644
--- a/target/hexagon/gen_tcg.h
+++ b/target/hexagon/gen_tcg.h
@@ -488,6 +488,7 @@
/* dczeroa clears the 32 byte cache line at the address given */
#define fGEN_TCG_Y2_dczeroa(SHORTCODE) SHORTCODE
+#define fGEN_TCG_Y2_dczeroa_nt(SHORTCODE) SHORTCODE
/* In linux-user mode, these are not modelled, suppress compiler warning */
#define fGEN_TCG_Y2_dcinva(SHORTCODE) \
@@ -1132,6 +1133,9 @@
RdV, tcg_constant_tl(0)); \
} while (0)
+#define fGEN_TCG_Y2_break(SHORTCODE)
+#define fGEN_TCG_J2_unpause(SHORTCODE)
+
#define fGEN_TCG_J2_pause(SHORTCODE) \
do { \
uiV = uiV; \
@@ -1341,6 +1345,11 @@
RsV = RsV; \
uiV = uiV; \
} while (0)
+#define fGEN_TCG_Y2_dcfetchbo_nt(SHORTCODE) \
+ do { \
+ RsV = RsV; \
+ uiV = uiV; \
+ } while (0)
#define fGEN_TCG_L2_loadw_aq(SHORTCODE) SHORTCODE
#define fGEN_TCG_L4_loadd_aq(SHORTCODE) SHORTCODE
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index 6c2862a2320..e4bfea4923f 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -631,8 +631,18 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
#define fCONSTLL(A) A##LL
#define fECHO(A) (A)
-#define fTRAP(TRAPTYPE, IMM) helper_raise_exception(env, HEX_EXCP_TRAP0)
+#ifdef CONFIG_USER_ONLY
+#define fTRAP(TRAPTYPE, IMM) \
+ do { \
+ hexagon_raise_exception_err(env, HEX_EVENT_TRAP0, PC); \
+ } while (0)
+#endif
+
+#define fDO_TRACE(SREG)
+#define fBREAK()
+#define fUNPAUSE()
#define fPAUSE(IMM)
+#define fDCFETCH(REG)
#define fALIGN_REG_FIELD_VALUE(FIELD, VAL) \
((VAL) << reg_field_info[FIELD].offset)
@@ -654,5 +664,18 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
#define fBRANCH_SPECULATE_STALL(DOTNEWVAL, JUMP_COND, SPEC_DIR, HINTBITNUM, \
STRBITNUM) /* Nothing */
+#ifdef CONFIG_USER_ONLY
+/*
+ * This macro can only be true in guest mode.
+ * In user mode, the 4 VIRTINSN's can't be reached
+ */
+#define fTRAP1_VIRTINSN(IMM) (false)
+#define fVIRTINSN_SPSWAP(IMM, REG) g_assert_not_reached()
+#define fVIRTINSN_GETIE(IMM, REG) g_assert_not_reached()
+#define fVIRTINSN_SETIE(IMM, REG) g_assert_not_reached()
+#define fVIRTINSN_RTE(IMM, REG) g_assert_not_reached()
+#endif
+
+#define fPREDUSE_TIMING()
#endif
diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h
new file mode 100644
index 00000000000..f497d55bb81
--- /dev/null
+++ b/target/hexagon/sys_macros.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXAGON_SYS_MACROS_H
+#define HEXAGON_SYS_MACROS_H
+
+/*
+ * Macro definitions for Hexagon system mode
+ */
+
+#ifndef CONFIG_USER_ONLY
+
+#ifdef QEMU_GENERATE
+#define GET_SSR_FIELD(RES, FIELD) \
+ GET_FIELD(RES, FIELD, hex_t_sreg[HEX_SREG_SSR])
+#else
+
+#define GET_SSR_FIELD(FIELD, REGIN) \
+ (uint32_t)GET_FIELD(FIELD, REGIN)
+#define GET_SYSCFG_FIELD(FIELD, REGIN) \
+ (uint32_t)GET_FIELD(FIELD, REGIN)
+#define SET_SYSTEM_FIELD(ENV, REG, FIELD, VAL) \
+ do { \
+ HexagonCPU *_sf_cpu = env_archcpu(ENV); \
+ uint32_t regval; \
+ if ((REG) < HEX_SREG_GLB_START) { \
+ regval = (ENV)->t_sreg[(REG)]; \
+ } else { \
+ regval = _sf_cpu->globalregs ? \
+ hexagon_globalreg_read(_sf_cpu->globalregs, (REG), \
+ (ENV)->threadId) : 0; \
+ } \
+ fINSERT_BITS(regval, reg_field_info[FIELD].width, \
+ reg_field_info[FIELD].offset, (VAL)); \
+ if ((REG) < HEX_SREG_GLB_START) { \
+ (ENV)->t_sreg[(REG)] = regval; \
+ } else if (_sf_cpu->globalregs) { \
+ hexagon_globalreg_write(_sf_cpu->globalregs, (REG), regval, \
+ (ENV)->threadId); \
+ } \
+ } while (0)
+#define SET_SSR_FIELD(ENV, FIELD, VAL) \
+ SET_SYSTEM_FIELD(ENV, HEX_SREG_SSR, FIELD, VAL)
+#define SET_SYSCFG_FIELD(ENV, FIELD, VAL) \
+ SET_SYSTEM_FIELD(ENV, HEX_SREG_SYSCFG, FIELD, VAL)
+
+#define CCR_FIELD_SET(ENV, FIELD) \
+ (!!GET_FIELD(FIELD, (ENV)->t_sreg[HEX_SREG_CCR]))
+
+/*
+ * Direct-to-guest is not implemented yet, continuing would cause unexpected
+ * behavior, so we abort.
+ */
+#define ASSERT_DIRECT_TO_GUEST_UNSET(ENV, EXCP) \
+ do { \
+ switch (EXCP) { \
+ case HEX_EVENT_TRAP0: \
+ g_assert(!CCR_FIELD_SET(ENV, CCR_GTE)); \
+ break; \
+ case HEX_EVENT_IMPRECISE: \
+ case HEX_EVENT_PRECISE: \
+ case HEX_EVENT_FPTRAP: \
+ g_assert(!CCR_FIELD_SET(ENV, CCR_GEE)); \
+ break; \
+ default: \
+ if ((EXCP) >= HEX_EVENT_INT0) { \
+ g_assert(!CCR_FIELD_SET(ENV, CCR_GIE)); \
+ } \
+ break; \
+ } \
+ } while (0)
+#endif
+
+#define fREAD_ELR() (env->t_sreg[HEX_SREG_ELR])
+
+#define fLOAD_PHYS(NUM, SIZE, SIGN, SRC1, SRC2, DST) { \
+ const uintptr_t rs = ((unsigned long)(unsigned)(SRC1)) & 0x7ff; \
+ const uintptr_t rt = ((unsigned long)(unsigned)(SRC2)) << 11; \
+ const uintptr_t addr = rs + rt; \
+ cpu_physical_memory_read(addr, &DST, sizeof(uint32_t)); \
+}
+
+#define fPOW2_HELP_ROUNDUP(VAL) \
+ ((VAL) | \
+ ((VAL) >> 1) | \
+ ((VAL) >> 2) | \
+ ((VAL) >> 4) | \
+ ((VAL) >> 8) | \
+ ((VAL) >> 16))
+#define fPOW2_ROUNDUP(VAL) (fPOW2_HELP_ROUNDUP((VAL) - 1) + 1)
+
+#define fTRAP(TRAPTYPE, IMM) \
+ register_trap_exception(env, TRAPTYPE, IMM, PC)
+
+#define fVIRTINSN_SPSWAP(IMM, REG)
+#define fVIRTINSN_GETIE(IMM, REG) { REG = 0xdeafbeef; }
+#define fVIRTINSN_SETIE(IMM, REG)
+#define fVIRTINSN_RTE(IMM, REG)
+#define fGRE_ENABLED() \
+ GET_FIELD(CCR_GRE, env->t_sreg[HEX_SREG_CCR])
+#define fTRAP1_VIRTINSN(IMM) \
+ (fGRE_ENABLED() && \
+ (((IMM) == 1) || ((IMM) == 3) || ((IMM) == 4) || ((IMM) == 6)))
+
+/* Not modeled in qemu */
+
+#define MARK_LATE_PRED_WRITE(RNUM)
+#define fICINVIDX(REG)
+#define fICKILL()
+#define fDCKILL()
+#define fL2KILL()
+#define fL2UNLOCK()
+#define fL2CLEAN()
+#define fL2CLEANINV()
+#define fL2CLEANPA(REG)
+#define fL2CLEANINVPA(REG)
+#define fL2CLEANINVIDX(REG)
+#define fL2CLEANIDX(REG)
+#define fL2INVIDX(REG)
+#define fL2TAGR(INDEX, DST, DSTREG)
+#define fL2UNLOCKA(VA) ((void) VA)
+#define fL2TAGW(INDEX, PART2)
+#define fDCCLEANIDX(REG)
+#define fDCCLEANINVIDX(REG)
+
+/* Always succeed: */
+#define fL2LOCKA(EA, PDV, PDN) ((void) EA, PDV = 0xFF)
+#define fCLEAR_RTE_EX() \
+ do { \
+ uint32_t tmp = env->t_sreg[HEX_SREG_SSR]; \
+ fINSERT_BITS(tmp, reg_field_info[SSR_EX].width, \
+ reg_field_info[SSR_EX].offset, 0); \
+ log_sreg_write(env, HEX_SREG_SSR, tmp, slot); \
+ } while (0)
+
+#define fDCINVIDX(REG)
+#define fDCINVA(REG) do { REG = REG; } while (0) /* Nothing to do in qemu */
+
+#define fTLB_IDXMASK(INDEX) \
+ ((INDEX) & (fPOW2_ROUNDUP( \
+ fCAST4u(hexagon_tlb_get_num_entries(env_archcpu(env)->tlb))) - 1))
+
+#define fTLB_NONPOW2WRAP(INDEX) \
+ (((INDEX) >= hexagon_tlb_get_num_entries(env_archcpu(env)->tlb)) ? \
+ ((INDEX) - hexagon_tlb_get_num_entries(env_archcpu(env)->tlb)) : \
+ (INDEX))
+
+
+#define fTLBW(INDEX, VALUE) \
+ hex_tlbw(env, (INDEX), (VALUE))
+#define fTLBW_EXTENDED(INDEX, VALUE) \
+ hex_tlbw(env, (INDEX), (VALUE))
+#define fTLB_ENTRY_OVERLAP(VALUE) \
+ (hex_tlb_check_overlap(env, VALUE, -1) != -2)
+#define fTLB_ENTRY_OVERLAP_IDX(VALUE) \
+ hex_tlb_check_overlap(env, VALUE, -1)
+#define fTLBR(INDEX) \
+ hexagon_tlb_read(env_archcpu(env)->tlb, \
+ fTLB_NONPOW2WRAP(fTLB_IDXMASK(INDEX)))
+#define fTLBR_EXTENDED(INDEX) \
+ hexagon_tlb_read(env_archcpu(env)->tlb, \
+ fTLB_NONPOW2WRAP(fTLB_IDXMASK(INDEX)))
+#define fTLBP(TLBHI) \
+ hex_tlb_lookup(env, ((TLBHI) >> 12), ((TLBHI) << 12))
+#define iic_flush_cache(p)
+
+#define fIN_DEBUG_MODE(TNUM) ({ \
+ HexagonCPU *_cpu = env_archcpu(env); \
+ uint32_t _isdbst = _cpu->globalregs ? \
+ hexagon_globalreg_read(_cpu->globalregs, \
+ HEX_SREG_ISDBST, env->threadId) : 0; \
+ (GET_FIELD(ISDBST_DEBUGMODE, _isdbst) \
+ & (0x1 << (TNUM))) != 0; })
+
+#define fIN_DEBUG_MODE_NO_ISDB(TNUM) false
+#define fIN_DEBUG_MODE_WARN(TNUM) false
+
+#ifdef QEMU_GENERATE
+
+/*
+ * Read tags back as zero for now:
+ *
+ * tag value in RD[31:10] for 32k, RD[31:9] for 16k
+ */
+#define fICTAGR(RS, RD, RD2) \
+ do { \
+ RD = ctx->zero; \
+ } while (0)
+#define fICTAGW(RS, RD)
+#define fICDATAR(RS, RD) \
+ do { \
+ RD = ctx->zero; \
+ } while (0)
+#define fICDATAW(RS, RD)
+
+#define fDCTAGW(RS, RT)
+/* tag: RD[23:0], state: RD[30:29] */
+#define fDCTAGR(INDEX, DST, DST_REG_NUM) \
+ do { \
+ DST = ctx->zero; \
+ } while (0)
+#else
+
+/*
+ * Read tags back as zero for now:
+ *
+ * tag value in RD[31:10] for 32k, RD[31:9] for 16k
+ */
+#define fICTAGR(RS, RD, RD2) \
+ do { \
+ RD = 0x00; \
+ } while (0)
+#define fICTAGW(RS, RD)
+#define fICDATAR(RS, RD) \
+ do { \
+ RD = 0x00; \
+ } while (0)
+#define fICDATAW(RS, RD)
+
+#define fDCTAGW(RS, RT)
+/* tag: RD[23:0], state: RD[30:29] */
+#define fDCTAGR(INDEX, DST, DST_REG_NUM) \
+ do { \
+ DST = 0; \
+ } while (0)
+#endif
+
+#else
+#define ASSERT_DIRECT_TO_GUEST_UNSET(ENV, EXCP) do { } while (0)
+#endif
+
+#define NUM_TLB_REGS(x) (hexagon_tlb_get_num_entries(env_archcpu(env)->tlb))
+
+#endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 368391bb846..53898db815b 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -24,6 +24,7 @@
#include "cpu.h"
#include "internal.h"
#include "macros.h"
+#include "sys_macros.h"
#include "arch.h"
#include "hex_arch_types.h"
#include "fma_emu.h"
@@ -31,6 +32,9 @@
#include "mmvec/macros.h"
#include "op_helper.h"
#include "translate.h"
+#ifndef CONFIG_USER_ONLY
+#include "hexswi.h"
+#endif
#define SF_BIAS 127
#define SF_MANTBITS 23
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 17/35] target/hexagon: Add handlers for guest/sysreg r/w
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (15 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 16/35] target/hexagon: Add new macro definitions " Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 18/35] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
` (17 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
This commit provides handlers to generate TCG for guest and system
register reads and writes. They will be leveraged by a future commit.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/genptr.c | 147 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 147 insertions(+)
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 9eb21da6f3e..2310b9aec3a 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -23,6 +23,7 @@
#include "exec/helper-gen.h"
#include "insn.h"
#include "opcodes.h"
+#include "sys_macros.h"
#include "translate.h"
#define QEMU_GENERATE /* Used internally by macros.h */
#include "macros.h"
@@ -120,6 +121,152 @@ TCGv get_result_pred(DisasContext *ctx, int pnum)
}
}
+#ifndef CONFIG_USER_ONLY
+G_GNUC_UNUSED
+static bool greg_writable(int rnum, bool pair)
+{
+ if (pair) {
+ if (rnum < HEX_GREG_G3) {
+ return true;
+ }
+ qemu_log_mask(LOG_UNIMP,
+ "Warning: ignoring write to guest register pair G%d:%d\n",
+ rnum + 1, rnum);
+ } else {
+ if (rnum <= HEX_GREG_G3) {
+ return true;
+ }
+ qemu_log_mask(LOG_UNIMP,
+ "Warning: ignoring write to guest register G%d\n", rnum);
+ }
+ return false;
+}
+
+G_GNUC_UNUSED
+static void check_greg_impl(int rnum, bool pair)
+{
+ if (pair && (!greg_implemented(rnum) || !greg_implemented(rnum + 1))) {
+ qemu_log_mask(LOG_UNIMP,
+ "Warning: guest register pair G%d:%d is unimplemented or "
+ "reserved. Read will yield 0.\n",
+ rnum + 1, rnum);
+ } else if (!pair && !greg_implemented(rnum)) {
+ qemu_log_mask(LOG_UNIMP,
+ "Warning: guest register G%d is unimplemented or reserved."
+ " Read will yield 0.\n", rnum);
+ }
+}
+
+G_GNUC_UNUSED
+static inline void gen_log_greg_write(DisasContext *ctx, int rnum, TCGv_i32 val)
+{
+ tcg_gen_mov_i32(ctx->greg_new_value[rnum], val);
+}
+
+G_GNUC_UNUSED
+static void gen_log_greg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
+{
+ TCGv_i32 val32 = tcg_temp_new_i32();
+
+ /* Low word */
+ tcg_gen_extrl_i64_i32(val32, val);
+ gen_log_greg_write(ctx, rnum, val32);
+
+ /* High word */
+ tcg_gen_extrh_i64_i32(val32, val);
+ gen_log_greg_write(ctx, rnum + 1, val32);
+}
+
+static const uint32_t sreg_immut_masks[NUM_SREGS] = {
+ [HEX_SREG_STID] = 0xff00ff00,
+ [HEX_SREG_ELR] = 0x00000003,
+ [HEX_SREG_SSR] = 0x00008000,
+ [HEX_SREG_CCR] = 0x10e0ff24,
+ [HEX_SREG_HTID] = IMMUTABLE,
+ [HEX_SREG_IMASK] = 0xffff0000,
+ [HEX_SREG_GEVB] = 0x000000ff,
+};
+
+G_GNUC_UNUSED
+static void gen_log_sreg_write(DisasContext *ctx, int rnum, TCGv_i32 val)
+{
+ const uint32_t reg_mask = sreg_immut_masks[rnum];
+
+ if (reg_mask != IMMUTABLE) {
+ if (rnum < HEX_SREG_GLB_START) {
+ gen_masked_reg_write(val, hex_t_sreg[rnum], reg_mask);
+ tcg_gen_mov_i32(ctx->t_sreg_new_value[rnum], val);
+ } else {
+ gen_helper_sreg_write_masked(tcg_env, tcg_constant_i32(rnum), val);
+ }
+ }
+}
+
+G_GNUC_UNUSED
+static void gen_log_sreg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
+{
+ TCGv_i32 val32 = tcg_temp_new_i32();
+
+ /* Low word */
+ tcg_gen_extrl_i64_i32(val32, val);
+ gen_log_sreg_write(ctx, rnum, val32);
+
+ /* High word */
+ tcg_gen_extrh_i64_i32(val32, val);
+ gen_log_sreg_write(ctx, rnum + 1, val32);
+}
+
+G_GNUC_UNUSED
+static void gen_read_sreg(TCGv_i32 dst, int reg_num)
+{
+ if (reg_num >= HEX_SREG_GLB_START || reg_num == HEX_SREG_BADVA) {
+ gen_helper_sreg_read(dst, tcg_env, tcg_constant_i32(reg_num));
+ } else {
+ tcg_gen_mov_i32(dst, hex_t_sreg[reg_num]);
+ }
+}
+
+G_GNUC_UNUSED
+static void gen_read_sreg_pair(TCGv_i64 dst, int reg_num)
+{
+ if (reg_num < HEX_SREG_GLB_START) {
+ if (reg_num + 1 == HEX_SREG_BADVA) {
+ TCGv_i32 badva = tcg_temp_new_i32();
+ gen_helper_sreg_read(badva, tcg_env,
+ tcg_constant_i32(HEX_SREG_BADVA));
+ tcg_gen_concat_i32_i64(dst, hex_t_sreg[reg_num], badva);
+ } else {
+ tcg_gen_concat_i32_i64(dst, hex_t_sreg[reg_num],
+ hex_t_sreg[reg_num + 1]);
+ }
+ } else {
+ gen_helper_sreg_read_pair(dst, tcg_env, tcg_constant_i32(reg_num));
+ }
+}
+
+G_GNUC_UNUSED
+static void gen_read_greg(TCGv_i32 dst, int reg_num)
+{
+ if (reg_num <= HEX_GREG_G3) {
+ tcg_gen_mov_i32(dst, hex_greg[reg_num]);
+ } else {
+ gen_helper_greg_read(dst, tcg_env, tcg_constant_i32(reg_num));
+ }
+}
+
+G_GNUC_UNUSED
+static void gen_read_greg_pair(TCGv_i64 dst, int reg_num)
+{
+ if (reg_num == HEX_GREG_G0 || reg_num == HEX_GREG_G2) {
+ tcg_gen_concat_i32_i64(dst, hex_greg[reg_num],
+ hex_greg[reg_num + 1]);
+ } else {
+ gen_helper_greg_read_pair(dst, tcg_env, tcg_constant_i32(reg_num));
+ }
+}
+#endif
+
+
void gen_pred_write(DisasContext *ctx, int pnum, TCGv val)
{
TCGv pred = get_result_pred(ctx, pnum);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 18/35] target/hexagon: Add placeholder greg/sreg r/w helpers
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (16 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 17/35] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 19/35] target/hexagon: Add vmstate representation Brian Cain
` (16 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/helper.h | 8 ++++++++
target/hexagon/op_helper.c | 28 ++++++++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 64456822bc1..28b9b59e0f2 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -107,3 +107,11 @@ DEF_HELPER_4(probe_noshuf_load, void, env, i32, int, int)
DEF_HELPER_2(probe_pkt_scalar_store_s0, void, env, int)
DEF_HELPER_2(probe_hvx_stores, void, env, int)
DEF_HELPER_2(probe_pkt_scalar_hvx_stores, void, env, int)
+
+#if !defined(CONFIG_USER_ONLY)
+DEF_HELPER_2(sreg_read, i32, env, i32)
+DEF_HELPER_2(sreg_read_pair, i64, env, i32)
+DEF_HELPER_2(greg_read, i32, env, i32)
+DEF_HELPER_2(greg_read_pair, i64, env, i32)
+DEF_HELPER_3(sreg_write_masked, void, env, i32, i32)
+#endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 53898db815b..359bf12f1f2 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1373,6 +1373,34 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
}
}
+#ifndef CONFIG_USER_ONLY
+void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
+{
+ g_assert_not_reached();
+}
+
+uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg)
+{
+ g_assert_not_reached();
+}
+
+uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg)
+{
+ g_assert_not_reached();
+}
+
+uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg)
+{
+ g_assert_not_reached();
+}
+
+uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg)
+{
+ g_assert_not_reached();
+}
+#endif
+
+
/* These macros can be referenced in the generated helper functions */
#define warn(...) /* Nothing */
#define fatal(...) g_assert_not_reached();
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 19/35] target/hexagon: Add vmstate representation
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (17 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 18/35] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-25 19:21 ` Philippe Mathieu-Daudé
2026-03-11 3:49 ` [PATCH v5 20/35] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
` (15 subsequent siblings)
34 siblings, 1 reply; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/internal.h | 4 ++++
target/hexagon/cpu.c | 3 +++
target/hexagon/machine.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 39 insertions(+)
create mode 100644 target/hexagon/machine.c
diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index 5fc837ae229..cd06ff41d4f 100644
--- a/target/hexagon/internal.h
+++ b/target/hexagon/internal.h
@@ -31,4 +31,8 @@ void hexagon_debug(CPUHexagonState *env);
extern const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS];
+#ifndef CONFIG_USER_ONLY
+extern const VMStateDescription vmstate_hexagon_cpu;
+#endif
+
#endif
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 6fabfaad6d2..38d605b06ba 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -387,6 +387,9 @@ static void hexagon_cpu_class_init(ObjectClass *c, const void *data)
cc->gdb_stop_before_watchpoint = true;
cc->gdb_core_xml_file = "hexagon-core.xml";
cc->disas_set_info = hexagon_cpu_disas_set_info;
+#ifndef CONFIG_USER_ONLY
+ dc->vmsd = &vmstate_hexagon_cpu;
+#endif
cc->tcg_ops = &hexagon_tcg_ops;
}
diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c
new file mode 100644
index 00000000000..d6dcd07dd4a
--- /dev/null
+++ b/target/hexagon/machine.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "migration/cpu.h"
+#include "cpu.h"
+
+const VMStateDescription vmstate_hexagon_cpu = {
+ .name = "cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(env.gpr, HexagonCPU, TOTAL_PER_THREAD_REGS),
+ VMSTATE_UINT32_ARRAY(env.pred, HexagonCPU, NUM_PREGS),
+ VMSTATE_UINT32_ARRAY(env.t_sreg, HexagonCPU, NUM_SREGS),
+ VMSTATE_UINT32_ARRAY(env.greg, HexagonCPU, NUM_GREGS),
+ VMSTATE_UINT32(env.next_PC, HexagonCPU),
+ VMSTATE_UINT32(env.tlb_lock_state, HexagonCPU),
+ VMSTATE_UINT32(env.k0_lock_state, HexagonCPU),
+ VMSTATE_UINT32(env.tlb_lock_count, HexagonCPU),
+ VMSTATE_UINT32(env.k0_lock_count, HexagonCPU),
+ VMSTATE_UINT32(env.threadId, HexagonCPU),
+ VMSTATE_UINT32(env.cause_code, HexagonCPU),
+ VMSTATE_UINT32(env.wait_next_pc, HexagonCPU),
+ VMSTATE_UINT64(env.t_cycle_count, HexagonCPU),
+
+ VMSTATE_END_OF_LIST()
+ },
+};
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 20/35] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env()
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (18 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 19/35] target/hexagon: Add vmstate representation Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 21/35] target/hexagon: Define register fields for system regs Brian Cain
` (14 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/hex_common.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index 1daf7239fc4..f7ca4986ca8 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -250,7 +250,9 @@ def need_env(tag):
"A_LOAD" in attribdict[tag] or
"A_CVI_GATHER" in attribdict[tag] or
"A_CVI_SCATTER" in attribdict[tag] or
- "A_IMPLICIT_WRITES_USR" in attribdict[tag])
+ "A_IMPLICIT_WRITES_USR" in attribdict[tag] or
+ "A_PRIV" in attribdict[tag] or
+ "J2_trap" in tag)
def need_slot(tag):
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 21/35] target/hexagon: Define register fields for system regs
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (19 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 20/35] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 22/35] target/hexagon: Implement do_raise_exception() Brian Cain
` (13 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Define the register fields for ssr, schedcfg, stid, bestwait, ccr,
modectl, imask, ipendad.
Define the fields for TLB entries.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/reg_fields_def.h.inc | 96 +++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/target/hexagon/reg_fields_def.h.inc b/target/hexagon/reg_fields_def.h.inc
index f2a58d486c5..9b112ccec64 100644
--- a/target/hexagon/reg_fields_def.h.inc
+++ b/target/hexagon/reg_fields_def.h.inc
@@ -39,3 +39,99 @@ DEF_REG_FIELD(USR_FPDBZE, 26, 1)
DEF_REG_FIELD(USR_FPOVFE, 27, 1)
DEF_REG_FIELD(USR_FPUNFE, 28, 1)
DEF_REG_FIELD(USR_FPINPE, 29, 1)
+
+DEF_REG_FIELD(IPENDAD_IAD, 16, 16)
+DEF_REG_FIELD(IPENDAD_IPEND, 0, 16)
+
+DEF_REG_FIELD(SCHEDCFG_EN, 8, 1)
+DEF_REG_FIELD(SCHEDCFG_INTNO, 0, 4)
+DEF_REG_FIELD(BESTWAIT_PRIO, 0, 9)
+
+
+/* PTE (aka TLB entry) fields */
+DEF_REG_FIELD(PTE_PPD, 0, 24)
+DEF_REG_FIELD(PTE_C, 24, 4)
+DEF_REG_FIELD(PTE_U, 28, 1)
+DEF_REG_FIELD(PTE_R, 29, 1)
+DEF_REG_FIELD(PTE_W, 30, 1)
+DEF_REG_FIELD(PTE_X, 31, 1)
+DEF_REG_FIELD(PTE_VPN, 32, 20)
+DEF_REG_FIELD(PTE_ASID, 52, 7)
+DEF_REG_FIELD(PTE_ATR0, 59, 1)
+DEF_REG_FIELD(PTE_ATR1, 60, 1)
+DEF_REG_FIELD(PTE_PA35, 61, 1)
+DEF_REG_FIELD(PTE_G, 62, 1)
+DEF_REG_FIELD(PTE_V, 63, 1)
+
+/* SYSCFG fields */
+DEF_REG_FIELD(SYSCFG_MMUEN, 0, 1)
+DEF_REG_FIELD(SYSCFG_ICEN, 1, 1)
+DEF_REG_FIELD(SYSCFG_DCEN, 2, 1)
+DEF_REG_FIELD(SYSCFG_ISDBTRUSTED, 3, 1)
+DEF_REG_FIELD(SYSCFG_GIE, 4, 1)
+DEF_REG_FIELD(SYSCFG_ISDBREADY, 5, 1)
+DEF_REG_FIELD(SYSCFG_PCYCLEEN, 6, 1)
+DEF_REG_FIELD(SYSCFG_V2X, 7, 1)
+DEF_REG_FIELD(SYSCFG_IGNOREDABORT, 8, 1)
+DEF_REG_FIELD(SYSCFG_PM, 9, 1)
+DEF_REG_FIELD(SYSCFG_TLBLOCK, 11, 1)
+DEF_REG_FIELD(SYSCFG_K0LOCK, 12, 1)
+DEF_REG_FIELD(SYSCFG_BQ, 13, 1)
+DEF_REG_FIELD(SYSCFG_PRIO, 14, 1)
+DEF_REG_FIELD(SYSCFG_DMT, 15, 1)
+DEF_REG_FIELD(SYSCFG_L2CFG, 16, 3)
+DEF_REG_FIELD(SYSCFG_ITCM, 19, 1)
+DEF_REG_FIELD(SYSCFG_L2NWA, 21, 1)
+DEF_REG_FIELD(SYSCFG_L2NRA, 22, 1)
+DEF_REG_FIELD(SYSCFG_L2WB, 23, 1)
+DEF_REG_FIELD(SYSCFG_L2P, 24, 1)
+DEF_REG_FIELD(SYSCFG_SLVCTL0, 25, 2)
+DEF_REG_FIELD(SYSCFG_SLVCTL1, 27, 2)
+DEF_REG_FIELD(SYSCFG_L2PARTSIZE, 29, 2)
+DEF_REG_FIELD(SYSCFG_L2GCA, 31, 1)
+
+/* SSR fields */
+DEF_REG_FIELD(SSR_CAUSE, 0, 8)
+DEF_REG_FIELD(SSR_ASID, 8, 7)
+DEF_REG_FIELD(SSR_UM, 16, 1)
+DEF_REG_FIELD(SSR_EX, 17, 1)
+DEF_REG_FIELD(SSR_IE, 18, 1)
+DEF_REG_FIELD(SSR_GM, 19, 1)
+DEF_REG_FIELD(SSR_V0, 20, 1)
+DEF_REG_FIELD(SSR_V1, 21, 1)
+DEF_REG_FIELD(SSR_BVS, 22, 1)
+DEF_REG_FIELD(SSR_CE, 23, 1)
+DEF_REG_FIELD(SSR_PE, 24, 1)
+DEF_REG_FIELD(SSR_BP, 25, 1)
+DEF_REG_FIELD(SSR_XE2, 26, 1)
+DEF_REG_FIELD(SSR_XA, 27, 3)
+DEF_REG_FIELD(SSR_SS, 30, 1)
+DEF_REG_FIELD(SSR_XE, 31, 1)
+
+/* misc registers */
+DEF_REG_FIELD(IMASK_MASK, 0, 16)
+
+DEF_REG_FIELD(STID_PRIO, 16, 8)
+DEF_REG_FIELD(STID_STID, 0, 8)
+
+/* MODECTL fields */
+DEF_REG_FIELD(MODECTL_E, 0, 8)
+DEF_REG_FIELD(MODECTL_W, 16, 8)
+
+DEF_REG_FIELD(CCR_L1ICP, 0, 2)
+DEF_REG_FIELD(CCR_L1DCP, 3, 2)
+DEF_REG_FIELD(CCR_L2CP, 6, 2)
+
+DEF_REG_FIELD(CCR_HFI, 16, 1)
+DEF_REG_FIELD(CCR_HFD, 17, 1)
+DEF_REG_FIELD(CCR_HFIL2, 18, 1)
+DEF_REG_FIELD(CCR_HFDL2, 19, 1)
+DEF_REG_FIELD(CCR_SFD, 20, 1)
+
+DEF_REG_FIELD(CCR_GIE, 24, 1)
+DEF_REG_FIELD(CCR_GTE, 25, 1)
+DEF_REG_FIELD(CCR_GEE, 26, 1)
+DEF_REG_FIELD(CCR_GRE, 27, 1)
+DEF_REG_FIELD(CCR_VV1, 29, 1)
+DEF_REG_FIELD(CCR_VV2, 30, 1)
+DEF_REG_FIELD(CCR_VV3, 31, 1)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 22/35] target/hexagon: Implement do_raise_exception()
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (20 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 21/35] target/hexagon: Define register fields for system regs Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 23/35] target/hexagon: Add system reg insns Brian Cain
` (12 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/internal.h | 5 +++++
target/hexagon/op_helper.c | 14 ++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index cd06ff41d4f..33d73ed18d1 100644
--- a/target/hexagon/internal.h
+++ b/target/hexagon/internal.h
@@ -31,6 +31,11 @@ void hexagon_debug(CPUHexagonState *env);
extern const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS];
+void G_NORETURN do_raise_exception(CPUHexagonState *env,
+ uint32_t exception,
+ uint32_t PC,
+ uintptr_t retaddr);
+
#ifndef CONFIG_USER_ONLY
extern const VMStateDescription vmstate_hexagon_cpu;
#endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 359bf12f1f2..327c233c01b 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -40,6 +40,20 @@
#define SF_MANTBITS 23
/* Exceptions processing helpers */
+G_NORETURN
+void do_raise_exception(CPUHexagonState *env, uint32_t exception,
+ uint32_t PC, uintptr_t retaddr)
+{
+ CPUState *cs = env_cpu(env);
+ qemu_log_mask(CPU_LOG_INT, "%s: 0x%08" PRIx32 ", @ %08" PRIx32 "\n",
+ __func__, exception, PC);
+ ASSERT_DIRECT_TO_GUEST_UNSET(env, exception);
+
+ env->gpr[HEX_REG_PC] = PC;
+ cs->exception_index = exception;
+ cpu_loop_exit_restore(cs, retaddr);
+}
+
G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
uint32_t exception,
uintptr_t pc)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 23/35] target/hexagon: Add system reg insns
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (21 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 22/35] target/hexagon: Implement do_raise_exception() Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 24/35] target/hexagon: Add sysemu TCG overrides Brian Cain
` (11 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Acked-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/imported/encode_pp.def | 128 ++++++++++++--
target/hexagon/imported/system.idef | 244 ++++++++++++++++++++++++--
2 files changed, 345 insertions(+), 27 deletions(-)
diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def
index 0cd30a5e857..04e911f59c8 100644
--- a/target/hexagon/imported/encode_pp.def
+++ b/target/hexagon/imported/encode_pp.def
@@ -382,15 +382,18 @@ DEF_ENC32(L4_return_fnew_pt, ICLASS_LD" 011 0 000 sssss PP1110vv ---ddddd")
DEF_ENC32(L4_return_tnew_pnt, ICLASS_LD" 011 0 000 sssss PP0010vv ---ddddd")
DEF_ENC32(L4_return_fnew_pnt, ICLASS_LD" 011 0 000 sssss PP1010vv ---ddddd")
-DEF_ENC32(L2_loadw_locked,ICLASS_LD" 001 0 000 sssss PP000--- 000ddddd")
-
+/** Load Acquire Store Release Encoding **/
+DEF_ENC32(L2_loadw_locked, ICLASS_LD" 001 0 000 sssss PP000--- 000ddddd")
+DEF_ENC32(L4_loadd_locked, ICLASS_LD" 001 0 000 sssss PP010--- 000ddddd")
DEF_ENC32(L2_loadw_aq, ICLASS_LD" 001 0 000 sssss PP001--- 000ddddd")
DEF_ENC32(L4_loadd_aq, ICLASS_LD" 001 0 000 sssss PP011--- 000ddddd")
-DEF_ENC32(R6_release_at_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --0011dd")
-DEF_ENC32(R6_release_st_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --1011dd")
+
+DEF_ENC32(S2_storew_locked, ICLASS_ST" 000 01 01sssss PP-ttttt ----00dd")
+DEF_ENC32(S4_stored_locked, ICLASS_ST" 000 01 11sssss PP0ttttt ----00dd")
+
DEF_ENC32(S2_storew_rl_at_vi, ICLASS_ST" 000 01 01sssss PP-ttttt --0010dd")
DEF_ENC32(S2_storew_rl_st_vi, ICLASS_ST" 000 01 01sssss PP-ttttt --1010dd")
@@ -398,17 +401,15 @@ DEF_ENC32(S2_storew_rl_st_vi, ICLASS_ST" 000 01 01sssss PP-ttttt --1010dd")
DEF_ENC32(S4_stored_rl_at_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --0010dd")
DEF_ENC32(S4_stored_rl_st_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --1010dd")
-DEF_ENC32(L4_loadd_locked,ICLASS_LD" 001 0 000 sssss PP010--- 000ddddd")
-DEF_EXT_SPACE(EXTRACTW, ICLASS_LD" 001 0 000 iiiii PP0iiiii -01iiiii")
+DEF_ENC32(R6_release_at_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --0011dd")
+DEF_ENC32(R6_release_st_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --1011dd")
+
+DEF_EXT_SPACE(EXTRACTW, ICLASS_LD" 001 0 000 iiiii PP0iiiii 001iiiii")
DEF_ENC32(Y2_dcfetchbo, ICLASS_LD" 010 0 000 sssss PP0--iii iiiiiiii")
-
-
-
-
/*******************************/
/* */
/* */
@@ -488,13 +489,17 @@ STD_PST_ENC(rinew, "1 101","10ttt")
/* x bus/cache */
/* x store/cache */
DEF_ENC32(S2_allocframe, ICLASS_ST" 000 01 00xxxxx PP000iii iiiiiiii")
-DEF_ENC32(S2_storew_locked,ICLASS_ST" 000 01 01sssss PP-ttttt ----00dd")
-DEF_ENC32(S4_stored_locked,ICLASS_ST" 000 01 11sssss PP0ttttt ----00dd")
+DEF_ENC32(Y5_l2locka, ICLASS_ST" 000 01 11sssss PP1----- ------dd")
DEF_ENC32(Y2_dczeroa, ICLASS_ST" 000 01 10sssss PP0----- --------")
DEF_ENC32(Y2_barrier, ICLASS_ST" 100 00 00----- PP------ 000-----")
DEF_ENC32(Y2_syncht, ICLASS_ST" 100 00 10----- PP------ --------")
+DEF_ENC32(Y2_l2kill, ICLASS_ST" 100 00 01----- PP-000-- --------")
+DEF_ENC32(Y5_l2gunlock, ICLASS_ST" 100 00 01----- PP-010-- --------")
+DEF_ENC32(Y5_l2gclean, ICLASS_ST" 100 00 01----- PP-100-- --------")
+DEF_ENC32(Y5_l2gcleaninv, ICLASS_ST" 100 00 01----- PP-110-- --------")
+DEF_ENC32(Y2_l2cleaninvidx,ICLASS_ST" 100 00 11sssss PP------ --------")
@@ -502,9 +507,28 @@ DEF_ENC32(Y2_dccleana, ICLASS_ST" 000 00 00sssss PP------ --------")
DEF_ENC32(Y2_dcinva, ICLASS_ST" 000 00 01sssss PP------ --------")
DEF_ENC32(Y2_dccleaninva, ICLASS_ST" 000 00 10sssss PP------ --------")
-DEF_ENC32(Y4_l2fetch, ICLASS_ST" 011 00 00sssss PP-ttttt 000-----")
+/* Super */
+DEF_ENC32(Y2_dckill, ICLASS_ST" 001 00 00----- PP------ --------")
+DEF_ENC32(Y2_dccleanidx, ICLASS_ST" 001 00 01sssss PP------ --------")
+DEF_ENC32(Y2_dcinvidx, ICLASS_ST" 001 00 10sssss PP------ --------")
+DEF_ENC32(Y2_dccleaninvidx,ICLASS_ST" 001 00 11sssss PP------ --------")
+
+DEF_ENC32(Y2_dctagw ,ICLASS_ST" 010 00 00sssss PP-ttttt --------")
+DEF_ENC32(Y2_dctagr ,ICLASS_ST" 010 00 01sssss PP------ ---ddddd")
+
+DEF_ENC32(Y4_l2tagw ,ICLASS_ST" 010 00 10sssss PP0ttttt --------")
+DEF_ENC32(Y4_l2tagr ,ICLASS_ST" 010 00 11sssss PP------ ---ddddd")
+
+DEF_ENC32(Y4_l2fetch, ICLASS_ST" 011 00 00sssss PP-ttttt 000-----")
+DEF_ENC32(Y5_l2cleanidx, ICLASS_ST" 011 00 01sssss PP------ --------")
+DEF_ENC32(Y5_l2invidx, ICLASS_ST" 011 00 10sssss PP------ --------")
+DEF_ENC32(Y5_l2unlocka, ICLASS_ST" 011 00 11sssss PP------ --------")
DEF_ENC32(Y5_l2fetch, ICLASS_ST" 011 01 00sssss PP-ttttt --------")
+DEF_ENC32(Y6_l2gcleanpa, ICLASS_ST" 011 01 01----- PP-ttttt --------")
+DEF_ENC32(Y6_l2gcleaninvpa,ICLASS_ST" 011 01 10----- PP-ttttt --------")
+
+
/*******************************/
/* */
/* */
@@ -547,13 +571,23 @@ DEF_ENC32(J2_jumprfnewpt, ICLASS_J" 0011 011sssss PP-11-uu --------")
DEF_FIELDROW_DESC32(ICLASS_J" 0100 -------- PP------ --------","[#4] (#u8) ")
DEF_ENC32(J2_trap0, ICLASS_J" 0100 00------ PP-iiiii ---iii--")
-DEF_ENC32(J2_pause, ICLASS_J" 0100 01------ PP-iiiii ---iii--")
+DEF_ENC32(J2_trap1, ICLASS_J" 0100 10-xxxxx PP-iiiii ---iii--")
+DEF_ENC32(J2_pause, ICLASS_J" 0100 01----ii PP-iiiii ---iii--")
+
+DEF_FIELDROW_DESC32(ICLASS_J" 0101 -------- PP------ --------","[#5] Rd=(Rs) ")
+DEF_ENC32(Y2_icdatar, ICLASS_J" 0101 101sssss PP------ ---ddddd")
+DEF_ENC32(Y2_ictagr, ICLASS_J" 0101 111sssss PP------ ---ddddd")
+DEF_ENC32(Y2_ictagw, ICLASS_J" 0101 110sssss PP0ttttt --------")
+DEF_ENC32(Y2_icdataw, ICLASS_J" 0101 110sssss PP1ttttt --------")
DEF_FIELDROW_DESC32(ICLASS_J" 0110 -------- PP------ --------","[#6] icop(Rs) ")
DEF_ENC32(Y2_icinva, ICLASS_J" 0110 110sssss PP000--- --------")
+DEF_ENC32(Y2_icinvidx, ICLASS_J" 0110 110sssss PP001--- --------")
+DEF_ENC32(Y2_ickill, ICLASS_J" 0110 110----- PP010--- --------")
DEF_FIELDROW_DESC32(ICLASS_J" 0111 -------- PP------ --------","[#7] () ")
DEF_ENC32(Y2_isync, ICLASS_J" 0111 11000000 PP0---00 00000010")
+DEF_ENC32(J2_rte, ICLASS_J" 0111 111----- PP00---- 000-----")
/* JUMP */
DEF_FIELDROW_DESC32(ICLASS_J" 100- -------- PP------ --------","[#8,9] PC=(#r22)")
@@ -738,12 +772,19 @@ DEF_ENC32(J2_jumprltezpt,ICLASS_CR" 0001 11isssss PPi1iiii iiiiiii-")
DEF_FIELDROW_DESC32( ICLASS_CR" 0010 -------- PP------ --------","[#2] Cd=Rs ")
DEF_ENC32(A2_tfrrcr, ICLASS_CR" 0010 001sssss PP------ ---ddddd")
+DEF_ENC32(G4_tfrgrcr, ICLASS_CR" 0010 000sssss PP------ ---ddddd")
+DEF_ENC32(Y4_trace, ICLASS_CR" 0010 010sssss PP------ 000-----")
+DEF_ENC32(Y6_diag, ICLASS_CR" 0010 010sssss PP------ 001-----")
+DEF_ENC32(Y6_diag0, ICLASS_CR" 0010 010sssss PP-ttttt 010-----")
+DEF_ENC32(Y6_diag1, ICLASS_CR" 0010 010sssss PP-ttttt 011-----")
DEF_FIELDROW_DESC32( ICLASS_CR" 0011 -------- PP------ --------","[#3] Cdd=Rss ")
DEF_ENC32(A4_tfrpcp, ICLASS_CR" 0011 001sssss PP------ ---ddddd")
+DEF_ENC32(G4_tfrgpcp, ICLASS_CR" 0011 000sssss PP------ ---ddddd")
DEF_FIELDROW_DESC32( ICLASS_CR" 1000 -------- PP------ --------","[#8] Rdd=Css ")
DEF_ENC32(A4_tfrcpp, ICLASS_CR" 1000 000sssss PP------ ---ddddd")
+DEF_ENC32(G4_tfrgcpp, ICLASS_CR" 1000 001sssss PP------ ---ddddd")
DEF_FIELDROW_DESC32( ICLASS_CR" 1001 -------- PP------ --------","[#9] (#r8,#U10)")
DEF_ENC32(J2_ploop1si, ICLASS_CR" 1001 101IIIII PP-iiiii IIIii-II")
@@ -754,6 +795,7 @@ DEF_ENC32(J2_loop1i, ICLASS_CR" 1001 001IIIII PP-iiiii IIIii-II")
DEF_FIELDROW_DESC32( ICLASS_CR" 1010 -------- PP------ --------","[#10] Rd=Cs ")
DEF_ENC32(A2_tfrcrr, ICLASS_CR" 1010 000sssss PP------ ---ddddd")
+DEF_ENC32(G4_tfrgcrr, ICLASS_CR" 1010 001sssss PP------ ---ddddd")
DEF_ENC32(C4_addipc, ICLASS_CR" 1010 01001001 PP-iiiii i--ddddd")
@@ -781,6 +823,64 @@ DEF_ENC32(C4_fastcorner9_not, ICLASS_CR"1011 0001--ss PP1---tt 1--1--dd")
+/* Supervisor CR ops */
+/* Interrupts */
+DEF_FIELDROW_DESC32( ICLASS_CR" 0100 -------- PP------ --------","[#4] (Rs,Pt)")
+DEF_ENC32(Y2_swi, ICLASS_CR" 0100 000sssss PP------ 000-----")
+DEF_ENC32(Y2_cswi, ICLASS_CR" 0100 000sssss PP------ 001-----")
+DEF_ENC32(Y2_iassignw, ICLASS_CR" 0100 000sssss PP------ 010-----")
+DEF_ENC32(Y2_ciad, ICLASS_CR" 0100 000sssss PP------ 011-----")
+DEF_ENC32(Y2_setimask, ICLASS_CR" 0100 100sssss PP----tt 000-----")
+DEF_ENC32(Y2_setprio, ICLASS_CR" 0100 100sssss PP----tt 001-----")
+DEF_ENC32(Y4_siad, ICLASS_CR" 0100 100sssss PP------ 011-----")
+
+DEF_ENC32(Y2_wait, ICLASS_CR" 0100 010sssss PP------ 000-----")
+DEF_ENC32(Y2_resume, ICLASS_CR" 0100 010sssss PP------ 001-----")
+DEF_ENC32(Y2_stop, ICLASS_CR" 0100 011sssss PP------ 000-----")
+DEF_ENC32(Y2_start, ICLASS_CR" 0100 011sssss PP------ 001-----")
+DEF_ENC32(Y4_nmi, ICLASS_CR" 0100 011sssss PP------ 010-----")
+
+DEF_FIELDROW_DESC32( ICLASS_CR" 0101 -------- PP------ --------","[#5] Rx ")
+DEF_ENC32(Y2_crswap0, ICLASS_CR" 0101 000xxxxx PP------ --------")
+DEF_ENC32(Y4_crswap1, ICLASS_CR" 0101 001xxxxx PP------ --------")
+
+DEF_FIELDROW_DESC32( ICLASS_CR" 0110 -------- PP------ --------","[#6] Rd=(Rs)")
+DEF_ENC32(Y2_getimask, ICLASS_CR" 0110 000sssss PP------ ---ddddd")
+DEF_ENC32(Y2_iassignr, ICLASS_CR" 0110 011sssss PP------ ---ddddd")
+
+DEF_FIELDROW_DESC32( ICLASS_CR" 0111 -------- PP------ --------","[#7] cr=Rs ")
+DEF_ENC32(Y2_tfrsrcr, ICLASS_CR" 0111 00-sssss PP------ -ddddddd")
+
+DEF_FIELDROW_DESC32( ICLASS_CR" 1100 -------- PP------ --------","[#12] ")
+DEF_ENC32(Y2_break, ICLASS_CR" 1100 001----- PP------ 000-----")
+DEF_ENC32(Y2_tlblock, ICLASS_CR" 1100 001----- PP------ 001-----")
+DEF_ENC32(Y2_tlbunlock,ICLASS_CR" 1100 001----- PP------ 010-----")
+DEF_ENC32(Y2_k0lock, ICLASS_CR" 1100 001----- PP------ 011-----")
+DEF_ENC32(Y2_k0unlock, ICLASS_CR" 1100 001----- PP------ 100-----")
+DEF_ENC32(Y2_tlbp, ICLASS_CR" 1100 100sssss PP------ ---ddddd")
+DEF_ENC32(Y5_tlboc, ICLASS_CR" 1100 111sssss PP------ ---ddddd")
+DEF_ENC32(Y5_tlbasidi, ICLASS_CR" 1100 101sssss PP------ --------")
+DEF_ENC32(Y2_tlbr, ICLASS_CR" 1100 010sssss PP------ ---ddddd")
+DEF_ENC32(Y2_tlbw, ICLASS_CR" 1100 000sssss PP0ttttt --------")
+DEF_ENC32(Y5_ctlbw, ICLASS_CR" 1100 110sssss PP0ttttt ---ddddd")
+
+DEF_FIELDROW_DESC32( ICLASS_CR" 1101 -------- PP------ --------","[#13] Rxx ")
+DEF_ENC32(Y4_crswap10, ICLASS_CR" 1101 10-xxxxx PP------ ---00000")
+DEF_ENC32(Y4_tfrspcp, ICLASS_CR" 1101 00-sssss PP------ -ddddddd")
+
+DEF_FIELDROW_DESC32( ICLASS_CR" 1110 -------- PP------ --------","[#14] Rd=cr ")
+DEF_ENC32(Y2_tfrscrr, ICLASS_CR" 1110 1sssssss PP------ ---ddddd")
+
+DEF_FIELDROW_DESC32( ICLASS_CR" 1111 -------- PP------ --------","[#15] Rdd=Sss ")
+DEF_ENC32(Y4_tfrscpp, ICLASS_CR" 1111 0sssssss PP------ ---ddddd")
+
+
+
+
+
+
+
+
/*******************************/
/* */
/* */
diff --git a/target/hexagon/imported/system.idef b/target/hexagon/imported/system.idef
index 7c6568e75e4..df4527a5fa9 100644
--- a/target/hexagon/imported/system.idef
+++ b/target/hexagon/imported/system.idef
@@ -25,31 +25,230 @@
/* User->OS interface */
/********************************************/
-Q6INSN(J2_trap0,"trap0(#u8)",ATTRIBS(A_COF),
+Q6INSN(J2_trap0,"trap0(#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),
"Trap to Operating System",
fTRAP(0,uiV);
)
-Q6INSN(J2_pause,"pause(#u8)",ATTRIBS(A_COF),
+Q6INSN(J2_trap1,"trap1(Rx32,#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),
+"Trap to Operating System",
+ /*
+ * Note: if RxV is not written, we get the same as the input.
+ * Since trap1 is SOLO, this means the register will effectively not be updated
+ */
+ if (!fTRAP1_VIRTINSN(uiV)) {
+ fTRAP(1,uiV);
+ } else if (uiV == 1) {
+ fVIRTINSN_RTE(uiV,RxV);
+ } else if (uiV == 3) {
+ fVIRTINSN_SETIE(uiV,RxV);
+ } else if (uiV == 4) {
+ fVIRTINSN_GETIE(uiV,RxV);
+ } else if (uiV == 6) {
+ fVIRTINSN_SPSWAP(uiV,RxV);
+ })
+
+Q6INSN(J2_pause,"pause(#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),
"Enter low-power state for #u8 cycles",{fPAUSE(uiV);})
-Q6INSN(Y2_icinva,"icinva(Rs32)",ATTRIBS(A_ICOP,A_ICFLUSHOP),"Instruction Cache Invalidate Address",{fEA_REG(RsV); fICINVA(EA);})
+Q6INSN(J2_rte, "rte", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NO_TIMING_LOG),
+"Return from Exception",
+{
+fHIDE(if((thread->timing_on) && (thread->status & EXEC_STATUS_REPLAY)) { return; })
+fHIDE(CALLBACK(thread->processor_ptr->options->rte_callback,
+ thread->system_ptr,thread->processor_ptr,
+ thread->threadId,0);)
+fCLEAR_RTE_EX();
+fBRANCH(fREAD_ELR(),COF_TYPE_RTE);})
-Q6INSN(Y2_isync,"isync",ATTRIBS(),"Memory Synchronization",{fISYNC();})
-Q6INSN(Y2_barrier,"barrier",ATTRIBS(A_RESTRICT_SLOT0ONLY),"Memory Barrier",{fBARRIER();})
-Q6INSN(Y2_syncht,"syncht",ATTRIBS(A_RESTRICT_SLOT0ONLY),"Memory Synchronization",{fSYNCH();})
+/********************************************/
+/* Interrupt Management */
+/********************************************/
-Q6INSN(Y2_dcfetchbo,"dcfetch(Rs32+#u11:3)",ATTRIBS(A_RESTRICT_PREFERSLOT0,A_DCFETCH),"Data Cache Prefetch",{fEA_RI(RsV,uiV); fDCFETCH(EA);})
+Q6INSN(Y2_swi,"swi(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Software Interrupt",{DO_SWI(RsV);})
+Q6INSN(Y2_cswi,"cswi(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Cancel Software Interrupt",{DO_CSWI(RsV);})
+Q6INSN(Y2_ciad,"ciad(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Re-enable interrupt in IAD",{DO_CIAD(RsV);})
+Q6INSN(Y4_siad,"siad(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Disable interrupt in IAD",{DO_SIAD(RsV);})
+Q6INSN(Y2_iassignr,"Rd32=iassignr(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Read interrupt to thread assignments",{DO_IASSIGNR(RsV,RdV);})
+Q6INSN(Y2_iassignw,"iassignw(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Write interrupt to thread assignments",{DO_IASSIGNW(RsV);})
-Q6INSN(Y2_dczeroa,"dczeroa(Rs32)",ATTRIBS(A_STORE,A_RESTRICT_SLOT0ONLY,A_DCZEROA),"Zero an aligned 32-byte cacheline",{fEA_REG(RsV); fDCZEROA(EA);})
-Q6INSN(Y2_dccleana,"dccleana(Rs32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_DCFLUSHOP),"Data Cache Clean Address",{fEA_REG(RsV); fDCCLEANA(EA);})
-Q6INSN(Y2_dccleaninva,"dccleaninva(Rs32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_DCFLUSHOP),"Data Cache Clean and Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);})
-Q6INSN(Y2_dcinva,"dcinva(Rs32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_DCFLUSHOP),"Data Cache Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);})
+Q6INSN(Y2_getimask,"Rd32=getimask(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Read imask register of another thread",
+{RdV = READ_IMASK(RsV & thread->processor_ptr->thread_system_mask); })
+Q6INSN(Y2_setimask,"setimask(Pt4,Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Change imask register of another thread",
+{fPREDUSE_TIMING();WRITE_IMASK(PtV & thread->processor_ptr->thread_system_mask,RsV); })
-Q6INSN(Y4_l2fetch,"l2fetch(Rs32,Rt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY),"L2 Cache Prefetch",
+
+
+/********************************************/
+/* TLB management */
+/********************************************/
+
+Q6INSN(Y2_tlbw,"tlbw(Rss32,Rt32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),
+"Write TLB entry", {fTLBW(RtV,RssV);})
+
+Q6INSN(Y5_ctlbw,"Rd32=ctlbw(Rss32,Rt32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),
+"Conditional Write TLB entry",
+{
+ if (fTLB_ENTRY_OVERLAP( (1LL<<63) | RssV )) {
+ RdV=fTLB_ENTRY_OVERLAP_IDX( (1LL<<63) | RssV);
+ } else {
+ fTLBW(RtV,RssV);
+ RdV=0x80000000;
+ }
+})
+
+Q6INSN(Y5_tlboc,"Rd32=tlboc(Rss32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),
+"TLB overlap check",
+{
+ if (fTLB_ENTRY_OVERLAP( (1LL<<63) | RssV )) {
+ RdV=fTLB_ENTRY_OVERLAP_IDX( (1LL<<63) | RssV);
+ } else {
+ RdV=0x80000000;
+ }
+})
+
+Q6INSN(Y2_tlbr,"Rdd32=tlbr(Rs32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Read TLB entry",
+{RddV = fTLBR(RsV);})
+
+Q6INSN(Y2_tlbp,"Rd32=tlbp(Rs32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Probe TLB", {RdV=fTLBP(RsV);})
+
+Q6INSN(Y5_tlbasidi,"tlbinvasid(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Invalidate ASID",
+{
+ fHIDE(int i;)
+ fHIDE(unsigned int NUM_TLB_ENTRIES = NUM_TLB_REGS(thread->processor_ptr);)
+ for (i = 0; i < NUM_TLB_ENTRIES; i++) {
+ if ((fGET_FIELD(fTLBR(i),PTE_G) == 0) &&
+ (fGET_FIELD(fTLBR(i),PTE_ASID) == fEXTRACTU_RANGE(RsV,26,20))) {
+ fTLBW(i,fTLBR(i) & ~(1ULL << 63));
+ }
+ }
+})
+
+Q6INSN(Y2_tlblock,"tlblock", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_NO_TIMING_LOG), "Lock TLB",
+{fSET_TLB_LOCK();})
+
+Q6INSN(Y2_tlbunlock,"tlbunlock", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Unlock TLB",
+{fCLEAR_TLB_LOCK();})
+
+Q6INSN(Y2_k0lock,"k0lock", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_NO_TIMING_LOG), "Lock K0",
+{fSET_K0_LOCK();})
+
+Q6INSN(Y2_k0unlock,"k0unlock", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Unlock K0",
+{fCLEAR_K0_LOCK();})
+
+/********************************************/
+/* Supervisor Reg Management */
+/********************************************/
+
+Q6INSN(Y2_crswap0,"crswap(Rx32,sgp0)",ATTRIBS(A_PRIV,A_NOTE_PRIV), "Swap system general pointer 0 with GPR",
+{fHIDE(size4s_t tmp;) tmp = RxV; RxV = READ_SGP0(); WRITE_SGP0(tmp);})
+Q6INSN(Y4_crswap1,"crswap(Rx32,sgp1)",ATTRIBS(A_PRIV,A_NOTE_PRIV), "Swap system general pointer 1 with GPR",
+{fHIDE(size4s_t tmp;) tmp = RxV; RxV = READ_SGP1(); WRITE_SGP1(tmp);})
+
+Q6INSN(Y4_crswap10,"crswap(Rxx32,sgp1:0)",ATTRIBS(A_PRIV,A_NOTE_PRIV), "Swap system general purpose 0/1 with GPR Pair",
+{fHIDE(size8s_t tmp;) tmp = RxxV; RxxV=READ_SGP10(); WRITE_SGP10(tmp);})
+
+Q6INSN(Y2_tfrscrr,"Rd32=Ss128",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Transfer Supervisor Reg to GPR", {RdV=SsV;})
+Q6INSN(Y2_tfrsrcr,"Sd128=Rs32",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Transfer GPR to Supervisor Reg", {SdV=RsV;})
+Q6INSN(Y4_tfrscpp,"Rdd32=Sss128",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Transfer Supervisor Reg to GPR", {RddV=SssV;})
+Q6INSN(Y4_tfrspcp,"Sdd128=Rss32",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Transfer GPR to Supervisor Reg", {SddV=RssV;})
+
+Q6INSN(G4_tfrgcrr,"Rd32=Gs32",ATTRIBS(A_GUEST,A_NOTE_GUEST),"Transfer Guest Reg to GPR", {RdV=GsV;})
+Q6INSN(G4_tfrgrcr,"Gd32=Rs32",ATTRIBS(A_GUEST,A_NOTE_GUEST),"Transfer GPR to Guest Reg", {GdV=RsV;})
+Q6INSN(G4_tfrgcpp,"Rdd32=Gss32",ATTRIBS(A_GUEST,A_NOTE_GUEST),"Transfer Guest Reg to GPR", {RddV=GssV;})
+Q6INSN(G4_tfrgpcp,"Gdd32=Rss32",ATTRIBS(A_GUEST,A_NOTE_GUEST),"Transfer GPR to Guest Reg", {GddV=RssV;})
+
+
+
+Q6INSN(Y2_setprio,"setprio(Pt4,Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Change TID Prio of another thread",
+{fPREDUSE_TIMING();WRITE_PRIO(PtV & thread->processor_ptr->thread_system_mask,RsV); })
+
+
+
+
+/********************************************/
+/* Power Management / Thread on/off */
+/********************************************/
+Q6INSN(Y6_diag,"diag(Rs32)",ATTRIBS(),"Send value to Diag trace module",{
+})
+Q6INSN(Y6_diag0,"diag0(Rss32,Rtt32)",ATTRIBS(),"Send values of two register to DIAG Trace. Set X=0",{
+})
+Q6INSN(Y6_diag1,"diag1(Rss32,Rtt32)",ATTRIBS(),"Send values of two register to DIAG Trace. Set X=1",{
+})
+
+
+Q6INSN(Y4_trace,"trace(Rs32)",ATTRIBS(A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Send value to ETM trace",{
+ fDO_TRACE(RsV);
+})
+
+Q6INSN(Y2_stop,"stop(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Stop thread(s)",{
+ fHIDE(RsV=RsV;)
+ if (!fIN_DEBUG_MODE_NO_ISDB(fGET_TNUM())) fCLEAR_RUN_MODE(fGET_TNUM());
+})
+
+Q6INSN(Y4_nmi,"nmi(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_NO_TIMING_LOG),"Raise NMI on thread(s)",{
+ fDO_NMI(RsV);
+})
+
+Q6INSN(Y2_start,"start(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Start thread(s)",fSTART(RsV);)
+
+Q6INSN(Y2_wait,"wait(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_NO_TIMING_LOG),"Make thread(s) wait",{
+ fHIDE(RsV=RsV;)
+ if (!fIN_DEBUG_MODE(fGET_TNUM())) fSET_WAIT_MODE(fGET_TNUM());
+ fIN_DEBUG_MODE_WARN(fGET_TNUM());
+})
+
+Q6INSN(Y2_resume,"resume(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Make thread(s) stop waiting",fRESUME(RsV);)
+
+Q6INSN(Y2_break,"brkpt",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Breakpoint",{fBREAK();})
+
+
+/********************************************/
+/* Cache Management */
+/********************************************/
+
+Q6INSN(Y2_ictagr,"Rd32=ictagr(Rs32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICTAGOP),"Instruction Cache Tag Read",{fICTAGR(RsV,RdV,RdN);})
+Q6INSN(Y2_ictagw,"ictagw(Rs32,Rt32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICTAGOP),"Instruction Cache Tag Write",{fICTAGW(RsV,RtV);})
+Q6INSN(Y2_icdataw,"icdataw(Rs32,Rt32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICTAGOP),"Instruction Cache Data Write",{fICDATAW(RsV,RtV);})
+Q6INSN(Y2_icdatar,"Rd32=icdatar(Rs32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICTAGOP),"Instruction Cache Data Read",{fICDATAR(RsV, RdV);})
+Q6INSN(Y2_icinva,"icinva(Rs32)",ATTRIBS(A_ICOP,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYADDRESS,A_ICFLUSHOP),"Instruction Cache Invalidate Address",{fEA_REG(RsV); fICINVA(EA);})
+Q6INSN(Y2_icinvidx,"icinvidx(Rs32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICFLUSHOP),"Instruction Cache Invalidate Index",{fICINVIDX(RsV);})
+Q6INSN(Y2_ickill,"ickill",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_ICFLUSHOP),"Instruction Cache Invalidate",{fICKILL();})
+
+Q6INSN(Y2_isync,"isync",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Memory Synchronization",{fISYNC();})
+Q6INSN(Y2_barrier,"barrier",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK),"Memory Barrier",{fBARRIER();})
+Q6INSN(Y2_syncht,"syncht",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET),"Memory Synchronization",{fSYNCH();})
+
+
+Q6INSN(Y2_dcfetchbo,"dcfetch(Rs32+#u11:3)",ATTRIBS(A_RESTRICT_PREFERSLOT0,A_DCFETCH,A_RESTRICT_NOSLOT1_STORE),"Data Cache Prefetch",{fEA_RI(RsV,uiV); fDCFETCH(EA);})
+Q6INSN(Y2_dckill,"dckill",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_DCFLUSHOP),"Data Cache Invalidate",{fDCKILL();})
+
+
+Q6INSN(Y2_dczeroa,"dczeroa(Rs32)",ATTRIBS(A_STORE,A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCZEROA),"Zero an aligned 32-byte cacheline",{fEA_REG(RsV); fDCZEROA(EA);})
+Q6INSN(Y2_dccleana,"dccleana(Rs32)",ATTRIBS(A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCFLUSHOP),"Data Cache Clean Address",{fEA_REG(RsV); fDCCLEANA(EA);})
+Q6INSN(Y2_dccleanidx,"dccleanidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCFLUSHOP),"Data Cache Clean Index",{fDCCLEANIDX(RsV);})
+Q6INSN(Y2_dccleaninva,"dccleaninva(Rs32)",ATTRIBS(A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCFLUSHOP),"Data Cache Clean and Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);})
+Q6INSN(Y2_dccleaninvidx,"dccleaninvidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCFLUSHOP),"Data Cache Clean and Invalidate Index",{fDCCLEANINVIDX(RsV);})
+Q6INSN(Y2_dcinva,"dcinva(Rs32)",ATTRIBS(A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCFLUSHOP),"Data Cache Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);})
+Q6INSN(Y2_dcinvidx,"dcinvidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCFLUSHOP),"Data Cache Invalidate Index",{fDCINVIDX(RsV);})
+Q6INSN(Y2_dctagr,"Rd32=dctagr(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCTAGOP),"Data Cache Tag Read",{fDCTAGR(RsV,RdV,RdN);})
+Q6INSN(Y2_dctagw,"dctagw(Rs32,Rt32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_SLOT0ONLY,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_DCTAGOP),"Data Cache Tag Write",{fDCTAGW(RsV,RtV);})
+
+
+Q6INSN(Y2_l2kill,"l2kill",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Cache Invalidate",{fL2KILL();})
+Q6INSN(Y4_l2tagw,"l2tagw(Rs32,Rt32)",ATTRIBS(A_PRIV,A_NOTE_BADTAG_UNDEF,A_NOTE_PRIV,A_RESTRICT_SLOT0ONLY,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_L2TAGOP),"L2 Cache Tag Write",{fL2TAGW(RsV,RtV);})
+Q6INSN(Y4_l2tagr,"Rd32=l2tagr(Rs32)",ATTRIBS(A_PRIV,A_NOTE_BADTAG_UNDEF,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_L2TAGOP),"L2 Cache Tag Read",{fL2TAGR(RsV,RdV,RdN);})
+
+Q6INSN(Y2_l2cleaninvidx,"l2cleaninvidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_L2FLUSHOP),"L2 Cache Clean and Invalidate Index",{fL2CLEANINVIDX(RsV); })
+Q6INSN(Y5_l2cleanidx,"l2cleanidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_L2FLUSHOP),"L2 Cache Clean by Index",{fL2CLEANIDX(RsV); })
+Q6INSN(Y5_l2invidx,"l2invidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_L2FLUSHOP),"L2 Cache Invalidate by Index",{fL2INVIDX(RsV); })
+
+
+
+Q6INSN(Y4_l2fetch,"l2fetch(Rs32,Rt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"L2 Cache Prefetch",
{ fL2FETCH(RsV,
(RtV&0xff), /*height*/
((RtV>>8)&0xff), /*width*/
@@ -59,10 +258,29 @@ Q6INSN(Y4_l2fetch,"l2fetch(Rs32,Rt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY),"L2 Cache P
-Q6INSN(Y5_l2fetch,"l2fetch(Rs32,Rtt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY),"L2 Cache Prefetch",
+Q6INSN(Y5_l2fetch,"l2fetch(Rs32,Rtt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"L2 Cache Prefetch",
{ fL2FETCH(RsV,
fGETUHALF(0,RttV), /*height*/
fGETUHALF(1,RttV), /*width*/
fGETUHALF(2,RttV), /*stride*/
fGETUHALF(3,RttV)); /*flags*/
})
+
+Q6INSN(Y5_l2locka,"Pd4=l2locka(Rs32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_CACHEOP,A_COPBYADDRESS,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_LATEPRED,A_NOTE_LATEPRED),
+"Lock L2 cache line by address", { fEA_REG(RsV); fL2LOCKA(EA,PdV,PdN); fHIDE(MARK_LATE_PRED_WRITE(PdN)) })
+
+
+Q6INSN(Y5_l2unlocka,"l2unlocka(Rs32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_CACHEOP,A_COPBYADDRESS,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK), "UnLock L2 cache line by address", { fEA_REG(RsV); fL2UNLOCKA(EA); })
+
+
+
+Q6INSN(Y5_l2gunlock,"l2gunlock",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Unlock",{fL2UNLOCK();})
+
+Q6INSN(Y5_l2gclean,"l2gclean",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Clean",{fL2CLEAN();})
+
+Q6INSN(Y5_l2gcleaninv,"l2gcleaninv",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Clean and Invalidate",{fL2CLEANINV();})
+
+Q6INSN(Y6_l2gcleanpa,"l2gclean(Rtt32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Clean by PA Range",{fL2CLEANPA(RttV);})
+
+Q6INSN(Y6_l2gcleaninvpa,"l2gcleaninv(Rtt32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Clean and Invalidate by PA Range",{fL2CLEANINVPA(RttV);})
+
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 24/35] target/hexagon: Add sysemu TCG overrides
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (22 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 23/35] target/hexagon: Add system reg insns Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-25 19:24 ` Philippe Mathieu-Daudé
2026-03-11 3:49 ` [PATCH v5 25/35] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
` (10 subsequent siblings)
34 siblings, 1 reply; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Define TCG overrides for setprio(), crswap(,sgp{0,1,1:0}).
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu_helper.h | 18 ++++++++++++++++
target/hexagon/gen_tcg_sys.h | 40 ++++++++++++++++++++++++++++++++++++
target/hexagon/helper.h | 1 +
target/hexagon/genptr.c | 4 ++++
target/hexagon/op_helper.c | 10 ++++++++-
target/hexagon/hex_common.py | 2 ++
target/hexagon/meson.build | 13 ++++++------
7 files changed, 81 insertions(+), 7 deletions(-)
create mode 100644 target/hexagon/cpu_helper.h
create mode 100644 target/hexagon/gen_tcg_sys.h
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
new file mode 100644
index 00000000000..1486a03c64a
--- /dev/null
+++ b/target/hexagon/cpu_helper.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXAGON_CPU_HELPER_H
+#define HEXAGON_CPU_HELPER_H
+
+uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index);
+uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env);
+uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env);
+uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env);
+void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t);
+void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t);
+void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t);
+
+#endif
diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
new file mode 100644
index 00000000000..04549831ea5
--- /dev/null
+++ b/target/hexagon/gen_tcg_sys.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXAGON_GEN_TCG_SYS_H
+#define HEXAGON_GEN_TCG_SYS_H
+
+#define fGEN_TCG_Y2_setprio(SHORTCODE) \
+ gen_helper_setprio(tcg_env, PtV, RsV)
+
+#define fGEN_TCG_Y2_crswap0(SHORTCODE) \
+ do { \
+ TCGv_i32 tmp = tcg_temp_new_i32(); \
+ tcg_gen_mov_tl(tmp, RxV); \
+ tcg_gen_mov_tl(RxV, hex_t_sreg[HEX_SREG_SGP0]); \
+ tcg_gen_mov_tl(ctx->t_sreg_new_value[HEX_SREG_SGP0], tmp); \
+ } while (0)
+
+#define fGEN_TCG_Y4_crswap1(SHORTCODE) \
+ do { \
+ TCGv_i32 tmp = tcg_temp_new_i32(); \
+ tcg_gen_mov_tl(tmp, RxV); \
+ tcg_gen_mov_tl(RxV, hex_t_sreg[HEX_SREG_SGP1]); \
+ tcg_gen_mov_tl(ctx->t_sreg_new_value[HEX_SREG_SGP1], tmp); \
+ } while (0)
+
+#define fGEN_TCG_Y4_crswap10(SHORTCODE) \
+ do { \
+ TCGv_i64 tmp = tcg_temp_new_i64(); \
+ tcg_gen_mov_i64(tmp, RxxV); \
+ tcg_gen_concat_i32_i64(RxxV, \
+ hex_t_sreg[HEX_SREG_SGP0], \
+ hex_t_sreg[HEX_SREG_SGP1]); \
+ tcg_gen_extrl_i64_i32(ctx->t_sreg_new_value[HEX_SREG_SGP0], tmp); \
+ tcg_gen_extrh_i64_i32(ctx->t_sreg_new_value[HEX_SREG_SGP1], tmp); \
+ } while (0)
+
+#endif
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 28b9b59e0f2..5405342f798 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -114,4 +114,5 @@ DEF_HELPER_2(sreg_read_pair, i64, env, i32)
DEF_HELPER_2(greg_read, i32, env, i32)
DEF_HELPER_2(greg_read_pair, i64, env, i32)
DEF_HELPER_3(sreg_write_masked, void, env, i32, i32)
+DEF_HELPER_3(setprio, void, env, i32, i32)
#endif
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 2310b9aec3a..bac63a42def 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -31,6 +31,10 @@
#undef QEMU_GENERATE
#include "gen_tcg.h"
#include "gen_tcg_hvx.h"
+#ifndef CONFIG_USER_ONLY
+#include "gen_tcg_sys.h"
+#endif
+
#include "genptr.h"
TCGv gen_read_reg(TCGv result, int num)
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 327c233c01b..d9d84f05553 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -19,9 +19,10 @@
#include "qemu/log.h"
#include "accel/tcg/cpu-ldst.h"
#include "accel/tcg/probe.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
#include "exec/helper-proto.h"
#include "fpu/softfloat.h"
-#include "cpu.h"
#include "internal.h"
#include "macros.h"
#include "sys_macros.h"
@@ -31,6 +32,7 @@
#include "mmvec/mmvec.h"
#include "mmvec/macros.h"
#include "op_helper.h"
+#include "cpu_helper.h"
#include "translate.h"
#ifndef CONFIG_USER_ONLY
#include "hexswi.h"
@@ -1412,6 +1414,12 @@ uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg)
{
g_assert_not_reached();
}
+
+void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio)
+{
+ g_assert_not_reached();
+}
+
#endif
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index f7ca4986ca8..3ba1a4523f1 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -1369,6 +1369,7 @@ def parse_common_args(desc):
parser.add_argument("semantics", help="semantics file")
parser.add_argument("overrides", help="overrides file")
parser.add_argument("overrides_vec", help="vector overrides file")
+ parser.add_argument("overrides_sys", help="system overrides file")
parser.add_argument("out", help="output file")
parser.add_argument("--idef-parser",
help="file of instructions translated by idef-parser")
@@ -1376,6 +1377,7 @@ def parse_common_args(desc):
read_semantics_file(args.semantics)
read_overrides_file(args.overrides)
read_overrides_file(args.overrides_vec)
+ read_overrides_file(args.overrides_sys)
if args.idef_parser:
read_idef_parser_enabled_file(args.idef_parser)
calculate_attribs()
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index d169cf71b2f..528beca3cd0 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -20,6 +20,7 @@ hexagon_ss = ss.source_set()
hex_common_py = 'hex_common.py'
gen_tcg_h = meson.current_source_dir() / 'gen_tcg.h'
gen_tcg_hvx_h = meson.current_source_dir() / 'gen_tcg_hvx.h'
+gen_tcg_sys_h = meson.current_source_dir() / 'gen_tcg_sys.h'
idef_parser_dir = meson.current_source_dir() / 'idef-parser'
#
@@ -337,12 +338,12 @@ if idef_parser_enabled and 'hexagon-linux-user' in target_dirs
# Setup input and dependencies for the next step, this depends on whether or
# not idef-parser is enabled
helper_dep = [semantics_generated, idef_generated_tcg_c, idef_generated_tcg]
- helper_in = [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, '--idef-parser', idef_generated_list]
+ helper_in = [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h, '--idef-parser', idef_generated_list]
else
# Setup input and dependencies for the next step, this depends on whether or
# not idef-parser is enabled
helper_dep = [semantics_generated]
- helper_in = [semantics_generated, gen_tcg_h, gen_tcg_hvx_h]
+ helper_in = [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h]
endif
#
@@ -356,7 +357,7 @@ helper_protos_generated = custom_target(
'helper_protos_generated.h.inc',
output: 'helper_protos_generated.h.inc',
depends: helper_dep,
- depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h],
+ depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h],
command: [python, files('gen_helper_protos.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(helper_protos_generated)
@@ -365,7 +366,7 @@ helper_funcs_generated = custom_target(
'helper_funcs_generated.c.inc',
output: 'helper_funcs_generated.c.inc',
depends: helper_dep,
- depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h],
+ depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h],
command: [python, files('gen_helper_funcs.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(helper_funcs_generated)
@@ -374,7 +375,7 @@ tcg_funcs_generated = custom_target(
'tcg_funcs_generated.c.inc',
output: 'tcg_funcs_generated.c.inc',
depends: helper_dep,
- depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h],
+ depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h],
command: [python, files('gen_tcg_funcs.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(tcg_funcs_generated)
@@ -383,7 +384,7 @@ analyze_funcs_generated = custom_target(
'analyze_funcs_generated.c.inc',
output: 'analyze_funcs_generated.c.inc',
depends: helper_dep,
- depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h],
+ depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h],
command: [python, files('gen_analyze_funcs.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(analyze_funcs_generated)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 25/35] target/hexagon: Add implicit attributes to sysemu macros
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (23 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 24/35] target/hexagon: Add sysemu TCG overrides Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 26/35] target/hexagon: Add TCG overrides for int handler insts Brian Cain
` (9 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/hex_common.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index 3ba1a4523f1..9986f47114e 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -128,8 +128,11 @@ def calculate_attribs():
add_qemu_macro_attrib("fTRAP", "A_IMPLICIT_READS_PC")
add_qemu_macro_attrib("fSET_OVERFLOW", "A_IMPLICIT_WRITES_USR")
add_qemu_macro_attrib("fSET_LPCFG", "A_IMPLICIT_WRITES_USR")
+ add_qemu_macro_attrib("fCLEAR_RTE_EX", "A_IMPLICIT_WRITES_SSR")
add_qemu_macro_attrib("fLOAD", "A_SCALAR_LOAD")
add_qemu_macro_attrib("fSTORE", "A_SCALAR_STORE")
+ add_qemu_macro_attrib("fSET_K0_LOCK", "A_IMPLICIT_READS_PC")
+ add_qemu_macro_attrib("fSET_TLB_LOCK", "A_IMPLICIT_READS_PC")
add_qemu_macro_attrib('fLSBNEW0', 'A_IMPLICIT_READS_P0')
add_qemu_macro_attrib('fLSBNEW0NOT', 'A_IMPLICIT_READS_P0')
add_qemu_macro_attrib('fREAD_P0', 'A_IMPLICIT_READS_P0')
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 26/35] target/hexagon: Add TCG overrides for int handler insts
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (24 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 25/35] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 27/35] target/hexagon: Add TCG overrides for thread ctl Brian Cain
` (8 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Define TCG overrides for {c,}swi {c,s}iad, iassign{r,w}, {s,g}etimask
instructions.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/gen_tcg_sys.h | 25 ++++++++++++++++++++++
target/hexagon/helper.h | 8 ++++++++
target/hexagon/op_helper.c | 40 ++++++++++++++++++++++++++++++++++++
3 files changed, 73 insertions(+)
diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
index 04549831ea5..cc72ca86db8 100644
--- a/target/hexagon/gen_tcg_sys.h
+++ b/target/hexagon/gen_tcg_sys.h
@@ -7,6 +7,31 @@
#ifndef HEXAGON_GEN_TCG_SYS_H
#define HEXAGON_GEN_TCG_SYS_H
+/* System mode instructions */
+#define fGEN_TCG_Y2_swi(SHORTCODE) \
+ gen_helper_swi(tcg_env, RsV)
+
+#define fGEN_TCG_Y2_cswi(SHORTCODE) \
+ gen_helper_cswi(tcg_env, RsV)
+
+#define fGEN_TCG_Y2_ciad(SHORTCODE) \
+ gen_helper_ciad(tcg_env, RsV)
+
+#define fGEN_TCG_Y4_siad(SHORTCODE) \
+ gen_helper_siad(tcg_env, RsV)
+
+#define fGEN_TCG_Y2_iassignw(SHORTCODE) \
+ gen_helper_iassignw(tcg_env, RsV)
+
+#define fGEN_TCG_Y2_iassignr(SHORTCODE) \
+ gen_helper_iassignr(RdV, tcg_env, RsV)
+
+#define fGEN_TCG_Y2_getimask(SHORTCODE) \
+ gen_helper_getimask(RdV, tcg_env, RsV)
+
+#define fGEN_TCG_Y2_setimask(SHORTCODE) \
+ gen_helper_setimask(tcg_env, PtV, RsV)
+
#define fGEN_TCG_Y2_setprio(SHORTCODE) \
gen_helper_setprio(tcg_env, PtV, RsV)
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 5405342f798..955287133e4 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -109,6 +109,14 @@ DEF_HELPER_2(probe_hvx_stores, void, env, int)
DEF_HELPER_2(probe_pkt_scalar_hvx_stores, void, env, int)
#if !defined(CONFIG_USER_ONLY)
+DEF_HELPER_2(swi, void, env, i32)
+DEF_HELPER_2(cswi, void, env, i32)
+DEF_HELPER_2(ciad, void, env, i32)
+DEF_HELPER_2(siad, void, env, i32)
+DEF_HELPER_2(iassignw, void, env, i32)
+DEF_HELPER_2(iassignr, i32, env, i32)
+DEF_HELPER_2(getimask, i32, env, i32)
+DEF_HELPER_3(setimask, void, env, i32, i32)
DEF_HELPER_2(sreg_read, i32, env, i32)
DEF_HELPER_2(sreg_read_pair, i64, env, i32)
DEF_HELPER_2(greg_read, i32, env, i32)
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index d9d84f05553..e81e89b8bd9 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1390,6 +1390,46 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
}
#ifndef CONFIG_USER_ONLY
+void HELPER(ciad)(CPUHexagonState *env, uint32_t mask)
+{
+ g_assert_not_reached();
+}
+
+void HELPER(siad)(CPUHexagonState *env, uint32_t mask)
+{
+ g_assert_not_reached();
+}
+
+void HELPER(swi)(CPUHexagonState *env, uint32_t mask)
+{
+ g_assert_not_reached();
+}
+
+void HELPER(cswi)(CPUHexagonState *env, uint32_t mask)
+{
+ g_assert_not_reached();
+}
+
+void HELPER(iassignw)(CPUHexagonState *env, uint32_t src)
+{
+ g_assert_not_reached();
+}
+
+uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src)
+{
+ g_assert_not_reached();
+}
+
+uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid)
+{
+ g_assert_not_reached();
+}
+
+void HELPER(setimask)(CPUHexagonState *env, uint32_t tid, uint32_t imask)
+{
+ g_assert_not_reached();
+}
+
void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
{
g_assert_not_reached();
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 27/35] target/hexagon: Add TCG overrides for thread ctl
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (25 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 26/35] target/hexagon: Add TCG overrides for int handler insts Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 28/35] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
` (7 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Define TCG overrides for start, stop, wait, resume instructions.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/gen_tcg_sys.h | 18 ++++++++++++++++++
target/hexagon/helper.h | 4 ++++
target/hexagon/op_helper.c | 20 ++++++++++++++++++++
3 files changed, 42 insertions(+)
diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
index cc72ca86db8..739e95ea60b 100644
--- a/target/hexagon/gen_tcg_sys.h
+++ b/target/hexagon/gen_tcg_sys.h
@@ -62,4 +62,22 @@
tcg_gen_extrh_i64_i32(ctx->t_sreg_new_value[HEX_SREG_SGP1], tmp); \
} while (0)
+#define fGEN_TCG_Y2_wait(SHORTCODE) \
+ do { \
+ RsV = RsV; \
+ gen_helper_wait(tcg_env, tcg_constant_tl(ctx->pkt->pc)); \
+ } while (0)
+
+#define fGEN_TCG_Y2_resume(SHORTCODE) \
+ gen_helper_resume(tcg_env, RsV)
+
+#define fGEN_TCG_Y2_start(SHORTCODE) \
+ gen_helper_start(tcg_env, RsV)
+
+#define fGEN_TCG_Y2_stop(SHORTCODE) \
+ do { \
+ RsV = RsV; \
+ gen_helper_stop(tcg_env); \
+ } while (0)
+
#endif
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 955287133e4..682f0c6c26e 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -123,4 +123,8 @@ DEF_HELPER_2(greg_read, i32, env, i32)
DEF_HELPER_2(greg_read_pair, i64, env, i32)
DEF_HELPER_3(sreg_write_masked, void, env, i32, i32)
DEF_HELPER_3(setprio, void, env, i32, i32)
+DEF_HELPER_2(start, void, env, i32)
+DEF_HELPER_1(stop, void, env)
+DEF_HELPER_2(wait, void, env, i32)
+DEF_HELPER_2(resume, void, env, i32)
#endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index e81e89b8bd9..eac6a22fd64 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1420,6 +1420,26 @@ uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src)
g_assert_not_reached();
}
+void HELPER(start)(CPUHexagonState *env, uint32_t imask)
+{
+ g_assert_not_reached();
+}
+
+void HELPER(stop)(CPUHexagonState *env)
+{
+ g_assert_not_reached();
+}
+
+void HELPER(wait)(CPUHexagonState *env, target_ulong PC)
+{
+ g_assert_not_reached();
+}
+
+void HELPER(resume)(CPUHexagonState *env, uint32_t mask)
+{
+ g_assert_not_reached();
+}
+
uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid)
{
g_assert_not_reached();
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 28/35] target/hexagon: Add TCG overrides for rte, nmi
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (26 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 27/35] target/hexagon: Add TCG overrides for thread ctl Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 29/35] target/hexagon: Add sreg_{read,write} helpers Brian Cain
` (6 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/gen_tcg_sys.h | 19 +++++++++++++++++++
target/hexagon/helper.h | 1 +
target/hexagon/op_helper.c | 4 ++++
3 files changed, 24 insertions(+)
diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
index 739e95ea60b..04406db6a4b 100644
--- a/target/hexagon/gen_tcg_sys.h
+++ b/target/hexagon/gen_tcg_sys.h
@@ -80,4 +80,23 @@
gen_helper_stop(tcg_env); \
} while (0)
+/*
+ * rte (return from exception)
+ * Clear the EX bit in SSR
+ * Jump to ELR
+ */
+#define fGEN_TCG_J2_rte(SHORTCODE) \
+ do { \
+ TCGv_i32 new_ssr = tcg_temp_new_i32(); \
+ tcg_gen_deposit_tl(new_ssr, hex_t_sreg[HEX_SREG_SSR], \
+ tcg_constant_tl(0), \
+ reg_field_info[SSR_EX].offset, \
+ reg_field_info[SSR_EX].width); \
+ gen_log_sreg_write(ctx, HEX_SREG_SSR, new_ssr); \
+ gen_jumpr(ctx, hex_t_sreg[HEX_SREG_ELR]); \
+ } while (0)
+
+#define fGEN_TCG_Y4_nmi(SHORTCODE) \
+ gen_helper_nmi(tcg_env, RsV)
+
#endif
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 682f0c6c26e..9ca87acfe63 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -127,4 +127,5 @@ DEF_HELPER_2(start, void, env, i32)
DEF_HELPER_1(stop, void, env)
DEF_HELPER_2(wait, void, env, i32)
DEF_HELPER_2(resume, void, env, i32)
+DEF_HELPER_2(nmi, void, env, i32)
#endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index eac6a22fd64..af93be7a232 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1480,6 +1480,10 @@ void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio)
g_assert_not_reached();
}
+void HELPER(nmi)(CPUHexagonState *env, uint32_t thread_mask)
+{
+ g_assert_not_reached();
+}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 29/35] target/hexagon: Add sreg_{read,write} helpers
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (27 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 28/35] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-25 19:26 ` Philippe Mathieu-Daudé
2026-03-11 3:49 ` [PATCH v5 30/35] target/hexagon: Add cpu modes, mmu indices, next_PC to state Brian Cain
` (5 subsequent siblings)
34 siblings, 1 reply; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain,
Sid Manning
From: Brian Cain <bcain@quicinc.com>
Co-authored-by: Sid Manning <sidneym@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.c | 1 -
target/hexagon/cpu_helper.c | 60 +++++++++++++++++++++++++++++++++++++
target/hexagon/op_helper.c | 30 +++++++++++++++++--
3 files changed, 87 insertions(+), 4 deletions(-)
create mode 100644 target/hexagon/cpu_helper.c
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 38d605b06ba..dc3bd82bc05 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -339,7 +339,6 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
qemu_init_vcpu(cs);
cpu_reset(cs);
-
mcc->parent_realize(dev, errp);
}
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
new file mode 100644
index 00000000000..b8e0625e3f8
--- /dev/null
+++ b/target/hexagon/cpu_helper.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "cpu_helper.h"
+#include "system/cpus.h"
+#include "hw/core/boards.h"
+#include "hw/hexagon/hexagon.h"
+#include "exec/cpu-interrupt.h"
+#include "exec/target_page.h"
+#include "accel/tcg/cpu-ldst.h"
+#include "exec/cputlb.h"
+#include "qemu/log.h"
+#include "tcg/tcg-op.h"
+#include "internal.h"
+#include "macros.h"
+#include "sys_macros.h"
+#include "arch.h"
+
+
+uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index)
+{
+ g_assert_not_reached();
+}
+
+uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env)
+{
+ g_assert_not_reached();
+}
+
+uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env)
+{
+ g_assert_not_reached();
+}
+
+uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env)
+{
+ g_assert_not_reached();
+}
+
+void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env,
+ uint32_t cycles_hi)
+{
+ g_assert_not_reached();
+}
+
+void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env,
+ uint32_t cycles_lo)
+{
+ g_assert_not_reached();
+}
+
+void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t cycles)
+{
+ g_assert_not_reached();
+}
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index af93be7a232..3517f3768fd 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1452,17 +1452,41 @@ void HELPER(setimask)(CPUHexagonState *env, uint32_t tid, uint32_t imask)
void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
{
- g_assert_not_reached();
+ BQL_LOCK_GUARD();
+ if (reg < HEX_SREG_GLB_START) {
+ env->t_sreg[reg] = val;
+ } else {
+ HexagonCPU *cpu = env_archcpu(env);
+ if (cpu->globalregs) {
+ hexagon_globalreg_write_masked(cpu->globalregs, reg, val);
+ }
+ }
+}
+
+static inline QEMU_ALWAYS_INLINE uint32_t sreg_read(CPUHexagonState *env,
+ uint32_t reg)
+{
+ g_assert(bql_locked());
+ if (reg < HEX_SREG_GLB_START) {
+ return env->t_sreg[reg];
+ }
+ HexagonCPU *cpu = env_archcpu(env);
+ return cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, reg, env->threadId) : 0;
}
uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg)
{
- g_assert_not_reached();
+ BQL_LOCK_GUARD();
+ return sreg_read(env, reg);
}
uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg)
{
- g_assert_not_reached();
+ BQL_LOCK_GUARD();
+
+ return deposit64((uint64_t) sreg_read(env, reg), 32, 32,
+ sreg_read(env, reg + 1));
}
uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 30/35] target/hexagon: Add cpu modes, mmu indices, next_PC to state
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (28 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 29/35] target/hexagon: Add sreg_{read,write} helpers Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 31/35] hw/hexagon: Introduce hexagon TLB device Brian Cain
` (4 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 21 ++++++++++++++++++++-
target/hexagon/cpu.c | 1 +
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 3562965c88a..9eb2d1bbabe 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -48,8 +48,26 @@
#define VSTORES_MAX 2
#define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU
+#ifndef CONFIG_USER_ONLY
+#define CPU_INTERRUPT_SWI CPU_INTERRUPT_TGT_INT_0
+
+#define HEX_CPU_MODE_USER 1
+#define HEX_CPU_MODE_GUEST 2
+#define HEX_CPU_MODE_MONITOR 3
+
+#define HEX_EXE_MODE_OFF 1
+#define HEX_EXE_MODE_RUN 2
+#define HEX_EXE_MODE_WAIT 3
+#define HEX_EXE_MODE_DEBUG 4
+#endif
+
+#define MMU_USER_IDX 0
+#ifndef CONFIG_USER_ONLY
+#define MMU_GUEST_IDX 1
+#define MMU_KERNEL_IDX 2
+
+#endif
-#define MMU_USER_IDX 0
#define HEXAGON_CPU_IRQ_0 0
#define HEXAGON_CPU_IRQ_1 1
@@ -110,6 +128,7 @@ typedef struct CPUArchState {
/* This alias of CPUState.cpu_index is used by imported sources: */
uint32_t threadId;
#endif
+ uint32_t next_PC;
target_ulong new_value_usr;
MemLog mem_log_stores[STORES_MAX];
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index dc3bd82bc05..b1317f83ef4 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -310,6 +310,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
memset(env->t_sreg, 0, sizeof(uint32_t) * NUM_SREGS);
memset(env->greg, 0, sizeof(uint32_t) * NUM_GREGS);
env->wait_next_pc = 0;
+ env->next_PC = 0;
#endif
env->cause_code = HEX_EVENT_NONE;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 31/35] hw/hexagon: Introduce hexagon TLB device
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (29 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 30/35] target/hexagon: Add cpu modes, mmu indices, next_PC to state Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-25 19:38 ` Philippe Mathieu-Daudé
2026-03-11 3:49 ` [PATCH v5 32/35] target/hexagon: Add stubs for modify_ssr/get_exe_mode Brian Cain
` (3 subsequent siblings)
34 siblings, 1 reply; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo
Add the hexagon TLB QOM device model.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
---
include/hw/hexagon/hexagon_tlb.h | 45 +++
target/hexagon/cpu.h | 4 +
hw/hexagon/hexagon_tlb.c | 463 +++++++++++++++++++++++++++++++
target/hexagon/cpu.c | 5 +
4 files changed, 517 insertions(+)
create mode 100644 include/hw/hexagon/hexagon_tlb.h
create mode 100644 hw/hexagon/hexagon_tlb.c
diff --git a/include/hw/hexagon/hexagon_tlb.h b/include/hw/hexagon/hexagon_tlb.h
new file mode 100644
index 00000000000..bcb387aa24d
--- /dev/null
+++ b/include/hw/hexagon/hexagon_tlb.h
@@ -0,0 +1,45 @@
+/*
+ * Hexagon TLB QOM Device
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_HEXAGON_TLB_H
+#define HW_HEXAGON_TLB_H
+
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+#include "exec/hwaddr.h"
+#include "exec/mmu-access-type.h"
+#define TYPE_HEXAGON_TLB "hexagon-tlb"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonTLBState, HEXAGON_TLB)
+
+struct HexagonTLBState {
+ SysBusDevice parent_obj;
+
+ uint32_t num_entries;
+ uint64_t *entries;
+};
+
+uint64_t hexagon_tlb_read(HexagonTLBState *tlb, uint32_t index);
+void hexagon_tlb_write(HexagonTLBState *tlb, uint32_t index, uint64_t value);
+
+bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
+ uint32_t VA, MMUAccessType access_type,
+ hwaddr *PA, int *prot, uint64_t *size,
+ int32_t *excp, int *cause_code, int mmu_idx);
+
+uint32_t hexagon_tlb_lookup(HexagonTLBState *tlb, uint32_t asid,
+ uint32_t VA, int *cause_code);
+
+int hexagon_tlb_check_overlap(HexagonTLBState *tlb, uint64_t entry,
+ uint64_t index);
+
+void hexagon_tlb_dump(HexagonTLBState *tlb);
+
+bool hexagon_tlb_dump_entry(FILE *f, uint64_t entry);
+
+uint32_t hexagon_tlb_get_num_entries(HexagonTLBState *tlb);
+
+#endif /* HW_HEXAGON_TLB_H */
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 9eb2d1bbabe..e39e6e39fec 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -46,6 +46,7 @@
#define REG_WRITES_MAX 32
#define PRED_WRITES_MAX 5 /* 4 insns + endloop */
#define VSTORES_MAX 2
+#define MAX_TLB_ENTRIES 1024
#define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU
#ifndef CONFIG_USER_ONLY
@@ -174,6 +175,9 @@ struct ArchCPU {
bool lldb_compat;
target_ulong lldb_stack_adjust;
bool short_circuit;
+#ifndef CONFIG_USER_ONLY
+ struct HexagonTLBState *tlb;
+#endif
};
#include "cpu_bits.h"
diff --git a/hw/hexagon/hexagon_tlb.c b/hw/hexagon/hexagon_tlb.c
new file mode 100644
index 00000000000..90f319f56d3
--- /dev/null
+++ b/hw/hexagon/hexagon_tlb.c
@@ -0,0 +1,463 @@
+/*
+ * Hexagon TLB QOM Device
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/hexagon/hexagon_tlb.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/resettable.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "target/hexagon/cpu.h"
+#include "target/hexagon/cpu_bits.h"
+
+/* PTE (TLB entry) field extraction */
+#define GET_PTE_PPD(entry) extract64((entry), 0, 24)
+#define GET_PTE_C(entry) extract64((entry), 24, 4)
+#define GET_PTE_U(entry) extract64((entry), 28, 1)
+#define GET_PTE_R(entry) extract64((entry), 29, 1)
+#define GET_PTE_W(entry) extract64((entry), 30, 1)
+#define GET_PTE_X(entry) extract64((entry), 31, 1)
+#define GET_PTE_VPN(entry) extract64((entry), 32, 20)
+#define GET_PTE_ASID(entry) extract64((entry), 52, 7)
+#define GET_PTE_ATR0(entry) extract64((entry), 59, 1)
+#define GET_PTE_ATR1(entry) extract64((entry), 60, 1)
+#define GET_PTE_PA35(entry) extract64((entry), 61, 1)
+#define GET_PTE_G(entry) extract64((entry), 62, 1)
+#define GET_PTE_V(entry) extract64((entry), 63, 1)
+
+/* PPD (physical page descriptor) */
+static inline uint64_t GET_PPD(uint64_t entry)
+{
+ return GET_PTE_PPD(entry) | (GET_PTE_PA35(entry) << 24);
+}
+
+#define NO_ASID (1 << 8)
+
+typedef enum {
+ PGSIZE_4K,
+ PGSIZE_16K,
+ PGSIZE_64K,
+ PGSIZE_256K,
+ PGSIZE_1M,
+ PGSIZE_4M,
+ PGSIZE_16M,
+ PGSIZE_64M,
+ PGSIZE_256M,
+ PGSIZE_1G,
+ NUM_PGSIZE_TYPES
+} tlb_pgsize_t;
+
+static const char *pgsize_str[NUM_PGSIZE_TYPES] = {
+ "4K",
+ "16K",
+ "64K",
+ "256K",
+ "1M",
+ "4M",
+ "16M",
+ "64M",
+ "256M",
+ "1G",
+};
+
+#define INVALID_MASK 0xffffffffLL
+
+static const uint64_t encmask_2_mask[] = {
+ 0x0fffLL, /* 4k, 0000 */
+ 0x3fffLL, /* 16k, 0001 */
+ 0xffffLL, /* 64k, 0010 */
+ 0x3ffffLL, /* 256k, 0011 */
+ 0xfffffLL, /* 1m, 0100 */
+ 0x3fffffLL, /* 4m, 0101 */
+ 0xffffffLL, /* 16m, 0110 */
+ 0x3ffffffLL, /* 64m, 0111 */
+ 0xfffffffLL, /* 256m, 1000 */
+ 0x3fffffffLL, /* 1g, 1001 */
+ INVALID_MASK, /* RSVD, 0111 */
+};
+
+static inline tlb_pgsize_t hex_tlb_pgsize_type(uint64_t entry)
+{
+ if (entry == 0) {
+ qemu_log_mask(CPU_LOG_MMU, "%s: Supplied TLB entry was 0!\n",
+ __func__);
+ return 0;
+ }
+ tlb_pgsize_t size = ctz64(entry);
+ g_assert(size < NUM_PGSIZE_TYPES);
+ return size;
+}
+
+static inline uint64_t hex_tlb_page_size_bytes(uint64_t entry)
+{
+ return 1ull << (TARGET_PAGE_BITS + 2 * hex_tlb_pgsize_type(entry));
+}
+
+static inline uint64_t hex_tlb_phys_page_num(uint64_t entry)
+{
+ uint32_t ppd = GET_PPD(entry);
+ return ppd >> 1;
+}
+
+static inline uint64_t hex_tlb_phys_addr(uint64_t entry)
+{
+ uint64_t pagemask = encmask_2_mask[hex_tlb_pgsize_type(entry)];
+ uint64_t pagenum = hex_tlb_phys_page_num(entry);
+ uint64_t PA = (pagenum << TARGET_PAGE_BITS) & (~pagemask);
+ return PA;
+}
+
+static inline uint64_t hex_tlb_virt_addr(uint64_t entry)
+{
+ return (uint64_t)GET_PTE_VPN(entry) << TARGET_PAGE_BITS;
+}
+
+bool hexagon_tlb_dump_entry(FILE *f, uint64_t entry)
+{
+ if (GET_PTE_V(entry)) {
+ fprintf(f, "0x%016" PRIx64 ": ", entry);
+ uint64_t PA = hex_tlb_phys_addr(entry);
+ uint64_t VA = hex_tlb_virt_addr(entry);
+ fprintf(f, "V:%" PRId64 " G:%" PRId64
+ " A1:%" PRId64 " A0:%" PRId64,
+ GET_PTE_V(entry),
+ GET_PTE_G(entry),
+ GET_PTE_ATR1(entry),
+ GET_PTE_ATR0(entry));
+ fprintf(f, " ASID:0x%02" PRIx64 " VA:0x%08" PRIx64,
+ GET_PTE_ASID(entry), VA);
+ fprintf(f,
+ " X:%" PRId64 " W:%" PRId64 " R:%" PRId64
+ " U:%" PRId64 " C:%" PRId64,
+ GET_PTE_X(entry),
+ GET_PTE_W(entry),
+ GET_PTE_R(entry),
+ GET_PTE_U(entry),
+ GET_PTE_C(entry));
+ fprintf(f, " PA:0x%09" PRIx64 " SZ:%s (0x%" PRIx64 ")", PA,
+ pgsize_str[hex_tlb_pgsize_type(entry)],
+ hex_tlb_page_size_bytes(entry));
+ fprintf(f, "\n");
+ return true;
+ }
+
+ /* Not valid */
+ return false;
+}
+
+static inline bool hex_tlb_entry_match_noperm(uint64_t entry, uint32_t asid,
+ uint64_t VA)
+{
+ if (GET_PTE_V(entry)) {
+ if (GET_PTE_G(entry)) {
+ /* Global entry - ignore ASID */
+ } else if (asid != NO_ASID) {
+ uint32_t tlb_asid = GET_PTE_ASID(entry);
+ if (tlb_asid != asid) {
+ return false;
+ }
+ }
+
+ uint64_t page_size = hex_tlb_page_size_bytes(entry);
+ uint64_t page_start =
+ ROUND_DOWN(hex_tlb_virt_addr(entry), page_size);
+ if (page_start <= VA && VA < page_start + page_size) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline void hex_tlb_entry_get_perm(uint64_t entry,
+ MMUAccessType access_type,
+ int mmu_idx, int *prot,
+ int32_t *excp, int *cause_code)
+{
+ bool perm_x = GET_PTE_X(entry);
+ bool perm_w = GET_PTE_W(entry);
+ bool perm_r = GET_PTE_R(entry);
+ bool perm_u = GET_PTE_U(entry);
+ bool user_idx = mmu_idx == MMU_USER_IDX;
+
+ if (mmu_idx == MMU_KERNEL_IDX) {
+ *prot = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return;
+ }
+
+ *prot = PAGE_VALID;
+ switch (access_type) {
+ case MMU_INST_FETCH:
+ if (user_idx && !perm_u) {
+ *excp = HEX_EVENT_PRECISE;
+ *cause_code = HEX_CAUSE_FETCH_NO_UPAGE;
+ } else if (!perm_x) {
+ *excp = HEX_EVENT_PRECISE;
+ *cause_code = HEX_CAUSE_FETCH_NO_XPAGE;
+ }
+ break;
+ case MMU_DATA_LOAD:
+ if (user_idx && !perm_u) {
+ *excp = HEX_EVENT_PRECISE;
+ *cause_code = HEX_CAUSE_PRIV_NO_UREAD;
+ } else if (!perm_r) {
+ *excp = HEX_EVENT_PRECISE;
+ *cause_code = HEX_CAUSE_PRIV_NO_READ;
+ }
+ break;
+ case MMU_DATA_STORE:
+ if (user_idx && !perm_u) {
+ *excp = HEX_EVENT_PRECISE;
+ *cause_code = HEX_CAUSE_PRIV_NO_UWRITE;
+ } else if (!perm_w) {
+ *excp = HEX_EVENT_PRECISE;
+ *cause_code = HEX_CAUSE_PRIV_NO_WRITE;
+ }
+ break;
+ }
+
+ if (!user_idx || perm_u) {
+ if (perm_x) {
+ *prot |= PAGE_EXEC;
+ }
+ if (perm_r) {
+ *prot |= PAGE_READ;
+ }
+ if (perm_w) {
+ *prot |= PAGE_WRITE;
+ }
+ }
+}
+
+static inline bool hex_tlb_entry_match(uint64_t entry, uint8_t asid,
+ uint32_t VA,
+ MMUAccessType access_type, hwaddr *PA,
+ int *prot, uint64_t *size,
+ int32_t *excp, int *cause_code,
+ int mmu_idx)
+{
+ if (hex_tlb_entry_match_noperm(entry, asid, VA)) {
+ hex_tlb_entry_get_perm(entry, access_type, mmu_idx, prot, excp,
+ cause_code);
+ *PA = hex_tlb_phys_addr(entry);
+ *size = hex_tlb_page_size_bytes(entry);
+ return true;
+ }
+ return false;
+}
+
+static bool hex_tlb_is_match(uint64_t entry1, uint64_t entry2,
+ bool consider_gbit)
+{
+ bool valid1 = GET_PTE_V(entry1);
+ bool valid2 = GET_PTE_V(entry2);
+ uint64_t size1 = hex_tlb_page_size_bytes(entry1);
+ uint64_t vaddr1 = ROUND_DOWN(hex_tlb_virt_addr(entry1), size1);
+ uint64_t size2 = hex_tlb_page_size_bytes(entry2);
+ uint64_t vaddr2 = ROUND_DOWN(hex_tlb_virt_addr(entry2), size2);
+ int asid1 = GET_PTE_ASID(entry1);
+ int asid2 = GET_PTE_ASID(entry2);
+ bool gbit1 = GET_PTE_G(entry1);
+ bool gbit2 = GET_PTE_G(entry2);
+
+ if (!valid1 || !valid2) {
+ return false;
+ }
+
+ if (((vaddr1 <= vaddr2) && (vaddr2 < (vaddr1 + size1))) ||
+ ((vaddr2 <= vaddr1) && (vaddr1 < (vaddr2 + size2)))) {
+ if (asid1 == asid2) {
+ return true;
+ }
+ if ((consider_gbit && gbit1) || gbit2) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Public API */
+
+uint64_t hexagon_tlb_read(HexagonTLBState *tlb, uint32_t index)
+{
+ g_assert(index < tlb->num_entries);
+ return tlb->entries[index];
+}
+
+void hexagon_tlb_write(HexagonTLBState *tlb, uint32_t index, uint64_t value)
+{
+ g_assert(index < tlb->num_entries);
+ tlb->entries[index] = value;
+}
+
+bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
+ uint32_t VA, MMUAccessType access_type,
+ hwaddr *PA, int *prot, uint64_t *size,
+ int32_t *excp, int *cause_code, int mmu_idx)
+{
+ *PA = 0;
+ *prot = 0;
+ *size = 0;
+ *excp = 0;
+ *cause_code = 0;
+
+ for (uint32_t i = 0; i < tlb->num_entries; i++) {
+ if (hex_tlb_entry_match(tlb->entries[i], asid, VA, access_type,
+ PA, prot, size, excp, cause_code, mmu_idx)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t hexagon_tlb_lookup(HexagonTLBState *tlb, uint32_t asid,
+ uint32_t VA, int *cause_code)
+{
+ uint32_t not_found = 0x80000000;
+ uint32_t idx = not_found;
+
+ for (uint32_t i = 0; i < tlb->num_entries; i++) {
+ uint64_t entry = tlb->entries[i];
+ if (hex_tlb_entry_match_noperm(entry, asid, VA)) {
+ if (idx != not_found) {
+ *cause_code = HEX_CAUSE_IMPRECISE_MULTI_TLB_MATCH;
+ break;
+ }
+ idx = i;
+ }
+ }
+
+ if (idx == not_found) {
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s: 0x%" PRIx32 ", 0x%08" PRIx32 " => NOT FOUND\n",
+ __func__, asid, VA);
+ } else {
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s: 0x%" PRIx32 ", 0x%08" PRIx32 " => %d\n",
+ __func__, asid, VA, idx);
+ }
+
+ return idx;
+}
+
+/*
+ * Return codes:
+ * 0 or positive index of match
+ * -1 multiple matches
+ * -2 no match
+ */
+int hexagon_tlb_check_overlap(HexagonTLBState *tlb, uint64_t entry,
+ uint64_t index)
+{
+ int matches = 0;
+ int last_match = 0;
+
+ for (uint32_t i = 0; i < tlb->num_entries; i++) {
+ if (hex_tlb_is_match(entry, tlb->entries[i], false)) {
+ matches++;
+ last_match = i;
+ }
+ }
+
+ if (matches == 1) {
+ return last_match;
+ }
+ if (matches == 0) {
+ return -2;
+ }
+ return -1;
+}
+
+void hexagon_tlb_dump(HexagonTLBState *tlb)
+{
+ for (uint32_t i = 0; i < tlb->num_entries; i++) {
+ hexagon_tlb_dump_entry(stdout, tlb->entries[i]);
+ }
+}
+
+uint32_t hexagon_tlb_get_num_entries(HexagonTLBState *tlb)
+{
+ return tlb->num_entries;
+}
+
+/* QOM lifecycle */
+
+static void hexagon_tlb_init(Object *obj)
+{
+}
+
+static void hexagon_tlb_realize(DeviceState *dev, Error **errp)
+{
+ HexagonTLBState *s = HEXAGON_TLB(dev);
+
+ if (s->num_entries == 0 || s->num_entries > MAX_TLB_ENTRIES) {
+ error_setg(errp, "Invalid TLB num-entries: %" PRIu32,
+ s->num_entries);
+ return;
+ }
+ s->entries = g_new0(uint64_t, s->num_entries);
+}
+
+static void hexagon_tlb_finalize(Object *obj)
+{
+ HexagonTLBState *s = HEXAGON_TLB(obj);
+ g_free(s->entries);
+ s->entries = NULL;
+}
+
+static void hexagon_tlb_reset_hold(Object *obj, ResetType type)
+{
+ HexagonTLBState *s = HEXAGON_TLB(obj);
+ if (s->entries) {
+ memset(s->entries, 0, sizeof(uint64_t) * s->num_entries);
+ }
+}
+
+static const VMStateDescription vmstate_hexagon_tlb = {
+ .name = "hexagon-tlb",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(num_entries, HexagonTLBState),
+ VMSTATE_VARRAY_UINT32_ALLOC(entries, HexagonTLBState, num_entries,
+ 0, vmstate_info_uint64, uint64_t),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const Property hexagon_tlb_properties[] = {
+ DEFINE_PROP_UINT32("num-entries", HexagonTLBState, num_entries,
+ MAX_TLB_ENTRIES),
+};
+
+static void hexagon_tlb_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = hexagon_tlb_realize;
+ rc->phases.hold = hexagon_tlb_reset_hold;
+ dc->vmsd = &vmstate_hexagon_tlb;
+ dc->user_creatable = false;
+ device_class_set_props(dc, hexagon_tlb_properties);
+}
+
+static const TypeInfo hexagon_tlb_info = {
+ .name = TYPE_HEXAGON_TLB,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HexagonTLBState),
+ .instance_init = hexagon_tlb_init,
+ .instance_finalize = hexagon_tlb_finalize,
+ .class_init = hexagon_tlb_class_init,
+};
+
+static void hexagon_tlb_register_types(void)
+{
+ type_register_static(&hexagon_tlb_info);
+}
+
+type_init(hexagon_tlb_register_types)
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index b1317f83ef4..32d158684a0 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -23,6 +23,7 @@
#include "qapi/error.h"
#include "hw/core/qdev-properties.h"
#include "fpu/softfloat-helpers.h"
+#include "hw/hexagon/hexagon_tlb.h"
#include "tcg/tcg.h"
#include "exec/gdbstub.h"
#include "accel/tcg/cpu-ops.h"
@@ -50,6 +51,10 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
}
static const Property hexagon_cpu_properties[] = {
+#if !defined(CONFIG_USER_ONLY)
+ DEFINE_PROP_LINK("tlb", HexagonCPU, tlb, TYPE_HEXAGON_TLB,
+ HexagonTLBState *),
+#endif
DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false),
DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0,
qdev_prop_uint32, target_ulong),
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 32/35] target/hexagon: Add stubs for modify_ssr/get_exe_mode
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (30 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 31/35] hw/hexagon: Introduce hexagon TLB device Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 33/35] target/hexagon: Add clear_wait_mode() definition Brian Cain
` (2 subsequent siblings)
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo
Add hex_mmu.[ch], cpu mode helpers, and additional includes/stubs
that integrate the TLB device with the CPU model.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu-param.h | 4 +
target/hexagon/cpu.h | 17 +++
target/hexagon/cpu_helper.h | 2 +
target/hexagon/hex_mmu.h | 25 ++++
target/hexagon/internal.h | 9 ++
target/hexagon/sys_macros.h | 3 +
target/hexagon/cpu.c | 25 ++++
target/hexagon/cpu_helper.c | 10 ++
target/hexagon/hex_mmu.c | 277 ++++++++++++++++++++++++++++++++++++
target/hexagon/translate.c | 2 +-
10 files changed, 373 insertions(+), 1 deletion(-)
create mode 100644 target/hexagon/hex_mmu.h
create mode 100644 target/hexagon/hex_mmu.c
diff --git a/target/hexagon/cpu-param.h b/target/hexagon/cpu-param.h
index 1f0f22a7968..9eae7d2361c 100644
--- a/target/hexagon/cpu-param.h
+++ b/target/hexagon/cpu-param.h
@@ -18,7 +18,11 @@
#ifndef HEXAGON_CPU_PARAM_H
#define HEXAGON_CPU_PARAM_H
+#ifdef CONFIG_USER_ONLY
#define TARGET_PAGE_BITS 16 /* 64K pages */
+#else
+#define TARGET_PAGE_BITS 12 /* 4K pages */
+#endif
#define TARGET_VIRT_ADDR_SPACE_BITS 32
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index e39e6e39fec..d8092cb6fe7 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -38,6 +38,9 @@
#error "Hexagon does not support system emulation"
#endif
+#ifndef CONFIG_USER_ONLY
+#endif
+
#define NUM_PREGS 4
#define TOTAL_PER_THREAD_REGS 64
@@ -51,6 +54,8 @@
#define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU
#ifndef CONFIG_USER_ONLY
#define CPU_INTERRUPT_SWI CPU_INTERRUPT_TGT_INT_0
+#define CPU_INTERRUPT_K0_UNLOCK CPU_INTERRUPT_TGT_INT_1
+#define CPU_INTERRUPT_TLB_UNLOCK CPU_INTERRUPT_TGT_INT_2
#define HEX_CPU_MODE_USER 1
#define HEX_CPU_MODE_GUEST 2
@@ -67,6 +72,12 @@
#define MMU_GUEST_IDX 1
#define MMU_KERNEL_IDX 2
+typedef enum {
+ HEX_LOCK_UNLOCKED = 0,
+ HEX_LOCK_WAITING = 1,
+ HEX_LOCK_OWNER = 2,
+ HEX_LOCK_QUEUED = 3
+} hex_lock_state_t;
#endif
@@ -128,6 +139,10 @@ typedef struct CPUArchState {
/* This alias of CPUState.cpu_index is used by imported sources: */
uint32_t threadId;
+ hex_lock_state_t tlb_lock_state;
+ hex_lock_state_t k0_lock_state;
+ uint32_t tlb_lock_count;
+ uint32_t k0_lock_count;
#endif
uint32_t next_PC;
target_ulong new_value_usr;
@@ -177,12 +192,14 @@ struct ArchCPU {
bool short_circuit;
#ifndef CONFIG_USER_ONLY
struct HexagonTLBState *tlb;
+ uint32_t htid;
#endif
};
#include "cpu_bits.h"
FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1)
+FIELD(TB_FLAGS, MMU_INDEX, 1, 3)
G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
uint32_t exception,
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index 1486a03c64a..18300657f3d 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -14,5 +14,7 @@ uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env);
void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t);
void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t);
void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t);
+void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
+int get_exe_mode(CPUHexagonState *env);
#endif
diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h
new file mode 100644
index 00000000000..99ddb3736a2
--- /dev/null
+++ b/target/hexagon/hex_mmu.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXAGON_MMU_H
+#define HEXAGON_MMU_H
+
+#include "cpu.h"
+
+extern void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value);
+extern uint32_t hex_tlb_lookup(CPUHexagonState *env, uint32_t ssr, uint32_t VA);
+extern void hex_mmu_on(CPUHexagonState *env);
+extern void hex_mmu_off(CPUHexagonState *env);
+extern void hex_mmu_mode_change(CPUHexagonState *env);
+extern bool hex_tlb_find_match(CPUHexagonState *env, uint32_t VA,
+ MMUAccessType access_type, hwaddr *PA, int *prot,
+ uint64_t *size, int32_t *excp, int mmu_idx);
+extern int hex_tlb_check_overlap(CPUHexagonState *env, uint64_t entry,
+ uint64_t index);
+extern void hex_tlb_lock(CPUHexagonState *env);
+extern void hex_tlb_unlock(CPUHexagonState *env);
+void dump_mmu(CPUHexagonState *env);
+#endif
diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index 33d73ed18d1..4338914efb5 100644
--- a/target/hexagon/internal.h
+++ b/target/hexagon/internal.h
@@ -36,6 +36,15 @@ void G_NORETURN do_raise_exception(CPUHexagonState *env,
uint32_t PC,
uintptr_t retaddr);
+#define hexagon_cpu_mmu_enabled(env) ({ \
+ HexagonCPU *cpu = env_archcpu(env); \
+ cpu->globalregs ? \
+ GET_SYSCFG_FIELD(SYSCFG_MMUEN, \
+ hexagon_globalreg_read(cpu->globalregs, \
+ HEX_SREG_SYSCFG, (env)->threadId)) : \
+ 0; \
+})
+
#ifndef CONFIG_USER_ONLY
extern const VMStateDescription vmstate_hexagon_cpu;
#endif
diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h
index f497d55bb81..364fcde7383 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -139,6 +139,9 @@
#define fDCINVIDX(REG)
#define fDCINVA(REG) do { REG = REG; } while (0) /* Nothing to do in qemu */
+#define fSET_TLB_LOCK() hex_tlb_lock(env);
+#define fCLEAR_TLB_LOCK() hex_tlb_unlock(env);
+
#define fTLB_IDXMASK(INDEX) \
((INDEX) & (fPOW2_ROUNDUP( \
fCAST4u(hexagon_tlb_get_num_entries(env_archcpu(env)->tlb))) - 1))
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 32d158684a0..5c937fa1cd1 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -27,6 +27,13 @@
#include "tcg/tcg.h"
#include "exec/gdbstub.h"
#include "accel/tcg/cpu-ops.h"
+#include "cpu_helper.h"
+#include "hex_mmu.h"
+
+#ifndef CONFIG_USER_ONLY
+#include "sys_macros.h"
+#include "accel/tcg/cpu-ldst.h"
+#endif
static void hexagon_v66_cpu_init(Object *obj) { }
static void hexagon_v67_cpu_init(Object *obj) { }
@@ -54,6 +61,7 @@ static const Property hexagon_cpu_properties[] = {
#if !defined(CONFIG_USER_ONLY)
DEFINE_PROP_LINK("tlb", HexagonCPU, tlb, TYPE_HEXAGON_TLB,
HexagonTLBState *),
+ DEFINE_PROP_UINT32("htid", HexagonCPU, htid, 0),
#endif
DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false),
DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0,
@@ -280,6 +288,13 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0);
}
+#ifndef CONFIG_USER_ONLY
+ hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
+ cpu_mmu_index(env_cpu(env), false));
+#else
+ hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
+#endif
+
return (TCGTBCPUState){ .pc = pc, .flags = hex_flags };
}
@@ -297,6 +312,7 @@ static void hexagon_restore_state_to_opc(CPUState *cs,
cpu_env(cs)->gpr[HEX_REG_PC] = data[0];
}
+
static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
{
CPUState *cs = CPU(obj);
@@ -315,7 +331,15 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
memset(env->t_sreg, 0, sizeof(uint32_t) * NUM_SREGS);
memset(env->greg, 0, sizeof(uint32_t) * NUM_GREGS);
env->wait_next_pc = 0;
+ env->tlb_lock_state = HEX_LOCK_UNLOCKED;
+ env->k0_lock_state = HEX_LOCK_UNLOCKED;
+ env->tlb_lock_count = 0;
+ env->k0_lock_count = 0;
env->next_PC = 0;
+
+ HexagonCPU *cpu = HEXAGON_CPU(cs);
+ env->t_sreg[HEX_SREG_HTID] = cpu->htid;
+ env->threadId = cpu->htid;
#endif
env->cause_code = HEX_EVENT_NONE;
}
@@ -344,6 +368,7 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
gdb_find_static_feature("hexagon-hvx.xml"), 0);
qemu_init_vcpu(cs);
+
cpu_reset(cs);
mcc->parent_realize(dev, errp);
}
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index b8e0625e3f8..b6a8bd35309 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -58,3 +58,13 @@ void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t cycles)
{
g_assert_not_reached();
}
+
+void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
+{
+ g_assert_not_reached();
+}
+
+int get_exe_mode(CPUHexagonState *env)
+{
+ g_assert_not_reached();
+}
diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c
new file mode 100644
index 00000000000..1cdc92fdc31
--- /dev/null
+++ b/target/hexagon/hex_mmu.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "qemu/qemu-print.h"
+#include "cpu.h"
+#include "system/cpus.h"
+#include "internal.h"
+#include "exec/cpu-interrupt.h"
+#include "cpu_helper.h"
+#include "exec/cputlb.h"
+#include "hex_mmu.h"
+#include "macros.h"
+#include "sys_macros.h"
+#include "hw/hexagon/hexagon_tlb.h"
+#include "hw/hexagon/hexagon_globalreg.h"
+
+static inline void hex_log_tlbw(uint32_t index, uint64_t entry)
+{
+ if (qemu_loglevel_mask(CPU_LOG_MMU)) {
+ if (qemu_log_enabled()) {
+ FILE *logfile = qemu_log_trylock();
+ if (logfile) {
+ fprintf(logfile, "tlbw[%03d]: ", index);
+ if (!hexagon_tlb_dump_entry(logfile, entry)) {
+ fprintf(logfile, "invalid\n");
+ }
+ qemu_log_unlock(logfile);
+ }
+ }
+ }
+}
+
+void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value)
+{
+ uint32_t myidx = fTLB_NONPOW2WRAP(fTLB_IDXMASK(index));
+ HexagonTLBState *tlb = env_archcpu(env)->tlb;
+ uint64_t old_entry = hexagon_tlb_read(tlb, myidx);
+
+ bool old_entry_valid = extract64(old_entry, 63, 1);
+ if (old_entry_valid && hexagon_cpu_mmu_enabled(env)) {
+ CPUState *cs = env_cpu(env);
+ tlb_flush(cs);
+ }
+ hexagon_tlb_write(tlb, myidx, value);
+ hex_log_tlbw(myidx, value);
+}
+
+void hex_mmu_on(CPUHexagonState *env)
+{
+ CPUState *cs = env_cpu(env);
+ qemu_log_mask(CPU_LOG_MMU, "Hexagon MMU turned on!\n");
+ tlb_flush(cs);
+}
+
+void hex_mmu_off(CPUHexagonState *env)
+{
+ CPUState *cs = env_cpu(env);
+ qemu_log_mask(CPU_LOG_MMU, "Hexagon MMU turned off!\n");
+ tlb_flush(cs);
+}
+
+void hex_mmu_mode_change(CPUHexagonState *env)
+{
+ qemu_log_mask(CPU_LOG_MMU, "Hexagon mode change!\n");
+ CPUState *cs = env_cpu(env);
+ tlb_flush(cs);
+}
+
+bool hex_tlb_find_match(CPUHexagonState *env, uint32_t VA,
+ MMUAccessType access_type, hwaddr *PA, int *prot,
+ uint64_t *size, int32_t *excp, int mmu_idx)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
+ uint8_t asid = GET_SSR_FIELD(SSR_ASID, ssr);
+ int cause_code = 0;
+
+ bool found = hexagon_tlb_find_match(cpu->tlb, asid, VA, access_type,
+ PA, prot, size, excp, &cause_code,
+ mmu_idx);
+ if (cause_code) {
+ env->cause_code = cause_code;
+ }
+ return found;
+}
+
+/* Called from tlbp instruction */
+uint32_t hex_tlb_lookup(CPUHexagonState *env, uint32_t ssr, uint32_t VA)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint8_t asid = GET_SSR_FIELD(SSR_ASID, ssr);
+ int cause_code = 0;
+
+ uint32_t result = hexagon_tlb_lookup(cpu->tlb, asid, VA, &cause_code);
+ if (cause_code) {
+ env->cause_code = cause_code;
+ }
+ return result;
+}
+
+/*
+ * Return codes:
+ * 0 or positive index of match
+ * -1 multiple matches
+ * -2 no match
+ */
+int hex_tlb_check_overlap(CPUHexagonState *env, uint64_t entry, uint64_t index)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ return hexagon_tlb_check_overlap(cpu->tlb, entry, index);
+}
+
+void dump_mmu(CPUHexagonState *env)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ hexagon_tlb_dump(cpu->tlb);
+}
+
+static inline void print_thread(const char *str, CPUState *cs)
+{
+ g_assert(bql_locked());
+ CPUHexagonState *thread = cpu_env(cs);
+ bool is_stopped = cpu_is_stopped(cs);
+ int exe_mode = get_exe_mode(thread);
+ hex_lock_state_t lock_state = thread->tlb_lock_state;
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s: threadId = %d: %s, exe_mode = %s, tlb_lock_state = %s\n",
+ str,
+ thread->threadId,
+ is_stopped ? "stopped" : "running",
+ exe_mode == HEX_EXE_MODE_OFF ? "off" :
+ exe_mode == HEX_EXE_MODE_RUN ? "run" :
+ exe_mode == HEX_EXE_MODE_WAIT ? "wait" :
+ exe_mode == HEX_EXE_MODE_DEBUG ? "debug" :
+ "unknown",
+ lock_state == HEX_LOCK_UNLOCKED ? "unlocked" :
+ lock_state == HEX_LOCK_WAITING ? "waiting" :
+ lock_state == HEX_LOCK_OWNER ? "owner" :
+ "unknown");
+}
+
+static inline void print_thread_states(const char *str)
+{
+ CPUState *cs;
+ CPU_FOREACH(cs) {
+ print_thread(str, cs);
+ }
+}
+
+void hex_tlb_lock(CPUHexagonState *env)
+{
+ qemu_log_mask(CPU_LOG_MMU, "hex_tlb_lock: " TARGET_FMT_ld "\n",
+ env->threadId);
+ BQL_LOCK_GUARD();
+ g_assert((env->tlb_lock_count == 0) || (env->tlb_lock_count == 1));
+
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t syscfg = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
+ env->threadId) : 0;
+ uint8_t tlb_lock = GET_SYSCFG_FIELD(SYSCFG_TLBLOCK, syscfg);
+ if (tlb_lock) {
+ if (env->tlb_lock_state == HEX_LOCK_QUEUED) {
+ env->next_PC += 4;
+ env->tlb_lock_count++;
+ env->tlb_lock_state = HEX_LOCK_OWNER;
+ SET_SYSCFG_FIELD(env, SYSCFG_TLBLOCK, 1);
+ return;
+ }
+ if (env->tlb_lock_state == HEX_LOCK_OWNER) {
+ qemu_log_mask(CPU_LOG_MMU | LOG_GUEST_ERROR,
+ "Double tlblock at PC: 0x%x, thread may hang\n",
+ env->next_PC);
+ env->next_PC += 4;
+ CPUState *cs = env_cpu(env);
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+ return;
+ }
+ env->tlb_lock_state = HEX_LOCK_WAITING;
+ CPUState *cs = env_cpu(env);
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+ } else {
+ env->next_PC += 4;
+ env->tlb_lock_count++;
+ env->tlb_lock_state = HEX_LOCK_OWNER;
+ SET_SYSCFG_FIELD(env, SYSCFG_TLBLOCK, 1);
+ }
+
+ if (qemu_loglevel_mask(CPU_LOG_MMU)) {
+ qemu_log_mask(CPU_LOG_MMU, "Threads after hex_tlb_lock:\n");
+ print_thread_states("\tThread");
+ }
+}
+
+void hex_tlb_unlock(CPUHexagonState *env)
+{
+ BQL_LOCK_GUARD();
+ g_assert((env->tlb_lock_count == 0) || (env->tlb_lock_count == 1));
+
+ /* Nothing to do if the TLB isn't locked by this thread */
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t syscfg = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
+ env->threadId) : 0;
+ uint8_t tlb_lock = GET_SYSCFG_FIELD(SYSCFG_TLBLOCK, syscfg);
+ if ((tlb_lock == 0) ||
+ (env->tlb_lock_state != HEX_LOCK_OWNER)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "thread %d attempted to tlbunlock without having the "
+ "lock, tlb_lock state = %d\n",
+ env->threadId, env->tlb_lock_state);
+ g_assert(env->tlb_lock_state != HEX_LOCK_WAITING);
+ return;
+ }
+
+ env->tlb_lock_count--;
+ env->tlb_lock_state = HEX_LOCK_UNLOCKED;
+ SET_SYSCFG_FIELD(env, SYSCFG_TLBLOCK, 0);
+
+ /* Look for a thread to unlock */
+ unsigned int this_threadId = env->threadId;
+ CPUHexagonState *unlock_thread = NULL;
+ CPUState *cs;
+ CPU_FOREACH(cs) {
+ CPUHexagonState *thread = cpu_env(cs);
+
+ /*
+ * The hardware implements round-robin fairness, so we look for threads
+ * starting at env->threadId + 1 and incrementing modulo the number of
+ * threads.
+ *
+ * To implement this, we check if thread is a earlier in the modulo
+ * sequence than unlock_thread.
+ * if unlock thread is higher than this thread
+ * thread must be between this thread and unlock_thread
+ * else
+ * thread higher than this thread is ahead of unlock_thread
+ * thread must be lower then unlock thread
+ */
+ if (thread->tlb_lock_state == HEX_LOCK_WAITING) {
+ if (!unlock_thread) {
+ unlock_thread = thread;
+ } else if (unlock_thread->threadId > this_threadId) {
+ if (this_threadId < thread->threadId &&
+ thread->threadId < unlock_thread->threadId) {
+ unlock_thread = thread;
+ }
+ } else {
+ if (thread->threadId > this_threadId) {
+ unlock_thread = thread;
+ }
+ if (thread->threadId < unlock_thread->threadId) {
+ unlock_thread = thread;
+ }
+ }
+ }
+ }
+ if (unlock_thread) {
+ cs = env_cpu(unlock_thread);
+ print_thread("\tWaiting thread found", cs);
+ unlock_thread->tlb_lock_state = HEX_LOCK_QUEUED;
+ SET_SYSCFG_FIELD(unlock_thread, SYSCFG_TLBLOCK, 1);
+ cpu_interrupt(cs, CPU_INTERRUPT_TLB_UNLOCK);
+ }
+
+ if (qemu_loglevel_mask(CPU_LOG_MMU)) {
+ qemu_log_mask(CPU_LOG_MMU, "Threads after hex_tlb_unlock:\n");
+ print_thread_states("\tThread");
+ }
+
+}
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index cd6affa2f49..4df4226cbcb 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -987,7 +987,7 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase,
HexagonCPU *hex_cpu = env_archcpu(cpu_env(cs));
uint32_t hex_flags = dcbase->tb->flags;
- ctx->mem_idx = MMU_USER_IDX;
+ ctx->mem_idx = FIELD_EX32(hex_flags, TB_FLAGS, MMU_INDEX);
ctx->num_packets = 0;
ctx->num_insns = 0;
ctx->num_hvx_insns = 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 33/35] target/hexagon: Add clear_wait_mode() definition
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (31 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 32/35] target/hexagon: Add stubs for modify_ssr/get_exe_mode Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 34/35] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
2026-03-11 3:49 ` [PATCH v5 35/35] target/hexagon: Add hex_interrupts support Brian Cain
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu_helper.h | 1 +
target/hexagon/cpu_helper.c | 15 +++++++++++++++
2 files changed, 16 insertions(+)
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index 18300657f3d..d15385daf83 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -16,5 +16,6 @@ void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t);
void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t);
void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
int get_exe_mode(CPUHexagonState *env);
+void clear_wait_mode(CPUHexagonState *env);
#endif
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index b6a8bd35309..6fbf5fc8e2f 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -64,6 +64,21 @@ void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
g_assert_not_reached();
}
+void clear_wait_mode(CPUHexagonState *env)
+{
+ g_assert(bql_locked());
+
+ HexagonCPU *cpu = env_archcpu(env);
+ if (cpu->globalregs) {
+ const uint32_t modectl =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+ env->threadId);
+ uint32_t thread_wait_mask = GET_FIELD(MODECTL_W, modectl);
+ thread_wait_mask &= ~(0x1 << env->threadId);
+ SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask);
+ }
+}
+
int get_exe_mode(CPUHexagonState *env)
{
g_assert_not_reached();
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 34/35] target/hexagon: Define f{S,G}ET_FIELD macros
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (32 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 33/35] target/hexagon: Add clear_wait_mode() definition Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
2026-03-11 3:49 ` [PATCH v5 35/35] target/hexagon: Add hex_interrupts support Brian Cain
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/macros.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index e4bfea4923f..26d3f7d8a4b 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -653,6 +653,16 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
reg_field_info[FIELD].width, \
reg_field_info[FIELD].offset)
+#define fGET_FIELD(VAL, FIELD) \
+ fEXTRACTU_BITS(VAL, \
+ reg_field_info[FIELD].width, \
+ reg_field_info[FIELD].offset)
+#define fSET_FIELD(VAL, FIELD, NEWVAL) \
+ fINSERT_BITS(VAL, \
+ reg_field_info[FIELD].width, \
+ reg_field_info[FIELD].offset, \
+ (NEWVAL))
+
#ifdef QEMU_GENERATE
#define fDCZEROA(REG) \
do { \
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v5 35/35] target/hexagon: Add hex_interrupts support
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
` (33 preceding siblings ...)
2026-03-11 3:49 ` [PATCH v5 34/35] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
@ 2026-03-11 3:49 ` Brian Cain
34 siblings, 0 replies; 41+ messages in thread
From: Brian Cain @ 2026-03-11 3:49 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, philmd, ltaylorsimpson, matheus.bernardino,
marco.liebel, quic_mburton, sid.manning, ale, anjo, Brian Cain,
Sid Manning, Michael Lambert
From: Brian Cain <bcain@quicinc.com>
Co-authored-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Co-authored-by: Sid Manning <sidneym@quicinc.com>
Co-authored-by: Michael Lambert <mlambert@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 2 +
target/hexagon/hex_interrupts.h | 15 ++
target/hexagon/cpu.c | 4 +
target/hexagon/hex_interrupts.c | 375 ++++++++++++++++++++++++++++++++
4 files changed, 396 insertions(+)
create mode 100644 target/hexagon/hex_interrupts.h
create mode 100644 target/hexagon/hex_interrupts.c
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index d8092cb6fe7..0017be9dff7 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -192,6 +192,8 @@ struct ArchCPU {
bool short_circuit;
#ifndef CONFIG_USER_ONLY
struct HexagonTLBState *tlb;
+ uint32_t boot_addr;
+ struct HexagonGlobalRegState *globalregs;
uint32_t htid;
#endif
};
diff --git a/target/hexagon/hex_interrupts.h b/target/hexagon/hex_interrupts.h
new file mode 100644
index 00000000000..6b6f5403633
--- /dev/null
+++ b/target/hexagon/hex_interrupts.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEX_INTERRUPTS_H
+#define HEX_INTERRUPTS_H
+
+bool hex_check_interrupts(CPUHexagonState *env);
+void hex_clear_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type);
+void hex_raise_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type);
+void hex_interrupt_update(CPUHexagonState *env);
+
+#endif
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 5c937fa1cd1..938492897fd 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -61,6 +61,9 @@ static const Property hexagon_cpu_properties[] = {
#if !defined(CONFIG_USER_ONLY)
DEFINE_PROP_LINK("tlb", HexagonCPU, tlb, TYPE_HEXAGON_TLB,
HexagonTLBState *),
+ DEFINE_PROP_UINT32("exec-start-addr", HexagonCPU, boot_addr, 0xffffffff),
+ DEFINE_PROP_LINK("global-regs", HexagonCPU, globalregs,
+ TYPE_HEXAGON_GLOBALREG, HexagonGlobalRegState *),
DEFINE_PROP_UINT32("htid", HexagonCPU, htid, 0),
#endif
DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false),
@@ -340,6 +343,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
HexagonCPU *cpu = HEXAGON_CPU(cs);
env->t_sreg[HEX_SREG_HTID] = cpu->htid;
env->threadId = cpu->htid;
+ env->gpr[HEX_REG_PC] = cpu->boot_addr;
#endif
env->cause_code = HEX_EVENT_NONE;
}
diff --git a/target/hexagon/hex_interrupts.c b/target/hexagon/hex_interrupts.c
new file mode 100644
index 00000000000..f1be67d5116
--- /dev/null
+++ b/target/hexagon/hex_interrupts.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "cpu_helper.h"
+#include "exec/cpu-interrupt.h"
+#include "hex_interrupts.h"
+#include "macros.h"
+#include "sys_macros.h"
+#include "system/cpus.h"
+#include "hw/hexagon/hexagon_globalreg.h"
+
+static bool hex_is_qualified_for_int(CPUHexagonState *env, int int_num);
+
+static bool get_syscfg_gie(CPUHexagonState *env)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t syscfg = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
+ env->threadId) : 0;
+ return GET_SYSCFG_FIELD(SYSCFG_GIE, syscfg);
+}
+
+static bool get_ssr_ex(CPUHexagonState *env)
+{
+ uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
+ return GET_SSR_FIELD(SSR_EX, ssr);
+}
+
+static bool get_ssr_ie(CPUHexagonState *env)
+{
+ uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
+ return GET_SSR_FIELD(SSR_IE, ssr);
+}
+
+/* Do these together so we only have to call hexagon_modify_ssr once */
+static void set_ssr_ex_cause(CPUHexagonState *env, int ex, uint32_t cause)
+{
+ uint32_t old = env->t_sreg[HEX_SREG_SSR];
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, ex);
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause);
+ uint32_t new = env->t_sreg[HEX_SREG_SSR];
+ hexagon_modify_ssr(env, new, old);
+}
+
+static bool get_iad_bit(CPUHexagonState *env, int int_num)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t ipendad = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId) : 0;
+ uint32_t iad = GET_FIELD(IPENDAD_IAD, ipendad);
+ return extract32(iad, int_num, 1);
+}
+
+static void set_iad_bit(CPUHexagonState *env, int int_num, int val)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t ipendad = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId) : 0;
+ uint32_t iad = GET_FIELD(IPENDAD_IAD, ipendad);
+ iad = deposit32(iad, int_num, 1, val);
+ fSET_FIELD(ipendad, IPENDAD_IAD, iad);
+ if (cpu->globalregs) {
+ hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD,
+ ipendad, env->threadId);
+ }
+}
+
+static uint32_t get_ipend(CPUHexagonState *env)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t ipendad = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId) : 0;
+ return GET_FIELD(IPENDAD_IPEND, ipendad);
+}
+
+static inline bool get_ipend_bit(CPUHexagonState *env, int int_num)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t ipendad = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId) : 0;
+ uint32_t ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ return extract32(ipend, int_num, 1);
+}
+
+static void clear_ipend(CPUHexagonState *env, uint32_t mask)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t ipendad = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId) : 0;
+ uint32_t ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend &= ~mask;
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ if (cpu->globalregs) {
+ hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD,
+ ipendad, env->threadId);
+ }
+}
+
+static void set_ipend(CPUHexagonState *env, uint32_t mask)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t ipendad = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId) : 0;
+ uint32_t ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend |= mask;
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ if (cpu->globalregs) {
+ hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD,
+ ipendad, env->threadId);
+ }
+}
+
+static void set_ipend_bit(CPUHexagonState *env, int int_num, int val)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t ipendad = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId) : 0;
+ uint32_t ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend = deposit32(ipend, int_num, 1, val);
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ if (cpu->globalregs) {
+ hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD,
+ ipendad, env->threadId);
+ }
+}
+
+static bool get_imask_bit(CPUHexagonState *env, int int_num)
+{
+ uint32_t imask = env->t_sreg[HEX_SREG_IMASK];
+ return extract32(imask, int_num, 1);
+}
+
+static uint32_t get_prio(CPUHexagonState *env)
+{
+ uint32_t stid = env->t_sreg[HEX_SREG_STID];
+ return extract32(stid, reg_field_info[STID_PRIO].offset,
+ reg_field_info[STID_PRIO].width);
+}
+
+static void set_elr(CPUHexagonState *env, uint32_t val)
+{
+ env->t_sreg[HEX_SREG_ELR] = val;
+}
+
+static bool get_schedcfgen(CPUHexagonState *env)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t schedcfg = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SCHEDCFG,
+ env->threadId) : 0;
+ return extract32(schedcfg, reg_field_info[SCHEDCFG_EN].offset,
+ reg_field_info[SCHEDCFG_EN].width);
+}
+
+static bool is_lowest_prio(CPUHexagonState *env, int int_num)
+{
+ uint32_t my_prio = get_prio(env);
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ CPUHexagonState *hex_env = cpu_env(cs);
+ if (!hex_is_qualified_for_int(hex_env, int_num)) {
+ continue;
+ }
+
+ /* Note that lower values indicate *higher* priority */
+ if (my_prio < get_prio(hex_env)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool hex_is_qualified_for_int(CPUHexagonState *env, int int_num)
+{
+ bool syscfg_gie = get_syscfg_gie(env);
+ bool iad = get_iad_bit(env, int_num);
+ bool ssr_ie = get_ssr_ie(env);
+ bool ssr_ex = get_ssr_ex(env);
+ bool imask = get_imask_bit(env, int_num);
+
+ return syscfg_gie && !iad && ssr_ie && !ssr_ex && !imask;
+}
+
+static void clear_pending_locks(CPUHexagonState *env)
+{
+ g_assert(bql_locked());
+ if (env->k0_lock_state == HEX_LOCK_WAITING) {
+ env->k0_lock_state = HEX_LOCK_UNLOCKED;
+ }
+ if (env->tlb_lock_state == HEX_LOCK_WAITING) {
+ env->tlb_lock_state = HEX_LOCK_UNLOCKED;
+ }
+}
+
+static bool should_not_exec(CPUHexagonState *env)
+{
+ return (get_exe_mode(env) == HEX_EXE_MODE_WAIT);
+}
+
+static void restore_state(CPUHexagonState *env, bool int_accepted)
+{
+ CPUState *cs = env_cpu(env);
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI);
+ if (!int_accepted && should_not_exec(env)) {
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+ }
+}
+
+static void hex_accept_int(CPUHexagonState *env, int int_num)
+{
+ CPUState *cs = env_cpu(env);
+ HexagonCPU *cpu = env_archcpu(env);
+ uint32_t evb = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
+ env->threadId) : 0;
+ const int exe_mode = get_exe_mode(env);
+ const bool in_wait_mode = exe_mode == HEX_EXE_MODE_WAIT;
+
+ set_ipend_bit(env, int_num, 0);
+ set_iad_bit(env, int_num, 1);
+ set_ssr_ex_cause(env, 1, HEX_CAUSE_INT0 | int_num);
+ cs->exception_index = HEX_EVENT_INT0 + int_num;
+ env->cause_code = HEX_EVENT_INT0 + int_num;
+ clear_pending_locks(env);
+ if (in_wait_mode) {
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread " TARGET_FMT_ld " resuming, exiting WAIT mode\n",
+ __func__, env->threadId);
+ set_elr(env, env->wait_next_pc);
+ clear_wait_mode(env);
+ cs->halted = false;
+ } else if (env->k0_lock_state == HEX_LOCK_WAITING) {
+ g_assert_not_reached();
+ } else {
+ set_elr(env, env->gpr[HEX_REG_PC]);
+ }
+ env->gpr[HEX_REG_PC] = evb | (cs->exception_index << 2);
+ if (get_ipend(env) == 0) {
+ restore_state(env, true);
+ }
+}
+
+
+bool hex_check_interrupts(CPUHexagonState *env)
+{
+ CPUState *cs = env_cpu(env);
+ bool int_handled = false;
+ bool ssr_ex = get_ssr_ex(env);
+ int max_ints = 32;
+ bool schedcfgen;
+
+ /* Early exit if nothing pending */
+ if (get_ipend(env) == 0) {
+ restore_state(env, false);
+ return false;
+ }
+
+ BQL_LOCK_GUARD();
+ /* Only check priorities when schedcfgen is set */
+ schedcfgen = get_schedcfgen(env);
+ for (int i = 0; i < max_ints; i++) {
+ if (!get_iad_bit(env, i) && get_ipend_bit(env, i)) {
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread[" TARGET_FMT_ld "] "
+ "pc = 0x" TARGET_FMT_lx
+ " found int %d\n",
+ __func__, env->threadId,
+ env->gpr[HEX_REG_PC], i);
+ if (hex_is_qualified_for_int(env, i) &&
+ (!schedcfgen || is_lowest_prio(env, i))) {
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread[" TARGET_FMT_ld "] int %d handled_\n",
+ __func__, env->threadId, i);
+ hex_accept_int(env, i);
+ int_handled = true;
+ break;
+ }
+ bool syscfg_gie = get_syscfg_gie(env);
+ bool iad = get_iad_bit(env, i);
+ bool ssr_ie = get_ssr_ie(env);
+ bool imask = get_imask_bit(env, i);
+
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread[" TARGET_FMT_ld "] "
+ "int %d not handled, qualified: %d, "
+ "schedcfg_en: %d, low prio %d\n",
+ __func__, env->threadId, i,
+ hex_is_qualified_for_int(env, i), schedcfgen,
+ is_lowest_prio(env, i));
+
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: thread[" TARGET_FMT_ld "] "
+ "int %d not handled, GIE %d, iad %d, "
+ "SSR:IE %d, SSR:EX: %d, imask bit %d\n",
+ __func__, env->threadId, i, syscfg_gie, iad, ssr_ie,
+ ssr_ex, imask);
+ }
+ }
+
+ /*
+ * If we didn't handle the interrupt and it wasn't
+ * because we were in EX state, then we won't be able
+ * to execute the interrupt on this CPU unless something
+ * changes in the CPU state. Clear the interrupt_request bits
+ * while preserving the IPEND bits, and we can re-assert the
+ * interrupt_request bit(s) when we execute one of those instructions.
+ */
+ if (!int_handled && !ssr_ex) {
+ restore_state(env, int_handled);
+ } else if (int_handled) {
+ assert(!cs->halted);
+ }
+
+ return int_handled;
+}
+
+void hex_clear_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type)
+{
+ if (mask == 0) {
+ return;
+ }
+
+ /*
+ * Notify all CPUs that the interrupt has happened
+ */
+ BQL_LOCK_GUARD();
+ clear_ipend(env, mask);
+ hex_interrupt_update(env);
+}
+
+void hex_raise_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type)
+{
+ g_assert(bql_locked());
+ if (mask == 0) {
+ return;
+ }
+
+ /*
+ * Notify all CPUs that the interrupt has happened
+ */
+ set_ipend(env, mask);
+ hex_interrupt_update(env);
+}
+
+void hex_interrupt_update(CPUHexagonState *env)
+{
+ CPUState *cs;
+
+ g_assert(bql_locked());
+ if (get_ipend(env) != 0) {
+ CPU_FOREACH(cs) {
+ CPUHexagonState *hex_env = cpu_env(cs);
+ const int exe_mode = get_exe_mode(hex_env);
+ if (exe_mode != HEX_EXE_MODE_OFF) {
+ cpu_interrupt(cs, CPU_INTERRUPT_SWI);
+ cpu_resume(cs);
+ }
+ }
+ }
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH v5 06/35] target/hexagon: Suppress unused-variable warnings for sysemu source regs
2026-03-11 3:48 ` [PATCH v5 06/35] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
@ 2026-03-12 21:03 ` Taylor Simpson
0 siblings, 0 replies; 41+ messages in thread
From: Taylor Simpson @ 2026-03-12 21:03 UTC (permalink / raw)
To: Brian Cain
Cc: qemu-devel, philmd, matheus.bernardino, marco.liebel,
quic_mburton, sid.manning, ale, anjo
[-- Attachment #1: Type: text/plain, Size: 1030 bytes --]
On Tue, Mar 10, 2026 at 9:49 PM Brian Cain <brian.cain@oss.qualcomm.com>
wrote:
> The analyze_read() methods on GuestSource, GuestPairSource,
> SystemSource, and SystemPairSource were no-ops because these
> source registers do not need read-tracking in the analyze phase.
> However, gen_analyze_funcs.py unconditionally declares the
> register-number variable (e.g. GsN) via decl_reg_num() for all
> registers that are read or written. When building with
> hexagon-softmmu, the generated analyze function bodies are
> compiled (outside the #ifndef CONFIG_USER_ONLY guard), and the
> declared-but-unreferenced register-number variable triggers
> -Werror=unused-variable under both gcc and clang.
>
> Emit a (void) cast on the register number from analyze_read() to
> suppress the warning.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/hex_common.py | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
[-- Attachment #2: Type: text/html, Size: 1546 bytes --]
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v5 19/35] target/hexagon: Add vmstate representation
2026-03-11 3:49 ` [PATCH v5 19/35] target/hexagon: Add vmstate representation Brian Cain
@ 2026-03-25 19:21 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 41+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-25 19:21 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: ltaylorsimpson, matheus.bernardino, marco.liebel, quic_mburton,
sid.manning, ale, anjo, Brian Cain
On 11/3/26 04:49, Brian Cain wrote:
> From: Brian Cain <bcain@quicinc.com>
>
> Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/internal.h | 4 ++++
> target/hexagon/cpu.c | 3 +++
> target/hexagon/machine.c | 32 ++++++++++++++++++++++++++++++++
> 3 files changed, 39 insertions(+)
> create mode 100644 target/hexagon/machine.c
>
> diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
> index 5fc837ae229..cd06ff41d4f 100644
> --- a/target/hexagon/internal.h
> +++ b/target/hexagon/internal.h
> @@ -31,4 +31,8 @@ void hexagon_debug(CPUHexagonState *env);
>
> extern const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS];
>
> +#ifndef CONFIG_USER_ONLY
> +extern const VMStateDescription vmstate_hexagon_cpu;
> +#endif
> +
> #endif
> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
> index 6fabfaad6d2..38d605b06ba 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -387,6 +387,9 @@ static void hexagon_cpu_class_init(ObjectClass *c, const void *data)
> cc->gdb_stop_before_watchpoint = true;
> cc->gdb_core_xml_file = "hexagon-core.xml";
> cc->disas_set_info = hexagon_cpu_disas_set_info;
> +#ifndef CONFIG_USER_ONLY
> + dc->vmsd = &vmstate_hexagon_cpu;
> +#endif
> cc->tcg_ops = &hexagon_tcg_ops;
> }
>
> diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c
> new file mode 100644
> index 00000000000..d6dcd07dd4a
> --- /dev/null
> +++ b/target/hexagon/machine.c
> @@ -0,0 +1,32 @@
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "migration/cpu.h"
We don't need to include the target-specific "migration/cpu.h" header,
the target-agnostic "migration/vmstate.h" should be sufficient. With
that change:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> +#include "cpu.h"
> +
> +const VMStateDescription vmstate_hexagon_cpu = {
> + .name = "cpu",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32_ARRAY(env.gpr, HexagonCPU, TOTAL_PER_THREAD_REGS),
> + VMSTATE_UINT32_ARRAY(env.pred, HexagonCPU, NUM_PREGS),
> + VMSTATE_UINT32_ARRAY(env.t_sreg, HexagonCPU, NUM_SREGS),
> + VMSTATE_UINT32_ARRAY(env.greg, HexagonCPU, NUM_GREGS),
> + VMSTATE_UINT32(env.next_PC, HexagonCPU),
> + VMSTATE_UINT32(env.tlb_lock_state, HexagonCPU),
> + VMSTATE_UINT32(env.k0_lock_state, HexagonCPU),
> + VMSTATE_UINT32(env.tlb_lock_count, HexagonCPU),
> + VMSTATE_UINT32(env.k0_lock_count, HexagonCPU),
> + VMSTATE_UINT32(env.threadId, HexagonCPU),
> + VMSTATE_UINT32(env.cause_code, HexagonCPU),
> + VMSTATE_UINT32(env.wait_next_pc, HexagonCPU),
> + VMSTATE_UINT64(env.t_cycle_count, HexagonCPU),
> +
> + VMSTATE_END_OF_LIST()
> + },
> +};
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v5 24/35] target/hexagon: Add sysemu TCG overrides
2026-03-11 3:49 ` [PATCH v5 24/35] target/hexagon: Add sysemu TCG overrides Brian Cain
@ 2026-03-25 19:24 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 41+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-25 19:24 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: ltaylorsimpson, matheus.bernardino, marco.liebel, quic_mburton,
sid.manning, ale, anjo, Brian Cain
On 11/3/26 04:49, Brian Cain wrote:
> From: Brian Cain <bcain@quicinc.com>
>
> Define TCG overrides for setprio(), crswap(,sgp{0,1,1:0}).
>
> Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/cpu_helper.h | 18 ++++++++++++++++
> target/hexagon/gen_tcg_sys.h | 40 ++++++++++++++++++++++++++++++++++++
> target/hexagon/helper.h | 1 +
> target/hexagon/genptr.c | 4 ++++
> target/hexagon/op_helper.c | 10 ++++++++-
> target/hexagon/hex_common.py | 2 ++
> target/hexagon/meson.build | 13 ++++++------
> 7 files changed, 81 insertions(+), 7 deletions(-)
> create mode 100644 target/hexagon/cpu_helper.h
> create mode 100644 target/hexagon/gen_tcg_sys.h
> diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
> index 327c233c01b..d9d84f05553 100644
> --- a/target/hexagon/op_helper.c
> +++ b/target/hexagon/op_helper.c
> @@ -19,9 +19,10 @@
> #include "qemu/log.h"
> #include "accel/tcg/cpu-ldst.h"
> #include "accel/tcg/probe.h"
> +#include "qemu/main-loop.h"
"qemu/main-loop.h" doesn't seem used in this patch.
> +#include "cpu.h"
> #include "exec/helper-proto.h"
> #include "fpu/softfloat.h"
> -#include "cpu.h"
> #include "internal.h"
> #include "macros.h"
> #include "sys_macros.h"
> @@ -31,6 +32,7 @@
> #include "mmvec/mmvec.h"
> #include "mmvec/macros.h"
> #include "op_helper.h"
> +#include "cpu_helper.h"
> #include "translate.h"
> #ifndef CONFIG_USER_ONLY
> #include "hexswi.h"
> @@ -1412,6 +1414,12 @@ uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg)
> {
> g_assert_not_reached();
> }
> +
> +void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio)
> +{
> + g_assert_not_reached();
> +}
> +
> #endif
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v5 29/35] target/hexagon: Add sreg_{read,write} helpers
2026-03-11 3:49 ` [PATCH v5 29/35] target/hexagon: Add sreg_{read,write} helpers Brian Cain
@ 2026-03-25 19:26 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 41+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-25 19:26 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: ltaylorsimpson, matheus.bernardino, marco.liebel, quic_mburton,
sid.manning, ale, anjo, Brian Cain, Sid Manning
On 11/3/26 04:49, Brian Cain wrote:
> From: Brian Cain <bcain@quicinc.com>
>
> Co-authored-by: Sid Manning <sidneym@quicinc.com>
> Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/cpu.c | 1 -
> target/hexagon/cpu_helper.c | 60 +++++++++++++++++++++++++++++++++++++
> target/hexagon/op_helper.c | 30 +++++++++++++++++--
> 3 files changed, 87 insertions(+), 4 deletions(-)
> create mode 100644 target/hexagon/cpu_helper.c
> diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
> index af93be7a232..3517f3768fd 100644
> --- a/target/hexagon/op_helper.c
> +++ b/target/hexagon/op_helper.c
> @@ -1452,17 +1452,41 @@ void HELPER(setimask)(CPUHexagonState *env, uint32_t tid, uint32_t imask)
>
> void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
> {
> - g_assert_not_reached();
> + BQL_LOCK_GUARD();
> + if (reg < HEX_SREG_GLB_START) {
> + env->t_sreg[reg] = val;
> + } else {
> + HexagonCPU *cpu = env_archcpu(env);
> + if (cpu->globalregs) {
> + hexagon_globalreg_write_masked(cpu->globalregs, reg, val);
> + }
> + }
> +}
> +
> +static inline QEMU_ALWAYS_INLINE uint32_t sreg_read(CPUHexagonState *env,
> + uint32_t reg)
> +{
> + g_assert(bql_locked());
> + if (reg < HEX_SREG_GLB_START) {
> + return env->t_sreg[reg];
> + }
> + HexagonCPU *cpu = env_archcpu(env);
> + return cpu->globalregs ?
> + hexagon_globalreg_read(cpu->globalregs, reg, env->threadId) : 0;
> }
>
> uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg)
> {
> - g_assert_not_reached();
> + BQL_LOCK_GUARD();
Ah I see, I suppose this is the patch that requires "qemu/main-loop.h".
> + return sreg_read(env, reg);
> }
>
> uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg)
> {
> - g_assert_not_reached();
> + BQL_LOCK_GUARD();
> +
> + return deposit64((uint64_t) sreg_read(env, reg), 32, 32,
> + sreg_read(env, reg + 1));
> }
>
> uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg)
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v5 31/35] hw/hexagon: Introduce hexagon TLB device
2026-03-11 3:49 ` [PATCH v5 31/35] hw/hexagon: Introduce hexagon TLB device Brian Cain
@ 2026-03-25 19:38 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 41+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-03-25 19:38 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: ltaylorsimpson, matheus.bernardino, marco.liebel, quic_mburton,
sid.manning, ale, anjo
Hi Brian,
On 11/3/26 04:49, Brian Cain wrote:
> Add the hexagon TLB QOM device model.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>
> Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
> ---
> include/hw/hexagon/hexagon_tlb.h | 45 +++
> target/hexagon/cpu.h | 4 +
> hw/hexagon/hexagon_tlb.c | 463 +++++++++++++++++++++++++++++++
> target/hexagon/cpu.c | 5 +
> 4 files changed, 517 insertions(+)
> create mode 100644 include/hw/hexagon/hexagon_tlb.h
> create mode 100644 hw/hexagon/hexagon_tlb.c
>
> diff --git a/include/hw/hexagon/hexagon_tlb.h b/include/hw/hexagon/hexagon_tlb.h
> new file mode 100644
> index 00000000000..bcb387aa24d
> --- /dev/null
> +++ b/include/hw/hexagon/hexagon_tlb.h
> @@ -0,0 +1,45 @@
> +/*
> + * Hexagon TLB QOM Device
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef HW_HEXAGON_TLB_H
> +#define HW_HEXAGON_TLB_H
> +
> +#include "hw/core/sysbus.h"
> +#include "qom/object.h"
> +#include "exec/hwaddr.h"
> +#include "exec/mmu-access-type.h"
> +#define TYPE_HEXAGON_TLB "hexagon-tlb"
> +OBJECT_DECLARE_SIMPLE_TYPE(HexagonTLBState, HEXAGON_TLB)
> +
> +struct HexagonTLBState {
> + SysBusDevice parent_obj;
> +
> + uint32_t num_entries;
> + uint64_t *entries;
> +};
> +
> +uint64_t hexagon_tlb_read(HexagonTLBState *tlb, uint32_t index);
> +void hexagon_tlb_write(HexagonTLBState *tlb, uint32_t index, uint64_t value);
> +
> +bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
> + uint32_t VA, MMUAccessType access_type,
> + hwaddr *PA, int *prot, uint64_t *size,
> + int32_t *excp, int *cause_code, int mmu_idx);
> +
> +uint32_t hexagon_tlb_lookup(HexagonTLBState *tlb, uint32_t asid,
> + uint32_t VA, int *cause_code);
> +
> +int hexagon_tlb_check_overlap(HexagonTLBState *tlb, uint64_t entry,
> + uint64_t index);
> +
> +void hexagon_tlb_dump(HexagonTLBState *tlb);
> +
> +bool hexagon_tlb_dump_entry(FILE *f, uint64_t entry);
> +
> +uint32_t hexagon_tlb_get_num_entries(HexagonTLBState *tlb);
> +
> +#endif /* HW_HEXAGON_TLB_H */
> diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
> index 9eb2d1bbabe..e39e6e39fec 100644
> --- a/target/hexagon/cpu.h
> +++ b/target/hexagon/cpu.h
> @@ -46,6 +46,7 @@
> #define REG_WRITES_MAX 32
> #define PRED_WRITES_MAX 5 /* 4 insns + endloop */
> #define VSTORES_MAX 2
> +#define MAX_TLB_ENTRIES 1024
>
> #define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU
> #ifndef CONFIG_USER_ONLY
> @@ -174,6 +175,9 @@ struct ArchCPU {
> bool lldb_compat;
> target_ulong lldb_stack_adjust;
> bool short_circuit;
> +#ifndef CONFIG_USER_ONLY
> + struct HexagonTLBState *tlb;
Please use the typedef (dropping the 'struct').
> +#endif
> };
>
> #include "cpu_bits.h"
> diff --git a/hw/hexagon/hexagon_tlb.c b/hw/hexagon/hexagon_tlb.c
> new file mode 100644
> index 00000000000..90f319f56d3
> --- /dev/null
> +++ b/hw/hexagon/hexagon_tlb.c
> @@ -0,0 +1,463 @@
> +/*
> + * Hexagon TLB QOM Device
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "hw/hexagon/hexagon_tlb.h"
> +#include "hw/core/qdev-properties.h"
> +#include "hw/core/resettable.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +#include "target/hexagon/cpu.h"
> +#include "target/hexagon/cpu_bits.h"
> +
> +/* PTE (TLB entry) field extraction */
> +#define GET_PTE_PPD(entry) extract64((entry), 0, 24)
> +#define GET_PTE_C(entry) extract64((entry), 24, 4)
> +#define GET_PTE_U(entry) extract64((entry), 28, 1)
> +#define GET_PTE_R(entry) extract64((entry), 29, 1)
> +#define GET_PTE_W(entry) extract64((entry), 30, 1)
> +#define GET_PTE_X(entry) extract64((entry), 31, 1)
> +#define GET_PTE_VPN(entry) extract64((entry), 32, 20)
> +#define GET_PTE_ASID(entry) extract64((entry), 52, 7)
> +#define GET_PTE_ATR0(entry) extract64((entry), 59, 1)
> +#define GET_PTE_ATR1(entry) extract64((entry), 60, 1)
> +#define GET_PTE_PA35(entry) extract64((entry), 61, 1)
> +#define GET_PTE_G(entry) extract64((entry), 62, 1)
> +#define GET_PTE_V(entry) extract64((entry), 63, 1)
> +
> +/* PPD (physical page descriptor) */
> +static inline uint64_t GET_PPD(uint64_t entry)
> +{
> + return GET_PTE_PPD(entry) | (GET_PTE_PA35(entry) << 24);
> +}
> +
> +#define NO_ASID (1 << 8)
> +
> +typedef enum {
> + PGSIZE_4K,
> + PGSIZE_16K,
> + PGSIZE_64K,
> + PGSIZE_256K,
> + PGSIZE_1M,
> + PGSIZE_4M,
> + PGSIZE_16M,
> + PGSIZE_64M,
> + PGSIZE_256M,
> + PGSIZE_1G,
> + NUM_PGSIZE_TYPES
Matter of style, since the last entry isn't part of the enum
I'd use:
#define NUM_PGSIZE_TYPES (PGSIZE_1G + 1)
> +} tlb_pgsize_t;
> +
> +static const char *pgsize_str[NUM_PGSIZE_TYPES] = {
> + "4K",
> + "16K",
> + "64K",
> + "256K",
> + "1M",
> + "4M",
> + "16M",
> + "64M",
> + "256M",
> + "1G",
> +};
> +
> +#define INVALID_MASK 0xffffffffLL
> +
> +static const uint64_t encmask_2_mask[] = {
> + 0x0fffLL, /* 4k, 0000 */
> + 0x3fffLL, /* 16k, 0001 */
> + 0xffffLL, /* 64k, 0010 */
> + 0x3ffffLL, /* 256k, 0011 */
> + 0xfffffLL, /* 1m, 0100 */
> + 0x3fffffLL, /* 4m, 0101 */
> + 0xffffffLL, /* 16m, 0110 */
> + 0x3ffffffLL, /* 64m, 0111 */
> + 0xfffffffLL, /* 256m, 1000 */
> + 0x3fffffffLL, /* 1g, 1001 */
> + INVALID_MASK, /* RSVD, 0111 */
Typo '1111' I suppose, since 0111 is 64M.
> +};
> +
> +static inline tlb_pgsize_t hex_tlb_pgsize_type(uint64_t entry)
> +{
> + if (entry == 0) {
> + qemu_log_mask(CPU_LOG_MMU, "%s: Supplied TLB entry was 0!\n",
> + __func__);
> + return 0;
> + }
> + tlb_pgsize_t size = ctz64(entry);
> + g_assert(size < NUM_PGSIZE_TYPES);
> + return size;
> +}
> +
> +static inline uint64_t hex_tlb_page_size_bytes(uint64_t entry)
> +{
> + return 1ull << (TARGET_PAGE_BITS + 2 * hex_tlb_pgsize_type(entry));
> +}
> +
> +static inline uint64_t hex_tlb_phys_page_num(uint64_t entry)
> +{
> + uint32_t ppd = GET_PPD(entry);
> + return ppd >> 1;
> +}
> +
> +static inline uint64_t hex_tlb_phys_addr(uint64_t entry)
> +{
> + uint64_t pagemask = encmask_2_mask[hex_tlb_pgsize_type(entry)];
> + uint64_t pagenum = hex_tlb_phys_page_num(entry);
> + uint64_t PA = (pagenum << TARGET_PAGE_BITS) & (~pagemask);
We are replacing all TARGET_PAGE_BITS uses by qemu_target_page_bits().
> + return PA;
> +}
> +
> +static inline uint64_t hex_tlb_virt_addr(uint64_t entry)
> +{
> + return (uint64_t)GET_PTE_VPN(entry) << TARGET_PAGE_BITS;
> +}
> +
> +bool hexagon_tlb_dump_entry(FILE *f, uint64_t entry)
> +{
Prefer Monitor* instead of FILE*.
> + if (GET_PTE_V(entry)) {
> + fprintf(f, "0x%016" PRIx64 ": ", entry);
> + uint64_t PA = hex_tlb_phys_addr(entry);
> + uint64_t VA = hex_tlb_virt_addr(entry);
> + fprintf(f, "V:%" PRId64 " G:%" PRId64
> + " A1:%" PRId64 " A0:%" PRId64,
> + GET_PTE_V(entry),
> + GET_PTE_G(entry),
> + GET_PTE_ATR1(entry),
> + GET_PTE_ATR0(entry));
> + fprintf(f, " ASID:0x%02" PRIx64 " VA:0x%08" PRIx64,
> + GET_PTE_ASID(entry), VA);
> + fprintf(f,
> + " X:%" PRId64 " W:%" PRId64 " R:%" PRId64
> + " U:%" PRId64 " C:%" PRId64,
> + GET_PTE_X(entry),
> + GET_PTE_W(entry),
> + GET_PTE_R(entry),
> + GET_PTE_U(entry),
> + GET_PTE_C(entry));
> + fprintf(f, " PA:0x%09" PRIx64 " SZ:%s (0x%" PRIx64 ")", PA,
> + pgsize_str[hex_tlb_pgsize_type(entry)],
> + hex_tlb_page_size_bytes(entry));
> + fprintf(f, "\n");
> + return true;
> + }
> +
> + /* Not valid */
> + return false;
> +}
> +
> +static inline bool hex_tlb_entry_match_noperm(uint64_t entry, uint32_t asid,
> + uint64_t VA)
> +{
> + if (GET_PTE_V(entry)) {
> + if (GET_PTE_G(entry)) {
> + /* Global entry - ignore ASID */
> + } else if (asid != NO_ASID) {
> + uint32_t tlb_asid = GET_PTE_ASID(entry);
> + if (tlb_asid != asid) {
> + return false;
> + }
> + }
> +
> + uint64_t page_size = hex_tlb_page_size_bytes(entry);
> + uint64_t page_start =
> + ROUND_DOWN(hex_tlb_virt_addr(entry), page_size);
> + if (page_start <= VA && VA < page_start + page_size) {
> + return true;
> + }
> + }
> + return false;
> +}
> +
> +static inline void hex_tlb_entry_get_perm(uint64_t entry,
> + MMUAccessType access_type,
> + int mmu_idx, int *prot,
> + int32_t *excp, int *cause_code)
> +{
> + bool perm_x = GET_PTE_X(entry);
> + bool perm_w = GET_PTE_W(entry);
> + bool perm_r = GET_PTE_R(entry);
> + bool perm_u = GET_PTE_U(entry);
> + bool user_idx = mmu_idx == MMU_USER_IDX;
> +
> + if (mmu_idx == MMU_KERNEL_IDX) {
> + *prot = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> + return;
> + }
> +
> + *prot = PAGE_VALID;
> + switch (access_type) {
> + case MMU_INST_FETCH:
> + if (user_idx && !perm_u) {
> + *excp = HEX_EVENT_PRECISE;
> + *cause_code = HEX_CAUSE_FETCH_NO_UPAGE;
> + } else if (!perm_x) {
> + *excp = HEX_EVENT_PRECISE;
> + *cause_code = HEX_CAUSE_FETCH_NO_XPAGE;
> + }
> + break;
> + case MMU_DATA_LOAD:
> + if (user_idx && !perm_u) {
> + *excp = HEX_EVENT_PRECISE;
> + *cause_code = HEX_CAUSE_PRIV_NO_UREAD;
> + } else if (!perm_r) {
> + *excp = HEX_EVENT_PRECISE;
> + *cause_code = HEX_CAUSE_PRIV_NO_READ;
> + }
> + break;
> + case MMU_DATA_STORE:
> + if (user_idx && !perm_u) {
> + *excp = HEX_EVENT_PRECISE;
> + *cause_code = HEX_CAUSE_PRIV_NO_UWRITE;
> + } else if (!perm_w) {
> + *excp = HEX_EVENT_PRECISE;
> + *cause_code = HEX_CAUSE_PRIV_NO_WRITE;
> + }
> + break;
> + }
> +
> + if (!user_idx || perm_u) {
> + if (perm_x) {
> + *prot |= PAGE_EXEC;
> + }
> + if (perm_r) {
> + *prot |= PAGE_READ;
> + }
> + if (perm_w) {
> + *prot |= PAGE_WRITE;
> + }
> + }
> +}
> +
> +static inline bool hex_tlb_entry_match(uint64_t entry, uint8_t asid,
> + uint32_t VA,
> + MMUAccessType access_type, hwaddr *PA,
> + int *prot, uint64_t *size,
> + int32_t *excp, int *cause_code,
> + int mmu_idx)
> +{
> + if (hex_tlb_entry_match_noperm(entry, asid, VA)) {
> + hex_tlb_entry_get_perm(entry, access_type, mmu_idx, prot, excp,
> + cause_code);
> + *PA = hex_tlb_phys_addr(entry);
> + *size = hex_tlb_page_size_bytes(entry);
> + return true;
> + }
> + return false;
> +}
> +
> +static bool hex_tlb_is_match(uint64_t entry1, uint64_t entry2,
> + bool consider_gbit)
> +{
> + bool valid1 = GET_PTE_V(entry1);
> + bool valid2 = GET_PTE_V(entry2);
> + uint64_t size1 = hex_tlb_page_size_bytes(entry1);
> + uint64_t vaddr1 = ROUND_DOWN(hex_tlb_virt_addr(entry1), size1);
> + uint64_t size2 = hex_tlb_page_size_bytes(entry2);
> + uint64_t vaddr2 = ROUND_DOWN(hex_tlb_virt_addr(entry2), size2);
> + int asid1 = GET_PTE_ASID(entry1);
> + int asid2 = GET_PTE_ASID(entry2);
> + bool gbit1 = GET_PTE_G(entry1);
> + bool gbit2 = GET_PTE_G(entry2);
> +
> + if (!valid1 || !valid2) {
> + return false;
> + }
> +
> + if (((vaddr1 <= vaddr2) && (vaddr2 < (vaddr1 + size1))) ||
> + ((vaddr2 <= vaddr1) && (vaddr1 < (vaddr2 + size2)))) {
> + if (asid1 == asid2) {
> + return true;
> + }
> + if ((consider_gbit && gbit1) || gbit2) {
> + return true;
> + }
> + }
> + return false;
> +}
> +
> +/* Public API */
> +
> +uint64_t hexagon_tlb_read(HexagonTLBState *tlb, uint32_t index)
> +{
> + g_assert(index < tlb->num_entries);
> + return tlb->entries[index];
> +}
> +
> +void hexagon_tlb_write(HexagonTLBState *tlb, uint32_t index, uint64_t value)
> +{
> + g_assert(index < tlb->num_entries);
> + tlb->entries[index] = value;
> +}
> +
> +bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
> + uint32_t VA, MMUAccessType access_type,
> + hwaddr *PA, int *prot, uint64_t *size,
> + int32_t *excp, int *cause_code, int mmu_idx)
> +{
> + *PA = 0;
> + *prot = 0;
> + *size = 0;
> + *excp = 0;
> + *cause_code = 0;
> +
> + for (uint32_t i = 0; i < tlb->num_entries; i++) {
> + if (hex_tlb_entry_match(tlb->entries[i], asid, VA, access_type,
> + PA, prot, size, excp, cause_code, mmu_idx)) {
> + return true;
> + }
> + }
> + return false;
> +}
> +
> +uint32_t hexagon_tlb_lookup(HexagonTLBState *tlb, uint32_t asid,
> + uint32_t VA, int *cause_code)
> +{
> + uint32_t not_found = 0x80000000;
> + uint32_t idx = not_found;
> +
> + for (uint32_t i = 0; i < tlb->num_entries; i++) {
> + uint64_t entry = tlb->entries[i];
> + if (hex_tlb_entry_match_noperm(entry, asid, VA)) {
> + if (idx != not_found) {
> + *cause_code = HEX_CAUSE_IMPRECISE_MULTI_TLB_MATCH;
> + break;
> + }
> + idx = i;
> + }
> + }
> +
> + if (idx == not_found) {
> + qemu_log_mask(CPU_LOG_MMU,
> + "%s: 0x%" PRIx32 ", 0x%08" PRIx32 " => NOT FOUND\n",
> + __func__, asid, VA);
> + } else {
> + qemu_log_mask(CPU_LOG_MMU,
> + "%s: 0x%" PRIx32 ", 0x%08" PRIx32 " => %d\n",
> + __func__, asid, VA, idx);
> + }
> +
> + return idx;
> +}
> +
> +/*
> + * Return codes:
> + * 0 or positive index of match
> + * -1 multiple matches
> + * -2 no match
> + */
> +int hexagon_tlb_check_overlap(HexagonTLBState *tlb, uint64_t entry,
> + uint64_t index)
> +{
> + int matches = 0;
> + int last_match = 0;
> +
> + for (uint32_t i = 0; i < tlb->num_entries; i++) {
> + if (hex_tlb_is_match(entry, tlb->entries[i], false)) {
> + matches++;
> + last_match = i;
> + }
> + }
> +
> + if (matches == 1) {
> + return last_match;
> + }
> + if (matches == 0) {
> + return -2;
> + }
> + return -1;
> +}
> +
> +void hexagon_tlb_dump(HexagonTLBState *tlb)
> +{
> + for (uint32_t i = 0; i < tlb->num_entries; i++) {
> + hexagon_tlb_dump_entry(stdout, tlb->entries[i]);
> + }
> +}
> +
> +uint32_t hexagon_tlb_get_num_entries(HexagonTLBState *tlb)
> +{
> + return tlb->num_entries;
> +}
> +
> +/* QOM lifecycle */
> +
> +static void hexagon_tlb_init(Object *obj)
> +{
> +}
> +
> +static void hexagon_tlb_realize(DeviceState *dev, Error **errp)
> +{
> + HexagonTLBState *s = HEXAGON_TLB(dev);
> +
> + if (s->num_entries == 0 || s->num_entries > MAX_TLB_ENTRIES) {
> + error_setg(errp, "Invalid TLB num-entries: %" PRIu32,
> + s->num_entries);
> + return;
> + }
> + s->entries = g_new0(uint64_t, s->num_entries);
> +}
> +
> +static void hexagon_tlb_finalize(Object *obj)
> +{
> + HexagonTLBState *s = HEXAGON_TLB(obj);
> + g_free(s->entries);
This should be done in the unrealize() handler.
> + s->entries = NULL;
> +}
> +
> +static void hexagon_tlb_reset_hold(Object *obj, ResetType type)
> +{
> + HexagonTLBState *s = HEXAGON_TLB(obj);
> + if (s->entries) {
> + memset(s->entries, 0, sizeof(uint64_t) * s->num_entries);
> + }
> +}
> +
> +static const VMStateDescription vmstate_hexagon_tlb = {
> + .name = "hexagon-tlb",
> + .version_id = 0,
> + .minimum_version_id = 0,
> + .fields = (const VMStateField[]) {
> + VMSTATE_UINT32(num_entries, HexagonTLBState),
> + VMSTATE_VARRAY_UINT32_ALLOC(entries, HexagonTLBState, num_entries,
> + 0, vmstate_info_uint64, uint64_t),
> + VMSTATE_END_OF_LIST()
> + },
> +};
> +
> +static const Property hexagon_tlb_properties[] = {
> + DEFINE_PROP_UINT32("num-entries", HexagonTLBState, num_entries,
> + MAX_TLB_ENTRIES),
> +};
> +
> +static void hexagon_tlb_class_init(ObjectClass *klass, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + ResettableClass *rc = RESETTABLE_CLASS(klass);
> +
> + dc->realize = hexagon_tlb_realize;
> + rc->phases.hold = hexagon_tlb_reset_hold;
> + dc->vmsd = &vmstate_hexagon_tlb;
> + dc->user_creatable = false;
> + device_class_set_props(dc, hexagon_tlb_properties);
> +}
> +
> +static const TypeInfo hexagon_tlb_info = {
> + .name = TYPE_HEXAGON_TLB,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(HexagonTLBState),
> + .instance_init = hexagon_tlb_init,
> + .instance_finalize = hexagon_tlb_finalize,
> + .class_init = hexagon_tlb_class_init,
> +};
> +
> +static void hexagon_tlb_register_types(void)
> +{
> + type_register_static(&hexagon_tlb_info);
> +}
> +
> +type_init(hexagon_tlb_register_types)
> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
> index b1317f83ef4..32d158684a0 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -23,6 +23,7 @@
> #include "qapi/error.h"
> #include "hw/core/qdev-properties.h"
> #include "fpu/softfloat-helpers.h"
> +#include "hw/hexagon/hexagon_tlb.h"
> #include "tcg/tcg.h"
> #include "exec/gdbstub.h"
> #include "accel/tcg/cpu-ops.h"
> @@ -50,6 +51,10 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
> }
>
> static const Property hexagon_cpu_properties[] = {
> +#if !defined(CONFIG_USER_ONLY)
> + DEFINE_PROP_LINK("tlb", HexagonCPU, tlb, TYPE_HEXAGON_TLB,
> + HexagonTLBState *),
Not used at this point, maybe add later?
> +#endif
> DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false),
> DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0,
> qdev_prop_uint32, target_ulong),
^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2026-03-25 19:38 UTC | newest]
Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-11 3:48 [PATCH v5 00/35] Hexagon system emulation, Part 1/3 Brian Cain
2026-03-11 3:48 ` [PATCH v5 01/35] docs: Add hexagon sysemu docs Brian Cain
2026-03-11 3:48 ` [PATCH v5 02/35] docs/system: Add hexagon CPU emulation Brian Cain
2026-03-11 3:48 ` [PATCH v5 03/35] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
2026-03-11 3:48 ` [PATCH v5 04/35] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
2026-03-11 3:48 ` [PATCH v5 05/35] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
2026-03-11 3:48 ` [PATCH v5 06/35] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
2026-03-12 21:03 ` Taylor Simpson
2026-03-11 3:48 ` [PATCH v5 07/35] target/hexagon: Make gen_exception_end_tb non-static Brian Cain
2026-03-11 3:48 ` [PATCH v5 08/35] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain via qemu development
2026-03-11 3:48 ` [PATCH v5 09/35] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
2026-03-11 3:48 ` [PATCH v5 10/35] target/hexagon: Add a placeholder fp exception Brian Cain
2026-03-11 3:48 ` [PATCH v5 11/35] target/hexagon: Add guest, system reg number defs Brian Cain
2026-03-11 3:49 ` [PATCH v5 12/35] target/hexagon: Add guest, system reg number state Brian Cain
2026-03-11 3:49 ` [PATCH v5 13/35] target/hexagon: Add TCG values for sreg, greg Brian Cain
2026-03-11 3:49 ` [PATCH v5 14/35] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
2026-03-11 3:49 ` [PATCH v5 15/35] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
2026-03-11 3:49 ` [PATCH v5 16/35] target/hexagon: Add new macro definitions " Brian Cain
2026-03-11 3:49 ` [PATCH v5 17/35] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
2026-03-11 3:49 ` [PATCH v5 18/35] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
2026-03-11 3:49 ` [PATCH v5 19/35] target/hexagon: Add vmstate representation Brian Cain
2026-03-25 19:21 ` Philippe Mathieu-Daudé
2026-03-11 3:49 ` [PATCH v5 20/35] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
2026-03-11 3:49 ` [PATCH v5 21/35] target/hexagon: Define register fields for system regs Brian Cain
2026-03-11 3:49 ` [PATCH v5 22/35] target/hexagon: Implement do_raise_exception() Brian Cain
2026-03-11 3:49 ` [PATCH v5 23/35] target/hexagon: Add system reg insns Brian Cain
2026-03-11 3:49 ` [PATCH v5 24/35] target/hexagon: Add sysemu TCG overrides Brian Cain
2026-03-25 19:24 ` Philippe Mathieu-Daudé
2026-03-11 3:49 ` [PATCH v5 25/35] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
2026-03-11 3:49 ` [PATCH v5 26/35] target/hexagon: Add TCG overrides for int handler insts Brian Cain
2026-03-11 3:49 ` [PATCH v5 27/35] target/hexagon: Add TCG overrides for thread ctl Brian Cain
2026-03-11 3:49 ` [PATCH v5 28/35] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
2026-03-11 3:49 ` [PATCH v5 29/35] target/hexagon: Add sreg_{read,write} helpers Brian Cain
2026-03-25 19:26 ` Philippe Mathieu-Daudé
2026-03-11 3:49 ` [PATCH v5 30/35] target/hexagon: Add cpu modes, mmu indices, next_PC to state Brian Cain
2026-03-11 3:49 ` [PATCH v5 31/35] hw/hexagon: Introduce hexagon TLB device Brian Cain
2026-03-25 19:38 ` Philippe Mathieu-Daudé
2026-03-11 3:49 ` [PATCH v5 32/35] target/hexagon: Add stubs for modify_ssr/get_exe_mode Brian Cain
2026-03-11 3:49 ` [PATCH v5 33/35] target/hexagon: Add clear_wait_mode() definition Brian Cain
2026-03-11 3:49 ` [PATCH v5 34/35] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
2026-03-11 3:49 ` [PATCH v5 35/35] target/hexagon: Add hex_interrupts support Brian Cain
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox