/*
 * 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

#include "hw/core/cpu.h"
#include "hw/core/registerfields.h"
#include "hw/core/qdev-properties.h"
#include "exec/cpu-common.h"
#include "exec/cpu-interrupt.h"
#include "exec/gdbstub.h"
#include "exec/target_long.h"
#include "qemu/cpu-float.h"
#include "qom/object.h"
#include "qemu/int128.h"
#include "cpu_bits.h"
#include "cpu_cfg.h"
#include "qapi/qapi-types-common.h"
#include "cpu-qom.h"

typedef struct CPUArchState CPURISCVState;

#define CPU_RESOLVING_TYPE TYPE_RISCV_CPU

#if defined(TARGET_RISCV32)
# define TYPE_RISCV_CPU_BASE            TYPE_RISCV_CPU_BASE32
#elif defined(TARGET_RISCV64)
# define TYPE_RISCV_CPU_BASE            TYPE_RISCV_CPU_BASE64
#endif

/*
 * b0: Whether a instruction always raise a store AMO or not.
 */
#define RISCV_UW2_ALWAYS_STORE_AMO 1

#define RV(x) BIT(x - 'A')

/*
 * Update misa_bits[], misa_ext_info_arr[] and misa_ext_cfgs[]
 * when adding new MISA bits here.
 */
#define RVI RV('I')
#define RVE RV('E') /* E and I are mutually exclusive */
#define RVM RV('M')
#define RVA RV('A')
#define RVF RV('F')
#define RVD RV('D')
#define RVV RV('V')
#define RVC RV('C')
#define RVS RV('S')
#define RVU RV('U')
#define RVH RV('H')
#define RVG RV('G')
#define RVB RV('B')
#define RVX RV('X')

extern const uint32_t misa_bits[];
const char *riscv_get_misa_ext_name(uint32_t bit);
const char *riscv_get_misa_ext_description(uint32_t bit);

#define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop)
#define ENV_CSR_OFFSET(_csr) offsetof(CPURISCVState, _csr)

typedef struct riscv_cpu_profile {
    struct riscv_cpu_profile *u_parent;
    struct riscv_cpu_profile *s_parent;
    const char *name;
    uint32_t misa_ext;
    /*
     * The profile is enabled/disabled via command line or
     * via cpu_init(). Enabling a profile will add all its
     * mandatory extensions in the CPU during init().
     */
    bool enabled;
    /*
     * The profile is present in the CPU, i.e. the current set of
     * CPU extensions complies with it. A profile can be enabled
     * and not present (e.g. the user disabled a mandatory extension)
     * and the other way around (e.g. all mandatory extensions are
     * present in a non-profile CPU).
     *
     * QMP uses this flag.
     */
    bool present;
    bool user_set;
    int priv_spec;
    int satp_mode;
    const int32_t ext_offsets[];
} RISCVCPUProfile;

#define RISCV_PROFILE_EXT_LIST_END -1
#define RISCV_PROFILE_ATTR_UNUSED -1

extern RISCVCPUProfile *riscv_profiles[];

/*
 * Type large enough to hold all PRV_* fields, update CPUArchState::priv
 * migration field if changing this type.
 */
typedef uint8_t privilege_mode_t;

/* Privileged specification version */
#define PRIV_VER_1_10_0_STR "v1.10.0"
#define PRIV_VER_1_11_0_STR "v1.11.0"
#define PRIV_VER_1_12_0_STR "v1.12.0"
#define PRIV_VER_1_13_0_STR "v1.13.0"
enum {
    PRIV_VERSION_1_10_0 = 0,
    PRIV_VERSION_1_11_0,
    PRIV_VERSION_1_12_0,
    PRIV_VERSION_1_13_0,

    PRIV_VERSION_LATEST = PRIV_VERSION_1_13_0,
};

#define VEXT_VERSION_1_00_0 0x00010000
#define VEXT_VER_1_00_0_STR "v1.0"

enum {
    TRANSLATE_SUCCESS,
    TRANSLATE_FAIL,
    TRANSLATE_PMP_FAIL,
    TRANSLATE_G_STAGE_FAIL,
    TRANSLATE_PMA_FAIL,
};

