Message ID | 1750203584-32065-2-git-send-email-mark.hatle@kernel.crashing.org |
---|---|
State | New |
Headers | show |
Series | ISA based RISC-V tune implementation | expand |
On Wed, Jun 18, 2025 at 9:39 AM Mark Hatle via lists.openembedded.org <mark.hatle=kernel.crashing.org@lists.openembedded.org> wrote: > > From: Mark Hatle <mark.hatle@amd.com> > > This implements the following base ISAs: > > * rv32i, rv64i > * rv32e, rv64i > > The following ABIs: > * ilp32, ilp32e, ilp32f, ilp32d > * lp64, lp64e, lp64f, lp64d > > The following ISA extension are also implemented: > * M - Integer Multiplication and Division Extension > * A - Atomic Memory Extension > * F - Single-Precision Floating-Point Extension > * D - Double-Precision Floating-Point Extension > * C - Compressed Extension > * B - Bit Manipulation Extension (implies Zba, Zbb, Zbs) > * V - Vector Operations Extension > * Zicsr - Control and Status Register Access Extension > * Zifencei - Instruction-Fetch Fence Extension > * Zba - Address bit manipulation extension > * Zbb - Basic bit manipulation extension > * Zbc - Carry-less multiplication extension > * Zbs - Single-bit manipulation extension > * Zicbom - Cache-block management extension > > The existing processors tunes are preserved: > * riscv64 (rv64gc) > * riscv32 (rv32gc) > * riscv64nf (rv64imac_zicsr_zifencei) > * riscv32nf (rv32imac_zicsr_zifencei) > * riscv64nc (rv64imafd_zicsr_zifencei) I'm not sure this is the way we want to handle this. You are picking and choosing each individual extension, which is difficult for users to do. Not to mention it's easy to get wrong as some extensions conflict with other extensions. You also end up using the `rv32` or `rv64` CPUs with QEMU and enabling extensions manually. We will probably remove those CPUs from QEMU in the future as they cause a lot of user confusion. I think instead we should be moving towards the RISC-V profiles. Individual extensions can still be enabled/disabled on top of a profile if required. That's what we are doing in QEMU and it makes things a lot clearer to users exactly what is/isn't enabled. Alistair > > Previously defined feature 'big-endian' has been removed as it was not used. > > Signed-off-by: Mark Hatle <mark.hatle@amd.com> > --- > meta/conf/machine/include/riscv/README | 122 ++++++++++++++++ > .../conf/machine/include/riscv/arch-riscv.inc | 138 +++++++++++++++++- > .../conf/machine/include/riscv/tune-riscv.inc | 40 ++--- > meta/conf/machine/qemuriscv32.conf | 4 +- > meta/lib/oe/__init__.py | 2 +- > meta/lib/oe/tune.py | 81 ++++++++++ > 6 files changed, 349 insertions(+), 38 deletions(-) > create mode 100644 meta/conf/machine/include/riscv/README > create mode 100644 meta/lib/oe/tune.py > > diff --git a/meta/conf/machine/include/riscv/README b/meta/conf/machine/include/riscv/README > new file mode 100644 > index 0000000000..beef68f523 > --- /dev/null > +++ b/meta/conf/machine/include/riscv/README > @@ -0,0 +1,122 @@ > +2025/06/08 - Mark Hatle <mark.hatle@amd.com> > + - Initial Revision > + > +The RISC-V ISA is broken into two parts, a base ISA and extensions. As > +of the writing of this document these are documented at: > + > +https://lf-riscv.atlassian.net/wiki/spaces/HOME/pages/16154769/RISC-V+Technical+Specifications > + > +Specifically "The RISC-V Instruction Set Manual Volume I: Unprivileged ISA" > +was used to create this implementation. > + > +Requirements > +------------ > +As RISC-V is a “variable” ISA (a base isa plus numerous extensions), a > +mechanism is required to specify a series of ISA features that a user or > +tune can use to specify a specific CPU instantiation. > + > +Not all ratified or draft features should or can be implemented with the > +available resources. > + > +The implementation should work for Linux, baremetal (newlib), zephyr and > +other operating systems. Supported extensions should be based on > +real-world examples. > + > +Linux > +----- > +Linux required base and support extensions should be available. Linux > +requires: > +* Base: rv32ima & rv64ima > +* Optional FPU: fd > +* Optional RISCV_ISA_C: c > +* Optiona RISCV_ISA_V: v > +* Required additional: _zicsr_zifencei > +* Optional RISCV_ISA_ZBA: _zba > +* Optional RISCV_ISA_ZBB: _zbb > +* Optional RISCV_ISA_ZBC: _zbc (not supported by current QEMU design) > + > +See: https://git.yoctoproject.org/linux-yocto/tree/arch/riscv/Makefile?h=v6.12/base > + > +Baremetal > +--------- > +AMD Microblaze-V FPGA support uses the following static configurations: > +Base: rv32e, rv32i, rv64i > +Extensions: m, a, f, d, c, b, zicsr, zifencei > + > +Zephyr > +------ > +AMD Microblaze-V development for Zephyr is the same as Baremetal, with a > +few additional extensions: zbc, zicbom > + > +ABI > +--- > +The following ABIs are supported GNU tools and some combination of systems. > +* ilp32 - Integer, long and pointer are 32-bit > +* lp64 - Long and pointer are 64-bit (integer is 32-bit) > + > +The ABI is dependent upon the core system implementation, as ilp32 can > +only used on an ‘rv32’ system, while lp64 can only be used on an ‘rv64’ > +system. > + > +There are additional variations of each ABI: > +* e - used with the Reduced register extension > +* f - used when single precision floating point (but not double precision) is > + enabled > +* d - used when both single and double precision floating point is enabled > + > +Based on the above, the ABI should be automatically determined based on > +the selected Base ISA and Extensions. > + > +Implementation > +-------------- > +To make it easier to generate the RISC-V canonical arch, ISA based -march, > +and the ABI string, a few new variables are added for specific RISC-V items. > + > +TUNE_RISCV_ARCH - This contains the canonical GNU style arch, generally this > + will evaluate to "riscv32" or "riscv64". > + > +TUNE_RISCV_MARCH - This will contain an ISA based -march string compatible > + with gcc and similar toolchains. For example: > + rv32imacfd_zicsr_zifencei > + > +TUNE_RISCV_ABI - This is the generated ABI that corresponds to the ARCH and > + MARCH/ISA values. For riscv32, the value will be ilp32 > + (int, long and pointer is 32-bit) with the ISA > + variation. For riscv64, the value will be lp64 (long > + and pointer are 64-bit bit, while int is 32-bit) with the > + ISA variation. The ISA affects the ABI when the 'e', 'f' > + and 'd' extension are used. > + > +TUNE_RISCV_PKGARCH - This is the generated PKGARCH value. > + > +The standard variables are defined as: > + > +TUNE_CCARGS = "${@ '-march=${TUNE_RISCV_MARCH} -mabi=${TUNE_RISCV_ABI}' if not d.getVar('TUNE_CCARGS:tune-${DEFAULTTUNE}') else 'TUNE_CCARGS:tune-${DEFAULTTUNE}'}" > + > +The above will allow the user to specify an implementation specific > +TUNE_CCARGS for a given processor tune if the default implementtion is > +not adequate for some reason. It is expected that most, if not all, > +implementations will use the default behavior. > + > +TUNE_ARCH = "${TUNE_RISCV_ARCH}" > +TUNE_PKGARCH = "${TUNE_RISCV_PKGARCH}" > + > +The above two will always base their setting off the standard TUNE_FEATURES. > + > +Ratified and draft extensions should be implemented as TUNE_FEATURES in > +the arch-riscv.inc file. > + > +Vendor specific extensions and processor specific settings should go > +into a 'tune-<vendor>.inc' file, with tune-riscv.inc being reserved for > +general purpose tunes. > + > +TUNE_FEATURE Helper > +------------------- > +A special helper function has been written that will convert RISC-V ISA > +notation into TUNE_FEATURE notion, for example: > + > +rv32g -> rv 32 i m a f d zicsr zifencei > + > +The helper can be called using oe.tune.riscv_isa_to_tune("<ISA>") such as > +oe.tune.riscv_isa_to_tune("rv64gc") which would return: > + rv 64 i m a f d c zicsr zifencei > diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc b/meta/conf/machine/include/riscv/arch-riscv.inc > index b34064e78f..99bed8fde5 100644 > --- a/meta/conf/machine/include/riscv/arch-riscv.inc > +++ b/meta/conf/machine/include/riscv/arch-riscv.inc > @@ -1,14 +1,140 @@ > # RISCV Architecture definition > > -DEFAULTTUNE ?= "riscv64" > +# Based on the RISC-V Instruction Set Manual Volume I: Unprivileged ISA from May 2025 > +# As well as the RISC-V options for using GCC (as of June 2025) > > -TUNE_ARCH = "${TUNE_ARCH:tune-${DEFAULTTUNE}}" > -TUNE_PKGARCH = "${TUNE_PKGARCH:tune-${DEFAULTTUNE}}" > -TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nf', ' -mabi=lp64', ' ', d)}" > -TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv32nf', ' -mabi=ilp32', ' ', d)}" > +# Note: the following should be implemented in the order that GCC expects > +# -march= values to be defined in. > > -TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -march=rv64imafd', ' ', d)}" > +# Base ISA > +# All supported march strings must start with rv32 or rv64 > +TUNEVALID[rv] = "RISC-V" > +TUNE_RISCV_ARCH = "${@bb.utils.contains("TUNE_FEATURES", "rv", "riscv", "", d)}" > +TUNE_RISCV_MARCH = "${@bb.utils.contains("TUNE_FEATURES", "rv", "rv", "", d)}" > +TUNE_RISCV_ABI = "" > > +# There are two primary ABIs, ilp32 and lp64 > +# There are variants of both, that appears to be based on extensions above > +# For example: > +# rv32i uses ilp32, rv32e uses ilp32e, rv32f uses ilp32f > +# rv64i uses lp64, rv64if uses lp64f, rv64id uses lp64d > +TUNEVALID[32] = "ISA XLEN - 32-bit" > +TUNECONFLICTS[32] = "64" > +TUNE_RISCV_ARCH .= "${@bb.utils.contains("TUNE_FEATURES", "32", "32", "", d)}" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "32", "32", "", d)}" > +TUNE_RISCV_ABI .= "${@bb.utils.contains("TUNE_FEATURES", "32", "ilp32", "", d)}" > + > +TUNEVALID[64] = "ISA XLEN - 64-bit" > +TUNECONFLICTS[64] = "32" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "64", "64", "", d)}" > +TUNE_RISCV_ARCH .= "${@bb.utils.contains("TUNE_FEATURES", "64", "64", "", d)}" > +TUNE_RISCV_ABI .= "${@bb.utils.contains("TUNE_FEATURES", "64", "lp64", "", d)}" > + > +# The package arch starts with the canonical arch, but adds some extensions to make > +# package compatibility clear > +TUNE_RISCV_PKGARCH = "${TUNE_RISCV_ARCH}" > + > +# i, e, or g are defined by gcc, but 'g' refers to 'i' + extensions 'MAFD Zicsr Zifencei' > +# So 'g' will not be defined here as it is an abbreviation of the expanded version > +TUNEVALID[e] = "Reduced register base integer extension" > +TUNECONFLICTS[e] = "i" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "e", "e", "", d)}" > +TUNE_RISCV_ABI .= "${@bb.utils.contains("TUNE_FEATURES", "e", "e", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "e", "e", "", d)}" > + > +TUNEVALID[i] = "Base integer extension" > +TUNECONFLICTS[i] = "e" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "i", "i", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "i", "i", "", d)}" > + > +# Extensions > +TUNEVALID[m] = "Integer multiplication and division extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "m", "m", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "m", "m", "", d)}" > + > +TUNEVALID[a] = "Atomic extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "a", "a", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "a", "a", "", d)}" > + > +TUNEVALID[f] = "Single-precision floating-point extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "f d", "f", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "f d", "f", "", d)}" > + > +TUNEVALID[d] = "Double-precision floating-point extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "d", "d", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "d", "d", "", d)}" > + > +# Only f OR d, but just one > +TUNE_RISCV_ABI .= "${@bb.utils.contains("TUNE_FEATURES", "d", "d", bb.utils.contains("TUNE_FEATURES", "f", "f", "", d), d)}" > + > +TUNEVALID[c] = "Compressed extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "c", "c", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "c", "c", "", d)}" > + > +TUNEVALID[b] = "Bit Manipulation extension" > +# Handled below via zba, zbb, zbs > +# This matches current Linux kernel behavior > +#TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "b", "b", "", d)}" > +#TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "b", "b", "", d)}" > + > +TUNEVALID[v] = "Vector operations extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "v", "v", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "v", "v", "", d)}" > + > +# Now the special Z extensions > +TUNEVALID[zicbom] = "Cache-block management extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zicbom", "_zicbom", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zicbom", "_zicbom", "", d)}" > + > +TUNEVALID[zicsr] = "Control and status register access extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zicsr f d", "_zicsr", "", d)}" > +# If zicsr (or zifencei) is in the path, OpenSBI fails to use the extensions, do to (Makefile): > +# # Check whether the assembler and the compiler support the Zicsr and Zifencei extensions > +# CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep -e "zicsr" -e "zifencei" > /dev/null && echo n || echo y) > +# this will match on the path containing zicsr or zifencei when an error is reported, which > +# will always happens in this check. > +# > +# Yocto Project Bugzilla 15897 > +# > +#TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zicsr f d", "_zicsr", "", d)}" > + > +TUNEVALID[zifencei] = "Instruction-fetch fence extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "zifencei", "_zifencei", "", d)}" > +# See above Bug 15897 > +#TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "zifencei", "_zifencei", "", d)}" > + > +TUNEVALID[zba] = "Address bit manipulation extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zba", "_zba", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zba", "_zba", "", d)}" > + > +TUNEVALID[zbb] = "Basic bit manipulation extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zbb", "_zbb", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zbb", "_zbb", "", d)}" > + > +TUNEVALID[zbc] = "Carry-less multiplication extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zbc", "_zbc", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zbc", "_zbc", "", d)}" > + > +TUNEVALID[zbs] = "Single-bit manipulation extension" > +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zbs", "_zbs", "", d)}" > +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zbs", "_zbs", "", d)}" > + > +# Construct TUNE_CCARGS > +# This should result in a CCARG similar to: > +# -march=rv32imac -mabi=ilp32 > +TUNE_CCARGS = "${@ '-march=${TUNE_RISCV_MARCH} -mabi=${TUNE_RISCV_ABI}' if not d.getVar('TUNE_CCARGS:tune-${DEFAULTTUNE}') else 'TUNE_CCARGS:tune-${DEFAULTTUNE}'}" > + > +# Construct TUNE_ARCH > +# This should result in an arch string similar to: > +# riscv32 > +TUNE_ARCH = "${TUNE_RISCV_ARCH}" > + > +# Construct TUNE_PKGARCH > +# This should result in a package are like: > +# riscv32imac > +TUNE_PKGARCH = "${TUNE_RISCV_PKGARCH}" > + > +# Misc settings > # Fix: ld: unrecognized option '--hash-style=sysv' > LINKER_HASH_STYLE:libc-newlib = "" > LINKER_HASH_STYLE:libc-picolibc = "" > diff --git a/meta/conf/machine/include/riscv/tune-riscv.inc b/meta/conf/machine/include/riscv/tune-riscv.inc > index 804712077e..12c1125c8b 100644 > --- a/meta/conf/machine/include/riscv/tune-riscv.inc > +++ b/meta/conf/machine/include/riscv/tune-riscv.inc > @@ -1,41 +1,23 @@ > require conf/machine/include/riscv/arch-riscv.inc > > -TUNEVALID[riscv64] = "Enable 64-bit RISC-V optimizations" > -TUNEVALID[riscv32] = "Enable 32-bit RISC-V optimizations" > - > -TUNEVALID[riscv64nf] = "Enable 64-bit RISC-V optimizations no floating point" > -TUNEVALID[riscv32nf] = "Enable 32-bit RISC-V optimizations no floating point" > - > -TUNEVALID[riscv64nc] = "Enable 64-bit RISC-V optimizations without compressed instructions" > - > -TUNEVALID[bigendian] = "Big endian mode" > +DEFAULTTUNE ?= "riscv64" > > AVAILTUNES += "riscv64 riscv32 riscv64nc riscv64nf riscv32nf" > > # Default > -TUNE_FEATURES:tune-riscv64 = "riscv64" > -TUNE_ARCH:tune-riscv64 = "riscv64" > -TUNE_PKGARCH:tune-riscv64 = "riscv64" > -PACKAGE_EXTRA_ARCHS:tune-riscv64 = "riscv64" > +TUNE_FEATURES:tune-riscv64 := "${@oe.tune.riscv_isa_to_tune("rv64gc")}" > +PACKAGE_EXTRA_ARCHS:tune-riscv64 = "${TUNE_RISCV_PKGARCH}" > > -TUNE_FEATURES:tune-riscv32 = "riscv32" > -TUNE_ARCH:tune-riscv32 = "riscv32" > -TUNE_PKGARCH:tune-riscv32 = "riscv32" > -PACKAGE_EXTRA_ARCHS:tune-riscv32 = "riscv32" > +TUNE_FEATURES:tune-riscv32 := "${@oe.tune.riscv_isa_to_tune("rv32gc")}" > +PACKAGE_EXTRA_ARCHS:tune-riscv32 = "${TUNE_RISCV_PKGARCH}" > > # No float > -TUNE_FEATURES:tune-riscv64nf = "${TUNE_FEATURES:tune-riscv64} riscv64nf" > -TUNE_ARCH:tune-riscv64nf = "riscv64" > -TUNE_PKGARCH:tune-riscv64nf = "riscv64nf" > -PACKAGE_EXTRA_ARCHS:tune-riscv64nf = "riscv64nf" > +TUNE_FEATURES:tune-riscv64nf := "${@oe.tune.riscv_isa_to_tune("rv64imac_zicsr_zifencei")}" > +PACKAGE_EXTRA_ARCHS:tune-riscv64nf = "${TUNE_RISCV_PKGARCH}" > > -TUNE_FEATURES:tune-riscv32nf = "${TUNE_FEATURES:tune-riscv32} riscv32nf" > -TUNE_ARCH:tune-riscv32nf = "riscv32" > -TUNE_PKGARCH:tune-riscv32nf = "riscv32nf" > -PACKAGE_EXTRA_ARCHS:tune-riscv32nf = "riscv32nf" > +TUNE_FEATURES:tune-riscv32nf := "${@oe.tune.riscv_isa_to_tune("rv32imac_zicsr_zifencei")}" > +PACKAGE_EXTRA_ARCHS:tune-riscv32nf = "${TUNE_RISCV_PKGARCH}" > > # no compressed > -TUNE_FEATURES:tune-riscv64nc = "${TUNE_FEATURES:tune-riscv64} riscv64nc" > -TUNE_ARCH:tune-riscv64nc = "riscv64" > -TUNE_PKGARCH:tune-riscv64nc = "riscv64nc" > -PACKAGE_EXTRA_ARCHS:tune-riscv64nc = "riscv64nc" > +TUNE_FEATURES:tune-riscv64nc := "${@oe.tune.riscv_isa_to_tune("rv64imafd_zicsr_zifencei")}" > +PACKAGE_EXTRA_ARCHS:tune-riscv64nc = "${TUNE_RISCV_PKGARCH}" > diff --git a/meta/conf/machine/qemuriscv32.conf b/meta/conf/machine/qemuriscv32.conf > index d3858dc051..aff36c28a5 100644 > --- a/meta/conf/machine/qemuriscv32.conf > +++ b/meta/conf/machine/qemuriscv32.conf > @@ -2,9 +2,9 @@ > #@NAME: generic riscv32 machine > #@DESCRIPTION: Machine configuration for running a generic riscv32 > > -require conf/machine/include/riscv/qemuriscv.inc > +DEFAULTTUNE ?= "riscv32" > > -DEFAULTTUNE = "riscv32" > +require conf/machine/include/riscv/qemuriscv.inc > > PREFERRED_VERSION_openocd-native = "riscv" > PREFERRED_VERSION_openocd = "riscv" > diff --git a/meta/lib/oe/__init__.py b/meta/lib/oe/__init__.py > index dd094a874a..73de774266 100644 > --- a/meta/lib/oe/__init__.py > +++ b/meta/lib/oe/__init__.py > @@ -12,4 +12,4 @@ __path__ = extend_path(__path__, __name__) > BBIMPORTS = ["qa", "data", "path", "utils", "types", "package", "packagedata", \ > "packagegroup", "sstatesig", "lsb", "cachedpath", "license", "qemu", \ > "reproducible", "rust", "buildcfg", "go", "spdx30_tasks", "spdx_common", \ > - "cve_check"] > + "cve_check", "tune"] > diff --git a/meta/lib/oe/tune.py b/meta/lib/oe/tune.py > new file mode 100644 > index 0000000000..7fda19430d > --- /dev/null > +++ b/meta/lib/oe/tune.py > @@ -0,0 +1,81 @@ > +# > +# Copyright OpenEmbedded Contributors > +# > +# SPDX-License-Identifier: GPL-2.0-only > +# > + > +# riscv_isa_to_tune(isa) > +# > +# Automatically translate a RISC-V ISA string to TUNE_FEATURES > +# > +# Abbreviations, such as rv32g -> rv32imaffd_zicsr_zifencei are supported. > +# > +# Profiles, such as rva22u64, are NOT supported, you must use ISA strings. > +# > +def riscv_isa_to_tune(isa): > + _isa = isa.lower() > + > + feature = [] > + iter = 0 > + > + # rv or riscv > + if _isa[iter:].startswith('rv'): > + feature.append('rv') > + iter = iter + 2 > + elif _isa[iter:].startswith('riscv'): > + feature.append('rv') > + iter = iter + 5 > + else: > + # Not a risc-v ISA! > + return _isa > + > + while (_isa[iter:]): > + # Skip _ and whitespace > + if _isa[iter] == '_' or _isa[iter].isspace(): > + iter = iter + 1 > + continue > + > + # Length, just capture numbers here > + if _isa[iter].isdigit(): > + iter_end = iter > + while iter_end < len(_isa) and _isa[iter_end].isdigit(): > + iter_end = iter_end + 1 > + > + feature.append(_isa[iter:iter_end]) > + iter = iter_end > + continue > + > + # Typically i, e or g is next, followed by extensions. > + # Extensions are single character, except for Z, Ss, Sh, Sm, Sv, and X > + > + # If the extension starts with 'Z', 'S' or 'X' use the name until the next _, whitespace or end > + if _isa[iter] in ['z', 's', 'x']: > + ext_type = _isa[iter] > + iter_end = iter + 1 > + > + # Multicharacter extension, these are supposed to have a _ before the next multicharacter extension > + # See 37.4 and 37.5: > + # 37.4: Underscores "_" may be used to separate ISA extensions... > + # 37.5: All multi-letter extensions ... must be separated from other multi-letter extensions by an underscore... > + # Some extensions permit only alphabetic characters, while others allow alphanumeric chartacters > + while iter_end < len(_isa) and _isa[iter_end] != "_" and not _isa[iter_end].isspace(): > + iter_end = iter_end + 1 > + > + feature.append(_isa[iter:iter_end]) > + iter = iter_end > + continue > + > + # 'g' is special, it's an abbreviation for imafd_zicsr_zifencei > + # When expanding the abbreviation, any additional letters must appear before the _z* extensions > + if _isa[iter] == 'g': > + _isa = 'imafd' + _isa[iter+1:] + '_zicsr_zifencei' > + iter = 0 > + continue > + > + feature.append(_isa[iter]) > + iter = iter + 1 > + continue > + > + # Eliminate duplicates, but preserve the order > + feature = list(dict.fromkeys(feature)) > + return ' '.join(feature) > -- > 2.34.1 > > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#218948): https://lists.openembedded.org/g/openembedded-core/message/218948 > Mute This Topic: https://lists.openembedded.org/mt/113700338/3619028 > Group Owner: openembedded-core+owner@lists.openembedded.org > Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [alistair23@gmail.com] > -=-=-=-=-=-=-=-=-=-=-=- >
diff --git a/meta/conf/machine/include/riscv/README b/meta/conf/machine/include/riscv/README new file mode 100644 index 0000000000..beef68f523 --- /dev/null +++ b/meta/conf/machine/include/riscv/README @@ -0,0 +1,122 @@ +2025/06/08 - Mark Hatle <mark.hatle@amd.com> + - Initial Revision + +The RISC-V ISA is broken into two parts, a base ISA and extensions. As +of the writing of this document these are documented at: + +https://lf-riscv.atlassian.net/wiki/spaces/HOME/pages/16154769/RISC-V+Technical+Specifications + +Specifically "The RISC-V Instruction Set Manual Volume I: Unprivileged ISA" +was used to create this implementation. + +Requirements +------------ +As RISC-V is a “variable” ISA (a base isa plus numerous extensions), a +mechanism is required to specify a series of ISA features that a user or +tune can use to specify a specific CPU instantiation. + +Not all ratified or draft features should or can be implemented with the +available resources. + +The implementation should work for Linux, baremetal (newlib), zephyr and +other operating systems. Supported extensions should be based on +real-world examples. + +Linux +----- +Linux required base and support extensions should be available. Linux +requires: +* Base: rv32ima & rv64ima +* Optional FPU: fd +* Optional RISCV_ISA_C: c +* Optiona RISCV_ISA_V: v +* Required additional: _zicsr_zifencei +* Optional RISCV_ISA_ZBA: _zba +* Optional RISCV_ISA_ZBB: _zbb +* Optional RISCV_ISA_ZBC: _zbc (not supported by current QEMU design) + +See: https://git.yoctoproject.org/linux-yocto/tree/arch/riscv/Makefile?h=v6.12/base + +Baremetal +--------- +AMD Microblaze-V FPGA support uses the following static configurations: +Base: rv32e, rv32i, rv64i +Extensions: m, a, f, d, c, b, zicsr, zifencei + +Zephyr +------ +AMD Microblaze-V development for Zephyr is the same as Baremetal, with a +few additional extensions: zbc, zicbom + +ABI +--- +The following ABIs are supported GNU tools and some combination of systems. +* ilp32 - Integer, long and pointer are 32-bit +* lp64 - Long and pointer are 64-bit (integer is 32-bit) + +The ABI is dependent upon the core system implementation, as ilp32 can +only used on an ‘rv32’ system, while lp64 can only be used on an ‘rv64’ +system. + +There are additional variations of each ABI: +* e - used with the Reduced register extension +* f - used when single precision floating point (but not double precision) is + enabled +* d - used when both single and double precision floating point is enabled + +Based on the above, the ABI should be automatically determined based on +the selected Base ISA and Extensions. + +Implementation +-------------- +To make it easier to generate the RISC-V canonical arch, ISA based -march, +and the ABI string, a few new variables are added for specific RISC-V items. + +TUNE_RISCV_ARCH - This contains the canonical GNU style arch, generally this + will evaluate to "riscv32" or "riscv64". + +TUNE_RISCV_MARCH - This will contain an ISA based -march string compatible + with gcc and similar toolchains. For example: + rv32imacfd_zicsr_zifencei + +TUNE_RISCV_ABI - This is the generated ABI that corresponds to the ARCH and + MARCH/ISA values. For riscv32, the value will be ilp32 + (int, long and pointer is 32-bit) with the ISA + variation. For riscv64, the value will be lp64 (long + and pointer are 64-bit bit, while int is 32-bit) with the + ISA variation. The ISA affects the ABI when the 'e', 'f' + and 'd' extension are used. + +TUNE_RISCV_PKGARCH - This is the generated PKGARCH value. + +The standard variables are defined as: + +TUNE_CCARGS = "${@ '-march=${TUNE_RISCV_MARCH} -mabi=${TUNE_RISCV_ABI}' if not d.getVar('TUNE_CCARGS:tune-${DEFAULTTUNE}') else 'TUNE_CCARGS:tune-${DEFAULTTUNE}'}" + +The above will allow the user to specify an implementation specific +TUNE_CCARGS for a given processor tune if the default implementtion is +not adequate for some reason. It is expected that most, if not all, +implementations will use the default behavior. + +TUNE_ARCH = "${TUNE_RISCV_ARCH}" +TUNE_PKGARCH = "${TUNE_RISCV_PKGARCH}" + +The above two will always base their setting off the standard TUNE_FEATURES. + +Ratified and draft extensions should be implemented as TUNE_FEATURES in +the arch-riscv.inc file. + +Vendor specific extensions and processor specific settings should go +into a 'tune-<vendor>.inc' file, with tune-riscv.inc being reserved for +general purpose tunes. + +TUNE_FEATURE Helper +------------------- +A special helper function has been written that will convert RISC-V ISA +notation into TUNE_FEATURE notion, for example: + +rv32g -> rv 32 i m a f d zicsr zifencei + +The helper can be called using oe.tune.riscv_isa_to_tune("<ISA>") such as +oe.tune.riscv_isa_to_tune("rv64gc") which would return: + rv 64 i m a f d c zicsr zifencei diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc b/meta/conf/machine/include/riscv/arch-riscv.inc index b34064e78f..99bed8fde5 100644 --- a/meta/conf/machine/include/riscv/arch-riscv.inc +++ b/meta/conf/machine/include/riscv/arch-riscv.inc @@ -1,14 +1,140 @@ # RISCV Architecture definition -DEFAULTTUNE ?= "riscv64" +# Based on the RISC-V Instruction Set Manual Volume I: Unprivileged ISA from May 2025 +# As well as the RISC-V options for using GCC (as of June 2025) -TUNE_ARCH = "${TUNE_ARCH:tune-${DEFAULTTUNE}}" -TUNE_PKGARCH = "${TUNE_PKGARCH:tune-${DEFAULTTUNE}}" -TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nf', ' -mabi=lp64', ' ', d)}" -TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv32nf', ' -mabi=ilp32', ' ', d)}" +# Note: the following should be implemented in the order that GCC expects +# -march= values to be defined in. -TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -march=rv64imafd', ' ', d)}" +# Base ISA +# All supported march strings must start with rv32 or rv64 +TUNEVALID[rv] = "RISC-V" +TUNE_RISCV_ARCH = "${@bb.utils.contains("TUNE_FEATURES", "rv", "riscv", "", d)}" +TUNE_RISCV_MARCH = "${@bb.utils.contains("TUNE_FEATURES", "rv", "rv", "", d)}" +TUNE_RISCV_ABI = "" +# There are two primary ABIs, ilp32 and lp64 +# There are variants of both, that appears to be based on extensions above +# For example: +# rv32i uses ilp32, rv32e uses ilp32e, rv32f uses ilp32f +# rv64i uses lp64, rv64if uses lp64f, rv64id uses lp64d +TUNEVALID[32] = "ISA XLEN - 32-bit" +TUNECONFLICTS[32] = "64" +TUNE_RISCV_ARCH .= "${@bb.utils.contains("TUNE_FEATURES", "32", "32", "", d)}" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "32", "32", "", d)}" +TUNE_RISCV_ABI .= "${@bb.utils.contains("TUNE_FEATURES", "32", "ilp32", "", d)}" + +TUNEVALID[64] = "ISA XLEN - 64-bit" +TUNECONFLICTS[64] = "32" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "64", "64", "", d)}" +TUNE_RISCV_ARCH .= "${@bb.utils.contains("TUNE_FEATURES", "64", "64", "", d)}" +TUNE_RISCV_ABI .= "${@bb.utils.contains("TUNE_FEATURES", "64", "lp64", "", d)}" + +# The package arch starts with the canonical arch, but adds some extensions to make +# package compatibility clear +TUNE_RISCV_PKGARCH = "${TUNE_RISCV_ARCH}" + +# i, e, or g are defined by gcc, but 'g' refers to 'i' + extensions 'MAFD Zicsr Zifencei' +# So 'g' will not be defined here as it is an abbreviation of the expanded version +TUNEVALID[e] = "Reduced register base integer extension" +TUNECONFLICTS[e] = "i" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "e", "e", "", d)}" +TUNE_RISCV_ABI .= "${@bb.utils.contains("TUNE_FEATURES", "e", "e", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "e", "e", "", d)}" + +TUNEVALID[i] = "Base integer extension" +TUNECONFLICTS[i] = "e" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "i", "i", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "i", "i", "", d)}" + +# Extensions +TUNEVALID[m] = "Integer multiplication and division extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "m", "m", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "m", "m", "", d)}" + +TUNEVALID[a] = "Atomic extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "a", "a", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "a", "a", "", d)}" + +TUNEVALID[f] = "Single-precision floating-point extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "f d", "f", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "f d", "f", "", d)}" + +TUNEVALID[d] = "Double-precision floating-point extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "d", "d", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "d", "d", "", d)}" + +# Only f OR d, but just one +TUNE_RISCV_ABI .= "${@bb.utils.contains("TUNE_FEATURES", "d", "d", bb.utils.contains("TUNE_FEATURES", "f", "f", "", d), d)}" + +TUNEVALID[c] = "Compressed extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "c", "c", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "c", "c", "", d)}" + +TUNEVALID[b] = "Bit Manipulation extension" +# Handled below via zba, zbb, zbs +# This matches current Linux kernel behavior +#TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "b", "b", "", d)}" +#TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "b", "b", "", d)}" + +TUNEVALID[v] = "Vector operations extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "v", "v", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "v", "v", "", d)}" + +# Now the special Z extensions +TUNEVALID[zicbom] = "Cache-block management extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zicbom", "_zicbom", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zicbom", "_zicbom", "", d)}" + +TUNEVALID[zicsr] = "Control and status register access extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zicsr f d", "_zicsr", "", d)}" +# If zicsr (or zifencei) is in the path, OpenSBI fails to use the extensions, do to (Makefile): +# # Check whether the assembler and the compiler support the Zicsr and Zifencei extensions +# CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep -e "zicsr" -e "zifencei" > /dev/null && echo n || echo y) +# this will match on the path containing zicsr or zifencei when an error is reported, which +# will always happens in this check. +# +# Yocto Project Bugzilla 15897 +# +#TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zicsr f d", "_zicsr", "", d)}" + +TUNEVALID[zifencei] = "Instruction-fetch fence extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains("TUNE_FEATURES", "zifencei", "_zifencei", "", d)}" +# See above Bug 15897 +#TUNE_RISCV_PKGARCH .= "${@bb.utils.contains("TUNE_FEATURES", "zifencei", "_zifencei", "", d)}" + +TUNEVALID[zba] = "Address bit manipulation extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zba", "_zba", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zba", "_zba", "", d)}" + +TUNEVALID[zbb] = "Basic bit manipulation extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zbb", "_zbb", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zbb", "_zbb", "", d)}" + +TUNEVALID[zbc] = "Carry-less multiplication extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zbc", "_zbc", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "zbc", "_zbc", "", d)}" + +TUNEVALID[zbs] = "Single-bit manipulation extension" +TUNE_RISCV_MARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zbs", "_zbs", "", d)}" +TUNE_RISCV_PKGARCH .= "${@bb.utils.contains_any("TUNE_FEATURES", "b zbs", "_zbs", "", d)}" + +# Construct TUNE_CCARGS +# This should result in a CCARG similar to: +# -march=rv32imac -mabi=ilp32 +TUNE_CCARGS = "${@ '-march=${TUNE_RISCV_MARCH} -mabi=${TUNE_RISCV_ABI}' if not d.getVar('TUNE_CCARGS:tune-${DEFAULTTUNE}') else 'TUNE_CCARGS:tune-${DEFAULTTUNE}'}" + +# Construct TUNE_ARCH +# This should result in an arch string similar to: +# riscv32 +TUNE_ARCH = "${TUNE_RISCV_ARCH}" + +# Construct TUNE_PKGARCH +# This should result in a package are like: +# riscv32imac +TUNE_PKGARCH = "${TUNE_RISCV_PKGARCH}" + +# Misc settings # Fix: ld: unrecognized option '--hash-style=sysv' LINKER_HASH_STYLE:libc-newlib = "" LINKER_HASH_STYLE:libc-picolibc = "" diff --git a/meta/conf/machine/include/riscv/tune-riscv.inc b/meta/conf/machine/include/riscv/tune-riscv.inc index 804712077e..12c1125c8b 100644 --- a/meta/conf/machine/include/riscv/tune-riscv.inc +++ b/meta/conf/machine/include/riscv/tune-riscv.inc @@ -1,41 +1,23 @@ require conf/machine/include/riscv/arch-riscv.inc -TUNEVALID[riscv64] = "Enable 64-bit RISC-V optimizations" -TUNEVALID[riscv32] = "Enable 32-bit RISC-V optimizations" - -TUNEVALID[riscv64nf] = "Enable 64-bit RISC-V optimizations no floating point" -TUNEVALID[riscv32nf] = "Enable 32-bit RISC-V optimizations no floating point" - -TUNEVALID[riscv64nc] = "Enable 64-bit RISC-V optimizations without compressed instructions" - -TUNEVALID[bigendian] = "Big endian mode" +DEFAULTTUNE ?= "riscv64" AVAILTUNES += "riscv64 riscv32 riscv64nc riscv64nf riscv32nf" # Default -TUNE_FEATURES:tune-riscv64 = "riscv64" -TUNE_ARCH:tune-riscv64 = "riscv64" -TUNE_PKGARCH:tune-riscv64 = "riscv64" -PACKAGE_EXTRA_ARCHS:tune-riscv64 = "riscv64" +TUNE_FEATURES:tune-riscv64 := "${@oe.tune.riscv_isa_to_tune("rv64gc")}" +PACKAGE_EXTRA_ARCHS:tune-riscv64 = "${TUNE_RISCV_PKGARCH}" -TUNE_FEATURES:tune-riscv32 = "riscv32" -TUNE_ARCH:tune-riscv32 = "riscv32" -TUNE_PKGARCH:tune-riscv32 = "riscv32" -PACKAGE_EXTRA_ARCHS:tune-riscv32 = "riscv32" +TUNE_FEATURES:tune-riscv32 := "${@oe.tune.riscv_isa_to_tune("rv32gc")}" +PACKAGE_EXTRA_ARCHS:tune-riscv32 = "${TUNE_RISCV_PKGARCH}" # No float -TUNE_FEATURES:tune-riscv64nf = "${TUNE_FEATURES:tune-riscv64} riscv64nf" -TUNE_ARCH:tune-riscv64nf = "riscv64" -TUNE_PKGARCH:tune-riscv64nf = "riscv64nf" -PACKAGE_EXTRA_ARCHS:tune-riscv64nf = "riscv64nf" +TUNE_FEATURES:tune-riscv64nf := "${@oe.tune.riscv_isa_to_tune("rv64imac_zicsr_zifencei")}" +PACKAGE_EXTRA_ARCHS:tune-riscv64nf = "${TUNE_RISCV_PKGARCH}" -TUNE_FEATURES:tune-riscv32nf = "${TUNE_FEATURES:tune-riscv32} riscv32nf" -TUNE_ARCH:tune-riscv32nf = "riscv32" -TUNE_PKGARCH:tune-riscv32nf = "riscv32nf" -PACKAGE_EXTRA_ARCHS:tune-riscv32nf = "riscv32nf" +TUNE_FEATURES:tune-riscv32nf := "${@oe.tune.riscv_isa_to_tune("rv32imac_zicsr_zifencei")}" +PACKAGE_EXTRA_ARCHS:tune-riscv32nf = "${TUNE_RISCV_PKGARCH}" # no compressed -TUNE_FEATURES:tune-riscv64nc = "${TUNE_FEATURES:tune-riscv64} riscv64nc" -TUNE_ARCH:tune-riscv64nc = "riscv64" -TUNE_PKGARCH:tune-riscv64nc = "riscv64nc" -PACKAGE_EXTRA_ARCHS:tune-riscv64nc = "riscv64nc" +TUNE_FEATURES:tune-riscv64nc := "${@oe.tune.riscv_isa_to_tune("rv64imafd_zicsr_zifencei")}" +PACKAGE_EXTRA_ARCHS:tune-riscv64nc = "${TUNE_RISCV_PKGARCH}" diff --git a/meta/conf/machine/qemuriscv32.conf b/meta/conf/machine/qemuriscv32.conf index d3858dc051..aff36c28a5 100644 --- a/meta/conf/machine/qemuriscv32.conf +++ b/meta/conf/machine/qemuriscv32.conf @@ -2,9 +2,9 @@ #@NAME: generic riscv32 machine #@DESCRIPTION: Machine configuration for running a generic riscv32 -require conf/machine/include/riscv/qemuriscv.inc +DEFAULTTUNE ?= "riscv32" -DEFAULTTUNE = "riscv32" +require conf/machine/include/riscv/qemuriscv.inc PREFERRED_VERSION_openocd-native = "riscv" PREFERRED_VERSION_openocd = "riscv" diff --git a/meta/lib/oe/__init__.py b/meta/lib/oe/__init__.py index dd094a874a..73de774266 100644 --- a/meta/lib/oe/__init__.py +++ b/meta/lib/oe/__init__.py @@ -12,4 +12,4 @@ __path__ = extend_path(__path__, __name__) BBIMPORTS = ["qa", "data", "path", "utils", "types", "package", "packagedata", \ "packagegroup", "sstatesig", "lsb", "cachedpath", "license", "qemu", \ "reproducible", "rust", "buildcfg", "go", "spdx30_tasks", "spdx_common", \ - "cve_check"] + "cve_check", "tune"] diff --git a/meta/lib/oe/tune.py b/meta/lib/oe/tune.py new file mode 100644 index 0000000000..7fda19430d --- /dev/null +++ b/meta/lib/oe/tune.py @@ -0,0 +1,81 @@ +# +# Copyright OpenEmbedded Contributors +# +# SPDX-License-Identifier: GPL-2.0-only +# + +# riscv_isa_to_tune(isa) +# +# Automatically translate a RISC-V ISA string to TUNE_FEATURES +# +# Abbreviations, such as rv32g -> rv32imaffd_zicsr_zifencei are supported. +# +# Profiles, such as rva22u64, are NOT supported, you must use ISA strings. +# +def riscv_isa_to_tune(isa): + _isa = isa.lower() + + feature = [] + iter = 0 + + # rv or riscv + if _isa[iter:].startswith('rv'): + feature.append('rv') + iter = iter + 2 + elif _isa[iter:].startswith('riscv'): + feature.append('rv') + iter = iter + 5 + else: + # Not a risc-v ISA! + return _isa + + while (_isa[iter:]): + # Skip _ and whitespace + if _isa[iter] == '_' or _isa[iter].isspace(): + iter = iter + 1 + continue + + # Length, just capture numbers here + if _isa[iter].isdigit(): + iter_end = iter + while iter_end < len(_isa) and _isa[iter_end].isdigit(): + iter_end = iter_end + 1 + + feature.append(_isa[iter:iter_end]) + iter = iter_end + continue + + # Typically i, e or g is next, followed by extensions. + # Extensions are single character, except for Z, Ss, Sh, Sm, Sv, and X + + # If the extension starts with 'Z', 'S' or 'X' use the name until the next _, whitespace or end + if _isa[iter] in ['z', 's', 'x']: + ext_type = _isa[iter] + iter_end = iter + 1 + + # Multicharacter extension, these are supposed to have a _ before the next multicharacter extension + # See 37.4 and 37.5: + # 37.4: Underscores "_" may be used to separate ISA extensions... + # 37.5: All multi-letter extensions ... must be separated from other multi-letter extensions by an underscore... + # Some extensions permit only alphabetic characters, while others allow alphanumeric chartacters + while iter_end < len(_isa) and _isa[iter_end] != "_" and not _isa[iter_end].isspace(): + iter_end = iter_end + 1 + + feature.append(_isa[iter:iter_end]) + iter = iter_end + continue + + # 'g' is special, it's an abbreviation for imafd_zicsr_zifencei + # When expanding the abbreviation, any additional letters must appear before the _z* extensions + if _isa[iter] == 'g': + _isa = 'imafd' + _isa[iter+1:] + '_zicsr_zifencei' + iter = 0 + continue + + feature.append(_isa[iter]) + iter = iter + 1 + continue + + # Eliminate duplicates, but preserve the order + feature = list(dict.fromkeys(feature)) + return ' '.join(feature)