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) 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) 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