One of the goals of my RiscV toolchain project has always been more than simply generating RISC-V assembly.
I want to build a complete toolchain that makes writing,
compiling, and debugging RISC-V programs feel natural. This week, I reached
another milestone: my RISC-V simulator can now debug programs directly
inside Visual Studio Code.
Seeing breakpoints, registers, and single-step execution
inside VS Code is surprisingly satisfying. It makes the project feel much
closer to a real development environment.
Why a VS Code Debugger?
When developing a compiler, debugging generated assembly is
just as important as generating it.
Previously, my workflow looked something like this:
- Compile
C source code.
- Generate
RISC-V assembly.
- Run
the simulator.
- Print
register values.
- Repeat.
That works for small programs, but it quickly becomes
painful as the compiler grows.
Having an interactive debugger completely changes the
experience.
Instead of inserting print statements everywhere, I can now:
- set
breakpoints
- single-step
through instructions
- inspect
registers
- follow
the execution flow
- verify
generated assembly interactively
It dramatically shortens the feedback loop when tracking
down compiler bugs.
Using the Debug Adapter Protocol
Rather than inventing my own debugger UI, I decided to
integrate with Visual Studio Code's Debug Adapter Protocol (DAP).
This means the extension can take advantage of the debugger
interface that developers already know.
Currently the debugger supports:
- launching
a RISC-V program
- breakpoints
- stepping
through instructions
- viewing
all integer registers
- inspecting
the current execution point
- displaying
the call stack
Because the simulator acts as the debugging backend, every
instruction executed is under complete control of the debugger.
Connecting the Pieces
This project has gradually evolved into several independent
components that now work together:
C Source
│
▼
C Compiler
│
▼
RISC-V Assembly
│
▼
Simulator
│
▼
VS Code Debugger
Each component was originally developed independently.
Connecting them together has been one of the most rewarding
parts of the project.
When I hit F5 in VS Code, the debugger launches the
simulator, loads the executable, and immediately allows me to step through the
generated instructions.
That is a much nicer workflow than running individual
command-line tools.
The Screenshot
The screenshot below shows the debugger paused on an
instruction.
On the left, VS Code displays the complete register set.
On the right, the current instruction is highlighted while
breakpoints are shown directly in the editor.
Watching the register values change after each instruction
has already helped me identify several code-generation issues that would have
been much harder to diagnose otherwise.

No comments:
Post a Comment