HNHacker News
TopNewBestAskShowJobs

mbitsnbites

383 karma · joined March 21, 2018

submissionscomments
mbitsnbites··on MRISC32 – An Open 32-Bit RISC/Vector ISA (Suitable for FPGA CPU)
The RISC-V authors rely heavily on the argument and assumption that any high performance implementation will do instruction fusion, and the lack of indexed addressing is precisely one of the things that is expected to be fused (see page 6 in https://people.eecs.berkeley.edu/~krste/papers/EECS-2016-130...).

Any implementation that does not do instruction fusion (most implementations - especially lower end ones) are out of luck, and have to pay the penalty of executing extra instructions.

All modern high performance ISA:s include indexed addressing modes (most also have scaled indexed addressing). Some RISC-V implementations add these as non-standard extensions.

RISC-V was not designed primarily for high performance. It targets the extremely low end (education, microcontrollers), and does it really well, and they have this clever trick (compression + instruction fusion) that makes the situation OK:ish for high end implementations. But it's not ideal.

Also worth noting is that instruction fusion is far from free. It may be negligible in a really big implementation that already does things like instruction translation (uOP caches etc), but it sure feels like an unnecessary burden to bring to an ISA that hasn't even had the time to build up a legacy baggage yet.

Furthermore, fused instructions often "leak" data to architectural registers (e.g. temporary registers used for address calculation), which both increases register pressure and requires that fused internal instructions must produce extra outputs (often unnecessarily).

Edit: Consider the following code (https://godbolt.org/z/8YdfoT34o):

  void store(int* array, int index, int value) {
    array[index] = value;
  }
MRISC32:

  store(int*, int, int):
      stw     r3, [r1, r2*4]
      ret
RISC-V:

  store(int*, int, int):
      slli    a1,a1,2   // writes to a1
      add     a0,a0,a1  // writes to a0
      sw      a2,0(a0)
      ret
Note how the RISC-V version clobbers both the A1 and the A0 registers. Thus, a properly fused instruction would have to read from three registers and write to two register (that's bad!), whereas the MRISC32 solution only has to read three registers - no registers need to be written to (same thing for ARM and others). (You could teach the compiler to do an "add a1,a0,a1" instead so that only one register is clobbered, but that adds complexity to the compiler, and the micro architecture may not be able to rely such compiler optimizations but would most likely have to support the case with two clobbered registers anyway).

Edit 2: Another main reason for not including indexed addressing modes in RISC-V is that indexed stores require three source registers (i.e. at least three register file read ports are needed) - which is a big no-no in the RISC-V philosophy. For any implementation above the purely educational level, 3+ register file read ports is the norm, but AFAIK the RISC-V authors have claimed that the base integer ISA will never require more than two source operands. I think that this philosophy weighs very heavily - more so than optimal performance.

mbitsnbites··on MRISC32 – An Open 32-Bit RISC/Vector ISA (Suitable for FPGA CPU)
Yup. Latest and greatest GCC 14: https://gitlab.com/mrisc32/mrisc32-gnu-toolchain
mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
Yes. I run Quake at 320x180 (16:9), but the VGA signal is 1920x1080, so the video HW scales the framebuffer using nearest neighbor interpolation, and then it's all displayed on a super-crisp modern monitor. So the pixels are very sharp and visible.
mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
It would be much simpler to just put the FuryGPU and the MRISC32 CPU on the same FPGA, I guess.
mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
I'm really impressed by your work! I'd love to see more details (like the code ;-) ) in the future.

Perhaps meaningless, but a cool demo would be the FuryGPU being driven by an MRISC32 CPU. Everything custom FTW.

mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
You can visit https://reddit.com/r/fpga There are lots of discussions about learning and getting hobby boards.
mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
Turns out that they were a good fit for the kind of rasterization loops that you find in Quake and Doom. E.g. https://gitlab.com/mbitsnbites/mc1-quake/-/blob/feature/port...

They were also really simple to implement in hardware (basically just a small counter that iterates over vector elements while stalling the CPU frontend).

I have not yet scaled up the parallelism internally (by adding more execution units), but I still see performance benefits (less loop logic & branch overhead, less scalar register pressure, less I$ pressure).

mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
Haha! Infinitely far away (not on my horizon). Thought has crossed my mind, but there are so many other things I want to do first (e.g. audio, superscalar CPU, ...).
mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
The things you do in order to play Quake ;-)

(BTW, recently started eyeing Quake 2 - but will have to work more on the CPU performance first)

mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
Realistically: No that won't happen (sorry to disappoint you).

There are some niche demos, like a HW raytracer on an FPGA, but full systems is not realistic. General purpose code simply is a bad match for FPGAs.

mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
So I realize that the title is slightly misleading. It's obviously not a pure hardware implementation of Quake, but rather the original Quake software renderer running on a custom soft processor in an FPGA.

I like to use it as a benchmark while developing the CPU. E.g cache performance and branch predictor performance is so much more interesting in the context of a full game, rather than some boring synthetic benchmark.

The reason for the title, though, is that I have not seen many instances of Quake running on an FPGA, in any form (Doom is fairly common, but not Quake).

However there area few interesting projects on the aame theme:

* Quake level viewer with a custom GPU and a RISC-V soft processor: https://twitter.com/sylefeb/status/1564758778830065666

* A pretty fast general purpose GPU on an FPGA that can display Quake (FuryGPU): https://www.youtube.com/@dbarrie/videos

mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
There are efforts to bring FOSS FPGA tooling. Check out Yosys (still far from as mature as LLVM though). But yes, I agree...
mbitsnbites··on Quake on an FPGA (MRISC32 CPU) [video]
That would be closing the circle. Back in the 1970's some video games were more or less purely implemented in hardware (e.g. I believe Pong was originally implemented with discrete TTL chips, and a later hone version was implemented in a single VLSI chip).
mbitsnbites··on Ask HN: Is the weaponisation of ChatGPT now inevitable?
I think that there's a real risk that "information becomes useless" in the AI era. Neither text, speach/sound, images nor videos can be trusted, and it's far toi easy and rewarding for unscrupulous actors to use AI to put out fake/biased news/comments/opinions/media.
mbitsnbites··on Debunking CISC vs. RISC code density
The article has been updated with -O2 numbers.

Spoiler alert: ARM & RISC-V still win over x86 & z/Arch.

mbitsnbites··on Debunking CISC vs. RISC code density
I believe that ARM has a patent on a workaround. Apple M1 has 192KB L1I.
mbitsnbites··on Debunking CISC vs. RISC code density
My experience from Thumb was that it makes code slower. Probably because the CPU had to execute more insteuctions than in "ARM" mode.

Thumb was a thing for embedded systems with very limited RAM etc. It was not designed for optimal speed.

My guess is that ARM64 targeted higher end, and that severe memory constraints were no longer considered a big issue. ARM has its Cortex M4 (Thumb only microcontrollers) and the likes for those markets.

mbitsnbites··on Debunking CISC vs. RISC code density
It wouldn't matter. I still would not buy an i386, compile my programs in 32-bit mode instead of 64-bit, nor use the i386 ISA as a model when designing a new ISA.

Same thing with 6502, Z80, Vax, etc.

What matters is performance, and i386 code does not give as good performance as x86_64 code or modern RISC code (it doesn't have as many GPRs etc so it can't).

mbitsnbites··on Debunking CISC vs. RISC code density
The results mean what they mean: If you compile your software with GCC -O3 you will typically get smaller code and fewer instructions on average for modern fixed size RISC ISAs than for modern CISC ISAs.

You would have to do further and other investigations to draw any other conclusions.

mbitsnbites··on Debunking CISC vs. RISC code density
1) i386 is not representative of bleeding edge CPU architectures (as mentioned in the article). It would only be icluded for purely academic reasons - which was out of scope.

