chipsalliance / Cores-VeeR-EH1

VeeR EH1 core
Apache License 2.0
808 stars 219 forks source link

Problem with interrupts and SweRVolf #54

Closed albertodbg closed 4 years ago

albertodbg commented 4 years ago

I am trying to make interrupts work in the SweRVolf SoC. The concrete objective is to make switches work by using vectorized interrupts. I am following the Swerv documentation, trying to replicate the 7 steps mentioned in section 5.5.1 with the help of the code provided in section 5.14.1. Furthermore, I have included some code of my own to integrate the support for vectorized interrupts. Nevertheless, I am having problems with the code and also I have some doubts with the guide.

1) When trying to configure interrupts, it is necessary to access the CSR address space, concretely the one shown in Table 5-13. They are located in contiguous addresses, but according to documentation, these registers are 32-bits wide. It is true that there are many reserved sections, but if I am not wrong, there exists the possibility of overlapping. I am concerned about this, because the base address loaded in MEIVT for initializing the vector table is overwritten when initializing the thresholds through MEICIDPL. Here is an example:

MEIVT 0xBC8 ==> Write on bits 10..31, 9..0 reserved MEIPT 0xBC9 ==> Write on bits 3..0, 31..4 reserved MEICPCT 0xBCA ==> 31..0 reserved MEICIDPL 0xBCB ==> Write on bits 3..0, 31..4 reserved MEICURPL 0xBCC ==> Write on bits 3..0, 31..4 reserved

Memory in little endian (initialized to all 1s)

0xBC8 | 0xBC9 | 0xBCA | 0xBCB | 0xBCC FF FF FF FF FF

Sequence of all 0s Write MEIVT

0xBC8 | 0xBC9 | 0xBCA | 0xBCB | 0xBCC FF 03 00 00 FF

Write MEIPT (0x1)

0xBC8 | 0xBC9 | 0xBCA | 0xBCB | 0xBCC FF 01 00 00 FF

Write MEICIDPL (0x2)

0xBC8 | 0xBC9 | 0xBCA | 0xBCB | 0xBCC FF 01 00 02 FF (here overlapping is produced)

Write MEICURPL (0x3)

0xBC8 | 0xBC9 | 0xBCA | 0xBCB | 0xBCC FF 01 00 02 03

2) The mret instruction is not working. After executing the first routine in the code (init_vector_table_rt), the pc comes back and this routine is executed again and again. When substituting mret by just ret, the code finishes, but interrupts are not working.

3) Another issue is the id of the gateway. According to the PLIC documentation, all harts in RISC-V are connected through gateways. I have supposed this id is 1, but probably this is wrong.

I attach the code as well. If you could provide some answers it would be of great help.

LedsSwitches.dis.txt LedsSwitches.S.txt

aprnath commented 4 years ago

Hi Albertodbg, Please note that there are two sets of CSRs related to interrupts. One set is internal CSR space that uses csrr* instructions and are XLEN (32) bits wide, and another memory-mapped set for the gateway that uses load/store instructions. I believe you may be conflating the two in your programming? The internal CSRs that are programmed via the csrr* instructions (at CSR address 0xBC*) are not memory mapped, and are 32 bits wide.

Please change your code such that the macros use csrr* for the internal CSR space registers, and the gateway memory mapped CSRs uses RV_PIC_BASE_ADDR+offset addresses

aprnath commented 4 years ago

Regarding your second issue - if the gateway is configured as level-sensitive (default) and the interrupt input pin stays asserted on MRET, SweRV will take the interrupt again. Your interrupt handler must execute code to disable/clear/negate the interrupt pin (possibly by writing to the SOC agent that is generating the interrupt), prior to the MRET, and must validate this by confirming via a read of the interrupt pending registers of the gateway (MEIPx), prior to the MRET. The MRET will re-enable interrupts in MSTATUS, and level sensitive interrupts pins that continue to stay asserted following MRET will trigger interrupts processing again.

albertodbg commented 4 years ago

Thanks for your comments. I think that the first part is right now. The program runs, but the interrupt due to the switches is never pending, I am always in the "next" loop. Apparently the MEIE bit is active in the MIE register and things seems to be set up. I have tried to clear the interrupt in the handler, but as it is never run, I do not know whether is working (the same for mret). I have two questions now: 1) Is it possible to see what gateway is active? Maybe using id=1 was not right. 2) I am mapping the vector table to DCCM (I have also tried ICCM). Could this be causing problems? As the base address is shifted 10 positions when mapped to MEIVT, it is only possible to employ region 0x0 for mapping the vector table, right? LedsSwitches.S.txt

aprnath commented 4 years ago

Alberto, can you confirm that MSTATUS.mie is set (==1) ? Yes, MEIVT should be in data memory (anywhere in external data memory or DCCM). The MEIHAP register will contain a fully formed address that is made up of the MEIVT base, and the interrupt claim id. This address should contain the interrupt handler pointer (which should be in instruction memory or ICCM). If you are using external memory, you are not limited to any internally mapped region to hold the vector tables and the corresponding handlers.

