Altair 8800 computer was equipped with serial board called 88-SIO, or 88-2 SIO. It was a device which allowed connecting other devices using RS-232 interface. From one side it was attached to CPU on at least two ports (most commonly 0x10 and 0x11). The other side was ended with one or two physical ports (allowing to connect one or two devices). Real board supported both hardware and software interrupts.
The following image shows MITS 88-SIO-2 board.
Original manual of MITS 88-SIO serial board can be downloaded at this link.
The plugin emulates only basic functionality of the board. It has the following features:
- allows to connect one device only
- CPU ports can be set manually
- setting of transfer speed, parity, number of stop bits is not supported
Interrupts are not supported yet.
GUI can be seen here:
MITS 88-SIO board is attached to CPU using multiple ports. By default, the used CPU ports are:
- Status port:
- Data port:
The reason why there are multiple “bindings” is that there existed various software which expected specific bindings. The presented default values are the most common ones.
These numbers can be changed in the Settings window:
- A: Attach Status SIO port to some new CPU port. The CPU port must be unique among both Status and Data ports attachments.
- B: Detach Status SIO port from selected CPU port.
- C: Attach Data SIO port to some new CPU port. The CPU port must be unique among both Status and Data ports attachments.
- D: Detach Data SIO port from selected CPU port.
- E: List of CPU ports to which the Status SIO port is attached
- F: Clear the current attachments of the Status SIO port and attach it to default CPU ports
- G: List of CPU ports to which the Data SIO port is attached
- H: Clear the current attachments of the Data SIO port and attach it to default CPU ports
- I: Save the settings and close the dialog
MITS 88-SIO board as emuStudio plugin is a device which does nothing really useful. It just listens (and understands) commands coming from CPU through the I/O ports. The command is either a request for reading or request for writing to the attached device.
Theoretically any device which supports the basic I/O (reading/writing), can be attached to the board. More about plugin internals can be found in programmer’s manual of emuStudio, which is not part of the user documentation.
Usually, attached devices were:
- serial terminal
- line printer
- paper tape reader/punch
In current implementation of Altair 8800 emulator, the only suitable device which can be attached to the board is terminal ADM-3A from Lear Siegler, Inc and which is described in the particular section.
The following table shows all the possible settings of MITS 88-SIO plugin:
|Name||Default value||Valid values||Description|
| || ||> 0 and < 256; X range from 0 upwards||X-th Number of Status Port|
| || ||> 0 and < 256; X range from 0 upwards||X-th Number of Data Port|
As can be seen; the
X represents a number, it’s a way how two SIO ports can be attached to multiple CPU ports.
In order to show something useful, let’s assume that a terminal LSI ADM-3A is attached to the board. Remember, the board only mediates the communication, it does not interpret any of the sent/received characters.
Whole communication between the board (and attached device) and CPU is controlled by programming the two ports: Status port and Data port. The following table shows the ports and how they are used.
|1|| ||Read board status||Not used. Originally used for enabling/disabling interrupts.|
|2|| ||Read data||Write data|
Now, detailed description of the ports follow. Bits are ordered in a byte as follows:
D7 D6 D5 D4 D3 D2 D1 D0
D7 is the most significant bit, and
D0 the least significant bit.
0x18 (preferred is
Controls input/output interrupts enable. If both interrupts are set to be enabled, it only empties transmitter buffer in the device, which was a post-step after interrupts being enabled. However, the plugin does not implement interrupts support.
D7 D6 D5 D4 D3 D2: unused bits
D1 D0: Used for enabling/disabling interrupts. Not used in emuStudio.
Read status of the device.
D7: Output device ready. Always 0 in the emulator.
D6: Not used (always 0).
D5: Data available (for writing to the attached device). Always 0 in the emulator, meaning that no data is pending to be written. Data are written immediately after
D4: Data overflow. Value 1 means a new word of data has been received before the previous word was inputted to the accumulator. In emuStudio, this never happens.
D3: Framing error. Value 1 means that data bit has no valid stop bit. In emuStudio, this never happens.
D2: Parity error. Value 1 means that received parity does not agree with selected parity. In emuStudio, this never happens.
D1: Transmitter buffer empty. Value 1 means that the data word has been received from the attached device and it’s available for reading (from the Data port).
D0: Input device ready. Value 1 means that the CPU can write data to the SIO (that the board is ready). Always 1 in the emulator.
0x19 (preferred is
Write data to the attached device.
Read data from the attached device.
If the attached device sends asynchronously multiple data, the emulated board stores all in a buffer (queue) with unlimited capacity, so no data should be lost and can be read anytime.
In this section it will be shown a small “How to” program terminal using 88-SIO ports.
In emuStudio, it is enough to write data to Port 2, e.g.:
mvi a, 'H' out 11h mvi a, 'i' out 11h
For writing strings, it is more practical to have a procedure.
lxi h, text ; load address of 'text' label to HL call print ; print text hlt ; halt CPU text: db 'Hello, world!',0 ; Procedure for printing text to terminal. ; Input: pair HL must contain the address of the ASCIIZ string print: mov a, m ; load character from HL inx h ; increment HL cpi 0 ; is the character = 0? rz ; yes; quit out 11h ; otherwise; show it jmp print ; and repeat from the beginning
For reading a character, it is required to read the Port 1 until the character is not ready. Then we can read it from Port 2.
; Procedure will read a single character from terminal ; Input: none ; Output: register A will contain the character. getchar: in 10h ; read Port 1 ani 1 ; is data ready ? jz getchar ; not; try again in 11h ; yes; read it (into A register) ret
Now follows an example, which will read a whole line of characters into memory starting at address in
DE pair. The procedure will interpret some control keys, like: backspace and ENTER keys.
lxi h, text ; load address of 'text' label to HL xchg ; DE <-> HL call getline ; read line from the keyboard into DE lxi h, text ; load 'text' address again call print ; print the text on screen hlt ; halt CPU text: ds 30 ; here will be stored the read text ;Procedure for reading a text from keyboard. ;Input: DE = address, where the text should be put after reading ; C = is used internally getline: mvi c, 0 ; register C will be used as a counter of ; read characters next_char: in 10h ; read Port 1: status ani 1 ; is the char ready for reading? jz next_char ; not; try again in 11h ; yes; read it to A register ; now ENTER and Backspace will be interpreted cpi 13 ; ENTER? jz getline_ret ; yes; it means end of input cpi 8 ; Backspace ? jnz save_char ; if not; store the character ; Backspace interpretation mov a, c ; A <- number of read characters cpi 0 ; are we at the beginning? jz next_char ; yes; ignore the backspace dcx d ; not; decrement DE dcr c ; decrement count of read characters mvi a,8 ; "show" the backspace (terminal will ; interpret this by moving the cursor ; to the left by 1 char) out 11h mvi a, 32 ; "clear" the current character on screen ; by a space character (ASCII code 32) out 11h mvi a,8 ; and move the cursor back again out 11h jmp next_char ; jump to next char save_char: ; stores a character into memory at DE out 11h ; show the character in A register stax d ; store it at address DE inx d ; increment DE inr c ; increment number of read characters jmp next_char ; jump to next char getline_ret: ; end of input ; ENTER will be stored as CRLF mvi a,13 ; CR (Carriage Return) stax d ; store the char inx d ; increment DE mvi a, 10 ; LF (Line Feed) stax d ; store the char inx d ; increment DE mvi a, 0 ; char 0 (End-Of-Input) stax d ; store the char ret ; return