2) ...

3) In the real world most programs use a single optimization/tuning config for the entire program.

The article aimed to analyze real world programs running on contemporary modern architectures.

mbitsnbites··on Debunking CISC vs. RISC code density
I just don't see how I would run profiling counters on a z15 machine for instance ;-)

With my limited resources this got me much more architecture coverage.

And as usual, the answers are in the data, it's merely a matter of what questions you think that you are asking...

mbitsnbites··on Debunking CISC vs. RISC code density
Code density is not all about instruction length. It's also about instruction count. With shorter instructions you usually need to use more instructions to do the same thing (e.g. extra MOVs or stack spill etc).
mbitsnbites··on Debunking CISC vs. RISC code density
The 32-bit operands are actually hurting code density most of the time. An instruction that would take 4 bytes in a RISC ISA takes at least 5 bytes in a CISC ISA.

Same thing with the 32-bit offsets for x86_64 conditional branches.

Edit: With "CISC style" I meant those instructions that use implicit registers instead of GPRs and/or do fancy multi-operation stuff, like LOOP or POPA/PUSHA etc.

mbitsnbites··on Debunking CISC vs. RISC code density
One of the problems with the decoder is that it's "always on" so it always draws power (unlike the SIMD unit, for instance).

I also think that the uop L0 cache is closer to where the L1I cache is in a fixed width RISC implementation. The L1I cache of an x86 machine is quite far away from dispatch (in terms of pipeline stages). I think that z/Arch has something like 5-10 stages between L1I and dispatch, for instance.

