gdbdiff is a fast and reliable way to check our instruction set implementation. It runs the same piece of code on both the physical Pi Pico (the silicone) and the emulated Pi Pico, instruction by instruction, and compares the CPU state after each instruction.
We held a bug squashing session yesterday and spotted several instruction bugs thanks to gdbdiff. The gdbdiff part starts at hour 1:25:00 into the stream—
gdbdiff works by using the GDB Remote Serial Protocol to debug the Pi Pico and the emulator. It has a client implementation of the protocol which connects to the RP2040 silicone through OpenOCD, and to the RP2040 emulator using the gdbserver stub.
Thanks to gdbdiff, we were able to find and fix several bugs, mostly related to the Cortex-M0+ flags in the APSR register, and also an edge case in LSRS:
- don't update flags in ADD reg (encoding T2)
- adcs adding 0+0 with carry shouldn't set overflow
- CMP immediate doesn't set carry correctly
- CMP register doesn't set carry correctly
- LSRS returns incorrect result when shifting by 32 or more
The last issue in the list also caused a funny behavior of printf() when printing numbers from the Arduino Mbed OS core.
Using gdbdiff proved to be a very efficient way to spot tricky bugs. Previous attempts to spot such bugs required hours of laborious debugging, and now we have a tool which automates the process.
At this point, the emulator's instruction set is mostly ready. There are still some multi-core and interrupt-related instructions that we need to implement (e.g. SEV, WFI, WFE), but they shouldn't normally affect the code flow.
We'll keep hacking on the emulator this Tuesday, adding Timer Alarms, GPIO, and maybe also the SIO divider. See you then!