Introduction
Welcome to “The PC Emulation Book.”
This document aims to become a comprehensive guide to emulating the original models of the IBM Personal Computer:
- The IBM Model 5150 Personal Computer
- The IBM Model 5160 Personal Computer XT
When we refer to the original “IBM PC”, we are technically referring to the IBM Model 5150. However, the slightly improved IBM Model 5160 (otherwise known as the IBM XT) is similar enough in design and function that they are often lumped together. In this book, we will refer to the 5160 or XT interchangably, when a distinction between the PC and XT is important. Otherwise, consider any reference to the “IBM PC” as referring to either model.
🚧 UNDER CONSTRUCTION! 🚧
You’ll notice that many of the pages in this book are empty stubs. Content is still being fleshed out. Here is a list of some of the more complete pages:
- The Intel 8253 Programmable Interval Timer
- The Intel 8259 Programmable Interrupt Controller
- The Keyboard
Why Emulate the PC?
The IBM PC is arguably one of the most influential computers in history, establishing standards that enabled the proliferation of “PC-compatible” systems and cemented the very term “PC” as an Intel-based system, probably running a Microsoft operating system. The “PC” lives on even today, only recently challenged for supremacy by the rise of ARM-based CPUs.
The PC was an open and well-documented system. IBM published full schematics and commented BIOS source code listings, allowing anyone to understand in great detail how the system operated, even without owning the physical hardware.
There are thousands of software titles to explore on a PC emulator, although the PC’s limited graphics and sound capabilities make many of the games for the platform less than spectacular. Still, there are some classic titles that are still fun to play today, such as AlleyCat and Digger.
If you’re up for a challenge, recently several demos have been released that push the original PC hardware to its utter limits and require cycle-exact emulation of the 5150 and its components. These demos include 8088 MPH, released in 2015, and Area 5150, released in 2022.
Even without any attempt at cycle-accuracy, the PC can be emulated with a respectable level of compatibility.
What You’ll Learn
This book aims to cover the complete process of building a PC emulator from the ground up, including:
- Hardware Architecture: Understanding the IBM PC’s system design and component interactions
- CPU Emulation: Implementing the Intel 8088 processor
- Support Chips: Emulating the various Intel support chips that made the PC work
- Peripheral Devices: Implementing keyboards, displays, storage, and other I/O devices
- System Integration: Bringing all components together into a working emulator
Target Audience
This book is intended for emulator authors, but retro-developers may find it a useful reference as well, or anyone simply curious about how classic computers of the era worked.
Prerequisites
To get the most out of this book, you should have:
- A basic understanding of computer architecture concepts
- Familiarity with a high-performance programming language (C, C++, Rust, or similar)
- Basic understanding of digital logic
- Some experience with emulation
- If you have never programmed an emulator before, it is recommended that you start with the CHIP-8, a simple system that teaches basic emulation concepts. You can find a guide here.
License
This book is open-source and all content is licensed under the CC0 1.0 Creative Commons Public Domain license, except where otherwise noted.
Contributing
The main source repository for the PC Emulation Book can be found here.
IBM PC/XT Architecture Overview
The design of the original IBM 5150 reflected IBM’s project requirements to create a low-cost, maintainable system largely comprised of off-the-shelf parts, yet capable of being expanded. They succeeded in that effort far beyond any conceivable expectations - the IBM PC is now recognized as the ancestor of a line of “PC Compatible” systems that continue to be sold to this day.
CPU
IBM chose the Intel 8088 for the 5150, which is also used in the 5160. The 8088 was a lower-cost variant of the 8086 CPU. While still 16-bit internally, the 8088 only had an 8-bit data bus. This simplified the PC’s motherboard design, and made it easy to build a system around Intel’s various 8-bit peripheral chips.
The 8088 has 20 address lines, allowing it to address \(2^{20}\) bytes, or 1MB.
IBM chose to reserve addresses above 0xA0000, leading to the infamous “640KB” memory limit that is often mistakenly blamed on Microsoft.
Expansion Bus
The 8-bit data bus of the 8088 would also dictate the 8-bit data width of the system’s expansion bus. This bus would later be expanded to 16-bits with the IBM 5170 AT, and would later be dubbed the ISA bus by Compaq1 and a growing consortium of PC clone manufacturers.
System Clock
The 5150 has a single main system crystal with a frequency of 14.31818MHz. This frequency is exactly four times the NTSC color subcarrier frequency.
The crystal frequency can be expressed as a fraction:
$$f_{crystal} = \frac{315}{22} \text{ MHz} = 14.318181\overline{81} \text{ MHz}$$
This choice was likely made due to the low cost of NTSC-derived clock crystals, as they were being manufactured by the millions to be used in television sets. It also made the PC more easily compatible with North American television sets, making low-cost display option available to PC owners. It also allowed the IBM Color Graphics Adapter to omit a separate crystal.
The CPU frequency of 4.77 MHz is obtained by dividing the system clock by 3:
$$\frac{14.3181818}{3} = 4.773MHz$$
The 8088 was rated for 5MHz operation2, so this represents about a 5% underclock.
References
-
wikipedia.org Industry Standard Architecture. ↩
-
Intel Corporation. 8088 8-Bit Hmos Microprocessor. Intel Corporation, August 1990. Document Number: 231456-006. Available at: Intel 8088 Data Sheet PDF ↩
Intel 8088 CPU
Architecture and Registers
Instruction Set and Execution
Bus Interface and Timing
Intel 8259 Programmable Interrupt Controller
The Intel 8259 Programmable Interrupt Controller (PIC) plays an essential role in the operation of much of the hardware of the IBM PC. The PIC can be thought of as an expansion unit to the 8088’s single INTR pin, allowing 8 separate interrupt sources to be handled in a prioritized manner.
The PIC is a surprisingly challenging chip to emulate correctly, partially due to some ambiguities in its documentation.
Overview
The 8 inputs of the PIC are called Interrupt Request lines, which are often referred to as IRQs (Interrupt reQuest).
The PIC has three main 8-bit registers. Each bit in these registers corresponds to an IRQ with the least significant bit mapping to IRQ 0 and the most significant bit mapping to IRQ 7.
- Interrupt Request Register (IRR): This register holds bits reflecting the IRQ lines that are requesting service.
- Interrupt Mask Register (IMR): A
1bit set in this register prevents the corresponding IRQ line from being serviced. - In-Service Register (ISR): A
1bit set in this register indicates that the corresponding IRQ has been acknowledged by the CPU and is now “in-service”.
The 8 IRQs of the PIC are ordered in terms of priority, with IRQ 0 being the highest priority, and IRQ 7 being the lowest priority. This means that if IRQ 0 and IRQ 1 occur simultaneously, IRQ 0 will be serviced first.
This also means that it is possible for a higher priority interrupt to be serviced while a lower priority interrupt is already in service. Normally, the 8088 clears the I flag when executing an interrupt. If a programmer desires their interrupt service routine to be reentrant, they would need to issue an STI instruction to allow this to occur.
IBM PC PIC Configuration
IRQ Assignments
The IBM PC maps devices to the 8259’s IRQ lines as follows. Some of these connections are direct traces on the motherboard, other IRQs are connected to the ISA bus. In some cases, a peripheral card may have had a jumper to allow selection of a particular IRQ.
| IRQ | Connection | Device |
|---|---|---|
| IRQ 0 | Direct | System Timer |
| IRQ 1 | Direct | Keyboard Controller |
| IRQ 2 | ISA/Direct | Vsync Interrupt (EGA) or Secondary 8259 (AT) |
| IRQ 3 | ISA | Serial Port - COM2 |
| IRQ 4 | ISA | Serial Port - COM1 |
| IRQ 5 | ISA | Hard Disk Controller or LPT2 |
| IRQ 6 | ISA | Floppy Disk Controller |
| IRQ 7 | ISA | Parallel Port - LPT1 |
I/O Ports
The 8259 has a single address pin, A0, via which one of two registers can be selected.
The two registers are decoded by the PC at the following addresses:
| PC Port | 8259 Port | RW | Description |
|---|---|---|---|
| 0x20 | 0 | RW | Command/Status Register |
| 0x21 | 1 | RW | Data/Mask Register |
The Unimportant Stuff
The 8259 was designed to be compatible not only with the 8088 and 8086, but with Intel’s earlier CPUs, the 8080 and 8085. There are various mode flag bits that control whether the 8259 should expect to be paired with an 8088 or not - obviously, on the IBM PC, you can expect these bits to be set properly, and emulation of the 8080 modes is certainly not required.
The 8259 supported daisy-chaining of additional 8259 chips to enable more interrupt sources to be handled - something that Intel called cascading. This was not used on the IBM PC, which only had a single 8259. Two 8259s were employed on the IBM 5170 AT in a primary/secondary configuration. Obviously this is something you do not need to emulate either.
The PIC can be operated in edge-triggered or level-triggered mode. The IBM PC exclusively operates in edge-triggered mode, but implementing level-triggered mode is fairly trivial to do.
There are additional features like priority rotation and special mask mode which are not used by the IBM PC.
Interrupt Processing Logic
The important thing to understand about the PIC is that it is implemented as an array of 8 priority cell circuits. The IRR, IMR, and ISR “registers” are simply latches within each priority cell. This means that a good part of the interrupt evaluation logic happens continuously, since it is simply driven by immediate state of the circuit. The PIC has no clock input, so all it can do is respond to changes of its input pins. With one exception - but we’ll talk about that later.
Let’s look at an example of interrupt logic flow:
The Simple Version
- A device raises its IRQ line connected to the PIC.
- The PIC looks to see if that IRQ is masked off in the IMR, if it is already in service, or if a higher-priority interrupt is in service, in which case the interrupt cannot be serviced at the moment.
- If the IRQ can be serviced, the PIC raises the INTR line to the CPU.
- The CPU acknowledges the interrupt and the PIC sets the corresponding bit in the ISR to indicate that the interrupt is now in service. The corresponding bit in the IRR is cleared to indicate the IRQ is no longer requesting service.
- The CPU executes the interrupt based on the 8-bit vector the PIC provides in response to the CPU’s interrupt acknowledgement.
- The interrupt service routine executes. When it is done, it sends an
End-of-Interrupt (EOI)command to the PIC. - The PIC clears the corresponding bit in the
ISRindicating that the interrupt has completed servicing.
The original IRQ line may remain high at this point, but in the PC’s standard edge-triggered mode it will not be serviced again until it transitions low and then high again.
The Detailed Version
- A device raises its IRQ line connected to the PIC.
- The low-to-high transition of the IRQ line sets the IRQ’s edge latch and sets the corresponding bit in the
IRR.- If the corresponding bit in the
IMRis set, the signal from theIRRdoes not propagate further. - If the corresponding bit in the
IMRis clear, the signal from theIRRreaches thePriority Resolver.
- If the corresponding bit in the
- The priority resolver checks to see if the corresponding bit in the
ISRis set, or if any bits lower than the corresponding bit are set, indicating a higher priority interrupt is already in service.- If any of these bits are set, nothing further happens for the moment.
- If none of these bits are set, the priority resolver will instruct the control logic to raise the PIC’s INTR pin, which is connected to the CPU.
- The CPU finishes an instruction, at which point it samples the INTR pin.
- The CPU notices INTR is high.
- If the CPU’s
Iflag is cleared, it ignores INTR being high and continues execution as normal.
- If the CPU’s
- The CPU begins to acknowledge the interrupt.
- The CPU issues one bus cycle with the
INTAbus status encoded. - The CPU bus controller decodes the
INTAbus status and asserts the physical \(\overline{INTA}\) pin.
- The CPU issues one bus cycle with the
- The PIC detects the \(\overline{INTA}\) pin going high.
- The priority resolver sets the highest-priority bit in the
ISRto indicate that the interrupt is entering service. - In edge-triggered mode, the priority resolver clears the corresponding bit in the
IRR.
- This is the only difference between edge-triggered mode and level-triggered mode.
- The control logic asserts the internal \(\overline{FREEZE}\) signal. This prevents any change to any bit in the
IRRwhile the interrupt acknowledge process is active.
- The priority resolver sets the highest-priority bit in the
- The \(\overline{INTA}\) pin goes low as the CPU completes the INTA bus cycle.
- The \(\overline{INTA}\) pin goes high again as the CPU issues a second INTA bus cycle.
- The PIC emits the 8-bit interrupt vector which the CPU reads during the second INTA bus cycle.
- The \(\overline{INTA}\) pin goes low as the CPU completes the second INTA bus cycle.
- The control logic de-asserts the \(\overline{FREEZE}\) signal, allowing the
IRRto update again. - In auto-EOI mode, the priority resolver clears the corresponding
ISRbit.
- The control logic de-asserts the \(\overline{FREEZE}\) signal, allowing the
- The CPU uses the interrupt vector received from the PIC to look up a far pointer to the correct Interrupt Service Routine from the Interrupt Vector Table.
- The CPU clears the
IandTflags, then jumps to the interrupt service routine. - At the end of the interrupt service routine, the routine sends an
EOIcommand to the PIC. - The PIC clears the appropriate bit in the
ISRto indicate that the interrupt has completed servicing.
The Intel 8253 Programmable Interval Timer
The 8253 Programmable Interval Timer (PIT) is responsible for a number of tasks on the IBM PC. It maintains the system time, drives DRAM refresh, and controls the PC speaker to generate sound.
Overview
The PIT contains three independently operating 16-bit counters or ‘channels’, each capable of operating in different modes.
Physically, each timer channel is assigned a clock input, a gate pin, and an output pin (OUT). The gate pin can be used to control or disable counting in specific modes.
Counters are operated by first configuring them by writing a Control Word to the 8253’s Control Word Register. Then, an initial count - often referred to as a ‘reload value’ - is written directly to the timer channel port. A counter has a full 16-bit range, as an initial count of 0 is treated as a count of 65,536 in binary mode or \(10^4\) in BCD mode.
Once configured and running, on each tick of the channel’s clock input, the channel’s internal Counting Element decrements. When the counter reaches 0 (or 1 in some modes), some specific behavior will be triggered (depending on mode), usually changing the state of the channel’s output pin.
The current value of a counter channel can be read at any time by reading from the channel’s specified port.
Pinout
Figure 1: Intel 8253 Pinout
The 8253 has an 8-bit data bus by which you read and write the chip’s registers, which are selected by the A0 and A1 pins.
IBM PC Timer Configuration
The 8253 has three independent clock input pins, allowing each counter to be driven at a different frequency. The IBM PC ties all three clock inputs to the same clock line, which runs at the system crystal frequency divided by 12.
$$f_{timer} = \frac{\frac{315}{22}}{12} \text{ MHz} = 1.19318\overline{18} \text{ MHz}$$
Note: Other systems that use the 8253 can connect these timer clock inputs in different ways - even connecting one timer channel output to the clock input of another to act as a clock divisor.
| Timer | Purpose | Frequency | Connection |
|---|---|---|---|
| Timer 0 | System Timer | 18.2 Hz | System Timer Interrupt |
| Timer 1 | DRAM Refresh | 15 μs | DMA Controller for memory refresh |
| Timer 2 | Speaker | Variable | PC Speaker output |
Timer 0
Timer 0’s OUT pin is directly connected to the IR0 pin of the 8259A Programmable Interrupt Controller. When the Timer 0 OUT pin has a low-to-high transition, this will trigger an IRQ0. This causes an interrupt 8, which normally is configured to maintain the system’s time of day clock by the BIOS.
The BIOS initializes Timer 0 to a reload value of 0 (65,536)
$$ T = \frac{65536}{1.19318\overline{18}\times 10^{6}} \approx 0.0549254\ \text{s} $$
$$ T \approx 54.93\ \text{ms} $$
$$ \frac{1\text{s}}{54.93\text{ms}} \approx 18.2Hz $$
This will cause an Interrupt 8 to execute 18.2 times per second.
Many applications, especially games, will use Timer 0 for their own purposes, and so the time of day clock was notoriously inaccurate without being synchronized to a realtime clock module.
Timer 0’s GATE pin is tied to +5v.
Timer 1
Timer 1’s OUT pin connects to a 74LS74 flip-flop which latches its output. The output of this flip flop is connected to the DRQ0 pin of the 8237 DMA Controller, and is reset by the \(\overline{\text{DACK0}}\) signal. This causes one DMA transfer to occur in read mode, which refreshes the system’s DRAM.
The BIOS initializes Timer 1 to a reload value of 18:
$$ T = \frac{18}{1.19318\overline{18}\times 10^{6}} \approx 0.0000151\ \text{s} $$
$$ T \approx 15.1\ \text{μs} $$
$$ \frac{1\text{s}}{15.1\times 10^{-6}\text{s}} \approx 66.2\text{KHz} $$
This will cause a DMA refresh request approximately every 15 microseconds, or every 72 clock cycles. If this sounds like a lot, it is. The DRAM refresh process robs the 8088 of about 5-6% of its performance, depending on bus activity.
Note: You can ignore this channel if you are not interested in cycle-accuracy. However, the IBM PC BIOS does check that Timer 1 is running by checking that the DMA channel 0 is counting. You can hack your way around this test by just making the DMA channel 0 count on read.
Timer 1’s GATE pin is tied to +5v.
Timer 2
Timer 2’s OUT pin connects to the PC’s speaker and cassette interface circuitry. Timer 2 is typically configured to produce square waves to drive the speaker to play notes of specific frequencies, and Timer 2’s GATE input can be used to silence the speaker when desired.
For more details, see the PC Speaker chapter.
Timer 2’s GATE pin is tied to the 8255 PPI’s Port B, Bit 0 (Pin #18).
I/O Ports
The 8253 has two address lines, A0 and A1, which allow selection of four ports.
These four ports are decoded by the PC at the following addresses:
| PC Port | 8253 Port | RW | Description |
|---|---|---|---|
| 0x40 | 0 | RW | Timer 0 Count Register |
| 0x41 | 1 | RW | Timer 1 Count Register |
| 0x42 | 2 | RW | Timer 2 Count Register |
| 0x43 | 3 | W | Control Word Register |
Control Word Format
The 8253’s control word can be written to at port 0x43 and is used to configure one of the three counters, each of which can be configured with different modes.
Figure 2: Intel 8253 Control Word Format
The specified channel’s counting mode, IO mode, and whether or not it should count in BCD, is configured with a single 8-bit write. Note that using 0b11 as the timer selection is invalid on the 8253. On the 8254, it selects the read-back command, which will not be covered here.
Counter Channel Configuration
Binary vs BCD Mode
A timer channel can be configured to count in either binary or Binary Coded Decimal (BCD) mode. I have not seen any software that actually uses BCD mode. When writing your initial 8253 implementation, you can probably ignore BCD mode.
RW Mode
A timer channel can be configured for 16-bit read/writes in LSBMSB mode using 0b11 in the RW field, or in one of two 8-bit read/write modes:
LSB(0b01):- On write, an 8-bit value is used to initialize the \(\text{CR}_l\) register, which holds the least significant 8 bits of the initial 16-bit count.
- On read, the contents of the \(\text{O}_l\) register are returned. See Counter Channel Operation.
MSB(0b10):- On write, an 8-bit value is used to initialize the \(\text{CR}_m\) register, which holds the most significant 8 bits of the initial 16-bit count.
- On read, the contents of the \(\text{O}_m\) register are returned. See Counter Channel Operation.
The 8-bit RW modes allow programming a timer channel with fewer writes. In MSB mode, the full range of a timer channel is available, with reduced granularity.
Note: The RW mode of a channel does not affect its basic counting operation. It remains a full 16-bit counter internally regardless of input mode.
In LSBMSB mode, it takes two 8-bit writes to read or write to the timer channel. An internal latch keeps track of whether the initial LSB has been written. On a write, the first byte written is used to initialize the \(\text{CR}_l\) register. The second byte initializes the \(\text{CR}_m\) register. On a read, the first read returns the \(\text{O}_l\) register, the second read returns the \(\text{O}_m\) register.
Warning: The 8253 cannot handle interleaved 16-bit read and write operations. In
LSBMSBmode if you write one byte and then read one byte without completing the write operation, you will receive random data. Some software has been observed improperly operating the 8253 in this way, especially software designed for the 8254 which did not have this limitation. Ensure that your 8253 can recover in this scenario - what value you decide to return is up to you - the actual value is nondeterministic “open bus” behavior internal to the chip.
Counter Latch Command
There is a small matter of concern when a channel is configured for LSBMSB mode. Since it takes two bytes to read the full 16-bit counter value, it is possible that the counter can decrement between the time the first byte is read and the second. Therefore, a Counter Latch command is provided. The Counter Latch command is sent by setting the RW field of the control word to 0b00. This does not change the counter channel’s configuration otherwise - the Mode and BCD bits are ignored when sending the counter latch command. See the Counter Latch Operation section below for how the latching is implemented.
Counter Channel Operation
Figure 3: Intel 8253 Counter Block Diagram
There are a few important things to note in the channel block diagram above. The heart of the counter is the Counting Element (CE). This is a 16-bit synchronous down-counter that contains the current count value. Above the CE are \(\text{CR}_m\) and \(\text{CR}_l\), two halves of the Count Register (CR). The CR holds the initially configured count, and is used to reload the CE on terminal count in modes that do so.
The count value is transferred from the CR to the CE when a full write of the CR is complete. This may require one or two bytes, depending on the configured RW Mode.
Both Count Registers are initialized to 0 whenever a channel’s mode is set. This avoids leaving either of the CR registers in an indeterminate state when using either byte RW mode.
Counter Loading
Counter loading is not instantaneous on write. A CR is not loaded until the 8253 sees a full clock cycle with a rising and falling edge after the write occurs. If the specific mode requires that the CE be loaded immediately from the CR, all 16-bits are transferred at once.
A count can be loaded with any 16-bit value from 0-65,535. To allow a full 16-bit range, a count value of 0 is interpreted by the 8253 as a count value of 65536.
Counter Latch Operation
Below the CE are \(\text{O}_m\) and \(\text{O}_l\), two halves of the Output Latch. When reading the count value from a channel, we are actually reading from the output latch. Typically, the output latch is updated each time the CE changes. When the Counter Latch Command is issued, the CE simply stops updating the Output Latch, essentially “freezing” the value inside at the point in which the latch command was issued.
When the Output Latch is fully read, which may take one or two bytes depending on the configured RW Mode, the Output Latch is “unfrozen” and will resume being updated by the CE on every tick.
The Output Latch operation can only be reset by fully reading the Output Latch. Issuing a new Counter Latch command will be ignored until the Output Latch is fully read.
Clocking Logic
An 8253 timer channel generally takes an action, such as transferring the CR to CE or decrementing the CE on the next falling edge of its input clock.
Counter Operating Modes
Timer channels can be set to any of 6 different modes.
- Mode 0: Interrupt on Terminal Count
- Mode 1: Hardware Retriggerable One-Shot
- Mode 2: Rate Generator
- Mode 3: Square Wave Generator
- Mode 4: Software Triggered Strobe
- Mode 5: Hardware Triggered Strobe (Retriggerable)
Mode 0 — Interrupt on Terminal Count
Upon setting this mode, OUT is initially LOW. This is the only mode where the initial OUT state is LOW after a mode is set.
In Mode 0, the counter counts down once per tick from the initial count until it reaches 0. When it reaches 0, OUT goes high and stays high until reprogrammed. The counter will continue to count, rolling over from 0 to 0xFFFF, but no longer affects the state of the OUT pin.
Note: The word “Interrupt” in this mode name can be a little misleading. Nothing about this mode is specific to generating interrupts. Interrupts are generated whenever timer channel 0’s output has a rising edge. Therefore, any operating mode can generate interrupts with timer channel 0. Additionally, using the Interrupt on Terminal Count mode on any other timer channel will not generate an interrupt.
Count Loading
- After setting the mode and initial count, the CR will be loaded into the CE on the next clock edge after the final write of the initial count.
Output Behavior
- After mode set: OUT → LOW
- When countdown reaches 0: OUT → HIGH (and remains HIGH)
- Upon writing new count: OUT → LOW
GATE Behavior
- Level-triggered
- GATE HIGH: enables counting
- GATE LOW: inhibits counting (freezes the countdown)
Reload Behavior
- In 8-bit RW modes:
- Writing either the
LSBorMSBwhile the counter is running forces OUT low immediately. - The CR will be loaded into the CE on the next clock edge.
- Writing either the
- In
LSBMSBRW mode:- Writing the
LSBwhile the counter is running disables counting and forces OUT low immediately. - Writing the
MSBwill load the CR into the CE on the next clock edge.
- Writing the
Timing
- For initial count = N, OUT will go high up to N+1 timer clock cycles after the write.
Figure 4: Timer Mode 0 - Interrupt on Terminal Count Timing
Mode 1 — Hardware Retriggerable One-Shot
Summary
This mode allows a low pulse of the OUT pin of a configurable length, triggerable via the GATE pin. This mode is inoperable on the IBM PC except on timer channel 2.
Upon setting this mode, OUT is initially HIGH. A rising edge of the GATE input will trigger OUT → LOW on the next clock edge. When the count reaches 0, OUT → HIGH. The counter will continue to count, rolling over from 0 to 0xFFFF, but will not affect the state of the OUT pin until the counter is re-triggered.
We refer to a “trigger” as a LOW → HIGH transition of the GATE pin.
Note: The count starts running as soon as Mode 1 is selected - but you’ll note that the CE is not loaded until a GATE trigger. Presumably, the counting element still contains whatever it had in it when the mode was set, but this has not been verified.
Count Loading
- After setting the mode and initial count, the CR will hold the initial count but will NOT write it into the CE until a trigger occurs.
Output Behavior
- After mode set: OUT → HIGH
- After GATE LOW → HIGH: OUT → LOW
- At terminal count: OUT → HIGH
GATE Behavior
- Edge-triggered
- GATE LOW -> HIGH: Trigger. The CR is loaded into the CE on the next clock edge.
- Since the trigger reloads the CE, another trigger will restart any count in progress.
Reload Behavior
- Writing a new count during an active count will not affect the current count until the next trigger, as the trigger controls loading of the CE from CR.
Timing
Figure 5: Timer Mode 1 - Hardware Retriggerable One-Shot Timing
Mode 2 — Rate Generator
Summary
In this mode, OUT normally remains HIGH, but produces regular one-clock-wide low pulses. This mode is useful when a periodic LOW → HIGH transition is required.
On the IBM PC, timer channel 1 is typically configured for Mode 2 to repeatedly generate the \(DREQ0\) signal.
Output Behavior
- After mode set: OUT → HIGH
- When count reaches 1: OUT → LOW
- When count reaches 0: OUT → HIGH
GATE Behavior
- Edge-triggered
- GATE LOW -> HIGH: Trigger. The CR is loaded into the CE on the next clock edge. Counting enabled.
- GATE LOW: OUT is forced HIGH, counting disabled.
Reload Behavior
- Writing a new count during an active count will not affect the current count until either a terminal count or a GATE trigger.
- CR is automatically loaded into the CE after terminal count is reached, restarting the count.
Constraints
- A count of 1 is invalid and will cause the timer channel not to function.
Timing
Figure 5: Timer Mode 2 - Rate Generator Timing
Mode 3 — Square Wave Generator
Summary
Similar to Mode 2, but produces a square wave: OUT alternates high and low with a 50% duty cycle (if the initial count is even). This is a general-purpose mode with many applications. The IBM BIOS sets timer channel 0 to Mode 3 to run the BIOS time-of-day clock. This mode can also be used to drive a tone of a specific frequency to the PC speaker on timer channel 2.
This mode is a bit more complex than the other modes. The 8253 creates a square wave of a period determined by the initial count by decrementing the counting element by 2 instead of 1. This presents a problem if the initial count is odd, as we need to reach 0 to trigger the terminal count condition.
Odd Count Logic
Within the counter is a flip-flop I will call the 1/3 flip-flop. This flip-flop is initially 0.
- If the CE is odd, the 8253 will decrement it as follows:
- If the 1/3 flip-flop is 0, the CE will be decremented by 1. This sets the CE to an even value.
- If the 1/3 flip-flop is 1, the CE will be decremented by 3. This sets the CE to an even value.
- If the CE is even, the 8253 will decrement it by 2.
- When the counter reaches terminal count (0), CE is reloaded by CR, and the 1/3 flip-flop is toggled.
This is a somewhat awkward way of accounting for the one missed clock period per cycle we would otherwise accumulate over time with an odd count. The result of this logic is that the resulting square wave is HIGH for \(\frac{N+1}{2}\) clocks and LOW for \(\frac{N-1}{2}\) clocks.
Note: The 8254 implements the logic for Mode 3 differently than the 8253. Refer to the 8254 datasheet for an accurate description if you are emulating an 8254.
The counter also has an output flip-flop that it uses in this mode to toggle the state of the OUT pin when terminal count is reached.
Output Behavior
- After mode set: OUT → HIGH
- At terminal count: OUT toggles state
GATE Behavior
- Edge-triggered
- GATE HIGH: Trigger. The CR is loaded into the CE on the next clock edge. Counting enabled.
- GATE LOW: OUT → HIGH. Counting disabled.
Reload Behavior
- Writing a new count during an active count will not affect the current count until either a terminal count or a GATE trigger.
- CR is automatically loaded into the CE after terminal count is reached, restarting the count.
Timing
Figure 6: Timer Mode 3 - Square Wave Generator Timing
Mode 4 — Software Triggered Strobe
Summary
When the initial count reaches 0, OUT produces a one-clock-wide low pulse. This is similar to Mode 2, but with a distinct difference - in Mode 2, OUT goes low on a count of 1, and HIGH again on a count of 0. In Mode 4, OUT goes low on a count of 0, then HIGH again on the next clock edge. The counter will continue to count, rolling over from 0 to 0xFFFF, but will not affect the state of the OUT pin until the next count value is written.
Counting begins when the initial count is written (the “software trigger”).
Output Behavior
- After mode set: OUT → HIGH
- At terminal count: OUT → LOW for one clock period
Count Loading
- After writing the count, the CR is loaded into the CE on the next clock edge. Counting begins automatically on the following clock edge.
- Writing a new count during an active count will trigger a CR to be loaded into the CE at the next clock edge.
- In
LSBMSBmode, writing the first byte only has no effect.
- In
GATE Behavior
- Level-triggered
- GATE HIGH: Counting enabled.
- GATE LOW: Counting disabled.
- GATE does not affect OUT.
- GATE does not trigger a reload of the counter.
Timing
Figure 7: Timer Mode 4 - Software Triggered Strobe Timing
Mode 5 — Hardware Triggered Strobe
Summary
Similar to Mode 4, but triggered by a LOW → HIGH transition of GATE. In Mode 5, OUT goes low on a count of 0, then HIGH again on the next clock edge. The counter will continue to count, rolling over from 0 to 0xFFFF, but will not affect the state of the OUT pin until the counter is retriggered by the GATE pin.
Note: The count starts running as soon as Mode 5 is selected - but you’ll note that the CE is not loaded until a GATE trigger. Presumably, the counting element still contains whatever it had in it when the mode was set, but this has not been verified.
Output Behavior
- After mode set: OUT → HIGH
- At terminal count: OUT → LOW for one clock period
GATE Behavior
- Edge-triggered
- GATE LOW -> HIGH: Trigger. The CR is loaded into the CE on the next clock edge. Counting enabled.
- GATE does not affect OUT,
Reload Behavior
- Writing a new count value during an active count will not affect the current count until either a terminal count or a GATE trigger.
Timing
Figure 7: Timer Mode 5 - Hardware Triggered Strobe Timing
Mode Summary Table
| N | Mode | OUT after Mode set | GATE mode | Writing count reloads next clk | Automatic Reload | GATE initiates counting | GATE controls counting |
|---|---|---|---|---|---|---|---|
| 0 | Interrupt on Terminal Count | LOW | Level-triggered | YES | NO | NO | YES |
| 1 | Hardware Retriggerable One Shot | HIGH | Edge-triggered | NO | NO | YES | NO |
| 2 | Rate Generator | HIGH | Both | NO | YES | YES | YES |
| 3 | Square Wave Generator | HIGH | Both | NO | YES | YES | YES |
| 4 | Software Triggered Strobe | HIGH | Level-triggered | YES | NO | NO | YES |
| 5 | Hardware Triggered Strobe | HIGH | Edge-triggered | NO | NO | YES | NO |
Edge Cases
Some interesting edge cases have been observed. Consider the following scenario:
- A timer channel is set to Mode 2 - Rate Generator, RW mode
LSBMSB, and an initial count written, starting the count. - Only the
LSBof a new count is written. - The timer reaches terminal count. What value is loaded into the Counting Element?
- Once the Counting Element has been reloaded, what happens when the
MSBof the new count is then written?
If you have studied the counter channel block diagram, you may be able to figure out what should happen. The \(\text{CR}_m\) and \(\text{CR}_l\) registers are used to hold the programmed initial count, and the CE is reloaded from these registers. In addition, the counter keeps a flip-flop to keep track of the progress of writing a new count, and will write the contents of the CR registers to the CE when the write is complete (depending on mode).
The Intel 8254
The 8254 is an improved model of the 8253 and was used in the IBM AT. It would become the standard timer chip in PC compatible systems for many years.
Changes in the 8254
- Faster clock inputs
- A channel state read-back command
- Resolves the issue with the 8253 where reads and writes to the same channel could not be interleaved without leaving the chip in an undefined state.
- Modified the logic of Mode 3 - Square Wave Generator.
If you wish to emulate the 8254 instead of the 8253, there’s no real problem with doing so.
Emulation Tips
Implementation Priority
- Implement these modes first:
- Mode 3, Square Wave Generator
- Mode 2, Rate Generator
- Mode 0, Interrupt on Terminal Count
- Connect the output of Timer Channel 0 to IRQ0
- Connect the 8255 PPI Port B bit 0 to the GATE of Timer Channel 2
Primary Emulation Resources
- (alldatasheet.com) 8253 Datasheet
- (alldatasheet.com) 8254 Datasheet
- (wiki.osdev.org): Programmable Interval Timer - Mostly describes the 8254
Further Reading
- (wikipedia.org): Intel 8253
- (intel.com @ archive.org): 8254/82C54 Programmable Interval Timer
References
Programmable Peripheral Interface (8255 PPI)
The Intel 8255 PPI is a general-purpose IO chip that provides 24 configurable, bidirectional I/O pins.
The 8255 was used in a number of systems, and even a few mouse controller cards.
The IBM 5150 and 5160 utilize the PPI to receive scancodes from the keyboard interface, read the system’s DIP switches, read motherboard status lines and write control signals.
The PPI is a moderately complex chip with several modes of operation. Perhaps unique to all the support chips you need to emulate, the vast majority of the PPI’s extended capabilities and modes can be completely ignored by a basic PC emulator.
Intel 8237 DMA Controller
The Intel 8237 DMA (Direct Memory Access) Controller enables efficient data transfers between memory and I/O devices without CPU intervention. In the IBM PC, it coordinates data transfer to and from floppy and hard drives, as well as performing DRAM refresh cycles.
Overview
The 8237 provides four independent DMA channels, each capable of transferring data between memory and peripherals. In theory, the 8237 is capable of performing memory-to-memory transfers as well, but its implementation in the IBM PC prevents it from doing so.
IBM PC DMA Configuration
| Channel | Purpose | Device |
|---|---|---|
| 0 | Memory Refresh | DRAM |
| 1 | Unused | - |
| 2 | Floppy Disk | FDC |
| 3 | Hard Disk* | HDC |
Note: Not all hard disk controllers use DMA. Notably, most models of the XTIDE do not.
Hardware Interface
I/O Ports (8237A-5)
| Port | Register | Access |
|---|---|---|
| 0x00 | Channel 0 Address | R/W |
| 0x01 | Channel 0 Count | R/W |
| 0x02 | Channel 1 Address | R/W |
| 0x03 | Channel 1 Count | R/W |
| 0x04 | Channel 2 Address | R/W |
| 0x05 | Channel 2 Count | R/W |
| 0x06 | Channel 3 Address | R/W |
| 0x07 | Channel 3 Count | R/W |
| 0x08 | Status Register | R |
| 0x08 | Command Register | W |
| 0x09 | Request Register | W |
| 0x0A | Mask Register | W |
| 0x0B | Mode Register | W |
| 0x0C | Clear Flip-Flop | W |
| 0x0D | Master Clear | W |
| 0x0E | Clear Mask Register | W |
| 0x0F | Write All Mask Bits | W |
Page Registers
The DMA page registers are not part of the 8237 itself, but are implemented on the motherboard. They are provided here for convenience.
Note: The page register addresses are mapped out of order from their respective channels. Take note of the assignments.
- 0x81: Channel 2 Page Register (Address bits 16-19)
- 0x82: Channel 3 Page Register (Address bits 16-19)
- 0x83: Channel 1 Page Register (Address bits 16-19)
The IBM AT added a page register for Channel 0, but this is not implemented on the PC/XT:
- 0x87: Channel 0 Page (bits 16-19)
8288 Bus Controller
8284 Clock/Ready Generator
DIP switches
The Keyboard Interface
The DMA Page Registers
DRAM Refresh
DMA and Ready Generation
Floppy Drive Controller
IBM PC/XT systems outfitted with a floppy drive had an “IBM 5.25” Diskette Drive Adapter“ card installed in one of the available expansion slots.
For a good look at the Diskette Drive Adapter, see minuszerodegrees.net.
The IBM floppy drive controller, as we’ll refer to it here, was a collection of 74-series logic chips and a 16.0Mhz clock crystal supporting the “brain” of the card, a NEC µPD765A (NEC 765) floppy drive controller chip. It could support up to four floppy disk drives, although configurations of more than two were uncommon. Drives 0-3 would be assigned the drive letters A-D. It would feel a bit wrong to have a floppy disk as drive C, but if you did indeed have three drives connected, that’s what you’d end up with.
The NEC 765 takes an 8MHz clock, divided once from the card’s 16Mhz crystal.
The IBM controller card adds a main control register external to the 765, called the Digital Output Register or DOR. The DOR has several functions - it selects a specific drive as the target of operations, it can reset the 765, it can enable or disable interrupts and DMA, and it can turn on and off the attached floppy drive motors.
Figure 1: The Digital Output Register (DOR)
Drive Selection Bits
The two least significant bits (Bits 0-1) of the DOR control which floppy drive is selected:
| Bit 1 | Bit 0 | Selected Drive |
|---|---|---|
| 0 | 0 | Drive A |
| 0 | 1 | Drive B |
| 1 | 0 | Drive C |
| 1 | 1 | Drive D |
If a drive’s motor is not on, selecting it in the DOR will do nothing until the motor is turned on.
The DOR is implemented with an 74LS273 8-bit register chip. The DOR is write-only.
The FDC RESET bit 2 directly toggles the 765’s RST pin, resetting the controller chip.
Note: To avoid confusion, be aware that the DOR is the only drive selection method used by the IBM floppy drive controller. The NEC 765 command set includes fields that would, in theory, select which drive the operation is intended to target. Under IBM’s controller design, these bits do nothing - the 765 is not in control of which drive is selected. You can verify this yourself by noting the 765’s “unit select” pins, 28 and 29, are not connected.
On the IBM PC/XT, the floppy drive controller is operated by the BIOS in DMA mode exclusively. It is possible to operate the controller in polled-io mode in a manual fashion, but there are severe disadvantages to doing so - as was seen on the IBM PCjr which lacked a DMA controller. The lack of DMA prevented such operations as transferring data via the serial ports and floppy disk drive at the same time.
I/O Ports
The IBM Diskette Drive Adapter decodes the following IO port addresses:
| PC Port | 765 Port | RW | Description |
|---|---|---|---|
| 0x3F2 | n/a | W | Digital Output Register |
| 0x3F4 | 0 | R | µPD765A Status Register |
| 0x3F5 | 1 | RW | µPD765A Data Register |
DMA Channel
The IBM Diskette Drive Adapter uses DMA Channel 2.
IRQs
The IBM Diskette Drive Adapter uses IRQ 6.
Technical References
References
-
(minuszerodegrees.net) IBM 5-1/4“ Diskette Drive Adapter. IBM Corporation. Document Number: 6361505. ↩
Hard Disk Controllers
IBM/Xebec Hard Disk Controler
XTIDE
Display Concepts
The main displays for the IBM PC were cathode-ray tube (CRT) monitors and television sets.
A CRT works by directing a beam of electrons at a screen coated with phosphor within a vacuum-sealed glass tube. The phosphor glows when struck by the electron beam, emitting light visible from the front side of the glass. The beam can be moved around (or deflected) by magnets, since electrons have a charge. Some CRTs could move the beam around in arbitrary ways to draw lines - these were called vector displays. You may be familiar with them used in early arcade games like Asteroids or the Vectrex video game console.
Most, if not all home computer displays were raster displays. In a raster display, the electron beam is moved across the screen in a succession of lines called scanlines, usually starting in the upper-left corner. When the electron beam reached the right side of the screen, it was shut off briefly and the magnets set to deflect the beam back to the left side, slightly lower down on the screen, ready to draw the next scanline. In this manner the entire screen can be drawn, until the bottom-right corner of the screen is reached. After that, the beam must be turned off again and the deflection set to return the beam back to the upper left corner. This process repeats at frequency anywhere from 50Hz to 70Hz or more, depending on the adapter and monitor.
The phosphors on the screen only stay fully lit during the period at which the electron beam is directly illuminating them, after which they start to fade. Different phosphors faded more slowly than others - the phosphors used in older monochrome monitors faded slowly enough that scrolling text could leave “smears” on the screen. Fast responding phosphors were more preferable for this reason. To a high speed camera, a CRT will look like a bright line trailed by a fading image, however quirks of human perception means that we perceive a raster-scanned display as having a fixed, steady image. That said, many people experience eye strain using monitors with lower refresh rates.
Terminology
- pixel: - (Picture Element) This is usually the smallest addressable element of a raster display, determined by the capabilities of the display and display adapter.
- hdot: - (Horizontal dot) This is essentially the time-based unit equivalent to a pixel, but a pixel need not be drawn during every hdot.
- dot clock: - The frequency at which the video card produces pixels. By slowing down the dot clock, the effective horizontal resolution of a card can be decreased, making each pixel wider. The display timings of the card must be reconfigured to account for this.
- horizontal blanking period: - The period in which the electron beam is turned off at the left and right edges of the screen or beyond.
- vertical blanking period: - The period in which the display is turned off at the top and bottom edges of the screen or beyond.
- horizontal retrace: - The period in which the electron beam is being moved from the right side of the screen to the left side. Occurs during the horizontal blanking period. Also called a horizontal refresh.
- vertical retrace: - The period in which the electron beam is being moved from the bottom-right of the screen to the top-left side. Occurs duing the vertical blanking period. Also called a vertical refresh.
- horizontal front porch: - The period of the horizontal blanking period immediately before the horizontal retrace period.
- horizontal back porch: - The period of the horizontal blanking period immediately after the horizontal retrace period.
- vertical front porch: - The period of the vertical blanking period immediately before the vertical retrace period.
- vertical back porch: - The period of the verttical blanking period immediately after the vertical retrace period.
- hsync: - A signal the display adapter may send to the monitor to initiate the horizontal retrace period.
- vsync: - A signal the display adapter may send to the monitor to initiate the vertical retrace period.
- horizontal refresh rate: - The frequency at which the monitor displays an entire scanline, ending in an hsync. Expressed in KHz.
- vertical refresh rate: - The frequency at which the monitor displays an entire frame, ending in a vsync. Expressed in Hz.
- overscan:
- On analog television sets, the overscan is part of the video signal that may be hidden by the display’s bezels.
- On digital computer monitors, ‘overscan’ typically refers to the part of the video signal which lies outside of the region where addressable pixels are displayed, which may lie partially within the borders of the monitor’s bezels, and partially outside it. The overscan can often be set to a particular color, depending on the adapter.
Primary Emulation Resources:
- (cosmodoc.org) People Don’t Like Electrons Shooting At Their Face
The Motorola 6845 CRTC
6845 Registers
The 6845’s register numbers are frequently given in either decimal or hexadecimal. Motorola’s own references use decimal, so that is what we will use here.
| Index | Hex | Name |
|---|---|---|
| 0 | 00h | Horizontal Total |
| 1 | 01h | Horizontal Displayed |
| 2 | 02h | Horizontal Sync Position |
| 3 | 03h | Sync Width |
| 4 | 04h | Vertical Total |
| 5 | 05h | Vertical Total Adjust |
| 6 | 06h | Vertical Displayed |
| 7 | 07h | Vertical Sync Position |
| 8 | 08h | Interlace Mode and Skew |
| 9 | 09h | Max Scan Line Address |
| 10 | 0Ah | Cursor Start |
| 11 | 0Bh | Cursor End |
| 12 | 0Ch | Start Address (High) |
| 13 | 0Dh | Start Address (Low) |
| 14 | 0Eh | Cursor Address (High) |
| 15 | 0Fh | Cursor Address (Low) |
| 16 | 10h | Light Pen Latch Address (High) |
| 17 | 11h | Light Pen Latch Address (Low) |
Monochrome Display Adapter (MDA)
The IBM Color Graphics Adapter (CGA)
The IBM CGA card was one of the first video adapters available for the IBM PC/XT, along with the IBM Monochrome Display Adapter and the Hercules video adapter.
The CGA could be connected to a regular North American television set via its composite output connector. A digital DE-9 connection eventually allowed it to be connected to the IBM 5153 Color Display, once that was finally released. IBM left owners of the CGA waiting a bit for a proper monitor - it was only released in 1983, two years after the CGA’s debut.
The CGA has 16KB of DRAM dedicated to video memory, and a 4KB font ROM that holds bit patterns for drawing text glyphs.
In text mode, the CGA card was capable of outputting 16 colors. In graphics mode, it was limited to 3 palettes of 3 fixed colors each, with a selectable background color. The CGA also had a high-resolution mode, with a single, selectable foreground color on black.
Like the MDA, the CGA is built around the Motorola MC6845 CRTC. See that section first for a basic understanding of how that chip is used to define display geometry.
Display Timings
Unlike the MDA, the CGA does not have its own crystal. IBM designed the main system crystal of the PC itself around the NTSC display standard, with the apparent intent of simplifying the production of the CGA and other television-compatible peripherals.
The 5150 has a single main system crystal with a frequency of 14.31818MHz. This frequency is exactly four times the NTSC color subcarrier frequency.
The crystal frequency can be expressed as a fraction:
$$f_{crystal} = \frac{315}{22} \text{ MHz} = 14.318181\overline{81} \text{ MHz}$$
The CGA’s output is almost but not quite entirely NTSC-conforming. A real NTSC signal provides two interlaced fields of 262.5 scanlines, whereas the CGA outputs 262 progressive scanlines at approximately 60fps. This 565 vs 564 scanline difference is minor enough for television sets to ignore.
The CGA produces a display field of \(912 \times 262\) or \(238,944\) hdots.
The exact vertical refresh rate of the CGA can be calculated as:
$$f_{refresh} = \frac{14{,}318{,}181}{238{,}944} = 59.92 \text{ Hz}$$
The horizontal retrace rate can be calculated as:
$$f_{hsync} = \frac{14{,}318{,}181}{912} = 15.70 \text{ kHz}$$
This is a significant number in that you will often hear monitors capable of displaying 200-line resolution modes produced by the CGA and EGA video cards described as 15KHz displays.
Dot Clock
The 14.31818Mhz clock of the CGA can be used directly as the dot clock, which is the case in the card’s high resolution text mode. Alternatively, it can be divided by two to produce a 7.159Mhz dot clock, which is done in the card’s lower resolution modes. When using the native clock or hclock the card typically outputs 640 pixels per scanline. When using the halved clock or lclock, the card typically outputs 320 pixels per scanline, as the effective width of each pixel is doubled since the raster beam continues to scan out the screen at the same rate.
With either clock, the number of vertical scanlines remains the same, but the horizontal timings programmed into the CRTC must be adjusted to account for the lower clock when the clock divisor is in use.
Video Memory
The 16KB of DRAM on the CGA is not expandable. It also single-ported, meaning that only either the CPU or the CGA can access the video memory at any given time. This is a bit of a problem as the CGA needs to be reading video memory constantly as it rasterizes the screen.
The CGA has some circuitry for attempting to marshall the CPU’s access to video memory, but perhaps due to limitations in board space, this circuitry was only implemented for the card’s low-resolution modes where the lclock is used. In high-resolution text mode, attempts to access video memory by the CPU while the CGA is rasterizing the active display area will result in what is called snow - random glitches where the CGA reads the wrong data while attempting to read character glyphs or attribute bytes. IBM worked around this in BIOS routines that scrolled the screen - such as when you execute the DIR command in DOS by rapidly disabling and re-enabling the display, causing noticable flicker.
Operational Modes
The CGA has two main modes of operation, text mode and graphics mode.
Text Mode
In text mode, video memory is organized conceptually as a grid of character cells, the dimensions of which are directly configured on the CRTC. Typically, this will be a rectangular grid of 80x25 characters. Each logical cell is comprised of a pair of bytes in video memory, the first byte being a character code and the second byte being a character attribute. The character code indicates what character glyph to display. For a list of all character codes and their corresponding glyphs, see the ASCII table appendix.
The character code, combined with the vertical line counter of the CRTC, is used to resolve a byte contained in the CGA’s font ROM representing 8 pixels (or span) of a character glyph. The character attribute byte then describes the colors to use for the foreground and background as the glyph span is drawn.
Since each character cell requires two bytes, it takes 4KB of memory to display an 80x25 text mode screen. This means up to four text-mode screens can fit in the CGA’s 16KB of memory, and a program can switch between each screen by adjusting the CRTC’s start address registers. Multiple screens present in video memory are often called video pages, and switching between them may be referred to as page-switching or page-flipping when used for fast animation. Alternatively, a single large screen of up to 80x100 could be stored in memory and the visible 80x25 region panned down through it by adjusting the start address registers one row at a time.
Primary Emulation Resources
- (seasip.info) Colour Graphics Adapter: Notes
Video Memory and Timing
Keyboard
The IBM 5150 and 5160 originally used an 83-key IBM “Model F” keyboard1, IBM Part #1501100 (Part #1501105 in the UK2).
Later revisions of the BIOS ROM for the IBM 5160 contained support for the 101-key Enhanced Keyboard3. This keyboard introduced multi-byte scancodes, which required large changes in the keyboard handling code of the BIOS to accommodate.
IBM changed the keyboard protocol with the IBM 5170 AT, making everyone buy new keyboards. Therefore, keyboards of this era are often described as speaking either the “XT” or “AT” protocol. Some keyboards were made that could switch between both, and adapters were (and are) available.
The 83-key keyboard layout is missing many of the keys that we take for granted on modern keyboard layouts. Unlike modern keyboards, the function keys are arranged in a block on the left side.
Figure 1.1: IBM PC 83-key Model F Keyboard Layout with scancodes (Click to zoom)
Keyboard Operation
The keyboard communicates with the PC by sending scancodes when a key is pressed or released. On the original 83-key keyboard, each key produces a pair of single-byte scancodes, one when pressed, called the make scancode, and one when released called the break scancode. The make scancodes are typically the values provided in scancode tables, and can be seen in the figure above. Break scancodes are calculated by taking the make scancode and setting the MSB to 1.
Since keyboard operation is event-driven, if the host computer were ever to miss processing a ‘key-up’ scancode, this would cause the phenomenon of a “stuck key,” something most PC users have experienced at one point.
Inside the Model F keyboard is an Intel 8048 microcontroller that is responsible for scanning the internal key matrix and converting keypresses (and releases) into scancodes to send to the host PC. On early versions of the Model F, the 8048 could be reset directly through the RESET pin on the keyboard DIN connector. Later versions of the Model F disconnected this RESET line and the 8048 is no longer externally resettable, except perhaps by unplugging the keyboard.
The 8048 has burned-in program ROM and a small amount of onboard RAM, in which it keeps a 16-byte scancode FIFO buffer. Scancodes are placed into this buffer as they are detected from the keyboard matrix, and read out as they are sent to the host.
Note: It is important that you buffer scancodes in your emulator - a fast typist can generate scancodes very rapidly - consider how quickly scancodes may be produced in the event that multiple keys are pressed and released at once. It is generally insufficient to deliver one scancode per frame.
The keyboard is a serial device, and the keyboard port is a specialized serial port. The exact electrical details of the keyboard port are not crucially important to emulating the keyboard, except for the operation of the clock pin.
Bit 6 of the 8255 PPI’s Port B register, when set to 0, will pull the keyboard clock line low. When held in this state for approximately 20ms, the 8048 will perform a keyboard self-test. When the clock line is released by writing 1 to PPI Port B bit 6, the keyboard will send the special scancode 0xAA. If the keyboard internally detects a physically stuck key, it will send the scancode of that key 10ms after sending 0xAA.4.
If you fail to emulate sending the reset scancode 0xAA at the appropriate time, the BIOS will emit a POST error code 301.
Note that the ‘clock’ line does not actually clock the 8048. The keyboard data and clock lines are simply connected to specialized I/O pins on the 8048 that it can monitor. The 8048 is clocked via an internal oscillator configured for approximately 5MHz.
Typematic Repeat
Most computer users are familiar with what happens when a key on the keyboard is held down - typically after a short delay, the keyboard will begin repeating the keypress automatically.
IBM called this feature “typematic” on the Model F. When a key is held down, it will start to repeat after approximately 500ms at a rate of approximately 11 characters per second. Both the make and break scancodes are sent for each repeat.
It is possible to simply pass through the host’s typematic repeat to your emulator, but I recommend handling it yourself, as it gives you better control over the rate (which might otherwise be too fast).
There are some subtleties to typematic repeat operation:
- If more than one key is held down, only the last key will repeat.
- Repeat will stop when a key is released, even if other keys remain held down.
The IBM BIOS keyboard routines will filter typematic events for Ctrl, Shift, Alt, Num Lock, Scroll Lock, Caps Lock, and Insert. If the default BIOS keyboard routines are used by an application that does not process keyboard events fast enough, it is likely that holding down a key will fill the BIOS keyboard buffer and result in several angry beeps from the PC speaker.
The Keyboard Interface
Serial data from the keyboard is first read into a shift register on the motherboard, then ultimately read out in a parallel fashion via the 8255 PPI’s Port A. See the chapter on the IBM PC’s Keyboard Interface for more details.
SDL Scancode Table
If you happen to be using SDL for your emulator, here’s a table of SDL keycode definitions to IBM scancodes:
| SDL Key | Scancode (hex) |
|---|---|
| SDLK_A | 1E |
| SDLK_B | 30 |
| SDLK_C | 2E |
| SDLK_D | 20 |
| SDLK_E | 12 |
| SDLK_F | 21 |
| SDLK_G | 22 |
| SDLK_H | 23 |
| SDLK_I | 17 |
| SDLK_J | 24 |
| SDLK_K | 25 |
| SDLK_L | 26 |
| SDLK_M | 32 |
| SDLK_N | 31 |
| SDLK_O | 18 |
| SDLK_P | 19 |
| SDLK_Q | 10 |
| SDLK_R | 13 |
| SDLK_S | 1F |
| SDLK_T | 14 |
| SDLK_U | 16 |
| SDLK_V | 2F |
| SDLK_W | 11 |
| SDLK_X | 2D |
| SDLK_Y | 15 |
| SDLK_Z | 2C |
| SDLK_1 | 02 |
| SDLK_2 | 03 |
| SDLK_3 | 04 |
| SDLK_4 | 05 |
| SDLK_5 | 06 |
| SDLK_6 | 07 |
| SDLK_7 | 08 |
| SDLK_8 | 09 |
| SDLK_9 | 0A |
| SDLK_0 | 0B |
| SDLK_RETURN | 1C |
| SDLK_ESCAPE | 01 |
| SDLK_BACKSPACE | 0E |
| SDLK_TAB | 0F |
| SDLK_SPACE | 39 |
| SDLK_MINUS | 0C |
| SDLK_EQUALS | 0D |
| SDLK_LEFTBRACKET | 1A |
| SDLK_RIGHTBRACKET | 1B |
| SDLK_BACKSLASH | 2B |
| SDLK_SEMICOLON | 27 |
| SDLK_APOSTROPHE | 28 |
| SDLK_COMMA | 33 |
| SDLK_PERIOD | 34 |
| SDLK_SLASH | 35 |
| SDLK_GRAVE | 29 |
| SDLK_LSHIFT | 2A |
| SDLK_RSHIFT | 36 |
| SDLK_LCTRL | 1D |
| SDLK_RCTRL | 1D |
| SDLK_LALT | 38 |
| SDLK_RALT | 38 |
| SDLK_CAPSLOCK | 3A |
| SDLK_F1 | 3B |
| SDLK_F2 | 3C |
| SDLK_F3 | 3D |
| SDLK_F4 | 3E |
| SDLK_F5 | 3F |
| SDLK_F6 | 40 |
| SDLK_F7 | 41 |
| SDLK_F8 | 42 |
| SDLK_F9 | 43 |
| SDLK_F10 | 44 |
| SDLK_F11 | 57 |
| SDLK_F12 | 58 |
| SDLK_UP | 48 |
| SDLK_DOWN | 50 |
| SDLK_LEFT | 4B |
| SDLK_RIGHT | 4D |
| SDLK_INSERT | 52 |
| SDLK_DELETE | 53 |
| SDLK_HOME | 47 |
| SDLK_END | 4F |
| SDLK_PAGEUP | 49 |
| SDLK_PAGEDOWN | 51 |
| SDLK_KP_1 | 4F |
| SDLK_KP_2 | 50 |
| SDLK_KP_3 | 51 |
| SDLK_KP_4 | 4B |
| SDLK_KP_5 | 4C |
| SDLK_KP_6 | 4D |
| SDLK_KP_7 | 47 |
| SDLK_KP_8 | 48 |
| SDLK_KP_9 | 49 |
| SDLK_KP_0 | 52 |
| SDLK_KP_PLUS | 4E |
| SDLK_KP_MINUS | 4A |
| SDLK_KP_PERIOD | 53 |
| SDLK_KP_ENTER | 1C |
| SDLK_KP_DIVIDE | 35 |
| SDLK_KP_MULTIPLY | 37 |
| SDLK_KP_EQUALS | 0D |
References
-
wikipedia.org Model F keyboard. ↩
-
seasip.info The IBM 1501105 Keyboard ↩
-
minuszerodegrees.net IBM 5160 - Keyboards ↩
-
minuszerodegrees.net 5160 Keyboard Startup ↩
Speaker and Sound
The Cassette Interface
Serial Ports
Parallel Ports
The Game Port
Joystikcs
Mice
Microsoft Serial Mouse
Mouse Systems Serial Mouse
Light Pen
The IBM 5150 BIOS
The IBM 5160 BIOS
GLaBIOS
Emulation Architecture
CPU Emulation Techniques
Device Synchronization
Performance Optimization
Testing Strategies
Debugging Tools
Compatibility Issues
Extended ASCII Table
This table shows all 256 characters of the IBM PC’s Code Page 437 character set as rendered by the CGA’s 8x8 font.
| Dec | Hex | Oct | Char | Glyph | Dec | Hex | Oct | Char | Glyph | Dec | Hex | Oct | Char | Glyph | Dec | Hex | Oct | Char | Glyph |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 00 | 000 | NUL | 64 | 40 | 100 | @ | 128 | 80 | 200 | Ç | 192 | C0 | 300 | |||||
| 1 | 01 | 001 | SOH | 65 | 41 | 101 | A | 129 | 81 | 201 | ü | 193 | C1 | 301 | |||||
| 2 | 02 | 002 | STX | 66 | 42 | 102 | B | 130 | 82 | 202 | é | 194 | C2 | 302 | |||||
| 3 | 03 | 003 | ETX | 67 | 43 | 103 | C | 131 | 83 | 203 | â | 195 | C3 | 303 | |||||
| 4 | 04 | 004 | EOT | 68 | 44 | 104 | D | 132 | 84 | 204 | ä | 196 | C4 | 304 | |||||
| 5 | 05 | 005 | ENQ | 69 | 45 | 105 | E | 133 | 85 | 205 | à | 197 | C5 | 305 | |||||
| 6 | 06 | 006 | ACK | 70 | 46 | 106 | F | 134 | 86 | 206 | å | 198 | C6 | 306 | |||||
| 7 | 07 | 007 | BEL | 71 | 47 | 107 | G | 135 | 87 | 207 | ç | 199 | C7 | 307 | |||||
| 8 | 08 | 010 | BS | 72 | 48 | 110 | H | 136 | 88 | 210 | ê | 200 | C8 | 310 | |||||
| 9 | 09 | 011 | TAB | 73 | 49 | 111 | I | 137 | 89 | 211 | ë | 201 | C9 | 311 | |||||
| 10 | 0A | 012 | LF | 74 | 4A | 112 | J | 138 | 8A | 212 | è | 202 | CA | 312 | |||||
| 11 | 0B | 013 | VT | 75 | 4B | 113 | K | 139 | 8B | 213 | ï | 203 | CB | 313 | |||||
| 12 | 0C | 014 | FF | 76 | 4C | 114 | L | 140 | 8C | 214 | î | 204 | CC | 314 | |||||
| 13 | 0D | 015 | CR | 77 | 4D | 115 | M | 141 | 8D | 215 | ì | 205 | CD | 315 | |||||
| 14 | 0E | 016 | SO | 78 | 4E | 116 | N | 142 | 8E | 216 | Ä | 206 | CE | 316 | |||||
| 15 | 0F | 017 | SI | 79 | 4F | 117 | O | 143 | 8F | 217 | Å | 207 | CF | 317 | |||||
| 16 | 10 | 020 | DLE | 80 | 50 | 120 | P | 144 | 90 | 220 | É | 208 | D0 | 320 | |||||
| 17 | 11 | 021 | DC1 | 81 | 51 | 121 | Q | 145 | 91 | 221 | æ | 209 | D1 | 321 | |||||
| 18 | 12 | 022 | DC2 | 82 | 52 | 122 | R | 146 | 92 | 222 | Æ | 210 | D2 | 322 | |||||
| 19 | 13 | 023 | DC3 | 83 | 53 | 123 | S | 147 | 93 | 223 | ô | 211 | D3 | 323 | |||||
| 20 | 14 | 024 | DC4 | 84 | 54 | 124 | T | 148 | 94 | 224 | ö | 212 | D4 | 324 | |||||
| 21 | 15 | 025 | NAK | 85 | 55 | 125 | U | 149 | 95 | 225 | ò | 213 | D5 | 325 | |||||
| 22 | 16 | 026 | SYN | 86 | 56 | 126 | V | 150 | 96 | 226 | û | 214 | D6 | 326 | |||||
| 23 | 17 | 027 | ETB | 87 | 57 | 127 | W | 151 | 97 | 227 | ù | 215 | D7 | 327 | |||||
| 24 | 18 | 030 | CAN | 88 | 58 | 130 | X | 152 | 98 | 230 | ÿ | 216 | D8 | 330 | |||||
| 25 | 19 | 031 | EM | 89 | 59 | 131 | Y | 153 | 99 | 231 | Ö | 217 | D9 | 331 | |||||
| 26 | 1A | 032 | SUB | 90 | 5A | 132 | Z | 154 | 9A | 232 | Ü | 218 | DA | 332 | |||||
| 27 | 1B | 033 | ESC | 91 | 5B | 133 | [ | 155 | 9B | 233 | ¢ | 219 | DB | 333 | |||||
| 28 | 1C | 034 | FS | 92 | 5C | 134 | \ | 156 | 9C | 234 | £ | 220 | DC | 334 | |||||
| 29 | 1D | 035 | GS | 93 | 5D | 135 | ] | 157 | 9D | 235 | ¥ | 221 | DD | 335 | |||||
| 30 | 1E | 036 | RS | 94 | 5E | 136 | ^ | 158 | 9E | 236 | ₧ | 222 | DE | 336 | |||||
| 31 | 1F | 037 | US | 95 | 5F | 137 | _ | 159 | 9F | 237 | ƒ | 223 | DF | 337 | |||||
| 32 | 20 | 040 | Space | 96 | 60 | 140 | ` | 160 | A0 | 240 | á | 224 | E0 | 340 | α | ||||
| 33 | 21 | 041 | ! | 97 | 61 | 141 | a | 161 | A1 | 241 | í | 225 | E1 | 341 | ß | ||||
| 34 | 22 | 042 | " | 98 | 62 | 142 | b | 162 | A2 | 242 | ó | 226 | E2 | 342 | Γ | ||||
| 35 | 23 | 043 | # | 99 | 63 | 143 | c | 163 | A3 | 243 | ú | 227 | E3 | 343 | π | ||||
| 36 | 24 | 044 | $ | 100 | 64 | 144 | d | 164 | A4 | 244 | ñ | 228 | E4 | 344 | Σ | ||||
| 37 | 25 | 045 | % | 101 | 65 | 145 | e | 165 | A5 | 245 | Ñ | 229 | E5 | 345 | σ | ||||
| 38 | 26 | 046 | & | 102 | 66 | 146 | f | 166 | A6 | 246 | ª | 230 | E6 | 346 | µ | ||||
| 39 | 27 | 047 | ' | 103 | 67 | 147 | g | 167 | A7 | 247 | º | 231 | E7 | 347 | τ | ||||
| 40 | 28 | 050 | ( | 104 | 68 | 150 | h | 168 | A8 | 250 | ¿ | 232 | E8 | 350 | Φ | ||||
| 41 | 29 | 051 | ) | 105 | 69 | 151 | i | 169 | A9 | 251 | 233 | E9 | 351 | Θ | |||||
| 42 | 2A | 052 | * | 106 | 6A | 152 | j | 170 | AA | 252 | ¬ | 234 | EA | 352 | Ω | ||||
| 43 | 2B | 053 | + | 107 | 6B | 153 | k | 171 | AB | 253 | ½ | 235 | EB | 353 | δ | ||||
| 44 | 2C | 054 | , | 108 | 6C | 154 | l | 172 | AC | 254 | ¼ | 236 | EC | 354 | ∞ | ||||
| 45 | 2D | 055 | - | 109 | 6D | 155 | m | 173 | AD | 255 | ¡ | 237 | ED | 355 | φ | ||||
| 46 | 2E | 056 | . | 110 | 6E | 156 | n | 174 | AE | 256 | « | 238 | EE | 356 | ε | ||||
| 47 | 2F | 057 | / | 111 | 6F | 157 | o | 175 | AF | 257 | » | 239 | EF | 357 | ∩ | ||||
| 48 | 30 | 060 | 0 | 112 | 70 | 160 | p | 176 | B0 | 260 | 240 | F0 | 360 | ≡ | |||||
| 49 | 31 | 061 | 1 | 113 | 71 | 161 | q | 177 | B1 | 261 | 241 | F1 | 361 | ± | |||||
| 50 | 32 | 062 | 2 | 114 | 72 | 162 | r | 178 | B2 | 262 | 242 | F2 | 362 | ≥ | |||||
| 51 | 33 | 063 | 3 | 115 | 73 | 163 | s | 179 | B3 | 263 | 243 | F3 | 363 | ≤ | |||||
| 52 | 34 | 064 | 4 | 116 | 74 | 164 | t | 180 | B4 | 264 | 244 | F4 | 364 | ||||||
| 53 | 35 | 065 | 5 | 117 | 75 | 165 | u | 181 | B5 | 265 | 245 | F5 | 365 | ||||||
| 54 | 36 | 066 | 6 | 118 | 76 | 166 | v | 182 | B6 | 266 | 246 | F6 | 366 | ÷ | |||||
| 55 | 37 | 067 | 7 | 119 | 77 | 167 | w | 183 | B7 | 267 | 247 | F7 | 367 | ≈ | |||||
| 56 | 38 | 070 | 8 | 120 | 78 | 170 | x | 184 | B8 | 270 | 248 | F8 | 370 | ° | |||||
| 57 | 39 | 071 | 9 | 121 | 79 | 171 | y | 185 | B9 | 271 | 249 | F9 | 371 | ∙ | |||||
| 58 | 3A | 072 | : | 122 | 7A | 172 | z | 186 | BA | 272 | 250 | FA | 372 | · | |||||
| 59 | 3B | 073 | ; | 123 | 7B | 173 | { | 187 | BB | 273 | 251 | FB | 373 | √ | |||||
| 60 | 3C | 074 | < | 124 | 7C | 174 | | | 188 | BC | 274 | 252 | FC | 374 | ⁿ | |||||
| 61 | 3D | 075 | = | 125 | 7D | 175 | } | 189 | BD | 275 | 253 | FD | 375 | ² | |||||
| 62 | 3E | 076 | > | 126 | 7E | 176 | ~ | 190 | BE | 276 | 254 | FE | 376 | ■ | |||||
| 63 | 3F | 077 | ? | 127 | 7F | 177 | 191 | BF | 277 | 255 | FF | 377 |
Notable Characters
Control Characters (0x00-0x1F)
In the IBM PC character set, the control characters have glyphs mapped to them. These characters were often used in games. The two smiley faces are perhaps the most famous - they played the role of the player character in innumerable video games, such as Rogue.
| Dec | Hex | Description |
|---|---|---|
| 0 | 00 | Null (displays as blank) |
| 1 | 01 | Smiley face |
| 2 | 02 | Inverse smiley face |
| 3 | 03 | Heart |
| 4 | 04 | Diamond |
| 5 | 05 | Club |
| 6 | 06 | Spade |
| 7 | 07 | Bullet (BEL character) |
| 13 | 0D | Musical note (CR character) |
Box Drawing Characters (0xB0-0xDF)
The IBM PC character set includes an extensive set of box-drawing characters used for creating text-mode user interfaces. These include single-line, double-line, and mixed box corners and intersections.
Mathematical and Greek Symbols (0xE0-0xFF)
The upper range includes mathematical symbols and Greek letters commonly used in technical documentation:
| Dec | Hex | Description |
|---|---|---|
| 224 | E0 | Alpha |
| 225 | E1 | Beta |
| 227 | E3 | Pi |
| 228 | E4 | Sigma (uppercase) |
| 229 | E5 | Sigma (lowercase) |
| 230 | E6 | Mu |
| 241 | F1 | Plus-minus |
| 246 | F6 | Division |
| 248 | F8 | Degree |
| 253 | FD | Superscript 2 |
Memory Map Reference
The BIOS Data Area (BDA)
The BIOS Data Area (BDA) is a 257-byte1 region of memory located at segment 0x0040 (physical address 0x00400).
It is used by the BIOS to store system variables and state.
| Offset | Bytes | Description | Int | Comments |
|---|---|---|---|---|
| 00 | 2 | COM 1 base address | 14 | |
| 02 | 2 | COM 2 base address | 14 | |
| 04 | 2 | COM 3 base address | 14 | |
| 06 | 2 | COM 4 base address | 14 | |
| 08 | 2 | LPT 1 base address | 17 | |
| 0A | 2 | LPT 2 base address | 17 | |
| 0C | 2 | LPT 3 base address | 17 | |
| 0E | 2 | LPT 4 base address | 17 | EBDA on PS/2 and later |
| 10 | 2 | Equipment List Flags | 11 | See Equipment List Flags |
| 12 | 1 | Reserved | ||
| 12 | 1 | PCjr: infrared keyboard error count | ||
| 13 | 2 | Base memory size | 12 | Number of kilobytes of RAM |
| 15 | 2 | Reserved | ||
| 17 | 1 | Keyboard Flag Byte 0 | 16 | See Keyboard Flag Byte 0 |
| 18 | 1 | Keyboard Flag Byte 1 | 16 | See Keyboard Flag Byte 1 |
| 19 | 1 | Work area for ALT key | 16 | Handles ALT + numpad key entry |
| 1A | 2 | Keyboard-buffer Head Offset | 16 | Head offset into keyboard ring buffer |
| 1C | 2 | Keyboard-buffer Tail Offset | 16 | Tail offset into keyboard ring buffer |
| 1E | 32 | Keyboard Buffer | 16 | |
| 3E | 1 | Floppy recalibrate status | 13 | See Floppy Recalibrate Status |
| 3F | 1 | Floppy motor status | 13 | See Floppy Motor Status |
| 40 | 1 | Floppy motor timeout | 13 | |
| 41 | 1 | Floppy operation status | 13 | |
| 42 | 7 | Floppy controller status | 13 | See Floppy Controller Status |
| 49 | 30 | Video info | 10 | |
| 49 | 1 | Current Video Mode | 10 | |
| 4A | 2 | Number of Columns | ||
| 4C | 2 | Size of video buffer (bytes) | ||
| 4E | 2 | Offset of current video page | ||
| 50 | 16 | Cursor position of pages 1-8 | ||
| 60 | 1 | Cursor ending scanline | ||
| 61 | 1 | Cursor starting scanline | ||
| 62 | 1 | Active display page number | ||
| 63 | 2 | Base port for active CRTC | 3B4 for MDA, 3D4 for CGA+ | |
| 65 | 1 | CGA mode control register | Emulated on EGA+ | |
| 66 | 1 | CGA current palette | Emulated on EGA+ | |
| 67 | 5 | PC: Cassette tape control | ||
| 67 | 4 | AT: POST re-entry pointer | ||
| 6B | 1 | Last Unexpected interrupt | ||
| 6C | 4 | Timer Counter | 1A | |
| 70 | 1 | Timer Overflow | 1A | |
| 71 | 1 | Break key state | 16 | |
| 72 | 2 | Reset Flag | ||
| 74 | 1 | HDD operation status | 13 | |
| 75 | 1 | Number of HDDs attached | 13 | |
| 76 | 2 | Reserved | 13 | |
| 78 | 1 | LPT 1 time-out | 14 | |
| 79 | 1 | LPT 2 time-out | 14 | |
| 7A | 1 | LPT 3 time-out | 14 | |
| 7B | 1 | Reserved | ||
| 7C | 1 | COM 1 time-out | ||
| 7D | 1 | COM 2 time-out | ||
| 7E | 1 | COM 3 time-out | ||
| 7F | 1 | COM 4 time-out | ||
| 80 | 2 | Keyboard buffer start ptr | 16 | |
| 82 | 2 | Keyboard buffer end ptr | 16 | |
| 84 | 7 | Video info | 10 | |
| 85 | 2 | EGA: Character line height | ||
| 85 | 1 | PCjr: Typematic repeat key | ||
| 86 | 1 | PCjr: Typematic repeat delay | ||
| 87 | 1 | EGA: Video mode options | See Video Mode Options | |
| 87 | 1 | PCjr: Current Fn key number | ||
| 88 | 1 | EGA: Feature / DIP switches | See EGA Dip Switches | |
| 88 | 1 | PCjr: Keyboard status byte 3 | ||
| 89 | 1 | VGA/MCGA: Video Display Data | See VGA Display Data | |
| 8A | 1 | EGA: Display Combination Code (DCC) index | ||
| 8B | 1 | Floppy media control | 13 | See Floppy Media Control |
| 8C | 1 | HDD Controller status | 13 | |
| 8D | 1 | HDD Controller error status | 13 | |
| 8E | 1 | HDD Interrupt control | 13 | |
| 8F | 1 | Reserved | ||
| 90 | 1 | Floppy 0 media status | 13 | See Floppy Media Status |
| 91 | 1 | Floppy 1 media status | 13 | |
| 92 | 1 | Floppy 2 media status | 13 | |
| 93 | 1 | Floppy 3 media status | 13 | |
| 94 | 1 | Drive 0 current cylinder | 13 | |
| 95 | 1 | Drive 1 current cylinder | 13 | |
| 96 | 1 | Keyboard Mode State and Flags | 16 | See Keyboard Mode Byte |
| 97 | 1 | Keyboard LED State | 16 | See Keyboard LED State |
| 98 | 2 | User wait flag offset | 15 | |
| 9A | 2 | User wait flag segment | 15 | |
| 9C | 4 | User wait count (milliseconds) | ||
| A0 | 1 | RTC Wait active flag | 15 | See RTC Wait Flags |
| A1 | 7 | Reserved | ||
| A8 | 4 | BIOS Video info Pointer | 10 | |
| AC | 84 | Reserved | ||
| 100 | 1 | Print Screen Status | 5 |
| Bits | Name | Description |
|---|---|---|
| 0 | IPL | Floppy drive installed |
| 1 | FPU | FPU installed |
| 2:3 | RAM | Onboard RAM installed (first 256K) |
| 4:5 | VM | Initial video mode at boot time |
| 6:7 | nFLOP | Number of floppy drives installed, -1 |
| 8 | DMA | DMA controller installed (if 0) |
| 9:11 | nCOM | Number of serial ports installed |
| 12 | GP | Game port installed |
| 13 | – | Reserved |
| 14:15 | nPRN | Number of printer ports installed |
Initial Video Mode
| Bits 5,4 | Description |
|---|---|
00 | Unused |
01 | 40x25 color |
10 | 80x25 color |
11 | 80x25 monochrome |
| Bits | Name | Description |
|---|---|---|
| 0 | RSHFT | Right Shift key depressed |
| 1 | LSHFT | Left Shift key depressed |
| 2 | CTRL | CTRL key depressed |
| 3 | ALT | ALT key depressed |
| 4 | SCRL | Scroll-Lock active |
| 5 | NUM | Num-Lock active |
| 6 | CAPS | Caps-Lock active |
| 7 | INS | Insert active |
| Bits | Name | Description |
|---|---|---|
| 0 | LCTRL | Left CTRL key depressed |
| 1 | LALT | Left ALT key depressed |
| 2 | SYS | System key depressed and held |
| 3 | SUSP | Suspend key has been toggled |
| 4 | SCRL | Scroll-Lock key depressed |
| 5 | NUM | Num-Lock key depressed |
| 6 | CAPS | Caps-Lock key depressed |
| 7 | INS | Insert key depressed |
| Bits | Name | Description |
|---|---|---|
| 0 | DRV0 | 1 = Recalibrate drive 0 |
| 1 | DRV1 | 1 = Recalibrate drive 1 |
| 2 | DRV2 | 1 = Recalibrate drive 2 |
| 3 | DRV3 | 1 = Recalibrate drive 3 |
| 4:6 | – | Unused |
| 7 | INT | Working interrupt flag (1=working) |
| Bits | Name | Description |
|---|---|---|
| 0 | DRV0 | 1 = Drive 0 motor on |
| 1 | DRV1 | 1 = Drive 1 motor on |
| 2 | DRV2 | 1 = Drive 2 motor on |
| 3 | DRV3 | 1 = Drive 3 motor on |
| 4:6 | – | Unused |
| 7 | WR | Write operation in progress |
| Bits | Name | Description |
|---|---|---|
| 0 | CMD | Invalid floppy controller command |
| 1 | ADDR | Address mark not found |
| 2 | SEC | Sector not found |
| 3 | DMA | Floppy controller DMA error |
| 4 | CRC | CRC check / data error |
| 5 | FAIL | Floppy controller failure |
| 6 | SEEK | Seek to track failed |
| 7 | TMO | Floppy time-out |
| Bits | Name | Description |
|---|---|---|
| 0 | CURS | 1 = Alphanumeric cursor emulation enabled |
| 1 | MONO | 1 = Video subsystem attached to monochrome |
| 2 | – | Reserved |
| 3 | INACT | 1 = Video subsystem is inactive |
| 4 | – | Reserved |
| 5:6 | RAM | Video RAM: 00=64K, 01=128K, 10=192K, 11=256K |
| 7 | MODE | Video mode number passed to INT 10, function 0 (Bit 7) |
| Bits | Name | Description |
|---|---|---|
| 0 | SW1 | EGA SW1 config (1=off) |
| 1 | SW2 | EGA SW2 config (1=off) |
| 2 | SW3 | EGA SW3 config (1=off) |
| 3 | SW4 | EGA SW4 config (1=off) |
| 4 | FEAT0 | Input FEAT0 (ISR0 bit 5) after output on FCR0 |
| 5 | FEAT0 | Input FEAT0 (ISR0 bit 6) after output on FCR0 |
| 6 | FEAT1 | Input FEAT1 (ISR0 bit 5) after output on FCR1 |
| 7 | FEAT1 | Input FEAT1 (ISR0 bit 6) after output on FCR1 |
| Bits | Name | Description |
|---|---|---|
| 0 | VGA | 1 = VGA is active |
| 1 | GRAY | 1 = Gray scale is enabled |
| 2 | MONO | 1 = Using monochrome monitor |
| 3 | PAL | 1 = Default palette loading is disabled |
| 4 | SL_LO | Scan Line Select Bit 0 |
| 5:6 | – | Reserved |
| 7 | SL_HI | Scan Line Select Bit 1 (00=350, 01=400, 10=200) |
| Bits | Name | Description |
|---|---|---|
| 0:3 | – | Reserved |
| 4:5 | STEP | Step Rate: 00=0C, 01=0D, 10=0A |
| 6:7 | RATE | Data Rate: 00=500K, 01=300K, 10=250K |
| Bits | Name | Description |
|---|---|---|
| 0:2 | STATE | Drive/Media State |
| 3 | – | Reserved |
| 4 | EST | 1 = Media/drive established |
| 5 | DBL | Double stepping required |
| 6:7 | RATE | Data Rate: 00=500K, 01=300K, 10=250K |
| Bits | Name | Description |
|---|---|---|
| 0 | E1 | Last code was the E1 hidden code |
| 1 | E0 | Last code was the E0 hidden code |
| 2 | R_CTL | Right CTRL key depressed |
| 3 | R_ALT | Right ALT key depressed |
| 4 | 101 | 101/102 enhanced keyboard installed |
| 5 | NUM | Force Num-Lock if Rd ID & KBX |
| 6 | ID_CH | Last char was first ID char |
| 7 | RD_ID | Read ID in process |
| Bits | Name | Description |
|---|---|---|
| 0 | SCRL | Scroll-Lock indicator |
| 1 | NUM | Num-Lock indicator |
| 2 | CAPS | Caps-Lock indicator |
| 3 | CIRC | Circus system indicator |
| 4 | ACK | ACK received |
| 5 | RSND | Re-send received flag |
| 6 | MODE | Mode indicator update |
| 7 | ERR | Keyboard transmit error flag |
| Bits | Name | Description |
|---|---|---|
| 0 | PEND | 1 = Wait pending |
| 1:6 | – | Unused |
| 7 | ELAP | 1 = INT 15,86 wait time elapsed |
Primary Emulation Resources
- (helppc.netcore2k.net) BDA - BIOS Data Area - PC Memory Map
References
-
Intel® Platform Innovation Framework for EFI Compatibility Support Module Specification, Revision 0.97, September 4, 2007. ↩
I/O Port Reference
| Port(s) | System | Device | Access | Description |
|---|---|---|---|---|
| 0000-001F | PC/XT/AT | DMA | DMA Controller 1 - Intel 8237 | |
| 0000 | PC/XT/AT | DMA | r/w | DMA channel 0 address |
| 0001 | PC/XT/AT | DMA | r/w | DMA channel 0 word count |
| 0002 | PC/XT/AT | DMA | r/w | DMA channel 1 address |
| 0003 | PC/XT/AT | DMA | r/w | DMA channel 1 word count |
| 0004 | PC/XT/AT | DMA | r/w | DMA channel 2 address |
| 0005 | PC/XT/AT | DMA | r/w | DMA channel 2 word count |
| 0006 | PC/XT/AT | DMA | r/w | DMA channel 3 address |
| 0007 | PC/XT/AT | DMA | r/w | DMA channel 3 word count |
| 0008 | PC/XT/AT | DMA | r | DMA channel 0-3 status |
| 0008 | PC/XT/AT | DMA | w | DMA channel 0-3 command register |
| 0009 | PC/XT/AT | DMA | w | DMA write request register |
| 000A | PC/XT/AT | DMA | r/w | DMA channel 0-3 mask register |
| 000B | PC/XT/AT | DMA | w | DMA channel 0-3 mode register |
| 000C | PC/XT/AT | DMA | w | DMA clear byte pointer flip-flop |
| 000D | PC/XT/AT | DMA | r | DMA read temporary register |
| 000D | PC/XT/AT | DMA | w | DMA master clear |
| 000E | PC/XT/AT | DMA | w | DMA clear mask register |
| 000F | PC/XT/AT | DMA | w | DMA write mask register |
| 0020-003F | PC/XT/AT | PIC | PIC 1 - Programmable Interrupt Controller - Intel 8259 | |
| 0020 | PC/XT/AT | PIC | w | PIC Initialization command word ICW1 |
| 0021 | PC/XT/AT | PIC | w | PIC ICW2,ICW3,ICW4 after ICW1 to 0020 |
| 0021 | PC/XT/AT | PIC | r/w | PIC master interrupt mask register |
| 0020 | PC/XT/AT | PIC | r | PIC interrupt request/in-service registers by OCW3 |
| 0040-005F | PC/XT/AT | PIT | PIT - Programmable Interrupt Timer - Intel 8253 or 8254 | |
| 0040 | PC/XT/AT | PIT | r/w | PIT counter 0, counter divisor |
| 0041 | PC/XT/AT | PIT | r/w | PIT counter 1, RAM refresh counter (XT, AT) |
| 0042 | PC/XT/AT | PIT | r/w | PIT counter 2, cassette & speaker (XT, AT, PS/2) |
| 0043 | PC/XT/AT | PIT | r/w | PIT mode register for counters 0-2 |
| 0060-006F | PC/XT | PPI | r/w | PPI - Programmable Peripheral Interface - Intel 8255 |
| 0060-006F | AT | KBD | Keyboard microcontroller - 804x (8041, 8042) | |
| 0060 | PC/XT | PPI | r | PPI Port A |
| 0061 | AT | KBD | w | Keyboard microcontroller |
| 0061 | PC/XT | PPI | r | PPI Port B |
| 0062 | PC/XT | PPI | r/w | PPI Port C |
| 0063 | PC/XT | PPI | r/w | PPI Command Port |
| 0070-007F | PC/XT/AT | RTC | CMOS RAM/RTC (Real Time Clock MC146818) | |
| 0080-008F | PC/XT/AT | DMA | DMA page registers (74612) | |
| 0080 | PC/XT/AT | DMA | r/w | extra page register (temporary storage) |
| 0081 | PC/XT/AT | DMA | r/w | DMA channel 2 address byte 2 |
| 0082 | PC/XT/AT | DMA | r/w | DMA channel 3 address byte 2 |
| 0083 | PC/XT/AT | DMA | r/w | DMA channel 1 address byte 2 |
| 0084 | DMA | r/w | extra page register | |
| 0085 | DMA | r/w | extra page register | |
| 0086 | DMA | r/w | extra page register | |
| 0087 | DMA | r/w | DMA channel 0 address byte 2 | |
| 0088 | DMA | r/w | extra page register | |
| 0089 | DMA | r/w | DMA channel 6 address byte 2 | |
| 0089 | DMA | r/w | DMA channel 7 address byte 2 | |
| 0089 | DMA | r/w | DMA channel 5 address byte 2 | |
| 008C | DMA | r/w | extra page register | |
| 008D | DMA | r/w | extra page register | |
| 008E | DMA | r/w | extra page register | |
| 008F | DMA | r/w | DMA refresh page register | |
| 00A0-00AF | AT | PIC | PIC 2 - Programmable Interrupt Controller - Intel 8259 | |
| 00A0 | XT | NMI | r/w | NMI mask register (XT) |
| 00C0 | PCjr/Tandy | SN746496 programmable tone/noise generator | ||
| 00C0-00DF | AT | DMA | DMA 2 - Direct Memory Access controller - Intel 8237 | |
| 00F0-00F5 | PCjr | FDC | PCjr Disk Controller | |
| 00F0 | PCjr | FDC | disk controller | |
| 00F2 | PCjr | FDC | disk controller control port | |
| 00F4 | PCjr | FDC | disk controller status register | |
| 00F5 | PCjr | FDC | disk controller data port | |
| 00F0-00FF | AT | FPU | FPU - Math Coprocessor (80287..80387) | |
| 00F0 | AT | FPU | w | Math coprocessor clear busy latch |
| 00F1 | AT | FPU | w | Math coprocessor reset |
| 00F8 | AT | FPU | r/w | Math coprocessor opcode transfer |
| 00FA | AT | FPU | r/w | Math coprocessor opcode transfer |
| 0140-0157 | PC/XT/AT | RTC | RTC (alternate Real Time Clock for XT) (1st at 0340-0357) | |
| 0200-020F | PC/XT/AT | Game Port | Game port | |
| 0201 | PC/XT/AT | Game Port | r | Read joystick position and status |
| 0210-0217 | XT | Expansion | Expansion unit (XT) | |
| 0210 | XT | Expansion | w | latch expansion bus data |
| 0211 | XT | Expansion | w | clear wait, test latch |
| 0212 | XT | Expansion | r | Low byte data address |
| 0213 | XT | Expansion | w | 0=enable, 1=disable expansion unit |
| 0214 | XT | Expansion | w | latch data (receiver card port) |
| 0215 | XT | Expansion | r | High byte of address, then Low byte (receiver card port) |
| 0220-0223 | PC/XT/AT | Sound | Sound Blaster / Adlib port | |
| 0220 | PC/XT/AT | Sound | r/w | Left speaker – Status / Address port |
| 0221 | PC/XT/AT | Sound | w | Left speaker – Data port |
| 0222 | PC/XT/AT | Sound | r/w | Right speaker – Status / Address port |
| 0223 | PC/XT/AT | Sound | w | Right speaker – Data port |
| 0220-0227 | PC/XT/AT | Sound | Soundblaster PRO and SSB 16 ASP | |
| 0220-022F | PC/XT/AT | Sound | Soundblaster PRO 2.0 | |
| 0220-022F | PC/XT/AT | Sound | Soundblaster PRO 4.0 | |
| 0220 | PC/XT/AT | Sound | r | left FM status port |
| 0220 | PC/XT/AT | Sound | w | left FM music register address port (index) |
| 0221 | PC/XT/AT | Sound | r/w | left FM music data port |
| 0222 | PC/XT/AT | Sound | r | right FM status port |
| 0222 | PC/XT/AT | Sound | w | right FM music register address port (index) |
| 0223 | PC/XT/AT | Sound | r/w | right FM music data port |
| 0224 | PC/XT/AT | Sound | w | mixer register address port (index) |
| 0225 | PC/XT/AT | Sound | r/w | mixer data port |
| 0226 | PC/XT/AT | Sound | w | DSP reset |
| 0228 | PC/XT/AT | Sound | r | FM music status port |
| 0228 | PC/XT/AT | Sound | w | FM music register address port (index) |
| 0229 | PC/XT/AT | Sound | w | FM music data port |
| 022A | PC/XT/AT | Sound | r | DSP read data (voice I/O and Midi) |
| 022C | PC/XT/AT | Sound | w | DSP write data / write command |
| 022C | PC/XT/AT | Sound | r | DSP write buffer status (bit 7) |
| 022E | PC/XT/AT | Sound | r | DSP data available status (bit 7) |
| 0240-024F | PC/XT/AT | Sound | Gravis UltraSound | |
| 0240-0257 | AT/XT | RTC | RTC (alternate Real Time Clock for XT) (1st at 0340-0357) | |
| 0258-025F | PC/XT/AT | Memory | Intel Above Board | |
| 0278-027E | PC/XT/AT | Parallel | Parallel printer port, same as 0378 and 03BC | |
| 0278 | PC/XT/AT | Parallel | w | data port |
| 0279 | PC/XT/AT | Parallel | r/w | status port |
| 027A | PC/XT/AT | Parallel | r/w | control port |
| 02A2-02A3 | PC/XT/AT | RTC | MSM58321RS clock | |
| 02B0-02DF | AT | Video | Alternate EGA IO addresss (Primary at 3BX) - Basically unused | |
| 02E0-02EF | PC/XT/AT | GPIB | GPIB (General Purpose Interface Bus, IEEE 488 interface) | |
| 02E1 | PC/XT/AT | GPIB | GPIB (adapter 0) | |
| 02E0-02EF | AT | GPIB | data aquisition (AT) | |
| 02E2 | PC/XT/AT | GPIB | data aquisition (adapter 0) | |
| 02E3 | PC/XT/AT | GPIB | data aquisition (adapter 0) | |
| 02E8-02EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 02F8-02FF | PC/XT/AT | Serial | Serial port, same as 02E8, 03E8 and 03F8 | |
| 02F8 | PC/XT/AT | Serial | w | transmitter holding register |
| 02F8 | PC/XT/AT | Serial | r | receiver buffer register |
| 02F9 | PC/XT/AT | Serial | r/w | divisor latch, high byte when DLAB=1 |
| 02FA | PC/XT/AT | Serial | r | interrupt identification register |
| 02FB | PC/XT/AT | Serial | r/w | line control register |
| 02FC | PC/XT/AT | Serial | r/w | modem control register |
| 02FD | PC/XT/AT | Serial | r | line status register |
| 02FF | PC/XT/AT | Serial | r/w | scratch register |
| 0300 | AT | Diag | Award BIOS - POST Diagnostic | |
| 0300-0301 | PC/XT/AT | Sound | Soundblaster 16 ASP MPU-Midi | |
| 0320-0323 | XT | HDC | XT Hard Disk Controller 1 | |
| 0320 | PC/XT/AT | HDC | r/w | data register |
| 0321 | PC/XT/AT | HDC | w | reset controller |
| 0322 | XT | HDC | r | read DIPswitch setting on XT controller card |
| 0323 | PC/XT/AT | HDC | w | write pattern to DMA and INT mask register |
| 0324-0327 | XT | HDC | XT Hard Disk Controller 2 | |
| 0328-032B | XT | HDC | XT Hard Disk Controller 3 | |
| 032C-032F | XT | HDC | XT Hard Disk Controller 4 | |
| 0330-0331 | PC/XT/AT | Sound | MIDI interface | |
| 0338 | PC/XT/AT | Sound | AdLib FM Synthesis Card | |
| 0340-034F | PC/XT/AT | Sound | Gravis UltraSound (DIP option) | |
| 0340-0357 | PC/XT | RTC | RTC (1st Real Time Clock for XT), (alternate at 0240-0257) | |
| 0348-0357 | PC/XT/AT | DCA 3278 | ||
| 034C-034F | PC/XT/AT | Sound | Gravis UltraMax (DIP Option) | |
| 0360-036F | AT/XT | PC network (AT) | ||
| 0360-0367 | XT | PC network (XT only) | ||
| 0370-0377 | AT | FDC | FDC 2 (2nd Floppy Disk Controller) first FDC at 03F0 | |
| 0370 | FDC | r | diskette Extra High Density controller board jumpers (AT) | |
| 0372 | FDC | w | diskette controller DOR (Digital Output Register) | |
| 0374 | FDC | r | diskette controller main status register | |
| 0374 | FDC | w | diskette controller datarate select register | |
| 0375 | FDC | r/w | diskette controller command/data register | |
| 0376 | FDC | r/w | (2nd FIXED disk controller data register) | |
| 0377 | FDC | r | diskette controller DIR (Digital Input Register) | |
| 0377 | FDC | w | select register for diskette data transfer rate | |
| 0378-037A | PC/XT/AT | Parallel | Parallel printer port (LPT1) - See also 0278 and 03BC | |
| 0378 | Parallel | w | data port | |
| 0379 | Parallel | r/w | status port | |
| 037A | Parallel | r/w | control port | |
| 0388-0389 | PC/XT/AT | Sound | Sound Blaster / Adlib port | |
| 0388 | PC/XT/AT | Sound | r/w | Both Speakers – Status / Address port |
| 0389 | PC/XT/AT | Sound | w | Data port |
| 03B0-03BF | PC/XT/AT | Video | MDA (Monochrome Display Adapter based on 6845) | |
| 03B0 | PC/XT/AT | Video | same as 03B4 | |
| 03B1 | PC/XT/AT | Video | same as 03B5 | |
| 03B2 | PC/XT/AT | Video | same as 03B4 | |
| 03B3 | PC/XT/AT | Video | same as 03B5 | |
| 03B4 | PC/XT/AT | Video | w | MDA CRTC index register |
| 03B5 | PC/XT/AT | Video | r/w | MDA CRTC data register |
| 03B6 | PC/XT/AT | Video | same as 03B4 | |
| 03B7 | PC/XT/AT | Video | same as 03B5 | |
| 03B8 | PC/XT/AT | Video | r/w | MDA mode control register |
| 03B9 | PC/XT/AT | Video | reserved for color select register on color adapter | |
| 03BA | PC/XT/AT | Video | r | CRT status register EGA/VGA: input status 1 register |
| 03BA | PC/XT/AT | Video | w | EGA/VGA feature control register |
| 03BB | PC/XT/AT | Video | reserved for light pen strobe reset | |
| 03BC-03BF | PC/XT/AT | Video | Parallel printer port, same as 0278 and 0378 | |
| 03BC | PC/XT/AT | Video | w | data port |
| 03BD | PC/XT/AT | Video | r/w | status port |
| 03BE | PC/XT/AT | Video | r/w | control port |
| 03BF | Video | r/w | Hercules configuration switch register | |
| 03C0-03CF | Video | EGA (1st Enhanced Graphics Adapter) alternate at 02C0 | ||
| 03C0 | Video | (r)/w EGA VGA ATC index/data register | ||
| 03C1 | Video | r | VGA other attribute register | |
| 03C2 | Video | r | EGA VGA input status 0 register | |
| 03C3 | Video | r/w | VGA video subsystem enable (see also port 46E8h) | |
| 03C4 | Video | w | EGA TS index register | |
| 03C5 | Video | w | EGA TS data register | |
| 03C6 | Video | r/w | VGA PEL mask register | |
| 03C7 | Video | r/w | VGA PEL address read mode | |
| 03C8 | Video | r/w | VGA PEL address write mode | |
| 03C9 | Video | r/w | VGA PEL data register | |
| 03CA | Video | w | EGA graphics 2 position register | |
| 03CC | Video | w | EGA graphics 1 position register | |
| 03CE | Video | w | EGA GDC index register | |
| 03CF | Video | w | EGA GDC data register | |
| 03D0-03DF | Video | CGA (Color Graphics Adapter) | ||
| 03D0 | Video | same as 03D4 | ||
| 03D1 | Video | same as 03D5 | ||
| 03D2 | Video | same as 03D4 | ||
| 03D3 | Video | same as 03D5 | ||
| 03D4 | Video | w | CRTC (6845) index register (EGA/VGA) | |
| 03D5 | Video | w | CRTC (6845) data register (EGA/VGA) | |
| 03D6 | Video | same as 03D4 | ||
| 03D7 | Video | same as 03D5 | ||
| 03D8 | Video | r/w | CGA mode control register (except PCjr) | |
| 03D9 | Video | r/w | CGA palette register | |
| 03DA | Video | r | CGA status register | |
| 03DA | Video | r | EGA/VGA input status 1 register | |
| 03DA | Video | w | EGA/VGA feature control register | |
| 03DB | Video | w | clear light pen latch | |
| 03DC | Video | r/w | preset light pen latch | |
| 03DF | PCjr | System | CRT/CPU page register (PCjr only) | |
| 03E8-03EF | PC/XT/AT | Serial | serial port, same as 02E8, 02F8 and 03F8 | |
| 03F0-03F7 | AT | FDC | FDC 1 (1st Floppy Disk Controller) - second FDC at 0370 | |
| 03F0 | PC/XT/AT | FDC | r | diskette EHD controller board jumper settings (82072AA) |
| 03F2 | PC/XT/AT | FDC | w | diskette controller DOR (Digital Output Register) |
| 03F3 | PC/XT/AT | FDC | tape drive register (on the 82077AA) | |
| 03F4 | PC/XT/AT | FDC | r | diskette controller main status register |
| 03F4 | PC/XT/AT | FDC | w | diskette controller data rate select register |
| 03F5 | PC/XT/AT | FDC | r | diskette command/data register 0 (ST0) |
| 03F5 | PC/XT/AT | FDC | w | diskette command register |
| 03F6 | PC/XT/AT | FDC | r/w | FIXED disk controller data register |
| 03F7 | PC/XT/AT | FDC | r/w | harddisk controller |
| 03F7 | AT/XT | FDC | r | diskette controller DIR (Digital Input Register, PC/AT mode) |
| 03F7 | AT/XT | FDC | w | configuration control register (PC/AT, PS/2) |
| 03F8-03FF | PC/XT/AT | Serial | Serial port (8250,8251,16450,16550,16550A,etc.) | |
| 03F8 | PC/XT/AT | Serial | w | Serial port, transmitter holding register |
| 03F9 | PC/XT/AT | Serial | r/w | Serial port, divisor latch high byte when DLAB==1 |
| 03F9 | PC/XT/AT | Serial | r/w | Serial port, interrupt enable register when DLAB==0 |
| 03FA | PC/XT/AT | Serial | r | Serial port, interrupt identification register |
| 03FA | PC/XT/AT | Serial | w | 16650 FCR (FIFO Control Register) |
| 03FB | PC/XT/AT | Serial | r/w | line control register |
| 03FC | PC/XT/AT | Serial | r/w | modem control register |
| 03FD | PC/XT/AT | Serial | r | line status register |
| 03FE | PC/XT/AT | Serial | r | modem status register |
| 03FF | PC/XT/AT | Serial | r/w | scratch register |
| 0530-0533 | PC/XT/AT | Sound | Gravis UltraSound Daughter Card | |
| 0620-0627 | XT | Network | PC network (adapter 1) | |
| 0628-062F | XT | Network | PC network (adapter 2) | |
| 0680 | PC/XT/AT | System | w | Microchannel POST Diagnostic |
| 06E8-06EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 0746 | PC/XT/AT | Sound | Gravis UltraSound | |
| 0800-08FF | PC/XT/AT | System | I/O port access registers for extended CMOS RAM or SRAM | |
| 0A20-0A23 | PC/XT/AT | Network | Token Ring (adapter 1) | |
| 0A24-0A27 | PC/XT/AT | Network | Token Ring (adapter 2) | |
| 0AE8-0AEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 0EE8-0EEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 12E8-12EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 16E8-16EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 1AE8-1AEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 1EE8-1EEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 2100-210F | PC/XT/AT | Video | IBM XGA (eXtended Graphics Adapter 8514/A) (first installed) | |
| 2110-217F | PC/XT/AT | Video | secondary XGA adapters | |
| 22E8-22EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 3220-3227 | PC/XT/AT | Serial | serial port 3, description same as 03F8 | |
| 3228-322F | PC/XT/AT | Serial | serial port 4, description same as 03F8 | |
| 3540-354F | PC/XT/AT | SCSI | IBM SCSI (Small Computer System Interface) adapter | |
| 3550-355F | PC/XT/AT | SCSI | IBM SCSI (Small Computer System Interface) adapter | |
| 3560-356F | PC/XT/AT | SCSI | IBM SCSI (Small Computer System Interface) adapter | |
| 3570-357F | PC/XT/AT | SCSI | IBM SCSI (Small Computer System Interface) adapter | |
| 4220-4227 | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| 4228-422F | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| 42E0-42EF | PC/XT/AT | GPIB | GPIB (General Purpose Interface Bus, IEEE 488 interface) | |
| 46E8 | PC/XT/AT | Video | VGA video adapter enable | |
| 4AE8-4AEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 5220-5227 | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| 5228-522F | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| 62E0-62EF | PC/XT/AT | GPIB | GPIB (General Purpose Interface Bus, IEEE 488 interface) | |
| 82E0-82EF | PC/XT/AT | GPIB | GPIB (General Purpose Interface Bus, IEEE 488 interface) | |
| 82E8-82EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 8AE8-8AEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 8EE8-8EEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 92E8-92EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| 96E8-96EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| A2E0-A2EF | PC/XT/AT | GPIB | GPIB (General Purpose Interface Bus, IEEE 488 interface) | |
| A2E8-A2EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| A6E8-A6EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| AAE8-AAEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| AEE8-AEEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| B220-B227 | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| B228-B22F | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| B2E8-B2EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| B6E8-B6EF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| BAE8-BAEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| BEE8-BEEF | PC/XT/AT | Video | 8514/A and compatible video cards | |
| C220-C227 | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| C228-C22F | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| C2E0-C2EF | PC/XT/AT | GPIB | GPIB (General Purpose Interface Bus, IEEE 488 interface) | |
| D220-D227 | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| D228-D22F | PC/XT/AT | Serial | serial port, description same as 03F8 | |
| E2E0-E2EF | PC/XT/AT | GPIB | GPIB (General Purpose Interface Bus, IEEE 488 interface) | |
| E2E8-E2EF | PC/XT/AT | Video | 8514/A and compatible video cards |
Primary Emulation Resources
- (bochs.sourceforge.io) PORTS.LST
BIOS Interrupt Reference
Video References
This section contains reference material for video adapters.
BIOS Video Modes
This table is courtesy of minuszerodegrees.net.
| = HSYNC: positive at 18.43 kHz, VSYNC: negative at 50 Hz | |
| = HSYNC: positive at 15.7 kHz, VSYNC: positive at 60 Hz (a.k.a. EGA Mode 1) | |
| = HSYNC: positive at 21.85 kHz, VSYNC: negative at 60 Hz (a.k.a. EGA Mode 2 or EGA High Resolution) | |
| = HSYNC: 31.5 kHz, VSYNC: 70 Hz | |
| = HSYNC: 31.5 kHz, VSYNC: 60 Hz |
Note 1:
Changing the monitor type on an IBM EGA card requires that switches on the IBM EGA card be changed.
Note 2:
Register and attribute behaviour is not quite the same as an MDA card. For more info, read the first page of the document here.
Note 3:
4 Colors if 64KB of RAM fitted to EGA video card; 16 Colors if 128KB (or more) of RAM fitted.
Primary Emulation Resources
- (minuszerodegrees.net) BIOS Video Modes
EGA DIP Switch Settings
| SW1 | SW2 | SW3 | SW4 | Primary Card | EGA Monitor Type | DIP Hex |
|---|---|---|---|---|---|---|
| 0 (ON) | 0 (ON) | 0 (ON) | 0 (ON) | MDA Primary + EGA | Color (40x25) | 0 |
| 1 (OFF) | 0 (ON) | 0 (ON) | 0 (ON) | MDA Primary | Color (80x25) | 1 |
| 0 (ON) | 1 (OFF) | 0 (ON) | 0 (ON) | MDA Primary + EGA | Enhanced Color (in Normal Color Mode) | 2 |
| 1 (OFF) | 1 (OFF) | 0 (ON) | 0 (ON) | MDA Primary + EGA | Enhanced Color (in Enhanced Color Mode) | 3 |
| 0 (ON) | 0 (ON) | 1 (OFF) | 0 (ON) | CGA Primary + EGA | Monochrome (CGA Color (40x25)) | 4 |
| 1 (OFF) | 0 (ON) | 1 (OFF) | 0 (ON) | CGA Primary + EGA | Monochrome (CGA Color (80x25)) | 5 |
| 0 (ON) | 1 (OFF) | 1 (OFF) | 0 (ON) | EGA Primary + MDA | Color (40x25) | 6 |
| 1 (OFF) | 1 (OFF) | 1 (OFF) | 0 (ON) | EGA Primary + MDA | Color (80x25) | 7 |
| 0 (ON) | 0 (ON) | 0 (ON) | 1 (OFF) | EGA Primary + MDA | Enhanced Color (in Normal Color Mode) | 8 |
| 1 (OFF) | 0 (ON) | 0 (ON) | 1 (OFF) | EGA Primary + MDA | Enhanced Color (in Enhanced Color Mode) | 9 |
| 0 (ON) | 1 (OFF) | 0 (ON) | 1 (OFF) | EGA Primary + CGA | Monochrome (CGA Color (40x25)) | A |
| 1 (OFF) | 1 (OFF) | 0 (ON) | 1 (OFF) | EGA Primary + CGA | Monochrome (CGA Color (80x25)) | B |
| 0 (ON) | 0 (ON) | 1 (OFF) | 1 (OFF) | reserved | reserved | reserved |
| 1 (OFF) | 0 (ON) | 1 (OFF) | 1 (OFF) | reserved | reserved | reserved |
| 0 (ON) | 1 (OFF) | 1 (OFF) | 1 (OFF) | reserved | reserved | reserved |
| 1 (OFF) | 1 (OFF) | 1 (OFF) | 1 (OFF) | reserved | reserved | reserved |
Most EGA clone cards used the same settings - perhaps defining special interpretations of the last four unused settings on the original IBM EGA.
VGA cards or other cards without such DIP switches emulated the closest appropriate DIP HEX value to store in the BDA.
Note that DIP switches are read by the PC logically reversed. A switch that is ON reads logical low (0) while a switch that is OFF reads logically high (1).
Primary Emulation Resources
- (minuszerodegrees.net) IBM EGA - Switch Settings
- (minuszerodegrees.net) IBM EGA - Installation Instructions
EGA Registers
Most register references you will find online are for the VGA exclusively, or else intermingle EGA and VGA to the point where it can be confusing if you are looking for a EGA specific reference.
Every bit listed in this section is specific to the original IBM EGA, unless where noted.
NOTE: The original IBM EGA and several clones have jumpers that can invert address line A09 during port decoding. This causes all the
3XXrange registers to be decoded at2XX. This is a fairly obscure feature and I am not aware of anything that uses it - even video BIOS routines will typically fail to control the card with this jumper set.
The EGA can switch between a port base of 3DX and 3BX for the CRTC and Input Status Register 1 registers - this is primarily for MDA compatibility. The EGA may configure itself this way on boot depending on the status of the EGA DIP Switches.
Indexed Registers
Register indexing is a common way to reduce the complexity of address decoding and conserve the IO address space. In its most common form, it consists of a pair of registers - an address port and a data port. First, a byte address or register index is written to the address port. This selects the desired register, assuming it represents a valid index. Then, with the desired register selected, the new value for the register is written to the data port. The address port and data port are typically consecutive IO addresses, with the address port at an even address. There is a good reason for this.
A consequence of the 8088’s transparent 8-bit bus is that an indexed register can be selected and written to via a single word-sized OUT. The data byte is typically packed into AH, with the address in AL. The 8088’s BIU will convert the word write into two 8-bit writes at the base IO address and then the base address + 1. On the AT and subsequent 16-bit architectures, this conversion had to be specifically emulated by hardware on the motherboard.
Indexed registers can also be implemented via an internal flip-flop, where only a single IO port is required. The first write will set the register index, the second write will set the corresponding register data. Under this scheme there must be a way to reset the flip-flop to a known state. This technique is used for the EGA’s single Attribute Controller IO port, which can be reset by reading Input Status Register 1 at either 3DAh or 3BAh, depending on the EGA’s current base address.
Register File Overview
| I/O Address | Read Function | Write Function |
|---|---|---|
| 3B4 / 3D4 | Not Readable | CRTC Address Register |
| 3B5 / 3D5 | Not Readable | CRTC Data Register |
| 3BA / 3DA | Input Status Register 1 | Feature Control Register |
| 3C0 | Not Readable | Attribute Controller |
| 3C2 | Input Status Register 0 | Miscellaneous Output Register |
| 3C4 | Not Readable | Sequencer Address Register |
| 3C5 | Not Readable | Sequencer Data Register |
| 3CE | Not Readable | Graphics Controller Address Register |
| 3CF | Not Readable | Graphics Controller Data Register |
Register Set Details Index
CRTC Registers
The EGA uses a custom LSI CRTC chip. It is very similar in operation to the Motorola 6845, but defines most vertical counters in units of scanlines. Using scanlines as the vertical unit is more convenient for a graphics-mode oriented video adapter. It also has the big advantage of not requiring any memory-addressing tricks that lead to inconvenient video memory layouts on the CGA and Hercules cards.
Most of the EGA CRTC registers are write-only, with the exception of the three register pairs that hold memory addresses - the Start Address, Cursor Location, and Light Pen address registers can be read out. The inability to read the EGA CRTC registers was an annoyance for graphics and games programmers everywhere. This was rectified on the VGA which made most of the register file readable, but much software written for 4bpp modes did not rely on this to maintain backwards compatibility.
| Index | Register Name | Access | Description |
|---|---|---|---|
| 00h | Horizontal Total | W | Total character clocks in a scanline, minus 2 |
| 01h | Horizontal Display End | W | Number of characters visible per line |
| 02h | Start Horizontal Blank | W | Character position where horizontal blanking begins |
| 03h | End Horizontal Blank | W | Character position where horizontal blanking ends |
| 04h | Start Horizontal Retrace | W | Character position where horizontal retrace begins |
| 05h | End Horizontal Retrace | W | Character position where horizontal retrace ends |
| 06h | Vertical Total | W | Total number of scanlines per frame |
| 07h | Overflow | W | High bits for V-Total, V-Display, V-Sync |
| 08h | Preset Row Scan | W | Starting scanline within a character cell |
| 09h | Max Scan Line | W | Height of character cell minus 1 |
| 0Ah | Cursor Start | W | Top scanline of cursor |
| 0Bh | Cursor End | W | Bottom scanline of cursor |
| 0Ch | Start Address High | RW | High byte of display memory start pointer |
| 0Dh | Start Address Low | RW | Low byte of display memory start pointer |
| 0Eh | Cursor Location High | RW | High byte of cursor memory address |
| 0Fh | Cursor Location Low | RW | Low byte of cursor memory address |
| 10h | Vertical Retrace Start | W | Scanline where Vertical Retrace begins |
| 10h | Light Pen Address High | R | High byte of Light Pen latched memory address |
| 11h | Vertical Retrace End | W | Scanline where Vertical Retrace ends (Bits 0-3) |
| 11h | Light Pen Address Low | R | Low byte of Light Pen latched memory address |
| 12h | Vertical Display End | W | Last visible scanline (low 8 bits) |
| 13h | Offset | W | Span width of logical scanline |
| 14h | Underline Location | W | Scanline within cell for underline |
| 15h | Start Vertical Blank | W | Scanline where blanking starts |
| 16h | End Vertical Blank | W | Scanline where blanking ends |
| 17h | Mode Control | W | Hardware compatibility/timing toggles |
| 18h | Line Compare | W | Scanline on which CRTC start address is reset |
Graphics Controller Registers
| Port | Register Name | Access |
|---|---|---|
| 3CC | Graphics 1 Position | W |
| 3CA | Graphics 2 Position | W |
| 3CE | Graphics Address | W |
| 3CF | Graphics Data | W |
On the original IBM EGA, there are two separate Graphics Controller chips. They can generally be treated as a single entity except for the two Graphics Position registers. These two registers are used to tell each of the graphics controllers which pair of graphics planes they will be managing.
The Graphics Controller chips lack an IOW pin, thus all their registers are write-only.
Graphics Controller Indexed Registers
| Index | Register Name |
|---|---|
| 00h | Set/Reset |
| 01h | Enable Set/Reset |
| 02h | Color Compare |
| 03h | Data Rotate |
| 04h | Read Map Select |
| 05h | Mode Register |
| 06h | Miscellaneous |
| 07h | Color Don’t Care |
| 08h | Bit Mask |
Sequencer Registers
| Port | Register Name | Access |
|---|---|---|
| 3C4 | Sequencer Address | W |
| 3C5 | Sequencer Data | W |
Sequencer Indexed Registers
| Index | Register Name |
|---|---|
| 00h | Reset |
| 01h | Clocking Mode |
| 02h | Map Mask |
| 03h | Character Map Select |
| 04h | Memory Mode |
Attribute Controller Registers
| Port | Register Name | Access |
|---|---|---|
| 3BA / 3CA | Reset Attribute Flip-Flop | R |
| 3C0 | Address / Data (Flip-flops on each write) | W |
Attribute Controller Indexed Registers
| Index | Register Name | Access |
|---|---|---|
| 00h-0Fh | Attribute Palette Entries [0-F] | W* |
| 10h | Mode Control | W |
| 11h | Overscan Color | W |
| 12h | Color Plane Enable | W |
| 13h | Horizontal Pel Panning | W |
The first sixteen registers in the Attribute Controller define a 4bpp palette.
External Register Details
| Bits | Name | Description |
|---|---|---|
| 0 | IO | I/O Address (0=3Bx mono, 1=3Dx color) |
| 1 | ERAM | Enable RAM (1=Enabled) |
| 2:3 | CLK | Clock Select (00=14MHz, 01=16MHz, 10=External, 11=Unused) |
| 4 | DISABLE | Disable Video Drivers (1=Disable) |
| 5 | PAGE | Page bit for Odd/Even mode |
| 6 | HSP | Horizontal Sync Polarity (0=Pos, 1=Neg) |
| 7 | VSP | Vertical Sync Polarity (0=Pos, 1=Neg) |
| Bits | Name | Description |
|---|---|---|
| 0 | FC0 | Feature Control Bit 0 |
| 1 | FC1 | Feature Control Bit 1 |
| 2:3 | Reserved | Reserved |
| 4:7 | – | Unused |
| Bits | Name | Description |
|---|---|---|
| 0:3 | – | Unused |
| 4 | SENSE | Switch Sense - State of selected configuration switch |
| 5 | FEAT0 | State of FEAT0 pin on Feature Connector |
| 6 | FEAT1 | State of FEAT1 pin on Feature Connector |
| 7 | INT | CRT Interrupt Pending (1=Yes) |
Attribute Controller Register Details
| Bits | Name | Description |
|---|---|---|
| 0 | B | Blue |
| 1 | G | Green |
| 2 | R | Red |
| 3 | SB/I | Secondary Blue / Mono Intensity |
| 4 | SG/I | Secondary Green / Intensity |
| 5 | SR | Secondary Red |
| 6:7 | Unused | Unused |
| Bits | Name | Description |
|---|---|---|
| 0 | G/A | Video Mode: 1: Graphics Mode 0: Alphanumeric Mode |
| 1 | DT | Text Attribute Type: 0: Color 1: MDA |
| 2 | LG | Enable Line Graphics Characters |
| 3 | B/I | Attribute Bit 7 interpreted as: 1: Blink Enabled 0: Background Intensity |
| 4:7 | Unused | Unused |
| Bits | Name | Description |
|---|---|---|
| 0 | B | Blue |
| 1 | G | Green |
| 2 | R | Red |
| 3 | SB/I | Secondary Blue |
| 4 | SG/I | Secondary Green / Intensity |
| 5 | SR | Secondary Red |
| 6:7 | Unused | Unused |
| Bits | Name | Description |
|---|---|---|
| 0:3 | ECP | Enable Color Planes Each bit set in this field enables the corresponding plane 0-3. |
| 4:5 | MUX | Video Status MUX |
| 6:7 | Unused | Unused |
| Bits | Name | Description |
|---|---|---|
| 0:3 | PAN | Horizontal Pel Panning Value EGA Mode: 0-7 Monochrome Mode: 8,0-7 |
| 4:7 | Unused | Unused |
SuperEGA Registers
There were several video chipset manufacturers who produced EGA chipsets with extended capabilities, most typically an increased resolution of 640x480. These adapters were typically called SuperEGAs.
SuperEGA chipsets often extended the standard EGA register file, with new register indices defined for the CRTC, graphics controllers, sequencer and attribute controller.
ET2000
The Tseng Labs ET2000 was an advanced chipset designed to be adaptable to a variety of different graphics adapters, although it only ever appeared on three EGA cards: the Tseng Labs EVA and EVA/480, and the NEC GB-1 (a rebadged EVA/480). The plain EVA model lacks the 25MHz clock that allows 640x480 resolution.
It is comprised of three VLSI chips in PLCC68 packages:
| Chip | Function |
|---|---|
| ET2000 | CRTC / Sequencer |
| ET2001 | Attribute Controller |
| ET2002 | Graphics Controller |
A fourth chip, the ET2003 bit-slice processor, was announced but never saw production.
Clocking Select Bits
As with most SuperEGAs, the ET2000 in its full incarnation is typically paired with a 25MHz pixel clock - it also has a third crystal, a 19.96608MHz clock that is used as a pixel clock in 132 column modes, as well as clocking the memory address multiplexers.
| bits | clock select |
|---|---|
| 00 | 14.381818MHz (OSC pin from ISA bus) |
| 01 | 16.257MHz |
| 10 | 25MHz or external OSC (J3) |
| 11 | 19.96608MHz |
Extended General Registers
| Port | Access | Description |
|---|---|---|
| 7CXh | W | CMII Activation Port |
| 3C8h | W | CMII Command Port |
These are essentially the same decoded port - the CMII compatibility module will respond to A10 set as a special ‘wake’ address. It must be written to twice, with a data byte that has bits 7 and 6 set, to activate the card and begin hooking IO writes for translation.
Extended CRTC Registers
| Index | Name | Access | Description |
|---|---|---|---|
| 19h | Overflow #2 | W | High bits for V-Total, V-Display, V-Sync |
| 1Ah | ? | W | ET2000 BIOS sets bit 1 then reads 12h (?) |
| 1Bh | X Zoom Start Column | ? | Character clock of zoom viewport start |
| 1Ch | X Zoom End Column | ? | Character clock of zoom viewport end |
| 1Dh | Y Zoom Start Scanline | ? | Scanline on which zoom viewport starts |
| 1Eh | Y Zoom End Scanline | ? | Scanline on which zoom viewport ends |
| 1Fh | Y Zoom Start and End Scanline High | ? | |
| 20h | Zoom Start Address Low | ? | |
| 21h | Zoom Start Address Middle | ? | |
| 22h | ? | ? | |
| 23h | ? | ? | |
| 24h | ? | ? | |
| 25h | ? | ? |
Extended Sequencer Registers
| Index | Name | Access | Description |
|---|---|---|---|
| 06h | Zoom Timing | W | Controls timings for zoom/viewport feature |
| 07h | Character Timing | W | Set to 03, 02 or 01 in large column modes |
Extended Graphics Controller Registers
| Index | Name | Access | Description |
|---|---|---|---|
| 0Dh | ? | W | Initialized to 0 |
Extended Attribute Controller Registers
| Index | Name | Access | Description |
|---|---|---|---|
| 14h | ? | W | Initialized to 0 |
| 15h | ? | W | Initialized to 0 |
| 16h | ? | W | Bit 1 set in 132 column modes |
Video Palettes
CGA Text Mode
In color text modes, the CGA card can emit a total of 16 different colors - a combination of the four video signals: red, green, blue, and intensity - a signal that boosts the brightness of the previous three color signals. Note that the intensity bit also boosts the apparent brightness of pure black, creating a dim gray.
NOTE: The standard CGA brown color is not actually a color emitted by the CGA card; the conversion of ‘dark yellow’ to brown occurs via special circuitry within the IBM 5153 Color Display and most CGA-compatible monitors.
Full RGBI Palette
| R | G | B | I | Color | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 000000 | |
| 0 | 0 | 1 | 0 | 0000AA | |
| 0 | 1 | 0 | 0 | 00AA00 | |
| 0 | 1 | 1 | 0 | 00AAAA | |
| 1 | 0 | 0 | 0 | AA0000 | |
| 1 | 0 | 1 | 0 | AA00AA | |
| 1 | 1 | 0 | 0 | AA5500 | |
| 1 | 1 | 1 | 0 | AAAAAA | |
| 0 | 0 | 0 | 1 | 555555 | |
| 0 | 0 | 1 | 1 | 5555FF | |
| 0 | 1 | 0 | 1 | 55FF55 | |
| 0 | 1 | 1 | 1 | 55FFFF | |
| 1 | 0 | 0 | 1 | FF5555 | |
| 1 | 0 | 1 | 1 | FF55FF | |
| 1 | 1 | 0 | 1 | FFFF55 | |
| 1 | 1 | 1 | 1 | FFFFFF |
The “IBM 5153” Palette
The aforementioned palette represents “ideal” colors - theoretically perfect color outputs. Modern displays have no problem rendering such colors, but original CGA monitors such as the IBM 5153 Color Display had their own eccentricities.
Taking into account the electrical characteristics of the 5153, a more visually authentic CGA palette can be derived:
| R | G | B | I | Color | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 000000 | |
| 0 | 0 | 1 | 0 | 0000C4 | |
| 0 | 1 | 0 | 0 | 00C400 | |
| 0 | 1 | 1 | 0 | 00C4C4 | |
| 1 | 0 | 0 | 0 | C40000 | |
| 1 | 0 | 1 | 0 | C400C4 | |
| 1 | 1 | 0 | 0 | C47E00 | |
| 1 | 1 | 1 | 0 | C4C4C4 | |
| 0 | 0 | 0 | 1 | 4E4E4E | |
| 0 | 0 | 1 | 1 | 4E4EDC | |
| 0 | 1 | 0 | 1 | 4EDC4E | |
| 0 | 1 | 1 | 1 | 4EF3F3 | |
| 1 | 0 | 0 | 1 | DC4E4E | |
| 1 | 0 | 1 | 1 | F34EF3 | |
| 1 | 1 | 0 | 1 | F3F34E | |
| 1 | 1 | 1 | 1 | FFFFFF |
CGA Graphics Modes
Although much is said - derisively - about the CGA’s ugly ‘palettes’, the IBM CGA card does not actually have what we would typically consider palettes at all.
In graphics mode, pairs of bits from video memory drive the red and green video output lines directly, with no color look-ups performed. The effect of having multiple palettes is produced by miscellaneous logic that determines if and when the blue video output is additionally enabled or not.
When both bits from video memory are 0, the background/overscan color configured in the CGA Color Control register is substituted. Black is not a requirement for any of the CGA’s palettes.
The intensity bit, specified in the CGA Color Control register, provides two variations of brightness per palette.
Default Palette (Blue Disabled)
| R | G | B | I | Color | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Overscan | |
| 0 | 1 | 0 | 0 | 00AA00 | |
| 1 | 0 | 0 | 0 | AA0000 | |
| 1 | 1 | 0 | 0 | AA5500 |
| R | G | B | I | Color | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | Overscan | |
| 0 | 1 | 0 | 1 | 55FF55 | |
| 1 | 0 | 0 | 1 | FF5555 | |
| 1 | 1 | 0 | 1 | FFFF55 |
Secondary Palette (Blue Enabled)
| R | G | B | I | Color | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Overscan | |
| 0 | 1 | 1 | 0 | 00AAAA | |
| 1 | 0 | 1 | 0 | AA00AA | |
| 1 | 1 | 1 | 0 | AAAAAA |
| R | G | B | I | Color | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | Overscan | |
| 0 | 1 | 1 | 1 | 55FFFF | |
| 1 | 0 | 1 | 1 | FF55FF | |
| 1 | 1 | 1 | 1 | FFFFFF |
Alternate Palette (Blue Enabled Except When Red)
Sometimes described as a “hidden” palette, and often considered the most aesthetically pleasing, the cyan-red-white palette was only implemented to provide better contrast when displaying CGA graphics modes on a monochrome composite display, such as a black-and-white television set. It was not implemented for its aesthetics, and thus IBM probably didn’t see fit to document it as a color option - after all, later revisions of the CGA could have always disabled the need for it by adjustments to the composite output circuitry.
This palette is created by miscellaneous logic that enables the blue video output unless the color red is decoded.
| R | G | B | I | Color | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Overscan | |
| 0 | 1 | 1 | 0 | 00AAAA | |
| 1 | 0 | 0 | 0 | AA0000 | |
| 1 | 1 | 1 | 0 | AAAAAA |
| R | G | B | I | Color | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | Overscan | |
| 0 | 1 | 1 | 1 | 55FFFF | |
| 1 | 0 | 0 | 1 | FF5555 | |
| 1 | 1 | 1 | 1 | FFFFFF |
EGA 6-bit Palette (64 Colors)
The EGA can display any 16 of these 64 colors simultaneously when connected to an EGA monitor and operating in 350 line mode, although there are exceptions that enable use of 6bpp color in 200 line modes with the right hardware.
| Index | RI | GI | BI | R | G | B | Color | Hex | Index | RI | GI | BI | R | G | B | Color | Hex |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 00 | 0 | 0 | 0 | 0 | 0 | 0 | 000000 | 20 | 1 | 0 | 0 | 0 | 0 | 0 | 550000 | ||
| 01 | 0 | 0 | 0 | 0 | 0 | 1 | 0000AA | 21 | 1 | 0 | 0 | 0 | 0 | 1 | 5500AA | ||
| 02 | 0 | 0 | 0 | 0 | 1 | 0 | 00AA00 | 22 | 1 | 0 | 0 | 0 | 1 | 0 | 55AA00 | ||
| 03 | 0 | 0 | 0 | 0 | 1 | 1 | 00AAAA | 23 | 1 | 0 | 0 | 0 | 1 | 1 | 55AAAA | ||
| 04 | 0 | 0 | 0 | 1 | 0 | 0 | AA0000 | 24 | 1 | 0 | 0 | 1 | 0 | 0 | FF0000 | ||
| 05 | 0 | 0 | 0 | 1 | 0 | 1 | AA00AA | 25 | 1 | 0 | 0 | 1 | 0 | 1 | FF00AA | ||
| 06 | 0 | 0 | 0 | 1 | 1 | 0 | AAAA00 | 26 | 1 | 0 | 0 | 1 | 1 | 0 | FFAA00 | ||
| 07 | 0 | 0 | 0 | 1 | 1 | 1 | AAAAAA | 27 | 1 | 0 | 0 | 1 | 1 | 1 | FFAAAA | ||
| 08 | 0 | 0 | 1 | 0 | 0 | 0 | 000055 | 28 | 1 | 0 | 1 | 0 | 0 | 0 | 550055 | ||
| 09 | 0 | 0 | 1 | 0 | 0 | 1 | 0000FF | 29 | 1 | 0 | 1 | 0 | 0 | 1 | 5500FF | ||
| 0A | 0 | 0 | 1 | 0 | 1 | 0 | 00AA55 | 2A | 1 | 0 | 1 | 0 | 1 | 0 | 55AA55 | ||
| 0B | 0 | 0 | 1 | 0 | 1 | 1 | 00AAFF | 2B | 1 | 0 | 1 | 0 | 1 | 1 | 55AAFF | ||
| 0C | 0 | 0 | 1 | 1 | 0 | 0 | AA0055 | 2C | 1 | 0 | 1 | 1 | 0 | 0 | FF0055 | ||
| 0D | 0 | 0 | 1 | 1 | 0 | 1 | AA00FF | 2D | 1 | 0 | 1 | 1 | 0 | 1 | FF00FF | ||
| 0E | 0 | 0 | 1 | 1 | 1 | 0 | AAAA55 | 2E | 1 | 0 | 1 | 1 | 1 | 0 | FFAA55 | ||
| 0F | 0 | 0 | 1 | 1 | 1 | 1 | AAAAFF | 2F | 1 | 0 | 1 | 1 | 1 | 1 | FFAAFF | ||
| 10 | 0 | 1 | 0 | 0 | 0 | 0 | 005500 | 30 | 1 | 1 | 0 | 0 | 0 | 0 | 555500 | ||
| 11 | 0 | 1 | 0 | 0 | 0 | 1 | 0055AA | 31 | 1 | 1 | 0 | 0 | 0 | 1 | 5555AA | ||
| 12 | 0 | 1 | 0 | 0 | 1 | 0 | 00FF00 | 32 | 1 | 1 | 0 | 0 | 1 | 0 | 55FF00 | ||
| 13 | 0 | 1 | 0 | 0 | 1 | 1 | 00FFAA | 33 | 1 | 1 | 0 | 0 | 1 | 1 | 55FFAA | ||
| 14 | 0 | 1 | 0 | 1 | 0 | 0 | AA5500 | 34 | 1 | 1 | 0 | 1 | 0 | 0 | FF5500 | ||
| 15 | 0 | 1 | 0 | 1 | 0 | 1 | AA55AA | 35 | 1 | 1 | 0 | 1 | 0 | 1 | FF55AA | ||
| 16 | 0 | 1 | 0 | 1 | 1 | 0 | AAFF00 | 36 | 1 | 1 | 0 | 1 | 1 | 0 | FFFF00 | ||
| 17 | 0 | 1 | 0 | 1 | 1 | 1 | AAFFAA | 37 | 1 | 1 | 0 | 1 | 1 | 1 | FFFFAA | ||
| 18 | 0 | 1 | 1 | 0 | 0 | 0 | 005555 | 38 | 1 | 1 | 1 | 0 | 0 | 0 | 555555 | ||
| 19 | 0 | 1 | 1 | 0 | 0 | 1 | 0055FF | 39 | 1 | 1 | 1 | 0 | 0 | 1 | 5555FF | ||
| 1A | 0 | 1 | 1 | 0 | 1 | 0 | 00FF55 | 3A | 1 | 1 | 1 | 0 | 1 | 0 | 55FF55 | ||
| 1B | 0 | 1 | 1 | 0 | 1 | 1 | 00FFFF | 3B | 1 | 1 | 1 | 0 | 1 | 1 | 55FFFF | ||
| 1C | 0 | 1 | 1 | 1 | 0 | 0 | AA5555 | 3C | 1 | 1 | 1 | 1 | 0 | 0 | FF5555 | ||
| 1D | 0 | 1 | 1 | 1 | 0 | 1 | AA55FF | 3D | 1 | 1 | 1 | 1 | 0 | 1 | FF55FF | ||
| 1E | 0 | 1 | 1 | 1 | 1 | 0 | AAFF55 | 3E | 1 | 1 | 1 | 1 | 1 | 0 | FFFF55 | ||
| 1F | 0 | 1 | 1 | 1 | 1 | 1 | AAFFFF | 3F | 1 | 1 | 1 | 1 | 1 | 1 | FFFFFF |
The Default VGA Palette
The VGA has a total palette of 256 out of 262,144 colors, making a full table a bit impractical. The default VGA palette is shown below.
The VGA still has the 16 Attribute Controller Palette registers, which are used in text mode and 4bpp modes, however they no longer store color information. Instead, they contain indexes into the 256 color registers of the DAC. This DAC lookup is always active.
The first 16 colors of the default VGA palette correspond to the traditional 16 color RGBI palette, and so the Attribute Palette registers reference the same colors by virtue of being initialized with the values 0-F. The Attribute Palette registers remain 6 bits, and so they can only reference a total of 64 DAC Color registers. Due to this, the VGA divides the 256 total Color registers into four separate banks, which can be selected independently.
| 000000 | 0000AA | 00AA00 | 00AAAA | AA0000 | AA00AA | AA5500 | AAAAAA | 555555 | 5555FF | 55FF55 | 55FFFF | FF5555 | FF55FF | FFFF55 | FFFFFF |
| 000000 | 141414 | 202020 | 2C2C2C | 383838 | 454545 | 515151 | 616161 | 717171 | 828282 | 929292 | A2A2A2 | B6B6B6 | CBCBCB | E3E3E3 | FFFFFF |
| 0000FF | 4100FF | 7D00FF | BE00FF | FF00FF | FF00BE | FF007D | FF0041 | FF0000 | FF4100 | FF7D00 | FFBE00 | FFFF00 | BEFF00 | 7DFF00 | 41FF00 |
| 00FF00 | 00FF41 | 00FF7D | 00FFBE | 00FFFF | 00BEFF | 007DFF | 0041FF | 7D7DFF | 9E7DFF | BE7DFF | DF7DFF | FF7DFF | FF7DDF | FF7DBE | FF7D9E |
| FF7D7D | FF9E7D | FFBE7D | FFDF7D | FFFF7D | DFFF7D | BEFF7D | 9EFF7D | 7DFF7D | 7DFF9E | 7DFFBE | 7DFFDF | 7DFFFF | 7DDFFF | 7DBEFF | 7D9EFF |
| B6B6FF | C7B6FF | DBB6FF | EBB6FF | FFB6FF | FFB6EB | FFB6DB | FFB6C7 | FFB6B6 | FFC7B6 | FFDBB6 | FFEBB6 | FFFFB6 | EBFFB6 | DBFFB6 | C7FFB6 |
| B6FFB6 | B6FFC7 | B6FFDB | B6FFEB | B6FFFF | B6EBFF | B6DBFF | B6C7FF | 000071 | 1C0071 | 380071 | 550071 | 710071 | 710055 | 710038 | 71001C |
| 710000 | 711C00 | 713800 | 715500 | 717100 | 557100 | 387100 | 1C7100 | 007100 | 00711C | 007138 | 007155 | 007171 | 005571 | 003871 | 001C71 |
| 383871 | 453871 | 553871 | 613871 | 713871 | 713861 | 713855 | 713845 | 713838 | 714538 | 715538 | 716138 | 717138 | 617138 | 557138 | 457138 |
| 387138 | 387145 | 387155 | 387161 | 387171 | 386171 | 385571 | 384571 | 515171 | 595171 | 615171 | 695171 | 715171 | 715169 | 715161 | 715159 |
| 715151 | 715951 | 716151 | 716951 | 717151 | 697151 | 617151 | 597151 | 517151 | 517159 | 517161 | 517169 | 517171 | 516971 | 516171 | 515971 |
| 000041 | 100041 | 200041 | 300041 | 410041 | 410030 | 410020 | 410010 | 410000 | 411000 | 412000 | 413000 | 414100 | 304100 | 204100 | 104100 |
| 004100 | 004110 | 004120 | 004130 | 004141 | 003041 | 002041 | 001041 | 202041 | 282041 | 302041 | 382041 | 412041 | 412038 | 412030 | 412028 |
| 412020 | 412820 | 413020 | 413820 | 414120 | 384120 | 304120 | 284120 | 204120 | 204128 | 204130 | 204138 | 204141 | 203841 | 203041 | 202841 |
| 2C2C41 | 302C41 | 342C41 | 3C2C41 | 412C41 | 412C3C | 412C34 | 412C30 | 412C2C | 41302C | 41342C | 413C2C | 41412C | 3C412C | 34412C | 30412C |
| 2C412C | 2C4130 | 2C4134 | 2C413C | 2C4141 | 2C3C41 | 2C3441 | 2C3041 | 000000 | 000000 | 000000 | 000000 | 000000 | 000000 | 000000 | 000000 |
Primary Emulation Resources
- (int10h.org) The IBM 5153’s True CGA Palette and Color Output