aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPhilippe Mathieu-Daudé <philmd@linaro.org>2024-03-27 12:10:58 +0100
committerPhilippe Mathieu-Daudé <philmd@linaro.org>2024-04-24 16:03:38 +0200
commit6c3014858c4c0024dd0560f08a6eda0f92f658d6 (patch)
treedd474c2e68b37c51c9cb7526e48452aaddccb19e /target
parent92360d6e624404492afe5d32ca669a33df181742 (diff)
downloadqemu-6c3014858c4c0024dd0560f08a6eda0f92f658d6.zip
qemu-6c3014858c4c0024dd0560f08a6eda0f92f658d6.tar.gz
qemu-6c3014858c4c0024dd0560f08a6eda0f92f658d6.tar.bz2
target/nios2: Remove the deprecated Nios II target
The Nios II target is deprecated since v8.2 in commit 9997771bc1 ("target/nios2: Deprecate the Nios II architecture"). Remove: - Buildsys / CI infra - User emulation - System emulation (10m50-ghrd & nios2-generic-nommu machines) - Tests Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Acked-by: Marek Vasut <marex@denx.de> Message-Id: <20240327144806.11319-3-philmd@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/Kconfig1
-rw-r--r--target/meson.build1
-rw-r--r--target/nios2/Kconfig3
-rw-r--r--target/nios2/cpu-param.h20
-rw-r--r--target/nios2/cpu-qom.h18
-rw-r--r--target/nios2/cpu.c410
-rw-r--r--target/nios2/cpu.h301
-rw-r--r--target/nios2/helper.c371
-rw-r--r--target/nios2/helper.h32
-rw-r--r--target/nios2/meson.build17
-rw-r--r--target/nios2/mmu.c216
-rw-r--r--target/nios2/mmu.h52
-rw-r--r--target/nios2/monitor.c35
-rw-r--r--target/nios2/nios2-semi.c230
-rw-r--r--target/nios2/op_helper.c119
-rw-r--r--target/nios2/trace-events10
-rw-r--r--target/nios2/translate.c1107
17 files changed, 0 insertions, 2943 deletions
diff --git a/target/Kconfig b/target/Kconfig
index 83da0bd..5275a93 100644
--- a/target/Kconfig
+++ b/target/Kconfig
@@ -8,7 +8,6 @@ source loongarch/Kconfig
source m68k/Kconfig
source microblaze/Kconfig
source mips/Kconfig
-source nios2/Kconfig
source openrisc/Kconfig
source ppc/Kconfig
source riscv/Kconfig
diff --git a/target/meson.build b/target/meson.build
index dee2ac4..59b46b2 100644
--- a/target/meson.build
+++ b/target/meson.build
@@ -9,7 +9,6 @@ subdir('loongarch')
subdir('m68k')
subdir('microblaze')
subdir('mips')
-subdir('nios2')
subdir('openrisc')
subdir('ppc')
subdir('riscv')
diff --git a/target/nios2/Kconfig b/target/nios2/Kconfig
deleted file mode 100644
index c65550c..0000000
--- a/target/nios2/Kconfig
+++ /dev/null
@@ -1,3 +0,0 @@
-config NIOS2
- bool
- select SEMIHOSTING
diff --git a/target/nios2/cpu-param.h b/target/nios2/cpu-param.h
deleted file mode 100644
index 767bba4..0000000
--- a/target/nios2/cpu-param.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Altera Nios II cpu parameters for qemu.
- *
- * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#ifndef NIOS2_CPU_PARAM_H
-#define NIOS2_CPU_PARAM_H
-
-#define TARGET_LONG_BITS 32
-#define TARGET_PAGE_BITS 12
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
-#ifdef CONFIG_USER_ONLY
-# define TARGET_VIRT_ADDR_SPACE_BITS 31
-#else
-# define TARGET_VIRT_ADDR_SPACE_BITS 32
-#endif
-
-#endif
diff --git a/target/nios2/cpu-qom.h b/target/nios2/cpu-qom.h
deleted file mode 100644
index 2fd9121..0000000
--- a/target/nios2/cpu-qom.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * QEMU Nios II CPU QOM header (target agnostic)
- *
- * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-or-later
- */
-
-#ifndef QEMU_NIOS2_CPU_QOM_H
-#define QEMU_NIOS2_CPU_QOM_H
-
-#include "hw/core/cpu.h"
-
-#define TYPE_NIOS2_CPU "nios2-cpu"
-
-OBJECT_DECLARE_CPU_TYPE(Nios2CPU, Nios2CPUClass, NIOS2_CPU)
-
-#endif
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
deleted file mode 100644
index 679aff5..0000000
--- a/target/nios2/cpu.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * QEMU Nios II CPU
- *
- * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/lgpl-2.1.html>
- */
-
-#include "qemu/osdep.h"
-#include "qemu/module.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "exec/log.h"
-#include "gdbstub/helpers.h"
-#include "hw/qdev-properties.h"
-
-static void nios2_cpu_set_pc(CPUState *cs, vaddr value)
-{
- cpu_env(cs)->pc = value;
-}
-
-static vaddr nios2_cpu_get_pc(CPUState *cs)
-{
- return cpu_env(cs)->pc;
-}
-
-static void nios2_restore_state_to_opc(CPUState *cs,
- const TranslationBlock *tb,
- const uint64_t *data)
-{
- cpu_env(cs)->pc = data[0];
-}
-
-static bool nios2_cpu_has_work(CPUState *cs)
-{
- return cs->interrupt_request & CPU_INTERRUPT_HARD;
-}
-
-static int nios2_cpu_mmu_index(CPUState *cs, bool ifetch)
-{
- return (cpu_env(cs)->ctrl[CR_STATUS] & CR_STATUS_U
- ? MMU_USER_IDX : MMU_SUPERVISOR_IDX);
-}
-
-static void nios2_cpu_reset_hold(Object *obj)
-{
- CPUState *cs = CPU(obj);
- Nios2CPU *cpu = NIOS2_CPU(cs);
- Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(obj);
- CPUNios2State *env = &cpu->env;
-
- if (ncc->parent_phases.hold) {
- ncc->parent_phases.hold(obj);
- }
-
- memset(env->ctrl, 0, sizeof(env->ctrl));
- env->pc = cpu->reset_addr;
-
-#if defined(CONFIG_USER_ONLY)
- /* Start in user mode with interrupts enabled. */
- env->ctrl[CR_STATUS] = CR_STATUS_RSIE | CR_STATUS_U | CR_STATUS_PIE;
- memset(env->regs, 0, sizeof(env->regs));
-#else
- env->ctrl[CR_STATUS] = CR_STATUS_RSIE;
- nios2_update_crs(env);
- memset(env->shadow_regs, 0, sizeof(env->shadow_regs));
-#endif
-}
-
-#ifndef CONFIG_USER_ONLY
-static void eic_set_irq(void *opaque, int irq, int level)
-{
- Nios2CPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void iic_set_irq(void *opaque, int irq, int level)
-{
- Nios2CPU *cpu = opaque;
- CPUNios2State *env = &cpu->env;
- CPUState *cs = CPU(cpu);
-
- env->ctrl[CR_IPENDING] = deposit32(env->ctrl[CR_IPENDING], irq, 1, !!level);
-
- if (env->ctrl[CR_IPENDING]) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-#endif
-
-static void nios2_cpu_initfn(Object *obj)
-{
-#if !defined(CONFIG_USER_ONLY)
- Nios2CPU *cpu = NIOS2_CPU(obj);
-
- mmu_init(&cpu->env);
-#endif
-}
-
-static ObjectClass *nios2_cpu_class_by_name(const char *cpu_model)
-{
- return object_class_by_name(TYPE_NIOS2_CPU);
-}
-
-static void realize_cr_status(CPUState *cs)
-{
- Nios2CPU *cpu = NIOS2_CPU(cs);
-
- /* Begin with all fields of all registers are reserved. */
- memset(cpu->cr_state, 0, sizeof(cpu->cr_state));
-
- /*
- * The combination of writable and readonly is the set of all
- * non-reserved fields. We apply writable as a mask to bits,
- * and merge in existing readonly bits, before storing.
- */
-#define WR_REG(C) cpu->cr_state[C].writable = -1
-#define RO_REG(C) cpu->cr_state[C].readonly = -1
-#define WR_FIELD(C, F) cpu->cr_state[C].writable |= R_##C##_##F##_MASK
-#define RO_FIELD(C, F) cpu->cr_state[C].readonly |= R_##C##_##F##_MASK
-
- WR_FIELD(CR_STATUS, PIE);
- WR_REG(CR_ESTATUS);
- WR_REG(CR_BSTATUS);
- RO_REG(CR_CPUID);
- RO_REG(CR_EXCEPTION);
- WR_REG(CR_BADADDR);
-
- if (cpu->eic_present) {
- WR_FIELD(CR_STATUS, RSIE);
- RO_FIELD(CR_STATUS, NMI);
- WR_FIELD(CR_STATUS, PRS);
- RO_FIELD(CR_STATUS, CRS);
- WR_FIELD(CR_STATUS, IL);
- WR_FIELD(CR_STATUS, IH);
- } else {
- RO_FIELD(CR_STATUS, RSIE);
- WR_REG(CR_IENABLE);
- RO_REG(CR_IPENDING);
- }
-
- if (cpu->mmu_present) {
- WR_FIELD(CR_STATUS, U);
- WR_FIELD(CR_STATUS, EH);
-
- WR_FIELD(CR_PTEADDR, VPN);
- WR_FIELD(CR_PTEADDR, PTBASE);
-
- RO_FIELD(CR_TLBMISC, D);
- RO_FIELD(CR_TLBMISC, PERM);
- RO_FIELD(CR_TLBMISC, BAD);
- RO_FIELD(CR_TLBMISC, DBL);
- WR_FIELD(CR_TLBMISC, PID);
- WR_FIELD(CR_TLBMISC, WE);
- WR_FIELD(CR_TLBMISC, RD);
- WR_FIELD(CR_TLBMISC, WAY);
-
- WR_REG(CR_TLBACC);
- }
-
- /*
- * TODO: ECC (config, eccinj) and MPU (config, mpubase, mpuacc) are
- * unimplemented, so their corresponding control regs remain reserved.
- */
-
-#undef WR_REG
-#undef RO_REG
-#undef WR_FIELD
-#undef RO_FIELD
-}
-
-static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)
-{
- CPUState *cs = CPU(dev);
- Nios2CPU *cpu = NIOS2_CPU(cs);
- Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(dev);
- Error *local_err = NULL;
-
- cpu_exec_realizefn(cs, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return;
- }
-
- realize_cr_status(cs);
- qemu_init_vcpu(cs);
- cpu_reset(cs);
-
- /* We have reserved storage for cpuid; might as well use it. */
- cpu->env.ctrl[CR_CPUID] = cs->cpu_index;
-
-#ifndef CONFIG_USER_ONLY
- if (cpu->eic_present) {
- qdev_init_gpio_in_named(DEVICE(cpu), eic_set_irq, "EIC", 1);
- } else {
- qdev_init_gpio_in_named(DEVICE(cpu), iic_set_irq, "IRQ", 32);
- }
-#endif
-
- ncc->parent_realize(dev, errp);
-}
-
-#ifndef CONFIG_USER_ONLY
-static bool eic_take_interrupt(Nios2CPU *cpu)
-{
- CPUNios2State *env = &cpu->env;
- const uint32_t status = env->ctrl[CR_STATUS];
-
- if (cpu->rnmi) {
- return !(status & CR_STATUS_NMI);
- }
- if (!(status & CR_STATUS_PIE)) {
- return false;
- }
- if (cpu->ril <= FIELD_EX32(status, CR_STATUS, IL)) {
- return false;
- }
- if (cpu->rrs != FIELD_EX32(status, CR_STATUS, CRS)) {
- return true;
- }
- return status & CR_STATUS_RSIE;
-}
-
-static bool iic_take_interrupt(Nios2CPU *cpu)
-{
- CPUNios2State *env = &cpu->env;
-
- if (!(env->ctrl[CR_STATUS] & CR_STATUS_PIE)) {
- return false;
- }
- return env->ctrl[CR_IPENDING] & env->ctrl[CR_IENABLE];
-}
-
-static bool nios2_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
-{
- Nios2CPU *cpu = NIOS2_CPU(cs);
-
- if (interrupt_request & CPU_INTERRUPT_HARD) {
- if (cpu->eic_present
- ? eic_take_interrupt(cpu)
- : iic_take_interrupt(cpu)) {
- cs->exception_index = EXCP_IRQ;
- nios2_cpu_do_interrupt(cs);
- return true;
- }
- }
- return false;
-}
-#endif /* !CONFIG_USER_ONLY */
-
-static void nios2_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
-{
- /* NOTE: NiosII R2 is not supported yet. */
- info->mach = bfd_arch_nios2;
- info->print_insn = print_insn_nios2;
-}
-
-static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
-{
- Nios2CPU *cpu = NIOS2_CPU(cs);
- CPUNios2State *env = &cpu->env;
- uint32_t val;
-
- if (n < 32) { /* GP regs */
- val = env->regs[n];
- } else if (n == 32) { /* PC */
- val = env->pc;
- } else if (n < 49) { /* Status regs */
- unsigned cr = n - 33;
- if (nios2_cr_reserved(&cpu->cr_state[cr])) {
- val = 0;
- } else {
- val = env->ctrl[n - 33];
- }
- } else {
- /* Invalid regs */
- return 0;
- }
-
- return gdb_get_reg32(mem_buf, val);
-}
-
-static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
-{
- Nios2CPU *cpu = NIOS2_CPU(cs);
- CPUClass *cc = CPU_GET_CLASS(cs);
- CPUNios2State *env = &cpu->env;
- uint32_t val;
-
- if (n > cc->gdb_num_core_regs) {
- return 0;
- }
- val = ldl_p(mem_buf);
-
- if (n < 32) { /* GP regs */
- env->regs[n] = val;
- } else if (n == 32) { /* PC */
- env->pc = val;
- } else if (n < 49) { /* Status regs */
- unsigned cr = n - 33;
- /* ??? Maybe allow the debugger to write to readonly fields. */
- val &= cpu->cr_state[cr].writable;
- val |= cpu->cr_state[cr].readonly & env->ctrl[cr];
- env->ctrl[cr] = val;
- } else {
- g_assert_not_reached();
- }
-
- return 4;
-}
-
-static Property nios2_properties[] = {
- DEFINE_PROP_BOOL("diverr_present", Nios2CPU, diverr_present, true),
- DEFINE_PROP_BOOL("mmu_present", Nios2CPU, mmu_present, true),
- /* ALTR,pid-num-bits */
- DEFINE_PROP_UINT32("mmu_pid_num_bits", Nios2CPU, pid_num_bits, 8),
- /* ALTR,tlb-num-ways */
- DEFINE_PROP_UINT32("mmu_tlb_num_ways", Nios2CPU, tlb_num_ways, 16),
- /* ALTR,tlb-num-entries */
- DEFINE_PROP_UINT32("mmu_pid_num_entries", Nios2CPU, tlb_num_entries, 256),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-#ifndef CONFIG_USER_ONLY
-#include "hw/core/sysemu-cpu-ops.h"
-
-static const struct SysemuCPUOps nios2_sysemu_ops = {
- .get_phys_page_debug = nios2_cpu_get_phys_page_debug,
-};
-#endif
-
-#include "hw/core/tcg-cpu-ops.h"
-
-static const TCGCPUOps nios2_tcg_ops = {
- .initialize = nios2_tcg_init,
- .restore_state_to_opc = nios2_restore_state_to_opc,
-
-#ifndef CONFIG_USER_ONLY
- .tlb_fill = nios2_cpu_tlb_fill,
- .cpu_exec_interrupt = nios2_cpu_exec_interrupt,
- .do_interrupt = nios2_cpu_do_interrupt,
- .do_unaligned_access = nios2_cpu_do_unaligned_access,
-#endif /* !CONFIG_USER_ONLY */
-};
-
-static void nios2_cpu_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- CPUClass *cc = CPU_CLASS(oc);
- Nios2CPUClass *ncc = NIOS2_CPU_CLASS(oc);
- ResettableClass *rc = RESETTABLE_CLASS(oc);
-
- device_class_set_parent_realize(dc, nios2_cpu_realizefn,
- &ncc->parent_realize);
- device_class_set_props(dc, nios2_properties);
- resettable_class_set_parent_phases(rc, NULL, nios2_cpu_reset_hold, NULL,
- &ncc->parent_phases);
-
- cc->class_by_name = nios2_cpu_class_by_name;
- cc->has_work = nios2_cpu_has_work;
- cc->mmu_index = nios2_cpu_mmu_index;
- cc->dump_state = nios2_cpu_dump_state;
- cc->set_pc = nios2_cpu_set_pc;
- cc->get_pc = nios2_cpu_get_pc;
- cc->disas_set_info = nios2_cpu_disas_set_info;
-#ifndef CONFIG_USER_ONLY
- cc->sysemu_ops = &nios2_sysemu_ops;
-#endif
- cc->gdb_read_register = nios2_cpu_gdb_read_register;
- cc->gdb_write_register = nios2_cpu_gdb_write_register;
- cc->gdb_num_core_regs = 49;
- cc->tcg_ops = &nios2_tcg_ops;
-}
-
-static const TypeInfo nios2_cpu_type_info = {
- .name = TYPE_NIOS2_CPU,
- .parent = TYPE_CPU,
- .instance_size = sizeof(Nios2CPU),
- .instance_align = __alignof(Nios2CPU),
- .instance_init = nios2_cpu_initfn,
- .class_size = sizeof(Nios2CPUClass),
- .class_init = nios2_cpu_class_init,
-};
-
-static void nios2_cpu_register_types(void)
-{
- type_register_static(&nios2_cpu_type_info);
-}
-
-type_init(nios2_cpu_register_types)
diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
deleted file mode 100644
index 4164a34..0000000
--- a/target/nios2/cpu.h
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Altera Nios II virtual CPU header
- *
- * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/lgpl-2.1.html>
- */
-
-#ifndef NIOS2_CPU_H
-#define NIOS2_CPU_H
-
-#include "cpu-qom.h"
-#include "exec/cpu-defs.h"
-#include "hw/registerfields.h"
-
-typedef struct CPUArchState CPUNios2State;
-#if !defined(CONFIG_USER_ONLY)
-#include "mmu.h"
-#endif
-
-/**
- * Nios2CPUClass:
- * @parent_phases: The parent class' reset phase handlers.
- *
- * A Nios2 CPU model.
- */
-struct Nios2CPUClass {
- CPUClass parent_class;
-
- DeviceRealize parent_realize;
- ResettablePhases parent_phases;
-};
-
-#define TARGET_HAS_ICE 1
-
-/* Configuration options for Nios II */
-#define RESET_ADDRESS 0x00000000
-#define EXCEPTION_ADDRESS 0x00000004
-#define FAST_TLB_MISS_ADDRESS 0x00000008
-
-#define NUM_GP_REGS 32
-#define NUM_CR_REGS 32
-
-#ifndef CONFIG_USER_ONLY
-/* 63 shadow register sets; index 0 is the primary register set. */
-#define NUM_REG_SETS 64
-#endif
-
-/* General purpose register aliases */
-enum {
- R_ZERO = 0,
- R_AT = 1,
- R_RET0 = 2,
- R_RET1 = 3,
- R_ARG0 = 4,
- R_ARG1 = 5,
- R_ARG2 = 6,
- R_ARG3 = 7,
- R_ET = 24,
- R_BT = 25,
- R_GP = 26,
- R_SP = 27,
- R_FP = 28,
- R_EA = 29,
- R_BA = 30,
- R_SSTATUS = 30,
- R_RA = 31,
-};
-
-/* Control register aliases */
-enum {
- CR_STATUS = 0,
- CR_ESTATUS = 1,
- CR_BSTATUS = 2,
- CR_IENABLE = 3,
- CR_IPENDING = 4,
- CR_CPUID = 5,
- CR_EXCEPTION = 7,
- CR_PTEADDR = 8,
- CR_TLBACC = 9,
- CR_TLBMISC = 10,
- CR_ENCINJ = 11,
- CR_BADADDR = 12,
- CR_CONFIG = 13,
- CR_MPUBASE = 14,
- CR_MPUACC = 15,
-};
-
-FIELD(CR_STATUS, PIE, 0, 1)
-FIELD(CR_STATUS, U, 1, 1)
-FIELD(CR_STATUS, EH, 2, 1)
-FIELD(CR_STATUS, IH, 3, 1)
-FIELD(CR_STATUS, IL, 4, 6)
-FIELD(CR_STATUS, CRS, 10, 6)
-FIELD(CR_STATUS, PRS, 16, 6)
-FIELD(CR_STATUS, NMI, 22, 1)
-FIELD(CR_STATUS, RSIE, 23, 1)
-FIELD(CR_STATUS, SRS, 31, 1) /* only in sstatus */
-
-#define CR_STATUS_PIE R_CR_STATUS_PIE_MASK
-#define CR_STATUS_U R_CR_STATUS_U_MASK
-#define CR_STATUS_EH R_CR_STATUS_EH_MASK
-#define CR_STATUS_IH R_CR_STATUS_IH_MASK
-#define CR_STATUS_NMI R_CR_STATUS_NMI_MASK
-#define CR_STATUS_RSIE R_CR_STATUS_RSIE_MASK
-#define CR_STATUS_SRS R_CR_STATUS_SRS_MASK
-
-FIELD(CR_EXCEPTION, CAUSE, 2, 5)
-FIELD(CR_EXCEPTION, ECCFTL, 31, 1)
-
-FIELD(CR_PTEADDR, VPN, 2, 20)
-FIELD(CR_PTEADDR, PTBASE, 22, 10)
-
-FIELD(CR_TLBACC, PFN, 0, 20)
-FIELD(CR_TLBACC, G, 20, 1)
-FIELD(CR_TLBACC, X, 21, 1)
-FIELD(CR_TLBACC, W, 22, 1)
-FIELD(CR_TLBACC, R, 23, 1)
-FIELD(CR_TLBACC, C, 24, 1)
-FIELD(CR_TLBACC, IG, 25, 7)
-
-#define CR_TLBACC_C R_CR_TLBACC_C_MASK
-#define CR_TLBACC_R R_CR_TLBACC_R_MASK
-#define CR_TLBACC_W R_CR_TLBACC_W_MASK
-#define CR_TLBACC_X R_CR_TLBACC_X_MASK
-#define CR_TLBACC_G R_CR_TLBACC_G_MASK
-
-FIELD(CR_TLBMISC, D, 0, 1)
-FIELD(CR_TLBMISC, PERM, 1, 1)
-FIELD(CR_TLBMISC, BAD, 2, 1)
-FIELD(CR_TLBMISC, DBL, 3, 1)
-FIELD(CR_TLBMISC, PID, 4, 14)
-FIELD(CR_TLBMISC, WE, 18, 1)
-FIELD(CR_TLBMISC, RD, 19, 1)
-FIELD(CR_TLBMISC, WAY, 20, 4)
-FIELD(CR_TLBMISC, EE, 24, 1)
-
-#define CR_TLBMISC_EE R_CR_TLBMISC_EE_MASK
-#define CR_TLBMISC_RD R_CR_TLBMISC_RD_MASK
-#define CR_TLBMISC_WE R_CR_TLBMISC_WE_MASK
-#define CR_TLBMISC_DBL R_CR_TLBMISC_DBL_MASK
-#define CR_TLBMISC_BAD R_CR_TLBMISC_BAD_MASK
-#define CR_TLBMISC_PERM R_CR_TLBMISC_PERM_MASK
-#define CR_TLBMISC_D R_CR_TLBMISC_D_MASK
-
-/* Exceptions */
-#define EXCP_BREAK 0x1000
-#define EXCP_SEMIHOST 0x1001
-#define EXCP_RESET 0
-#define EXCP_PRESET 1
-#define EXCP_IRQ 2
-#define EXCP_TRAP 3
-#define EXCP_UNIMPL 4
-#define EXCP_ILLEGAL 5
-#define EXCP_UNALIGN 6
-#define EXCP_UNALIGND 7
-#define EXCP_DIV 8
-#define EXCP_SUPERA_X 9
-#define EXCP_SUPERI 10
-#define EXCP_SUPERA_D 11
-#define EXCP_TLB_X 12
-#define EXCP_TLB_D (0x1000 | EXCP_TLB_X)
-#define EXCP_PERM_X 13
-#define EXCP_PERM_R 14
-#define EXCP_PERM_W 15
-#define EXCP_MPUI 16
-#define EXCP_MPUD 17
-
-struct CPUArchState {
-#ifdef CONFIG_USER_ONLY
- uint32_t regs[NUM_GP_REGS];
-#else
- uint32_t shadow_regs[NUM_REG_SETS][NUM_GP_REGS];
- /* Pointer into shadow_regs for the current register set. */
- uint32_t *regs;
-#endif
- uint32_t ctrl[NUM_CR_REGS];
- uint32_t pc;
-
-#if !defined(CONFIG_USER_ONLY)
- Nios2MMU mmu;
-#endif
- int error_code;
-};
-
-typedef struct {
- uint32_t writable;
- uint32_t readonly;
-} ControlRegState;
-
-/**
- * Nios2CPU:
- * @env: #CPUNios2State
- *
- * A Nios2 CPU.
- */
-struct ArchCPU {
- CPUState parent_obj;
-
- CPUNios2State env;
-
- bool diverr_present;
- bool mmu_present;
- bool eic_present;
-
- uint32_t pid_num_bits;
- uint32_t tlb_num_ways;
- uint32_t tlb_num_entries;
-
- /* Addresses that are hard-coded in the FPGA build settings */
- uint32_t reset_addr;
- uint32_t exception_addr;
- uint32_t fast_tlb_miss_addr;
-
- /* Bits within each control register which are reserved or readonly. */
- ControlRegState cr_state[NUM_CR_REGS];
-
- /* External Interrupt Controller Interface */
- uint32_t rha; /* Requested handler address */
- uint32_t ril; /* Requested interrupt level */
- uint32_t rrs; /* Requested register set */
- bool rnmi; /* Requested nonmaskable interrupt */
-};
-
-
-static inline bool nios2_cr_reserved(const ControlRegState *s)
-{
- return (s->writable | s->readonly) == 0;
-}
-
-static inline void nios2_update_crs(CPUNios2State *env)
-{
-#ifndef CONFIG_USER_ONLY
- unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS);
- env->regs = env->shadow_regs[crs];
-#endif
-}
-
-void nios2_tcg_init(void);
-void nios2_cpu_do_interrupt(CPUState *cs);
-void dump_mmu(CPUNios2State *env);
-void nios2_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
-G_NORETURN void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
- MMUAccessType access_type, int mmu_idx,
- uintptr_t retaddr);
-G_NORETURN void nios2_cpu_loop_exit_advance(CPUNios2State *env,
- uintptr_t retaddr);
-
-void do_nios2_semihosting(CPUNios2State *env);
-
-#define CPU_RESOLVING_TYPE TYPE_NIOS2_CPU
-
-#define cpu_gen_code cpu_nios2_gen_code
-
-#define CPU_SAVE_VERSION 1
-
-/* MMU modes definitions */
-#define MMU_SUPERVISOR_IDX 0
-#define MMU_USER_IDX 1
-
-#ifndef CONFIG_USER_ONLY
-hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
-#endif
-
-typedef CPUNios2State CPUArchState;
-typedef Nios2CPU ArchCPU;
-
-#include "exec/cpu-all.h"
-
-FIELD(TBFLAGS, CRS0, 0, 1) /* Set if CRS == 0. */
-FIELD(TBFLAGS, U, 1, 1) /* Overlaps CR_STATUS_U */
-FIELD(TBFLAGS, R0_0, 2, 1) /* Set if R0 == 0. */
-
-static inline void cpu_get_tb_cpu_state(CPUNios2State *env, vaddr *pc,
- uint64_t *cs_base, uint32_t *flags)
-{
- unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS);
-
- *pc = env->pc;
- *cs_base = 0;
- *flags = (env->ctrl[CR_STATUS] & CR_STATUS_U)
- | (crs ? 0 : R_TBFLAGS_CRS0_MASK)
- | (env->regs[0] ? 0 : R_TBFLAGS_R0_0_MASK);
-}
-
-#endif /* NIOS2_CPU_H */
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
deleted file mode 100644
index ac57121..0000000
--- a/target/nios2/helper.c
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Altera Nios II helper routines.
- *
- * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/lgpl-2.1.html>
- */
-
-#include "qemu/osdep.h"
-
-#include "cpu.h"
-#include "qemu/host-utils.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "exec/log.h"
-#include "exec/helper-proto.h"
-#include "semihosting/semihost.h"
-
-
-static void do_exception(Nios2CPU *cpu, uint32_t exception_addr,
- uint32_t tlbmisc_set, bool is_break)
-{
- CPUNios2State *env = &cpu->env;
- CPUState *cs = CPU(cpu);
- uint32_t old_status = env->ctrl[CR_STATUS];
- uint32_t new_status = old_status;
-
- /* With shadow regs, exceptions are always taken into CRS 0. */
- new_status &= ~R_CR_STATUS_CRS_MASK;
- env->regs = env->shadow_regs[0];
-
- if ((old_status & CR_STATUS_EH) == 0) {
- int r_ea = R_EA, cr_es = CR_ESTATUS;
-
- if (is_break) {
- r_ea = R_BA;
- cr_es = CR_BSTATUS;
- }
- env->ctrl[cr_es] = old_status;
- env->regs[r_ea] = env->pc;
-
- if (cpu->mmu_present) {
- new_status |= CR_STATUS_EH;
-
- /*
- * There are 4 bits that are always written.
- * Explicitly clear them, to be set via the argument.
- */
- env->ctrl[CR_TLBMISC] &= ~(CR_TLBMISC_D |
- CR_TLBMISC_PERM |
- CR_TLBMISC_BAD |
- CR_TLBMISC_DBL);
- env->ctrl[CR_TLBMISC] |= tlbmisc_set;
- }
-
- /*
- * With shadow regs, and EH == 0, PRS is set from CRS.
- * At least, so says Table 3-9, and some other text,
- * though Table 3-38 says otherwise.
- */
- new_status = FIELD_DP32(new_status, CR_STATUS, PRS,
- FIELD_EX32(old_status, CR_STATUS, CRS));
- }
-
- new_status &= ~(CR_STATUS_PIE | CR_STATUS_U);
-
- env->ctrl[CR_STATUS] = new_status;
- if (!is_break) {
- env->ctrl[CR_EXCEPTION] = FIELD_DP32(0, CR_EXCEPTION, CAUSE,
- cs->exception_index);
- }
- env->pc = exception_addr;
-}
-
-static void do_iic_irq(Nios2CPU *cpu)
-{
- do_exception(cpu, cpu->exception_addr, 0, false);
-}
-
-static void do_eic_irq(Nios2CPU *cpu)
-{
- CPUNios2State *env = &cpu->env;
- uint32_t old_status = env->ctrl[CR_STATUS];
- uint32_t new_status = old_status;
- uint32_t old_rs = FIELD_EX32(old_status, CR_STATUS, CRS);
- uint32_t new_rs = cpu->rrs;
-
- new_status = FIELD_DP32(new_status, CR_STATUS, CRS, new_rs);
- new_status = FIELD_DP32(new_status, CR_STATUS, IL, cpu->ril);
- new_status = FIELD_DP32(new_status, CR_STATUS, NMI, cpu->rnmi);
- new_status &= ~(CR_STATUS_RSIE | CR_STATUS_U);
- new_status |= CR_STATUS_IH;
-
- if (!(new_status & CR_STATUS_EH)) {
- new_status = FIELD_DP32(new_status, CR_STATUS, PRS, old_rs);
- if (new_rs == 0) {
- env->ctrl[CR_ESTATUS] = old_status;
- } else {
- if (new_rs != old_rs) {
- old_status |= CR_STATUS_SRS;
- }
- env->shadow_regs[new_rs][R_SSTATUS] = old_status;
- }
- env->shadow_regs[new_rs][R_EA] = env->pc;
- }
-
- env->ctrl[CR_STATUS] = new_status;
- nios2_update_crs(env);
-
- env->pc = cpu->rha;
-}
-
-void nios2_cpu_do_interrupt(CPUState *cs)
-{
- Nios2CPU *cpu = NIOS2_CPU(cs);
- CPUNios2State *env = &cpu->env;
- uint32_t tlbmisc_set = 0;
-
- if (qemu_loglevel_mask(CPU_LOG_INT)) {
- const char *name = NULL;
-
- switch (cs->exception_index) {
- case EXCP_IRQ:
- name = "interrupt";
- break;
- case EXCP_TLB_X:
- case EXCP_TLB_D:
- if (env->ctrl[CR_STATUS] & CR_STATUS_EH) {
- name = "TLB MISS (double)";
- } else {
- name = "TLB MISS (fast)";
- }
- break;
- case EXCP_PERM_R:
- case EXCP_PERM_W:
- case EXCP_PERM_X:
- name = "TLB PERM";
- break;
- case EXCP_SUPERA_X:
- case EXCP_SUPERA_D:
- name = "SUPERVISOR (address)";
- break;
- case EXCP_SUPERI:
- name = "SUPERVISOR (insn)";
- break;
- case EXCP_ILLEGAL:
- name = "ILLEGAL insn";
- break;
- case EXCP_UNALIGN:
- name = "Misaligned (data)";
- break;
- case EXCP_UNALIGND:
- name = "Misaligned (destination)";
- break;
- case EXCP_DIV:
- name = "DIV error";
- break;
- case EXCP_TRAP:
- name = "TRAP insn";
- break;
- case EXCP_BREAK:
- name = "BREAK insn";
- break;
- case EXCP_SEMIHOST:
- name = "SEMIHOST insn";
- break;
- }
- if (name) {
- qemu_log("%s at pc=0x%08x\n", name, env->pc);
- } else {
- qemu_log("Unknown exception %d at pc=0x%08x\n",
- cs->exception_index, env->pc);
- }
- }
-
- switch (cs->exception_index) {
- case EXCP_IRQ:
- /* Note that PC is advanced for interrupts as well. */
- env->pc += 4;
- if (cpu->eic_present) {
- do_eic_irq(cpu);
- } else {
- do_iic_irq(cpu);
- }
- break;
-
- case EXCP_TLB_D:
- tlbmisc_set = CR_TLBMISC_D;
- /* fall through */
- case EXCP_TLB_X:
- if (env->ctrl[CR_STATUS] & CR_STATUS_EH) {
- tlbmisc_set |= CR_TLBMISC_DBL;
- /*
- * Normally, we don't write to tlbmisc unless !EH,
- * so do it manually for the double-tlb miss exception.
- */
- env->ctrl[CR_TLBMISC] &= ~(CR_TLBMISC_D |
- CR_TLBMISC_PERM |
- CR_TLBMISC_BAD);
- env->ctrl[CR_TLBMISC] |= tlbmisc_set;
- do_exception(cpu, cpu->exception_addr, 0, false);
- } else {
- tlbmisc_set |= CR_TLBMISC_WE;
- do_exception(cpu, cpu->fast_tlb_miss_addr, tlbmisc_set, false);
- }
- break;
-
- case EXCP_PERM_R:
- case EXCP_PERM_W:
- tlbmisc_set = CR_TLBMISC_D;
- /* fall through */
- case EXCP_PERM_X:
- tlbmisc_set |= CR_TLBMISC_PERM;
- if (!(env->ctrl[CR_STATUS] & CR_STATUS_EH)) {
- tlbmisc_set |= CR_TLBMISC_WE;
- }
- do_exception(cpu, cpu->exception_addr, tlbmisc_set, false);
- break;
-
- case EXCP_SUPERA_D:
- case EXCP_UNALIGN:
- tlbmisc_set = CR_TLBMISC_D;
- /* fall through */
- case EXCP_SUPERA_X:
- case EXCP_UNALIGND:
- tlbmisc_set |= CR_TLBMISC_BAD;
- do_exception(cpu, cpu->exception_addr, tlbmisc_set, false);
- break;
-
- case EXCP_SUPERI:
- case EXCP_ILLEGAL:
- case EXCP_DIV:
- case EXCP_TRAP:
- do_exception(cpu, cpu->exception_addr, 0, false);
- break;
-
- case EXCP_BREAK:
- do_exception(cpu, cpu->exception_addr, 0, true);
- break;
-
- case EXCP_SEMIHOST:
- do_nios2_semihosting(env);
- break;
-
- default:
- cpu_abort(cs, "unhandled exception type=%d\n", cs->exception_index);
- }
-}
-
-hwaddr nios2_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
-{
- Nios2CPU *cpu = NIOS2_CPU(cs);
- CPUNios2State *env = &cpu->env;
- target_ulong vaddr, paddr = 0;
- Nios2MMULookup lu;
- unsigned int hit;
-
- if (cpu->mmu_present && (addr < 0xC0000000)) {
- hit = mmu_translate(env, &lu, addr, 0, 0);
- if (hit) {
- vaddr = addr & TARGET_PAGE_MASK;
- paddr = lu.paddr + vaddr - lu.vaddr;
- } else {
- paddr = -1;
- qemu_log("cpu_get_phys_page debug MISS: %#" PRIx64 "\n", addr);
- }
- } else {
- paddr = addr & TARGET_PAGE_MASK;
- }
-
- return paddr;
-}
-
-void nios2_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
- MMUAccessType access_type,
- int mmu_idx, uintptr_t retaddr)
-{
- CPUNios2State *env = cpu_env(cs);
-
- env->ctrl[CR_BADADDR] = addr;
- cs->exception_index = EXCP_UNALIGN;
- nios2_cpu_loop_exit_advance(env, retaddr);
-}
-
-bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr)
-{
- Nios2CPU *cpu = NIOS2_CPU(cs);
- CPUNios2State *env = &cpu->env;
- unsigned int excp;
- target_ulong vaddr, paddr;
- Nios2MMULookup lu;
- unsigned int hit;
-
- if (!cpu->mmu_present) {
- /* No MMU */
- address &= TARGET_PAGE_MASK;
- tlb_set_page(cs, address, address, PAGE_BITS,
- mmu_idx, TARGET_PAGE_SIZE);
- return true;
- }
-
- if (MMU_SUPERVISOR_IDX == mmu_idx) {
- if (address >= 0xC0000000) {
- /* Kernel physical page - TLB bypassed */
- address &= TARGET_PAGE_MASK;
- tlb_set_page(cs, address, address, PAGE_BITS,
- mmu_idx, TARGET_PAGE_SIZE);
- return true;
- }
- } else {
- if (address >= 0x80000000) {
- /* Illegal access from user mode */
- if (probe) {
- return false;
- }
- cs->exception_index = (access_type == MMU_INST_FETCH
- ? EXCP_SUPERA_X : EXCP_SUPERA_D);
- env->ctrl[CR_BADADDR] = address;
- nios2_cpu_loop_exit_advance(env, retaddr);
- }
- }
-
- /* Virtual page. */
- hit = mmu_translate(env, &lu, address, access_type, mmu_idx);
- if (hit) {
- vaddr = address & TARGET_PAGE_MASK;
- paddr = lu.paddr + vaddr - lu.vaddr;
-
- if (((access_type == MMU_DATA_LOAD) && (lu.prot & PAGE_READ)) ||
- ((access_type == MMU_DATA_STORE) && (lu.prot & PAGE_WRITE)) ||
- ((access_type == MMU_INST_FETCH) && (lu.prot & PAGE_EXEC))) {
- tlb_set_page(cs, vaddr, paddr, lu.prot,
- mmu_idx, TARGET_PAGE_SIZE);
- return true;
- }
-
- /* Permission violation */
- excp = (access_type == MMU_DATA_LOAD ? EXCP_PERM_R :
- access_type == MMU_DATA_STORE ? EXCP_PERM_W : EXCP_PERM_X);
- } else {
- excp = (access_type == MMU_INST_FETCH ? EXCP_TLB_X: EXCP_TLB_D);
- }
-
- if (probe) {
- return false;
- }
-
- env->ctrl[CR_TLBMISC] = FIELD_DP32(env->ctrl[CR_TLBMISC], CR_TLBMISC, D,
- access_type != MMU_INST_FETCH);
- env->ctrl[CR_PTEADDR] = FIELD_DP32(env->ctrl[CR_PTEADDR], CR_PTEADDR, VPN,
- address >> TARGET_PAGE_BITS);
- env->mmu.pteaddr_wr = env->ctrl[CR_PTEADDR];
-
- cs->exception_index = excp;
- env->ctrl[CR_BADADDR] = address;
- nios2_cpu_loop_exit_advance(env, retaddr);
-}
diff --git a/target/nios2/helper.h b/target/nios2/helper.h
deleted file mode 100644
index 1648d76..0000000
--- a/target/nios2/helper.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Altera Nios II helper routines header.
- *
- * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/lgpl-2.1.html>
- */
-
-DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32)
-DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_WG, s32, env, s32, s32)
-DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32)
-
-#if !defined(CONFIG_USER_ONLY)
-DEF_HELPER_3(eret, noreturn, env, i32, i32)
-DEF_HELPER_FLAGS_2(rdprs, TCG_CALL_NO_WG, i32, env, i32)
-DEF_HELPER_3(wrprs, void, env, i32, i32)
-DEF_HELPER_2(mmu_write_tlbacc, void, env, i32)
-DEF_HELPER_2(mmu_write_tlbmisc, void, env, i32)
-DEF_HELPER_2(mmu_write_pteaddr, void, env, i32)
-#endif
diff --git a/target/nios2/meson.build b/target/nios2/meson.build
deleted file mode 100644
index 12d8abf..0000000
--- a/target/nios2/meson.build
+++ /dev/null
@@ -1,17 +0,0 @@
-nios2_ss = ss.source_set()
-nios2_ss.add(files(
- 'cpu.c',
- 'op_helper.c',
- 'translate.c',
-))
-
-nios2_system_ss = ss.source_set()
-nios2_system_ss.add(files(
- 'helper.c',
- 'monitor.c',
- 'mmu.c',
- 'nios2-semi.c',
-))
-
-target_arch += {'nios2': nios2_ss}
-target_system_arch += {'nios2': nios2_system_ss}
diff --git a/target/nios2/mmu.c b/target/nios2/mmu.c
deleted file mode 100644
index d9b690b..0000000
--- a/target/nios2/mmu.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Altera Nios II MMU emulation for qemu.
- *
- * Copyright (C) 2012 Chris Wulff <crwulff@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/lgpl-2.1.html>
- */
-
-#include "qemu/osdep.h"
-#include "qemu/qemu-print.h"
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "mmu.h"
-#include "exec/helper-proto.h"
-#include "trace/trace-target_nios2.h"
-
-
-/* rw - 0 = read, 1 = write, 2 = fetch. */
-unsigned int mmu_translate(CPUNios2State *env,
- Nios2MMULookup *lu,
- target_ulong vaddr, int rw, int mmu_idx)
-{
- Nios2CPU *cpu = env_archcpu(env);
- int pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID);
- int vpn = vaddr >> 12;
- int way, n_ways = cpu->tlb_num_ways;
-
- for (way = 0; way < n_ways; way++) {
- uint32_t index = (way * n_ways) + (vpn & env->mmu.tlb_entry_mask);
- Nios2TLBEntry *entry = &env->mmu.tlb[index];
-
- if (((entry->tag >> 12) != vpn) ||
- (((entry->tag & (1 << 11)) == 0) &&
- ((entry->tag & ((1 << cpu->pid_num_bits) - 1)) != pid))) {
- trace_nios2_mmu_translate_miss(vaddr, pid, index, entry->tag);
- continue;
- }
-
- lu->vaddr = vaddr & TARGET_PAGE_MASK;
- lu->paddr = FIELD_EX32(entry->data, CR_TLBACC, PFN) << TARGET_PAGE_BITS;
- lu->prot = ((entry->data & CR_TLBACC_R) ? PAGE_READ : 0) |
- ((entry->data & CR_TLBACC_W) ? PAGE_WRITE : 0) |
- ((entry->data & CR_TLBACC_X) ? PAGE_EXEC : 0);
-
- trace_nios2_mmu_translate_hit(vaddr, pid, index, lu->paddr, lu->prot);
- return 1;
- }
- return 0;
-}
-
-static void mmu_flush_pid(CPUNios2State *env, uint32_t pid)
-{
- CPUState *cs = env_cpu(env);
- Nios2CPU *cpu = env_archcpu(env);
- int idx;
-
- for (idx = 0; idx < cpu->tlb_num_entries; idx++) {
- Nios2TLBEntry *entry = &env->mmu.tlb[idx];
-
- if ((entry->tag & (1 << 10)) && (!(entry->tag & (1 << 11))) &&
- ((entry->tag & ((1 << cpu->pid_num_bits) - 1)) == pid)) {
- uint32_t vaddr = entry->tag & TARGET_PAGE_MASK;
-
- trace_nios2_mmu_flush_pid_hit(pid, idx, vaddr);
- tlb_flush_page(cs, vaddr);
- } else {
- trace_nios2_mmu_flush_pid_miss(pid, idx, entry->tag);
- }
- }
-}
-
-void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
-{
- CPUState *cs = env_cpu(env);
- Nios2CPU *cpu = env_archcpu(env);
-
- trace_nios2_mmu_write_tlbacc(FIELD_EX32(v, CR_TLBACC, IG),
- (v & CR_TLBACC_C) ? 'C' : '.',
- (v & CR_TLBACC_R) ? 'R' : '.',
- (v & CR_TLBACC_W) ? 'W' : '.',
- (v & CR_TLBACC_X) ? 'X' : '.',
- (v & CR_TLBACC_G) ? 'G' : '.',
- FIELD_EX32(v, CR_TLBACC, PFN));
-
- /* if tlbmisc.WE == 1 then trigger a TLB write on writes to TLBACC */
- if (env->ctrl[CR_TLBMISC] & CR_TLBMISC_WE) {
- int way = FIELD_EX32(env->ctrl[CR_TLBMISC], CR_TLBMISC, WAY);
- int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
- int pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID);
- int g = FIELD_EX32(v, CR_TLBACC, G);
- int valid = FIELD_EX32(vpn, CR_TLBACC, PFN) < 0xC0000;
- Nios2TLBEntry *entry =
- &env->mmu.tlb[(way * cpu->tlb_num_ways) +
- (vpn & env->mmu.tlb_entry_mask)];
- uint32_t newTag = (vpn << 12) | (g << 11) | (valid << 10) | pid;
- uint32_t newData = v & (CR_TLBACC_C | CR_TLBACC_R | CR_TLBACC_W |
- CR_TLBACC_X | R_CR_TLBACC_PFN_MASK);
-
- if ((entry->tag != newTag) || (entry->data != newData)) {
- if (entry->tag & (1 << 10)) {
- /* Flush existing entry */
- tlb_flush_page(cs, entry->tag & TARGET_PAGE_MASK);
- }
- entry->tag = newTag;
- entry->data = newData;
- }
- /* Auto-increment tlbmisc.WAY */
- env->ctrl[CR_TLBMISC] = FIELD_DP32(env->ctrl[CR_TLBMISC],
- CR_TLBMISC, WAY,
- (way + 1) & (cpu->tlb_num_ways - 1));
- }
-
- /* Writes to TLBACC don't change the read-back value */
- env->mmu.tlbacc_wr = v;
-}
-
-void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
-{
- Nios2CPU *cpu = env_archcpu(env);
- uint32_t new_pid = FIELD_EX32(v, CR_TLBMISC, PID);
- uint32_t old_pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID);
- uint32_t way = FIELD_EX32(v, CR_TLBMISC, WAY);
-
- trace_nios2_mmu_write_tlbmisc(way,
- (v & CR_TLBMISC_RD) ? 'R' : '.',
- (v & CR_TLBMISC_WE) ? 'W' : '.',
- (v & CR_TLBMISC_DBL) ? '2' : '.',
- (v & CR_TLBMISC_BAD) ? 'B' : '.',
- (v & CR_TLBMISC_PERM) ? 'P' : '.',
- (v & CR_TLBMISC_D) ? 'D' : '.',
- new_pid);
-
- if (new_pid != old_pid) {
- mmu_flush_pid(env, old_pid);
- }
-
- /* if tlbmisc.RD == 1 then trigger a TLB read on writes to TLBMISC */
- if (v & CR_TLBMISC_RD) {
- int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
- Nios2TLBEntry *entry =
- &env->mmu.tlb[(way * cpu->tlb_num_ways) +
- (vpn & env->mmu.tlb_entry_mask)];
-
- env->ctrl[CR_TLBACC] &= R_CR_TLBACC_IG_MASK;
- env->ctrl[CR_TLBACC] |= entry->data;
- env->ctrl[CR_TLBACC] |= (entry->tag & (1 << 11)) ? CR_TLBACC_G : 0;
- env->ctrl[CR_TLBMISC] = FIELD_DP32(v, CR_TLBMISC, PID,
- entry->tag &
- ((1 << cpu->pid_num_bits) - 1));
- env->ctrl[CR_PTEADDR] = FIELD_DP32(env->ctrl[CR_PTEADDR],
- CR_PTEADDR, VPN,
- entry->tag >> TARGET_PAGE_BITS);
- } else {
- env->ctrl[CR_TLBMISC] = v;
- }
-
- env->mmu.tlbmisc_wr = v;
-}
-
-void helper_mmu_write_pteaddr(CPUNios2State *env, uint32_t v)
-{
- trace_nios2_mmu_write_pteaddr(FIELD_EX32(v, CR_PTEADDR, PTBASE),
- FIELD_EX32(v, CR_PTEADDR, VPN));
-
- /* Writes to PTEADDR don't change the read-back VPN value */
- env->ctrl[CR_PTEADDR] = ((v & ~R_CR_PTEADDR_VPN_MASK) |
- (env->ctrl[CR_PTEADDR] & R_CR_PTEADDR_VPN_MASK));
- env->mmu.pteaddr_wr = v;
-}
-
-void mmu_init(CPUNios2State *env)
-{
- Nios2CPU *cpu = env_archcpu(env);
- Nios2MMU *mmu = &env->mmu;
-
- mmu->tlb_entry_mask = (cpu->tlb_num_entries / cpu->tlb_num_ways) - 1;
- mmu->tlb = g_new0(Nios2TLBEntry, cpu->tlb_num_entries);
-}
-
-void dump_mmu(CPUNios2State *env)
-{
- Nios2CPU *cpu = env_archcpu(env);
- int i;
-
- qemu_printf("MMU: ways %d, entries %d, pid bits %d\n",
- cpu->tlb_num_ways, cpu->tlb_num_entries,
- cpu->pid_num_bits);
-
- for (i = 0; i < cpu->tlb_num_entries; i++) {
- Nios2TLBEntry *entry = &env->mmu.tlb[i];
- qemu_printf("TLB[%d] = %08X %08X %c VPN %05X "
- "PID %02X %c PFN %05X %c%c%c%c\n",
- i, entry->tag, entry->data,
- (entry->tag & (1 << 10)) ? 'V' : '-',
- entry->tag >> 12,
- entry->tag & ((1 << cpu->pid_num_bits) - 1),
- (entry->tag & (1 << 11)) ? 'G' : '-',
- FIELD_EX32(entry->data, CR_TLBACC, PFN),
- (entry->data & CR_TLBACC_C) ? 'C' : '-',
- (entry->data & CR_TLBACC_R) ? 'R' : '-',
- (entry->data & CR_TLBACC_W) ? 'W' : '-',
- (entry->data & CR_TLBACC_X) ? 'X' : '-');
- }
-}
diff --git a/target/nios2/mmu.h b/target/nios2/mmu.h
deleted file mode 100644
index 5b08590..0000000
--- a/target/nios2/mmu.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Altera Nios II MMU emulation for qemu.
- *
- * Copyright (C) 2012 Chris Wulff <crwulff@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/lgpl-2.1.html>
- */
-
-#ifndef NIOS2_MMU_H
-#define NIOS2_MMU_H
-
-#include "cpu.h"
-
-typedef struct Nios2TLBEntry {
- target_ulong tag;
- target_ulong data;
-} Nios2TLBEntry;
-
-typedef struct Nios2MMU {
- int tlb_entry_mask;
- uint32_t pteaddr_wr;
- uint32_t tlbacc_wr;
- uint32_t tlbmisc_wr;
- Nios2TLBEntry *tlb;
-} Nios2MMU;
-
-typedef struct Nios2MMULookup {
- target_ulong vaddr;
- target_ulong paddr;
- int prot;
-} Nios2MMULookup;
-
-void mmu_flip_um(CPUNios2State *env, unsigned int um);
-unsigned int mmu_translate(CPUNios2State *env,
- Nios2MMULookup *lu,
- target_ulong vaddr, int rw, int mmu_idx);
-void mmu_write(CPUNios2State *env, uint32_t rn, uint32_t v);
-void mmu_init(CPUNios2State *env);
-
-#endif /* NIOS2_MMU_H */
diff --git a/target/nios2/monitor.c b/target/nios2/monitor.c
deleted file mode 100644
index 0152dec..0000000
--- a/target/nios2/monitor.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * QEMU monitor
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "monitor/monitor.h"
-#include "monitor/hmp-target.h"
-#include "monitor/hmp.h"
-
-void hmp_info_tlb(Monitor *mon, const QDict *qdict)
-{
- CPUArchState *env1 = mon_get_cpu_env(mon);
-
- dump_mmu(env1);
-}
diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
deleted file mode 100644
index 420702e..0000000
--- a/target/nios2/nios2-semi.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Nios II Semihosting syscall interface.
- * This code is derived from m68k-semi.c.
- * The semihosting protocol implemented here is described in the
- * libgloss sources:
- * https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/nios2/nios2-semi.txt;hb=HEAD
- *
- * Copyright (c) 2017-2019 Mentor Graphics
- *
- * 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 2 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "gdbstub/syscalls.h"
-#include "gdbstub/helpers.h"
-#include "semihosting/syscalls.h"
-#include "semihosting/uaccess.h"
-#include "qemu/log.h"
-
-#define HOSTED_EXIT 0
-#define HOSTED_INIT_SIM 1
-#define HOSTED_OPEN 2
-#define HOSTED_CLOSE 3
-#define HOSTED_READ 4
-#define HOSTED_WRITE 5
-#define HOSTED_LSEEK 6
-#define HOSTED_RENAME 7
-#define HOSTED_UNLINK 8
-#define HOSTED_STAT 9
-#define HOSTED_FSTAT 10
-#define HOSTED_GETTIMEOFDAY 11
-#define HOSTED_ISATTY 12
-#define HOSTED_SYSTEM 13
-
-static int host_to_gdb_errno(int err)
-{
-#define E(X) case E##X: return GDB_E##X
- switch (err) {
- E(PERM);
- E(NOENT);
- E(INTR);
- E(BADF);
- E(ACCES);
- E(FAULT);
- E(BUSY);
- E(EXIST);
- E(NODEV);
- E(NOTDIR);
- E(ISDIR);
- E(INVAL);
- E(NFILE);
- E(MFILE);
- E(FBIG);
- E(NOSPC);
- E(SPIPE);
- E(ROFS);
- E(NAMETOOLONG);
- default:
- return GDB_EUNKNOWN;
- }
-#undef E
-}
-
-static void nios2_semi_u32_cb(CPUState *cs, uint64_t ret, int err)
-{
- CPUNios2State *env = cpu_env(cs);
- target_ulong args = env->regs[R_ARG1];
-
- if (put_user_u32(ret, args) ||
- put_user_u32(host_to_gdb_errno(err), args + 4)) {
- /*
- * The nios2 semihosting ABI does not provide any way to report this
- * error to the guest, so the best we can do is log it in qemu.
- * It is always a guest error not to pass us a valid argument block.
- */
- qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: return value "
- "discarded because argument block not writable\n");
- }
-}
-
-static void nios2_semi_u64_cb(CPUState *cs, uint64_t ret, int err)
-{
- CPUNios2State *env = cpu_env(cs);
- target_ulong args = env->regs[R_ARG1];
-
- if (put_user_u32(ret >> 32, args) ||
- put_user_u32(ret, args + 4) ||
- put_user_u32(host_to_gdb_errno(err), args + 8)) {
- /* No way to report this via nios2 semihosting ABI; just log it */
- qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: return value "
- "discarded because argument block not writable\n");
- }
-}
-
-/*
- * Read the input value from the argument block; fail the semihosting
- * call if the memory read fails.
- */
-#define GET_ARG(n) do { \
- if (get_user_ual(arg ## n, args + (n) * 4)) { \
- goto failed; \
- } \
-} while (0)
-
-#define GET_ARG64(n) do { \
- if (get_user_ual(arg ## n, args + (n) * 4)) { \
- goto failed64; \
- } \
-} while (0)
-
-void do_nios2_semihosting(CPUNios2State *env)
-{
- CPUState *cs = env_cpu(env);
- int nr;
- uint32_t args;
- target_ulong arg0, arg1, arg2, arg3;
-
- nr = env->regs[R_ARG0];
- args = env->regs[R_ARG1];
- switch (nr) {
- case HOSTED_EXIT:
- gdb_exit(env->regs[R_ARG1]);
- exit(env->regs[R_ARG1]);
-
- case HOSTED_OPEN:
- GET_ARG(0);
- GET_ARG(1);
- GET_ARG(2);
- GET_ARG(3);
- semihost_sys_open(cs, nios2_semi_u32_cb, arg0, arg1, arg2, arg3);
- break;
-
- case HOSTED_CLOSE:
- GET_ARG(0);
- semihost_sys_close(cs, nios2_semi_u32_cb, arg0);
- break;
-
- case HOSTED_READ:
- GET_ARG(0);
- GET_ARG(1);
- GET_ARG(2);
- semihost_sys_read(cs, nios2_semi_u32_cb, arg0, arg1, arg2);
- break;
-
- case HOSTED_WRITE:
- GET_ARG(0);
- GET_ARG(1);
- GET_ARG(2);
- semihost_sys_write(cs, nios2_semi_u32_cb, arg0, arg1, arg2);
- break;
-
- case HOSTED_LSEEK:
- GET_ARG64(0);
- GET_ARG64(1);
- GET_ARG64(2);
- GET_ARG64(3);
- semihost_sys_lseek(cs, nios2_semi_u64_cb, arg0,
- deposit64(arg2, 32, 32, arg1), arg3);
- break;
-
- case HOSTED_RENAME:
- GET_ARG(0);
- GET_ARG(1);
- GET_ARG(2);
- GET_ARG(3);
- semihost_sys_rename(cs, nios2_semi_u32_cb, arg0, arg1, arg2, arg3);
- break;
-
- case HOSTED_UNLINK:
- GET_ARG(0);
- GET_ARG(1);
- semihost_sys_remove(cs, nios2_semi_u32_cb, arg0, arg1);
- break;
-
- case HOSTED_STAT:
- GET_ARG(0);
- GET_ARG(1);
- GET_ARG(2);
- semihost_sys_stat(cs, nios2_semi_u32_cb, arg0, arg1, arg2);
- break;
-
- case HOSTED_FSTAT:
- GET_ARG(0);
- GET_ARG(1);
- semihost_sys_fstat(cs, nios2_semi_u32_cb, arg0, arg1);
- break;
-
- case HOSTED_GETTIMEOFDAY:
- GET_ARG(0);
- GET_ARG(1);
- semihost_sys_gettimeofday(cs, nios2_semi_u32_cb, arg0, arg1);
- break;
-
- case HOSTED_ISATTY:
- GET_ARG(0);
- semihost_sys_isatty(cs, nios2_semi_u32_cb, arg0);
- break;
-
- case HOSTED_SYSTEM:
- GET_ARG(0);
- GET_ARG(1);
- semihost_sys_system(cs, nios2_semi_u32_cb, arg0, arg1);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: unsupported "
- "semihosting syscall %d\n", nr);
- nios2_semi_u32_cb(cs, -1, ENOSYS);
- break;
-
- failed:
- nios2_semi_u32_cb(cs, -1, EFAULT);
- break;
- failed64:
- nios2_semi_u64_cb(cs, -1, EFAULT);
- break;
- }
-}
diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c
deleted file mode 100644
index 5017457..0000000
--- a/target/nios2/op_helper.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Altera Nios II helper routines.
- *
- * Copyright (C) 2012 Chris Wulff <crwulff@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/lgpl-2.1.html>
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/helper-proto.h"
-#include "exec/exec-all.h"
-
-void helper_raise_exception(CPUNios2State *env, uint32_t index)
-{
- CPUState *cs = env_cpu(env);
- cs->exception_index = index;
- cpu_loop_exit(cs);
-}
-
-void nios2_cpu_loop_exit_advance(CPUNios2State *env, uintptr_t retaddr)
-{
- CPUState *cs = env_cpu(env);
-
- /*
- * Note that PC is advanced for all hardware exceptions.
- * Do this here, rather than in restore_state_to_opc(),
- * lest we affect QEMU internal exceptions, like EXCP_DEBUG.
- */
- cpu_restore_state(cs, retaddr);
- env->pc += 4;
- cpu_loop_exit(cs);
-}
-
-static void maybe_raise_div(CPUNios2State *env, uintptr_t ra)
-{
- Nios2CPU *cpu = env_archcpu(env);
- CPUState *cs = env_cpu(env);
-
- if (cpu->diverr_present) {
- cs->exception_index = EXCP_DIV;
- nios2_cpu_loop_exit_advance(env, ra);
- }
-}
-
-int32_t helper_divs(CPUNios2State *env, int32_t num, int32_t den)
-{
- if (unlikely(den == 0) || unlikely(den == -1 && num == INT32_MIN)) {
- maybe_raise_div(env, GETPC());
- return num; /* undefined */
- }
- return num / den;
-}
-
-uint32_t helper_divu(CPUNios2State *env, uint32_t num, uint32_t den)
-{
- if (unlikely(den == 0)) {
- maybe_raise_div(env, GETPC());
- return num; /* undefined */
- }
- return num / den;
-}
-
-#ifndef CONFIG_USER_ONLY
-void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc)
-{
- Nios2CPU *cpu = env_archcpu(env);
- CPUState *cs = env_cpu(env);
-
- if (unlikely(new_pc & 3)) {
- env->ctrl[CR_BADADDR] = new_pc;
- cs->exception_index = EXCP_UNALIGND;
- nios2_cpu_loop_exit_advance(env, GETPC());
- }
-
- /*
- * None of estatus, bstatus, or sstatus have constraints on write;
- * do not allow reserved fields in status to be set.
- * When shadow registers are enabled, eret *does* restore CRS.
- * Rather than testing eic_present to decide, mask CRS out of
- * the set of readonly fields.
- */
- new_status &= cpu->cr_state[CR_STATUS].writable |
- (cpu->cr_state[CR_STATUS].readonly & R_CR_STATUS_CRS_MASK);
-
- env->ctrl[CR_STATUS] = new_status;
- env->pc = new_pc;
- nios2_update_crs(env);
- cpu_loop_exit(cs);
-}
-
-/*
- * RDPRS and WRPRS are implemented out of line so that if PRS == CRS,
- * all of the tcg global temporaries are synced back to ENV.
- */
-uint32_t helper_rdprs(CPUNios2State *env, uint32_t regno)
-{
- unsigned prs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, PRS);
- return env->shadow_regs[prs][regno];
-}
-
-void helper_wrprs(CPUNios2State *env, uint32_t regno, uint32_t val)
-{
- unsigned prs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, PRS);
- env->shadow_regs[prs][regno] = val;
-}
-#endif /* !CONFIG_USER_ONLY */
diff --git a/target/nios2/trace-events b/target/nios2/trace-events
deleted file mode 100644
index 07f1f0a..0000000
--- a/target/nios2/trace-events
+++ /dev/null
@@ -1,10 +0,0 @@
-# mmu.c
-nios2_mmu_translate_miss(uint32_t vaddr, uint32_t pid, uint32_t index, uint32_t tag) "mmu_translate: MISS vaddr=0x%08x pid=%u TLB[%u] tag=0x%08x"
-nios2_mmu_translate_hit(uint32_t vaddr, uint32_t pid, uint32_t index, uint32_t paddr, uint32_t prot) "mmu_translate: HIT vaddr=0x%08x pid=%u TLB[%u] paddr=0x%08x prot=0x%x"
-
-nios2_mmu_flush_pid_miss(uint32_t pid, uint32_t index, uint32_t vaddr) "mmu_flush: MISS pid=%u TLB[%u] tag=0x%08x"
-nios2_mmu_flush_pid_hit(uint32_t pid, uint32_t index, uint32_t vaddr) "mmu_flush: HIT pid=%u TLB[%u] vaddr=0x%08x"
-
-nios2_mmu_write_tlbacc(uint32_t ig, char c, char r, char w, char x, char g, uint32_t pfn) "mmu_write_tlbacc: ig=0x%02x flags=%c%c%c%c%c pfn=0x%08x"
-nios2_mmu_write_tlbmisc(uint32_t way, char r, char w, char t, char b, char p, char d, uint32_t pid) "mmu_write_tlbmisc: way=0x%x flags=%c%c%c%c%c%c pid=%u"
-nios2_mmu_write_pteaddr(uint32_t ptb, uint32_t vpn) "mmu_write_pteaddr: ptbase=0x%03x vpn=0x%05x"
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
deleted file mode 100644
index 7ddc6ac..0000000
--- a/target/nios2/translate.c
+++ /dev/null
@@ -1,1107 +0,0 @@
-/*
- * Altera Nios II emulation for qemu: main translation routines.
- *
- * Copyright (C) 2016 Marek Vasut <marex@denx.de>
- * Copyright (C) 2012 Chris Wulff <crwulff@gmail.com>
- * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
- * (Portions of this file that were originally from nios2sim-ng.)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see
- * <http://www.gnu.org/licenses/lgpl-2.1.html>
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "tcg/tcg-op.h"
-#include "exec/exec-all.h"
-#include "disas/disas.h"
-#include "exec/helper-proto.h"
-#include "exec/helper-gen.h"
-#include "exec/log.h"
-#include "exec/translator.h"
-#include "qemu/qemu-print.h"
-#include "semihosting/semihost.h"
-
-#define HELPER_H "helper.h"
-#include "exec/helper-info.c.inc"
-#undef HELPER_H
-
-
-/* is_jmp field values */
-#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
-
-#define INSTRUCTION_FLG(func, flags) { (func), (flags) }
-#define INSTRUCTION(func) \
- INSTRUCTION_FLG(func, 0)
-#define INSTRUCTION_NOP() \
- INSTRUCTION_FLG(nop, 0)
-#define INSTRUCTION_UNIMPLEMENTED() \
- INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
-#define INSTRUCTION_ILLEGAL() \
- INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
-
-/* Special R-Type instruction opcode */
-#define INSN_R_TYPE 0x3A
-
-/* I-Type instruction parsing */
-typedef struct {
- uint8_t op;
- union {
- uint16_t u;
- int16_t s;
- } imm16;
- uint8_t b;
- uint8_t a;
-} InstrIType;
-
-#define I_TYPE(instr, code) \
- InstrIType (instr) = { \
- .op = extract32((code), 0, 6), \
- .imm16.u = extract32((code), 6, 16), \
- .b = extract32((code), 22, 5), \
- .a = extract32((code), 27, 5), \
- }
-
-typedef target_ulong ImmFromIType(const InstrIType *);
-
-static target_ulong imm_unsigned(const InstrIType *i)
-{
- return i->imm16.u;
-}
-
-static target_ulong imm_signed(const InstrIType *i)
-{
- return i->imm16.s;
-}
-
-static target_ulong imm_shifted(const InstrIType *i)
-{
- return i->imm16.u << 16;
-}
-
-/* R-Type instruction parsing */
-typedef struct {
- uint8_t op;
- uint8_t imm5;
- uint8_t opx;
- uint8_t c;
- uint8_t b;
- uint8_t a;
-} InstrRType;
-
-#define R_TYPE(instr, code) \
- InstrRType (instr) = { \
- .op = extract32((code), 0, 6), \
- .imm5 = extract32((code), 6, 5), \
- .opx = extract32((code), 11, 6), \
- .c = extract32((code), 17, 5), \
- .b = extract32((code), 22, 5), \
- .a = extract32((code), 27, 5), \
- }
-
-/* J-Type instruction parsing */
-typedef struct {
- uint8_t op;
- uint32_t imm26;
-} InstrJType;
-
-#define J_TYPE(instr, code) \
- InstrJType (instr) = { \
- .op = extract32((code), 0, 6), \
- .imm26 = extract32((code), 6, 26), \
- }
-
-typedef void GenFn2i(TCGv, TCGv, target_long);
-typedef void GenFn3(TCGv, TCGv, TCGv);
-typedef void GenFn4(TCGv, TCGv, TCGv, TCGv);
-
-typedef struct DisasContext {
- DisasContextBase base;
- target_ulong pc;
- int mem_idx;
- uint32_t tb_flags;
- TCGv sink;
- const ControlRegState *cr_state;
- bool eic_present;
-} DisasContext;
-
-static TCGv cpu_R[NUM_GP_REGS];
-static TCGv cpu_pc;
-#ifndef CONFIG_USER_ONLY
-static TCGv cpu_crs_R[NUM_GP_REGS];
-#endif
-
-typedef struct Nios2Instruction {
- void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
- uint32_t flags;
-} Nios2Instruction;
-
-static uint8_t get_opcode(uint32_t code)
-{
- I_TYPE(instr, code);
- return instr.op;
-}
-
-static uint8_t get_opxcode(uint32_t code)
-{
- R_TYPE(instr, code);
- return instr.opx;
-}
-
-static TCGv load_gpr(DisasContext *dc, unsigned reg)
-{
- assert(reg < NUM_GP_REGS);
-
- /*
- * With shadow register sets, register r0 does not necessarily contain 0,
- * but it is overwhelmingly likely that it does -- software is supposed
- * to have set r0 to 0 in every shadow register set before use.
- */
- if (unlikely(reg == R_ZERO) && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
- return tcg_constant_tl(0);
- }
- if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
- return cpu_R[reg];
- }
-#ifdef CONFIG_USER_ONLY
- g_assert_not_reached();
-#else
- return cpu_crs_R[reg];
-#endif
-}
-
-static TCGv dest_gpr(DisasContext *dc, unsigned reg)
-{
- assert(reg < NUM_GP_REGS);
-
- /*
- * The spec for shadow register sets isn't clear, but we assume that
- * writes to r0 are discarded regardless of CRS.
- */
- if (unlikely(reg == R_ZERO)) {
- if (dc->sink == NULL) {
- dc->sink = tcg_temp_new();
- }
- return dc->sink;
- }
- if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
- return cpu_R[reg];
- }
-#ifdef CONFIG_USER_ONLY
- g_assert_not_reached();
-#else
- return cpu_crs_R[reg];
-#endif
-}
-
-static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
-{
- /* Note that PC is advanced for all hardware exceptions. */
- tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
- gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
- dc->base.is_jmp = DISAS_NORETURN;
-}
-
-static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
-{
- const TranslationBlock *tb = dc->base.tb;
-
- if (translator_use_goto_tb(&dc->base, dest)) {
- tcg_gen_goto_tb(n);
- tcg_gen_movi_tl(cpu_pc, dest);
- tcg_gen_exit_tb(tb, n);
- } else {
- tcg_gen_movi_tl(cpu_pc, dest);
- tcg_gen_lookup_and_goto_ptr();
- }
- dc->base.is_jmp = DISAS_NORETURN;
-}
-
-static void gen_jumpr(DisasContext *dc, int regno, bool is_call)
-{
- TCGLabel *l = gen_new_label();
- TCGv test = tcg_temp_new();
- TCGv dest = load_gpr(dc, regno);
-
- tcg_gen_andi_tl(test, dest, 3);
- tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l);
-
- tcg_gen_mov_tl(cpu_pc, dest);
- if (is_call) {
- tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
- }
- tcg_gen_lookup_and_goto_ptr();
-
- gen_set_label(l);
- tcg_gen_st_tl(dest, tcg_env, offsetof(CPUNios2State, ctrl[CR_BADADDR]));
- t_gen_helper_raise_exception(dc, EXCP_UNALIGND);
-
- dc->base.is_jmp = DISAS_NORETURN;
-}
-
-static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- t_gen_helper_raise_exception(dc, flags);
-}
-
-static bool gen_check_supervisor(DisasContext *dc)
-{
- if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) {
- /* CPU in user mode, privileged instruction called, stop. */
- t_gen_helper_raise_exception(dc, EXCP_SUPERI);
- return false;
- }
- return true;
-}
-
-/*
- * Used as a placeholder for all instructions which do not have
- * an effect on the simulator (e.g. flush, sync)
- */
-static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- /* Nothing to do here */
-}
-
-/*
- * J-Type instructions
- */
-static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- J_TYPE(instr, code);
- gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
-}
-
-static void call(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
- jmpi(dc, code, flags);
-}
-
-/*
- * I-Type instructions
- */
-/* Load instructions */
-static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- I_TYPE(instr, code);
-
- TCGv addr = tcg_temp_new();
- TCGv data = dest_gpr(dc, instr.b);
-
- tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
-#ifdef CONFIG_USER_ONLY
- flags |= MO_UNALN;
-#else
- flags |= MO_ALIGN;
-#endif
- tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
-}
-
-/* Store instructions */
-static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- I_TYPE(instr, code);
- TCGv val = load_gpr(dc, instr.b);
-
- TCGv addr = tcg_temp_new();
- tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
-#ifdef CONFIG_USER_ONLY
- flags |= MO_UNALN;
-#else
- flags |= MO_ALIGN;
-#endif
- tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
-}
-
-/* Branch instructions */
-static void br(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- I_TYPE(instr, code);
-
- gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4));
-}
-
-static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- I_TYPE(instr, code);
-
- TCGLabel *l1 = gen_new_label();
- tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1);
- gen_goto_tb(dc, 0, dc->base.pc_next);
- gen_set_label(l1);
- gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
-}
-
-/* Comparison instructions */
-static void do_i_cmpxx(DisasContext *dc, uint32_t insn,
- TCGCond cond, ImmFromIType *imm)
-{
- I_TYPE(instr, insn);
- tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b),
- load_gpr(dc, instr.a), imm(&instr));
-}
-
-#define gen_i_cmpxx(fname, imm) \
- static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
- { do_i_cmpxx(dc, code, flags, imm); }
-
-gen_i_cmpxx(gen_cmpxxsi, imm_signed)
-gen_i_cmpxx(gen_cmpxxui, imm_unsigned)
-
-/* Math/logic instructions */
-static void do_i_math_logic(DisasContext *dc, uint32_t insn,
- GenFn2i *fn, ImmFromIType *imm,
- bool x_op_0_eq_x)
-{
- I_TYPE(instr, insn);
- target_ulong val;
-
- if (unlikely(instr.b == R_ZERO)) {
- /* Store to R_ZERO is ignored -- this catches the canonical NOP. */
- return;
- }
-
- val = imm(&instr);
-
- if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
- /* This catches the canonical expansions of movi and movhi. */
- tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0);
- } else {
- fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val);
- }
-}
-
-#define gen_i_math_logic(fname, insn, x_op_0, imm) \
- static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
- { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); }
-
-gen_i_math_logic(addi, addi, 1, imm_signed)
-gen_i_math_logic(muli, muli, 0, imm_signed)
-
-gen_i_math_logic(andi, andi, 0, imm_unsigned)
-gen_i_math_logic(ori, ori, 1, imm_unsigned)
-gen_i_math_logic(xori, xori, 1, imm_unsigned)
-
-gen_i_math_logic(andhi, andi, 0, imm_shifted)
-gen_i_math_logic(orhi , ori, 1, imm_shifted)
-gen_i_math_logic(xorhi, xori, 1, imm_shifted)
-
-/* rB <- prs.rA + sigma(IMM16) */
-static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- if (!dc->eic_present) {
- t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
- return;
- }
- if (!gen_check_supervisor(dc)) {
- return;
- }
-
-#ifdef CONFIG_USER_ONLY
- g_assert_not_reached();
-#else
- I_TYPE(instr, code);
- TCGv dest = dest_gpr(dc, instr.b);
- gen_helper_rdprs(dest, tcg_env, tcg_constant_i32(instr.a));
- tcg_gen_addi_tl(dest, dest, instr.imm16.s);
-#endif
-}
-
-/* Prototype only, defined below */
-static void handle_r_type_instr(DisasContext *dc, uint32_t code,
- uint32_t flags);
-
-static const Nios2Instruction i_type_instructions[] = {
- INSTRUCTION(call), /* call */
- INSTRUCTION(jmpi), /* jmpi */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */
- INSTRUCTION(addi), /* addi */
- INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */
- INSTRUCTION(br), /* br */
- INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */
- INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(gen_ldx, MO_TEUW), /* ldhu */
- INSTRUCTION(andi), /* andi */
- INSTRUCTION_FLG(gen_stx, MO_TEUW), /* sth */
- INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */
- INSTRUCTION_FLG(gen_ldx, MO_TESW), /* ldh */
- INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_NOP(), /* initda */
- INSTRUCTION(ori), /* ori */
- INSTRUCTION_FLG(gen_stx, MO_TEUL), /* stw */
- INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */
- INSTRUCTION_FLG(gen_ldx, MO_TEUL), /* ldw */
- INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_NOP(), /* flushda */
- INSTRUCTION(xori), /* xori */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */
- INSTRUCTION(muli), /* muli */
- INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */
- INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */
- INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */
- INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(gen_ldx, MO_TEUW), /* ldhuio */
- INSTRUCTION(andhi), /* andhi */
- INSTRUCTION_FLG(gen_stx, MO_TEUW), /* sthio */
- INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */
- INSTRUCTION_FLG(gen_ldx, MO_TESW), /* ldhio */
- INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_UNIMPLEMENTED(), /* custom */
- INSTRUCTION_NOP(), /* initd */
- INSTRUCTION(orhi), /* orhi */
- INSTRUCTION_FLG(gen_stx, MO_TESL), /* stwio */
- INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */
- INSTRUCTION_FLG(gen_ldx, MO_TEUL), /* ldwio */
- INSTRUCTION(rdprs), /* rdprs */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */
- INSTRUCTION_NOP(), /* flushd */
- INSTRUCTION(xorhi), /* xorhi */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
-};
-
-/*
- * R-Type instructions
- */
-/*
- * status <- estatus
- * PC <- ea
- */
-static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- if (!gen_check_supervisor(dc)) {
- return;
- }
-
-#ifdef CONFIG_USER_ONLY
- g_assert_not_reached();
-#else
- if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
- TCGv tmp = tcg_temp_new();
- tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS]));
- gen_helper_eret(tcg_env, tmp, load_gpr(dc, R_EA));
- } else {
- gen_helper_eret(tcg_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA));
- }
- dc->base.is_jmp = DISAS_NORETURN;
-#endif
-}
-
-/* PC <- ra */
-static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- gen_jumpr(dc, R_RA, false);
-}
-
-/*
- * status <- bstatus
- * PC <- ba
- */
-static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- if (!gen_check_supervisor(dc)) {
- return;
- }
-
-#ifdef CONFIG_USER_ONLY
- g_assert_not_reached();
-#else
- TCGv tmp = tcg_temp_new();
- tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS]));
- gen_helper_eret(tcg_env, tmp, load_gpr(dc, R_BA));
-
- dc->base.is_jmp = DISAS_NORETURN;
-#endif
-}
-
-/* PC <- rA */
-static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- R_TYPE(instr, code);
-
- gen_jumpr(dc, instr.a, false);
-}
-
-/* rC <- PC + 4 */
-static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- R_TYPE(instr, code);
-
- tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next);
-}
-
-/*
- * ra <- PC + 4
- * PC <- rA
- */
-static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- R_TYPE(instr, code);
-
- gen_jumpr(dc, instr.a, true);
-}
-
-/* rC <- ctlN */
-static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- if (!gen_check_supervisor(dc)) {
- return;
- }
-
-#ifdef CONFIG_USER_ONLY
- g_assert_not_reached();
-#else
- R_TYPE(instr, code);
- TCGv t1, t2, dest = dest_gpr(dc, instr.c);
-
- /* Reserved registers read as zero. */
- if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
- tcg_gen_movi_tl(dest, 0);
- return;
- }
-
- switch (instr.imm5) {
- case CR_IPENDING:
- /*
- * The value of the ipending register is synthetic.
- * In hw, this is the AND of a set of hardware irq lines
- * with the ienable register. In qemu, we re-use the space
- * of CR_IPENDING to store the set of irq lines, and so we
- * must perform the AND here, and anywhere else we need the
- * guest value of ipending.
- */
- t1 = tcg_temp_new();
- t2 = tcg_temp_new();
- tcg_gen_ld_tl(t1, tcg_env, offsetof(CPUNios2State, ctrl[CR_IPENDING]));
- tcg_gen_ld_tl(t2, tcg_env, offsetof(CPUNios2State, ctrl[CR_IENABLE]));
- tcg_gen_and_tl(dest, t1, t2);
- break;
- default:
- tcg_gen_ld_tl(dest, tcg_env,
- offsetof(CPUNios2State, ctrl[instr.imm5]));
- break;
- }
-#endif
-}
-
-/* ctlN <- rA */
-static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- if (!gen_check_supervisor(dc)) {
- return;
- }
-
-#ifdef CONFIG_USER_ONLY
- g_assert_not_reached();
-#else
- R_TYPE(instr, code);
- TCGv v = load_gpr(dc, instr.a);
- uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]);
- uint32_t wr = dc->cr_state[instr.imm5].writable;
- uint32_t ro = dc->cr_state[instr.imm5].readonly;
-
- /* Skip reserved or readonly registers. */
- if (wr == 0) {
- return;
- }
-
- switch (instr.imm5) {
- case CR_PTEADDR:
- gen_helper_mmu_write_pteaddr(tcg_env, v);
- break;
- case CR_TLBACC:
- gen_helper_mmu_write_tlbacc(tcg_env, v);
- break;
- case CR_TLBMISC:
- gen_helper_mmu_write_tlbmisc(tcg_env, v);
- break;
- case CR_STATUS:
- case CR_IENABLE:
- /* If interrupts were enabled using WRCTL, trigger them. */
- dc->base.is_jmp = DISAS_UPDATE;
- /* fall through */
- default:
- if (wr == -1) {
- /* The register is entirely writable. */
- tcg_gen_st_tl(v, tcg_env, ofs);
- } else {
- /*
- * The register is partially read-only or reserved:
- * merge the value.
- */
- TCGv n = tcg_temp_new();
-
- tcg_gen_andi_tl(n, v, wr);
-
- if (ro != 0) {
- TCGv o = tcg_temp_new();
- tcg_gen_ld_tl(o, tcg_env, ofs);
- tcg_gen_andi_tl(o, o, ro);
- tcg_gen_or_tl(n, n, o);
- }
-
- tcg_gen_st_tl(n, tcg_env, ofs);
- }
- break;
- }
-#endif
-}
-
-/* prs.rC <- rA */
-static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- if (!dc->eic_present) {
- t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
- return;
- }
- if (!gen_check_supervisor(dc)) {
- return;
- }
-
-#ifdef CONFIG_USER_ONLY
- g_assert_not_reached();
-#else
- R_TYPE(instr, code);
- gen_helper_wrprs(tcg_env, tcg_constant_i32(instr.c),
- load_gpr(dc, instr.a));
- /*
- * The expected write to PRS[r0] is 0, from CRS[r0].
- * If not, and CRS == PRS (which we cannot tell from here),
- * we may now have a non-zero value in our current r0.
- * By ending the TB, we re-evaluate tb_flags and find out.
- */
- if (instr.c == 0
- && (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) {
- dc->base.is_jmp = DISAS_UPDATE;
- }
-#endif
-}
-
-/* Comparison instructions */
-static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- R_TYPE(instr, code);
- tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c),
- load_gpr(dc, instr.a), load_gpr(dc, instr.b));
-}
-
-/* Math/logic instructions */
-static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn)
-{
- R_TYPE(instr, insn);
- fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5);
-}
-
-static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn)
-{
- R_TYPE(instr, insn);
- fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b));
-}
-
-#define gen_ri_math_logic(fname, insn) \
- static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
- { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); }
-
-#define gen_rr_math_logic(fname, insn) \
- static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
- { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); }
-
-gen_rr_math_logic(add, add)
-gen_rr_math_logic(sub, sub)
-gen_rr_math_logic(mul, mul)
-
-gen_rr_math_logic(and, and)
-gen_rr_math_logic(or, or)
-gen_rr_math_logic(xor, xor)
-gen_rr_math_logic(nor, nor)
-
-gen_ri_math_logic(srai, sari)
-gen_ri_math_logic(srli, shri)
-gen_ri_math_logic(slli, shli)
-gen_ri_math_logic(roli, rotli)
-
-static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn)
-{
- R_TYPE(instr, insn);
- TCGv discard = tcg_temp_new();
-
- fn(discard, dest_gpr(dc, instr.c),
- load_gpr(dc, instr.a), load_gpr(dc, instr.b));
-}
-
-#define gen_rr_mul_high(fname, insn) \
- static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
- { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); }
-
-gen_rr_mul_high(mulxss, muls2)
-gen_rr_mul_high(mulxuu, mulu2)
-gen_rr_mul_high(mulxsu, mulsu2)
-
-static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn)
-{
- R_TYPE(instr, insn);
- TCGv sh = tcg_temp_new();
-
- tcg_gen_andi_tl(sh, load_gpr(dc, instr.b), 31);
- fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), sh);
-}
-
-#define gen_rr_shift(fname, insn) \
- static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \
- { do_rr_shift(dc, code, tcg_gen_##insn##_tl); }
-
-gen_rr_shift(sra, sar)
-gen_rr_shift(srl, shr)
-gen_rr_shift(sll, shl)
-gen_rr_shift(rol, rotl)
-gen_rr_shift(ror, rotr)
-
-static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- R_TYPE(instr, (code));
- gen_helper_divs(dest_gpr(dc, instr.c), tcg_env,
- load_gpr(dc, instr.a), load_gpr(dc, instr.b));
-}
-
-static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- R_TYPE(instr, (code));
- gen_helper_divu(dest_gpr(dc, instr.c), tcg_env,
- load_gpr(dc, instr.a), load_gpr(dc, instr.b));
-}
-
-static void trap(DisasContext *dc, uint32_t code, uint32_t flags)
-{
-#ifdef CONFIG_USER_ONLY
- /*
- * The imm5 field is not stored anywhere on real hw; the kernel
- * has to load the insn and extract the field. But we can make
- * things easier for cpu_loop if we pop this into env->error_code.
- */
- R_TYPE(instr, code);
- tcg_gen_st_i32(tcg_constant_i32(instr.imm5), tcg_env,
- offsetof(CPUNios2State, error_code));
-#endif
- t_gen_helper_raise_exception(dc, EXCP_TRAP);
-}
-
-static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags)
-{
-#ifndef CONFIG_USER_ONLY
- /* The semihosting instruction is "break 1". */
- bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U);
- R_TYPE(instr, code);
- if (semihosting_enabled(is_user) && instr.imm5 == 1) {
- t_gen_helper_raise_exception(dc, EXCP_SEMIHOST);
- return;
- }
-#endif
-
- t_gen_helper_raise_exception(dc, EXCP_BREAK);
-}
-
-static const Nios2Instruction r_type_instructions[] = {
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(eret), /* eret */
- INSTRUCTION(roli), /* roli */
- INSTRUCTION(rol), /* rol */
- INSTRUCTION_NOP(), /* flushp */
- INSTRUCTION(ret), /* ret */
- INSTRUCTION(nor), /* nor */
- INSTRUCTION(mulxuu), /* mulxuu */
- INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */
- INSTRUCTION(bret), /* bret */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(ror), /* ror */
- INSTRUCTION_NOP(), /* flushi */
- INSTRUCTION(jmp), /* jmp */
- INSTRUCTION(and), /* and */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(slli), /* slli */
- INSTRUCTION(sll), /* sll */
- INSTRUCTION(wrprs), /* wrprs */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(or), /* or */
- INSTRUCTION(mulxsu), /* mulxsu */
- INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(srli), /* srli */
- INSTRUCTION(srl), /* srl */
- INSTRUCTION(nextpc), /* nextpc */
- INSTRUCTION(callr), /* callr */
- INSTRUCTION(xor), /* xor */
- INSTRUCTION(mulxss), /* mulxss */
- INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(divu), /* divu */
- INSTRUCTION(divs), /* div */
- INSTRUCTION(rdctl), /* rdctl */
- INSTRUCTION(mul), /* mul */
- INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */
- INSTRUCTION_NOP(), /* initi */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(trap), /* trap */
- INSTRUCTION(wrctl), /* wrctl */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */
- INSTRUCTION(add), /* add */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(gen_break), /* break */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(nop), /* nop */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION(sub), /* sub */
- INSTRUCTION(srai), /* srai */
- INSTRUCTION(sra), /* sra */
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
- INSTRUCTION_ILLEGAL(),
-};
-
-static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
-{
- uint8_t opx;
- const Nios2Instruction *instr;
-
- opx = get_opxcode(code);
- if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
- goto illegal_op;
- }
-
- instr = &r_type_instructions[opx];
- instr->handler(dc, code, instr->flags);
-
- return;
-
-illegal_op:
- t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
-}
-
-static const char * const gr_regnames[NUM_GP_REGS] = {
- "zero", "at", "r2", "r3",
- "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11",
- "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19",
- "r20", "r21", "r22", "r23",
- "et", "bt", "gp", "sp",
- "fp", "ea", "ba", "ra",
-};
-
-#ifndef CONFIG_USER_ONLY
-static const char * const cr_regnames[NUM_CR_REGS] = {
- "status", "estatus", "bstatus", "ienable",
- "ipending", "cpuid", "res6", "exception",
- "pteaddr", "tlbacc", "tlbmisc", "reserved1",
- "badaddr", "config", "mpubase", "mpuacc",
- "res16", "res17", "res18", "res19",
- "res20", "res21", "res22", "res23",
- "res24", "res25", "res26", "res27",
- "res28", "res29", "res30", "res31",
-};
-#endif
-
-/* generate intermediate code for basic block 'tb'. */
-static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
- CPUNios2State *env = cpu_env(cs);
- Nios2CPU *cpu = env_archcpu(env);
- int page_insns;
-
- dc->mem_idx = cpu_mmu_index(cs, false);
- dc->cr_state = cpu->cr_state;
- dc->tb_flags = dc->base.tb->flags;
- dc->eic_present = cpu->eic_present;
-
- /* Bound the number of insns to execute to those left on the page. */
- page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
- dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
-}
-
-static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
-{
-}
-
-static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
-{
- tcg_gen_insn_start(dcbase->pc_next);
-}
-
-static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
- const Nios2Instruction *instr;
- uint32_t code, pc;
- uint8_t op;
-
- pc = dc->base.pc_next;
- dc->pc = pc;
- dc->base.pc_next = pc + 4;
-
- /* Decode an instruction */
- code = cpu_ldl_code(cpu_env(cs), pc);
- op = get_opcode(code);
-
- if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
- t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
- return;
- }
-
- dc->sink = NULL;
-
- instr = &i_type_instructions[op];
- instr->handler(dc, code, instr->flags);
-}
-
-static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
-
- /* Indicate where the next block should start */
- switch (dc->base.is_jmp) {
- case DISAS_TOO_MANY:
- gen_goto_tb(dc, 0, dc->base.pc_next);
- break;
-
- case DISAS_UPDATE:
- /* Save the current PC, and return to the main loop. */
- tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
- tcg_gen_exit_tb(NULL, 0);
- break;
-
- case DISAS_NORETURN:
- /* nothing more to generate */
- break;
-
- default:
- g_assert_not_reached();
- }
-}
-
-static void nios2_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
-static const TranslatorOps nios2_tr_ops = {
- .init_disas_context = nios2_tr_init_disas_context,
- .tb_start = nios2_tr_tb_start,
- .insn_start = nios2_tr_insn_start,
- .translate_insn = nios2_tr_translate_insn,
- .tb_stop = nios2_tr_tb_stop,
- .disas_log = nios2_tr_disas_log,
-};
-
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
- vaddr pc, void *host_pc)
-{
- DisasContext dc;
- translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base);
-}
-
-void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
- Nios2CPU *cpu = NIOS2_CPU(cs);
- CPUNios2State *env = &cpu->env;
- int i;
-
- qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
-
- for (i = 0; i < NUM_GP_REGS; i++) {
- qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]);
- if ((i + 1) % 4 == 0) {
- qemu_fprintf(f, "\n");
- }
- }
-
-#if !defined(CONFIG_USER_ONLY)
- int j;
-
- for (i = j = 0; i < NUM_CR_REGS; i++) {
- if (!nios2_cr_reserved(&cpu->cr_state[i])) {
- qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
- if (++j % 4 == 0) {
- qemu_fprintf(f, "\n");
- }
- }
- }
- if (j % 4 != 0) {
- qemu_fprintf(f, "\n");
- }
- if (cpu->mmu_present) {
- qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
- env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
- FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
- env->mmu.tlbacc_wr);
- }
-#endif
- qemu_fprintf(f, "\n\n");
-}
-
-void nios2_tcg_init(void)
-{
-#ifndef CONFIG_USER_ONLY
- TCGv_ptr crs = tcg_global_mem_new_ptr(tcg_env,
- offsetof(CPUNios2State, regs), "crs");
-
- for (int i = 0; i < NUM_GP_REGS; i++) {
- cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
- }
-
-#define offsetof_regs0(N) offsetof(CPUNios2State, shadow_regs[0][N])
-#else
-#define offsetof_regs0(N) offsetof(CPUNios2State, regs[N])
-#endif
-
- for (int i = 0; i < NUM_GP_REGS; i++) {
- cpu_R[i] = tcg_global_mem_new(tcg_env, offsetof_regs0(i),
- gr_regnames[i]);
- }
-
-#undef offsetof_regs0
-
- cpu_pc = tcg_global_mem_new(tcg_env,
- offsetof(CPUNios2State, pc), "pc");
-}