Vintage PC pages
Home -> Vintage PCs -> Sanyo MBC550

The Sanyo MBC550


The Sanyo MBC-550 series is a curiosity - one of the MS-DOS computers that weren't compatible with the IBM PC at a hardware level.

[Picture of two MBCs]

Left: MBC-555 with its original floppy drives. Right: MBC-550 with salvaged Amstrad floppy drives.

The specifications of either MBC are pretty unimpressive:

The following connectors are on the back panel:

Inside the case

All facilities are provided by a single circuit board, with the following chips and connectors:

The floppy drives

The floppy drives in the MBC are fairly standard 5.25" units, but there's one important difference in the way they're configured. They report Drive Ready on pin 34, and the MBC depends on this. Therefore, if you need to replace the drives, you need to find replacements that can be jumpered to report Drive Ready rather than (as on most PCs) Disk Changed. Drives from an Amstrad PC1640 have proved to be suitable replacements; therefore, drives from PC1512s will probably work as well.

The floppy drive cable also lacks a twist, so if you're replacing the A: drive you'll need to set its selection jumpers to drive 0. Once again, the PC1640 has the same cable arrangement so its drives were already set up properly.


ROM loader

Rather than a full ROM BIOS, as on the IBM PC, the MBC has a positively minimal bootloader. Most of the 8k ROM space is empty; there's 1k of keyboard lookup tables, 2k of font (standard Codepage 437 at the 8x8 size), and slightly less than 256 bytes of code. What the code actually does is relatively straightforward -- it initialises some of the hardware, loads cylinder 0 head 0 sector 1 from drive A: at 0038:0000, and jumps to it.


Because there's no ROM BIOS, the boot sector has to access the hardware directly to load the DOS system files. This fact alone would render the MBC unable to boot from normal PC-DOS discs, even without all the hardware differences. The provided boot sector is another reason why the MBC can't handle drives that have changelines; it fails to load IO.SYS, but then jumps to where it thinks it should be, resulting in a crash.

Anyway, once the boot sector has done its work, IO.SYS and MSDOS.SYS have been loaded. IO.SYS comes in two modules: one which mimics (as far as is possible) an IBM ROM BIOS, and a smaller one which parses CONFIG.SYS and launches COMMAND.COM.

The services provided by the RAM BIOS are a mix of standard IBM services, and interrupt handlers for the Sanyo's hardware. They are covered later in this document.

Programming the Hardware

Floppy Disc Controller

The FDC uses the following I/O ports:

Port | Meaning
 08h | WD1793 command register
 0Ah | WD1793 track register
 0Ch | WD1793 sector register
 0Eh | WD1793 data register
 1Ch | Bits 2-0 (read/write) are:
     |   Bit 2:   Head select,  0-1
     |   Bit 1-0: Drive select, 0-3

There is no DMA, and no use of the floppy controller interrupt; all I/O is done by polling.

The currently selected drive has its activity light permanently on.

Interrupt Controller

The interrupt controller is accessed through ports 0 and 2. The first initialisation word (ICW1) is sent to port 0; all other commands to port 2.

The standard initialisation done by the BIOS is:

At the end of BIOS initialisation, OCW1 is set to 0F0h (enable IRQ0-IRQ3 only).

According to the Interrupt List, the IRQ lines are allocated as follows:

IRQ0: 100Hz timer.
IRQ1: Reserved.
IRQ2: Serial character received.
IRQ3: Keyboard character received.
IRQ4: Parallel port ready
IRQ5: Floppy controller
IRQ6: 8087 coprocessor
IRQ7: User interrupt


There is a 100Hz timer interrupt; this corresponds to IRQ0 (INT 0F8h).

The 8253 timer is at ports 20h-26h:

Port | R/W | Purpose
 20h | R,W | 8253, counter 0. 
 22h | R,W | 8253, counter 1 - used for cursor blink and beeper tone. 
 24h | R,W | 8253, counter 2 - used for serial port baud rate. 
 26h |  W  | 8253, control word.

At BIOS initialisation, the counters are initialised as follows:

According to the technical manual, the counter 0 has a base frequency of 78.6KHz; counter 1 is based on the output of counter 0, so is normally 100Hz; and counter 2 is based at 1.78977MHz. The value to write to the counter for a given baud rate is calculated as 59658 / ((speed/30)*16).

Video Controller

