From nobody Fri Nov 14 19:47:10 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=1761559873; cv=none; d=zohomail.com; s=zohoarc; b=FCDUa4yZx1N8qTzlyIe3cEnaqd2ixzlxwW6X3ewFjDaM/5kcd/AsC0LQMTs/T2p3zsjeILn1uUhFp4vOmvmMC6RbwxMzw8sR1wLFLNetMCTOOfg9b0cekv0dETA+OtWdfoOyGGd6RFtKAn61khorl1o6aT9EU5jMauE3f9Vb6To= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761559873; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=mtRQJoFiB7pcTJCh+ZvnNXtLRl+nmZQ4jx3qoxA5tBk=; b=Y1biWCnpi5/d8rYnX0MdQ96BzXDtuRN96v+NkEZ/ivI3YLURmKZd8+tKJCC3d+9qEb286vQRxWFQ66rrJHwbbefUq3Xt/5jC5CqJ6rbSk+jHSN4aE0R4sdlhe2m1AeGsUXoMlyUPjGaS+nYM7EL72Xcf/hjeA5TrTTGYn214Dig= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 1761559873570277.36741181562206; Mon, 27 Oct 2025 03:11:13 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vDKAw-0001yD-Tz; Mon, 27 Oct 2025 06:10:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vDKAq-0001wV-LH for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:10:02 -0400 Received: from mail-wm1-x332.google.com ([2a00:1450:4864:20::332]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vDKAf-00040B-Qb for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:10:00 -0400 Received: by mail-wm1-x332.google.com with SMTP id 5b1f17b1804b1-470ffbf2150so32280245e9.1 for ; Mon, 27 Oct 2025 03:09:44 -0700 (PDT) Received: from DDesktop.local ([2a10:8012:d:eea4:f4de:376b:66b1:d7b5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-475dd494d5csm128625465e9.9.2025.10.27.03.09.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Oct 2025 03:09:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=videogpu-com.20230601.gappssmtp.com; s=20230601; t=1761559782; x=1762164582; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=mtRQJoFiB7pcTJCh+ZvnNXtLRl+nmZQ4jx3qoxA5tBk=; b=YbySV2tIQmmgIjqYxRKslY/wiFV07pMO6efwzarUtTWR+V8sYujhKPgeNZe8kkWoRn /oQ1SZ7VGE5uWqKunVvP5HNdpi5HcAkWYzjKYt+zimIyIIxYtD1PtLDeXK/yJm0cgeAY xLWzq/qapYgdUpW6wv6A7U5cgfPv4bJ+pqG4/ZdJNIv8sq3Xd2mbfrA3qbuFcL1etTd4 6/bmRhcLtRHH/7rQWGjQh7zyN4PSpDbVsitI4WYcJil9aAt1Q4skRdREXnzVhA7z3HlI 9hBwrP3ypn4UGJTag5ON5I32STf5dnx21jAZ+eQSfuzfsiwphAJjPAwtPfQVijBltOW0 XhzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761559782; x=1762164582; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=mtRQJoFiB7pcTJCh+ZvnNXtLRl+nmZQ4jx3qoxA5tBk=; b=HRF1/O0JvPylpHzY7yN3l4/iHIFtn1+hic7dZVXOsmE8h4QFNL3vfEufIsUzLekoFG N8gvNUDteMlNEneTkQVP5NunDTTjE/JBbRlt4BXPaqz2QCdV6JAjUlXB7pMPlk7p32/K TdTfTXmDBMcZW2dy0M2oQ19s/27o7wF3PM27PqRmpa6t2s5HDQN1eOK8blPPkOBCkerk m0s0h94WAmuIxRrBp0MB5+4XYtBa9v0SEzMyGzffDT+C9N6Q11AfVFqQfax5WiIxjJyY upJQW30C+Vj7m0ZmZgNQQGIobXfQr4JS8zHSll9NnHDyLozHAC+vMP2usoNp5OqlXrYq /lBQ== X-Gm-Message-State: AOJu0YySs/Eja5jbXv5huDHuctKe8s4nn8by7NdR0GMXQ/8FwAmMiOOM imeH0UVYaqmGtBwobbr9l7Qj2Aw0NbFYINzGAI5RBg1lTSp5PqfxEDaV44IGPuFOWcqYE40NemG 7XyPNwvY= X-Gm-Gg: ASbGncvOVp0bgSVwj3JUlSpymnsq/dTBO+B7tZ+9qJtZWHiy1CR1GowDWw+6Pah5GMW SMOaQ8lc5j21mfs8XAHikSi4d8if7B6lr6fdflZ6WAaFS3mP9XUe5GUJgkUWrBIQ6yeckM5a2sm 1yjRjDxNXOVSqz8YCze0wJ5zyVBbr31T/vDi00GR37Xjg41GtrSGbwjqaT12G+9fZh3yj9V0DZd Dj8PmU40mGojVbJ6BxnadpVHcmFR9JpRGMAywhMx0jtDdRM0Qb7Y/muo3JhTsrS/Vy3awWak/LN YFGejqeWqL0WzbSIgHCl/U1na/TJZRV8koN9PF7jA9zujuMdL8XE1uS11a4hdDL6ArTPB9z2E4z /csWGM6KPPsiNduWmD5MCaHb6La3E99IUoDVz/7BkG7o2N6Ol44J8H8KgTNXssAszgFEEcdjF8A eLcUfDiuHMb0JRO7E= X-Google-Smtp-Source: AGHT+IFMy/yGpwSLnbhwF8Ns79k3ADjKozexDFT+nkocGz91RvifcgzOmOpWlobffcHHka6vsUksrw== X-Received: by 2002:a05:600c:4ed0:b0:46e:59bd:f7e2 with SMTP id 5b1f17b1804b1-475d2426e58mr93920965e9.11.1761559782105; Mon, 27 Oct 2025 03:09:42 -0700 (PDT) From: Michael Levit To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, philmd@linaro.org, pbonzini@redhat.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, liwei1518@gmail.com, smishash@gmail.com Subject: [PATCH v2 1/5] target/riscv: add NEORV32 RV32 CPU type and vendor CSR hooks Date: Mon, 27 Oct 2025 12:09:34 +0200 Message-ID: <20251027100938.11822-2-michael@videogpu.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251027100938.11822-1-michael@videogpu.com> References: <20251027100938.11822-1-michael@videogpu.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2a00:1450:4864:20::332; envelope-from=michael@videogpu.com; helo=mail-wm1-x332.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @videogpu-com.20230601.gappssmtp.com) X-ZM-MESSAGEID: 1761559877460158500 Content-Type: text/plain; charset="utf-8" From: Michael Introduce NEORV32 RV32 CPU type under target/riscv, wire NEORV32 vendor ID, and add a vendor CSR (CSR_MXISA) guarded by mvendorid match, plus meson glu= e. Signed-off-by: Michael Levit diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index 75f4e43408..a39bf853cc 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -57,6 +57,8 @@ #define TYPE_RISCV_CPU_XIANGSHAN_NANHU RISCV_CPU_TYPE_NAME("xiangshan-nan= hu") #define TYPE_RISCV_CPU_XIANGSHAN_KMH RISCV_CPU_TYPE_NAME("xiangshan-kun= minghu") #define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host") +#define TYPE_RISCV_CPU_NEORV32 RISCV_CPU_TYPE_NAME("neorv32") + =20 OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 73d4280d7c..7bcf93c66c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -245,6 +245,7 @@ const RISCVIsaExtData isa_edata_arr[] =3D { ISA_EXT_DATA_ENTRY(xtheadmempair, PRIV_VERSION_1_11_0, ext_xtheadmempa= ir), ISA_EXT_DATA_ENTRY(xtheadsync, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, PRIV_VERSION_1_12_0, ext_XVentanaC= ondOps), + ISA_EXT_DATA_ENTRY(xneorv32xisa,PRIV_VERSION_1_10_0,ext_xneorv32xisa),=20 =20 { }, }; @@ -1366,6 +1367,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = =3D { MULTI_EXT_CFG_BOOL("xtheadmempair", ext_xtheadmempair, false), MULTI_EXT_CFG_BOOL("xtheadsync", ext_xtheadsync, false), MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), + MULTI_EXT_CFG_BOOL("xneorv32xisa", ext_xneorv32xisa, false), =20 { }, }; @@ -3032,6 +3034,7 @@ static const TypeInfo riscv_cpu_type_infos[] =3D { .cfg.pmp_regions =3D 8 ), =20 + #if defined(TARGET_RISCV32) || \ (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE32, TYPE_RISCV_DYNAMIC_CPU, @@ -3075,6 +3078,21 @@ static const TypeInfo riscv_cpu_type_infos[] =3D { .misa_mxl_max =3D MXL_RV32, .misa_ext =3D RVE ), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_NEORV32, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max =3D MXL_RV32, + .misa_ext =3D RVI | RVM | RVA | RVC | RVU, + .priv_spec =3D PRIV_VERSION_1_10_0, + + .cfg.max_satp_mode =3D VM_1_10_MBARE, + .cfg.ext_zifencei =3D true, + .cfg.ext_zicsr =3D true, + .cfg.pmp =3D true, + .cfg.pmp_regions =3D 16, + .cfg.mvendorid =3D NEORV32_VENDOR_ID, +#ifndef CONFIG_USER_ONLY + .custom_csrs =3D neorv32_csr_list +#endif + ), #endif =20 #if (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 36e7f10037..6a9918a25a 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -985,5 +985,8 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32= _bit); /* In th_csr.c */ extern const RISCVCSR th_csr_list[]; =20 +/* Implemented in neorv32_csr.c */ +extern const RISCVCSR neorv32_csr_list[]; + const char *priv_spec_to_str(int priv_version); #endif /* RISCV_CPU_H */ diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index aa28dc8d7e..9ad38506e4 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -64,5 +64,6 @@ MATERIALISE_EXT_PREDICATE(xtheadmemidx) MATERIALISE_EXT_PREDICATE(xtheadmempair) MATERIALISE_EXT_PREDICATE(xtheadsync) MATERIALISE_EXT_PREDICATE(XVentanaCondOps) +MATERIALISE_EXT_PREDICATE(xneorv32xisa) =20 #endif diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_field= s.h.inc index a154ecdc79..b84e1bd287 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -147,6 +147,7 @@ BOOL_FIELD(ext_xtheadmemidx) BOOL_FIELD(ext_xtheadmempair) BOOL_FIELD(ext_xtheadsync) BOOL_FIELD(ext_XVentanaCondOps) +BOOL_FIELD(ext_xneorv32xisa) =20 BOOL_FIELD(mmu) BOOL_FIELD(pmp) diff --git a/target/riscv/cpu_vendorid.h b/target/riscv/cpu_vendorid.h index 96b6b9c2cb..66a8f30b81 100644 --- a/target/riscv/cpu_vendorid.h +++ b/target/riscv/cpu_vendorid.h @@ -7,4 +7,6 @@ #define VEYRON_V1_MIMPID 0x111 #define VEYRON_V1_MVENDORID 0x61f =20 +#define NEORV32_VENDOR_ID 0xF0000001 + #endif /* TARGET_RISCV_CPU_VENDORID_H */ diff --git a/target/riscv/meson.build b/target/riscv/meson.build index fdefe88ccd..44e706ad3f 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -40,6 +40,7 @@ riscv_system_ss.add(files( 'th_csr.c', 'time_helper.c', 'riscv-qmp-cmds.c', + 'neorv32_csr.c', )) =20 subdir('tcg') diff --git a/target/riscv/neorv32_csr.c b/target/riscv/neorv32_csr.c new file mode 100644 index 0000000000..0cb8663436 --- /dev/null +++ b/target/riscv/neorv32_csr.c @@ -0,0 +1,54 @@ +/* + * Neorv32-specific CSR. + * + * Copyright (c) 2025 Michael Levit + * + * Author: + * Michael Levit + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * 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 "cpu.h" +#include "cpu_vendorid.h" + +#define CSR_MXISA (0xfc0) + +static RISCVException smode(CPURISCVState *env, int csrno) +{ + return RISCV_EXCP_NONE; +} + +static RISCVException read_neorv32_xisa(CPURISCVState *env, int csrno, + target_ulong *val) +{ + /* We don't support any extension for now on QEMU */ + *val =3D 0x00; + return RISCV_EXCP_NONE; +} + +static bool test_neorv32_mvendorid(RISCVCPU *cpu) +{ + return cpu->cfg.mvendorid =3D=3D NEORV32_VENDOR_ID; +} + +const RISCVCSR neorv32_csr_list[] =3D { + { + .csrno =3D CSR_MXISA, + .insertion_test =3D test_neorv32_mvendorid, + .csr_ops =3D { "neorv32.xisa", smode, read_neorv32_xisa } + }, + { } +}; + --=20 2.51.1 From nobody Fri Nov 14 19:47:10 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=1761559878; cv=none; d=zohomail.com; s=zohoarc; b=LnfDvMGvyYMV+ZSTlOxRBuHyTjIN7SDzo1cw6YD2MDLCd9tWkep7AR4mTZEWSmGAbiMAqjHeMznAa+62rZEHOi3c5RG8x+sh84OXSOqhna5txfz3xv/yfd/AppWQPPL+u/bJ4gcFSH/r2ji4SDFoxS48uP6WfwnF6f2Q3wCV8Rg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761559878; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=fN0QnICoUT6MEBF4Ji7phYQOT+IPiFwRXn3HKIjLCxI=; b=Eyy07959BqWreplIs1YI/VGb64lP5nrrvzFKbBh3bwWDopE/zM98JlrR+7+ts1zcxuboX+jfBTO8qRbtVCvuJyn2BYJ+JUcYVANBrKmvZCLFlAMCnUyfnz5NNy3xbq0un4LV3QFAP25+3j/J4BrVMjDyv5ZeLPsg4P9hNqd/FJg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 1761559877924143.02182094240834; Mon, 27 Oct 2025 03:11:17 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vDKAq-0001wS-Q3; Mon, 27 Oct 2025 06:10:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vDKAm-0001us-5C for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:09:56 -0400 Received: from mail-wm1-x331.google.com ([2a00:1450:4864:20::331]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vDKAg-00040J-2l for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:09:55 -0400 Received: by mail-wm1-x331.google.com with SMTP id 5b1f17b1804b1-475dc0ed8aeso18705115e9.2 for ; Mon, 27 Oct 2025 03:09:45 -0700 (PDT) Received: from DDesktop.local ([2a10:8012:d:eea4:f4de:376b:66b1:d7b5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-475dd494d5csm128625465e9.9.2025.10.27.03.09.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Oct 2025 03:09:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=videogpu-com.20230601.gappssmtp.com; s=20230601; t=1761559783; x=1762164583; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=fN0QnICoUT6MEBF4Ji7phYQOT+IPiFwRXn3HKIjLCxI=; b=vKOEwLoVvr4tk/s97uIOfsqG1l83hLlP8BV5A0wL/Xmu6sNwBJnghiawDqM6BU3+Ea +rgo7ynVRhzCuYeReEbOhTlAGa70llFB6f3/0YOMt1hrPfay+p+DijgXguPxLmo7TR/O nd+H5qw2EZ5h/Eo2aH5X5AR/7aYe02dt3nIGSBp7m5OkiTvUhu6hUwy8FolPdjzFsJAX BwdRDpq4OL5ysd24TG1Rj0S0n2T0IZNq5TcgnbZh0tTah0cJd3KDRG/Jddk0/pSL301H 2sal5OfbZAIemyX8fqk/YAxT/diYW7ScRgqveuwENARMMvzX5XNLgNaJIkmOVVZ7OZ6m pCOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761559783; x=1762164583; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fN0QnICoUT6MEBF4Ji7phYQOT+IPiFwRXn3HKIjLCxI=; b=vqidmeFHuumpJyjcRPHC8xNyKPJyXePAtTKpkuxTn+7Lm+hInSd4zgCBmbs9EsUO4W TWj1ZaDLH8o768TcCqxTuHYFMl+zP3ReePbX1QCXBbt0UQ7WdF1UClYvZantGmiwC4se HnZXdJ5LVY6MK+KY/ozNLSWlgKLVUsP5ZLA69HQVuUJmRdJRJmC4QtMwsiUVqvOfkTao G8d/gem2MItqo0ko9fgYB9B7lANxBhaey19D99HVD87woE1OGZol0REYT4oR2U5tmCGn NnEPMxV3oPtn3Esj+fzhSEB3ld+PkjdHWVFeXDzFP00l3ppK4PZFB8o5SmIpnI0VsLbr IODQ== X-Gm-Message-State: AOJu0YydrETkGL2mCbx3qhSiVjaHxSYRpAVsuFP/76ni/IjnfoAht+0c 6F/64+V2RKWK1ZExBeUB/u3mSm8mHf+Dn6AuMlAccCvFn4q9vByd1UGYmHBUGbI3NfJl1m68QcK sclo9J3E= X-Gm-Gg: ASbGnctc9/dT9w3F9O6lc+mWhzqROQHKRGNW4ocC5p+if6ZS4qoqwXNjn9WHrJ4aDNV G8UNHdnhJThz1H1D9+q5fprBlpiPPic7jLOXVlYhxouKdTZgQEtMfuGD7PcGD1Qt39EFqWJjCBK r82qTJx2bJtgo4HZKW+aYsyfIgMSlh3Q/bd6jh04sTro2TpYKOvWqw8xqnnczETW7UjA/CWwuYc tdkve3i0FCSmGZkK/TI6zgtUv4vE5/TCWd1Lv9PnHab4v0Sw1yTNOW9+EVtO0Rkvjxx63PIQvdB 1BQi6gzsoLpSjnzmEQsy0NfVNhHKjEGR40DUdpS9JTkjJo+Dva3nzAP6R3quHh1VM96HSxuUMY+ PFsWk7Iz+A6DTi8bnrdSAfdggmH4pax/OczIxJgTrEy4SEZLqaBPhuFGJzdsxYAsFCR+QHLNaSE pZvLgt X-Google-Smtp-Source: AGHT+IHH4ogYQUJAwwYfKaV2HF4nzUr18Eh4tIIhlzkp5rxfnKowDJaTYMIfrBvssbeWD0v/SDY4jA== X-Received: by 2002:a05:600c:811b:b0:471:14b1:da13 with SMTP id 5b1f17b1804b1-4711787dcfbmr256434305e9.14.1761559783377; Mon, 27 Oct 2025 03:09:43 -0700 (PDT) From: Michael Levit To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, philmd@linaro.org, pbonzini@redhat.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, liwei1518@gmail.com, smishash@gmail.com Subject: [PATCH v2 2/5] hw/misc: add NEORV32 SYSINFO block (CLK/MISC/SOC/CACHE) Date: Mon, 27 Oct 2025 12:09:35 +0200 Message-ID: <20251027100938.11822-3-michael@videogpu.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251027100938.11822-1-michael@videogpu.com> References: <20251027100938.11822-1-michael@videogpu.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2a00:1450:4864:20::331; envelope-from=michael@videogpu.com; helo=mail-wm1-x331.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @videogpu-com.20230601.gappssmtp.com) X-ZM-MESSAGEID: 1761559879153158500 Content-Type: text/plain; charset="utf-8" From: Michael Add a minimal SYSINFO MMIO device compatible with NEORV32 SDK expectations: CLK (rw), MISC/SOC/CACHE (ro) composed from constants. Includes Kconfig/mes= on. Signed-off-by: Michael Levit diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 4e35657468..3de644a9e0 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -235,4 +235,6 @@ config IOSB config XLNX_VERSAL_TRNG bool =20 +config NEORV32_SYSINFO_QEMU + bool source macio/Kconfig diff --git a/hw/misc/meson.build b/hw/misc/meson.build index b1d8d8e5d2..4ea46ec2d1 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -34,6 +34,7 @@ system_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: file= s('sifive_e_prci.c')) system_ss.add(when: 'CONFIG_SIFIVE_E_AON', if_true: files('sifive_e_aon.c'= )) system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c'= )) system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.= c')) +system_ss.add(when: 'CONFIG_NEORV32_SYSINFO_QEMU', if_true: files('neorv32= _sysinfo.c')) =20 subdir('macio') diff --git a/hw/misc/neorv32_sysinfo.c b/hw/misc/neorv32_sysinfo.c new file mode 100644 index 0000000000..09378b17a9 --- /dev/null +++ b/hw/misc/neorv32_sysinfo.c @@ -0,0 +1,183 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "system/address-spaces.h" +#include "neorv32_sysinfo.h" /* QEMU related */ +#include "neorv32_sysinfo_rtl.h" /* RTL related */ + + +/* Register addresses (offsets) */ +enum { + REG_SYSINFO_CLK =3D 0x00, + REG_SYSINFO_MISC =3D 0x04, + REG_SYSINFO_SOC =3D 0x08, + REG_SYSINFO_CACHE =3D 0x0C, +}; + + +typedef struct Neorv32SysInfoState { + MemoryRegion mmio; + uint32_t clk_hz; /* rw */ + uint32_t misc; /* ro */ + uint32_t soc; /* ro */ + uint32_t cache; /* ro */ +} Neorv32SysInfoState; + + +/* Safe integer log2: assumes power-of-two sizes; returns 0 if size is 0 */ +static unsigned int neorv32_log2u(uint32_t x) +{ + if (x =3D=3D 0U) { + return 0U; + } + unsigned int r =3D 0U; + while ((x >>=3D 1U) !=3D 0U) { + r++; + } + return r; +} + +/* Compose MISC register per the firmware header */ +static uint32_t neorv32_sysinfo_build_misc(void) +{ + const uint32_t imem_log2 =3D neorv32_log2u(SYSINFO_IMEM_SIZE) & 0xFFU= ; /* [7:0] */ + const uint32_t dmem_log2 =3D neorv32_log2u(SYSINFO_DMEM_SIZE) & 0xFFU= ; /* [15:8] */ + const uint32_t harts =3D (SYSINFO_NUM_HARTS & 0x0FU); = /* [19:16] */ + const uint32_t bootmode =3D (SYSINFO_BOOTMODE_ID & 0x03U); = /* [21:20] */ + const uint32_t intbus_to =3D (SYSINFO_INTBUS_TO_LOG2 & 0x1FU); = /* [26:22] */ + const uint32_t extbus_to =3D (SYSINFO_EXTBUS_TO_LOG2 & 0x1FU); = /* [31:27] */ + + uint32_t v =3D 0U; + v |=3D (imem_log2 << 0); + v |=3D (dmem_log2 << 8); + v |=3D (harts << 16); + v |=3D (bootmode << 20); + v |=3D (intbus_to << 22); + v |=3D (extbus_to << 27); + return v; +} + +/* Compose CACHE register per the firmware header */ +static uint32_t neorv32_sysinfo_build_cache(void) +{ + uint32_t v =3D 0U; + v |=3D ((ICACHE_BLOCK_SIZE_LOG2 & 0x0FU) << 0); + v |=3D ((ICACHE_NUM_BLOCKS_LOG2 & 0x0FU) << 4); + v |=3D ((DCACHE_BLOCK_SIZE_LOG2 & 0x0FU) << 8); + v |=3D ((DCACHE_NUM_BLOCKS_LOG2 & 0x0FU) << 12); + v |=3D ((ICACHE_BURSTS_EN ? 1U : 0U) << 16); + v |=3D ((DCACHE_BURSTS_EN ? 1U : 0U) << 24); + return v; +} + +static uint64_t neorv32_sysinfo_read(void *opaque, hwaddr addr, unsigned s= ize) +{ + Neorv32SysInfoState *s =3D opaque; + uint32_t val =3D 0U; + + switch (addr) { + case REG_SYSINFO_CLK: + val =3D s->clk_hz; + break; + case REG_SYSINFO_MISC: + val =3D s->misc; + break; + case REG_SYSINFO_SOC: + val =3D s->soc; + break; + case REG_SYSINFO_CACHE: + val =3D s->cache; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid read addr=3D0x%" HWADDR_PRIx " size=3D%= u\n", + __func__, addr, size); + return 0; + } + + /* Enforce access size semantics (1/2/4 ok); we just return the low by= tes */ + switch (size) { + case 4: return val; + case 2: return (uint16_t)val; + case 1: return (uint8_t)val; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid read size=3D%u at addr=3D0x%" HWADDR_PR= Ix "\n", + __func__, size, addr); + return 0; + } +} + +static void neorv32_sysinfo_write(void *opaque, hwaddr addr, uint64_t data= , unsigned size) +{ + Neorv32SysInfoState *s =3D opaque; + + /* Only CLK is writable; others are read-only */ + if (addr =3D=3D REG_SYSINFO_CLK) { + /* Accept 1/2/4 byte writes; update the corresponding bytes of clk= _hz */ + uint32_t old =3D s->clk_hz; + uint32_t val =3D old; + + switch (size) { + case 4: + val =3D (uint32_t)data; + break; + case 2: { + uint16_t part =3D (uint16_t)data; + /* Little-endian halfword at offset (0 or 2) */ + if ((addr & 0x3) =3D=3D 0x0) { + val =3D (old & 0xFFFF0000U) | part; + } else if ((addr & 0x3) =3D=3D 0x2) { + val =3D (old & 0x0000FFFFU) | ((uint32_t)part << 16); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: misaligned 16-bit write at 0x%" HWADDR_= PRIx "\n", + __func__, addr); + return; + } + break; + } + case 1: { + uint8_t part =3D (uint8_t)data; + uint32_t shift =3D (addr & 0x3) * 8U; + val =3D (old & ~(0xFFU << shift)) | ((uint32_t)part << shift); + break; + } + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid write size=3D%u at addr=3D0x%" HWAD= DR_PRIx "\n", + __func__, size, addr); + return; + } + + s->clk_hz =3D val; + return; + } + + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to read-only addr=3D0x%" HWADDR_PRIx " val=3D= 0x%" PRIx64 " size=3D%u\n", + __func__, addr, data, size); +} + +static const MemoryRegionOps neorv32_sysinfo_ops =3D { + .read =3D neorv32_sysinfo_read, + .write =3D neorv32_sysinfo_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid.min_access_size =3D 1, + .valid.max_access_size =3D 4, +}; + +void neorv32_sysinfo_create(MemoryRegion *address_space, hwaddr base) +{ + Neorv32SysInfoState *s =3D g_new0(Neorv32SysInfoState, 1); + + s->clk_hz =3D SYSINFO_CLK_HZ_DEFAULT; + s->misc =3D neorv32_sysinfo_build_misc(); + s->soc =3D SYSINFO_SOC_VAL; + s->cache =3D neorv32_sysinfo_build_cache(); + + memory_region_init_io(&s->mmio, NULL, &neorv32_sysinfo_ops, + s, "neorv32.sysinfo", 16 /* 4 regs x 4 bytes */); + + memory_region_add_subregion(address_space, base, &s->mmio); +} diff --git a/hw/misc/neorv32_sysinfo.h b/hw/misc/neorv32_sysinfo.h new file mode 100644 index 0000000000..c0ac7d87e4 --- /dev/null +++ b/hw/misc/neorv32_sysinfo.h @@ -0,0 +1,79 @@ +#ifndef HW_NEORV32_SYSINFO_H +#define HW_NEORV32_SYSINFO_H + +#include "system/memory.h" + + +/* Internal memory sizes (bytes) */ +#define SYSINFO_IMEM_SIZE 0x00008000U /* 32 KiB IMEM */ +#define SYSINFO_DMEM_SIZE 0x00008000U /* 32 KiB DMEM */ + +/* Number of harts (physical cores) */ +#define SYSINFO_NUM_HARTS 1U + +/* Boot mode (matches RTL BOOT_MODE_SELECT encoding used in your firmware)= */ +#define SYSINFO_BOOTMODE_ID 0U /* 0..3 */ + +/* Bus timeout encodings: value is log2(cycles); 0 means "no timeout" per = your helper */ +#define SYSINFO_INTBUS_TO_LOG2 0U /* 0 =3D> returns 0 */ +#define SYSINFO_EXTBUS_TO_LOG2 0U /* 0 =3D> returns 0 */ + +/* Clock (Hz): writable at runtime via SYSINFO.CLK */ +#define SYSINFO_CLK_HZ_DEFAULT 100000000U /* 100 MHz */ + +/* Cache topology encodings (log2 values ) */ +#define ICACHE_BLOCK_SIZE_LOG2 0U /* bits [3:0] */ +#define ICACHE_NUM_BLOCKS_LOG2 0U /* bits [7:4] */ +#define DCACHE_BLOCK_SIZE_LOG2 0U /* bits [11:8] */ +#define DCACHE_NUM_BLOCKS_LOG2 0U /* bits [15:12] */ +#define ICACHE_BURSTS_EN 0U /* bit 16 */ +#define DCACHE_BURSTS_EN 0U /* bit 24 */ + +/* Feature bitmap for SOC register. */ +#define SYSINFO_SOC_ENABLE(x) (1U << (x)) + +// Enable Bootloader, IMEM, DMEM, UART and SPI +#define SYSINFO_SOC_VAL \ + ( SYSINFO_SOC_ENABLE(SYSINFO_SOC_BOOTLOADER) | \ + SYSINFO_SOC_ENABLE(SYSINFO_SOC_IMEM) | \ + SYSINFO_SOC_ENABLE(SYSINFO_SOC_DMEM) | \ + SYSINFO_SOC_ENABLE(SYSINFO_SOC_IO_UART0) | \ + SYSINFO_SOC_ENABLE(SYSINFO_SOC_IO_SPI) ) + +/* -----------------------------------------------------------------------= --------------- + * Address map + * -----------------------------------------------------------------------= -------------*/ +#define NEORV32_BOOTLOADER_BASE_ADDRESS (0xFFE00000U) +#define NEORV32_IO_BASE_ADDRESS (0xFFE00000U) + +#define NEORV32_IMEM_BASE (0x00000000U) +#define NEORV32_DMEM_BASE (0x80000000U) + +/* IO base addresses */ +#define NEORV32_TWD_BASE (0xFFEA0000U) +#define NEORV32_CFS_BASE (0xFFEB0000U) +#define NEORV32_SLINK_BASE (0xFFEC0000U) +#define NEORV32_DMA_BASE (0xFFED0000U) +#define NEORV32_CRC_BASE (0xFFEE0000U) +#define NEORV32_XIP_BASE (0xFFEF0000U) +#define NEORV32_PWM_BASE (0xFFF00000U) +#define NEORV32_GPTMR_BASE (0xFFF10000U) +#define NEORV32_ONEWIRE_BASE (0xFFF20000U) +#define NEORV32_XIRQ_BASE (0xFFF30000U) +#define NEORV32_MTIME_BASE (0xFFF40000U) +#define NEORV32_UART0_BASE (0xFFF50000U) +#define NEORV32_UART1_BASE (0xFFF60000U) +#define NEORV32_SDI_BASE (0xFFF70000U) +#define NEORV32_SPI_BASE (0xFFF80000U) +#define NEORV32_TWI_BASE (0xFFF90000U) +#define NEORV32_TRNG_BASE (0xFFFA0000U) +#define NEORV32_WDT_BASE (0xFFFB0000U) +#define NEORV32_GPIO_BASE (0xFFFC0000U) +#define NEORV32_NEOLED_BASE (0xFFFD0000U) +#define NEORV32_SYSINFO_BASE (0xFFFE0000U) +#define NEORV32_DM_BASE (0xFFFF0000U) + +/* MMIO creator */ +void neorv32_sysinfo_create(MemoryRegion *address_space, hwaddr base); + +#endif //HW_NEORV32_SYSINFO_H diff --git a/hw/misc/neorv32_sysinfo_rtl.h b/hw/misc/neorv32_sysinfo_rtl.h new file mode 100644 index 0000000000..594e251c5b --- /dev/null +++ b/hw/misc/neorv32_sysinfo_rtl.h @@ -0,0 +1,134 @@ +// #######################################################################= ########################## +// # << NEORV32: neorv32_sysinfo.h - System Information Memory (SYSINFO) H= W Driver >> # +// # *********************************************************************= ************************ # +// # BSD 3-Clause License = # +// # = # +// # Copyright (c) 2023, Stephan Nolting. All rights reserved. = # +// # = # +// # Redistribution and use in source and binary forms, with or without mo= dification, are # +// # permitted provided that the following conditions are met: = # +// # = # +// # 1. Redistributions of source code must retain the above copyright not= ice, this list of # +// # conditions and the following disclaimer. = # +// # = # +// # 2. Redistributions in binary form must reproduce the above copyright = notice, this list of # +// # conditions and the following disclaimer in the documentation and/o= r other materials # +// # provided with the distribution. = # +// # = # +// # 3. Neither the name of the copyright holder nor the names of its cont= ributors may be used to # +// # endorse or promote products derived from this software without spe= cific prior written # +// # permission. = # +// # = # +// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "= AS IS" AND ANY EXPRESS # +// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR= RANTIES OF # +// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. = IN NO EVENT SHALL THE # +// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, = INCIDENTAL, SPECIAL, # +// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, P= ROCUREMENT OF SUBSTITUTE # +// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRU= PTION) HOWEVER CAUSED # +// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY= , OR TORT (INCLUDING # +// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SO= FTWARE, EVEN IF ADVISED # +// # OF THE POSSIBILITY OF SUCH DAMAGE. = # +// # *********************************************************************= ************************ # +// # The NEORV32 Processor - https://github.com/stnolting/neorv32 = (c) Stephan Nolting # +// #######################################################################= ########################## + + +/**********************************************************************//** + * @file neorv32_cfs.h + * @brief System Configuration Information Memory (SYSINFO) HW driver head= er file. + *************************************************************************= */ + +#ifndef neorv32_sysinfo_h +#define neorv32_sysinfo_h + +/**********************************************************************//** + * @name IO Device: System Configuration Information Memory (SYSINFO) + *************************************************************************= */ +/**@{*/ +/** SYSINFO module prototype - whole module is read-only */ +typedef volatile struct __attribute__((packed,aligned(4))) { + uint32_t CLK; /**< offset 0: Clock speed in Hz */ + const uint32_t MISC; /**< offset 4: Miscellaneous system configuration= s (#NEORV32_SYSINFO_MISC_enum) */ + const uint32_t SOC; /**< offset 8: SoC features (#NEORV32_SYSINFO_SOC= _enum) */ + const uint32_t CACHE; /**< offset 12: Cache configuration (#NEORV32_SYSI= NFO_CACHE_enum) */ +} neorv32_sysinfo_t; + +/** SYSINFO module hardware access (#neorv32_sysinfo_t) */ +#define NEORV32_SYSINFO ((neorv32_sysinfo_t*) (NEORV32_SYSINFO_BASE)) + +/** NEORV32_SYSINFO.MISC (r/-): Miscellaneous system configurations */ +enum NEORV32_SYSINFO_MISC_enum { + SYSINFO_MISC_IMEM_LSB =3D 0, /**< SYSINFO_MISC (0) (r/-): log2(interna= l IMEM size in bytes) (via IMEM_SIZE generic), LSB */ + SYSINFO_MISC_IMEM_MBS =3D 7, /**< SYSINFO_MISC (7) (r/-): log2(interna= l IMEM size in bytes) (via IMEM_SIZE generic), MSB */ + + SYSINFO_MISC_DMEM_LSB =3D 8, /**< SYSINFO_MISC (8) (r/-): log2(interna= l DMEM size in bytes) (via DMEM_SIZE generic), LSB */ + SYSINFO_MISC_DMEM_MSB =3D 15, /**< SYSINFO_MISC (15) (r/-): log2(interna= l DMEM size in bytes) (via DMEM_SIZE generic), MSB */ + + SYSINFO_MISC_HART_LSB =3D 16, /**< SYSINFO_MISC (16) (r/-): number of ph= ysical CPU cores ("harts"), LSB */ + SYSINFO_MISC_HART_MSB =3D 19, /**< SYSINFO_MISC (19) (r/-): number of ph= ysical CPU cores ("harts"), MSB */ + + SYSINFO_MISC_BOOT_LSB =3D 20, /**< SYSINFO_MISC (20) (r/-): boot mode co= nfiguration (via BOOT_MODE_SELECT generic), LSB */ + SYSINFO_MISC_BOOT_MSB =3D 21, /**< SYSINFO_MISC (21) (r/-): boot mode co= nfiguration (via BOOT_MODE_SELECT generic), MSB */ + + SYSINFO_MISC_ITMO_LSB =3D 22, /**< SYSINFO_MISC (22) (r/-): log2(interna= l bus timeout cycles), LSB */ + SYSINFO_MISC_ITMO_MSB =3D 26, /**< SYSINFO_MISC (26) (r/-): log2(interna= l bus timeout cycles), MSB */ + + SYSINFO_MISC_ETMO_LSB =3D 27, /**< SYSINFO_MISC (27) (r/-): log2(externa= l bus timeout cycles), LSB */ + SYSINFO_MISC_ETMO_MSB =3D 31 /**< SYSINFO_MISC (31) (r/-): log2(externa= l bus timeout cycles), MSB */ +}; + +/** NEORV32_SYSINFO.SOC (r/-): Implemented processor devices/features */ +enum NEORV32_SYSINFO_SOC_enum { + SYSINFO_SOC_BOOTLOADER =3D 0, /**< SYSINFO_SOC (0) (r/-): Bootloader i= mplemented when 1 (via BOOT_MODE_SELECT generic) */ + SYSINFO_SOC_XBUS =3D 1, /**< SYSINFO_SOC (1) (r/-): External bus= interface implemented when 1 (via XBUS_EN generic) */ + SYSINFO_SOC_IMEM =3D 2, /**< SYSINFO_SOC (2) (r/-): Processor-in= ternal instruction memory implemented when 1 (via IMEM_EN generic) */ + SYSINFO_SOC_DMEM =3D 3, /**< SYSINFO_SOC (3) (r/-): Processor-in= ternal data memory implemented when 1 (via DMEM_EN generic) */ + SYSINFO_SOC_OCD =3D 4, /**< SYSINFO_SOC (4) (r/-): On-chip debu= gger implemented when 1 (via OCD_EN generic) */ + SYSINFO_SOC_ICACHE =3D 5, /**< SYSINFO_SOC (5) (r/-): Processor-in= ternal instruction cache implemented when 1 (via ICACHE_EN generic) */ + SYSINFO_SOC_DCACHE =3D 6, /**< SYSINFO_SOC (6) (r/-): Processor-in= ternal instruction cache implemented when 1 (via DCACHE_EN generic) */ +//SYSINFO_SOC_reserved =3D 7, /**< SYSINFO_SOC (7) (r/-): reserved */ +//SYSINFO_SOC_reserved =3D 8, /**< SYSINFO_SOC (8) (r/-): reserved */ +//SYSINFO_SOC_reserved =3D 9, /**< SYSINFO_SOC (9) (r/-): reserved */ +//SYSINFO_SOC_reserved =3D 10, /**< SYSINFO_SOC (10) (r/-): reserved */ + SYSINFO_SOC_OCD_AUTH =3D 11, /**< SYSINFO_SOC (11) (r/-): On-chip debu= gger authentication implemented when 1 (via OCD_AUTHENTICATION generic) */ + SYSINFO_SOC_IMEM_ROM =3D 12, /**< SYSINFO_SOC (12) (r/-): Processor-in= ternal instruction memory implemented as pre-initialized ROM when 1 (via BO= OT_MODE_SELECT generic) */ + SYSINFO_SOC_IO_TWD =3D 13, /**< SYSINFO_SOC (13) (r/-): Two-wire dev= ice implemented when 1 (via IO_TWD_EN generic) */ + SYSINFO_SOC_IO_DMA =3D 14, /**< SYSINFO_SOC (14) (r/-): Direct memor= y access controller implemented when 1 (via IO_DMA_EN generic) */ + SYSINFO_SOC_IO_GPIO =3D 15, /**< SYSINFO_SOC (15) (r/-): General purp= ose input/output port unit implemented when 1 (via IO_GPIO_EN generic) */ + SYSINFO_SOC_IO_CLINT =3D 16, /**< SYSINFO_SOC (16) (r/-): Core local i= nterruptor implemented when 1 (via IO_CLINT_EN generic) */ + SYSINFO_SOC_IO_UART0 =3D 17, /**< SYSINFO_SOC (17) (r/-): Primary univ= ersal asynchronous receiver/transmitter 0 implemented when 1 (via IO_UART0_= EN generic) */ + SYSINFO_SOC_IO_SPI =3D 18, /**< SYSINFO_SOC (18) (r/-): Serial perip= heral interface implemented when 1 (via IO_SPI_EN generic) */ + SYSINFO_SOC_IO_TWI =3D 19, /**< SYSINFO_SOC (19) (r/-): Two-wire int= erface implemented when 1 (via IO_TWI_EN generic) */ + SYSINFO_SOC_IO_PWM =3D 20, /**< SYSINFO_SOC (20) (r/-): Pulse-width = modulation unit implemented when 1 (via IO_PWM_EN generic) */ + SYSINFO_SOC_IO_WDT =3D 21, /**< SYSINFO_SOC (21) (r/-): Watchdog tim= er implemented when 1 (via IO_WDT_EN generic) */ + SYSINFO_SOC_IO_CFS =3D 22, /**< SYSINFO_SOC (22) (r/-): Custom funct= ions subsystem implemented when 1 (via IO_CFS_EN generic) */ + SYSINFO_SOC_IO_TRNG =3D 23, /**< SYSINFO_SOC (23) (r/-): True random = number generator implemented when 1 (via IO_TRNG_EN generic) */ + SYSINFO_SOC_IO_SDI =3D 24, /**< SYSINFO_SOC (24) (r/-): Serial data = interface implemented when 1 (via IO_SDI_EN generic) */ + SYSINFO_SOC_IO_UART1 =3D 25, /**< SYSINFO_SOC (25) (r/-): Secondary un= iversal asynchronous receiver/transmitter 1 implemented when 1 (via IO_UART= 1_EN generic) */ + SYSINFO_SOC_IO_NEOLED =3D 26, /**< SYSINFO_SOC (26) (r/-): NeoPixel-com= patible smart LED interface implemented when 1 (via IO_NEOLED_EN generic) */ + SYSINFO_SOC_IO_TRACER =3D 27, /**< SYSINFO_SOC (10) (r/-): Execution tr= acer implemented when 1 (via IO_TRACER_EN generic) */ + SYSINFO_SOC_IO_GPTMR =3D 28, /**< SYSINFO_SOC (28) (r/-): General purp= ose timer implemented when 1 (via IO_GPTMR_EN generic) */ + SYSINFO_SOC_IO_SLINK =3D 29, /**< SYSINFO_SOC (29) (r/-): Stream link = interface implemented when 1 (via IO_SLINK_EN generic) */ + SYSINFO_SOC_IO_ONEWIRE =3D 30 /**< SYSINFO_SOC (30) (r/-): 1-wire inter= face controller implemented when 1 (via IO_ONEWIRE_EN generic) */ +//SYSINFO_SOC_reserved =3D 31 /**< SYSINFO_SOC (31) (r/-): reserved */ +}; + +/** NEORV32_SYSINFO.CACHE (r/-): Cache configuration */ + enum NEORV32_SYSINFO_CACHE_enum { + SYSINFO_CACHE_INST_BLOCK_SIZE_0 =3D 0, /**< SYSINFO_CACHE (0) (r/-): i= -cache: log2(Block size in bytes), bit 0 (via CACHE_BLOCK_SIZE generic) */ + SYSINFO_CACHE_INST_BLOCK_SIZE_3 =3D 3, /**< SYSINFO_CACHE (3) (r/-): i= -cache: log2(Block size in bytes), bit 3 (via CACHE_BLOCK_SIZE generic) */ + SYSINFO_CACHE_INST_NUM_BLOCKS_0 =3D 4, /**< SYSINFO_CACHE (4) (r/-): i= -cache: log2(Number of cache blocks), bit 0 (via ICACHE_NUM_BLOCKS generic)= */ + SYSINFO_CACHE_INST_NUM_BLOCKS_3 =3D 7, /**< SYSINFO_CACHE (7) (r/-): i= -cache: log2(Number of cache blocks), bit 3 (via ICACHE_NUM_BLOCKS generic)= */ + + SYSINFO_CACHE_DATA_BLOCK_SIZE_0 =3D 8, /**< SYSINFO_CACHE (8) (r/-): d= -cache: log2(Block size in bytes), bit 0 (via CACHE_BLOCK_SIZE generic) */ + SYSINFO_CACHE_DATA_BLOCK_SIZE_3 =3D 11, /**< SYSINFO_CACHE (11) (r/-): d= -cache: log2(Block size in bytes), bit 3 (via CACHE_BLOCK_SIZE generic) */ + SYSINFO_CACHE_DATA_NUM_BLOCKS_0 =3D 12, /**< SYSINFO_CACHE (12) (r/-): d= -cache: log2(Number of cache blocks), bit 0 (via DCACHE_NUM_BLOCKS generic)= */ + SYSINFO_CACHE_DATA_NUM_BLOCKS_3 =3D 15, /**< SYSINFO_CACHE (15) (r/-): d= -cache: log2(Number of cache blocks), bit 3 (via DCACHE_NUM_BLOCKS generic)= */ + + SYSINFO_CACHE_INST_BURSTS_EN =3D 16, /**< SYSINFO_CACHE (16) (r/-): i= -cache: issue burst transfers or cache update (via CACHE_BURSTS_EN generic)= */ + SYSINFO_CACHE_DATA_BURSTS_EN =3D 24 /**< SYSINFO_CACHE (14) (r/-): d= -cache: issue burst transfers or cache update (via CACHE_BURSTS_EN generic)= */ +}; +/**@}*/ + + +#endif // neorv32_sysinfo_h From nobody Fri Nov 14 19:47:10 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=1761559911; cv=none; d=zohomail.com; s=zohoarc; b=SfukNNYs27FlmAnqoOpeTrumTNtlbHF9hZOo5rVKNiOI1P/fVpqj+TZvL0GBU+ilhUyIBssbw4fA6vKchPM0cTLD6UUd/wURsjrAvTqlyVQTFbytOqnvX/ppy9eZ7YolokvxpQvJm+mEvYIUeC7jpywwE6wHiTaQgFVJFVUEV9I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761559911; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=yXm7iwl3TKbL+GRAZzq6sVDRy60d5/xKUnEl1wLLcuA=; b=H9F/w1lHMfTupNJD+VIlLgN8jSncfclsmLdpkPDtKIKIzCr1EWxa93b/0K7mDPWAUlA271F/02ruKIK/mLK9WatgDa11Hk48qOOskGH2UDTr5DZUQp/2OXXktB+ZfRmuEezrVTEIO7i6xl4MF5L1mBXXPm0K7Ex9gg8zuk/pXOM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 1761559911436755.0431706641684; Mon, 27 Oct 2025 03:11:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vDKAx-0001yl-H9; Mon, 27 Oct 2025 06:10:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vDKAr-0001wX-4T for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:10:02 -0400 Received: from mail-wm1-x32f.google.com ([2a00:1450:4864:20::32f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vDKAh-00040a-KM for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:10:00 -0400 Received: by mail-wm1-x32f.google.com with SMTP id 5b1f17b1804b1-4710683a644so36909165e9.0 for ; Mon, 27 Oct 2025 03:09:47 -0700 (PDT) Received: from DDesktop.local ([2a10:8012:d:eea4:f4de:376b:66b1:d7b5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-475dd494d5csm128625465e9.9.2025.10.27.03.09.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Oct 2025 03:09:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=videogpu-com.20230601.gappssmtp.com; s=20230601; t=1761559785; x=1762164585; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yXm7iwl3TKbL+GRAZzq6sVDRy60d5/xKUnEl1wLLcuA=; b=g+DTGvf4hS//qex/39/08XPrJMhcncczWvmnMIJg3F73JqaNT6b7aVeIa9lmhnCP2R a17sz+q1/bxFTVi0WALEGHKu+VZXuSjzANgvaSADrBZXEmgyUE9BsU/NUL5d+2mMk3zX 8qbZU28hm6BjdoHZqLVK4Yv6mJxdDS3E7IAT4v+u7TfraCHYHx81rbU54RL4FPoyXEuZ qD+MGEAjSlR8Z26wInk/1S/+GjRVfJTYMv/lJmyzc1AqUr5/CoBUbEuO7MLauvijWiQe WVcW08Rz56/HNkPW9CCsPMfaiL7JuHdHtkfi6Lkyo5ShZ2OIVoPfpVNvVbDdPZxtiiWm pTFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761559785; x=1762164585; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=yXm7iwl3TKbL+GRAZzq6sVDRy60d5/xKUnEl1wLLcuA=; b=vIsnhmb1ZUMc+JiVvWekAoFaNaeK9i0p3HWSpFhG7ORrScSyyT5yqgRzJ4Py1NDCtu nPxbEp+4lxIiIiZvmcWq60l6RgqK+t7aRpQ3/uFEC9sMFEB7tRQtYn6KPVGBFwgV/3O2 KENWEPF136Vg6cEEMpLtcc2w2JGfYVVD5rUbnYC+y01MObHCktPxWIVVVuRQsU9vx2WT JvK07yB8w/3ynGWegQE9ciDahI4yj7lrvYKNyDQVBzy0PJGgvIyNQD2zWtu+QjoojJpS i5/9VF+6UoQKGD3bVIQtQ9K5qxfM8d/dyV7rKK2RDFZmaFDn+8deWK5J2QSoMHXD1OEK jjFQ== X-Gm-Message-State: AOJu0YyouDGwxnwRsIeyNO5ifKSoIAe6o1gLkogoezxy6sZbc57UqOQD pwea0V+7PlPaG2aJ3+6OwAo5uxe7g8v5EJsepKCCP2Hpy174Q7ekDWFBeHIZNUZHEteHvFfRtMw l9RwSDss= X-Gm-Gg: ASbGncvAbhsN8AzN3uuaeY6GACfZnccrVi8sieSd4AsAJohJv28edu7Hrv7QaTlysjZ AuA/wAYCcadsXYS/8lg8w3RaXS42/a93W3mx9DrWKW4hbEconk4BI4r0o32naoYBpKcC8Ns9Wat HbVR5w/2Cj+D0J9g8v/mVZAZ44f/oXQ4a4jIYVuKjnLyTML7Qq1f4vPr/9fkaKE42AvNmeYQvoI qJWAEb/2ssx94odTdJQv4KcZKMkCdhnDsv82nuHYbmfnC/JlGMIr2TWFjAyX2672h4I7U4L8cWb ttL7a85YDnUbiCdJzINzVldRF0ihFTZPaz3LVyXxW+8GkwT9RHsCUJSUPk8v7K8aEllKIyalnsE +M2sxOkJkgoyC3rxogOsM3PgXllLcvL4/25UFFcJqHmHBwJs7LCw0qATj5mtBw3LQzoqNRnHbfl 4jSRNw X-Google-Smtp-Source: AGHT+IFp3vqcf7iD+4dG8cpkbQByduiIezN1acmsJ9YjPS+KBI4Zpc4qMTQNXjYszh5HeVf+LNFEWA== X-Received: by 2002:a05:600c:5296:b0:46f:b42e:e38f with SMTP id 5b1f17b1804b1-475d243b771mr91368775e9.19.1761559784755; Mon, 27 Oct 2025 03:09:44 -0700 (PDT) From: Michael Levit To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, philmd@linaro.org, pbonzini@redhat.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, liwei1518@gmail.com, smishash@gmail.com Subject: [PATCH v2 3/5] hw/char: add NEORV32 UART (CTRL/DATA, fifo, chardev) Date: Mon, 27 Oct 2025 12:09:36 +0200 Message-ID: <20251027100938.11822-4-michael@videogpu.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251027100938.11822-1-michael@videogpu.com> References: <20251027100938.11822-1-michael@videogpu.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2a00:1450:4864:20::32f; envelope-from=michael@videogpu.com; helo=mail-wm1-x32f.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @videogpu-com.20230601.gappssmtp.com) X-ZM-MESSAGEID: 1761559913450154100 Content-Type: text/plain; charset="utf-8" From: Michael Add NEORV32 UART device: CTRL/DATA registers, RX FIFO, TX to chardev.=20 Includes Kconfig/meson and public header. Signed-off-by: Michael Levit diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 020c0a84bb..1fd39c2b30 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -95,3 +95,6 @@ config IP_OCTAL_232 bool default y depends on IPACK + +config NEORV32_UART + bool diff --git a/hw/char/meson.build b/hw/char/meson.build index a9e1dc26c0..2f5bf827a7 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -31,6 +31,7 @@ system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_u= art.c')) system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_aux.c')) system_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c')) system_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c')) +system_ss.add(when: 'CONFIG_NEORV32_UART', if_true: files('neorv32_uart.c'= )) system_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c')) system_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_us= art.c')) system_ss.add(when: 'CONFIG_STM32L4X5_USART', if_true: files('stm32l4x5_us= art.c')) diff --git a/hw/char/neorv32_uart.c b/hw/char/neorv32_uart.c new file mode 100644 index 0000000000..b54ab54d6a --- /dev/null +++ b/hw/char/neorv32_uart.c @@ -0,0 +1,311 @@ +/* + * Neorv32-specific UART. + * + * Copyright (c) 2025 Michael Levit + * + * Author: + * Michael Levit + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * 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 "migration/vmstate.h" +#include "chardev/char.h" +#include "chardev/char-fe.h" +#include "hw/irq.h" +#include "hw/char/neorv32_uart.h" +#include "hw/qdev-properties-system.h" + +typedef volatile struct __attribute__((packed,aligned(4))) { + uint32_t CTRL; /**< offset 0: control register (#NEORV32_UART_CTRL_enum= ) */ + uint32_t DATA; /**< offset 4: data register (#NEORV32_UART_DATA_enum) = */ +} neorv32_uart_t; + +#define NEORV32_UART_IO_REGION_SIZE (32) + +static Property neorv32_uart_properties[] =3D { + DEFINE_PROP_CHR("chardev", Neorv32UARTState, chr), +}; + +enum { + NEORV32_UART_CTRL =3D 0, /**< offset 0: control register */ + NEORV32_UART_DATA =3D 4 /**< offset 4: data register */ +}; + +/** UART control register bits */ +enum NEORV32_UART_CTRL_enum { + UART_CTRL_EN =3D 0, /**< UART control register(0) (r/w): UA= RT global enable */ + UART_CTRL_SIM_MODE =3D 1, /**< UART control register(1) (r/w): Si= mulation output override enable */ + UART_CTRL_HWFC_EN =3D 2, /**< UART control register(2) (r/w): En= able RTS/CTS hardware flow-control */ + UART_CTRL_PRSC_LSB =3D 3, /**< UART control register(3) (r/w): cl= ock prescaler select, bit 0 (LSB) */ + UART_CTRL_PRSC_MSB =3D 5, /**< UART control register(5) (r/w): cl= ock prescaler select, bit 2 (MSB) */ + UART_CTRL_BAUD_LSB =3D 6, /**< UART control register(6) (r/w): BA= UD rate divisor, bit 0 (LSB) */ + UART_CTRL_BAUD_MSB =3D 15, /**< UART control register(15) (r/w): BA= UD rate divisor, bit 9 (MSB) */ + UART_CTRL_RX_NEMPTY =3D 16, /**< UART control register(16) (r/-): RX= FIFO not empty */ + UART_CTRL_RX_FULL =3D 17, /**< UART control register(17) (r/-): RX= FIFO full */ + UART_CTRL_TX_EMPTY =3D 18, /**< UART control register(18) (r/-): TX= FIFO empty */ + UART_CTRL_TX_NFULL =3D 19, /**< UART control register(19) (r/-): TX= FIFO not full */ + UART_CTRL_IRQ_RX_NEMPTY =3D 20, /**< UART control register(20) (r/w): Fi= re IRQ if RX FIFO not empty */ + UART_CTRL_IRQ_RX_FULL =3D 21, /**< UART control register(21) (r/w): Fi= re IRQ if RX FIFO full */ + UART_CTRL_IRQ_TX_EMPTY =3D 22, /**< UART control register(22) (r/w): Fi= re IRQ if TX FIFO empty */ + UART_CTRL_IRQ_TX_NFULL =3D 23, /**< UART control register(23) (r/w): Fi= re IRQ if TX FIFO not full */ + + UART_CTRL_RX_OVER =3D 30, /**< UART control register(30) (r/-): RX= FIFO overflow */ + UART_CTRL_TX_BUSY =3D 31 /**< UART control register(31) (r/-): Tr= ansmitter busy or TX FIFO not empty */ +}; + +/** bits */ +enum NEORV32_UART_DATA_enum { + UART_DATA_RTX_LSB =3D 0, /**< (r/w): UART rx/tx data, LSB */ + UART_DATA_RTX_MSB =3D 7, /**< (r/w): UART rx/tx data, MSB */ + + UART_DATA_RX_FIFO_SIZE_LSB =3D 8, /**< (r/-): log2(RX FIFO size), LSB */ + UART_DATA_RX_FIFO_SIZE_MSB =3D 11, /**< (r/-): log2(RX FIFO size), MSB */ + + UART_DATA_TX_FIFO_SIZE_LSB =3D 12, /**< (r/-): log2(RX FIFO size), LSB */ + UART_DATA_TX_FIFO_SIZE_MSB =3D 15, /**< (r/-): log2(RX FIFO size), MSB */ +}; +/**@}*/ + +static void neorv32_uart_update_irq(Neorv32UARTState *s) +{ + int cond =3D 0; + if ((s->ie & NEORV32_UART_IE_TXWM) || + ((s->ie & NEORV32_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 +neorv32_uart_read(void *opaque, hwaddr addr, unsigned int size) +{ + Neorv32UARTState *s =3D opaque; + unsigned char r; + + switch (addr) { + case NEORV32_UART_CTRL: + if (s->rx_fifo_len) { + s->CTRL |=3D (1 << UART_CTRL_RX_NEMPTY); /* set data available */ + } else { + s->CTRL &=3D ~(1 << UART_CTRL_RX_NEMPTY); /* clear data available */ + } + //TODO: assuming here TX is always avalable, fix it. + s->CTRL |=3D (1 << UART_CTRL_TX_NFULL); /* set TX not full */ + + return s->CTRL; + + case NEORV32_UART_DATA: + if (s->rx_fifo_len) { + r =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); + s->DATA =3D r; + + neorv32_uart_update_irq(s); /* TODO: check if need to call= */ + return r; + } + } + + + + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=3D0x%x\n", + __func__, (int)addr); + return 0; +} + + + +static void +neorv32_uart_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + + Neorv32UARTState *s =3D opaque; + uint32_t value =3D val64; + unsigned char ch =3D value; + + /* TODO: check if need to update data and control bits */ + switch (addr) { + case NEORV32_UART_CTRL: + s->CTRL =3D value; + /* TODO: check if need to call, depending on IRQ flags */ + /* neorv32_uart_update_irq(s); */ + return; + case NEORV32_UART_DATA: + s->DATA =3D value; + qemu_chr_fe_write(&s->chr, &ch, 1); + /* neorv32_uart_update_irq(s); TODO: check if need to call */ + return; + } + + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=3D0x%x v=3D0x%x\n", + __func__, (int)addr, (int)value); +} + +static const MemoryRegionOps neorv32_uart_ops =3D { + .read =3D neorv32_uart_read, + .write =3D neorv32_uart_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 4 + } +}; + +static void neorv32_uart_init(Object *obj) +{ + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + Neorv32UARTState *s =3D NEORV32_UART(obj); + + memory_region_init_io(&s->mmio, OBJECT(s), &neorv32_uart_ops, s, + TYPE_NEORV32_UART, NEORV32_UART_IO_REGION_SIZE); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); +} + + +static void neorv32_uart_rx(void *opaque, const uint8_t *buf, int size) +{ + Neorv32UARTState *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; + + neorv32_uart_update_irq(s); +} + +static int neorv32_uart_can_rx(void *opaque) +{ + Neorv32UARTState *s =3D opaque; + + return s->rx_fifo_len < sizeof(s->rx_fifo); +} + +static void neorv32_uart_event(void *opaque, QEMUChrEvent event) +{ +} + +static int neorv32_uart_be_change(void *opaque) +{ + Neorv32UARTState *s =3D opaque; + + qemu_chr_fe_set_handlers(&s->chr, neorv32_uart_can_rx, neorv32_uart_rx, + neorv32_uart_event, neorv32_uart_be_change, s, + NULL, true); + + return 0; +} + +static void neorv32_uart_realize(DeviceState *dev, Error **errp) +{ + Neorv32UARTState *s =3D NEORV32_UART(dev); + + qemu_chr_fe_set_handlers(&s->chr, neorv32_uart_can_rx, neorv32_uart_rx, + neorv32_uart_event, neorv32_uart_be_change, s, + NULL, true); + +} + +static const VMStateDescription vmstate_neorv32_uart =3D { + .name =3D TYPE_NEORV32_UART, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT8_ARRAY(rx_fifo, + Neorv32UARTState, + NEORV32_UART_RX_FIFO_SIZE), + VMSTATE_UINT8(rx_fifo_len, Neorv32UARTState), + VMSTATE_UINT32(ie, Neorv32UARTState), + VMSTATE_END_OF_LIST() + }, +}; + +static void neorv32_uart_reset_enter(Object *obj, ResetType type) +{ + Neorv32UARTState *s =3D NEORV32_UART(obj); + s->rx_fifo_len =3D 0; + s->ie =3D 0; +} + +static void neorv32_uart_reset_hold(Object *obj, ResetType type) +{ + Neorv32UARTState *s =3D NEORV32_UART(obj); + qemu_irq_lower(s->irq); +} + +static void neorv32_uart_class_init(ObjectClass *oc,const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + ResettableClass *rc =3D RESETTABLE_CLASS(oc); + + dc->realize =3D neorv32_uart_realize; + dc->vmsd =3D &vmstate_neorv32_uart; + rc->phases.enter =3D neorv32_uart_reset_enter; + rc->phases.hold =3D neorv32_uart_reset_hold; + device_class_set_props(dc, neorv32_uart_properties); + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); +} + +static const TypeInfo neorv32_uart_info =3D { + .name =3D TYPE_NEORV32_UART, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(Neorv32UARTState), + .instance_init =3D neorv32_uart_init, + .class_init =3D neorv32_uart_class_init, +}; + +static void neorv32_uart_register_types(void) +{ + type_register_static(&neorv32_uart_info); +} + +type_init(neorv32_uart_register_types) +/* + * Create UART device. + */ +Neorv32UARTState *neorv32_uart_create(MemoryRegion *address_space, + hwaddr base, + Chardev *chr) +{ + DeviceState *dev; + SysBusDevice *s; + bool succed=3D false; + + dev =3D qdev_new("riscv.neorv32.uart"); + + qdev_prop_set_chr(dev, "chardev", chr); + s =3D SYS_BUS_DEVICE(dev); + succed =3D sysbus_realize_and_unref(s, &error_fatal); + + if (succed) { + memory_region_add_subregion(address_space, base, + sysbus_mmio_get_region(s, 0)); + return NEORV32_UART(dev); + } else { + return NULL; + } +} //neorv32_uart_create diff --git a/include/hw/char/neorv32_uart.h b/include/hw/char/neorv32_uart.h new file mode 100644 index 0000000000..3651d4741f --- /dev/null +++ b/include/hw/char/neorv32_uart.h @@ -0,0 +1,68 @@ +/* + * Neorv32-specific UART. + * + * Copyright (c) 2025 Michael Levit + * + * Author: + * Michael Levit + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ + +#ifndef HW_NEORV32_UART_H +#define HW_NEORV32_UART_H + +#include "chardev/char-fe.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_NEORV32_UART "riscv.neorv32.uart" +OBJECT_DECLARE_SIMPLE_TYPE(Neorv32UARTState, NEORV32_UART) + +#define QEMU_UART_DATA_RX_FIFO_SIZE_LSB 8 /**256 < UART data register(8) = (r/-): log2(RX FIFO size), LSB */ +#define QEMU_UART_DATA_RX_FIFO_SIZE_MSB 11 /** 2048 < UART data register(= 11) (r/-): log2(RX FIFO size), MSB */ + +#define NEORV32_UART_RX_FIFO_SIZE 32 //in HW it is 2048 + 256 =3D _MSB += _LSB + +enum { + NEORV32_UART_IE_TXWM =3D 1, /* Transmit watermark interrupt enable = */ + NEORV32_UART_IE_RXWM =3D 2 /* Receive watermark interrupt enable */ +}; + +enum { + NEORV32_UART_IP_TXWM =3D 1, /* Transmit watermark interrupt pending= */ + NEORV32_UART_IP_RXWM =3D 2 /* Receive watermark interrupt pending = */ +}; + + + +struct Neorv32UARTState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + qemu_irq irq; + MemoryRegion mmio; + CharBackend chr; + uint8_t rx_fifo[NEORV32_UART_RX_FIFO_SIZE]; + uint8_t rx_fifo_len; + uint32_t ie; //interrupt enable + uint32_t CTRL; + uint32_t DATA; +}; + +Neorv32UARTState *neorv32_uart_create(MemoryRegion *address_space, hwaddr = base, + Chardev *chr); + +#endif //HW_NEORV32_UART_H From nobody Fri Nov 14 19:47:10 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=1761559909; cv=none; d=zohomail.com; s=zohoarc; b=Jk1EQ2Z3V4JZxfTpf8dBDBdViOuyErDWiG7jYfKSI3Xq0LzBcz9GukFa8ScYdM99A5OJbgz0fteuP202204cB3n8JOOvaHLdk0S3sPLOJHZURVkJMnEMCJaTIeBRQBEepIH5YNQ4NNYd/vyZXh4j0s48+mnGwR36WSVDx9dbnQU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761559909; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=n9Fst5UAwHIvj9ew1YZbzpjY9nHPpy4BfgEtp4Ahqt8=; b=VQgnTd/6E1pH0Au91j4ut6t1/tlaejMz+FtNuWG9n5jQGRjnyqoW6mX9lLl/O7wTH0c7aiQCDzBJPsirqecX3coi1p4Zl8Xkt6knTOQfS5cxMtsBWk1j2WSXucybeL9vEK0KyAF/1qlHLMlDnUihPt7mxmlr7SqsFEqNNwECeXU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 1761559909462839.9047408793247; Mon, 27 Oct 2025 03:11:49 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vDKB0-000200-6I; Mon, 27 Oct 2025 06:10:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vDKAy-0001zd-Dp for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:10:08 -0400 Received: from mail-wm1-x32f.google.com ([2a00:1450:4864:20::32f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vDKAi-00040g-Og for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:10:08 -0400 Received: by mail-wm1-x32f.google.com with SMTP id 5b1f17b1804b1-47106fc51faso57056565e9.0 for ; Mon, 27 Oct 2025 03:09:49 -0700 (PDT) Received: from DDesktop.local ([2a10:8012:d:eea4:f4de:376b:66b1:d7b5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-475dd494d5csm128625465e9.9.2025.10.27.03.09.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Oct 2025 03:09:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=videogpu-com.20230601.gappssmtp.com; s=20230601; t=1761559786; x=1762164586; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=n9Fst5UAwHIvj9ew1YZbzpjY9nHPpy4BfgEtp4Ahqt8=; b=joMiVHSIzbop/3XtbySDEG+z7lqfZFRtPIJsMFvXSJgZkZ9HGfDL/3RcmLF2ffpPYS Ov/zr/yvoXFLM9KRHDqj4V9EfyhtVu/HWqJj3IDb5Kq2lWKXPY/AGSmx5hhcJoF1+sDY iGp7GzMfMv2w4kWK5NkP+Jh2uoKW1PT0j9UmpVSd3AuXjw01OZZwlUH/Cdm3ZwUTkLE+ aTXWCMqD8tylQCJMUPCYtqcPgBvRD7hTKPi7brvN3dSwNSCXMiixvI0NBy6ILoAzzIf7 D8i1tS7wk3kbbbhIxcwPXqucrzyuVA60/V1NZmqTvEQ4kbHmBLUUdemTFn2Le3owXEQR RQ6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761559786; x=1762164586; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=n9Fst5UAwHIvj9ew1YZbzpjY9nHPpy4BfgEtp4Ahqt8=; b=jCr0WP3b0emqK9/2QVd2lKJ8wawNxH8BcOe4qjfsqDtL7GE2aVQFvnmK+dc622qeNZ xlWumqTQ3kJS4qt1gMaQRxpMuhlLwN3OkGpXFOS/XgrZQFwtZPFYRFz/gkumv7h/sxW+ L4OQ86jgNcbrIm/5arpBFhXDqY5s68vvp2/f++CdqvmnniYaQ1MNC8o0MybrRI8/pUjD qTIcU782ov98mXN12CSxz/e/YFvwzrblTah7jh5+IlG/Ut0C3pB0tZwxYpLmrFfFjxvl BCkpF2yHPfu9c4978K1KVwYu/VszC1JVyjD4maHknvEmj5PWfZ1OmBYdZGCJpnM8tveH Gvxw== X-Gm-Message-State: AOJu0YyIFxiI84WblEsbPEybQpqwLwz78/ibQ+lABCHTCMSDAXz1nzaM ko54vrsq3NXN0PreNflqjRjkvAaM0wrOn0EXG/L7WVh3G/uF5740hByAq2czdXlWrfCRmTuFaNQ cQN5isbE= X-Gm-Gg: ASbGnctTV1mzp2e6yjSExVjheOnmWIU4Zm63ikvW570BG3ESa/FdUdB0FS5fnMUHBA+ N6S1jS7jVBiMjCy25GMZ1K6eUVPZFRsLLg36qj/nN33rfgJvHrEPcPgxRB+SmOnk4pdx7Qm3rci GeCPAjWI3XqfbbO6xgTKXkcxOIlNuo97PUuwuyQ3VLgq2Q8cXJmuvbzqvPvbeSmKlUE1HY9O4Lb bYmxmd538pPMfCmp42t8/MSEXRbzzF/XNRxlQoT6xLifJR7K5/nVJPxPZ9eDX7xF6d080cj8GRT Hy5IDsFijOuT5QqkBfWuPF0soxyd3SBAXWPaS4BwemkKQQ/Fdh8X5+CuMys0m65RnZPBFpUDxYA UkR3dBNvGqmFXTqT7RY0pbumYh9KtboS40Ipe4iZLgdlPpIc/EikOiahJ46WZFUr6P+h0AA/dN5 mzgAPG X-Google-Smtp-Source: AGHT+IGWUBAnziyL1PgyGjvpj807hqqRNZ9Un/8PT21CAXjkL5hxDJ/Rre58A/m+sqiEmQ8dzoiJdw== X-Received: by 2002:a05:600c:6214:b0:475:dd59:d8d8 with SMTP id 5b1f17b1804b1-475dd59db1dmr75070735e9.8.1761559786133; Mon, 27 Oct 2025 03:09:46 -0700 (PDT) From: Michael Levit To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, philmd@linaro.org, pbonzini@redhat.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, liwei1518@gmail.com, smishash@gmail.com Subject: [PATCH v2 4/5] hw/ssi: add NEORV32 SPI controller (SSI master, CS command) Date: Mon, 27 Oct 2025 12:09:37 +0200 Message-ID: <20251027100938.11822-5-michael@videogpu.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251027100938.11822-1-michael@videogpu.com> References: <20251027100938.11822-1-michael@videogpu.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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=2a00:1450:4864:20::32f; envelope-from=michael@videogpu.com; helo=mail-wm1-x32f.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @videogpu-com.20230601.gappssmtp.com) X-ZM-MESSAGEID: 1761559913323158500 From: Michael Add NEORV32 SPI controller: CTRL/DATA, tiny TX/RX FIFOs, command-mode CS (a= ctive-low), SSI master bus, and helper to attach n25q flash when an MTD drive is provid= ed. Includes Kconfig/meson and public header. Signed-off-by: Michael Levit diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig index 1bd56463c1..5b1a03f3c4 100644 --- a/hw/ssi/Kconfig +++ b/hw/ssi/Kconfig @@ -32,3 +32,7 @@ config PNV_SPI config ALLWINNER_A10_SPI bool select SSI + +config NEORV32_SPI + bool + select SSI diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index 6afb1ea200..5139cc1ca0 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi= .c')) system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c')) system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c')) system_ss.add(when: 'CONFIG_PNV_SPI', if_true: files('pnv_spi.c')) +system_ss.add(when: 'CONFIG_NEORV32_SPI', if_true: files('neorv32_spi.c')) diff --git a/hw/ssi/neorv32_spi.c b/hw/ssi/neorv32_spi.c new file mode 100644 index 0000000000..43fb822f1a --- /dev/null +++ b/hw/ssi/neorv32_spi.c @@ -0,0 +1,504 @@ +/* + * QEMU implementation of the Neorv32 SPI block. + * + * Copyright (c) 2025 Michael Levit. + * + * Author: + * Michael Levit + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ + + +/* + * QEMU model of a NEORV32 SPI Controller + * + * This example is inspired by the SiFive SPI controller implementation sh= own + * previously and adapted to the NEORV32 SPI register interface and semant= ics. + * + * IMPORTANT: + * This code is an illustrative example. Adjust register addresses, IRQ lo= gic, + * FIFO sizes, and chip select configurations according to actual NEORV32 = SPI + * specifications. The following is based on the given register bits and a + * presumed memory map. Check the official NEORV32 documentation for the + * correct register definitions, addressing scheme, and functionality. + * + * The code simulates: + * - A single SPI control register (CTRL) and a data register (DATA). + * - TX and RX FIFOs for SPI transfers. + * - Basic SPI master logic (no advanced timing or prescaler logic shown). + * - Chip select lines and interrupts based on FIFO status. + * + * This code will: + * - Create a QEMU device "neorv32-spi" + * - Map it to a 0x1000 address space region + * - Provide a simple SPI master interface using QEMU=E2=80=99s ssi bus + * - Allow reading/writing CTRL and DATA registers + * - Simulate FIFO behavior and trigger IRQ lines + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/ssi/ssi.h" +#include "qemu/fifo8.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "trace/trace-root.h" +#include "qapi/error.h" +#include "hw/irq.h" +#include "hw/ssi/neorv32_spi.h" +#include "system/blockdev.h" + + + +/** SPI control register bits */ +enum NEORV32_SPI_CTRL_enum { + SPI_CTRL_EN =3D 0, /**< SPI control register(0) (r/w): SPI u= nit enable */ + SPI_CTRL_CPHA =3D 1, /**< SPI control register(1) (r/w): Clock= phase */ + SPI_CTRL_CPOL =3D 2, /**< SPI control register(2) (r/w): Clock= polarity */ + SPI_CTRL_PRSC0 =3D 3, /**< SPI control register(3) (r/w): Clock= prescaler select bit 0 */ + SPI_CTRL_PRSC1 =3D 4, /**< SPI control register(4) (r/w): Clock= prescaler select bit 1 */ + SPI_CTRL_PRSC2 =3D 5, /**< SPI control register(5) (r/w): Clock= prescaler select bit 2 */ + SPI_CTRL_CDIV0 =3D 6, /**< SPI control register(6) (r/w): Clock= divider bit 0 */ + SPI_CTRL_CDIV1 =3D 7, /**< SPI control register(7) (r/w): Clock= divider bit 1 */ + SPI_CTRL_CDIV2 =3D 8, /**< SPI control register(8) (r/w): Clock= divider bit 2 */ + SPI_CTRL_CDIV3 =3D 9, /**< SPI control register(9) (r/w): Clock= divider bit 3 */ + + SPI_CTRL_RX_AVAIL =3D 16, /**< SPI control register(16) (r/-): RX FI= FO data available (RX FIFO not empty) */ + SPI_CTRL_TX_EMPTY =3D 17, /**< SPI control register(17) (r/-): TX FI= FO empty */ + SPI_CTRL_TX_FULL =3D 18, /**< SPI control register(18) (r/-): TX FI= FO full */ + + SPI_CTRL_FIFO_LSB =3D 24, /**< SPI control register(24) (r/-): log2(= FIFO size), LSB */ + SPI_CTRL_FIFO_MSB =3D 27, /**< SPI control register(27) (r/-): log2(= FIFO size), MSB */ + + SPI_CS_ACTIVE =3D 30, /**< SPI control register(30) (r/-): At le= ast one CS line is active when set */ + SPI_CTRL_BUSY =3D 31 /**< SPI control register(31) (r/-): seria= l PHY busy or TX FIFO not empty yet */ +}; + +//TODO: +//Implement NEORV32_SPI_DATA_enum +/** SPI data register bits */ +enum NEORV32_SPI_DATA_enum { + SPI_DATA_LSB =3D 0, /**< SPI data register(0) (r/w): Data byte LSB */ + SPI_DATA_CSEN =3D 3, /**< SPI data register(3) (-/w): Chip select enab= le (command-mode) */ + SPI_DATA_MSB =3D 7, /**< SPI data register(7) (r/w): Data byte MSB */ + SPI_DATA_CMD =3D 31 /**< SPI data register(31) (-/w): 1=3Dcommand, 0= =3Ddata */ +}; + +/* Register offsets */ +#define NEORV32_SPI_CTRL 0x00 +#define NEORV32_SPI_DATA 0x04 +#define NEORV32_SPI_MMIO_SIZE 0x8 // ctrl + data (8 bytes total) +/* Various constants */ +#define NEORV32_SPI_MAX_CS_LINES 7 +#define NEORV32_SPI_FIFO_CAPACITY 8 + +/* Utility functions to get/set bits in ctrl register */ +static inline bool get_ctrl_bit(NEORV32SPIState *s, int bit) +{ + return (s->ctrl & (1 << bit)) !=3D 0; +} + +static inline void set_ctrl_bit(NEORV32SPIState *s, int bit, bool val) +{ + if (val) { + s->ctrl |=3D (1 << bit); + } else { + s->ctrl &=3D ~(1 << bit); + } +} + +static inline bool get_data_bit(uint32_t v, int bit) +{ + return (v >> bit) & 1; +} + +/* Update read-only status bits in CTRL register */ +static void neorv32_spi_update_status(NEORV32SPIState *s) +{ + /* RX_AVAIL: set if RX FIFO not empty */ + set_ctrl_bit(s, SPI_CTRL_RX_AVAIL, !fifo8_is_empty(&s->rx_fifo)); + + /* TX_EMPTY: set if TX FIFO empty */ + set_ctrl_bit(s, SPI_CTRL_TX_EMPTY, fifo8_is_empty(&s->tx_fifo)); + + /* TX_FULL: set if TX FIFO full */ + set_ctrl_bit(s, SPI_CTRL_TX_FULL, fifo8_is_full(&s->tx_fifo)); + + + /* BUSY: We'll consider SPI busy if TX FIFO is not empty or currently = shifting data. + * For simplicity, if TX is not empty we say busy. + */ + bool busy =3D !fifo8_is_empty(&s->tx_fifo); + set_ctrl_bit(s, SPI_CTRL_BUSY, busy); + + /* Update CS status */ + if (s->cmd_cs_active) { + s->ctrl |=3D (1u << SPI_CS_ACTIVE); + } else { + s->ctrl &=3D ~(1u << SPI_CS_ACTIVE); + } + +} + +/* Update chip select lines based on command-mode CS (active-low on the wi= re) */ +static void neorv32_spi_update_cs(NEORV32SPIState *s) +{ + /* Check that input valid */ + if (!s->cs_lines || s->num_cs <=3D 0) { + return; + } + + /* Deassert all CS lines (inactive =3D high) */ + for (int i =3D 0; i < s->num_cs; i++) { + qemu_set_irq(s->cs_lines[i], 1); + } + + /* If DATA command says CS active, assert selected line (low =3D activ= e) */ + if (s->cmd_cs_active) { + int cs_idx =3D s->current_cs; + if (cs_idx < 0 || cs_idx >=3D s->num_cs) { + /* Out of range: keep all deasserted, but warn once per event = */ + qemu_log_mask(LOG_GUEST_ERROR, "%s: CS index %d out of range (= num_cs=3D%d)\n", + __func__, cs_idx, s->num_cs); + return; + } + /* Active-low when enabled */ + qemu_set_irq(s->cs_lines[cs_idx], 0); + } + +} + +/* Update IRQ based on conditions */ +static void neorv32_spi_update_irq(NEORV32SPIState *s) +{ + /* Conditions for IRQ: + * IRQ if RX data available and IRQ_RX_AVAIL is set: + * if (!RX FIFO empty && SPI_CTRL_IRQ_RX_AVAIL set) + * + * IRQ if TX empty and IRQ_TX_EMPTY is set: + * if (TX empty && SPI_CTRL_IRQ_TX_EMPTY set) + * + * IRQ if TX < half full and IRQ_TX_HALF is set: + * if (TX < half full && SPI_CTRL_IRQ_TX_HALF set) + */ + + bool rx_irq =3D !fifo8_is_empty(&s->rx_fifo); + bool tx_empty_irq =3D fifo8_is_empty(&s->tx_fifo); + int used =3D fifo8_num_used(&s->tx_fifo); + bool tx_half_irq =3D (used < (s->fifo_capacity / 2)); + + bool irq_level =3D rx_irq || tx_empty_irq || tx_half_irq; + qemu_set_irq(s->irq, irq_level ? 1 : 0); +} + +/* Flush the TX FIFO to the SPI bus: + * For each byte in TX FIFO, send it out via ssi_transfer. + * If direction is not explicitly given, we assume: + * - On write to DATA, we push to TX FIFO and then transfer out. + * - On receiving data back from ssi_transfer, we push it into RX FIFO + * if SPI is enabled. + */ +static void neorv32_spi_flush_txfifo(NEORV32SPIState *s) +{ + if (!get_ctrl_bit(s, SPI_CTRL_EN)) { + /* SPI not enabled, do nothing */ + return; + } + + while (!fifo8_is_empty(&s->tx_fifo)) { + uint8_t tx =3D fifo8_pop(&s->tx_fifo); + uint8_t rx =3D ssi_transfer(s->bus, tx); + + /* Push received byte into RX FIFO if not full */ + if (!fifo8_is_full(&s->rx_fifo)) { + fifo8_push(&s->rx_fifo, rx); + } + } +} + +/* Reset the device state */ +static void neorv32_spi_reset(DeviceState *d) +{ + NEORV32SPIState *s =3D NEORV32_SPI(d); + + s->ctrl =3D 0; + s->data =3D 0; + + /* Reset FIFOs */ + fifo8_reset(&s->tx_fifo); + fifo8_reset(&s->rx_fifo); + + neorv32_spi_update_status(s); + neorv32_spi_update_cs(s); + neorv32_spi_update_irq(s); +} + +/* MMIO read handler */ +static uint64_t neorv32_spi_read(void *opaque, hwaddr addr, unsigned int s= ize) +{ + NEORV32SPIState *s =3D opaque; + uint32_t r =3D 0; + + switch (addr) { + case NEORV32_SPI_CTRL: + /* Return the current CTRL register value (including status bits) = */ + neorv32_spi_update_status(s); + r =3D s->ctrl; + break; + + case NEORV32_SPI_DATA: + /* If RX FIFO is empty, return some default, else pop from RX FIFO= */ + if (fifo8_is_empty(&s->rx_fifo)) { + /* No data available, could return 0xFFFFFFFF or 0x00000000 as= "no data" */ + r =3D 0x00000000; + } else { + r =3D fifo8_pop(&s->rx_fifo); + } + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read at address 0x%" + HWADDR_PRIx "\n", __func__, addr); + break; + } + + neorv32_spi_update_status(s); + neorv32_spi_update_irq(s); + + return r; +} + +/* MMIO write handler */ +static void neorv32_spi_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + NEORV32SPIState *s =3D opaque; + uint32_t value =3D val64; + + switch (addr) { + case NEORV32_SPI_CTRL: { + + /* Writing control register: + * Some bits are read-only (e.g., status bits). + * We should mask them out or ignore writes to them. + * For simplicity, we overwrite ctrl except for RO bits. + */ + + /* Save old RO bits: RX_AVAIL, TX_EMPTY, TX_NHALF, TX_FULL, BUSY a= nd FIFO size bits */ + uint32_t ro_mask =3D ((1 << SPI_CTRL_BUSY) | + (1 << SPI_CTRL_TX_EMPTY) | + (1 << SPI_CTRL_TX_FULL) | + (1 << SPI_CTRL_RX_AVAIL)); + + /* FIFO size bits might be hardwired read-only. Assume we do not c= hange them: + * FIFO size: bits [SPI_CTRL_FIFO_LSB..SPI_CTRL_FIFO_MSB], here as= sume read-only. + */ + uint32_t fifo_size_mask =3D 0; + for (int b =3D SPI_CTRL_FIFO_LSB; b <=3D SPI_CTRL_FIFO_MSB; b++) { + fifo_size_mask |=3D (1 << b); + } + ro_mask |=3D fifo_size_mask; + + uint32_t ro_bits =3D s->ctrl & ro_mask; + s->ctrl =3D (value & ~ro_mask) | ro_bits; + + neorv32_spi_update_cs(s); + break; + } //NEORV32_SPI_CTRL + + case NEORV32_SPI_DATA: + { + /* If CMD=3D1, this write is a command, not payload */ + const bool is_cmd =3D get_data_bit(value, SPI_DATA_CMD); + + if (is_cmd) { + /* DATA command format: + * bit 31: CMD =3D 1 + * bit 3: CSEN (1=3Dassert CS, 0=3Ddeassert All) + * bits [2:0]: CS index (0..7) when asserting + */ + const bool csen =3D get_data_bit(value, SPI_DATA_CSEN); + const int cs_index =3D (int)(value & 0x7); + + if (csen) { + /* Select and assert a single CS */ + s->current_cs =3D cs_index; /* range checking in update_c= s() */ + s->cmd_cs_active =3D true; + } else { + /* Deassert all CS lines */ + s->cmd_cs_active =3D false; + } + + /* Drive the wires */ + neorv32_spi_update_cs(s); + /* Update status (SPI_CS_ACTIVE is read-only status bit) */ + neorv32_spi_update_status(s); + neorv32_spi_update_irq(s); + break; /* no FIFO push on command */ + } + + /* Writing DATA puts a byte into TX FIFO if not full */ + if (!fifo8_is_full(&s->tx_fifo)) { + uint8_t tx_byte =3D (uint8_t)value; + + fifo8_push(&s->tx_fifo, tx_byte); + /* After pushing data, flush TX to SPI bus */ + neorv32_spi_flush_txfifo(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: TX FIFO full, cannot write 0x%x\n", + __func__, value); + } + break; + } //NEORV32_SPI_DATA + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write at address 0x%" + HWADDR_PRIx " value=3D0x%x\n", __func__, addr, value= ); + break; + + } //switch (addr) + + neorv32_spi_update_status(s); + neorv32_spi_update_irq(s); +} //neorv32_spi_write + +static const MemoryRegionOps neorv32_spi_ops =3D { + .read =3D neorv32_spi_read, + .write =3D neorv32_spi_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, +}; + +static void neorv32_spi_init(Object *obj) +{ + NEORV32SPIState *s =3D NEORV32_SPI(obj); + s->ctrl =3D 0; + s->data =3D 0; + s->fifo_capacity =3D NEORV32_SPI_FIFO_CAPACITY; + s->num_cs =3D NEORV32_SPI_MAX_CS_LINES; /* Default to 1 CS line= */ + s->cmd_cs_active =3D false; + s->current_cs =3D 0; /* Use CS0 by default */ +} + +/* Realize the device */ +static void neorv32_spi_realize(DeviceState *dev, Error **errp) +{ + NEORV32SPIState *s =3D NEORV32_SPI(dev); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(dev); + + /* Create the SSI master bus */ + s->bus =3D ssi_create_bus(dev, "neorv32-spi-bus"); + + /* 1) IRQ inputs: first the main IRQ, then each CS line */ + sysbus_init_irq(sbd, &s->irq); + s->cs_lines =3D g_new0(qemu_irq, s->num_cs); + for (int i =3D 0; i < s->num_cs; i++) { + sysbus_init_irq(sbd, &s->cs_lines[i]); + qemu_set_irq(s->cs_lines[i], 1); /* deassert CS (high) */ + } + + /* 2) Now map the MMIO region */ + memory_region_init_io(&s->mmio, OBJECT(s), &neorv32_spi_ops, s, + TYPE_NEORV32_SPI, NEORV32_SPI_MMIO_SIZE); + sysbus_init_mmio(sbd, &s->mmio); + + + /* Initialize FIFOs */ + fifo8_create(&s->tx_fifo, s->fifo_capacity); + fifo8_create(&s->rx_fifo, s->fifo_capacity); + + /* Set FIFO size bits (log2 of FIFO size =3D 3 for capacity=3D8) */ + /* FIFO size bits: from SPI_CTRL_FIFO_LSB to SPI_CTRL_FIFO_MSB + * We'll store a value of 3 (log2(8)=3D3) + */ + int fifo_size_log2 =3D 3; + for (int b =3D SPI_CTRL_FIFO_LSB; b <=3D SPI_CTRL_FIFO_MSB; b++) { + int shift =3D b - SPI_CTRL_FIFO_LSB; + if (fifo_size_log2 & (1 << shift)) { + s->ctrl |=3D (1 << b); + } else { + s->ctrl &=3D ~(1 << b); + } + } +} + +/* Device properties can be added if needed. For now, none. */ +static Property neorv32_spi_properties[] =3D { + DEFINE_PROP_UINT32("num-cs", NEORV32SPIState, num_cs, 1), +}; + +static void neorv32_spi_class_init(ObjectClass *klass,const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + device_class_set_props(dc, neorv32_spi_properties); + device_class_set_legacy_reset(dc, neorv32_spi_reset); + dc->realize =3D neorv32_spi_realize; +} + +static const TypeInfo neorv32_spi_type_info =3D { + .name =3D TYPE_NEORV32_SPI, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(NEORV32SPIState), + .instance_init =3D neorv32_spi_init, + .class_init =3D neorv32_spi_class_init, +}; + +static void neorv32_spi_register_types(void) +{ + type_register_static(&neorv32_spi_type_info); +} + +type_init(neorv32_spi_register_types) + + + +NEORV32SPIState *neorv32_spi_create(MemoryRegion *sys_mem, hwaddr base_add= r) +{ + /* Allocate and initialize the SPI state object */ + NEORV32SPIState *s =3D g_new0(NEORV32SPIState, 1); + object_initialize(&s->parent_obj, sizeof(*s), TYPE_NEORV32_SPI); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(&s->parent_obj); + + /* Realize the SPI controller (sets up mmio, irq, SSI bus, cs_lines) */ + sysbus_realize_and_unref(sbd, &error_fatal); + + /* Map the MMIO region into the system address space */ + sysbus_mmio_map(sbd, 0, base_addr); + + /* Attach an SPI flash to SPI0 if a drive image is provided */ + DriveInfo *dinfo =3D drive_get(IF_MTD, 0, 0); + if (dinfo) { + /* Create the flash device and bind the MTD backend */ + DeviceState *flash =3D qdev_new("n25q512a11"); + qdev_prop_set_drive_err(flash, "drive", + blk_by_legacy_dinfo(dinfo), + &error_fatal); + + /* Realize flash on the same SSI bus created during controller rea= lize */ + qdev_realize_and_unref(flash, BUS(s->bus), &error_fatal); + + /* Retrieve and wire the flash's CS input line to CS0 output */ + qemu_irq flash_cs =3D qdev_get_gpio_in_named(flash, SSI_GPIO_CS, 0= ); + sysbus_connect_irq(sbd, 1, flash_cs); + } + + return s; +} + diff --git a/include/hw/ssi/neorv32_spi.h b/include/hw/ssi/neorv32_spi.h new file mode 100644 index 0000000000..525bacf2d3 --- /dev/null +++ b/include/hw/ssi/neorv32_spi.h @@ -0,0 +1,70 @@ +/* + * QEMU implementation of the Neorv32 SPI block. + * + * Copyright (c) 2025 Michael Levit. + * + * Author: + * Michael Levit + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ + +#ifndef NEORV32_SPI_H +#define NEORV32_SPI_H + +#include "qemu/osdep.h" +#include "hw/sysbus.h" + +#define TYPE_NEORV32_SPI "neorv32.spi" +#define NEORV32_SPI(obj) OBJECT_CHECK(NEORV32SPIState, (obj), TYPE_NEORV32= _SPI) + +typedef struct NEORV32SPIState { + SysBusDevice parent_obj; + + /* Memory-mapped registers */ + MemoryRegion mmio; + + /* IRQ line */ + qemu_irq irq; + + /* SPI bus (master) */ + SSIBus *bus; + + /* Chip selects (assume up to 3 CS lines) */ + qemu_irq *cs_lines; + uint32_t num_cs; + + /* Registers: + * Assume: + * 0x00: CTRL (r/w) + * 0x04: DATA (r/w) + */ + uint32_t ctrl; + uint32_t data; + + /* FIFOs */ + Fifo8 tx_fifo; + Fifo8 rx_fifo; + + /* FIFO capacity */ + int fifo_capacity; + /* Track CS state driven by command writes */ + bool cmd_cs_active; /* true =3D CS asserted (active-low on wire) */ + int current_cs; /* which CS line is active; default 0 for now */ +} NEORV32SPIState; + + + +NEORV32SPIState *neorv32_spi_create(MemoryRegion *sys_mem, hwaddr base_add= r); + +#endif /* NEORV32_SPI_H */ From nobody Fri Nov 14 19:47:10 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=1761559879; cv=none; d=zohomail.com; s=zohoarc; b=NpFiQNkO+fZ+I3FRFOW3/TR0d/DQNvFVDjnn9BU2u2njweNdTKqhE0pgA5WWyl8T6cC/6lklmhzbEVS77KuZxmB21QQgeVtbDQgsKKDELRJ8PBvDRjpH2/+/LwEI+Js3TTWh2tPGGfjzhH2x8QD9DLg2opCkSKkH868DUPO5028= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761559879; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=5PQdbl4UZGW83YAi5bz1Jc0F7Lg5yFncpHLv97b9pZ4=; b=CZW23gDZ4nisqDsnvmSrSBGIiu4WSSPdR8wcSiYgATviogdUVNIe6BTmKLS5yte01RTVdMcmeFJAf2RRLEB086sBpqy9HElKj0a+ZBv6OTab+YjRwPicFkR3cxQNbcicS3rKmCpVAJoRV1t9V2kkYAwoQbbcA2zmwqw1zGnqIN0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 1761559879860704.2494073064713; Mon, 27 Oct 2025 03:11:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vDKAy-0001zj-J1; Mon, 27 Oct 2025 06:10:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vDKAt-0001xv-TB for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:10:03 -0400 Received: from mail-wm1-x32c.google.com ([2a00:1450:4864:20::32c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vDKAj-00040s-9v for qemu-devel@nongnu.org; Mon, 27 Oct 2025 06:10:03 -0400 Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-475dbc3c9efso13839815e9.0 for ; Mon, 27 Oct 2025 03:09:50 -0700 (PDT) Received: from DDesktop.local ([2a10:8012:d:eea4:f4de:376b:66b1:d7b5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-475dd494d5csm128625465e9.9.2025.10.27.03.09.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Oct 2025 03:09:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=videogpu-com.20230601.gappssmtp.com; s=20230601; t=1761559788; x=1762164588; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=5PQdbl4UZGW83YAi5bz1Jc0F7Lg5yFncpHLv97b9pZ4=; b=Kk8u3P8Pu7sQaBejEVYBzE94S3gKHNTOf40G5E/jrP++FNven/Oe7rUZPJsYzvoJ7Q NwUmaMom0rSzABuhxuV+1G2CY3WlvbhjaqsJnugzEmp5eOBRBqgy0JjMav/WYl7JDqtv 6gxpiy45e0O8W9Ma9Y/6JUURS+6G1uFVrmJlYmEyYtZGjdOi17Fw8GkBMjhpe50O+b7Z LvNzkWxJA8QdF7gOrs+6+h467QCI7a6OnFmOkZZqndPmZPMx/IhW5IzP8EHM+YNMGe5H OY0tiEYpwXN8z1oRjSTx2+n2kSkuZjUNcmmF3mYtaxMPHimiZc2jshneUhy9Ye0NUImV vp4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1761559788; x=1762164588; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=5PQdbl4UZGW83YAi5bz1Jc0F7Lg5yFncpHLv97b9pZ4=; b=V0rlj+kiLAvXqFVKSdFLb6EjCGHO4f0iAlWPQnKT06t87uR2nbARg6BjWRam5rY5er WkjdoxnOjvDb9IGZ6xWqsTOEncTx5LUfL91tRvUqFSkH8xs9XibGtz4G+nI/9YYzetCa XD/meF6WuTAUVK9cnvhkNmYHuX7qhnMGDyOqzWtlJ+prIh5zvVA2gBztXrousfdG8qr/ Tn0fX1zvjhNJnW9OJGpZPB2u+1OIWOp4VWs8RtDv1s1p0mmfKjZp8u9Vp7nUiLMMJvGR 4FuhkRRxrr74RaifSO9Dn0Iqu51/7MJTfO+vKkuEIRx30IGP5ZTJCYJ5FDGHzgzeVlhK FS7A== X-Gm-Message-State: AOJu0YwTiswXnw4RIpPHoCfFcIDnjElloLxNeWb65Q15Qe2gOCu9NAYh vDEO6+L7SgkEi/X1lEQYm+hlRNeb8xgD7Ul7bgMsGDyCZCKNPJJdtBl1XAalk0dnTUgpHA8EUm1 1GljNlAA= X-Gm-Gg: ASbGncviU44avqdBrqX7voQlc4qevv23hCq6IUnB7uQfhGdT0KmkEWfT8ciBiTXMq99 LBS5kQBuNCIcFHmeE6nQZb6NY2M4cTSuOiqEPtC7YqgHvDrbMlvItFgLdOmZ0A9qpYFC01F2Fwu G8uEZZNeheNWDbYX8swfLypY+6LSWNOPbO6IRWxsBodgkCh4PJZFbXFo7viv7dVq1qbCKTO/p9G lb70f218Hc2I8b4K2KmyJyk3bQwWejB4be5zSX18y20x9/qwnipKSj9/7jDhX45B0KL3jTp/ZW8 y2kKz4d+PBWKqwIDT0bM/i4QsOddrS/cWzu4g0jgaEGzvQkUDqjopoctg8gJ1JMtlvJFKoerTCu T2WxKoSbsM6v3yhuDvdXMTU0Xz5F5OiPILvh0JYFKH55zJbOqzdIYCh9NGymxjruJdCoepCVjfd dSE02b X-Google-Smtp-Source: AGHT+IHJUQhP81mHp17CIs+lp86iMQ52WhoBsunAEQHn0/BQQbn156xfXbaH8+w6cQN88pqvAM3Xpg== X-Received: by 2002:a05:600c:1f93:b0:46f:b42e:e367 with SMTP id 5b1f17b1804b1-4711792a527mr270231655e9.41.1761559787630; Mon, 27 Oct 2025 03:09:47 -0700 (PDT) From: Michael Levit To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, philmd@linaro.org, pbonzini@redhat.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, liwei1518@gmail.com, smishash@gmail.com Subject: [PATCH v2 5/5] hw/riscv: introduce 'neorv32' board, docs, and riscv32 device config Date: Mon, 27 Oct 2025 12:09:38 +0200 Message-ID: <20251027100938.11822-6-michael@videogpu.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251027100938.11822-1-michael@videogpu.com> References: <20251027100938.11822-1-michael@videogpu.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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=2a00:1450:4864:20::32c; envelope-from=michael@videogpu.com; helo=mail-wm1-x32c.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @videogpu-com.20230601.gappssmtp.com) X-ZM-MESSAGEID: 1761559881556154100 From: Michael Introduce the 'neorv32' board wiring IMEM/DMEM/BOOTROM, SYSINFO, UART0, and= SPI0; add docs/system/riscv/neorv32.rst and riscv32-softmmu device config entry. Signed-off-by: Michael Levit diff --git a/configs/devices/riscv32-softmmu/default.mak b/configs/devices/= riscv32-softmmu/default.mak index c2cd86ce05..4fdc94ab48 100644 --- a/configs/devices/riscv32-softmmu/default.mak +++ b/configs/devices/riscv32-softmmu/default.mak @@ -10,3 +10,4 @@ # CONFIG_SIFIVE_U=3Dn # CONFIG_RISCV_VIRT=3Dn # CONFIG_OPENTITAN=3Dn +# CONFIG_NEORV32=3Dn diff --git a/docs/system/riscv/neorv32.rst b/docs/system/riscv/neorv32.rst new file mode 100644 index 0000000000..7f9048a7ad --- /dev/null +++ b/docs/system/riscv/neorv32.rst @@ -0,0 +1,110 @@ + +NEORV32 Soft SoC (``neorv32``) +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D + +The ``neorv32`` machine models a minimal NEORV32-based SoC sufficient to +exercise the stock NEORV32 bootloader and run example applications from an +emulated SPI NOR flash. It exposes a UART for console I/O and an MTD-backed +SPI flash device that can be populated with user binaries. + +Neorv32 full repo: +https://github.com/stnolting/neorv32 + +Current QEMU implementation base on commit 7d0ef6b2 in Neorv32 repo. + +Supported devices +----------------- + +The ``neorv32`` machine provides the core peripherals needed by the +bootloader and examples: + +* UART for console (mapped to the QEMU stdio when ``-nographic`` or + ``-serial stdio`` is used). +* SPI controller connected to an emulated SPI NOR flash (exposed to the + guest via QEMU's ``if=3Dmtd`` backend). +* Basic timer/CLINT-like facilities required by the example software. + +(Exact register maps and optional peripherals depend on the QEMU version a= nd +the specific patch series you are using.) + + +QEMU build configuration: +------------------------ +/path/to/qemu/configure \ + --python=3D/usr/local/bin/python3.12 \ + --target-list=3Driscv32-softmmu \ + --enable-fdt \ + --enable-debug \ + --disable-vnc \ + --disable-gtk + +Boot options +------------ + +Typical usage is to boot the NEORV32 bootloader as the QEMU ``-bios`` imag= e, +and to provide a raw SPI flash image via an MTD drive. The bootloader will +then jump to the application image placed at the configured flash offset. + +Preparing the SPI flash with a =E2=80=9CHello World=E2=80=9D example +---------------------------------------------------- + +1. Create a 64 MiB flash image (filled with zeros):: + + $ dd if=3D/dev/zero of=3D$HOME/flash_contents.bin bs=3D1 count=3D$((0x0= 4000000)) + +2. Place your application binary at the **4 MiB** offset inside the flash. + Replace ``/path/to/neorv32_exe.bin`` with the path to your compiled + example application (e.g., the NEORV32 ``hello_world`` example):: + + $ dd if=3D/path/to/neorv32_exe.bin of=3D$HOME/flash_contents.bin \ + bs=3D1 seek=3D$((0x00400000)) conv=3Dnotrunc + +Running the =E2=80=9CHello World=E2=80=9D example +--------------------------------- + +Run QEMU with the NEORV32 bootloader as ``-bios`` and attach the prepared +flash image via the MTD interface. Replace the placeholder paths with your +local paths:: + + $ /path/to/qemu-system-riscv32 -nographic -machine neorv32 \ + -bios /path/to/neorv32/bootloader/neorv32_raw_exe.bin \ + -drive file=3D$HOME/flash_contents.bin,if=3Dmtd,format=3Draw + +Notes: + +* ``-nographic`` routes the UART to your terminal (Ctrl-A X to quit when + using the QEMU monitor hotkeys; or just close the terminal). +* The bootloader starts first and will transfer control to your application + located at the 4 MiB offset of the flash image. +* If you prefer, you can use ``-serial stdio`` instead of ``-nographic``. + +Machine-specific options +------------------------ + +Unless otherwise noted by the patch series, there are no special board +options beyond the standard QEMU options shown above. Commonly useful +generic options include: + +* ``-s -S`` to open a GDB stub on TCP port 1234 and start paused, so you c= an + debug both QEMU and the guest. +* ``-d guest_errors,unimp`` (or other trace flags) for additional logging. + +Example: debugging with GDB:: + + $ /path/to/qemu-system-riscv32 -nographic -machine neorv32 \ + -bios /path/to/neorv32/bootloader/neorv32_raw_exe.bin \ + -drive file=3D$HOME/flash_contents.bin,if=3Dmtd,format=3Draw \ + -s -S + + # In another shell: + $ riscv32-unknown-elf-gdb /path/to/neorv32/bootloader/main.elf + (gdb) target remote :1234 + + +Known limitations +----------------- + +This is a functional model intended for software bring-up and testing of +example programs. It may not model all timing details or every optional +peripheral available in a specific NEORV32 SoC configuration. + diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index fc9c35bd98..976acd2a1b 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -128,3 +128,11 @@ config XIANGSHAN_KUNMINGHU select RISCV_APLIC select RISCV_IMSIC select SERIAL_MM + +config NEORV32 + bool + default y + depends on RISCV32 + select NEORV32_UART + select NEORV32_SPI + select NEORV32_SYSINFO_QEMU diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 2a8d5b136c..b8788e2035 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -14,5 +14,6 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files( 'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-h= pm.c')) riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-gen= eric.c')) riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan= _kmh.c')) +riscv_ss.add(when: 'CONFIG_NEORV32', if_true: files('neorv32.c')) =20 hw_arch +=3D {'riscv': riscv_ss} diff --git a/hw/riscv/neorv32.c b/hw/riscv/neorv32.c new file mode 100644 index 0000000000..87e35a9b0d --- /dev/null +++ b/hw/riscv/neorv32.c @@ -0,0 +1,219 @@ +/* + * QEMU RISC-V Board Compatible with Neorv32 IP + * + * Provides a board compatible with the Neorv32 IP: + * + * 0) SYSINFO + * 1) IMEM + * 2) DMEM + * 3) UART + * 4) SPI + * + * Author: + * Michael Levit + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * 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/cutils.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/sysbus.h" +#include "hw/char/serial.h" +#include "hw/misc/unimp.h" +#include "target/riscv/cpu.h" +#include "hw/riscv/riscv_hart.h" +#include "hw/riscv/boot.h" +#include "hw/intc/riscv_aclint.h" +#include "chardev/char.h" +#include "system/system.h" +#include "hw/ssi/ssi.h" /* For ssi_realize_and_unref() */ + +#include "hw/riscv/neorv32.h" +#include "hw/misc/neorv32_sysinfo.h" +#include "hw/char/neorv32_uart.h" +#include "hw/ssi/neorv32_spi.h" + +static const MemMapEntry neorv32_memmap[] =3D { + + [NEORV32_IMEM] =3D { NEORV32_IMEM_BASE, SYSINF= O_IMEM_SIZE}, + [NEORV32_BOOTLOADER_ROM] =3D { NEORV32_BOOTLOADER_BASE_ADDRESS, 0x2000= }, /* 8K ROM for bootloader */ + [NEORV32_DMEM] =3D { NEORV32_DMEM_BASE, SYSINF= O_DMEM_SIZE}, + [NEORV32_SYSINFO] =3D { NEORV32_SYSINFO_BASE, 0x100}, + [NEORV32_UART0] =3D { NEORV32_UART0_BASE, 0x100}, + [NEORV32_SPI0] =3D { NEORV32_SPI_BASE, 0x100}, +}; + +static void neorv32_machine_init(MachineState *machine) +{ + MachineClass *mc =3D MACHINE_GET_CLASS(machine); + const MemMapEntry *memmap =3D neorv32_memmap; + + Neorv32State *s =3D NEORV32_MACHINE(machine); + MemoryRegion *sys_mem =3D get_system_memory(); + int i; + RISCVBootInfo boot_info; + hwaddr start_addr =3D memmap[NEORV32_BOOTLOADER_ROM].base; + + if (machine->ram_size !=3D mc->default_ram_size) { + char *sz =3D size_to_str(mc->default_ram_size); + error_report("Invalid RAM size, should be %s", sz); + g_free(sz); + exit(EXIT_FAILURE); + } + + /* Initialize SoC */ + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_NE= ORV32_SOC); + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); + + /* Data Tightly Integrated Memory */ + memory_region_add_subregion(sys_mem, + memmap[NEORV32_DMEM].base, machine->ram); + + /* Instruction Memory (IMEM) */ + memory_region_init_ram(&s->soc.imem_region, OBJECT(&s->soc), "riscv.neorv= 32.imem", + memmap[NEORV32_IMEM].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[NEORV32_IMEM].base, &s->soc.i= mem_region); + + /* Mask ROM reset vector */ + uint32_t reset_vec[4]; + + reset_vec[1] =3D 0x204002b7; /* 0x1004: lui t0,0x20400 */ + reset_vec[2] =3D 0x00028067; /* 0x1008: jr t0 */ + reset_vec[0] =3D reset_vec[3] =3D 0; + + /* copy in the reset vector in little_endian byte order */ + for (i =3D 0; i < sizeof(reset_vec) >> 2; i++) { + reset_vec[i] =3D cpu_to_le32(reset_vec[i]); + } + + /* Neorv32 bootloader */ + if (machine->firmware) { + riscv_find_and_load_firmware(machine, machine->firmware, + &start_addr, NULL); + } + + /* Neorv32 example applications */ + riscv_boot_info_init(&boot_info, &s->soc.cpus); + if (machine->kernel_filename) { + riscv_load_kernel(machine, &boot_info, + memmap[NEORV32_IMEM].base, + false, NULL); + } +} + +static void neorv32_machine_instance_init(Object *obj) +{ + + /* Placeholder for now */ + /* Neorv32State *s =3D NEORV32_MACHINE(obj); */ +} + +static void neorv32_machine_class_init(ObjectClass *oc,const void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->desc =3D "RISC-V SOC compatible with Neorv32 SDK"; + mc->init =3D neorv32_machine_init; + mc->max_cpus =3D 1; + mc->default_cpu_type =3D NEORV32_CPU; + mc->default_ram_id =3D "riscv.neorv32.dmem"; + mc->default_ram_size =3D neorv32_memmap[NEORV32_DMEM].size; + +} + +static const TypeInfo neorv32_machine_typeinfo =3D { + .name =3D MACHINE_TYPE_NAME("neorv32"), + .parent =3D TYPE_MACHINE, + .class_init =3D neorv32_machine_class_init, + .instance_init =3D neorv32_machine_instance_init, + .instance_size =3D sizeof(Neorv32State), +}; + +static void neorv32_machine_init_register_types(void) +{ + type_register_static(&neorv32_machine_typeinfo); +} + +type_init(neorv32_machine_init_register_types) + +static void neorv32_soc_init(Object *obj) +{ + MachineState *ms =3D MACHINE(qdev_get_machine()); + Neorv32SoCState *s =3D RISCV_NEORV32_SOC(obj); + + object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); + object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, + &error_abort); + + object_property_set_int(OBJECT(&s->cpus), "resetvec", NEORV32_BOOTLOAD= ER_BASE_ADDRESS, &error_abort); + +} + +static void neorv32_soc_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms =3D MACHINE(qdev_get_machine()); + const MemMapEntry *memmap =3D neorv32_memmap; + Neorv32SoCState *s =3D RISCV_NEORV32_SOC(dev); + MemoryRegion *sys_mem =3D get_system_memory(); + + object_property_set_str(OBJECT(&s->cpus), "cpu-type", ms->cpu_type, + &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal); + + /* Bootloader ROM */ + memory_region_init_rom(&s->bootloader_rom, OBJECT(dev), "riscv.bootloa= der.rom", + memmap[NEORV32_BOOTLOADER_ROM].size, &error_fat= al); + memory_region_add_subregion(sys_mem, + memmap[NEORV32_BOOTLOADER_ROM].base, &s->bootloader_rom); + + + /* Sysinfo ROM */ + neorv32_sysinfo_create(sys_mem, memmap[NEORV32_SYSINFO].base); + + /* Uart0 */ + neorv32_uart_create(sys_mem, memmap[NEORV32_UART0].base,serial_hd(0)); + + /* SPI controller */ + NEORV32SPIState *spi =3D neorv32_spi_create(sys_mem, memmap[NEORV32_SPI0]= .base); + + if (!spi) { + error_setg(errp, "SPI is not created"); + return; + } +} + +static void neorv32_soc_class_init(ObjectClass *oc,const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + dc->realize =3D neorv32_soc_realize; + dc->user_creatable =3D false; +} + +static const TypeInfo neorv32_soc_type_info =3D { + .name =3D TYPE_RISCV_NEORV32_SOC, + .parent =3D TYPE_DEVICE, + .instance_size =3D sizeof(Neorv32SoCState), + .instance_init =3D neorv32_soc_init, + .class_init =3D neorv32_soc_class_init, +}; + +static void neorv32_soc_register_types(void) +{ + type_register_static(&neorv32_soc_type_info); +} + +type_init(neorv32_soc_register_types) diff --git a/include/hw/riscv/neorv32.h b/include/hw/riscv/neorv32.h new file mode 100644 index 0000000000..46c7f6767e --- /dev/null +++ b/include/hw/riscv/neorv32.h @@ -0,0 +1,60 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ +#ifndef HW_NEORV32_H +#define HW_NEORV32_H + +#include "hw/riscv/riscv_hart.h" +#include "hw/boards.h" + +#if defined(TARGET_RISCV32) +#define NEORV32_CPU TYPE_RISCV_CPU_NEORV32 +#endif + +#define TYPE_RISCV_NEORV32_SOC "riscv.neorv32.soc" +#define RISCV_NEORV32_SOC(obj) \ + OBJECT_CHECK(Neorv32SoCState, (obj), TYPE_RISCV_NEORV32_SOC) + +typedef struct Neorv32SoCState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + RISCVHartArrayState cpus; + DeviceState *plic; + MemoryRegion imem_region; + MemoryRegion bootloader_rom; +} Neorv32SoCState; + +typedef struct Neorv32State { + /*< private >*/ + MachineState parent_obj; + + /*< public >*/ + Neorv32SoCState soc; +} Neorv32State; + +#define TYPE_NEORV32_MACHINE MACHINE_TYPE_NAME("neorv32") +#define NEORV32_MACHINE(obj) \ + OBJECT_CHECK(Neorv32State, (obj), TYPE_NEORV32_MACHINE) + +enum { + NEORV32_IMEM, + NEORV32_BOOTLOADER_ROM, + NEORV32_DMEM, + NEORV32_SYSINFO, + NEORV32_UART0, + NEORV32_SPI0, +}; + +#endif //HW_NEORV32_H