Written by Kevin Cole ( 2020.10.18

These instructions will provide users with the ability to use their own Linux computer to:

  • write programs for the Altair using meaningful mnemonics (abbreviations) for the machine instructions instead of toggling binary numbers into switches,

  • assemble those programs from source code file (the meaningful mnemonics) into executable object code file, which consists of the binary numbers that would have been toggled in,

  • produce a list file which is a report showing both the source code and the corresponding binary machine code, as well as a list of errors, and other useful information regarding the assembly of the source code,

  • test the code in an Altair software simulator running on their computer,

  • establish communications between their Linux computer and the Altair,

  • send executable object code files to the Altair,

  • and, send data from their Linux computer to the Altair and receive data back.

Beginners should start with a computer running the Raspberry Pi Desktop operating system.


First, start by install the Macroassembler AS. Go to the download page and download the latest beta version of the C Sources Click the as bz2 link at the end of the first line in the list.

To build and install, your system will also need LaTeX, which is part of the texlive package.


  1. The steps below assume you are running on a Linux system that has all of the programs needed to build the application and its documentation. If you are running the Raspberry Pi Desktop operating system, everything is fine. You can proceed without worry.

  2. The make docs step below will complain 10 or 11 times that it is missing the file german.sty. Unless you need the documentation in German, you can safely ignore the error. Just press ENTER each time it complains.

  3. make install (as of 2021.09.13) has introduced an error saying it cannot create directory ‘/usr/local/include/asl/.’ because it already exists, but the error can safely be ignored. (I have submitted a fix which may be accepted by the time you read this.)

  4. If you are NOT on a system running the Raspberry Pi Desktop, see the INSTALL document for more gory, hoary details regarding other systems and customization.

  5. The last step below removes the broken German documentation.

Type the following:

$ sudo apt update
$ sudo apt install texlive texlive-latex-extra
$ cd ~/Downloads
$ wget
$ tar xjvf asl-current.tar.bz2
$ cd asl-current
$ cp -v Makefile.def-samples/Makefile.def-unknown-linux Makefile.def
$ make
$ make test
$ make docs
$ sudo make install
$ sudo rm /usr/local/doc/asl/as_DE.*

Next, obtain:

  • an old-school communications program (minicom),

  • a file transfer protocol add-on (gkermit) for minicom,

  • a software Altair simulator (simh) and

  • everyone’s favorite pager (most). See below: It comes in handy.

You can probably skip gkermit but it “rounds out” minicom which, by default wants to have a version of Kermit “at the ready”, even if the Altair won’t use it. Install them all with:

$ sudo apt update
$ sudo apt install minicom gkermit simh most


Then using your favorite editor – even if it isn’t emacs – create an assembler source file, program.asm for example. To understand the syntax of the source file, study:

For example, the source code below is an assembler language version of the addition program from Part 3, Section B of this manual that was toggled into the front panel.

; NAME:    add.asm
; AUTHOR:  Kevin Cole ("The Ubuntourist") <>
; LASTMOD: 2020.10.06 (kjc)
;     This is the assembly source code that produces the same machine
;     op codes as shown by the first example (add two numbers) in the
;     Altair 8800 Operator's Manual.

; Code segment:

        ORG    0o       ; Set Program Counter to address 0
START:  LDA    VAL1     ; Load value (5) at VAL1 (200) into Accumulator
        MOV    B,A      ; Move value in Accumulator to Register B
        LDA    VAL2     ; Load value (8) at VAL2 (201) into Accumulator
        ADD    B        ; Add value in Register B to value in Accumulator
        STA    SUM      ; Store accumulator at SUM (202)
        JMP    START    ; Jump to start of code (infinite loop)

; Data segment:

        ORG    200o     ; Set Program Counter to address 200
VAL1:   DB     5o       ; Data Byte at address 200 = 5
VAL2:   DB     10o      ; Data Byte at address 201 = 8 (10 octal)
SUM:    DB     0o       ; Data Byte at address 202 = 0

        END             ; End

Assemble it with:

$ asl -a -cpu 8080 -L -listradix 8 program.asm

which produces a list report (program.lst) and an object file (program.p) Compare the generated list file to the octal machine op codes provided in the manual.

However, if you have installed most – you know you want it – it is VERY instructive to instead assemble the source file with the command:

$ asl -a -cpu 8080 -L -listradix 16 program.asm

This produces the same binary file (program.p) as in the first command but changes the format of the list file, displaying the machine op codes in hexadecimal, rather than octal, and, together with the command:

$ most program.p

you can study the actual binary “executable” produced, and “debug” it by finding the machine op codes (in hex) embedded in the executable (by comparing it to program.lst).

Whichever way you assemble, you’ll want to produce a program.bin and program.hex file by issuing:

$ p2hex program.p
$ p2bin program.p

(Look at both the .bin and .hex files with most and compare that with what you see in the .p and hexadecimal list file.)


The simh Debian package simulates at least 30 different architectures – including seven others besides the Altair that I had the pleasure of spending time with.

Each simulator is started with a separate program. The Altair simulator is named, logically enough, altair. In order to use it:

  1. Start the siimulator (altair).

  2. As on the front panel of the actual machine, reset (reset all).

  3. Load your binary file into the simulator’s “memory” (load program.bin).

  4. Start the program running (run).

  5. If the program does not finish and stop on its own, you need to stop the simulation by pressing Ctrl-E (which will display as ^E).

  6. Examine memory locations with e followed by the address, or read up and experiment with other simulator commands shown by the help command.

  7. When finished, type exit.

Using the addition program above as an example, enter the following:

$ altair

Altair 8800 simulator V3.8-1
sim> reset all
sim> load program.bin
131 Bytes loaded.
sim> run

Simulation stopped, PC: 000004 (LDA 201)
sim> e 202
202:    015
PC:     000004
sim> exit

The second examine (e) command above lists the registers and other useful locations.

simh register and status flags




Program Counter




Register Pair BC


Register Pair DE


Register Pair HL


Carry flag


Zero flag


Auxillary Carry flag


Parity flag


Sign flag


Front Panel switches


Breakpoint address


Interrupt character

There are LOTS of other commands to the simulator, but the above gets the basic job done. Ctrl-E stops the program currently running in the simulator, and reports the current program counter (PC) and the instruction being executed when stopped.

If you were running the program shown above, the list file tells us that data byte (DB) labeled SUM is at memory address 202 (octal). Using the simulator’s e command to examine that address reveals that it contains the data value 015 (octal).


You should remember that the program above (the add two numbers program from Part 3, Section B) is an infinite loop and is repeating the code over and over again very quickly.


When you stop the simulation by pressing Ctrl-E there is no way to know which instruction was being executed at the time. This means that the Program Counter PC and the instruction it is pointing to will vary with every running of the simulation – unless you are a supercomputer yourself and have incredibly quick reflexes.


In my example above, you can see that the Program Counter was at 000004 and executing the instruction LDA 201 when the simulation was stopped, but it will likely be different for you.


The 131 Bytes loaded. above is in decimal. Counting in octal, that would be 203 bytes. You will note that the program starts at memory address 000 (octal), and that the sum of the addition, which is the last byte of memory that the program uses, is at memory address 202 (octal). In other words, the program is contained in the first 203 (octal) bytes of memory – though bytes between byte 015 (octal) in memory, which is the last byte of actual instruction code, and byte 200 (octal) where the first value to be added is stored, are unused, and therefore those bytes are uninitialized, and will contain unpredictable random values.

A summary of the more useful simulator commands provided by the help command:

Useful simh commands

r{eset} {ALL|<device>}

reset simulator

e{xamine} <list>

examine memory or registers

ie{xamine} <list>

interactive examine memory or registers

d{eposit} <list> <val>

deposit in memory or registers

id{eposit} <list>

interactive deposit in memory or registers

ev{aluate} <expr>

evaluate symbolic expression

ru{n} {new PC}

reset and start simulation

go {new PC}

start simulation

s{tep} {n}

simulate n instructions


The simh Debian package is hopelessly out of date, and if your programs become complex enough – for example, trying to load the entire CP/M operating system into the simulator – it will barf. Newer versions are available from both the Altair clone site and the GitHub repository.


After unboxing, plugging in and powering up, the status is:

  • inte

  • prot

  • MEMR

  • inp

  • M1

  • out

  • hlta

  • stack

  • WO

  • int

  • WAIT

  • hlda

where the upper-case, bold represents the LEDs that are “ON” and the lower-case represents the LEDs that are “OFF”.

Plug the serial cable into both the TOP port on the back of the Altair and any USB port on the Linux box. Then issue the command lsusb. A new USB device should appear in the list:

Bus 003 Device 002: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port

In addition, after plugging the cable in, you should see two new entries in the /dev directory: a /dev/ttyUSB0 device and a /dev/serial/ directory. It’s that /dev/ttyUSB0 we’re looking for.


First, verify that your system identifies the cable as /dev/ttyUSB0. (This can vary from computer to computer, particularly depending upon what you have plugged in at the time.) The only way I know of to do this is, both before and after plugging in the cable, issue the command:

$ ls /dev/tty*

and check for the differences between the two. There should be a new /dev/ttyUSB0 or /dev/ttyUSB1 – or possibly another number, depending upon the number of other USB devices plugged in and identifying themselves as a terminals. [I have also seen systems that use /dev/ttyACM0 (or 1, or 2, etc.) to identify USB devices capable of communicating like a terminal.]


If you intend to connect the Altair 8800 clone to the same computer frequently, it may be worth setting up a udev rule. Create a file named 99-local.rules in /etc/udev/rules.d/ as follows:

$ sudo cat > /etc/udev/rules.d/99-local.rules <<EOF
# Written by Kevin Cole <> 2020.10.19 (kjc)
# Custom udev rules

# Create a symlink ALTAIR for Prolific Technology USB-Serial Controller
# (idVendor=067b, idProduct=2303, driver=pl2303)
# Determined via:
#     $ udevadm info -a -n /dev/ttyUSB0 | grep -i "driver"
SUBSYSTEMS=="usb",      \
    DRIVERS=="pl2303",  \
$ sudo udevadm control --reload-rules && sudo udevadm trigger

The serial attribute can be determined via:

$ udevadm info -a -n /dev/ttyUSB0 | grep "[\{]serial[\}]"

and ATTRS{serial}=="..." used in place of DRIVERS--"pl2303" but, since the serial attribute changes each time it is put in a new USB slot, using the drive identification is, I hope more practical.

minicom has a perverse sense of humor when it comes to writing its configuration files in a sane way. So one has to do some stupid dancing to get it to put a configuration file where you want it. You can fight with it, or just edit mine to suit your needs. (See the ~/.minirc.altair section below. To fight with it:

$ sudo usermod -aG dialout kjcole
$ cp /usr/share/doc/minicom/examples/minirc.dfl ~/.minirc.altair
$ sudo minicom --setup altair
Filenames and paths
   A - Download directory: ~/Downloads
   B - Upload directory: ~/Code/Altair
   C - Script directory:
   D - Script program: runscript
   E - Kermit program: gkermit
   F - Logging options:
       A - File name (empty=disable) : minicom.log
       B - Log connects and hangups  : Yes
       C - Log file transfers        : Yes
File transfer protocols:
   G kermit   /usr/bin/gkermit -i -s
   H kermit   /usr/bin/gkermit -i -r
Serial port setup
   A - Serial Device         : /dev/ttyUSB0
   B - Lockfile Location     : /var/lock
   C - Callin Program        :
   D - Callout Program       :
   E - BPS/Parity/Bits       : 115200 8N1
   F - Hardware Flow Control : Yes
   G - Software Flow Control : No
Save setup as altair
Exit from Minicom
$ cp /etc/minicom/minirc.altair ~/.minirc.altair
$ sudo rm /etc/minicom/minirc.altair


If you’ve successfully created the udev rule, you should use /dev/ALTAIR as the serial device above, as it will be more reliable across reboots.

At this point, one should be able to edit ~/.minirc.altair directly, though there’s not any documentation on the file format.


Edit your updir and downdir to suit. (You probably don’t want to try putting it in MY home directory.)

# Minicom Altair 8800 Clone configuration
# Last edited by Kevin Cole <> 2020.10.18

pu pprog7           /usr/bin/gkermit -i -s
pu pprog8           /usr/bin/gkermit -i -r
pu port             /dev/ALTAIR
pu baudrate         9600
pu kermit           gkermit
pu updir            /home/kjcole/Code/Altair/
pu downdir          /home/kjcole/Downloads/


Once you have the above in your home directory, you are now ready to load code into the Altair:

$ minicom altair
Welcome to minicom 2.7.1

Compiled on Dec 23 2019, 02:06:26.
Port /dev/ALTAIR, 08:32:24

Press CTRL-A Z for help on special keys

Now, on the Altair front panel, raise and hold the STOP switch, and while holding, raise and release the left AUX switch, and finally, release the STOP. You should see, in the minicom window:

=== Configuration Monitor 1.94 ===

1) Floppies
2) PROMs
3) Serial Ports
4) Load .BIN
5) Load .HEX
6) Admin
x) Exit to Altair


