Skip to content

LanderXT/tiny386

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

355 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tiny386 — ESP32-S3 Wi-Fi browser-streaming fork

A fork of hchunhui/tiny386 (a tiny, from-scratch x86 PC emulator in C) that turns it into a headless retro PC you reach from any web browser over Wi-Fi — no LCD panel required. The emulated screen streams to an HTML <canvas> over a WebSocket, and you type and click straight from the page. The board can even be its own Wi-Fi access point with a captive portal, so a laptop or phone connects directly (no router) and the browser pops open on the emulator automatically.

It runs DOS, EGA/CGA games (Commander Keen, Pac-Man, Digger), Windows 9x and Linux on an ESP32-S3 (8 MB PSRAM) — streamed live to your browser.

The original tiny386 documentation is preserved below, under Upstream: Tiny386.

What this fork adds

Headless Wi-Fi browser streaming (BOARD=stream)

A from-scratch streaming backend for boards with no display: an HTTP server ships a small JS client, then pushes framebuffer deltas over a WebSocket to a <canvas>; keyboard and pointer-lock mouse go back the other way. Open http://<board>/ and you have the machine.

Streaming pipeline — efficient EGA/CGA delta encoding

  • Dirty-tile detection — a per-16×16-tile FNV hash; only changed tiles are re-encoded and sent, so a static screen costs ~0.
  • Native-resolution rasterization (STREAM_NATIVE) — render low-res modes at the guest's true size (e.g. 320×200) and let the browser upscale: ~4× less to rasterize, hash and send.
  • 4-bit palette encoding (STREAM_PALETTE) — for ≤16-colour EGA/CGA, send packed 4-bit indices + a 16-colour palette instead of RGB565 (~4× fewer bytes); the browser expands them.
  • CGA native path — mode 04h (320×200 4-colour, used by Pac-Man/Digger) now takes the same native + 4-bit fast path as EGA (2-bpp decode + CGA interleaved scanline addressing), instead of falling back to full-panel RGB565.
  • Scroll copy-rect BLIT (STREAM_BLIT) — detect a CRTC start-address scroll and tell the browser to drawImage-shift the moved pixels instead of resending them (vertical, horizontal, diagonal, and 1-px pel-pan).
  • RLE run-length coding of tiles, adaptive frame pacing, a WS heartbeat, latest-wins frame drop under backpressure, and a double-buffered canvas so every frame presents atomically (no tile-by-tile tearing).

Emulator performance

  • IN 0x3DA retrace-poll fast-path — the VGA status poll dominated scroll instructions; reading it directly (bypassing the I/O dispatch) gave +65% emulator throughput.
  • Retrace clock on core 1 — advancing the VGA retrace at the guest's instruction rate lifted the guest-perceived vsync from ~20 Hz to ~132 Hz, unthrottling scroll fps and smoothing motion.
  • EGA display-address aperture-wrap and double-scan-width fixes (smooth scroll, no stripes / half-screen).
  • x87 FPU fixes (tag word, reset/environment, 80→64-bit significand rounding).

Direct connect — no router needed

  • SoftAP "TINY386-WIFI" + captive portal (-DWIFI_AP=on) — the board is its own open access point at 192.168.4.1 with a DNS-hijack + HTTP-redirect captive portal, so joining the network auto-opens the browser on the stream.
  • STA mode with a no-IP reconnect watchdog, open-auth support, and a pre-connect RSSI scan log; Wi-Fi tuned (modem-sleep off) for streaming throughput.
  • Guest networking bridged to Wi-Fi via the NE2000 ↔ lwIP packet filter.

Storage, memory & quality-of-life

  • USB Host Mass-Storage (pen drive) support (-DUSB_MSC) for disk images.
  • PSRAM handed to the ESP heap (CONFIG_SPIRAM_USE_MALLOC), fixing the internal-DRAM starvation that was the real streaming bottleneck.
  • "reset guest" web button — reboot the emulated PC from the browser (works even when a hung DOS game has halted the CPU), no power-cycle.
  • GET /bench link-throughput probe, and serial perf logs (emulated-CPU Msteps/s, tiles/frame, KB/s).

Quick start (stream board)

# ESP-IDF 5.2.x, ESP32-S3 with 8 MB PSRAM
cd esp
idf.py -DBOARD=stream -DSTREAM_PALETTE=on -DSTREAM_BLIT=on -DUSB_MSC=on -DWIFI_AP=on build
idf.py -p <PORT> flash

Then join Wi-Fi TINY386-WIFI (the captive portal opens the stream), or browse to the board's IP in STA mode.


Upstream: Tiny386

Introduction

Tiny386 is an x86 PC emulator written in C99. The highlight of the project is its portability. It now boots Windows 9x/NT on MCU such as ESP32-S3.

The core of the project is a built-from-scratch, simple and stupid i386 cpu emulator. Some features are missing, e.g. debugging, hardware tasking and some permission checks, but it should be able to run most 16/32 bit software. To boot modern linux kernel and windows, some 486 and 586 instrutions are added. The cpu emulator is kept in ~6K LOC. There is also an optional x87 fpu emulator.