To a programmer, the MBC's video hardware appears as a 6845 chip and three bitmapped graphics planes.

The 6845

The 6845 appears at I/O ports 30h (register select) and 32h (data). At system boot, it is programmed for 25 lines x 72 columns. The RAM BIOS then reprograms it for 25 x 80. The ROM also provides timings for what appears to be a different 80-column mode; it decides which to use by reading port 1Ch. If bit 7 of the result is 1, the 72-column mode is used; otherwise, the 80-column mode is.

Here are the values written to the 6845 in each case, plus (for comparison) the values used by a real CGA:

    6845 Register            | IO.SYS | ROM 80 | ROM 72 | Real CGA
    Horizontal total         |  112   |  101   |  112   |    83
    Horizontal display end   |   80   |   80   |   72   |    80
    Horizontal sync pos      |   89   |   83   |   85   |    81
    Horizontal sync width    |   72   |   72   |   74   |     1
    Vertical total           |   65   |  105   |   65   |    26
    Vertical total adjust    |    0   |    2   |    0   |     0
    Vertical displayed       |   50   |  100   |   50   |    26
    Vertical sync position   |   56   |  100   |   56   |    25
    Interlace                |    0   |    0   |    0   |     2
    Max scan address         |    3   |    3   |    3   |     7
    Cursor start             |    0   |    0   |    0   |     6
    Cursor end               |    0   |    0   |    0   |     7

The important thing to note here is that from the 6845's point of view, a character is 4 lines high. This explains why the framebuffer memory is mapped as it is.

The framebuffers

The MBC video RAM is composed of three planes - green, red and blue. The green plane occupies main memory, and its position varies; writes to port 10h set its address:

Value | Address
    4 | 0C000h
    5 | 1C000h     (other values have not been tested)
    6 | 2C000h
    7 | 3C000h

The red and blue planes appear to have fixed locations of F0000h and F4000h respectively.

When output goes to a composite monitor, the green plane is usually used by itself. The red plane becomes "blink", causing pixels in it to blink; and the blue plane becomes "bright".

Within each plane, memory is organised as 50 rows of 320 bytes (288 bytes in 72-column mode). This corresponds to a rectangle, 640 (576) pixels wide and four pixels high. The first four bytes give the leftmost column of the rectangle, the next four give the next column, and so on:

[--byte 0--] [--byte 4--] [--byte  8--] [--byte 12--] ...
[--byte 1--] [--byte 5--] [--byte  9--] [--byte 13--] ...
[--byte 2--] [--byte 6--] [--byte 10--] [--byte 14--] ...
[--byte 3--] [--byte 7--] [--byte 11--] [--byte 15--] ...

Keyboard I/O

The keyboard and beeper are connected through the 8251 USART on the motherboard.

Port | R/W | Purpose
 38h |  R  | Scancode received. 
 38h |  W  | Beep frequency. To make a beep, wait until bit 0 of port 3Ah
     |     |   goes high, and then write the frequency to this port. The 
     |     |   standard "beep" command in the RAM BIOS does this ten times 
     |     |   with frequency 0.
 3Ah |  R  | 8251 USART status status 
     |     |   Bit 7: DSR
     |     |   Bit 6: Break detected
     |     |   Bit 5: Framing error
     |     |   Bit 4: Overrun error
     |     |   Bit 3: Parity error  (CTRL pressed)
     |     |   Bit 2: TxEmpty
     |     |   Bit 1: Character received
     |     |   Bit 0: Ready to transmit
 3Ah |  W  | 8251 command / mode byte.
     |     |   The RAM BIOS never does a full USART reset; it just writes 35h 
     |     |   (enable transmit and receive, DTR inactive, RTS active)
     |     |   initially and after each character is received. 

The scancodes received appear to correspond to ASCII, with keys producing different scancodes in different shift states. For example, key 1 produces 31h ('1') unshifted, but 21h ('!') shifted. Scancodes are:

00: -
01: End
02: Page Down
03: Scroll Lock / Break
04: Page Up
05: Backtab?
06: -
07: Ins / Print Screen
08: Backspace
09: Tab
0A: Enter
0B: Home
0C: -
0D: Return
0E: -
0F: -
10-19: F1-F10
1A: -
1B: Esc
1C: Cursor left
1D: Cursor right
1E: Cursor up
1F: Cursor down
20-7E: ASCII characters SPACE to ~
7F: Del
80-FF: Graphical characters

