SpinalHDL / VexRiscv

A FPGA friendly 32 bit RISC-V CPU implementation
MIT License
2.52k stars 420 forks source link

Predicted branch taken after compressed EBREAK #345

Closed patstew closed 1 year ago

patstew commented 1 year ago

I'm trying to use a simulated vexriscv with a custom gdbserver and I'm seeing an issue with C.EBREAK instructions followed by jumps (or the upper part of a 4 byte instruction that happens to decompress to a jump after breakpoint insertion). If prediction is enabled then it appears that the pc is updated to the predicted value from the instruction following the C.EBREAK, rather than simply being the address of the following instruction. I'm using prediction = STATIC, and reading the pc using an AUIPC instruction in the debug interface.

xobs commented 1 year ago

Just chiming in here -- I was linked your issue, but I'm not sure I understand it.

When C.EBREAK is hit, the address of the ebreak instruction is written to $mepc and the program jumps to $mtvec. Your handler then needs to do whatever it needs to in order to swap the instruction back, or jump over the ebreak instruction if you don't want to swap it out.

This is in contrast to ARM where the break instruction will return to the instruction following the trap.

I have a test at https://github.com/xobs/renode-ebreak-test/blob/89f02df07b828e2117432b3db7ade90255a84cae/src/riscv_support.rs#L438-L546 that will replace every instruction in a program with ebreak or c.ebreak and will end up single-stepping through it. I've only tested it on emulators, but can you see if it exhibits the same issue you're seeing? The program basically single-steps its way through the entire program once it hits the first ebreak.

patstew commented 1 year ago

Sorry, I'm using it with the debugplugin, not the csrplugin.

On Thu, 18 May 2023, 06:15 Sean Cross, @.***> wrote:

Just chiming in here -- I was linked your issue, but I'm not sure I understand it.

When C.EBREAK is hit, the address of the ebreak instruction is written to $mepc and the program jumps to $mtvec. Your handler then needs to do whatever it needs to in order to swap the instruction back, or jump over the ebreak instruction if you don't want to swap it out.

This is in contrast to ARM where the break instruction will return to the instruction following the trap.

I have a test at https://github.com/xobs/renode-ebreak-test/blob/89f02df07b828e2117432b3db7ade90255a84cae/src/riscv_support.rs#L438-L546 that will replace every instruction in a program with ebreak or c.ebreak and will end up single-stepping through it. I've only tested it on emulators, but can you see if it exhibits the same issue you're seeing? The program basically single-steps its way through the entire program once it hits the first ebreak.

— Reply to this email directly, view it on GitHub https://github.com/SpinalHDL/VexRiscv/issues/345#issuecomment-1552409349, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABCFMZ2CAU2CN2E2KYDRVEDXGWV5PANCNFSM6AAAAAAYFYLQ64 . You are receiving this because you authored the thread.Message ID: @.***>

Dolu1990 commented 1 year ago

Hi,

reading the pc using an AUIPC instruction in the debug interface.

I think that's the issue. When the DebugPlugin get a ebreak and is in debug mode, the CPU fetch PC is messed up, the only way to retrieve the PC is to read address 0x04 of the DebugPlugin debug bus. If you push any instruction in, the value will be lost.

PC saved on ebreak here : https://github.com/SpinalHDL/VexRiscv/blob/c52433575dec04f10063b2fd7cebd0545c8b1be9/src/main/scala/vexriscv/plugin/DebugPlugin.scala#L310

Mapped to the debug bus here : https://github.com/SpinalHDL/VexRiscv/blob/c52433575dec04f10063b2fd7cebd0545c8b1be9/src/main/scala/vexriscv/plugin/DebugPlugin.scala#L256

Openocd code which save the PC when the CPU enter debug mode from ebreak: https://github.com/SpinalHDL/openocd_riscv/blob/058dfa50d625893bee9fecf8d604141911fac125/src/target/vexriscv.c#L794

xobs commented 1 year ago

That makes sense. Here's the same steps in Rust flavour:

https://github.com/litex-hub/wishbone-utils/blob/7a6358533e7df63a059d65c612f3e992552cdfc5/wishbone-tool/crates/core/riscv/mod.rs#L900-L907

Dolu1990 commented 1 year ago

@xobs Ahhh didn't knew that tool :D

patstew commented 1 year ago

Thanks, I missed that, that's solved my issue.