/* Extension context status */
typedef enum {
    EXT_STATUS_DISABLED = 0,
    EXT_STATUS_INITIAL,
    EXT_STATUS_CLEAN,
    EXT_STATUS_DIRTY,
} RISCVExtStatus;

/* Enum holds PMM field values for Zjpm v1.0 extension */
typedef enum {
    PMM_FIELD_DISABLED = 0,
    PMM_FIELD_RESERVED = 1,
    PMM_FIELD_PMLEN7   = 2,
    PMM_FIELD_PMLEN16  = 3,
} RISCVPmPmm;

typedef struct riscv_cpu_implied_exts_rule {
#ifndef CONFIG_USER_ONLY
    /*
     * Bitmask indicates the rule enabled status for the harts.
     * This enhancement is only available in system-mode QEMU,
     * as we don't have a good way (e.g. mhartid) to distinguish
     * the SMP cores in user-mode QEMU.
     */
    unsigned long *enabled;
#endif
    /* True if this is a MISA implied rule. */
    bool is_misa;
    /* ext is MISA bit if is_misa flag is true, else multi extension offset. */
    const uint32_t ext;
    const uint32_t implied_misa_exts;
    const uint32_t implied_multi_exts[];
} RISCVCPUImpliedExtsRule;

extern RISCVCPUImpliedExtsRule *riscv_misa_ext_implied_rules[];
extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[];

#define RISCV_IMPLIED_EXTS_RULE_END -1

#define MMU_USER_IDX 3

#if !defined(CONFIG_USER_ONLY)
#include "pmp.h"
#endif

#define RV_VLEN_MAX 1024
#define RV_MAX_MHPMEVENTS 32
#define RV_MAX_MHPMCOUNTERS 32

/*
 * The Debug 1.0 spec allows a humongous amount of triggers.  Section
 * "Enumeration" says: "The above algorithm reads back tselect so that
 * implementations which have 2^n triggers only need to implement n
 * bits of tselect.".  tselect can have up to XLEN bits, so the max
 * theoretical RV_MAX_TRIGGERS value is 2^XLEN.
 *
 * Allowing 2^XLEN triggers per hart is silly so we'll set a max to a
 * modest 1024 triggers, which is way more than what we see current
 * hardware use (most chips uses 2-4 triggers per hart, RISC-V Server
 * Ref requires at least 11).  With a 1024 max per hart we'll be set
 * for a long time ... hopefully.
 */
#define RV_MAX_TRIGGERS 1024
#define RV_DEFAULT_NUM_TRIGGERS 2

FIELD(VTYPE, VLMUL, 0, 3)
FIELD(VTYPE, VSEW, 3, 3)
FIELD(VTYPE, VTA, 6, 1)
FIELD(VTYPE, VMA, 7, 1)
FIELD(VTYPE, ALTFMT, 8, 1)
FIELD(VTYPE, RESERVED, 9, sizeof(uint64_t) * 8 - 10)

#ifndef CONFIG_USER_ONLY
/* machine specific AIA ireg read-modify-write callback */
#define AIA_MAKE_IREG(__isel, __priv, __virt, __vgein, __xlen)                 \
    ((uint32_t)((((__xlen) & 0xff) << 24) |                                    \
                (((__vgein) & 0x3f) << 20) |                                   \
                (((__virt) & 0x1) << 18) |                                     \
                (((__priv) & 0x3) << 16) |                                     \
                  (__isel & 0xffff)))
#define AIA_IREG_ISEL(__ireg) ((__ireg) & 0xffff)
#define AIA_IREG_PRIV(__ireg) (((__ireg) >> 16) & 0x3)
#define AIA_IREG_VIRT(__ireg) (((__ireg) >> 18) & 0x1)
#define AIA_IREG_VGEIN(__ireg) (((__ireg) >> 20) & 0x3f)
#define AIA_IREG_XLEN(__ireg) (((__ireg) >> 24) & 0xff)

typedef int (*aia_ireg_rmw_fn)(void *arg, uint32_t reg, uint64_t *val,
                               uint64_t new_val, uint64_t write_mask);
