MSX Assembly Page

MSX I/O ports overview

Here’s an overview of I/O ports on the MSX. Some entries will link to a description on how to use those ports.

Note that this list, though comprehensive, is most certainly incomplete. If you have additions or see an error, please let us know.

Port range Description
#00-#01 Music Module MIDI, output ports
#00-#01 Sensor Kid
#02-#03 FAC MIDI interface (i8251, mirrored on ports #00-#07)
#04-#05 Music Module MIDI, input ports
#0A Music Module DAC (enable with Y8950 IO0)
#0F Zemina memory extensions
#10-#11 MegaFlashROM PSG (AY-3-8910 clone)
#14-#17 YM2608 OPNA cartridge (in development)
#18-#19 Philips Barcode Reader NMS1170/20
#20-#28 Philips NMS1251 modem second setting
#20-#28 Miniware M4000 modem second setting
#21-#27 Sunrise MP3 Player
#27-#2F Philips NMS1210/1211/1212 RS232 Serial Interface second setting (hardware switch)
#27-#2F Philips NMS1255 MSX interface/modem second setting (hardware switch) (see NMS121x)
#28-#29 DenYoNet Ethernet Interface, mapper / status
#2A-#2B PlaySoniq SID chip / settings
#2C PlaySoniq 8-bit DAC
#2D PlaySoniq joypad / temporary data
#2E-#2F openMSX debug device (default address)
#30-#38 Philips NMS1251 modem
#30-#38 Miniware M4000 modem
#30-#38 GREEN/MAK SCSI-interface
#30-#38 CD-ROM interface
#37-#3F Philips NMS1210/1211/1212 RS232 Serial Interface
#37-#3F Philips NMS1255 MSX interface/modem (see NMS121x)
#3C Musical Memory Mapper control
#3F Musical Memory Mapper SN76489 DCSG (when enabled)
#40-#4F Switched I/O ports
#48-#49 Franky SN76489 DCSG / VDP H/V counters
#5E-#5F GR8NET Ethernet Interface
#60-#6F Graphics9000 / V9990
#70-73 MIDI Saurus
#7E-#7F MSX 2 key cartridge (what is it?)
#7E-#7F MoonSound / OPL4 - Wave
#80-#83 RS232C UART / 8251 (Spectravideo, and Sony (if enabled))
#84-#87 RS232C programmable timer / 8253 (Spectravideo, and Sony (if enabled))
#88-#8B Alternate VDP v9938 ports for MSX1 to MSX2 adapter
#88-#89 Franky VDP (315-5124 / 315-5246)
#8C-#8D Sony MSX Modem (HBI-1200?)
#8E-#8F MegaRAM / MegaRAM Disk
#90-#91 Printer port interface
#93 Printer port bus direction (does it exist?)
#98-#9B VDP / Video Display Processor / TMS9918A / V9938 / V9958
#A0-#A3 PSG / AY-3-8910 / YM2149
PSG I/O ports A & B
#A4-#A5 PCM controller (turboR)
#A7 Pause / R800 info (turboR)
#A8-AB PPI / Programmable Peripheral Interface / 8255
#B0-B3 Sony HBI-55 Data Cartridge / Yamaha UDC-01 Data Memory (4kB SRAM) (8255 i/f)
#B4-B5 Clock chip / RP-5C01
#B6 CIEL ExpertTurbo / Expert3 turbo switch (bit 7: 1 = turbo on)
#B8-BB Card Reader (which?)
#B8-BB Sanyo lightpen interface
#BC-BF JVC VHD video controller (8255 i/f)
#C0-#C1 MSX-AUDIO / Music Module
#C0-#C3 MoonSound / OPL4 - FM alternate addressing mode
#C2-#C3 MSX-AUDIO / Music Module - 2nd cartridge
#C4-#C7 MoonSound / OPL4 - FM
#C8-#CF MSX INTERFACE (asynchronous serial communication interface)
#D0-#D7 FDC / Floppy Disk Controller (WD2793 Microsol)
#D8-#D9 Kanji ROM, JIS 1
#DA-#DB Kanji ROM, JIS 2
#DC-#DD Kanji ROM, 24-dots
#E0-#E2 External MSX-MIDI interface (µ·pack)
#E4-#E7 S1990 controller (turboR)
#E8-#EF Internal MSX-MIDI interface (turboR GT)
#F3 VDP display mode (MSX2+)
#F4 System flags
#F5 System control
#F6 Color bus I/O
#F7 A/V control
#F8 Optional A/V control for PAL version
#F8-#FB Memory Mapper segment selection MSB in 16-bit mappers (PlaySoniq, disabled by default)
#FC-#FF Memory Mapper registers

Here are also some memory-mapped I/O areas:

Address Range Description
#7FC0-#7FCF Panasonic FS-A1FM Modem ROM
#FFFF Secondary slot select register

Information collected from various sources. Special thanks go to Alex Wulms for the nice overview published in MCCM 75.

Zemina memory extensions

Port #0F is used for the Zemina Golden Box (ZMB-1024, 1Mbit / 128K), Black Box (1Mbit / 128K), Deluxe Box (ZMB-2048, 2Mbit / 256K) and Deluxe IV (4Mbit / 512K) memory extensions.

It uses I/O port #0F for device settings, and address #4000 for page select if the device is in RAM SELECT mode.

Port Description
#0F Page size select
bit 7, 6: 8K (1, 0) or 16K (0, 1)
Function of writing to address range #4000-#BFFF
bit 5, 4: RAM SELECT (1, 0) or WRITE (0, 1)

For a 128K extension, with a page size of 8K there are 16 pages, with a page size of 16K there are 8 pages.

Following are some examples, that assume the Zemina memory extension slot is selected for address range #4000-#7FFF.

To switch RAM page 5 to address #4000-#5FFF (8K page size):

LD   A,10100000B
OUT  (0FH),A
LD   A,5
LD   (4000H),A

To copy the contents of the MSX main RAM address range #A000-#BFFF to RAM page 3 (8K page size):

LD   A,10100000B
OUT  (0FH),A
LD   A,3
LD   (4000H),A
LD   A,10010000B
OUT  (0FH),A
LD   HL,0A000H
LD   DE,4000H
LD   BC,2000H

See the scanned manual with partial translation for more info.

Switched I/O ports

According to the MSX2 Hardware Specification, ports #40-#4F are forming the so-called ‘switched I/O ports’. With these the limitation of a maximum number of 256 I/O ports can be overcome, although it does require a little additional logic on the hardware’s behalf. The port numbers #41-#4F are the actual switched ports, and the device addressed via those ports is determined by the device ID written to port #40. When port #40 is read the currently selected device returns the complement of the current device ID, if present.

Port range Description
#40 Device ID register
#41-#4F Switched I/O ports

ID numbers between 1 and 127 are manufacturer ID numbers, and ID numbers 128 to 254 are device IDs. Built-in devices should use the manufacturer’s company ID, while periperhal devices which can be used on all MSX computers should use a device ID number.

As the Z80 has a 16-bit I/O addressing space, for those IDs which might be expanded in the future, it is recommended to use 16-bit access by decoding the upper 8 bits. Particularly for devices connected by manufacturer ID, with 16-bit access the address space for each ID can be expanded 256 times, which will help to support future expansion.

List of BIOS extension device ID’s:

8Matsushita (Panasonic)
11Nippon Gakki (Yamaha)
23Sharp Brazil
24GoldStar (LG)
128Image Scanner (Matsushita)
2121chipMSX / Zemmix Neo (KdL firmware)

Some example code, this enables the 6MHz mode on Panasonic FS-A1WX/WSX/FX computers:

PortPanasonic extensions
#40 = 8 (Panasonic manufacturer ID)
#41 Available on FS-A1FX/WX/WSX only:
bit 0: CPU speed mode (0=5.37MHz, 1=3.57MHz)
Available on FS-A1FX/WX/WSX/ST/GT only:
bit 7: Firmware switch status (0=on, 1=off) (read-only)
	LD	A,8
	OUT 	(040H),A	;out the manufacturer code 8 (Panasonic) to I/O port 40h
	IN	A,(040H)	;read the value you have just written
	CPL			;complement all bits of the value
	CP	8		;if it does not match the value you originally wrote,
	JR	NZ,Not_WX	;it is not a WX/WSX/FX.
	XOR	A		;write 0 to I/O port 41h
	OUT	(041H),A	;and the mode changes to high-speed clock

So you can check if certain extensions are available and ready to be accessed by reading back the value you just wrote to the device ID register. If that value is not the complement of what you wrote, then the extensions are not present.

Graphics9000 / V9990

The V9990 has 16 registers in total, covering the range #60-#6F. Only the first eight are used in the Graphics9000, ports #68-#6B are used in combination with an optional Kanji ROM extension, and the rest is left as reserve. In the Graphics9000, port #6F is mapped to the V7040 superimpose chip.

Port rangeDescription
#60VRAM data port
#61Palette data port
#62Command data port
#63Register data port
#64Register select port (write only)
#65Status port (read only)
#66Interrupt flag port
#67System control port (write only)
#68-#69Primary standard Kanji ROM address port (write only) (not used in Gfx9000)
#69Primary standard Kanji ROM data port (read only) (not used in Gfx9000)
#6A-#6BSecondary standard Kanji ROM address port (write only) (not used in Gfx9000)
#6BSecondary standard Kanji ROM data port (read only) (not used in Gfx9000)
#6Fv7040 superimpose chip (write only) (both Gfx9000 and Video9000)

Important note: for correct behaviour, all Gfx9000 applications should initialize by writing 0 to port #6F (the v7040 superimpose chip), and then wait a frame before accessing the Gfx9000 again. Not ensuring this register has the value 0 written to it will cause the Gfx9000 output to be blurred occasionally. On exit, Gfx9000 applications should write #10 to port #6F as a courtesy to Video9000 owners.

Refer to the Video9000 manual, page 13, for more (Video9000-specific) details about the v7040 chip.

RS232C UART (8251) / timer (8253)

These are the functions of the I/O registers:

Port Description
#80 i-8251 data transmission
#81 i-8251 command / status register
#82 (read) i-8251 connection state
#83 (write) i-8251 interrupt mask
#84 i-8253 counter 0
#85 i-8253 counter 1
#86 i-8253 counter 2
#87 (write) i-8253 control register

VDP / Video Display Processor / TMS9918A / v9938 / v9958

These are the I/O registers for accessing the standard MSX VDPs:

Port range Description
#98 VRAM data read/write port
#99 (write) VDP register write port (bit 7=1 in second write)
VRAM address register (bit 7=0 in second write, bit 6: read/write access (0=read))
#99 (read) Status register read port
#9A Palette access port (only v9938/v9958)
#9B Indirect register access port (only v9938/v9958)

See the TMS9918, v9938 and v9958 application manuals for more details.

PSG / AY-3-8910 / YM2149

These are the I/O registers for accessing the MSX PSG (Programmable Sound Generator):

Port range Description
#A0 (write) Register write port
#A1 (write) Value write port
#A2 (read) Value read port

The following table describes the registers of the PSG:

Register(s) Description
0-5 Tone generator control
6 Noise generator control
7 Mixer control-I/O enable
Important note: bit 6 must be 0, and bit 7 must be 1. Setting different values can cause damage on some systems. Safest approach is to just not touch them and read them first before writing a new value.
8-10 Amplitude control
11-13 Envelope generator control
14-15 I/O ports A & B

See the AY-3-8910 and YM2149 application manuals for more details.

Additional PSG I/O ports A & B

The PSG has two additional I/O ports in registers 14 and 15. They are used by the MSX standard for several device I/O related tasks, comparable with the PPI and working more or less in conjunction with it. These are the functions:

