8088
PCXT · MiSTer FPGA

Technical report · EGA core with optional VGA mode 13h

IBM PC/XT EGA recreated in FPGA

A MiSTer implementation designed to reproduce the IBM PC/XT ecosystem reliably, with an 8088 CPU, native EGA architecture, integrated CGA compatibility and an optional VGA mode 13h extension.

Video: EGA VGA mode 13h: optional License: GPL-3.0 Platform: MiSTer FPGA
01

Overview

A complete PC/XT, not a software-only emulator

The project implements classic components as RTL logic running on the MiSTer FPGA. Its goal is to recreate the machine and its interfaces, rather than translate instructions on a host operating system.

CPU

PC/XT foundation

8088 CPU with multiple clock rates, compatible chipset, conventional memory, UMB, EMS, BIOS, floppy drives and XTIDE.

EGA

Single-owner video

EGA owns CPU access, VRAM, text, graphics, timing and RGB output. CGA compatibility is part of EGA.

13h

Focused VGA extension

Adds 320x200 with 256 colours, a packed framebuffer and DAC, without turning the core into a general VGA implementation.

8088
Main CPU recreated in logic
640 KiB
Conventional memory
2 MiB
EMS page frame at D000h
320x200x256
VGA mode 13h extension
i
How to read this project

This is an EGA-centred PC/XT core. Compatibility with CGA modes does not mean that an independent CGA card exists, and mode 13h support does not imply a complete VGA implementation.

02

Logical design

Core architecture

The design combines CPU, chipset, memory and peripheral blocks with a unified video subsystem. MiSTer provides the physical integration for storage, video, audio and controls.

i
Video implementation reference

The EGA implementation and the optional VGA mode 13h behaviour are based on the video emulation code in 86Box. It is used as a behavioural reference; the MiSTer core remains an RTL implementation tailored to this project.

Logical architecture of the PCXT core for MiSTer The MCL86 CPU communicates with the KFPC-XT chipset. The chipset connects memory, storage, audio, input and the EGA video subsystem with its optional VGA mode 13h extension. CPU MCL86 8088 · 4 clock settings PC/XT-compatible bus Chipset KFPC-XT Decoding · DMA · IRQ Timing · peripherals System integration Memory 640 KiB · UMB · EMS up to 2 MiB Storage FDD A/B · XTIDE · second SD Unified video Native EGA + CGA compatibility VGA mode 13h when enabled Audio and input OPL2 · C/MS · speaker · mouse · joystick MiSTer platform Video · audio · SD · OSD · controls

Crossing into the video clock domain

The video subsystem runs on its own 28.636 MHz clock, so every I/O write to a video port crosses a clock boundary. That crossing is a posted write: the cycle is captured in the chipset domain, where it is synchronous and a single clock of IOW is enough to take it, and presented to the video side as a pulse of guaranteed minimum width and gap. A new I/O cycle arriving while one is still draining is held through the ready tree.

Reads cross the same boundary and have to come back, which takes two synchroniser stages out, the settled-bus qualifier, the decode, and two stages back — five to six chipset clocks. A free bus is not an answered read, so the crossing holds the CPU for the return trip as well, counted from the moment the read is presented to the video side rather than from when the CPU asserted: a read issued behind a draining write reaches the card late and has to be given the trip from there. At the three lower CPU speeds the bus cycle is longer than the trip and the hold never becomes the thing that ends it. At the fastest setting it is what stops the CPU latching the bus while the answer is still crossing, which is what corrupted palette reads and, through them, any software that fades by reading the palette back and scaling it.

The alternative — sampling the live bus and trusting the pulse to be wide enough — works comfortably at the three lower CPU speeds and fails at the fastest one, where an I/O write can be four chipset clocks. Losing a CRTC index leaves the data byte that follows in whatever register the index last named, so the damage accumulates rather than showing up at once. Handling it by construction removes a whole class of speed-dependent faults instead of one symptom: rtl/video/TESTBENCH/ega_io_stretch_tb.sv drives two identical video instances, one through each style of crossing, and sweeps the natural phase drift of the two clocks.

!
RTC/CMOS moved to 340h-341h

