All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL v3 00/76] hex queue
@ 2026-06-25 14:15 Brian Cain
  2026-06-25 14:15 ` [PULL v3 01/76] tests/docker: add flex and bison to emsdk-wasm64-cross Brian Cain
                   ` (76 more replies)
  0 siblings, 77 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain

The following changes since commit b83371668192a705b878e909c5ae9c1233cbd5fb:

  Merge tag 'pbouvier/pr/plugins-20260618' of https://gitlab.com/p-b-o/qemu into staging (2026-06-19 15:00:01 -0400)

are available in the Git repository at:

  https://github.com/qualcomm/qemu tags/pull-hex-20260625

for you to fetch changes up to 0281aa50c4792fd091e00051031aa927ea0790ea:

  tests/qtest: Add hexagon boot-serial-test (2026-06-24 22:18:47 -0700)

----------------------------------------------------------------
hex queue sysemu v3

w/`tests/docker: add flex and bison to emsdk-wasm64-cross`, now passes:

    Program flex found: YES (/usr/bin/flex)
    Program bison found: YES 3.8.2 (/usr/bin/bison)
    ...
    Build-time dependency glib-2.0 found: YES 2.72.4
    ...
    Build targets in project: 527
    ...
    [1421/1421] Linking target qemu-system-hexagon.js


----------------------------------------------------------------
Brian Cain (73):
      tests/docker: add flex and bison to emsdk-wasm64-cross
      target/hexagon: use cmd_array() instead of get_id()
      target/hexagon/idef-parser: open input file in binary mode
      docs: Add hexagon sysemu docs
      docs/system: Add hexagon CPU emulation
      target/hexagon: Fix badva reference, delete CAUSE
      target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof
      target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py
      target/hexagon: Suppress unused-variable warnings for sysemu source regs
      target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags()
      target/hexagon: Add privilege check, use tag_ignore()
      target/hexagon: Add a placeholder fp exception
      target/hexagon: Add guest, system reg number defs
      target/hexagon: Add guest, system reg number state
      target/hexagon: Add TCG values for sreg, greg
      target/hexagon: Add guest/sys reg writes to DisasContext
      target/hexagon: Add imported macro, attr defs for sysemu
      target/hexagon: Add new macro definitions for sysemu
      target/hexagon: Add handlers for guest/sysreg r/w
      target/hexagon: Add placeholder greg/sreg r/w helpers
      target/hexagon: Add vmstate representation
      target/hexagon: Make A_PRIV, "J2_trap*" insts need_env()
      target/hexagon: Define register fields for system regs
      target/hexagon: Implement do_raise_exception()
      target/hexagon: Add system reg insns
      target/hexagon: Add sysemu TCG overrides
      target/hexagon: Add implicit attributes to sysemu macros
      target/hexagon: Add TCG overrides for int handler insts
      target/hexagon: Add TCG overrides for thread ctl
      target/hexagon: Add TCG overrides for rte, nmi
      target/hexagon: Add sreg_{read,write} helpers
      target/hexagon: Add representation to count cycles
      target/hexagon: Add implementation of cycle counters
      target/hexagon: Add pcycle setting functionality
      target/hexagon: Add cpu modes, mmu indices, next_PC to state
      hw/hexagon: Declare hexagon TLB device interface
      target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode
      target/hexagon: Define f{S,G}ET_FIELD macros
      target/hexagon: Add hex_interrupts support
      target/hexagon: Implement {c,}swi helpers
      target/hexagon: Implement iassign{r,w} helpers
      target/hexagon: Implement start/stop helpers, soft reset
      target/hexagon: Implement {g,s}etimask helpers
      target/hexagon: Implement wait helper
      target/hexagon: Implement get_exe_mode()
      target/hexagon: Implement hex_tlb_entry_get_perm()
      target/hexagon: Implement software interrupt
      target/hexagon: Implement stack overflow exception
      target/hexagon: Implement exec_interrupt, set_irq
      target/hexagon: Implement hexagon_tlb_fill()
      target/hexagon: Implement siad inst
      target/hexagon: Implement hexagon_resume_threads()
      target/hexagon: Implement setprio, resched
      target/hexagon: Add sysemu_ops, cpu_get_phys_page_debug()
      target/hexagon: extend hexagon_cpu_mmu_index() for sysemu
      target/hexagon: Decode trap1, rte as COF
      target/hexagon: Implement modify_ssr, resched, pending_interrupt
      target/hexagon: Add pkt_ends_tb to translation
      target/hexagon: Add next_PC, {s,g}reg writes
      target/hexagon: Add implicit sysreg writes
      target/hexagon: Define system, guest reg names
      target/hexagon: Add k0 {un,}lock
      target/hexagon: Add PC to raise_exception, use fTRAP() helper
      target/hexagon: Add TCG overrides for transfer insts
      target/hexagon: Add support for loadw_phys
      hw/hexagon: Add globalreg model
      hw/hexagon: Add global register tracing
      hw/hexagon: Add hexagon TLB device implementation
      hw/hexagon: Add machine configs for sysemu
      hw/hexagon: Add v68, sa8775-cdsp0 defs
      target/hexagon: add build config for softmmu
      hw/hexagon: Define hexagon "virt" machine
      tests/qtest: Add hexagon boot-serial-test

Matheus Tavares Bernardino (2):
      target/hexagon: add simple cpu_exec_reset and pointer_wrap
      target/hexagon: Add guest reg reading functionality

Sid Manning (1):
      hw/hexagon: Add support for cfgbase

 MAINTAINERS                                        |  16 +
 docs/devel/hexagon-sys.rst                         | 112 ++++
 docs/devel/index-internals.rst                     |   1 +
 docs/system/hexagon/cdsp.rst                       |  12 +
 docs/system/hexagon/emulation.rst                  |  15 +
 docs/system/target-hexagon.rst                     | 103 ++++
 docs/system/targets.rst                            |   1 +
 configs/devices/hexagon-softmmu/default.mak        |   7 +
 configs/targets/hexagon-softmmu.mak                |   8 +
 meson.build                                        |   1 +
 hw/hexagon/trace.h                                 |   2 +
 include/hw/hexagon/hexagon.h                       | 161 ++++++
 include/hw/hexagon/hexagon_globalreg.h             |  55 ++
 include/hw/hexagon/hexagon_tlb.h                   |  46 ++
 include/hw/hexagon/virt.h                          |  30 ++
 target/hexagon/cpu-param.h                         |   2 +-
 target/hexagon/cpu.h                               |  89 +++-
 target/hexagon/cpu_bits.h                          |  75 ++-
 target/hexagon/cpu_helper.h                        |  26 +
 target/hexagon/gen_tcg.h                           |  16 +-
 target/hexagon/gen_tcg_sys.h                       | 139 +++++
 target/hexagon/helper.h                            |  27 +-
 target/hexagon/hex_interrupts.h                    |  15 +
 target/hexagon/hex_mmu.h                           |  26 +
 target/hexagon/hex_regs.h                          | 117 +++++
 target/hexagon/hexswi.h                            |  17 +
 target/hexagon/idef-parser/parser-helpers.h        |   2 +
 target/hexagon/internal.h                          |  22 +
 target/hexagon/macros.h                            |  38 +-
 target/hexagon/sys_macros.h                        | 252 +++++++++
 target/hexagon/translate.h                         |  47 ++
 hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc          |  64 +++
 hw/hexagon/machine_cfg_v66g_1024.h.inc             |  64 +++
 hw/hexagon/machine_cfg_v68n_1024.h.inc             |  64 +++
 target/hexagon/attribs_def.h.inc                   |  35 +-
 target/hexagon/reg_fields_def.h.inc                | 107 ++++
 hw/hexagon/hexagon_dsp.c                           | 225 ++++++++
 hw/hexagon/hexagon_globalreg.c                     | 316 +++++++++++
 hw/hexagon/hexagon_tlb.c                           | 467 +++++++++++++++++
 hw/hexagon/virt.c                                  | 347 +++++++++++++
 linux-user/hexagon/cpu_loop.c                      |  23 +
 system/qdev-monitor.c                              |   2 +-
 target/hexagon/arch.c                              |   5 +
 target/hexagon/cpu.c                               | 422 ++++++++++++++-
 target/hexagon/cpu_helper.c                        | 399 ++++++++++++++
 target/hexagon/decode.c                            |  14 +
 target/hexagon/genptr.c                            | 173 ++++++-
 target/hexagon/hex_interrupts.c                    | 371 +++++++++++++
 target/hexagon/hex_mmu.c                           | 270 ++++++++++
 target/hexagon/hexswi.c                            | 271 ++++++++++
 target/hexagon/idef-parser/parser-helpers.c        |   9 +
 target/hexagon/machine.c                           |  32 ++
 target/hexagon/op_helper.c                         | 576 ++++++++++++++++++++-
 target/hexagon/translate.c                         | 265 +++++++++-
 tests/qtest/boot-serial-test.c                     |   8 +
 tests/docker/dockerfiles/emsdk-wasm64-cross.docker |   2 +
 hw/Kconfig                                         |   1 +
 hw/hexagon/Kconfig                                 |  14 +
 hw/hexagon/meson.build                             |   7 +
 hw/hexagon/trace-events                            |   3 +
 hw/meson.build                                     |   1 +
 target/Kconfig                                     |   1 +
 target/hexagon/Kconfig                             |   2 +
 target/hexagon/gen_analyze_funcs.py                |  14 +-
 target/hexagon/gen_helper_funcs.py                 |  26 +-
 target/hexagon/gen_helper_protos.py                |  23 +-
 target/hexagon/gen_idef_parser_funcs.py            |   2 +
 target/hexagon/gen_op_attribs.py                   |   2 +-
 target/hexagon/gen_opcodes_def.py                  |   5 +-
 target/hexagon/gen_tcg_funcs.py                    |  35 +-
 target/hexagon/hex_common.py                       | 184 ++++++-
 target/hexagon/idef-parser/idef-parser.y           |   5 +-
 target/hexagon/imported/encode_pp.def              | 129 ++++-
 target/hexagon/imported/ldst.idef                  |   3 +
 target/hexagon/imported/macros.def                 | 482 ++++++++++++++++-
 target/hexagon/imported/system.idef                | 243 ++++++++-
 target/hexagon/meson.build                         |  30 +-
 tests/qemu-iotests/testenv.py                      |   1 +
 tests/qtest/meson.build                            |   2 +
 79 files changed, 7076 insertions(+), 150 deletions(-)
 create mode 100644 docs/devel/hexagon-sys.rst
 create mode 100644 docs/system/hexagon/cdsp.rst
 create mode 100644 docs/system/hexagon/emulation.rst
 create mode 100644 docs/system/target-hexagon.rst
 create mode 100644 configs/devices/hexagon-softmmu/default.mak
 create mode 100644 configs/targets/hexagon-softmmu.mak
 create mode 100644 hw/hexagon/trace.h
 create mode 100644 include/hw/hexagon/hexagon.h
 create mode 100644 include/hw/hexagon/hexagon_globalreg.h
 create mode 100644 include/hw/hexagon/hexagon_tlb.h
 create mode 100644 include/hw/hexagon/virt.h
 create mode 100644 target/hexagon/cpu_helper.h
 create mode 100644 target/hexagon/gen_tcg_sys.h
 create mode 100644 target/hexagon/hex_interrupts.h
 create mode 100644 target/hexagon/hex_mmu.h
 create mode 100644 target/hexagon/hexswi.h
 create mode 100644 target/hexagon/sys_macros.h
 create mode 100644 hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc
 create mode 100644 hw/hexagon/machine_cfg_v66g_1024.h.inc
 create mode 100644 hw/hexagon/machine_cfg_v68n_1024.h.inc
 create mode 100644 hw/hexagon/hexagon_dsp.c
 create mode 100644 hw/hexagon/hexagon_globalreg.c
 create mode 100644 hw/hexagon/hexagon_tlb.c
 create mode 100644 hw/hexagon/virt.c
 create mode 100644 target/hexagon/cpu_helper.c
 create mode 100644 target/hexagon/hex_interrupts.c
 create mode 100644 target/hexagon/hex_mmu.c
 create mode 100644 target/hexagon/hexswi.c
 create mode 100644 target/hexagon/machine.c
 create mode 100644 hw/hexagon/Kconfig
 create mode 100644 hw/hexagon/meson.build
 create mode 100644 hw/hexagon/trace-events
 create mode 100644 target/hexagon/Kconfig
 mode change 100755 => 100644 target/hexagon/imported/macros.def

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PULL v3 01/76] tests/docker: add flex and bison to emsdk-wasm64-cross
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 02/76] target/hexagon: use cmd_array() instead of get_id() Brian Cain
                   ` (75 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Pierrick Bouvier, Philippe Mathieu-Daudé,
	Kohei Tokunaga, Alex Bennée

The hexagon idef-parser requires flex and bison as host build
tools.  Add them to the emsdk-wasm64-cross container image so that
wasm64 builds including hexagon-softmmu can find them.

Link: https://lore.kernel.org/qemu-devel/CAJSP0QVk6wsOnPAspC4YfXRp90saKibQfD4Mk-44-RQo0k=z3w@mail.gmail.com/
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 tests/docker/dockerfiles/emsdk-wasm64-cross.docker | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tests/docker/dockerfiles/emsdk-wasm64-cross.docker b/tests/docker/dockerfiles/emsdk-wasm64-cross.docker
index 8a924816f92..5debbc77d08 100644
--- a/tests/docker/dockerfiles/emsdk-wasm64-cross.docker
+++ b/tests/docker/dockerfiles/emsdk-wasm64-cross.docker
@@ -19,7 +19,9 @@ ENV CXXFLAGS="$CFLAGS"
 ENV LDFLAGS="-sWASM_BIGINT -sASYNCIFY=1 -L$TARGET/lib"
 RUN apt-get update && apt-get install -y \
     autoconf \
+    bison \
     build-essential \
+    flex \
     libglib2.0-dev \
     libtool \
     pkgconf \
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 02/76] target/hexagon: use cmd_array() instead of get_id()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
  2026-06-25 14:15 ` [PULL v3 01/76] tests/docker: add flex and bison to emsdk-wasm64-cross Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 03/76] target/hexagon/idef-parser: open input file in binary mode Brian Cain
                   ` (74 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Philippe Mathieu-Daudé, Pierrick Bouvier

get_id() returns the compiler's short name not a program.
Passing it directly as the command for the idef-parser preprocessing
custom_target happened to work for native gcc/clang builds but
breaks under cross compilers such as emcc or any ccache-wrapped compiler.

Link: https://lore.kernel.org/qemu-devel/CAJSP0QWzQEgoYMCgZX+9jCvrV6O3RqnA+df1DpT2R6MZvVXiNg@mail.gmail.com/
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/meson.build | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index d169cf71b2f..ff22b4e4706 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -270,13 +270,13 @@ if idef_parser_enabled and 'hexagon-linux-user' in target_dirs
         command: [python, files('gen_idef_parser_funcs.py'), semantics_generated, '@OUTPUT@'],
     )
 
-    compiler = meson.get_compiler('c').get_id()
+    compiler = meson.get_compiler('c').cmd_array()
     preprocessed_idef_parser_input_generated = custom_target(
         'idef_parser_input.preprocessed.h.inc',
         output: 'idef_parser_input.preprocessed.h.inc',
         input: idef_parser_input_generated,
         depend_files: [idef_parser_dir / 'macros.h.inc'],
-        command: [compiler, '-x', 'c', '-E', '-I', idef_parser_dir, '-o', '@OUTPUT@', '@INPUT@'],
+        command: compiler + ['-x', 'c', '-E', '-I', idef_parser_dir, '-o', '@OUTPUT@', '@INPUT@'],
     )
 
     flex = generator(
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 03/76] target/hexagon/idef-parser: open input file in binary mode
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
  2026-06-25 14:15 ` [PULL v3 01/76] tests/docker: add flex and bison to emsdk-wasm64-cross Brian Cain
  2026-06-25 14:15 ` [PULL v3 02/76] target/hexagon: use cmd_array() instead of get_id() Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 04/76] docs: Add hexagon sysemu docs Brian Cain
                   ` (73 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Pierrick Bouvier, Philippe Mathieu-Daudé,
	Alessandro Di Federico, Anton Johansson

On Windows, opening a file in text mode causes fread() to return fewer
bytes than ftell() reported, because CRLF sequences are translated to
LF on read.  This causes idef-parser to report an error and abort.

Open the input file in binary mode ("rb") so that ftell() and fread()
agree on the file size across all platforms.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/idef-parser/idef-parser.y | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y
index c6f17c6afa7..caba0d2644d 100644
--- a/target/hexagon/idef-parser/idef-parser.y
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -869,7 +869,7 @@ int main(int argc, char **argv)
     context.header_str = g_string_new(NULL);
     context.ternary = g_array_new(FALSE, TRUE, sizeof(Ternary));
     /* Read input file */
-    FILE *input_file = fopen(argv[ARG_INDEX_IDEFS], "r");
+    FILE *input_file = fopen(argv[ARG_INDEX_IDEFS], "rb");
     fseek(input_file, 0L, SEEK_END);
     long input_size = ftell(input_file);
     context.input_buffer = (char *) calloc(input_size + 1, sizeof(char));
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 04/76] docs: Add hexagon sysemu docs
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (2 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 03/76] target/hexagon/idef-parser: open input file in binary mode Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 05/76] docs/system: Add hexagon CPU emulation Brian Cain
                   ` (72 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 MAINTAINERS                    |   3 +
 docs/devel/hexagon-sys.rst     | 112 +++++++++++++++++++++++++++++++++
 docs/devel/index-internals.rst |   1 +
 docs/system/hexagon/cdsp.rst   |  12 ++++
 docs/system/target-hexagon.rst | 101 +++++++++++++++++++++++++++++
 docs/system/targets.rst        |   1 +
 6 files changed, 230 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 93df53d87f6..9d195e56ce9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -258,6 +258,9 @@ F: disas/hexagon.c
 F: configs/targets/hexagon-linux-user.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..65866296724
--- /dev/null
+++ b/docs/system/target-hexagon.rst
@@ -0,0 +1,101 @@
+.. 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] 78+ messages in thread

* [PULL v3 05/76] docs/system: Add hexagon CPU emulation
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (3 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 04/76] docs: Add hexagon sysemu docs Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 06/76] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
                   ` (71 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 docs/system/hexagon/emulation.rst | 15 +++++++++++++++
 docs/system/target-hexagon.rst    |  2 ++
 2 files changed, 17 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 65866296724..416b8f7be76 100644
--- a/docs/system/target-hexagon.rst
+++ b/docs/system/target-hexagon.rst
@@ -98,4 +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] 78+ messages in thread

* [PULL v3 06/76] target/hexagon: Fix badva reference, delete CAUSE
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (4 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 05/76] docs/system: Add hexagon CPU emulation Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 07/76] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
                   ` (70 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Philippe Mathieu-Daudé,
	Taylor Simpson, Pierrick Bouvier

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>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.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] 78+ messages in thread

* [PULL v3 07/76] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (5 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 06/76] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 08/76] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
                   ` (69 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.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 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] 78+ messages in thread

* [PULL v3 08/76] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (6 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 07/76] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 09/76] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
                   ` (68 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 09/76] target/hexagon: Suppress unused-variable warnings for sysemu source regs
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (7 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 08/76] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 10/76] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain
                   ` (67 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Taylor Simpson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 10/76] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (8 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 09/76] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 11/76] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
                   ` (66 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier,
	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] 78+ messages in thread

* [PULL v3 11/76] target/hexagon: Add privilege check, use tag_ignore()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (9 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 10/76] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 12/76] target/hexagon: Add a placeholder fp exception Brian Cain
                   ` (65 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Taylor Simpson, Pierrick Bouvier, 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] 78+ messages in thread

* [PULL v3 12/76] target/hexagon: Add a placeholder fp exception
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (10 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 11/76] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 13/76] target/hexagon: Add guest, system reg number defs Brian Cain
                   ` (64 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson,
	Philippe Mathieu-Daudé, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 13/76] target/hexagon: Add guest, system reg number defs
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (11 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 12/76] target/hexagon: Add a placeholder fp exception Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 14/76] target/hexagon: Add guest, system reg number state Brian Cain
                   ` (63 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.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] 78+ messages in thread

* [PULL v3 14/76] target/hexagon: Add guest, system reg number state
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (12 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 13/76] target/hexagon: Add guest, system reg number defs Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 15/76] target/hexagon: Add TCG values for sreg, greg Brian Cain
                   ` (62 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 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] 78+ messages in thread

* [PULL v3 15/76] target/hexagon: Add TCG values for sreg, greg
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (13 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 14/76] target/hexagon: Add guest, system reg number state Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 16/76] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
                   ` (61 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson,
	Philippe Mathieu-Daudé, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 16/76] target/hexagon: Add guest/sys reg writes to DisasContext
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (14 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 15/76] target/hexagon: Add TCG values for sreg, greg Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 17/76] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
                   ` (60 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 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] 78+ messages in thread

* [PULL v3 17/76] target/hexagon: Add imported macro, attr defs for sysemu
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (15 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 16/76] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 18/76] target/hexagon: Add new macro definitions " Brian Cain
                   ` (59 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Brian Cain, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 18/76] target/hexagon: Add new macro definitions for sysemu
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (16 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 17/76] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 19/76] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
                   ` (58 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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 | 239 ++++++++++++++++++++++++++++++++++++
 target/hexagon/op_helper.c  |   4 +
 4 files changed, 276 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..4de4d53823a
--- /dev/null
+++ b/target/hexagon/sys_macros.h
@@ -0,0 +1,239 @@
+/*
+ * 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
+
+#include "system/physmem.h"
+
+#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;         \
+  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 0a946433644..5b9c266d02f 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -25,6 +25,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"
@@ -32,6 +33,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] 78+ messages in thread

* [PULL v3 19/76] target/hexagon: Add handlers for guest/sysreg r/w
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (17 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 18/76] target/hexagon: Add new macro definitions " Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 20/76] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
                   ` (57 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 20/76] target/hexagon: Add placeholder greg/sreg r/w helpers
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (18 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 19/76] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 21/76] target/hexagon: Add vmstate representation Brian Cain
                   ` (56 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 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 5b9c266d02f..cd324c19a9d 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1374,6 +1374,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] 78+ messages in thread

* [PULL v3 21/76] target/hexagon: Add vmstate representation
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (19 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 20/76] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 22/76] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
                   ` (55 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson,
	Philippe Mathieu-Daudé, Richard Henderson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 22/76] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (20 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 21/76] target/hexagon: Add vmstate representation Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 23/76] target/hexagon: Define register fields for system regs Brian Cain
                   ` (54 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 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] 78+ messages in thread

* [PULL v3 23/76] target/hexagon: Define register fields for system regs
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (21 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 22/76] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 24/76] target/hexagon: Implement do_raise_exception() Brian Cain
                   ` (53 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 24/76] target/hexagon: Implement do_raise_exception()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (22 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 23/76] target/hexagon: Define register fields for system regs Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 25/76] target/hexagon: Add system reg insns Brian Cain
                   ` (52 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson,
	Philippe Mathieu-Daudé, Pierrick Bouvier

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 cd324c19a9d..0f43a666341 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -41,6 +41,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] 78+ messages in thread

* [PULL v3 25/76] target/hexagon: Add system reg insns
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (23 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 24/76] target/hexagon: Implement do_raise_exception() Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 26/76] target/hexagon: Add sysemu TCG overrides Brian Cain
                   ` (51 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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   | 243 ++++++++++++++++++++++++--
 2 files changed, 344 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..9e85bed0a6e 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,28 @@ 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] 78+ messages in thread

* [PULL v3 26/76] target/hexagon: Add sysemu TCG overrides
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (24 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 25/76] target/hexagon: Add system reg insns Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 27/76] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
                   ` (50 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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 0f43a666341..3236ce0c8f0 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -20,9 +20,9 @@
 #include "accel/tcg/cpu-ldst.h"
 #include "accel/tcg/cpu-loop.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"
@@ -32,6 +32,7 @@
 #include "mmvec/mmvec.h"
 #include "mmvec/macros.h"
 #include "op_helper.h"
+#include "cpu_helper.h"
 #include "translate.h"
 #ifndef CONFIG_USER_ONLY
 #include "hexswi.h"
@@ -1413,6 +1414,12 @@ uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg)
 {
     g_assert_not_reached();
 }
+
+void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio)
+{
+    g_assert_not_reached();
+}
+
 #endif
 
 
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index 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 ff22b4e4706..fd3d69feffd 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] 78+ messages in thread

* [PULL v3 27/76] target/hexagon: Add implicit attributes to sysemu macros
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (25 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 26/76] target/hexagon: Add sysemu TCG overrides Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 28/76] target/hexagon: Add TCG overrides for int handler insts Brian Cain
                   ` (49 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 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] 78+ messages in thread

* [PULL v3 28/76] target/hexagon: Add TCG overrides for int handler insts
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (26 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 27/76] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 29/76] target/hexagon: Add TCG overrides for thread ctl Brian Cain
                   ` (48 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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 3236ce0c8f0..c90b7572419 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1390,6 +1390,46 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
 }
 
 #ifndef CONFIG_USER_ONLY
+void HELPER(ciad)(CPUHexagonState *env, uint32_t mask)
+{
+    g_assert_not_reached();
+}
+
+void HELPER(siad)(CPUHexagonState *env, uint32_t mask)
+{
+    g_assert_not_reached();
+}
+
+void HELPER(swi)(CPUHexagonState *env, uint32_t mask)
+{
+    g_assert_not_reached();
+}
+
+void HELPER(cswi)(CPUHexagonState *env, uint32_t mask)
+{
+    g_assert_not_reached();
+}
+
+void HELPER(iassignw)(CPUHexagonState *env, uint32_t src)
+{
+    g_assert_not_reached();
+}
+
+uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src)
+{
+    g_assert_not_reached();
+}
+
+uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid)
+{
+    g_assert_not_reached();
+}
+
+void HELPER(setimask)(CPUHexagonState *env, uint32_t tid, uint32_t imask)
+{
+    g_assert_not_reached();
+}
+
 void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
 {
     g_assert_not_reached();
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 29/76] target/hexagon: Add TCG overrides for thread ctl
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (27 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 28/76] target/hexagon: Add TCG overrides for int handler insts Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 30/76] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
                   ` (47 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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 c90b7572419..c620a5b8636 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1420,6 +1420,26 @@ uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src)
     g_assert_not_reached();
 }
 
+void HELPER(start)(CPUHexagonState *env, uint32_t imask)
+{
+    g_assert_not_reached();
+}
+
+void HELPER(stop)(CPUHexagonState *env)
+{
+    g_assert_not_reached();
+}
+
+void HELPER(wait)(CPUHexagonState *env, target_ulong PC)
+{
+    g_assert_not_reached();
+}
+
+void HELPER(resume)(CPUHexagonState *env, uint32_t mask)
+{
+    g_assert_not_reached();
+}
+
 uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid)
 {
     g_assert_not_reached();
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 30/76] target/hexagon: Add TCG overrides for rte, nmi
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (28 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 29/76] target/hexagon: Add TCG overrides for thread ctl Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 31/76] target/hexagon: Add sreg_{read,write} helpers Brian Cain
                   ` (46 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 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 4de4d53823a..e8bbeadfdfb 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -236,4 +236,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 c620a5b8636..2cd7f48ea2f 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1480,6 +1480,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] 78+ messages in thread

* [PULL v3 31/76] target/hexagon: Add sreg_{read,write} helpers
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (29 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 30/76] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 32/76] target/hexagon: Add representation to count cycles Brian Cain
                   ` (45 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Sid Manning, Taylor Simpson,
	Pierrick Bouvier

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 2cd7f48ea2f..4dc2b8e63a7 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -20,6 +20,7 @@
 #include "accel/tcg/cpu-ldst.h"
 #include "accel/tcg/cpu-loop.h"
 #include "accel/tcg/probe.h"
+#include "qemu/main-loop.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
 #include "fpu/softfloat.h"
@@ -1452,17 +1453,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] 78+ messages in thread