I have found it slightly easier to load the .hex files. Loading .bin files requires the extra step of telling the Altair what address to start loading the file at. (The .hex file has this information embedded into it.)

Choice: 5

Send .hex file now...
Ctrl-A S

Ctrl-A, followed by S brings up the Send file dialog.

  • Choose ascii as the file transfer protocol

  • G ([Goto]) followed by the full directory path from your home

    directory to navigate to the .hex file. For example, if program.hex lives in /home/kjcole/Code/Altair/Assembler, use Code/Altair/Assembler (This step becomes unnecessary if you configured your upload directory to point to a directory where you keep all your Altair files.)

  • Type S (for [Show]) to narrow the filename pattern or scroll to the appropriate file and press SPACE which should highlight it, and then, either O or ENTER (for [Okay], which should already be highlighted.)

You should see something like:

+------------[ascii upload - Press CTRL-C to quit]------------+
|ASCII upload of "program.hex"                                |
|                                                             |
|0.2 Kbytes transferred at 194 CPS... Done.                   |
|                                                             |
| READY: press any key to continue...                         |
|                                                             |
|                                                             |
  • Press ENTER (or, as it says, any key) and then x to Exit to Altair Like so:

    0219h bytes loaded at 0000h
    === Configuration Monitor 1.94 ===
    1) Floppies
    2) PROMs
    3) Serial Ports
    4) Load .BIN
    5) Load .HEX
    6) Admin
    x) Exit to Altair
    Choice: x
    Control Returned to Altair