#endif

typedef struct PMUCTRState {
    /* Current value of a counter */
    uint64_t mhpmcounter_val;
    /* Snapshot value of a counter */
    uint64_t mhpmcounter_prev;
    /* Value beyond INT64_MAX before overflow interrupt trigger */
    uint64_t irq_overflow_left;
} PMUCTRState;

typedef struct PMUFixedCtrState {
    /* Track cycle and icount for each privilege mode */
    uint64_t counter[4];
    uint64_t counter_prev[4];
    /* Track cycle and icount for each privilege mode when V = 1*/
    uint64_t counter_virt[2];
    uint64_t counter_virt_prev[2];
} PMUFixedCtrState;

struct CPUArchState {
    uint64_t gpr[32];
    uint64_t gprh[32]; /* 64 top bits of the 128-bit registers */

    /* vector coprocessor state. */
    uint64_t vreg[32 * RV_VLEN_MAX / 64] QEMU_ALIGNED(16);
    uint64_t vtype;
    uint32_t vl;
    uint32_t vstart;
    uint8_t vxrm;
    uint8_t vxsat;
    bool vill;

    uint64_t pc;
    uint64_t load_res;
    uint64_t load_val;

    /* Floating-Point state */
    uint64_t fpr[32]; /* assume both F and D extensions */
    uint8_t frm;
    float_status fp_status;

    uint64_t badaddr;
    uint64_t bins;

    uint64_t guest_phys_fault_addr;

    uint32_t priv_ver;
    uint32_t vext_ver;

    /* RISCVMXL, but uint32_t for vmstate migration */
    uint32_t misa_mxl;      /* current mxl */
    uint32_t misa_ext;      /* current extensions */
    uint32_t misa_ext_mask; /* max ext for this cpu */
    uint32_t xl;            /* current xlen */

    /* 128-bit helpers upper part return value */
    uint64_t retxh;

    uint64_t jvt;

    /* elp state for zicfilp extension */
    bool      elp;
    /* shadow stack register for zicfiss extension */
    uint64_t ssp;
    /* env place holder for extra word 2 during unwind */
    uint64_t excp_uw2;
    /* sw check code for sw check exception */
    uint8_t sw_check_code;
#ifdef CONFIG_USER_ONLY
    uint32_t elf_flags;
#endif

    privilege_mode_t priv;
    /* CSRs for execution environment configuration */
    uint64_t menvcfg;
    uint64_t senvcfg;

#ifndef CONFIG_USER_ONLY
    /* This contains QEMU specific information about the virt state. */
    bool virt_enabled;
    uint8_t geilen;
    uint64_t resetvec;

    uint64_t mhartid;
    /*
     * For RV32 this is 32-bit mstatus and 32-bit mstatush.
     * For RV64 this is a 64-bit mstatus.
     */
    uint64_t mstatus;

    uint64_t mip;
    /*
     * MIP contains the software writable version of SEIP ORed with the
     * external interrupt value. The MIP register is always up-to-date.
     * To keep track of the current source, we also save booleans of the values
     * here.
     */
    bool external_seip;
    bool software_seip;

    uint64_t miclaim;

    uint64_t mie;
    uint64_t mideleg;

    /*
     * When mideleg[i]=0 and mvien[i]=1, sie[i] is no more
     * alias of mie[i] and needs to be maintained separately.
     */
    uint64_t sie;

    /*
     * When hideleg[i]=0 and hvien[i]=1, vsie[i] is no more
     * alias of sie[i] (mie[i]) and needs to be maintained separately.
     */
    uint64_t vsie;

    uint64_t satp;   /* since: priv-1.10.0 */
    uint64_t stval;
    uint64_t medeleg;

    uint64_t stvec;
    uint64_t sepc;
    uint64_t scause;

    uint64_t mtvec;
    uint64_t mepc;
    uint64_t mcause;
    uint64_t mtval;  /* since: priv-1.10.0 */

    uint64_t mctrctl;
    uint32_t sctrdepth;
    uint32_t sctrstatus;
    uint64_t vsctrctl;