* [PULL v3 32/76] target/hexagon: Add representation to count cycles
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (30 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 31/76] target/hexagon: Add sreg_{read,write} helpers Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 33/76] target/hexagon: Add implementation of cycle counters Brian Cain
                   ` (44 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Taylor Simpson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 33/76] target/hexagon: Add implementation of cycle counters
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (31 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 32/76] target/hexagon: Add representation to count cycles Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 34/76] target/hexagon: Add pcycle setting functionality Brian Cain
                   ` (43 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Taylor Simpson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 34/76] target/hexagon: Add pcycle setting functionality
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (32 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 33/76] target/hexagon: Add implementation of cycle counters Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 35/76] target/hexagon: Add cpu modes, mmu indices, next_PC to state Brian Cain
                   ` (42 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Taylor Simpson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 35/76] target/hexagon: Add cpu modes, mmu indices, next_PC to state
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (33 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 34/76] target/hexagon: Add pcycle setting functionality Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 36/76] hw/hexagon: Declare hexagon TLB device interface Brian Cain
                   ` (41 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 36/76] hw/hexagon: Declare hexagon TLB device interface
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (34 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 35/76] target/hexagon: Add cpu modes, mmu indices, next_PC to state Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 37/76] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode Brian Cain
                   ` (40 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Pierrick Bouvier

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] 78+ messages in thread

* [PULL v3 37/76] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (35 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 36/76] hw/hexagon: Declare hexagon TLB device interface Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 38/76] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
                   ` (39 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Pierrick Bouvier

Add hex_mmu.[ch], cpu mode helpers, and additional includes/stubs
that integrate the TLB device with the CPU model.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
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    | 270 ++++++++++++++++++++++++++++++++++++
 7 files changed, 366 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 e8bbeadfdfb..ade57290166 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -141,6 +141,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..1c8ccec69ef
--- /dev/null
+++ b/target/hexagon/hex_mmu.c
@@ -0,0 +1,270 @@
+/*
+ * 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] 78+ messages in thread

* [PULL v3 38/76] target/hexagon: Define f{S,G}ET_FIELD macros
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (36 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 37/76] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 39/76] target/hexagon: Add hex_interrupts support Brian Cain
                   ` (38 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 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] 78+ messages in thread

* [PULL v3 39/76] target/hexagon: Add hex_interrupts support
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (37 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 38/76] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 40/76] target/hexagon: Implement {c,}swi helpers Brian Cain
                   ` (37 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Sid Manning,
	Michael Lambert, Pierrick Bouvier

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>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.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] 78+ messages in thread

* [PULL v3 40/76] target/hexagon: Implement {c,}swi helpers
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (38 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 39/76] target/hexagon: Add hex_interrupts support Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 41/76] target/hexagon: Implement iassign{r,w} helpers Brian Cain
                   ` (36 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

{c,}swi are the "software interrupt"/"Cancel pending interrupts" instructions.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/op_helper.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 4dc2b8e63a7..7827696c6b2 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -24,6 +24,7 @@
 #include "cpu.h"
 #include "exec/helper-proto.h"
 #include "fpu/softfloat.h"
+#include "exec/cpu-interrupt.h"
 #include "internal.h"
 #include "macros.h"
 #include "sys_macros.h"
@@ -36,6 +37,7 @@
 #include "cpu_helper.h"
 #include "translate.h"
 #ifndef CONFIG_USER_ONLY
+#include "hex_interrupts.h"
 #include "hexswi.h"
 #endif
 
@@ -1403,12 +1405,14 @@ void HELPER(siad)(CPUHexagonState *env, uint32_t mask)
 
 void HELPER(swi)(CPUHexagonState *env, uint32_t mask)
 {
-    g_assert_not_reached();
+    BQL_LOCK_GUARD();
+    hex_raise_interrupts(env, mask, CPU_INTERRUPT_SWI);
 }
 
 void HELPER(cswi)(CPUHexagonState *env, uint32_t mask)
 {
-    g_assert_not_reached();
+    BQL_LOCK_GUARD();
+    hex_clear_interrupts(env, mask, CPU_INTERRUPT_SWI);
 }
 
 void HELPER(iassignw)(CPUHexagonState *env, uint32_t src)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 41/76] target/hexagon: Implement iassign{r,w} helpers
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (39 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 40/76] target/hexagon: Implement {c,}swi helpers Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:15 ` [PULL v3 42/76] target/hexagon: Implement start/stop helpers, soft reset Brian Cain
                   ` (35 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

iassign{r,w} are the "Interrupt to thread assignment {read,write}"
instructions.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/op_helper.c | 56 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 54 insertions(+), 2 deletions(-)

diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 7827696c6b2..6f01f3b91d8 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1417,12 +1417,64 @@ void HELPER(cswi)(CPUHexagonState *env, uint32_t mask)
 
 void HELPER(iassignw)(CPUHexagonState *env, uint32_t src)
 {
-    g_assert_not_reached();
+    uint32_t modectl;
+    uint32_t thread_enabled_mask;
+    CPUState *cpu;
+    HexagonCPU *hex_cpu;
+
+    BQL_LOCK_GUARD();
+    hex_cpu = env_archcpu(env);
+    modectl = hex_cpu->globalregs ?
+        hexagon_globalreg_read(hex_cpu->globalregs, HEX_SREG_MODECTL,
+                               env->threadId) : 0;
+    thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
+
+    CPU_FOREACH(cpu) {
+        CPUHexagonState *thread_env = &(HEXAGON_CPU(cpu)->env);
+        uint32_t thread_id_mask = 0x1 << thread_env->threadId;
+        if (thread_enabled_mask & thread_id_mask) {
+            uint32_t imask = thread_env->t_sreg[HEX_SREG_IMASK];
+            uint32_t intbitpos = (src >> 16) & 0xF;
+            uint32_t val = (src >> thread_env->threadId) & 0x1;
+            imask = deposit32(imask, intbitpos, 1, val);
+            thread_env->t_sreg[HEX_SREG_IMASK] = imask;
+
+            qemu_log_mask(CPU_LOG_INT, "%s: thread " TARGET_FMT_ld
+               ", new imask 0x%" PRIx32 "\n", __func__,
+               thread_env->threadId, imask);
+        }
+    }
+    hex_interrupt_update(env);
 }
 
 uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src)
 {
-    g_assert_not_reached();
+    uint32_t modectl;
+    uint32_t thread_enabled_mask;
+    uint32_t intbitpos;
+    uint32_t dest_reg;
+    CPUState *cpu;
+    HexagonCPU *hex_cpu;
+
+    BQL_LOCK_GUARD();
+    hex_cpu = env_archcpu(env);
+    modectl = hex_cpu->globalregs ?
+        hexagon_globalreg_read(hex_cpu->globalregs, HEX_SREG_MODECTL,
+                               env->threadId) : 0;
+    thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
+    /* src fields are in same position as modectl, but mean different things */
+    intbitpos = GET_FIELD(MODECTL_W, src);
+    dest_reg = 0;
+    CPU_FOREACH(cpu) {
+        CPUHexagonState *thread_env = &(HEXAGON_CPU(cpu)->env);
+        uint32_t thread_id_mask = 0x1 << thread_env->threadId;
+        if (thread_enabled_mask & thread_id_mask) {
+            uint32_t imask = thread_env->t_sreg[HEX_SREG_IMASK];
+            dest_reg |= ((imask >> intbitpos) & 0x1) << thread_env->threadId;
+        }
+    }
+
+    return dest_reg;
 }
 
 void HELPER(start)(CPUHexagonState *env, uint32_t imask)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 42/76] target/hexagon: Implement start/stop helpers, soft reset
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (40 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 41/76] target/hexagon: Implement iassign{r,w} helpers Brian Cain
@ 2026-06-25 14:15 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 43/76] target/hexagon: Implement {g,s}etimask helpers Brian Cain
                   ` (34 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:15 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Brian Cain, Pierrick Bouvier

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/cpu.h       |  9 +++++++++
 target/hexagon/cpu.c       | 28 ++++++++++++++++++++++++++--
 target/hexagon/op_helper.c |  4 ++--
 3 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 1b225e35abc..92d4bb97129 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -213,6 +213,15 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
                                             uint32_t exception,
                                             uintptr_t pc);
 
+#ifndef CONFIG_USER_ONLY
+/*
+ * @return true if the @a thread_env hardware thread is
+ * not stopped.
+ */
+bool hexagon_thread_is_enabled(CPUHexagonState *thread_env);
+void hexagon_cpu_soft_reset(CPUHexagonState *env);
+#endif
+
 typedef HexagonCPU ArchCPU;
 
 void hexagon_translate_init(void);
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index eb1f7049298..27f0ef50df2 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -33,6 +33,7 @@
 #ifndef CONFIG_USER_ONLY
 #include "sys_macros.h"
 #include "accel/tcg/cpu-ldst.h"
+#include "qemu/main-loop.h"
 #endif
 
 static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
@@ -310,6 +311,28 @@ static void hexagon_restore_state_to_opc(CPUState *cs,
 }
 
 
+#ifndef CONFIG_USER_ONLY
+void hexagon_cpu_soft_reset(CPUHexagonState *env)
+{
+    HexagonCPU *cpu;
+
+    BQL_LOCK_GUARD();
+    env->t_sreg[HEX_SREG_SSR] = 0;
+    hexagon_ssr_set_cause(env, HEX_CAUSE_RESET);
+
+    cpu = env_archcpu(env);
+    if (cpu->globalregs) {
+        uint32_t evb =
+            hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
+                                   env->threadId);
+        env->gpr[HEX_REG_PC] = evb;
+    } else {
+        env->gpr[HEX_REG_PC] = cpu->boot_addr;
+    }
+}
+#endif
+
+
 static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
@@ -339,9 +362,10 @@ 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
+    hexagon_cpu_soft_reset(env);
     env->cause_code = HEX_EVENT_NONE;
+    env->gpr[HEX_REG_PC] = cpu->boot_addr;
+#endif
 }
 
 static void hexagon_cpu_disas_set_info(const CPUState *cs,
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 6f01f3b91d8..b9cf1f188bb 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1479,12 +1479,12 @@ uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src)
 
 void HELPER(start)(CPUHexagonState *env, uint32_t imask)
 {
-    g_assert_not_reached();
+    hexagon_start_threads(env, imask);
 }
 
 void HELPER(stop)(CPUHexagonState *env)
 {
-    g_assert_not_reached();
+    hexagon_stop_thread(env);
 }
 
 void HELPER(wait)(CPUHexagonState *env, target_ulong PC)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 43/76] target/hexagon: Implement {g,s}etimask helpers
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (41 preceding siblings ...)
  2026-06-25 14:15 ` [PULL v3 42/76] target/hexagon: Implement start/stop helpers, soft reset Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 44/76] target/hexagon: Implement wait helper Brian Cain
                   ` (33 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/op_helper.c | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index b9cf1f188bb..1680e300ec4 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1499,12 +1499,44 @@ void HELPER(resume)(CPUHexagonState *env, uint32_t mask)
 
 uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid)
 {
-    g_assert_not_reached();
+    CPUState *cs;
+    BQL_LOCK_GUARD();
+    CPU_FOREACH(cs) {
+        HexagonCPU *found_cpu = HEXAGON_CPU(cs);
+        CPUHexagonState *found_env = &found_cpu->env;
+        if (found_env->threadId == tid) {
+            uint32_t imask = found_env->t_sreg[HEX_SREG_IMASK];
+            qemu_log_mask(CPU_LOG_INT, "%s: tid " TARGET_FMT_lx
+                          " imask = 0x%" PRIx32 "\n", __func__,
+                          env->threadId,
+                          (uint32_t)GET_FIELD(IMASK_MASK, imask));
+            return GET_FIELD(IMASK_MASK, imask);
+        }
+    }
+    return 0;
 }
 
 void HELPER(setimask)(CPUHexagonState *env, uint32_t tid, uint32_t imask)
 {
-    g_assert_not_reached();
+    CPUState *cs;
+
+    BQL_LOCK_GUARD();
+    CPU_FOREACH(cs) {
+        HexagonCPU *found_cpu = HEXAGON_CPU(cs);
+        CPUHexagonState *found_env = &found_cpu->env;
+
+        if (tid == found_env->threadId) {
+            SET_SYSTEM_FIELD(found_env, HEX_SREG_IMASK, IMASK_MASK, imask);
+            qemu_log_mask(CPU_LOG_INT, "%s: tid " TARGET_FMT_lx
+                          " imask 0x%" PRIx32 "\n",
+                          __func__, found_env->threadId, imask);
+            hex_interrupt_update(found_env);
+            return;
+        }
+    }
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "setimask used with an invalid tid near PC: 0x%"
+                  PRIx32 "\n", env->next_PC);
 }
 
 void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 44/76] target/hexagon: Implement wait helper
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (42 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 43/76] target/hexagon: Implement {g,s}etimask helpers Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 45/76] target/hexagon: Implement get_exe_mode() Brian Cain
                   ` (32 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/gen_tcg_sys.h |  2 +-
 target/hexagon/op_helper.c   | 60 ++++++++++++++++++++++++++++++++++--
 2 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
index 264ea02752d..68b23895428 100644
--- a/target/hexagon/gen_tcg_sys.h
+++ b/target/hexagon/gen_tcg_sys.h
@@ -80,7 +80,7 @@
 #define fGEN_TCG_Y2_wait(SHORTCODE) \
     do { \
         RsV = RsV; \
-        gen_helper_wait(tcg_env, tcg_constant_tl(ctx->pkt->pc)); \
+        gen_helper_wait(tcg_env, tcg_constant_tl(ctx->pkt.pc)); \
     } while (0)
 
 #define fGEN_TCG_Y2_resume(SHORTCODE) \
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 1680e300ec4..9d50e6ef882 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1487,9 +1487,65 @@ void HELPER(stop)(CPUHexagonState *env)
     hexagon_stop_thread(env);
 }
 
-void HELPER(wait)(CPUHexagonState *env, target_ulong PC)
+static void set_wait_mode(CPUHexagonState *env)
 {
-    g_assert_not_reached();
+    HexagonCPU *cpu;
+    uint32_t modectl;
+    uint32_t thread_wait_mask;
+
+    g_assert(bql_locked());
+
+    cpu = env_archcpu(env);
+    if (!cpu->globalregs) {
+        return;
+    }
+    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);
+}
+
+static void hexagon_wait_thread(CPUHexagonState *env, uint32_t PC)
+{
+    CPUState *cs;
+
+    g_assert(bql_locked());
+
+    if (qemu_loglevel_mask(LOG_GUEST_ERROR) &&
+        (env->k0_lock_state != HEX_LOCK_UNLOCKED ||
+         env->tlb_lock_state != HEX_LOCK_UNLOCKED)) {
+        qemu_log("WARNING: executing wait() with acquired lock"
+                 "may lead to deadlock\n");
+    }
+    g_assert(get_exe_mode(env) != HEX_EXE_MODE_WAIT);
+
+    cs = env_cpu(env);
+    /*
+     * The addtion of cpu_has_work is borrowed from arm's wfi helper
+     * and is critical for our stability
+     */
+    if ((cs->exception_index != HEX_EVENT_NONE) ||
+        (cpu_has_work(cs))) {
+        qemu_log_mask(CPU_LOG_INT,
+            "%s: thread %" PRIu32 " skipping WAIT mode, have some work\n",
+            __func__, env->threadId);
+        return;
+    }
+    set_wait_mode(env);
+    env->wait_next_pc = PC + 4;
+
+    cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+}
+
+void HELPER(wait)(CPUHexagonState *env, uint32_t PC)
+{
+    BQL_LOCK_GUARD();
+
+    if (!fIN_DEBUG_MODE(env->threadId)) {
+        hexagon_wait_thread(env, PC);
+    }
 }
 
 void HELPER(resume)(CPUHexagonState *env, uint32_t mask)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 45/76] target/hexagon: Implement get_exe_mode()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (43 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 44/76] target/hexagon: Implement wait helper Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 46/76] target/hexagon: Implement hex_tlb_entry_get_perm() Brian Cain
                   ` (31 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/reg_fields_def.h.inc | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/target/hexagon/reg_fields_def.h.inc b/target/hexagon/reg_fields_def.h.inc
index 9b112ccec64..d2c706d56b5 100644
--- a/target/hexagon/reg_fields_def.h.inc
+++ b/target/hexagon/reg_fields_def.h.inc
@@ -135,3 +135,14 @@ 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)
+
+/* ISDB ST fields */
+DEF_REG_FIELD(ISDBST_WAITRUN, 24, 8)
+DEF_REG_FIELD(ISDBST_ONOFF, 16, 8)
+DEF_REG_FIELD(ISDBST_DEBUGMODE, 8, 8)
+DEF_REG_FIELD(ISDBST_STUFFSTATUS, 5, 1)
+DEF_REG_FIELD(ISDBST_CMDSTATUS, 4, 1)
+DEF_REG_FIELD(ISDBST_PROCMODE, 3, 1)
+DEF_REG_FIELD(ISDBST_MBXINSTATUS, 2, 1)
+DEF_REG_FIELD(ISDBST_MBXOUTSTATUS, 1, 1)
+DEF_REG_FIELD(ISDBST_READY, 0, 1)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 46/76] target/hexagon: Implement hex_tlb_entry_get_perm()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (44 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 45/76] target/hexagon: Implement get_exe_mode() Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 47/76] target/hexagon: Implement software interrupt Brian Cain
                   ` (30 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier,
	Laurent Vivier, Helge Deller

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 linux-user/hexagon/cpu_loop.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c
index 9f54c7b3f96..0958c51fbb3 100644
--- a/linux-user/hexagon/cpu_loop.c
+++ b/linux-user/hexagon/cpu_loop.c
@@ -63,6 +63,13 @@ void cpu_loop(CPUHexagonState *env)
             break;
         case HEX_EVENT_PRECISE:
             switch (env->cause_code) {
+            case HEX_CAUSE_FETCH_NO_UPAGE:
+            case HEX_CAUSE_PRIV_NO_UREAD:
+            case HEX_CAUSE_PRIV_NO_UWRITE:
+            force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
+                    env->gpr[HEX_REG_PC]);
+
+            break;
             case HEX_CAUSE_PRIV_USER_NO_GINSN:
             case HEX_CAUSE_PRIV_USER_NO_SINSN:
             case HEX_CAUSE_INVALID_PACKET:
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 47/76] target/hexagon: Implement software interrupt
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (45 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 46/76] target/hexagon: Implement hex_tlb_entry_get_perm() Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 48/76] target/hexagon: Implement stack overflow exception Brian Cain
                   ` (29 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Mike Lambert, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Co-authored-by: Mike Lambert <mlambert@quicinc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/hexswi.h |  17 +++
 target/hexagon/cpu.c    |   1 +
 target/hexagon/hexswi.c | 271 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 289 insertions(+)
 create mode 100644 target/hexagon/hexswi.h
 create mode 100644 target/hexagon/hexswi.c

diff --git a/target/hexagon/hexswi.h b/target/hexagon/hexswi.h
new file mode 100644
index 00000000000..48c1ae6e4c1
--- /dev/null
+++ b/target/hexagon/hexswi.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXSWI_H
+#define HEXSWI_H
+
+
+#include "cpu.h"
+
+void hexagon_cpu_do_interrupt(CPUState *cpu);
+void register_trap_exception(CPUHexagonState *env, int type, int imm,
+                             uint32_t PC);
+
+#endif /* HEXSWI_H */
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 27f0ef50df2..ec0ca3ee678 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -34,6 +34,7 @@
 #include "sys_macros.h"
 #include "accel/tcg/cpu-ldst.h"
 #include "qemu/main-loop.h"
+#include "hex_interrupts.h"
 #endif
 
 static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
new file mode 100644
index 00000000000..43c373ea2ee
--- /dev/null
+++ b/target/hexagon/hexswi.c
@@ -0,0 +1,271 @@
+/*
+ * 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 "exec/helper-proto.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "arch.h"
+#include "internal.h"
+#include "macros.h"
+#include "sys_macros.h"
+#include "accel/tcg/cpu-loop.h"
+#include "tcg/tcg-op.h"
+#include "hex_mmu.h"
+#include "hexswi.h"
+#include "hw/hexagon/hexagon_globalreg.h"
+
+#ifdef CONFIG_USER_ONLY
+#error "This file is only used in system emulation"
+#endif
+
+static void set_addresses(CPUHexagonState *env, uint32_t pc_offset,
+                          uint32_t exception_index)
+
+{
+    HexagonCPU *cpu = env_archcpu(env);
+    uint32_t evb = cpu->globalregs ?
+        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
+                               env->threadId) :
+        cpu->boot_addr;
+    env->t_sreg[HEX_SREG_ELR] = env->gpr[HEX_REG_PC] + pc_offset;
+    env->gpr[HEX_REG_PC] = evb | (exception_index << 2);
+}
+
+static const char *event_name[] = {
+    [HEX_EVENT_RESET] = "HEX_EVENT_RESET",
+    [HEX_EVENT_IMPRECISE] = "HEX_EVENT_IMPRECISE",
+    [HEX_EVENT_PRECISE] = "HEX_EVENT_PRECISE",
+    [HEX_EVENT_TLB_MISS_X] = "HEX_EVENT_TLB_MISS_X",
+    [HEX_EVENT_TLB_MISS_RW] = "HEX_EVENT_TLB_MISS_RW",
+    [HEX_EVENT_TRAP0] = "HEX_EVENT_TRAP0",
+    [HEX_EVENT_TRAP1] = "HEX_EVENT_TRAP1",
+    [HEX_EVENT_FPTRAP] = "HEX_EVENT_FPTRAP",
+    [HEX_EVENT_DEBUG] = "HEX_EVENT_DEBUG",
+    [HEX_EVENT_INT0] = "HEX_EVENT_INT0",
+    [HEX_EVENT_INT1] = "HEX_EVENT_INT1",
+    [HEX_EVENT_INT2] = "HEX_EVENT_INT2",
+    [HEX_EVENT_INT3] = "HEX_EVENT_INT3",
+    [HEX_EVENT_INT4] = "HEX_EVENT_INT4",
+    [HEX_EVENT_INT5] = "HEX_EVENT_INT5",
+    [HEX_EVENT_INT6] = "HEX_EVENT_INT6",
+    [HEX_EVENT_INT7] = "HEX_EVENT_INT7",
+    [HEX_EVENT_INT8] = "HEX_EVENT_INT8",
+    [HEX_EVENT_INT9] = "HEX_EVENT_INT9",
+    [HEX_EVENT_INTA] = "HEX_EVENT_INTA",
+    [HEX_EVENT_INTB] = "HEX_EVENT_INTB",
+    [HEX_EVENT_INTC] = "HEX_EVENT_INTC",
+    [HEX_EVENT_INTD] = "HEX_EVENT_INTD",
+    [HEX_EVENT_INTE] = "HEX_EVENT_INTE",
+    [HEX_EVENT_INTF] = "HEX_EVENT_INTF"
+};
+
+void hexagon_cpu_do_interrupt(CPUState *cs)
+
+{
+    CPUHexagonState *env = cpu_env(cs);
+    uint32_t ssr;
+
+    BQL_LOCK_GUARD();
+
+    qemu_log_mask(CPU_LOG_INT,
+                  "\t%s: event 0x%02x:%s, cause 0x%" PRIx32 "(%" PRIu32 ")\n",
+                  __func__, (unsigned)cs->exception_index,
+                  event_name[cs->exception_index], env->cause_code,
+                  env->cause_code);
+
+    env->llsc_addr = ~0;
+
+    ssr = env->t_sreg[HEX_SREG_SSR];
+    if (GET_SSR_FIELD(SSR_EX, ssr) == 1) {
+        HexagonCPU *cpu = env_archcpu(env);
+        if (cpu->globalregs) {
+            hexagon_globalreg_write(cpu->globalregs, HEX_SREG_DIAG,
+                                    env->cause_code, env->threadId);
+        }
+        env->cause_code = HEX_CAUSE_DOUBLE_EXCEPT;
+        cs->exception_index = HEX_EVENT_PRECISE;
+    }
+
+    switch (cs->exception_index) {
+    case HEX_EVENT_TRAP0:
+        if (env->cause_code == 0) {
+            qemu_log_mask(LOG_UNIMP,
+                          "trap0 is unhandled, no semihosting available\n");
+        }
+
+        hexagon_ssr_set_cause(env, env->cause_code);
+        set_addresses(env, 4, cs->exception_index);
+        break;
+
+    case HEX_EVENT_TRAP1:
+        hexagon_ssr_set_cause(env, env->cause_code);
+        set_addresses(env, 4, cs->exception_index);
+        break;
+
+    case HEX_EVENT_TLB_MISS_X:
+        switch (env->cause_code) {
+        case HEX_CAUSE_TLBMISSX_CAUSE_NORMAL:
+        case HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE:
+            qemu_log_mask(CPU_LOG_MMU,
+                          "TLB miss EX exception (0x%02" PRIx32 ") caught: "
+                          "Cause code (0x%" PRIx32 ") "
+                          "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32
+                          ", BADVA = 0x%" PRIx32 "\n",
+                          (uint32_t)cs->exception_index,
+                          env->cause_code, env->threadId,
+                          env->gpr[HEX_REG_PC],
+                          env->t_sreg[HEX_SREG_BADVA]);
+
+            hexagon_ssr_set_cause(env, env->cause_code);
+            set_addresses(env, 0, cs->exception_index);
+            break;
+
+        default:
+            cpu_abort(cs,
+                      "1:Hexagon exception %" PRId32 "/0x%02" PRIx32 ": "
+                      "Unknown cause code %" PRIu32 "/0x%" PRIx32 "\n",
+                      (uint32_t)cs->exception_index,
+                      (uint32_t)cs->exception_index,
+                      env->cause_code,
+                      env->cause_code);
+            break;
+        }
+        break;
+
+    case HEX_EVENT_TLB_MISS_RW:
+        switch (env->cause_code) {
+        case HEX_CAUSE_TLBMISSRW_CAUSE_READ:
+        case HEX_CAUSE_TLBMISSRW_CAUSE_WRITE:
+            qemu_log_mask(CPU_LOG_MMU,
+                          "TLB miss RW exception (0x%02" PRIx32 ") caught: "
+                          "Cause code (0x%" PRIx32 ") "
+                          "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32
+                          ", BADVA = 0x%" PRIx32 "\n",
+                          (uint32_t)cs->exception_index,
+                          env->cause_code, env->threadId,
+                          env->gpr[HEX_REG_PC],
+                          env->t_sreg[HEX_SREG_BADVA]);
+
+            hexagon_ssr_set_cause(env, env->cause_code);
+            set_addresses(env, 0, cs->exception_index);
+            /* env->sreg[HEX_SREG_BADVA] is set when the exception is raised */
+            break;
+
+        default:
+            cpu_abort(cs,
+                      "2:Hexagon exception %" PRId32 "/0x%02" PRIx32 ": "
+                      "Unknown cause code %" PRIu32 "/0x%" PRIx32 "\n",
+                      (uint32_t)cs->exception_index,
+                      (uint32_t)cs->exception_index,
+                      env->cause_code,
+                      env->cause_code);
+            break;
+        }
+        break;
+
+    case HEX_EVENT_FPTRAP:
+        hexagon_ssr_set_cause(env, env->cause_code);
+        set_addresses(env, 0, cs->exception_index);
+        break;
+
+    case HEX_EVENT_DEBUG:
+        hexagon_ssr_set_cause(env, env->cause_code);
+        set_addresses(env, 0, cs->exception_index);
+        qemu_log_mask(LOG_UNIMP, "single-step exception is not handled\n");
+        break;
+
+    case HEX_EVENT_PRECISE:
+        switch (env->cause_code) {
+        case HEX_CAUSE_FETCH_NO_XPAGE:
+        case HEX_CAUSE_FETCH_NO_UPAGE:
+        case HEX_CAUSE_PRIV_NO_READ:
+        case HEX_CAUSE_PRIV_NO_UREAD:
+        case HEX_CAUSE_PRIV_NO_WRITE:
+        case HEX_CAUSE_PRIV_NO_UWRITE:
+        case HEX_CAUSE_MISALIGNED_LOAD:
+        case HEX_CAUSE_MISALIGNED_STORE:
+        case HEX_CAUSE_PC_NOT_ALIGNED:
+            qemu_log_mask(CPU_LOG_MMU,
+                          "MMU permission exception (0x%02" PRIx32 ") caught: "
+                          "Cause code (0x%" PRIx32 ") "
+                          "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32
+                          ", BADVA = 0x%" PRIx32 "\n",
+                          (uint32_t)cs->exception_index,
+                          env->cause_code, env->threadId,
+                          env->gpr[HEX_REG_PC],
+                          env->t_sreg[HEX_SREG_BADVA]);
+
+
+            hexagon_ssr_set_cause(env, env->cause_code);
+            set_addresses(env, 0, cs->exception_index);
+            /* env->sreg[HEX_SREG_BADVA] is set when the exception is raised */
+            break;
+
+        case HEX_CAUSE_DOUBLE_EXCEPT:
+        case HEX_CAUSE_PRIV_USER_NO_SINSN:
+        case HEX_CAUSE_PRIV_USER_NO_GINSN:
+        case HEX_CAUSE_INVALID_OPCODE:
+        case HEX_CAUSE_NO_COPROC_ENABLE:
+        case HEX_CAUSE_NO_COPROC2_ENABLE:
+        case HEX_CAUSE_UNSUPPORTED_HVX_64B:
+        case HEX_CAUSE_REG_WRITE_CONFLICT:
+        case HEX_CAUSE_VWCTRL_WINDOW_MISS:
+            hexagon_ssr_set_cause(env, env->cause_code);
+            set_addresses(env, 0, cs->exception_index);
+            break;
+
+        case HEX_CAUSE_COPROC_LDST:
+            hexagon_ssr_set_cause(env, env->cause_code);
+            set_addresses(env, 0, cs->exception_index);
+            break;
+
+        case HEX_CAUSE_STACK_LIMIT:
+            hexagon_ssr_set_cause(env, env->cause_code);
+            set_addresses(env, 0, cs->exception_index);
+            break;
+
+        default:
+            cpu_abort(cs,
+                      "3:Hexagon exception %" PRId32 "/0x%02" PRIx32 ": "
+                      "Unknown cause code %" PRIu32 "/0x%" PRIx32 "\n",
+                      (uint32_t)cs->exception_index,
+                      (uint32_t)cs->exception_index,
+                      env->cause_code,
+                      env->cause_code);
+            break;
+        }
+        break;
+
+    case HEX_EVENT_IMPRECISE:
+        qemu_log_mask(LOG_UNIMP,
+                "Imprecise exception: this case is not yet handled");
+        break;
+
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                "Hexagon Unsupported exception 0x%02x/0x%" PRIx32 "\n",
+                (unsigned)cs->exception_index, env->cause_code);
+        break;
+    }
+
+    cs->exception_index = HEX_EVENT_NONE;
+}
+
+void register_trap_exception(CPUHexagonState *env, int traptype, int imm,
+                             uint32_t PC)
+{
+    CPUState *cs = env_cpu(env);
+
+    cs->exception_index = (traptype == 0) ? HEX_EVENT_TRAP0 : HEX_EVENT_TRAP1;
+    ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
+
+    env->cause_code = imm;
+    env->gpr[HEX_REG_PC] = PC;
+    cpu_loop_exit(cs);
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 48/76] target/hexagon: Implement stack overflow exception
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (46 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 47/76] target/hexagon: Implement software interrupt Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 49/76] target/hexagon: Implement exec_interrupt, set_irq Brian Cain
                   ` (28 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Taylor Simpson, Pierrick Bouvier,
	Alessandro Di Federico, Anton Johansson

Implement the frame limit check for system emulation mode.  When
allocframe computes a new stack pointer below FRAMELIMIT, raise a
precise exception (HEX_CAUSE_STACK_LIMIT).  The check is skipped in
monitor mode.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/helper.h                     |  1 +
 target/hexagon/idef-parser/parser-helpers.h |  2 ++
 target/hexagon/macros.h                     |  3 --
 target/hexagon/sys_macros.h                 |  4 +++
 target/hexagon/translate.h                  |  2 ++
 target/hexagon/genptr.c                     | 18 +++++++----
 target/hexagon/idef-parser/parser-helpers.c |  9 ++++++
 target/hexagon/op_helper.c                  | 36 +++++++++++++++++++++
 target/hexagon/idef-parser/idef-parser.y    |  3 ++
 9 files changed, 68 insertions(+), 10 deletions(-)

diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 0ec3a099cb6..aa3604dbdc5 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -109,6 +109,7 @@ 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_3(raise_stack_overflow, void, env, i32, i32)
 DEF_HELPER_2(swi, void, env, i32)
 DEF_HELPER_2(cswi, void, env, i32)
 DEF_HELPER_2(ciad, void, env, i32)
diff --git a/target/hexagon/idef-parser/parser-helpers.h b/target/hexagon/idef-parser/parser-helpers.h
index 2087d534a93..d3dfcec5690 100644
--- a/target/hexagon/idef-parser/parser-helpers.h
+++ b/target/hexagon/idef-parser/parser-helpers.h
@@ -295,6 +295,8 @@ void gen_cancel(Context *c, YYLTYPE *locp);
 
 void gen_load_cancel(Context *c, YYLTYPE *locp);
 
+void gen_framecheck(Context *c, YYLTYPE *locp, HexValue *addr, HexValue *ea);
+
 void gen_load(Context *c, YYLTYPE *locp, HexValue *size,
               HexSignedness signedness, HexValue *ea, HexValue *dst);
 
diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h
index 041e68a150e..21ab8ae5bbf 100644
--- a/target/hexagon/macros.h
+++ b/target/hexagon/macros.h
@@ -538,9 +538,6 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
 
 #ifdef CONFIG_USER_ONLY
 #define fFRAMECHECK(ADDR, EA) do { } while (0) /* Not modelled in linux-user */
-#else
-/* System mode not implemented yet */
-#define fFRAMECHECK(ADDR, EA)  g_assert_not_reached();
 #endif
 
 #ifdef QEMU_GENERATE
diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h
index ade57290166..707afc53e1f 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -97,6 +97,10 @@
 #define fTRAP(TRAPTYPE, IMM) \
     register_trap_exception(env, TRAPTYPE, IMM, PC)
 
+#ifdef QEMU_GENERATE
+#define fFRAMECHECK(ADDR, EA) gen_framecheck(ctx, ADDR, EA)
+#endif
+
 #define fVIRTINSN_SPSWAP(IMM, REG)
 #define fVIRTINSN_GETIE(IMM, REG) { REG = 0xdeafbeef; }
 #define fVIRTINSN_SETIE(IMM, REG)
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 208cf141e7e..f79bdedd7b6 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -341,4 +341,6 @@ FIELD(PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED,     3, 1)
 FIELD(PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED,     4, 1)
 FIELD(PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX,        5, 2)
 
+void gen_framecheck(DisasContext *ctx, TCGv_i32 addr, TCGv_i32 ea);
+
 #endif
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index ee69feae4b0..1ebc7471409 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -893,26 +893,30 @@ static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA)
     tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_LE | MO_UQ);
 }
 