And if you start comparing the uop cache with an L1I$ of a fixed width RISC machine, things dont't look good for CISC (the uop cache is extremely inefficient in terms of capacity/silicon, only holding a handful kuops). It's probably not an entirely fair comparison, but neither is comparing the L1I$ of a CISC machine with that of a RISC machine.

I don't think it has so much to do with being transistor limited as it has to do with keeping the latency sensitive parts tight and avoiding unnecessary pipeline stages etc. It's "easy" to throw transistors on L2 & L3 cache, but minimising branch misprediction penalties and keeping a wide pipeline 100% fed with instructions all the time is trickier.

mbitsnbites··on Debunking CISC vs. RISC code density
I agree, but in absence of an accurate method this felt like the second best method.

Then there's also the elephant in the room that I'd like to write an article about some time: The decoder/translator + uop-cache in the front end has a devastating effect on instruction fetch & decode performance. That silicon eats power, could be used for better things (larger L1I cache etc), adds latency, limits how wide you can decode, and so on.

Rationale: CISC is not just about density. With good RISC you can get much better fetch & decode bandwidth (all other things being equal). E.g. see Apple silicon.

mbitsnbites··on Debunking CISC vs. RISC code density
Will have a look at -O2, time permitting.
mbitsnbites··on Debunking CISC vs. RISC code density
> I would expect the -O2 numbers to reflect better the actual ISA capabilities.

I will have a more thorough look at -O2 too, good point.

However w.r.t. "ISA capabilities" the simple fact is that compilers don't use CISC style instructions. They prefer RISC style load/store + many GPRs code, and new x86_64 instructions are modelled after this paradigm. Hence I wouldn't expect there to be a huge difference at -O2 (and in my experience x86_64 often loses at -O2 too).

mbitsnbites··on Debunking CISC vs. RISC code density
Simple: Optimizing for small code size is uninteresting for 99% of the software that a CPU runs. What matters is performance (especially when you argue that dense code is good for performance), and most real world software is optimized for performance.

I get the argument of -O2 vs -O3 and I'll be sure to measure that. However my experience is that x86_64 does pretty poorly in -O2 too compared to RISC.

mbitsnbites··on Debunking CISC vs. RISC code density
Just using I$ hit ratio is problematic in many ways. E.g:

- You'll probably not find implementations of different ISAs with identical cache configurations (size, associativity etc).

- It says little about what work is actually done (different ISAs = insns do different amounts of work).

- On x86 all bets are off w.r.t. the effect of the uop cache on the L1I cache hit ratio, and the uop cache hit ratio can't be compared to any other machine.

- You need to reproduce the same program flow on different architectures to be able to compare the numbers.

...etc.

I think that the only reasonable way to do it is to have a multi-ISA simulator where you are in full control of all these aspects. And it would be really hard work.

mbitsnbites··on Avoiding Premature Software Abstractions
My general rule is: Don't abstract something before you have at least two different implementations that serve roughly the same purpose.
← PreviousPage 3 of 4Next →