Finally, assuming you loaded the program at 000, press the RUN switch on the Altair clone and you should be “off to the races”.

To exit minicom and return to the Bash shell, type Ctrl-A followed by Q.


A Makefile will automate the production of the two list reports, object file, BIN file and HEX file, and even let you assemble several source files at once. The following Makefile accepts the commands:

make options


Assemble all .asm files in current directory

make program

Assemble program.asm

make clean

Remove all generated files for all asm

IMPORTANT: make likes TAB not SPACE. Change all occurances of eight consecutive spaces to tabs in the code below!

#!/usr/bin/make -f
# Written by Kevin Cole <> 2020.10.17 (kjc)
# This takes Altair-8800 assembler source files and produces:
#    - an object file                                 (.p)
#    - an Intel HEX file                              (.hex)
#    - a  binary executable                           (.bin)
#    - a  list report file with octal       op codes  (.oct.lst)
#    - a  list report file with hexadecimal op codes  (.oct.lst)
#    - an include(?) file -- thus far, empty          (.inc)
# To use:
#        make         # to generate for all .asm files
# or     make root    # (where "root" is the root of a specific "root.asm")
# or     make clean   # to remove all generated files

SHELL = /bin/bash
OBJECTS := $(patsubst %.asm,%,$(wildcard *.asm))

