A retro computer setup displays Windows 95 on a monitor beside a RISC-V board, vintage keyboard, and BIOS screen.
Windows 95 is now booting on a $22 microcontroller board, and the interesting part is how it got there. A hobbyist going by winitboonkliang has ported tiny386 to the Guition JC8012P4A1C, a 10.1-inch ESP32-P4 development board. The result starts Windows 95 OSR2 from a microSD card, with USB keyboard and mouse input. The project is a curiosity rather than a practical computer, but the write-up is a good lesson in emulation, profiling and where the time really goes in a slow system.

A retro computer setup displays Windows 95 on a monitor beside a RISC-V board, vintage keyboard, and BIOS screen. It's an emulator, not native Windows​

The headline can mislead, so here is the key point. The ESP32-P4 is a dual-core RISC-V chip, not an x86 processor, so Windows 95 cannot run on it directly. The project is a port of tiny386, Chunhui He's x86 PC emulator, to the Guition board, which has a 1280×800 MIPI-DSI panel. The emulator supplies the PC hardware that Windows expects: a BIOS, VGA and IDE disks. That is why a SeaBIOS image and a SeaVGABIOS image sit on the SD card.

XDA Developers, which reported the story after Adafruit spotted it, says the author calls this a "study project" aimed at seeing how far an old OS can go on $22 hardware, not a daily driver. Adafruit's write-up notes that the guest gets 16 MB of RAM so Windows does not page to the card.

The hardware​

Per the project's README, the board has:

  • an ESP32-P4 SoC at 360 MHz, dual-core RISC-V
  • 32 MB of PSRAM and 16 MB of flash
  • a 10.1-inch 800×1280 IPS panel on 2-lane MIPI-DSI
  • a capacitive touch controller, which this project does not use
  • audio through an ES8311 codec
  • a companion ESP32-C6 for Wi-Fi, deliberately unused

The README also lists what works: the Windows 95 desktop, Explorer, Control Panel, Paint, Calculator and DOS programs. It also lists two IDE disks backed by files on the SD card, and Adlib OPL2 and SoundBlaster 16 audio. FreeDOS and MS-DOS boot as well. The author describes the speed as roughly a 386SX-class machine, "usable, not fast", and says you will not be running Office.

Performance: 155 seconds to the desktop​

Expect about 155 seconds to reach the desktop, with performance around a 386SX at roughly 1.5 MIPS. The README warns of a long black-screen stretch during boot that is working, not hung.

Windows runs in 16-colour VGA, which produces visible vertical striping from desktop dithering. The author lists this as something still to fix.

The disk bottleneck​

The most useful part of the write-up is the measurement work. The firmware prints a performance line every 10 seconds, splitting wall-clock time into executing, halted and blocked on disk. That showed Windows spending 97% of its time waiting for the disk.

The obvious suspect was the SD card, but the author cleared it. According to the README, a raw sector read took 0.36 ms through the SD driver, while the same reads through the full filesystem path took about 9 ms each. Reads of every size came out at 55 KB/s, the signature of newlib's unbuffered refill path reading one byte at a time. In practice, one 512-byte sector turned into 512 round trips through the VFS and FatFs layers.

The README adds that the culprit was an setvbuf(_IONBF) call added earlier as an optimisation. Its reasoning, that stdio's buffer could never be reused because every read seeks first, was sound. The conclusion drawn from it was wrong.

The fix was a real block cache: 4 KB lines, 2 MB in total, direct-mapped and write-through. A 2 MB block cache with 4 KB lines brought disk time down to 36%. The README puts the cache hit rate at 78–87%, since Windows keeps re-reading the same registry, VMM and font sectors. Disk wait fell from 97% to between 0% and 36%.

Display and CPU fixes​

Other fixes in the README cover the display and the CPU scheduler:

  • Rotation and scaling: the panel is portrait and the emulated PC is landscape. The P4's Pixel Processing Accelerator rotates and scales the image in hardware, so no CPU time goes on each pixel.
  • White flashes: the display FIFO was underrunning because the emulator, the accelerator and the panel all share the PSRAM bus. Dropping the pixel clock from 60 MHz to 30 MHz fixed it.
  • Wasted frames: the code was computing frames that were then thrown away. A dirty flag now skips unchanged frames, and conversion is gated to the rate at which frames actually reach the panel.
  • HLT handling: yielding a full FreeRTOS tick on every halt added minutes to boot, because most halts are brief waits for an interrupt. The idle path now spins first and sleeps only if the guest stays halted.
  • Dead end: CONFIG_FATFS_USE_FASTSEEK does nothing here, because ESP-IDF only builds its cluster map for read-only files and the emulator needs write access.

Adafruit also mentions re-enabling jump tables for the opcode switch.

Can you do it too?​

Only with conditions. The README targets one specific board, with its pin assignments and quirks documented, so don't assume it works unchanged on another ESP32-P4 board. Here is what you need:

  1. Firmware. Flash the prebuilt merged image with esptool at offset 0, or build it with ESP-IDF 5.4.x.
  2. SD card. Format it FAT32 and copy on the included BIOS and VGA BIOS files and the tiny386.ini config.
  3. Disk image. You supply an hd.img with a bootable x86 OS. No operating system is included in the repository. You need your own licensed Windows 95 copy, or you can use FreeDOS instead.
  4. Insert everything first. The SD card is read about 150 ms into boot, so it and the USB input devices must be connected before power-on.

Installing Windows 95 on the board itself would take hours, so the README suggests installing on a desktop PC with the host build of tiny386 and then copying the finished image across. Its notes from doing this:

  • Put the CD on cdc, not cda, or it hides your hard disk.
  • Use LCHS 1024/16/63 geometry and partition type 0x0E.
  • Set the BPB heads field to 16, or you get a disk I/O error at boot.
  • Remove DOS=HIGH from the boot floppy config.
  • If Setup fails on a fast PC with a "Windows protection error" while initialising device IOS, that is a real Windows 95 bug, not the emulator. It comes from a speed-calibration loop overflowing, and throttling the emulator to about 15 MIPS avoids it.

If power is lost while Windows is running, the next boot runs ScanDisk. The README advises choosing Fix It on everything and skipping the undo disk, and shutting down properly through Start → Shut Down to avoid it.

Why it matters​

This won't change your desktop. It does show that a cheap board, a well-profiled emulator and a hardware rotation block can run a 1995 operating system. The most reusable lesson is that the SD card was blameless and a stdio buffering decision cost a factor of 25. Guess at bottlenecks and you can spend a long time optimising the wrong thing.

 

References

  1. Windows 95 running on an ESP32-P4, a tiny386 port blog.adafruit.com