    uint64_t ctr_src[16 << SCTRDEPTH_MAX];
    uint64_t ctr_dst[16 << SCTRDEPTH_MAX];
    uint64_t ctr_data[16 << SCTRDEPTH_MAX];

    /* Machine and Supervisor interrupt priorities */
    uint8_t miprio[64];
    uint8_t siprio[64];

    /* AIA CSRs */
    uint16_t miselect;
    uint16_t siselect;
    uint64_t mvien;
    uint64_t mvip;

    /* Hypervisor CSRs */
    uint64_t hstatus;
    uint64_t hedeleg;
    uint64_t hideleg;
    uint32_t hcounteren;
    uint64_t htval;
    uint64_t htinst;
    uint64_t hgatp;
    uint64_t hgeie;
    uint64_t hgeip;
    uint64_t htimedelta;
    uint64_t hvien;

    /*
     * Bits VSSIP, VSTIP and VSEIP in hvip are maintained in mip. Other bits
     * from 0:12 are reserved. Bits 13:63 are not aliased and must be separately
     * maintain in hvip.
     */
    uint64_t hvip;

    /* Hypervisor controlled virtual interrupt priorities */
    uint32_t hvictl;
    uint8_t hviprio[64];

    /* Upper 64-bits of 128-bit CSRs */
    uint64_t mscratchh;
    uint64_t sscratchh;

    /* Virtual CSRs */
    /*
     * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
     * For RV64 this is a 64-bit vsstatus.
     */
    uint64_t vsstatus;
    uint64_t vstvec;
    uint64_t vsscratch;
    uint64_t vsepc;
    uint64_t vscause;
    uint64_t vstval;
    uint64_t vsatp;

    /* AIA VS-mode CSRs */
    uint16_t vsiselect;

    uint64_t mtval2;
    uint64_t mtinst;

    /* HS Backup CSRs */
    uint64_t stvec_hs;
    uint64_t sscratch_hs;
    uint64_t sepc_hs;
    uint64_t scause_hs;
    uint64_t stval_hs;
    uint64_t satp_hs;
    uint64_t mstatus_hs;

    /*
     * Signals whether the current exception occurred with two-stage address
     * translation active.
     */
    bool two_stage_lookup;
    /*
     * Signals whether the current exception occurred while doing two-stage
     * address translation for the VS-stage page table walk.
     */
    bool two_stage_indirect_lookup;

    uint32_t scounteren;
    uint32_t mcounteren;

    uint32_t scountinhibit;
    uint32_t mcountinhibit;

    /* PMU cycle & instret privilege mode filtering */
    uint64_t mcyclecfg;
    uint64_t minstretcfg;

    /* PMU counter state */
    PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS];

    /*
     * PMU event selector configured values. First three are unused.
     * For RV32 top 32 bits are accessed via the mhpmeventh CSR.
     */
    uint64_t mhpmevent_val[RV_MAX_MHPMEVENTS];

    PMUFixedCtrState pmu_fixed_ctrs[2];

    uint64_t sscratch;
    uint64_t mscratch;

    /* Sstc CSRs */
    uint64_t stimecmp;

    uint64_t vstimecmp;

    /* physical memory protection */
    pmp_table_t pmp_state;
    uint64_t mseccfg;

    /* trigger module */
    uint16_t mcontext;
    uint8_t trigger_cur;
    /*
     * num_triggers is the length of tdata1, tdata2, tdata3,
     * cpu_breakpoint, cpu_watchpoint and itrigger_timer
     * arrays.
     */
    uint32_t num_triggers;
    uint64_t *tdata1;
    uint64_t *tdata2;
    uint64_t *tdata3;
    struct CPUBreakpoint **cpu_breakpoint;
    struct CPUWatchpoint **cpu_watchpoint;
    QEMUTimer **itrigger_timer;
    int64_t last_icount;
    bool itrigger_enabled;

    /* machine specific rdtime callback */
    uint64_t (*rdtime_fn)(void *);
    void *rdtime_fn_arg;

    /* machine specific AIA ireg read-modify-write callback */
    aia_ireg_rmw_fn aia_ireg_rmw_cb[4];
    void *aia_ireg_rmw_cb_arg[4];

    /* True if in debugger mode.  */
    bool debugger;

    uint64_t mstateen[SMSTATEEN_MAX_COUNT];
    uint64_t hstateen[SMSTATEEN_MAX_COUNT];
    uint64_t sstateen[SMSTATEEN_MAX_COUNT];
    uint64_t henvcfg;

    /* RNMI */
    uint64_t mnscratch;
    uint64_t mnepc;
    uint64_t mncause; /* mncause without bit XLEN-1 set to 1 */
    uint64_t mnstatus;
    uint64_t rnmip;
    uint64_t rnmi_irqvec;
    uint64_t rnmi_excpvec;
