From nobody Mon Feb 9 23:03:19 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1620393993; cv=none; d=zohomail.com; s=zohoarc; b=hqL8kofiz80ynRMIvGTFB2mUx8VP7qgyg5k5v+i6Zalnr58pIXEvGGJNtcYrmOsLnLS+/d+ZH8YIJTZ+0FcmI+qAlhduQes/rLQiH/7outcIngsFfYj9OdIGFqXM8kz/VJ1UTiND8/TJhKwBZO4MYDx6i50bOPQ/dgAoHsFTv2M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1620393993; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=arv3lEti3Bu76W601RK6X/gVLNNS6uzoqncYImK5w/U=; b=ZHgfRSXNrEWHB2SP5S4B6LCntwVsFOar3gUg+NHYxC1+5q9Ls+fi9VsKZD8kZ/nlYVEjeYeTgtKT5RalxAxzQQbCArzs4UyFYJwA+pc4W80qU7vigjJ1/TDf9hLXyTmR7nFqc60GJUKeKrRIN6YPDxxV2DEnoHI9iPQbnwaNlGM= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1620393993142561.5514010830218; Fri, 7 May 2021 06:26:33 -0700 (PDT) Received: from localhost ([::1]:54486 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lf0Uy-0002ID-12 for importer@patchew.org; Fri, 07 May 2021 09:26:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60720) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1levgX-0004aF-HI; Fri, 07 May 2021 04:18:09 -0400 Received: from smtp25.cstnet.cn ([159.226.251.25]:50032 helo=cstnet.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1levgS-0005jm-C2; Fri, 07 May 2021 04:18:09 -0400 Received: from localhost.localdomain (unknown [121.232.13.213]) by APP-05 (Coremail) with SMTP id zQCowAB3fSnh9pRgTQ5HAQ--.1834S3; Fri, 07 May 2021 16:14:26 +0800 (CST) From: wangjunqiang To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Subject: [RFC PATCH 1/5] target/riscv: Add Nuclei CSR and Update interrupt handling Date: Fri, 7 May 2021 16:16:50 +0800 Message-Id: <20210507081654.11056-2-wangjunqiang@iscas.ac.cn> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210507081654.11056-1-wangjunqiang@iscas.ac.cn> References: <20210507081654.11056-1-wangjunqiang@iscas.ac.cn> X-CM-TRANSID: zQCowAB3fSnh9pRgTQ5HAQ--.1834S3 X-Coremail-Antispam: 1UD129KBjvAXoWfWFyftr4rCrW8uF1UXw15twb_yoW5GrW7Ao WfJF4SvrsYywnakrZ29r12qr1jgFn8AwsavF1qkrWfWwn7Zr4rWF4Ut3Zava43trsIg3yU Jan2gF9xtFykAryfn29KB7ZKAUJUUUU5529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYZ7AC8VAFwI0_Xr0_Wr1l1xkIjI8I6I8E6xAIw20EY4v20xva j40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l82xGYIkIc2x26280x7IE14v26r18M28IrcIa0x kI8VCY1x0267AKxVWUCVW8JwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK021l84AC jcxK6xIIjxv20xvE14v26F1j6w1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26F4j6r4UJw A2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq3wAS 0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2 IY67AKxVWUGVWUXwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0 Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwCY02Avz4vE14v_GFyl42xK82 IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC2 0s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMI IF0xvE2Ix0cI8IcVAFwI0_JFI_Gr1lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF 0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I8E87 Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjfUea0PDUUUU X-Originating-IP: [121.232.13.213] X-CM-SenderInfo: pzdqwy5xqtxt1qj6x2xfdvhtffof0/1tbiBgcOAF0TfNHfbAAAsf Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: none client-ip=159.226.251.25; envelope-from=wangjunqiang@iscas.ac.cn; helo=cstnet.cn X-Spam_score_int: -31 X-Spam_score: -3.2 X-Spam_bar: --- X-Spam_report: (-3.2 / 5.0 requ) BAYES_00=-1.9, FORGED_SPF_HELO=1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 07 May 2021 09:24:09 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: liweiwei@iscas.ac.cn, wangjunqiang , bin.meng@windriver.com, Alistair.Francis@wdc.com, alapha23@gmail.com, palmer@dabbelt.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch adds Nuclei CSR support for ECLIC and update the related interrupt handling. https://doc.nucleisys.com/nuclei_spec/isa/core_csr.html --- target/riscv/cpu.c | 25 +- target/riscv/cpu.h | 42 ++- target/riscv/cpu_bits.h | 37 +++ target/riscv/cpu_helper.c | 80 +++++- target/riscv/csr.c | 347 +++++++++++++++++++++++- target/riscv/insn_trans/trans_rvi.c.inc | 16 +- target/riscv/op_helper.c | 14 + 7 files changed, 552 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7d6ed80f6b..b2a96effbc 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -173,6 +173,16 @@ static void rv64_sifive_e_cpu_init(Object *obj) set_priv_version(env, PRIV_VERSION_1_10_0); qdev_prop_set_bit(DEVICE(obj), "mmu", false); } + +static void rv64imafdcu_nuclei_cpu_init(Object *obj) +{ + CPURISCVState *env =3D &RISCV_CPU(obj)->env; + set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVU); + set_priv_version(env, PRIV_VERSION_1_10_0); + qdev_prop_set_bit(DEVICE(obj), "mmu", false); + set_resetvec(env, DEFAULT_RSTVEC); + set_feature(env, RISCV_FEATURE_PMP); +} #else static void rv32_base_cpu_init(Object *obj) { @@ -212,6 +222,16 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) set_resetvec(env, DEFAULT_RSTVEC); qdev_prop_set_bit(DEVICE(obj), "mmu", false); } + +static void rv32imafdcu_nuclei_cpu_init(Object *obj) +{ + CPURISCVState *env =3D &RISCV_CPU(obj)->env; + set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVU); + set_priv_version(env, PRIV_VERSION_1_10_0); + qdev_prop_set_bit(DEVICE(obj), "mmu", false); + set_resetvec(env, DEFAULT_RSTVEC); + set_feature(env, RISCV_FEATURE_PMP); +} #endif =20 static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) @@ -331,7 +351,7 @@ static bool riscv_cpu_has_work(CPUState *cs) * Definition of the WFI instruction requires it to ignore the privile= ge * mode and delegation registers, but respect individual enables */ - return (env->mip & env->mie) !=3D 0; + return ((env->mip & env->mie) !=3D 0 || (env->exccode !=3D -1)); #else return true; #endif @@ -356,6 +376,7 @@ static void riscv_cpu_reset(DeviceState *dev) env->mstatus &=3D ~(MSTATUS_MIE | MSTATUS_MPRV); env->mcause =3D 0; env->pc =3D env->resetvec; + env->exccode =3D -1; env->two_stage_lookup =3D false; #endif cs->exception_index =3D EXCP_NONE; @@ -704,10 +725,12 @@ static const TypeInfo riscv_cpu_type_infos[] =3D { DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32_sifive_e_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init= ), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32_sifive_u_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_NUCLEI_N307FD, rv32imafdcu_nuclei_cpu_ini= t), #elif defined(TARGET_RISCV64) DEFINE_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_NUCLEI_NX600FD, rv64imafdcu_nuclei_cpu_in= it), #endif }; =20 diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 0a33d387ba..1d3a1986a6 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -33,6 +33,7 @@ #define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU #define RISCV_CPU_TYPE_NAME(name) (name RISCV_CPU_TYPE_SUFFIX) #define CPU_RESOLVING_TYPE TYPE_RISCV_CPU +#define CPU_INTERRUPT_ECLIC CPU_INTERRUPT_TGT_EXT_0 =20 #define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any") #define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") @@ -43,6 +44,8 @@ #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 TYPE_RISCV_CPU_NUCLEI_N307FD RISCV_CPU_TYPE_NAME("nuclei-n307fd= ") +#define TYPE_RISCV_CPU_NUCLEI_NX600FD RISCV_CPU_TYPE_NAME("nuclei-nx600= fd") =20 #if defined(TARGET_RISCV32) # define TYPE_RISCV_CPU_BASE TYPE_RISCV_CPU_BASE32 @@ -80,7 +83,8 @@ enum { RISCV_FEATURE_MMU, RISCV_FEATURE_PMP, - RISCV_FEATURE_MISA + RISCV_FEATURE_MISA, + RISCV_FEATURE_ECLIC }; =20 #define PRIV_VERSION_1_10_0 0x00011000 @@ -174,10 +178,34 @@ struct CPURISCVState { target_ulong scause; =20 target_ulong mtvec; + target_ulong mtvt; /* eclic */ target_ulong mepc; target_ulong mcause; target_ulong mtval; /* since: priv-1.10.0 */ =20 + target_ulong mnxti; /* eclic */ + target_ulong mintstatus; /* eclic */ + target_ulong mscratchcsw; + target_ulong mscratchcswl; + + /* NMI CSR*/ + target_ulong mnvec; + target_ulong msubm; + target_ulong mdcause; + target_ulong mmisc_ctl; + target_ulong msavestatus; + target_ulong msaveepc1; + target_ulong msavecause1; + target_ulong msaveepc2; + target_ulong msavecause2; + target_ulong msavedcause1; + target_ulong msavedcause2; + target_ulong pushmsubm; + target_ulong mtvt2; + target_ulong jalmnxti; + target_ulong pushmcause; + target_ulong pushmepc; + /* Hypervisor CSRs */ target_ulong hstatus; target_ulong hedeleg; @@ -228,6 +256,9 @@ struct CPURISCVState { uint64_t mtohost; uint64_t timecmp; =20 + /*nuclei timer comparators */ + uint64_t mtimecmp; + /* physical memory protection */ pmp_table_t pmp_state; =20 @@ -243,6 +274,13 @@ struct CPURISCVState { =20 /* Fields from here on are preserved across CPU reset. */ QEMUTimer *timer; /* Internal timer */ + + QEMUTimer *mtimer; /* Nuclei Internal timer */ + void *eclic; + uint32_t exccode; /* irq id: 0~11 shv: 12 */ + uint32_t eclic_flag; + + bool irq_pending; }; =20 OBJECT_DECLARE_TYPE(RISCVCPU, RISCVCPUClass, @@ -364,6 +402,8 @@ void riscv_cpu_list(void); void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env); int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value= ); +void riscv_cpu_eclic_clean_pending(void *eclic, int irq); +void riscv_cpu_eclic_get_next_interrupt(void *eclic); #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value = */ void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), uint32_t arg); diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index caf4599207..24ed7a99e1 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -149,6 +149,7 @@ #define CSR_MIE 0x304 #define CSR_MTVEC 0x305 #define CSR_MCOUNTEREN 0x306 +#define CSR_MTVT 0x307 /* customized */ =20 /* 32-bit only */ #define CSR_MSTATUSH 0x310 @@ -165,6 +166,10 @@ #define CSR_MCAUSE 0x342 #define CSR_MTVAL 0x343 #define CSR_MIP 0x344 +#define CSR_MNXTI 0x345 /* customized */ +#define CSR_MINTSTATUS 0x346 /* customized */ +#define CSR_MSCRATCHCSW 0x348 /* customized */ +#define CSR_MSCRATCHCSWL 0x349 /* customized */ =20 /* Legacy Machine Trap Handling (priv v1.9.1) */ #define CSR_MBADADDR 0x343 @@ -265,6 +270,24 @@ #define CSR_DPC 0x7b1 #define CSR_DSCRATCH 0x7b2 =20 +/* Nuclei Customized Registers*/ +#define CSR_MNVEC 0x07c3 +#define CSR_MSUBM 0x07c4 +#define CSR_MDCAUSE 0x07c9 +#define CSR_MMISC_CTL 0x07d0 +#define CSR_MSAVESTATUS 0x07d6 +#define CSR_MSAVEEPC1 0x07d7 +#define CSR_MSAVECAUSE1 0x07d8 +#define CSR_MSAVEEPC2 0x07d9 +#define CSR_MSAVECAUSE2 0x07da +#define CSR_MSAVEDCAUSE1 0x07db +#define CSR_MSAVEDCAUSE2 0x07dc +#define CSR_PUSHMSUBM 0x07eb +#define CSR_MTVT2 0x07ec +#define CSR_JALMNXTI 0x07ed +#define CSR_PUSHMCAUSE 0x07ee +#define CSR_PUSHMEPC 0x07ef + /* Performance Counters */ #define CSR_MHPMCOUNTER3 0xb03 #define CSR_MHPMCOUNTER4 0xb04 @@ -549,6 +572,7 @@ #define RISCV_EXCP_VIRT_INSTRUCTION_FAULT 0x16 #define RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT 0x17 =20 +#define RISCV_EXCP_INT_ECLIC 0x40000000 #define RISCV_EXCP_INT_FLAG 0x80000000 #define RISCV_EXCP_INT_MASK 0x7fffffff =20 @@ -592,4 +616,17 @@ #define MIE_UTIE (1 << IRQ_U_TIMER) #define MIE_SSIE (1 << IRQ_S_SOFT) #define MIE_USIE (1 << IRQ_U_SOFT) + +/* mintstatus */ +#define MINTSTATUS_MIL 0xff000000 /* mil[31:24] */ +#define MINTSTATUS_UIL 0x000000ff /* uil[7:0] */ + +/* mcause */ +#define MCAUSE_INTERRUPT 0x80000000 /* INTERRUPT 31*/ +#define MCAUSE_MINHV 0x40000000 /* minhv 30*/ +#define MCAUSE_MPP 0x30000000 /* mpp[29:28] */ +#define MCAUSE_MPIE 0x08000000 /* mpie 27*/ +#define MCAUSE_MPIL 0x00ff0000 /* mpil[23:16] */ +#define MCAUSE_EXCCODE 0x00000fff /* exccode[11:0] */ + #endif diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 21c54ef561..e481e1b216 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -36,6 +36,22 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) } =20 #ifndef CONFIG_USER_ONLY +static int riscv_cpu_local_irq_mode_enabled(CPURISCVState *env, int mode) +{ + switch (mode) { + case PRV_M: + return env->priv < PRV_M || + (env->priv =3D=3D PRV_M && + get_field(env->mstatus, MSTATUS_MIE)); + case PRV_S: + return env->priv < PRV_S || + (env->priv =3D=3D PRV_S && + get_field(env->mstatus, MSTATUS_SIE)); + default: + return false; + } +} + static int riscv_cpu_local_irq_pending(CPURISCVState *env) { target_ulong irqs; @@ -90,6 +106,19 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interru= pt_request) return true; } } + + if (interrupt_request & CPU_INTERRUPT_ECLIC) { + RISCVCPU *cpu =3D RISCV_CPU(cs); + CPURISCVState *env =3D &cpu->env; + int mode =3D PRV_M; + int enabled =3D riscv_cpu_local_irq_mode_enabled(env, mode); + if (enabled) { + cs->exception_index =3D RISCV_EXCP_INT_ECLIC | env->exccode; + cs->interrupt_request &=3D ~CPU_INTERRUPT_ECLIC; + riscv_cpu_do_interrupt(cs); + return true; + } + } #endif return false; } @@ -884,6 +913,30 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, i= nt size, #endif } =20 +#if !defined(CONFIG_USER_ONLY) +static target_ulong riscv_intr_pc(CPURISCVState *env, bool async, + bool eclic_flag, int cause, bool m= ode) +{ + target_ulong newpc =3D 0; + if (eclic_flag) { + if (mode) { + uint64_t vec_addr =3D (cause & 0x3FF) * 4 + env->mtvt; + cpu_physical_memory_rw(vec_addr, &newpc, 4, 0); + } else { + if ((env->mtvt2 & 0x1) =3D=3D 0) { + newpc =3D env->mtvec & 0xfffffffc; + } else if ((env->mtvt2 & 0x1) =3D=3D 1) { + newpc =3D env->mtvt2 & 0xfffffffc; + } + } + } else { + newpc =3D (env->mtvec >> 2 << 2) + + ((async && (env->mtvec & 3) =3D=3D 1) ? cause * 4 : 0); + } + return newpc; +} +#endif + /* * Handle Traps * @@ -892,8 +945,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, in= t size, */ void riscv_cpu_do_interrupt(CPUState *cs) { -#if !defined(CONFIG_USER_ONLY) =20 +#if !defined(CONFIG_USER_ONLY) RISCVCPU *cpu =3D RISCV_CPU(cs); CPURISCVState *env =3D &cpu->env; bool force_hs_execp =3D riscv_cpu_force_hs_excep_enabled(env); @@ -903,12 +956,15 @@ void riscv_cpu_do_interrupt(CPUState *cs) * so we mask off the MSB and separate into trap type and cause. */ bool async =3D !!(cs->exception_index & RISCV_EXCP_INT_FLAG); + bool eclic_flag =3D !!(cs->exception_index & RISCV_EXCP_INT_ECLIC); target_ulong cause =3D cs->exception_index & RISCV_EXCP_INT_MASK; target_ulong deleg =3D async ? env->mideleg : env->medeleg; bool write_tval =3D false; target_ulong tval =3D 0; target_ulong htval =3D 0; target_ulong mtval2 =3D 0; + bool mode =3D false; + uint8_t level =3D 0; =20 if (cause =3D=3D RISCV_EXCP_SEMIHOST) { if (env->priv >=3D PRV_S) { @@ -919,7 +975,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) cause =3D RISCV_EXCP_BREAKPOINT; } =20 - if (!async) { + if (!(async || eclic_flag)) { /* set tval to badaddr for traps with address information */ switch (cause) { case RISCV_EXCP_INST_GUEST_PAGE_FAULT: @@ -958,6 +1014,22 @@ void riscv_cpu_do_interrupt(CPUState *cs) } } =20 + if (eclic_flag) { + mode =3D (cause >> 12) & 0x1; + level =3D (cause >> 13) & 0xFF; + cause &=3D 0x3ff; + + cause |=3D get_field(env->mstatus, MSTATUS_MPP) << 28; + cause |=3D get_field(env->mintstatus, MINTSTATUS_MIL) << 16; + cause |=3D get_field(env->mstatus, MSTATUS_MPIE) << 27; + cause =3D set_field(cause, MCAUSE_MPP, PRV_M); + cause =3D set_field(cause, MCAUSE_INTERRUPT, 1); + + env->mintstatus =3D set_field(env->mintstatus, MINTSTATUS_MIL, lev= el); + } else { + cause =3D set_field(cause, MCAUSE_INTERRUPT, 0); + } + trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, riscv_cpu_get_trap_name(cause, async)); =20 @@ -1030,6 +1102,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) riscv_cpu_set_mode(env, PRV_S); } else { /* handle the trap in M-mode */ + if (riscv_has_ext(env, RVH)) { if (riscv_cpu_virt_enabled(env)) { riscv_cpu_swap_hypervisor_regs(env); @@ -1056,8 +1129,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->mepc =3D env->pc; env->mbadaddr =3D tval; env->mtval2 =3D mtval2; - env->pc =3D (env->mtvec >> 2 << 2) + - ((async && (env->mtvec & 3) =3D=3D 1) ? cause * 4 : 0); + env->pc =3D riscv_intr_pc(env, async, eclic_flag, cause, mode); riscv_cpu_set_mode(env, PRV_M); } =20 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index d2585395bf..555b29d8f3 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -188,6 +188,11 @@ static int pmp(CPURISCVState *env, int csrno) { return -!riscv_feature(env, RISCV_FEATURE_PMP); } + +static int eclic(CPURISCVState *env, int csrno) +{ + return !!env->eclic; +} #endif =20 /* User Floating-Point CSRs */ @@ -623,11 +628,20 @@ static int read_mtvec(CPURISCVState *env, int csrno, = target_ulong *val) =20 static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val) { + int mode1 =3D val & 0b11, mode2 =3D val & 0b111111; /* bits [1:0] encode mode; 0 =3D direct, 1 =3D vectored, 2 >=3D reserv= ed */ - if ((val & 3) < 2) { + if (mode1 < 2) { env->mtvec =3D val; } else { - qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n= "); + /* bits [5:0] encode extended modes currently used by the ECLIC */ + switch (mode2) { + case 0b000011: /* ECLIC mode */ + env->mtvec =3D val; + break; + default: + qemu_log_mask(LOG_UNIMP, + "CSR_MTVEC: reserved mode not supported\n"); + } } return 0; } @@ -644,6 +658,300 @@ static int write_mcounteren(CPURISCVState *env, int c= srno, target_ulong val) return 0; } =20 +static int read_mtvt(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->mtvt; + return 0; +} + +static int write_mtvt(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mtvt =3D val; + return 0; +} + +static int read_mnxti(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->mnxti; + return 0; +} + +static int write_mnxti(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mnxti =3D val; + return 0; +} + +static int rmw_mnxti(CPURISCVState *env, int csrno, target_ulong *ret_valu= e, + target_ulong new_value, target_ulong write_mask) +{ + env->mstatus |=3D (new_value & write_mask) & 0b11111; + if (ret_value) { + *ret_value =3D 0; + } + + return 0; +} + +static int read_mintstatus(CPURISCVState *env, int csrno, target_ulong *va= l) +{ + *val =3D env->mintstatus; + return 0; +} + +static int write_mintstatus(CPURISCVState *env, int csrno, target_ulong va= l) +{ + env->mintstatus =3D val; + return 0; +} + +static int read_mscratchcsw(CPURISCVState *env, int csrno, target_ulong *v= al) +{ + *val =3D env->mscratchcsw; + return 0; +} + +static int write_mscratchcsw(CPURISCVState *env, int csrno, target_ulong v= al) +{ + env->mscratchcsw =3D val; + return 0; +} + +static int rmw_mscratchcsw(CPURISCVState *env, int csrno, target_ulong *re= t_value, + target_ulong new_value, target_ulong write_mask) +{ + target_ulong t; + if (get_field(env->mcause, MCAUSE_MPP) !=3D PRV_M) { + t =3D new_value; + *ret_value =3D env->mscratch; + env->mscratch =3D t; + }else { + *ret_value =3D new_value; + } + return 0; +} + +static int read_mscratchcswl(CPURISCVState *env, int csrno, target_ulong *= val) +{ + *val =3D env->mscratchcswl; + return 0; +} + +static int write_mscratchcswl(CPURISCVState *env, int csrno, target_ulong = val) +{ + env->mscratchcswl =3D val; + return 0; +} + +static int rmw_mscratchcswl(CPURISCVState *env, int csrno, + target_ulong *ret_value, target_ulong new_value, + target_ulong write_mask) +{ + target_ulong t; + if ((get_field(env->mcause, MCAUSE_MPIL) =3D=3D 0) !=3D + (get_field(env->mintstatus, MINTSTATUS_MIL) =3D=3D 0)) { + t =3D new_value; + *ret_value =3D env->mscratch; + env->mscratch =3D t; + } else { + *ret_value =3D new_value; + } + return 0; +} + +static int read_mnvec(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->mnvec; + return 0; +} + +static int write_mnvec(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mnvec =3D val; + return 0; +} + +static int read_msubm(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->msubm; + return 0; +} + +static int write_msubm(CPURISCVState *env, int csrno, target_ulong val) +{ + env->msubm =3D val; + return 0; +} + +static int read_mdcause(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->mdcause; + return 0; +} + +static int write_mdcause(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mdcause =3D val; + return 0; +} + +static int read_mmisc_ctl(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->mmisc_ctl; + return 0; +} + +static int write_mmisc_ctl(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mmisc_ctl =3D val; + return 0; +} + +static int read_msavestatus(CPURISCVState *env, int csrno, target_ulong *v= al) +{ + *val =3D env->msavestatus; + return 0; +} + +static int write_msavestatus(CPURISCVState *env, int csrno, target_ulong v= al) +{ + env->msavestatus =3D val; + return 0; +} + +static int read_msaveepc1(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->msaveepc1; + return 0; +} + +static int write_msaveepc1(CPURISCVState *env, int csrno, target_ulong val) +{ + env->msaveepc1 =3D val; + return 0; +} + +static int read_msavecause1(CPURISCVState *env, int csrno, target_ulong *v= al) +{ + *val =3D env->msavecause1; + return 0; +} + +static int write_msavecause1(CPURISCVState *env, int csrno, target_ulong v= al) +{ + env->msavecause1 =3D val; + return 0; +} + +static int read_msaveepc2(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->msaveepc2; + return 0; +} + +static int write_msaveepc2(CPURISCVState *env, int csrno, target_ulong val) +{ + env->msaveepc2 =3D val; + return 0; +} + +static int read_msavecause2(CPURISCVState *env, int csrno, target_ulong *v= al) +{ + *val =3D env->msavecause2; + return 0; +} + +static int write_msavecause2(CPURISCVState *env, int csrno, target_ulong v= al) +{ + env->msavecause2 =3D val; + return 0; +} + +static int read_msavedcause1(CPURISCVState *env, int csrno, target_ulong *= val) +{ + *val =3D env->msavedcause1; + return 0; +} + +static int write_msavedcause1(CPURISCVState *env, int csrno, target_ulong = val) +{ + env->msavedcause1 =3D val; + return 0; +} + +static int read_msavedcause2(CPURISCVState *env, int csrno, target_ulong *= val) +{ + *val =3D env->msavedcause2; + return 0; +} + +static int write_msavedcause2(CPURISCVState *env, int csrno, target_ulong = val) +{ + env->msavedcause2 =3D val; + return 0; +} + +static int rmw_pushmsubm(CPURISCVState *env, int csrno, target_ulong *ret_= value, + target_ulong new_value, target_ulong write_mask) +{ + + uint64_t notify_addr =3D new_value * 4 + env->gpr[2]; + + cpu_physical_memory_rw(notify_addr, &env->msubm, 4, 1); + + return 0; +} + +static int read_mtvt2(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val =3D env->mtvt2; + return 0; +} + +static int write_mtvt2(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mtvt2 =3D val; + return 0; +} + +static int rmw_jalmnxti(CPURISCVState *env, int csrno, + target_ulong *ret_value, target_ulong new_value, + target_ulong write_mask) +{ + target_ulong addr; + + if (env->irq_pending) { + uint64_t vec_addr =3D (env->mcause & 0x3FF) * 4 + env->mtvt; + cpu_physical_memory_rw(vec_addr, &addr, 4, 0); + env->gpr[1] =3D env->pc + 4; + env->gpr[5] =3D env->pc + 4; + *ret_value =3D addr; + riscv_cpu_eclic_clean_pending(env->eclic, env->mcause & 0x3ff); + env->mstatus =3D set_field(env->mstatus, MSTATUS_MIE, 1); + } else + *ret_value =3D env->pc + 4; + return 0; +} + +static int rmw_pushmcause(CPURISCVState *env, int csrno, + target_ulong *ret_value, target_ulong new_value, + target_ulong write_mask) +{ + uint64_t notify_addr =3D new_value * 4 + env->gpr[2]; + cpu_physical_memory_rw(notify_addr, &env->mcause, 4, 1); + + return 0; +} + +static int rmw_pushmepc(CPURISCVState *env, int csrno, + target_ulong *ret_value, target_ulong new_value, + target_ulong write_mask) +{ + uint64_t notify_addr =3D new_value * 4 + env->gpr[2]; + cpu_physical_memory_rw(notify_addr, &env->mepc, 4, 1); + return 0; +} + /* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *v= al) { @@ -654,6 +962,19 @@ static int read_mscounteren(CPURISCVState *env, int cs= rno, target_ulong *val) return 0; } =20 +static int read_mucounteren(CPURISCVState *env, int csrno, target_ulong *v= al) +{ + *val =3D env->scounteren; + return 0; +} + +static int write_mucounteren(CPURISCVState *env, int csrno, target_ulong v= al) +{ + env->scounteren =3D val; + return 0; +} + + /* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong v= al) { @@ -1416,9 +1737,31 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] =3D { [CSR_MIE] =3D { "mie", any, read_mie, write_m= ie }, [CSR_MTVEC] =3D { "mtvec", any, read_mtvec, write_m= tvec }, [CSR_MCOUNTEREN] =3D { "mcounteren", any, read_mcounteren, write_m= counteren }, + [CSR_MTVT] =3D { "mtvt", eclic, read_mtvt, write_mtvt }, + [CSR_MNXTI] =3D { "mnxti", eclic, read_mnxti, write_mnxti, rmw_= mnxti}, + [CSR_MINTSTATUS] =3D {"mintstatus", eclic, read_mintstatus, write_mi= ntstatus }, + [CSR_MSCRATCHCSW] =3D {"mscratchcsw", any, read_mscratchcsw, write_m= scratchcsw, rmw_mscratchcsw}, + [CSR_MSCRATCHCSWL] =3D { "mscratchcswl", any, read_mscratchcswl, wri= te_mscratchcswl, rmw_mscratchcswl}, + [CSR_MNVEC] =3D { "mnvec", any, read_mnvec, write_mnvec = }, + [CSR_MSUBM] =3D { "msubm", any, read_msubm, write_msubm = }, + [CSR_MDCAUSE] =3D { "mdcause", any, read_mdcause, write_mdcause = }, + [CSR_MMISC_CTL] =3D { "mmisc_ctl", any, read_mmisc_ctl, write_mmis= c_ctl }, + [CSR_MSAVESTATUS] =3D { "msavestatus", any, read_msavestatus, write_= msavestatus }, + [CSR_MSAVEEPC1] =3D { "msaveepc1", any, read_msaveepc1, write_msave= epc1 }, + [CSR_MSAVECAUSE1] =3D { "msavecause1", any, read_msavecause1, write_= msavecause1 }, + [CSR_MSAVEEPC2] =3D { "msaveepc2", any, read_msaveepc2, write_msav= eepc2 }, + [CSR_MSAVECAUSE2] =3D { "msavecause2", any, read_msavecause2, write_= msavecause2 }, + [CSR_MSAVEDCAUSE1] =3D { "msavedcause1", any, read_msavedcause1, wri= te_msavedcause1 }, + [CSR_MSAVEDCAUSE2] =3D { "msavedcause2", any, read_msavedcause2, wri= te_msavedcause2 }, + [CSR_PUSHMSUBM] =3D { "pushmsubm", eclic, NULL, NULL, rmw_pushmsub= m }, + [CSR_MTVT2] =3D { "mtvt2", eclic, read_mtvt2, write_mtvt2 = }, + [CSR_JALMNXTI] =3D { "jalmnxti", eclic, NULL, NULL, rmw_jalmnxti= }, + [CSR_PUSHMCAUSE] =3D { "pushmcause", eclic, NULL, NULL , rmw_pushmc= ause }, + [CSR_PUSHMEPC] =3D { "pushmepc", eclic, NULL, NULL, rmw_pushmepc= }, =20 [CSR_MSTATUSH] =3D { "mstatush", any32, read_mstatush, write_m= statush }, =20 + [CSR_MUCOUNTEREN] =3D { "mucounteren", any, read_mucounteren, write_m= ucounteren }, [CSR_MSCOUNTEREN] =3D { "msounteren", any, read_mscounteren, write_m= scounteren }, =20 /* Machine Trap Handling */ diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_tr= ans/trans_rvi.c.inc index d04ca0394c..e4bf61f3c0 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -521,13 +521,27 @@ static bool trans_fence_i(DisasContext *ctx, arg_fenc= e_i *a) tcg_temp_free(rs1_pass); \ } while (0) =20 +#define RISCV_OP_CSR_JAL_POST do {\ + tcg_gen_mov_tl(cpu_pc, dest); \ + exit_tb(ctx); \ + ctx->base.is_jmp =3D DISAS_NORETURN; \ + tcg_temp_free(source1); \ + tcg_temp_free(csr_store); \ + tcg_temp_free(dest); \ + tcg_temp_free(rs1_pass); \ +} while (0) =20 static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a) { TCGv source1, csr_store, dest, rs1_pass; RISCV_OP_CSR_PRE; gen_helper_csrrw(dest, cpu_env, source1, csr_store); - RISCV_OP_CSR_POST; + + if(a->csr =3D=3D CSR_JALMNXTI) + RISCV_OP_CSR_JAL_POST; + else + RISCV_OP_CSR_POST; + return true; } =20 diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index f0bbd73ca5..57eda9336a 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -171,6 +171,20 @@ target_ulong helper_mret(CPURISCVState *env, target_ul= ong cpu_pc_deb) riscv_cpu_set_virt_enabled(env, prev_virt); } =20 + if ((env->mtvec & 0b111111) =3D=3D 0b000011) { + target_ulong mpil =3D get_field(env->mcause, MCAUSE_MPIL); + env->mintstatus =3D set_field(env->mintstatus, MINTSTATUS_MIL, mpi= l); + + qemu_mutex_lock_iothread(); + riscv_cpu_eclic_get_next_interrupt(env->eclic); + qemu_mutex_unlock_iothread(); + + if (get_field(env->mcause, MCAUSE_INTERRUPT) =3D=3D 1) { + env->mstatus =3D set_field(env->mstatus, MSTATUS_MPP, + get_field(env->mcause, MCAUSE_MPP)); + } + } + return retpc; } =20 --=20 2.17.1