From nobody Tue May 21 06:59:56 2024 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 From nobody Tue May 21 06:59:56 2024 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=1620393962; cv=none; d=zohomail.com; s=zohoarc; b=esMiKCVkyB003medTsG+FuALODDAyBV/4jKZ9FvLhi/oaZdnQujaUUzzAN5UEXROIYLHwIejAeaHVYI6dONfhPYaeTUE0hVj5dae1ysTNymI9O+rTR60fZLdLDZsJwsmDYCzdFRmxDehow1qAh2iVerC12v6h5RMeP2okilNnX4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1620393962; 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=hfisQQMNNCfnlmr6iayJ5V57YPPjR2uyyosXKbdbsBg=; b=i9tOL/7I7965EGibQe+H2eeru41v3csDLc2TmGVHeqhpPEipNhCQHdWAJ+fOdBJ27yXm+jTZMCsV0ABIpP+qSlVbosdDw62TT6d0Ebr4Tvvdd0CgZ6lblkDtjCXwIk65HlGkYvNWNZiScNWrKYgVnfTa3M3vuI/2Lby2mnG7P9I= 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 1620393962151505.0673987113033; Fri, 7 May 2021 06:26:02 -0700 (PDT) Received: from localhost ([::1]:51446 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lf0US-0000z5-RC for importer@patchew.org; Fri, 07 May 2021 09:26:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60742) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1levgY-0004ac-Nr; Fri, 07 May 2021 04:18:10 -0400 Received: from smtp25.cstnet.cn ([159.226.251.25]:50028 helo=cstnet.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1levgS-0005jn-JQ; Fri, 07 May 2021 04:18:10 -0400 Received: from localhost.localdomain (unknown [121.232.13.213]) by APP-05 (Coremail) with SMTP id zQCowAB3fSnh9pRgTQ5HAQ--.1834S4; Fri, 07 May 2021 16:14:27 +0800 (CST) From: wangjunqiang To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Subject: [RFC PATCH 2/5] hw/intc: Add Nuclei ECLIC device Date: Fri, 7 May 2021 16:16:51 +0800 Message-Id: <20210507081654.11056-3-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--.1834S4 X-Coremail-Antispam: 1UD129KBjvAXoWfJw13tFykJrykZrW3Gry8Zrb_yoW8CFyUCo WfAr4DJ395Xr4UXrsakF1UGry7WF1ayFWYqFs7Wr4qyF18ZwnxX3yDKa43ZF4SvrZ8KrWx ZryagFs3Xrs3JF1fn29KB7ZKAUJUUUU5529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYZ7AC8VAFwI0_Wr0E3s1l1xkIjI8I6I8E6xAIw20EY4v20xva j40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l82xGYIkIc2x26280x7IE14v26r15M28IrcIa0x kI8VCY1x0267AKxVW8JVW5JwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK021l84AC jcxK6xIIjxv20xvE14v26F1j6w1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26F4j6r4UJw A2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq3wAS 0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2 IY67AKxVWUGVWUXwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0 Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwCY02Avz4vE14v_GFyl42xK82 IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC2 0s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMI IF0xvE2Ix0cI8IcVAFwI0_JFI_Gr1lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF 0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I8E87 Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjfU1yCJDUUUU X-Originating-IP: [121.232.13.213] X-CM-SenderInfo: pzdqwy5xqtxt1qj6x2xfdvhtffof0/1tbiBgcOAF0TfNHfbQAAse 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 provides an implementation of Nuclei ECLIC Device. Nuclei processor core have been equipped with an Enhanced Core Local Interrupt Controller (ECLIC), which is optimized based on the RISC-V standard CLIC, to manage all interrupt sources. https://doc.nucleisys.com/nuclei_spec/isa/eclic.html --- hw/intc/Kconfig | 3 + hw/intc/meson.build | 1 + hw/intc/nuclei_eclic.c | 437 +++++++++++++++++++++++++++++++++ include/hw/intc/nuclei_eclic.h | 115 +++++++++ 4 files changed, 556 insertions(+) create mode 100644 hw/intc/nuclei_eclic.c create mode 100644 include/hw/intc/nuclei_eclic.h diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index f4694088a4..eab30f6ffd 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -73,3 +73,6 @@ config GOLDFISH_PIC =20 config M68K_IRQC bool + +config NUCLEI_ECLIC + bool diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 1c299039f6..7577ba69d2 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -50,6 +50,7 @@ specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: fi= les('s390_flic_kvm.c')) specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c')) specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.= c')) specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'= )) +specific_ss.add(when: 'CONFIG_NUCLEI_ECLIC', if_true: files('nuclei_eclic.= c')) specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'], if_true: files('xics_kvm.c')) diff --git a/hw/intc/nuclei_eclic.c b/hw/intc/nuclei_eclic.c new file mode 100644 index 0000000000..52de83cb1d --- /dev/null +++ b/hw/intc/nuclei_eclic.c @@ -0,0 +1,437 @@ +/* + * NUCLEI ECLIC(Enhanced Core Local Interrupt Controller) + * + * Copyright (c) 2020 Gao ZhiYuan + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * This provides a parameterizable interrupt controller based on NucLei's = ECLIC. + * + * 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 3 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "hw/sysbus.h" +#include "hw/pci/msi.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "target/riscv/cpu.h" +#include "sysemu/sysemu.h" +#include "hw/intc/nuclei_eclic.h" +#include "qapi/error.h" + +#define RISCV_DEBUG_ECLIC 0 + +static void riscv_cpu_eclic_interrupt(RISCVCPU *cpu, int exccode) +{ + CPURISCVState *env =3D &cpu->env; + bool locked =3D false; + + env->exccode =3D exccode; + + if (!qemu_mutex_iothread_locked()) { + locked =3D true; + qemu_mutex_lock_iothread(); + } + + if (exccode !=3D -1) { + env->irq_pending =3D true; + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_ECLIC); + } else { + env->irq_pending =3D false; + cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_ECLIC); + } + + if (locked) { + qemu_mutex_unlock_iothread(); + } +} + +static int level_compare(NucLeiECLICState *eclic, + ECLICPendingInterrupt *irq1, + ECLICPendingInterrupt *irq2) +{ + if (irq1->level =3D=3D irq2->level) { + if (irq1->prio =3D=3D irq2->prio) { + if (irq1->irq >=3D irq2->irq) { + return 0; + } else { + return 1; + } + } else if (irq1->prio > irq2->level) { + return 0; + } else { + return 1; + } + } else if (irq1->level > irq2->level) { + return 0; + } else { + return 1; + } +} + +static void nuclei_eclic_next_interrupt(void *eclic_ptr) +{ + RISCVCPU *cpu =3D RISCV_CPU(qemu_get_cpu(0)); + CPURISCVState *env =3D &cpu->env; + NucLeiECLICState *eclic =3D (NucLeiECLICState *)eclic_ptr; + ECLICPendingInterrupt *active; + target_ulong mil; + int shv; + + QLIST_FOREACH(active, &eclic->pending_list, next) + { + if (active->enable) { + mil =3D get_field(env->mintstatus, MINTSTATUS_MIL); + if (active->level >=3D eclic->mth && active->level > mil) { + shv =3D eclic->clicintattr[active->irq] & 0x1; + eclic->active_count++; + riscv_cpu_eclic_interrupt(cpu, + (active->irq & 0xFFF) | (shv << = 12) | (active->level << 13)); + return; + } + } + } +} + +static void nuclei_eclic_update_intmth(NucLeiECLICState *eclic, + int irq, int mth) +{ + eclic->mth =3D mth; + nuclei_eclic_next_interrupt(eclic); +} + +static void update_eclic_int_info(NucLeiECLICState *eclic, int irq) +{ + int level_width =3D (eclic->cliccfg >> 1) & 0xF; + if (level_width > CLICINTCTLBITS) { + level_width =3D CLICINTCTLBITS; + } + int prio_width =3D CLICINTCTLBITS - level_width; + + if (level_width =3D=3D 0) { + eclic->clicintlist[irq].level =3D 255; + } else { + eclic->clicintlist[irq].level =3D (( + (eclic->clicintctl[irq] >> (8= - level_width)) & + ~((char)0x80 >> (8 - level_wi= dth))) + << (8 - level_width)) | + (0xff >> level_width); + } + + if (prio_width =3D=3D 0) { + eclic->clicintlist[irq].prio =3D 0; + } else { + eclic->clicintlist[irq].prio =3D + (eclic->clicintctl[irq] >> (8 - level_width)) & + ~(0x80 >> (8 - prio_width)); + } + + eclic->clicintlist[irq].enable =3D eclic->clicintie[irq] & 0x1; + eclic->clicintlist[irq].trigger =3D (eclic->clicintattr[irq] >> 1) & 0= x3; +} + +static void eclic_remove_pending_list(NucLeiECLICState *eclic, int irq) +{ + QLIST_REMOVE(&eclic->clicintlist[irq], next); +} + +static void eclic_insert_pending_list(NucLeiECLICState *eclic, int irq) +{ + ECLICPendingInterrupt *node; + if (QLIST_EMPTY(&eclic->pending_list)) { + QLIST_INSERT_HEAD(&eclic->pending_list, &eclic->clicintlist[irq], = next); + } else { + QLIST_FOREACH(node, &eclic->pending_list, next) + { + if (level_compare(eclic, node, &eclic->clicintlist[irq])) { + QLIST_INSERT_BEFORE(node, &eclic->clicintlist[irq], next); + break; + } else if (node->next.le_next =3D=3D NULL) { + QLIST_INSERT_AFTER(node, &eclic->clicintlist[irq], next); + break; + } + } + } +} + +static void nuclei_eclic_update_intip(NucLeiECLICState *eclic, int irq, in= t new_intip) +{ + + int old_intip =3D eclic->clicintlist[irq].sig; + int trigger =3D (eclic->clicintattr[irq] >> 1) & 0x3; + if (((trigger =3D=3D 0) && new_intip) || + ((trigger =3D=3D 1) && !old_intip && new_intip) || + ((trigger =3D=3D 3) && old_intip && !new_intip)) { + eclic->clicintip[irq] =3D 1; + eclic->clicintlist[irq].sig =3D new_intip; + eclic_insert_pending_list(eclic, irq); + } else { + if (eclic->clicintip[irq]) { + eclic_remove_pending_list(eclic, irq); + } + eclic->clicintip[irq] =3D 0; + eclic->clicintlist[irq].sig =3D new_intip; + } + + nuclei_eclic_next_interrupt(eclic); +} + +static void nuclei_eclic_update_intie(NucLeiECLICState *eclic, + int irq, int new_intie) +{ + eclic->clicintie[irq] =3D new_intie; + update_eclic_int_info(eclic, irq); + nuclei_eclic_next_interrupt(eclic); +} + +static void nuclei_eclic_update_intattr(NucLeiECLICState *eclic, + int irq, int new_intattr) +{ + eclic->clicintattr[irq] =3D new_intattr; + update_eclic_int_info(eclic, irq); + nuclei_eclic_next_interrupt(eclic); +} + +static void nuclei_eclic_update_intctl(NucLeiECLICState *eclic, + int irq, int new_intctl) +{ + eclic->clicintctl[irq] =3D new_intctl; + update_eclic_int_info(eclic, irq); + nuclei_eclic_next_interrupt(eclic); +} + +qemu_irq nuclei_eclic_get_irq(DeviceState *dev, int irq) +{ + NucLeiECLICState *eclic =3D NUCLEI_ECLIC(dev); + return eclic->irqs[irq]; +} + +static uint64_t nuclei_eclic_read(void *opaque, hwaddr offset, unsigned si= ze) +{ + NucLeiECLICState *eclic =3D NUCLEI_ECLIC(opaque); + uint64_t value =3D 0; + uint32_t id =3D 0; + if (offset >=3D NUCLEI_ECLIC_REG_CLICINTIP_BASE) { + if ((offset - 0x1000) % 4 =3D=3D 0) { + id =3D (offset - 0x1000) / 4; + } else if ((offset - 0x1001) % 4 =3D=3D 0) { + id =3D (offset - 0x1001) / 4; + } else if ((offset - 0x1002) % 4 =3D=3D 0) { + id =3D (offset - 0x1002) / 4; + } else if ((offset - 0x1003) % 4 =3D=3D 0) { + id =3D (offset - 0x1003) / 4; + } + offset =3D offset - 4 * id; + } + + switch (offset) { + case NUCLEI_ECLIC_REG_CLICCFG: + value =3D eclic->cliccfg & 0xFF; + break; + case NUCLEI_ECLIC_REG_CLICINFO: + value =3D (CLICINTCTLBITS << 21) & 0xFFFFFFFF; + break; + case NUCLEI_ECLIC_REG_MTH: + value =3D eclic->mth & 0xFF; + break; + case NUCLEI_ECLIC_REG_CLICINTIP_BASE: + value =3D eclic->clicintip[id] & 0xFF; + break; + case NUCLEI_ECLIC_REG_CLICINTIE_BASE: + value =3D eclic->clicintie[id] & 0xFF; + break; + case NUCLEI_ECLIC_REG_CLICINTATTR_BASE: + value =3D eclic->clicintattr[id] & 0xFF; + break; + case NUCLEI_ECLIC_REG_CLICINTCTL_BASE: + value =3D eclic->clicintctl[id] & 0xFF; + break; + default: + break; + } + + return value; +} + +static void nuclei_eclic_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + NucLeiECLICState *eclic =3D NUCLEI_ECLIC(opaque); + uint32_t id =3D 0; + if (offset >=3D NUCLEI_ECLIC_REG_CLICINTIP_BASE) { + + if ((offset - 0x1000) % 4 =3D=3D 0) { + id =3D (offset - 0x1000) / 4; + } else if ((offset - 0x1001) % 4 =3D=3D 0) { + id =3D (offset - 0x1001) / 4; + } else if ((offset - 0x1002) % 4 =3D=3D 0) { + id =3D (offset - 0x1002) / 4; + } else if ((offset - 0x1003) % 4 =3D=3D 0) { + id =3D (offset - 0x1003) / 4; + } + offset =3D offset - 4 * id; + } + switch (offset) { + case NUCLEI_ECLIC_REG_CLICCFG: + eclic->cliccfg =3D value & 0xFF; + for (id =3D 0; id < eclic->num_sources; id++) { + update_eclic_int_info(eclic, id); + } + break; + case NUCLEI_ECLIC_REG_MTH: + nuclei_eclic_update_intmth(eclic, id, value & 0xFF); + break; + case NUCLEI_ECLIC_REG_CLICINTIP_BASE: + if ((eclic->clicintlist[id].trigger & 0x1) !=3D 0) { + if ((eclic->clicintip[id] =3D=3D 0) && (value & 0x1) =3D=3D 1)= { + eclic->clicintip[id] =3D 1; + eclic_insert_pending_list(eclic, id); + } else if ((eclic->clicintip[id] =3D=3D 1) && (value & 0x1) = =3D=3D 0) { + eclic->clicintip[id] =3D 0; + eclic_remove_pending_list(eclic, id); + } + } + nuclei_eclic_next_interrupt(eclic); + break; + case NUCLEI_ECLIC_REG_CLICINTIE_BASE: + nuclei_eclic_update_intie(eclic, id, value & 0xFF); + break; + case NUCLEI_ECLIC_REG_CLICINTATTR_BASE: + nuclei_eclic_update_intattr(eclic, id, value & 0xFF); + break; + case NUCLEI_ECLIC_REG_CLICINTCTL_BASE: + nuclei_eclic_update_intctl(eclic, id, value & 0xFF); + break; + default: + break; + } +} + +static const MemoryRegionOps nuclei_eclic_ops =3D { + .read =3D nuclei_eclic_read, + .write =3D nuclei_eclic_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, +}; + +void riscv_cpu_eclic_clean_pending(void *eclic_ptr, int irq) +{ + NucLeiECLICState *eclic =3D (NucLeiECLICState *)eclic_ptr; + if ((eclic->clicintlist[irq].trigger & 0x1) !=3D 0 && irq >=3D 0) { + eclic->clicintip[irq] =3D 0; + eclic_remove_pending_list(eclic, irq); + } +} + +void riscv_cpu_eclic_get_next_interrupt(void *eclic_ptr) +{ + NucLeiECLICState *eclic =3D (NucLeiECLICState *)eclic_ptr; + nuclei_eclic_next_interrupt(eclic); +} + + + +static void nuclei_eclic_irq_request(void *opaque, int id, int new_intip) +{ + NucLeiECLICState *eclic =3D NUCLEI_ECLIC(opaque); + nuclei_eclic_update_intip(eclic, id, new_intip); +} + +static void nuclei_eclic_realize(DeviceState *dev, Error **errp) +{ + NucLeiECLICState *eclic =3D NUCLEI_ECLIC(dev); + int id; + + memory_region_init_io(&eclic->mmio, OBJECT(dev), &nuclei_eclic_ops, ec= lic, + TYPE_NUCLEI_ECLIC, eclic->aperture_size); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &eclic->mmio); + + eclic->clicintip =3D g_new0(uint8_t, eclic->num_sources); + eclic->clicintlist =3D g_new0(ECLICPendingInterrupt, eclic->num_source= s); + eclic->clicintie =3D g_new0(uint8_t, eclic->num_sources); + eclic->clicintattr =3D g_new0(uint8_t, eclic->num_sources); + eclic->clicintctl =3D g_new0(uint8_t, eclic->num_sources); + eclic->irqs =3D g_new0(qemu_irq, eclic->num_sources); + QLIST_INIT(&eclic->pending_list); + for (id =3D 0; id < eclic->num_sources; id++) { + eclic->clicintlist[id].irq =3D id; + update_eclic_int_info(eclic, id); + } + eclic->active_count =3D 0; + + /* Init ECLIC IRQ */ + eclic->irqs[Internal_SysTimerSW_IRQn] =3D + qemu_allocate_irq(nuclei_eclic_irq_request, + eclic, Internal_SysTimerSW_IRQn); + eclic->irqs[Internal_SysTimer_IRQn] =3D + qemu_allocate_irq(nuclei_eclic_irq_request, + eclic, Internal_SysTimer_IRQn); + + for (id =3D Internal_Reserved_Max_IRQn; id < eclic->num_sources; id++)= { + eclic->irqs[id] =3D qemu_allocate_irq(nuclei_eclic_irq_request, + eclic, id); + } + + RISCVCPU *cpu =3D RISCV_CPU(qemu_get_cpu(0)); + cpu->env.eclic =3D eclic; +} + +static Property nuclei_eclic_properties[] =3D { + DEFINE_PROP_UINT32("aperture-size", NucLeiECLICState, aperture_size, 0= ), + DEFINE_PROP_UINT32("num-sources", NucLeiECLICState, num_sources, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void nuclei_eclic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + device_class_set_props(dc, nuclei_eclic_properties); + dc->realize =3D nuclei_eclic_realize; +} + +static const TypeInfo nuclei_eclic_info =3D { + .name =3D TYPE_NUCLEI_ECLIC, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(NucLeiECLICState), + .class_init =3D nuclei_eclic_class_init, +}; + +static void nuclei_eclic_register_types(void) +{ + type_register_static(&nuclei_eclic_info); +} + +type_init(nuclei_eclic_register_types); + +void nuclei_eclic_systimer_cb(DeviceState *dev) +{ + NucLeiECLICState *eclic =3D NUCLEI_ECLIC(dev); + nuclei_eclic_irq_request(eclic, Internal_SysTimer_IRQn, 1); +} + +DeviceState *nuclei_eclic_create(hwaddr addr, + uint32_t aperture_size, uint32_t num_sour= ces) +{ + DeviceState *dev =3D qdev_new(TYPE_NUCLEI_ECLIC); + + qdev_prop_set_uint32(dev, "aperture-size", aperture_size); + qdev_prop_set_uint32(dev, "num-sources", num_sources); + + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); + return dev; +} diff --git a/include/hw/intc/nuclei_eclic.h b/include/hw/intc/nuclei_eclic.h new file mode 100644 index 0000000000..18b25485b9 --- /dev/null +++ b/include/hw/intc/nuclei_eclic.h @@ -0,0 +1,115 @@ +/* + * NUCLEI ECLIC (Enhanced Core Local Interrupt Controller) interface + * + * Copyright (c) 2020 Gao ZhiYuan + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * This provides a parameterizable interrupt controller based on NucLei's = ECLIC. + * + * 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 3 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 . + */ +#ifndef HW_NUCLEI_ECLIC_H +#define HW_NUCLEI_ECLIC_H + +#include "hw/irq.h" +#include "hw/sysbus.h" + +#define TYPE_NUCLEI_ECLIC "riscv.nuclei.eclic" + +#define INTERRUPT_SOURCE_MIN_ID (18) +#define INTERRUPT_SOURCE_MAX_ID (4096) + +typedef struct NucLeiECLICState NucLeiECLICState; +DECLARE_INSTANCE_CHECKER(NucLeiECLICState, NUCLEI_ECLIC, + TYPE_NUCLEI_ECLIC) + +typedef struct ECLICPendingInterrupt { + int irq; + int prio; + int level; + int enable; + int trigger; + int sig; + QLIST_ENTRY(ECLICPendingInterrupt) next; +} ECLICPendingInterrupt; + +#define NUCLEI_ECLIC_REG_CLICCFG 0x0000 +#define NUCLEI_ECLIC_REG_CLICINFO 0x0004 +#define NUCLEI_ECLIC_REG_MTH 0x000b +#define NUCLEI_ECLIC_REG_CLICINTIP_BASE 0x1000 +#define NUCLEI_ECLIC_REG_CLICINTIE_BASE 0x1001 +#define NUCLEI_ECLIC_REG_CLICINTATTR_BASE 0x1002 +#define NUCLEI_ECLIC_REG_CLICINTCTL_BASE 0x1003 + +#define CLICINTCTLBITS 0x6 + +typedef struct NucLeiECLICState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion mmio; + + uint32_t num_sources; /* 4-1024 */ + + /* config */ + uint32_t sources_id; + uint8_t cliccfg; /* nlbits(1~4) */ + uint32_t clicinfo; + uint8_t mth; /* mth(0~7) */ + uint8_t *clicintip; + uint8_t *clicintie; + uint8_t *clicintattr; /* shv(0) trig(1~2)*/ + uint8_t *clicintctl; + ECLICPendingInterrupt *clicintlist; + uint32_t aperture_size; + + QLIST_HEAD(, ECLICPendingInterrupt) + pending_list; + size_t active_count; + + /* ECLIC IRQ handlers */ + qemu_irq *irqs; + +} NucLeiECLICState; + +enum { + Internal_Reserved0_IRQn =3D 0, /*!< Internal reserved */ + Internal_Reserved1_IRQn =3D 1, /*!< Internal reserved */ + Internal_Reserved2_IRQn =3D 2, /*!< Internal reserved */ + Internal_SysTimerSW_IRQn =3D 3, /*!< System Timer SW interrupt */ + Internal_Reserved3_IRQn =3D 4, /*!< Internal reserved */ + Internal_Reserved4_IRQn =3D 5, /*!< Internal reserved */ + Internal_Reserved5_IRQn =3D 6, /*!< Internal reserved */ + Internal_SysTimer_IRQn =3D 7, /*!< System Timer Interrupt */ + Internal_Reserved6_IRQn =3D 8, /*!< Internal reserved */ + Internal_Reserved7_IRQn =3D 9, /*!< Internal reserved */ + Internal_Reserved8_IRQn =3D 10, /*!< Internal reserved */ + Internal_Reserved9_IRQn =3D 11, /*!< Internal reserved */ + Internal_Reserved10_IRQn =3D 12, /*!< Internal reserved */ + Internal_Reserved11_IRQn =3D 13, /*!< Internal reserved */ + Internal_Reserved12_IRQn =3D 14, /*!< Internal reserved */ + Internal_Reserved13_IRQn =3D 15, /*!< Internal reserved */ + Internal_Reserved14_IRQn =3D 16, /*!< Internal reserved */ + Internal_BusError_IRQn =3D 17, /*!< Bus Error interrupt */ + Internal_PerfMon_IRQn =3D 18, /*!< Performance Monitor */ + Internal_Reserved_Max_IRQn =3D 19, /*!< Internal reserved Max */ +}; + +DeviceState *nuclei_eclic_create(hwaddr addr, + uint32_t aperture_size, uint32_t num_sour= ces); +qemu_irq nuclei_eclic_get_irq(DeviceState *dev, int irq); +void nuclei_eclic_systimer_cb(DeviceState *dev); + +#endif --=20 2.17.1 From nobody Tue May 21 06:59:56 2024 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=1620394127; cv=none; d=zohomail.com; s=zohoarc; b=GhVURkza50BgGmaPGi+hzcaumIooO0g8F3UtB6gKBOsBkiCHIfBuXzU5hlYfhu+dHDOeVG8jUd/k2bVtwRR/C7ERhmD73smINFSQVtqqHrtxJmUmJryn83S9v/kbO4x47VsL/tDumC+qZq8Xg1ffFRpDiQzt7Qlw4YMGgTKuwug= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1620394127; 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=G8/vp3CRxHwEG85wFShhR72Vgg+ZPbeevQ8G6SCnR+c=; b=nptP/MKo+3qspGIJrAFBWL5Om+yXYSBH/emHVH3ehuub0NvNfkVjeWf0v+hfbW72A7vA8COwxghi1zuwGbSlFPZ0WMbi9iLLg8ijoL2IIrygl9r1efGx9rJ9ELBeLvzxLYsd+WvuTDs5vtbaQnVs8FQ0nvbTDysPWDkpyVJrQ34= 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 1620394127587516.3670322540493; Fri, 7 May 2021 06:28:47 -0700 (PDT) Received: from localhost ([::1]:32910 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lf0X8-00051j-8S for importer@patchew.org; Fri, 07 May 2021 09:28:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60728) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1levgX-0004aM-RP; Fri, 07 May 2021 04:18:09 -0400 Received: from smtp25.cstnet.cn ([159.226.251.25]:50030 helo=cstnet.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1levgS-0005jj-D6; 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--.1834S5; Fri, 07 May 2021 16:14:27 +0800 (CST) From: wangjunqiang To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Subject: [RFC PATCH 3/5] hw/intc: Add Nuclei Systimer Date: Fri, 7 May 2021 16:16:52 +0800 Message-Id: <20210507081654.11056-4-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--.1834S5 X-Coremail-Antispam: 1UD129KBjvJXoW3urykCw4DGw1fuFW5Ww4UArb_yoWktFWxpF WkKa43Kw1UGF47G397Cw1DXFn3JwsrCF4DJ3Z7Ca12kF47G348G34qkFWayFZ7AFWkWFWr JF95XF15GF45A3DanT9S1TB71UUUUUDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBa14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JrWl82xGYIkIc2 x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1UM2 8EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v26rxl6s0DM2AI xVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20x vE14v26r106r15McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xv r2IYc2Ij64vIr41lF7I21c0EjII2zVCS5cI20VAGYxC7MxkIecxEwVAFwVW8ZwCF04k20x vY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I 3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIxkGc2Ij64vIr41lIx AIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAI cVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F4UMIIF0xvEx4A2js IEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x0JUBWlkUUUUU= X-Originating-IP: [121.232.13.213] X-CM-SenderInfo: pzdqwy5xqtxt1qj6x2xfdvhtffof0/1tbiCwoOAFz4kC9qyQABs2 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 provides an implementation of Nuclei Systimer, which like clint. In MCU mode, It only work for hart-0. MultiCore support will run on 200t board for Linux. https://doc.nucleisys.com/nuclei_spec/isa/timer.html Signed-off-by: Wang Junqiang --- hw/intc/Kconfig | 3 + hw/intc/meson.build | 1 + hw/intc/nuclei_systimer.c | 254 ++++++++++++++++++++++++++++++ include/hw/intc/nuclei_systimer.h | 70 ++++++++ 4 files changed, 328 insertions(+) create mode 100644 hw/intc/nuclei_systimer.c create mode 100644 include/hw/intc/nuclei_systimer.h diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index eab30f6ffd..70059d96fa 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -76,3 +76,6 @@ config M68K_IRQC =20 config NUCLEI_ECLIC bool + +config NUCLEI_SYSTIMER + bool \ No newline at end of file diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 7577ba69d2..d064f769ee 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -51,6 +51,7 @@ specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('s= h_intc.c')) specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.= c')) specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'= )) specific_ss.add(when: 'CONFIG_NUCLEI_ECLIC', if_true: files('nuclei_eclic.= c')) +specific_ss.add(when: 'CONFIG_NUCLEI_SYSTIMER', if_true: files('nuclei_sys= timer.c')) specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'], if_true: files('xics_kvm.c')) diff --git a/hw/intc/nuclei_systimer.c b/hw/intc/nuclei_systimer.c new file mode 100644 index 0000000000..7d5f97b54c --- /dev/null +++ b/hw/intc/nuclei_systimer.c @@ -0,0 +1,254 @@ +/* + * NUCLEI TIMER (Timer Unit) interface + * + * Copyright (c) 2020 Gao ZhiYuan + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * This provides a parameterizable timer controller based on NucLei's Syst= imer. + * + * 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 3 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/timer.h" +#include "target/riscv/cpu.h" +#include "hw/intc/nuclei_systimer.h" +#include "hw/intc/nuclei_eclic.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "trace.h" + +static uint64_t cpu_riscv_read_rtc(uint64_t timebase_freq) +{ + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + timebase_freq, NANOSECONDS_PER_SECOND); +} + +static void nuclei_timer_update_compare(NucLeiSYSTIMERState *s) +{ + CPUState *cpu =3D qemu_get_cpu(0); + CPURISCVState *env =3D cpu ? cpu->env_ptr : NULL; + uint64_t cmp, real_time; + int64_t diff; + + real_time =3D s->mtime_lo | ((uint64_t)s->mtime_hi << 32); + + cmp =3D (uint64_t)s->mtimecmp_lo | ((uint64_t)s->mtimecmp_hi << 32); + env->mtimecmp =3D cmp; + env->timecmp =3D cmp; + + diff =3D cmp - real_time; + + if (real_time >=3D cmp) { + qemu_set_irq(*(s->timer_irq), 1); + } else { + qemu_set_irq(*(s->timer_irq), 0); + + if (s->mtimecmp_hi !=3D 0xffffffff) { + uint64_t next_ns =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + muldiv64(diff, NANOSECONDS_PER_SECOND, s->timebase_freq); + timer_mod(env->mtimer, next_ns); + } + } +} + +static void nuclei_timer_reset(DeviceState *dev) +{ + NucLeiSYSTIMERState *s =3D NUCLEI_SYSTIMER(dev); + s->mtime_lo =3D 0x0; + s->mtime_hi =3D 0x0; + s->mtimecmp_lo =3D 0xFFFFFFFF; + s->mtimecmp_hi =3D 0xFFFFFFFF; + s->mstop =3D 0x0; + s->mstop =3D 0x0; +} + +static uint64_t nuclei_timer_read(void *opaque, hwaddr offset, + unsigned size) +{ + NucLeiSYSTIMERState *s =3D NUCLEI_SYSTIMER(opaque); + CPUState *cpu =3D qemu_get_cpu(0); + CPURISCVState *env =3D cpu ? cpu->env_ptr : NULL; + uint64_t value =3D 0; + + switch (offset) { + case NUCLEI_SYSTIMER_REG_MTIMELO: + value =3D cpu_riscv_read_rtc(s->timebase_freq); + s->mtime_lo =3D value & 0xffffffff; + s->mtime_hi =3D (value >> 32) & 0xffffffff; + value =3D s->mtime_lo; + break; + case NUCLEI_SYSTIMER_REG_MTIMEHI: + value =3D s->mtime_hi; + break; + case NUCLEI_SYSTIMER_REG_MTIMECMPLO: + s->mtimecmp_lo =3D (env->mtimecmp) & 0xFFFFFFFF; + value =3D s->mtimecmp_lo; + break; + case NUCLEI_SYSTIMER_REG_MTIMECMPHI: + s->mtimecmp_hi =3D (env->mtimecmp >> 32) & 0xFFFFFFFF; + value =3D s->mtimecmp_hi; + break; + case NUCLEI_SYSTIMER_REG_MSFTRST: + break; + case NUCLEI_SYSTIMER_REG_MSTOP: + value =3D s->mstop; + break; + case NUCLEI_SYSTIMER_REG_MSIP: + value =3D s->msip; + break; + default: + break; + } + value &=3D 0xFFFFFFFF; + return value; + +} + +static void nuclei_timer_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + NucLeiSYSTIMERState *s =3D NUCLEI_SYSTIMER(opaque); + CPUState *cpu =3D qemu_get_cpu(0); + CPURISCVState *env =3D cpu ? cpu->env_ptr : NULL; + + value =3D value & 0xFFFFFFFF; + switch (offset) { + case NUCLEI_SYSTIMER_REG_MTIMELO: + s->mtime_lo =3D value; + env->mtimer->expire_time |=3D (value & 0xFFFFFFFF); + break; + case NUCLEI_SYSTIMER_REG_MTIMEHI: + s->mtime_hi =3D value; + env->mtimer->expire_time |=3D ((value << 32) & 0xFFFFFFFF); + break; + case NUCLEI_SYSTIMER_REG_MTIMECMPLO: + s->mtimecmp_lo =3D value; + s->mtimecmp_hi =3D 0xFFFFFFFF; + env->mtimecmp |=3D (value & 0xFFFFFFFF); + nuclei_timer_update_compare(s); + break; + case NUCLEI_SYSTIMER_REG_MTIMECMPHI: + s->mtimecmp_hi =3D value; + env->mtimecmp |=3D ((value << 32) & 0xFFFFFFFF); + nuclei_timer_update_compare(s); + break; + case NUCLEI_SYSTIMER_REG_MSFTRST: + if (!(value & 0x80000000) =3D=3D 0) { + nuclei_timer_reset((DeviceState *)s); + } + break; + case NUCLEI_SYSTIMER_REG_MSTOP: + s->mstop =3D value; + break; + case NUCLEI_SYSTIMER_REG_MSIP: + s->msip =3D value; + if ((s->msip & 0x1) =3D=3D 1) { + qemu_set_irq(*(s->soft_irq), 1); + } else { + qemu_set_irq(*(s->soft_irq), 0); + } + + break; + default: + break; + } +} + +static const MemoryRegionOps nuclei_timer_ops =3D { + .read =3D nuclei_timer_read, + .write =3D nuclei_timer_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, +}; + +static Property nuclei_systimer_properties[] =3D { + DEFINE_PROP_UINT32("aperture-size", NucLeiSYSTIMERState, aperture_size= , 0), + DEFINE_PROP_UINT32("timebase-freq", NucLeiSYSTIMERState, timebase_freq= , 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void nuclei_timer_realize(DeviceState *dev, Error **errp) +{ + NucLeiSYSTIMERState *s =3D NUCLEI_SYSTIMER(dev); + + if (s->aperture_size =3D=3D 0) { + s->aperture_size =3D 0x1000; + } + memory_region_init_io(&s->iomem, OBJECT(dev), &nuclei_timer_ops, + s, TYPE_NUCLEI_SYSTIMER, s->aperture_size); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); +} + +static void nuclei_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + dc->realize =3D nuclei_timer_realize; + dc->reset =3D nuclei_timer_reset; + dc->desc =3D "NucLei Systimer Timer"; + device_class_set_props(dc, nuclei_systimer_properties); +} + +static const TypeInfo nuclei_timer_info =3D { + .name =3D TYPE_NUCLEI_SYSTIMER, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(NucLeiSYSTIMERState), + .class_init =3D nuclei_timer_class_init, +}; + +static void nuclei_timer_register_types(void) +{ + type_register_static(&nuclei_timer_info); +} +type_init(nuclei_timer_register_types); + +static void nuclei_mtimecmp_cb(void *opaque) +{ + RISCVCPU *cpu =3D RISCV_CPU(qemu_get_cpu(0)); + CPURISCVState *env =3D &cpu->env; + nuclei_eclic_systimer_cb(((RISCVCPU *)cpu)->env.eclic); + timer_del(env->mtimer); +} + +DeviceState *nuclei_systimer_create(hwaddr addr, hwaddr size, + DeviceState *eclic, uint32_t timebase_= freq) +{ + RISCVCPU *cpu =3D RISCV_CPU(qemu_get_cpu(0)); + CPURISCVState *env =3D &cpu->env; + + env->features |=3D (1ULL << RISCV_FEATURE_ECLIC); + env->mtimer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, + &nuclei_mtimecmp_cb, cpu); + env->mtimecmp =3D 0; + + DeviceState *dev =3D qdev_new(TYPE_NUCLEI_SYSTIMER); + qdev_prop_set_uint32(dev, "aperture-size", size); + qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); + NucLeiSYSTIMERState *s =3D NUCLEI_SYSTIMER(dev); + if (eclic !=3D NULL) { + s->eclic =3D eclic; + s->soft_irq =3D &(NUCLEI_ECLIC(eclic)->irqs[Internal_SysTimerSW_IR= Qn]); + s->timer_irq =3D &(NUCLEI_ECLIC(eclic)->irqs[Internal_SysTimer_IRQ= n]); + } + return dev; +} diff --git a/include/hw/intc/nuclei_systimer.h b/include/hw/intc/nuclei_sys= timer.h new file mode 100644 index 0000000000..1f7756bb6f --- /dev/null +++ b/include/hw/intc/nuclei_systimer.h @@ -0,0 +1,70 @@ +/* + * NUCLEI TIMER (Timer Unit) interface + * + * Copyright (c) 2020 Gao ZhiYuan + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * This provides a parameterizable timer controller based on NucLei's Syst= imer. + * + * 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 3 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 . + */ +#ifndef HW_NUCLEI_SYSTIMER_H +#define HW_NUCLEI_SYSTIMER_H + +#include "hw/intc/nuclei_eclic.h" +#include "hw/irq.h" +#include "hw/sysbus.h" + +#define TYPE_NUCLEI_SYSTIMER "riscv.nuclei.systimer" + +#define NUCLEI_SYSTIMER(obj) \ + OBJECT_CHECK(NucLeiSYSTIMERState, (obj), TYPE_NUCLEI_SYSTIMER) + +#define NUCLEI_SYSTIMER_REG_MTIMELO 0x0000 +#define NUCLEI_SYSTIMER_REG_MTIMEHI 0x0004 +#define NUCLEI_SYSTIMER_REG_MTIMECMPLO 0x0008 +#define NUCLEI_SYSTIMER_REG_MTIMECMPHI 0x000C +#define NUCLEI_SYSTIMER_REG_MSFTRST 0xFF0 +#define NUCLEI_SYSTIMER_REG_MSTOP 0xFF8 +#define NUCLEI_SYSTIMER_REG_MSIP 0xFFC + +typedef struct NucLeiSYSTIMERState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + qemu_irq *timer_irq; + qemu_irq *soft_irq; + + DeviceState *eclic; + + uint32_t mtime_lo; + uint32_t mtime_hi; + uint32_t mtimecmp_lo; + uint32_t mtimecmp_hi; + uint32_t mstop; + uint32_t msip; + + uint32_t aperture_size; + uint32_t timebase_freq; + +} NucLeiSYSTIMERState; + +#define NUCLEI_GD32_TIMEBASE_FREQ (108000000 * 2) +#define NUCLEI_HBIRD_TIMEBASE_FREQ (10000000) + +DeviceState *nuclei_systimer_create(hwaddr addr, hwaddr size, + DeviceState *eclic, uint32_t timebase_= freq); +#endif --=20 2.17.1 From nobody Tue May 21 06:59:56 2024 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=1620393962; cv=none; d=zohomail.com; s=zohoarc; b=fg7kkorCdSaaTxZHBibJcwICmvNAN3bPwsJWMAyE4PLjB5oMpuDzadqkUzF/yxk6YxsSGgqMPU+ul/Y1nLB01jdI3sZe/PfCl5Pi3j/ehj4nf0lfJsa76uDL/+UCrNX6w7p5By4k04iqrx26h3xLsNxdPRo4YLBhMllmUKBNm/A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1620393962; 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=RfqGKnYZQgaGxyIwt4LtEZiUoLPIEZMV9xnJgee+V34=; b=ZlOstkoosKOTwKBV/0P3JKhAoPtJ9RSbKo3nZIWEVdCjpcV9tQ1wqdUnzZ7JUx/NHC44znrRa4kJkaYsdaF5R2uSKd8DFC1QLFe831kIKBqqVLf/z8APke4ivLKOncvdWtDqklCx7PQK1kddK+fD9WM3bXFOo8vvRLh0EmCox2E= 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 1620393961843266.1364681226395; Fri, 7 May 2021 06:26:01 -0700 (PDT) Received: from localhost ([::1]:51440 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lf0US-0000yr-7W for importer@patchew.org; Fri, 07 May 2021 09:26:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60706) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1levgW-0004Zx-JY; Fri, 07 May 2021 04:18:08 -0400 Received: from smtp25.cstnet.cn ([159.226.251.25]:50026 helo=cstnet.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1levgS-0005jl-7t; Fri, 07 May 2021 04:18:08 -0400 Received: from localhost.localdomain (unknown [121.232.13.213]) by APP-05 (Coremail) with SMTP id zQCowAB3fSnh9pRgTQ5HAQ--.1834S6; Fri, 07 May 2021 16:14:28 +0800 (CST) From: wangjunqiang To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Subject: [RFC PATCH 4/5] hw/char: Add Nuclei Uart Date: Fri, 7 May 2021 16:16:53 +0800 Message-Id: <20210507081654.11056-5-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--.1834S6 X-Coremail-Antispam: 1UD129KBjvJXoWxKF18KrW3GryDAFy3Gry7trb_yoWfWF4kpF W5CFy5Ka1UKF13G393Ga17JF4fJF1kAF1DWa4xG3yvvr47Kr40yF92gayavFWDArWfGr45 AFZxXFWUG3W8XFJanT9S1TB71UUUUUDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBm14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF0E3s1l82xGYI kIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2 z4x0Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr1j6F 4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AKxVW0oVCq 3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7 IYx2IY67AKxVWUGVWUXwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4U M4x0Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwCY02Avz4vE14v_GFyl42 xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWU GwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI4 8JMIIF0xvE2Ix0cI8IcVAFwI0_Gr0_Xr1lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4U MIIF0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I 8E87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjfUYyxRDUUUU X-Originating-IP: [121.232.13.213] X-CM-SenderInfo: pzdqwy5xqtxt1qj6x2xfdvhtffof0/1tbiCwgOAFz4kC9qzQAAsx 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 provides the initial implementation of Nuclei Uart which is opensource in Nuclei's Hummingbird Project. Signed-off-by: Wang Junqiang --- hw/char/Kconfig | 3 + hw/char/meson.build | 1 + hw/char/nuclei_uart.c | 208 ++++++++++++++++++++++++++++++++++ include/hw/char/nuclei_uart.h | 73 ++++++++++++ 4 files changed, 285 insertions(+) create mode 100644 hw/char/nuclei_uart.c create mode 100644 include/hw/char/nuclei_uart.h diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 4cf36ac637..de003d0609 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -67,3 +67,6 @@ config SIFIVE_UART =20 config GOLDFISH_TTY bool + +config NUCLEI_UART + bool diff --git a/hw/char/meson.build b/hw/char/meson.build index da5bb8b762..fd0a0a34f4 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -34,6 +34,7 @@ softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files= ('sifive_uart.c')) softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_u= sart.c')) softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfso= c_mmuart.c')) +softmmu_ss.add(when: 'CONFIG_NUCLEI_UART', if_true: files('nuclei_uart.c')) =20 specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c')) specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.= c')) diff --git a/hw/char/nuclei_uart.c b/hw/char/nuclei_uart.c new file mode 100644 index 0000000000..0b6bfa33a7 --- /dev/null +++ b/hw/char/nuclei_uart.c @@ -0,0 +1,208 @@ +/* + * NUCLEI Hummingbird Evaluation Kit 100T/200T UART interface + * + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * 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 3 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 . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "hw/sysbus.h" +#include "chardev/char.h" +#include "chardev/char-fe.h" +#include "hw/hw.h" +#include "hw/irq.h" +#include "hw/char/nuclei_uart.h" + +/* + * Not yet implemented: + * + * Transmit FIFO using "qemu/fifo8.h" + */ +static uint64_t uart_ip(NucLeiUARTState *s) +{ + uint64_t ret =3D 0; + + uint64_t txcnt =3D NUCLEI_UART_GET_TXCNT(s->txctrl); + uint64_t rxcnt =3D NUCLEI_UART_GET_RXCNT(s->rxctrl); + + if (txcnt !=3D 0) { + ret |=3D NUCLEI_UART_IP_TXWM; + } + if (s->rx_fifo_len > rxcnt) { + ret |=3D NUCLEI_UART_IP_RXWM; + } + + return ret; +} + +static void update_irq(NucLeiUARTState *s) +{ + int cond =3D 0; + s->txctrl |=3D 0x1; + if (s->rx_fifo_len) { + s->rxctrl &=3D ~0x1; + } else { + s->rxctrl |=3D 0x1; + } + + if ((s->ie & NUCLEI_UART_IE_TXWM) || + ((s->ie & NUCLEI_UART_IE_RXWM) && s->rx_fifo_len)) { + cond =3D 1; + } + + if (cond) { + qemu_irq_raise(s->irq); + } else { + qemu_irq_lower(s->irq); + } +} + +static uint64_t +uart_read(void *opaque, hwaddr offset, unsigned int size) +{ + NucLeiUARTState *s =3D opaque; + uint64_t value =3D 0; + uint8_t fifo_val; + + switch (offset) { + case NUCLEI_UART_REG_TXDATA: + return 0; + case NUCLEI_UART_REG_RXDATA: + if (s->rx_fifo_len) { + fifo_val =3D s->rx_fifo[0]; + memmove(s->rx_fifo, s->rx_fifo + 1, s->rx_fifo_len - 1); + s->rx_fifo_len--; + qemu_chr_fe_accept_input(&s->chr); + update_irq(s); + return fifo_val; + } + return 0x80000000; + case NUCLEI_UART_REG_TXCTRL: + value =3D s->txctrl; + break; + case NUCLEI_UART_REG_RXCTRL: + value =3D s->rxctrl; + break; + case NUCLEI_UART_REG_IE: + value =3D s->ie; + break; + case NUCLEI_UART_REG_IP: + value =3D uart_ip(s); + break; + case NUCLEI_UART_REG_DIV: + value =3D s->div; + break; + default: + break; + } + return value; +} + +static void +uart_write(void *opaque, hwaddr offset, + uint64_t value, unsigned int size) +{ + NucLeiUARTState *s =3D opaque; + unsigned char ch =3D value; + + switch (offset) { + case NUCLEI_UART_REG_TXDATA: + qemu_chr_fe_write(&s->chr, &ch, 1); + update_irq(s); + break; + case NUCLEI_UART_REG_TXCTRL: + s->txctrl =3D value; + break; + case NUCLEI_UART_REG_RXCTRL: + s->rxctrl =3D value; + break; + case NUCLEI_UART_REG_IE: + s->ie =3D value; + update_irq(s); + break; + case NUCLEI_UART_REG_IP: + s->ip =3D value; + break; + case NUCLEI_UART_REG_DIV: + s->div =3D value; + break; + default: + break; + } +} + +static const MemoryRegionOps uart_ops =3D { + .read =3D uart_read, + .write =3D uart_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + } +}; + +static void uart_rx(void *opaque, const uint8_t *buf, int size) +{ + NucLeiUARTState *s =3D opaque; + + /* Got a byte. */ + if (s->rx_fifo_len >=3D sizeof(s->rx_fifo)) { + printf("WARNING: UART dropped char.\n"); + return; + } + s->rx_fifo[s->rx_fifo_len++] =3D *buf; + + update_irq(s); +} + +static int uart_can_rx(void *opaque) +{ + NucLeiUARTState *s =3D opaque; + return s->rx_fifo_len < sizeof(s->rx_fifo); +} + +static void uart_event(void *opaque, QEMUChrEvent event) +{ +} + +static int uart_be_change(void *opaque) +{ + NucLeiUARTState *s =3D opaque; + + qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event, + uart_be_change, s, NULL, true); + + return 0; +} + +/* + * Create UART device. + */ +NucLeiUARTState *nuclei_uart_create(MemoryRegion *address_space, + hwaddr base, uint64_t size, Chardev *chr, qemu_irq irq) +{ + NucLeiUARTState *s =3D g_malloc0(sizeof(NucLeiUARTState)); + s->irq =3D irq; + qemu_chr_fe_init(&s->chr, chr, &error_abort); + qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event, + uart_be_change, s, NULL, true); + memory_region_init_io(&s->mmio, NULL, &uart_ops, s, + TYPE_NUCLEI_UART, size); + memory_region_add_subregion(address_space, base, &s->mmio); + + return s; +} diff --git a/include/hw/char/nuclei_uart.h b/include/hw/char/nuclei_uart.h new file mode 100644 index 0000000000..a7f2c72fb7 --- /dev/null +++ b/include/hw/char/nuclei_uart.h @@ -0,0 +1,73 @@ +/* + * NUCLEI Hummingbird Evaluation Kit 100T/200T UART interface + * + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * 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 3 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 . + */ + +#ifndef HW_NUCLEI_UART_H +#define HW_NUCLEI_UART_H + +#include "chardev/char-fe.h" +#include "hw/irq.h" +#include "hw/sysbus.h" + +#define TYPE_NUCLEI_UART "riscv.nuclei.uart" +OBJECT_DECLARE_SIMPLE_TYPE(NucLeiUARTState, NUCLEI_UART) + +#define NUCLEI_UART_REG_TXDATA 0x000 +#define NUCLEI_UART_REG_RXDATA 0x004 +#define NUCLEI_UART_REG_TXCTRL 0x008 +#define NUCLEI_UART_REG_RXCTRL 0x00C +#define NUCLEI_UART_REG_IE 0x010 +#define NUCLEI_UART_REG_IP 0x014 +#define NUCLEI_UART_REG_DIV 0x018 + +#define NUCLEI_UART_GET_TXCNT(txctrl) (txctrl & 0x1) +#define NUCLEI_UART_GET_RXCNT(rxctrl) (rxctrl & 0x1) + +enum { + NUCLEI_UART_IE_TXWM =3D 1, /* Transmit watermark interrupt enable */ + NUCLEI_UART_IE_RXWM =3D 2 /* Receive watermark interrupt enable */ +}; + +enum { + NUCLEI_UART_IP_TXWM =3D 1, /* Transmit watermark interrupt pending */ + NUCLEI_UART_IP_RXWM =3D 2 /* Receive watermark interrupt pending */ +}; + +typedef struct NucLeiUARTState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + qemu_irq irq; + MemoryRegion mmio; + CharBackend chr; + uint8_t rx_fifo[8]; + unsigned int rx_fifo_len; + + uint32_t txdata; + uint32_t rxdata; + uint32_t txctrl; + uint32_t rxctrl; + uint32_t ie; + uint32_t ip; + uint32_t div; +} NucLeiUARTState; + +NucLeiUARTState *nuclei_uart_create(MemoryRegion *address_space, + hwaddr base, uint64_t size, Chardev *chr, qemu_irq irq= ); +#endif --=20 2.17.1 From nobody Tue May 21 06:59:56 2024 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=1620394085; cv=none; d=zohomail.com; s=zohoarc; b=PTBlyg5he1FO7t+lqg9P1OQWDH4Gd1BkldkuFCTdJNKLEOD4kePwNwp2NEZj8TRIBSSEOXyes7dpIWNLWtRD4wvecksTbtyjcuK1N3+GHn5V/k7koFi8X6G/4QmEkFxqB1+2b+sifizadAwIoq4P8pL68Z4UwI/WPZFOvkmEpRA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1620394085; 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=kgO3NvF22RCsnj9m0XRFyBjt9DBL9723e7ukMQiPp6Y=; b=LRUSJdWvvAyH//ulhGsX0yBRqE5uIQXAgklIN9ipfxm8a+jOBNt/a53dCv6cgBG1NcYqV8gx4SMNYhVHvbfrIscrU1Gy/cOqGMIzn7t5JJPBcdlEgX8UfR4NtqzSirX3uFPmvAlix6WCQJ52e3sM2lDYqJRN+m2s2HV0xnUS+tA= 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 1620394085161622.1462154658889; Fri, 7 May 2021 06:28:05 -0700 (PDT) Received: from localhost ([::1]:58880 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lf0WS-00045U-1H for importer@patchew.org; Fri, 07 May 2021 09:28:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60708) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1levgW-0004a0-RT; Fri, 07 May 2021 04:18:08 -0400 Received: from smtp25.cstnet.cn ([159.226.251.25]:50046 helo=cstnet.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1levgS-0005lP-Bn; Fri, 07 May 2021 04:18:08 -0400 Received: from localhost.localdomain (unknown [121.232.13.213]) by APP-05 (Coremail) with SMTP id zQCowAB3fSnh9pRgTQ5HAQ--.1834S7; Fri, 07 May 2021 16:14:28 +0800 (CST) From: wangjunqiang To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Subject: [RFC PATCH 5/5] Nuclei FPGA Evaluation Kit MCU Machine Date: Fri, 7 May 2021 16:16:54 +0800 Message-Id: <20210507081654.11056-6-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--.1834S7 X-Coremail-Antispam: 1UD129KBjvAXoW3ZryfKFWDWFyUXFy7KF1fXrb_yoW8WrWUKo WfJFWfJFW8Gw15Zr4FkFyDGrZrWrnakF42q398CF93u3WxWF47WryrK34DJwsxJr1rGwn7 XFWa9w47W3WDXrykn29KB7ZKAUJUUUU5529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYM7AC8VAFwI0_Wr0E3s1l1xkIjI8I6I8E6xAIw20EY4v20xva j40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l82xGYIkIc2x26280x7IE14v26r126s0DM28Irc Ia0xkI8VCY1x0267AKxVW5JVCq3wA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK021l 84ACjcxK6xIIjxv20xvE14v26F1j6w1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4UJV WxJr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_GcCE 3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2I x0cI8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJVW8 JwACjcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lc2xSY4AK67AK6r43Mx AIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_ Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUtVW8ZwCIc40Y0x0EwI xGrwCI42IY6xIIjxv20xvE14v26r4j6ryUMIIF0xvE2Ix0cI8IcVCY1x0267AKxVWxJVW8 Jr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F4UMIIF0x vEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x0JU9F4iUUUUU= X-Originating-IP: [121.232.13.213] X-CM-SenderInfo: pzdqwy5xqtxt1qj6x2xfdvhtffof0/1tbiCgkOAFz4jlgX+wAAsT 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 provides an implementation of Nuclei FPGA Evaluation Kit Board as MCU mode. The Machine based on Nuclei's specification which has Customiz= ed register. The following machine is implemented: -"Nuclei 100T": SYSTIMER, ECLIC, UART ... Signed-off-by: Wang Junqiang --- default-configs/devices/riscv32-softmmu.mak | 1 + default-configs/devices/riscv64-softmmu.mak | 1 + hw/riscv/Kconfig | 9 + hw/riscv/meson.build | 1 + hw/riscv/nuclei_n.c | 276 ++++++++++++++++++++ include/hw/riscv/nuclei_n.h | 136 ++++++++++ 6 files changed, 424 insertions(+) create mode 100644 hw/riscv/nuclei_n.c create mode 100644 include/hw/riscv/nuclei_n.h diff --git a/default-configs/devices/riscv32-softmmu.mak b/default-configs/= devices/riscv32-softmmu.mak index d847bd5692..52fb26ef01 100644 --- a/default-configs/devices/riscv32-softmmu.mak +++ b/default-configs/devices/riscv32-softmmu.mak @@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=3Dy CONFIG_SIFIVE_U=3Dy CONFIG_RISCV_VIRT=3Dy CONFIG_OPENTITAN=3Dy +CONFIG_NUCLEI_N=3Dy \ No newline at end of file diff --git a/default-configs/devices/riscv64-softmmu.mak b/default-configs/= devices/riscv64-softmmu.mak index d5eec75f05..ff688bbbc6 100644 --- a/default-configs/devices/riscv64-softmmu.mak +++ b/default-configs/devices/riscv64-softmmu.mak @@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=3Dy CONFIG_SIFIVE_U=3Dy CONFIG_RISCV_VIRT=3Dy CONFIG_MICROCHIP_PFSOC=3Dy +CONFIG_NUCLEI_N=3Dy \ No newline at end of file diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 1de18cdcf1..427ed3afd3 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -67,3 +67,12 @@ config SPIKE select MSI_NONBROKEN select SIFIVE_CLINT select SIFIVE_PLIC + +config NUCLEI_N + bool + select MSI_NONBROKEN + select NUCLEI_SYSTIMER + select NUCLEI_ECLIC + select SIFIVE_GPIO + select NUCLEI_UART + select UNIMP \ No newline at end of file diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 275c0f7eb7..840c2852e2 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -8,5 +8,6 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifiv= e_e.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c')) riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c')) riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfs= oc.c')) +riscv_ss.add(when: 'CONFIG_NUCLEI_N', if_true: files('nuclei_n.c')) =20 hw_arch +=3D {'riscv': riscv_ss} diff --git a/hw/riscv/nuclei_n.c b/hw/riscv/nuclei_n.c new file mode 100644 index 0000000000..a95b8a7d29 --- /dev/null +++ b/hw/riscv/nuclei_n.c @@ -0,0 +1,276 @@ +/* + * Nuclei N series SOC machine interface + * + * Copyright (c) 2020 Gao ZhiYuan + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * 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 3 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 . + */ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/sysbus.h" +#include "target/riscv/cpu.h" +#include "hw/misc/unimp.h" +#include "hw/char/riscv_htif.h" +#include "hw/riscv/riscv_hart.h" +#include "hw/intc/nuclei_eclic.h" +#include "hw/char/nuclei_uart.h" +#include "hw/riscv/nuclei_n.h" +#include "hw/riscv/boot.h" +#include "chardev/char.h" +#include "sysemu/arch_init.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" + +#include + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} nuclei_memmap[] =3D { + [HBIRD_DEBUG] =3D {0x0, 0x1000}, + [HBIRD_ROM] =3D {0x1000, 0x1000}, + [HBIRD_TIMER] =3D {0x2000000, 0x1000}, + [HBIRD_ECLIC] =3D {0xc000000, 0x10000}, + [HBIRD_GPIO] =3D {0x10012000, 0x1000}, + [HBIRD_UART0] =3D {0x10013000, 0x1000}, + [HBIRD_QSPI0] =3D {0x10014000, 0x1000}, + [HBIRD_PWM0] =3D {0x10015000, 0x1000}, + [HBIRD_UART1] =3D {0x10023000, 0x1000}, + [HBIRD_QSPI1] =3D {0x10024000, 0x1000}, + [HBIRD_PWM1] =3D {0x10025000, 0x1000}, + [HBIRD_QSPI2] =3D {0x10034000, 0x1000}, + [HBIRD_PWM2] =3D {0x10035000, 0x1000}, + [HBIRD_XIP] =3D {0x20000000, 0x10000000}, + [HBIRD_DRAM] =3D {0xa0000000, 0x0}, + [HBIRD_ILM] =3D {0x80000000, 0x20000}, + [HBIRD_DLM] =3D {0x90000000, 0x20000}, +}; + +static void nuclei_machine_get_uint32_prop(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + visit_type_uint32(v, name, (uint32_t *)opaque, errp); +} + +static void nuclei_machine_set_uint32_prop(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + visit_type_uint32(v, name, (uint32_t *)opaque, errp); +} + +static void nuclei_board_init(MachineState *machine) +{ + const struct MemmapEntry *memmap =3D nuclei_memmap; + NucleiHBState *s =3D HBIRD_FPGA_MACHINE(machine); + MemoryRegion *system_memory =3D get_system_memory(); + MemoryRegion *main_mem =3D g_new(MemoryRegion, 1); + MemoryRegion *flash =3D g_new(MemoryRegion, 1); + target_ulong start_addr =3D memmap[HBIRD_ILM].base; + int i; + + /* TODO: Add qtest support */ + /* Initialize SOC */ + object_initialize_child(OBJECT(machine), "soc", + &s->soc, TYPE_NUCLEI_HBIRD_SOC); + qdev_realize(DEVICE(&s->soc), NULL, &error_abort); + + memory_region_init_ram(&s->soc.ilm, NULL, "riscv.nuclei.ram.ilm", + memmap[HBIRD_ILM].size, &error_fatal); + memory_region_add_subregion(system_memory, + memmap[HBIRD_ILM].base, &s->soc.ilm); + + memory_region_init_ram(&s->soc.dlm, NULL, "riscv.nuclei.ram.dlm", + memmap[HBIRD_DLM].size, &error_fatal); + memory_region_add_subregion(system_memory, + memmap[HBIRD_DLM].base, &s->soc.dlm); + + /* register DRAM */ + memory_region_init_ram(main_mem, NULL, "riscv.nuclei.dram", + machine->ram_size, &error_fatal); + memory_region_add_subregion(system_memory, memmap[HBIRD_DRAM].base, + main_mem); + + /* Flash memory */ + memory_region_init_ram(flash, NULL, "riscv.nuclei.xip", + memmap[HBIRD_XIP].size, &error_fatal); + memory_region_add_subregion(system_memory, memmap[HBIRD_XIP].base, + flash); + + switch (s->msel) { + case MSEL_ILM: + start_addr =3D memmap[HBIRD_ILM].base; + break; + case MSEL_FLASH: + start_addr =3D memmap[HBIRD_XIP].base; + break; + case MSEL_FLASHXIP: + start_addr =3D memmap[HBIRD_XIP].base; + break; + case MSEL_DDR: + start_addr =3D memmap[HBIRD_DRAM].base; + break; + default: + start_addr =3D memmap[HBIRD_ILM].base; + break; + } + + /* reset vector */ + uint32_t reset_vec[8] =3D { + 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ + 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ + 0xf1402573, /* csrr a0, mhartid */ +#if defined(TARGET_RISCV32) + 0x0182a283, /* lw t0, 24(t0) */ +#elif defined(TARGET_RISCV64) + 0x0182b283, /* ld t0, 24(t0) */ +#endif + 0x00028067, /* jr t0 */ + 0x00000000, + start_addr, /* start: .dword DRAM_BASE */ + 0x00000000, + }; + + for (i =3D 0; i < sizeof(reset_vec) >> 2; i++) { + reset_vec[i] =3D cpu_to_le32(reset_vec[i]); + } + rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), + memmap[HBIRD_ROM].base, &address_space_memory); + + /* boot rom */ + if (machine->kernel_filename) { + riscv_load_kernel(machine->kernel_filename, start_addr, NULL); + } +} + +static void nuclei_soc_init(Object *obj) +{ + NucleiHBSoCState *s =3D RISCV_NUCLEI_HBIRD_SOC(obj); + + object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); + + object_initialize_child(obj, "riscv.nuclei.gpio", + &s->gpio, TYPE_SIFIVE_GPIO); +} + +static void nuclei_soc_realize(DeviceState *dev, Error **errp) +{ + const struct MemmapEntry *memmap =3D nuclei_memmap; + MachineState *ms =3D MACHINE(qdev_get_machine()); + NucleiHBSoCState *s =3D RISCV_NUCLEI_HBIRD_SOC(dev); + MemoryRegion *sys_mem =3D get_system_memory(); + Error *err =3D NULL; + + object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type, + &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); + + /* Mask ROM */ + memory_region_init_rom(&s->internal_rom, OBJECT(dev), "riscv.nuclei.ir= om", + memmap[HBIRD_ROM].size, &error_fatal); + memory_region_add_subregion(sys_mem, + memmap[HBIRD_ROM].base, &s->internal_rom); + + s->eclic =3D nuclei_eclic_create(memmap[HBIRD_ECLIC].base, + memmap[HBIRD_ECLIC].size, HBIRD_SOC_INT= _MAX); + + s->timer =3D nuclei_systimer_create(memmap[HBIRD_TIMER].base, + memmap[HBIRD_TIMER].size, + s->eclic, + NUCLEI_HBIRD_TIMEBASE_FREQ); + + /* GPIO */ + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[HBIRD_GPIO].base); + + nuclei_uart_create(sys_mem, + memmap[HBIRD_UART0].base, + memmap[HBIRD_UART0].size, + serial_hd(0), + nuclei_eclic_get_irq(DEVICE(s->eclic), + HBIRD_SOC_INT22_IRQn)); +} + +static void nuclei_machine_instance_init(Object *obj) +{ + NucleiHBState *s =3D HBIRD_FPGA_MACHINE(obj); + + s->msel =3D 0; + object_property_add(obj, "msel", "uint32", + nuclei_machine_get_uint32_prop, + nuclei_machine_set_uint32_prop, NULL, &s->msel); + object_property_set_description(obj, "msel", + "Mode Select Startup"); +} + +static void nuclei_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->desc =3D "Nuclei HummingBird Evaluation Kit"; + mc->init =3D nuclei_board_init; + mc->max_cpus =3D 1; + mc->default_cpu_type =3D NUCLEI_N_CPU; +} + +static const TypeInfo nuclei_machine_typeinfo =3D { + .name =3D MACHINE_TYPE_NAME("hbird_fpga"), + .parent =3D TYPE_MACHINE, + .class_init =3D nuclei_machine_class_init, + .instance_init =3D nuclei_machine_instance_init, + .instance_size =3D sizeof(NucleiHBState), +}; + +static void nuclei_machine_init_register_types(void) +{ + type_register_static(&nuclei_machine_typeinfo); +} + +type_init(nuclei_machine_init_register_types) + + static void nuclei_soc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + dc->realize =3D nuclei_soc_realize; + dc->user_creatable =3D false; +} + +static const TypeInfo nuclei_soc_type_info =3D { + .name =3D TYPE_NUCLEI_HBIRD_SOC, + .parent =3D TYPE_DEVICE, + .instance_size =3D sizeof(NucleiHBSoCState), + .instance_init =3D nuclei_soc_init, + .class_init =3D nuclei_soc_class_init, +}; + +static void nuclei_soc_register_types(void) +{ + type_register_static(&nuclei_soc_type_info); +} + +type_init(nuclei_soc_register_types) diff --git a/include/hw/riscv/nuclei_n.h b/include/hw/riscv/nuclei_n.h new file mode 100644 index 0000000000..83776c5c22 --- /dev/null +++ b/include/hw/riscv/nuclei_n.h @@ -0,0 +1,136 @@ +/* + * Nuclei U series SOC machine interface + * + * Copyright (c) 2020 Gao ZhiYuan + * Copyright (c) 2020-2021 PLCT Lab.All rights reserved. + * + * 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 3 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 . + */ +#ifndef HW_RISCV_NUCLEI_HBIRD_H +#define HW_RISCV_NUCLEI_HBIRD_H + +#include "hw/char/nuclei_uart.h" +#include "hw/gpio/sifive_gpio.h" +#include "hw/intc/nuclei_eclic.h" +#include "hw/intc/nuclei_systimer.h" +#include "hw/riscv/riscv_hart.h" +#include "hw/sysbus.h" + +#define TYPE_NUCLEI_HBIRD_SOC "riscv.nuclei.hbird.soc" +#define RISCV_NUCLEI_HBIRD_SOC(obj) \ + OBJECT_CHECK(NucleiHBSoCState, (obj), TYPE_NUCLEI_HBIRD_SOC) + +typedef struct NucleiHBSoCState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + RISCVHartArrayState cpus; + + DeviceState *eclic; + MemoryRegion ilm; + MemoryRegion dlm; + MemoryRegion internal_rom; + MemoryRegion xip_mem; + + DeviceState *timer; + NucLeiUARTState uart; + SIFIVEGPIOState gpio; + +} NucleiHBSoCState; + +#define TYPE_HBIRD_FPGA_MACHINE MACHINE_TYPE_NAME("hbird_fpga") +#define HBIRD_FPGA_MACHINE(obj) \ + OBJECT_CHECK(NucleiHBState, (obj), TYPE_HBIRD_FPGA_MACHINE) + +typedef struct NucleiHBState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + NucleiHBSoCState soc; + + uint32_t msel; +} NucleiHBState; + +enum { + MSEL_ILM =3D 1, + MSEL_FLASH =3D 2, + MSEL_FLASHXIP =3D 3, + MSEL_DDR =3D 4 +}; + +enum { + HBIRD_DEBUG, + HBIRD_ROM, + HBIRD_TIMER, + HBIRD_ECLIC, + HBIRD_GPIO, + HBIRD_UART0, + HBIRD_QSPI0, + HBIRD_PWM0, + HBIRD_UART1, + HBIRD_QSPI1, + HBIRD_PWM1, + HBIRD_QSPI2, + HBIRD_PWM2, + HBIRD_XIP, + HBIRD_DRAM, + HBIRD_ILM, + HBIRD_DLM +}; + +enum { + HBIRD_SOC_INT19_IRQn =3D 19, /*!< Device Interrupt */ + HBIRD_SOC_INT20_IRQn =3D 20, /*!< Device Interrupt */ + HBIRD_SOC_INT21_IRQn =3D 21, /*!< Device Interrupt */ + HBIRD_SOC_INT22_IRQn =3D 22, /*!< Device Interrupt */ + HBIRD_SOC_INT23_IRQn =3D 23, /*!< Device Interrupt */ + HBIRD_SOC_INT24_IRQn =3D 24, /*!< Device Interrupt */ + HBIRD_SOC_INT25_IRQn =3D 25, /*!< Device Interrupt */ + HBIRD_SOC_INT26_IRQn =3D 26, /*!< Device Interrupt */ + HBIRD_SOC_INT27_IRQn =3D 27, /*!< Device Interrupt */ + HBIRD_SOC_INT28_IRQn =3D 28, /*!< Device Interrupt */ + HBIRD_SOC_INT29_IRQn =3D 29, /*!< Device Interrupt */ + HBIRD_SOC_INT30_IRQn =3D 30, /*!< Device Interrupt */ + HBIRD_SOC_INT31_IRQn =3D 31, /*!< Device Interrupt */ + HBIRD_SOC_INT32_IRQn =3D 32, /*!< Device Interrupt */ + HBIRD_SOC_INT33_IRQn =3D 33, /*!< Device Interrupt */ + HBIRD_SOC_INT34_IRQn =3D 34, /*!< Device Interrupt */ + HBIRD_SOC_INT35_IRQn =3D 35, /*!< Device Interrupt */ + HBIRD_SOC_INT36_IRQn =3D 36, /*!< Device Interrupt */ + HBIRD_SOC_INT37_IRQn =3D 37, /*!< Device Interrupt */ + HBIRD_SOC_INT38_IRQn =3D 38, /*!< Device Interrupt */ + HBIRD_SOC_INT39_IRQn =3D 39, /*!< Device Interrupt */ + HBIRD_SOC_INT40_IRQn =3D 40, /*!< Device Interrupt */ + HBIRD_SOC_INT41_IRQn =3D 41, /*!< Device Interrupt */ + HBIRD_SOC_INT42_IRQn =3D 42, /*!< Device Interrupt */ + HBIRD_SOC_INT43_IRQn =3D 43, /*!< Device Interrupt */ + HBIRD_SOC_INT44_IRQn =3D 44, /*!< Device Interrupt */ + HBIRD_SOC_INT45_IRQn =3D 45, /*!< Device Interrupt */ + HBIRD_SOC_INT46_IRQn =3D 46, /*!< Device Interrupt */ + HBIRD_SOC_INT47_IRQn =3D 47, /*!< Device Interrupt */ + HBIRD_SOC_INT48_IRQn =3D 48, /*!< Device Interrupt */ + HBIRD_SOC_INT49_IRQn =3D 49, /*!< Device Interrupt */ + HBIRD_SOC_INT50_IRQn =3D 50, /*!< Device Interrupt */ + HBIRD_SOC_INT_MAX, +}; + +#if defined(TARGET_RISCV32) +#define NUCLEI_N_CPU TYPE_RISCV_CPU_NUCLEI_N307FD +#elif defined(TARGET_RISCV64) +#define NUCLEI_N_CPU TYPE_RISCV_CPU_NUCLEI_NX600FD +#endif + +#endif --=20 2.17.1