Follow the original manual’s seven-chapter sequence with explanations and exercises adapted for this interface. Loading a lesson example replaces the current program and returns to the editor. Save your work first.
1 · Introduction
Learn to: enter, assemble, step, stop and save a program; identify registers and memory; use breakpoints and number views.
1.1 Assembly language and this computer
An assembly instruction names one operation for the processor to perform. The assembler turns that instruction into machine words. ASMTutor uses a small teaching instruction set so you can watch each operation change the machine.
1.2–1.4 Files, starting up and the interface
This browser version needs no installer. New creates an empty program, Open .asm reads a saved file, and Save .asm downloads it. Enter instructions from address 100. Put any explanatory text in the Comment column.
Assemble prepares the debugger. Step executes one instruction; the green address marks the next instruction. Run continues until a breakpoint, input request, error or final RTS. Stop pauses. Restart restores the program and registers. Select Edit program to change the code or load another program. The speed slider and Trace setting control how execution is shown.
1.5 The teaching architecture
R0–R7: eight data registers, each holding 16 bits.
PC: the address of the next instruction. Execution starts at 100.
SP: the stack pointer. It points to the most recently pushed value.
SR: status flags for negative, zero, overflow, carry and interrupt enable.
INT: a pending keyboard interrupt request.
Each memory cell has three 16-bit words, making 48 bits. An instruction occupies one cell. Ordinary data operations read or write only its third word. Addresses 0–99 are reserved; the default memory contains 200 cells. Toggle Show system memory to inspect the reserved area. The ten mapped-output characters come from addresses 5–14. System routines provide text and number input/output.
1.6 Your first guided run
Load the example and select Assemble. Check PC=100 and SP=15.
Select Step once. Address 100 copies the ASCII code for 'A' to location 5, and an A appears in mapped output.
Keep stepping. Notice that addresses 107–108 move the last letter through R0 before writing it to the display.
Select Restart, then Run. The saved breakpoint pauses before address 105. Select Run again to finish. The output reads AsmTutor.
Select Edit program. Change one of the quoted letters, assemble and run again. Save the edited program under a new name.
Change View to Hexadecimal. Address 100 contains 0610 0005 0041. Binary and Decimal show the same words in other bases.
Try an error and recover
In the editor, replace R0 at address 107 with R9. The register is invalid and assembly is blocked. Correct it to R0, or select Restart to discard the invalid edit. Removing the final RTS lets execution fall into an empty cell and produces an error; restore RTS before running again.
Check yourself: Why does the green marker move before the next instruction has run? What is the difference between Restart and Edit program?
2 · Moving values around
Learn to: use MOVE, distinguish data from addresses, read several number formats and drive mapped output.
2.1 MOVE copies a source into a destination
MOVE source,destination copies a 16-bit value without erasing the source. MOVE #10,R0 puts the number 10 into R0. MOVE 110,R0 reads the value stored at memory address 110. The # changes the meaning of the operand.
2.2 Number formats
Decimal 100, hexadecimal $64, binary %1100100 and character 'd' all represent the same value. Use a number’s prefix when entering an operand; use View to inspect its encoded words. A character is enclosed in straight single quotes. Values occupy 16 bits; signed interpretation uses −32768 through 32767.
2.3 Addressing modes
Mode
Example
Meaning
Immediate
MOVE #10,R0
The operand itself supplies the value.
Direct / absolute
MOVE 110,R0
Read the value at address 110.
Register
MOVE R0,R1
Copy the value from R0 into R1.
Indirect
MOVE (R0),R1
R0 contains the address to read.
Base plus offset
MOVE 2(R0),R1
Read memory at R0+2.
Indexed
MOVE R1(R0),150
Read memory at R0+R1; store at 150.
PC-relative
MOVE 5(PC),R0
Read five cells beyond the current instruction.
The available combinations depend on the instruction. Flow-control operations use their effective address as a target, whereas MOVE normally reads the data stored at that address. For example, JMP 110 jumps to 110; it does not read 110’s data as a second address.
2.4 Memory-mapped characters
Assemble and step through addresses 100–108. Watch the mapped output build abcdef.
Inspect the data at addresses 110–114 and the changes to R0.
At address 104, R0 points to the cell holding 'c'. At 106–108, offsets select consecutive characters.
Return to the editor and change the offset at 107. Predict which character will appear before running it.
Extra exploration: changing stored data
This extra file demonstrates different numeric and character constants and writes into other cells’ third words. Step only through its six instructions at 100–105, then Stop or Edit program. It has no final RTS and will fault if allowed to continue into empty memory. Compare the third words at 108–111 in machine-code views.
Check yourself: If R0 contains 112, what addresses do (R0) and 2(R0) select? How is #112 different?
3 · Flow control
Learn to: jump, use subroutines and the stack, compare values, branch conditionally and call input/output routines.
3.1 Jumps and polling loops
Normally PC advances by one. JMP 100 replaces PC with 100, creating a loop when used later in a program. An indirect target such as JMP (R0) uses the address in R0.
Assemble, Run and click keyboard letters. The program repeatedly reads address 4 and copies it to mapped output. In this recovered version, pressing Q exits; Stop also pauses it. Notice the work required to keep checking the keyboard.
3.2–3.3 The stack and subroutines
The stack occupies addresses 15–85 and works last-in, first-out. PUSH increments SP before storing; POP reads the top value and then decrements SP. JSR target pushes the following instruction’s address and jumps. RTS pops that return address. The main program also ends with RTS because the system calls it as a subroutine.
Enable Show system memory, assemble and step to the JSR at 102.
Step the JSR. PC becomes 108, and SP grows as the return address is pushed.
Follow the three moves which swap R0 and R1 using cell 112.
Step RTS at 111 and check that execution returns to 103. The second call reuses the same subroutine. At completion R0=20 and R1=8.
3.4 Status flags
Step the first MOVE and watch Z turn on for zero. Step the next MOVE and watch N turn on because the high bit of $FF00 is set. SR bits 0–4 are N (negative), Z (zero), V (signed overflow), C (carry), and I (interrupt enable). Ordinary MOVE updates N/Z and clears V/C. An explicit SR operation controls its bits directly.
3.5 Comparisons and conditional branches
CMP #15,R0 sets flags as if calculating R0−15, but leaves R0 unchanged. A following branch tests those flags.
Branches
Take the branch when…
BT / BF
Always / never
BEQ / BNE
Equal / not equal (Z set / clear)
BGE / BGT
Signed greater-or-equal / greater
BLE / BLT
Signed less-or-equal / less
BCC / BCS
Carry clear / set
BOC / BOS
Overflow clear / set
Compare1 reads keys until Q is pressed. In Compare2, R0 starts at 16; comparison with 15 makes BGT at 102 jump to 105. Try comparison values 16 and 20, then try BEQ, BGE, BNE, BLT and BLE. Predict whether each branch is taken. Assemble again after each edit.
3.6 System subroutines and input/output
Call
Registers and result
JSR 86
Print a zero-terminated string beginning at the address in R0.
JSR 87
Print the number held in R0.
JSR 88
Input a string into the buffer at R0; R1 is its capacity, including the zero terminator.
JSR 89
Input a number and return it in R0.
In StringIO, enter a short word in the input panel, submit it, then select Run again. The program prints a prefix and your word and asks for another. Its ten-cell buffer holds nine characters plus zero. NumberIO prints each entered number and repeats until you enter 10. Character code 10 creates a newline in an output string.
Check yourself: Why use JSR rather than JMP for an I/O routine? What would happen if a printed string had no zero terminator?
4 · Arithmetic instructions
Learn to: add, subtract, multiply and divide; interpret results and recognise overflow.
4.1 Addition and subtraction
Arithmetic uses source,destination order. ADD #1,R0 increments R0. SUB #1,R0 decrements it: subtraction calculates destination minus source. Results remain in the destination and arithmetic updates the status flags. A 16-bit result wraps when it exceeds the available bits; signed overflow and unsigned carry describe different conditions.
Run at a slow speed and watch letters appear in mapped-output cell 10.
At address 102 the counter increases. CMP checks it against 'z'; BLE repeats the inner loop.
The supplied file jumps back to 100 after reaching z, so it repeats the alphabet. Use Stop. The manual’s narrative describes an exit, but this recovered file loops.
In the editor, replace the JMP at 105 with RTS and clear its operand to make a single-pass version.
4.2 Signed multiplication
MULS source,destination multiplies signed values and retains a 16-bit result. Step the example: 5×2 leaves 10 in R0, while 20×10 leaves 200 at address 105. Try a negative operand, then a multiplication whose signed result exceeds 32767, watching V.
4.3 Division: two results in one word
DIVS divides the destination by the source. The low eight bits hold the quotient; the high eight bits hold the remainder. After 20÷6 the whole register is $0203: remainder 2, quotient 3. It is not simply the decimal number 3.
Step through the first division: 20÷5 gives R0=4.
Step the division at 103 and switch View to Hexadecimal. R1 contains 0203.
AND #$FF00,R1 keeps only the remainder byte. LSR #8,R1 moves it down so R1 becomes 2.
To keep the quotient instead, experiment with AND #$00FF,R1 and omit the shift.
The manual specifies that division by zero causes an error and division by one signals overflow. Use divisors of at least two for these introductory exercises. Detailed negative division and overflow compatibility is still being checked against the original.
Check yourself: What packed hexadecimal result represents 23÷5?
Show answer
$0304: remainder 3, quotient 4.
5 · Logic instructions
Learn to: mask and invert bits, distinguish logical and arithmetic shifts, and rotate bits.
5.1 AND, OR, EOR and NOT
Each operation acts on corresponding bits across a whole 16-bit value. AND produces 1 only when both input bits are 1. OR produces 1 when either is 1. EOR (exclusive OR) produces 1 when they differ. NOT inverts every bit. Binary view makes leading zeroes and all 16 positions visible.
A
B
AND
OR
EOR
0
0
0
0
0
0
1
0
1
1
1
0
0
1
1
1
1
1
1
0
Assemble and step in Binary view, watching word 3 at 109–112. The final values are 34, 59, 26 and 65494 (unsigned decimal). AND masks selected bits; OR sets selected bits; EOR toggles them. NOT operates on all 16 bits, which is why inverting a short-looking binary constant can produce a large unsigned value.
5.2 Logical and arithmetic shifts
LSL #n,destination shifts left and inserts zeroes; LSR shifts right and inserts zeroes. C records the last bit shifted out. ASR shifts right while preserving the sign bit. ASL shifts left and signals signed overflow if the sign changes during the shift. Without overflow or discarded bits, left shift by one doubles an unsigned value.
Step and inspect cells 109–112 in Binary view.
The first result is 344; logical right shift gives 3 at 110.
Compare ASR on $F000 with LSR on the same value. ASR repeats the leading 1, while LSR inserts 0.
Change a count to 1 and predict both the result and carry before stepping.
5.3 Rotating left and right
ROL moves the high bit around to the low position; ROR moves the low bit around to the high position. The outgoing bit also appears in C. Unlike a logical shift, a rotate recirculates the bits. The supplied example leaves 344 at 109 and 36865 ($9001) at 110.
Try it: use $8001 as a starting value and rotate right once. Predict $C000 with carry set. Explain why shifting right gives a different result.
6 · Interrupts
Learn to: distinguish polling from interrupts, install a handler, enable keyboard interrupts and return with RTE.
6.1 Let the machine interrupt its main task
A polling loop repeatedly asks whether input has arrived. An interrupt lets the main program continue other work until an event requests service. The machine finishes its current instruction, saves its register state, runs the handler, then resumes the main program.
6.2 Keyboard interrupts in ASMTutor
A keyboard button writes its ASCII value into cell 4 and sets INT.
Cell 1 holds the interrupt handler’s starting address.
SR bit 4 enables interrupts here: set it with OR #$0010,SR.
The handler ends with RTE, which restores the saved R0–R7, PC, SP and SR. Its changes to memory remain.
Load the example and set a breakpoint at 105, the handler entry.
Assemble. Step the first two instructions: address 105 is installed in cell 1, then interrupts are enabled.
Run. The main program repeatedly increments R0 at 102 and jumps back from 103.
Click a keyboard letter. Execution pauses at the handler breakpoint. Record the main counter in R0.
Step through 105 and 106: R0 temporarily receives the key and mapped cell 10 displays it.
Step RTE at 107. R0 returns to the saved main-counter value, and PC resumes the main loop. The mapped character stays visible.
Use Stop, then Edit program. Remove the OR instruction’s enabling effect and compare behaviour: the buffer and INT can change while the handler remains uncalled.
Use RTE only to finish an interrupt handler; RTS is for ordinary subroutines. Returning with the wrong instruction loses the intended saved-context behaviour. The main example loops until stopped.
Check yourself: Why does R0 recover its counter value after RTE while the character at address 10 remains? What two settings are needed before an interrupt can reach your handler?
7 · What now?
Learn to: recognise which ideas transfer to other processors and which details belong to this teaching machine.
7.1 Moving to another system
Registers, addresses, arithmetic flags, conditional branches, subroutines and interrupts are widely useful ideas. Their exact encodings and conventions change between machines. Read the target processor’s instruction-set and system documentation before translating a program.
Memory: many systems address individual 8-bit bytes. ASMTutor instead gives each instruction one 48-bit cell and lets normal data operations touch its low 16 bits.
Instruction length: one ASMTutor instruction always advances by one cell. Other processors can have different or variable instruction sizes.
Instruction set: ASMTutor resembles some Motorola-style conventions, but its encodings, available modes, explicit PUSH/POP and division layout are specific to this simulator.
System services: addresses 86–89 and keyboard cells 1/4 are ASMTutor conventions. Another machine uses different APIs, registers, interrupt vectors and device interfaces.
Registers: register sizes and names vary. For example, the Intel 8086 has a 16-bit architecture; do not carry over the original manual’s description of it as an 8-bit processor.
Bring the ideas together
NameAge combines strings, a buffer, numeric input and output. Run it, enter a name, resume, enter an age, then resume again. Follow how R5 keeps the age while R0 is reused for string addresses. Its output concatenates the age and “years” without an extra space; find where you would add one.
Scroll repeatedly fills the ten mapped characters from a zero-terminated string. Step through its indirect reads and base-offset writes, then run it slowly. Locate the reset logic when the end of the string is reached. Use Stop to pause it.
Independent projects
Write a ten-character message to addresses 5–14 using a loop.
Read numbers until a sentinel is entered and keep a running total in another register.
Write a subroutine that preserves its caller’s temporary register using PUSH and POP.
Modify the interrupt handler to put consecutive keys into different mapped positions.
Before moving on: explain one program from its machine words, predict a branch from SR flags, trace a subroutine return through the stack, and describe the difference between a keyboard request and an enabled interrupt.