-#ifndef CONFIG_HEXAGON_IDEF_PARSER
 /* Stack overflow check */
-static void gen_framecheck(TCGv EA, int framesize)
+void gen_framecheck(DisasContext *ctx, TCGv_i32 addr, TCGv_i32 ea)
 {
-    /* Not modelled in linux-user mode */
-    /* Placeholder for system mode */
 #ifndef CONFIG_USER_ONLY
-    g_assert_not_reached();
+    TCGLabel *ok = gen_new_label();
+    tcg_gen_brcond_i32(TCG_COND_GEU, addr, hex_gpr[HEX_REG_FRAMELIMIT], ok);
+    gen_helper_raise_stack_overflow(tcg_env,
+                                   tcg_constant_i32(ctx->insn->slot), ea);
+    gen_set_label(ok);
 #endif
 }
 
+#ifndef CONFIG_HEXAGON_IDEF_PARSER
 static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize)
 {
     TCGv r30 = get_result_gpr(ctx, HEX_REG_FP);
+    TCGv_i32 new_r29 = tcg_temp_new_i32();
     TCGv_i64 frame;
     tcg_gen_addi_tl(r30, r29, -8);
     frame = gen_frame_scramble();
     gen_store8(tcg_env, r30, frame, ctx->insn->slot);
-    gen_framecheck(r30, framesize);
-    tcg_gen_subi_tl(r29, r30, framesize);
+    tcg_gen_subi_tl(new_r29, r30, framesize);
+    gen_framecheck(ctx, new_r29, hex_gpr[HEX_REG_PC]);
+    tcg_gen_mov_tl(r29, new_r29);
 }
 
 static void gen_deallocframe(DisasContext *ctx, TCGv_i64 r31_30, TCGv r30)
diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c
index 70bfa64432d..b942d9ea16b 100644
--- a/target/hexagon/idef-parser/parser-helpers.c
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -1731,6 +1731,15 @@ void gen_load_cancel(Context *c, YYLTYPE *locp)
     OUT(c, locp, "}\n");
 }
 
+void gen_framecheck(Context *c, YYLTYPE *locp, HexValue *addr, HexValue *ea)
+{
+    HexValue addr_m = rvalue_materialize(c, locp, addr);
+    HexValue ea_m = rvalue_materialize(c, locp, ea);
+    addr_m = gen_rvalue_truncate(c, locp, &addr_m);
+    ea_m = gen_rvalue_truncate(c, locp, &ea_m);
+    OUT(c, locp, "gen_framecheck(ctx, ", &addr_m, ", ", &ea_m, ");\n");
+}
+
 void gen_load(Context *c, YYLTYPE *locp, HexValue *width,
               HexSignedness signedness, HexValue *ea, HexValue *dst)
 {
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 9d50e6ef882..a8bf89ab996 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1393,6 +1393,42 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
 }
 
 #ifndef CONFIG_USER_ONLY
+void HELPER(raise_stack_overflow)(CPUHexagonState *env, uint32_t slot,
+                                  uint32_t badva)
+{
+    /*
+     * Per section 7.3.1 of the V67 Programmer's Reference,
+     * stack limit exception isn't raised in monitor mode.
+     */
+    uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
+    CPUState *cs;
+
+    if (GET_SSR_FIELD(SSR_EX, ssr) ||
+        !GET_SSR_FIELD(SSR_UM, ssr)) {
+        return;
+    }
+
+    cs = env_cpu(env);
+    cs->exception_index = HEX_EVENT_PRECISE;
+    env->cause_code = HEX_CAUSE_STACK_LIMIT;
+    ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
+
+    if (slot == 0) {
+        env->t_sreg[HEX_SREG_BADVA0] = badva;
+        SET_SSR_FIELD(env, SSR_V0, 1);
+        SET_SSR_FIELD(env, SSR_V1, 0);
+        SET_SSR_FIELD(env, SSR_BVS, 0);
+    } else if (slot == 1) {
+        env->t_sreg[HEX_SREG_BADVA1] = badva;
+        SET_SSR_FIELD(env, SSR_V0, 0);
+        SET_SSR_FIELD(env, SSR_V1, 1);
+        SET_SSR_FIELD(env, SSR_BVS, 1);
+    } else {
+        g_assert_not_reached();
+    }
+    cpu_loop_exit_restore(cs, 0);
+}
+
 void HELPER(ciad)(CPUHexagonState *env, uint32_t mask)
 {
     g_assert_not_reached();
diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y
index caba0d2644d..3cffafa5b76 100644
--- a/target/hexagon/idef-parser/idef-parser.y
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -404,6 +404,9 @@ control_statement : frame_check
                   ;
 
 frame_check : FCHK '(' rvalue ',' rvalue ')' ';'
+              {
+                  gen_framecheck(c, &@1, &$3, &$5);
+              }
             ;
 
 cancel_statement : LOAD_CANCEL
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 49/76] target/hexagon: Implement exec_interrupt, set_irq
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (47 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 48/76] target/hexagon: Implement stack overflow exception Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 50/76] target/hexagon: add simple cpu_exec_reset and pointer_wrap Brian Cain
                   ` (27 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/cpu.c | 84 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index ec0ca3ee678..0d6551dd5b6 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -16,6 +16,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/log.h"
 #include "qemu/qemu-print.h"
 #include "cpu.h"
 #include "internal.h"
@@ -31,10 +32,12 @@
 #include "hex_mmu.h"
 
 #ifndef CONFIG_USER_ONLY
+#include "macros.h"
 #include "sys_macros.h"
 #include "accel/tcg/cpu-ldst.h"
 #include "qemu/main-loop.h"
 #include "hex_interrupts.h"
+#include "exec/cpu-interrupt.h"
 #endif
 
 static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
@@ -304,6 +307,36 @@ static void hexagon_cpu_synchronize_from_tb(CPUState *cs,
     cpu_env(cs)->gpr[HEX_REG_PC] = tb->pc;
 }
 
+#ifndef CONFIG_USER_ONLY
+bool hexagon_thread_is_enabled(CPUHexagonState *env)
+{
+    HexagonCPU *cpu = env_archcpu(env);
+    uint32_t modectl;
+    uint32_t thread_enabled_mask;
+    bool E_bit;
+
+    if (!cpu->globalregs) {
+        return true;
+    }
+    modectl =
+        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+                               env->threadId);
+    thread_enabled_mask = GET_FIELD(MODECTL_E, modectl);
+    E_bit = thread_enabled_mask & (0x1 << env->threadId);
+
+    return E_bit;
+}
+
+static bool hexagon_cpu_has_work(CPUState *cs)
+{
+    CPUHexagonState *env = cpu_env(cs);
+
+    return hexagon_thread_is_enabled(env) &&
+        (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI
+            | CPU_INTERRUPT_K0_UNLOCK | CPU_INTERRUPT_TLB_UNLOCK));
+}
+#endif
+
 static void hexagon_restore_state_to_opc(CPUState *cs,
                                          const TranslationBlock *tb,
                                          const uint64_t *data)
@@ -412,10 +445,58 @@ static int hexagon_cpu_mmu_index(CPUState *cs, bool ifetch)
     return MMU_USER_IDX;
 }
 
+#ifndef CONFIG_USER_ONLY
+static void hexagon_cpu_set_irq(void *opaque, int irq, int level)
+{
+    HexagonCPU *cpu = HEXAGON_CPU(opaque);
+    CPUState *cs = CPU(cpu);
+    CPUHexagonState *env = cpu_env(cs);
+
+    switch (irq) {
+    case HEXAGON_CPU_IRQ_0 ... HEXAGON_CPU_IRQ_7:
+        qemu_log_mask(CPU_LOG_INT, "%s: irq %d, level %d\n",
+                      __func__, irq, level);
+        if (level) {
+            hex_raise_interrupts(env, 1 << irq, CPU_INTERRUPT_HARD);
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+#endif
+
 static void hexagon_cpu_init(Object *obj)
 {
+#ifndef CONFIG_USER_ONLY
+    HexagonCPU *cpu = HEXAGON_CPU(obj);
+    qdev_init_gpio_in(DEVICE(cpu), hexagon_cpu_set_irq, 8);
+#endif
 }
 
+#ifndef CONFIG_USER_ONLY
+
+static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+    CPUHexagonState *env = cpu_env(cs);
+    if (interrupt_request & CPU_INTERRUPT_TLB_UNLOCK) {
+        cs->halted = false;
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_TLB_UNLOCK);
+        return true;
+    }
+    if (interrupt_request & CPU_INTERRUPT_K0_UNLOCK) {
+        cs->halted = false;
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_K0_UNLOCK);
+        return true;
+    }
+    if (interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI)) {
+        return hex_check_interrupts(env);
+    }
+    return false;
+}
+
+#endif
+
 static const TCGCPUOps hexagon_tcg_ops = {
     /* MTTCG not yet supported: require strict ordering */
     .guest_default_memory_order = TCG_MO_ALL,
@@ -426,6 +507,9 @@ static const TCGCPUOps hexagon_tcg_ops = {
     .synchronize_from_tb = hexagon_cpu_synchronize_from_tb,
     .restore_state_to_opc = hexagon_restore_state_to_opc,
     .mmu_index = hexagon_cpu_mmu_index,
+#ifndef CONFIG_USER_ONLY
+    .cpu_exec_interrupt = hexagon_cpu_exec_interrupt,
+#endif /* !CONFIG_USER_ONLY */
 };
 
 static void hexagon_cpu_class_init(ObjectClass *c, const void *data)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 50/76] target/hexagon: add simple cpu_exec_reset and pointer_wrap
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (48 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 49/76] target/hexagon: Implement exec_interrupt, set_irq Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 51/76] target/hexagon: Implement hexagon_tlb_fill() Brian Cain
                   ` (26 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Matheus Tavares Bernardino, Taylor Simpson,
	Pierrick Bouvier

From: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>

Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/cpu.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 0d6551dd5b6..edde4b1db84 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -495,6 +495,12 @@ static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
     return false;
 }
 
+static vaddr hexagon_pointer_wrap(CPUState *cs, int mmu_idx,
+                                  vaddr result, vaddr base)
+{
+    return result;
+}
+
 #endif
 
 static const TCGCPUOps hexagon_tcg_ops = {
@@ -509,6 +515,8 @@ static const TCGCPUOps hexagon_tcg_ops = {
     .mmu_index = hexagon_cpu_mmu_index,
 #ifndef CONFIG_USER_ONLY
     .cpu_exec_interrupt = hexagon_cpu_exec_interrupt,
+    .pointer_wrap = hexagon_pointer_wrap,
+    .cpu_exec_reset = cpu_reset,
 #endif /* !CONFIG_USER_ONLY */
 };
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 51/76] target/hexagon: Implement hexagon_tlb_fill()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (49 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 50/76] target/hexagon: add simple cpu_exec_reset and pointer_wrap Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 52/76] target/hexagon: Implement siad inst Brian Cain
                   ` (25 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/cpu.c | 136 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)

diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index edde4b1db84..4e5a25744a1 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -38,6 +38,9 @@
 #include "qemu/main-loop.h"
 #include "hex_interrupts.h"
 #include "exec/cpu-interrupt.h"
+#include "exec/page-protection.h"
+#include "exec/target_page.h"
+#include "hw/hexagon/hexagon_globalreg.h"
 #endif
 
 static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
@@ -475,6 +478,138 @@ static void hexagon_cpu_init(Object *obj)
 }
 
 #ifndef CONFIG_USER_ONLY
+static bool get_physical_address(CPUHexagonState *env, hwaddr *phys, int *prot,
+                                 uint64_t *size, int32_t *excp,
+                                 uint32_t address,
+                                 MMUAccessType access_type, int mmu_idx)
+
+{
+    if (hexagon_cpu_mmu_enabled(env)) {
+        return hex_tlb_find_match(env, address, access_type, phys, prot, size,
+                                  excp, mmu_idx);
+    } else {
+        *phys = address & 0xFFFFFFFF;
+        *prot = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        *size = TARGET_PAGE_SIZE;
+        return true;
+    }
+}
+
+/* qemu seems to only want to know about TARGET_PAGE_SIZE pages */
+static void find_qemu_subpage(vaddr *addr, hwaddr *phys, uint64_t page_size)
+{
+    vaddr page_start = *addr & ~((vaddr)(page_size - 1));
+    vaddr offset = ((*addr - page_start) / TARGET_PAGE_SIZE) * TARGET_PAGE_SIZE;
+    *addr = page_start + offset;
+    *phys += offset;
+}
+
+
+#define INVALID_BADVA 0xbadabada
+
+static void set_badva_regs(CPUHexagonState *env, uint32_t VA, int slot,
+                           MMUAccessType access_type)
+{
+    env->t_sreg[HEX_SREG_BADVA] = VA;
+
+    if (access_type == MMU_INST_FETCH || slot == 0) {
+        env->t_sreg[HEX_SREG_BADVA0] = VA;
+        env->t_sreg[HEX_SREG_BADVA1] = INVALID_BADVA;
+        SET_SSR_FIELD(env, SSR_V0, 1);
+        SET_SSR_FIELD(env, SSR_V1, 0);
+        SET_SSR_FIELD(env, SSR_BVS, 0);
+    } else if (slot == 1) {
+        env->t_sreg[HEX_SREG_BADVA0] = INVALID_BADVA;
+        env->t_sreg[HEX_SREG_BADVA1] = VA;
+        SET_SSR_FIELD(env, SSR_V0, 0);
+        SET_SSR_FIELD(env, SSR_V1, 1);
+        SET_SSR_FIELD(env, SSR_BVS, 1);
+    } else {
+        g_assert_not_reached();
+    }
+}
+
+static void raise_tlbmiss_exception(CPUState *cs, uint32_t VA, int slot,
+                                    MMUAccessType access_type)
+{
+    CPUHexagonState *env = cpu_env(cs);
+
+    set_badva_regs(env, VA, slot, access_type);
+
+    switch (access_type) {
+    case MMU_INST_FETCH:
+        cs->exception_index = HEX_EVENT_TLB_MISS_X;
+        if ((VA & ~TARGET_PAGE_MASK) == 0) {
+            env->cause_code = HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE;
+        } else {
+            env->cause_code = HEX_CAUSE_TLBMISSX_CAUSE_NORMAL;
+        }
+        break;
+    case MMU_DATA_LOAD:
+        cs->exception_index = HEX_EVENT_TLB_MISS_RW;
+        env->cause_code = HEX_CAUSE_TLBMISSRW_CAUSE_READ;
+        break;
+    case MMU_DATA_STORE:
+        cs->exception_index = HEX_EVENT_TLB_MISS_RW;
+        env->cause_code = HEX_CAUSE_TLBMISSRW_CAUSE_WRITE;
+        break;
+    }
+}
+
+static void raise_perm_exception(CPUState *cs, uint32_t VA, int slot,
+                                 MMUAccessType access_type, int32_t excp)
+{
+    CPUHexagonState *env = cpu_env(cs);
+
+    set_badva_regs(env, VA, slot, access_type);
+    cs->exception_index = excp;
+}
+
+static const char *access_type_names[] = { "MMU_DATA_LOAD ", "MMU_DATA_STORE",
+                                           "MMU_INST_FETCH" };
+
+static const char *mmu_idx_names[] = { "MMU_USER_IDX", "MMU_GUEST_IDX",
+                                       "MMU_KERNEL_IDX" };
+
+static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size,
+                             MMUAccessType access_type, int mmu_idx, bool probe,
+                             uintptr_t retaddr)
+{
+    CPUHexagonState *env = cpu_env(cs);
+    int slot = 0;
+    hwaddr phys;
+    int prot = 0;
+    uint64_t page_size = 0;
+    int32_t excp = 0;
+    bool ret = 0;
+
+    qemu_log_mask(
+        CPU_LOG_MMU,
+        "%s: tid = 0x%" PRIx32 ", pc = 0x%08" PRIx32
+        ", vaddr = 0x%08" VADDR_PRIx ", size = %d, %s,\tprobe = %d, %s\n",
+        __func__, env->threadId, env->gpr[HEX_REG_PC], address, size,
+        access_type_names[access_type], probe, mmu_idx_names[mmu_idx]);
+    ret = get_physical_address(env, &phys, &prot, &page_size, &excp, address,
+                               access_type, mmu_idx);
+    if (ret) {
+        if (!excp) {
+            find_qemu_subpage(&address, &phys, page_size);
+            tlb_set_page(cs, address, phys, prot, mmu_idx, TARGET_PAGE_SIZE);
+            return ret;
+        }
+        if (probe) {
+            return false;
+        }
+        raise_perm_exception(cs, address, slot, access_type, excp);
+        do_raise_exception(env, cs->exception_index, env->gpr[HEX_REG_PC],
+                           retaddr);
+    }
+    if (probe) {
+        return false;
+    }
+    raise_tlbmiss_exception(cs, address, slot, access_type);
+    do_raise_exception(env, cs->exception_index, env->gpr[HEX_REG_PC], retaddr);
+}
 
 static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
@@ -517,6 +652,7 @@ static const TCGCPUOps hexagon_tcg_ops = {
     .cpu_exec_interrupt = hexagon_cpu_exec_interrupt,
     .pointer_wrap = hexagon_pointer_wrap,
     .cpu_exec_reset = cpu_reset,
+    .tlb_fill = hexagon_tlb_fill,
 #endif /* !CONFIG_USER_ONLY */
 };
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 52/76] target/hexagon: Implement siad inst
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (50 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 51/76] target/hexagon: Implement hexagon_tlb_fill() Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 53/76] target/hexagon: Implement hexagon_resume_threads() Brian Cain
                   ` (24 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

siad is the 'Set interrupt auto disable' instruction.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/op_helper.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index a8bf89ab996..4d319a2637f 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1436,7 +1436,22 @@ void HELPER(ciad)(CPUHexagonState *env, uint32_t mask)
 
 void HELPER(siad)(CPUHexagonState *env, uint32_t mask)
 {
-    g_assert_not_reached();
+    uint32_t ipendad;
+    uint32_t iad;
+    HexagonCPU *cpu;
+
+    BQL_LOCK_GUARD();
+    cpu = env_archcpu(env);
+    ipendad = cpu->globalregs ?
+        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
+                               env->threadId) : 0;
+    iad = fGET_FIELD(ipendad, IPENDAD_IAD);
+    fSET_FIELD(ipendad, IPENDAD_IAD, iad | mask);
+    if (cpu->globalregs) {
+        hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD,
+                                ipendad, env->threadId);
+    }
+    hex_interrupt_update(env);
 }
 
 void HELPER(swi)(CPUHexagonState *env, uint32_t mask)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 53/76] target/hexagon: Implement hexagon_resume_threads()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (51 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 52/76] target/hexagon: Implement siad inst Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 54/76] target/hexagon: Implement setprio, resched Brian Cain
                   ` (23 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/cpu.h       | 1 +
 target/hexagon/op_helper.c | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 92d4bb97129..6a95a6bc5b1 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -52,6 +52,7 @@ typedef struct HexagonGlobalRegState HexagonGlobalRegState;
 #define PRED_WRITES_MAX 5                   /* 4 insns + endloop */
 #define VSTORES_MAX 2
 #define MAX_TLB_ENTRIES 1024
+#define THREADS_MAX 8
 
 #define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU
 #ifndef CONFIG_USER_ONLY
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 4d319a2637f..34c55b560ca 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1601,7 +1601,8 @@ void HELPER(wait)(CPUHexagonState *env, uint32_t PC)
 
 void HELPER(resume)(CPUHexagonState *env, uint32_t mask)
 {
-    g_assert_not_reached();
+    BQL_LOCK_GUARD();
+    hexagon_resume_threads(env, mask);
 }
 
 uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 54/76] target/hexagon: Implement setprio, resched
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (52 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 53/76] target/hexagon: Implement hexagon_resume_threads() Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 55/76] target/hexagon: Add sysemu_ops, cpu_get_phys_page_debug() Brian Cain
                   ` (22 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Brian Cain, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

The hardware-assisted scheduler helps manage tasks on the run queue
and interrupt steering.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/op_helper.c | 77 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 34c55b560ca..3c253b391e7 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1590,6 +1590,64 @@ static void hexagon_wait_thread(CPUHexagonState *env, uint32_t PC)
     cpu_interrupt(cs, CPU_INTERRUPT_HALT);
 }
 
+static inline QEMU_ALWAYS_INLINE void resched(CPUHexagonState *env)
+{
+    uint32_t schedcfg;
+    uint32_t schedcfg_en;
+    int int_number;
+    CPUState *cs;
+    uint32_t lowest_th_prio = 0; /* 0 is highest prio */
+    uint32_t bestwait_reg;
+    uint32_t best_prio;
+    HexagonCPU *cpu;
+
+    BQL_LOCK_GUARD();
+    qemu_log_mask(CPU_LOG_INT, "%s: check resched\n", __func__);
+    cpu = env_archcpu(env);
+    schedcfg = cpu->globalregs ?
+        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SCHEDCFG,
+                               env->threadId) : 0;
+    schedcfg_en = GET_FIELD(SCHEDCFG_EN, schedcfg);
+    int_number = GET_FIELD(SCHEDCFG_INTNO, schedcfg);
+
+    if (!schedcfg_en) {
+        return;
+    }
+
+    CPU_FOREACH(cs) {
+        HexagonCPU *thread = HEXAGON_CPU(cs);
+        CPUHexagonState *thread_env = &(thread->env);
+        uint32_t th_prio = GET_FIELD(
+            STID_PRIO, thread_env->t_sreg[HEX_SREG_STID]);
+        if (!hexagon_thread_is_enabled(thread_env)) {
+            continue;
+        }
+
+        lowest_th_prio = (lowest_th_prio > th_prio)
+            ? lowest_th_prio
+            : th_prio;
+    }
+
+    bestwait_reg = cpu->globalregs ?
+        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_BESTWAIT,
+                               env->threadId) : 0;
+    best_prio = GET_FIELD(BESTWAIT_PRIO, bestwait_reg);
+
+    /*
+     * If the lowest priority thread is lower priority than the
+     * value in the BESTWAIT register, we must raise the reschedule
+     * interrupt on the lowest priority thread.
+     */
+    if (lowest_th_prio > best_prio) {
+        qemu_log_mask(CPU_LOG_INT,
+                "%s: raising resched int %u,"
+                " cur PC 0x%" PRIx32 "\n",
+                __func__, (unsigned)int_number, env->gpr[HEX_REG_PC]);
+        SET_SYSTEM_FIELD(env, HEX_SREG_BESTWAIT, BESTWAIT_PRIO, ~0);
+        hex_raise_interrupts(env, 1 << int_number, CPU_INTERRUPT_SWI);
+    }
+}
+
 void HELPER(wait)(CPUHexagonState *env, uint32_t PC)
 {
     BQL_LOCK_GUARD();
@@ -1698,8 +1756,27 @@ uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg)
     g_assert_not_reached();
 }
 