The EGA attribute controller mirrors 3C0h-3CFh at 2C0h-2CFh, the address the RTC/CMOS device used on the previous CGA/Hercules-based core. Any index write landing there also reaches the attribute controller and clears Palette Address Source, blanking the display. The RTC/CMOS is now decoded at 340h-341h instead, one of the standard base addresses of a real MM58167 card and clear of every other port used by the core. Tools that read it directly - GET_RTC.EXE and the x86_launcher AppId handled by LAUNCHER.EXE - need to be pointed at the new port.

Origins of the main blocks
  • MCL86, by MicroCoreLabs, as the CPU foundation.
  • KFPC-XT, by kitune-san, as the PC/XT platform foundation.
  • 86Box, whose video emulation code provides the basis for the EGA implementation and optional VGA mode 13h support.
  • JTOPL, by José Tejada/jotego, for AdLib OPL2 audio.
  • MiSTer port integration, adaptation and further development by spark2k06.
03

Video architecture

EGA as the central video architecture

The current core replaces the former model of several selectable video cards with one maintained EGA subsystem.

End-to-end ownership

  • CPU-visible video-port decoding.
  • Memory decoding and planar VRAM access.
  • Text and graphics rendering.
  • CGA-compatible modes implemented within EGA.
  • Splash, timing, blanking and RGB output.
  • Resolution information exposed to the MiSTer environment.

What was removed

  • An independent CGA card as a fallback.
  • Active HGC and Tandy paths in this variant.
  • OSD selection between video cards.
  • Hidden passthrough for splash, boot or CGA games.
  • Conditional build paths with no present purpose.

Dual dot clock

A standard IBM EGA runs two dot clocks and selects between them from Miscellaneous Output bit 2: 14.318181 MHz for the 200-line CGA-compatible modes and 16.257 MHz for the 350-line and MDA-compatible ones. Both are implemented and switch per mode, rather than deriving everything from one fixed rate.

Horizontal Pel Panning

The Attribute Controller panning register (3C0h, index 13h) shifts the displayed image left within the character cell, which is what turns a byte-granular start address into smooth pixel-by-pixel scrolling. The core applies it to the finished dot stream, so text, graphics and the splash all go through one implementation, and it follows the same table 86Box derives in vid_ega.c: one step per register value in the 8-dot modes, doubled in the 320-wide modes so a step is one visible pixel, and the 9-dot text cell taking its aligned position at value 8 the way a real EGA does.

A panned line displays part of one more character than it fetches, so the fetch window carries one extra character past the end of the line, and the panning value is latched once per scanline rather than once per frame — that is what a per-scanline panning wave, a stock EGA effect, needs in order to work at all. rtl/video/TESTBENCH/ega_pan_split_tb.v checks the shift table, the extra fetch and the fact that the display window itself does not move against HSYNC.

Line Compare and split screen

The CRTC Line Compare register (18h, with bit 8 in the overflow register and bit 9 in Maximum Scan Line) names the last scanline drawn from the start address. The one after it restarts the display at address 0 with a fresh character row, which is how a status area stays pinned to the bottom of the screen while everything above it scrolls. The core follows the compare 86Box builds in ega_recalctimings and acts on it where ega_poll does, at the scanline boundary.

The register resets to 0FFh — the value the BIOS writes in every ordinary mode — because the compare is the register plus one, so a zero would split every frame at its second scanline.

Monitor profiles

An IBM EGA card carried a switch pack on its bracket telling the option ROM which display was attached. The core models it: the Hardware menu offers IBM 5154/ECD, IBM 5153/CGA and IBM 5151/MDA, and like the real card the setting is read while the machine is held in reset, so a change takes effect at the next boot rather than immediately.

The choice is not cosmetic. Selecting 5153/CGA makes the ROM build its 200-line, 8x8 text tables at 15.7 kHz, which is what a period CGA monitor or a television expects; 5151/MDA selects the 720x350 monochrome configuration and interprets the connector's Mono Video and Intensity pins as normal and bright white, leaving the separate display tint free to render it green or amber.

Driving a 15 kHz set

