PaperCPU

PaperCPU is a simple CPU architecture where programs and execution steps can be written on paper or a whiteboard, designed for teaching and learning purposes. The idea comes from computer educational aids used in the 1950s–70s, with which students would write programs and manually simulate register operations to help learn how computers work, which was useful when actual machines were too expensive or inaccessible. Of course nowadays computers are widely accessible, so this site provides a simulator for the CPU, allowing students to experiment either on paper or directly in the browser.

To use the simulator, simply write your program on the left and press 'Run Program'. You can pause the execution by pressing 'Pause' and step through instructions one at at time using 'Step'. You can adjust the speed using the speed slider, and when the program wants input the CPU will pause and highlight the input box green, when done writing a number you press 'Set' and the CPU will read the input and continue.

To use the PaperCPU on paper, print this linked PDF on a sheet of 8.5x11 paper, or draw a similar design on paper or whiteboard. Write the instructions for your program to the left and step through each instruction, writing the result of the operations in the registers. You can use a calculator to do any math as needed.

Instruction Set Architecture

To the left is the program editor. The CPU has an internal 'program counter' (PC) that keeps track of the currently executing instruction, which is highlighted in green when running. When working on paper, you can use a paper cut-out arrow or any pointing object to mark the current instruction. The line numbers on the left correspond to instruction numbers and help when using jump instructions. (Note: the simulator currently doesn't number blank lines correctly, so keep that in mind when writing code.)

To the right, the CPU provides 8 general purpose registers and an input and output register. Each register holds a floating-point value. On paper you can be flexible and write values as integers or decimals, or write them in different number bases, but the javascript simulator implements them using JavaScript’s 'Number' type and displays them as base 10 decimals.

Instructions

Arithmetic & Logical Instructions

These instruction do arithmetic and logical operations and operate on the 8 registers. They support register and immediate addressing modes:

InstructionDescriptionExample
movMove a value into a registermov r0, #10
notBitwise NOTnot r0, r1
andBitwise ANDand r0, r1, #255
orBitwise ORor r0, r1, r2
addAdd two valuesadd r0, r1, #1
subSubtract second value from firstsub r0, r0, #1
mulMultiply two valuesmul r1, r1, r0
divDivide first value by seconddiv r0, r0, #2
remRemainder (modulo) of divisionrem r0, r1, #3

Note on bitwise operations: JavaScript performs bitwise operations (and, or, not) by converting values to 32-bit signed integers internally, does the operation, then converts them back to a float. On paper, round the values down to the nearest integer (floor operation) then apply the bitwise operation.

Control Flow Instructions

Control flow instructions change the order of execution by setting the PC to a specific line in the program. Jump instructions can be unconditional or conditional, and conditional jumps have register or immediate addressing modes.

InstructionDescriptionExample
jmpJump to line numberjmp 10
jeqJump if equaljeq r0, #0, 5
jneqJump if not equaljneq r1, r2, 3
jgtJump if greater thanjgt r0, #10, 8
jgteJump if greater than or equaljgte r1, r2, 12
jltJump if less thanjlt r0, #1, 4
jlteJump if less than or equaljlte r0, r1, 6

Input/Output Instructions

These instructions send or recieve values from the input and output registers and allow for the program to interact with the user.

InstructionDescriptionExample
inRead value into register from input registerin r0
outWrite register value to output registerout r1

Halt Instruction

This instruction halts execution. If the CPU reaches the end of the program and there's no 'hlt' instruction, the CPU will show an error message.

InstructionDescriptionExample
hltStop executionhlt

Possible Errors

Example programs

Calculate the factorial of input value

in r0 mov r1, #1 mul r1, r1, r0 sub r0, r0, #1 jneq r0, #0, 2 out r1 hlt

Calculate the sum of fibonacci numbers up to input value

in n mov first, #0 mov second, #1 mov next, #0 mov sum, #0 mov i, #0 loop: jgte i, n, endloop jgt i, #1, else if: mov next, i jmp endif else: add next, first, second mov first, second mov second, next endif add sum, sum, next add i, i, #1 jmp loop endloop: out sum hlt

becomes:

in r0 mov r1, #0 mov r2, #1 mov r3, #0 mov r4, #0 mov r5, #0 jgte r5, r0, 16 jgt r5, #1, 10 mov r3, r5 jmp 13 add r3, r1, r2 mov r1, r2 mov r2, r3 add r4, r4, r3 add r5, r5, #1 jmp 6 out r4 hlt

Outputs 0 if input value is even, 1 if odd

in r0 rem r1, r0, #2 out r1 hlt

Calculates base ^ exponent, where first input is base and second is exponent

in r0 in r1 mov r2, #1 jeq r1, #0, 7 mul r2, r2, r0 sub r1, r1, #1 jmp 3 out r2 hlt

Interactive four-function calculator

Asks for the first input, then the second input, then the operation, where 0 = add, 1 = sub, 2 = mul, 3 = div.

in r0 # first number in r1 # second number in r2 # operation jeq r2, #0, add jeq r2, #1, sub jeq r2, #2, mul jeq r2, #3, div jmp invalid add: add r3, r0, r1 jmp done sub: sub r3, r0, r1 jmp done mul: mul r3, r0, r1 jmp done div: jeq r1, #0, invalid # check for divide by zero div r3, r0, r1 jmp done invalid: mov r3, #-999999 # special error code for invalid operator done: out r3 jmp 0 # jump to start

becomes:

in r0 in r1 in r2 jeq r2, #0, 8 jeq r2, #1, 10 jeq r2, #2, 12 jeq r2, #3, 14 jmp 17 add r3, r0, r1 jmp 18 sub r3, r0, r1 jmp 18 mul r3, r0, r1 jmp 18 jeq r1, #0, 17 div r3, r0, r1 jmp 18 mov r3, #-999999 out r3 jmp 0

Number guessing game

The user thinks of a secret number 1-100, and the CPU will try to guess it. If its guess is too low, enter 0, if too high, enter 1, if it's correct, enter 2.

mov r0, #1 # bottom mov r1, #100 # top guessloop: add r2, r0, r1 # guess = floor((low + high) / 2) div r2, r2, #2 or r2, r2, #0 # bitwise or for floor out r2 # output guess and get user input in r3 jeq r3, #0, toolow jeq r3, #1, toohigh jeq r3, #2, correct toolow: add r0, r2, #1 # low = guess + 1 jmp guessloop toohigh: sub r1, r2, #1 # high = guess - 1 jmp guessloop correct: hlt

becomes:

mov r0, #1 mov r1, #100 add r2, r0, r1 div r2, r2, #2 or r2, r2, #0 out r2 in r3 jeq r3, #0, 10 jeq r3, #1, 12 jeq r3, #2, 14 add r0, r2, #1 jmp 2 sub r1, r2, #1 jmp 2 hlt

License and Source code

Code is under MPL, media is under CC-BY-SA. Code is at https://codeberg.org/bobbbob/papercpu