+/*
+ * setprio/resched - hardware-assisted scheduler helpers for managing
+ * the run queue and interrupt steering.
+ */
 void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio)
 {
+    CPUState *cs;
+
+    BQL_LOCK_GUARD();
+    CPU_FOREACH(cs) {
+        HexagonCPU *found_cpu = HEXAGON_CPU(cs);
+        CPUHexagonState *found_env = &found_cpu->env;
+        if (thread == found_env->threadId) {
+            SET_SYSTEM_FIELD(found_env, HEX_SREG_STID, STID_PRIO, prio);
+            qemu_log_mask(CPU_LOG_INT,
+                          "%s: tid %" PRIu32 " prio = 0x%" PRIx32 "\n",
+                          __func__, found_env->threadId, prio);
+            resched(env);
+            return;
+        }
+    }
     g_assert_not_reached();
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 55/76] target/hexagon: Add sysemu_ops, cpu_get_phys_page_debug()
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (53 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 54/76] target/hexagon: Implement setprio, resched Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 56/76] target/hexagon: extend hexagon_cpu_mmu_index() for sysemu Brian Cain
                   ` (21 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/cpu.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 4e5a25744a1..670668808a8 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -20,6 +20,7 @@
 #include "qemu/qemu-print.h"
 #include "cpu.h"
 #include "internal.h"
+#include "exec/cputlb.h"
 #include "exec/translation-block.h"
 #include "qapi/error.h"
 #include "hw/core/qdev-properties.h"
@@ -37,6 +38,7 @@
 #include "accel/tcg/cpu-ldst.h"
 #include "qemu/main-loop.h"
 #include "hex_interrupts.h"
+#include "hexswi.h"
 #include "exec/cpu-interrupt.h"
 #include "exec/page-protection.h"
 #include "exec/target_page.h"
@@ -504,6 +506,24 @@ static void find_qemu_subpage(vaddr *addr, hwaddr *phys, uint64_t page_size)
     *phys += offset;
 }
 
+static hwaddr hexagon_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
+{
+    CPUHexagonState *env = cpu_env(cs);
+    hwaddr phys_addr;
+    int prot;
+    uint64_t page_size = 0;
+    int32_t excp = 0;
+    int mmu_idx = MMU_KERNEL_IDX;
+
+    if (get_physical_address(env, &phys_addr, &prot, &page_size, &excp,
+                             addr, 0, mmu_idx)) {
+        find_qemu_subpage(&addr, &phys_addr, page_size);
+        return phys_addr;
+    }
+
+    return -1;
+}
+
 
 #define INVALID_BADVA 0xbadabada
 
@@ -611,6 +631,13 @@ static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size,
     do_raise_exception(env, cs->exception_index, env->gpr[HEX_REG_PC], retaddr);
 }
 
+#include "hw/core/sysemu-cpu-ops.h"
+
+static const struct SysemuCPUOps hexagon_sysemu_ops = {
+    .has_work = hexagon_cpu_has_work,
+    .get_phys_addr_debug = hexagon_cpu_get_phys_addr_debug,
+};
+
 static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
     CPUHexagonState *env = cpu_env(cs);
@@ -653,6 +680,8 @@ static const TCGCPUOps hexagon_tcg_ops = {
     .pointer_wrap = hexagon_pointer_wrap,
     .cpu_exec_reset = cpu_reset,
     .tlb_fill = hexagon_tlb_fill,
+    .cpu_exec_halt = hexagon_cpu_has_work,
+    .do_interrupt = hexagon_cpu_do_interrupt,
 #endif /* !CONFIG_USER_ONLY */
 };
 
@@ -680,9 +709,12 @@ static void hexagon_cpu_class_init(ObjectClass *c, const void *data)
     cc->gdb_core_xml_file = "hexagon-core.xml";
     cc->disas_set_info = hexagon_cpu_disas_set_info;
 #ifndef CONFIG_USER_ONLY
+    cc->sysemu_ops = &hexagon_sysemu_ops;
     dc->vmsd = &vmstate_hexagon_cpu;
 #endif
+#ifdef CONFIG_TCG
     cc->tcg_ops = &hexagon_tcg_ops;
+#endif
 }
 
 static void hexagon_cpu_class_base_init(ObjectClass *c, const void *data)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 56/76] target/hexagon: extend hexagon_cpu_mmu_index() for sysemu
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (54 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 55/76] target/hexagon: Add sysemu_ops, cpu_get_phys_page_debug() Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 57/76] target/hexagon: Decode trap1, rte as COF Brian Cain
                   ` (20 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/cpu_helper.h |  8 ++++++++
 target/hexagon/cpu.c        | 24 ++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index 75a28fc10f9..d1767503156 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -8,6 +8,14 @@
 #define HEXAGON_CPU_HELPER_H
 
 uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index);
+void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
+int get_cpu_mode(CPUHexagonState *env);
+int get_exe_mode(CPUHexagonState *env);
+void clear_wait_mode(CPUHexagonState *env);
+void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause);
+void hexagon_start_threads(CPUHexagonState *env, uint32_t mask);
+void hexagon_stop_thread(CPUHexagonState *env);
+void hexagon_resume_threads(CPUHexagonState *env, uint32_t mask);
 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);
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 670668808a8..3af90e30b0f 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -447,6 +447,30 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
 
 static int hexagon_cpu_mmu_index(CPUState *cs, bool ifetch)
 {
+#ifndef CONFIG_USER_ONLY
+    CPUHexagonState *env = cpu_env(cs);
+    HexagonCPU *cpu = HEXAGON_CPU(cs);
+    int cpu_mode;
+
+    BQL_LOCK_GUARD();
+    if (cpu->globalregs) {
+        uint32_t syscfg =
+            hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
+                                   env->threadId);
+        uint8_t mmuen = GET_SYSCFG_FIELD(SYSCFG_MMUEN, syscfg);
+        if (!mmuen) {
+            return MMU_KERNEL_IDX;
+        }
+    }
+
+    cpu_mode = get_cpu_mode(env);
+    if (cpu_mode == HEX_CPU_MODE_MONITOR) {
+        return MMU_KERNEL_IDX;
+    } else if (cpu_mode == HEX_CPU_MODE_GUEST) {
+        return MMU_GUEST_IDX;
+    }
+#endif
+
     return MMU_USER_IDX;
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 57/76] target/hexagon: Decode trap1, rte as COF
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (55 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 56/76] target/hexagon: extend hexagon_cpu_mmu_index() for sysemu Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 58/76] target/hexagon: Implement modify_ssr, resched, pending_interrupt Brian Cain
                   ` (19 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Also: handle rte instructions at the end of the packet.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/decode.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c
index 15954518b83..6eddcca26ed 100644
--- a/target/hexagon/decode.c
+++ b/target/hexagon/decode.c
@@ -185,6 +185,8 @@ static bool decode_opcode_can_jump(int opcode)
     if ((GET_ATTRIB(opcode, A_JUMP)) ||
         (GET_ATTRIB(opcode, A_CALL)) ||
         (opcode == J2_trap0) ||
+        (opcode == J2_trap1) ||
+        (opcode == J2_rte) ||
         (opcode == J2_pause)) {
         /* Exception to A_JUMP attribute */
         if (opcode == J4_hintjumpr) {
@@ -363,6 +365,18 @@ static void decode_shuffle_for_execution(Packet *packet)
             break;
         }
     }
+    /*
+     * And at the very very very end, move any RTE's, since they update
+     * user/supervisor mode.
+     */
+#if !defined(CONFIG_USER_ONLY)
+    for (i = 0; i < last_insn; i++) {
+        if (packet->insn[i].opcode == J2_rte) {
+            decode_send_insn_to(packet, i, last_insn);
+            break;
+        }
+    }
+#endif
 }
 
 static void
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 58/76] target/hexagon: Implement modify_ssr, resched, pending_interrupt
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (56 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 57/76] target/hexagon: Decode trap1, rte as COF Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 59/76] target/hexagon: Add pkt_ends_tb to translation Brian Cain
                   ` (18 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/op_helper.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 3c253b391e7..9fbcd79c9d4 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1227,6 +1227,15 @@ float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
     return RxxV;
 }
 
+#ifndef CONFIG_USER_ONLY
+void HELPER(modify_ssr)(CPUHexagonState *env, uint32_t new, uint32_t old)
+{
+    BQL_LOCK_GUARD();
+    hexagon_modify_ssr(env, new, old);
+}
+#endif
+
+
 /* Histogram instructions */
 
 void HELPER(vhist)(CPUHexagonState *env)
@@ -1648,6 +1657,11 @@ static inline QEMU_ALWAYS_INLINE void resched(CPUHexagonState *env)
     }
 }
 
+void HELPER(resched)(CPUHexagonState *env)
+{
+    resched(env);
+}
+
 void HELPER(wait)(CPUHexagonState *env, uint32_t PC)
 {
     BQL_LOCK_GUARD();
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 59/76] target/hexagon: Add pkt_ends_tb to translation
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (57 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 58/76] target/hexagon: Implement modify_ssr, resched, pending_interrupt Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 60/76] target/hexagon: Add next_PC, {s,g}reg writes Brian Cain
                   ` (17 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/translate.h |   1 -
 target/hexagon/translate.c | 102 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index f79bdedd7b6..fea88cb2db7 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -86,7 +86,6 @@ typedef struct DisasContext {
     TCGv branch_taken;
     TCGv dczero_addr;
     bool pcycle_enabled;
-    bool pkt_ends_tb;
     uint32_t num_cycles;
 } DisasContext;
 
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index ce5bbe92d5d..35e90362880 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -270,6 +270,16 @@ static bool check_for_attrib(Packet *pkt, int attrib)
     return false;
 }
 
+static bool check_for_opcode(Packet *pkt, uint16_t opcode)
+{
+    for (int i = 0; i < pkt->num_insns; i++) {
+        if (pkt->insn[i].opcode == opcode) {
+            return true;
+        }
+    }
+    return false;
+}
+
 static bool need_slot_cancelled(Packet *pkt)
 {
     /* We only need slot_cancelled for conditional store instructions */
@@ -283,6 +293,90 @@ static bool need_slot_cancelled(Packet *pkt)
     return false;
 }
 
+#ifndef CONFIG_USER_ONLY
+static bool sreg_write_ends_tb(int reg_num)
+{
+    return reg_num == HEX_SREG_SSR ||
+           reg_num == HEX_SREG_STID ||
+           reg_num == HEX_SREG_IMASK ||
+           reg_num == HEX_SREG_IPENDAD ||
+           reg_num == HEX_SREG_BESTWAIT ||
+           reg_num == HEX_SREG_SCHEDCFG;
+}
+
+static bool has_sreg_write_ends_tb(Packet const *pkt)
+{
+    for (int i = 0; i < pkt->num_insns; i++) {
+        Insn const *insn = &pkt->insn[i];
+        uint16_t opcode = insn->opcode;
+        if (opcode == Y2_tfrsrcr) {
+            /* Write to a single sreg */
+            int reg_num = insn->regno[0];
+            if (sreg_write_ends_tb(reg_num)) {
+                return true;
+            }
+        } else if (opcode == Y4_tfrspcp) {
+            /* Write to a sreg pair */
+            int reg_num = insn->regno[0];
+            if (sreg_write_ends_tb(reg_num)) {
+                return true;
+            }
+            if (sreg_write_ends_tb(reg_num + 1)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+#endif
+
+static bool pkt_ends_tb(Packet *pkt)
+{
+    if (pkt->pkt_has_cof) {
+        return true;
+    }
+#ifndef CONFIG_USER_ONLY
+    /* System mode instructions that end TLB */
+    if (check_for_opcode(pkt, Y2_swi) ||
+        check_for_opcode(pkt, Y2_cswi) ||
+        check_for_opcode(pkt, Y2_ciad) ||
+        check_for_opcode(pkt, Y4_siad) ||
+        check_for_opcode(pkt, Y2_wait) ||
+        check_for_opcode(pkt, Y2_resume) ||
+        check_for_opcode(pkt, Y2_iassignw) ||
+        check_for_opcode(pkt, Y2_setimask) ||
+        check_for_opcode(pkt, Y4_nmi) ||
+        check_for_opcode(pkt, Y2_setprio) ||
+        check_for_opcode(pkt, Y2_start) ||
+        check_for_opcode(pkt, Y2_stop) ||
+        check_for_opcode(pkt, Y2_k0lock) ||
+        check_for_opcode(pkt, Y2_k0unlock) ||
+        check_for_opcode(pkt, Y2_tlblock) ||
+        check_for_opcode(pkt, Y2_tlbunlock) ||
+        check_for_opcode(pkt, Y2_break) ||
+        check_for_opcode(pkt, Y2_isync) ||
+        check_for_opcode(pkt, Y2_syncht) ||
+        check_for_opcode(pkt, Y2_tlbp) ||
+        check_for_opcode(pkt, Y2_tlbw) ||
+        check_for_opcode(pkt, Y5_ctlbw) ||
+        check_for_opcode(pkt, Y5_tlbasidi)) {
+        return true;
+    }
+
+    /*
+     * Check for sreg writes that would end the TB
+     */
+    if (check_for_attrib(pkt, A_IMPLICIT_WRITES_SSR)) {
+        return true;
+    }
+    if (has_sreg_write_ends_tb(pkt)) {
+        return true;
+    }
+#endif
+    return false;
+}
+
+
 static bool need_next_PC(DisasContext *ctx)
 {
     /* Check for conditional control flow or HW loop end */
@@ -439,7 +533,11 @@ static void analyze_packet(DisasContext *ctx)
 
 static void gen_start_packet(DisasContext *ctx)
 {
-    target_ulong next_PC = ctx->base.pc_next + ctx->pkt.encod_pkt_size_in_bytes;
+    Packet *pkt = &ctx->pkt;
+    target_ulong next_PC = (check_for_opcode(pkt, Y2_k0lock) ||
+                            check_for_opcode(pkt, Y2_tlblock)) ?
+                               ctx->base.pc_next :
+                               ctx->base.pc_next + pkt->encod_pkt_size_in_bytes;
     int i;
 
     /* Clear out the disassembly context */
@@ -944,7 +1042,7 @@ static void gen_commit_packet(DisasContext *ctx)
         ctx->pkt.vhist_insn->generate(ctx);
     }
 
-    if (ctx->pkt.pkt_has_cof) {
+    if (pkt_ends_tb(&ctx->pkt) || ctx->base.is_jmp == DISAS_NORETURN) {
         gen_end_tb(ctx);
     }
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 60/76] target/hexagon: Add next_PC, {s,g}reg writes
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (58 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 59/76] target/hexagon: Add pkt_ends_tb to translation Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 61/76] target/hexagon: Add implicit sysreg writes Brian Cain
                   ` (16 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Brian Cain, Pierrick Bouvier

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/translate.h |  2 +-
 target/hexagon/translate.c | 77 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 74 insertions(+), 5 deletions(-)

diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index fea88cb2db7..0a7f37d5842 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -46,7 +46,7 @@ typedef struct DisasContext {
     int greg_log_idx;
     int sreg_log[SREG_WRITES_MAX];
     int sreg_log_idx;
-    TCGv_i32 t_sreg_new_value[NUM_SREGS];
+    TCGv_i32 t_sreg_new_value[HEX_SREG_GLB_START];
     TCGv_i32 greg_new_value[NUM_GREGS];
 #endif
     int preg_log[PRED_WRITES_MAX];
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 35e90362880..f4a353958ff 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -545,6 +545,10 @@ static void gen_start_packet(DisasContext *ctx)
     ctx->reg_log_idx = 0;
     bitmap_zero(ctx->regs_written, TOTAL_PER_THREAD_REGS);
     bitmap_zero(ctx->predicated_regs, TOTAL_PER_THREAD_REGS);
+#ifndef CONFIG_USER_ONLY
+    ctx->greg_log_idx = 0;
+    ctx->sreg_log_idx = 0;
+#endif
     ctx->preg_log_idx = 0;
     bitmap_zero(ctx->pregs_written, NUM_PREGS);
     ctx->future_vregs_idx = 0;
@@ -577,6 +581,25 @@ static void gen_start_packet(DisasContext *ctx)
      * gen phase, so clear it again.
      */
     bitmap_zero(ctx->pregs_written, NUM_PREGS);
+#ifndef CONFIG_USER_ONLY
+    for (i = 0; i < HEX_SREG_GLB_START; i++) {
+        ctx->t_sreg_new_value[i] = NULL;
+    }
+    for (i = 0; i < ctx->sreg_log_idx; i++) {
+        int reg_num = ctx->sreg_log[i];
+        if (reg_num < HEX_SREG_GLB_START &&
+            (ctx->need_commit || reg_num == HEX_SREG_SSR)) {
+            ctx->t_sreg_new_value[reg_num] = tcg_temp_new();
+        }
+    }
+    for (i = 0; i < NUM_GREGS; i++) {
+        ctx->greg_new_value[i] = NULL;
+    }
+    for (i = 0; i < ctx->greg_log_idx; i++) {
+        int reg_num = ctx->greg_log[i];
+        ctx->greg_new_value[reg_num] = tcg_temp_new();
+    }
+#endif
 
     /* Initialize the runtime state for packet semantics */
     if (need_slot_cancelled(&ctx->pkt)) {
@@ -734,6 +757,50 @@ static void gen_reg_writes(DisasContext *ctx)
     }
 }
 
+#ifndef CONFIG_USER_ONLY
+static void gen_greg_writes(DisasContext *ctx)
+{
+    int i;
+
+    for (i = 0; i < ctx->greg_log_idx; i++) {
+        int reg_num = ctx->greg_log[i];
+
+        tcg_gen_mov_tl(hex_greg[reg_num], ctx->greg_new_value[reg_num]);
+    }
+}
+
+
+static void gen_sreg_writes(DisasContext *ctx)
+{
+    int i;
+
+    TCGv_i32 old_reg = tcg_temp_new_i32();
+    for (i = 0; i < ctx->sreg_log_idx; i++) {
+        int reg_num = ctx->sreg_log[i];
+
+        if (reg_num == HEX_SREG_SSR) {
+            tcg_gen_mov_tl(old_reg, hex_t_sreg[reg_num]);
+            tcg_gen_mov_tl(hex_t_sreg[reg_num], ctx->t_sreg_new_value[reg_num]);
+            gen_helper_modify_ssr(tcg_env, ctx->t_sreg_new_value[reg_num],
+                                  old_reg);
+        } else if ((reg_num == HEX_SREG_STID) ||
+                   (reg_num == HEX_SREG_IMASK) ||
+                   (reg_num == HEX_SREG_IPENDAD)) {
+            if (ctx->need_commit && reg_num < HEX_SREG_GLB_START) {
+                tcg_gen_mov_tl(hex_t_sreg[reg_num],
+                               ctx->t_sreg_new_value[reg_num]);
+            }
+            gen_helper_pending_interrupt(tcg_env);
+        } else if ((reg_num == HEX_SREG_BESTWAIT) ||
+                   (reg_num == HEX_SREG_SCHEDCFG)) {
+            gen_helper_resched(tcg_env);
+        } else if (ctx->need_commit && reg_num < HEX_SREG_GLB_START) {
+            tcg_gen_mov_tl(hex_t_sreg[reg_num], ctx->t_sreg_new_value[reg_num]);
+        }
+    }
+}
+#endif
+
 static void gen_pred_writes(DisasContext *ctx)
 {
     /* Early exit if not needed or the log is empty */
@@ -1030,6 +1097,10 @@ static void gen_commit_packet(DisasContext *ctx)
     process_store_log(ctx);
 
     gen_reg_writes(ctx);
+#ifndef CONFIG_USER_ONLY
+    gen_greg_writes(ctx);
+    gen_sreg_writes(ctx);
+#endif
     gen_pred_writes(ctx);
     if (ctx->pkt.pkt_has_hvx) {
         gen_commit_hvx(ctx);
@@ -1242,6 +1313,8 @@ void hexagon_translate_init(void)
     hex_llsc_val_i64 = tcg_global_mem_new_i64(tcg_env,
         offsetof(CPUHexagonState, llsc_val_i64), "llsc_val_i64");
 #ifndef CONFIG_USER_ONLY
+    hex_cause_code = tcg_global_mem_new_i32(tcg_env,
+        offsetof(CPUHexagonState, cause_code), "cause_code");
     hex_cycle_count = tcg_global_mem_new_i64(tcg_env,
         offsetof(CPUHexagonState, t_cycle_count), "t_cycle_count");
 #endif
@@ -1282,8 +1355,4 @@ 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
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 61/76] target/hexagon: Add implicit sysreg writes
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (59 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 60/76] target/hexagon: Add next_PC, {s,g}reg writes Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 62/76] target/hexagon: Define system, guest reg names Brian Cain
                   ` (15 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/translate.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index f4a353958ff..f5450ced7de 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -424,6 +424,16 @@ static void mark_implicit_usr_write(DisasContext *ctx, int attrib)
     }
 }
 
+#ifndef CONFIG_USER_ONLY
+static void mark_implicit_sreg_write(DisasContext *ctx, int attrib, int snum)
+{
+    uint16_t opcode = ctx->insn->opcode;
+    if (GET_ATTRIB(opcode, attrib)) {
+        ctx_log_sreg_write(ctx, snum);
+    }
+}
+#endif
+
 static void mark_implicit_reg_writes(DisasContext *ctx)
 {
     mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_FP,  HEX_REG_FP);
@@ -436,6 +446,12 @@ static void mark_implicit_reg_writes(DisasContext *ctx)
 
     mark_implicit_usr_write(ctx, A_IMPLICIT_WRITES_USR);
     mark_implicit_usr_write(ctx, A_FPOP);
+
+#ifndef CONFIG_USER_ONLY
+    mark_implicit_sreg_write(ctx, A_IMPLICIT_WRITES_SGP0, HEX_SREG_SGP0);
+    mark_implicit_sreg_write(ctx, A_IMPLICIT_WRITES_SGP1, HEX_SREG_SGP1);
+    mark_implicit_sreg_write(ctx, A_IMPLICIT_WRITES_SSR, HEX_SREG_SSR);
+#endif
 }
 
 static void mark_implicit_pred_write(DisasContext *ctx, int attrib, int pnum)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 62/76] target/hexagon: Define system, guest reg names
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (60 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 61/76] target/hexagon: Add implicit sysreg writes Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 63/76] target/hexagon: Add k0 {un,}lock Brian Cain
                   ` (14 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/internal.h |  4 ++++
 target/hexagon/cpu.c      | 29 +++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index 4338914efb5..00b37aea7af 100644
--- a/target/hexagon/internal.h
+++ b/target/hexagon/internal.h
@@ -30,6 +30,10 @@ void hexagon_debug_qreg(CPUHexagonState *env, int regnum);
 void hexagon_debug(CPUHexagonState *env);
 
 extern const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS];
+#ifndef CONFIG_USER_ONLY
+extern const char * const hexagon_sregnames[];
+extern const char * const hexagon_gregnames[];
+#endif
 
 void G_NORETURN do_raise_exception(CPUHexagonState *env,
         uint32_t exception,
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 3af90e30b0f..b35caaecfae 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -86,6 +86,35 @@ const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = {
   "c24", "c25", "c26", "c27", "c28",  "c29", "c30", "c31",
 };
 
+#ifndef CONFIG_USER_ONLY
+const char * const hexagon_sregnames[] = {
+    "sgp0",       "sgp1",       "stid",       "elr",        "badva0",
+    "badva1",     "ssr",        "ccr",        "htid",       "badva",
+    "imask",      "gevb",       "vwctrl",     "s13",        "s14",
+    "s15",        "evb",        "modectl",    "syscfg",     "segment",
+    "ipendad",    "vid",        "vid1",       "bestwait",   "s24",
+    "schedcfg",   "s26",        "cfgbase",    "diag",       "rev",
+    "pcyclelo",   "pcyclehi",   "isdbst",     "isdbcfg0",   "isdbcfg1",
+    "livelock",   "brkptpc0",   "brkptcfg0",  "brkptpc1",   "brkptcfg1",
+    "isdbmbxin",  "isdbmbxout", "isdben",     "isdbgpr",    "pmucnt4",
+    "pmucnt5",    "pmucnt6",    "pmucnt7",    "pmucnt0",    "pmucnt1",
+    "pmucnt2",    "pmucnt3",    "pmuevtcfg",  "pmustid0",   "pmuevtcfg1",
+    "pmustid1",   "timerlo",    "timerhi",    "pmucfg",     "s59",
+    "s60",        "s61",        "s62",        "s63",
+};
+
+G_STATIC_ASSERT(NUM_SREGS == ARRAY_SIZE(hexagon_sregnames));
+
+const char * const hexagon_gregnames[] = {
+    "gelr",       "gsr",       "gosp",      "gbadva",    "gcommit1t",
+    "gcommit2t",  "gcommit3t", "gcommit4t", "gcommit5t", "gcommit6t",
+    "gpcycle1t",  "gpcycle2t", "gpcycle3t", "gpcycle4t", "gpcycle5t",
+    "gpcycle6t",  "gpmucnt4",  "gpmucnt5",  "gpmucnt6",  "gpmucnt7",
+    "gcommit7t",  "gcommit8t", "gpcycle7t", "gpcycle8t", "gpcyclelo",
+    "gpcyclehi",  "gpmucnt0",  "gpmucnt1",  "gpmucnt2",  "gpmucnt3",
+    "g30",        "g31",
+};
+#endif
 /*
  * One of the main debugging techniques is to use "-d cpu" and compare against
  * LLDB output when single stepping.  However, the target and qemu put the
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 63/76] target/hexagon: Add k0 {un,}lock
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (61 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 62/76] target/hexagon: Define system, guest reg names Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 64/76] target/hexagon: Add PC to raise_exception, use fTRAP() helper Brian Cain
                   ` (13 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/sys_macros.h |   3 +
 target/hexagon/hex_mmu.c    |   4 +-
 target/hexagon/op_helper.c  | 119 ++++++++++++++++++++++++++++++++++++
 3 files changed, 124 insertions(+), 2 deletions(-)

diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h
index 707afc53e1f..a49c72715dc 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -148,6 +148,9 @@
 #define fSET_TLB_LOCK()       hex_tlb_lock(env);
 #define fCLEAR_TLB_LOCK()     hex_tlb_unlock(env);
 
+#define fSET_K0_LOCK()        hex_k0_lock(env);
+#define fCLEAR_K0_LOCK()      hex_k0_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/hex_mmu.c b/target/hexagon/hex_mmu.c
index 1c8ccec69ef..81d64a6146c 100644
--- a/target/hexagon/hex_mmu.c
+++ b/target/hexagon/hex_mmu.c
@@ -206,8 +206,8 @@ void hex_tlb_unlock(CPUHexagonState *env)
         (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);
+                      " without having the lock, tlb_lock state = %u\n",
+                      env->threadId, (unsigned)env->tlb_lock_state);
         g_assert(env->tlb_lock_state != HEX_LOCK_WAITING);
         return;
     }
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 9fbcd79c9d4..b82713bd1c0 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -37,6 +37,9 @@
 #include "cpu_helper.h"
 #include "translate.h"
 #ifndef CONFIG_USER_ONLY
+#include "hw/hexagon/hexagon_globalreg.h"
+#include "hex_mmu.h"
+#include "hw/hexagon/hexagon_tlb.h"
 #include "hex_interrupts.h"
 #include "hexswi.h"
 #endif
@@ -1233,6 +1236,122 @@ void HELPER(modify_ssr)(CPUHexagonState *env, uint32_t new, uint32_t old)
     BQL_LOCK_GUARD();
     hexagon_modify_ssr(env, new, old);
 }
+
+static void hex_k0_lock(CPUHexagonState *env)
+{
+    HexagonCPU *cpu = env_archcpu(env);
+    CPUState *cs = env_cpu(env);
+    target_ulong syscfg;
+
+    BQL_LOCK_GUARD();
+    g_assert((env->k0_lock_count == 0) || (env->k0_lock_count == 1));
+
+    syscfg = cpu->globalregs ?
+        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
+                               env->threadId) : 0;
+    if (GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg)) {
+        if (env->k0_lock_state == HEX_LOCK_QUEUED) {
+            env->next_PC += 4;
+            env->k0_lock_count++;
+            env->k0_lock_state = HEX_LOCK_OWNER;
+            SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 1);
+            return;
+        }
+        if (env->k0_lock_state == HEX_LOCK_OWNER) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "Double k0lock at PC: 0x%" PRIx32
+                          ", thread may hang\n",
+                          env->next_PC);
+            env->next_PC += 4;
+            cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+            cpu_loop_exit(cs);
+            return;
+        }
+        env->k0_lock_state = HEX_LOCK_WAITING;
+        cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+        cpu_loop_exit(cs);
+    } else {
+        env->next_PC += 4;
+        env->k0_lock_count++;
+        env->k0_lock_state = HEX_LOCK_OWNER;
+        SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 1);
+    }
+}
+
+static void hex_k0_unlock(CPUHexagonState *env)
+{
+    HexagonCPU *cpu = env_archcpu(env);
+    unsigned int this_threadId = env->threadId;
+    CPUHexagonState *unlock_thread = NULL;
+    CPUState *cs;
+    target_ulong syscfg;
+
+    BQL_LOCK_GUARD();
+    g_assert((env->k0_lock_count == 0) || (env->k0_lock_count == 1));
+
+    /* Nothing to do if the k0 isn't locked by this thread */
+    syscfg = cpu->globalregs ?
+        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
+                               env->threadId) : 0;
+    if ((GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg) == 0) ||
+        (env->k0_lock_state != HEX_LOCK_OWNER)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "thread %" PRIu32 " attempted to unlock k0 without"
+                      " having the lock, k0_lock state = %u,"
+                      " syscfg:k0 = %" PRIu32 "\n",
+                      env->threadId, (unsigned)env->k0_lock_state,
+                      (uint32_t)GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg));
+        g_assert(env->k0_lock_state != HEX_LOCK_WAITING);
+        return;
+    }
+
+    env->k0_lock_count--;
+    env->k0_lock_state = HEX_LOCK_UNLOCKED;
+    SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 0);
+
+    /* Look for a thread to unlock */
+    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->k0_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);
+        unlock_thread->k0_lock_state = HEX_LOCK_QUEUED;
+        SET_SYSCFG_FIELD(unlock_thread, SYSCFG_K0LOCK, 1);
+        cpu_interrupt(cs, CPU_INTERRUPT_K0_UNLOCK);
+    }
+
+}
 #endif
 
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 64/76] target/hexagon: Add PC to raise_exception, use fTRAP() helper
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (62 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 63/76] target/hexagon: Add k0 {un,}lock Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 65/76] target/hexagon: Add TCG overrides for transfer insts Brian Cain
                   ` (12 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Add PC to raise_exception helper

Replace the fGEN_TCG_J2_trap0 macro override with the fTRAP()-generated
system helper instead.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/gen_tcg.h   |  7 -------
 target/hexagon/helper.h    |  2 +-
 target/hexagon/op_helper.c | 10 ++++------
 target/hexagon/translate.c | 21 ++++++++++++++++-----
 4 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h
index 4a58ead877b..a28af0c245b 100644
--- a/target/hexagon/gen_tcg.h
+++ b/target/hexagon/gen_tcg.h
@@ -1349,13 +1349,6 @@
 #define fGEN_TCG_S2_storew_rl_st_vi(SHORTCODE)          SHORTCODE
 #define fGEN_TCG_S4_stored_rl_st_vi(SHORTCODE)          SHORTCODE
 
-#define fGEN_TCG_J2_trap0(SHORTCODE) \
-    do { \
-        uiV = uiV; \
-        tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->pkt.pc); \
-        TCGv excp = tcg_constant_tl(HEX_EVENT_TRAP0); \
-        gen_helper_raise_exception(tcg_env, excp); \
-    } while (0)
 #endif
 
 #define fGEN_TCG_A2_nop(SHORTCODE) do { } while (0)
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index aa3604dbdc5..033e5619d6b 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -18,7 +18,7 @@
 #include "internal.h"
 #include "helper_protos_generated.h.inc"
 
-DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_RETURN, noreturn, env, i32)
+DEF_HELPER_FLAGS_3(raise_exception, TCG_CALL_NO_RETURN, noreturn, env, i32, i32)
 DEF_HELPER_2(commit_store, void, env, int)
 DEF_HELPER_3(gather_store, void, env, i32, int)
 DEF_HELPER_1(commit_hvx_stores, void, env)
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index b82713bd1c0..8a3723cbafa 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -66,15 +66,13 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
                                             uint32_t exception,
                                             uintptr_t pc)
 {
-    CPUState *cs = env_cpu(env);
-    qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
-    cs->exception_index = exception;
-    cpu_loop_exit_restore(cs, pc);
+    do_raise_exception(env, exception, pc, 0);
 }
 
-G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
+G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp,
+                                        uint32_t PC)
 {
-    hexagon_raise_exception_err(env, excp, 0);
+    hexagon_raise_exception_err(env, excp, PC);
 }
 
 void log_store32(CPUHexagonState *env, target_ulong addr,
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index f5450ced7de..e0418ee990d 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -126,12 +126,19 @@ intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnum,
     return offset;
 }
 
-static void gen_exception_raw(int excp)
+static void gen_exception(int excp, uint32_t PC)
 {
-    gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp));
+    gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp),
+                               tcg_constant_i32(PC));
 }
 
 #ifndef CONFIG_USER_ONLY
+static inline void gen_precise_exception(int excp, uint32_t PC)
+{
+    tcg_gen_movi_i32(hex_cause_code, excp);
+    gen_exception(HEX_EVENT_PRECISE, PC);
+}
+
 static void gen_pcycle_counters(DisasContext *ctx)
 {
     if (ctx->pcycle_enabled) {
@@ -140,6 +147,7 @@ static void gen_pcycle_counters(DisasContext *ctx)
 }
 #endif
 
+
 static void gen_exec_counters(DisasContext *ctx)
 {
     tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT],
@@ -211,8 +219,11 @@ static void gen_end_tb(DisasContext *ctx)
 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);
-    gen_exception_raw(excp);
+#ifdef CONFIG_USER_ONLY
+    gen_exception(excp, ctx->pkt.pc);
+#else
+    gen_precise_exception(excp, ctx->pkt.pc);
+#endif
     ctx->base.is_jmp = DISAS_NORETURN;
 }
 
@@ -226,7 +237,7 @@ static void gen_exception_decode_fail(DisasContext *ctx, int nwords, int excp)
 
     gen_exec_counters(ctx);
     tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], fail_pc);
-    gen_exception_raw(excp);
+    gen_exception(excp, fail_pc);
     ctx->base.is_jmp = DISAS_NORETURN;
     ctx->base.pc_next = fail_pc;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 65/76] target/hexagon: Add TCG overrides for transfer insts
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (63 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 64/76] target/hexagon: Add PC to raise_exception, use fTRAP() helper Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 66/76] target/hexagon: Add support for loadw_phys Brian Cain
                   ` (11 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/gen_tcg_sys.h | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
index 68b23895428..af5032214c4 100644
--- a/target/hexagon/gen_tcg_sys.h
+++ b/target/hexagon/gen_tcg_sys.h
@@ -95,6 +95,31 @@
         gen_helper_stop(tcg_env); \
     } while (0)
 
