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.
PC/XT foundation
Selectable 8088/8086 CPU with multiple clock rates, compatible chipset, conventional memory, UMB, EMS, BIOS, floppy drives and XTIDE.
Single-owner video
EGA owns CPU access, VRAM, text, graphics, timing and RGB output. CGA compatibility is part of EGA.
Focused VGA extension
Adds packed and selected unchained 256-colour profiles, planar mode 0Dh and a DAC without becoming a general VGA implementation.
This is an EGA-centred PC/XT core. Compatibility with CGA modes does not mean that an independent CGA card exists, and VGA 13h+ support does not imply a complete VGA implementation.
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.
The EGA implementation and the optional VGA 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.
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 Max 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 Max, 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.
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 13h+ support.
- JTOPL, by José Tejada/jotego, for AdLib OPL2 audio.
- MiSTer port integration, adaptation and further development by spark2k06.
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 video 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 at that rate, 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.
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.
Graphics extension
VGA 13h+, deliberately limited in scope
Familiar VGA profiles for DOS software
The extension implements packed 320x200x256 mode 13h,
plus partial, deliberately bounded Mode X support: unchained
256-colour profiles at 320x200, 360x200 and 320x240, and a fixed
planar 320x200x16 mode 0Dh profile. It adds the VGA
DAC while leaving normal EGA modes on the EGA path.
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 extension-off path unchanged by
construction.
Activation and output timing
VGA 13h+ starts disabled after reset. VGATSR.COM
enables it through XTEGACTL before installing its
INT 10h hook; a warm boot clears the extension again.
The OSD's VGA 13h+ CRT choice is independent: it selects a
conventional Native 31.5 kHz / 70 Hz raster or the 15.7 kHz / 59.9
Hz TV raster, but does not activate or remove the VGA device.
| Item | Supported behaviour |
|---|---|
| Mode entry | INT 10h AX=0013h through the resident TSR. |
| Framebuffer |
Packed mode 13h uses A000:0000, one byte per
pixel and 64,000 visible bytes. The supported Mode X
profiles use the four EGA planes with four pixels per byte.
|
| 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, loading the TSR doesn't break EGA software: 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 3C7h–3C9h looks
identical with the extension enabled or disabled, and
VGATSR.COM chains every unrecognised
INT 10h call straight through to the real BIOS.
But the bounded activation exists for a reason, and not loading the TSR 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 extension state rather than left decoding permanently:
-
Port-level fingerprint. With the extension enabled,
ports
3C7h–3C9hanswer 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 throughINT 10h, can see that and conclude a VGA is present. Leaving the extension disabled 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.COMresident,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 load VGATSR for normal play, but omit it 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.
It does not claim VBE/SVGA, arbitrary Mode X profiles beyond the supported subset, planar 16-colour VGA modes beyond the supported mode 0Dh, an independent VGA text pipeline, programmable timings or full compatibility with VGA registers outside the supported profiles.
Features
System capabilities
Processor and timing
- MCL86 CPU with a selectable 8088 or 8086 BIU. The shared EU derives from Boogermann's rewrite, which passes the 3M-case SingleStepTests/8088 suite in full.
- 8086 mode has a six-byte prefetch queue and wide aligned SDRAM word transfers; 8088 retains its four-byte queue and byte-wide transfers. Odd words and the XT-class I/O/video path remain byte-split.
- 4.77 MHz, 7.16 MHz and 9.54 MHz with a cycle-accurate target in both CPU modes.
- Max: an unthrottled performance profile for both CPU modes, not a historical speed grade or a cycle-accurate profile.
- 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.
- Sound Blaster Pro at 220h, DMA 1 and selectable IRQ 5/7.
- Optional Tandy SN76489 audio at 0C0h.
- 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.
| Address range | Size | Core assignment | DOS availability |
|---|---|---|---|
00000h-9FFFFh | 640 KiB | Conventional SDRAM | Conventional memory |
A0000h-AFFFFh | 64 KiB | EGA aperture and VGA 13h+ framebuffer | Reserved for video |
B0000h-B7FFFh | 32 KiB | Selectable EGA monochrome aperture | Reserved for video |
B8000h-BFFFFh | 32 KiB | Selectable EGA colour/text aperture | Reserved for video |
C0000h-C3FFFh | 16 KiB | EGA option ROM | Reserved for EGA BIOS |
C4000h-CFFFFh | 48 KiB | Optional SDRAM-backed UMB | UMB when enabled in the OSD |
D0000h-D3FFFh | 16 KiB | EMS page-frame bank 0 | EMS bank 0 when enabled and mapped; otherwise unmapped |
D4000h-D7FFFh | 16 KiB | EMS page-frame bank 1 | EMS bank 1 when enabled and mapped; otherwise unmapped |
D8000h-DBFFFh | 16 KiB | EMS page-frame bank 2 | EMS bank 2 when enabled and mapped; otherwise unmapped |
DC000h-DFFFFh | 16 KiB | EMS page-frame bank 3 | EMS bank 3 when enabled and mapped; otherwise unmapped |
E0000h-EBFFFh | 48 KiB | Directly decoded SDRAM | Not registered as UMB by the supplied DOS configuration |
EC0000h-EFFFFh | 16 KiB | XTIDE option ROM | Reserved when an XTIDE ROM is loaded |
F0000h-FFFFFh | 64 KiB | Main system BIOS | Reserved 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 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.
The former intermittent memory fault at Max 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 Max.
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 Max 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.
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
| 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 Max (unthrottled). |
| Audio and video | Audio 220h (C/MS, Sound Blaster or disabled), OPL2, Tandy, speaker, mixing, CRT offsets, sync widths, effects, aspect ratio and the VGA 13h+ raster. |
| Hardware | 2 MiB EMS at D000h-DFFFh, UMB at C400h-CFFFh, Sound Blaster IRQ 5/7, MPU-401, two joysticks and synchronisation options. |
DOS startup reference
hdd/CONFIG.SYS registers the core's real windows: the 48 KiB UMB at C400h-CFFFh and the four-bank EMS frame at D000h-DFFFh.
DEVICE=C:\UTIL\USE!UMBS.SYS C400-D000
DEVICE=C:\UTIL\DOSMAX\DOSMAX.EXE /R+ /N+ /P-
DEVICEHIGH=C:\UTIL\LTEMM.EXE /p:D000 /x /n
The driver's D000 upper bound is exclusive, so it stops before EMS. E000h-EBFFh remains outside the DOS UMB chain.
Sound Blaster environment
SET BLASTER=A220 I5 D1 T4
SET SOUND=C:\SB
SET MIDI=SYNTH:1 MAP:E MODE:0
IRQ 5 is the default. If the OSD or XTEGACTL selects IRQ 7, DOS software must use I7 too. The repository includes complete CONFIG.SYS and AUTOEXEC.BAT examples under hdd/.
Core-specific MiSTer.ini example for 31 kHz analogue output
[PCXT-EGA]
vga_scaler=1
video_mode=6
vsync_adjust=2
The section applies only to this core. Mode 6 is MiSTer's built-in 640x480 preset; use vsync_adjust=1 if a flat panel rejects the core-following refresh, and leave vga_scaler disabled for direct 15 kHz output.
Getting started
BIOS, ROM and startup
Recommended startup path
- Copy the contents of
games/PCXTto the MiSTer SD card. - Extract the bundled FreeDOS image.
- Select the core in Computers / PCXT.
- Choose the IBM PCXT model and a CPU speed.
- Mount
FreeDOS_HD.imgas the HDD image. - Select a compatible BIOS, such as Micro8088.
- 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.
- VGA 13h+ requires
hdd/VGATSR.COMto be loaded from DOS.
IBM 5160 works reliably with 360 KiB images; Micro8088 normally supports 720 KiB and 1.44 MiB. Smaller images may need to be preformatted.
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.
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.
This roadmap is about making the existing EGA model more faithful. It does not imply a move towards a complete VGA, VBE, SVGA or additional video adapters.
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 bounded VGA 13h+ profiles for selected DOS software.
- Keep the architecture understandable and verifiable.
Outside the current goal
- Active HGC or Tandy video hardware in this variant.
- Dynamic switching between video cards.
- General VGA or SVGA compatibility.
- VBE/SVGA, arbitrary Mode X profiles beyond the supported subset and undocumented VGA extensions.
- Guaranteed compatibility with every BIOS or game.
The distinctive value is reducing legacy paths without losing the historical software that a real EGA can run. VGA 13h+ is added as a bounded extension: it takes ownership of the display only in its supported packed, unchained and planar profiles; outside them it contributes only the DAC.
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 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.