Meet the Altair · Calling a subroutine

Remembering
where to return.

A program can ask another piece of code to do a job, then continue where it left off. Our familiar printing loop will do the same job twice, returning to a different place each time.

Begin here: Step once to set SP to 0200. Step again to execute CALL. PC becomes 000A, SP becomes 01FE, and the two stack bytes hold 06 and 00. No character has been read or printed yet. The CPU has saved where to come back.

Loaded subroutine program · reference card All addresses and bytes here are hexadecimal
These twenty-six program bytes are loaded at 0000. HELLO, LF, and NUL begin at 0100; CALL uses RAM at 01FE–01FF. RAM shows what is stored now.
AddressReferenceRAMCheck

0000: LXI SP,0200H chooses a stack starting point. 0003 and 0006: CALL 000AH call the same routine, saving 0006 and 0009 respectively. 0009: HLT finishes after the second return.

000A: LXI H,0100H resets the message pointer. 000D: MOV A,M, 000E: CPI 0, and 0010: JZ 0019H check for NUL. 0013: OUT 01H, 0015: INX H, and 0016: JMP 000DH print each nonzero byte. 0019: RET resumes at the address read from the stack.

The lesson checks all twenty-six program bytes. Message and stack data can be edited while stopped. The CPU reads the saved address from RAM; the viewer does not choose the return destination.

Operate the memory panel

The 8080 behind the panel

A decimal
0
PC hex
0000
HL address · hex
0000
SP stack address · hex
0000

Return address in RAM

Addresses and bytes in hexadecimal.
AddressByteRole
01FE 00Low byte
01FF 00High byte

Enable JavaScript to follow SP.

The marker follows SP. Looking at these bytes changes no CPU or memory state.

Message in RAM

Addresses and bytes in hexadecimal; characters interpreted as ASCII.
AddressByteCharacter
0100 48H
0101 45E
0102 4CL
0103 4CL
0104 4FO
0105 0ALF
0106 00NUL

Enable JavaScript to follow HL.

The marker follows HL. Looking at these bytes changes no CPU or memory state.

With SP at 01FE, RET reads the low byte at 01FE and the high byte at 01FF. For example, 06 then 00 forms address 0006. At SP 0200, these bytes have been released but remain in RAM. The window shows two locations, not a CPU-enforced stack limit.

Zero flag Z: 0 · the most recent comparison’s answer

CPU halted: no

The program is loaded. Enable JavaScript to run or step it.

Last CPU instruction

No instruction has run.

Received text Output port 1


    Waiting for output
  

No byte sent yet.

0 writes received.

Only OUT adds text. LF starts a new line; other non-printing bytes appear as labels in angle brackets.

Look inside the last instruction
Step an instruction to see its fetched bytes, memory accesses, and any port transfers.
Recent instructions

