diff options
author | Michael Clark <mjc@sifive.com> | 2018-03-03 01:31:10 +1300 |
---|---|---|
committer | Michael Clark <mjc@sifive.com> | 2018-03-07 08:30:28 +1300 |
commit | dc5bd18fa57254e4b8597747c2100c92a55fc409 (patch) | |
tree | 3468959ae773ecbd22a911d6bd7fff966d2ad767 /target/riscv/cpu.h | |
parent | f71a8eaffba3271cf7cdad95572f6996f7523a5b (diff) | |
download | qemu-dc5bd18fa57254e4b8597747c2100c92a55fc409.zip qemu-dc5bd18fa57254e4b8597747c2100c92a55fc409.tar.gz qemu-dc5bd18fa57254e4b8597747c2100c92a55fc409.tar.bz2 |
RISC-V CPU Core Definition
Add CPU state header, CPU definitions and initialization routines
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
Signed-off-by: Michael Clark <mjc@sifive.com>
Diffstat (limited to 'target/riscv/cpu.h')
-rw-r--r-- | target/riscv/cpu.h | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h new file mode 100644 index 0000000..cff02a2 --- /dev/null +++ b/target/riscv/cpu.h @@ -0,0 +1,296 @@ +/* + * QEMU RISC-V CPU + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2017-2018 SiFive, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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/>. + */ + +#ifndef RISCV_CPU_H +#define RISCV_CPU_H + +/* QEMU addressing/paging config */ +#define TARGET_PAGE_BITS 12 /* 4 KiB Pages */ +#if defined(TARGET_RISCV64) +#define TARGET_LONG_BITS 64 +#define TARGET_PHYS_ADDR_SPACE_BITS 50 +#define TARGET_VIRT_ADDR_SPACE_BITS 39 +#elif defined(TARGET_RISCV32) +#define TARGET_LONG_BITS 32 +#define TARGET_PHYS_ADDR_SPACE_BITS 34 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 +#endif + +#define TCG_GUEST_DEFAULT_MO 0 + +#define ELF_MACHINE EM_RISCV +#define CPUArchState struct CPURISCVState + +#include "qemu-common.h" +#include "qom/cpu.h" +#include "exec/cpu-defs.h" +#include "fpu/softfloat.h" + +#define TYPE_RISCV_CPU "riscv-cpu" + +#define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU +#define RISCV_CPU_TYPE_NAME(name) (name RISCV_CPU_TYPE_SUFFIX) + +#define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any") +#define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1") +#define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0") +#define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu") +#define TYPE_RISCV_CPU_RV64GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.9.1") +#define TYPE_RISCV_CPU_RV64GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.10.0") +#define TYPE_RISCV_CPU_RV64IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv64imacu-nommu") +#define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") +#define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") +#define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34") +#define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54") + +#define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2)) +#define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2)) + +#if defined(TARGET_RISCV32) +#define RVXLEN RV32 +#elif defined(TARGET_RISCV64) +#define RVXLEN RV64 +#endif + +#define RV(x) ((target_ulong)1 << (x - 'A')) + +#define RVI RV('I') +#define RVM RV('M') +#define RVA RV('A') +#define RVF RV('F') +#define RVD RV('D') +#define RVC RV('C') +#define RVS RV('S') +#define RVU RV('U') + +/* S extension denotes that Supervisor mode exists, however it is possible + to have a core that support S mode but does not have an MMU and there + is currently no bit in misa to indicate whether an MMU exists or not + so a cpu features bitfield is required */ +enum { + RISCV_FEATURE_MMU +}; + +#define USER_VERSION_2_02_0 0x00020200 +#define PRIV_VERSION_1_09_1 0x00010901 +#define PRIV_VERSION_1_10_0 0x00011000 + +#define TRANSLATE_FAIL 1 +#define TRANSLATE_SUCCESS 0 +#define NB_MMU_MODES 4 +#define MMU_USER_IDX 3 + +#define MAX_RISCV_PMPS (16) + +typedef struct CPURISCVState CPURISCVState; + +#include "pmp.h" + +struct CPURISCVState { + target_ulong gpr[32]; + uint64_t fpr[32]; /* assume both F and D extensions */ + target_ulong pc; + target_ulong load_res; + target_ulong load_val; + + target_ulong frm; + + target_ulong badaddr; + + target_ulong user_ver; + target_ulong priv_ver; + target_ulong misa; + + uint32_t features; + +#ifndef CONFIG_USER_ONLY + target_ulong priv; + target_ulong resetvec; + + target_ulong mhartid; + target_ulong mstatus; + /* + * CAUTION! Unlike the rest of this struct, mip is accessed asynchonously + * by I/O threads and other vCPUs, so hold the iothread mutex before + * operating on it. CPU_INTERRUPT_HARD should be in effect iff this is + * non-zero. Use riscv_cpu_set_local_interrupt. + */ + uint32_t mip; /* allow atomic_read for >= 32-bit hosts */ + target_ulong mie; + target_ulong mideleg; + + target_ulong sptbr; /* until: priv-1.9.1 */ + target_ulong satp; /* since: priv-1.10.0 */ + target_ulong sbadaddr; + target_ulong mbadaddr; + target_ulong medeleg; + + target_ulong stvec; + target_ulong sepc; + target_ulong scause; + + target_ulong mtvec; + target_ulong mepc; + target_ulong mcause; + target_ulong mtval; /* since: priv-1.10.0 */ + + uint32_t mucounteren; + uint32_t mscounteren; + target_ulong scounteren; /* since: priv-1.10.0 */ + target_ulong mcounteren; /* since: priv-1.10.0 */ + + target_ulong sscratch; + target_ulong mscratch; + + /* temporary htif regs */ + uint64_t mfromhost; + uint64_t mtohost; + uint64_t timecmp; + + /* physical memory protection */ + pmp_table_t pmp_state; +#endif + + float_status fp_status; + + /* QEMU */ + CPU_COMMON + + /* Fields from here on are preserved across CPU reset. */ + QEMUTimer *timer; /* Internal timer */ +}; + +#define RISCV_CPU_CLASS(klass) \ + OBJECT_CLASS_CHECK(RISCVCPUClass, (klass), TYPE_RISCV_CPU) +#define RISCV_CPU(obj) \ + OBJECT_CHECK(RISCVCPU, (obj), TYPE_RISCV_CPU) +#define RISCV_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RISCVCPUClass, (obj), TYPE_RISCV_CPU) + +/** + * RISCVCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * + * A RISCV CPU model. + */ +typedef struct RISCVCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; + void (*parent_reset)(CPUState *cpu); +} RISCVCPUClass; + +/** + * RISCVCPU: + * @env: #CPURISCVState + * + * A RISCV CPU. + */ +typedef struct RISCVCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + CPURISCVState env; +} RISCVCPU; + +static inline RISCVCPU *riscv_env_get_cpu(CPURISCVState *env) +{ + return container_of(env, RISCVCPU, env); +} + +static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext) +{ + return (env->misa & ext) != 0; +} + +static inline bool riscv_feature(CPURISCVState *env, int feature) +{ + return env->features & (1ULL << feature); +} + +#include "cpu_user.h" +#include "cpu_bits.h" + +extern const char * const riscv_int_regnames[]; +extern const char * const riscv_fpr_regnames[]; +extern const char * const riscv_excp_names[]; +extern const char * const riscv_intr_names[]; + +#define ENV_GET_CPU(e) CPU(riscv_env_get_cpu(e)) +#define ENV_OFFSET offsetof(RISCVCPU, env) + +void riscv_cpu_do_interrupt(CPUState *cpu); +int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); +int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch); +hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); +int riscv_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, + int rw, int mmu_idx); + +char *riscv_isa_string(RISCVCPU *cpu); +void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf); + +#define cpu_init(cpu_model) cpu_generic_init(TYPE_RISCV_CPU, cpu_model) +#define cpu_signal_handler cpu_riscv_signal_handler +#define cpu_list riscv_cpu_list +#define cpu_mmu_index riscv_cpu_mmu_index + +void riscv_set_mode(CPURISCVState *env, target_ulong newpriv); + +void riscv_translate_init(void); +RISCVCPU *cpu_riscv_init(const char *cpu_model); +int cpu_riscv_signal_handler(int host_signum, void *pinfo, void *puc); +void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env, + uint32_t exception, uintptr_t pc); + +target_ulong cpu_riscv_get_fflags(CPURISCVState *env); +void cpu_riscv_set_fflags(CPURISCVState *env, target_ulong); + +#define TB_FLAGS_MMU_MASK 3 +#define TB_FLAGS_FP_ENABLE MSTATUS_FS + +static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; +#ifdef CONFIG_USER_ONLY + *flags = TB_FLAGS_FP_ENABLE; +#else + *flags = cpu_mmu_index(env, 0) | (env->mstatus & MSTATUS_FS); +#endif +} + +void csr_write_helper(CPURISCVState *env, target_ulong val_to_write, + target_ulong csrno); +target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno); + +#ifndef CONFIG_USER_ONLY +void riscv_set_local_interrupt(RISCVCPU *cpu, target_ulong mask, int value); +#endif + +#include "exec/cpu-all.h" + +#endif /* RISCV_CPU_H */ |