+#define fGEN_TCG_Y2_tfrscrr(SHORTCODE) \
+    tcg_gen_mov_tl(RdV, SsV)
+
+#define fGEN_TCG_Y2_tfrsrcr(SHORTCODE) \
+    tcg_gen_mov_tl(SdV, RsV)
+
+#define fGEN_TCG_Y4_tfrscpp(SHORTCODE) \
+    tcg_gen_mov_i64(RddV, SssV)
+
+#define fGEN_TCG_Y4_tfrspcp(SHORTCODE) \
+    tcg_gen_mov_i64(SddV, RssV)
+
+#define fGEN_TCG_G4_tfrgcrr(SHORTCODE) \
+    tcg_gen_mov_tl(RdV, GsV)
+
+#define fGEN_TCG_G4_tfrgrcr(SHORTCODE) \
+    tcg_gen_mov_tl(GdV, RsV)
+
+#define fGEN_TCG_G4_tfrgcpp(SHORTCODE) \
+    tcg_gen_mov_i64(RddV, GssV)
+
+#define fGEN_TCG_G4_tfrgpcp(SHORTCODE) \
+    tcg_gen_mov_i64(GddV, RssV)
+
+
 /*
  * rte (return from exception)
  *     Clear the EX bit in SSR
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 66/76] target/hexagon: Add support for loadw_phys
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (64 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 65/76] target/hexagon: Add TCG overrides for transfer insts Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 67/76] target/hexagon: Add guest reg reading functionality Brian Cain
                   ` (10 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/hex_common.py          | 3 +++
 target/hexagon/imported/encode_pp.def | 1 +
 target/hexagon/imported/ldst.idef     | 3 +++
 3 files changed, 7 insertions(+)

diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index acaaa3c944a..d91a653c3d4 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -264,6 +264,9 @@ def need_slot(tag):
         and "A_CVI_GATHER" not in attribdict[tag]
         and ("A_STORE" in attribdict[tag]
              or "A_LOAD" in attribdict[tag])
+        and tag != "L4_loadw_phys"
+        and tag != "L6_memcpy"
+        and tag != "Y6_dmlink"
     ):
         return 1
     else:
diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def
index 04e911f59c8..1c64495d519 100644
--- a/target/hexagon/imported/encode_pp.def
+++ b/target/hexagon/imported/encode_pp.def
@@ -384,6 +384,7 @@ DEF_ENC32(L4_return_fnew_pnt, ICLASS_LD" 011 0 000 sssss PP1010vv ---ddddd")
 
 /** Load Acquire Store Release Encoding **/
 
+DEF_ENC32(L4_loadw_phys,      ICLASS_LD" 001 0 000 sssss PP1ttttt -00ddddd")
 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")
 
diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef
index 53198176a99..4e1e5d5326d 100644
--- a/target/hexagon/imported/ldst.idef
+++ b/target/hexagon/imported/ldst.idef
@@ -203,6 +203,9 @@ Q6INSN(S2_storew_locked,"memw_locked(Rs32,Pd4)=Rt32", ATTRIBS(A_REGWRSIZE_4B,A_M
 Q6INSN(L4_loadd_locked,"Rdd32=memd_locked(Rs32)", ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_LOAD,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK), "Load double with lock",
 { fEA_REG(RsV); fLOAD_LOCKED(1,8,u,EA,RddV) })
 
+Q6INSN(L4_loadw_phys,"Rd32=memw_phys(Rs32,Rt32)", ATTRIBS(A_REGWRSIZE_4B,A_PRIV,A_RESTRICT_SLOT0ONLY,A_NOTE_PRIV,A_MEMSIZE_4B,A_LOAD,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Load word from physical address",
+{ fLOAD_PHYS(1,4,u,RsV,RtV,RdV); })
+
 Q6INSN(S4_stored_locked,"memd_locked(Rs32,Pd4)=Rtt32", ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_STORE,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_LATEPRED,A_NOTE_LATEPRED), "Store word with lock",
 { fEA_REG(RsV); fSTORE_LOCKED(1,8,EA,RttV,PdV) })
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 67/76] target/hexagon: Add guest reg reading functionality
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (65 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 66/76] target/hexagon: Add support for loadw_phys Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 68/76] hw/hexagon: Add globalreg model Brian Cain
                   ` (9 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Matheus Tavares Bernardino, Taylor Simpson,
	Pierrick Bouvier

From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>

Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/cpu.h       |  1 +
 target/hexagon/cpu.c       | 19 +++++++++++++++++++
 target/hexagon/op_helper.c | 16 ++++++++++++++--
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 6a95a6bc5b1..4a12dc04727 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -220,6 +220,7 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
  * not stopped.
  */
 bool hexagon_thread_is_enabled(CPUHexagonState *thread_env);
+uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg);
 void hexagon_cpu_soft_reset(CPUHexagonState *env);
 #endif
 
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index b35caaecfae..06be5c8d498 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -770,6 +770,25 @@ static void hexagon_cpu_class_init(ObjectClass *c, const void *data)
 #endif
 }
 
+#ifndef CONFIG_USER_ONLY
+uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg)
+{
+    if (reg <= HEX_GREG_G3) {
+        return env->greg[reg];
+    }
+    switch (reg) {
+    case HEX_GREG_GPCYCLELO:
+        return hexagon_get_sys_pcycle_count_low(env);
+    case HEX_GREG_GPCYCLEHI:
+        return hexagon_get_sys_pcycle_count_high(env);
+    default:
+        qemu_log_mask(LOG_UNIMP, "reading greg %" PRId32
+                " not yet supported.\n", reg);
+        return 0;
+    }
+}
+#endif
+
 static void hexagon_cpu_class_base_init(ObjectClass *c, const void *data)
 {
     HexagonCPUClass *mcc = HEXAGON_CPU_CLASS(c);
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 8a3723cbafa..125952aee59 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1878,13 +1878,25 @@ uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg)
 }
 
 uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg)
+
 {
-    g_assert_not_reached();
+    return hexagon_greg_read(env, reg);
 }
 
 uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg)
+
 {
-    g_assert_not_reached();
+    if (reg == HEX_GREG_G0 || reg == HEX_GREG_G2) {
+        return (uint64_t)(env->greg[reg]) |
+               (((uint64_t)(env->greg[reg + 1])) << 32);
+    }
+    switch (reg) {
+    case HEX_GREG_GPCYCLELO:
+        return hexagon_get_sys_pcycle_count(env);
+    default:
+        return (uint64_t)hexagon_greg_read(env, reg) |
+               ((uint64_t)(hexagon_greg_read(env, reg + 1)) << 32);
+    }
 }
 
 /*
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 68/76] hw/hexagon: Add globalreg model
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (66 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 67/76] target/hexagon: Add guest reg reading functionality Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 69/76] hw/hexagon: Add global register tracing Brian Cain
                   ` (8 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Sid Manning, Philippe Mathieu-Daudé,
	Pierrick Bouvier

Some of the system registers are shared among all threads
in the core.  This object contains the representation and
interface to the system registers.

Reviewed-by: Sid Manning <sid.manning@oss.qualcomm.com>
Acked-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 include/hw/hexagon/hexagon_globalreg.h |  55 ++++++
 hw/hexagon/hexagon_globalreg.c         | 243 +++++++++++++++++++++++++
 2 files changed, 298 insertions(+)
 create mode 100644 include/hw/hexagon/hexagon_globalreg.h
 create mode 100644 hw/hexagon/hexagon_globalreg.c

diff --git a/include/hw/hexagon/hexagon_globalreg.h b/include/hw/hexagon/hexagon_globalreg.h
new file mode 100644
index 00000000000..950099808fd
--- /dev/null
+++ b/include/hw/hexagon/hexagon_globalreg.h
@@ -0,0 +1,55 @@
+/*
+ * Hexagon Global Registers QOM Object
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXAGON_GLOBALREG_H
+#define HEXAGON_GLOBALREG_H
+
+#include "hw/core/qdev.h"
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+#include "target/hexagon/cpu.h"
+
+#define TYPE_HEXAGON_GLOBALREG "hexagon-globalreg"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonGlobalRegState, HEXAGON_GLOBALREG)
+
+struct HexagonGlobalRegState {
+    SysBusDevice parent_obj;
+
+    /* Array of system registers */
+    uint32_t regs[NUM_SREGS];
+
+    /* Global performance cycle counter base */
+    uint64_t g_pcycle_base;
+
+    /* Properties for global register reset values */
+    uint32_t boot_evb;           /* Boot Exception Vector Base (HEX_SREG_EVB) */
+    uint64_t config_table_addr;  /* Configuration table base */
+    uint32_t dsp_rev;           /* DSP revision register (HEX_SREG_REV) */
+
+    /* ISDB properties */
+    bool isdben_etm_enable;     /* ISDB ETM enable bit */
+    bool isdben_dfd_enable;     /* ISDB DFD enable bit */
+    bool isdben_trusted;        /* ISDB trusted mode bit */
+    bool isdben_secure;         /* ISDB secure mode bit */
+};
+
+/* Public interface functions */
+uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
+                                uint32_t htid);
+void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
+                             uint32_t value, uint32_t htid);
+uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
+                                        uint32_t value);
+void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
+                                    uint32_t value);
+
+/* Global performance cycle counter access */
+uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s);
+void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
+                                       uint64_t value);
+
+#endif /* HEXAGON_GLOBALREG_H */
diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c
new file mode 100644
index 00000000000..28cb5a4158d
--- /dev/null
+++ b/hw/hexagon/hexagon_globalreg.c
@@ -0,0 +1,243 @@
+/*
+ * Hexagon Global Registers
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/sysbus.h"
+#include "hw/core/resettable.h"
+#include "migration/vmstate.h"
+#include "qom/object.h"
+#include "target/hexagon/cpu.h"
+#include "target/hexagon/hex_regs.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+
+#define IMMUTABLE (~0)
+#define INVALID_REG_VAL 0xdeadbeef
+
+/* Global system register mutability masks */
+static const uint32_t global_sreg_immut_masks[NUM_SREGS] = {
+    [HEX_SREG_EVB] = 0x000000ff,
+    [HEX_SREG_MODECTL] = IMMUTABLE,
+    [HEX_SREG_SYSCFG] = 0x80001c00,
+    [HEX_SREG_IPENDAD] = IMMUTABLE,
+    [HEX_SREG_VID] = 0xfc00fc00,
+    [HEX_SREG_VID1] = 0xfc00fc00,
+    [HEX_SREG_BESTWAIT] = 0xfffffe00,
+    [HEX_SREG_IAHL] = 0x00000000,
+    [HEX_SREG_SCHEDCFG] = 0xfffffee0,
+    [HEX_SREG_CFGBASE] = IMMUTABLE,
+    [HEX_SREG_DIAG] = 0x00000000,
+    [HEX_SREG_REV] = IMMUTABLE,
+    [HEX_SREG_ISDBST] = IMMUTABLE,
+    [HEX_SREG_ISDBCFG0] = 0xe0000000,
+    [HEX_SREG_BRKPTPC0] = 0x00000003,
+    [HEX_SREG_BRKPTCFG0] = 0xfc007000,
+    [HEX_SREG_BRKPTPC1] = 0x00000003,
+    [HEX_SREG_BRKPTCFG1] = 0xfc007000,
+    [HEX_SREG_ISDBMBXIN] = IMMUTABLE,
+    [HEX_SREG_ISDBMBXOUT] = 0x00000000,
+    [HEX_SREG_ISDBEN] = 0xfffffffe,
+    [HEX_SREG_TIMERLO] = IMMUTABLE,
+    [HEX_SREG_TIMERHI] = IMMUTABLE,
+};
+
+static void hexagon_globalreg_init(Object *obj)
+{
+    HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
+
+    memset(s->regs, 0, sizeof(s->regs));
+}
+
+static inline uint32_t apply_write_mask(uint32_t new_val, uint32_t cur_val,
+                                        uint32_t reg_mask)
+{
+    if (reg_mask) {
+        return (new_val & ~reg_mask) | (cur_val & reg_mask);
+    }
+    return new_val;
+}
+
+uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
+                                uint32_t htid)
+{
+    uint32_t value;
+
+    if (!s) {
+        return 0;
+    }
+    g_assert(reg < NUM_SREGS);
+    g_assert(reg >= HEX_SREG_GLB_START);
+
+    value = s->regs[reg];
+
+    return value;
+}
+
+void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
+                             uint32_t value, uint32_t htid)
+{
+    if (!s) {
+        return;
+    }
+    g_assert(reg < NUM_SREGS);
+    g_assert(reg >= HEX_SREG_GLB_START);
+    s->regs[reg] = value;
+}
+
+uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
+                                        uint32_t value)
+{
+    uint32_t reg_mask;
+
+    if (!s) {
+        return value;
+    }
+    g_assert(reg < NUM_SREGS);
+    g_assert(reg >= HEX_SREG_GLB_START);
+    reg_mask = global_sreg_immut_masks[reg];
+    return reg_mask == IMMUTABLE ?
+            s->regs[reg] :
+            apply_write_mask(value, s->regs[reg], reg_mask);
+}
+
+void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg,
+                                    uint32_t value)
+{
+    if (!s) {
+        return;
+    }
+    s->regs[reg] = hexagon_globalreg_masked_value(s, reg, value);
+}
+
+uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s)
+{
+    g_assert(s);
+    return s->g_pcycle_base;
+}
+
+void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
+                                       uint64_t value)
+{
+    g_assert(s);
+    s->g_pcycle_base = value;
+}
+
+static void do_hexagon_globalreg_reset(HexagonGlobalRegState *s)
+{
+    uint32_t isdben_val = 0;
+
+    g_assert(s);
+    memset(s->regs, 0, sizeof(s->regs));
+
+    s->g_pcycle_base = 0;
+
+    s->regs[HEX_SREG_EVB] = s->boot_evb;
+    s->regs[HEX_SREG_CFGBASE] = HEXAGON_CFG_ADDR_BASE(s->config_table_addr);
+    s->regs[HEX_SREG_REV] = s->dsp_rev;
+
+    if (s->isdben_etm_enable) {
+        isdben_val |= (1 << 0);  /* ETM enable bit */
+    }
+    if (s->isdben_dfd_enable) {
+        isdben_val |= (1 << 1);  /* DFD enable bit */
+    }
+    if (s->isdben_trusted) {
+        isdben_val |= (1 << 2);  /* Trusted bit */
+    }
+    if (s->isdben_secure) {
+        isdben_val |= (1 << 3);  /* Secure bit */
+    }
+    s->regs[HEX_SREG_ISDBEN] = isdben_val;
+    s->regs[HEX_SREG_MODECTL] = 0x1;
+
+    /*
+     * These register indices are placeholders in these arrays
+     * and their actual values are synthesized from state elsewhere.
+     * We can initialize these with invalid values so that if we
+     * mistakenly generate reads, they will look obviously wrong.
+     */
+    s->regs[HEX_SREG_PCYCLELO] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PCYCLEHI] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_TIMERLO] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_TIMERHI] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PMUCNT0] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PMUCNT1] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PMUCNT2] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PMUCNT3] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PMUCNT4] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PMUCNT5] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PMUCNT6] = INVALID_REG_VAL;
+    s->regs[HEX_SREG_PMUCNT7] = INVALID_REG_VAL;
+}
+
+static void hexagon_globalreg_reset_hold(Object *obj, ResetType type)
+{
+    HexagonGlobalRegState *s = HEXAGON_GLOBALREG(obj);
+    do_hexagon_globalreg_reset(s);
+}
+
+static const VMStateDescription vmstate_hexagon_globalreg = {
+    .name = "hexagon_globalreg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]){
+        VMSTATE_UINT32_ARRAY(regs, HexagonGlobalRegState, NUM_SREGS),
+        VMSTATE_UINT64(g_pcycle_base, HexagonGlobalRegState),
+        VMSTATE_UINT32(boot_evb, HexagonGlobalRegState),
+        VMSTATE_UINT64(config_table_addr, HexagonGlobalRegState),
+        VMSTATE_UINT32(dsp_rev, HexagonGlobalRegState),
+        VMSTATE_BOOL(isdben_etm_enable, HexagonGlobalRegState),
+        VMSTATE_BOOL(isdben_dfd_enable, HexagonGlobalRegState),
+        VMSTATE_BOOL(isdben_trusted, HexagonGlobalRegState),
+        VMSTATE_BOOL(isdben_secure, HexagonGlobalRegState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const Property hexagon_globalreg_properties[] = {
+    DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0),
+    DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState,
+                       config_table_addr, 0xffffffffULL),
+    DEFINE_PROP_UINT32("dsp-rev", HexagonGlobalRegState, dsp_rev, 0),
+    DEFINE_PROP_BOOL("isdben-etm-enable", HexagonGlobalRegState,
+                     isdben_etm_enable, false),
+    DEFINE_PROP_BOOL("isdben-dfd-enable", HexagonGlobalRegState,
+                     isdben_dfd_enable, false),
+    DEFINE_PROP_BOOL("isdben-trusted", HexagonGlobalRegState,
+                     isdben_trusted, false),
+    DEFINE_PROP_BOOL("isdben-secure", HexagonGlobalRegState,
+                     isdben_secure, false),
+};
+
+static void hexagon_globalreg_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+    rc->phases.hold = hexagon_globalreg_reset_hold;
+    dc->vmsd = &vmstate_hexagon_globalreg;
+    dc->user_creatable = false;
+    device_class_set_props(dc, hexagon_globalreg_properties);
+}
+
+static const TypeInfo hexagon_globalreg_info = {
+    .name = TYPE_HEXAGON_GLOBALREG,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(HexagonGlobalRegState),
+    .instance_init = hexagon_globalreg_init,
+    .class_init = hexagon_globalreg_class_init,
+};
+
+static void hexagon_globalreg_register_types(void)
+{
+    type_register_static(&hexagon_globalreg_info);
+}
+
+type_init(hexagon_globalreg_register_types)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 69/76] hw/hexagon: Add global register tracing
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (67 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 68/76] hw/hexagon: Add globalreg model Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 70/76] hw/hexagon: Add hexagon TLB device implementation Brian Cain
                   ` (7 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Philippe Mathieu-Daudé, Pierrick Bouvier,
	Paolo Bonzini, Marc-André Lureau, Daniel P. Berrangé,
	Philippe Mathieu-Daudé

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 meson.build                    |  1 +
 hw/hexagon/trace.h             |  2 +
 hw/hexagon/hexagon_globalreg.c | 73 ++++++++++++++++++++++++++++++++++
 hw/hexagon/trace-events        |  3 ++
 4 files changed, 79 insertions(+)
 create mode 100644 hw/hexagon/trace.h
 create mode 100644 hw/hexagon/trace-events

diff --git a/meson.build b/meson.build
index e026851309e..d4206a5d3f8 100644
--- a/meson.build
+++ b/meson.build
@@ -3599,6 +3599,7 @@ if have_system
     'hw/display',
     'hw/dma',
     'hw/fsi',
+    'hw/hexagon',
     'hw/hyperv',
     'hw/i2c',
     'hw/i3c',
diff --git a/hw/hexagon/trace.h b/hw/hexagon/trace.h
new file mode 100644
index 00000000000..9e0b39f3c66
--- /dev/null
+++ b/hw/hexagon/trace.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "trace/trace-hw_hexagon.h"
diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c
index 28cb5a4158d..b5e5913507e 100644
--- a/hw/hexagon/hexagon_globalreg.c
+++ b/hw/hexagon/hexagon_globalreg.c
@@ -16,11 +16,82 @@
 #include "target/hexagon/cpu.h"
 #include "target/hexagon/hex_regs.h"
 #include "qemu/log.h"
+#include "trace.h"
 #include "qapi/error.h"
 
 #define IMMUTABLE (~0)
 #define INVALID_REG_VAL 0xdeadbeef
 
+static const char *hex_sreg_names[] = {
+    [HEX_SREG_SGP0] = "sgp0",
+    [HEX_SREG_SGP1] = "sgp1",
+    [HEX_SREG_STID] = "stid",
+    [HEX_SREG_ELR] = "elr",
+    [HEX_SREG_BADVA0] = "badva0",
+    [HEX_SREG_BADVA1] = "badva1",
+    [HEX_SREG_SSR] = "ssr",
+    [HEX_SREG_CCR] = "ccr",
+    [HEX_SREG_HTID] = "htid",
+    [HEX_SREG_BADVA] = "badva",
+    [HEX_SREG_IMASK] = "imask",
+    [HEX_SREG_GEVB] = "gevb",
+    [HEX_SREG_EVB] = "evb",
+    [HEX_SREG_MODECTL] = "modectl",
+    [HEX_SREG_SYSCFG] = "syscfg",
+    [HEX_SREG_IPENDAD] = "ipendad",
+    [HEX_SREG_VID] = "vid",
+    [HEX_SREG_VID1] = "vid1",
+    [HEX_SREG_BESTWAIT] = "bestwait",
+    [HEX_SREG_IEL] = "iel",
+    [HEX_SREG_SCHEDCFG] = "schedcfg",
+    [HEX_SREG_IAHL] = "iahl",
+    [HEX_SREG_CFGBASE] = "cfgbase",
+    [HEX_SREG_DIAG] = "diag",
+    [HEX_SREG_REV] = "rev",
+    [HEX_SREG_PCYCLELO] = "pcyclelo",
+    [HEX_SREG_PCYCLEHI] = "pcyclehi",
+    [HEX_SREG_ISDBST] = "isdbst",
+    [HEX_SREG_ISDBCFG0] = "isdbcfg0",
+    [HEX_SREG_ISDBCFG1] = "isdbcfg1",
+    [HEX_SREG_LIVELOCK] = "livelock",
+    [HEX_SREG_BRKPTPC0] = "brkptpc0",
+    [HEX_SREG_BRKPTCFG0] = "brkptcfg0",
+    [HEX_SREG_BRKPTPC1] = "brkptpc1",
+    [HEX_SREG_BRKPTCFG1] = "brkptcfg1",
+    [HEX_SREG_ISDBMBXIN] = "isdbmbxin",
+    [HEX_SREG_ISDBMBXOUT] = "isdbmbxout",
+    [HEX_SREG_ISDBEN] = "isdben",
+    [HEX_SREG_ISDBGPR] = "isdbgpr",
+    [HEX_SREG_PMUCNT4] = "pmucnt4",
+    [HEX_SREG_PMUCNT5] = "pmucnt5",
+    [HEX_SREG_PMUCNT6] = "pmucnt6",
+    [HEX_SREG_PMUCNT7] = "pmucnt7",
+    [HEX_SREG_PMUCNT0] = "pmucnt0",
+    [HEX_SREG_PMUCNT1] = "pmucnt1",
+    [HEX_SREG_PMUCNT2] = "pmucnt2",
+    [HEX_SREG_PMUCNT3] = "pmucnt3",
+    [HEX_SREG_PMUEVTCFG] = "pmuevtcfg",
+    [HEX_SREG_PMUSTID0] = "pmustid0",
+    [HEX_SREG_PMUEVTCFG1] = "pmuevtcfg1",
+    [HEX_SREG_PMUSTID1] = "pmustid1",
+    [HEX_SREG_TIMERLO] = "timerlo",
+    [HEX_SREG_TIMERHI] = "timerhi",
+    [HEX_SREG_PMUCFG] = "pmucfg",
+    [HEX_SREG_S59] = "s59",
+    [HEX_SREG_S60] = "s60",
+    [HEX_SREG_S61] = "s61",
+    [HEX_SREG_S62] = "s62",
+    [HEX_SREG_S63] = "s63",
+};
+
+static const char *get_sreg_name(uint32_t reg)
+{
+    if (reg < ARRAY_SIZE(hex_sreg_names) && hex_sreg_names[reg]) {
+        return hex_sreg_names[reg];
+    }
+    return "UNKNOWN";
+}
+
 /* Global system register mutability masks */
 static const uint32_t global_sreg_immut_masks[NUM_SREGS] = {
     [HEX_SREG_EVB] = 0x000000ff,
@@ -77,6 +148,7 @@ uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
 
     value = s->regs[reg];
 
+    trace_hexagon_globalreg_read(htid, get_sreg_name(reg), value);
     return value;
 }
 
@@ -89,6 +161,7 @@ void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg,
     g_assert(reg < NUM_SREGS);
     g_assert(reg >= HEX_SREG_GLB_START);
     s->regs[reg] = value;
+    trace_hexagon_globalreg_write(htid, get_sreg_name(reg), value);
 }
 
 uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg,
diff --git a/hw/hexagon/trace-events b/hw/hexagon/trace-events
new file mode 100644
index 00000000000..5d623ed2516
--- /dev/null
+++ b/hw/hexagon/trace-events
@@ -0,0 +1,3 @@
+# Hexagon global register access
+hexagon_globalreg_read(uint32_t htid, const char *reg_name, uint32_t value) "htid=%u reg=%s value=0x%x"
+hexagon_globalreg_write(uint32_t htid, const char *reg_name, uint32_t value) "htid=%u reg=%s value=0x%x"
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 70/76] hw/hexagon: Add hexagon TLB device implementation
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (68 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 69/76] hw/hexagon: Add global register tracing Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 71/76] hw/hexagon: Add machine configs for sysemu Brian Cain
                   ` (6 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha; +Cc: brian.cain, Pierrick Bouvier

Add the hexagon TLB QOM device model implementation.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 hw/hexagon/hexagon_tlb.c | 467 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 467 insertions(+)
 create mode 100644 hw/hexagon/hexagon_tlb.c

diff --git a/hw/hexagon/hexagon_tlb.c b/hw/hexagon/hexagon_tlb.c
new file mode 100644
index 00000000000..b6d4aff389e
--- /dev/null
+++ b/hw/hexagon/hexagon_tlb.c
@@ -0,0 +1,467 @@
+/*
+ * Hexagon TLB QOM Device
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/hexagon/hexagon_tlb.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/resettable.h"
+#include "migration/vmstate.h"
+#include "monitor/monitor.h"
+#include "qapi/error.h"
+#include "exec/page-protection.h"
+#include "exec/target_page.h"
+#include "target/hexagon/cpu.h"
+#include "target/hexagon/cpu_bits.h"
+
+/* PTE (TLB entry) field extraction */
+#define GET_PTE_PPD(entry)   extract64((entry),  0, 24)
+#define GET_PTE_C(entry)     extract64((entry), 24,  4)
+#define GET_PTE_U(entry)     extract64((entry), 28,  1)
+#define GET_PTE_R(entry)     extract64((entry), 29,  1)
+#define GET_PTE_W(entry)     extract64((entry), 30,  1)
+#define GET_PTE_X(entry)     extract64((entry), 31,  1)
+#define GET_PTE_VPN(entry)   extract64((entry), 32, 20)
+#define GET_PTE_ASID(entry)  extract64((entry), 52,  7)
+#define GET_PTE_ATR0(entry)  extract64((entry), 59,  1)
+#define GET_PTE_ATR1(entry)  extract64((entry), 60,  1)
+#define GET_PTE_PA35(entry)  extract64((entry), 61,  1)
+#define GET_PTE_G(entry)     extract64((entry), 62,  1)
+#define GET_PTE_V(entry)     extract64((entry), 63,  1)
+
+/* PPD (physical page descriptor) */
+static inline uint64_t GET_PPD(uint64_t entry)
+{
+    return GET_PTE_PPD(entry) | (GET_PTE_PA35(entry) << 24);
+}
+
+#define NO_ASID      (1 << 8)
+
+typedef enum {
+    PGSIZE_4K,
+    PGSIZE_16K,
+    PGSIZE_64K,
+    PGSIZE_256K,
+    PGSIZE_1M,
+    PGSIZE_4M,
+    PGSIZE_16M,
+    PGSIZE_64M,
+    PGSIZE_256M,
+    PGSIZE_1G,
+} tlb_pgsize_t;
+
+#define NUM_PGSIZE_TYPES (PGSIZE_1G + 1)
+
+static const char *pgsize_str[NUM_PGSIZE_TYPES] = {
+    "4K",
+    "16K",
+    "64K",
+    "256K",
+    "1M",
+    "4M",
+    "16M",
+    "64M",
+    "256M",
+    "1G",
+};
+
+#define INVALID_MASK 0xffffffffLL
+
+static const uint64_t encmask_2_mask[] = {
+    0x0fffLL,                           /* 4k,   0000 */
+    0x3fffLL,                           /* 16k,  0001 */
+    0xffffLL,                           /* 64k,  0010 */
+    0x3ffffLL,                          /* 256k, 0011 */
+    0xfffffLL,                          /* 1m,   0100 */
+    0x3fffffLL,                         /* 4m,   0101 */
+    0xffffffLL,                         /* 16m,  0110 */
+    0x3ffffffLL,                        /* 64m,  0111 */
+    0xfffffffLL,                        /* 256m, 1000 */
+    0x3fffffffLL,                       /* 1g,   1001 */
+    INVALID_MASK,                       /* RSVD, 1010 */
+};
+
+static inline tlb_pgsize_t hex_tlb_pgsize_type(uint64_t entry)
+{
+    if (entry == 0) {
+        qemu_log_mask(CPU_LOG_MMU, "%s: Supplied TLB entry was 0!\n",
+                      __func__);
+        return 0;
+    }
+    tlb_pgsize_t size = ctz64(entry);
+    g_assert(size < NUM_PGSIZE_TYPES);
+    return size;
+}
+
+static inline uint64_t hex_tlb_page_size_bytes(uint64_t entry)
+{
+    return 1ull << (qemu_target_page_bits() + 2 * hex_tlb_pgsize_type(entry));
+}
+
+static inline uint64_t hex_tlb_phys_page_num(uint64_t entry)
+{
+    uint32_t ppd = GET_PPD(entry);
+    return ppd >> 1;
+}
+
+static inline uint64_t hex_tlb_phys_addr(uint64_t entry)
+{
+    uint64_t pagemask = encmask_2_mask[hex_tlb_pgsize_type(entry)];
+    uint64_t pagenum = hex_tlb_phys_page_num(entry);
+    uint64_t PA = (pagenum << qemu_target_page_bits()) & (~pagemask);
+    return PA;
+}
+
+static inline uint64_t hex_tlb_virt_addr(uint64_t entry)
+{
+    return (uint64_t)GET_PTE_VPN(entry) << qemu_target_page_bits();
+}
+
+bool hexagon_tlb_dump_entry(Monitor *mon, uint64_t entry)
+{
+    if (GET_PTE_V(entry)) {
+        uint64_t PA = hex_tlb_phys_addr(entry);
+        uint64_t VA = hex_tlb_virt_addr(entry);
+        monitor_printf(mon, "0x%016" PRIx64 ": ", entry);
+        monitor_printf(mon, "V:%" PRId64 " G:%" PRId64
+                       " A1:%" PRId64 " A0:%" PRId64,
+                       GET_PTE_V(entry),
+                       GET_PTE_G(entry),
+                       GET_PTE_ATR1(entry),
+                       GET_PTE_ATR0(entry));
+        monitor_printf(mon, " ASID:0x%02" PRIx64 " VA:0x%08" PRIx64,
+                       GET_PTE_ASID(entry), VA);
+        monitor_printf(mon,
+                       " X:%" PRId64 " W:%" PRId64 " R:%" PRId64
+                       " U:%" PRId64 " C:%" PRId64,
+                       GET_PTE_X(entry),
+                       GET_PTE_W(entry),
+                       GET_PTE_R(entry),
+                       GET_PTE_U(entry),
+                       GET_PTE_C(entry));
+        monitor_printf(mon, " PA:0x%09" PRIx64 " SZ:%s (0x%" PRIx64 ")",
+                       PA, pgsize_str[hex_tlb_pgsize_type(entry)],
+                       hex_tlb_page_size_bytes(entry));
+        monitor_printf(mon, "\n");
+        return true;
+    }
+
+    /* Not valid */
+    return false;
+}
+
+static inline bool hex_tlb_entry_match_noperm(uint64_t entry, uint32_t asid,
+                                              uint64_t VA)
+{
+    if (GET_PTE_V(entry)) {
+        if (GET_PTE_G(entry)) {
+            /* Global entry - ignore ASID */
+        } else if (asid != NO_ASID) {
+            uint32_t tlb_asid = GET_PTE_ASID(entry);
+            if (tlb_asid != asid) {
+                return false;
+            }
+        }
+
+        uint64_t page_size = hex_tlb_page_size_bytes(entry);
+        uint64_t page_start =
+            ROUND_DOWN(hex_tlb_virt_addr(entry), page_size);
+        if (page_start <= VA && VA < page_start + page_size) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static inline void hex_tlb_entry_get_perm(uint64_t entry,
+                                          MMUAccessType access_type,
+                                          int mmu_idx, int *prot,
+                                          int32_t *excp, int *cause_code)
+{
+    bool perm_x = GET_PTE_X(entry);
+    bool perm_w = GET_PTE_W(entry);
+    bool perm_r = GET_PTE_R(entry);
+    bool perm_u = GET_PTE_U(entry);
+    bool user_idx = mmu_idx == MMU_USER_IDX;
+
+    if (mmu_idx == MMU_KERNEL_IDX) {
+        *prot = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return;
+    }
+
+    *prot = PAGE_VALID;
+    switch (access_type) {
+    case MMU_INST_FETCH:
+        if (user_idx && !perm_u) {
+            *excp = HEX_EVENT_PRECISE;
+            *cause_code = HEX_CAUSE_FETCH_NO_UPAGE;
+        } else if (!perm_x) {
+            *excp = HEX_EVENT_PRECISE;
+            *cause_code = HEX_CAUSE_FETCH_NO_XPAGE;
+        }
+        break;
+    case MMU_DATA_LOAD:
+        if (user_idx && !perm_u) {
+            *excp = HEX_EVENT_PRECISE;
+            *cause_code = HEX_CAUSE_PRIV_NO_UREAD;
+        } else if (!perm_r) {
+            *excp = HEX_EVENT_PRECISE;
+            *cause_code = HEX_CAUSE_PRIV_NO_READ;
+        }
+        break;
+    case MMU_DATA_STORE:
+        if (user_idx && !perm_u) {
+            *excp = HEX_EVENT_PRECISE;
+            *cause_code = HEX_CAUSE_PRIV_NO_UWRITE;
+        } else if (!perm_w) {
+            *excp = HEX_EVENT_PRECISE;
+            *cause_code = HEX_CAUSE_PRIV_NO_WRITE;
+        }
+        break;
+    }
+
+    if (!user_idx || perm_u) {
+        if (perm_x) {
+            *prot |= PAGE_EXEC;
+        }
+        if (perm_r) {
+            *prot |= PAGE_READ;
+        }
+        if (perm_w) {
+            *prot |= PAGE_WRITE;
+        }
+    }
+}
+
+static inline bool hex_tlb_entry_match(uint64_t entry, uint8_t asid,
+                                       uint32_t VA,
+                                       MMUAccessType access_type, hwaddr *PA,
+                                       int *prot, uint64_t *size,
+                                       int32_t *excp, int *cause_code,
+                                       int mmu_idx)
+{
+    if (hex_tlb_entry_match_noperm(entry, asid, VA)) {
+        hex_tlb_entry_get_perm(entry, access_type, mmu_idx, prot, excp,
+                               cause_code);
+        *PA = hex_tlb_phys_addr(entry);
+        *size = hex_tlb_page_size_bytes(entry);
+        return true;
+    }
+    return false;
+}
+
+static bool hex_tlb_is_match(uint64_t entry1, uint64_t entry2,
+                             bool consider_gbit)
+{
+    bool valid1 = GET_PTE_V(entry1);
+    bool valid2 = GET_PTE_V(entry2);
+    uint64_t size1 = hex_tlb_page_size_bytes(entry1);
+    uint64_t vaddr1 = ROUND_DOWN(hex_tlb_virt_addr(entry1), size1);
+    uint64_t size2 = hex_tlb_page_size_bytes(entry2);
+    uint64_t vaddr2 = ROUND_DOWN(hex_tlb_virt_addr(entry2), size2);
+    int asid1 = GET_PTE_ASID(entry1);
+    int asid2 = GET_PTE_ASID(entry2);
+    bool gbit1 = GET_PTE_G(entry1);
+    bool gbit2 = GET_PTE_G(entry2);
+
+    if (!valid1 || !valid2) {
+        return false;
+    }
+
+    if (((vaddr1 <= vaddr2) && (vaddr2 < (vaddr1 + size1))) ||
+        ((vaddr2 <= vaddr1) && (vaddr1 < (vaddr2 + size2)))) {
+        if (asid1 == asid2) {
+            return true;
+        }
+        if ((consider_gbit && gbit1) || gbit2) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/* Public API */
+
+uint64_t hexagon_tlb_read(HexagonTLBState *tlb, uint32_t index)
+{
+    g_assert(index < tlb->num_entries);
+    return tlb->entries[index];
+}
+
+void hexagon_tlb_write(HexagonTLBState *tlb, uint32_t index, uint64_t value)
+{
+    g_assert(index < tlb->num_entries);
+    tlb->entries[index] = value;
+}
+
+bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
+                            uint32_t VA, MMUAccessType access_type,
+                            hwaddr *PA, int *prot, uint64_t *size,
+                            int32_t *excp, int *cause_code, int mmu_idx)
+{
+    *PA = 0;
+    *prot = 0;
+    *size = 0;
+    *excp = 0;
+    *cause_code = 0;
+
+    for (uint32_t i = 0; i < tlb->num_entries; i++) {
+        if (hex_tlb_entry_match(tlb->entries[i], asid, VA, access_type,
+                                PA, prot, size, excp, cause_code, mmu_idx)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+uint32_t hexagon_tlb_lookup(HexagonTLBState *tlb, uint32_t asid,
+                            uint32_t VA, int *cause_code)
+{
+    uint32_t not_found = 0x80000000;
+    uint32_t idx = not_found;
+
+    for (uint32_t i = 0; i < tlb->num_entries; i++) {
+        uint64_t entry = tlb->entries[i];
+        if (hex_tlb_entry_match_noperm(entry, asid, VA)) {
+            if (idx != not_found) {
+                *cause_code = HEX_CAUSE_IMPRECISE_MULTI_TLB_MATCH;
+                break;
+            }
+            idx = i;
+        }
+    }
+
+    if (idx == not_found) {
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s: 0x%" PRIx32 ", 0x%08" PRIx32 " => NOT FOUND\n",
+                      __func__, asid, VA);
+    } else {
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s: 0x%" PRIx32 ", 0x%08" PRIx32 " => %d\n",
+                      __func__, asid, VA, idx);
+    }
+
+    return idx;
+}
+
+/*
+ * Return codes:
+ * 0 or positive             index of match
+ * -1                        multiple matches
+ * -2                        no match
+ */
+int hexagon_tlb_check_overlap(HexagonTLBState *tlb, uint64_t entry,
+                              uint64_t index)
+{
+    int matches = 0;
+    int last_match = 0;
+
+    for (uint32_t i = 0; i < tlb->num_entries; i++) {
+        if (hex_tlb_is_match(entry, tlb->entries[i], false)) {
+            matches++;
+            last_match = i;
+        }
+    }
+
+    if (matches == 1) {
+        return last_match;
+    }
+    if (matches == 0) {
+        return -2;
+    }
+    return -1;
+}
+
+void hexagon_tlb_dump(Monitor *mon, HexagonTLBState *tlb)
+{
+    for (uint32_t i = 0; i < tlb->num_entries; i++) {
+        hexagon_tlb_dump_entry(mon, tlb->entries[i]);
+    }
+}
+
+uint32_t hexagon_tlb_get_num_entries(HexagonTLBState *tlb)
+{
+    return tlb->num_entries;
+}
+
+/* QOM lifecycle */
+
+static void hexagon_tlb_init(Object *obj)
+{
+}
+
+static void hexagon_tlb_realize(DeviceState *dev, Error **errp)
+{
+    HexagonTLBState *s = HEXAGON_TLB(dev);
+
+    if (s->num_entries == 0 || s->num_entries > MAX_TLB_ENTRIES) {
+        error_setg(errp, "Invalid TLB num-entries: %" PRIu32,
+                   s->num_entries);
+        return;
+    }
+    s->entries = g_new0(uint64_t, s->num_entries);
+}
+
+static void hexagon_tlb_unrealize(DeviceState *dev)
+{
+    HexagonTLBState *s = HEXAGON_TLB(dev);
+    g_free(s->entries);
+    s->entries = NULL;
+}
+
+static void hexagon_tlb_reset_hold(Object *obj, ResetType type)
+{
+    HexagonTLBState *s = HEXAGON_TLB(obj);
+    if (s->entries) {
+        memset(s->entries, 0, sizeof(uint64_t) * s->num_entries);
+    }
+}
+
+static const VMStateDescription vmstate_hexagon_tlb = {
+    .name = "hexagon-tlb",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32(num_entries, HexagonTLBState),
+        VMSTATE_VARRAY_UINT32_ALLOC(entries, HexagonTLBState, num_entries,
+                                    0, vmstate_info_uint64, uint64_t),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static const Property hexagon_tlb_properties[] = {
+    DEFINE_PROP_UINT32("num-entries", HexagonTLBState, num_entries,
+                       MAX_TLB_ENTRIES),
+};
+
+static void hexagon_tlb_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+    dc->realize = hexagon_tlb_realize;
+    dc->unrealize = hexagon_tlb_unrealize;
+    rc->phases.hold = hexagon_tlb_reset_hold;
+    dc->vmsd = &vmstate_hexagon_tlb;
+    dc->user_creatable = false;
+    device_class_set_props(dc, hexagon_tlb_properties);
+}
+
+static const TypeInfo hexagon_tlb_info = {
+    .name = TYPE_HEXAGON_TLB,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(HexagonTLBState),
+    .instance_init = hexagon_tlb_init,
+    .class_init = hexagon_tlb_class_init,
+};
+
+static void hexagon_tlb_register_types(void)
+{
+    type_register_static(&hexagon_tlb_info);
+}
+
+type_init(hexagon_tlb_register_types)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 71/76] hw/hexagon: Add machine configs for sysemu
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (69 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 70/76] hw/hexagon: Add hexagon TLB device implementation Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 72/76] hw/hexagon: Add v68, sa8775-cdsp0 defs Brian Cain
                   ` (5 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Markus Armbruster, Mike Lambert,
	Sid Manning, Pierrick Bouvier, Paolo Bonzini,
	Daniel P. Berrangé

From: Brian Cain <bcain@quicinc.com>

Some header includes are modified here: these are uniquely required for
basic system emulation functionality and had not been required for linux-user.

Acked-by: Markus Armbruster <armbru@redhat.com>
Co-authored-by: Mike Lambert <mlambert@quicinc.com>
Co-authored-by: Sid Manning <sidneym@quicinc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 MAINTAINERS                            |  12 ++
 include/hw/hexagon/hexagon.h           | 161 ++++++++++++++++++
 hw/hexagon/machine_cfg_v66g_1024.h.inc |  64 +++++++
 hw/hexagon/hexagon_dsp.c               | 221 +++++++++++++++++++++++++
 system/qdev-monitor.c                  |   2 +-
 target/hexagon/translate.c             |   1 +
 hw/Kconfig                             |   1 +
 hw/hexagon/Kconfig                     |   4 +
 hw/hexagon/meson.build                 |   6 +
 hw/meson.build                         |   1 +
 10 files changed, 472 insertions(+), 1 deletion(-)
 create mode 100644 include/hw/hexagon/hexagon.h
 create mode 100644 hw/hexagon/machine_cfg_v66g_1024.h.inc
 create mode 100644 hw/hexagon/hexagon_dsp.c
 create mode 100644 hw/hexagon/Kconfig
 create mode 100644 hw/hexagon/meson.build

diff --git a/MAINTAINERS b/MAINTAINERS
index 9d195e56ce9..44063d6e13b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1344,6 +1344,18 @@ F: pc-bios/hppa-firmware.img
 F: roms/seabios-hppa/
 F: tests/functional/hppa/
 
+Hexagon Machines
+----------------
+V66G_1024, V68N_1024, sa8775-cdsp0
+M: Brian Cain <brian.cain@oss.qualcomm.com>
+R: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
+S: Supported
+F: hw/hexagon/
+F: include/hw/hexagon/
+F: configs/devices/hexagon-softmmu/default.mak
+F: docs/system/hexagon/
+F: docs/devel/hexagon-sys.rst
+
 LoongArch Machines
 ------------------
 Virt
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
new file mode 100644
index 00000000000..1034b09c2ac
--- /dev/null
+++ b/include/hw/hexagon/hexagon.h
@@ -0,0 +1,161 @@
+/*
+ * Hexagon Baseboard System emulation.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+
+#ifndef HW_HEXAGON_H
+#define HW_HEXAGON_H
+
+#include "system/memory.h"
+#include "hw/core/boards.h"
+
+struct hexagon_board_boot_info {
+    uint64_t ram_size;
+    const char *kernel_filename;
+    uint32_t kernel_elf_flags;
+};
+
+typedef enum {
+    unknown_rev = 0,
+    v66_rev = 0xa666,
+    v67_rev = 0x2667,
+    v68_rev = 0x8d68,
+    v69_rev = 0x8c69,
+    v71_rev = 0x8c71,
+    v73_rev = 0x8c73,
+    v73m_rev = 0xcc73,
+} Rev_t;
+#define HEXAGON_LATEST_REV v73
+#define HEXAGON_LATEST_REV_UPPER V73
+
+/*
+ * Config table address bases represent bits [35:16].
+ */
+#define HEXAGON_CFG_ADDR_BASE(addr) (((addr) >> 16) & 0x0fffff)
+
+#define HEXAGON_CFGSPACE_ENTRIES (128)
+
+union hexagon_config_table {
+    struct {
+        /* Base address of L2TCM space */
+        uint32_t l2tcm_base;
+        uint32_t reserved0;
+        /* Base address of subsystem space */
+        uint32_t subsystem_base;
+        /* Base address of ETM space */
+        uint32_t etm_base;
+        /* Base address of L2 configuration space */
+        uint32_t l2cfg_base;
+        uint32_t reserved1;
+        /* Base address of L1S */
+        uint32_t l1s0_base;
+        /* Base address of AXI2 */
+        uint32_t axi2_lowaddr;
+        /* Base address of streamer base */
+        uint32_t streamer_base;
+        uint32_t reserved2;
+        /* Base address of fast L2VIC */
+        uint32_t fastl2vic_base;
+        /* Number of entries in JTLB */
+        uint32_t jtlb_size_entries;
+        /* Coprocessor type */
+        uint32_t coproc_present;
+        /* Number of extension execution contexts available */
+        uint32_t ext_contexts;
+        /* Base address of Hexagon Vector Tightly Coupled Memory (VTCM) */
+        uint32_t vtcm_base;
+        /* Size of VTCM (in KB) */
+        uint32_t vtcm_size_kb;
+        /* L2 tag size */
+        uint32_t l2tag_size;
+        /* Amount of physical L2 memory in released version */
+        uint32_t l2ecomem_size;
+        /* Hardware threads available on the core */
+        uint32_t thread_enable_mask;
+        /* Base address of the ECC registers */
+        uint32_t eccreg_base;
+        /* L2 line size */
+        uint32_t l2line_size;
+        /* Small Core processor (also implies audio extension) */
+        uint32_t tiny_core;
+        /* Size of L2TCM */
+        uint32_t l2itcm_size;
+        /* Base address of L2-ITCM */
+        uint32_t l2itcm_base;
+        uint32_t reserved3;
+        /* DTM is present */
+        uint32_t dtm_present;
+        /* Version of the DMA */
+        uint32_t dma_version;
+        /* Native HVX vector length in log of bytes */
+        uint32_t hvx_vec_log_length;
+        /* Core ID of the multi-core */
+        uint32_t core_id;
+        /* Number of multi-core cores */
+        uint32_t core_count;
+        uint32_t coproc2_reg0;
+        uint32_t coproc2_reg1;
+        /* Supported HVX vector length */
+        uint32_t v2x_mode;
+        uint32_t coproc2_reg2;
+        uint32_t coproc2_reg3;
+        uint32_t coproc2_reg4;
+        uint32_t coproc2_reg5;
+        uint32_t coproc2_reg6;
+        uint32_t coproc2_reg7;
+        /* Voltage droop mitigation technique parameter */
+        uint32_t acd_preset;
+        /* Voltage droop mitigation technique parameter */
+        uint32_t mnd_preset;
+        /* L1 data cache size (in KB) */
+        uint32_t l1d_size_kb;
+        /* L1 instruction cache size in (KB) */
+        uint32_t l1i_size_kb;
+        /* L1 data cache write policy: see HexagonL1WritePolicy */
+        uint32_t l1d_write_policy;
+        /* VTCM bank width  */
+        uint32_t vtcm_bank_width;
+        uint32_t reserved4;
+        uint32_t reserved5;
+        uint32_t reserved6;
+        uint32_t coproc2_cvt_mpy_size;
+        uint32_t consistency_domain;
+        uint32_t capacity_domain;
+        uint32_t axi3_lowaddr;
+        uint32_t coproc2_int8_subcolumns;
+        uint32_t corecfg_present;
+        uint32_t coproc2_fp16_acc_exp;
+        uint32_t AXIM2_secondary_base;
+    };
+    uint32_t raw[HEXAGON_CFGSPACE_ENTRIES];
+};
+
+struct hexagon_machine_config {
+    /* Base address of config table */
+    uint32_t cfgbase;
+    /* Size of L2 TCM */
+    uint32_t l2tcm_size;
+    /* Base address of L2VIC */
+    uint32_t l2vic_base;
+    /* Size of L2VIC region */
+    uint32_t l2vic_size;
+    /* QTimer csr base */
+    uint32_t csr_base;
+    uint32_t qtmr_region;
+    union hexagon_config_table cfgtable;
+};
+
+#define TYPE_HEXAGON_COMMON_MACHINE "hexagon-common-machine"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonCommonMachineState, HEXAGON_COMMON_MACHINE)
+
+struct HexagonCommonMachineState {
+    MachineState parent_obj;
+
+    MemoryRegion ram;
+    MemoryRegion cfgtable_rom;
+};
+
+#endif
diff --git a/hw/hexagon/machine_cfg_v66g_1024.h.inc b/hw/hexagon/machine_cfg_v66g_1024.h.inc
new file mode 100644
index 00000000000..cc4d89b89c9
--- /dev/null
+++ b/hw/hexagon/machine_cfg_v66g_1024.h.inc
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+static const struct hexagon_machine_config v66g_1024 = {
+    .cfgbase =        0xd8180000,
+    .l2tcm_size =     0x00000000,
+    .l2vic_base =     0xfc910000,
+    .l2vic_size =     0x00001000,
+    .csr_base =       0xfc900000,
+    .qtmr_region =    0xfc921000,
+    .cfgtable = {
+        .l2tcm_base = 0x0000d800,
+        .reserved0 = 0x0000d400,
+        .subsystem_base = 0x0000fc90,
+        .etm_base = 0x0000d805,
+        .l2cfg_base = 0x0000d81a,
+        .reserved1 = 0x00000000,
+        .l1s0_base = 0x0000d820,
+        .axi2_lowaddr = 0x00003000,
+        .streamer_base = 0x00000000,
+        .reserved2 = 0x0000d819,
+        .fastl2vic_base = 0x0000d81e,
+        .jtlb_size_entries = 0x00000080,
+        .coproc_present = 0x00000001,
+        .ext_contexts = 0x00000004,
+        .vtcm_base = 0x0000d820,
+        .vtcm_size_kb = 0x00000100,
+        .l2tag_size = 0x00000400,
+        .l2ecomem_size = 0x00000400,
+        .thread_enable_mask = 0x0000000f,
+        .eccreg_base = 0x0000d81f,
+        .l2line_size = 0x00000080,
+        .tiny_core = 0x00000000,
+        .l2itcm_size = 0x00000000,
+        .l2itcm_base = 0x0000d820,
+        .reserved3 = 0x00000000,
+        .dtm_present = 0x00000000,
+        .dma_version = 0x00000000,
+        .hvx_vec_log_length = 0x00000080,
+        .core_id = 0x00000000,
+        .core_count = 0x00000000,
+        .coproc2_reg0 = 0x00000000,
+        .coproc2_reg1 = 0x00000000,
+        .v2x_mode = 0x00000000,
+        .coproc2_reg2 = 0x00000000,
+        .coproc2_reg3 = 0x00000000,
+        .coproc2_reg4 = 0x00000000,
+        .coproc2_reg5 = 0x00000000,
+        .coproc2_reg6 = 0x00000000,
+        .coproc2_reg7 = 0x00000000,
+        .acd_preset = 0x00000000,
+        .mnd_preset = 0x00000000,
+        .l1d_size_kb = 0x00000000,
+        .l1i_size_kb = 0x00000000,
+        .l1d_write_policy = 0x00000000,
+        .vtcm_bank_width = 0x00000000,
+        .reserved4 = 0x00000000,
+        .reserved5 = 0x00000000,
+        .reserved6 = 0x00000000,
+        .coproc2_cvt_mpy_size = 0x00000000,
+        .consistency_domain = 0x00000000,
+        .capacity_domain = 0x00000000,
+        .axi3_lowaddr = 0x00000000,
+    },
+};
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
new file mode 100644
index 00000000000..ac01d359928
--- /dev/null
+++ b/hw/hexagon/hexagon_dsp.c
@@ -0,0 +1,221 @@
+/*
+ * Hexagon DSP Subsystem emulation.  This represents a generic DSP
+ * subsystem with few peripherals, like the Compute DSP.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "system/address-spaces.h"
+#include "hw/core/boards.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/hexagon/hexagon_tlb.h"
+#include "hw/core/loader.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "elf.h"
+#include "cpu.h"
+#include "migration/cpu.h"
+#include "system/system.h"
+#include "target/hexagon/internal.h"
+#include "system/physmem.h"
+#include "system/reset.h"
+
+#include "machine_cfg_v66g_1024.h.inc"
+
+#define TYPE_HEXAGON_DSP_MACHINE "hexagon-dsp-machine"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonDspMachineState, HEXAGON_DSP_MACHINE)
+
+struct HexagonDspMachineState {
+    HexagonCommonMachineState parent_obj;
+
+    hwaddr isdb_secure_flag;
+    hwaddr isdb_trusted_flag;
+};
+
+static HexagonDspMachineState *current_dms;
+
+static void hex_symbol_callback(const char *st_name, int st_info,
+                                uint64_t st_value, uint64_t st_size)
+{
+    if (!g_strcmp0("isdb_secure_flag", st_name)) {
+        current_dms->isdb_secure_flag = st_value;
+    }
+    if (!g_strcmp0("isdb_trusted_flag", st_name)) {
+        current_dms->isdb_trusted_flag = st_value;
+    }
+}
+
+/* Board init.  */
+static struct hexagon_board_boot_info hexagon_binfo;
+
+static void hexagon_load_kernel(HexagonDspMachineState *dms, HexagonCPU *cpu)
+{
+    uint64_t pentry;
+    long kernel_size;
+
+    current_dms = dms;
+    kernel_size = load_elf_ram_sym(hexagon_binfo.kernel_filename, NULL, NULL,
+                      NULL, &pentry, NULL, NULL,
+                      &hexagon_binfo.kernel_elf_flags, 0, EM_HEXAGON, 0, 0,
+                      &address_space_memory, false, hex_symbol_callback);
+    current_dms = NULL;
+
+    if (kernel_size <= 0) {
+        error_report("no kernel file '%s'",
+            hexagon_binfo.kernel_filename);
+        exit(1);
+    }
+
+    qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", pentry);
+}
+
+static void hexagon_init_bootstrap(HexagonDspMachineState *dms, HexagonCPU *cpu)
+{
+    MachineState *machine = MACHINE(dms);
+
+    if (machine->kernel_filename) {
+        uint32_t mem = 1;
+
+        hexagon_load_kernel(dms, cpu);
+        if (dms->isdb_secure_flag) {
+            physical_memory_write(dms->isdb_secure_flag,
+                                     &mem, sizeof(mem));
+        }
+        if (dms->isdb_trusted_flag) {
+            physical_memory_write(dms->isdb_trusted_flag,
+                                     &mem, sizeof(mem));
+        }
+    }
+}
+
+static void do_cpu_reset(void *opaque)
+{
+    HexagonCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
+    cpu_reset(cs);
+}
+
+static void hexagon_common_init(MachineState *machine, Rev_t rev,
+                                const struct hexagon_machine_config *m_cfg)
+{
+    HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(machine);
+    HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(machine);
+    MemoryRegion *address_space;
+    DeviceState *glob_regs_dev;
+    DeviceState *tlb_dev;
+
+    memset(&hexagon_binfo, 0, sizeof(hexagon_binfo));
+    if (machine->kernel_filename) {
+        hexagon_binfo.ram_size = machine->ram_size;
+        hexagon_binfo.kernel_filename = machine->kernel_filename;
+    }
+
+    machine->enable_graphics = 0;
+
+    address_space = get_system_memory();
+
+    memory_region_init_rom(&hms->cfgtable_rom, NULL, "config_table.rom",
+                           sizeof(m_cfg->cfgtable), &error_fatal);
+    memory_region_add_subregion(address_space, m_cfg->cfgbase,
+                                &hms->cfgtable_rom);
+
+    memory_region_init_ram(&hms->ram, NULL, "ddr.ram",
+                           machine->ram_size, &error_fatal);
+    memory_region_add_subregion(address_space, 0x0, &hms->ram);
+
+    glob_regs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG);
+    object_property_add_child(OBJECT(machine), "global-regs",
+                              OBJECT(glob_regs_dev));
+    qdev_prop_set_uint64(glob_regs_dev, "config-table-addr", m_cfg->cfgbase);
+    qdev_prop_set_uint32(glob_regs_dev, "dsp-rev", rev);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs_dev), &error_fatal);
+
+    tlb_dev = qdev_new(TYPE_HEXAGON_TLB);
+    object_property_add_child(OBJECT(machine), "tlb", OBJECT(tlb_dev));
+    qdev_prop_set_uint32(tlb_dev, "num-entries",
+                         m_cfg->cfgtable.jtlb_size_entries);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(tlb_dev), &error_fatal);
+
+    for (int i = 0; i < machine->smp.cpus; i++) {
+        HexagonCPU *cpu = HEXAGON_CPU(object_new(machine->cpu_type));
+        qemu_register_reset(do_cpu_reset, cpu);
+
+        /*
+         * CPU #0 is the only CPU running at boot, others must be
+         * explicitly enabled via start instruction.
+         */
+        qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
+        if (i == 0) {
+            hexagon_init_bootstrap(dms, cpu);
+        }
+        object_property_set_link(OBJECT(cpu), "global-regs",
+                                 OBJECT(glob_regs_dev), &error_fatal);
+        object_property_set_link(OBJECT(cpu), "tlb",
+                                 OBJECT(tlb_dev), &error_fatal);
+        qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal);
+    }
+}
+
+static void init_mc(MachineClass *mc)
+{
+    mc->block_default_type = IF_SD;
+    mc->default_ram_size = 4 * GiB;
+    mc->no_parallel = 1;
+    mc->no_floppy = 1;
+    mc->no_cdrom = 1;
+    mc->no_serial = 1;
+    mc->is_default = false;
+    mc->max_cpus = 8;
+}
+
+/* ----------------------------------------------------------------- */
+/* Core-specific configuration settings are defined below this line. */
+/* Config table values defined in machine_configs.h.inc              */
+/* ----------------------------------------------------------------- */
+
+static void v66g_1024_config_init(MachineState *machine)
+{
+    hexagon_common_init(machine, v66_rev, &v66g_1024);
+}
+
+static void v66g_1024_init(ObjectClass *oc, const void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "Hexagon V66G_1024";
+    mc->init = v66g_1024_config_init;
+    init_mc(mc);
+    mc->is_default = true;
+    mc->default_cpu_type = TYPE_HEXAGON_CPU_V66;
+    mc->default_cpus = 4;
+}
+
+static const TypeInfo hexagon_machine_types[] = {
+    {
+        .name = TYPE_HEXAGON_COMMON_MACHINE,
+        .parent = TYPE_MACHINE,
+        .instance_size = sizeof(HexagonCommonMachineState),
+        .abstract = true,
+    },
+    {
+        .name = TYPE_HEXAGON_DSP_MACHINE,
+        .parent = TYPE_HEXAGON_COMMON_MACHINE,
+        .instance_size = sizeof(HexagonDspMachineState),
+        .abstract = true,
+    },
+    {
+        .name = MACHINE_TYPE_NAME("V66G_1024"),
+        .parent = TYPE_HEXAGON_DSP_MACHINE,
+        .class_init = v66g_1024_init,
+    },
+};
+
+DEFINE_TYPES(hexagon_machine_types)
diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
index dfc95a08c10..00fed791cce 100644
--- a/system/qdev-monitor.c
+++ b/system/qdev-monitor.c
@@ -71,7 +71,7 @@ typedef struct QDevAlias
                               QEMU_ARCH_SPARC | \
                               QEMU_ARCH_XTENSA)
 #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
-#define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
+#define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K | QEMU_ARCH_HEXAGON)
 
 /* Please keep this table sorted by typename. */
 static const QDevAlias qdev_alias_table[] = {
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index e0418ee990d..77235916f4b 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -32,6 +32,7 @@
 #include "translate.h"
 #include "genptr.h"
 #include "printinsn.h"
+#include "exec/target_page.h"
 
 #define HELPER_H "helper.h"
 #include "exec/helper-info.c.inc"
diff --git a/hw/Kconfig b/hw/Kconfig
index c109f5537b2..c92ca2b13a3 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -53,6 +53,7 @@ source arm/Kconfig
 source cpu/Kconfig
 source alpha/Kconfig
 source avr/Kconfig
+source hexagon/Kconfig
 source hppa/Kconfig
 source i386/Kconfig
 source loongarch/Kconfig
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
new file mode 100644
index 00000000000..cdf7770a305
--- /dev/null
+++ b/hw/hexagon/Kconfig
@@ -0,0 +1,4 @@
+config HEX_DSP
+    bool
+    default y
+    depends on HEXAGON
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
new file mode 100644
index 00000000000..f528d2bc4ab
--- /dev/null
+++ b/hw/hexagon/meson.build
@@ -0,0 +1,6 @@
+hexagon_ss = ss.source_set()
+hexagon_ss.add(files('hexagon_tlb.c'))
+hexagon_ss.add(files('hexagon_globalreg.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c'))
+
+hw_arch += {'hexagon': hexagon_ss}
diff --git a/hw/meson.build b/hw/meson.build
index ef65ba51950..7fa81db453e 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -3,6 +3,7 @@ subdir('alpha')
 subdir('arm')
 subdir('avr')
 subdir('hppa')
+subdir('hexagon')
 subdir('xenpv') # i386 uses it
 subdir('i386')
 subdir('loongarch')
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 72/76] hw/hexagon: Add v68, sa8775-cdsp0 defs
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (70 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 71/76] hw/hexagon: Add machine configs for sysemu Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 73/76] hw/hexagon: Add support for cfgbase Brian Cain
                   ` (4 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Taylor Simpson,
	Philippe Mathieu-Daudé, Pierrick Bouvier

From: Brian Cain <bcain@quicinc.com>

Acked-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Acked-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc | 64 +++++++++++++++++++++++
 hw/hexagon/machine_cfg_v68n_1024.h.inc    | 64 +++++++++++++++++++++++
 2 files changed, 128 insertions(+)
 create mode 100644 hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc
 create mode 100644 hw/hexagon/machine_cfg_v68n_1024.h.inc

diff --git a/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc b/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc
new file mode 100644
index 00000000000..442cbe3be31
--- /dev/null
+++ b/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+static const struct hexagon_machine_config SA8775P_cdsp0 = {
+    .cfgbase =         0x24000000 + 0x180000,
+    .l2tcm_size =      0x00000000,
+    .l2vic_base =      0x26300000 + 0x90000,
+    .l2vic_size =      0x00001000,
+    .csr_base =        0x26300000,
+    .qtmr_region =     0x26300000 + 0xA1000,
+    .cfgtable = {
+        .l2tcm_base = 0x00002400,
+        .reserved0 = 0x00000000,
+        .subsystem_base = 0x00002638,
+        .etm_base = 0x00002419,
+        .l2cfg_base = 0x0000241a,
+        .reserved1 = 0x0000241b,
+        .l1s0_base = 0x00002500,
+        .axi2_lowaddr = 0x00000000,
+        .streamer_base = 0x00000000,
+        .reserved2 = 0x00000000,
+        .fastl2vic_base = 0x0000241e,
+        .jtlb_size_entries = 0x00000080,
+        .coproc_present = 0x00000001,
+        .ext_contexts = 0x00000004,
+        .vtcm_base = 0x00002500,
+        .vtcm_size_kb = 0x00002000,
+        .l2tag_size = 0x00000400,
+        .l2ecomem_size = 0x00000000,
+        .thread_enable_mask = 0x0000003f,
+        .eccreg_base = 0x0000241f,
+        .l2line_size = 0x00000080,
+        .tiny_core = 0x00000000,
+        .l2itcm_size = 0x00000000,
+        .l2itcm_base = 0x00002400,
+        .reserved3 = 0x00000000,
+        .dtm_present = 0x00000000,
+        .dma_version = 0x00000003,
+        .hvx_vec_log_length = 0x00000007,
+        .core_id = 0x00000000,
+        .core_count = 0x00000000,
+        .coproc2_reg0 = 0x00000040,
+        .coproc2_reg1 = 0x00000020,
+        .v2x_mode = 0x00000001,
+        .coproc2_reg2 = 0x00000008,
+        .coproc2_reg3 = 0x00000020,
+        .coproc2_reg4 = 0x00000000,
+        .coproc2_reg5 = 0x00000002,
+        .coproc2_reg6 = 0x00000016,
+        .coproc2_reg7 = 0x00000006,
+        .acd_preset = 0x00000001,
+        .mnd_preset = 0x00000000,
+        .l1d_size_kb = 0x00000010,
+        .l1i_size_kb = 0x00000020,
+        .l1d_write_policy = 0x00000002,
+        .vtcm_bank_width = 0x00000080,
+        .reserved4 = 0x00000001,
+        .reserved5 = 0x00000000,
+        .reserved6 = 0x00000003,
+        .coproc2_cvt_mpy_size = 0x0000000a,
+        .consistency_domain = 0x000000e0,
+        .capacity_domain = 0x00000080,
+        .axi3_lowaddr = 0x00000000,
+    },
+};
diff --git a/hw/hexagon/machine_cfg_v68n_1024.h.inc b/hw/hexagon/machine_cfg_v68n_1024.h.inc
new file mode 100644
index 00000000000..0c79689bc21
--- /dev/null
+++ b/hw/hexagon/machine_cfg_v68n_1024.h.inc
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+static const struct hexagon_machine_config v68n_1024 = {
+    .cfgbase =           0xde000000,
+    .l2tcm_size =        0x00000000,
+    .l2vic_base =        0xfc910000,
+    .l2vic_size =        0x00001000,
+    .csr_base =          0xfc900000,
+    .qtmr_region =       0xfc921000,
+    .cfgtable = {
+        .l2tcm_base = 0x0000d800,
+        .reserved0 = 0x00000000,
+        .subsystem_base = 0x0000fc90,
+        .etm_base = 0x0000d819,
+        .l2cfg_base = 0x0000d81a,
+        .reserved1 = 0x00000000,
+        .l1s0_base = 0x0000d840,
+        .axi2_lowaddr = 0x00003000,
+        .streamer_base = 0x0000d81c,
+        .reserved2 = 0x0000d81d,
+        .fastl2vic_base = 0x0000d81e,
+        .jtlb_size_entries = 0x00000080,
+        .coproc_present = 0x00000001,
+        .ext_contexts = 0x00000004,
+        .vtcm_base = 0x0000d840,
+        .vtcm_size_kb = 0x00001000,
+        .l2tag_size = 0x00000400,
+        .l2ecomem_size = 0x00000400,
+        .thread_enable_mask = 0x0000003f,
+        .eccreg_base = 0x0000d81f,
+        .l2line_size = 0x00000080,
+        .tiny_core = 0x00000000,
+        .l2itcm_size = 0x00000000,
+        .l2itcm_base = 0x0000d820,
+        .reserved3 = 0x00000000,
+        .dtm_present = 0x00000000,
+        .dma_version = 0x00000001,
+        .hvx_vec_log_length = 0x00000007,
+        .core_id = 0x00000000,
+        .core_count = 0x00000000,
+        .coproc2_reg0 = 0x00000040,
+        .coproc2_reg1 = 0x00000020,
+        .v2x_mode = 0x1f1f1f1f,
+        .coproc2_reg2 = 0x1f1f1f1f,
+        .coproc2_reg3 = 0x1f1f1f1f,
+        .coproc2_reg4 = 0x1f1f1f1f,
+        .coproc2_reg5 = 0x1f1f1f1f,
+        .coproc2_reg6 = 0x1f1f1f1f,
+        .coproc2_reg7 = 0x1f1f1f1f,
+        .acd_preset = 0x1f1f1f1f,
+        .mnd_preset = 0x1f1f1f1f,
+        .l1d_size_kb = 0x1f1f1f1f,
+        .l1i_size_kb = 0x1f1f1f1f,
+        .l1d_write_policy = 0x1f1f1f1f,
+        .vtcm_bank_width = 0x1f1f1f1f,
+        .reserved4 = 0x1f1f1f1f,
+        .reserved5 = 0x1f1f1f1f,
+        .reserved6 = 0x1f1f1f1f,
+        .coproc2_cvt_mpy_size = 0x1f1f1f1f,
+        .consistency_domain = 0x1f1f1f1f,
+        .capacity_domain = 0x1f1f1f1f,
+        .axi3_lowaddr = 0x1f1f1f1f,
+    },
+};
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 73/76] hw/hexagon: Add support for cfgbase
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (71 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 72/76] hw/hexagon: Add v68, sa8775-cdsp0 defs Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 74/76] target/hexagon: add build config for softmmu Brian Cain
                   ` (3 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Sid Manning, Taylor Simpson, Pierrick Bouvier

From: Sid Manning <sidneym@quicinc.com>

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Sid Manning <sidneym@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 hw/hexagon/hexagon_dsp.c | 4 ++++
 target/hexagon/cpu.c     | 1 -
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index ac01d359928..aa493993229 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -162,6 +162,10 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev,
                                  OBJECT(tlb_dev), &error_fatal);
         qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal);
     }
+
+    rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable,
+                          sizeof(m_cfg->cfgtable), m_cfg->cfgbase,
+                          &address_space_memory);
 }
 
 static void init_mc(MachineClass *mc)
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 06be5c8d498..42d93e5da47 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -400,7 +400,6 @@ void hexagon_cpu_soft_reset(CPUHexagonState *env)
 }
 #endif
 
-
 static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
 {
     CPUState *cs = CPU(obj);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 74/76] target/hexagon: add build config for softmmu
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (72 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 73/76] hw/hexagon: Add support for cfgbase Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 75/76] hw/hexagon: Define hexagon "virt" machine Brian Cain
                   ` (2 subsequent siblings)
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Taylor Simpson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Paolo Bonzini

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Philippe Mathieu-Daudé <philmd@mailo.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 MAINTAINERS                                 |  1 +
 configs/devices/hexagon-softmmu/default.mak |  6 ++++++
 configs/targets/hexagon-softmmu.mak         |  7 +++++++
 target/hexagon/cpu.h                        |  5 +----
 target/Kconfig                              |  1 +
 target/hexagon/Kconfig                      |  2 ++
 target/hexagon/meson.build                  | 13 ++++++++++++-
 7 files changed, 30 insertions(+), 5 deletions(-)
 create mode 100644 configs/devices/hexagon-softmmu/default.mak
 create mode 100644 configs/targets/hexagon-softmmu.mak
 create mode 100644 target/hexagon/Kconfig

diff --git a/MAINTAINERS b/MAINTAINERS
index 44063d6e13b..cda4d57b495 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -256,6 +256,7 @@ F: linux-user/hexagon/
 F: tests/tcg/hexagon/
 F: disas/hexagon.c
 F: configs/targets/hexagon-linux-user.mak
+F: configs/targets/hexagon-softmmu.mak
 F: tests/docker/dockerfiles/debian-hexagon-cross.docker
 F: gdbstub/gdb-xml/hexagon*.xml
 F: docs/system/target-hexagon.rst
diff --git a/configs/devices/hexagon-softmmu/default.mak b/configs/devices/hexagon-softmmu/default.mak
new file mode 100644
index 00000000000..f7fc874eb0c
--- /dev/null
+++ b/configs/devices/hexagon-softmmu/default.mak
@@ -0,0 +1,6 @@
+# Default configuration for hexagon-softmmu
+
+# Uncomment the following lines to disable these optional devices:
+
+# Boards are selected by default, uncomment to keep out of the build.
+# CONFIG_HEX_DSP=y
diff --git a/configs/targets/hexagon-softmmu.mak b/configs/targets/hexagon-softmmu.mak
new file mode 100644
index 00000000000..fdfa29b4f39
--- /dev/null
+++ b/configs/targets/hexagon-softmmu.mak
@@ -0,0 +1,7 @@
+# Default configuration for hexagon-softmmu
+
+TARGET_ARCH=hexagon
+TARGET_XML_FILES=hexagon-core.xml hexagon-hvx.xml
+TARGET_LONG_BITS=32
+TARGET_NOT_USING_LEGACY_LDST_PHYS_API=y
+TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=y
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 4a12dc04727..7694fd91fa8 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -38,10 +38,7 @@ typedef struct HexagonGlobalRegState HexagonGlobalRegState;
 #include "hw/core/registerfields.h"
 #include "qemu/bitmap.h"
 
-#ifndef CONFIG_USER_ONLY
-#error "Hexagon does not support system emulation"
-#endif
-
+#include "target/hexagon/reg_fields.h"
 
 #define NUM_PREGS 4
 #define TOTAL_PER_THREAD_REGS 64
diff --git a/target/Kconfig b/target/Kconfig
index 3c73e3bae01..0288a3f4164 100644
--- a/target/Kconfig
+++ b/target/Kconfig
@@ -16,6 +16,7 @@ source sh4/Kconfig
 source sparc/Kconfig
 source tricore/Kconfig
 source xtensa/Kconfig
+source hexagon/Kconfig
 
 config TARGET_BIG_ENDIAN
     bool
diff --git a/target/hexagon/Kconfig b/target/hexagon/Kconfig
new file mode 100644
index 00000000000..7e556f35063
--- /dev/null
+++ b/target/hexagon/Kconfig
@@ -0,0 +1,2 @@
+config HEXAGON
+    bool
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index fd3d69feffd..59cb09c1070 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -235,6 +235,7 @@ decodetree_trans_funcs_generated = custom_target(
     command: [python, files('gen_trans_funcs.py'), semantics_generated, '@OUTPUT@'],
 )
 hexagon_ss.add(decodetree_trans_funcs_generated)
+hexagon_softmmu_ss = ss.source_set()
 
 hexagon_ss.add(files(
     'cpu.c',
@@ -253,6 +254,14 @@ hexagon_ss.add(files(
     'mmvec/system_ext_mmvec.c',
 ))
 
+hexagon_softmmu_ss.add(files(
+    'cpu_helper.c',
+    'hex_mmu.c',
+    'hex_interrupts.c',
+    'hexswi.c',
+    'machine.c',
+))
+
 #
 # Step 4.5
 # We use flex/bison based idef-parser to generate TCG code for a lot
@@ -262,7 +271,8 @@ hexagon_ss.add(files(
 #     idef-generated-enabled-instructions
 #
 idef_parser_enabled = get_option('hexagon_idef_parser')
-if idef_parser_enabled and 'hexagon-linux-user' in target_dirs
+if idef_parser_enabled and ('hexagon-linux-user' in target_dirs or
+                            'hexagon-softmmu' in target_dirs)
     idef_parser_input_generated = custom_target(
         'idef_parser_input.h.inc',
         output: 'idef_parser_input.h.inc',
@@ -390,3 +400,4 @@ analyze_funcs_generated = custom_target(
 hexagon_ss.add(analyze_funcs_generated)
 
 target_arch += {'hexagon': hexagon_ss}
+target_system_arch += {'hexagon': hexagon_softmmu_ss}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 75/76] hw/hexagon: Define hexagon "virt" machine
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (73 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 74/76] target/hexagon: add build config for softmmu Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 14:16 ` [PULL v3 76/76] tests/qtest: Add hexagon boot-serial-test Brian Cain
  2026-06-25 20:58 ` [PULL v3 00/76] hex queue Stefan Hajnoczi
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Brian Cain, Pierrick Bouvier, Paolo Bonzini,
	Kevin Wolf, Hanna Reitz, open list:Block layer core

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>
---
 configs/devices/hexagon-softmmu/default.mak |   1 +
 configs/targets/hexagon-softmmu.mak         |   1 +
 include/hw/hexagon/virt.h                   |  30 ++
 hw/hexagon/virt.c                           | 347 ++++++++++++++++++++
 hw/hexagon/Kconfig                          |  10 +
 hw/hexagon/meson.build                      |   1 +
 tests/qemu-iotests/testenv.py               |   1 +
 7 files changed, 391 insertions(+)
 create mode 100644 include/hw/hexagon/virt.h
 create mode 100644 hw/hexagon/virt.c

diff --git a/configs/devices/hexagon-softmmu/default.mak b/configs/devices/hexagon-softmmu/default.mak
index f7fc874eb0c..6f2007771b5 100644
--- a/configs/devices/hexagon-softmmu/default.mak
+++ b/configs/devices/hexagon-softmmu/default.mak
@@ -3,4 +3,5 @@
 # Uncomment the following lines to disable these optional devices:
 
 # Boards are selected by default, uncomment to keep out of the build.
+# CONFIG_HEX_VIRT=y
 # CONFIG_HEX_DSP=y
diff --git a/configs/targets/hexagon-softmmu.mak b/configs/targets/hexagon-softmmu.mak
index fdfa29b4f39..a77c100f0c5 100644
--- a/configs/targets/hexagon-softmmu.mak
+++ b/configs/targets/hexagon-softmmu.mak
@@ -5,3 +5,4 @@ TARGET_XML_FILES=hexagon-core.xml hexagon-hvx.xml
 TARGET_LONG_BITS=32
 TARGET_NOT_USING_LEGACY_LDST_PHYS_API=y
 TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=y
+TARGET_NEED_FDT=y
diff --git a/include/hw/hexagon/virt.h b/include/hw/hexagon/virt.h
new file mode 100644
index 00000000000..fcb47762194
--- /dev/null
+++ b/include/hw/hexagon/virt.h
@@ -0,0 +1,30 @@
+/*
+ * Definitions for hexagon virt board.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_HEXAGONVIRT_H
+#define HW_HEXAGONVIRT_H
+
+#include "hw/hexagon/hexagon.h"
+#include "target/hexagon/cpu.h"
+
+struct HexagonVirtMachineState {
+    HexagonCommonMachineState parent_obj;
+
+    int fdt_size;
+    MemoryRegion *sys;
+    MemoryRegion tcm;
+    MemoryRegion vtcm;
+    MemoryRegion bios;
+    Clock *apb_clk;
+};
+
+void hexagon_load_fdt(const struct HexagonVirtMachineState *vms);
+
+#define TYPE_HEXAGON_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonVirtMachineState, HEXAGON_VIRT_MACHINE)
+
+#endif /* HW_HEXAGONVIRT_H */
diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c
new file mode 100644
index 00000000000..a3638998b87
--- /dev/null
+++ b/hw/hexagon/virt.c
@@ -0,0 +1,347 @@
+/*
+ * Hexagon virt emulation
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hexagon/virt.h"
+#include "elf.h"
+#include "hw/char/pl011.h"
+#include "hw/core/clock.h"
+#include "hw/core/sysbus-fdt.h"
+#include "hw/hexagon/hexagon.h"
+#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/hexagon/hexagon_tlb.h"
+#include "hw/core/loader.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/qdev-clock.h"
+#include "hw/core/register.h"
+#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
+#include "qemu/units.h"
+#include "machine_cfg_v68n_1024.h.inc"
+#include "system/address-spaces.h"
+#include "system/device_tree.h"
+#include "system/reset.h"
+#include "system/system.h"
+#include <libfdt.h>
+
+enum {
+    VIRT_UART0,
+    VIRT_FDT,
+};
+
+static const MemMapEntry base_memmap[] = {
+    [VIRT_UART0] = { 0x10000000, 0x00000200 },
+    [VIRT_FDT] = { 0x99800000, 0x00400000 },
+};
+
+
+static void create_fdt(HexagonVirtMachineState *vms)
+{
+    MachineState *ms = MACHINE(vms);
+    void *fdt = create_device_tree(&vms->fdt_size);
+    uint8_t rng_seed[32];
+
+    if (!fdt) {
+        error_report("create_device_tree() failed");
+        exit(1);
+    }
+
+    ms->fdt = fdt;
+
+    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
+    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1);
+    qemu_fdt_setprop_string(fdt, "/", "model", "hexagon-virt,qemu");
+    qemu_fdt_setprop_string(fdt, "/", "compatible", "qcom,sm8150");
+
+    qemu_fdt_add_subnode(fdt, "/soc");
+    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
+    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1);
+    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
+
+    qemu_fdt_add_subnode(fdt, "/chosen");
+    qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
+    qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
+}
+
+static void fdt_add_hvx(HexagonVirtMachineState *vms,
+                        const struct hexagon_machine_config *m_cfg)
+{
+    const MachineState *ms = MACHINE(vms);
+    uint32_t vtcm_size_bytes = m_cfg->cfgtable.vtcm_size_kb * 1024;
+    if (vtcm_size_bytes > 0) {
+        memory_region_init_ram(&vms->vtcm, NULL, "vtcm.ram", vtcm_size_bytes,
+                               &error_fatal);
+        memory_region_add_subregion(vms->sys, m_cfg->cfgtable.vtcm_base << 16,
+                                    &vms->vtcm);
+
+        qemu_fdt_add_subnode(ms->fdt, "/soc/vtcm");
+        qemu_fdt_setprop_string(ms->fdt, "/soc/vtcm", "compatible",
+                                "qcom,hexagon_vtcm");
+
+        assert(sizeof(m_cfg->cfgtable.vtcm_base) == sizeof(uint32_t));
+        qemu_fdt_setprop_cells(ms->fdt, "/soc/vtcm", "reg", 0,
+                               m_cfg->cfgtable.vtcm_base << 16,
+                               vtcm_size_bytes);
+    }
+
+    if (m_cfg->cfgtable.ext_contexts > 0) {
+        qemu_fdt_add_subnode(ms->fdt, "/soc/hvx");
+        qemu_fdt_setprop_string(ms->fdt, "/soc/hvx", "compatible",
+                                "qcom,hexagon-hvx");
+        qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-max-ctxts",
+                               m_cfg->cfgtable.ext_contexts);
+        qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-vlength",
+                               m_cfg->cfgtable.hvx_vec_log_length);
+    }
+}
+
+static int32_t fdt_add_clocks(const HexagonVirtMachineState *vms)
+{
+    MachineState *ms = MACHINE(vms);
+    int32_t clk_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+
+    qemu_fdt_add_subnode(ms->fdt, "/apb-pclk");
+    qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "compatible", "fixed-clock");
+    qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "#clock-cells", 0x0);
+    qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "clock-frequency", 24000000);
+    qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "clock-output-names",
+                            "clk24mhz");
+    qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "phandle", clk_phandle);
+
+    return clk_phandle;
+}
+
+static void fdt_add_uart(const HexagonVirtMachineState *vms, int uart,
+                         int32_t clk_phandle)
+{
+    char *nodename;
+    hwaddr base = base_memmap[uart].base;
+    hwaddr size = base_memmap[uart].size;
+    assert(uart == 0);
+    const char compat[] = "arm,pl011\0arm,primecell";
+    const char clocknames[] = "uartclk\0apb_pclk";
+    MachineState *ms = MACHINE(vms);
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_new(TYPE_PL011);
+    s = SYS_BUS_DEVICE(dev);
+    qdev_prop_set_chr(dev, "chardev", serial_hd(0));
+    qdev_connect_clock_in(dev, "clk", vms->apb_clk);
+    sysbus_realize_and_unref(s, &error_fatal);
+    sysbus_mmio_map(s, 0, base);
+
+    nodename = g_strdup_printf("/pl011@%" PRIx64, base);
+    qemu_fdt_add_subnode(ms->fdt, nodename);
+
+    /* Note that we can't use setprop_string because of the embedded NUL */
+    qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
+    qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size);
+    qemu_fdt_setprop_cells(ms->fdt, nodename, "clocks", clk_phandle,
+                           clk_phandle);
+    qemu_fdt_setprop(ms->fdt, nodename, "clock-names", clocknames,
+                     sizeof(clocknames));
+
+    qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+    qemu_fdt_add_subnode(ms->fdt, "/aliases");
+    qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", nodename);
+
+    g_free(nodename);
+}
+
+static void fdt_add_cpu_nodes(const HexagonVirtMachineState *vms)
+{
+    MachineState *ms = MACHINE(vms);
+    qemu_fdt_add_subnode(ms->fdt, "/cpus");
+    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
+    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
+
+    /* cpu nodes */
+    for (int num = ms->smp.cpus - 1; num >= 0; num--) {
+        char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
+        qemu_fdt_add_subnode(ms->fdt, nodename);
+        qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
+        qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
+        qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
+                              qemu_fdt_alloc_phandle(ms->fdt));
+        g_free(nodename);
+    }
+}
+
+
+
+static void virt_instance_init(Object *obj)
+{
+    HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(obj);
+
+    create_fdt(vms);
+}
+
+void hexagon_load_fdt(const HexagonVirtMachineState *vms)
+{
+    MachineState *ms = MACHINE(vms);
+    hwaddr fdt_addr = base_memmap[VIRT_FDT].base;
+    uint32_t fdtsize = vms->fdt_size;
+
+    g_assert(fdtsize <= base_memmap[VIRT_FDT].size);
+    /* copy in the device tree */
+    rom_add_blob_fixed_as("fdt", ms->fdt, fdtsize, fdt_addr,
+                          &address_space_memory);
+    qemu_register_reset_nosnapshotload(
+        qemu_fdt_randomize_seeds,
+        rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize));
+}
+
+static uint64_t load_kernel(const HexagonVirtMachineState *vms)
+{
+    MachineState *ms = MACHINE(vms);
+    uint64_t entry = 0;
+    if (load_elf_ram_sym(ms->kernel_filename, NULL, NULL, NULL, &entry, NULL,
+                         NULL, NULL, 0, EM_HEXAGON, 0, 0, &address_space_memory,
+                         false, NULL) > 0) {
+        return entry;
+    }
+    error_report("error loading '%s'", ms->kernel_filename);
+    exit(1);
+}
+
+static uint64_t load_bios(HexagonVirtMachineState *vms)
+{
+    MachineState *ms = MACHINE(vms);
+    uint64_t bios_addr = 0x0;  /* Load BIOS at reset vector address 0x0 */
+    int bios_size;
+
+    bios_size = load_image_targphys(ms->firmware ?: "",
+                                    bios_addr, 64 * 1024, NULL);
+    if (bios_size < 0) {
+        error_report("Could not load BIOS '%s'", ms->firmware ?: "");
+        exit(1);
+    }
+
+    return bios_addr;  /* Return entry point at address 0x0 */
+}
+
+static void do_cpu_reset(void *opaque)
+{
+    HexagonCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
+    cpu_reset(cs);
+}
+
+static void virt_init(MachineState *ms)
+{
+    HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(ms);
+    const struct hexagon_machine_config *m_cfg = &v68n_1024;
+    DeviceState *gsregs_dev;
+    DeviceState *tlb_dev;
+    DeviceState *cpu0;
+    int32_t clk_phandle;
+
+    qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline);
+
+    vms->sys = get_system_memory();
+
+    /* Create APB clock for peripherals */
+    vms->apb_clk = clock_new(OBJECT(ms), "apb-pclk");
+    clock_set_hz(vms->apb_clk, 24000000);
+
+    memory_region_init_ram(&vms->parent_obj.ram, NULL, "ddr.ram",
+                           ms->ram_size, &error_fatal);
+    memory_region_add_subregion(vms->sys, 0x0, &vms->parent_obj.ram);
+
+    if (m_cfg->l2tcm_size) {
+        memory_region_init_ram(&vms->tcm, NULL, "tcm.ram", m_cfg->l2tcm_size,
+                               &error_fatal);
+        memory_region_add_subregion(vms->sys, m_cfg->cfgtable.l2tcm_base << 16,
+                                    &vms->tcm);
+    }
+
+    memory_region_init_rom(&vms->parent_obj.cfgtable_rom, NULL,
+                           "config_table.rom", sizeof(m_cfg->cfgtable),
+                           &error_fatal);
+    memory_region_add_subregion(vms->sys, m_cfg->cfgbase,
+                                &vms->parent_obj.cfgtable_rom);
+    fdt_add_hvx(vms, m_cfg);
+
+    gsregs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG);
+    object_property_add_child(OBJECT(ms), "global-regs", OBJECT(gsregs_dev));
+    qdev_prop_set_uint64(gsregs_dev, "config-table-addr", m_cfg->cfgbase);
+    qdev_prop_set_uint32(gsregs_dev, "dsp-rev", v68_rev);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(gsregs_dev), &error_fatal);
+
+    tlb_dev = qdev_new(TYPE_HEXAGON_TLB);
+    object_property_add_child(OBJECT(ms), "tlb", OBJECT(tlb_dev));
+    qdev_prop_set_uint32(tlb_dev, "num-entries",
+                         m_cfg->cfgtable.jtlb_size_entries);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(tlb_dev), &error_fatal);
+
+    cpu0 = NULL;
+    for (int i = 0; i < ms->smp.cpus; i++) {
+        HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type));
+        qemu_register_reset(do_cpu_reset, cpu);
+
+        if (i == 0) {
+            cpu0 = DEVICE(cpu);
+            if (ms->kernel_filename) {
+                uint64_t entry = load_kernel(vms);
+                qdev_prop_set_uint32(cpu0, "exec-start-addr", entry);
+            } else if (ms->firmware) {
+                uint64_t entry = load_bios(vms);
+                qdev_prop_set_uint32(cpu0, "exec-start-addr", entry);
+            }
+        }
+        qdev_prop_set_uint32(DEVICE(cpu), "htid", i);
+        qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
+        object_property_set_link(OBJECT(cpu), "global-regs",
+                                 OBJECT(gsregs_dev), &error_fatal);
+        object_property_set_link(OBJECT(cpu), "tlb",
+                                 OBJECT(tlb_dev), &error_fatal);
+
+        qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal);
+    }
+    fdt_add_cpu_nodes(vms);
+    clk_phandle = fdt_add_clocks(vms);
+    fdt_add_uart(vms, VIRT_UART0, clk_phandle);
+
+    rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable,
+                          sizeof(m_cfg->cfgtable), m_cfg->cfgbase,
+                          &address_space_memory);
+
+    hexagon_load_fdt(vms);
+}
+
+
+static void virt_class_init(ObjectClass *oc, const void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "Hexagon Virtual Machine";
+    mc->init = virt_init;
+    mc->default_cpu_type = HEXAGON_CPU_TYPE_NAME("v68");
+    mc->default_ram_size = 4 * GiB;
+    mc->max_cpus = 8;
+    mc->default_cpus = 8;
+    mc->is_default = false;
+    mc->default_kernel_irqchip_split = false;
+    mc->block_default_type = IF_VIRTIO;
+    mc->default_boot_order = NULL;
+    mc->no_cdrom = 1;
+    mc->numa_mem_supported = false;
+    mc->default_nic = "virtio-mmio-bus";
+}
+
+
+static const TypeInfo virt_machine_types[] = { {
+    .name = TYPE_HEXAGON_VIRT_MACHINE,
+    .parent = TYPE_HEXAGON_COMMON_MACHINE,
+    .instance_size = sizeof(HexagonVirtMachineState),
+    .class_init = virt_class_init,
+    .instance_init = virt_instance_init,
+} };
+
+DEFINE_TYPES(virt_machine_types)
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index cdf7770a305..52065ab3b22 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -2,3 +2,13 @@ config HEX_DSP
     bool
     default y
     depends on HEXAGON
