Recently RoccoLox and I have been working on adding a ZGC4 machine to QEMU. It's been an interesting learning experience, since neither of us had done much with emulation / reverse engineering hardware prior to this. I'll provide a little write-up of some of the process, but first here's some eye candy:
QEMU integrates quite nicely with gdb, which made debugging a lot easier. Additionally, the emulator will print data the calculator sends over UART to the console:
Process
Turns out before you can make an emulator you have to actually know what you're emulating, so the first thing we did was identify the peripherals. Some of the stuff on the board was more obvious (everything that was labeled), but a few things proved to be trickier. By dumping the firmware (shoutout to this little tool that was super helpful!) and looking through a decomp in Ghidra, I was able to make a guess as to the LCD controller model and identify the remainder of the peripherals, along with the pins / interfaces they were connected to. Here's what we came up with:
Since the GD32 is essentially an STM32 clone, we were able to re-use some of the pre-existing STM32 code in QEMU as a starting point. Additionally, the Numworks also has an ST7789 display controller, so we were able to work off the pre-existing numworks-qemu fork for a few things.
Status
While it's certainly by no means complete, most general OS stuff seems to be working as expected. We haven't been able to test on the latest firmware yet, though it does seem to work at least up v2.24.0. There are a few things that most certainly do not work right now, the obvious ones being anything USB related and RTC (which is completely un-implemented). So for now the clock is permanently stuck in 1999 :P
Interestingly, we also found that the HW version (presumably ZGC3 vs ZGC4) is determined based on the value of PB11, which messed us up initially since we hadn't accounted for that and the emulator expected a different keypad layout. I'm not sure what the other differences between the ZGC3 and 4 are, but for now you can spoof either hardware version if you feel like it!
Using / GitHub etc
The source is available on GitHub: https://github.com/EzCE/qemu-zero
Since this was our first attempt at working with QEMU, the code is likely a bit messy. Feel free to contribute or give any feedback about stuff we should improve / fix.
You can build it following the instructions for building QEMU here. It's pretty straightforward, just install the dependencies required and then:
Code:
To run it, you'll need both a dump of internal flash from 0x08000000 - 0x082FFFFF, and a dump of the external flash (All 8MB. Doesn't seem to be memory mapped so you need to connect to the chip). Then run:
Code:
QEMU integrates quite nicely with gdb, which made debugging a lot easier. Additionally, the emulator will print data the calculator sends over UART to the console:
Process
Turns out before you can make an emulator you have to actually know what you're emulating, so the first thing we did was identify the peripherals. Some of the stuff on the board was more obvious (everything that was labeled), but a few things proved to be trickier. By dumping the firmware (shoutout to this little tool that was super helpful!) and looking through a decomp in Ghidra, I was able to make a guess as to the LCD controller model and identify the remainder of the peripherals, along with the pins / interfaces they were connected to. Here's what we came up with:
- MCU is a GD32F470ZKT6
- External flash is a Winbond W25Q64JV on SPI5
- External RAM is an ISSI IS42S16400J on EXMC SDRAM
- UART is on USART1
- LED uses PA6-8 for BGR respectively
- USB is using the USBFS interface
- The display controller seems to be in the ST7789 family. The command register is at 0x60000000 and the data register is at 0x60000002
- The battery gauge seems to be an STC3100 on I2C0
Since the GD32 is essentially an STM32 clone, we were able to re-use some of the pre-existing STM32 code in QEMU as a starting point. Additionally, the Numworks also has an ST7789 display controller, so we were able to work off the pre-existing numworks-qemu fork for a few things.
Status
While it's certainly by no means complete, most general OS stuff seems to be working as expected. We haven't been able to test on the latest firmware yet, though it does seem to work at least up v2.24.0. There are a few things that most certainly do not work right now, the obvious ones being anything USB related and RTC (which is completely un-implemented). So for now the clock is permanently stuck in 1999 :P
Interestingly, we also found that the HW version (presumably ZGC3 vs ZGC4) is determined based on the value of PB11, which messed us up initially since we hadn't accounted for that and the emulator expected a different keypad layout. I'm not sure what the other differences between the ZGC3 and 4 are, but for now you can spoof either hardware version if you feel like it!
Using / GitHub etc
The source is available on GitHub: https://github.com/EzCE/qemu-zero
Since this was our first attempt at working with QEMU, the code is likely a bit messy. Feel free to contribute or give any feedback about stuff we should improve / fix.
You can build it following the instructions for building QEMU here. It's pretty straightforward, just install the dependencies required and then:
Code:
./configure --enable-sdl --target-list=arm-softmmu
makeTo run it, you'll need both a dump of internal flash from 0x08000000 - 0x082FFFFF, and a dump of the external flash (All 8MB. Doesn't seem to be memory mapped so you need to connect to the chip). Then run:
Code:
./qemu-system-arm -M zgc4 --kernel <internal flash>.bin -drive file=<external-flash>.bin,if=mtd,format=raw