.PHONY : all
all : $(OBJECTS)

.PHONY : clean
clean :
        -rm -f *.hex         \
               *.bin         \
               *.lst         \
               *.inc         \

% : %.asm
        asl -a -cpu 8080 -L -listradix  8 $<
        mv $@.lst $@.oct.lst
        asl -a -cpu 8080 -L -listradix 16 $<
        mv $@.lst $@.hex.lst
        p2hex $@.p
        p2bin $@.p


If you’re going blind trying to read the blinky lights and make sense out of them, and would just rather see text (and/or if you’d like to be able to type strings of input rather than toggle strings, eight bits at a time), you will need to dig deeper into the mechanics of the 88-2SIO Serial I/O hardware, which is not covered in any of the manuals you’ve encountered so far.

In order to understand communications between the Altair and an external device like a terminal, connected via the serial / USB cable, the above documents should be perused pondered. They provide details like:

HEX record layout


Universal Asynchronous Recever / Transmitter


Transmit (OUT)


Receive (IN)


Request to Send

And settings for synchronous (polled) communication:

15H = 0 0 0 1 0 1 0 1
      ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
      │ │ │ │ │ │ │ │
      │ │ │ │ │ │ └─┴─► 1 = Clock Divide = 16
      │ │ │ └─┴─┴─────► 5 = 8 Data bits, No parity, 1 Stop bit (8N1)
      │ └─┴───────────► 0 = RTS = Low, XMIT interrupt = disabled
      └───────────────► 0 = RECV interrupt = disabled


