Closed patstew closed 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
.
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: @.***>
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
That makes sense. Here's the same steps in Rust flavour:
@xobs Ahhh didn't knew that tool :D
Thanks, I missed that, that's solved my issue.
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.