The keyboard translation table (which converts Sanyo scancodes to PC-compatible scancode+character pairs) is at the start of the ROM (0FE000h). It contains 512 words; the first 256 are for when the CTRL key is up, and the second 256 for when it is down.

Notable mappings in this table include:

In general, Ctrl+key or Ctrl+Shift+key translates to a scancode of 54h or higher and an ASCII value of 0. The exceptions are the letter keys, which produce their normal IBM-compatible scancodes and the expected ASCII value in the range 01h-1Ah.

According to the technical manual, the keyboard operates at 1200 baud, with 8 data bits, 2 stop bits and even parity. Key repeat is handled within the keyboard.

Serial I/O

The RAM BIOS includes code to drive a serial port, though no serial port is present on my MBC. There is a 20-pin connector on the motherboard beside the 8251; this corresponds to the serial port, which appears to consist of a daughterboard plugged into this connector.

The serial port code uses channel 2 of the 8253 timer (for the baud rate) and an 8251 at ports 28h-2Ah:

Port | R/W | Purpose
 28h |  R  | Byte received
 28h |  W  | Byte to transmit
 2Ah |  R  | 8251 USART status 
     |     |   Bit 7: DSR
     |     |   Bit 6: Break detected
     |     |   Bit 5: Framing error
     |     |   Bit 4: Overrun error
     |     |   Bit 3: Parity error
     |     |   Bit 2: TxEmpty
     |     |   Bit 1: Character received
     |     |   Bit 0: Ready to transmit
 2Ah |  W  | 8251 command / mode byte
     |     |   To do a mode set, the RAM BIOS writes three zeroes (to flush
     |     |   any existing command); then 40h (reset); then the mode byte;
     |     |   then 37h (return to normal, with ~RTS and ~DTR active).  
     |     | The mode byte is:
     |     |   Bits 7-6: Stop bits (0=>None,1=>1,  2=>1.5, 3=>2)
     |     |   Bits 5-4: Parity    (0=>None,1=>Odd,2=>None,3=>Even)
     |     |   Bits 3-2: Data bits (0=>5,   1=>6,  2=>7,   3=>8)
     |     |   Bits 0-1: Baud rate factor. MBC always uses 2 (16x).
     |     | The command byte is:
     |     |   Bit 7: Hunt mode (always 0)
     |     |   Bit 6: Reset
     |     |   Bit 5: If 1, ~RTS is 0 (ie, ready). If 0, ~RTS is 1 (not ready).
     |     |   Bit 4: Reset error flag
     |     |   Bit 3: Send break
     |     |   Bit 2: Enable receive
     |     |   Bit 1: If 1, ~DTR is 0 (ie, ready). If 0, ~DTR is 1 (not ready).
     |     |   Bit 0: Enable transmit

Parallel I/O

The parallel port lives at addresses 1Ah, 1Ch and 1Eh, and uses ports B and C of the 8255 PPI.

Port | R/W | Purpose
 1Ah |  W  | Data lines (inverted, so A would be written as ~41h = 0BEh).
 1Ch |  R  | Parallel port status. As mentioned elsewhere in this document,
     |     | other bits of this port give other settings:
     |     |   Bit 7:    Initial video mode; 0 = 80-column 1=72-column
     |     |             According to the technical manual, this value 
     |     |             comes from motherboard switch SW2. I can't find this 
     |     |             switch on my MBC; the existing switch is marked SW1.
     |     |   Bit 6:    Parallel port status: Selected
     |     |   Bit 5:    Parallel port status: Paper out
     |     |   Bit 4:    Parallel port status: ~Busy
     |     |   Bit 3:    According to the technical manual, printer strobe.
     |     |   Bit 2:    Head select, 0 or 1.
     |     |   Bits 1-0: Currently selected floppy drive.
 1Eh |  W  | PPI control port - used to activate / deactivate the parallel 
     |     | port strobe. To activate ~STROBE, 7 is written (making port 1Ch
     |     | an output port) and to deactivate it, 6 is written (changing it
     |     | back to an input port).
     |     | The boot ROM writes 98h to this port to initialise the PPI.

Joystick port

According to the technical manual, the joystick port is also handled by the PPI. The diagram is somewhat obscure; it appears to show the top 4 bits of the value read being treated as an analogue value, while the bottom 4 bits come straight from the port.