Starting with Chapter 6: Utility Programs in the Macroassembler AS manual (page 251).

Working from the object file produced from add.asm


plist summarizes .p file data:

$ plist add.p
PLIST/C V1.42 Beta [Bld 174]
(C) 1992,2020 Alfred Arnold

Code-Type   Segment    Start-Address  Length (Bytes) End-Address
8080/8085     CODE      00000000          000E       0000000D
8080/8085     CODE      00000080          0003       00000082
creator : AS 1.42 Beta [Bld 174]/x86_64-unknown-linux

altogether 17 bytes CODE

plist was able to analyze the object file and determine:

  • the object code contained machine op codes for an Intel 8080 or Intel 8085.

  • a code block of 14 bytes supposed to be loaded into memory locations 000 to 00D (hex), a.k.a. 000 to 015 (octal)

  • a code block of 3 bytes should be loaded into 080 to 082 (hex), a.k.a. 200 to 202 (octal)


p2bin converts a .p file to a binary memory dump, without formatting. By default, uninitialized bytes become FF. Although it could potentially take a very long time to load, this, on the surface, appears to be the most straight-forward representation of what the memory of the Altair will look like, once a program is loaded.


p2hex converts a .p object file to an ASCII representation of the file (.hex). There are several different format available for the output file, based in part on the target machine. In our example:

$ p2hex add.p
$ most add.hex

Looking at the above, and comparing it to the hexadecimal list file produced by the assembler, we can determine that the first two lines represent the two data segments:

HEX record layout







Colon. Start of record delimiter



Lenghth of data in record



Starting address in memory for data



???? possibly a record type? (00 or 01)






???? possibly a record checksum?

The first two lines contain 00 in columns 8-9, while the last, which does not appear to have any relation to the machine code shown in the list file, contains 01. Perhaps an “End of Data” record?

Lo and behold, Wikipedia (naturally) has an entry on Intel HEX which confirms, yea verily,

  • 8-9 is a record type indicator, with 00 being data and 01 being end of file

  • the last two characters are a checksum

The entry even offers an example of the checksum calculation algorithm.


In minicom, the common default kermit options for both send and receive were -i -l %l -b %b which according to C-KERMIT 9.0 Unix man page and tutorial mean:

HEX record layout


Force binary (Image) mode for file transfer; implies -V


-l %l

Make a connection on the given serial communications device.

Equivalent to the SET LINE (SET PORT) command

Argument: Serial device name, e.g. /dev/ttyS0

-b %b

Speed for serial device

Equivalent to SET SPEED

Argument: Numeric Bits per second for serial connections

gkermit does not appear to be a full-fledged Kermit as we once knew it, but, rather the transfer protocol portion only, and depends on an established communication channel to determine the -l and -b above. So, I’ve removed those two options from my ~/.minirc.altair configuration.


Columbia U. is no longer the home of Kermit. It is now The Kermit Project.