To assemble a complete PC system, we have ported many peripherals from TinyEMU and QEMU, it now includes:

  • 8259 PIC
  • 8254 PIT
  • 8042 Keyboard Controller
  • CMOS RTC
  • ISA VGA with Bochs VBE
  • IDE Disk Controller
  • NE2000 ISA Network Card
  • 8257 ISA DMA
  • PC Speaker
  • Adlib OPL2 (optional)
  • SoundBlaster 16

For firmware, the BIOS/VGABIOS comes from seabios. Tiny386 also supports booting linux kernel directly, without traditional BIOS. The idea comes from JSLinux, and it uses a small stub code called linuxstart.

Demo

See here

Build

Linux (with rawdraw): You need to install libslirp libx11 and libasound2 first, then type make.

Linux (with SDL): You need to install libslirp SDL1.2 (or sdl12-compat) first, then type make USE_SDL=y.

For other platforms, please refer to .github/workflows/build.yml.

Pre-built binaries: here

Usage

  • Prepare an ini file
[pc]
; set path to BIOS and VGA BIOS
bios = bios.bin
vga_bios = vgabios.bin

; set memory size and VGA memory size
mem_size = 32M
vga_mem_size = 2M

; fda/fdb for floppy disks (optional)
fda = floppy.img

; hda/hdb/hdc/hdd for hard disks (optional)
; cda/cdb/cdc/cdd for CD-ROM disks (optional)
hda = win95.img
cdb = win95_cd.iso

; "fill_cmos" fixes "MS-DOS compatibility mode" in win9x, but it breaks winNT...
fill_cmos = 1

; force 8-dot mode (640 pixel wide in text mode) if set to 1
vga_force_8dm = 0

[display]
width = 720
height = 480

[cpu]
; gen = 3/4/5/6, for 386/486/586/686
gen = 3
; fpu = 0/1, to disable/enable x87
fpu = 0
  • Run
./tiny386 config.ini
./tiny386 -kvm config.ini  # run with KVM (build with `make USE_CPUABS=y`)

For rawdraw and SDL port: Press "Ctrl + ]" to grab/ungrab the keyboard and mouse. Press "Ctrl + [" to show/hide OSD (On Screen Display). In OSD mode, the floppy/CD-ROM disk can be changed on the fly.

ESP32 port

Supported boards:

With ESP-IDF 5.2.x:

With ESP-IDF 6.0.x (experimental):

  • JC4880P443 (ESP32-P4 Rev1.3 360MHz, 800x480)

Build and Flash

You can find the pre-built flash image esp/flash_image_JC3248W535.bin from here. The pre-built image can be flashed directly to offset 0.

Online flasher for esp chips: https://espressif.github.io/esptool-js

To build and flash manually:

scripts/build.sh patch_idf  # apply patches to ESP-IDF 5.2.x
#scripts/build.sh patch_idf_60  # apply patches to ESP-IDF 6.0.x
make prepare
cd esp
idf.py -DBOARD=jc3248w535 update-dependencies build  # or -DBOARD=elecrow7s3
idf.py flash

Configure

All files should be put in a SD card with FAT/exFAT file system. The ini file should be tiny386.ini and put in the root directory. Please refer to esp/tiny386.ini.

Alternative usage: bios.bin vgabios.bin vmlinux.bin and linuxstart.bin can be put in corresponding flash partition. Other files can be put in the storage flash partition. Please refer to esp/partition.csv.

Keyboard/Mouse Input

  • Forward over WIFI

wifikbd is used to forward keyboard/mouse events to the dev board over WIFI:

(ESP32-S3 board: listen on TCP port 9999) <--- WIFI ---> AP <--- WIFI/Wire ---> (PC: ./wifikbd esp_board_addr 9999)
  • USB hid (WIP)

See here.

Troubleshooting

"0 bytes of memory" during Windows 95 setup

Use "setup /im" to bypass memory check.

"protection error" during Windows 95 startup

Use patcher9x.

NE2000 doesn't work

Manually set the IRQ to 9(or 2).

freeze during Windows NT4/2000/XP startup

Use fill_cmos = 0 in the config ini file.

License

The cpu emulator and the project as a whole are both licensed under the BSD-3-Clause license.

Adlib emulation is an optional part of the project, and it requires the library fmopl which is licensed under the LGPL. Use make USE_FMOPL=n to build without adlib emulation.

SeaBIOS is distributed under the GNU LGPL-3 license.

Some parts ported from QEMU/TinyEMU are under the MIT license.

About

Headless ESP32-S3 x86 PC emulator streamed to your browser over Wi-Fi - runs DOS, EGA/CGA games, Win9x and Linux. Fork of tiny386 with a SoftAP captive portal so you connect with no router.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • C 81.1%
  • C++ 13.4%
  • Python 1.8%
  • HTML 1.2%
  • JavaScript 1.1%
  • Makefile 0.5%
  • Other 0.9%