Huh, it does have CLZ on all ALUs (And CLZ can actually be used to reduce the cost of checking for all zeros).
So it must be something about limiting the complexity of the flags register file and/or its bypass network.
> But I hadn't considered the ISA design option of only carry flag, no seperate cmp and branch, before.
Well, RISC-V does have a decent point: Most of the time you simply don't need flags. The only area this approach falls apart is detecting overflow or add-with-carry.
So, why not just cover that flaw by adding a carry/overflow flag.
The counter-argument is that as soon has you "ruin the purity of the design" by adding one flag, you might as well add the complete set of all four. Then you can simply branch instruction encodings, and use the extra bits for something else (like seperate set-flags versions of all the ALU instructions)
> So, why not just cover that flaw by adding a carry/overflow flag.
Actually, why not just have a single generic 1-bit flag?
You could still have cmp + branch, but now you put the comparison type into the cmp. This gives you a larger branch range again. A flag setting add/sub could also simply set that flag on carry. cmov works, some form of ccmp also works.
Designing an ISA arround carry flags certainly gives you many goodies: cmov, adc, ccmp, larger branch range
Well, cmov is absolutely possible without flags. You see such "select" instructions all the time on GPUs. Doesn't even require an extra instruction, cmp + cmov is two instructions, seqz + select is two.
But it does require three input registers. One for a control value, plus the two options. And RISC-V has a thing about not requiring three input registers.... Yeah, I'm not a fan of RISC-V.
One of the other major advantages of flags is it allowed for a cheap third input to certain instructions (like cmov, adc, ccmp), without requiring a full 3R1W register file.
The fact that it's possible to design a viable ISA without flags is really neat, it was absolutely worth trying. But MIPS already proved it was possible, and showed all the downsides, it did not need to be tried a second time with RISC-V.
> Well, cmov is absolutely possible without flags. You see such "select" instructions all the time on GPUs
Well, yes, because GPUs need 3r1w anyways, for fmadd, and because a dedicated cmov (blen/merge) is a lot more important in those workloads. RVV also has "cmov" vmerge and full predication in general.
RISC-V wants to avoid needing to 3r1w on the integer side.
> But it does require three input registers. One for a control value, plus the two options. And RISC-V has a thing about not requiring three input registers.... Yeah, I'm not a fan of RISC-V.
Arm also tried to avoid 3R1W on the scalar integer side. It's really only madd (on one or two ALUs) and some of the complex load/store ops, which are usually cracked.
My guess is that arm has 3R1W integer instructions, because they needed load/store pair for code density. That means they have to support renaming 3R1W integer instructions, so you may as well add integer madd. I don't think they would've added 3r1w if it wasn't for the complex load/stores.
> One of the other major advantages of flags is it allowed for a cheap third input to certain instructions (like cmov, adc, ccmp), without requiring a full 3R1W register file.
Exactlty. Although I don't think the 3R1W instructions increase the register file size that much, because it grows linear with read ports and you usually don't need the full read bandwidth on very wide cores, as you can do port stealing. I think it's mostly about rename.
> But MIPS already proved it was possible, and showed all the downsides, it did not need to be tried a second time with RISC-V.
I think it's a fine way to design an ISA, however Zicond should've been on the base ISA.
> some of the complex load/store ops, which are usually cracked
Ah, cracking. Another thing the RISC-V ISA will try to avoid at all costs.
> I don't think they would've added 3r1w if it wasn't for the complex load/stores.
Agreed. The complex load/store addressing is one of the fundamental parts of the original ARM design, and IMO the only one that really survived into AArch64 unscathed.
It actually needs to be 3r2w so that it can writeback both the updated base register and memory value for indexed loads.
And if you already need 3r2w (or to emulate it via cracking), might as well add other instructions to take advantage of it.
> I think it's a fine way to design an ISA
Really depends on what the design criteria are. If the goal is to create a "better MIPS" or "Easy to implement ISA, great for education" or "Optimised for low-transistor classic-RISC pipelines", then avoiding flags is a great idea.
And a good idea to avoid cracking, it just adds complexity and pushes you away from that "RISC purity". TBH, I'm a little surprised they got rid of branch delay slots, but I guess they really confuse people writing assembly (or compilers).
In many ways RISC-V is a great ISA, the extendability and openness is unparalleled and it does actually deliver on scaling all the way from ultra-low transistor designs, all the way up to high-performance out-of-order cores.
But if the design criteria is "An Open ISA optimised for the modern era", then I think RISC-V falls short. And the choice to avoid flags is one of the many minor issues that add up to making RISC-V sub-optimal for higher-end μarches.