#endif

    /* Fields from here on are preserved across CPU reset. */
    QEMUTimer *stimer; /* Internal timer for S-mode interrupt */
    QEMUTimer *vstimer; /* Internal timer for VS-mode interrupt */
    bool vstime_irq;

    hwaddr kernel_addr;
    hwaddr fdt_addr;

#ifdef CONFIG_KVM
    /* kvm timer */
    bool kvm_timer_dirty;
    uint64_t kvm_timer_time;
    uint64_t kvm_timer_compare;
    uint64_t kvm_timer_state;
    uint64_t kvm_timer_frequency;
#endif /* CONFIG_KVM */
};

/*
 * map is a 16-bit bitmap: the most significant set bit in map is the maximum
 * satp mode that is supported. It may be chosen by the user and must respect
 * what qemu implements (valid_1_10_32/64) and what the hw is capable of
 * (supported bitmap below).
 *
 * init is a 16-bit bitmap used to make sure the user selected a correct
 * configuration as per the specification.
 */
typedef struct {
    uint16_t map, init;
} RISCVSATPModes;

/*
 * RISCVCPU:
 * @env: #CPURISCVState
 *
 * A RISCV CPU.
 */
struct ArchCPU {
    CPUState parent_obj;

    CPURISCVState env;

    GDBFeature dyn_csr_feature;
    GDBFeature dyn_vreg_feature;

    /* Configuration Settings */
    RISCVCPUConfig cfg;
    RISCVSATPModes satp_modes;

    QEMUTimer *pmu_timer;
    /* A bitmask of Available programmable counters */
    uint32_t pmu_avail_ctrs;
    /* Mapping of events to counters */
    GHashTable *pmu_event_ctr_map;
    GHashTable *user_options;
    const GPtrArray *decoders;
};

typedef struct RISCVCSR RISCVCSR;

typedef struct RISCVCPUDef {
    RISCVMXL misa_mxl_max;  /* max mxl for this cpu */
    RISCVCPUProfile *profile;
    uint32_t misa_ext;
    int priv_spec;
    int32_t vext_spec;
    RISCVCPUConfig cfg;
    bool bare;
    const RISCVCSR *custom_csrs;
    /* This is just a setter for env->num_triggers.  */
    uint32_t num_triggers;
} RISCVCPUDef;

/**
 * RISCVCPUClass:
 * @parent_realize: The parent class' realize handler.
 * @parent_unrealize: The parent class' unrealize handler.
 * @parent_phases: The parent class' reset phase handlers.
 *
 * A RISCV CPU model.
 */
struct RISCVCPUClass {
    CPUClass parent_class;

    DeviceRealize parent_realize;
    DeviceUnrealize parent_unrealize;
    ResettablePhases parent_phases;
    RISCVCPUDef *def;
};

static inline int riscv_has_ext(CPURISCVState *env, uint32_t ext)
{
    return (env->misa_ext & ext) != 0;
}

#include "cpu_user.h"

extern const char * const riscv_int_regnames[];
extern const char * const riscv_int_regnamesh[];
extern const char * const riscv_fpr_regnames[];
extern const char * const riscv_rvv_regnames[];

const char *riscv_cpu_get_trap_name(uint64_t cause, bool async);
int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
                               int cpuid, DumpState *s);
int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
                               int cpuid, DumpState *s);
