Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I think I get it. I've tried microblaze-v for a while now. And just look at their interrupt handler. https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/sta... . With the FPU enabled at compile time, that's > 128 memory ops per interrupt. That's insane, especially without an NVIC and chaining and all that. My latency was astronomical, and my maximum interrupt frequency was pitiful. Ended up doing the work (sw and hardware options) to get it to operate more like arm-m, but arm-m doesn't need that work to be done. NVIC is always NVIC, and NVIC is good


Yeah, this is a bug. They should only be saving the FP state if it's dirty.

Also this is one of the reasons I think Zfinx is a better option for embedded (i.e., the standard FP instructions operate on x registers instead of f registers): 31 registers is plenty to hold a mixture of integer and floating-point values, and you avoid the worst-case context save penalty.


Not a bug, just not optimized. Because I think there's a csr to read it the fpu is dirty but... That requires csr extension. It would also increase jitter, which in some cases is more important. At best it should be still there as an option, but also optionally improved


Fair enough. It's a performance issue but not a functional correctness issue.

> Because I think there's a csr to read it the fpu is dirty but... That requires csr extension

Yes, and they already unconditionally read that CSR :-)

The "CSR extension" is an almost 100% theoretical concern. It was the spec authors being defensive in case the privileged ISA was so flawed they had to throw it out in future, while keeping the base ISA. I don't see that happening at this point.

The only exception is deeply embedded cores that drop even basic IRQ and exception support. These are always going to exist and I think they're a sufficiently separate class of processor that they don't really factor into the compatibility equation, because such processors usually only run one program in their entire lives.


You know what, you're right. I was thinking of the timer option. I don't think you can turn off the csr functions on that core. But I've gotten into trouble turning off the timer


> That requires csr extension.

Interrupts require the CSR extension. In practice all RISC-V CPUs support Zicsr.


Don't you have to save registers on any architecture, or not use them in the interrupt handler?


No. That's also partially in the article. But even in ones that do, usually it's a subset. In arm-m, some registers get stacked on interrupt (basically the caller saved ones in the ABI so any regular functio is automatically IRQ compatible). In this implementation, 64 registers do. Very different from I think it's r0-r3, lr, and pc. Some architectures bank them, so as long as you don't nest or call functions you can just use the interrupt bank.

RV actually allows for that. But not dictating that registers get pushed to the stack, flexibility in how you manage them opens up. So for RV, and some other architectures, you have to mark the function an IRQ and the compiler will know how to figure that out.

Another gotcha is that for AXI and other burst interfaces, the hardware being able to say "I'm going to send you X words" is dramatically better for latency than each one being a single transaction. So if your stack is in a location that requires multi-cycle memory access times, this balloons in timing cost.

Sadly this is a very hard topic to condense into a few sentences. Maybe if I wrote an article on it with graphics it would help. Unsure


Are all registers caller-saved in RISC-V, or are you blaming the ISA for a specific inefficient implementation and ABI?


The delta is that no, not all registers are caller saved. However, that's how it does interrupts. So they're different. In cortex-m, they're not The hardware/ISA matches the ABI. I'm struggling to find the RV doc that describes it on mobile, but I am confident about it. So in RV, there's no pushing required at all which can save time. Interestingly, it looks like GCC (didn't check others) can compile compilation units with only using some registers. So presumably you could implement some compiler-driven banking of registers... Which I'd never thought about and actually is interesting. RV gives you that flexibility. But you really have to work for it. Which goes back to my other comment. NVIC just handles it pretty well. Especially with ARM recommending 64 bit memory alignment for the stack, it allows devices like the STM32H7 to have 64 bit buses on 32-bit CPUs to halve the transfer time. RV can't do that. No hardware memory ops, no multiple load/store. Trade offs, certainly


It isn't the CPU that's saving all registers here, it's the interrupt handler code, which, if the author wanted to reduce latency, he wasn't forced to save all registers.


> if the author wanted to reduce latency, he wasn't forced to save all registers

Yup.. If author's working with a RISC-V softcore, there are several options to reduce interrupt latency:

  # If softcore saves many registers as a hardware feature: adapt it to not do so
  # Save (and use) only a few registers in interrupt handler
  # Reserve some registers to be nuked by the interrupt handler, and don't use those in application code
  # Use another softcore with faster interrupt response
  # Move to a part with cpu as hard silicon (with sane interrupt handling)
Just to name a few (or some combo thereof).


It depends. On cortex-m, it is the CPU. On RV, it's the code. However, if your IRQs are within the ABI, you are forced to save some registers. I believe Xilinx is overly aggressive with their saving but you still need to save at least some without hardware assistance.


You can bypass AMD's heavy BSP abstractions according to gpt.


Is that what you think that is here?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: