Skip to content

About

A small Python script to simulate the Little Man Computer

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Little Man Computer (LMC) Simulator

A simple Python-based simulator for the Little Man Computer (LMC) educational model. This simulator supports standard LMC instructions and includes an optional OTC instruction for ASCII character output.

The repository includes a /programs folder with example LMC programs:

  • sumN.lmc — sum of the first N numbers
  • multiply.lmc — multiplication by repeated addition
  • divide.lmc — integer division with quotient and remainder
  • fibonacci.lmc — every Fibonacci number that fits in a word, with overflow detection
  • hello.lmc — prints "Hello, world!" using self-modifying code
  • bubblesort.lmc — sorts an array in place with self-modifying indexed loads and stores
  • arrays.lmc — table lookup using self-modifying code
  • ascii.lmc — character output with OTC

Why

I was introduced to LMC in IN1020 at UiO, where we used a browser-based LMC simulator. Nothing could be saved, so every session began by retyping the program. It only ran in the browser, it was slow, and it looked its age. I wanted a better way to write programs, save them, always see the information I wanted, and use it from the terminal. So I decided to write my own compiler and executor in Python, and used that to properly learn the ins and outs of LMC.

I hope you have as much fun with it as I did :)


Features

  • Supports LMC instructions: LDA, STA, ADD, SUB, INP, OUT, HLT, BRZ, BRP, BRA
  • Supports DAT data declarations for memory
  • OTC instruction to output ASCII characters
  • Branch labels for loops and conditional execution
  • Configurable memory size
  • Debug mode to print CPU state and memory
  • Step-by-step execution (--step) for learning and debugging

Configuration

You can customize the simulator with these settings in CONFIGS.py:

MEMORY_SIZE

  • Controls how many memory addresses your simulator has (default: 100).
  • Sizes above 100 widen the machine word automatically so every cell stays addressable (e.g. MEMORY_SIZE = 1000 gives four-digit words: LDA 150 = 5150, INP = 9001).
MEMORY_SIZE = 100

DEBUG

  • Sets the default for the --debug flag (see Usage): DEBUG = True enables debug output on every run without passing the flag.
DEBUG = False

Installation

  1. Clone the repository:
git clone https://github.com/triceraz/lmc-simulator
cd lmc_simulator
  1. Ensure Python 3 is installed on your system.

Usage

Ensure you are in the project directory

Run the simulator with an LMC program file:

./main.py programs/arrays.lmc
  • Use INP to enter numbers when prompted.
  • OUT prints numeric values, OTC prints ASCII characters.

Debug output

./main.py --debug programs/sumN.lmc
  • Prints the labels, a memory snapshot and a disassembly before execution, then a trace line (PC, ACC, negative flag, instruction) for every executed instruction.

Step-by-step execution

./main.py --step programs/sumN.lmc

Shows each instruction before it executes and waits for a command:

  • Enter — execute one instruction
  • a number — run that many instructions before pausing again (handy in long programs like bubblesort)
  • c — stop pausing and run to the end
  • q — stop the program

--debug and --step combine cleanly: you get the pre-run dump first, then the same trace, paused at every instruction.


Included Example: Sum of First N Numbers

File: /programs/sumN.lmc

// Sum the first N numbers input by the user, e.g., N=5 → Sum=15
INP             // Read N
STA COUNT       // Store in COUNT
LDA ZERO
STA SUM         // Initialize SUM = 0

LOOP    LDA SUM
        ADD COUNT
        STA SUM         // SUM += COUNT
        LDA COUNT
        SUB ONE
        STA COUNT       // COUNT -= 1
        BRP LOOP        // Loop while COUNT >= 0

        LDA SUM
        OUT             // Output the total sum
        HLT

// Data
COUNT   DAT 0
SUM     DAT 0
ZERO    DAT 0
ONE     DAT 1

How it works

  1. Reads a number N from the user
  2. Initializes a memory location SUM to 0
  3. Loops from N down to 0, adding COUNT to SUM each iteration
  4. Prints the total sum when finished

Example run:

Input Output
5 15
12 78

Featured Example: Bubble Sort

File: /programs/bubblesort.lmc

LMC has no indexed addressing — an instruction can only reference one fixed address. Bubble sort still needs arr[j] and arr[j+1] for a moving j, so the program writes its own instructions while it runs.

The trick: with three-digit words, LDA 47 is stored as 547 and STA 47 as 347. Instructions are just numbers, so the program can do arithmetic on them:

  • +1 points an instruction at the next array element (LDA 47 → LDA 48)
  • −200 turns a load into a store (LDA 47 → STA 47)

Each round of the inner loop builds all four indexed instructions from a single moving template CUR and stores them into exec slots — cells that are executed right after being written:

INNER   LDA CUR
        STA XLOADJ      // Exec slot <- LDA arr[j]
        ADD ONE
        STA XLOADJ1     // Exec slot <- LDA arr[j+1]
        SUB C200
        STA XSTAJ1      // Exec slot <- STA arr[j+1]
        SUB ONE
        STA XSTAJ       // Exec slot <- STA arr[j]

XLOADJ  DAT 0           // Runs as: LDA arr[j]
        STA TMPA
XLOADJ1 DAT 0           // Runs as: LDA arr[j+1]
        STA TMPB

The outer loop repeats passes until a pass makes no swaps. Equal neighbours are never swapped, so arrays containing duplicates terminate too.

Run it:

./main.py programs/bubblesort.lmc

It sorts 42, 7, 999, 0, 314, 7, 100, 55 in place and prints the result in ascending order. To watch it rewrite itself one instruction at a time:

./main.py --step programs/bubblesort.lmc

Adding Your Own Programs

  1. Create a .lmc file in the /programs folder
  2. Write LMC assembly using supported instructions
  3. Run the simulator:
./main.py programs/your_program.lmc

Notes

  • OUT prints numeric values
  • OTC prints ASCII characters (0–127); values outside that range are an error
  • Values are words in the range 0–999 (with the default memory size): ADD wraps around on overflow, and SUB below zero wraps and sets a negative flag that BRP/BRZ consult
  • DAT and INP values must fit in the word range (0–999 by default)
  • Labels are case-insensitive
  • Memory addresses are automatically assigned to DAT variables
  • Configure MEMORY_SIZE and DEBUG in CONFIGS.py
  • You can use unnamed DAT's after each other to make an array. Look at arrays.lmc for an example
  • Assembly and runtime errors are reported with line numbers/addresses
  • Run the tests with python3 -m unittest

About

A small Python script to simulate the Little Man Computer

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages