Basics of Computer Programming: From Machine Code to Abstraction
Computer programming is the art of instructing machines to perform tasks through code. At its core, computers understand only binary—1's and 0's—but layers of abstraction make programming human-friendly. This overview explores machine code, assembly instructions, registers vs. memory, stack usage, and how early programmers worked by hand in the "old days."
Abstraction Layers: From Binary to Human-Readable Code
Computers execute instructions as binary patterns (machine code)—sequences of 1's and 0's representing operations and data. These are grouped into bytes (8 bits) or words (e.g., 16/32 bits). Abstraction layers build on this:
- Binary/Machine Code: Raw bits the CPU decodes (e.g., 10101010 might mean "load register"). Hard for humans to read/write.
- Assembly Language: Mnemonics like MOV (move data), ADD (add), etc., map to binary opcodes. Assemblers translate to machine code.
- Higher Levels: Languages like BASIC, C, or Python compile/interpret to assembly/machine code.
Example: Binary 1010 0110 (hex A6) might be LDA (load accumulator) in 6502 assembly—humans use "LDA $00" instead of bits.
Example Instruction Set: From a Simple Processor (MOS 6502)
The MOS 6502 (used in Apple II, Commodore 64) has a simple 8-bit instruction set. Here's a subset with opcodes, mnemonics, and descriptions:
| Opcode (Hex) | Mnemonic | Description | Bytes | Cycles |
| A9 | LDA # | Load accumulator with immediate value | 2 | 2 |
| 8D | STA abs | Store accumulator to absolute address | 3 | 4 |
| 18 | CLC | Clear carry flag | 1 | 2 |
| 69 | ADC # | Add immediate to accumulator with carry | 2 | 2 |
| 4C | JMP abs | Jump to absolute address | 3 | 3 |
| 20 | JSR abs | Jump to subroutine (push return address to stack) | 3 | 6 |
| 60 | RTS | Return from subroutine (pop return address from stack) | 1 | 6 |
This set allows basic operations: load/store data, arithmetic, jumps. Assemblers convert mnemonics to binary.
Registers vs. Instruction and Data Memory
Registers are fast, on-chip storage locations inside the CPU—small but accessible in 1-2 cycles. They differ from memory:
- Registers: Few (e.g., 6502 has A (accumulator), X/Y (indexes), PC (program counter), SP (stack pointer), status flags). Used for temporary data, arithmetic, addressing. Not addressable like RAM.
- Memory: Larger off-chip storage (RAM/ROM); slower access (multiple cycles). Divided into:
- Instruction Memory: ROM/EPROM holding code (e.g., BASIC interpreter).
- Data Memory: RAM for variables, stacks, heaps.
- Difference: Registers are CPU-internal "scratchpads"; memory is external "workspace." Harvard architecture separates instruction/data; von Neumann combines them.
The Stack and Subroutine Calls
The stack is a LIFO (last-in, first-out) region in data memory for temporary storage, managed by the stack pointer (SP) register.
- Function: For subroutine calls: JSR pushes return address to stack; RTS pops it to return. Also stores local variables, parameters.
- Example (6502): JSR $1234 pushes PC+3 to stack, jumps to $1234; RTS pops address, returns.
- Advantages: Enables recursion, nested calls without fixed memory allocation.
- Hobbyist Note: Stacks often fixed-size (256 bytes on 6502); overflows crashed systems.
Programming in the "Old Days": By Hand
Early hobbyists (1970s) programmed without IDEs—often by hand-assembling code on paper.
- Process: Write assembly mnemonics, look up opcodes in datasheets, calculate addresses/jumps, convert to hex/binary.
- Entry: Toggle switches (Altair 8800) or hex keypads to enter machine code byte-by-byte into memory.
- Debug: Single-step via front panel LEDs; no debuggers—trace with pencil/paper.
- Examples: Apple I monitor for hex entry; TRS-80 ZAPPLE monitor. Magazines published hex dumps for typing in.
- Challenges: Error-prone (miscalculated jumps), time-consuming; assemblers (on tape/disk) eased this by 1980s.
This hands-on approach taught CPU internals but was tedious—modern tools abstract it away.
Back to Misc
Copyright 2026 - MicroBasement