* [PATCH v8] docs: Add hexagon sysemu docs
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] docs/system: Add hexagon CPU emulation Brian Cain
` (34 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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>
---
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 4ff33eb630b..a2b04177be0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -259,6 +259,9 @@ F: disas/hexagon.c
F: configs/targets/hexagon-linux-user/default.mak
F: tests/docker/dockerfiles/debian-hexagon-cross.docker
F: gdbstub/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/qualcomm/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] 43+ messages in thread* [PATCH v8] docs/system: Add hexagon CPU emulation
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
2026-06-11 5:28 ` [PATCH v8] docs: Add hexagon sysemu docs Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
` (33 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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>
---
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] 43+ messages in thread* [PATCH v8] target/hexagon: Fix badva reference, delete CAUSE
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
2026-06-11 5:28 ` [PATCH v8] docs: Add hexagon sysemu docs Brian Cain
2026-06-11 5:28 ` [PATCH v8] docs/system: Add hexagon CPU emulation Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
` (32 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain, Philippe Mathieu-Daudé
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 2c53f2c2836..bd568bdd871 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -110,6 +110,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)
{
@@ -209,8 +217,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] 43+ messages in thread* [PATCH v8] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (2 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
` (31 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 e37d5a514f0..280aef0df3f 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] 43+ messages in thread* [PATCH v8] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (3 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
` (30 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 280aef0df3f..79436ee29d7 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] 43+ messages in thread* [PATCH v8] target/hexagon: Suppress unused-variable warnings for sysemu source regs
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (4 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain via qemu development
` (29 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd
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.
Override decl_reg_num() in each class to declare the register number with
G_GNUC_UNUSED, suppressing the warning.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
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 79436ee29d7..df8d3ba6586 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] 43+ messages in thread* [PATCH v8] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags()
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (5 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
@ 2026-06-11 5:28 ` Brian Cain via qemu development
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
` (28 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain via qemu development @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain, Alessandro Di Federico,
Anton Johansson
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] 43+ messages in thread* [PATCH v8] target/hexagon: Add privilege check, use tag_ignore()
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (6 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain via qemu development
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add a placeholder fp exception Brian Cain
` (27 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Laurent Vivier, Helge Deller
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.
Expose hex_gen_exception_end_tb() via translate.h (previously the
static gen_exception_end_tb) so that it can be called from the
generated privileged-instruction TCG stubs.
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 +++++++++++++++++++++++++++++----
target/hexagon/translate.h | 2 +
linux-user/hexagon/cpu_loop.c | 16 +++++++
target/hexagon/cpu.c | 1 +
target/hexagon/translate.c | 12 +++++-
target/hexagon/gen_tcg_funcs.py | 35 +++++++++------
7 files changed, 127 insertions(+), 24 deletions(-)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 7c09c97db85..e22567d8e67 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -45,6 +45,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;
@@ -77,6 +86,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 aaac6b9ea64..164e74c782b 100644
--- a/target/hexagon/cpu_bits.h
+++ b/target/hexagon/cpu_bits.h
@@ -25,20 +25,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/target/hexagon/translate.h b/target/hexagon/translate.h
index 1fc185e3edd..d80bc532e24 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -283,6 +283,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/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 bd568bdd871..5bf6e85b939 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -299,6 +299,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 0b9337d9120..d61658a798c 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"
};
@@ -187,7 +191,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);
@@ -580,7 +584,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);
}
}
@@ -1138,4 +1142,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 e7f90a0da11..6d5d99cee3a 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] 43+ messages in thread* [PATCH v8] target/hexagon: Add a placeholder fp exception
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (7 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add guest, system reg number defs Brian Cain
` (26 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain, Philippe Mathieu-Daudé
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
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] 43+ messages in thread* [PATCH v8] target/hexagon: Add guest, system reg number defs
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (8 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add a placeholder fp exception Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add guest, system reg number state Brian Cain
` (25 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 e22567d8e67..e0cf87e5a4c 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/target_long.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] 43+ messages in thread* [PATCH v8] target/hexagon: Add guest, system reg number state
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (9 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add guest, system reg number defs Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add TCG values for sreg, greg Brian Cain
` (24 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 e0cf87e5a4c..4bea953ac73 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -100,6 +100,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 5bf6e85b939..d30e5b64eac 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -299,6 +299,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] 43+ messages in thread* [PATCH v8] target/hexagon: Add TCG values for sreg, greg
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (10 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add guest, system reg number state Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
` (23 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain, Philippe Mathieu-Daudé
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
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 d80bc532e24..d8eea56191d 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -282,6 +282,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 d61658a798c..97849ab861a 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
@@ -1084,6 +1086,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] 43+ messages in thread* [PATCH v8] target/hexagon: Add guest/sys reg writes to DisasContext
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (11 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add TCG values for sreg, greg Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
` (22 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 d8eea56191d..57767acf002 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -41,6 +41,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);
@@ -81,6 +89,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] 43+ messages in thread* [PATCH v8] target/hexagon: Add imported macro, attr defs for sysemu
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (12 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add new macro definitions " Brian Cain
` (21 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/attribs_def.h.inc | 35 ++-
target/hexagon/imported/macros.def | 482 ++++++++++++++++++++++++++++-
2 files changed, 504 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..6c55063a309 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,7 +104,9 @@ 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_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_WRITES_LC0, "Writes loop count for loop 0", "", "UREG.LC0")
DEF_ATTRIB(IMPLICIT_WRITES_LC1, "Writes loop count for loop 1", "", "UREG.LC1")
@@ -111,13 +116,19 @@ 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_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_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 +148,14 @@ 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_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 +167,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 +186,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] 43+ messages in thread* [PATCH v8] target/hexagon: Add new macro definitions for sysemu
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (13 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
` (20 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 0159e5c2d5f..4a58ead877b 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) \
@@ -1112,6 +1113,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; \
@@ -1321,6 +1325,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 eebfe1e5ed9..38a43647dd9 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] 43+ messages in thread* [PATCH v8] target/hexagon: Add handlers for guest/sysreg r/w
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (14 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add new macro definitions " Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
` (19 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 | 151 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 151 insertions(+)
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 5d5adace4b3..8f191f80619 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,156 @@ 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);
+ if (ctx->need_commit || rnum == HEX_SREG_SSR) {
+ tcg_gen_mov_i32(ctx->t_sreg_new_value[rnum], val);
+ } else {
+ tcg_gen_mov_i32(hex_t_sreg[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] 43+ messages in thread* [PATCH v8] target/hexagon: Add placeholder greg/sreg r/w helpers
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (15 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add vmstate representation Brian Cain
` (18 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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] 43+ messages in thread* [PATCH v8] target/hexagon: Add vmstate representation
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (16 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
` (17 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain, Philippe Mathieu-Daudé,
Richard Henderson
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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 d30e5b64eac..3059196bcac 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -382,6 +382,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..2dd95466e7d
--- /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/vmstate.h"
+#include "cpu.h"
+
+const VMStateDescription vmstate_hexagon_cpu = {
+ .name = "cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const 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] 43+ messages in thread* [PATCH v8] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env()
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (17 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add vmstate representation Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Define register fields for system regs Brian Cain
` (16 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 df8d3ba6586..b555e2b663b 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] 43+ messages in thread* [PATCH v8] target/hexagon: Define register fields for system regs
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (18 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Implement do_raise_exception() Brian Cain
` (15 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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] 43+ messages in thread* [PATCH v8] target/hexagon: Implement do_raise_exception()
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (19 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Define register fields for system regs Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add system reg insns Brian Cain
` (14 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain, Philippe Mathieu-Daudé
From: Brian Cain <bcain@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
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] 43+ messages in thread* [PATCH v8] target/hexagon: Add system reg insns
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (20 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Implement do_raise_exception() Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add sysemu TCG overrides Brian Cain
` (13 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Acked-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.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] 43+ messages in thread* [PATCH v8] target/hexagon: Add sysemu TCG overrides
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (21 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add system reg insns Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
` (12 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 | 55 ++++++++++++++++++++++++++++++++++++
target/hexagon/helper.h | 1 +
target/hexagon/genptr.c | 4 +++
target/hexagon/op_helper.c | 9 +++++-
target/hexagon/hex_common.py | 2 ++
target/hexagon/meson.build | 13 +++++----
7 files changed, 95 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..75a28fc10f9
--- /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_high(CPUHexagonState *env);
+uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env);
+void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t val);
+void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t val);
+void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t val);
+
+#endif
diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
new file mode 100644
index 00000000000..f78c9635c3f
--- /dev/null
+++ b/target/hexagon/gen_tcg_sys.h
@@ -0,0 +1,55 @@
+/*
+ * 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]); \
+ if (ctx->need_commit) { \
+ tcg_gen_mov_tl(ctx->t_sreg_new_value[HEX_SREG_SGP0], tmp); \
+ } else { \
+ tcg_gen_mov_tl(hex_t_sreg[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]); \
+ if (ctx->need_commit) { \
+ tcg_gen_mov_tl(ctx->t_sreg_new_value[HEX_SREG_SGP1], tmp); \
+ } else { \
+ tcg_gen_mov_tl(hex_t_sreg[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]); \
+ if (ctx->need_commit) { \
+ 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); \
+ } else { \
+ tcg_gen_extrl_i64_i32(hex_t_sreg[HEX_SREG_SGP0], tmp); \
+ tcg_gen_extrh_i64_i32(hex_t_sreg[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 8f191f80619..ee69feae4b0 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..ed43258cd91 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -19,9 +19,9 @@
#include "qemu/log.h"
#include "accel/tcg/cpu-ldst.h"
#include "accel/tcg/probe.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 +31,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 +1413,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 b555e2b663b..8c6a0589f88 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] 43+ messages in thread* [PATCH v8] target/hexagon: Add implicit attributes to sysemu macros
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (22 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add sysemu TCG overrides Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add TCG overrides for int handler insts Brian Cain
` (11 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 8c6a0589f88..acaaa3c944a 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] 43+ messages in thread* [PATCH v8] target/hexagon: Add TCG overrides for int handler insts
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (23 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add TCG overrides for thread ctl Brian Cain
` (10 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 f78c9635c3f..4cbbdd1f70b 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 ed43258cd91..ee282e66e86 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1389,6 +1389,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] 43+ messages in thread* [PATCH v8] target/hexagon: Add TCG overrides for thread ctl
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (24 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add TCG overrides for int handler insts Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
` (9 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 4cbbdd1f70b..8650f64a6d4 100644
--- a/target/hexagon/gen_tcg_sys.h
+++ b/target/hexagon/gen_tcg_sys.h
@@ -77,4 +77,22 @@
} \
} 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 ee282e66e86..da00dfd65c3 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1419,6 +1419,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] 43+ messages in thread* [PATCH v8] target/hexagon: Add TCG overrides for rte, nmi
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (25 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add TCG overrides for thread ctl Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add sreg_{read,write} helpers Brian Cain
` (8 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 | 16 ++++++++++++++++
target/hexagon/helper.h | 3 +++
target/hexagon/sys_macros.h | 3 +++
target/hexagon/op_helper.c | 6 ++++++
4 files changed, 28 insertions(+)
diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
index 8650f64a6d4..264ea02752d 100644
--- a/target/hexagon/gen_tcg_sys.h
+++ b/target/hexagon/gen_tcg_sys.h
@@ -95,4 +95,20 @@
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)
+
#endif
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 682f0c6c26e..0ec3a099cb6 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -127,4 +127,7 @@ 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_1(resched, void, env)
+DEF_HELPER_3(modify_ssr, void, env, i32, i32)
+DEF_HELPER_1(pending_interrupt, void, env)
#endif
diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h
index f497d55bb81..09d78b002e6 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -234,4 +234,7 @@
#define NUM_TLB_REGS(x) (hexagon_tlb_get_num_entries(env_archcpu(env)->tlb))
+/* NMI routing not yet implemented; Y4_nmi is a no-op for now */
+#define fDO_NMI(THREAD_MASK) do { } while (0)
+
#endif
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index da00dfd65c3..82d016196df 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1479,6 +1479,12 @@ void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio)
g_assert_not_reached();
}
+
+void HELPER(pending_interrupt)(CPUHexagonState *env)
+{
+ BQL_LOCK_GUARD();
+ hex_interrupt_update(env);
+}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 43+ messages in thread* [PATCH v8] target/hexagon: Add sreg_{read,write} helpers
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (26 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-08-14 17:33 ` Philippe Mathieu-Daudé
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add representation to count cycles Brian Cain
` (7 subsequent siblings)
35 siblings, 1 reply; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 | 354 ++++++++++++++++++++++++++++++++++++
target/hexagon/op_helper.c | 33 +++-
3 files changed, 384 insertions(+), 4 deletions(-)
create mode 100644 target/hexagon/cpu_helper.c
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 3059196bcac..a08083ea290 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -334,7 +334,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..a2b486f4bb5
--- /dev/null
+++ b/target/hexagon/cpu_helper.c
@@ -0,0 +1,354 @@
+/*
+ * 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 "hw/hexagon/hexagon_globalreg.h"
+#include "hex_interrupts.h"
+#include "hex_mmu.h"
+#include "system/runstate.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 val)
+{
+ g_assert_not_reached();
+}
+
+void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t val)
+{
+ g_assert_not_reached();
+}
+
+void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t val)
+{
+ g_assert_not_reached();
+}
+
+static void hexagon_resume_thread(CPUHexagonState *env)
+{
+ CPUState *cs = env_cpu(env);
+ clear_wait_mode(env);
+ /*
+ * The wait instruction keeps the PC pointing to itself
+ * so that it has an opportunity to check for interrupts.
+ *
+ * When we come out of wait mode, adjust the PC to the
+ * next executable instruction.
+ */
+ env->gpr[HEX_REG_PC] = env->wait_next_pc;
+ cs = env_cpu(env);
+ ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
+ cs->halted = false;
+ cs->exception_index = HEX_EVENT_NONE;
+ qemu_cpu_kick(cs);
+}
+
+void hexagon_resume_threads(CPUHexagonState *current_env, uint32_t mask)
+{
+ CPUState *cs;
+ CPUHexagonState *env;
+
+ g_assert(bql_locked());
+ CPU_FOREACH(cs) {
+ env = cpu_env(cs);
+ g_assert(env->threadId < THREADS_MAX);
+ if ((mask & (0x1 << env->threadId))) {
+ if (get_exe_mode(env) == HEX_EXE_MODE_WAIT) {
+ hexagon_resume_thread(env);
+ }
+ }
+ }
+}
+
+void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
+{
+ bool old_EX, old_UM, old_GM, old_IE;
+ bool new_EX, new_UM, new_GM, new_IE;
+ uint8_t old_asid, new_asid;
+
+ g_assert(bql_locked());
+
+ old_EX = GET_SSR_FIELD(SSR_EX, old);
+ old_UM = GET_SSR_FIELD(SSR_UM, old);
+ old_GM = GET_SSR_FIELD(SSR_GM, old);
+ old_IE = GET_SSR_FIELD(SSR_IE, old);
+ new_EX = GET_SSR_FIELD(SSR_EX, new);
+ new_UM = GET_SSR_FIELD(SSR_UM, new);
+ new_GM = GET_SSR_FIELD(SSR_GM, new);
+ new_IE = GET_SSR_FIELD(SSR_IE, new);
+
+ if ((old_EX != new_EX) ||
+ (old_UM != new_UM) ||
+ (old_GM != new_GM)) {
+ hex_mmu_mode_change(env);
+ }
+
+ old_asid = GET_SSR_FIELD(SSR_ASID, old);
+ new_asid = GET_SSR_FIELD(SSR_ASID, new);
+ if (new_asid != old_asid) {
+ CPUState *cs = env_cpu(env);
+ tlb_flush(cs);
+ }
+
+ /* See if the interrupts have been enabled or we have exited EX mode */
+ if ((new_IE && !old_IE) ||
+ (!new_EX && old_EX)) {
+ hex_interrupt_update(env);
+ }
+}
+
+void clear_wait_mode(CPUHexagonState *env)
+{
+ HexagonCPU *cpu;
+ uint32_t modectl, thread_wait_mask;
+
+ g_assert(bql_locked());
+
+ cpu = env_archcpu(env);
+ if (cpu->globalregs) {
+ modectl =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+ env->threadId);
+ 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);
+ }
+}
+
+void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause)
+{
+ uint32_t old, new;
+
+ g_assert(bql_locked());
+
+ old = env->t_sreg[HEX_SREG_SSR];
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, 1);
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause);
+ new = env->t_sreg[HEX_SREG_SSR];
+
+ hexagon_modify_ssr(env, new, old);
+}
+
+
+int get_exe_mode(CPUHexagonState *env)
+{
+ HexagonCPU *cpu;
+ uint32_t modectl, thread_enabled_mask, thread_wait_mask;
+ uint32_t isdbst, debugmode;
+ bool E_bit, W_bit, D_bit;
+
+ g_assert(bql_locked());
+
+ cpu = env_archcpu(env);
+ modectl = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+ env->threadId) : 0;
+ thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
+ E_bit = thread_enabled_mask & (0x1 << env->threadId);
+ thread_wait_mask = GET_FIELD(MODECTL_W, modectl);
+ W_bit = thread_wait_mask & (0x1 << env->threadId);
+ isdbst = cpu->globalregs ?
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_ISDBST,
+ env->threadId) : 0;
+ debugmode = GET_FIELD(ISDBST_DEBUGMODE, isdbst);
+ D_bit = debugmode & (0x1 << env->threadId);
+
+ if (!D_bit && !W_bit && !E_bit) {
+ return HEX_EXE_MODE_OFF;
+ }
+ if (!D_bit && !W_bit && E_bit) {
+ return HEX_EXE_MODE_RUN;
+ }
+ if (!D_bit && W_bit && E_bit) {
+ return HEX_EXE_MODE_WAIT;
+ }
+ if (D_bit && !W_bit && E_bit) {
+ return HEX_EXE_MODE_DEBUG;
+ }
+ g_assert_not_reached();
+}
+
+static uint32_t set_enable_mask(CPUHexagonState *env)
+{
+ HexagonCPU *cpu;
+ uint32_t modectl, thread_enabled_mask;
+
+ g_assert(bql_locked());
+
+ cpu = env_archcpu(env);
+ if (!cpu->globalregs) {
+ return 0;
+ }
+ modectl =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+ env->threadId);
+ thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
+ thread_enabled_mask |= 0x1 << env->threadId;
+ SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask);
+ return thread_enabled_mask;
+}
+
+static uint32_t clear_enable_mask(CPUHexagonState *env)
+{
+ HexagonCPU *cpu;
+ uint32_t modectl, thread_enabled_mask;
+
+ g_assert(bql_locked());
+
+ cpu = env_archcpu(env);
+ if (!cpu->globalregs) {
+ return 0;
+ }
+ modectl =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+ env->threadId);
+ thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
+ thread_enabled_mask &= ~(0x1 << env->threadId);
+ SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask);
+ return thread_enabled_mask;
+}
+static void do_start_thread(CPUState *cs, run_on_cpu_data tbd)
+{
+ CPUHexagonState *env;
+
+ BQL_LOCK_GUARD();
+
+ env = cpu_env(cs);
+
+ hexagon_cpu_soft_reset(env);
+
+ set_enable_mask(env);
+
+ cs->halted = 0;
+ cs->exception_index = HEX_EVENT_NONE;
+ cpu_resume(cs);
+}
+
+void hexagon_start_threads(CPUHexagonState *current_env, uint32_t mask)
+{
+ CPUState *cs;
+ CPU_FOREACH(cs) {
+ CPUHexagonState *env = cpu_env(cs);
+ if (!(mask & (0x1 << env->threadId))) {
+ continue;
+ }
+
+ if (current_env->threadId != env->threadId) {
+ async_safe_run_on_cpu(cs, do_start_thread, RUN_ON_CPU_NULL);
+ }
+ }
+}
+
+/*
+ * When we have all threads stopped, the return
+ * value to the shell is register 2 from thread 0.
+ */
+static uint32_t get_thread0_r2(void)
+{
+ CPUState *cs;
+ CPU_FOREACH(cs) {
+ CPUHexagonState *thread = cpu_env(cs);
+ if (thread->threadId == 0) {
+ return thread->gpr[2];
+ }
+ }
+ g_assert_not_reached();
+}
+
+void hexagon_stop_thread(CPUHexagonState *env)
+{
+ uint32_t thread_enabled_mask;
+ CPUState *cs;
+
+ BQL_LOCK_GUARD();
+
+ thread_enabled_mask = clear_enable_mask(env);
+ cs = env_cpu(env);
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+ if (!thread_enabled_mask) {
+ /* All threads are stopped, request shutdown */
+ qemu_system_shutdown_request_with_code(
+ SHUTDOWN_CAUSE_GUEST_SHUTDOWN, get_thread0_r2());
+ }
+}
+
+static int sys_in_monitor_mode_ssr(uint32_t ssr)
+{
+ if ((GET_SSR_FIELD(SSR_EX, ssr) != 0) ||
+ ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
+ (GET_SSR_FIELD(SSR_UM, ssr) == 0))) {
+ return 1;
+ }
+ return 0;
+}
+
+static int sys_in_guest_mode_ssr(uint32_t ssr)
+{
+ if ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
+ (GET_SSR_FIELD(SSR_UM, ssr) != 0) &&
+ (GET_SSR_FIELD(SSR_GM, ssr) != 0)) {
+ return 1;
+ }
+ return 0;
+}
+
+static int sys_in_user_mode_ssr(uint32_t ssr)
+{
+ if ((GET_SSR_FIELD(SSR_EX, ssr) == 0) &&
+ (GET_SSR_FIELD(SSR_UM, ssr) != 0) &&
+ (GET_SSR_FIELD(SSR_GM, ssr) == 0)) {
+ return 1;
+ }
+ return 0;
+}
+
+int get_cpu_mode(CPUHexagonState *env)
+{
+ uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
+
+ if (sys_in_monitor_mode_ssr(ssr)) {
+ return HEX_CPU_MODE_MONITOR;
+ } else if (sys_in_guest_mode_ssr(ssr)) {
+ return HEX_CPU_MODE_GUEST;
+ } else if (sys_in_user_mode_ssr(ssr)) {
+ return HEX_CPU_MODE_USER;
+ }
+ return HEX_CPU_MODE_MONITOR;
+}
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 82d016196df..706cb0a5d9f 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -19,6 +19,7 @@
#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"
@@ -1451,17 +1452,43 @@ 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)
+{
+ HexagonCPU *cpu;
+
+ g_assert(bql_locked());
+ if (reg < HEX_SREG_GLB_START) {
+ return env->t_sreg[reg];
+ }
+ 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] 43+ messages in thread* Re: [PATCH v8] target/hexagon: Add sreg_{read,write} helpers
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add sreg_{read,write} helpers Brian Cain
@ 2026-08-14 17:33 ` Philippe Mathieu-Daudé
2026-08-18 19:51 ` Brian Cain
0 siblings, 1 reply; 43+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-14 17:33 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: matheus.bernardino, pierrick.bouvier, ltaylorsimpson, philmd,
Brian Cain, Sid Manning
Hi,
(merged as 9b63a54dd2c0ea9a667c9e9dc662755b9feffa7e)
On 11/6/26 07:28, 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 | 354 ++++++++++++++++++++++++++++++++++++
> target/hexagon/op_helper.c | 33 +++-
> 3 files changed, 384 insertions(+), 4 deletions(-)
> create mode 100644 target/hexagon/cpu_helper.c
> +static void hexagon_resume_thread(CPUHexagonState *env)
> +{
> + CPUState *cs = env_cpu(env);
> + clear_wait_mode(env);
> + /*
> + * The wait instruction keeps the PC pointing to itself
> + * so that it has an opportunity to check for interrupts.
> + *
> + * When we come out of wait mode, adjust the PC to the
> + * next executable instruction.
> + */
> + env->gpr[HEX_REG_PC] = env->wait_next_pc;
> + cs = env_cpu(env);
> + ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
> + cs->halted = false;
> + cs->exception_index = HEX_EVENT_NONE;
> + qemu_cpu_kick(cs);
Why not call cpu_resume()?
If you don't mind I'll send a patch to clean that up.
> +}
^ permalink raw reply [flat|nested] 43+ messages in thread* Re: [PATCH v8] target/hexagon: Add sreg_{read,write} helpers
2026-08-14 17:33 ` Philippe Mathieu-Daudé
@ 2026-08-18 19:51 ` Brian Cain
0 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-08-18 19:51 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: matheus.bernardino, pierrick.bouvier, ltaylorsimpson, philmd,
Brian Cain, Sid Manning
On 8/14/2026 12:33 PM, Philippe Mathieu-Daudé wrote:
> Hi,
>
> (merged as 9b63a54dd2c0ea9a667c9e9dc662755b9feffa7e)
>
> On 11/6/26 07:28, 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 | 354 ++++++++++++++++++++++++++++++++++++
>> target/hexagon/op_helper.c | 33 +++-
>> 3 files changed, 384 insertions(+), 4 deletions(-)
>> create mode 100644 target/hexagon/cpu_helper.c
>
>
>> +static void hexagon_resume_thread(CPUHexagonState *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + clear_wait_mode(env);
>> + /*
>> + * The wait instruction keeps the PC pointing to itself
>> + * so that it has an opportunity to check for interrupts.
>> + *
>> + * When we come out of wait mode, adjust the PC to the
>> + * next executable instruction.
>> + */
>> + env->gpr[HEX_REG_PC] = env->wait_next_pc;
>> + cs = env_cpu(env);
>> + ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
>> + cs->halted = false;
>> + cs->exception_index = HEX_EVENT_NONE;
>> + qemu_cpu_kick(cs);
>
> Why not call cpu_resume()?
>
> If you don't mind I'll send a patch to clean that up.
Sure - that seems reasonable.
Thanks!
>
>> +}
>
^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH v8] target/hexagon: Add representation to count cycles
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (27 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add sreg_{read,write} helpers Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add implementation of cycle counters Brian Cain
` (6 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd
Add t_cycle_count to CPUArchState for tracking processor
cycle counts in system emulation.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 4bea953ac73..2540458b370 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -110,6 +110,7 @@ typedef struct CPUArchState {
/* This alias of CPUState.cpu_index is used by imported sources: */
uint32_t threadId;
+ uint64_t t_cycle_count;
#endif
target_ulong new_value_usr;
--
2.34.1
^ permalink raw reply related [flat|nested] 43+ messages in thread* [PATCH v8] target/hexagon: Add implementation of cycle counters
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (28 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add representation to count cycles Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add pcycle setting functionality Brian Cain
` (5 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd
Add cycle counting infrastructure for system emulation:
- PCYCLE_ENABLED TB flag to gate cycle counting
- gen_pcycle_counters() to emit cycle count increments
- Real implementations replacing pcycle stubs in cpu_helper.c
- hex_cycle_count TCG global for t_cycle_count
- pcycle_enabled context field in DisasContext
All pcycle code is guarded by #ifndef CONFIG_USER_ONLY.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 1 +
target/hexagon/translate.h | 3 +++
target/hexagon/cpu.c | 4 ++++
target/hexagon/cpu_helper.c | 14 +++++++++++---
target/hexagon/translate.c | 26 ++++++++++++++++++++++++++
5 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 2540458b370..ddf6da78c18 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -164,6 +164,7 @@ struct ArchCPU {
#include "cpu_bits.h"
FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1)
+FIELD(TB_FLAGS, PCYCLE_ENABLED, 4, 1)
G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
uint32_t exception,
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 57767acf002..208cf141e7e 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -85,6 +85,9 @@ typedef struct DisasContext {
TCGv new_pred_value[NUM_PREGS];
TCGv branch_taken;
TCGv dczero_addr;
+ bool pcycle_enabled;
+ bool pkt_ends_tb;
+ uint32_t num_cycles;
} DisasContext;
bool is_gather_store_insn(DisasContext *ctx);
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index a08083ea290..0773ef8fe79 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -268,6 +268,10 @@ 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, PCYCLE_ENABLED, 1);
+#endif
+
return (TCGTBCPUState){ .pc = pc, .flags = hex_flags };
}
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index a2b486f4bb5..bb991a671e8 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -33,17 +33,25 @@ uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index)
uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env)
{
- g_assert_not_reached();
+ uint64_t total = 0;
+ CPUState *cs;
+
+ g_assert(bql_locked());
+ CPU_FOREACH(cs) {
+ CPUHexagonState *thread_env = cpu_env(cs);
+ total += thread_env->t_cycle_count;
+ }
+ return total;
}
uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env)
{
- g_assert_not_reached();
+ return (uint32_t)(hexagon_get_sys_pcycle_count(env) >> 32);
}
uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env)
{
- g_assert_not_reached();
+ return (uint32_t)(hexagon_get_sys_pcycle_count(env));
}
void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t val)
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 97849ab861a..ed96d9a66b3 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -61,6 +61,9 @@ TCGv_i64 hex_store_val64[STORES_MAX];
TCGv hex_llsc_addr;
TCGv hex_llsc_val;
TCGv_i64 hex_llsc_val_i64;
+#ifndef CONFIG_USER_ONLY
+TCGv_i64 hex_cycle_count;
+#endif
TCGv hex_vstore_addr[VSTORES_MAX];
TCGv hex_vstore_size[VSTORES_MAX];
TCGv hex_vstore_pending[VSTORES_MAX];
@@ -128,6 +131,15 @@ static void gen_exception_raw(int excp)
gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp));
}
+#ifndef CONFIG_USER_ONLY
+static void gen_pcycle_counters(DisasContext *ctx)
+{
+ if (ctx->pcycle_enabled) {
+ tcg_gen_addi_i64(hex_cycle_count, hex_cycle_count, ctx->num_cycles);
+ }
+}
+#endif
+
static void gen_exec_counters(DisasContext *ctx)
{
tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT],
@@ -136,6 +148,9 @@ static void gen_exec_counters(DisasContext *ctx)
hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns);
tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_HVX_CNT],
hex_gpr[HEX_REG_QEMU_HVX_CNT], ctx->num_hvx_insns);
+#ifndef CONFIG_USER_ONLY
+ gen_pcycle_counters(ctx);
+#endif
}
static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
@@ -810,6 +825,8 @@ static void gen_commit_hvx(DisasContext *ctx)
}
}
+#define PCYCLES_PER_PACKET 1
+
static void update_exec_counters(DisasContext *ctx)
{
int num_real_insns = 0;
@@ -829,6 +846,7 @@ static void update_exec_counters(DisasContext *ctx)
ctx->num_packets++;
ctx->num_insns += num_real_insns;
ctx->num_hvx_insns += num_hvx_insns;
+ ctx->num_cycles += PCYCLES_PER_PACKET;
}
static void gen_commit_packet(DisasContext *ctx)
@@ -978,6 +996,10 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase,
ctx->is_tight_loop = FIELD_EX32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP);
ctx->short_circuit = hex_cpu->short_circuit;
ctx->hex_def = HEXAGON_CPU_GET_CLASS(hex_cpu)->hex_def;
+#ifndef CONFIG_USER_ONLY
+ ctx->num_cycles = 0;
+ ctx->pcycle_enabled = FIELD_EX32(hex_flags, TB_FLAGS, PCYCLE_ENABLED);
+#endif
}
static void hexagon_tr_tb_start(DisasContextBase *db, CPUState *cpu)
@@ -1121,6 +1143,10 @@ void hexagon_translate_init(void)
offsetof(CPUHexagonState, llsc_val), "llsc_val");
hex_llsc_val_i64 = tcg_global_mem_new_i64(tcg_env,
offsetof(CPUHexagonState, llsc_val_i64), "llsc_val_i64");
+#ifndef CONFIG_USER_ONLY
+ hex_cycle_count = tcg_global_mem_new_i64(tcg_env,
+ offsetof(CPUHexagonState, t_cycle_count), "t_cycle_count");
+#endif
for (i = 0; i < STORES_MAX; i++) {
snprintf(store_addr_names[i], NAME_LEN, "store_addr_%d", i);
hex_store_addr[i] = tcg_global_mem_new(tcg_env,
--
2.34.1
^ permalink raw reply related [flat|nested] 43+ messages in thread* [PATCH v8] target/hexagon: Add pcycle setting functionality
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (29 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add implementation of cycle counters Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add cpu modes, mmu indices, next_PC to state Brian Cain
` (4 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd
Replace pcycle set stubs with real implementations that
distribute cycle count changes across all active threads.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu_helper.c | 43 ++++++++++++++++++++++++++++++++++---
1 file changed, 40 insertions(+), 3 deletions(-)
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index bb991a671e8..64c5746c6d9 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -56,17 +56,54 @@ uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env)
void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t val)
{
- g_assert_not_reached();
+ uint64_t old;
+
+ g_assert(bql_locked());
+ old = hexagon_get_sys_pcycle_count(env);
+ old = deposit64(old, 32, 32, val);
+ hexagon_set_sys_pcycle_count(env, old);
}
void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t val)
{
- g_assert_not_reached();
+ uint64_t old;
+
+ g_assert(bql_locked());
+ old = hexagon_get_sys_pcycle_count(env);
+ old = deposit64(old, 0, 32, val);
+ hexagon_set_sys_pcycle_count(env, old);
}
void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t val)
{
- g_assert_not_reached();
+ CPUState *cs;
+ uint64_t total;
+ int num_threads;
+ int64_t delta, per_thread, remainder;
+
+ g_assert(bql_locked());
+ total = hexagon_get_sys_pcycle_count(env);
+
+ /* Count active threads */
+ num_threads = 0;
+ CPU_FOREACH(cs) {
+ num_threads++;
+ }
+ g_assert(num_threads > 0);
+
+ /*
+ * Distribute the delta evenly across all threads.
+ * Any remainder goes to the calling thread.
+ */
+ delta = (int64_t)(val - total);
+ per_thread = delta / num_threads;
+ remainder = delta - per_thread * num_threads;
+
+ CPU_FOREACH(cs) {
+ CPUHexagonState *thread_env = cpu_env(cs);
+ thread_env->t_cycle_count += per_thread;
+ }
+ env->t_cycle_count += remainder;
}
static void hexagon_resume_thread(CPUHexagonState *env)
--
2.34.1
^ permalink raw reply related [flat|nested] 43+ messages in thread* [PATCH v8] target/hexagon: Add cpu modes, mmu indices, next_PC to state
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (30 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add pcycle setting functionality Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] hw/hexagon: Declare hexagon TLB device interface Brian Cain
` (3 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, Brian Cain
From: Brian Cain <bcain@quicinc.com>
Add cpu execution mode (user/supervisor/guest), MMU index, and next_PC
to DisasContext and translation state. Declare the MMU_INDEX bit field
in TB_FLAGS and use it to propagate the mmu index into translations.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 22 +++++++++++++++++++++-
target/hexagon/cpu.c | 1 +
target/hexagon/translate.c | 2 +-
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index ddf6da78c18..7ba1d3047df 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -49,8 +49,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
@@ -112,6 +130,7 @@ typedef struct CPUArchState {
uint32_t threadId;
uint64_t t_cycle_count;
#endif
+ uint32_t next_PC;
target_ulong new_value_usr;
MemLog mem_log_stores[STORES_MAX];
@@ -164,6 +183,7 @@ struct ArchCPU {
#include "cpu_bits.h"
FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1)
+FIELD(TB_FLAGS, MMU_INDEX, 1, 3)
FIELD(TB_FLAGS, PCYCLE_ENABLED, 4, 1)
G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 0773ef8fe79..626100d43fd 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -307,6 +307,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;
}
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index ed96d9a66b3..ce5bbe92d5d 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -988,7 +988,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] 43+ messages in thread* [PATCH v8] hw/hexagon: Declare hexagon TLB device interface
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (31 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add cpu modes, mmu indices, next_PC to state Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode Brian Cain
` (2 subsequent siblings)
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd
Add the hexagon TLB device interface header.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/hw/hexagon/hexagon_tlb.h | 46 ++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 include/hw/hexagon/hexagon_tlb.h
diff --git a/include/hw/hexagon/hexagon_tlb.h b/include/hw/hexagon/hexagon_tlb.h
new file mode 100644
index 00000000000..90d9ed84043
--- /dev/null
+++ b/include/hw/hexagon/hexagon_tlb.h
@@ -0,0 +1,46 @@
+/*
+ * 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"
+#include "monitor/monitor.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(Monitor *mon, HexagonTLBState *tlb);
+
+bool hexagon_tlb_dump_entry(Monitor *mon, uint64_t entry);
+
+uint32_t hexagon_tlb_get_num_entries(HexagonTLBState *tlb);
+
+#endif /* HW_HEXAGON_TLB_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 43+ messages in thread* [PATCH v8] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (32 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] hw/hexagon: Declare hexagon TLB device interface Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-17 15:03 ` Pierrick Bouvier
2026-08-12 6:59 ` Marc-André Lureau
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add hex_interrupts support Brian Cain
35 siblings, 2 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd
Add hex_mmu.[ch], cpu mode helpers, and additional includes/stubs
that integrate the TLB device with the CPU model.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu-param.h | 2 +-
target/hexagon/cpu.h | 21 +++
target/hexagon/hex_mmu.h | 26 ++++
target/hexagon/internal.h | 9 ++
target/hexagon/sys_macros.h | 3 +
target/hexagon/cpu.c | 36 +++++
target/hexagon/hex_mmu.c | 268 ++++++++++++++++++++++++++++++++++++
7 files changed, 364 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..bfe9a868d63 100644
--- a/target/hexagon/cpu-param.h
+++ b/target/hexagon/cpu-param.h
@@ -18,7 +18,7 @@
#ifndef HEXAGON_CPU_PARAM_H
#define HEXAGON_CPU_PARAM_H
-#define TARGET_PAGE_BITS 16 /* 64K pages */
+#define TARGET_PAGE_BITS 12 /* 4K pages */
#define TARGET_VIRT_ADDR_SPACE_BITS 32
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 7ba1d3047df..dbdc456d732 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -27,6 +27,9 @@
#define SREG_WRITES_MAX 2
#endif
+typedef struct HexagonTLBState HexagonTLBState;
+typedef struct HexagonGlobalRegState HexagonGlobalRegState;
+
#include "cpu-qom.h"
#include "exec/cpu-common.h"
#include "exec/target_long.h"
@@ -39,6 +42,7 @@
#error "Hexagon does not support system emulation"
#endif
+
#define NUM_PREGS 4
#define TOTAL_PER_THREAD_REGS 64
@@ -47,10 +51,13 @@
#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
#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 +74,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 +141,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;
uint64_t t_cycle_count;
#endif
uint32_t next_PC;
@@ -178,6 +195,10 @@ struct ArchCPU {
bool lldb_compat;
target_ulong lldb_stack_adjust;
bool short_circuit;
+#ifndef CONFIG_USER_ONLY
+ HexagonTLBState *tlb;
+ uint32_t htid;
+#endif
};
#include "cpu_bits.h"
diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h
new file mode 100644
index 00000000000..4f556c715a9
--- /dev/null
+++ b/target/hexagon/hex_mmu.h
@@ -0,0 +1,26 @@
+/*
+ * 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"
+#include "monitor/monitor.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(Monitor *mon, 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 09d78b002e6..8b81e1ca0af 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 626100d43fd..73aca0a4217 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -23,9 +23,17 @@
#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"
+#include "cpu_helper.h"
+#include "hex_mmu.h"
+
+#ifndef CONFIG_USER_ONLY
+#include "sys_macros.h"
+#include "accel/tcg/cpu-ldst.h"
+#endif
static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
{
@@ -43,6 +51,11 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
}
static const Property hexagon_cpu_properties[] = {
+#ifndef 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,
qdev_prop_uint32, target_ulong),
@@ -269,7 +282,11 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
}
#ifndef CONFIG_USER_ONLY
+ hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
+ cpu_mmu_index(env_cpu(env), false));
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1);
+#else
+ hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
#endif
return (TCGTBCPUState){ .pc = pc, .flags = hex_flags };
@@ -289,11 +306,15 @@ 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);
HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(obj);
CPUHexagonState *env = cpu_env(cs);
+#ifndef CONFIG_USER_ONLY
+ HexagonCPU *cpu = HEXAGON_CPU(cs);
+#endif
if (mcc->parent_phases.hold) {
mcc->parent_phases.hold(obj, type);
@@ -307,7 +328,14 @@ 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;
+
+ env->t_sreg[HEX_SREG_HTID] = cpu->htid;
+ env->threadId = cpu->htid;
#endif
env->cause_code = HEX_EVENT_NONE;
}
@@ -337,7 +365,15 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
hexagon_hvx_gdb_write_register,
gdb_find_static_feature("hexagon-hvx.xml"));
+#ifndef CONFIG_USER_ONLY
+ if (!HEXAGON_CPU(dev)->tlb) {
+ error_setg(errp, "hexagon cpu requires 'tlb' link property to be set");
+ return;
+ }
+#endif
+
qemu_init_vcpu(cs);
+
cpu_reset(cs);
mcc->parent_realize(dev, errp);
}
diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c
new file mode 100644
index 00000000000..c921e82b377
--- /dev/null
+++ b/target/hexagon/hex_mmu.c
@@ -0,0 +1,268 @@
+/*
+ * 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)
+{
+ qemu_log_mask(CPU_LOG_MMU,
+ "tlbw[%03" PRIu32 "]: 0x%016" PRIx64 "\n",
+ index, entry);
+}
+
+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(Monitor *mon, CPUHexagonState *env)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ hexagon_tlb_dump(mon, 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 = %" PRIu32 ": %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%" PRIx32 ", 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 %" PRIu32 " 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");
+ }
+
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 43+ messages in thread* Re: [PATCH v8] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode Brian Cain
@ 2026-06-17 15:03 ` Pierrick Bouvier
2026-08-12 6:59 ` Marc-André Lureau
1 sibling, 0 replies; 43+ messages in thread
From: Pierrick Bouvier @ 2026-06-17 15:03 UTC (permalink / raw)
To: Brian Cain, qemu-devel; +Cc: matheus.bernardino, ltaylorsimpson, philmd, philmd
On 6/10/2026 10:28 PM, Brian Cain wrote:
> Add hex_mmu.[ch], cpu mode helpers, and additional includes/stubs
> that integrate the TLB device with the CPU model.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/cpu-param.h | 2 +-
> target/hexagon/cpu.h | 21 +++
> target/hexagon/hex_mmu.h | 26 ++++
> target/hexagon/internal.h | 9 ++
> target/hexagon/sys_macros.h | 3 +
> target/hexagon/cpu.c | 36 +++++
> target/hexagon/hex_mmu.c | 268 ++++++++++++++++++++++++++++++++++++
> 7 files changed, 364 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..bfe9a868d63 100644
> --- a/target/hexagon/cpu-param.h
> +++ b/target/hexagon/cpu-param.h
> @@ -18,7 +18,7 @@
> #ifndef HEXAGON_CPU_PARAM_H
> #define HEXAGON_CPU_PARAM_H
>
> -#define TARGET_PAGE_BITS 16 /* 64K pages */
> +#define TARGET_PAGE_BITS 12 /* 4K pages */
>
For information and people reviewing this series, this change has been
tested internally with our test suite, for user and system mode.
> #define TARGET_VIRT_ADDR_SPACE_BITS 32
>
> diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
> index 7ba1d3047df..dbdc456d732 100644
> --- a/target/hexagon/cpu.h
> +++ b/target/hexagon/cpu.h
> @@ -27,6 +27,9 @@
> #define SREG_WRITES_MAX 2
> #endif
>
> +typedef struct HexagonTLBState HexagonTLBState;
> +typedef struct HexagonGlobalRegState HexagonGlobalRegState;
> +
> #include "cpu-qom.h"
> #include "exec/cpu-common.h"
> #include "exec/target_long.h"
> @@ -39,6 +42,7 @@
> #error "Hexagon does not support system emulation"
> #endif
>
> +
> #define NUM_PREGS 4
> #define TOTAL_PER_THREAD_REGS 64
>
> @@ -47,10 +51,13 @@
> #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
> #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 +74,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 +141,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;
> uint64_t t_cycle_count;
> #endif
> uint32_t next_PC;
> @@ -178,6 +195,10 @@ struct ArchCPU {
> bool lldb_compat;
> target_ulong lldb_stack_adjust;
> bool short_circuit;
> +#ifndef CONFIG_USER_ONLY
> + HexagonTLBState *tlb;
> + uint32_t htid;
> +#endif
> };
>
> #include "cpu_bits.h"
> diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h
> new file mode 100644
> index 00000000000..4f556c715a9
> --- /dev/null
> +++ b/target/hexagon/hex_mmu.h
> @@ -0,0 +1,26 @@
> +/*
> + * 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"
> +#include "monitor/monitor.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(Monitor *mon, 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 09d78b002e6..8b81e1ca0af 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 626100d43fd..73aca0a4217 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -23,9 +23,17 @@
> #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"
> +#include "cpu_helper.h"
> +#include "hex_mmu.h"
> +
> +#ifndef CONFIG_USER_ONLY
> +#include "sys_macros.h"
> +#include "accel/tcg/cpu-ldst.h"
> +#endif
>
> static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
> {
> @@ -43,6 +51,11 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
> }
>
> static const Property hexagon_cpu_properties[] = {
> +#ifndef 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,
> qdev_prop_uint32, target_ulong),
> @@ -269,7 +282,11 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
> }
>
> #ifndef CONFIG_USER_ONLY
> + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
> + cpu_mmu_index(env_cpu(env), false));
> hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1);
> +#else
> + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
> #endif
>
> return (TCGTBCPUState){ .pc = pc, .flags = hex_flags };
> @@ -289,11 +306,15 @@ 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);
> HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(obj);
> CPUHexagonState *env = cpu_env(cs);
> +#ifndef CONFIG_USER_ONLY
> + HexagonCPU *cpu = HEXAGON_CPU(cs);
> +#endif
>
> if (mcc->parent_phases.hold) {
> mcc->parent_phases.hold(obj, type);
> @@ -307,7 +328,14 @@ 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;
> +
> + env->t_sreg[HEX_SREG_HTID] = cpu->htid;
> + env->threadId = cpu->htid;
> #endif
> env->cause_code = HEX_EVENT_NONE;
> }
> @@ -337,7 +365,15 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
> hexagon_hvx_gdb_write_register,
> gdb_find_static_feature("hexagon-hvx.xml"));
>
> +#ifndef CONFIG_USER_ONLY
> + if (!HEXAGON_CPU(dev)->tlb) {
> + error_setg(errp, "hexagon cpu requires 'tlb' link property to be set");
> + return;
> + }
> +#endif
> +
> qemu_init_vcpu(cs);
> +
> cpu_reset(cs);
> mcc->parent_realize(dev, errp);
> }
> diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c
> new file mode 100644
> index 00000000000..c921e82b377
> --- /dev/null
> +++ b/target/hexagon/hex_mmu.c
> @@ -0,0 +1,268 @@
> +/*
> + * 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)
> +{
> + qemu_log_mask(CPU_LOG_MMU,
> + "tlbw[%03" PRIu32 "]: 0x%016" PRIx64 "\n",
> + index, entry);
> +}
> +
> +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(Monitor *mon, CPUHexagonState *env)
> +{
> + HexagonCPU *cpu = env_archcpu(env);
> + hexagon_tlb_dump(mon, 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 = %" PRIu32 ": %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%" PRIx32 ", 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 %" PRIu32 " 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");
> + }
> +
> +}
For the rest, it looks good to me.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Regards,
Pierrick
^ permalink raw reply [flat|nested] 43+ messages in thread* Re: [PATCH v8] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode Brian Cain
2026-06-17 15:03 ` Pierrick Bouvier
@ 2026-08-12 6:59 ` Marc-André Lureau
2026-08-12 9:39 ` Philippe Mathieu-Daudé
1 sibling, 1 reply; 43+ messages in thread
From: Marc-André Lureau @ 2026-08-12 6:59 UTC (permalink / raw)
To: Brian Cain
Cc: qemu-devel, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd
Hi Brian
On Thu, Jun 11, 2026 at 9:31 AM Brian Cain <brian.cain@oss.qualcomm.com> wrote:
>
> Add hex_mmu.[ch], cpu mode helpers, and additional includes/stubs
> that integrate the TLB device with the CPU model.
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/cpu-param.h | 2 +-
> target/hexagon/cpu.h | 21 +++
> target/hexagon/hex_mmu.h | 26 ++++
> target/hexagon/internal.h | 9 ++
> target/hexagon/sys_macros.h | 3 +
> target/hexagon/cpu.c | 36 +++++
> target/hexagon/hex_mmu.c | 268 ++++++++++++++++++++++++++++++++++++
> 7 files changed, 364 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..bfe9a868d63 100644
> --- a/target/hexagon/cpu-param.h
> +++ b/target/hexagon/cpu-param.h
> @@ -18,7 +18,7 @@
> #ifndef HEXAGON_CPU_PARAM_H
> #define HEXAGON_CPU_PARAM_H
>
> -#define TARGET_PAGE_BITS 16 /* 64K pages */
> +#define TARGET_PAGE_BITS 12 /* 4K pages */
>
> #define TARGET_VIRT_ADDR_SPACE_BITS 32
>
> diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
> index 7ba1d3047df..dbdc456d732 100644
> --- a/target/hexagon/cpu.h
> +++ b/target/hexagon/cpu.h
> @@ -27,6 +27,9 @@
> #define SREG_WRITES_MAX 2
> #endif
>
> +typedef struct HexagonTLBState HexagonTLBState;
> +typedef struct HexagonGlobalRegState HexagonGlobalRegState;
> +
> #include "cpu-qom.h"
> #include "exec/cpu-common.h"
> #include "exec/target_long.h"
> @@ -39,6 +42,7 @@
> #error "Hexagon does not support system emulation"
> #endif
>
> +
> #define NUM_PREGS 4
> #define TOTAL_PER_THREAD_REGS 64
>
> @@ -47,10 +51,13 @@
> #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
> #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 +74,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 +141,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;
> uint64_t t_cycle_count;
> #endif
> uint32_t next_PC;
> @@ -178,6 +195,10 @@ struct ArchCPU {
> bool lldb_compat;
> target_ulong lldb_stack_adjust;
> bool short_circuit;
> +#ifndef CONFIG_USER_ONLY
> + HexagonTLBState *tlb;
> + uint32_t htid;
> +#endif
> };
>
> #include "cpu_bits.h"
> diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h
> new file mode 100644
> index 00000000000..4f556c715a9
> --- /dev/null
> +++ b/target/hexagon/hex_mmu.h
> @@ -0,0 +1,26 @@
> +/*
> + * 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"
> +#include "monitor/monitor.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(Monitor *mon, CPUHexagonState *env);
dump_mmu() is unused, should it be dropped or commented out (and
reintroduced when wired to info tlb?)
> +#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 09d78b002e6..8b81e1ca0af 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 626100d43fd..73aca0a4217 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -23,9 +23,17 @@
> #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"
> +#include "cpu_helper.h"
> +#include "hex_mmu.h"
> +
> +#ifndef CONFIG_USER_ONLY
> +#include "sys_macros.h"
> +#include "accel/tcg/cpu-ldst.h"
> +#endif
>
> static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
> {
> @@ -43,6 +51,11 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
> }
>
> static const Property hexagon_cpu_properties[] = {
> +#ifndef 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,
> qdev_prop_uint32, target_ulong),
> @@ -269,7 +282,11 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
> }
>
> #ifndef CONFIG_USER_ONLY
> + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
> + cpu_mmu_index(env_cpu(env), false));
> hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1);
> +#else
> + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
> #endif
>
> return (TCGTBCPUState){ .pc = pc, .flags = hex_flags };
> @@ -289,11 +306,15 @@ 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);
> HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(obj);
> CPUHexagonState *env = cpu_env(cs);
> +#ifndef CONFIG_USER_ONLY
> + HexagonCPU *cpu = HEXAGON_CPU(cs);
> +#endif
>
> if (mcc->parent_phases.hold) {
> mcc->parent_phases.hold(obj, type);
> @@ -307,7 +328,14 @@ 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;
> +
> + env->t_sreg[HEX_SREG_HTID] = cpu->htid;
> + env->threadId = cpu->htid;
> #endif
> env->cause_code = HEX_EVENT_NONE;
> }
> @@ -337,7 +365,15 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
> hexagon_hvx_gdb_write_register,
> gdb_find_static_feature("hexagon-hvx.xml"));
>
> +#ifndef CONFIG_USER_ONLY
> + if (!HEXAGON_CPU(dev)->tlb) {
> + error_setg(errp, "hexagon cpu requires 'tlb' link property to be set");
> + return;
> + }
> +#endif
> +
> qemu_init_vcpu(cs);
> +
> cpu_reset(cs);
> mcc->parent_realize(dev, errp);
> }
> diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c
> new file mode 100644
> index 00000000000..c921e82b377
> --- /dev/null
> +++ b/target/hexagon/hex_mmu.c
> @@ -0,0 +1,268 @@
> +/*
> + * 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)
> +{
> + qemu_log_mask(CPU_LOG_MMU,
> + "tlbw[%03" PRIu32 "]: 0x%016" PRIx64 "\n",
> + index, entry);
> +}
> +
> +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(Monitor *mon, CPUHexagonState *env)
> +{
> + HexagonCPU *cpu = env_archcpu(env);
> + hexagon_tlb_dump(mon, 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 = %" PRIu32 ": %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%" PRIx32 ", 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 %" PRIu32 " 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");
> + }
> +
> +}
> --
> 2.34.1
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 43+ messages in thread* Re: [PATCH v8] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode
2026-08-12 6:59 ` Marc-André Lureau
@ 2026-08-12 9:39 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 43+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-12 9:39 UTC (permalink / raw)
To: Marc-André Lureau, Brian Cain
Cc: qemu-devel, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd
On 12/8/26 08:59, Marc-André Lureau wrote:
> Hi Brian
>
> On Thu, Jun 11, 2026 at 9:31 AM Brian Cain <brian.cain@oss.qualcomm.com> wrote:
>>
>> Add hex_mmu.[ch], cpu mode helpers, and additional includes/stubs
>> that integrate the TLB device with the CPU model.
>>
>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>> ---
>> target/hexagon/cpu-param.h | 2 +-
>> target/hexagon/cpu.h | 21 +++
>> target/hexagon/hex_mmu.h | 26 ++++
>> target/hexagon/internal.h | 9 ++
>> target/hexagon/sys_macros.h | 3 +
>> target/hexagon/cpu.c | 36 +++++
>> target/hexagon/hex_mmu.c | 268 ++++++++++++++++++++++++++++++++++++
>> 7 files changed, 364 insertions(+), 1 deletion(-)
>> create mode 100644 target/hexagon/hex_mmu.h
>> create mode 100644 target/hexagon/hex_mmu.c
>> diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h
>> new file mode 100644
>> index 00000000000..4f556c715a9
>> --- /dev/null
>> +++ b/target/hexagon/hex_mmu.h
>> @@ -0,0 +1,26 @@
>> +/*
>> + * 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"
>> +#include "monitor/monitor.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(Monitor *mon, CPUHexagonState *env);
>
> dump_mmu() is unused, should it be dropped or commented out (and
> reintroduced when wired to info tlb?)
Indeed we are missing the hmp_info_tlb() binding.
We are not testing "info tlb" at all, so hard to blame anyone.
If we want to keep having this HMP command I suppose we should
convert each target to qmp_info_tlb() and have a generic HMP
dispatch. (out of scope of this Hexagon patch).
>> diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c
>> new file mode 100644
>> index 00000000000..c921e82b377
>> --- /dev/null
>> +++ b/target/hexagon/hex_mmu.c
>> @@ -0,0 +1,268 @@
>> +void dump_mmu(Monitor *mon, CPUHexagonState *env)
>> +{
>> + HexagonCPU *cpu = env_archcpu(env);
>> + hexagon_tlb_dump(mon, cpu->tlb);
>> +}
^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH v8] target/hexagon: Define f{S,G}ET_FIELD macros
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (33 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add hex_interrupts support Brian Cain
35 siblings, 0 replies; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 38a43647dd9..041e68a150e 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] 43+ messages in thread* [PATCH v8] target/hexagon: Add hex_interrupts support
2026-06-11 5:28 [PATCH v8 00/36] Hexagon system emulation - Part 1/3 Brian Cain
` (34 preceding siblings ...)
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
@ 2026-06-11 5:28 ` Brian Cain
2026-06-17 19:34 ` Pierrick Bouvier
35 siblings, 1 reply; 43+ messages in thread
From: Brian Cain @ 2026-06-11 5:28 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, matheus.bernardino, pierrick.bouvier, ltaylorsimpson,
philmd, philmd, 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 | 371 ++++++++++++++++++++++++++++++++
4 files changed, 392 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 dbdc456d732..1b225e35abc 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -197,6 +197,8 @@ struct ArchCPU {
bool short_circuit;
#ifndef CONFIG_USER_ONLY
HexagonTLBState *tlb;
+ uint32_t boot_addr;
+ 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 73aca0a4217..eb1f7049298 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -54,6 +54,9 @@ static const Property hexagon_cpu_properties[] = {
#ifndef 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),
@@ -336,6 +339,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
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..3534481da24
--- /dev/null
+++ b/target/hexagon/hex_interrupts.c
@@ -0,0 +1,371 @@
+/*
+ * 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
+ env->threadId);
+ 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, new;
+
+ 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);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId);
+ uint32_t iad = GET_FIELD(IPENDAD_IAD, ipendad);
+ iad = deposit32(iad, int_num, 1, val);
+ fSET_FIELD(ipendad, IPENDAD_IAD, iad);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId);
+ uint32_t ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend &= ~mask;
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId);
+ uint32_t ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend |= mask;
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+ env->threadId);
+ uint32_t ipend = GET_FIELD(IPENDAD_IPEND, ipendad);
+ ipend = deposit32(ipend, int_num, 1, val);
+ fSET_FIELD(ipendad, IPENDAD_IPEND, ipend);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SCHEDCFG,
+ env->threadId);
+ 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 =
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
+ env->threadId);
+ 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)) {
+ bool syscfg_gie, iad, ssr_ie, imask;
+
+ 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;
+ }
+ syscfg_gie = get_syscfg_gie(env);
+ iad = get_iad_bit(env, i);
+ ssr_ie = get_ssr_ie(env);
+ 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] 43+ messages in thread* Re: [PATCH v8] target/hexagon: Add hex_interrupts support
2026-06-11 5:28 ` [PATCH v8] target/hexagon: Add hex_interrupts support Brian Cain
@ 2026-06-17 19:34 ` Pierrick Bouvier
0 siblings, 0 replies; 43+ messages in thread
From: Pierrick Bouvier @ 2026-06-17 19:34 UTC (permalink / raw)
To: Brian Cain, qemu-devel
Cc: matheus.bernardino, ltaylorsimpson, philmd, philmd, Brian Cain,
Sid Manning, Michael Lambert
On 6/10/2026 10:28 PM, Brian Cain wrote:
> 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 | 371 ++++++++++++++++++++++++++++++++
> 4 files changed, 392 insertions(+)
> create mode 100644 target/hexagon/hex_interrupts.h
> create mode 100644 target/hexagon/hex_interrupts.c
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 43+ messages in thread