0 instructions executed.

    RUN and STOP are teaching controls at instruction boundaries. Pace is for reading, not a simulation of the Altair’s clock. This page stops running when hidden. Looking at these readouts changes no state; EXAMINE changes PC.

    EXAMINE changes PC without running a program instruction. Stepping advances PC, and the panel lights follow it. This added control executes a whole instruction; the original SINGLE STEP switch advanced one machine cycle.

    ALTAIR 8800

    Memory controls · learning view

    Address lights The selected location

    0 decimal · 0000 hex

    Data lights The byte at that location

    0 decimal · 00 hex

    A lit lamp is 1; a dark lamp is 0. The digits help you read the lights.

    Data / address switches Up = 1 · Down = 0

    15–8 · Address only

    7–0 · Address or data

    All switches as an address
    0 decimal · 0000 hex
    Lower eight as a byte
    0 decimal · 00 hex

    Setting the switches prepares a number. It does not read or write memory.

    Lower all switches and press EXAMINE to select 0000.

    Select the address in the switches and read its byte.

    Move to the next address and read its byte.

    Write the lower eight switches to the selected address.

    Move to the next address, then write the lower eight switches.

    EXAMINE would select address 0. DEPOSIT would write 0 to the selected address, 0.

    Last memory operation

    Enable JavaScript to operate the panel.

    This lesson connects an 8080, 65,536 bytes of RAM, and a teaching output device at port 1. It calls one printing routine twice, then halts. Start again restores program and message bytes, clears the stack RAM, registers, flags, halted state, output, counts, and history, and stops at PC 0000. It is not the hardware RESET switch.

    Give a piece of code a job.

    A subroutine is a piece of a program that can be called to do a job and then return. Here, its job is to print the zero-terminated message at 0100.

    The routine begins at 000A. It sets HL to 0100, reads through HL, and sends each nonzero byte with OUT. When it reaches NUL, it executes RET. The surrounding code—the caller—calls it twice, then halts.

    The printing instructions occur once in RAM. Both calls execute those same instructions and read the same message. Each call resets HL, so the second one starts at H again.

    Remember the instruction after the call.

    You have used JMP to change PC. CALL also saves a return address before changing PC. The saved address is where execution should continue after the routine finishes.

    The CALL at 0003 occupies three bytes: CD 0A 00. Its destination is 000A, but the next instruction is at 0006. The CPU saves 0006, then sets PC to 000A. The destination and the return address have different jobs.

    CALL does not execute the whole routine as one step. After it finishes, PC points at the routine's first instruction. Its loads, comparisons, branches, and outputs still run one instruction at a time.

    Keep the address in RAM.

    The 8080 keeps saved return addresses in ordinary RAM. SP, the stack pointer, tells it where to put and find them. The first instruction, LXI SP,0200H, chooses a starting point. Setting SP does not itself write any memory.

    CALL decreases SP to 01FF and writes the high byte of the return address. It decreases SP again to 01FE and writes the low byte. The stack grows toward lower addresses; SP now points at the low byte.

    The table lists RAM in ascending address order, so it shows the low byte first. For address 0006, that is 06 at 01FE and 00 at 01FF. These are pieces of an address, not characters to print.

    We use only these two stack locations because the first call returns before the second begins. The CPU does not know that the picture has two rows, and it does not check whether a chosen stack area overlaps other data or code.

    Read the way back.

    When the print loop finds NUL, its conditional jump selects RET at 0019. RET reads the low byte at SP and the high byte at the following address, advances SP past both, and puts the combined address into PC.

    For the first return, that makes PC 0006 and SP 0200. The caller is ready to continue. A, HL, and flags keep the values left by the routine; RET does not restore their earlier values.

    Reading does not erase RAM. The saved 06 and 00 remain visible after SP moves above them. They are no longer an outstanding return address. Another call can reuse those locations.

    The same routine, a different continuation.

    The next instruction is the CALL at 0006. It has the same destination, 000A, but its following instruction is at 0009. This call saves 0009 in the reused stack locations, replacing the low byte 06 with 09.

    RET itself is still the same single byte, C9, at 0019. It has no fixed destination written after it. Its destination comes from the bytes in RAM at SP.

    After the second return, PC is 0009 and SP is 0200. The caller's HLT then stops the CPU. PC advances to 000A, but the CPU is halted: that address alone does not mean the routine will run a third time.

    A return address is data too.

    Because RET reads RAM, changing the saved bytes changes where it goes. There is no hidden list in the viewer that sends the CPU back to its caller.

    Skip the second call by changing the saved address

    Start again and step twice to execute the first CALL. EXAMINE 01FE, set the switches to 0009, and DEPOSIT. The last-instruction explanation still reports the 0006 that CALL originally saved. Then EXAMINE 000A to restore PC and RUN. The routine prints one HELLO line, but RET now returns directly to HLT at 0009, skipping the second call.

    This experiment deliberately changes the program's continuation. The lesson guards instruction bytes and pauses at unknown instruction addresses; a real 8080 does not check that a return lands where the programmer intended. Start again to restore the ordinary two-call path.