You can read the meip registers to see which interrupts are pending.

olofk commented 4 years ago

Hi @albertodbg . It would help a lot if you could show us the modifications to the SweRVolf RTL that you have made. I'm flying blind here, but suspect there are several errors involved.

  1. I find it unlikely that gateway ID should be 1, since that is normally used for the UART Interrupts and you seem to get your interrupts from switches, which is not available in the upstream SweRVolf SoC.
  2. I don't see that the interrupt source is cleared anywhere. Since you say that this is a level-triggered interrupt, there must be some way of resetting the source. Not sure if this is what you have done, but connecting the switches directly to the interrupt line will not work since it will continuously trigger a new interrupt as soon as the previous one is handled.
  3. ICCM and DCCM are not connected in SweRVolf (yet), so you can't put the interrupt vectors there
albertodbg commented 4 years ago

Alberto, can you confirm that MSTATUS.mie is set (==1) ?

Yes it is. The content of MSTATUS is 0x1808, but I had to force the mei bit after enabling the external interrupts. The MIE content is 0x800 (which I guess is right), but the MIP content is 0x80, so the meip bit is 0, so the interrupt is not being triggered, right?

Yes, MEIVT should be in data memory (anywhere in external data memory or DCCM). The MEIHAP register will contain a fully formed address that is made up of the MEIVT base, and the interrupt claim id. This address should contain the interrupt handler pointer (which should be in instruction memory or ICCM). If you are using external memory, you are not limited to any internally mapped region to hold the vector tables and the corresponding handlers.

I think that the "base" term misguided me. So the MEIHAP register just contains the address by concatenating the base address with the claimid and "00". You can read the meip registers to see which interrupts are pending.

I have tried looking at address 0x10001000 but all 256 bytes are always 0.

albertodbg commented 4 years ago

Hi @albertodbg . It would help a lot if you could show us the modifications to the SweRVolf RTL that you have made. I'm flying blind here, but suspect there are several errors involved.

I did not modify the SoC. I am using EH1_1.5 on a Nexys A7 board. Using polling, I was able to read the least significant 8 switches and update the corresponding leds.

1. I find it unlikely that gateway ID should be 1, since that is normally used for the UART Interrupts and you seem to get your interrupts from switches, which is not available in the upstream SweRVolf SoC.

I have parameterized the id in the new version of the code, I have tested several id's but still not working. In this regard, when grepping the Verilog I found that the maximum number of interrupts is 8. Aslo, I found this line ../src/swervolf_0.6/rtl/swervolf_core.v: .extintsrc_req ({6'd0, spi0_irq, uart_irq}), Every bit of this signal is asserted when an interrupt is triggered with the proper priority, but apparently just spi and uart are mapped?? How could I handle gpio if this is true? LedsSwitches.S.txt

2. I don't see that the interrupt source is cleared anywhere. Since you say that this is a level-triggered interrupt, there must be some way of resetting the source. Not sure if this is what you have done, but connecting the switches directly to the interrupt line will not work since it will continuously trigger a new interrupt as soon as the previous one is handled.

In the handler I introduced these lines at the end //Clear interrupt pending register li t0, (RV_PIC_BASE_ADDR + RV_PIC_MEIGWCLR_OFFSET) sw x0, 0(t0) but the handler is never executed.

3. ICCM and DCCM are not connected in SweRVolf (yet), so you can't put the interrupt vectors there

Ok. I tried 0xC0000000 for instance.

olofk commented 4 years ago
1. I find it unlikely that gateway ID should be 1, since that is normally used for the UART Interrupts and you seem to get your interrupts from switches, which is not available in the upstream SweRVolf SoC.

I have parameterized the id in the new version of the code, I have tested several id's but still not working. In this regard, when grepping the Verilog I found that the maximum number of interrupts is 8. Aslo, I found this line

../src/swervolf_0.6/rtl/swervolf_core.v: .extintsrc_req ({6'd0, spi0_irq, uart_irq}),

Every bit of this signal is asserted when an interrupt is triggered with the proper priority, but apparently just spi and uart are mapped?? How could I handle gpio if this is true?

You can't. There is no interrupt connected to the GPIO. The only interrupts in SweRVolf 0.6 are from the UART, connected to gateway 1 and the SPI controller, connected to gateway 2. There is also the timer interrupt, but that goes directly to the core, not through the PIC.

One solution, if you want to set LEDs based on input switches could be to trigger a timer interrupt, say every 10 ms, and check the status of switches there

3. ICCM and DCCM are not connected in SweRVolf (yet), so you can't put the interrupt vectors there

Ok. I tried 0xC0000000 for instance.

There is nothing at 0xC0000000, so you won't be able to write or read anything there. You can find the full memory map here. In addition to that, the PIC is mapped to 0xf00c0000

albertodbg commented 4 years ago

Thanks!