int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
uint8_t riscv_cpu_default_priority(int irq);
uint64_t riscv_cpu_all_pending(CPURISCVState *env);
int riscv_cpu_mirq_pending(CPURISCVState *env);
int riscv_cpu_sirq_pending(CPURISCVState *env);
int riscv_cpu_vsirq_pending(CPURISCVState *env);
bool riscv_cpu_fp_enabled(CPURISCVState *env);
uint8_t riscv_cpu_get_geilen(CPURISCVState *env);
void riscv_cpu_set_geilen(CPURISCVState *env, uint8_t geilen);
bool riscv_cpu_vector_enabled(CPURISCVState *env);
void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch);
bool cpu_get_fcfien(CPURISCVState *env);
bool cpu_get_bcfien(CPURISCVState *env);
bool riscv_env_smode_dbltrp_enabled(CPURISCVState *env, bool virt);
G_NORETURN void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
                                               MMUAccessType access_type,
                                               int mmu_idx, uintptr_t retaddr);
bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                        MMUAccessType access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr);
char *riscv_isa_string(RISCVCPU *cpu);
int riscv_cpu_max_xlen(RISCVCPUClass *mcc);
bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname);

#ifndef CONFIG_USER_ONLY
void riscv_cpu_do_interrupt(CPUState *cpu);
void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename);
void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
                                     vaddr addr, unsigned size,
                                     MMUAccessType access_type,
                                     int mmu_idx, MemTxAttrs attrs,
                                     MemTxResult response, uintptr_t retaddr);
hwaddr riscv_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask,
                              uint64_t value);
void riscv_cpu_set_rnmi(RISCVCPU *cpu, uint32_t irq, bool level);
void riscv_cpu_interrupt(CPURISCVState *env);
#define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
                             void *arg);
void riscv_cpu_set_aia_ireg_rmw_cb(CPURISCVState *env, privilege_mode_t priv,
                                   aia_ireg_rmw_fn rmw_fn,
                                   void *rmw_fn_arg);

RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
#endif /* !CONFIG_USER_ONLY */

void riscv_cpu_set_mode(CPURISCVState *env, privilege_mode_t newpriv,
                        bool virt_en);

void riscv_ctr_add_entry(CPURISCVState *env, uint64_t src, uint64_t dst,
                         enum CTRType type, privilege_mode_t prev_priv,
                         bool prev_virt);
void riscv_ctr_clear(CPURISCVState *env);

void riscv_translate_init(void);
void riscv_translate_code(CPUState *cs, TranslationBlock *tb,
                          int *max_insns, vaddr pc, void *host_pc);

G_NORETURN void riscv_raise_exception(CPURISCVState *env,
                                      RISCVException exception,
                                      uintptr_t pc);

uint8_t riscv_cpu_get_fflags(CPURISCVState *env);
void riscv_cpu_set_fflags(CPURISCVState *env, uint8_t);
void riscv_cpu_check_fflags(CPURISCVState *env, FloatExceptionFlags);

#ifndef CONFIG_USER_ONLY
void cpu_set_exception_base(int vp_index, uint64_t address);
#endif

FIELD(TB_FLAGS, MEM_IDX, 0, 3)
FIELD(TB_FLAGS, FS, 3, 2)
/* Vector flags */
FIELD(TB_FLAGS, VS, 5, 2)
FIELD(TB_FLAGS, LMUL, 7, 3)
FIELD(TB_FLAGS, SEW, 10, 3)
FIELD(TB_FLAGS, VL_EQ_VLMAX, 13, 1)
FIELD(TB_FLAGS, VILL, 14, 1)
FIELD(TB_FLAGS, VSTART_EQ_ZERO, 15, 1)
/* The combination of MXL/SXL/UXL that applies to the current cpu mode. */
FIELD(TB_FLAGS, XL, 16, 2)
/* If PointerMasking should be applied */
FIELD(TB_FLAGS, PM_MASK_ENABLED, 18, 1)
FIELD(TB_FLAGS, PM_BASE_ENABLED, 19, 1)
FIELD(TB_FLAGS, VTA, 18, 1)
FIELD(TB_FLAGS, VMA, 19, 1)
/* Native debug itrigger */
FIELD(TB_FLAGS, ITRIGGER, 20, 1)
/* Virtual mode enabled */
FIELD(TB_FLAGS, VIRT_ENABLED, 21, 1)
FIELD(TB_FLAGS, PRIV, 22, 2)
FIELD(TB_FLAGS, AXL, 24, 2)
/* zicfilp needs a TB flag to track indirect branches */
FIELD(TB_FLAGS, FCFI_ENABLED, 26, 1)
FIELD(TB_FLAGS, FCFI_LP_EXPECTED, 27, 1)
/* zicfiss needs a TB flag so that correct TB is located based on tb flags */
FIELD(TB_FLAGS, BCFI_ENABLED, 28, 1)
/* If pointer masking should be applied and address sign extended */
FIELD(TB_FLAGS, PM_PMM, 29, 2)
FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)

FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)

#ifdef TARGET_RISCV32
#define riscv_cpu_mxl(env)  ((void)(env), MXL_RV32)
#else
static inline RISCVMXL riscv_cpu_mxl(CPURISCVState *env)
{
    return env->misa_mxl;
}
#endif
#define riscv_cpu_mxl_bits(env) (1UL << (4 + riscv_cpu_mxl(env)))

static inline const RISCVCPUConfig *riscv_cpu_cfg(CPURISCVState *env)
{
    return &env_archcpu(env)->cfg;
}

#if !defined(CONFIG_USER_ONLY)
static inline privilege_mode_t cpu_address_mode(CPURISCVState *env)
{
    privilege_mode_t mode = env->priv;

    if (mode == PRV_M && get_field(env->mstatus, MSTATUS_MPRV)) {
        mode = get_field(env->mstatus, MSTATUS_MPP);
    }
    return mode;
}

static inline RISCVMXL cpu_get_xl(CPURISCVState *env, privilege_mode_t mode)
{
    RISCVMXL xl = env->misa_mxl;
    /*
     * When emulating a 32-bit-only cpu, use RV32.
     * When emulating a 64-bit cpu, and MXL has been reduced to RV32,
     * MSTATUSH doesn't have UXL/SXL, therefore XLEN cannot be widened
     * back to RV64 for lower privs.
     */
    if (xl != MXL_RV32) {
        switch (mode) {
        case PRV_M:
            break;
        case PRV_U:
            xl = get_field(env->mstatus, MSTATUS64_UXL);
            break;
        default: /* PRV_S */
            xl = get_field(env->mstatus, MSTATUS64_SXL);
            break;
        }
    }
    return xl;
}
#endif

#if defined(TARGET_RISCV32)
#define cpu_recompute_xl(env)  ((void)(env), MXL_RV32)
#else
static inline RISCVMXL cpu_recompute_xl(CPURISCVState *env)
{
#if !defined(CONFIG_USER_ONLY)
    return cpu_get_xl(env, env->priv);
#else
    return env->misa_mxl;
#endif
}
#endif

#if defined(TARGET_RISCV32)
#define cpu_address_xl(env)  ((void)(env), MXL_RV32)
#else
static inline RISCVMXL cpu_address_xl(CPURISCVState *env)
{
#ifdef CONFIG_USER_ONLY
    return env->xl;
#else
    privilege_mode_t mode = cpu_address_mode(env);

    return cpu_get_xl(env, mode);
#endif
}
#endif

static inline uint16_t riscv_cpu_xlen(CPURISCVState *env)
{
    return 16 << env->xl;
}

#ifdef TARGET_RISCV32
#define riscv_cpu_sxl(env)  ((void)(env), MXL_RV32)
#else
static inline RISCVMXL riscv_cpu_sxl(CPURISCVState *env)
{
#ifdef CONFIG_USER_ONLY
    return env->misa_mxl;
#else
    if (env->misa_mxl != MXL_RV32) {
        return get_field(env->mstatus, MSTATUS64_SXL);
    }
#endif
    return MXL_RV32;
}
#endif

/*
 * Returns the current effective privilege mode.
 *
 * @env: CPURISCVState
 * @priv: The returned effective privilege mode.
 * @virt: The returned effective virtualization mode.
 *
 * Returns true if the effective privilege mode is modified.
 */
