From cef416f6c5e0858f1044e14620ac23a91c30db74 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 22 Mar 2026 00:06:25 +0100
Subject: [PATCH 01/28] ume: Add interpolation and specific pass for ume
template tags #757
---
.../iss/linux-user/gen-arch/cpu_loop.c | 52 +++---
.../iss/linux-user/gen-arch/meson.build | 2 +-
.../iss/linux-user/gen-arch/signal.c | 38 ++---
.../iss/linux-user/gen-arch/syscall.tbl | 4 +-
.../iss/linux-user/gen-arch/target_cpu.h | 41 ++---
.../iss/linux-user/gen-arch/target_elf.h | 4 +-
.../linux-user/gen-arch/target_errno_defs.h | 4 +-
.../iss/linux-user/gen-arch/target_fcntl.h | 4 +-
.../iss/linux-user/gen-arch/target_mman.h | 2 +-
.../iss/linux-user/gen-arch/target_proc.h | 6 +-
.../iss/linux-user/gen-arch/target_signal.h | 6 +-
.../iss/linux-user/gen-arch/target_syscall.h | 8 +-
.../templates/iss/linux-user/meson.build | 2 +-
vadl/main/vadl/ast/AstVisitor.java | 12 +-
vadl/main/vadl/ast/Definition.java | 160 ++++++++++++++++++
vadl/main/vadl/ast/MacroExpander.java | 10 ++
vadl/main/vadl/ast/ModelRemover.java | 10 ++
vadl/main/vadl/ast/TypeChecker.java | 10 ++
vadl/main/vadl/ast/Ungrouper.java | 10 ++
vadl/main/vadl/ast/ViamLowering.java | 10 ++
.../iss/passes/UmeTemplateRenderingPass.java | 65 +++++++
.../vadl/iss/passes/extensions/UmeInfo.java | 41 +++++
22 files changed, 415 insertions(+), 86 deletions(-)
create mode 100644 vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
create mode 100644 vadl/main/vadl/iss/passes/extensions/UmeInfo.java
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 008d05752..3e0513e19 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -24,13 +24,15 @@
#include "signal-common.h"
#include "elf.h"
+
+//TODO get value
enum {
- RV64UME_EXC_ILLEGAL_INSTR = 2,
- RV64UME_EXC_BREAKPOINT = 3,
- RV64UME_EXC_ECALL = 11,
+ [# th:each="exc : ${exc_info.exceptions}"]
+ [(${exc.enum_name})] = ,
+ [/]
};
-void cpu_loop(CPURV64UMEState *env)
+void cpu_loop(CPU[(${gen_arch_upper})]State *env)
{
CPUState *cs = env_cpu(env);
int trapnr;
@@ -50,45 +52,45 @@ void cpu_loop(CPURV64UMEState *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
- case RV64UME_EXCP_EXC:
+ case [(${gen_arch_upper})]_EXCP_EXC:
cause = env->arg_exc_cause;
switch (cause) {
- case RV64UME_EXC_ECALL:
- env->pc += 4;
- if (env->x[RV64UME_REG_A7] == TARGET_NR_rv64ume_flush_icache) {
+ case [(${gen_arch_upper})]_EXC_ECALL:
+ env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
+ if (env->[(${register_tensors[0].name_lower})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
/* no-op in QEMU; TB invalidation is automatic */
ret = 0;
} else {
ret = do_syscall(env,
- env->x[RV64UME_REG_A7],
- env->x[RV64UME_REG_A0],
- env->x[RV64UME_REG_A1],
- env->x[RV64UME_REG_A2],
- env->x[RV64UME_REG_A3],
- env->x[RV64UME_REG_A4],
- env->x[RV64UME_REG_A5],
- 0, 0);
+ env->[(${register_tensors[0].name_lower})][ [(${config.sysReg})] ],
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[0]})] ],
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[1]})] ],
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[2]})] ],
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[3]})] ],
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[4]})] ],
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[5]})] ],
+ 0, 0);
}
if (ret == -QEMU_ERESTARTSYS) {
- env->pc -= 4;
+ env->[(${pc_reg.name_lower})] -= 4;
} else if (ret != -QEMU_ESIGRETURN) {
- env->x[RV64UME_REG_A0] = ret;
+ env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_A0] = ret;
}
if (cs->singlestep_enabled) {
goto gdbstep;
}
break;
- case RV64UME_EXC_ILLEGAL_INSTR:
- force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
+ case [(${gen_arch_upper})]_EXC_ILLEGAL_INSTR:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
break;
- case RV64UME_EXC_BREAKPOINT:
+ case [(${gen_arch_upper})]_EXC_BREAKPOINT:
case EXCP_DEBUG:
gdbstep:
- force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
break;
default:
EXCP_DUMP(env,
- "\nqemu: unhandled rv64ume exception cause %#x - aborting\n",
+ "\nqemu: unhandled [(${gen_arch_lower})] exception cause %#x - aborting\n",
cause);
exit(EXIT_FAILURE);
}
@@ -109,8 +111,8 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
TaskState *ts = get_task_state(cpu);
struct image_info *info = ts->info;
- env->pc = regs->sepc;
- env->x[RV64UME_REG_SP] = regs->sp;
+ env->[(${pc_reg.name_lower})] = regs->sepc;
+ env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP] = regs->sp;
ts->stack_base = info->start_stack;
}
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/meson.build b/vadl/main/resources/templates/iss/linux-user/gen-arch/meson.build
index a37e8fc3c..404ac04fe 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/meson.build
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/meson.build
@@ -1,5 +1,5 @@
syscall_nr_generators += {
- 'rv64ume': generator(sh,
+ '[(${gen_arch_lower})]': generator(sh,
arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
output: '@BASENAME@_nr.h')
}
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
index a6a1bc14c..eb0bc7da9 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
@@ -1,5 +1,5 @@
/*
- * Emulation of Linux signals for rv64ume user-mode.
+ * Emulation of Linux signals for [(${gen_arch_lower})] user-mode.
*/
#include "qemu/osdep.h"
@@ -9,12 +9,12 @@
#include "linux-user/trace.h"
/*
- * Minimal sigcontext matching rv64ume state:
+ * Minimal sigcontext matching [(${gen_arch_lower})] state:
* - pc
* - x1..x31 (x0 is always zero and omitted)
*/
struct target_sigcontext {
- abi_long pc;
+ abi_long [(${pc_reg.name_lower})];
abi_long gpr[31];
};
@@ -33,7 +33,7 @@ struct target_rt_sigframe {
};
static abi_ulong get_sigframe(struct target_sigaction *ka,
- CPURV64UMEState *regs, size_t framesize)
+ CPU[(${gen_arch_upper})]State *regs, size_t framesize)
{
abi_ulong sp = get_sp_from_cpustate(regs);
@@ -47,18 +47,18 @@ static abi_ulong get_sigframe(struct target_sigaction *ka,
return sp;
}
-static void setup_sigcontext(struct target_sigcontext *sc, CPURV64UMEState *env)
+static void setup_sigcontext(struct target_sigcontext *sc, CPU[(${gen_arch_upper})]State *env)
{
int i;
- __put_user(env->pc, &sc->pc);
+ __put_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
for (i = 1; i < 32; i++) {
__put_user(env->x[i], &sc->gpr[i - 1]);
}
}
static void setup_ucontext(struct target_ucontext *uc,
- CPURV64UMEState *env, target_sigset_t *set)
+ CPU[(${gen_arch_upper})]State *env, target_sigset_t *set)
{
int i;
@@ -76,7 +76,7 @@ static void setup_ucontext(struct target_ucontext *uc,
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
- target_sigset_t *set, CPURV64UMEState *env)
+ target_sigset_t *set, CPU[(${gen_arch_upper})]State *env)
{
abi_ulong frame_addr;
struct target_rt_sigframe *frame;
@@ -91,12 +91,12 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
setup_ucontext(&frame->uc, env, set);
frame->info = *info;
- env->pc = ka->_sa_handler;
- env->x[RV64UME_REG_SP] = frame_addr;
- env->x[RV64UME_REG_A0] = sig;
- env->x[RV64UME_REG_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
- env->x[RV64UME_REG_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
- env->x[RV64UME_REG_RA] = default_rt_sigreturn;
+ env->[(${pc_reg.name_lower})] = ka->_sa_handler;
+ env->x[[(${gen_arch_upper})]_REG_SP] = frame_addr;
+ env->x[[(${gen_arch_upper})]_REG_A0] = sig;
+ env->x[[(${gen_arch_upper})]_REG_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
+ env->x[[(${gen_arch_upper})]_REG_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ env->x[[(${gen_arch_upper})]_REG_RA] = default_rt_sigreturn;
return;
@@ -108,17 +108,17 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
force_sig(TARGET_SIGSEGV);
}
-static void restore_sigcontext(CPURV64UMEState *env, struct target_sigcontext *sc)
+static void restore_sigcontext(CPU[(${gen_arch_upper})]State *env, struct target_sigcontext *sc)
{
int i;
- __get_user(env->pc, &sc->pc);
+ __get_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
for (i = 1; i < 32; ++i) {
__get_user(env->x[i], &sc->gpr[i - 1]);
}
}
-static void restore_ucontext(CPURV64UMEState *env, struct target_ucontext *uc)
+static void restore_ucontext(CPU[(${gen_arch_upper})]State *env, struct target_ucontext *uc)
{
sigset_t blocked;
target_sigset_t target_set;
@@ -135,12 +135,12 @@ static void restore_ucontext(CPURV64UMEState *env, struct target_ucontext *uc)
restore_sigcontext(env, &uc->uc_mcontext);
}
-long do_rt_sigreturn(CPURV64UMEState *env)
+long do_rt_sigreturn(CPU[(${gen_arch_upper})]State *env)
{
struct target_rt_sigframe *frame;
abi_ulong frame_addr;
- frame_addr = env->x[RV64UME_REG_SP];
+ frame_addr = env->x[[(${gen_arch_upper})]_REG_SP];
trace_user_do_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/syscall.tbl b/vadl/main/resources/templates/iss/linux-user/gen-arch/syscall.tbl
index 84eb280d3..249da1518 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/syscall.tbl
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/syscall.tbl
@@ -302,8 +302,8 @@
244 or1k or1k_atomic sys_or1k_atomic
-258 rv64ume rv64ume_hwprobe sys_rv64ume_hwprobe
-259 rv64ume rv64ume_flush_icache sys_rv64ume_flush_icache
+258 [(${gen_arch_lower})] [(${gen_arch_lower})]_hwprobe sys_[(${gen_arch_lower})]_hwprobe
+259 [(${gen_arch_lower})] [(${gen_arch_lower})]_flush_icache sys_[(${gen_arch_lower})]_flush_icache
260 time32 wait4 sys_wait4 compat_sys_wait4
260 64 wait4 sys_wait4
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
index d06911d34..8a1627947 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
@@ -1,40 +1,41 @@
-#ifndef RV64UME_TARGET_CPU_H
-#define RV64UME_TARGET_CPU_H
+#ifndef [(${gen_arch_upper})]_TARGET_CPU_H
+#define [(${gen_arch_upper})]_TARGET_CPU_H
+//TODO: check for correct interpolattions for regs & values
enum {
- RV64UME_REG_RA = 1,
- RV64UME_REG_SP = 2,
- RV64UME_REG_TP = 4,
- RV64UME_REG_A0 = 10,
- RV64UME_REG_A1 = 11,
- RV64UME_REG_A2 = 12,
- RV64UME_REG_A3 = 13,
- RV64UME_REG_A4 = 14,
- RV64UME_REG_A5 = 15,
- RV64UME_REG_A7 = 17,
+ [(${gen_arch_upper})]_REG_RA = 1,
+ [(${gen_arch_upper})]_REG_SP = 2,
+ [(${gen_arch_upper})]_REG_TP = 4,
+ [(${gen_arch_upper})]_REG_A0 = 10,
+ [(${gen_arch_upper})]_REG_A1 = 11,
+ [(${gen_arch_upper})]_REG_A2 = 12,
+ [(${gen_arch_upper})]_REG_A3 = 13,
+ [(${gen_arch_upper})]_REG_A4 = 14,
+ [(${gen_arch_upper})]_REG_A5 = 15,
+ [(${gen_arch_upper})]_REG_A7 = 17,
};
-static inline void cpu_clone_regs_child(CPURV64UMEState *env, target_ulong newsp,
+static inline void cpu_clone_regs_child(CPU[(${gen_arch_upper})]State *env, target_ulong newsp,
unsigned flags)
{
if (newsp) {
- env->x[RV64UME_REG_SP] = newsp;
+ env->x[[(${gen_arch_upper})]_REG_SP] = newsp;
}
- env->x[RV64UME_REG_A0] = 0;
+ env->x[[(${gen_arch_upper})]_REG_A0] = 0;
}
-static inline void cpu_clone_regs_parent(CPURV64UMEState *env, unsigned flags)
+static inline void cpu_clone_regs_parent(CPU[(${gen_arch_upper})]State *env, unsigned flags)
{
}
-static inline void cpu_set_tls(CPURV64UMEState *env, target_ulong newtls)
+static inline void cpu_set_tls(CPU[(${gen_arch_upper})]State *env, target_ulong newtls)
{
- env->x[RV64UME_REG_TP] = newtls;
+ env->x[[(${gen_arch_upper})]_REG_TP] = newtls;
}
-static inline abi_ulong get_sp_from_cpustate(CPURV64UMEState *state)
+static inline abi_ulong get_sp_from_cpustate(CPU[(${gen_arch_upper})]State *state)
{
- return state->x[RV64UME_REG_SP];
+ return state->x[[(${gen_arch_upper})]_REG_SP];
}
#endif
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_elf.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_elf.h
index a316ece3f..37e3965bf 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_elf.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_elf.h
@@ -5,8 +5,8 @@
* later version. See the COPYING file in the top-level directory.
*/
-#ifndef RV64UME_TARGET_ELF_H
-#define RV64UME_TARGET_ELF_H
+#ifndef [(${gen_arch_upper})]_TARGET_ELF_H
+#define [(${gen_arch_upper})]_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
return "max";
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_errno_defs.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_errno_defs.h
index 07f1e5f33..b797200bc 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_errno_defs.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_errno_defs.h
@@ -1,5 +1,5 @@
-#ifndef RV64UME_TARGET_ERRNO_DEFS_H
-#define RV64UME_TARGET_ERRNO_DEFS_H
+#ifndef [(${gen_arch_upper})]_TARGET_ERRNO_DEFS_H
+#define [(${gen_arch_upper})]_TARGET_ERRNO_DEFS_H
/* Target uses generic errno */
#include "../generic/target_errno_defs.h"
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_fcntl.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_fcntl.h
index 10bec4603..afc18d959 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_fcntl.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_fcntl.h
@@ -5,7 +5,7 @@
* later version. See the COPYING file in the top-level directory.
*/
-#ifndef RV64UME_TARGET_FCNTL_H
-#define RV64UME_TARGET_FCNTL_H
+#ifndef [(${gen_arch_upper})]_TARGET_FCNTL_H
+#define [(${gen_arch_upper})]_TARGET_FCNTL_H
#include "../generic/fcntl.h"
#endif
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_mman.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_mman.h
index 97a04f176..abf0ffde1 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_mman.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_mman.h
@@ -5,7 +5,7 @@
#define TASK_UNMAPPED_BASE \
TARGET_PAGE_ALIGN((1ull << (TARGET_VIRT_ADDR_SPACE_BITS - 1)) / 3)
-/* arch/rv64ume/include/asm/elf.h */
+/* arch/[(${gen_arch_lower})]/include/asm/elf.h */
#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE * 2)
#include "../generic/target_mman.h"
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_proc.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_proc.h
index 752050f26..0536a6aca 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_proc.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_proc.h
@@ -3,8 +3,8 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
-#ifndef RV64UME_TARGET_PROC_H
-#define RV64UME_TARGET_PROC_H
+#ifndef [(${gen_arch_upper})]_TARGET_PROC_H
+#define [(${gen_arch_upper})]_TARGET_PROC_H
static int open_cpuinfo(CPUArchState *cpu_env, int fd)
{
@@ -20,4 +20,4 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd)
}
#define HAVE_ARCH_PROC_CPUINFO
-#endif /* RV64UME_TARGET_PROC_H */
+#endif /* [(${gen_arch_upper})]_TARGET_PROC_H */
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_signal.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_signal.h
index cb50d749f..b936e162f 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_signal.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_signal.h
@@ -1,6 +1,6 @@
-#ifndef RV64UME_TARGET_SIGNAL_H
-#define RV64UME_TARGET_SIGNAL_H
+#ifndef [(${gen_arch_upper})]_TARGET_SIGNAL_H
+#define [(${gen_arch_upper})]_TARGET_SIGNAL_H
#include "../generic/signal.h"
-#endif /* RV64UME_TARGET_SIGNAL_H */
+#endif /* [(${gen_arch_upper})]_TARGET_SIGNAL_H */
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
index 77fa2385d..3860bde86 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
@@ -2,11 +2,11 @@
* This struct defines the way the registers are stored on the
* stack during a system call.
*
- * Reference: linux/arch/rv64ume/include/uapi/asm/ptrace.h
+ * Reference: linux/arch/[(${gen_arch_lower})]/include/uapi/asm/ptrace.h
*/
-#ifndef LINUX_USER_RV64UME_TARGET_SYSCALL_H
-#define LINUX_USER_RV64UME_TARGET_SYSCALL_H
+#ifndef LINUX_USER_[(${gen_arch_upper})]_TARGET_SYSCALL_H
+#define LINUX_USER_[(${gen_arch_upper})]_TARGET_SYSCALL_H
struct target_pt_regs {
abi_long sepc;
@@ -43,7 +43,7 @@ struct target_pt_regs {
abi_long t6;
};
-#define UNAME_MACHINE "rv64ume"
+#define UNAME_MACHINE "[(${gen_arch_lower})]"
#define UNAME_MINIMUM_RELEASE "4.15.0"
#define TARGET_MCL_CURRENT 1
diff --git a/vadl/main/resources/templates/iss/linux-user/meson.build b/vadl/main/resources/templates/iss/linux-user/meson.build
index 33ef639c0..fda18df94 100644
--- a/vadl/main/resources/templates/iss/linux-user/meson.build
+++ b/vadl/main/resources/templates/iss/linux-user/meson.build
@@ -56,7 +56,7 @@ subdir('x86_64')
subdir('xtensa')
# VADL generated target
[# th:if="${gen_arch_upper == 'RV64UME'}"]
-subdir('rv64ume')
+subdir('gen-arch')
[/]
specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss)
diff --git a/vadl/main/vadl/ast/AstVisitor.java b/vadl/main/vadl/ast/AstVisitor.java
index a9be7f63f..dfbc141af 100644
--- a/vadl/main/vadl/ast/AstVisitor.java
+++ b/vadl/main/vadl/ast/AstVisitor.java
@@ -538,6 +538,16 @@ public Void visit(StageDefinition definition) {
return null;
}
+ @Override
+ public Void visit(UmeSequenceDefinition definition) {
+ return null;
+ }
+
+ @Override
+ public Void visit(UserModeEmulationDefinition definition) {
+ return null;
+ }
+
@Override
public Void visit(UsingDefinition definition) {
beforeTravel(definition);
@@ -937,4 +947,4 @@ public Void visit(StatementList statement) {
afterTravel(statement);
return null;
}
-}
\ No newline at end of file
+}
diff --git a/vadl/main/vadl/ast/Definition.java b/vadl/main/vadl/ast/Definition.java
index aaa52a794..7cce3b41f 100644
--- a/vadl/main/vadl/ast/Definition.java
+++ b/vadl/main/vadl/ast/Definition.java
@@ -222,6 +222,10 @@ interface DefinitionVisitor {
R visit(StageDefinition definition);
+ R visit(UmeSequenceDefinition definition);
+
+ R visit(UserModeEmulationDefinition definition);
+
R visit(UsingDefinition definition);
R visit(AbiClangTypeDefinition abiClangTypeDefinition);
@@ -3491,6 +3495,154 @@ public Identifier identifier() {
}
}
+class UserModeEmulationDefinition extends Definition implements IdentifiableNode {
+ Identifier id;
+ @Child
+ IsId isa;
+ @Child
+ List definitions;
+ SourceLocation loc;
+
+ @Nullable
+ InstructionSetDefinition isaNode;
+
+ UserModeEmulationDefinition(Identifier id, IsId isa, List definitions,
+ SourceLocation loc) {
+ this.id = id;
+ this.isa = isa;
+ this.definitions = definitions;
+ this.loc = loc;
+ }
+
+ @Override
+ R accept(DefinitionVisitor visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public SourceLocation location() {
+ return loc;
+ }
+
+ @Override
+ SyntaxType syntaxType() {
+ return BasicSyntaxType.INVALID;
+ }
+
+ @Override
+ void prettyPrint(int indent, StringBuilder builder) {
+ prettyPrintAnnotations(indent, builder);
+ builder.append(prettyIndentString(indent)).append("user mode emulation ");
+ id.prettyPrint(indent, builder);
+ builder.append(" for ");
+ isa.prettyPrint(indent, builder);
+ builder.append(" = {\n");
+ prettyPrintDefinitions(indent + 1, builder, definitions);
+ builder.append(prettyIndentString(indent)).append("}\n");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ UserModeEmulationDefinition that = (UserModeEmulationDefinition) o;
+ return Objects.equals(id, that.id) && Objects.equals(isa, that.isa)
+ && Objects.equals(definitions, that.definitions);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, isa, definitions);
+ }
+
+ @Override
+ public Identifier identifier() {
+ return id;
+ }
+}
+
+class UmeSequenceDefinition extends InstructionSequenceDefinition {
+ SeqKind umeKind;
+
+ UmeSequenceDefinition(SeqKind umeKind,
+ List params,
+ List statements,
+ SourceLocation loc) {
+ super(params, statements, loc);
+ this.umeKind = umeKind;
+ }
+
+ @Override
+ public List children() {
+ // Since this class has no @Child annotations the Annotationprocessor doesn't find it.
+ return NodeChildrenRegistry.unsafeGetChildrenDirect(this,
+ (Class extends Node>) getClass().getSuperclass());
+ }
+
+ @Override
+ R accept(DefinitionVisitor visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public SourceLocation location() {
+ return loc;
+ }
+
+ @Override
+ SyntaxType syntaxType() {
+ return BasicSyntaxType.INVALID;
+ }
+
+ @Override
+ void prettyPrint(int indent, StringBuilder builder) {
+ prettyPrintAnnotations(indent, builder);
+ builder.append(prettyIndentString(indent));
+ builder.append(umeKind.keyword);
+ builder.append(" sequence ");
+ Parameter.prettyPrintMultiple(indent, params, builder);
+ builder.append(" = {\n");
+ for (InstructionCallStatement statement : statements) {
+ statement.prettyPrint(indent + 1, builder);
+ }
+ builder.append(prettyIndentString(indent)).append("}\n");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ UmeSequenceDefinition that = (UmeSequenceDefinition) o;
+ return umeKind == that.umeKind && Objects.equals(params, that.params)
+ && Objects.equals(statements, that.statements);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(umeKind, params, statements);
+ }
+
+ enum SeqKind {
+ CONSTANT("constant"),
+ REGISTER("register adjustment");
+
+ private final String keyword;
+
+ SeqKind(String keyword) {
+ this.keyword = keyword;
+ }
+ }
+}
+
+
/**
* The compiler generator requires a few special instructions. Those need to be defined
* in the ABI. They are distinguished with the {@link AbiSpecialPurposeInstructionDefinition#kind}
@@ -3976,6 +4128,14 @@ ApplicationBinaryInterfaceDefinition abiNode() {
return (ApplicationBinaryInterfaceDefinition) requireNonNull(abi.target());
}
+ /*@Nullable
+ UserModeEmulationDefinition umeNode() {
+ if (ume == null) {
+ return null;
+ }
+ return (UserModeEmulationDefinition) Objects.requireNonNull(ume.target());
+ } */
+
@Override
public SourceLocation location() {
return loc;
diff --git a/vadl/main/vadl/ast/MacroExpander.java b/vadl/main/vadl/ast/MacroExpander.java
index 820604800..515a8b8c9 100644
--- a/vadl/main/vadl/ast/MacroExpander.java
+++ b/vadl/main/vadl/ast/MacroExpander.java
@@ -1099,6 +1099,16 @@ public Definition visit(StageDefinition definition) {
);
}
+ @Override
+ public Definition visit(UmeSequenceDefinition definition) {
+ return new UmeSequenceDefinition(definition.umeKind, definition.params, definition.statements, definition.loc).withAnnotations(definition.annotations);
+ }
+
+ @Override
+ public Definition visit(UserModeEmulationDefinition definition) {
+ return new UserModeEmulationDefinition(definition.id, definition.isa, definition.definitions, definition.loc).withAnnotations(definition.annotations);
+ }
+
@Override
public Definition visit(CacheDefinition definition) {
return new CacheDefinition(
diff --git a/vadl/main/vadl/ast/ModelRemover.java b/vadl/main/vadl/ast/ModelRemover.java
index 192438506..a7d769961 100644
--- a/vadl/main/vadl/ast/ModelRemover.java
+++ b/vadl/main/vadl/ast/ModelRemover.java
@@ -306,6 +306,16 @@ public Definition visit(StageDefinition definition) {
return definition;
}
+ @Override
+ public Definition visit(UmeSequenceDefinition definition) {
+ return definition;
+ }
+
+ @Override
+ public Definition visit(UserModeEmulationDefinition definition) {
+ return definition;
+ }
+
@Override
public Definition visit(CacheDefinition definition) {
return definition;
diff --git a/vadl/main/vadl/ast/TypeChecker.java b/vadl/main/vadl/ast/TypeChecker.java
index 5adbc285d..3689ed43f 100644
--- a/vadl/main/vadl/ast/TypeChecker.java
+++ b/vadl/main/vadl/ast/TypeChecker.java
@@ -2947,6 +2947,16 @@ public Void visit(StageDefinition definition) {
return null;
}
+ @Override
+ public Void visit(UmeSequenceDefinition definition) {
+ return null;
+ }
+
+ @Override
+ public Void visit(UserModeEmulationDefinition definition) {
+ return null;
+ }
+
@Override
public Void visit(CacheDefinition definition) {
throw addErrorAndStopChecking(unimplementedError(definition));
diff --git a/vadl/main/vadl/ast/Ungrouper.java b/vadl/main/vadl/ast/Ungrouper.java
index ad10bccc2..3e0d94a42 100644
--- a/vadl/main/vadl/ast/Ungrouper.java
+++ b/vadl/main/vadl/ast/Ungrouper.java
@@ -603,6 +603,16 @@ public Void visit(StageDefinition definition) {
return null;
}
+ @Override
+ public Void visit(UmeSequenceDefinition definition) {
+ return null;
+ }
+
+ @Override
+ public Void visit(UserModeEmulationDefinition definition) {
+ return null;
+ }
+
@Override
public Void visit(CacheDefinition definition) {
ungroupAnnotations(definition);
diff --git a/vadl/main/vadl/ast/ViamLowering.java b/vadl/main/vadl/ast/ViamLowering.java
index 177fb68a5..a7cb482a6 100644
--- a/vadl/main/vadl/ast/ViamLowering.java
+++ b/vadl/main/vadl/ast/ViamLowering.java
@@ -1964,6 +1964,16 @@ public Optional visit(StageDefinition definition) {
return Optional.of(new Stage(identifier, behaivor, List.of()));
}
+ @Override
+ public Optional visit(UmeSequenceDefinition definition) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional visit(UserModeEmulationDefinition definition) {
+ return Optional.empty();
+ }
+
@Override
public Optional visit(UsingDefinition definition) {
// Do nothing on purpose.
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
new file mode 100644
index 000000000..986af6ace
--- /dev/null
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText : © 2026 TU Wien
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package vadl.iss.passes;
+
+import java.util.List;
+import java.util.Map;
+import vadl.configuration.IssConfiguration;
+import vadl.iss.passes.extensions.UmeInfo;
+import vadl.iss.template.IssTemplateRenderingPass;
+import vadl.pass.PassName;
+import vadl.pass.PassResults;
+import vadl.viam.Specification;
+
+public class UmeTemplateRenderingPass extends IssTemplateRenderingPass {
+
+ private final String templateFilename;
+
+ public UmeTemplateRenderingPass(IssConfiguration configuration, String templateFilename) {
+ super(configuration);
+ this.templateFilename = templateFilename;
+ }
+
+ @Override
+ protected String issTemplatePath() {
+ return "linux-user/gen-arch/" + templateFilename;
+ }
+
+ @Override
+ public PassName getName() {
+ return PassName.of("Rendering UME template: " + templateFilename);
+ }
+
+ @Override
+ protected Map createVariables(PassResults passResults, Specification specification) {
+ var vars = super.createVariables(passResults, specification);
+
+ //if (specification.userModeEmulation().isPresent()) {
+ // var umeDef = specification.userModeEmulation().get();
+
+ //TODO remove hardcoded values (finish vadl with ume)
+ int extractedSysReg = 17;
+ int extractedRetReg = 10;
+ List extractedArgs = List.of(10, 11, 12, 13, 14, 15);
+
+ vars.put("config", new UmeInfo(extractedSysReg, extractedRetReg, extractedArgs));
+ vars.put("insn_width_bytes", 4); //TODO make dynamic
+ // }
+
+ return vars;
+ }
+}
diff --git a/vadl/main/vadl/iss/passes/extensions/UmeInfo.java b/vadl/main/vadl/iss/passes/extensions/UmeInfo.java
new file mode 100644
index 000000000..4ab7004bd
--- /dev/null
+++ b/vadl/main/vadl/iss/passes/extensions/UmeInfo.java
@@ -0,0 +1,41 @@
+// SPDX-FileCopyrightText : © 2026 TU Wien
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package vadl.iss.passes.extensions;
+
+import java.util.List;
+import java.util.Map;
+import vadl.template.Renderable;
+
+/**
+ * Holds the extracted ABI register indices for User-Mode Emulation.
+ * Maps the software calling convention to the raw hardware registers.
+ */
+public record UmeInfo(
+ int sysReg, // e.g., 17 for RISC-V a7 (syscall number)
+ int retReg, // e.g., 10 for RISC-V a0 (return value)
+ List args // e.g., [10, 11, 12, 13, 14, 15] for a0-a5 (syscall arguments)
+) implements Renderable {
+
+ @Override
+ public Map renderObj() {
+ return Map.of(
+ "sysReg", sysReg,
+ "retReg", retReg,
+ "args", args
+ );
+ }
+}
From 33bf7f8f7a101df7ec0d0972ba01dad45ebe1882 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 22 Mar 2026 11:12:33 +0100
Subject: [PATCH 02/28] ume: Add specific tags for regs and exceptions #757
---
.../iss/linux-user/gen-arch/cpu_loop.c | 22 +++++++---------
.../iss/linux-user/gen-arch/signal.c | 16 ++++++------
.../iss/linux-user/gen-arch/target_cpu.h | 26 ++++++++-----------
.../iss/passes/UmeTemplateRenderingPass.java | 12 +++++++--
.../vadl/iss/passes/extensions/UmeInfo.java | 12 +++++++--
5 files changed, 48 insertions(+), 40 deletions(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 3e0513e19..25bd63094 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -25,11 +25,11 @@
#include "elf.h"
-//TODO get value
+//TODO check for diff way to get exc+value
enum {
- [# th:each="exc : ${exc_info.exceptions}"]
- [(${exc.enum_name})] = ,
- [/]
+ [# th:each="exc : ${config.excIds}"]
+ [(${gen_arch_upper})]_EXC_[(${exc.key})] = [(${exc.value})],
+ [/]
};
void cpu_loop(CPU[(${gen_arch_upper})]State *env)
@@ -63,19 +63,15 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
} else {
ret = do_syscall(env,
env->[(${register_tensors[0].name_lower})][ [(${config.sysReg})] ],
- env->[(${register_tensors[0].name_lower})][ [(${config.args[0]})] ],
- env->[(${register_tensors[0].name_lower})][ [(${config.args[1]})] ],
- env->[(${register_tensors[0].name_lower})][ [(${config.args[2]})] ],
- env->[(${register_tensors[0].name_lower})][ [(${config.args[3]})] ],
- env->[(${register_tensors[0].name_lower})][ [(${config.args[4]})] ],
- env->[(${register_tensors[0].name_lower})][ [(${config.args[5]})] ],
+ [# th:each="arg : ${config.args}"]
+ env->[(${register_tensors[0].name_lower})][ [(${arg})] ],
+ [/]
0, 0);
}
if (ret == -QEMU_ERESTARTSYS) {
env->[(${pc_reg.name_lower})] -= 4;
} else if (ret != -QEMU_ESIGRETURN) {
- env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_A0] = ret;
- }
+ env->[(${register_tensors[0].name_lower})][ [(${config.retReg})] ] = ret; }
if (cs->singlestep_enabled) {
goto gdbstep;
}
@@ -112,7 +108,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
struct image_info *info = ts->info;
env->[(${pc_reg.name_lower})] = regs->sepc;
- env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP] = regs->sp;
+ env->[(${register_tensors[0].name_lower})][ [(${config.spReg})] ] = regs->sp;
ts->stack_base = info->start_stack;
}
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
index eb0bc7da9..ed276af48 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
@@ -53,7 +53,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPU[(${gen_arch_upper
__put_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
for (i = 1; i < 32; i++) {
- __put_user(env->x[i], &sc->gpr[i - 1]);
+ __put_user(env->[(${register_tensors[0].name_lower})][i], &sc->gpr[i - 1]);
}
}
@@ -92,11 +92,11 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
frame->info = *info;
env->[(${pc_reg.name_lower})] = ka->_sa_handler;
- env->x[[(${gen_arch_upper})]_REG_SP] = frame_addr;
- env->x[[(${gen_arch_upper})]_REG_A0] = sig;
- env->x[[(${gen_arch_upper})]_REG_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
- env->x[[(${gen_arch_upper})]_REG_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
- env->x[[(${gen_arch_upper})]_REG_RA] = default_rt_sigreturn;
+ env->[(${register_tensors[0].name_lower})][ [(${config.spReg})] ] = frame_addr;
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[0]})] ] = sig;
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[1]})] ] = frame_addr + offsetof(struct target_rt_sigframe, info);
+ env->[(${register_tensors[0].name_lower})][ [(${config.args[2]})] ] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ env->[(${register_tensors[0].name_lower})][ [(${config.raReg})] ] = default_rt_sigreturn;
return;
@@ -114,7 +114,7 @@ static void restore_sigcontext(CPU[(${gen_arch_upper})]State *env, struct target
__get_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
for (i = 1; i < 32; ++i) {
- __get_user(env->x[i], &sc->gpr[i - 1]);
+ __get_user(env->[(${register_tensors[0].name_lower})][i], &sc->gpr[i - 1]);
}
}
@@ -140,7 +140,7 @@ long do_rt_sigreturn(CPU[(${gen_arch_upper})]State *env)
struct target_rt_sigframe *frame;
abi_ulong frame_addr;
- frame_addr = env->x[[(${gen_arch_upper})]_REG_SP];
+ frame_addr = env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP];
trace_user_do_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
index 8a1627947..dbb6686c8 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
@@ -1,28 +1,24 @@
#ifndef [(${gen_arch_upper})]_TARGET_CPU_H
#define [(${gen_arch_upper})]_TARGET_CPU_H
-//TODO: check for correct interpolattions for regs & values
enum {
- [(${gen_arch_upper})]_REG_RA = 1,
- [(${gen_arch_upper})]_REG_SP = 2,
- [(${gen_arch_upper})]_REG_TP = 4,
- [(${gen_arch_upper})]_REG_A0 = 10,
- [(${gen_arch_upper})]_REG_A1 = 11,
- [(${gen_arch_upper})]_REG_A2 = 12,
- [(${gen_arch_upper})]_REG_A3 = 13,
- [(${gen_arch_upper})]_REG_A4 = 14,
- [(${gen_arch_upper})]_REG_A5 = 15,
- [(${gen_arch_upper})]_REG_A7 = 17,
+ [(${gen_arch_upper})]_REG_RA = [(${config.raReg})],
+ [(${gen_arch_upper})]_REG_SP = [(${config.spReg})],
+ [(${gen_arch_upper})]_REG_TP = [(${config.tpReg})],
+
+ [# th:each="arg, stat : ${config.args}"]
+ [(${gen_arch_upper})]_REG_ARG[(${stat.index})] = [(${arg})],
+ [/]
};
static inline void cpu_clone_regs_child(CPU[(${gen_arch_upper})]State *env, target_ulong newsp,
unsigned flags)
{
if (newsp) {
- env->x[[(${gen_arch_upper})]_REG_SP] = newsp;
+ env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP] = newsp;
}
- env->x[[(${gen_arch_upper})]_REG_A0] = 0;
+ env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_A0] = 0;
}
static inline void cpu_clone_regs_parent(CPU[(${gen_arch_upper})]State *env, unsigned flags)
@@ -31,11 +27,11 @@ static inline void cpu_clone_regs_parent(CPU[(${gen_arch_upper})]State *env, uns
static inline void cpu_set_tls(CPU[(${gen_arch_upper})]State *env, target_ulong newtls)
{
- env->x[[(${gen_arch_upper})]_REG_TP] = newtls;
+ env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_TP] = newtls;
}
static inline abi_ulong get_sp_from_cpustate(CPU[(${gen_arch_upper})]State *state)
{
- return state->x[[(${gen_arch_upper})]_REG_SP];
+ return state->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP];
}
#endif
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index 986af6ace..5e51aa5d8 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -54,10 +54,18 @@ protected Map createVariables(PassResults passResults, Specifica
//TODO remove hardcoded values (finish vadl with ume)
int extractedSysReg = 17;
int extractedRetReg = 10;
+ int extractedSpReg = 2;
+ int extractedRaReg = 1;
+ int extractedTpReg = 4;
List extractedArgs = List.of(10, 11, 12, 13, 14, 15);
+ Map extractedExcIds = Map.of(
+ "ILLEGAL_INSTR", 2,
+ "BREAKPOINT", 3,
+ "ECALL", 11
+ );
- vars.put("config", new UmeInfo(extractedSysReg, extractedRetReg, extractedArgs));
- vars.put("insn_width_bytes", 4); //TODO make dynamic
+ vars.put("config", new UmeInfo(extractedSysReg, extractedRetReg, extractedSpReg, extractedRaReg, extractedTpReg, extractedArgs, extractedExcIds));
+ vars.put("insn_width_bytes", 4);
// }
return vars;
diff --git a/vadl/main/vadl/iss/passes/extensions/UmeInfo.java b/vadl/main/vadl/iss/passes/extensions/UmeInfo.java
index 4ab7004bd..bda170087 100644
--- a/vadl/main/vadl/iss/passes/extensions/UmeInfo.java
+++ b/vadl/main/vadl/iss/passes/extensions/UmeInfo.java
@@ -27,7 +27,11 @@
public record UmeInfo(
int sysReg, // e.g., 17 for RISC-V a7 (syscall number)
int retReg, // e.g., 10 for RISC-V a0 (return value)
- List args // e.g., [10, 11, 12, 13, 14, 15] for a0-a5 (syscall arguments)
+ int spReg, // Stack Pointer (e.g., 2 for RISC-V)
+ int raReg, // Return Address (e.g., 1 for RISC-V)
+ int tpReg,
+ List args,
+ Map excIds
) implements Renderable {
@Override
@@ -35,7 +39,11 @@ public Map renderObj() {
return Map.of(
"sysReg", sysReg,
"retReg", retReg,
- "args", args
+ "spReg", spReg,
+ "raReg", raReg,
+ "tpReg", tpReg,
+ "args", args,
+ "excIds", excIds
);
}
}
From 95cdeb5bbc890f98829290b1fd62eaa8e46057c1 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 22 Mar 2026 17:25:45 +0100
Subject: [PATCH 03/28] ume: Fix subdir in meson
---
vadl/main/resources/templates/iss/linux-user/meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/meson.build b/vadl/main/resources/templates/iss/linux-user/meson.build
index fda18df94..679c26e9a 100644
--- a/vadl/main/resources/templates/iss/linux-user/meson.build
+++ b/vadl/main/resources/templates/iss/linux-user/meson.build
@@ -56,7 +56,7 @@ subdir('x86_64')
subdir('xtensa')
# VADL generated target
[# th:if="${gen_arch_upper == 'RV64UME'}"]
-subdir('gen-arch')
+subdir('[(${gen_arch_lower})]')
[/]
specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss)
From 2a65a6c93347689b7515bb20c76bf0ce3340bd5b Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 22 Mar 2026 00:06:25 +0100
Subject: [PATCH 04/28] ume: Add interpolation and specific pass for ume
template tags #757
---
.../main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c | 2 ++
.../resources/templates/iss/linux-user/gen-arch/target_cpu.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 25bd63094..9db9b1b58 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -82,10 +82,12 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
case [(${gen_arch_upper})]_EXC_BREAKPOINT:
case EXCP_DEBUG:
gdbstep:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
break;
default:
EXCP_DUMP(env,
+ "\nqemu: unhandled [(${gen_arch_lower})] exception cause %#x - aborting\n",
"\nqemu: unhandled [(${gen_arch_lower})] exception cause %#x - aborting\n",
cause);
exit(EXIT_FAILURE);
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
index dbb6686c8..dea9ad147 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
@@ -1,6 +1,7 @@
#ifndef [(${gen_arch_upper})]_TARGET_CPU_H
#define [(${gen_arch_upper})]_TARGET_CPU_H
+//TODO: check for correct interpolattions for regs & values
enum {
[(${gen_arch_upper})]_REG_RA = [(${config.raReg})],
[(${gen_arch_upper})]_REG_SP = [(${config.spReg})],
From 87497924ba91afbcc7a4c2a80d71d6271d916a26 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Mon, 23 Mar 2026 01:38:01 +0100
Subject: [PATCH 05/28] ume: Remove everything related to frontend #757
---
vadl/main/vadl/ast/AstVisitor.java | 10 --
vadl/main/vadl/ast/Definition.java | 160 --------------------------
vadl/main/vadl/ast/MacroExpander.java | 10 --
vadl/main/vadl/ast/ModelRemover.java | 10 --
vadl/main/vadl/ast/TypeChecker.java | 10 --
vadl/main/vadl/ast/Ungrouper.java | 10 --
vadl/main/vadl/ast/ViamLowering.java | 10 --
7 files changed, 220 deletions(-)
diff --git a/vadl/main/vadl/ast/AstVisitor.java b/vadl/main/vadl/ast/AstVisitor.java
index dfbc141af..dc10df295 100644
--- a/vadl/main/vadl/ast/AstVisitor.java
+++ b/vadl/main/vadl/ast/AstVisitor.java
@@ -538,16 +538,6 @@ public Void visit(StageDefinition definition) {
return null;
}
- @Override
- public Void visit(UmeSequenceDefinition definition) {
- return null;
- }
-
- @Override
- public Void visit(UserModeEmulationDefinition definition) {
- return null;
- }
-
@Override
public Void visit(UsingDefinition definition) {
beforeTravel(definition);
diff --git a/vadl/main/vadl/ast/Definition.java b/vadl/main/vadl/ast/Definition.java
index 7cce3b41f..aaa52a794 100644
--- a/vadl/main/vadl/ast/Definition.java
+++ b/vadl/main/vadl/ast/Definition.java
@@ -222,10 +222,6 @@ interface DefinitionVisitor {
R visit(StageDefinition definition);
- R visit(UmeSequenceDefinition definition);
-
- R visit(UserModeEmulationDefinition definition);
-
R visit(UsingDefinition definition);
R visit(AbiClangTypeDefinition abiClangTypeDefinition);
@@ -3495,154 +3491,6 @@ public Identifier identifier() {
}
}
-class UserModeEmulationDefinition extends Definition implements IdentifiableNode {
- Identifier id;
- @Child
- IsId isa;
- @Child
- List definitions;
- SourceLocation loc;
-
- @Nullable
- InstructionSetDefinition isaNode;
-
- UserModeEmulationDefinition(Identifier id, IsId isa, List definitions,
- SourceLocation loc) {
- this.id = id;
- this.isa = isa;
- this.definitions = definitions;
- this.loc = loc;
- }
-
- @Override
- R accept(DefinitionVisitor visitor) {
- return visitor.visit(this);
- }
-
- @Override
- public SourceLocation location() {
- return loc;
- }
-
- @Override
- SyntaxType syntaxType() {
- return BasicSyntaxType.INVALID;
- }
-
- @Override
- void prettyPrint(int indent, StringBuilder builder) {
- prettyPrintAnnotations(indent, builder);
- builder.append(prettyIndentString(indent)).append("user mode emulation ");
- id.prettyPrint(indent, builder);
- builder.append(" for ");
- isa.prettyPrint(indent, builder);
- builder.append(" = {\n");
- prettyPrintDefinitions(indent + 1, builder, definitions);
- builder.append(prettyIndentString(indent)).append("}\n");
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- UserModeEmulationDefinition that = (UserModeEmulationDefinition) o;
- return Objects.equals(id, that.id) && Objects.equals(isa, that.isa)
- && Objects.equals(definitions, that.definitions);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id, isa, definitions);
- }
-
- @Override
- public Identifier identifier() {
- return id;
- }
-}
-
-class UmeSequenceDefinition extends InstructionSequenceDefinition {
- SeqKind umeKind;
-
- UmeSequenceDefinition(SeqKind umeKind,
- List params,
- List statements,
- SourceLocation loc) {
- super(params, statements, loc);
- this.umeKind = umeKind;
- }
-
- @Override
- public List children() {
- // Since this class has no @Child annotations the Annotationprocessor doesn't find it.
- return NodeChildrenRegistry.unsafeGetChildrenDirect(this,
- (Class extends Node>) getClass().getSuperclass());
- }
-
- @Override
- R accept(DefinitionVisitor visitor) {
- return visitor.visit(this);
- }
-
- @Override
- public SourceLocation location() {
- return loc;
- }
-
- @Override
- SyntaxType syntaxType() {
- return BasicSyntaxType.INVALID;
- }
-
- @Override
- void prettyPrint(int indent, StringBuilder builder) {
- prettyPrintAnnotations(indent, builder);
- builder.append(prettyIndentString(indent));
- builder.append(umeKind.keyword);
- builder.append(" sequence ");
- Parameter.prettyPrintMultiple(indent, params, builder);
- builder.append(" = {\n");
- for (InstructionCallStatement statement : statements) {
- statement.prettyPrint(indent + 1, builder);
- }
- builder.append(prettyIndentString(indent)).append("}\n");
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- UmeSequenceDefinition that = (UmeSequenceDefinition) o;
- return umeKind == that.umeKind && Objects.equals(params, that.params)
- && Objects.equals(statements, that.statements);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(umeKind, params, statements);
- }
-
- enum SeqKind {
- CONSTANT("constant"),
- REGISTER("register adjustment");
-
- private final String keyword;
-
- SeqKind(String keyword) {
- this.keyword = keyword;
- }
- }
-}
-
-
/**
* The compiler generator requires a few special instructions. Those need to be defined
* in the ABI. They are distinguished with the {@link AbiSpecialPurposeInstructionDefinition#kind}
@@ -4128,14 +3976,6 @@ ApplicationBinaryInterfaceDefinition abiNode() {
return (ApplicationBinaryInterfaceDefinition) requireNonNull(abi.target());
}
- /*@Nullable
- UserModeEmulationDefinition umeNode() {
- if (ume == null) {
- return null;
- }
- return (UserModeEmulationDefinition) Objects.requireNonNull(ume.target());
- } */
-
@Override
public SourceLocation location() {
return loc;
diff --git a/vadl/main/vadl/ast/MacroExpander.java b/vadl/main/vadl/ast/MacroExpander.java
index 515a8b8c9..820604800 100644
--- a/vadl/main/vadl/ast/MacroExpander.java
+++ b/vadl/main/vadl/ast/MacroExpander.java
@@ -1099,16 +1099,6 @@ public Definition visit(StageDefinition definition) {
);
}
- @Override
- public Definition visit(UmeSequenceDefinition definition) {
- return new UmeSequenceDefinition(definition.umeKind, definition.params, definition.statements, definition.loc).withAnnotations(definition.annotations);
- }
-
- @Override
- public Definition visit(UserModeEmulationDefinition definition) {
- return new UserModeEmulationDefinition(definition.id, definition.isa, definition.definitions, definition.loc).withAnnotations(definition.annotations);
- }
-
@Override
public Definition visit(CacheDefinition definition) {
return new CacheDefinition(
diff --git a/vadl/main/vadl/ast/ModelRemover.java b/vadl/main/vadl/ast/ModelRemover.java
index a7d769961..192438506 100644
--- a/vadl/main/vadl/ast/ModelRemover.java
+++ b/vadl/main/vadl/ast/ModelRemover.java
@@ -306,16 +306,6 @@ public Definition visit(StageDefinition definition) {
return definition;
}
- @Override
- public Definition visit(UmeSequenceDefinition definition) {
- return definition;
- }
-
- @Override
- public Definition visit(UserModeEmulationDefinition definition) {
- return definition;
- }
-
@Override
public Definition visit(CacheDefinition definition) {
return definition;
diff --git a/vadl/main/vadl/ast/TypeChecker.java b/vadl/main/vadl/ast/TypeChecker.java
index 3689ed43f..5adbc285d 100644
--- a/vadl/main/vadl/ast/TypeChecker.java
+++ b/vadl/main/vadl/ast/TypeChecker.java
@@ -2947,16 +2947,6 @@ public Void visit(StageDefinition definition) {
return null;
}
- @Override
- public Void visit(UmeSequenceDefinition definition) {
- return null;
- }
-
- @Override
- public Void visit(UserModeEmulationDefinition definition) {
- return null;
- }
-
@Override
public Void visit(CacheDefinition definition) {
throw addErrorAndStopChecking(unimplementedError(definition));
diff --git a/vadl/main/vadl/ast/Ungrouper.java b/vadl/main/vadl/ast/Ungrouper.java
index 3e0d94a42..ad10bccc2 100644
--- a/vadl/main/vadl/ast/Ungrouper.java
+++ b/vadl/main/vadl/ast/Ungrouper.java
@@ -603,16 +603,6 @@ public Void visit(StageDefinition definition) {
return null;
}
- @Override
- public Void visit(UmeSequenceDefinition definition) {
- return null;
- }
-
- @Override
- public Void visit(UserModeEmulationDefinition definition) {
- return null;
- }
-
@Override
public Void visit(CacheDefinition definition) {
ungroupAnnotations(definition);
diff --git a/vadl/main/vadl/ast/ViamLowering.java b/vadl/main/vadl/ast/ViamLowering.java
index a7cb482a6..177fb68a5 100644
--- a/vadl/main/vadl/ast/ViamLowering.java
+++ b/vadl/main/vadl/ast/ViamLowering.java
@@ -1964,16 +1964,6 @@ public Optional visit(StageDefinition definition) {
return Optional.of(new Stage(identifier, behaivor, List.of()));
}
- @Override
- public Optional visit(UmeSequenceDefinition definition) {
- return Optional.empty();
- }
-
- @Override
- public Optional visit(UserModeEmulationDefinition definition) {
- return Optional.empty();
- }
-
@Override
public Optional visit(UsingDefinition definition) {
// Do nothing on purpose.
From 275af19e9708b1d0ace3ec84352aa8395cbb332d Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Mon, 30 Mar 2026 08:17:17 +0200
Subject: [PATCH 06/28] ume: Add ume definition #757
---
vadl/main/vadl/viam/DefinitionVisitor.java | 13 ++++
vadl/main/vadl/viam/UserModeEmulation.java | 91 ++++++++++++++++++++++
2 files changed, 104 insertions(+)
create mode 100644 vadl/main/vadl/viam/UserModeEmulation.java
diff --git a/vadl/main/vadl/viam/DefinitionVisitor.java b/vadl/main/vadl/viam/DefinitionVisitor.java
index b5d0a6755..601100120 100644
--- a/vadl/main/vadl/viam/DefinitionVisitor.java
+++ b/vadl/main/vadl/viam/DefinitionVisitor.java
@@ -72,6 +72,8 @@ public interface DefinitionVisitor {
void visit(Abi abi);
+ void visit(UserModeEmulation userModeEmulation);
+
void visit(Processor processor);
void visit(MicroArchitecture microArchitecture);
@@ -313,6 +315,12 @@ public void visit(Abi abi) {
afterTraversal(abi);
}
+ @Override
+ public void visit(UserModeEmulation userModeEmulation) {
+ beforeTraversal(userModeEmulation);
+ afterTraversal(userModeEmulation);
+ }
+
@Override
public void visit(Processor processor) {
beforeTraversal(processor);
@@ -555,6 +563,11 @@ public void visit(Abi abi) {
}
+ @Override
+ public void visit(UserModeEmulation userModeEmulation) {
+
+ }
+
@Override
public void visit(Processor processor) {
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
new file mode 100644
index 000000000..7c2957093
--- /dev/null
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -0,0 +1,91 @@
+// SPDX-FileCopyrightText : © 2026 TU Wien
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package vadl.viam;
+
+import java.util.List;
+import java.util.Map;
+
+public class UserModeEmulation extends Definition {
+ private final int sysReg; // e.g., 17 for RISC-V a7 (syscall number)
+ private final int retReg; // e.g., 10 for RISC-V a0 (return value)
+ private final int spReg; // Stack Pointer (e.g., 2 for RISC-V)
+ private final int raReg; // Return Address (e.g., 1 for RISC-V)
+ private final int tpReg; // Thread Pointer
+ private final List args; // Argument registers (e.g., [10, 11, 12, 13, 14, 15])
+ private final Map excIds; // Exception IDs mapping
+
+ /**
+ * Constructs a UserModeEmulation configuration.
+ */
+ public UserModeEmulation(
+ Identifier identifier,
+ int sysReg,
+ int retReg,
+ int spReg,
+ int raReg,
+ int tpReg,
+ List args,
+ Map excIds) {
+ super(identifier);
+ this.sysReg = sysReg;
+ this.retReg = retReg;
+ this.spReg = spReg;
+ this.raReg = raReg;
+ this.tpReg = tpReg;
+ this.args = args;
+ this.excIds = excIds;
+ }
+
+ public int sysReg() {
+ return sysReg;
+ }
+
+ public int retReg() {
+ return retReg;
+ }
+
+ public int spReg() {
+ return spReg;
+ }
+
+ public int raReg() {
+ return raReg;
+ }
+
+ public int tpReg() {
+ return tpReg;
+ }
+
+ public List args() {
+ return args;
+ }
+
+ public Map excIds() {
+ return excIds;
+ }
+
+ @Override
+ public void accept(DefinitionVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return simpleName() + " [sysReg=" + sysReg + ", retReg=" + retReg + ", spReg=" + spReg
+ + ", raReg=" + raReg + ", tpReg=" + tpReg + ", args=" + args + ", excIds=" + excIds + "]";
+ }
+}
From f9870ad2d4f9a9692061f1de84e709007001267c Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sat, 4 Apr 2026 04:06:34 +0200
Subject: [PATCH 07/28] ume: Add more values for interpolation #757
---
.../iss/linux-user/gen-arch/cpu_loop.c | 18 ++-
.../iss/passes/UmeTemplateRenderingPass.java | 20 ++-
.../vadl/iss/passes/extensions/UmeInfo.java | 49 -------
vadl/main/vadl/viam/UserModeEmulation.java | 123 +++++++++++++++---
4 files changed, 129 insertions(+), 81 deletions(-)
delete mode 100644 vadl/main/vadl/iss/passes/extensions/UmeInfo.java
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 9db9b1b58..7d827f407 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -53,33 +53,37 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
cpu_exec_step_atomic(cs);
break;
case [(${gen_arch_upper})]_EXCP_EXC:
- cause = env->arg_exc_cause;
+ cause = env->[(${config.excCauseVar})];
switch (cause) {
- case [(${gen_arch_upper})]_EXC_ECALL:
+ case [(${gen_arch_upper})]_EXC_[(${config.SYSCALL_NAME})]:
env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
+ [# th:if="${config.hasIcacheFlush}"]
if (env->[(${register_tensors[0].name_lower})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
/* no-op in QEMU; TB invalidation is automatic */
ret = 0;
} else {
+ [/]
ret = do_syscall(env,
env->[(${register_tensors[0].name_lower})][ [(${config.sysReg})] ],
[# th:each="arg : ${config.args}"]
env->[(${register_tensors[0].name_lower})][ [(${arg})] ],
[/]
0, 0);
+ [# th:if="${config.hasIcacheFlush}"]
}
+ [/]
if (ret == -QEMU_ERESTARTSYS) {
- env->[(${pc_reg.name_lower})] -= 4;
+ env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];;
} else if (ret != -QEMU_ESIGRETURN) {
env->[(${register_tensors[0].name_lower})][ [(${config.retReg})] ] = ret; }
if (cs->singlestep_enabled) {
goto gdbstep;
}
break;
- case [(${gen_arch_upper})]_EXC_ILLEGAL_INSTR:
+ case [(${gen_arch_upper})]_EXC_[(${config.ILLEGAL_INSTR_NAME})]:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
break;
- case [(${gen_arch_upper})]_EXC_BREAKPOINT:
+ case [(${gen_arch_upper})]_EXC_[(${config.BREAKPOINT_NAME})]:
case EXCP_DEBUG:
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
@@ -109,8 +113,8 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
TaskState *ts = get_task_state(cpu);
struct image_info *info = ts->info;
- env->[(${pc_reg.name_lower})] = regs->sepc;
- env->[(${register_tensors[0].name_lower})][ [(${config.spReg})] ] = regs->sp;
+ env->[(${pc_reg.name_lower})] = regs->[(${config.ptRegPc})];
+ env->[(${register_tensors[0].name_lower})][ [(${config.spReg})] ] = regs->[(${config.ptRegSp})];
ts->stack_base = info->start_stack;
}
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index 5e51aa5d8..0ba767d7c 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -16,14 +16,13 @@
package vadl.iss.passes;
-import java.util.List;
import java.util.Map;
import vadl.configuration.IssConfiguration;
-import vadl.iss.passes.extensions.UmeInfo;
import vadl.iss.template.IssTemplateRenderingPass;
import vadl.pass.PassName;
import vadl.pass.PassResults;
import vadl.viam.Specification;
+import vadl.viam.UserModeEmulation;
public class UmeTemplateRenderingPass extends IssTemplateRenderingPass {
@@ -52,7 +51,7 @@ protected Map createVariables(PassResults passResults, Specifica
// var umeDef = specification.userModeEmulation().get();
//TODO remove hardcoded values (finish vadl with ume)
- int extractedSysReg = 17;
+ /* int extractedSysReg = 17;
int extractedRetReg = 10;
int extractedSpReg = 2;
int extractedRaReg = 1;
@@ -65,9 +64,22 @@ protected Map createVariables(PassResults passResults, Specifica
);
vars.put("config", new UmeInfo(extractedSysReg, extractedRetReg, extractedSpReg, extractedRaReg, extractedTpReg, extractedArgs, extractedExcIds));
- vars.put("insn_width_bytes", 4);
+ vars.put("insn_width_bytes", 4); */
// }
+ /*specification.definitions()
+ .filter(UserModeEmulation.class::isInstance)
+ .map(UserModeEmulation.class::cast)
+ .findFirst()
+ .ifPresent(ume -> {
+ vars.put("config", ume);
+ vars.put("insn_width_bytes", 4); // or get from elsewhere if needed
+ });*/
+
+ UserModeEmulation ume = UserModeEmulation.createDefault();
+ vars.put("config", ume.asMap());
+ vars.put("insn_width_bytes", 4); // or get from elsewhere if needed
+
return vars;
}
}
diff --git a/vadl/main/vadl/iss/passes/extensions/UmeInfo.java b/vadl/main/vadl/iss/passes/extensions/UmeInfo.java
deleted file mode 100644
index bda170087..000000000
--- a/vadl/main/vadl/iss/passes/extensions/UmeInfo.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-FileCopyrightText : © 2026 TU Wien
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package vadl.iss.passes.extensions;
-
-import java.util.List;
-import java.util.Map;
-import vadl.template.Renderable;
-
-/**
- * Holds the extracted ABI register indices for User-Mode Emulation.
- * Maps the software calling convention to the raw hardware registers.
- */
-public record UmeInfo(
- int sysReg, // e.g., 17 for RISC-V a7 (syscall number)
- int retReg, // e.g., 10 for RISC-V a0 (return value)
- int spReg, // Stack Pointer (e.g., 2 for RISC-V)
- int raReg, // Return Address (e.g., 1 for RISC-V)
- int tpReg,
- List args,
- Map excIds
-) implements Renderable {
-
- @Override
- public Map renderObj() {
- return Map.of(
- "sysReg", sysReg,
- "retReg", retReg,
- "spReg", spReg,
- "raReg", raReg,
- "tpReg", tpReg,
- "args", args,
- "excIds", excIds
- );
- }
-}
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index 7c2957093..251d9f1c5 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -18,29 +18,61 @@
import java.util.List;
import java.util.Map;
+import vadl.utils.SourceLocation;
public class UserModeEmulation extends Definition {
- private final int sysReg; // e.g., 17 for RISC-V a7 (syscall number)
- private final int retReg; // e.g., 10 for RISC-V a0 (return value)
- private final int spReg; // Stack Pointer (e.g., 2 for RISC-V)
- private final int raReg; // Return Address (e.g., 1 for RISC-V)
- private final int tpReg; // Thread Pointer
- private final List args; // Argument registers (e.g., [10, 11, 12, 13, 14, 15])
- private final Map excIds; // Exception IDs mapping
+ /**
+ * Returns a map representation of this UserModeEmulation for template rendering.
+ */
+ public Map asMap() {
+ return Map.ofEntries(
+ Map.entry("sysReg", sysReg),
+ Map.entry("retReg", retReg),
+ Map.entry("spReg", spReg),
+ Map.entry("raReg", raReg),
+ Map.entry("tpReg", tpReg),
+ Map.entry("args", args),
+ Map.entry("excIds", excIds),
+ Map.entry("SYSCALL_NAME", syscallExcName),
+ Map.entry("BREAKPOINT_NAME", breakpointExcName),
+ Map.entry("ILLEGAL_INSTR_NAME", illegalInstrExcName),
+ // NEW FIELDS FOR CPU_LOOP.C:
+ Map.entry("ptRegPc", ptRegPc),
+ Map.entry("ptRegSp", ptRegSp),
+ Map.entry("excCauseVar", excCauseVar),
+ Map.entry("hasIcacheFlush", hasIcacheFlush)
+ );
+ }
+
+ private final int sysReg;
+ private final int retReg;
+ private final int spReg;
+ private final int raReg;
+ private final int tpReg;
+ private final List args;
+ private final Map excIds;
+ private final String syscallExcName;
+ private final String breakpointExcName;
+ private final String illegalInstrExcName;
+ // NEW FIELDS:
+ private final String ptRegPc;
+ private final String ptRegSp;
+ private final String excCauseVar;
+ private final boolean hasIcacheFlush;
/**
* Constructs a UserModeEmulation configuration.
*/
public UserModeEmulation(
Identifier identifier,
- int sysReg,
- int retReg,
- int spReg,
- int raReg,
- int tpReg,
- List args,
- Map excIds) {
+ int sysReg, int retReg, int spReg, int raReg, int tpReg,
+ List args, Map excIds,
+ String syscallExcName, String breakpointExcName, String illegalInstrExcName,
+ String ptRegPc, String ptRegSp, String excCauseVar, boolean hasIcacheFlush) {
super(identifier);
+ if (args == null || args.isEmpty()) throw new IllegalArgumentException("args must not be null/empty");
+ if (excIds == null || excIds.isEmpty()) throw new IllegalArgumentException("excIds must not be null/empty");
+
this.sysReg = sysReg;
this.retReg = retReg;
this.spReg = spReg;
@@ -48,33 +80,82 @@ public UserModeEmulation(
this.tpReg = tpReg;
this.args = args;
this.excIds = excIds;
+ this.syscallExcName = syscallExcName;
+ this.breakpointExcName = breakpointExcName;
+ this.illegalInstrExcName = illegalInstrExcName;
+ this.ptRegPc = ptRegPc;
+ this.ptRegSp = ptRegSp;
+ this.excCauseVar = excCauseVar;
+ this.hasIcacheFlush = hasIcacheFlush;
+ }
+
+ public static UserModeEmulation createDefault() {
+ Identifier identifier = new Identifier(new String[]{"ume"}, SourceLocation.INVALID_SOURCE_LOCATION);
+ Map excIds = Map.of("ILLEGAL_INSTR", 2, "BREAKPOINT", 3, "ECALL", 11);
+
+ return new UserModeEmulation(
+ identifier,
+ 17, 10, 2, 1, 4,
+ List.of(10, 11, 12, 13, 14, 15),
+ excIds,
+ "ECALL", "BREAKPOINT", "ILLEGAL_INSTR",
+ "sepc", "sp", "arg_exc_cause", true
+ );
+ }
+
+ public String getPtRegPc() {
+ return ptRegPc;
+ }
+
+ public String getPtRegSp() {
+ return ptRegSp;
+ }
+
+ public String getExcCauseVar() {
+ return excCauseVar;
+ }
+
+ public boolean hasIcacheFlush() {
+ return hasIcacheFlush;
+ }
+
+ public String getSyscallExcName() {
+ return syscallExcName;
+ }
+
+ public String getBreakpointExcName() {
+ return breakpointExcName;
+ }
+
+ public String getIllegalInstrExcName() {
+ return illegalInstrExcName;
}
- public int sysReg() {
+ public int getSysReg() {
return sysReg;
}
- public int retReg() {
+ public int getRetReg() {
return retReg;
}
- public int spReg() {
+ public int getSpReg() {
return spReg;
}
- public int raReg() {
+ public int getRaReg() {
return raReg;
}
- public int tpReg() {
+ public int getTpReg() {
return tpReg;
}
- public List args() {
+ public List getArgs() {
return args;
}
- public Map excIds() {
+ public Map getExcIds() {
return excIds;
}
From fec5dc88850ebc682d639e2f9cdaab09241efe64 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 12 Apr 2026 16:47:55 +0200
Subject: [PATCH 08/28] ume: Add missing interpolation #757
---
.idea/misc.xml | 3 +-
.../iss/linux-user/gen-arch/cpu_loop.c | 16 ++++----
.../iss/linux-user/gen-arch/signal.c | 14 +++----
.../iss/linux-user/gen-arch/target_cpu.h | 2 +-
.../iss/linux-user/gen-arch/target_proc.h | 2 +-
.../iss/passes/UmeTemplateRenderingPass.java | 3 +-
vadl/main/vadl/viam/UserModeEmulation.java | 39 ++++++++++++++++---
7 files changed, 55 insertions(+), 24 deletions(-)
diff --git a/.idea/misc.xml b/.idea/misc.xml
index ff1573df9..d9bd4697b 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,3 +1,4 @@
+
@@ -56,5 +57,5 @@
-
+
\ No newline at end of file
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 7d827f407..207b56772 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -65,15 +65,18 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
[/]
ret = do_syscall(env,
env->[(${register_tensors[0].name_lower})][ [(${config.sysReg})] ],
- [# th:each="arg : ${config.args}"]
- env->[(${register_tensors[0].name_lower})][ [(${arg})] ],
- [/]
- 0, 0);
+ [(${config.args.size() > 0 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(0) + ']' : '0'})],
+ [(${config.args.size() > 1 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(1) + ']' : '0'})],
+ [(${config.args.size() > 2 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(2) + ']' : '0'})],
+ [(${config.args.size() > 3 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(3) + ']' : '0'})],
+ [(${config.args.size() > 4 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(4) + ']' : '0'})],
+ [(${config.args.size() > 5 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(5) + ']' : '0'})],
+ 0, 0);
[# th:if="${config.hasIcacheFlush}"]
}
[/]
if (ret == -QEMU_ERESTARTSYS) {
- env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];;
+ env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
} else if (ret != -QEMU_ESIGRETURN) {
env->[(${register_tensors[0].name_lower})][ [(${config.retReg})] ] = ret; }
if (cs->singlestep_enabled) {
@@ -85,8 +88,7 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
break;
case [(${gen_arch_upper})]_EXC_[(${config.BREAKPOINT_NAME})]:
case EXCP_DEBUG:
-gdbstep:
- force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
+ gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
break;
default:
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
index ed276af48..678276a22 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
@@ -15,7 +15,7 @@
*/
struct target_sigcontext {
abi_long [(${pc_reg.name_lower})];
- abi_long gpr[31];
+ abi_long gpr[ [(${register_tensors[0].size - 1})] ];
};
struct target_ucontext {
@@ -42,7 +42,7 @@ static abi_ulong get_sigframe(struct target_sigaction *ka,
}
sp = target_sigsp(sp, ka) - framesize;
- sp &= ~0xf;
+ sp &= ~[(${config.stack_align_mask} ?: '0xf')];
return sp;
}
@@ -52,7 +52,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPU[(${gen_arch_upper
int i;
__put_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
- for (i = 1; i < 32; i++) {
+ for (i = 1; i < [(${register_tensors[0].size})]; i++) {
__put_user(env->[(${register_tensors[0].name_lower})][i], &sc->gpr[i - 1]);
}
}
@@ -113,7 +113,7 @@ static void restore_sigcontext(CPU[(${gen_arch_upper})]State *env, struct target
int i;
__get_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
- for (i = 1; i < 32; ++i) {
+ for (i = 1; i < [(${register_tensors[0].size})]; ++i) {
__get_user(env->[(${register_tensors[0].name_lower})][i], &sc->gpr[i - 1]);
}
}
@@ -140,7 +140,7 @@ long do_rt_sigreturn(CPU[(${gen_arch_upper})]State *env)
struct target_rt_sigframe *frame;
abi_ulong frame_addr;
- frame_addr = env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP];
+ frame_addr = env->[(${register_tensors[0].name_lower})][ [(${config.spReg})] ];
trace_user_do_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
@@ -163,8 +163,8 @@ void setup_sigtramp(abi_ulong sigtramp_page)
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
assert(tramp != NULL);
- __put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
- __put_user(0x00000073, tramp + 1); /* ecall */
+ __put_user([(${config.sigtrampLoadSyscallInstr})], tramp + 0); /* load rt_sigreturn syscall number */
+ __put_user([(${config.sigtrampTrapInstr})], tramp + 1); /* syscall/trap instruction */
default_rt_sigreturn = sigtramp_page;
unlock_user(tramp, sigtramp_page, 8);
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
index dea9ad147..6f0363942 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
@@ -19,7 +19,7 @@ static inline void cpu_clone_regs_child(CPU[(${gen_arch_upper})]State *env, targ
env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP] = newsp;
}
- env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_A0] = 0;
+ env->[(${register_tensors[0].name_lower})][ [(${config.retReg})] ] = 0;
}
static inline void cpu_clone_regs_parent(CPU[(${gen_arch_upper})]State *env, unsigned flags)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_proc.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_proc.h
index 0536a6aca..07eb9eff4 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_proc.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_proc.h
@@ -12,7 +12,7 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd)
dprintf(fd, "processor\t: 0\n");
dprintf(fd, "hart\t\t: 0\n");
- dprintf(fd, "isa\t\t: rv64im\n");
+ dprintf(fd, "isa\t\t: [(${gen_arch_lower})]\n");
dprintf(fd, "mmu\t\t: none\n");
dprintf(fd, "uarch\t\t: qemu\n\n");
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index 0ba767d7c..ea9b51a94 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -73,12 +73,11 @@ protected Map createVariables(PassResults passResults, Specifica
.findFirst()
.ifPresent(ume -> {
vars.put("config", ume);
- vars.put("insn_width_bytes", 4); // or get from elsewhere if needed
+ vars.put("insn_width_bytes", 4);
});*/
UserModeEmulation ume = UserModeEmulation.createDefault();
vars.put("config", ume.asMap());
- vars.put("insn_width_bytes", 4); // or get from elsewhere if needed
return vars;
}
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index 251d9f1c5..4c03958c4 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -36,11 +36,14 @@ public Map asMap() {
Map.entry("SYSCALL_NAME", syscallExcName),
Map.entry("BREAKPOINT_NAME", breakpointExcName),
Map.entry("ILLEGAL_INSTR_NAME", illegalInstrExcName),
- // NEW FIELDS FOR CPU_LOOP.C:
Map.entry("ptRegPc", ptRegPc),
Map.entry("ptRegSp", ptRegSp),
Map.entry("excCauseVar", excCauseVar),
- Map.entry("hasIcacheFlush", hasIcacheFlush)
+ Map.entry("hasIcacheFlush", hasIcacheFlush),
+ Map.entry("insn_width_bytes", insnWidthBytes),
+ Map.entry("stack_align_mask", stackAlignMask),
+ Map.entry("sigtrampLoadSyscallInstr", sigtrampLoadSyscallInstr),
+ Map.entry("sigtrampTrapInstr", sigtrampTrapInstr)
);
}
@@ -54,11 +57,14 @@ public Map asMap() {
private final String syscallExcName;
private final String breakpointExcName;
private final String illegalInstrExcName;
- // NEW FIELDS:
private final String ptRegPc;
private final String ptRegSp;
private final String excCauseVar;
private final boolean hasIcacheFlush;
+ private final int insnWidthBytes;
+ private final int stackAlignMask;
+ private final int sigtrampLoadSyscallInstr;
+ private final int sigtrampTrapInstr;
/**
* Constructs a UserModeEmulation configuration.
@@ -68,7 +74,9 @@ public UserModeEmulation(
int sysReg, int retReg, int spReg, int raReg, int tpReg,
List args, Map excIds,
String syscallExcName, String breakpointExcName, String illegalInstrExcName,
- String ptRegPc, String ptRegSp, String excCauseVar, boolean hasIcacheFlush) {
+ String ptRegPc, String ptRegSp, String excCauseVar, boolean hasIcacheFlush,
+ int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
+ int sigtrampTrapInstr) {
super(identifier);
if (args == null || args.isEmpty()) throw new IllegalArgumentException("args must not be null/empty");
if (excIds == null || excIds.isEmpty()) throw new IllegalArgumentException("excIds must not be null/empty");
@@ -87,6 +95,10 @@ public UserModeEmulation(
this.ptRegSp = ptRegSp;
this.excCauseVar = excCauseVar;
this.hasIcacheFlush = hasIcacheFlush;
+ this.insnWidthBytes = insnWidthBytes;
+ this.stackAlignMask = stackAlignMask;
+ this.sigtrampLoadSyscallInstr = sigtrampLoadSyscallInstr;
+ this.sigtrampTrapInstr = sigtrampTrapInstr;
}
public static UserModeEmulation createDefault() {
@@ -99,10 +111,27 @@ public static UserModeEmulation createDefault() {
List.of(10, 11, 12, 13, 14, 15),
excIds,
"ECALL", "BREAKPOINT", "ILLEGAL_INSTR",
- "sepc", "sp", "arg_exc_cause", true
+ "sepc", "sp", "arg_exc_cause", true,
+ 4, 0xf, 0x08b00893, 0x00000073
);
}
+ public int getSigtrampLoadSyscallInstr() {
+ return sigtrampLoadSyscallInstr;
+ }
+
+ public int getSigtrampTrapInstr() {
+ return sigtrampTrapInstr;
+ }
+
+ public int getStackAlignMask() {
+ return stackAlignMask;
+ }
+
+ public int getInsnWidthBytes() {
+ return insnWidthBytes;
+ }
+
public String getPtRegPc() {
return ptRegPc;
}
From fc5e22e94e385bd535dccbd88aa22d8fad826b68 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 12 Apr 2026 17:07:08 +0200
Subject: [PATCH 09/28] ume: Fix checkstyle violations #757
---
.../iss/passes/UmeTemplateRenderingPass.java | 39 +++-------
vadl/main/vadl/viam/UserModeEmulation.java | 77 ++++++++++++-------
2 files changed, 58 insertions(+), 58 deletions(-)
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index ea9b51a94..e4567a943 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -24,6 +24,16 @@
import vadl.viam.Specification;
import vadl.viam.UserModeEmulation;
+/**
+ * A specialized template rendering pass for QEMU User-Mode Emulation (UME) source files.
+ *
+ * This pass populates the template context with architecture-specific configurations
+ * required for Linux user-mode emulation, such as register mappings for system calls,
+ * stack alignment, and exception handling indices.
+ *
+ * * @see IssTemplateRenderingPass
+ * @see UserModeEmulation
+ */
public class UmeTemplateRenderingPass extends IssTemplateRenderingPass {
private final String templateFilename;
@@ -47,35 +57,6 @@ public PassName getName() {
protected Map createVariables(PassResults passResults, Specification specification) {
var vars = super.createVariables(passResults, specification);
- //if (specification.userModeEmulation().isPresent()) {
- // var umeDef = specification.userModeEmulation().get();
-
- //TODO remove hardcoded values (finish vadl with ume)
- /* int extractedSysReg = 17;
- int extractedRetReg = 10;
- int extractedSpReg = 2;
- int extractedRaReg = 1;
- int extractedTpReg = 4;
- List extractedArgs = List.of(10, 11, 12, 13, 14, 15);
- Map extractedExcIds = Map.of(
- "ILLEGAL_INSTR", 2,
- "BREAKPOINT", 3,
- "ECALL", 11
- );
-
- vars.put("config", new UmeInfo(extractedSysReg, extractedRetReg, extractedSpReg, extractedRaReg, extractedTpReg, extractedArgs, extractedExcIds));
- vars.put("insn_width_bytes", 4); */
- // }
-
- /*specification.definitions()
- .filter(UserModeEmulation.class::isInstance)
- .map(UserModeEmulation.class::cast)
- .findFirst()
- .ifPresent(ume -> {
- vars.put("config", ume);
- vars.put("insn_width_bytes", 4);
- });*/
-
UserModeEmulation ume = UserModeEmulation.createDefault();
vars.put("config", ume.asMap());
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index 4c03958c4..6187ccf48 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -20,30 +20,38 @@
import java.util.Map;
import vadl.utils.SourceLocation;
+/**
+ * Represents the configuration for QEMU user-mode emulation.
+ *
+ * This class defines architecture-specific parameters required for Linux-user emulation,
+ * including system call register mappings, signal trampoline instructions, stack
+ * alignment requirements, and exception IDs.
+ *
+ */
public class UserModeEmulation extends Definition {
/**
* Returns a map representation of this UserModeEmulation for template rendering.
*/
- public Map asMap() {
- return Map.ofEntries(
- Map.entry("sysReg", sysReg),
- Map.entry("retReg", retReg),
- Map.entry("spReg", spReg),
- Map.entry("raReg", raReg),
- Map.entry("tpReg", tpReg),
- Map.entry("args", args),
- Map.entry("excIds", excIds),
- Map.entry("SYSCALL_NAME", syscallExcName),
- Map.entry("BREAKPOINT_NAME", breakpointExcName),
- Map.entry("ILLEGAL_INSTR_NAME", illegalInstrExcName),
- Map.entry("ptRegPc", ptRegPc),
- Map.entry("ptRegSp", ptRegSp),
- Map.entry("excCauseVar", excCauseVar),
- Map.entry("hasIcacheFlush", hasIcacheFlush),
- Map.entry("insn_width_bytes", insnWidthBytes),
- Map.entry("stack_align_mask", stackAlignMask),
- Map.entry("sigtrampLoadSyscallInstr", sigtrampLoadSyscallInstr),
- Map.entry("sigtrampTrapInstr", sigtrampTrapInstr)
+ public Map asMap() {
+ return Map.ofEntries(
+ Map.entry("sysReg", sysReg),
+ Map.entry("retReg", retReg),
+ Map.entry("spReg", spReg),
+ Map.entry("raReg", raReg),
+ Map.entry("tpReg", tpReg),
+ Map.entry("args", args),
+ Map.entry("excIds", excIds),
+ Map.entry("SYSCALL_NAME", syscallExcName),
+ Map.entry("BREAKPOINT_NAME", breakpointExcName),
+ Map.entry("ILLEGAL_INSTR_NAME", illegalInstrExcName),
+ Map.entry("ptRegPc", ptRegPc),
+ Map.entry("ptRegSp", ptRegSp),
+ Map.entry("excCauseVar", excCauseVar),
+ Map.entry("hasIcacheFlush", hasIcacheFlush),
+ Map.entry("insn_width_bytes", insnWidthBytes),
+ Map.entry("stack_align_mask", stackAlignMask),
+ Map.entry("sigtrampLoadSyscallInstr", sigtrampLoadSyscallInstr),
+ Map.entry("sigtrampTrapInstr", sigtrampTrapInstr)
);
}
@@ -70,16 +78,22 @@ public Map asMap() {
* Constructs a UserModeEmulation configuration.
*/
public UserModeEmulation(
- Identifier identifier,
- int sysReg, int retReg, int spReg, int raReg, int tpReg,
- List args, Map excIds,
- String syscallExcName, String breakpointExcName, String illegalInstrExcName,
- String ptRegPc, String ptRegSp, String excCauseVar, boolean hasIcacheFlush,
- int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
- int sigtrampTrapInstr) {
+ Identifier identifier,
+ int sysReg, int retReg, int spReg, int raReg, int tpReg,
+ List args, Map excIds,
+ String syscallExcName, String breakpointExcName, String illegalInstrExcName,
+ String ptRegPc, String ptRegSp, String excCauseVar, boolean hasIcacheFlush,
+ int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
+ int sigtrampTrapInstr) {
+
super(identifier);
- if (args == null || args.isEmpty()) throw new IllegalArgumentException("args must not be null/empty");
- if (excIds == null || excIds.isEmpty()) throw new IllegalArgumentException("excIds must not be null/empty");
+ if (args == null || args.isEmpty()) {
+ throw new IllegalArgumentException("args must not be null/empty");
+ }
+
+ if (excIds == null || excIds.isEmpty()) {
+ throw new IllegalArgumentException("excIds must not be null/empty");
+ }
this.sysReg = sysReg;
this.retReg = retReg;
@@ -101,6 +115,11 @@ public UserModeEmulation(
this.sigtrampTrapInstr = sigtrampTrapInstr;
}
+ /**
+ * Creates a default {@link UserModeEmulation} configuration,
+ * pre-configured for the RISC-V architecture.
+ * * @return a standard RISC-V user-mode emulation setup.
+ */
public static UserModeEmulation createDefault() {
Identifier identifier = new Identifier(new String[]{"ume"}, SourceLocation.INVALID_SOURCE_LOCATION);
Map excIds = Map.of("ILLEGAL_INSTR", 2, "BREAKPOINT", 3, "ECALL", 11);
From 1440cb70d1c65bcdba1c2f87f1c89f0ab394de86 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 12 Apr 2026 17:14:40 +0200
Subject: [PATCH 10/28] ume: Fix more checkstyle violations #757
---
.../iss/passes/UmeTemplateRenderingPass.java | 8 +++---
vadl/main/vadl/viam/UserModeEmulation.java | 28 ++++++++++---------
2 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index e4567a943..d1d28bed8 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -31,8 +31,6 @@
* required for Linux user-mode emulation, such as register mappings for system calls,
* stack alignment, and exception handling indices.
*
- * * @see IssTemplateRenderingPass
- * @see UserModeEmulation
*/
public class UmeTemplateRenderingPass extends IssTemplateRenderingPass {
@@ -50,11 +48,13 @@ protected String issTemplatePath() {
@Override
public PassName getName() {
- return PassName.of("Rendering UME template: " + templateFilename);
+ return PassName.of("Rendering UME template: "
+ + templateFilename);
}
@Override
- protected Map createVariables(PassResults passResults, Specification specification) {
+ protected Map createVariables(PassResults passResults,
+ Specification specification) {
var vars = super.createVariables(passResults, specification);
UserModeEmulation ume = UserModeEmulation.createDefault();
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index 6187ccf48..b7014e950 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -29,9 +29,9 @@
*
*/
public class UserModeEmulation extends Definition {
- /**
- * Returns a map representation of this UserModeEmulation for template rendering.
- */
+ /**
+ * Returns a map representation of this UserModeEmulation for template rendering.
+ */
public Map asMap() {
return Map.ofEntries(
Map.entry("sysReg", sysReg),
@@ -53,7 +53,7 @@ public Map asMap() {
Map.entry("sigtrampLoadSyscallInstr", sigtrampLoadSyscallInstr),
Map.entry("sigtrampTrapInstr", sigtrampTrapInstr)
);
- }
+ }
private final int sysReg;
private final int retReg;
@@ -78,13 +78,13 @@ public Map asMap() {
* Constructs a UserModeEmulation configuration.
*/
public UserModeEmulation(
- Identifier identifier,
- int sysReg, int retReg, int spReg, int raReg, int tpReg,
- List args, Map excIds,
- String syscallExcName, String breakpointExcName, String illegalInstrExcName,
- String ptRegPc, String ptRegSp, String excCauseVar, boolean hasIcacheFlush,
- int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
- int sigtrampTrapInstr) {
+ Identifier identifier,
+ int sysReg, int retReg, int spReg, int raReg, int tpReg,
+ List args, Map excIds,
+ String syscallExcName, String breakpointExcName, String illegalInstrExcName,
+ String ptRegPc, String ptRegSp, String excCauseVar, boolean hasIcacheFlush,
+ int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
+ int sigtrampTrapInstr) {
super(identifier);
if (args == null || args.isEmpty()) {
@@ -121,8 +121,10 @@ public UserModeEmulation(
* * @return a standard RISC-V user-mode emulation setup.
*/
public static UserModeEmulation createDefault() {
- Identifier identifier = new Identifier(new String[]{"ume"}, SourceLocation.INVALID_SOURCE_LOCATION);
- Map excIds = Map.of("ILLEGAL_INSTR", 2, "BREAKPOINT", 3, "ECALL", 11);
+ Identifier identifier = new Identifier(new String[]{"ume"},
+ SourceLocation.INVALID_SOURCE_LOCATION);
+ Map excIds = Map.of("ILLEGAL_INSTR",
+ 2, "BREAKPOINT", 3, "ECALL", 11);
return new UserModeEmulation(
identifier,
From 28c1e59e0e2584713194c32420a4d961c869e95f Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 12 Apr 2026 22:29:55 +0200
Subject: [PATCH 11/28] ume: Remove duplicate line #757
---
vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 207b56772..0ce166ae3 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -93,7 +93,6 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
break;
default:
EXCP_DUMP(env,
- "\nqemu: unhandled [(${gen_arch_lower})] exception cause %#x - aborting\n",
"\nqemu: unhandled [(${gen_arch_lower})] exception cause %#x - aborting\n",
cause);
exit(EXIT_FAILURE);
From 3f37df909032421e979514b8f0e0ebcfc99656a5 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Mon, 13 Apr 2026 23:26:59 +0200
Subject: [PATCH 12/28] ume: Revert frontend changes #757
---
vadl/main/vadl/ast/AstVisitor.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vadl/main/vadl/ast/AstVisitor.java b/vadl/main/vadl/ast/AstVisitor.java
index dc10df295..a9be7f63f 100644
--- a/vadl/main/vadl/ast/AstVisitor.java
+++ b/vadl/main/vadl/ast/AstVisitor.java
@@ -937,4 +937,4 @@ public Void visit(StatementList statement) {
afterTravel(statement);
return null;
}
-}
+}
\ No newline at end of file
From 3f7de33531fbfa3b88162319024354ff06be4204 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Mon, 13 Apr 2026 23:33:08 +0200
Subject: [PATCH 13/28] ume: Revert atg file changes #757
---
vadl/main/vadl/ast/vadl.ATG | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vadl/main/vadl/ast/vadl.ATG b/vadl/main/vadl/ast/vadl.ATG
index 35946b1ee..765a38af2 100644
--- a/vadl/main/vadl/ast/vadl.ATG
+++ b/vadl/main/vadl/ast/vadl.ATG
@@ -1199,7 +1199,7 @@ The #miaDefinition production rule lists all micro architecture language element
\listing{lst_mia_definitions, Example micro architecture definition}
~~~{.vadl}
micro architecture FiveStage implements RV32IM = {
-
+
logic [forwarding] bypass
stage FETCH -> ( fr : FetchResult ) = {
From b6d7912802a7d644ae941980ce8dd9fd501b92ea Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Tue, 14 Apr 2026 21:34:51 +0200
Subject: [PATCH 14/28] ume: Use proper viam objects and fix templates #757
---
.../iss/linux-user/gen-arch/cpu_loop.c | 29 ++-
.../UmeHardcodedRiscvDefinitionPass.java | 47 ++++
.../iss/passes/UmeTemplateRenderingPass.java | 30 ++-
vadl/main/vadl/viam/Specification.java | 12 +-
vadl/main/vadl/viam/UserModeEmulation.java | 218 +++++++++++++-----
5 files changed, 257 insertions(+), 79 deletions(-)
create mode 100644 vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 0ce166ae3..1e69f0e90 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -25,7 +25,6 @@
#include "elf.h"
-//TODO check for diff way to get exc+value
enum {
[# th:each="exc : ${config.excIds}"]
[(${gen_arch_upper})]_EXC_[(${exc.key})] = [(${exc.value})],
@@ -52,41 +51,39 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
- case [(${gen_arch_upper})]_EXCP_EXC:
+ case [(${gen_arch_upper})]_EXCP_[(${config.syscallException})]:
cause = env->[(${config.excCauseVar})];
switch (cause) {
- case [(${gen_arch_upper})]_EXC_[(${config.SYSCALL_NAME})]:
+ case [(${gen_arch_upper})]_EXC_[(${config.syscallInstr})]:
env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
[# th:if="${config.hasIcacheFlush}"]
- if (env->[(${register_tensors[0].name_lower})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
+ if (env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
/* no-op in QEMU; TB invalidation is automatic */
ret = 0;
} else {
[/]
ret = do_syscall(env,
- env->[(${register_tensors[0].name_lower})][ [(${config.sysReg})] ],
- [(${config.args.size() > 0 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(0) + ']' : '0'})],
- [(${config.args.size() > 1 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(1) + ']' : '0'})],
- [(${config.args.size() > 2 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(2) + ']' : '0'})],
- [(${config.args.size() > 3 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(3) + ']' : '0'})],
- [(${config.args.size() > 4 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(4) + ']' : '0'})],
- [(${config.args.size() > 5 ? 'env->' + register_tensors[0].name_lower + '[' + config.args.get(5) + ']' : '0'})],
- 0, 0);
+ env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
+ [# th:each="arg : ${config.args}"]
+ env->[(${config.mainRegisterFile})][ [(${arg})] ],
+ [/]
+ 0, 0);
[# th:if="${config.hasIcacheFlush}"]
}
[/]
if (ret == -QEMU_ERESTARTSYS) {
env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
} else if (ret != -QEMU_ESIGRETURN) {
- env->[(${register_tensors[0].name_lower})][ [(${config.retReg})] ] = ret; }
+ env->[(${config.mainRegisterFile})][ [(${config.retReg})] ] = ret; }
if (cs->singlestep_enabled) {
goto gdbstep;
}
break;
- case [(${gen_arch_upper})]_EXC_[(${config.ILLEGAL_INSTR_NAME})]:
+
+ case [(${gen_arch_upper})]_EXC_[(${config.illegalInstrExcName})]:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
break;
- case [(${gen_arch_upper})]_EXC_[(${config.BREAKPOINT_NAME})]:
+ case [(${gen_arch_upper})]_EXC_[(${config.breakpointExcName})]:
case EXCP_DEBUG:
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
@@ -115,7 +112,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
struct image_info *info = ts->info;
env->[(${pc_reg.name_lower})] = regs->[(${config.ptRegPc})];
- env->[(${register_tensors[0].name_lower})][ [(${config.spReg})] ] = regs->[(${config.ptRegSp})];
+ env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = regs->[(${config.ptRegSp})];
ts->stack_base = info->start_stack;
}
diff --git a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
new file mode 100644
index 000000000..aacb188f3
--- /dev/null
+++ b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText : © 2026 TU Wien
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package vadl.iss.passes;
+
+import java.io.IOException;
+import javax.annotation.CheckForNull;
+import vadl.configuration.IssConfiguration;
+import vadl.pass.PassName;
+import vadl.pass.PassResults;
+import vadl.viam.Specification;
+import vadl.viam.UserModeEmulation;
+
+/**
+ * A specialized hardcoded rendering pass for QEMU User-Mode Emulation (UME) source files.
+ */
+public class UmeHardcodedRiscvDefinitionPass extends AbstractIssPass {
+ public UmeHardcodedRiscvDefinitionPass(IssConfiguration configuration) {
+ super(configuration);
+ }
+
+ @Override
+ public PassName getName() {
+ return PassName.of("UME Hardcoded RISC-V Definition");
+ }
+
+ @CheckForNull
+ @Override
+ public Object execute(PassResults passResults, Specification viam) throws IOException {
+ UserModeEmulation ume = UserModeEmulation.createDefault();
+ viam.add(ume);
+ return null;
+ }
+}
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index d1d28bed8..ca259262d 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -19,6 +19,7 @@
import java.util.Map;
import vadl.configuration.IssConfiguration;
import vadl.iss.template.IssTemplateRenderingPass;
+import vadl.lcb.templateUtils.RegisterUtils;
import vadl.pass.PassName;
import vadl.pass.PassResults;
import vadl.viam.Specification;
@@ -57,8 +58,33 @@ protected Map createVariables(PassResults passResults,
Specification specification) {
var vars = super.createVariables(passResults, specification);
- UserModeEmulation ume = UserModeEmulation.createDefault();
- vars.put("config", ume.asMap());
+ UserModeEmulation ume = specification.userModeEmulation()
+ .orElseThrow(() -> new IllegalStateException("No UserModeEmulation defined"));
+
+ vars.put("config", Map.ofEntries(
+ Map.entry("sysReg", ume.getSysReg().index()),
+ Map.entry("retReg", ume.getRetReg().index()),
+ Map.entry("spReg", ume.getSpReg().index()),
+ Map.entry("raReg", ume.getRaReg().index()),
+ Map.entry("tpReg", ume.getTpReg().index()),
+ Map.entry("args", ume.getArgs().stream()
+ .map(RegisterUtils.Register::index)
+ .toList()),
+ Map.entry("excIds", ume.getExcIds()),
+ Map.entry("syscallInstr", ume.getSyscallInstr().simpleName()),
+ Map.entry("syscallException", ume.getSyscallException().simpleName()),
+ Map.entry("breakpointExcName", ume.getBreakpointExcName().simpleName()),
+ Map.entry("illegalInstrExcName", ume.getIllegalInstrExcName().simpleName()),
+ Map.entry("ptRegPc", ume.getPtRegPc()),
+ Map.entry("ptRegSp", ume.getPtRegSp()),
+ Map.entry("excCauseVar", ume.getExcCauseVar().simpleName()),
+ Map.entry("hasIcacheFlush", ume.hasIcacheFlush()),
+ Map.entry("insn_width_bytes", ume.getInsnWidthBytes()),
+ Map.entry("stack_align_mask", ume.getStackAlignMask()),
+ Map.entry("sigtrampLoadSyscallInstr", ume.getSigtrampLoadSyscallInstr()),
+ Map.entry("sigtrampTrapInstr", ume.getSigtrampTrapInstr()),
+ Map.entry("mainRegisterFile", ume.getMainRegisterFile().simpleName().toLowerCase())
+ ));
return vars;
}
diff --git a/vadl/main/vadl/viam/Specification.java b/vadl/main/vadl/viam/Specification.java
index 8fd70f8c5..e52b3f1cb 100644
--- a/vadl/main/vadl/viam/Specification.java
+++ b/vadl/main/vadl/viam/Specification.java
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText : © 2025 TU Wien
+// SPDX-FileCopyrightText : © 2025-2026 TU Wien
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
@@ -137,6 +137,16 @@ public Stream findAllFormats() {
return Stream.concat(formats(), innerFormats);
}
+ /**
+ * Returns the ume of the specification.
+ */
+ public Optional userModeEmulation() {
+ return definitions()
+ .filter(UserModeEmulation.class::isInstance)
+ .map(UserModeEmulation.class::cast)
+ .findFirst();
+ }
+
public void add(Definition definition) {
definitions.add(definition);
}
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index b7014e950..c502a0e41 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -16,9 +16,16 @@
package vadl.viam;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.IntStream;
+import vadl.lcb.templateUtils.RegisterUtils;
+import vadl.types.BitsType;
+import vadl.types.Type;
+import vadl.utils.Pair;
import vadl.utils.SourceLocation;
+import vadl.viam.graph.Graph;
/**
* Represents the configuration for QEMU user-mode emulation.
@@ -29,45 +36,22 @@
*
*/
public class UserModeEmulation extends Definition {
- /**
- * Returns a map representation of this UserModeEmulation for template rendering.
- */
- public Map asMap() {
- return Map.ofEntries(
- Map.entry("sysReg", sysReg),
- Map.entry("retReg", retReg),
- Map.entry("spReg", spReg),
- Map.entry("raReg", raReg),
- Map.entry("tpReg", tpReg),
- Map.entry("args", args),
- Map.entry("excIds", excIds),
- Map.entry("SYSCALL_NAME", syscallExcName),
- Map.entry("BREAKPOINT_NAME", breakpointExcName),
- Map.entry("ILLEGAL_INSTR_NAME", illegalInstrExcName),
- Map.entry("ptRegPc", ptRegPc),
- Map.entry("ptRegSp", ptRegSp),
- Map.entry("excCauseVar", excCauseVar),
- Map.entry("hasIcacheFlush", hasIcacheFlush),
- Map.entry("insn_width_bytes", insnWidthBytes),
- Map.entry("stack_align_mask", stackAlignMask),
- Map.entry("sigtrampLoadSyscallInstr", sigtrampLoadSyscallInstr),
- Map.entry("sigtrampTrapInstr", sigtrampTrapInstr)
- );
- }
-
- private final int sysReg;
- private final int retReg;
- private final int spReg;
- private final int raReg;
- private final int tpReg;
- private final List args;
+
+ private final Identifier excCauseVar;
+ private final RegisterTensor mainRegisterFile;
+ private final RegisterUtils.Register sysReg;
+ private final RegisterUtils.Register retReg;
+ private final RegisterUtils.Register spReg;
+ private final RegisterUtils.Register raReg;
+ private final RegisterUtils.Register tpReg;
+ private final List args;
private final Map excIds;
- private final String syscallExcName;
- private final String breakpointExcName;
- private final String illegalInstrExcName;
+ private final Instruction syscallInstr;
+ private final ExceptionDef syscallException;
+ private final ExceptionDef breakpointExcName;
+ private final ExceptionDef illegalInstrExcName;
private final String ptRegPc;
private final String ptRegSp;
- private final String excCauseVar;
private final boolean hasIcacheFlush;
private final int insnWidthBytes;
private final int stackAlignMask;
@@ -78,15 +62,20 @@ public Map asMap() {
* Constructs a UserModeEmulation configuration.
*/
public UserModeEmulation(
- Identifier identifier,
- int sysReg, int retReg, int spReg, int raReg, int tpReg,
- List args, Map excIds,
- String syscallExcName, String breakpointExcName, String illegalInstrExcName,
- String ptRegPc, String ptRegSp, String excCauseVar, boolean hasIcacheFlush,
+ Identifier identifier, ExceptionDef syscallException,
+ RegisterTensor mainRegisterFile,
+ RegisterUtils.Register sysReg, RegisterUtils.Register retReg,
+ RegisterUtils.Register spReg, RegisterUtils.Register raReg, RegisterUtils.Register tpReg,
+ List args, Map excIds,
+ Instruction syscallInstr, ExceptionDef breakpointExcName,
+ ExceptionDef illegalInstrExcName,
+ String ptRegPc, String ptRegSp, Identifier excCauseVar, boolean hasIcacheFlush,
int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
int sigtrampTrapInstr) {
super(identifier);
+ this.syscallException = syscallException;
+ this.mainRegisterFile = mainRegisterFile;
if (args == null || args.isEmpty()) {
throw new IllegalArgumentException("args must not be null/empty");
}
@@ -102,7 +91,7 @@ public UserModeEmulation(
this.tpReg = tpReg;
this.args = args;
this.excIds = excIds;
- this.syscallExcName = syscallExcName;
+ this.syscallInstr = syscallInstr;
this.breakpointExcName = breakpointExcName;
this.illegalInstrExcName = illegalInstrExcName;
this.ptRegPc = ptRegPc;
@@ -123,17 +112,118 @@ public UserModeEmulation(
public static UserModeEmulation createDefault() {
Identifier identifier = new Identifier(new String[]{"ume"},
SourceLocation.INVALID_SOURCE_LOCATION);
- Map excIds = Map.of("ILLEGAL_INSTR",
- 2, "BREAKPOINT", 3, "ECALL", 11);
+
+ RegisterTensor.Dimension regDim = new RegisterTensor.Dimension(
+ 0,
+ Type.bits(5),
+ 32
+ );
+
+ RegisterTensor.Dimension dummyDim = new RegisterTensor.Dimension(
+ 1,
+ Type.bits(1),
+ 1
+ );
+
+ List dimensions = List.of(regDim, dummyDim);
+ RegisterTensor mainFile = new RegisterTensor(
+ new Identifier(new String[]{"x"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ dimensions
+ );
+
+ var dummyMap = new HashMap, List>();
+
+ RegisterUtils.RegisterClass gprClass = RegisterUtils.getRegisterClass(mainFile, dummyMap);
+
+ RegisterUtils.Register sp = gprClass.registers().get(2);
+ RegisterUtils.Register ra = gprClass.registers().get(1);
+ RegisterUtils.Register tp = gprClass.registers().get(4);
+ RegisterUtils.Register sys = gprClass.registers().get(17);
+ RegisterUtils.Register ret = gprClass.registers().get(10);
+
+ List args = IntStream.range(10, 16)
+ .mapToObj(i -> gprClass.registers().get(i))
+ .toList();
+
+ Parameter[] emptyParams = new Parameter[0];
+ Graph emptyGraph = new Graph("empty_graph");
+
+ ExceptionDef mockSyscallExc = new ExceptionDef(
+ new Identifier(new String[]{"EXC"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ emptyParams,
+ emptyGraph,
+ ExceptionDef.Kind.DECLARED
+ );
+
+ ExceptionDef mockBreakpointExc = new ExceptionDef(
+ new Identifier(new String[]{"BREAKPOINT"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ emptyParams,
+ emptyGraph,
+ ExceptionDef.Kind.DECLARED
+ );
+
+ ExceptionDef mockIllegalExc = new ExceptionDef(
+ new Identifier(new String[]{"ILLEGAL_INSTR"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ emptyParams,
+ emptyGraph,
+ ExceptionDef.Kind.DECLARED
+ );
+
+ BitsType mockType = BitsType.bits(32);
+
+ Function mockFunc = new Function(
+ new Identifier(new String[]{"dummy_function"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ new Parameter[0],
+ Type.string(),
+ emptyGraph
+ );
+
+ Assembly emptyAssembly = new Assembly(new Identifier(new String[]{"dummy_assembly"},
+ SourceLocation.INVALID_SOURCE_LOCATION), mockFunc);
+
+ Format dummyFormat = new Format(new Identifier(new String[]{"dummy_format"},
+ SourceLocation.INVALID_SOURCE_LOCATION), mockType);
+
+ Encoding emptyEncoding = new Encoding(
+ new Identifier(new String[]{"dummy_encoding"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ dummyFormat, new Encoding.Field[0]);
+
+ Instruction mockSyscallInsn = new Instruction(
+ new Identifier(new String[]{"ECALL"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ emptyGraph, emptyAssembly, emptyEncoding
+ );
+
+
+ Identifier riscvCauseVar = new Identifier(new String[]{"cause"},
+ SourceLocation.INVALID_SOURCE_LOCATION);
+
+ Map excIds = Map.of(
+ "ILLEGAL_INSTR", 2,
+ "BREAKPOINT", 3,
+ "ECALL", 11
+ );
+
return new UserModeEmulation(
identifier,
- 17, 10, 2, 1, 4,
- List.of(10, 11, 12, 13, 14, 15),
+ mockSyscallExc,
+ mainFile,
+ sys, ret, sp, ra, tp,
+ args,
excIds,
- "ECALL", "BREAKPOINT", "ILLEGAL_INSTR",
- "sepc", "sp", "arg_exc_cause", true,
- 4, 0xf, 0x08b00893, 0x00000073
+ mockSyscallInsn,
+ mockBreakpointExc,
+ mockIllegalExc,
+ "sepc", "sp", riscvCauseVar,
+ true, 4, 0xf,
+ 0x08b00893, 0x00000073
);
}
@@ -161,7 +251,7 @@ public String getPtRegSp() {
return ptRegSp;
}
- public String getExcCauseVar() {
+ public Identifier getExcCauseVar() {
return excCauseVar;
}
@@ -169,39 +259,39 @@ public boolean hasIcacheFlush() {
return hasIcacheFlush;
}
- public String getSyscallExcName() {
- return syscallExcName;
+ public Instruction getSyscallInstr() {
+ return syscallInstr;
}
- public String getBreakpointExcName() {
+ public ExceptionDef getBreakpointExcName() {
return breakpointExcName;
}
- public String getIllegalInstrExcName() {
+ public ExceptionDef getIllegalInstrExcName() {
return illegalInstrExcName;
}
- public int getSysReg() {
+ public RegisterUtils.Register getSysReg() {
return sysReg;
}
- public int getRetReg() {
+ public RegisterUtils.Register getRetReg() {
return retReg;
}
- public int getSpReg() {
+ public RegisterUtils.Register getSpReg() {
return spReg;
}
- public int getRaReg() {
+ public RegisterUtils.Register getRaReg() {
return raReg;
}
- public int getTpReg() {
+ public RegisterUtils.Register getTpReg() {
return tpReg;
}
- public List getArgs() {
+ public List getArgs() {
return args;
}
@@ -209,6 +299,14 @@ public Map getExcIds() {
return excIds;
}
+ public ExceptionDef getSyscallException() {
+ return syscallException;
+ }
+
+ public RegisterTensor getMainRegisterFile() {
+ return mainRegisterFile;
+ }
+
@Override
public void accept(DefinitionVisitor visitor) {
visitor.visit(this);
From 488a431ab8758ca7c652565ad97f2b2d7dc092e9 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Wed, 15 Apr 2026 15:18:03 +0200
Subject: [PATCH 15/28] ume: Revert misc file
#757
---
.idea/misc.xml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.idea/misc.xml b/.idea/misc.xml
index d9bd4697b..ff1573df9 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-
@@ -57,5 +56,5 @@
-
+
\ No newline at end of file
From 8c54fa7b261fdec27ab21be4f0df800c3a5553a4 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Thu, 23 Apr 2026 22:11:11 +0200
Subject: [PATCH 16/28] ume: Fix signal.c reigster handling #757
---
.../iss/linux-user/gen-arch/signal.c | 31 ++++++++++++-------
.../UmeHardcodedRiscvDefinitionPass.java | 2 +-
.../iss/passes/UmeTemplateRenderingPass.java | 15 ++++++---
vadl/main/vadl/viam/UserModeEmulation.java | 29 ++++++++++++-----
4 files changed, 53 insertions(+), 24 deletions(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
index 678276a22..5b063bc13 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
@@ -15,7 +15,10 @@
*/
struct target_sigcontext {
abi_long [(${pc_reg.name_lower})];
- abi_long gpr[ [(${register_tensors[0].size - 1})] ];
+
+ [# th:each="tensor : ${config.signalStateTensors}"]
+ abi_long [(${tensor.name_lower})][ [(${tensor.size})] ];
+ [/]
};
struct target_ucontext {
@@ -52,8 +55,8 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPU[(${gen_arch_upper
int i;
__put_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
- for (i = 1; i < [(${register_tensors[0].size})]; i++) {
- __put_user(env->[(${register_tensors[0].name_lower})][i], &sc->gpr[i - 1]);
+ for (i = 1; i < [(${config.mainRegFileSize})]; i++) {
+ __put_user(env->[(${config.mainRegisterFile})][i], &sc->gpr[i - 1]);
}
}
@@ -92,11 +95,17 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
frame->info = *info;
env->[(${pc_reg.name_lower})] = ka->_sa_handler;
- env->[(${register_tensors[0].name_lower})][ [(${config.spReg})] ] = frame_addr;
- env->[(${register_tensors[0].name_lower})][ [(${config.args[0]})] ] = sig;
- env->[(${register_tensors[0].name_lower})][ [(${config.args[1]})] ] = frame_addr + offsetof(struct target_rt_sigframe, info);
- env->[(${register_tensors[0].name_lower})][ [(${config.args[2]})] ] = frame_addr + offsetof(struct target_rt_sigframe, uc);
- env->[(${register_tensors[0].name_lower})][ [(${config.raReg})] ] = default_rt_sigreturn;
+ env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = frame_addr;
+ env->[(${config.mainRegisterFile})][ [(${config.args[0]})] ] = sig;
+ [# th:if="${#lists.size(config.args) > 1}"]
+ env->[(${config.mainRegisterFile})][ [(${config.args[1]})] ] = frame_addr + offsetof(struct target_rt_sigframe, info);
+ [/]
+ [# th:if="${#lists.size(config.args) > 2}"]
+ env->[(${config.mainRegisterFile})][ [(${config.args[2]})] ] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ [/]
+ [# th:if="${config.raReg != null}"]
+ env->[(${config.mainRegisterFile})][ [(${config.raReg})] ] = default_rt_sigreturn;
+ [/]
return;
@@ -113,8 +122,8 @@ static void restore_sigcontext(CPU[(${gen_arch_upper})]State *env, struct target
int i;
__get_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
- for (i = 1; i < [(${register_tensors[0].size})]; ++i) {
- __get_user(env->[(${register_tensors[0].name_lower})][i], &sc->gpr[i - 1]);
+ for (i = 1; i < [(${config.mainRegFileSize})]; ++i) {
+ __get_user(env->[(${config.mainRegisterFile})][i], &sc->gpr[i - 1]);
}
}
@@ -140,7 +149,7 @@ long do_rt_sigreturn(CPU[(${gen_arch_upper})]State *env)
struct target_rt_sigframe *frame;
abi_ulong frame_addr;
- frame_addr = env->[(${register_tensors[0].name_lower})][ [(${config.spReg})] ];
+ frame_addr = env->[(${config.mainRegisterFile})][ [(${config.spReg})] ];
trace_user_do_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
diff --git a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
index aacb188f3..a81cf8b5c 100644
--- a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
+++ b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
@@ -40,7 +40,7 @@ public PassName getName() {
@CheckForNull
@Override
public Object execute(PassResults passResults, Specification viam) throws IOException {
- UserModeEmulation ume = UserModeEmulation.createDefault();
+ UserModeEmulation ume = UserModeEmulation.createDummySolution();
viam.add(ume);
return null;
}
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index ca259262d..d7526c100 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -75,16 +75,23 @@ protected Map createVariables(PassResults passResults,
Map.entry("syscallException", ume.getSyscallException().simpleName()),
Map.entry("breakpointExcName", ume.getBreakpointExcName().simpleName()),
Map.entry("illegalInstrExcName", ume.getIllegalInstrExcName().simpleName()),
- Map.entry("ptRegPc", ume.getPtRegPc()),
- Map.entry("ptRegSp", ume.getPtRegSp()),
+ Map.entry("ptRegPc", ume.getPtRegPc().simpleName()),
+ Map.entry("ptRegSp", ume.getPtRegSp().simpleName()),
Map.entry("excCauseVar", ume.getExcCauseVar().simpleName()),
Map.entry("hasIcacheFlush", ume.hasIcacheFlush()),
Map.entry("insn_width_bytes", ume.getInsnWidthBytes()),
Map.entry("stack_align_mask", ume.getStackAlignMask()),
Map.entry("sigtrampLoadSyscallInstr", ume.getSigtrampLoadSyscallInstr()),
Map.entry("sigtrampTrapInstr", ume.getSigtrampTrapInstr()),
- Map.entry("mainRegisterFile", ume.getMainRegisterFile().simpleName().toLowerCase())
- ));
+ Map.entry("mainRegisterFile", ume.getMainRegisterFile().simpleName().toLowerCase()),
+ Map.entry("mainRegFileSize", ume.getMainRegisterFile().outermostDim().size()),
+ Map.entry("signalStateTensors", ume.getSignalStateTensors().stream()
+ .map(t -> Map.of(
+ "name_lower", t.simpleName().toLowerCase(),
+ "size", t.outermostDim().size()
+ ))
+ .toList())
+ ));
return vars;
}
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index c502a0e41..d96020178 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -44,14 +44,15 @@ public class UserModeEmulation extends Definition {
private final RegisterUtils.Register spReg;
private final RegisterUtils.Register raReg;
private final RegisterUtils.Register tpReg;
+ private final List signalStateTensors;
private final List args;
private final Map excIds;
private final Instruction syscallInstr;
private final ExceptionDef syscallException;
private final ExceptionDef breakpointExcName;
private final ExceptionDef illegalInstrExcName;
- private final String ptRegPc;
- private final String ptRegSp;
+ private final Identifier ptRegPc;
+ private final Identifier ptRegSp;
private final boolean hasIcacheFlush;
private final int insnWidthBytes;
private final int stackAlignMask;
@@ -66,16 +67,18 @@ public UserModeEmulation(
RegisterTensor mainRegisterFile,
RegisterUtils.Register sysReg, RegisterUtils.Register retReg,
RegisterUtils.Register spReg, RegisterUtils.Register raReg, RegisterUtils.Register tpReg,
+ List signalStateTensors,
List args, Map excIds,
Instruction syscallInstr, ExceptionDef breakpointExcName,
ExceptionDef illegalInstrExcName,
- String ptRegPc, String ptRegSp, Identifier excCauseVar, boolean hasIcacheFlush,
+ Identifier ptRegPc, Identifier ptRegSp, Identifier excCauseVar, boolean hasIcacheFlush,
int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
int sigtrampTrapInstr) {
super(identifier);
this.syscallException = syscallException;
this.mainRegisterFile = mainRegisterFile;
+ this.signalStateTensors = signalStateTensors;
if (args == null || args.isEmpty()) {
throw new IllegalArgumentException("args must not be null/empty");
}
@@ -109,7 +112,7 @@ public UserModeEmulation(
* pre-configured for the RISC-V architecture.
* * @return a standard RISC-V user-mode emulation setup.
*/
- public static UserModeEmulation createDefault() {
+ public static UserModeEmulation createDummySolution() {
Identifier identifier = new Identifier(new String[]{"ume"},
SourceLocation.INVALID_SOURCE_LOCATION);
@@ -210,18 +213,24 @@ public static UserModeEmulation createDefault() {
"ECALL", 11
);
+ Identifier ptRegsPcField = new Identifier(new String[]{"sepc"},
+ SourceLocation.INVALID_SOURCE_LOCATION);
+ Identifier ptRegsSpField = new Identifier(new String[]{"sp"},
+ SourceLocation.INVALID_SOURCE_LOCATION);
+
+ List signalStateTensors = List.of(mainFile);
return new UserModeEmulation(
identifier,
mockSyscallExc,
mainFile,
sys, ret, sp, ra, tp,
- args,
+ signalStateTensors, args,
excIds,
mockSyscallInsn,
mockBreakpointExc,
mockIllegalExc,
- "sepc", "sp", riscvCauseVar,
+ ptRegsPcField, ptRegsSpField, riscvCauseVar,
true, 4, 0xf,
0x08b00893, 0x00000073
);
@@ -243,11 +252,11 @@ public int getInsnWidthBytes() {
return insnWidthBytes;
}
- public String getPtRegPc() {
+ public Identifier getPtRegPc() {
return ptRegPc;
}
- public String getPtRegSp() {
+ public Identifier getPtRegSp() {
return ptRegSp;
}
@@ -317,4 +326,8 @@ public String toString() {
return simpleName() + " [sysReg=" + sysReg + ", retReg=" + retReg + ", spReg=" + spReg
+ ", raReg=" + raReg + ", tpReg=" + tpReg + ", args=" + args + ", excIds=" + excIds + "]";
}
+
+ public List getSignalStateTensors() {
+ return signalStateTensors;
+ }
}
From 5fde96ba5e486716804e02969a5fa3a88127ee6a Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sat, 9 May 2026 12:37:22 +0200
Subject: [PATCH 17/28] ume: Add ifs for causevar and signal to template #757
---
.../iss/linux-user/gen-arch/cpu_loop.c | 42 ++++++++++++++++++-
.../iss/linux-user/gen-arch/signal.c | 14 ++++---
.../iss/passes/UmeTemplateRenderingPass.java | 8 ++--
vadl/main/vadl/viam/UserModeEmulation.java | 26 ++++++------
4 files changed, 67 insertions(+), 23 deletions(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 1e69f0e90..6797fb7d2 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -51,6 +51,7 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
+ [# th:if="${not #strings.isEmpty(config.excCauseVar)}"]
case [(${gen_arch_upper})]_EXCP_[(${config.syscallException})]:
cause = env->[(${config.excCauseVar})];
switch (cause) {
@@ -100,6 +101,43 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
trapnr);
exit(EXIT_FAILURE);
}
+ [/]
+ [# th:if="${#strings.isEmpty(config.excCauseVar)}"]
+ case [(${gen_arch_upper})]_EXC_[(${config.syscallInstr})]:
+ env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
+ [# th:if="${config.hasIcacheFlush}"]
+ if (env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
+ /* no-op in QEMU; TB invalidation is automatic */
+ ret = 0;
+ } else {
+ [/]
+ ret = do_syscall(env,
+ env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
+ [# th:each="arg : ${config.args}"]
+ env->[(${config.mainRegisterFile})][ [(${arg})] ],
+ [/]
+ 0, 0);
+ [# th:if="${config.hasIcacheFlush}"]
+ }
+ [/]
+ if (ret == -QEMU_ERESTARTSYS) {
+ env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
+ } else if (ret != -QEMU_ESIGRETURN) {
+ env->[(${config.mainRegisterFile})][ [(${config.retReg})] ] = ret; }
+ if (cs->singlestep_enabled) {
+ goto gdbstep;
+ }
+ break;
+
+ case [(${gen_arch_upper})]_EXC_[(${config.illegalInstrExcName})]:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
+ break;
+ case [(${gen_arch_upper})]_EXC_[(${config.breakpointExcName})]:
+ case EXCP_DEBUG:
+ gdbstep:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
+ break;
+ [/]
process_pending_signals(env);
}
@@ -111,8 +149,8 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
TaskState *ts = get_task_state(cpu);
struct image_info *info = ts->info;
- env->[(${pc_reg.name_lower})] = regs->[(${config.ptRegPc})];
- env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = regs->[(${config.ptRegSp})];
+ env->[(${pc_reg.name_lower})] = regs->[(${config.initialPc})];
+ env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = regs->[(${config.initalSp})];
ts->stack_base = info->start_stack;
}
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
index 5b063bc13..cd085a196 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
@@ -55,9 +55,11 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPU[(${gen_arch_upper
int i;
__put_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
- for (i = 1; i < [(${config.mainRegFileSize})]; i++) {
- __put_user(env->[(${config.mainRegisterFile})][i], &sc->gpr[i - 1]);
- }
+ [# th:each="tensor : ${config.signalStateTensors}"]
+ for (i = 0; i < [(${tensor.size})]; i++) {
+ __put_user(env->[(${tensor.name_lower})][i], &sc->[(${tensor.name_lower})][i]);
+ }
+ [/]
}
static void setup_ucontext(struct target_ucontext *uc,
@@ -122,9 +124,11 @@ static void restore_sigcontext(CPU[(${gen_arch_upper})]State *env, struct target
int i;
__get_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
- for (i = 1; i < [(${config.mainRegFileSize})]; ++i) {
- __get_user(env->[(${config.mainRegisterFile})][i], &sc->gpr[i - 1]);
+ [# th:each="tensor : ${config.signalStateTensors}"]
+ for (i = 0; i < [(${tensor.size})]; i++) {
+ __get_user(env->[(${tensor.name_lower})][i], &sc->[(${tensor.name_lower})][i]);
}
+ [/]
}
static void restore_ucontext(CPU[(${gen_arch_upper})]State *env, struct target_ucontext *uc)
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index d7526c100..87712d3fe 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -75,9 +75,11 @@ protected Map createVariables(PassResults passResults,
Map.entry("syscallException", ume.getSyscallException().simpleName()),
Map.entry("breakpointExcName", ume.getBreakpointExcName().simpleName()),
Map.entry("illegalInstrExcName", ume.getIllegalInstrExcName().simpleName()),
- Map.entry("ptRegPc", ume.getPtRegPc().simpleName()),
- Map.entry("ptRegSp", ume.getPtRegSp().simpleName()),
- Map.entry("excCauseVar", ume.getExcCauseVar().simpleName()),
+ Map.entry("initialPc", ume.getInitialPc().simpleName()),
+ Map.entry("initialSp", ume.getInitialSp().simpleName()),
+ Map.entry("excCauseVar", ume.getExcCauseVar() != null
+ ? ume.getExcCauseVar().simpleName()
+ : ""),
Map.entry("hasIcacheFlush", ume.hasIcacheFlush()),
Map.entry("insn_width_bytes", ume.getInsnWidthBytes()),
Map.entry("stack_align_mask", ume.getStackAlignMask()),
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index d96020178..2109cd05c 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -51,8 +51,8 @@ public class UserModeEmulation extends Definition {
private final ExceptionDef syscallException;
private final ExceptionDef breakpointExcName;
private final ExceptionDef illegalInstrExcName;
- private final Identifier ptRegPc;
- private final Identifier ptRegSp;
+ private final Identifier initialPc;
+ private final Identifier initialSp;
private final boolean hasIcacheFlush;
private final int insnWidthBytes;
private final int stackAlignMask;
@@ -71,9 +71,10 @@ public UserModeEmulation(
List args, Map excIds,
Instruction syscallInstr, ExceptionDef breakpointExcName,
ExceptionDef illegalInstrExcName,
- Identifier ptRegPc, Identifier ptRegSp, Identifier excCauseVar, boolean hasIcacheFlush,
+ Identifier initialPc, Identifier initialSp, Identifier excCauseVar, boolean hasIcacheFlush,
int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
- int sigtrampTrapInstr) {
+ int sigtrampTrapInstr
+ ) {
super(identifier);
this.syscallException = syscallException;
@@ -97,8 +98,8 @@ public UserModeEmulation(
this.syscallInstr = syscallInstr;
this.breakpointExcName = breakpointExcName;
this.illegalInstrExcName = illegalInstrExcName;
- this.ptRegPc = ptRegPc;
- this.ptRegSp = ptRegSp;
+ this.initialPc = initialPc;
+ this.initialSp = initialSp;
this.excCauseVar = excCauseVar;
this.hasIcacheFlush = hasIcacheFlush;
this.insnWidthBytes = insnWidthBytes;
@@ -204,7 +205,7 @@ public static UserModeEmulation createDummySolution() {
);
- Identifier riscvCauseVar = new Identifier(new String[]{"cause"},
+ Identifier riscvCauseVar = new Identifier(new String[]{"arg_exc_cause"},
SourceLocation.INVALID_SOURCE_LOCATION);
Map excIds = Map.of(
@@ -232,8 +233,7 @@ public static UserModeEmulation createDummySolution() {
mockIllegalExc,
ptRegsPcField, ptRegsSpField, riscvCauseVar,
true, 4, 0xf,
- 0x08b00893, 0x00000073
- );
+ 0x08b00893, 0x00000073);
}
public int getSigtrampLoadSyscallInstr() {
@@ -252,12 +252,12 @@ public int getInsnWidthBytes() {
return insnWidthBytes;
}
- public Identifier getPtRegPc() {
- return ptRegPc;
+ public Identifier getInitialPc() {
+ return initialPc;
}
- public Identifier getPtRegSp() {
- return ptRegSp;
+ public Identifier getInitialSp() {
+ return initialSp;
}
public Identifier getExcCauseVar() {
From dcb384784f709ef9c3c0babf53a731a4a90485b9 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 17 May 2026 21:44:08 +0200
Subject: [PATCH 18/28] ume: Refactor UME definitions #757
---
.../iss/linux-user/gen-arch/cpu_loop.c | 56 +---
.../iss/linux-user/gen-arch/signal.c | 171 +---------
.../iss/linux-user/gen-arch/target_cpu.h | 6 +-
.../UmeHardcodedRiscvDefinitionPass.java | 148 ++++++++-
.../iss/passes/UmeTemplateRenderingPass.java | 61 ++--
vadl/main/vadl/viam/UserModeEmulation.java | 291 ++----------------
6 files changed, 225 insertions(+), 508 deletions(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 6797fb7d2..9deed0ef8 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -51,27 +51,17 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
- [# th:if="${not #strings.isEmpty(config.excCauseVar)}"]
case [(${gen_arch_upper})]_EXCP_[(${config.syscallException})]:
cause = env->[(${config.excCauseVar})];
switch (cause) {
case [(${gen_arch_upper})]_EXC_[(${config.syscallInstr})]:
env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
- [# th:if="${config.hasIcacheFlush}"]
- if (env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
- /* no-op in QEMU; TB invalidation is automatic */
- ret = 0;
- } else {
- [/]
ret = do_syscall(env,
env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
[# th:each="arg : ${config.args}"]
env->[(${config.mainRegisterFile})][ [(${arg})] ],
[/]
0, 0);
- [# th:if="${config.hasIcacheFlush}"]
- }
- [/]
if (ret == -QEMU_ERESTARTSYS) {
env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
} else if (ret != -QEMU_ESIGRETURN) {
@@ -81,10 +71,10 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
}
break;
- case [(${gen_arch_upper})]_EXC_[(${config.illegalInstrExcName})]:
+ case [(${gen_arch_upper})]_EXC_[(${config.illegalInstrExc})]:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
break;
- case [(${gen_arch_upper})]_EXC_[(${config.breakpointExcName})]:
+ case [(${gen_arch_upper})]_EXC_[(${config.breakpointExc})]:
case EXCP_DEBUG:
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
@@ -101,44 +91,6 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
trapnr);
exit(EXIT_FAILURE);
}
- [/]
- [# th:if="${#strings.isEmpty(config.excCauseVar)}"]
- case [(${gen_arch_upper})]_EXC_[(${config.syscallInstr})]:
- env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
- [# th:if="${config.hasIcacheFlush}"]
- if (env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
- /* no-op in QEMU; TB invalidation is automatic */
- ret = 0;
- } else {
- [/]
- ret = do_syscall(env,
- env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
- [# th:each="arg : ${config.args}"]
- env->[(${config.mainRegisterFile})][ [(${arg})] ],
- [/]
- 0, 0);
- [# th:if="${config.hasIcacheFlush}"]
- }
- [/]
- if (ret == -QEMU_ERESTARTSYS) {
- env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
- } else if (ret != -QEMU_ESIGRETURN) {
- env->[(${config.mainRegisterFile})][ [(${config.retReg})] ] = ret; }
- if (cs->singlestep_enabled) {
- goto gdbstep;
- }
- break;
-
- case [(${gen_arch_upper})]_EXC_[(${config.illegalInstrExcName})]:
- force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
- break;
- case [(${gen_arch_upper})]_EXC_[(${config.breakpointExcName})]:
- case EXCP_DEBUG:
- gdbstep:
- force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
- break;
- [/]
-
process_pending_signals(env);
}
}
@@ -149,8 +101,8 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
TaskState *ts = get_task_state(cpu);
struct image_info *info = ts->info;
- env->[(${pc_reg.name_lower})] = regs->[(${config.initialPc})];
- env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = regs->[(${config.initalSp})];
+ env->[(${pc_reg.name_lower})] = regs->[(${pc_reg.name_lower})];
+ env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = regs->[(${config.spRegName})];
ts->stack_base = info->start_stack;
}
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
index cd085a196..63d649e7a 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
@@ -1,184 +1,33 @@
-/*
- * Emulation of Linux signals for [(${gen_arch_lower})] user-mode.
- */
-
#include "qemu/osdep.h"
#include "qemu.h"
#include "user-internals.h"
#include "signal-common.h"
-#include "linux-user/trace.h"
-
-/*
- * Minimal sigcontext matching [(${gen_arch_lower})] state:
- * - pc
- * - x1..x31 (x0 is always zero and omitted)
- */
-struct target_sigcontext {
- abi_long [(${pc_reg.name_lower})];
-
- [# th:each="tensor : ${config.signalStateTensors}"]
- abi_long [(${tensor.name_lower})][ [(${tensor.size})] ];
- [/]
-};
-
-struct target_ucontext {
- abi_ulong uc_flags;
- abi_ptr uc_link;
- target_stack_t uc_stack;
- target_sigset_t uc_sigmask;
- uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)];
- struct target_sigcontext uc_mcontext QEMU_ALIGNED(16);
-};
-
-struct target_rt_sigframe {
- struct target_siginfo info;
- struct target_ucontext uc;
-};
-
-static abi_ulong get_sigframe(struct target_sigaction *ka,
- CPU[(${gen_arch_upper})]State *regs, size_t framesize)
-{
- abi_ulong sp = get_sp_from_cpustate(regs);
-
- if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) {
- return -1L;
- }
-
- sp = target_sigsp(sp, ka) - framesize;
- sp &= ~[(${config.stack_align_mask} ?: '0xf')];
-
- return sp;
-}
-
-static void setup_sigcontext(struct target_sigcontext *sc, CPU[(${gen_arch_upper})]State *env)
-{
- int i;
-
- __put_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
- [# th:each="tensor : ${config.signalStateTensors}"]
- for (i = 0; i < [(${tensor.size})]; i++) {
- __put_user(env->[(${tensor.name_lower})][i], &sc->[(${tensor.name_lower})][i]);
- }
- [/]
-}
-
-static void setup_ucontext(struct target_ucontext *uc,
- CPU[(${gen_arch_upper})]State *env, target_sigset_t *set)
-{
- int i;
-
- __put_user(0, &(uc->uc_flags));
- __put_user(0, &(uc->uc_link));
-
- target_save_altstack(&uc->uc_stack, env);
-
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &(uc->uc_sigmask.sig[i]));
- }
-
- setup_sigcontext(&uc->uc_mcontext, env);
-}
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPU[(${gen_arch_upper})]State *env)
{
- abi_ulong frame_addr;
- struct target_rt_sigframe *frame;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
+ (void)ka;
+ (void)info;
+ (void)set;
+ (void)env;
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto badframe;
- }
-
- setup_ucontext(&frame->uc, env, set);
- frame->info = *info;
-
- env->[(${pc_reg.name_lower})] = ka->_sa_handler;
- env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = frame_addr;
- env->[(${config.mainRegisterFile})][ [(${config.args[0]})] ] = sig;
- [# th:if="${#lists.size(config.args) > 1}"]
- env->[(${config.mainRegisterFile})][ [(${config.args[1]})] ] = frame_addr + offsetof(struct target_rt_sigframe, info);
- [/]
- [# th:if="${#lists.size(config.args) > 2}"]
- env->[(${config.mainRegisterFile})][ [(${config.args[2]})] ] = frame_addr + offsetof(struct target_rt_sigframe, uc);
- [/]
- [# th:if="${config.raReg != null}"]
- env->[(${config.mainRegisterFile})][ [(${config.raReg})] ] = default_rt_sigreturn;
- [/]
-
- return;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 1);
if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
+ force_sig(TARGET_SIGSEGV);
+ } else {
+ force_sig(sig);
}
- force_sig(TARGET_SIGSEGV);
-}
-
-static void restore_sigcontext(CPU[(${gen_arch_upper})]State *env, struct target_sigcontext *sc)
-{
- int i;
-
- __get_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
- [# th:each="tensor : ${config.signalStateTensors}"]
- for (i = 0; i < [(${tensor.size})]; i++) {
- __get_user(env->[(${tensor.name_lower})][i], &sc->[(${tensor.name_lower})][i]);
- }
- [/]
-}
-
-static void restore_ucontext(CPU[(${gen_arch_upper})]State *env, struct target_ucontext *uc)
-{
- sigset_t blocked;
- target_sigset_t target_set;
- int i;
-
- target_sigemptyset(&target_set);
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &(uc->uc_sigmask.sig[i]));
- }
-
- target_to_host_sigset_internal(&blocked, &target_set);
- set_sigmask(&blocked);
-
- restore_sigcontext(env, &uc->uc_mcontext);
}
long do_rt_sigreturn(CPU[(${gen_arch_upper})]State *env)
{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
-
- frame_addr = env->[(${config.mainRegisterFile})][ [(${config.spReg})] ];
- trace_user_do_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- restore_ucontext(env, &frame->uc);
- target_restore_altstack(&frame->uc.uc_stack, env);
-
- unlock_user_struct(frame, frame_addr, 0);
- return -QEMU_ESIGRETURN;
+ (void)env;
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
return 0;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
- uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
- assert(tramp != NULL);
-
- __put_user([(${config.sigtrampLoadSyscallInstr})], tramp + 0); /* load rt_sigreturn syscall number */
- __put_user([(${config.sigtrampTrapInstr})], tramp + 1); /* syscall/trap instruction */
-
- default_rt_sigreturn = sigtramp_page;
- unlock_user(tramp, sigtramp_page, 8);
-}
+ (void)sigtramp_page;
+}
\ No newline at end of file
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
index 6f0363942..ccfd828f8 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
@@ -1,11 +1,11 @@
#ifndef [(${gen_arch_upper})]_TARGET_CPU_H
#define [(${gen_arch_upper})]_TARGET_CPU_H
-//TODO: check for correct interpolattions for regs & values
+//TODO: check for correct interpolations for regs & values
enum {
- [(${gen_arch_upper})]_REG_RA = [(${config.raReg})],
+ [(${gen_arch_upper})]_REG_RA = 1,
[(${gen_arch_upper})]_REG_SP = [(${config.spReg})],
- [(${gen_arch_upper})]_REG_TP = [(${config.tpReg})],
+ [(${gen_arch_upper})]_REG_TP = 4,
[# th:each="arg, stat : ${config.args}"]
[(${gen_arch_upper})]_REG_ARG[(${stat.index})] = [(${arg})],
diff --git a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
index a81cf8b5c..4637ea9bc 100644
--- a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
+++ b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
@@ -17,12 +17,33 @@
package vadl.iss.passes;
import java.io.IOException;
-import javax.annotation.CheckForNull;
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.IntStream;
+import javax.annotation.Nullable;
import vadl.configuration.IssConfiguration;
+import vadl.lcb.templateUtils.RegisterUtils;
import vadl.pass.PassName;
import vadl.pass.PassResults;
+import vadl.types.BitsType;
+import vadl.types.Type;
+import vadl.utils.Pair;
+import vadl.utils.SourceLocation;
+import vadl.viam.Abi;
+import vadl.viam.Assembly;
+import vadl.viam.Encoding;
+import vadl.viam.ExceptionDef;
+import vadl.viam.Format;
+import vadl.viam.Function;
+import vadl.viam.Identifier;
+import vadl.viam.Instruction;
+import vadl.viam.InstructionSetArchitecture;
+import vadl.viam.Parameter;
+import vadl.viam.RegisterResource;
+import vadl.viam.RegisterTensor;
import vadl.viam.Specification;
import vadl.viam.UserModeEmulation;
+import vadl.viam.graph.Graph;
/**
* A specialized hardcoded rendering pass for QEMU User-Mode Emulation (UME) source files.
@@ -37,11 +58,132 @@ public PassName getName() {
return PassName.of("UME Hardcoded RISC-V Definition");
}
- @CheckForNull
+ @Nullable
@Override
public Object execute(PassResults passResults, Specification viam) throws IOException {
- UserModeEmulation ume = UserModeEmulation.createDummySolution();
+ if (!"rv64ume".equals(viam.simpleName())) {
+ return null;
+ }
+
+ InstructionSetArchitecture isa = viam.isa()
+ .orElseThrow(() -> new IllegalStateException("ISA not found in " + viam.simpleName()));
+
+ Abi abi = viam.abi()
+ .orElseThrow(() -> new IllegalStateException("ABI not found in " + viam.simpleName()));
+
+ UserModeEmulation ume = createDummySolution(abi, isa);
viam.add(ume);
return null;
}
+
+ /**
+ * Creates a default {@link UserModeEmulation} configuration,
+ * pre-configured for the RISC-V architecture.
+ * * @return a standard RISC-V user-mode emulation setup.
+ */
+ public static UserModeEmulation createDummySolution(Abi abi, InstructionSetArchitecture isa) {
+ Identifier identifier = new Identifier(new String[]{"ume"},
+ SourceLocation.INVALID_SOURCE_LOCATION);
+
+ RegisterTensor.Dimension regDim = new RegisterTensor.Dimension(
+ 0,
+ Type.bits(5),
+ 32
+ );
+
+ RegisterTensor.Dimension dummyDim = new RegisterTensor.Dimension(
+ 1,
+ Type.bits(1),
+ 1
+ );
+
+ List dimensions = List.of(regDim, dummyDim);
+ RegisterTensor mainFile = new RegisterTensor(
+ new Identifier(new String[]{"x"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ dimensions
+ );
+
+ var dummyMap = new HashMap, List>();
+
+ RegisterUtils.RegisterClass gprClass = RegisterUtils.getRegisterClass(mainFile, dummyMap);
+
+ List args = IntStream.range(10, 16)
+ .mapToObj(i -> gprClass.registers().get(i))
+ .toList();
+
+ Parameter[] emptyParams = new Parameter[0];
+ Graph emptyGraph = new Graph("empty_graph");
+
+ ExceptionDef mockSyscallExc = new ExceptionDef(
+ new Identifier(new String[]{"EXC"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ emptyParams,
+ emptyGraph,
+ ExceptionDef.Kind.DECLARED
+ );
+
+ ExceptionDef mockBreakpointExc = new ExceptionDef(
+ new Identifier(new String[]{"BREAKPOINT"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ emptyParams,
+ emptyGraph,
+ ExceptionDef.Kind.DECLARED
+ );
+
+ ExceptionDef mockIllegalExc = new ExceptionDef(
+ new Identifier(new String[]{"ILLEGAL_INSTR"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ emptyParams,
+ emptyGraph,
+ ExceptionDef.Kind.DECLARED
+ );
+
+ BitsType mockType = BitsType.bits(32);
+
+ Function mockFunc = new Function(
+ new Identifier(new String[]{"dummy_function"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ new Parameter[0],
+ Type.string(),
+ emptyGraph
+ );
+
+ Assembly emptyAssembly = new Assembly(new Identifier(new String[]{"dummy_assembly"},
+ SourceLocation.INVALID_SOURCE_LOCATION), mockFunc);
+
+ Format dummyFormat = new Format(new Identifier(new String[]{"dummy_format"},
+ SourceLocation.INVALID_SOURCE_LOCATION), mockType);
+
+ Encoding emptyEncoding = new Encoding(
+ new Identifier(new String[]{"dummy_encoding"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ dummyFormat, new Encoding.Field[0]);
+
+ Instruction mockSyscallInsn = new Instruction(
+ new Identifier(new String[]{"ECALL"},
+ SourceLocation.INVALID_SOURCE_LOCATION),
+ emptyGraph, emptyAssembly, emptyEncoding
+ );
+
+ RegisterTensor mainRegFile = (RegisterTensor) abi.stackPointer().registerFile();
+
+ SourceLocation loc = SourceLocation.INVALID_SOURCE_LOCATION;
+ Abi.Alignment align = Abi.Alignment.DEFAULT;
+
+ Abi.RegisterRef spReg = new Abi.RegisterRef(mainRegFile, 2, align, loc);
+
+ Abi.RegisterRef sysReg = new Abi.RegisterRef(mainRegFile, 17, align, loc);
+
+ Abi.RegisterRef retReg = new Abi.RegisterRef(mainRegFile, 10, align, loc);
+
+ return new UserModeEmulation(
+ identifier,
+ isa, abi,
+ mockSyscallExc, args,
+ mockSyscallInsn,
+ mockBreakpointExc,
+ mockIllegalExc);
+ }
+
}
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index 87712d3fe..1037adc65 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -22,6 +22,8 @@
import vadl.lcb.templateUtils.RegisterUtils;
import vadl.pass.PassName;
import vadl.pass.PassResults;
+import vadl.viam.Abi;
+import vadl.viam.RegisterTensor;
import vadl.viam.Specification;
import vadl.viam.UserModeEmulation;
@@ -61,39 +63,38 @@ protected Map createVariables(PassResults passResults,
UserModeEmulation ume = specification.userModeEmulation()
.orElseThrow(() -> new IllegalStateException("No UserModeEmulation defined"));
+ Abi abi = ume.abi();
+ RegisterTensor mainRegFile = (RegisterTensor) abi.stackPointer().registerFile();
+
+ Map excIds = Map.of(
+ "RV64UME_EXC_ILLEGAL_INSTR", 2,
+ "RV64UME_EXC_ECALL", 11,
+ "RV64UME_EXC_BREAKPOINT", 3
+ );
+
vars.put("config", Map.ofEntries(
- Map.entry("sysReg", ume.getSysReg().index()),
- Map.entry("retReg", ume.getRetReg().index()),
- Map.entry("spReg", ume.getSpReg().index()),
- Map.entry("raReg", ume.getRaReg().index()),
- Map.entry("tpReg", ume.getTpReg().index()),
- Map.entry("args", ume.getArgs().stream()
+ Map.entry("sysReg", abi.stackPointer()),
+ Map.entry("retReg", abi.returnRegisters().get(0).get(0).addr()),
+ Map.entry("spReg", abi.stackPointer().addr()),
+ Map.entry("spRegName", abi.stackPointer().render()),
+ Map.entry("args", ume.args().stream()
.map(RegisterUtils.Register::index)
.toList()),
- Map.entry("excIds", ume.getExcIds()),
- Map.entry("syscallInstr", ume.getSyscallInstr().simpleName()),
- Map.entry("syscallException", ume.getSyscallException().simpleName()),
- Map.entry("breakpointExcName", ume.getBreakpointExcName().simpleName()),
- Map.entry("illegalInstrExcName", ume.getIllegalInstrExcName().simpleName()),
- Map.entry("initialPc", ume.getInitialPc().simpleName()),
- Map.entry("initialSp", ume.getInitialSp().simpleName()),
- Map.entry("excCauseVar", ume.getExcCauseVar() != null
- ? ume.getExcCauseVar().simpleName()
- : ""),
- Map.entry("hasIcacheFlush", ume.hasIcacheFlush()),
- Map.entry("insn_width_bytes", ume.getInsnWidthBytes()),
- Map.entry("stack_align_mask", ume.getStackAlignMask()),
- Map.entry("sigtrampLoadSyscallInstr", ume.getSigtrampLoadSyscallInstr()),
- Map.entry("sigtrampTrapInstr", ume.getSigtrampTrapInstr()),
- Map.entry("mainRegisterFile", ume.getMainRegisterFile().simpleName().toLowerCase()),
- Map.entry("mainRegFileSize", ume.getMainRegisterFile().outermostDim().size()),
- Map.entry("signalStateTensors", ume.getSignalStateTensors().stream()
- .map(t -> Map.of(
- "name_lower", t.simpleName().toLowerCase(),
- "size", t.outermostDim().size()
- ))
- .toList())
- ));
+ Map.entry("excIds", excIds),
+ Map.entry("syscallInstr", ume.syscallInstr().simpleName()),
+ Map.entry("syscallException", ume.syscallException().simpleName()),
+ Map.entry(
+ "breakpointExc",
+ ume.breakpointExc() != null ? ume.breakpointExc().simpleName() : ""
+ ),
+ Map.entry(
+ "IllegalInstrExc",
+ ume.illegalInstrExc() != null ? ume.illegalInstrExc().simpleName() : ""
+ ),
+ Map.entry("insn_width_bytes", ume.syscallInstr().format().type().bitWidth() / 8),
+ Map.entry("mainRegisterFile", mainRegFile.simpleName().toLowerCase()),
+ Map.entry("mainRegFileSize", mainRegFile.outermostDim().size())
+ ));
return vars;
}
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index 2109cd05c..91b08ca30 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -16,16 +16,9 @@
package vadl.viam;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.stream.IntStream;
+import javax.annotation.Nullable;
import vadl.lcb.templateUtils.RegisterUtils;
-import vadl.types.BitsType;
-import vadl.types.Type;
-import vadl.utils.Pair;
-import vadl.utils.SourceLocation;
-import vadl.viam.graph.Graph;
/**
* Represents the configuration for QEMU user-mode emulation.
@@ -37,285 +30,69 @@
*/
public class UserModeEmulation extends Definition {
- private final Identifier excCauseVar;
- private final RegisterTensor mainRegisterFile;
- private final RegisterUtils.Register sysReg;
- private final RegisterUtils.Register retReg;
- private final RegisterUtils.Register spReg;
- private final RegisterUtils.Register raReg;
- private final RegisterUtils.Register tpReg;
- private final List signalStateTensors;
+ private final InstructionSetArchitecture isa;
+ private final Abi abi;
+
private final List args;
- private final Map excIds;
private final Instruction syscallInstr;
private final ExceptionDef syscallException;
- private final ExceptionDef breakpointExcName;
- private final ExceptionDef illegalInstrExcName;
- private final Identifier initialPc;
- private final Identifier initialSp;
- private final boolean hasIcacheFlush;
- private final int insnWidthBytes;
- private final int stackAlignMask;
- private final int sigtrampLoadSyscallInstr;
- private final int sigtrampTrapInstr;
+ @Nullable
+ private final ExceptionDef breakpointExc;
+ @Nullable
+ private final ExceptionDef illegalInstrExc;
/**
* Constructs a UserModeEmulation configuration.
*/
public UserModeEmulation(
- Identifier identifier, ExceptionDef syscallException,
- RegisterTensor mainRegisterFile,
- RegisterUtils.Register sysReg, RegisterUtils.Register retReg,
- RegisterUtils.Register spReg, RegisterUtils.Register raReg, RegisterUtils.Register tpReg,
- List signalStateTensors,
- List args, Map excIds,
- Instruction syscallInstr, ExceptionDef breakpointExcName,
- ExceptionDef illegalInstrExcName,
- Identifier initialPc, Identifier initialSp, Identifier excCauseVar, boolean hasIcacheFlush,
- int insnWidthBytes, int stackAlignMask, int sigtrampLoadSyscallInstr,
- int sigtrampTrapInstr
+ Identifier identifier, InstructionSetArchitecture isa, Abi abi, ExceptionDef syscallException,
+ List args,
+ Instruction syscallInstr, ExceptionDef breakpointExc,
+ ExceptionDef illegalInstrExc
) {
super(identifier);
+ this.isa = isa;
+ this.abi = abi;
this.syscallException = syscallException;
- this.mainRegisterFile = mainRegisterFile;
- this.signalStateTensors = signalStateTensors;
- if (args == null || args.isEmpty()) {
- throw new IllegalArgumentException("args must not be null/empty");
- }
-
- if (excIds == null || excIds.isEmpty()) {
- throw new IllegalArgumentException("excIds must not be null/empty");
- }
- this.sysReg = sysReg;
- this.retReg = retReg;
- this.spReg = spReg;
- this.raReg = raReg;
- this.tpReg = tpReg;
this.args = args;
- this.excIds = excIds;
this.syscallInstr = syscallInstr;
- this.breakpointExcName = breakpointExcName;
- this.illegalInstrExcName = illegalInstrExcName;
- this.initialPc = initialPc;
- this.initialSp = initialSp;
- this.excCauseVar = excCauseVar;
- this.hasIcacheFlush = hasIcacheFlush;
- this.insnWidthBytes = insnWidthBytes;
- this.stackAlignMask = stackAlignMask;
- this.sigtrampLoadSyscallInstr = sigtrampLoadSyscallInstr;
- this.sigtrampTrapInstr = sigtrampTrapInstr;
- }
-
- /**
- * Creates a default {@link UserModeEmulation} configuration,
- * pre-configured for the RISC-V architecture.
- * * @return a standard RISC-V user-mode emulation setup.
- */
- public static UserModeEmulation createDummySolution() {
- Identifier identifier = new Identifier(new String[]{"ume"},
- SourceLocation.INVALID_SOURCE_LOCATION);
-
- RegisterTensor.Dimension regDim = new RegisterTensor.Dimension(
- 0,
- Type.bits(5),
- 32
- );
-
- RegisterTensor.Dimension dummyDim = new RegisterTensor.Dimension(
- 1,
- Type.bits(1),
- 1
- );
-
- List dimensions = List.of(regDim, dummyDim);
- RegisterTensor mainFile = new RegisterTensor(
- new Identifier(new String[]{"x"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- dimensions
- );
-
- var dummyMap = new HashMap, List>();
-
- RegisterUtils.RegisterClass gprClass = RegisterUtils.getRegisterClass(mainFile, dummyMap);
-
- RegisterUtils.Register sp = gprClass.registers().get(2);
- RegisterUtils.Register ra = gprClass.registers().get(1);
- RegisterUtils.Register tp = gprClass.registers().get(4);
- RegisterUtils.Register sys = gprClass.registers().get(17);
- RegisterUtils.Register ret = gprClass.registers().get(10);
-
- List args = IntStream.range(10, 16)
- .mapToObj(i -> gprClass.registers().get(i))
- .toList();
-
- Parameter[] emptyParams = new Parameter[0];
- Graph emptyGraph = new Graph("empty_graph");
-
- ExceptionDef mockSyscallExc = new ExceptionDef(
- new Identifier(new String[]{"EXC"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- emptyParams,
- emptyGraph,
- ExceptionDef.Kind.DECLARED
- );
-
- ExceptionDef mockBreakpointExc = new ExceptionDef(
- new Identifier(new String[]{"BREAKPOINT"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- emptyParams,
- emptyGraph,
- ExceptionDef.Kind.DECLARED
- );
-
- ExceptionDef mockIllegalExc = new ExceptionDef(
- new Identifier(new String[]{"ILLEGAL_INSTR"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- emptyParams,
- emptyGraph,
- ExceptionDef.Kind.DECLARED
- );
-
- BitsType mockType = BitsType.bits(32);
-
- Function mockFunc = new Function(
- new Identifier(new String[]{"dummy_function"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- new Parameter[0],
- Type.string(),
- emptyGraph
- );
-
- Assembly emptyAssembly = new Assembly(new Identifier(new String[]{"dummy_assembly"},
- SourceLocation.INVALID_SOURCE_LOCATION), mockFunc);
-
- Format dummyFormat = new Format(new Identifier(new String[]{"dummy_format"},
- SourceLocation.INVALID_SOURCE_LOCATION), mockType);
-
- Encoding emptyEncoding = new Encoding(
- new Identifier(new String[]{"dummy_encoding"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- dummyFormat, new Encoding.Field[0]);
-
- Instruction mockSyscallInsn = new Instruction(
- new Identifier(new String[]{"ECALL"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- emptyGraph, emptyAssembly, emptyEncoding
- );
-
-
- Identifier riscvCauseVar = new Identifier(new String[]{"arg_exc_cause"},
- SourceLocation.INVALID_SOURCE_LOCATION);
-
- Map excIds = Map.of(
- "ILLEGAL_INSTR", 2,
- "BREAKPOINT", 3,
- "ECALL", 11
- );
-
- Identifier ptRegsPcField = new Identifier(new String[]{"sepc"},
- SourceLocation.INVALID_SOURCE_LOCATION);
- Identifier ptRegsSpField = new Identifier(new String[]{"sp"},
- SourceLocation.INVALID_SOURCE_LOCATION);
-
- List signalStateTensors = List.of(mainFile);
-
- return new UserModeEmulation(
- identifier,
- mockSyscallExc,
- mainFile,
- sys, ret, sp, ra, tp,
- signalStateTensors, args,
- excIds,
- mockSyscallInsn,
- mockBreakpointExc,
- mockIllegalExc,
- ptRegsPcField, ptRegsSpField, riscvCauseVar,
- true, 4, 0xf,
- 0x08b00893, 0x00000073);
+ this.breakpointExc = breakpointExc;
+ this.illegalInstrExc = illegalInstrExc;
}
- public int getSigtrampLoadSyscallInstr() {
- return sigtrampLoadSyscallInstr;
- }
-
- public int getSigtrampTrapInstr() {
- return sigtrampTrapInstr;
- }
-
- public int getStackAlignMask() {
- return stackAlignMask;
- }
-
- public int getInsnWidthBytes() {
- return insnWidthBytes;
- }
-
- public Identifier getInitialPc() {
- return initialPc;
- }
-
- public Identifier getInitialSp() {
- return initialSp;
- }
-
- public Identifier getExcCauseVar() {
- return excCauseVar;
- }
-
- public boolean hasIcacheFlush() {
- return hasIcacheFlush;
- }
-
- public Instruction getSyscallInstr() {
+ public Instruction syscallInstr() {
return syscallInstr;
}
- public ExceptionDef getBreakpointExcName() {
- return breakpointExcName;
+ @Nullable
+ public ExceptionDef breakpointExc() {
+ return breakpointExc;
}
- public ExceptionDef getIllegalInstrExcName() {
- return illegalInstrExcName;
+ @Nullable
+ public ExceptionDef illegalInstrExc() {
+ return illegalInstrExc;
}
- public RegisterUtils.Register getSysReg() {
- return sysReg;
- }
-
- public RegisterUtils.Register getRetReg() {
- return retReg;
- }
-
- public RegisterUtils.Register getSpReg() {
- return spReg;
- }
-
- public RegisterUtils.Register getRaReg() {
- return raReg;
- }
-
- public RegisterUtils.Register getTpReg() {
- return tpReg;
- }
-
- public List getArgs() {
+ public List args() {
return args;
}
- public Map getExcIds() {
- return excIds;
+ public ExceptionDef syscallException() {
+ return syscallException;
}
- public ExceptionDef getSyscallException() {
- return syscallException;
+ public InstructionSetArchitecture isa() {
+ return isa;
}
- public RegisterTensor getMainRegisterFile() {
- return mainRegisterFile;
+ public Abi abi() {
+ return abi;
}
+
@Override
public void accept(DefinitionVisitor visitor) {
visitor.visit(this);
@@ -323,11 +100,7 @@ public void accept(DefinitionVisitor visitor) {
@Override
public String toString() {
- return simpleName() + " [sysReg=" + sysReg + ", retReg=" + retReg + ", spReg=" + spReg
- + ", raReg=" + raReg + ", tpReg=" + tpReg + ", args=" + args + ", excIds=" + excIds + "]";
+ return simpleName() + " [args=" + args + "]";
}
- public List getSignalStateTensors() {
- return signalStateTensors;
- }
}
From daec0b8e5edc5403727cc1b1e38f9e809deb20ba Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Wed, 27 May 2026 00:15:23 +0200
Subject: [PATCH 19/28] ume: Add UME section to vadl file, remove exceptions
from cpuloop #757
---
sys/risc-v/rv64ume.vadl | 26 ++++++++++
.../iss/linux-user/gen-arch/cpu_loop.c | 50 +++++++------------
.../UmeHardcodedRiscvDefinitionPass.java | 11 ----
.../iss/passes/UmeTemplateRenderingPass.java | 8 +--
4 files changed, 47 insertions(+), 48 deletions(-)
diff --git a/sys/risc-v/rv64ume.vadl b/sys/risc-v/rv64ume.vadl
index 14653d305..040678e60 100644
--- a/sys/risc-v/rv64ume.vadl
+++ b/sys/risc-v/rv64ume.vadl
@@ -4,6 +4,32 @@ import rv64csr::{ RV64IMZicsr }
instruction set architecture RV64UME extending RV64IMZicsr = {}
+application binary interface ABI for RV64UME = {
+ alias register a0 = X(10)
+ alias register a1 = X(11)
+ alias register a2 = X(12)
+ alias register a3 = X(13)
+ alias register a4 = X(14)
+ alias register a5 = X(15)
+ alias register a7 = X(17)
+ alias register sp = X(2)
+ alias register ra = X(1)
+
+ return address = ra
+ stack pointer = sp
+ return value = a0
+ frame pointer = X(8)
+ function argument = a{0..5}
+ caller saved = [ a{0..5} ]
+ callee saved = [ X(1) ]
+ special absolute address load instruction = LA
+ return value = a{0..1}
+
+ special return instruction = RET
+ special call instruction = CALL
+ special local address load instruction = LLA
+ special global address load instruction = LGA_64
+}
// This is the system-mode entry point.
// Once we have a user-mode definition, this should be removed.
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 9deed0ef8..67a948873 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -52,40 +52,24 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
cpu_exec_step_atomic(cs);
break;
case [(${gen_arch_upper})]_EXCP_[(${config.syscallException})]:
- cause = env->[(${config.excCauseVar})];
- switch (cause) {
- case [(${gen_arch_upper})]_EXC_[(${config.syscallInstr})]:
- env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
- ret = do_syscall(env,
- env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
- [# th:each="arg : ${config.args}"]
- env->[(${config.mainRegisterFile})][ [(${arg})] ],
- [/]
- 0, 0);
- if (ret == -QEMU_ERESTARTSYS) {
- env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
- } else if (ret != -QEMU_ESIGRETURN) {
- env->[(${config.mainRegisterFile})][ [(${config.retReg})] ] = ret; }
- if (cs->singlestep_enabled) {
- goto gdbstep;
- }
- break;
-
- case [(${gen_arch_upper})]_EXC_[(${config.illegalInstrExc})]:
- force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
- break;
- case [(${gen_arch_upper})]_EXC_[(${config.breakpointExc})]:
- case EXCP_DEBUG:
- gdbstep:
- force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
- break;
- default:
- EXCP_DUMP(env,
- "\nqemu: unhandled [(${gen_arch_lower})] exception cause %#x - aborting\n",
- cause);
- exit(EXIT_FAILURE);
+ env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
+ ret = do_syscall(env,
+ env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
+ [# th:each="arg : ${config.args}"]
+ env->[(${config.mainRegisterFile})][ [(${arg})] ],
+ [/]
+ 0, 0);
+ if (ret == -QEMU_ERESTARTSYS) {
+ env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
+ } else if (ret != -QEMU_ESIGRETURN) {
+ env->[(${config.mainRegisterFile})][ [(${config.retReg})] ] = ret; }
+ if (cs->singlestep_enabled) {
+ goto gdbstep;
}
- break;
+ case EXCP_DEBUG:
+ gdbstep:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
+ break;
default:
EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
trapnr);
diff --git a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
index 4637ea9bc..79e544504 100644
--- a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
+++ b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
@@ -166,17 +166,6 @@ public static UserModeEmulation createDummySolution(Abi abi, InstructionSetArchi
emptyGraph, emptyAssembly, emptyEncoding
);
- RegisterTensor mainRegFile = (RegisterTensor) abi.stackPointer().registerFile();
-
- SourceLocation loc = SourceLocation.INVALID_SOURCE_LOCATION;
- Abi.Alignment align = Abi.Alignment.DEFAULT;
-
- Abi.RegisterRef spReg = new Abi.RegisterRef(mainRegFile, 2, align, loc);
-
- Abi.RegisterRef sysReg = new Abi.RegisterRef(mainRegFile, 17, align, loc);
-
- Abi.RegisterRef retReg = new Abi.RegisterRef(mainRegFile, 10, align, loc);
-
return new UserModeEmulation(
identifier,
isa, abi,
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index 1037adc65..aaad5b4f8 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -67,13 +67,13 @@ protected Map createVariables(PassResults passResults,
RegisterTensor mainRegFile = (RegisterTensor) abi.stackPointer().registerFile();
Map excIds = Map.of(
- "RV64UME_EXC_ILLEGAL_INSTR", 2,
- "RV64UME_EXC_ECALL", 11,
- "RV64UME_EXC_BREAKPOINT", 3
+ "ILLEGAL_INSTR", 2,
+ "ECALL", 11,
+ "BREAKPOINT", 3
);
vars.put("config", Map.ofEntries(
- Map.entry("sysReg", abi.stackPointer()),
+ Map.entry("sysReg", abi.stackPointer().addr()),
Map.entry("retReg", abi.returnRegisters().get(0).get(0).addr()),
Map.entry("spReg", abi.stackPointer().addr()),
Map.entry("spRegName", abi.stackPointer().render()),
From a6a88bfacb4ef81a4571c5cd6bd62959fb8009d2 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 31 May 2026 20:05:49 +0200
Subject: [PATCH 20/28] ume: Add syscall section to vadl file #757
---
sys/risc-v/rv64ume.vadl | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/sys/risc-v/rv64ume.vadl b/sys/risc-v/rv64ume.vadl
index 040678e60..bcdf22e8c 100644
--- a/sys/risc-v/rv64ume.vadl
+++ b/sys/risc-v/rv64ume.vadl
@@ -11,24 +11,34 @@ application binary interface ABI for RV64UME = {
alias register a3 = X(13)
alias register a4 = X(14)
alias register a5 = X(15)
+ alias register a6 = X(16)
alias register a7 = X(17)
alias register sp = X(2)
alias register ra = X(1)
+ alias register gp = X(3)
+ alias register fp = X(8)
return address = ra
stack pointer = sp
return value = a0
- frame pointer = X(8)
- function argument = a{0..5}
- caller saved = [ a{0..5} ]
- callee saved = [ X(1) ]
+ frame pointer = fp
+ global pointer = gp
+ function argument = a{0..7}
+ caller saved = [ a{0..7} ]
+ callee saved = [ ra, fp,
+ X(9), X(18), X(19), X(20), X(21),
+ X(22), X(23), X(24), X(25), X(26), X(27) ]
+
special absolute address load instruction = LA
- return value = a{0..1}
+ special local address load instruction = LLA
special return instruction = RET
special call instruction = CALL
- special local address load instruction = LLA
- special global address load instruction = LGA_64
+}
+
+enumeration LinuxSyscall : Bits<64> = {
+ sys_riscv_hwprobe = 258
+ , sys_riscv_flush_icache = 259
}
// This is the system-mode entry point.
From 1379c83254bb7af46581a1af7827ed99a4cb22c3 Mon Sep 17 00:00:00 2001
From: Johannes Zottele
Date: Wed, 3 Jun 2026 19:19:21 +0200
Subject: [PATCH 21/28] iss: Fix UME pass order
---
vadl/main/vadl/pass/order/IssPassOrder.java | 59 +++++++++++----------
1 file changed, 30 insertions(+), 29 deletions(-)
diff --git a/vadl/main/vadl/pass/order/IssPassOrder.java b/vadl/main/vadl/pass/order/IssPassOrder.java
index 4ddf6298c..d08d09bca 100644
--- a/vadl/main/vadl/pass/order/IssPassOrder.java
+++ b/vadl/main/vadl/pass/order/IssPassOrder.java
@@ -24,6 +24,8 @@
import vadl.configuration.IssConfiguration;
import vadl.dump.DumpIssInstructionGraphsPass;
import vadl.gcb.passes.RenamingConflictingRegistersPass;
+import vadl.iss.passes.UmeHardcodedRiscvDefinitionPass;
+import vadl.iss.passes.UmeTemplateRenderingPass;
import vadl.iss.passes.common.IssApplyMemoryEndiannessPass;
import vadl.iss.passes.common.IssBitfieldWriteLoweringPass;
import vadl.iss.passes.common.IssBuiltInArgTruncOptPass;
@@ -52,7 +54,6 @@
import vadl.iss.passes.tcg.lowering.TcgBranchLoweringPass;
import vadl.iss.passes.tcg.lowering.TcgOpLoweringPass;
import vadl.iss.passes.vector.IssDirectGvecLoweringPass;
-import vadl.iss.template.IssDefaultRenderingPass;
import vadl.iss.template.gdb_xml.EmitIssGdbXmlPass;
import vadl.iss.template.hw.EmitIssHwMachineCPass;
import vadl.iss.template.target.EmitIssCpuHeaderPass;
@@ -215,37 +216,37 @@ private static void addIssTemplatePasses(PassOrder order, IssConfiguration confi
}
private static void addUserModeEmitPasses(PassOrder order, IssConfiguration config) {
+ // right now, we only emit those passes if we generate the ISS for RV64UME
var inputPath = config.inputPath();
if (inputPath != null && inputPath.getFileName().endsWith("rv64ume.vadl")) {
order
- .add(IssDefaultRenderingPass.issDefault("/configs/targets/gen-arch-linux-user.mak",
- config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/meson.build", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/elfload.c", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/syscall_defs.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/meson.build", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/cpu_loop.c", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/signal.c", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/sockbits.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/syscall.tbl", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/syscallhdr.sh", true,
- config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_cpu.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_elf.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_errno_defs.h",
- config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_fcntl.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_mman.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_prctl.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_proc.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_resource.h",
- config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_signal.h", config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_structs.h",
- config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/target_syscall.h",
- config))
- .add(IssDefaultRenderingPass.issDefault("/linux-user/gen-arch/termbits.h", config));
+ .add(new UmeHardcodedRiscvDefinitionPass(config))
+ .add(issDefault("/configs/targets/gen-arch-linux-user.mak", config))
+
+ .add(issDefault("/linux-user/meson.build", config))
+ .add(issDefault("/linux-user/elfload.c", config))
+ .add(issDefault("/linux-user/syscall_defs.h", config))
+
+ .add(issDefault("/linux-user/gen-arch/meson.build", config))
+ .add(new UmeTemplateRenderingPass(config, "cpu_loop.c"))
+ .add(new UmeTemplateRenderingPass(config, "signal.c"))
+ .add(issDefault("/linux-user/gen-arch/sockbits.h", config))
+ .add(issDefault("/linux-user/gen-arch/syscall.tbl", config))
+ .add(issDefault("/linux-user/gen-arch/syscallhdr.sh", true, config))
+ .add(new UmeTemplateRenderingPass(config, "target_cpu.h"))
+
+ .add(issDefault("/linux-user/gen-arch/target_elf.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_errno_defs.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_fcntl.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_mman.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_prctl.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_proc.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_resource.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_signal.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_structs.h", config))
+ .add(issDefault("/linux-user/gen-arch/target_syscall.h", config))
+ .add(issDefault("/linux-user/gen-arch/termbits.h", config))
+ ;
}
}
From 53fbd00f3f582c2f956d3fd2ef919a103f1076a6 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Mon, 8 Jun 2026 14:59:51 +0200
Subject: [PATCH 22/28] ume: Fix registers #757
---
sys/risc-v/rv64ume.vadl | 2 +-
.../iss/linux-user/gen-arch/cpu_loop.c | 25 ++----
.../iss/linux-user/gen-arch/target_cpu.h | 2 +-
.../UmeHardcodedRiscvDefinitionPass.java | 88 +++++++------------
.../iss/passes/UmeTemplateRenderingPass.java | 50 +++++------
vadl/main/vadl/viam/UserModeEmulation.java | 40 +++------
6 files changed, 77 insertions(+), 130 deletions(-)
diff --git a/sys/risc-v/rv64ume.vadl b/sys/risc-v/rv64ume.vadl
index bcdf22e8c..6829c7039 100644
--- a/sys/risc-v/rv64ume.vadl
+++ b/sys/risc-v/rv64ume.vadl
@@ -23,7 +23,7 @@ application binary interface ABI for RV64UME = {
return value = a0
frame pointer = fp
global pointer = gp
- function argument = a{0..7}
+ function argument = [ a{0..7} ]
caller saved = [ a{0..7} ]
callee saved = [ ra, fp,
X(9), X(18), X(19), X(20), X(21),
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 67a948873..01e94e13f 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -24,13 +24,6 @@
#include "signal-common.h"
#include "elf.h"
-
-enum {
- [# th:each="exc : ${config.excIds}"]
- [(${gen_arch_upper})]_EXC_[(${exc.key})] = [(${exc.value})],
- [/]
-};
-
void cpu_loop(CPU[(${gen_arch_upper})]State *env)
{
CPUState *cs = env_cpu(env);
@@ -51,24 +44,24 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
- case [(${gen_arch_upper})]_EXCP_[(${config.syscallException})]:
- env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
+ case [(${gen_arch_upper})]_EXCP_SYSCALL:
+ env->[(${pc_info.accessor})] += [(${config.insn_width_bytes})];
ret = do_syscall(env,
- env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
+ env->[(${config.sysRegFile})][ [(${config.sysReg})] ],
[# th:each="arg : ${config.args}"]
- env->[(${config.mainRegisterFile})][ [(${arg})] ],
+ env->[(${arg.file})][ [(${arg.index})] ],
[/]
0, 0);
if (ret == -QEMU_ERESTARTSYS) {
- env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
+ env->[(${pc_info.accessor})] -= [(${config.insn_width_bytes})];
} else if (ret != -QEMU_ESIGRETURN) {
- env->[(${config.mainRegisterFile})][ [(${config.retReg})] ] = ret; }
+ env->[(${config.retRegFile})][ [(${config.retReg})] ] = ret; }
if (cs->singlestep_enabled) {
goto gdbstep;
}
case EXCP_DEBUG:
gdbstep:
- force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_info.accessor})]);
break;
default:
EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
@@ -85,8 +78,8 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
TaskState *ts = get_task_state(cpu);
struct image_info *info = ts->info;
- env->[(${pc_reg.name_lower})] = regs->[(${pc_reg.name_lower})];
- env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = regs->[(${config.spRegName})];
+ env->[(${pc_info.accessor})] = regs->[(${pc_info.accessor})];
+ env->[(${config.spRegFile})][ [(${config.spReg})] ] = regs->[(${config.spRegName})];
ts->stack_base = info->start_stack;
}
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
index ccfd828f8..1a68d4074 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
@@ -8,7 +8,7 @@ enum {
[(${gen_arch_upper})]_REG_TP = 4,
[# th:each="arg, stat : ${config.args}"]
- [(${gen_arch_upper})]_REG_ARG[(${stat.index})] = [(${arg})],
+ [(${gen_arch_upper})]_REG_ARG[(${stat.index})] = [(${arg.index})],
[/]
};
diff --git a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
index 79e544504..a55482299 100644
--- a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
+++ b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
@@ -17,30 +17,27 @@
package vadl.iss.passes;
import java.io.IOException;
-import java.util.HashMap;
+import java.math.BigInteger;
import java.util.List;
-import java.util.stream.IntStream;
import javax.annotation.Nullable;
import vadl.configuration.IssConfiguration;
-import vadl.lcb.templateUtils.RegisterUtils;
import vadl.pass.PassName;
import vadl.pass.PassResults;
import vadl.types.BitsType;
+import vadl.types.DataType;
import vadl.types.Type;
-import vadl.utils.Pair;
import vadl.utils.SourceLocation;
import vadl.viam.Abi;
import vadl.viam.Assembly;
+import vadl.viam.Constant;
import vadl.viam.Encoding;
-import vadl.viam.ExceptionDef;
import vadl.viam.Format;
import vadl.viam.Function;
import vadl.viam.Identifier;
import vadl.viam.Instruction;
import vadl.viam.InstructionSetArchitecture;
import vadl.viam.Parameter;
-import vadl.viam.RegisterResource;
-import vadl.viam.RegisterTensor;
+import vadl.viam.RegisterRef;
import vadl.viam.Specification;
import vadl.viam.UserModeEmulation;
import vadl.viam.graph.Graph;
@@ -85,60 +82,24 @@ public static UserModeEmulation createDummySolution(Abi abi, InstructionSetArchi
Identifier identifier = new Identifier(new String[]{"ume"},
SourceLocation.INVALID_SOURCE_LOCATION);
- RegisterTensor.Dimension regDim = new RegisterTensor.Dimension(
- 0,
- Type.bits(5),
- 32
- );
+ var registerResource = isa.registerTensors()
+ .stream()
+ .filter(r -> r.simpleName().equals("X"))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("Register file X not found in ISA"));
- RegisterTensor.Dimension dummyDim = new RegisterTensor.Dimension(
- 1,
- Type.bits(1),
- 1
- );
+ var index = Constant.Value.of(BigInteger.valueOf(10).toByteArray(), DataType.bits(5));
- List dimensions = List.of(regDim, dummyDim);
- RegisterTensor mainFile = new RegisterTensor(
- new Identifier(new String[]{"x"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- dimensions
+ var ref = new RegisterRef(
+ registerResource,
+ List.of(index),
+ SourceLocation.INVALID_SOURCE_LOCATION
);
- var dummyMap = new HashMap, List>();
-
- RegisterUtils.RegisterClass gprClass = RegisterUtils.getRegisterClass(mainFile, dummyMap);
-
- List args = IntStream.range(10, 16)
- .mapToObj(i -> gprClass.registers().get(i))
- .toList();
+ List args = List.of(ref);
- Parameter[] emptyParams = new Parameter[0];
Graph emptyGraph = new Graph("empty_graph");
- ExceptionDef mockSyscallExc = new ExceptionDef(
- new Identifier(new String[]{"EXC"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- emptyParams,
- emptyGraph,
- ExceptionDef.Kind.DECLARED
- );
-
- ExceptionDef mockBreakpointExc = new ExceptionDef(
- new Identifier(new String[]{"BREAKPOINT"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- emptyParams,
- emptyGraph,
- ExceptionDef.Kind.DECLARED
- );
-
- ExceptionDef mockIllegalExc = new ExceptionDef(
- new Identifier(new String[]{"ILLEGAL_INSTR"},
- SourceLocation.INVALID_SOURCE_LOCATION),
- emptyParams,
- emptyGraph,
- ExceptionDef.Kind.DECLARED
- );
-
BitsType mockType = BitsType.bits(32);
Function mockFunc = new Function(
@@ -166,13 +127,24 @@ public static UserModeEmulation createDummySolution(Abi abi, InstructionSetArchi
emptyGraph, emptyAssembly, emptyEncoding
);
+ var syscallNrRef = new RegisterRef(
+ registerResource,
+ List.of(Constant.Value.of(BigInteger.valueOf(17).toByteArray(), DataType.bits(5))),
+ SourceLocation.INVALID_SOURCE_LOCATION
+ );
+
+ var syscallReturnRef = new RegisterRef(
+ registerResource,
+ List.of(Constant.Value.of(BigInteger.valueOf(10).toByteArray(), DataType.bits(5))),
+ SourceLocation.INVALID_SOURCE_LOCATION
+ );
+
return new UserModeEmulation(
identifier,
- isa, abi,
- mockSyscallExc, args,
+ isa, abi, args,
mockSyscallInsn,
- mockBreakpointExc,
- mockIllegalExc);
+ syscallNrRef,
+ syscallReturnRef);
}
}
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index aaad5b4f8..a30ba4265 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -16,14 +16,14 @@
package vadl.iss.passes;
+import java.util.List;
import java.util.Map;
import vadl.configuration.IssConfiguration;
import vadl.iss.template.IssTemplateRenderingPass;
-import vadl.lcb.templateUtils.RegisterUtils;
import vadl.pass.PassName;
import vadl.pass.PassResults;
+import vadl.utils.Pair;
import vadl.viam.Abi;
-import vadl.viam.RegisterTensor;
import vadl.viam.Specification;
import vadl.viam.UserModeEmulation;
@@ -64,36 +64,32 @@ protected Map createVariables(PassResults passResults,
.orElseThrow(() -> new IllegalStateException("No UserModeEmulation defined"));
Abi abi = ume.abi();
- RegisterTensor mainRegFile = (RegisterTensor) abi.stackPointer().registerFile();
-
- Map excIds = Map.of(
- "ILLEGAL_INSTR", 2,
- "ECALL", 11,
- "BREAKPOINT", 3
- );
vars.put("config", Map.ofEntries(
- Map.entry("sysReg", abi.stackPointer().addr()),
- Map.entry("retReg", abi.returnRegisters().get(0).get(0).addr()),
+ Map.entry("sysReg", ume.getSyscallNumber().singleIndex()),
+ Map.entry("sysRegFile", ume.getSyscallNumber().resource().simpleName().toLowerCase()),
+ Map.entry("retReg", ume.getSyscallReturn().singleIndex()),
+ Map.entry("retRegFile", ume.getSyscallReturn().resource().simpleName().toLowerCase()),
Map.entry("spReg", abi.stackPointer().addr()),
- Map.entry("spRegName", abi.stackPointer().render()),
- Map.entry("args", ume.args().stream()
- .map(RegisterUtils.Register::index)
+ Map.entry("spRegFile", abi.stackPointer().registerFile().simpleName().toLowerCase()),
+ Map.entry("spRegName", abi.aliases()
+ .getOrDefault(
+ Pair.of(abi.stackPointer().registerFile(), abi.stackPointer().addr()),
+ List.of(new Abi.RegisterAlias("sp"))
+ )
+ .getFirst().value()),
+ Map.entry("args", abi.argumentRegisters().stream()
+ .map(abiReg -> {
+ var ref = abiReg.registerRef();
+
+ return Map.of(
+ "index", ref.singleIndex(),
+ "file", ref.resource().simpleName().toLowerCase()
+ );
+ })
.toList()),
- Map.entry("excIds", excIds),
Map.entry("syscallInstr", ume.syscallInstr().simpleName()),
- Map.entry("syscallException", ume.syscallException().simpleName()),
- Map.entry(
- "breakpointExc",
- ume.breakpointExc() != null ? ume.breakpointExc().simpleName() : ""
- ),
- Map.entry(
- "IllegalInstrExc",
- ume.illegalInstrExc() != null ? ume.illegalInstrExc().simpleName() : ""
- ),
- Map.entry("insn_width_bytes", ume.syscallInstr().format().type().bitWidth() / 8),
- Map.entry("mainRegisterFile", mainRegFile.simpleName().toLowerCase()),
- Map.entry("mainRegFileSize", mainRegFile.outermostDim().size())
+ Map.entry("insn_width_bytes", ume.syscallInstr().format().type().bitWidth() / 8)
));
return vars;
diff --git a/vadl/main/vadl/viam/UserModeEmulation.java b/vadl/main/vadl/viam/UserModeEmulation.java
index 91b08ca30..56175f6c2 100644
--- a/vadl/main/vadl/viam/UserModeEmulation.java
+++ b/vadl/main/vadl/viam/UserModeEmulation.java
@@ -17,8 +17,6 @@
package vadl.viam;
import java.util.List;
-import javax.annotation.Nullable;
-import vadl.lcb.templateUtils.RegisterUtils;
/**
* Represents the configuration for QEMU user-mode emulation.
@@ -33,57 +31,45 @@ public class UserModeEmulation extends Definition {
private final InstructionSetArchitecture isa;
private final Abi abi;
- private final List args;
+ private final List args;
private final Instruction syscallInstr;
- private final ExceptionDef syscallException;
- @Nullable
- private final ExceptionDef breakpointExc;
- @Nullable
- private final ExceptionDef illegalInstrExc;
+ private final RegisterRef syscallNumber;
+ private final RegisterRef syscallReturn;
/**
* Constructs a UserModeEmulation configuration.
*/
public UserModeEmulation(
- Identifier identifier, InstructionSetArchitecture isa, Abi abi, ExceptionDef syscallException,
- List args,
- Instruction syscallInstr, ExceptionDef breakpointExc,
- ExceptionDef illegalInstrExc
+ Identifier identifier, InstructionSetArchitecture isa, Abi abi,
+ List args,
+ Instruction syscallInstr, RegisterRef syscallNumber, RegisterRef syscallReturn
) {
super(identifier);
this.isa = isa;
this.abi = abi;
- this.syscallException = syscallException;
-
this.args = args;
this.syscallInstr = syscallInstr;
- this.breakpointExc = breakpointExc;
- this.illegalInstrExc = illegalInstrExc;
+ this.syscallNumber = syscallNumber;
+ this.syscallReturn = syscallReturn;
}
public Instruction syscallInstr() {
return syscallInstr;
}
- @Nullable
- public ExceptionDef breakpointExc() {
- return breakpointExc;
+ public RegisterRef getSyscallNumber() {
+ return syscallNumber;
}
- @Nullable
- public ExceptionDef illegalInstrExc() {
- return illegalInstrExc;
+ public RegisterRef getSyscallReturn() {
+ return syscallReturn;
}
- public List args() {
+ public List args() {
return args;
}
- public ExceptionDef syscallException() {
- return syscallException;
- }
-
public InstructionSetArchitecture isa() {
return isa;
}
From 4f2a2ecf7627b46e8a2ad9bd35e0b182b180aecf Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Fri, 12 Jun 2026 18:47:41 +0200
Subject: [PATCH 23/28] ume: Use hardcoded arguments #757
---
.../vadl/iss/passes/UmeTemplateRenderingPass.java | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
index a30ba4265..4749aa428 100644
--- a/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
+++ b/vadl/main/vadl/iss/passes/UmeTemplateRenderingPass.java
@@ -78,15 +78,11 @@ protected Map createVariables(PassResults passResults,
List.of(new Abi.RegisterAlias("sp"))
)
.getFirst().value()),
- Map.entry("args", abi.argumentRegisters().stream()
- .map(abiReg -> {
- var ref = abiReg.registerRef();
-
- return Map.of(
- "index", ref.singleIndex(),
- "file", ref.resource().simpleName().toLowerCase()
- );
- })
+ Map.entry("args", ume.args().stream()
+ .map(ref -> Map.of(
+ "index", ref.singleIndex(),
+ "file", ref.resource().simpleName().toLowerCase()
+ ))
.toList()),
Map.entry("syscallInstr", ume.syscallInstr().simpleName()),
Map.entry("insn_width_bytes", ume.syscallInstr().format().type().bitWidth() / 8)
From 16ea90bd270aa5c8ef03e08ae402dc3f51c4415d Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Fri, 12 Jun 2026 18:53:53 +0200
Subject: [PATCH 24/28] ume: Improve register hardcoding #757
---
.../UmeHardcodedRiscvDefinitionPass.java | 23 ++++++++-----------
1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
index a55482299..772567821 100644
--- a/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
+++ b/vadl/main/vadl/iss/passes/UmeHardcodedRiscvDefinitionPass.java
@@ -19,6 +19,7 @@
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
+import java.util.stream.IntStream;
import javax.annotation.Nullable;
import vadl.configuration.IssConfiguration;
import vadl.pass.PassName;
@@ -82,21 +83,15 @@ public static UserModeEmulation createDummySolution(Abi abi, InstructionSetArchi
Identifier identifier = new Identifier(new String[]{"ume"},
SourceLocation.INVALID_SOURCE_LOCATION);
- var registerResource = isa.registerTensors()
- .stream()
- .filter(r -> r.simpleName().equals("X"))
- .findFirst()
- .orElseThrow(() -> new IllegalStateException("Register file X not found in ISA"));
+ var registerResource = abi.stackPointer().registerFile();
- var index = Constant.Value.of(BigInteger.valueOf(10).toByteArray(), DataType.bits(5));
-
- var ref = new RegisterRef(
- registerResource,
- List.of(index),
- SourceLocation.INVALID_SOURCE_LOCATION
- );
-
- List args = List.of(ref);
+ List args = IntStream.rangeClosed(10, 15)
+ .mapToObj(i -> new RegisterRef(
+ registerResource,
+ List.of(Constant.Value.of(BigInteger.valueOf(i).toByteArray(), DataType.bits(5))),
+ SourceLocation.INVALID_SOURCE_LOCATION
+ ))
+ .toList();
Graph emptyGraph = new Graph("empty_graph");
From 93f5a2b8385553844d29af0849fd24e7e07d4bf5 Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 19 Jul 2026 18:46:56 +0200
Subject: [PATCH 25/28] ume: Add syscall #757
---
.../resources/templates/iss/linux-user/gen-arch/cpu_loop.c | 3 +--
.../templates/iss/linux-user/gen-arch/target_syscall.h | 1 +
vadl/main/resources/templates/iss/target/gen-arch/translate.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 01e94e13f..6bb2916c7 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -28,7 +28,6 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
{
CPUState *cs = env_cpu(env);
int trapnr;
- uint32_t cause;
target_ulong ret;
for (;;) {
@@ -44,7 +43,7 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
- case [(${gen_arch_upper})]_EXCP_SYSCALL:
+ case [(${gen_arch_upper})]_EXCP_EXC:
env->[(${pc_info.accessor})] += [(${config.insn_width_bytes})];
ret = do_syscall(env,
env->[(${config.sysRegFile})][ [(${config.sysReg})] ],
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
index 3860bde86..027cb51d1 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
@@ -9,6 +9,7 @@
#define LINUX_USER_[(${gen_arch_upper})]_TARGET_SYSCALL_H
struct target_pt_regs {
+ abi_long pc;
abi_long sepc;
abi_long ra;
abi_long sp;
diff --git a/vadl/main/resources/templates/iss/target/gen-arch/translate.c b/vadl/main/resources/templates/iss/target/gen-arch/translate.c
index 37763c2ce..b7c559fc5 100644
--- a/vadl/main/resources/templates/iss/target/gen-arch/translate.c
+++ b/vadl/main/resources/templates/iss/target/gen-arch/translate.c
@@ -215,7 +215,7 @@ static void translate(DisasContext *ctx)
return;
}
- error_report("[[(${gen_arch_upper})]] translate, illegal instr, pc: 0x%04llx , insn: 0x%04x\n", ctx->base.pc_next, insn);
+ error_report("[[(${gen_arch_upper})]] translate, illegal instr, pc: 0x%04 , insn: 0x%04x\n", ctx->base.pc_next, insn);
gen_update_pc_diff(ctx, 0);
gen_helper_unsupported(tcg_env);
From ad2f2e576cf75f22800db7723119e2caf9d7584c Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 19 Jul 2026 18:51:03 +0200
Subject: [PATCH 26/28] ume: Remove sepc #757
---
.../resources/templates/iss/linux-user/gen-arch/target_syscall.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
index 027cb51d1..b3661577f 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
@@ -10,7 +10,6 @@
struct target_pt_regs {
abi_long pc;
- abi_long sepc;
abi_long ra;
abi_long sp;
abi_long gp;
From e39efafc96558a9abdeb00c6866f61c33298163b Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 19 Jul 2026 19:48:55 +0200
Subject: [PATCH 27/28] ume: Add synthetic exception #757
---
.../resources/templates/iss/linux-user/gen-arch/cpu_loop.c | 3 ++-
.../templates/iss/linux-user/gen-arch/target_syscall.h | 1 +
vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h | 1 +
3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index 6bb2916c7..e0480c24a 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -43,7 +43,7 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
- case [(${gen_arch_upper})]_EXCP_EXC:
+ case [(${gen_arch_upper})]_EXCP_SYSCALL:
env->[(${pc_info.accessor})] += [(${config.insn_width_bytes})];
ret = do_syscall(env,
env->[(${config.sysRegFile})][ [(${config.sysReg})] ],
@@ -58,6 +58,7 @@ void cpu_loop(CPU[(${gen_arch_upper})]State *env)
if (cs->singlestep_enabled) {
goto gdbstep;
}
+ break;
case EXCP_DEBUG:
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_info.accessor})]);
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
index b3661577f..f7b903b03 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
@@ -9,6 +9,7 @@
#define LINUX_USER_[(${gen_arch_upper})]_TARGET_SYSCALL_H
struct target_pt_regs {
+ abi_long sepc;
abi_long pc;
abi_long ra;
abi_long sp;
diff --git a/vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h b/vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h
index 04e8efa19..922ffdc28 100644
--- a/vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h
+++ b/vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h
@@ -7,6 +7,7 @@ typedef enum [(${gen_arch_upper})]Exception {
[# th:each="exc, iterState : ${exc_info.exceptions}"]
[[${exc.enum_name}]],
[/]
+ [(${gen_arch_upper})]_EXCP_SYSCALL = 0xFFFF,
} [(${gen_arch_upper})]Exception;
#endif //[(${gen_arch_upper})]_CPU_BITS_H
From 20f20ffaa93f5aeada16045b87159249bc19675e Mon Sep 17 00:00:00 2001
From: arcane-quill
Date: Sun, 26 Jul 2026 16:29:27 +0200
Subject: [PATCH 28/28] ume: Add more synth syscall logic #757
---
.../iss/linux-user/gen-arch/cpu_loop.c | 2 +-
.../iss/linux-user/gen-arch/target_syscall.h | 30 -------------------
.../templates/iss/target/gen-arch/cpu-bits.h | 2 +-
.../templates/iss/target/gen-arch/helper.c | 9 ++++++
.../templates/iss/target/gen-arch/helper.h | 2 ++
.../templates/iss/target/gen-arch/translate.c | 8 +++++
6 files changed, 21 insertions(+), 32 deletions(-)
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
index e0480c24a..1ec5598b5 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
@@ -78,7 +78,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
TaskState *ts = get_task_state(cpu);
struct image_info *info = ts->info;
- env->[(${pc_info.accessor})] = regs->[(${pc_info.accessor})];
+ env->[(${pc_info.accessor})] = regs->sepc;
env->[(${config.spRegFile})][ [(${config.spReg})] ] = regs->[(${config.spRegName})];
ts->stack_base = info->start_stack;
diff --git a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
index f7b903b03..80e26fbbd 100644
--- a/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
+++ b/vadl/main/resources/templates/iss/linux-user/gen-arch/target_syscall.h
@@ -11,37 +11,7 @@
struct target_pt_regs {
abi_long sepc;
abi_long pc;
- abi_long ra;
abi_long sp;
- abi_long gp;
- abi_long tp;
- abi_long t0;
- abi_long t1;
- abi_long t2;
- abi_long s0;
- abi_long s1;
- abi_long a0;
- abi_long a1;
- abi_long a2;
- abi_long a3;
- abi_long a4;
- abi_long a5;
- abi_long a6;
- abi_long a7;
- abi_long s2;
- abi_long s3;
- abi_long s4;
- abi_long s5;
- abi_long s6;
- abi_long s7;
- abi_long s8;
- abi_long s9;
- abi_long s10;
- abi_long s11;
- abi_long t3;
- abi_long t4;
- abi_long t5;
- abi_long t6;
};
#define UNAME_MACHINE "[(${gen_arch_lower})]"
diff --git a/vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h b/vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h
index 922ffdc28..1ae19fd13 100644
--- a/vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h
+++ b/vadl/main/resources/templates/iss/target/gen-arch/cpu-bits.h
@@ -7,7 +7,7 @@ typedef enum [(${gen_arch_upper})]Exception {
[# th:each="exc, iterState : ${exc_info.exceptions}"]
[[${exc.enum_name}]],
[/]
- [(${gen_arch_upper})]_EXCP_SYSCALL = 0xFFFF,
+ [(${gen_arch_upper})]_EXCP_SYSCALL = 0x10000,
} [(${gen_arch_upper})]Exception;
#endif //[(${gen_arch_upper})]_CPU_BITS_H
diff --git a/vadl/main/resources/templates/iss/target/gen-arch/helper.c b/vadl/main/resources/templates/iss/target/gen-arch/helper.c
index b0df5e67a..fff71fe2b 100644
--- a/vadl/main/resources/templates/iss/target/gen-arch/helper.c
+++ b/vadl/main/resources/templates/iss/target/gen-arch/helper.c
@@ -24,6 +24,15 @@ void helper_unsupported(CPU[(${gen_arch_upper})]State *env) {
cpu_loop_exit(cs);
}
+void helper_raise_syscall(CPU[(${gen_arch_upper})]State *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->exception_index = EXCP_SYSCALL;
+
+ cpu_loop_exit(cs);
+}
+
[# th:each="exc : ${exc_info.exceptions}"]
[(${exc.helper_impl})]
[/]
diff --git a/vadl/main/resources/templates/iss/target/gen-arch/helper.h b/vadl/main/resources/templates/iss/target/gen-arch/helper.h
index 107003b8d..47dbb6ef2 100644
--- a/vadl/main/resources/templates/iss/target/gen-arch/helper.h
+++ b/vadl/main/resources/templates/iss/target/gen-arch/helper.h
@@ -6,6 +6,8 @@ DEF_HELPER_1(unsupported, noreturn, env)
[(${exc.helper_def})]
[/]
+DEF_HELPER_1(raise_syscall, void, env)
+
// helper definitions for instructions
[# th:each="instr : ${instr_helper_defs}"]
[(${instr})]
diff --git a/vadl/main/resources/templates/iss/target/gen-arch/translate.c b/vadl/main/resources/templates/iss/target/gen-arch/translate.c
index b7c559fc5..40a441750 100644
--- a/vadl/main/resources/templates/iss/target/gen-arch/translate.c
+++ b/vadl/main/resources/templates/iss/target/gen-arch/translate.c
@@ -150,6 +150,14 @@ static void gen_update_pc_diff(DisasContext *ctx, target_long diff) {
gen_update_pc(ctx, dest);
}
+static void gen_raise_syscall(DisasContext *ctx) {
+ gen_update_pc(ctx, ctx->pc_curr);
+
+ gen_helper_raise_syscall(tcg_env);
+
+ ctx->base.is_jmp = DISAS_NORETURN;
+}
+
/*
* Jumps to the given target_pc and sets is_jmp to NORETURN. n indicates the jump slot