1.2.4 - Little Man Computer programs

1.2.4 - Little Man Computer programs

Little Man Computer makes a program's storage and control decisions visible. You will follow the accumulator, write arithmetic and branch instructions, and check that a small assembly program produces the intended output.

Instructions act on an accumulator and mailboxes

An LMC program exposes individual machine operations and their order.

Assembly language

An assembly language represents a machine's instructions using mnemonics such as LDA and labels for locations. An assembler translates that source into machine code.

Assembly is tied to the instruction set of a particular machine; LMC is a simplified teaching machine, not the instruction set of every processor.

Assembly is useful when software needs precise control of a machine's registers, hardware operations or instruction sequence. The cost is more detail to manage and less portability between architectures than high-level code; mnemonics do not remove that machine dependence.

The LMC model has addressed mailboxes holding instructions or data, an accumulator holding the current arithmetic value, and a program counter identifying the next instruction. Ordinary execution moves to the next instruction; a branch changes that next position. Input places a value in the accumulator. Output copies the accumulator to the output device: it does not automatically output a named mailbox.

InstructionEffect
INP / OUTRead input into / output the accumulator
LDA addressCopy the value at that address into the accumulator
STA addressCopy the accumulator into that mailbox
ADD address / SUB addressAdd / subtract the value stored at that address
BRA labelContinue at the labelled instruction unconditionally
BRZ labelBranch when the accumulator is zero
BRP labelBranch when the subtraction/arithmetic result is nonnegative, including zero
HLTHalt execution
DAT valueReserve a data mailbox, optionally with an initial value

A label gives a location a readable name. It is not a new variable that moves between locations: the assembler resolves it to an address. DAT is an assembler directive reserving data, not an instruction to execute. Place data after HLT so ordinary execution does not fall into it.

OCR also accepts STO, LOAD, BR, BZ, BP, IN/INPUT and COB/END for the corresponding instructions. A simulator may choose different aliases. Use the printed meanings, especially BRP's zero case.

Mnemonics make machine instructions readable; they do not make assembly independent of the machine. These LMC examples remain static assembly, not runnable Python.

Store values before another input replaces them

The accumulator holds only one current value, so a second input replaces the first unless you store it. This program inputs two nonnegative integers whose sum is at most 999 and outputs their sum.

Plain text
        INP
        STA FIRST
        INP
        ADD FIRST
        OUT
        HLT
FIRST   DAT 0

For inputs 18 then 7, follow the effect of each instruction rather than guessing from the labels.

After instructionAccumulatorFIRSTOutput
INP180none
STA FIRST1818none
INP718none
ADD FIRST2518none
OUT251825

ADD FIRST adds the contents of FIRST, not its address. This is direct addressing. LDA FIRST would replace the accumulator with 18; it would not add 18. A comment or a label does not change either operation.

LMC simulators normally have three-digit mailboxes. Overflow and the display of negative subtraction results vary between implementations. Our arithmetic examples avoid overflow; when a comparison is needed, we reason about the subtraction's zero/nonnegative condition rather than output a negative result.

Subtract to decide which branch to take

A comparison can be implemented by subtraction followed by a conditional branch. If the first number minus the second is zero, they are equal; if it is nonnegative, the first is at least as large. Subtraction changes the accumulator, so reload an original value when you need to output it.

This original program inputs two numbers in 0–999 and outputs the smaller, including when they are equal.

Plain text
        INP
        STA FIRST
        INP
        STA SECOND
        LDA FIRST
        SUB SECOND
        BRP SECONDOUT
        LDA FIRST
        BRA DISPLAY
SECONDOUT LDA SECOND
DISPLAY OUT
        HLT
FIRST   DAT 0
SECOND  DAT 0

With 4 then 9, the comparison has a negative result, so BRP is not taken and FIRST is loaded. With 9 then 4, BRP is taken and SECOND is loaded. With 4 then 4, the zero condition also takes BRP, correctly outputting 4. The unconditional BRA DISPLAY prevents the FIRST route from falling through into LDA SECOND.

Use BRZ when equality alone matters. For example, after LDA COUNT and SUB LIMIT, BRZ DONE takes the branch only when COUNT and LIMIT are equal. BRP DONE would also take it when COUNT exceeds LIMIT.

A loop needs a changing value and a stopping branch

A branch back to an earlier label creates repetition, but it terminates only if the tested state can reach the stopping condition. This program accepts a count in 0–999, outputs that many descending positive integers, and outputs nothing for zero.

Plain text
        INP
        STA COUNT
LOOP    LDA COUNT
        BRZ DONE
        OUT
        SUB ONE
        STA COUNT
        BRA LOOP
DONE    HLT
COUNT   DAT 0
ONE     DAT 1

For input 3, COUNT is tested at 3, 2, 1 and 0. The output sequence is 3, 2, 1. Subtracting ONE changes the accumulator; STA COUNT saves that decrease for the next iteration. Omitting STA would cause the next LDA to reload the unchanged count and repeat forever for a positive input.

The zero check occurs before output. If moved after OUT, input zero would output zero once, violating the contract. For input 1, the loop outputs 1, stores 0, then halts on its next visit to LOOP. The precondition excludes negative inputs and does not promise behavior for them.

Write and amend code from its input and output contract

To design a short LMC routine, decide which values must survive the next input or arithmetic operation, then allocate DAT locations. Put branches around genuinely different routes; identify the join and the halt before writing the body. Finally trace normal and boundary inputs against the required output.

For a program that inputs a number in 0–499 and outputs double it, store the input as VALUE, then add VALUE to the still-current accumulator. A complete solution is:

Plain text
        INP
        STA VALUE
        ADD VALUE
        OUT
        HLT
VALUE   DAT 0

The 499 bound matters: the largest requested result is 998, within a three-digit mailbox. Tests 8→16, 0→0 and 499→998 check ordinary, minimum and maximum cases. Replacing ADD with LDA would output the original number; adding an extra INP would wrongly require a second input. Alternative designs can load/add a stored input more than once if they satisfy the same contract.

These are static assembly examples. As ungraded practical writing, use a local editor or compatible LMC simulator to write a three-input sum program, then test 10, 0, 7→17 and 300, 300, 300→900. Preserve the partial sum before the third input replaces the accumulator. Enter the labelled source, assemble it, inspect its address listing and single-step while watching the accumulator, data mailboxes and program counter. Confirm the simulator's supported aliases, three-digit range and negative-result/overflow behavior before interpreting a trace. NovaLearn Testing uses static LMC interpretation, diagnosis and design reasoning here; its Python runner and source editors do not assess LMC assembly.