Posted by dmitrygr 1 day ago
"Good enough ISA plus zero licensing cost" beats "perfect ISA plus royalties" in the embedded space.
Also, let's not forget that the reason the world is built on the von Neumann architecture is that it was made available for free.
[1] - https://www.eenewseurope.com/en/espressif-moves-exclusively-...
The conclusion is honest, and you can of course brute force any ISA into any role. I used to loathe x86 for that reason, but now that I'm older I respect the game.
It just blows my mind sometimes when designers don't learn insanely obvious lessons from the past, basic stuff like "complexity is evil" and "make the fast path overlap with the most common use cases" and "a standard with N optional extensions is actually N! (N factorial) standards."
That being said all real world architectures seem to have messy corners and warts. RISC-V was a chance to do away with a lot of that and they... didn't?
One of the things I've been playing with off and on in my spare time is poking at the x86 ISA. And yet, while the ISA does have some weirdness to it, it is a lot less weird than its reputation makes it out to be. For example, the sum total of the opcode form amounts to does-it-have-ModR/M + size of immediate operand (in bytes)... which honestly strikes me as simpler than RISC-V instruction form decoding.
I know there's an earlier criticism of RISC-V that points out that one of the common instruction sequences for which "macro-op fusion" is the suggested solution involves 5 instructions... and I don't think any of the existing chips ever fuse more than 3 instructions?
I don't think that's actually true. There's weird historical baggage and whatnot. But if you're running in long mode, it's actually a fairly sensible architecture with useful memory addressing modes.
The underlying truth seems to be that a “clean” ISA doesn’t by nature make the beer taste better, and many of the warts probably have a reason for existing.
In particular, the next generation might recognize some aspects that seem bad and be confused over how to prioritize correctly because they don't know any better.
It is just that it is some combination of behind closed doors, for competitive advantage, and/or the new generations don’t want to hear it.
Previous generations had learned long ago that sharing everything in public, or even in patents, was a bad idea for long term survival, a lesson that has now taken on a more extreme form.
As a fellow olderster, I can't help but think that after almost 50 years of "ISA X is sooooo much better than x86 it's obvious ISA X is the future and x86 will be dead Real Soon Now (for whatever todays version of x86 is)" I can only shake my head ruefully and say "ping me when that happens".
Controversial Take (that history proves isn't): Software matters; ISAs don't.
Today, we have Intel and AMD, and some bit-player embedded folks.
Humans are weird.
They always had a much cleaner instruction set internally, going back to the 8086.
If what they say is true, then x86 won because ISA doesn't matter, precisely because ISA is the public instruction set architecture. If you can convert anything to a better representation then the argument of exposing the better representation doesn't actually follow.
Additionally, you are claiming that an internal implementation detail that only Intel and AMD know about is secretly implementing your favourite instruction set, which when you think about it, is incredibly implausible and impossible to prove. It's eerily similar to an unfalsifiable theological claim.
Then there is the silly argument that x86 chips don't exist anymore, when x86 chips have distinctive differentiating factors that make them unlike chips that implement other ISAs. The most obvious one is that x86 is primarily used in the personal computing and server space. This means the chips focus on high single threaded performance with large caches and large core counts plus swappable memory and storage devices, whereas most ARM and RISC-V devices target a completely different space, primarily embedded devices where everything is included on the PCB and there are very few external interfaces. You have to be pretty delusional that an unfalsifiable claim on an internal architectural detail of a CPU core somehow invalidates the rest of the silicon that happens to be on the same die.
I hate comments like yours because they are self defeating and require a lot of effort to debunk.
I suspect Vulkan suffers from the same design by committee problem, which similarly caused it to miss seemingly basic features in the base spec that then need to be filled in with extensions and also made it too difficult for developers to want to move too.
Most MCUs are used for dead-simple solutions, like electric blankets and microwaves with segment displays or LEDs. Whether their interrupts are handled in 44 or 22 cycles doesn't really matter that much.
And RISC-V does have a link register, making returning much faster when the parameters for the interrupt can all fit in registers and no external memory access is needed, as is the case with most MCUs which put the stack in RAM. To fetch the return address an external memory access is always needed even if there are no parameters.
We already had the mystery meat CPU wars several decades ago. We know how to make sane ISAs now and should be past that.
Armv9-a doesn't mandate FP or SIMD support, but nobody does detection for those, why? Because it's required on the OS level. Similarly OS are moving their baseline to RVA23 so software can assume all of those instructions are available.
Different problems require different solutions. An electric blanket doesn't need a barrel shifter for multiplication or even floating point hardware. The ISA can change depending on what's needed to solve a particular problem, not to provide an "one size fits all" solution.
That's how a sizeable chunk of software is written and shipped.
Runtime detection of CPU features is very much a thing, and is in fact used extensively in software you use or interact with every single day.
Just as a quick example, OpenSSL's approach for x86_64 is OPENSSL_ia32cap
https://docs.openssl.org/master/man3/OPENSSL_ia32cap/
This ensures (in theory, at least) that even if you're using your linux distribution's openssl library which is more generically targeted, you will get optimal/native runtime performance for your actual CPU.
Especially consider the possibility that a product manager decides to swap out the core for a different core to save 5¢ on the BOM. Does the product manager know to ask if the two cores follow the same RISC-V profile? Do the software programmers think to ask? How about communicating the change to all of the vendors or contractors providing you binary blobs? I don't know how likely it would be for a scenario like he author here describes, but it is definitely a plausible scenario.
Even if the core was supported just fine, all of the IO mux stuff is pretty much guaranteed to be different even with the same chip in a different package.
You're looking at explicit support for each chip.
In practice, this is not the case. The scenarios mentioned in the article involving binary blobs are pretty common, as well as other similar scenarios.
Really, I'm going to go out and say it bluntly: it is just completely freaking stupid to make an architecture where everything is optional but you have no way to query what's present. If you're going to go the optional-pieces route, you have to have a query mechanism of some sort. As the article explains, you cannot even trap instructions on RISC-V to figure out what your core supports, because bad instructions might belong to some other option. Complete. Idiocy.
But you'll practically be passed a device tree from SBI that will tell you.
Where are you getting the idea that RISC-V is dominant? As someone who works in this space, that doesn't jive with my experience or the sources I've seen.[1] 32-bit microcontrollers only recently achieved a majority market share for gosh sakes!
RISC-V is claiming that they have achieved 25% market share across selected segments, but they're still behind ARM (and x86).[2]
[1] https://www.grandviewresearch.com/industry-analysis/microcon...
[2] https://www.aestechno.com/en/risc-v-2026-arm-x86-market/
In terms of dollar volume ARM is still the leader, especially for higher-end (application level MCUs) stuff. RISC-V MCUs with MMUs or MPUs are scarce at the moment.
MPUs are more common. The Physical Memory Protection option is basic and allows ranges of memory to be set unavailable in user mode. A few well-defined ranges do let you lock a user process down securely but it's not a real MMU. Low-end microcontrollers don't have enough RAM to warrant a real MMU.
The RISC-V core in the Raspberry Pi RP2350 has PMP as do the ESP32 cores.
I do find it odd that you go on and compare to x86 marketshare however, the topic you've quoted is very clearly about MCU and whilst 8086 MCU still exists they haven't been used in greenfield projects for decades. Let alone any more recent x86 implementation.
Do you really think Chinese manufacturers are going to buy ARM MCUs when their budget for a controller is less than 10 cents?
ARM has long ceded this market to RISC-V. It's mostly focusing on high-end application MCUs and AI now.
And lots of newer stuff is making use of standardized boards like Raspberry Pi Pico (RISC-V and ARM hybrid) or ESP32 (RISC-V too on some versions).
Because nobody will write software for 300 unique hardware variations of a platform that have inconsistent capabilities. Consistency is one of the reasons why x86-64 with extensions like like SSE, AVX2 etc is popular.
They didn't choose 8051 there for experience, but because it was a tiny core with a decent IPC they could license for a small part, then focus on the main cores. I wouldn't be surprised if they eventually switch to riscv there too.
Also, these 8051 cores tend to be extremely diverse. I don't think I've come across cores from different manufacturers that were actually compatible for real code. They all seem to want to handle accessing 16/32 bit memory differently, have different interrupt details, etc.
I really don't know anything about this space, but you just said that 8051 is dominant because it has one dominant architecture since the 70s. It has hundreds of manufacturers making identical parts.
As you say, software matters. If the Software can't run because of hundreds of extensions that can't be checked for, then you're going to pick a target that works, no? So in fact the ISA matters most: which ISA has the most software? Which ISA means my software runs on the most devices?
And yet you couldn't help yourself...
but you just said that 8051 is dominant
I said absolutely no such thing.
If the Software can't run because of hundreds of extensions
The software in the x86 world runs because there aren't hundreds of mutually incompatible extensions. I think the last time there was a major completely incompatible x86 ISA divergence was AMD "3DNow" vs other SIMD extensions. AFAIK the rest were "processor X got feature Y later than competitor Z".
Which ISA means my software runs on the most devices?
Easiest question evah: x86.
SSE has inconsistencies like SSE4.x vs SSE4a. AVX is an even more mixed bag. There are some 19 AVX-512 extensions and ZERO chips support all of them.
The situation is so bad that AMD and Intel got together to make AVX10 to unify everything. That seemed great, but Intel now has AVX 10.1 and 10.2 in addition to the base set, so there we go again...
x86 is a massive battleground with tons of competing extensions like FMA3 vs FMA4 (why did FMA3 win???) and in cases where one of the competing variants didn't win, we get something like virtualization extensions being completely different between Intel and AMD. There's also the rash of security extensions that have gone through various support and dropped support (not to mention using some of this stuff for market segmentation and further fragmenting the ecosystem).
x86 is anything but consistent if you look into its history (or even it's present).
Who said they have to? One can select a RISC-V configuration for a baseline for a particular purpose. Desktop? Choose the one that's most powerful.
ARM is more popular than x86 and is less consistent than it.
The reality? The fastest "available" RISC-V CPUs don't match the best chips in terms of speed, power consumption, or die area. "available" obviously means the chips that have been released to the public and can be independently benchmarked.
I do think that is okay, however I also think that those involved with RISC-V aren't helping much, and current attempts at standardizing seem to be just creating a bigger problem.
That being said, RISC-V does seem to perform well in specific niches.
- A big problem with extension detection RISC-V has is that there's no central authority mandating vendors to not overlap things (obviously, given RISC-V being an open standard), so basic bitmasks for supported extensions is generally rather problematic (and of course even if you collected a standardized bitmask of all extensions from all vendors, it'd grow quite massive quite quickly); you'd at least want some grouping/marking by vendor, if not full extension strings. That said, it would be nice to at the very least have some standard in-memory blob format if nothing else, that you could query from any OS/libc. (which maybe somewhat-exists to some extent with a C API meant for libc, but as-is still doesn't attempt to figure out vendor extensions).
- many, if not the vast majority, of aarch64 TBZ/TBNZ are probably branching on a boolean; something RISC-V can also of course do in one instruction. Generally, comparing instruction frequencies across ISAs is messy if not approximately meaningless due to different sorts of things existing for solving the same tasks.
- "Having this happen means that instead of a clearly-understandable crash you get ... well ... anything." - RISC-V will do you one better - it doesn't even guarantee a crash when an instruction isn't defined at all! Overlapping extensions is definitely messy for disassembly, sure, but that's also just basically unavoidable as long as RISC-V is open (see my first point). (perhaps there could've been stricter rules for reserved-for-standard encodings than reserved-for-vendor ones? of course still doesn't help vendor encodings, nor non-compliant vendors)
> The spec says that bit must be zero, and yet no encoding uses the space opened up by that bit being one.
The spec says "the code points with shamt[5]=1 are designated for custom extensions.", so the space is specifically reserved for custom vendor extensions.
So, if I wanted to add a custom "dzaima.c.clear_top_n_bits rd, imm5" instruction, that's space I could safely put it in, knowing that no future standard instruction will be added there that I may regret overlapping. So while that space goes unused in the standard, its existence helps with the overlapping encoding problem!
> For I-type instructions, bit 1 [...], bit 11
Of course, that's cherry-picking two of the 25% of bits that have multiple positions they come from, and specifically 11 as it's the worst one. Full stats:
1 position: 24 bits: (everything that's not listed below)
2 positions: 7 bits: 0, 1, 2, 3, 4, 12, 20
3 positions: 1 bits: 11 (the single worst case)
So that's like 9 muxes for merging all immediates to the same place (or less of course if the different encodings' immediates go to different places), the rest is just wires.Obligatory note is that some of the funkiness is to place the sign-extended bit in the same bit position, so some saved muxes from that.
Now, I am a "software person who's never written verilog", but I highly doubt a 3:1 mux is as cheap as a 2:1 mux in silicon, so even if you always need to merge in the sign bit, reducing the number of cases is still beneficial.
Compressed does make it a ton more ugly though (combining both 32-bit and 16-bit instruction encodings, placing the 16-bit ones in the low 16 bits):
1 position: 13 bits
2 positions: 7 bits: 10, 13, 14, 15, 16, 17, 20
3 positions: 4 bits: 3, 4, 9, 12
4 positions: 5 bits: 0, 1, 2, 5, 11
5 positions: 3 bits: 6, 7, 8
looking at aarch64 on https://asmjit.com/asmgrid/: tbz Xt, #imm, #relS*4 imm:1|0110110|imm:5 | relS:14 |Rt
lsl Xd, Xn, #n 1 1010011|01|immr:6|imms:6|Rn|Rd
Fun! (lsl being a subset of the bitfield extract instrs is neat; tbz's similar-functionality 6-bit field is just entirely-differently placed though. Also.. using the Rd slot for an input-only Rt? that's one thing RISC-V doesn't do, even across compressed and 32-bit instrs!)None are. There is CBZ/CBNZ for that. https://www.scs.stanford.edu/~zyedidia/arm64/cbnz.html
It is just THAT useful to branch in a bit.
There is still plenty of unused 32 bit (30 bit) opcode space.
I really do hope that the arch is eventually able to fix this. Better that there be an open ISA than them all be closed IMO.
RISC-V somehow manages to be more fragmented than x86 (which is impressive), and just can't compete on instruction density.
I think a large part of the issue with RISC-V is that it predates (public knowledge of) ARMv8 by a year or two, so it couldn't use it as inspiration. If you compare RISC-V to 32-bit ARM, the comparisons are much more favourable.
Does it? https://people.eecs.berkeley.edu/~krste/papers/EECS-2016-1.p... has a section on ARMv8 (section 2.5)
It says they became aware of it a year after they started the RISC-V project, but that’s five years before that paper was published.
But version 1.0 of the spec [1] was released all the way back in May 2011, and the first RISC-V chip was taped out at the same time. This is 5 months before ARMv8 was even announced, and we didn't start seeing actual aarch64 chips until late 2013.
And TBH, I'm not sure anyone realised just how good of an ISA aarch64 is until quite a bit later.
RISC-V 1.0 isn't binary compatible with modern RISC-V, they hadn't frozen the encoding, but rough design is all there.
[1] https://www2.eecs.berkeley.edu/Pubs/TechRpts/2011/Archive/EE...
The only reason it's "competitive" is the compressed instructions, which means it's paying all the costs of variable length instructions, yet only getting marginal benefits. IMO a modern ISA taking advantage of variable length instructions should be able to absolutely smash the code density of a fixed width ISA like aarch64. At minimum, it should be competitive with x86 code density, if not smashing that too (because x86 has a lot of legacy baggage)
Compressed instructions aren't a bad idea for very small cores. They give you a decent code density boost with minimal added complexity.
But for large cores you either want to go full fixed length (like AArch64 and Qualcomm's proposal, which bought non-compressed RISC-V into the range of AArch64) or adopt a much more complex variable length scheme that can actually beat x86 on code density.
It is a different front end design, so that's why Qualcomm didn't want to reengineer their aarch64 core more than they had to, but the rest of the riscv community was right to not embrace it.
Not to mention that a lot of the aarch64 derived pieces in the proposed qualcomm extension are almost certainly patent encumbered. Qualcomm can absolutely handle just about any patent fight, but other risc-v companies can't.
The important point is that there is no reason why a 16-bit/32-bit encoding shouldn't have smashed Aarch64's 32-bit only code density.
My secondary point, is that why should RISC-V limit itself to just 16-bit/32-bit? It has the encoding space set aside for 6 bytes, 8 bytes, 10 bytes and all the way up to 24 bytes (which is overkill). If it's already paying the variable length tax, it should be making better use of it. IMO, a 2, 4, 6, 8, 10... byte scheme should be able to massively improve on x86's code density.
I'm saying the opposite. Maybe some theoretical CISC-V would leave RISC-V behind, but x86(and -64) makes wild choices for instruction density, and RV64GC already clearly beats x86-64 in .text density.
> My secondary point, is that why should RISC-V limit itself to just 16-bit/32-bit? It has the encoding space set aside for 6 bytes, 8 bytes, 10 bytes and all the way up to 24 bytes (which is overkill). If it's already paying the variable length tax, it should be making better use of it. IMO, a 2, 4, 6, 8, 10... byte scheme should be able to massively improve on x86's code density.
There's nonlinear issues as you add more options. A 16-32 decoder is pretty simple, a 16-32-48 isn't the worse thing in the world (and a 32bit immediate might make it worth it), but you start to hit weird explosions in gate count once you go much past that. Hence x86's splitting into essentially multiple front end banks in modern designs, and even then typically only has one decoder per bank that can decode everything, and even that takes multiple cycles for some instruction sequences, even just to discover the length.
The larger lengths in the RISC-V spec are more targeted towards bespoke stuff like GPGPU that's maxing out issuing a single instruction per instruction stream anyway. When you look at shader machine code, it's clear density was essentially an afterthought, but they love them some 64bit wide instructions. Which unsurprisingly is pretty much the same width of vertical microcode in archs that still do such a thing.
Maybe I'm misremembering. Or maybe the numbers I'm remembering took into account the fact that most compilers unroll more aggressively on x86 than on targets they consider to be "embedded" (another pet peeve of mine)
I stand by my assessment that the code density of rv64gc (and especially rv64g) is lower than it would be if they had actually put a focus on code density.
> A 16-32 decoder is pretty simple, a 16-32-48 isn't the worse thing in the world (and a 32bit immediate might make it worth it), but you start to hit weird explosions in gate count once you go much past that.
Not sure I would say 16-32 is simple, certainly massively simpler than x86. My point is that you have already paid the tax for going variable length, and 16-32-48 isn't that much more complex. And probably worth it for 32-bit immediate/offsets.
And maybe 16-32-48-64 is worth it... Hard to tell, but I wouldn't entirely rule it out without study. The advantage would either be immediates/offsets that are too big to fit in 48 bits. Or some kind of VLIW style scheme which actually packed three 20-bit instructions into aligned 64-bit packets. (Or other mixtures of sizes like 30-30, 30-15-15, 40-20, or 15-15-15; We are talking about a complete break from RISC-V. There is a thread somewhere on HN where we brainstorm something like this).
But beyond that, no point really. Just pointing out that RISC-V reserved the space.
Maybe I need to prototype the 64-bit aligned packets idea someday, at least far enough to get instruction density numbers.
It is, with a prefix encoding, you can reuse the RVC decode path 1-to-1 and get the 48/64-bit instruction starts with a simple bitshift (or simply handle the 48/64-bit instructions via the fusion path). This seems to be the encoding direction RISC-V is headed in.
Arm uses complex instructions with multiple writeback, that require cracking, to improve code density. RISC-V uses a variable length encoding to improve code density. Both have anaougus decoding complexity, but RISC-V achieves higher code density, while impacting the cost of things before decode (how much, idk).
> Arm uses complex instructions with multiple writeback, that require cracking, to improve code density.
While smaller cores have the option of cracking the multiple writeback instructions, many arm cores just pay the extra cost of having a 3 read, 2 write register file, so they aren’t actually cracking those instructions.
They do crack other instructions.
But the cracking seems to be more about ALU limitations (aarch64 has instructions that can do both a shift of any width and an add, but the ALUs might not support this, or only support smaller shifts of 1-3 bits (useful for addressing)
What this means is that despite the cracking, each μop in an aarch64 core is quite a bit more powerful than a typical RISC-V instruction (especially compressed instructions).
So to be competitive on backend performance, a high performance RISC-V is going to spend a lot of resources post-decode doing massive amounts of instruction fusion to try to get μops of similar capabilities to aarch64 (or just settle for simpler μops, and pay scheduling costs of more μops)
So the costs of the RISC-V compressed instruction approach aren’t just limited to pre-decode.
No, every high performance core I know of cracks them at decode, some re-fuse some of them after rename (Apple). Because otherwise you would need to rename up to 4 destinations per rename slot, effectively 4xing your already limiting rename stage.
Cracking other stuff later in the pipeline isn't expensive.
Though, I guess fusing after cracking makes things easier because you don't actually have to search for fusion candidates (supported by the fact that Apple's Firestorm doesn't seem to make any effort to fuse things that aren't alu + branch, crypto, or amx)
Yeah, fusing is probably easier, if you already know what to fuse. On the other hand, if you want to fuse load pair on RISC-V you have the entire rename stage to figure out which uops can be fused independently of the rename stage, if fusion haopens after rename as well.
That's a good point.
If some RISC-V μarch was going to invest the extra gates for a complex fusion setup, the search isn't actually going to slow anything down, as it can run in parallel with other frontend operations (like renaming).
I always just assumed fusion was done as early as possible, only considering instructions that are right next to each-other (that's certainly the intent of the RISC-V spec), and then resolved immediately after decode.
But maybe it's better to do it right at the end of the front end; After renaming, during insertion into the scheduler.
Despite my curiosity, I explicitly refused to agree to Apples terms for accessing those documents, because they were very draconian. The terms absolutely forbids using the information for anything other than optimising software for apple devices.
Discussing the design tradeoffs of RISC-V μarches couldn't be further from "optimising software for apple's devices".
Ah, I suppose.
Such as? I can't think of anything it does better for high performance cores.
With RISC-V, multiple instruction workarounds are needed for all of the above, and those sequences are usually sequentially dependent ones so they can't be run in parallel. i.e. the insanity of loading a 64-bit value through repeated 12-bit immediates with shifts, using multiple instructions to compute branch offsets, and RVV needing setvli instructions everywhere due to not having opcode space to encode vector length/type.
AArch64 is better, but still has problems with limited opcode space when it comes to future extensions. They've had to make "start mode" and "end mode" for SME to save on opcode space, and future compromises will likely be necessary.