The 200-line EGA and CGA-compatible modes already scan at 15.7 kHz, which is exactly what a television wants. The core sends them out undoubled — the scandoubler is permanently off — so they reach a set over RGB/SCART the way the original hardware drove one, with VGA mode 13h retimed onto the same raster so a single pair of centring offsets covers everything.

The 350-line modes cannot do that: they scan at about 21.8 kHz, and MDA at 18.4, which no 15 kHz set will lock to. For those the core captures a whole frame into the board's DDR3 and rebuilds the raster from it, publishing only complete frames so a mode change landing mid-picture cannot show half of one frame and half of another. Two targets are offered from the OSD:

  • 480i — a standard interlaced television frame, 15.73 kHz at 59.94 Hz. All 350 lines are shown, half in each field.
  • 240p — a progressive 262-line frame at the same line rate. Steady, with no interlace flicker, at the cost of fitting 350 lines into 224.

Neither reaches the emulated hardware. The CRTC, the display enable and the retrace bits software polls behave identically whichever setting is chosen; this is the output stage only. Native output is the default and is untouched, for an enhanced display, a 5151, or the scaler.

!
CGA compatibility does not mean separate CGA hardware

Text modes, 2 bpp graphics and B8000h-style accesses are retained as compatible behaviour of a real EGA. This reduces duplication and prevents two pipelines from competing for video.

04

Graphics extension

VGA mode 13h, deliberately limited in scope

A direct and familiar mode for DOS software

The extension implements the familiar 320x200x256 mode: one byte per pixel, 64,000 visible bytes and linear access from A000:0000.

8 bpp packed 64 KiB aperture 256 DAC entries Ports 03C7h–03C9h
13h

Why it is called VGA and not MCGA

This extension was called MCGA until the behaviour it actually provides was pinned down. Real MCGA hardware does not implement EGA's 16-colour planar graphics modes (0Dh/0Eh/10h) at all, so an MCGA could never run the mode 0Dh gameplay this feature was built for. 86Box, whose video emulation this path is modelled on, has no MCGA code anywhere - even the one machine that historically shipped it is emulated as a VGA variant. What makes the target software work is the DAC augmenting the EGA modes plus mode 13h, which is VGA behaviour. The name was changed to match.

The DAC feeds every mode, not only 13h

This is the part that matters for real software. A game that detects a VGA, switches to a 16-colour mode for gameplay and then loads its palette through the DAC gets the palette it intended, instead of the stock EGA one. Titus the Fox and Prehistorik 2 both do exactly this, and it is why their title screens looked right while gameplay did not.

A single default table cannot serve both conventions at once - VGA attribute code 14h is brown, the EGA 200-line code 14h is light red - so each of the 256 entries carries a validity bit. Entries software never wrote fall back to the classic EGA palette, which is what keeps the option-off path unchanged by construction.

Activation path

VGA Mode 13h is an OSD option and defaults to Off. When enabled, VGATSR.COM intercepts INT 10h and drives the RTL path through control port 03CDh. With the option disabled the DAC ports do not decode at all, which is correct for an EGA: a real IBM EGA has no DAC, its palette lives in the attribute controller. The TSR refuses to install in that case, since answering “VGA present” on a machine that will never render mode 13h only sends games down a path that leaves the screen black.

Item Supported behaviour
Mode entry INT 10h AX=0013h through the TSR, with the OSD option enabled.
Framebuffer A000:0000, one byte per pixel and 64,000 visible bytes.
Palette 256-entry DAC, 6-bit RGB components and auto-increment.
Auxiliary BIOS Pixel read/write, detection, and the DAC subfunctions (AH=10h with AL=10h/12h/15h/17h) that a real EGA option ROM drops silently because they are VGA additions.
Mode exit Another BIOS mode change returns ownership to the EGA path.

Should it stay off for EGA-only sessions?

For everyday use, leaving it on doesn't break anything: in ega_top.v, ega_dac_hit only substitutes a palette entry when that specific DAC index was actually written by software (vga_dac_sample_valid), so an EGA game that never writes 3C7h3C9h looks identical with the option on or off, and VGATSR.COM chains every unrecognised INT 10h call straight through to the real BIOS.

