The Sanyo MBC550
- Programming the Hardware
- Interrupts provided by Sanyo RAM BIOS
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.
Left: MBC-555 with its original floppy drives. Right: MBC-550 with salvaged Amstrad floppy drives.
The specifications of either MBC are pretty unimpressive:
- 128k, 192k or 256k RAM on the motherboard. With a suitable expansion card the maximum they can address is probably 960k.
- CPU: 8088 at 3.58MHz (NTSC subcarrier frequency). For comparison, the IBM PC uses 4.77MHz, which is (4 * NTSC) / 3.
- Two 5.25" drive bays. An original MBC550 has one drive, while an MBC555 (or an upgraded MBC550) has two.
- Video display approximates CGA — 640×200 pixels text and graphics. MBCs could also be fitted with an add-on card that provided true CGA compatibility at the hardware level.
- Sound is provided by a beeper.
The following connectors are on the back panel:
- Centronics printer port.
- Keyboard socket (5-pin DIN; not IBM compatible).
- Two video connectors - an 8-pin DIN socket for RGB, and a co-axial connector for composite video. On my two, the co-axial connector is standard on one but more like a TV aerial plug on the other.
- There are blanks marked "Line", "Joy Stick / Paddle" [sic] and "External".
All facilities are provided by a single circuit board, with the following chips and connectors:
- The Intel 8088 processor.
- An empty socket for an 8087 coprocessor.
- A HD68A45 (Motorola 6845 clone) to handle video output.
- A M5W1793 (Western Digital 1793 clone) to control the floppy drives.
- An 8k ROM.
- The usual support chips of an Intel chipset:
- 8259 Programmable Interrupt Controller
- 8255 Programmable Peripheral Interface
- 8253 Programmable Interval Timer
- 8251 USART (as opposed to the 8250 UART in the PC)
- A fairly large number of discrete logic chips (soldered to the board) and 4164 RAM chips (half are soldered, half are socketed; the two socketed banks mean the mainboard memory can be 128k, 192k or 256k).
- A standard Shugart floppy drive connector.
- Connections for power (+12v and +5v) and the beeper.
- Three further connectors for expansion. The blanked-off sockets on the back of the MBC correspond to these; an interface board would sit behind the socket and connect to the motherboard. The largest (62 pins) is the expansion bus. The next one (20 pins) is for a serial port. The last one (2 pins) is missing its pins on both my MBCs, and I've no idea what (if anything) it's for. It may be just to provide a keyway for the 20-pin serial port connector.
- A bank of four DIP switches (nos. 2 and 3 on, nos. 1 and 4 off).
The technical manual describes these as:
- Monochrome mixed mode: Three levels of green for graphic programs. Used for test.
- Half intensity.
- Not used.
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.
The Michtron DS-DOS operating system allows the use of 80-track drives rather than the usual 40-track. Drive types are stored in the boot file IO.SYS; the four bytes at offset 67h give the types of up to four floppy drives (0 for 40 track, 1 for 80 track).
The CGA card plugs into the expansion bus connector on the mainboard, and provides the standard 9-pin TTL and composite video connectors.
A larger version of the card existed, which contained a 256k RAM expansion as well as the CGA hardware.
The card is sufficiently similar to a genuine IBM CGA that it displays 'snow' when video memory is accessed while the screen is being refreshed.
An alternative version of MS-DOS was supplied, in which video output was sent to the CGA rather than the built-in video hardware. Michtron's DS-DOS took a different approach; DS-DOS defaulted to the built-in hardware, and the CGA driver VIDEO.COM was a TSR. This approach allowed switching between the two displays without rebooting.
The card has an 8k 2764 ROM. The first 6k is blank; the last 2k contains the 8×8 font.
Oddly, the drivers for both MS-DOS and DS-DOS contain at least some support for the MDA monochrome mode as well as CGA. The card doesn't show any signs of having hardware support for the MDA, and selecting mode 7 does not produce a usable video signal (at least on the display I was using).
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.
The usual operating system for the MBC series is MS-DOS 2.11, in two variants: native video and CGA. Sanyo also distributed MS-DOS 1.25 for native video. In each case, the Sanyo support is in IO.SYS.
Unlike on (for example) the Apricot Xi, IO.SYS attempts to provide a reasonable facsimile of the IBM PC ROM BIOS — video on INT 10h, disk on INT 13h, etc. The MS-DOS devices are then implemented by calls to this RAM BIOS.
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.
An alternative RAM BIOS, known as DS-DOS, was provided by Michtron. This BIOS allows a greater range of disk formats, including 80-track drives and up to 10 sectors per track. It consists of a substitute IO.SYS and a set of utilities; the installer works by copying MSDOS.SYS and COMMAND.COM from a standard MS-DOS 2.11 boot disk onto the DS-DOS disk, to join the IO.SYS already present.
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.
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:
- ICW1 = 13h (Single mode, edge triggered, ICW4 needed)
- ICW2 = 0F8h (use INT F8h - INT FFh)
- ICW3 is not needed since the controller is in single mode
- ICW4 = 0Fh (8086 mode, auto EOI, buffered mode master)
- OCW1 = 0FFh (disable all IRQs)
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:
- Counter 0: 00313h
- Counter 1: 0EA60h
- Counter 2: 0005Dh (1200 bps)
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).
To a programmer, the MBC's video hardware appears as a 6845 chip and three bitmapped graphics planes.
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 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--] ...
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:
- 05 -> Scancode 0Fh (TAB), ASCII 00
- 80-FF -> Scancode 00, ASCII unchanged
- Ctrl+End -> Scancode 75h, ASCII 00
- Ctrl+PgDn -> Scancode 76h, ASCII 00
- Ctrl+Tab -> Scancode 00, ASCII 09
- Ctrl+Enter -> Scancode 75h, ASCII 00
- Ctrl+Home -> Scancode 77h, ASCII 00
- Ctrl+function keys -> Scancode 68h-71h (F21-F30), ASCII 00
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.
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 =====+=====+===================================================================
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. =====+=====+===================================================================
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.
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.
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.
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.
If the version of DOS is for the CGA card, then the INT 10h code drives the CGA rather than the native video adapter. In this case, it's a conventional CGA BIOS without the quirks noted below. Of the extra functions, only AH=74h is supported. In fact, in the version I examined, all functions numbered above AH=0Fh behave like AH=74h — it looks as if a conditional jump has been patched to be unconditional.
- 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", 25x80Unlike 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.
Returns the fixed value 42ECh, corresponding to:
- No floppy drives
- No 8087
- Motherboard fully populated with RAM
- Initial video mode: CGA colour
- 4 floppy drives (and yes, this contradicts the "no floppy drives" above).
- No DMA support
- 1 serial port
- 1 parallel port
Returns the memory size in Kbytes.
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.
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.
This function is not implemented; it returns, leaving all registers unchanged.
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.
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.
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.
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.
A simple wrapper around INT 10h / AH=0Eh.
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.
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.
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.
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).
Triggered by channel 1 of the timer (cursor blink / sound frequency). Does nothing.
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.
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.
John Elliott 27 January 2016