The other day we reported about GigaDevice GD32V general-purpose 32-bit RISC-V microcontroller, and one of the commenters asked whether it was rv32imac or rv32emac, and it turned out to be the former. In most cases, silicon vendors report whether they are using 32-bit, 64-bit, or the upcoming 128-bit RISC-V processors, but rarely go into details, so I asked why it mattered and got the following answer:
RISC-V is a federation of ISA extensions — from the baseline rv{32|64|128}I, to an arbitrary combination of a handful of extensions. There are combinations which are dubbed ‘application-processor level’ (the G subset), but implementations can and often are not G-compliant, which is naturally the case with MCUs. Difference between rv32i and rv32e is 32-strong vs 16-strong GPR file, respectively. In the case of GD32VF103, rv32imac stands for a ‘full-size GPR file, integer mul/div, atomics, compressed (16bit) ISA’ set. What is missing from ‘application-processor level’ (G) is the FPU – F & D extensions.
So I went to look for more details and Wikipedia has a good run-down of the RISC-V ISA bases, and extensions.
RISC-V Bases
There are currently six ISA bases:
- RVWMO – Weak Memory Ordering. Currently version 2.0
- RV32I – Base Integer Instruction Set, 32-bit. Currently version 2.1
- RV32E – Base Integer Instruction Set (embedded), 32-bit, 16 registers with a smaller instruction set. Currently version 2.0
- RV64I – Base Integer Instruction Set, 64-bit. Currently version 2.1
- RV64E – Base Integer Instruction Set (embedded), 64-bit. Currently version 2.0
- RV128I – Base Integer Instruction Set, 128-bit. Currently version 1.7, but not frozen yet.
Provided Wikipedia status information is right, we are more likely to see RV32I and RV64I designs right now since RV32E and RV128I specifications are not finalized.
RISC-V Extensions
Once we have the base we can add extensions to it to define the exact features of the core (frozen extensions – as of July 2023 – highlighted in bold) :
- M – Standard Extension for Integer Multiplication and Division
- A – Standard Extension for Atomic Instructions
- F – Standard Extension for Single-Precision Floating-Point
- D – Standard Extension for Double-Precision Floating-Point
- Zicsr – Control and Status Register (CSR) Instructions
- Zifencei – Instruction-Fetch Fence
- G – Shorthand for the base and above extensions
- Q – Standard Extension for Quad-Precision Floating-Point
- L – Standard Extension for Decimal Floating-Point
- C – Standard Extension for Compressed Instructions
- B – Standard Extensions for Bit Manipulation
- J – Standard Extension for Dynamically Translated Languages such as C#, Go, Haskell, Java, JavaScript, OCaml, PHP, Python, R, Ruby, Scala or WebAssembly
- T – Standard Extension for Transactional Memory
- P – Standard Extension for Packed-SIMD Instructions
- V – Standard Extension for Vector Operations
- Zk – Standard Extension for Scalar Cryptography
- H – Standard Extension for Hypervisor
- S – Standard Extension for Supervisor-level Instructions
- Zam – Misaligned Atomics
- Zihintpause – Pause Hint
- Zihintntl – Non-Temporal Locality Hints
- Zfa – Additional Floating-Point Instructions
- Zfh – Half-Precision Floating-Point
- Zfhmin – Minimal Half-Precision Floating-Point
- Zfinx – Single-Precision Floating-Point in Integer Register
- Zdinx – Double-Precision Floating-Point in Integer Register
- Zhinx – Half-Precision Floating-Point in Integer Register
- Zhinxmin – Minimal Half-Precision Floating-Point in Integer Register
- Zmmul (shortened to “m” as in the CH32V002 MCU) – Multiplication Subset of the M Extension
- Ztso – Total Store Ordering
The first remark is that some extensions are still being finalized, and more extensions are planned as the architecture matures.
RISC-V “Codes” Examples
We’ve learned that GD32V features an RV32IMAC core. Let’s decode what that means: GD32V is a 32-bit RISC-V core (RV32I) with integer multiplication and division (M), atomic instructions (A) and compressed (16-bit) instructions (C). That means it does not feature an FPU, in which case it would have been an RV32GC core (and not RV32IMACFD) if both single and double-precision were supported.
Let’s check another one: Kendryte K210 dual-core RV64IMAFDC / RV64GC processor: that’s a 64-bit RISC-V processor (RV64I), with integer multiplication and division (M), atomic instructions (A), single-precision (F) and double-precision (D) floating-point (I + M+A+F+D = G), as well as compressed instructions (C).
Update: Initially published in August 2019, the post was updated on July 2023 for new bases and extensions
Jean-Luc started CNX Software in 2010 as a part-time endeavor, before quitting his job as a software engineering manager, and starting to write daily news, and reviews full time later in 2011.
Support CNX Software! Donate via cryptocurrencies, become a Patron on Patreon, or purchase goods on Amazon or Aliexpress
Good summay, thank you!
That will be nice if all these extensions are kept under control and properly supported by tools. If not, welcome to hell. I have bad memories of the mess MIPS was. The R5900 of the PS2 Linux was only supported by old tools and that was a pain.
The hell you speak of already exists. Almost all SoCs contain some common IP block with the registers messed with, totally reordered or otherwise broken. This means almost every driver for something that should just work has to manage a bunch of quirks and magic values. Then you have the tens or hundreds of differing interrupt controllers, bus interconnects etc.
At least the RISC-V isa extensions are discoverable at runtime (misa register), can optionally be turned off (misa can be writable) and orthogonal.
> This means almost every driver for something that should just work has to
There’s nothing unusual or uncommon about this in the general driver world. Plenty of peripherals and components come with a dozen different revisions and are all handled by the same driver.
Even at the user facing level I’m currently writing this reply on a CPU core that is at its third or fourth microcode revision, with the 5th bios firmware update and at the 2nd out of 4 PCB revisions. And this laptop been on the market for 3 years…
The fact It’s now done on the core level is really not a big deal and will barely be felt on the code-base.
>There’s nothing unusual or uncommon about this in the general driver world.
and it’s not a good thing. 😉
>Plenty of peripherals and components come with a dozen different revisions
>and are all handled by the same driver.
Take a look in drivers/usb/host in Linux. Notice how many something-hcd.c files there are in there.
A few of those are drivers for “ehci” controllers that are so messed up by the IP vendor that they don’t just work with the generic ehci driver and are an exact copy of it from sometime in Linux 3 with a bunch of hacks to make it work. Then take a look at drivers/usb/musb .. There are multiple glue layers and fudges for a single IP block.
A lot of drivers in the Linux source have ways to override the register read/write functions because just reading a register apparently isn’t something SoC vendors could come up with a standard for. There’s so much bloat and wasted effort that’s caused by SoC vendors obfuscating their hardware for no good reason.
>The fact It’s now done on the core level is really not a big deal and will barely be felt on the code-base.
It’s not a new thing. ARC, Xtensa and others are the same deal where you can configure the IP block and drop it into your design. That’s fine for embedded stuff where the only code that ever runs on it is yours.
I perhaps wasn’t clear enough 🙂
I’m talking about the possible lack of tools (assembler, compiler) for the CPU. If you don’t have that you won’t be able to discover anything at runtime, and you won’t be bothered by your undocumented IP because you won’t be able to build programs that support all of your CPU.
The extensions are optional so theoretically if you only target the base instruction set you will be able run some code and then check if the extensions exist. I think vendors shipping buggy or intentionally broken implementations that require special compiler versions to generate working code will be a bigger problem.
I cringe to this day at the memory of how gcc had ‘supported’ the paired-singles SIMD extension of the ppc750cxe/cl — it was being shadowed by the support for another extension, and so to get 750cxe/cl’s paired singles one had to build gcc with a very ritualistic set of flags.
An apt summary, Jean-Luc! What puzzles me is how some vendors don’t bother giving this information up front in their product briefs, as if labeling their product ‘n-bit RISC-V’ is sufficient to allow their customers make informed decisions. Luckily other RV players are well aware of the importance of the ISA for a CPU they’re selling.
I can’t see any problem with such a lot of extensions because they are all orthogonal. Any risc-v designs can do ALL extensions – may be some of them via an „illegal instruction interrupt“.
> Any risc-v designs can do ALL extensions – may be some of them via an „illegal instruction interrupt“.
That’s a bit like saying it’s turing-complete, no? : )
Chances are that if I’m looking for a MCU part that does mul/div, one that does it via a trap might not be what I’m looking for.
>Chances are that if I’m looking for a MCU part that does mul/div,
MCUs usually have pin compatible series with a low end eco parts and a premium parts because redesigning a board if you need a few more k of flash is a real pain. So I imagine if RISC-V mcus take off past off-brand Chinese parts you’ll be able to get both. And both will be the same die just with the misa bits adjusted by laser or blowing some e-fuse.
No problem with this. If you need this choose the right architecture (i.e. rv32im or above)
I was referring to the ‘any RV implementation doing all extensions’ statement, thus my counter example to that.
ARM soft vs hard float as an example? Sure, there’s an emulator for hard float in the kernel, but trapping illegal instructions and emulating them is a good deal slower than just using inline float emulation and skipping that trip through kernel land.
Yes, that’s a good example. In situations where a missing feature is needed and you have full control of the code, it makes much more sense to implement the feature manually/by lib/by compiler, rather than rely on invalid-op emulation , which is the slowest possible approach.
>it makes much more sense to implement the feature manually/by lib/by compiler
If the only concern is performance which it probably isn’t if you’re using floats but spec out an MCU that doesn’t have those extensions. If you do it via a trap the floating point emulator can be in the “utility ROM” that a lot of MCUs have now. If you have intentionally spec’d a more basic MCU into your project it’s likely it’s because you have a hard limit for the BoM cost and probably don’t want GCCs soft float library pushing your code size up to the next flash tier.
Doing it via a trap means you can use the same binaries for both situations though.
It’s probably a pretty rare case but in MCU land maybe you have a cost reduced version of your product that uses a slightly cheaper version of the MCU without hard floats. If you have the emulation in the RTOS you can run the same binaries on both versions. Libraries like the Apple Homekit ADK ship as binaries so they have to generate 20 different versions for ARM alone. I wouldn’t want to be the guy responsible for validating all of those.
That means it does not features an FPU, in which case it would have been an RV32IG core (and not RV32IMACFD)
It would actually be RV32GC, just like the example you gave below for RV64GC
Thanks. I missed that, and I had not realized the G would also “eat” the “I” of the base. Fixed.
Here’s the ESP32-S2 ULP:
The ULP co-processor implements RISC-V architecture that has the following features:
• Support for IMC instruction set
• Thirty-two 32-bit general registers
• 32-bit multiplier and divider
• Support for interrupts
• Boot by the CPU, or its dedicated timer, or RTC GPIO
This is no more informative than the risc-v docs. Very lazy article.
I don’t think it was meant to be. It does what it says on the tin.
“B – Standard Extension for Bit Manipulation” – That is not totally true (any more)
It was actually
“B – Tentatively reserved for Bit-Manipulation extension”
And that reservation has been cancelled and replaced by four Ratified Extensions:
Zba Address computation.
Zbb Basic bit manipulation.
Zbc Carry-less multiplication
Zbs Single-bit instructions.
(ref: https://wiki.riscv.org/display/HOME/Recently+Ratified+Extensions )
Thanks for the update. The related document still reads “RISC-V Bit-Manipulation ISA-extensions”, so I guess I’ll write extensions to correct the post.