But the option exists for a reason, and turning it off is the right call when the goal is a machine that behaves and is detected as a real EGA with no VGA trace at all — which is why the ports are gated on the option in the first place rather than left decoding permanently:

  • Port-level fingerprint. With the option on, ports 3C7h3C9h answer as a DAC even when no software ever calls the BIOS for one — a real IBM EGA doesn't decode those ports at all, its palette lives in the attribute controller. Software that fingerprints hardware by probing I/O ports directly, rather than through INT 10h, can see that and conclude a VGA is present. Turning the option off closes those ports, so the card answers exactly as an EGA should to a port probe as much as to a BIOS call.
  • BIOS-level fidelity. With VGATSR.COM resident, INT 10h AH=12h/BL=10h (“Return EGA information”, a standard EGA call, not a VGA-only one) is answered by the TSR with a fixed value instead of being chained to the loaded EGA BIOS ROM. Not loading the TSR means every EGA BIOS call gets exactly what that ROM would answer, with nothing intercepted.

So: fine to leave on for normal play, but turn it off when the goal is specifically authentic, untraceable EGA behaviour — testing against real hardware, for example, or running EGA-only software with nothing else in the picture.

×
This is not a complete VGA

It does not claim VBE/SVGA, Mode X, planar 256-colour VGA modes, an independent VGA text pipeline or full compatibility with VGA registers unnecessary for the mode 13h objective.

05

Features

System capabilities

Processor and timing

  • MCL86-based 8088 CPU, in Boogermann's rewrite, which passes the 3M-case SingleStepTests/8088 suite in full.
  • 4.77 MHz, 7.16 MHz and 9.54 MHz with a cycle-accurate target.
  • Fast mode equivalent to a 3.5 MHz PC/AT 286 - see the note on its current state below.
  • Clock selection from the OSD.

Memory

  • 640 KiB of conventional memory.
  • Optional 48 KiB UMB at C400h-CFFFh.
  • Optional EMS of up to 2 MiB with a fixed D000h-DFFFh page frame.
  • E000h-EBFFh remains decoded SDRAM, but is not assigned as a DOS UMB.

Storage and ROM

  • Two floppy drives using compatible images.
  • Two IDE targets and second SD-card support.
  • XTIDE for hard-disk images.
  • Separate slots for the main BIOS, EC00h BIOS and EGA BIOS.
  • Selectable ROM writing for development.

Audio

  • Internal PC speaker.
  • AdLib OPL2 through JTOPL.
  • Creative Music System / Game Blaster.
  • MPU-401 MIDI at 330h, IRQ 2, for an mt32-pi or a USB MIDI interface.
  • Volume, boost and stereo-mix controls from the OSD.

Input

  • Two analogue or digital joysticks.
  • Optional joystick synchronisation with CPU speed.
  • Joystick swapping from the menu.
  • Microsoft-compatible mouse through COM1.

MiSTer output

  • Direct 15 kHz output for every mode a television can scan.
  • 350-line modes convertible to 480i or 240p from the OSD.
  • Horizontal and vertical centring, one pair of values for all modes.
  • Aspect-ratio adjustment and sync width correction.
  • Full-colour, green, amber, monochrome and tinted display modes.
  • HDMI through the MiSTer scaler, unaffected by the above.

Effective 8088 memory map

The 8088 sees one 1 MiB physical address space. With the default UMB and EMS options enabled, its regions have the following ownership; ROM rows describe the normal state after their images are loaded.

