This document tries to provide some valuable information about low-level programming of the PC-98 from a comparative standpoint with the similar-in-purpose IBM PC AT architecture with the intent of being useful to programmers with knowledge of the latter.
This document is (C) 2025 evv42 and released in the public domain. The author kindly requests remarks and additions to be provided at @evv42@donotsta.re
The following document was prepared using translations of PC-98 hardware and software manuals, software sources and disassemblies available on the Internet, but also with the many attempts from various people to document and program the PC-98 without which this document would not have been written. The Bibliography section will try to hopefully lists all of those resources.
The PC-98 was a 16-bit bus architecture from the start and thus has more in
common with IBM’s PC AT than with the 5150/XT machines.
The original machine had the following core components:
8086 CPU
one 8237 DMA controller
two 8259 PIC
one 8253 Timer
two µPD7220 chips forming the GDC, one for text and one for graphics
Integrated peripherals were:
a keyboard controller using a 8251 USART
a parallel printer port using a 8255 PIO
a serial port interface using a 8251 USART
a disk interface using a 8255 PIO (only on early models)
configuration switches wired to a 8255 PIO
a real time clock (?)
a beeper
Unlike IBM contemporaries which were made entirely of off the shelf parts and
were modular in their configuration, NEC used large amounts of gate arrays to
implement their architecture into a single circuit board.
The C-Bus carries signals in a similar fashion to the IBM’s 16-bit ISA
bus.
Later models may use different components but, like on the PC/AT, will provide to the programmer a compatible interface.
The Disk BIOS routines use a single byte to identify which type of device to address
and which device to address, called DA/UA in the documentation. The second
nibble, the UA (Unit Address ?) can be anything from 0 to 15 depending of the
interface.
The first nibble is the DA (Device Address), here’s a list of the known values (most
common in bold):
0x0 | SASI/ESDI/IDE hard drive (linear sector addressing) |
0x1 | 640KB floppy from 1MB interface |
0x2 | SCSI hard drive (linear sector addressing) |
0x3 | 1.44MB floppy from 1MB interface |
0x4 | RAM drive |
0x5 | 320KB floppy |
0x6 | BRANCH 4670 virtual disk (NIC ?) |
0x7 | 640KB floppy from 640KB interface |
0x8 | SASI/ESDI/IDE hard drive (absolute sector addressing) |
0x9 | 1MB floppy |
0xA | SCSI hard drive (absolute sector addressing) |
0xB | 1.44MB floppy from 1MB interface on some models ? |
0xC | SCSI (non-hard drives ?) |
0xD | Memory devices (ROM, PCMCIA) not usable by the disk BIOS |
0xE | RAMDISK.SYS |
0xF | 1MB floppy from 640KB interface |
The IPL is a sector-sized section of code that’s copied to memory by the PC-98 BIOS
from the boot media to be executed. Typically, the IPL then loads further code and
data from the boot media.
It’s the equivalent of the boot sector in the PC/AT, with the difference that
partitioned media (typically hard drives) can contain multiple IPL sectors, located
anywhere on the media, that can be selected by the user, using a specific interface
provided by the PC-98 BIOS.
For partitioned media, the PC-98 stored a table on the second sector of the drive
that contains the location of those, with an optional location for a IPL associated
with the partition label on the boot menu.
The boot menu typically does not show itself to the user if a single partition is
marked as bootable.
Address 0x584, one byte
Some BIOSes do store this value in the al register before jumping to the IPL but
most emulators do not replicate this.
empty :p
The PC-98 BIOS is very barebones and expects the user to have some familiarity with the PC-98 architecture.
int 0x1B, ah=0x_6
bit 7 of ah | MF (Multi-Track) flag |
bit 6 of ah | MF flag (1=MFM, 0=FM) |
bit 5 of ah | Retry flag (1=single try, 0=8 retries) |
bit 4 of ah | Seek flag (1=Seek, 0=Don’t seek) |
(typical value is 0101) | |
es:bp | Destination Address |
al | Device DA/UA |
cl | Cylinder |
dh | Head |
dl | Sector |
ch | Sector Size (0=128, 1=256, 2=512, 3=1024) |
bx | Destination Size |
empty :p
640KiB DSDD | 80 cylinders, 2 heads, 8 sectors, sector size 512 |
1232KiB DSHD | 77 cylinders, 2 heads, 8 sectors, sector size 1024 |
720KiB DSDD | 80 cylinders, 2 heads, 8 sectors, sector size 512 |
1440KiB DSHD | 80 cylinders, 2 heads, 18 sectors, sector size 512 |
From the horse’s mouth (NEC):
PC-9800 Technical Data Book CDs: https://archive.org/details/pc-9800-tdb-cd
(incomplete pdf version here : https://archive.org/details/bi_20240423)
NEC PC-9800 Quick Guide:
https://web.archive.org/web/20010202090900/http://www.pc98.com/info/quick-guide/quick-guide-intro.html
Independent references:
UNDOCUMENTED 9801/9821 Vol.1 and 2, available from various sources
radioc.dat PC-98 reference, with some pages in english:
https://radioc.web.fc2.com/column/pc98bas/
ReactOS FAT12 Bootloader:
https://github.com/reactos/reactos/blob/master/boot/freeldr/bootsect/pc98/fat12fdd.S
Additional references:
http://bauxite.sakura.ne.jp/wiki/mypad.cgi?p=PC-98x1
http://www.ctyme.com/intr/cat-021.htm
https://printf.neocities.org/programming
https://github.com/tmk/tmk_keyboard/wiki/PC-9801-Keyboard
https://cgit.freebsd.org/src/tree/sys/pc98?h=stable/5
https://people.freebsd.org/~kato/pc98.html