The byte written to the printer port (1Ah) also controls the joystick port in some way. Bits 0-5 are sent to the connector; bit 7 is marked "A/D trigger" and feeds into the A/D converter.

Interrupts provided by Sanyo RAM BIOS

The Sanyo RAM BIOS (I'm working from version 2.02) provides the following services. Beware: other operating systems, or even other DOS versions on the same computer, may not implement some or any of these.

Calling any interrupt not mentioned in this table will stop the system with an "Interrupt Trap Halt" message.

INT 05h (Print Screen)

Performs a simple text screendump. Rather than read the graphical screen, it prints the contents of the text buffer maintained by the BIOS; so characters written directly to the graphics memory will not appear.

INT 08h (Timer)

Does nothing.

INT 09h (Keyboard)

Does nothing.

INT 10h (Video)

The functions provided by INT 10h attempt to imitate a CGA. They are not always successful in this aim. In general, if a function has very little documentation in the list below, it means it behaves like the standard PC function with the same number. The more documentation, the more differences.

Selects video mode in AL. The modes are roughly similar to those on a real CGA:
	Mode number   Characteristics
	0             "Black/white", 25x40
	1             "Colour",      25x40
	2             "Black/white", 25x80
	3             "Colour",      25x80
	4             "Colour",      25x40   
	5             "Black/white", 25x40    
	6             "Black/white", 25x80    
	7             "Black/white", 25x80    
Unlike on a real CGA, there's no distinction between text and graphics modes. The difference between "Black/White" and "Colour" modes is how character attributes are drawn, rather than any changes to hardware registers. See AH=9 for the details.
Sets cursor shape in CX. There are only three cases:
  • If CH=26h, disable cursor
  • If CX=0107h and the cursor is visible, quadruple the blink rate so that it flickers madly.
  • Otherwise, enable the cursor at the normal blink rate.
Set cursor position
Get cursor position and size. Returns the size requested (by default, 0067h) - as mentioned for AH=01h, the size in use never actually changes.
Read light pen - returns AX=0 and leaves other registers unchanged.
Select active display page in AL. Also resets the CRTC registers to default values. On a 128k MBC, multiple display pages are not supported. On the MBC, the graphical framebuffer only holds the current display page, so switching pages causes the selected page to be redrawn from a text buffer.
Scroll rectangle up. Appears to be buggy in 40-column modes.
Scroll rectangle down. Appears to be buggy in 40-column modes.
Read character and attribute. In mode 6, this reads the bitmap from the video RAM and attempts to match it against the current font; in other modes, it retrieves the character last written to that position.
Write character and attribute. The attribute is handled differently in the different modes:
	Bit 7:    Blink (b/w modes only)
	Bits 4-6: Background.
	Bit 3:    Bright (b/w modes only)
	Bits 0-2: Foreground.

In the "B/W" modes 0, 2 and 5-7, all background and foreground combinations involving colours other than 0 and 7 display as white on black. Additionally, attribute 01h (only) displays as underlined.

In the "colour" modes 1, 3 and 4, the "Blink" and "Bright" bits are ignored, and the background and foreground colours are used.

Write character only.
Set palette or border. Only has an effect in mode 4, with BH=1 (set palette). If palette is zero, blanks out the blue plane. Otherwise sets the blue plane to the binary OR of the red and green planes.
Write pixel. Works in all modes.
Read pixel. Works in all modes.
Write character in terminal mode.
Get current mode.
Return framebuffer addresses. Returns:
		AX:BX -> A word containing the offset of the green plane.	
		AX:CX -> A word containing the segment of the green plane.	
		AX:DX -> A word containing the segment of the red and
			   blue planes. Red is at seg:0000, blue at seg:4000.
Return text buffer addresses. Returns:
		AX:BX -> A word containing the segment of all text buffers.
		AX:CX -> 8 words containing the offsets of up to 8 text
                           buffers, one for each screen page.
Scroll rectangle right. As with the other scrolling functions, this does not appear to work well in the 40-column modes. Parameters are the same as for AH=06h.
Scroll rectangle left. As with the other scrolling functions, this does not appear to work well in the 40-column modes. Parameters are the same as for AH=06h.
Manage codepages. The BIOS supports 8 screen fonts, and 8 keyboard layouts; at startup, all of them point to the copies in the boot ROM. AL describes what to do, as follows:
	Bits 0-2 give the codepage number, 0-7.
	Bits 3-4 say what the codepage applies to.
		0      => Keyboard layout only
		1      => Screen font only
		2 or 3 => Both
	If bit 5 is set: Select the specified layout/font as current.
	Otherwise, bits 7 and 6 give the operation to perform.
		0 => Normalise the address of the specified layout/font.
		1 => Normalise the address, and select it as current.
		2 => Set the address of the specified layout/font. Note
			that the codepage number must be 4-7; codepages 0-3 
			cannot be overridden. 
			BX = segment of new font (if setting font)
			DX = segment of new keyboard layout (if setting layout)
		3 => Set the address as above, and select as current.

INT 11h (Equipment list)

Returns the fixed value 42ECh, corresponding to:

INT 12h (Memory size)

Returns the memory size in Kbytes.

INT 13h (Disk)

Supports functions 0-4 only, for floppy drives. There is no hard drive support.

Attempting to read/write sectors across multiple tracks does not appear to be a good idea; it appears to use bit 1 of the passed head number to tell it whether the disc has 8 or 9 sectors.

INT 14h (Serial)

This implements functions 0-3 of the standard INT 14h (serial) API. It only supports one serial port, so the value in DX (selecting which port to use) is ignored. Also, the "modem status" returned by AH=3 is largely fictitious, as the 8251 doesn't return many of the required signals.

INT 15h (Cassette)

This function is not implemented; it returns, leaving all registers unchanged.

INT 16h (Keyboard)

Supports functions 0, 1 and 2. Functions 0 (get keystroke) and 1 (check for keystroke) behave pretty much the same as usual; function 2 (get shift state) always returns 0.

INT 17h (Printer)

Supports functions 0, 1 and 2, pretty much as standard. It only supports one printer, so the value in DX (selecting which port to use) is ignored.

INT 1Ah (Timer)

These get and set the system clock tick count. The low word actually only goes up to 0FFAEh before rolling over, to make the high word correspond to a fairly exact count of hours. Also, the low bit of the count is always zero; it's updated at a rate more like 9.1Hz than 18.2Hz, and to match the rate of an IBM PC each update increases the count by 2.

INT 1Bh (Control-Break)

Does nothing.

INT 1Ch (Tick)

Does nothing.

INT 1Dh (Video parameters)

Points at a 16-byte table of 6845 registers for the one and only video mode, rather than the 88-byte table you'd find on a PC.

INT 29h (Fast character output)

A simple wrapper around INT 10h / AH=0Eh.

INT EDh (Cursor blink)

Called by the INT 16h handler before attempting to read the keyboard. It uses counter 1 of the 8253 timer to blink the text cursor if necessary.

INT EEh (Enable serial)

Called by the floppy drive code after sector read/write. It attempts to catch up on missed timer interrupts, and re-enables the DTR and RTS lines of the serial port.

INT EFh (Disable serial)

Called by the floppy drive code before a sector read/write. It disables the DTR and RTS lines of the serial port, preventing serial I/O during sector access. Use of this interrupt means that GEM cannot be run on an unpatched MBC; a patch exists which moves it to INT F0h. Since GEM doesn't have a driver for the MBC's onboard video, this also requires a CGA board to be fitted.

INT F8h (IRQ0, Timer 0)

Handles the 100Hz timer. Every eleventh tick it calls INT 8 and INT 1Ch; this is about half as often as on a real IBM PC (9.1Hz rather than 18.2Hz).

INT F9h (IRQ1, Timer 1)

Triggered by channel 1 of the timer (cursor blink / sound frequency). Does nothing.

INT FAh (IRQ2, Serial)

This interrupt is called when the serial port has a character ready. The serial port read (INT 14h AH=2) waits until a character is received, calls this interrupt to add it to the receive buffer, and then returns the buffered character.

INT FBh (IRQ3, Keyboard)

This interrupt is called when the keyboard has a character ready. It translates the scancode and calls INT 9 (the default implementation of which does nothing); then adds the scancode to the keyboard buffer.

INT F4h (IRQ4, Parallel port)

Does nothing.

INT FDh (IRQ5, Floppy controller)

Does nothing.

INT FEh (IRQ6, 8087)

Does nothing.

INT FFh (IRQ7, user interrupt)

Does nothing.

John Elliott 30 April 2006