PSG I/O port A (r#14) – read-only
Bit Description Comment
0 Input joystick pin 1 0 = up
1 Input joystick pin 2 0 = down
2 Input joystick pin 3 0 = left
3 Input joystick pin 4 0 = right
4 Input joystick pin 6 0 = trigger A
5 Input joystick pin 7 0 = trigger B
6 Japanese keyboard layout bit 1 = JIS, 0 = ANSI/AIUEO/50on
7 Cassette input signal
PSG I/O port B (r#15) – write/read
Bit Description Comment
0 Output joystick port 1, pin 6 Set to 1 to allow input
1 Output joystick port 1, pin 7 Set to 1 to allow input
2 Output joystick port 2, pin 6 Set to 1 to allow input
3 Output joystick port 2, pin 7 Set to 1 to allow input
4 Output joystick port 1, pin 8
5 Output joystick port 2, pin 8
6 Joystick input selection, for r#14 inputs 1 = port 2
7 Kana led control 1 = off

Pause / R800 info (turboR)

This I/O register is only present on MSX turboR computers. Its function differs depending on whether you are reading or writing.

Port range Description
#A7 (read) bit 0: pause switch (1=on)
Works only in R800 mode (connected to WAIT of Z80)
#A7 (write) bit 0: pause LED (1=on)
bit 7: R800 LED (1=on)
Mirror address is #FCB1 in the system RAM.

PPI / Programmable Peripheral Interface / 8255

The PPI controls a number of things in the MSX system, ranging from slot selection through cassette output to interfacing with the keyboard.

Port range Description
#A8 PPI-register A
Primary slot select register.
#A9 (read) PPI-register B
Keyboard matrix row input register.
#AA PPI-register C
Keyboard and cassette interface.
#AB (write) Command register.

Below, we will describe the registers in more detail.

Primary slot select register

The 64k of MSX main memory is divided into four blocks of 16k, referred to as pages. This register controls which primary slot will be mapped to each page of memory.

PPI-register A (#A8)
Bits Description
0-1 Slot for page 0 (#0000-#3FFF)
2-3 Slot for page 1 (#4000-#7FFF)
4-5 Slot for page 2 (#8000-#BFFF)
6-7 Slot for page 3 (#C000-#FFFF)

This register can both be written and be read.

Additionally, each primary slot can and often will be expanded into four secondary slots, also known as subslots. The subslot select register can be found at memory address #FFFF. For more details, go to the secondary slot select register.

Misc PPI controls

With PPI register C you can access the keyboard (including CAPS LED and key click), and control the cassette interface. The precise function of each bit is described in the table below:

PPI-register C (#AA)
Bits Description
0-3 Keyboard matrix row select register.
Matrix row can be read from PPI-register B (#A9).
4 Cassette motor control. 1 = off.
5 Cassette write signal. 1 = high.
6 Keyboard CAPS LED. 1 = off.
7 1-bit key click sound output. 1 = high.

More information about keyboard matrices can be found in the keyboard matrices article.

PPI command register

With this write-only register you can set or reset individual bits in PPI-register C. This is the recommended (fastest) method to use when you want to modify bits 4-7.

PPI command register (#AB)
Bits Description
0 Value to set.
1-3 Bit no. within PPI-register C.
4-6 Not used.
7 Must be 0.

S1990 controller (turboR)

Through these ports you can access the turboR’s S1990 bus controller.

Port range Description
#E4 Register select port
#E5 Register access port
#E6-#E7 (read) 16-bit counter, little endian, running at 255682 Hz
#E6 (write) 16-bit counter reset (write to reset)

S1990 registers
Register Description
5 bit 6: Switch (0=right, 1=left)
6 bit 5: Processor mode (0=R800, 1=Z80)
bit 6: ROM mode (0=DRAM, 1=ROM)
14 Contains last but one byte written to memory
15 Contains last byte written to memory

VDP display mode (MSX2+)

Port Bit Description
#F3 0M3

System flags

This register is a simple memory cell which is preserved after a reset. It is used on the MSX2+ to differentiate between a hard boot (power on) and a soft boot (reset button) by writing a value to it during the boot routine, and check for that value everytime the computer starts. On the turboR, it also indicates whether the Z80 or the R800 has to boot.

Port Bit Description
#F4 5CPU boot mode (1=R800)
7Boot method (1=soft boot, doesn’t show start logo)

System control

Bits to avoid the collision of internal I/O devices with external cartridges. These let the built-in devices be disabled. During the BIOS initialisation, the internal device should be enabled if there is no external device. Applications should not read or set these values.

Write a 1 to enable.

Port Bit Description
#F5 (write) 0Kanji ROM, JIS 1 (see also S1985 MSX-ENGINE)
1Kanji ROM, JIS 2
3Super impose
6Light pen
7CLOCK-IC (MSX2, MSX2+ only implementation)

See MSX turboR Tech Handbook section 2.2.7 & MSX Datapack appendix A.6.

A/V control

Port Bit Description
#F7 0Audio RMixing on(Write)
1Audio LMixing off(Write)
2Video input selection21-pin RGB(Write)
3Synchronous mode switch(Write)
3Video input detectionNo input(Read)
4AV control0: TV(Write)
5Ym control0: TV(Write)
6Ys control0: Super(Write)
7Video select0: TV(Write)

See MSX Datapack appendix A.6 and MSX Technical Data Book section 1.7.9.

Memory Mapper registers

The Z80 used in the MSX has 64k of addressable memory. To be able to use more memory, memory mappers are used in MSX2 computers and above. A memory mapper divides the 64k of RAM into four 16k blocks called pages, into which up to 256 different memory segments can be mapped. Note that these segments are shared – it is possible to map a segment used in page 0 into page 1 as well.

Port range Description
#FC (write) Mapper segment for page 0 (#0000-#3FFF)
#FD (write) Mapper segment for page 1 (#4000-#7FFF)
#FE (write) Mapper segment for page 2 (#8000-#BFFF)
#FF (write) Mapper segment for page 3 (#C000-#FFFF)

Note that reading those registers is not reliable, and should not be done.

Detecting the amount of available memory can be done by writing a unique value into all mapper pages and iterating through them until you see repetition. If the repetition e.g. occurs after 8 pages, there is 128k of RAM available. Usually, you will want to do this with interrupts disabled and also want to restore the original values.

Note about DOS2: MSX-DOS2 provides a set of convenient memory management routines. In a DOS2 environment, you should not access the mapper registers directly, as this will cause various problems. The routines DOS2 offers are very fast, and there should be no reason not to use them.

Panasonic FS-A1FM Modem ROM

The Panasonic FS-A1FM computer has a built-in modem with firmware. On the back of the computer, there is a switch to enable the modem software. This firmware, including a memory-mapped I/O area in the #7FC0-#7FFF range, is located in slot 3-1. I do not know if there is a detection method.

Address range Description
#7FC4 bits 0-3: mapper for #4000-#5FFF area (uses slot 3-3 ROM pages #00-#0F)
bits 4-7: mapper for #6000-#7FFF area (RAM, don’t know how much)
#7FC6 bit 2: modem switch on back of case setting
#7FF9 bit 2: set activates ports 7FF0-7FF7

Secondary slot select register

Each primary slot can and often will be expanded into four secondary slots, also known as subslots. Just like a primary slot, a subslot can also be mapped to one of the four pages in main memory.

The subslot select register can be found at memory address #FFFF, and looks as follows:

Bits Description
0-1 Subslot for page 0 (#0000-#3FFF)
2-3 Subslot for page 1 (#4000-#7FFF)
4-5 Subslot for page 2 (#8000-#BFFF)
6-7 Subslot for page 3 (#C000-#FFFF)

When this register is read, it returns the complement of the previous value written.

It is important to note that the subslot register only affects the primary slot which is selected in page 3 (which the #FFFF address is in). This makes selecting a different subslot in e.g. page 1 a little less than trivial when page 1 doesn’t have the same primary slot as page 3. This involves switching page 1’s slot into page 3, selecting the desired subslot, and switching back the original slot into page 3. All this must be done with interrupts disabled and, logically, from an address not in the #C000-#FFFF range. Don’t forget to take care of the stack as well.

Usually it will be easier to use the BIOS-provided slot select routines (e.g. ENASLT or its DOS equivalent). While on the subject of the BIOS, the easiest method to determine whether a slot is expanded is to read out the EXPTBL system variables. Also, the BIOS maintains a mirror of the value of each primary slot’s subslot register in the SLTTBL system variables.