+
+config HEX_VIRT
+    bool
+    default y
+    depends on HEX_DSP && FDT
+    select DEVICE_TREE
+    select VIRTIO_MMIO
+    select PL011
+    select VIRTIO_BLK
+    select VIRTIO_SCSI
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index f528d2bc4ab..bade3a32921 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -2,5 +2,6 @@ hexagon_ss = ss.source_set()
 hexagon_ss.add(files('hexagon_tlb.c'))
 hexagon_ss.add(files('hexagon_globalreg.c'))
 hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c'))
+hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c'))
 
 hw_arch += {'hexagon': hexagon_ss}
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
index c357e6ebf50..86bcdf7cfad 100644
--- a/tests/qemu-iotests/testenv.py
+++ b/tests/qemu-iotests/testenv.py
@@ -259,6 +259,7 @@ def __init__(self, source_dir: str, build_dir: str,
             ('arm', 'virt'),
             ('aarch64', 'virt'),
             ('avr', 'mega2560'),
+            ('hexagon', 'virt'),
             ('m68k', 'virt'),
             ('or1k', 'virt'),
             ('riscv32', 'virt'),
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PULL v3 76/76] tests/qtest: Add hexagon boot-serial-test
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (74 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 75/76] hw/hexagon: Define hexagon "virt" machine Brian Cain
@ 2026-06-25 14:16 ` Brian Cain
  2026-06-25 20:58 ` [PULL v3 00/76] hex queue Stefan Hajnoczi
  76 siblings, 0 replies; 78+ messages in thread
From: Brian Cain @ 2026-06-25 14:16 UTC (permalink / raw)
  To: qemu-devel, stefanha
  Cc: brian.cain, Fabiano Rosas, Philippe Mathieu-Daudé,
	Pierrick Bouvier, Laurent Vivier, Paolo Bonzini

Add boot-serial-test support for Hexagon architecture using the virt
machine.

Reviewed-by: Fabiano Rosas <farosas@suse.de>
Acked-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 tests/qtest/boot-serial-test.c | 8 ++++++++
 tests/qtest/meson.build        | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
index bcd0a9c50e7..37fee7a91c4 100644
--- a/tests/qtest/boot-serial-test.c
+++ b/tests/qtest/boot-serial-test.c
@@ -142,6 +142,13 @@ static const uint8_t kernel_stm32vldiscovery[] = {
     0x04, 0x38, 0x01, 0x40                  /* 0x40013804 = USART1 TXD */
 };
 
+static const uint8_t bios_hexagon[] = {
+    0x00, 0x40, 0x00, 0x01,                 /* immext(#0x10000000) */
+    0x00, 0xc0, 0x00, 0x78,                 /* r0 = ##0x10000000 */
+    0x54, 0xc0, 0x00, 0x3c,                 /* memb(r0+#0) = #0x54 Write 'T' */
+    0xf8, 0xff, 0xff, 0x59                  /* jump 0x0 ; Loop back to start */
+};
+
 typedef struct testdef {
     const char *arch;       /* Target architecture */
     const char *machine;    /* Name of the machine */
@@ -194,6 +201,7 @@ static const testdef_t tests[] = {
     { "arm", "microbit", "", "T", sizeof(kernel_nrf51), kernel_nrf51 },
     { "arm", "stm32vldiscovery", "", "T",
       sizeof(kernel_stm32vldiscovery), kernel_stm32vldiscovery },
+    { "hexagon", "virt", "", "TT", sizeof(bios_hexagon), NULL, bios_hexagon },
 
     { NULL }
 };
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 4897325d84a..b2d36499d27 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -295,6 +295,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
    ['iommu-riscv-test'] : []) + \
   (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
 
+qtests_hexagon = ['boot-serial-test']
+
 qos_test_ss = ss.source_set()
 qos_test_ss.add(
   'ac97-test.c',
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 78+ messages in thread

* Re: [PULL v3 00/76] hex queue
  2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
                   ` (75 preceding siblings ...)
  2026-06-25 14:16 ` [PULL v3 76/76] tests/qtest: Add hexagon boot-serial-test Brian Cain
@ 2026-06-25 20:58 ` Stefan Hajnoczi
  76 siblings, 0 replies; 78+ messages in thread
From: Stefan Hajnoczi @ 2026-06-25 20:58 UTC (permalink / raw)
  To: Brian Cain; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3197 bytes --]

On Thu, Jun 25, 2026 at 07:15:17AM -0700, Brian Cain wrote:
> The following changes since commit b83371668192a705b878e909c5ae9c1233cbd5fb:
> 
>   Merge tag 'pbouvier/pr/plugins-20260618' of https://gitlab.com/p-b-o/qemu into staging (2026-06-19 15:00:01 -0400)
> 
> are available in the Git repository at:
> 
>   https://github.com/qualcomm/qemu tags/pull-hex-20260625
> 
> for you to fetch changes up to 0281aa50c4792fd091e00051031aa927ea0790ea:
> 
>   tests/qtest: Add hexagon boot-serial-test (2026-06-24 22:18:47 -0700)
> 
> ----------------------------------------------------------------
> hex queue sysemu v3
> 
> w/`tests/docker: add flex and bison to emsdk-wasm64-cross`, now passes:
> 
>     Program flex found: YES (/usr/bin/flex)
>     Program bison found: YES 3.8.2 (/usr/bin/bison)
>     ...
>     Build-time dependency glib-2.0 found: YES 2.72.4
>     ...
>     Build targets in project: 527
>     ...
>     [1421/1421] Linking target qemu-system-hexagon.js

There is another wasm-related hexagon failure:

https://gitlab.com/qemu-project/qemu/-/jobs/15042103056#L9777

Note that I also applied 20260625193320.260312-1-stefanha@redhat.com to
solve a zlib.net tarball 404 error that breaks the emsdk-wasm64-cross
image. The mailing list is slow right now, so just in case you don't
have that email, here is a copy of it:

From: Stefan Hajnoczi <stefanha@redhat.com>
Subject: [PATCH] tests/docker: bump emsdk-wasm64-cross zlib version to 1.3.2
Date: Thu, 25 Jun 2026 15:33:20 -0400
Message-ID: <20260625193320.260312-1-stefanha@redhat.com>

Container image builds have started failing because zlib.net no longer
hosts the 1.3.1 tarball. Move to the 1.3.2 release from February 17,
2026.

  $ make docker-image-emsdk-wasm64-cross
  changing dir to build for make "docker-image-emsdk-wasm64-cross"...
  make[1]: Entering directory 'qemu/build'
    BUILD   emsdk-wasm64-cross
  ...
  xz: (stdin): File format not recognized
  tar: Child returned status 1
  tar: Error is not recoverable: exiting now
  Error: building at STEP "RUN curl -Ls https://zlib.net/zlib-$ZLIB_VERSION.tar.xz |     tar xJC /zlib --strip-components=1": while running runtime: exit status 2
  make[1]: *** [qemu/tests/docker/Makefile.include:43: docker-image-emsdk-wasm64-cross] Error 2
  make[1]: Leaving directory 'qemu/build'
  make: *** [GNUmakefile:6: build] Error 2

Cc: Kohei Tokunaga <ktokunaga.mail@gmail.com>
Cc: Brian Cain <brian.cain@oss.qualcomm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/docker/dockerfiles/emsdk-wasm64-cross.docker | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/docker/dockerfiles/emsdk-wasm64-cross.docker b/tests/docker/dockerfiles/emsdk-wasm64-cross.docker
index 8a924816f92..cbe20c7193e 100644
--- a/tests/docker/dockerfiles/emsdk-wasm64-cross.docker
+++ b/tests/docker/dockerfiles/emsdk-wasm64-cross.docker
@@ -1,7 +1,7 @@
 # syntax = docker/dockerfile:1.5

 ARG EMSDK_VERSION_QEMU=4.0.10
-ARG ZLIB_VERSION=1.3.1
+ARG ZLIB_VERSION=1.3.2
 ARG GLIB_MINOR_VERSION=2.84
 ARG GLIB_VERSION=${GLIB_MINOR_VERSION}.0
 ARG PIXMAN_VERSION=0.44.2
--
2.54.0

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related	[flat|nested] 78+ messages in thread

end of thread, other threads:[~2026-06-25 20:58 UTC | newest]

Thread overview: 78+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-25 14:15 [PULL v3 00/76] hex queue Brian Cain
2026-06-25 14:15 ` [PULL v3 01/76] tests/docker: add flex and bison to emsdk-wasm64-cross Brian Cain
2026-06-25 14:15 ` [PULL v3 02/76] target/hexagon: use cmd_array() instead of get_id() Brian Cain
2026-06-25 14:15 ` [PULL v3 03/76] target/hexagon/idef-parser: open input file in binary mode Brian Cain
2026-06-25 14:15 ` [PULL v3 04/76] docs: Add hexagon sysemu docs Brian Cain
2026-06-25 14:15 ` [PULL v3 05/76] docs/system: Add hexagon CPU emulation Brian Cain
2026-06-25 14:15 ` [PULL v3 06/76] target/hexagon: Fix badva reference, delete CAUSE Brian Cain
2026-06-25 14:15 ` [PULL v3 07/76] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Brian Cain
2026-06-25 14:15 ` [PULL v3 08/76] target/hexagon: Handle system/guest registers in gen_analyze_funcs.py and hex_common.py Brian Cain
2026-06-25 14:15 ` [PULL v3 09/76] target/hexagon: Suppress unused-variable warnings for sysemu source regs Brian Cain
2026-06-25 14:15 ` [PULL v3 10/76] target/hexagon: Switch to tag_ignore(), generate via get_{user, sys}_tags() Brian Cain
2026-06-25 14:15 ` [PULL v3 11/76] target/hexagon: Add privilege check, use tag_ignore() Brian Cain
2026-06-25 14:15 ` [PULL v3 12/76] target/hexagon: Add a placeholder fp exception Brian Cain
2026-06-25 14:15 ` [PULL v3 13/76] target/hexagon: Add guest, system reg number defs Brian Cain
2026-06-25 14:15 ` [PULL v3 14/76] target/hexagon: Add guest, system reg number state Brian Cain
2026-06-25 14:15 ` [PULL v3 15/76] target/hexagon: Add TCG values for sreg, greg Brian Cain
2026-06-25 14:15 ` [PULL v3 16/76] target/hexagon: Add guest/sys reg writes to DisasContext Brian Cain
2026-06-25 14:15 ` [PULL v3 17/76] target/hexagon: Add imported macro, attr defs for sysemu Brian Cain
2026-06-25 14:15 ` [PULL v3 18/76] target/hexagon: Add new macro definitions " Brian Cain
2026-06-25 14:15 ` [PULL v3 19/76] target/hexagon: Add handlers for guest/sysreg r/w Brian Cain
2026-06-25 14:15 ` [PULL v3 20/76] target/hexagon: Add placeholder greg/sreg r/w helpers Brian Cain
2026-06-25 14:15 ` [PULL v3 21/76] target/hexagon: Add vmstate representation Brian Cain
2026-06-25 14:15 ` [PULL v3 22/76] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Brian Cain
2026-06-25 14:15 ` [PULL v3 23/76] target/hexagon: Define register fields for system regs Brian Cain
2026-06-25 14:15 ` [PULL v3 24/76] target/hexagon: Implement do_raise_exception() Brian Cain
2026-06-25 14:15 ` [PULL v3 25/76] target/hexagon: Add system reg insns Brian Cain
2026-06-25 14:15 ` [PULL v3 26/76] target/hexagon: Add sysemu TCG overrides Brian Cain
2026-06-25 14:15 ` [PULL v3 27/76] target/hexagon: Add implicit attributes to sysemu macros Brian Cain
2026-06-25 14:15 ` [PULL v3 28/76] target/hexagon: Add TCG overrides for int handler insts Brian Cain
2026-06-25 14:15 ` [PULL v3 29/76] target/hexagon: Add TCG overrides for thread ctl Brian Cain
2026-06-25 14:15 ` [PULL v3 30/76] target/hexagon: Add TCG overrides for rte, nmi Brian Cain
2026-06-25 14:15 ` [PULL v3 31/76] target/hexagon: Add sreg_{read,write} helpers Brian Cain
2026-06-25 14:15 ` [PULL v3 32/76] target/hexagon: Add representation to count cycles Brian Cain
2026-06-25 14:15 ` [PULL v3 33/76] target/hexagon: Add implementation of cycle counters Brian Cain
2026-06-25 14:15 ` [PULL v3 34/76] target/hexagon: Add pcycle setting functionality Brian Cain
2026-06-25 14:15 ` [PULL v3 35/76] target/hexagon: Add cpu modes, mmu indices, next_PC to state Brian Cain
2026-06-25 14:15 ` [PULL v3 36/76] hw/hexagon: Declare hexagon TLB device interface Brian Cain
2026-06-25 14:15 ` [PULL v3 37/76] target/hexagon: Update TARGET_PAGE_BITS, stubs for modify_ssr/get_exe_mode Brian Cain
2026-06-25 14:15 ` [PULL v3 38/76] target/hexagon: Define f{S,G}ET_FIELD macros Brian Cain
2026-06-25 14:15 ` [PULL v3 39/76] target/hexagon: Add hex_interrupts support Brian Cain
2026-06-25 14:15 ` [PULL v3 40/76] target/hexagon: Implement {c,}swi helpers Brian Cain
2026-06-25 14:15 ` [PULL v3 41/76] target/hexagon: Implement iassign{r,w} helpers Brian Cain
2026-06-25 14:15 ` [PULL v3 42/76] target/hexagon: Implement start/stop helpers, soft reset Brian Cain
2026-06-25 14:16 ` [PULL v3 43/76] target/hexagon: Implement {g,s}etimask helpers Brian Cain
2026-06-25 14:16 ` [PULL v3 44/76] target/hexagon: Implement wait helper Brian Cain
2026-06-25 14:16 ` [PULL v3 45/76] target/hexagon: Implement get_exe_mode() Brian Cain
2026-06-25 14:16 ` [PULL v3 46/76] target/hexagon: Implement hex_tlb_entry_get_perm() Brian Cain
2026-06-25 14:16 ` [PULL v3 47/76] target/hexagon: Implement software interrupt Brian Cain
2026-06-25 14:16 ` [PULL v3 48/76] target/hexagon: Implement stack overflow exception Brian Cain
2026-06-25 14:16 ` [PULL v3 49/76] target/hexagon: Implement exec_interrupt, set_irq Brian Cain
2026-06-25 14:16 ` [PULL v3 50/76] target/hexagon: add simple cpu_exec_reset and pointer_wrap Brian Cain
2026-06-25 14:16 ` [PULL v3 51/76] target/hexagon: Implement hexagon_tlb_fill() Brian Cain
2026-06-25 14:16 ` [PULL v3 52/76] target/hexagon: Implement siad inst Brian Cain
2026-06-25 14:16 ` [PULL v3 53/76] target/hexagon: Implement hexagon_resume_threads() Brian Cain
2026-06-25 14:16 ` [PULL v3 54/76] target/hexagon: Implement setprio, resched Brian Cain
2026-06-25 14:16 ` [PULL v3 55/76] target/hexagon: Add sysemu_ops, cpu_get_phys_page_debug() Brian Cain
2026-06-25 14:16 ` [PULL v3 56/76] target/hexagon: extend hexagon_cpu_mmu_index() for sysemu Brian Cain
2026-06-25 14:16 ` [PULL v3 57/76] target/hexagon: Decode trap1, rte as COF Brian Cain
2026-06-25 14:16 ` [PULL v3 58/76] target/hexagon: Implement modify_ssr, resched, pending_interrupt Brian Cain
2026-06-25 14:16 ` [PULL v3 59/76] target/hexagon: Add pkt_ends_tb to translation Brian Cain
2026-06-25 14:16 ` [PULL v3 60/76] target/hexagon: Add next_PC, {s,g}reg writes Brian Cain
2026-06-25 14:16 ` [PULL v3 61/76] target/hexagon: Add implicit sysreg writes Brian Cain
2026-06-25 14:16 ` [PULL v3 62/76] target/hexagon: Define system, guest reg names Brian Cain
2026-06-25 14:16 ` [PULL v3 63/76] target/hexagon: Add k0 {un,}lock Brian Cain
2026-06-25 14:16 ` [PULL v3 64/76] target/hexagon: Add PC to raise_exception, use fTRAP() helper Brian Cain
2026-06-25 14:16 ` [PULL v3 65/76] target/hexagon: Add TCG overrides for transfer insts Brian Cain
2026-06-25 14:16 ` [PULL v3 66/76] target/hexagon: Add support for loadw_phys Brian Cain
2026-06-25 14:16 ` [PULL v3 67/76] target/hexagon: Add guest reg reading functionality Brian Cain
2026-06-25 14:16 ` [PULL v3 68/76] hw/hexagon: Add globalreg model Brian Cain
2026-06-25 14:16 ` [PULL v3 69/76] hw/hexagon: Add global register tracing Brian Cain
2026-06-25 14:16 ` [PULL v3 70/76] hw/hexagon: Add hexagon TLB device implementation Brian Cain
2026-06-25 14:16 ` [PULL v3 71/76] hw/hexagon: Add machine configs for sysemu Brian Cain
2026-06-25 14:16 ` [PULL v3 72/76] hw/hexagon: Add v68, sa8775-cdsp0 defs Brian Cain
2026-06-25 14:16 ` [PULL v3 73/76] hw/hexagon: Add support for cfgbase Brian Cain
2026-06-25 14:16 ` [PULL v3 74/76] target/hexagon: add build config for softmmu Brian Cain
2026-06-25 14:16 ` [PULL v3 75/76] hw/hexagon: Define hexagon "virt" machine Brian Cain
2026-06-25 14:16 ` [PULL v3 76/76] tests/qtest: Add hexagon boot-serial-test Brian Cain
2026-06-25 20:58 ` [PULL v3 00/76] hex queue Stefan Hajnoczi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.