Hi Jonathan,
If you can get the easier method going of masking the interrupt controller interrupt output in BBL before returning from machine mode, that solved the problem for me
Sorry for the previous misleading information but in the latest Rocket the platform level interrupt controller is integrated by default.
Although documentation is scanty on how this works you can get a good idea by reading SiFive documentation
and applying mutatis mutandis (see chapter 10 of the link https://static.dev.sifive.com/FE310-G000.pdf).
The basic idea is that you read and write the claim
and complete register to satisfy the interrupt and prevent looping. You need to know the address of the controller
but this is printed on the log when building the Rocket, and put in the boot rom.
So your choices are to disable the internal PLIC if you want to use my original suggestion or remove the external
interrupt controller.
If you remove the external interrupt controller you are back to the original problem of not having sufficient interrupt
sources available. Have you discovered that the configuration parameter WithNExtTopInterrupts(nExtInts) configured in Configs.scala?
This defaults to 2 and I think this is why you are seeing the behaviour. So for example if you are using DefaultConfig,
you would change
Hi Dr Jonathan Kimmitt,
We are using latest interrupt controller (PLIC) along with the
our Interrupt controller in cascaded form. We are trying to use
the default config.scala, we are not interested in changing it.
In this case, could you suggest as what would be the cause for
ISR looping ?
Thanks
Saravanan
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/hw-dev/ce05f5e8-5511-9ed7-859c-67e20489c1c3%40cam.ac.uk.
As already mentioned, you need to read and write claim register in the PLIC otherwise it will
not know that you have serviced the interrupt. This is a simple software hack, no need to modify
any chisel or HDL code. This is how I do it:
// At this point we already checked that the mcause was negative
as per the privilege spec.
void handle_interrupt(long cause)
{
int mip;
char code[20];
cause &= 0x7FFFFFFF;
if (cause==IRQ_M_DEV) // There are other sources, software
interrupt, timer etc.
external_interrupt();
}
volatile uint32_t *plic;
// So we know the interrupt is external
void external_interrupt(void)
{
int i, claim, handled = 0;
#ifdef VERBOSE
printf("Hello external interrupt! "__TIMESTAMP__"\n");
#endif
claim = plic[0x80001]; // pick out the highest priority
interrupt that the PLIC knows about
// poll the external sources that we know about, including any
secondary interrupt controller
if (uart_check_read_irq())
{
int rslt = uart_read_irq();
printf("uart interrupt read %x (%c)\n", rslt, rslt);
handled = 1;
}
// Das Tut Mir Leid, we couldn't find the interrupt source
if (!handled)
{
printf("unhandled interrupt!\n");
}
plic[0x80001] = claim; // make that interrupt go away
}
// Consult the PLIC documentation for the boring details of this
code
void init_plic(void)
{
int i;
for (i = 1; i <= 64; i++)
{
plic[i] = 1;
}
for (i = 1; i <= 64; i++)
{
plic[0x800+i/32] |= 1<<(i&31);
}
plic[0x80000] = 0;
}
int main()
{
plic = (volatile uint32_t *)0x0c000000; // hard-wired since we
don't want to change scary Chisel code
init_plic();
printf("Enabling interrupts\n");
set_csr(mstatus, MSTATUS_MIE|MSTATUS_HIE);
set_csr(mie, ~(1 << IRQ_M_TIMER)); // everything except
the timer
printf("Enabling UART interrupt\n");
uart_enable_read_irq();
for(;;)
{
// background code goes here
Hi Dr Jonathan Kimmitt,
While entering into ISR we are reading claim id from the PLIC.
and while exiting from ISR we are witting back the claim id into
PLIC register.
but still we see ISR is looping.
Note : Same thing works fine for us in machine mode. Only in
supervisor mode we have this issue. Do we have to take care
anything special in BBL. Could you please suggest us any idea,
how to proceed.
Thanks
Saravanan
One obvious difference is that memory protection is usually switched on in supervisor mode, so the address
of the PLIC might be different or inaccessible. Another difference is that machine level interrupts take priority over
supervisor level interrupts, so if you rely on supervisor mode to clear the PLIC via software interrupt, that interrupt
will never take place unless machine mode has turned off the interrupt source (inside BBL). Check out the documentation for
medeleg and mideleg csr registers concerning delegating interrupts directly to supervisor mode.
You can use the PLIC to mask interrupt sources in BBL to prevent recursion until you have had a chance to service the request
in supervisor mode.
If all else fails, I recommend writing a minimal program that contains the essentials of what you are trying to do and run it in
the vsim subdirectory of Rocket using Verilator to dump the internal values of registers and find out the root cause of the looping.
Also have you checked out your memory protection regions are
valid (pmpaddr?, pmpcfg?)