PCXT core physical memory map A proportional overview of the full 1 MiB 8088 address space and an enlarged map of its upper 384 KiB. It identifies conventional SDRAM, video memory, EGA and system ROMs, the C400h UMB, the D000h EMS page frame, and directly decoded SDRAM at E000h. Complete address space 1 MiB physical map · proportional view Upper 384 KiB video · ROM · UMB · EMS Conventional SDRAM 640 KiB FFFFFh A0000h 00000h expanded at right Upper memory detail A0000h-FFFFFh · 384 KiB · top address at the top Main system BIOS 64 KiB · F0000h-FFFFFh XTIDE option ROM · 16 KiB Directly decoded SDRAM 48 KiB · E0000h-EBFFFh · not in the UMB chain EMS page frame · D0000h-DFFFFh · 4 × 16 KiB banks OSD-gated; each bank responds only when mapped Optional SDRAM-backed UMB 48 KiB · C4000h-CFFFFh · enabled in the OSD EGA option ROM · C0000h-C3FFFh · 16 KiB Video memory A0000h-BFFFFh · 128 KiB reserved for EGA / VGA A0000h-AFFFFh · 64 KiB · EGA / VGA mode 13h B0000h-BFFFFh · 64 KiB · selectable EGA apertures FFFFFh EC000h E0000h D0000h C4000h C0000h A0000h Conventional SDRAM Video / EMS Optional UMB ROM SDRAM, not a UMB
Address range Size Core assignment DOS availability
00000h-9FFFFh640 KiBConventional SDRAMConventional memory
A0000h-AFFFFh64 KiBEGA aperture and VGA mode 13h framebufferReserved for video
B0000h-B7FFFh32 KiBSelectable EGA monochrome apertureReserved for video
B8000h-BFFFFh32 KiBSelectable EGA colour/text apertureReserved for video
C0000h-C3FFFh16 KiBEGA option ROMReserved for EGA BIOS
C4000h-CFFFFh48 KiBOptional SDRAM-backed UMBUMB when enabled in the OSD
D0000h-D3FFFh16 KiBEMS page-frame bank 0EMS bank 0 when enabled and mapped; otherwise unmapped
D4000h-D7FFFh16 KiBEMS page-frame bank 1EMS bank 1 when enabled and mapped; otherwise unmapped
D8000h-DBFFFh16 KiBEMS page-frame bank 2EMS bank 2 when enabled and mapped; otherwise unmapped
DC000h-DFFFFh16 KiBEMS page-frame bank 3EMS bank 3 when enabled and mapped; otherwise unmapped
E0000h-EBFFFh48 KiBDirectly decoded SDRAMNot registered as UMB by the supplied DOS configuration
EC0000h-EFFFFh16 KiBXTIDE option ROMReserved when an XTIDE ROM is loaded
F0000h-FFFFFh64 KiBMain system BIOSReserved for system BIOS

EGA can select an A0000h-BFFFFh, A0000h-AFFFFh, B0000h-B7FFFh or B8000h-BFFFFh aperture through its graphics controller. The whole A/B region is therefore reserved for video, regardless of the current EGA map. VGA mode 13h owns A0000h-AFFFFh while active.

The supplied DOS configuration registers only C400h-CFFFh with USE!UMBS.SYS. The E000h block is kept out of the UMB chain because it is separated by the D000h EMS frame; treating the whole C400h-EC00h interval as one UMB would collide with EMS.

The 2MB EMS D000-DFFF OSD option gates the D000h page frame as a whole. With it disabled, D0000h-DFFFFh is unmapped. With it enabled, each 16 KiB bank responds only after its corresponding EMS page register has been mapped.

Two fixes at the fastest CPU setting

The former intermittent memory fault at PC/AT 3.5 MHz was caused by the 8088 write pulse ending before a refresh-induced wait could reach the CPU. RAM now retains an accepted address and byte until the SDRAM write completes. A regression covers every clock of the refresh sequence at addresses throughout conventional memory, including the IBM BIOS IRQ flag at 0046Bh, and also checks tight consecutive writes. RTL simulation passes; Supersoft SLOW REFRESH has also been confirmed error-free on MiSTer hardware.

The IBM 5160 BIOS dated 11/08/82 also printed 101 before the memory count at that same speed, independently of the memory fault: the 8088 core recognized INTR asynchronously instead of only at instruction boundaries, which could race the POST's PIC/PIT hot-interrupt check. The core now samples INTR synchronously at each instruction boundary, and hardware testing confirms the POST completes without 101 at maximum speed.

This INTR-sampling defect is not new. It was fixed once already, years earlier, and the fix was silently lost when the CPU core was resynced from its upstream source — well before the EGA work, and before this build's own maximum-speed baseline. Being a genuine race between two asynchronous events rather than a missing feature, the regression stayed dormant without a visible symptom until unrelated timing changes elsewhere in the design shifted the CPU's cycle-by-cycle timing enough to land inside the failure window. The EGA work did not introduce this defect; it exposed one that had already been present, silently, for a long time.

06

Effective configuration

OSD and build options

The menu retains the user's practical configuration choices, but no longer selects between competing graphics adapters: EGA is always the main video path.

Features enabled in config.tcl

ENABLE_OPL2ENABLE_CMSENABLE_EMSENABLE_UMB
OSD group Main available options
System and BIOS Splash, main BIOS, EC00, EGA BIOS and write control.
Disks FDD A/B, write protection, IDE 0-0, IDE 0-1 and second SD.
CPU 4.77 MHz, 7.16 MHz, 9.54 MHz and fast PC/AT mode.
Audio and video C/MS, OPL2, speaker, mixing, CRT offsets, timing, effects, aspect ratio and VGA Mode 13h.
Hardware 2 MiB EMS at D000h-DFFFh, UMB at C400h-CFFFh, two joysticks and synchronisation options.
07

Getting started

BIOS, ROM and startup

Recommended startup path

  1. Copy the contents of games/PCXT to the MiSTer SD card.
  2. Extract the bundled FreeDOS image.
  3. Select the core in Computers / PCXT.
  4. Choose the IBM PCXT model and a CPU speed.
  5. Mount FreeDOS_HD.img as the HDD image.
  6. Select a compatible BIOS, such as Micro8088.
  7. Run Reset & apply settings.

Firmware options

  • Scripts in SW/ROMs/ build ROMs from IBM 5160 or Juko ST sources.
  • Open PCXT31 and Micro8088 BIOS options with integrated XTIDE.
  • Additional XTIDE of up to 16 KiB at EC00h.
  • Floppy compatibility depends on the BIOS in use.
  • Current VGA mode 13h support requires the TSR to be loaded from DOS.
!
The BIOS determines part of floppy compatibility

IBM 5160 works reliably with 360 KiB images; Micro8088 normally supports 720 KiB and 1.44 MiB. Smaller images may need to be preformatted.

08

Future work

Possible EGA improvements

The core is already functional for its intended use. Comparing its EGA path against the mature 86Box implementation surfaced a handful of register-edge behaviours worth closing; all of them are now implemented, as noted below.

Delivered since this list was first written

Authentic EGA clock selection is done — both dot clocks are implemented and selected per mode from Miscellaneous Output bit 2. Horizontal Pel Panning and Line Compare, the two register behaviours this list originally called out, are implemented and covered by regression benches; both are described in the video section.

!
Compatibility first, not feature expansion

This roadmap is about making the existing EGA model more faithful. It does not imply a move towards VGA, VBE, SVGA or additional video adapters.

09

Scope

What this core does and does not claim

Explicit goals

  • Recreate a reliable PC/XT on MiSTer.
  • Keep EGA as the sole owner of normal video.
  • Run compatible CGA software through EGA.
  • Offer a packed mode 13h for common DOS software.
  • Keep the architecture understandable and verifiable.

Outside the current goal

  • Active HGC or Tandy hardware in this variant.
  • Dynamic switching between video cards.
  • General VGA or SVGA compatibility.
  • VBE, Mode X and undocumented VGA extensions.
  • Guaranteed compatibility with every BIOS or game.
Technical direction

The distinctive value is reducing legacy paths without losing the historical software that a real EGA can run. VGA mode 13h is added as a bounded extension: it takes ownership of the display only in mode 13h, and outside it contributes only the DAC.

10

Open project

Credits and licence

MiSTer port and continued project development by spark2k06, built on important contributions from the FPGA recreation and classic PC preservation community.

The 8088 CPU comes from the MCL86 project by MicroCoreLabs, in the rewrite contributed by Boogermann, and the chipset from KFPC-XT by kitune-san. The EGA and VGA mode 13h behaviour is modelled on the video emulation in 86Box. AdLib sound uses JTOPL by Jose Tejada, and the MIDI path reuses the mt32-pi bridge by Sorgelig and Kitrinx that ships with the MiSTer framework. Earlier releases used the Graphics Gremlin CGA and Hercules adapters by TubeTimeUS, since replaced by the EGA path. Splash artwork by mills32.

The repository is licensed under the GNU General Public License, version 3. Redistribution and modification must comply with that licence and the terms that apply to the integrated components.