static inline QEMU_ALWAYS_INLINE
bool riscv_cpu_eff_priv(CPURISCVState *env, privilege_mode_t *priv, bool *virt)
{
    privilege_mode_t mode = env->priv;
    bool virt_enabled = false;
    bool mode_modified = false;

#ifndef CONFIG_USER_ONLY
    if (mode == PRV_M && get_field(env->mstatus, MSTATUS_MPRV)) {
        mode = get_field(env->mstatus, MSTATUS_MPP);
        virt_enabled = get_field(env->mstatus, MSTATUS_MPV) && (mode != PRV_M);
        mode_modified = true;
    } else {
        virt_enabled = env->virt_enabled;
    }
#endif

    if (priv) {
        *priv = mode;
    }

    if (virt) {
        *virt = virt_enabled;
    }

    return mode_modified;
}

static inline bool riscv_cpu_allow_16bit_insn(const RISCVCPUConfig *cfg,
                                              uint32_t priv_ver,
                                              uint32_t misa_ext)
{
    /* In priv spec version 1.12 or newer, C always implies Zca */
    if (priv_ver >= PRIV_VERSION_1_12_0) {
        return cfg->ext_zca;
    } else {
        return misa_ext & RVC;
    }
}

/*
 * Encode LMUL to lmul as follows:
 *     LMUL    vlmul    lmul
 *      1       000       0
 *      2       001       1
 *      4       010       2
 *      8       011       3
 *      -       100       -
 *     1/8      101      -3
 *     1/4      110      -2
 *     1/2      111      -1
 *
 * then, we can calculate VLMAX = vlen >> (vsew + 3 - lmul)
 * e.g. vlen = 256 bits, SEW = 16, LMUL = 1/8
 *      => VLMAX = vlen >> (1 + 3 - (-3))
 *               = 256 >> 7
 *               = 2
 */
static inline uint32_t vext_get_vlmax(uint32_t vlenb, uint32_t vsew,
                                      int8_t lmul)
{
    uint32_t vlen = vlenb << 3;

    /*
     * We need to use 'vlen' instead of 'vlenb' to
     * preserve the '+ 3' in the formula. Otherwise
     * we risk a negative shift if vsew < lmul.
     */
    return vlen >> (vsew + 3 - lmul);
}

bool riscv_cpu_is_32bit(RISCVCPU *cpu);

bool riscv_cpu_virt_mem_enabled(CPURISCVState *env, bool is_vm_ldst);
RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env);
RISCVPmPmm riscv_pm_get_vm_ldst_pmm(CPURISCVState *env);
uint32_t riscv_pm_get_pmlen(RISCVPmPmm pmm);

/*
 * Externally facing CSR access functions, wrappers around riscv_csr*().
 */

RISCVException riscv_csr_write_i64(CPURISCVState *env, int csrno, uint64_t val);
RISCVException riscv_csr_read_i64(CPURISCVState *env, int csrn, uint64_t *res);

/*
 * The event id are encoded based on the encoding specified in the
 * SBI specification v0.3
 */

enum riscv_pmu_event_idx {
    RISCV_PMU_EVENT_HW_CPU_CYCLES = 0x01,
    RISCV_PMU_EVENT_HW_INSTRUCTIONS = 0x02,
    RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS = 0x10019,
    RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS = 0x1001B,
    RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS = 0x10021,
};

/* used by tcg/tcg-cpu.c*/
void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en);
bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset);
void riscv_cpu_set_misa_ext(CPURISCVState *env, uint32_t ext);
bool riscv_cpu_is_vendor(Object *cpu_obj);

typedef struct isa_ext_data {
    const char *name;
    const char *prop_name;
    int min_version;
    int ext_enable_offset;
} RISCVIsaExtData;
extern const RISCVIsaExtData isa_edata_arr[];
char *riscv_cpu_get_name(RISCVCPU *cpu);

void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp);
void riscv_add_satp_mode_properties(Object *obj);
bool riscv_cpu_accelerator_compatible(RISCVCPU *cpu);

extern const bool valid_vm_1_10_32[], valid_vm_1_10_64[];

void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);

const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit);

const char *priv_spec_to_str(int priv_version);
#endif /* RISCV_CPU_H */
