Writing a program
A complete program, and the limit that grows the ISA
Writing a program for the accumulator CPU means laying out instructions and data in memory so a straight-line sequence of LOAD, ADD, and STORE computes and saves a result; the machine runs top to bottom once, and adding control flow (loops and decisions) requires a jump instruction that changes the program counter.
Build it in the lab →Time to write a whole program. The task: add three numbers and store the result. With labels for the data and one
ADD per number, it is a short, readable listing, real software for the CPU you built. LOAD a ; ACC = a
ADD b ; ACC = a + b
ADD c ; ACC = a + b + c
STORE sum ; sum = ACC
HALT
a: .byte 3
b: .byte 5
c: .byte 7
sum: .byte 0The assembler places the five instructions at addresses
0 to 4, then the four data bytes at 5 to 8, so the symbol table is a = 5, b = 6, c = 7, sum = 8. Resolving the labels and packing each opcode with its address gives the bytes that go into memory:addr byte source 0 0x15 LOAD a (LOAD 5) 1 0x26 ADD b (ADD 6) 2 0x27 ADD c (ADD 7) 3 0x38 STORE sum (STORE 8) 4 0xF0 HALT 5 0x03 a: .byte 3 6 0x05 b: .byte 5 7 0x07 c: .byte 7 8 0x00 sum: .byte 0
Running it
Now fetch-decode-execute walks the program counter from
0 upward, one instruction per go, exactly as in the program trace. Follow the accumulator:step PC instruction ACC effect 1 0 LOAD a 3 ACC = mem[5] = 3 2 1 ADD b 8 ACC = 3 + mem[6] = 3 + 5 3 2 ADD c 15 ACC = 8 + mem[7] = 8 + 7 4 3 STORE sum 15 mem[8] = 15 5 4 HALT 15 stop
After
HALT, address 8 (sum) holds 15, and the accumulator holds 15 too. That is a complete, correct program: written in assembly, assembled to bytes, run to an answer on the hardware you built gate by gate.The limit: no loops, no choices
Notice what this machine cannot do. It runs straight down, top to bottom, exactly once. There is no way to say "repeat this ten times" or "if the accumulator is zero, skip ahead." To add ten numbers you would need ten
ADD lines; you cannot loop. That limit is not the accumulator's fault, it is the instruction set: with only LOAD, ADD, STORE, and HALT, nothing ever changes the straight march of the program counter.What is missing is a jump: an instruction that loads the program counter with an address instead of letting it increment. An unconditional
JMP addr gives loops (jump back); a conditional JZ addr (jump if the accumulator is zero) gives decisions. And the hardware is already there: the program counter you built can load a value through the mux on its D input, not just count. Adding jumps is one more opcode wired to that load path, and with loops plus decisions the little machine becomes a fully general computer.Keep results inside a byte. The accumulator is 8 bits, so it wraps past
255 (0xFF), the two's-complement and overflow behavior you saw. Summing 3 + 5 + 7 = 15 is fine, but a program that adds large values must expect wraparound, exactly as the 8-bit adder does. Assembly does not protect you from the width of the hardware.Try it
Change the program to compute
a + b + c + d for four data bytes. How many instructions does the code section now take, and at what address does the data start?Answer
Add one more
ADD d line, so the code is LOAD a, ADD b, ADD c, ADD d, STORE sum, HALT, six instructions at addresses 0 to 5. The data (a, b, c, d, sum) then starts at address 6. Every extra number costs one instruction, because with no loop you must spell out each ADD by hand, the very limit that makes a jump instruction worth adding.Frequently asked
How do you write a program in assembly for a simple CPU?
Lay out instructions then data in memory: use LOAD to bring a value into the accumulator, ADD to accumulate more, STORE to save the result, and HALT to stop, with labels naming the data. The assembler turns the mnemonics and labels into bytes, which you load into the CPU's RAM to run.
Why can't this CPU do loops?
Its instruction set has only LOAD, ADD, STORE, and HALT, none of which changes the program counter's steady increment, so execution runs straight from top to bottom exactly once. Loops (and if-decisions) require a jump instruction that loads the program counter with a new address.
What instruction is needed to add loops and if-statements?
A jump. An unconditional JMP loads the program counter with an address (jump back to loop); a conditional jump like JZ (jump if the accumulator is zero) makes it a decision. The program counter's existing load path (a mux on its input) already supports this in hardware, so a jump is one more opcode.
What happens if a program's result is larger than 255?
It wraps around, because the accumulator is 8 bits. Adding past 255 rolls over to a small number (with the carry and two's-complement/overflow behavior you saw in the adder). Assembly does not hide the hardware's width, so programs must keep values within a byte or handle the wraparound.
You've got the theory. Now build it from scratch and watch it work.
Build it in the lab →