2017-01-19 01:01:41 +03:00
|
|
|
/*
|
|
|
|
* 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>
|
|
|
|
*/
|
2019-03-15 17:51:20 +03:00
|
|
|
|
|
|
|
#ifndef NIOS2_CPU_H
|
|
|
|
#define NIOS2_CPU_H
|
2017-01-19 01:01:41 +03:00
|
|
|
|
2019-03-22 21:51:19 +03:00
|
|
|
#include "exec/cpu-defs.h"
|
2019-07-09 18:20:52 +03:00
|
|
|
#include "hw/core/cpu.h"
|
2022-04-21 18:16:55 +03:00
|
|
|
#include "hw/registerfields.h"
|
2020-09-03 23:43:22 +03:00
|
|
|
#include "qom/object.h"
|
2017-01-19 01:01:41 +03:00
|
|
|
|
2022-02-07 15:35:58 +03:00
|
|
|
typedef struct CPUArchState CPUNios2State;
|
2017-01-19 01:01:41 +03:00
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
#include "mmu.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define TYPE_NIOS2_CPU "nios2-cpu"
|
|
|
|
|
2022-02-14 19:08:40 +03:00
|
|
|
OBJECT_DECLARE_CPU_TYPE(Nios2CPU, Nios2CPUClass, NIOS2_CPU)
|
2017-01-19 01:01:41 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Nios2CPUClass:
|
2022-11-24 14:50:14 +03:00
|
|
|
* @parent_phases: The parent class' reset phase handlers.
|
2017-01-19 01:01:41 +03:00
|
|
|
*
|
|
|
|
* A Nios2 CPU model.
|
|
|
|
*/
|
2020-09-03 23:43:22 +03:00
|
|
|
struct Nios2CPUClass {
|
2017-01-19 01:01:41 +03:00
|
|
|
/*< private >*/
|
|
|
|
CPUClass parent_class;
|
|
|
|
/*< public >*/
|
|
|
|
|
|
|
|
DeviceRealize parent_realize;
|
2022-11-24 14:50:14 +03:00
|
|
|
ResettablePhases parent_phases;
|
2020-09-03 23:43:22 +03:00
|
|
|
};
|
2017-01-19 01:01:41 +03:00
|
|
|
|
|
|
|
#define TARGET_HAS_ICE 1
|
|
|
|
|
|
|
|
/* Configuration options for Nios II */
|
|
|
|
#define RESET_ADDRESS 0x00000000
|
|
|
|
#define EXCEPTION_ADDRESS 0x00000004
|
|
|
|
#define FAST_TLB_MISS_ADDRESS 0x00000008
|
|
|
|
|
2022-04-21 18:16:46 +03:00
|
|
|
#define NUM_GP_REGS 32
|
|
|
|
#define NUM_CR_REGS 32
|
2017-01-19 01:01:41 +03:00
|
|
|
|
2022-04-21 18:17:24 +03:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
/* 63 shadow register sets; index 0 is the primary register set. */
|
|
|
|
#define NUM_REG_SETS 64
|
|
|
|
#endif
|
|
|
|
|
2017-01-19 01:01:41 +03:00
|
|
|
/* General purpose register aliases */
|
2022-04-21 18:17:01 +03:00
|
|
|
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,
|
2022-04-21 18:17:26 +03:00
|
|
|
R_SSTATUS = 30,
|
2022-04-21 18:17:01 +03:00
|
|
|
R_RA = 31,
|
|
|
|
};
|
2017-01-19 01:01:41 +03:00
|
|
|
|
|
|
|
/* Control register aliases */
|
2022-04-21 18:17:01 +03:00
|
|
|
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,
|
|
|
|
};
|
2022-04-21 18:16:55 +03:00
|
|
|
|
|
|
|
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)
|
2022-04-21 18:17:27 +03:00
|
|
|
FIELD(CR_STATUS, SRS, 31, 1) /* only in sstatus */
|
2022-04-21 18:16:55 +03:00
|
|
|
|
|
|
|
#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
|
2022-04-21 18:17:27 +03:00
|
|
|
#define CR_STATUS_SRS R_CR_STATUS_SRS_MASK
|
2022-04-21 18:16:55 +03:00
|
|
|
|
2022-04-21 18:16:56 +03:00
|
|
|
FIELD(CR_EXCEPTION, CAUSE, 2, 5)
|
|
|
|
FIELD(CR_EXCEPTION, ECCFTL, 31, 1)
|
|
|
|
|
2022-04-21 18:16:57 +03:00
|
|
|
FIELD(CR_PTEADDR, VPN, 2, 20)
|
|
|
|
FIELD(CR_PTEADDR, PTBASE, 22, 10)
|
|
|
|
|
2022-04-21 18:16:58 +03:00
|
|
|
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
|
|
|
|
|
2022-04-21 18:17:00 +03:00
|
|
|
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
|
|
|
|
|
2017-01-19 01:01:41 +03:00
|
|
|
/* Exceptions */
|
2019-04-03 22:53:05 +03:00
|
|
|
#define EXCP_BREAK 0x1000
|
2022-04-21 18:17:02 +03:00
|
|
|
#define EXCP_SEMIHOST 0x1001
|
2017-01-19 01:01:41 +03:00
|
|
|
#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
|
target/nios2: Clean up handling of tlbmisc in do_exception
The 4 lower bits, D, PERM, BAD, DBL, are unconditionally set on any
exception with EH=0, or so says Table 42 (Processor Status After
Taking Exception).
We currently do not set PERM or BAD at all, and only set/clear
DBL for tlb miss, and do not clear DBL for any other exception.
It is a bit confusing to set D in tlb_fill and the rest during
do_interrupt, so move the setting of D to do_interrupt as well.
To do this, split EXP_TLBD into two cases, EXCP_TLB_X and EXCP_TLB_D,
which allows us to distinguish them during do_interrupt. Choose
a value for EXCP_TLB_D such that when truncated it produces the
correct value for exception.CAUSE.
Rename EXCP_TLB[RWX] to EXCP_PERM_[RWX], to emphasize that the
exception is permissions related. Rename EXCP_SUPER[AD] to
EXCP_SUPERA_[DX] to emphasize that they are both "supervisor
address" exceptions, data and execute.
Retain the setting of tlbmisc.WE for the fast-tlb-miss path, as it
is being relied upon, but remove it from the permission path.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20220421151735.31996-37-richard.henderson@linaro.org>
2022-04-21 18:17:07 +03:00
|
|
|
#define EXCP_SUPERA_X 9
|
2017-01-19 01:01:41 +03:00
|
|
|
#define EXCP_SUPERI 10
|
target/nios2: Clean up handling of tlbmisc in do_exception
The 4 lower bits, D, PERM, BAD, DBL, are unconditionally set on any
exception with EH=0, or so says Table 42 (Processor Status After
Taking Exception).
We currently do not set PERM or BAD at all, and only set/clear
DBL for tlb miss, and do not clear DBL for any other exception.
It is a bit confusing to set D in tlb_fill and the rest during
do_interrupt, so move the setting of D to do_interrupt as well.
To do this, split EXP_TLBD into two cases, EXCP_TLB_X and EXCP_TLB_D,
which allows us to distinguish them during do_interrupt. Choose
a value for EXCP_TLB_D such that when truncated it produces the
correct value for exception.CAUSE.
Rename EXCP_TLB[RWX] to EXCP_PERM_[RWX], to emphasize that the
exception is permissions related. Rename EXCP_SUPER[AD] to
EXCP_SUPERA_[DX] to emphasize that they are both "supervisor
address" exceptions, data and execute.
Retain the setting of tlbmisc.WE for the fast-tlb-miss path, as it
is being relied upon, but remove it from the permission path.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20220421151735.31996-37-richard.henderson@linaro.org>
2022-04-21 18:17:07 +03:00
|
|
|
#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
|
2017-01-19 01:01:41 +03:00
|
|
|
#define EXCP_MPUI 16
|
|
|
|
#define EXCP_MPUD 17
|
|
|
|
|
2022-02-07 15:35:58 +03:00
|
|
|
struct CPUArchState {
|
2022-04-21 18:17:24 +03:00
|
|
|
#ifdef CONFIG_USER_ONLY
|
2022-04-21 18:16:53 +03:00
|
|
|
uint32_t regs[NUM_GP_REGS];
|
2022-04-21 18:17:24 +03:00
|
|
|
#else
|
|
|
|
uint32_t shadow_regs[NUM_REG_SETS][NUM_GP_REGS];
|
|
|
|
/* Pointer into shadow_regs for the current register set. */
|
|
|
|
uint32_t *regs;
|
|
|
|
#endif
|
2022-04-21 18:16:53 +03:00
|
|
|
uint32_t ctrl[NUM_CR_REGS];
|
2022-04-21 18:16:47 +03:00
|
|
|
uint32_t pc;
|
2017-01-19 01:01:41 +03:00
|
|
|
|
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
Nios2MMU mmu;
|
|
|
|
#endif
|
2021-12-21 05:50:06 +03:00
|
|
|
int error_code;
|
2017-01-19 01:01:41 +03:00
|
|
|
};
|
|
|
|
|
2022-04-21 18:17:08 +03:00
|
|
|
typedef struct {
|
|
|
|
uint32_t writable;
|
|
|
|
uint32_t readonly;
|
|
|
|
} ControlRegState;
|
|
|
|
|
2017-01-19 01:01:41 +03:00
|
|
|
/**
|
|
|
|
* Nios2CPU:
|
|
|
|
* @env: #CPUNios2State
|
|
|
|
*
|
|
|
|
* A Nios2 CPU.
|
|
|
|
*/
|
2022-02-14 19:15:16 +03:00
|
|
|
struct ArchCPU {
|
2017-01-19 01:01:41 +03:00
|
|
|
/*< private >*/
|
|
|
|
CPUState parent_obj;
|
|
|
|
/*< public >*/
|
|
|
|
|
2019-03-23 03:16:06 +03:00
|
|
|
CPUNegativeOffsetState neg;
|
2017-01-19 01:01:41 +03:00
|
|
|
CPUNios2State env;
|
2019-03-23 03:16:06 +03:00
|
|
|
|
2022-04-21 18:17:12 +03:00
|
|
|
bool diverr_present;
|
2017-01-19 01:01:41 +03:00
|
|
|
bool mmu_present;
|
2022-04-21 18:17:25 +03:00
|
|
|
bool eic_present;
|
2022-04-21 18:17:12 +03:00
|
|
|
|
2017-01-19 01:01:41 +03:00
|
|
|
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;
|
2022-04-21 18:17:08 +03:00
|
|
|
|
|
|
|
/* Bits within each control register which are reserved or readonly. */
|
|
|
|
ControlRegState cr_state[NUM_CR_REGS];
|
2022-04-21 18:17:27 +03:00
|
|
|
|
|
|
|
/* 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 */
|
2020-09-03 23:43:22 +03:00
|
|
|
};
|
2017-01-19 01:01:41 +03:00
|
|
|
|
|
|
|
|
2022-04-21 18:17:08 +03:00
|
|
|
static inline bool nios2_cr_reserved(const ControlRegState *s)
|
|
|
|
{
|
|
|
|
return (s->writable | s->readonly) == 0;
|
|
|
|
}
|
|
|
|
|
2022-04-21 18:17:24 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-01-19 01:01:41 +03:00
|
|
|
void nios2_tcg_init(void);
|
|
|
|
void nios2_cpu_do_interrupt(CPUState *cs);
|
2019-04-17 22:17:58 +03:00
|
|
|
void dump_mmu(CPUNios2State *env);
|
2019-04-17 22:18:02 +03:00
|
|
|
void nios2_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
2017-01-19 01:01:41 +03:00
|
|
|
hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
2022-04-20 16:26:02 +03:00
|
|
|
G_NORETURN void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
|
|
|
MMUAccessType access_type, int mmu_idx,
|
|
|
|
uintptr_t retaddr);
|
2022-04-21 18:17:28 +03:00
|
|
|
G_NORETURN void nios2_cpu_loop_exit_advance(CPUNios2State *env,
|
|
|
|
uintptr_t retaddr);
|
2017-01-19 01:01:41 +03:00
|
|
|
|
2019-04-03 22:53:05 +03:00
|
|
|
void do_nios2_semihosting(CPUNios2State *env);
|
|
|
|
|
2018-02-07 13:40:25 +03:00
|
|
|
#define CPU_RESOLVING_TYPE TYPE_NIOS2_CPU
|
2017-01-19 01:01:41 +03:00
|
|
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
static inline int cpu_mmu_index(CPUNios2State *env, bool ifetch)
|
|
|
|
{
|
2022-04-21 18:16:53 +03:00
|
|
|
return (env->ctrl[CR_STATUS] & CR_STATUS_U) ? MMU_USER_IDX :
|
2017-01-19 01:01:41 +03:00
|
|
|
MMU_SUPERVISOR_IDX;
|
|
|
|
}
|
|
|
|
|
2022-04-21 18:16:41 +03:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2019-04-02 12:47:37 +03:00
|
|
|
bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
|
|
|
MMUAccessType access_type, int mmu_idx,
|
|
|
|
bool probe, uintptr_t retaddr);
|
2021-09-30 20:41:43 +03:00
|
|
|
#endif
|
2017-01-19 01:01:41 +03:00
|
|
|
|
2019-03-23 01:32:23 +03:00
|
|
|
typedef CPUNios2State CPUArchState;
|
2019-03-23 01:56:19 +03:00
|
|
|
typedef Nios2CPU ArchCPU;
|
2019-03-23 01:32:23 +03:00
|
|
|
|
2017-01-19 01:01:41 +03:00
|
|
|
#include "exec/cpu-all.h"
|
|
|
|
|
2022-04-21 18:17:24 +03:00
|
|
|
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. */
|
|
|
|
|
2017-01-19 01:01:41 +03:00
|
|
|
static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc,
|
|
|
|
target_ulong *cs_base, uint32_t *flags)
|
|
|
|
{
|
2022-04-21 18:17:24 +03:00
|
|
|
unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS);
|
|
|
|
|
2022-04-21 18:16:47 +03:00
|
|
|
*pc = env->pc;
|
2017-01-19 01:01:41 +03:00
|
|
|
*cs_base = 0;
|
2022-04-21 18:17:24 +03:00
|
|
|
*flags = (env->ctrl[CR_STATUS] & CR_STATUS_U)
|
|
|
|
| (crs ? 0 : R_TBFLAGS_CRS0_MASK)
|
|
|
|
| (env->regs[0] ? 0 : R_TBFLAGS_R0_0_MASK);
|
2017-01-19 01:01:41 +03:00
|
|
|
}
|
|
|
|
|
2019-03-15 17:51:20 +03:00
|
|
|
#endif /* NIOS2_CPU_H */
|