← AS/A Level

CS · Chapter 6

Cambridge AS & A Level · Part 1 · Chapter 6

Assembly Language Programming

The language one step above the 1s and 0s the processor actually runs. Learn how instructions are built, how an assembler turns them into machine code, and how each addressing mode finds its data. Then run the book's programs one instruction at a time on a working accumulator machine.

Guru Jazzy
Chapter 6 opener: program code on a screen

🎯 Learning objectives

By the end of this chapter you should be able to:

  • explain how assembly language relates to machine code
  • describe the stages of a two-pass assembler
  • Trace a simple assembly language program
  • describe the instruction groups: data movement, input and output, arithmetic, unconditional and conditional jumps, and comparisons
  • describe the different modes of addressing
  • Show your understanding of binary shifts

🔢 6.01 Machine code instructions

A processor only understands one thing: machine code, its own binary instructions. Programs written any other way have to be translated before they can run.

Opcode: the part of an instruction that says which action to carry out.
Operand: the part of an instruction that supplies the data the action needs, or says where to find it.
Machine code instruction: a binary code with a fixed number of bits. It is made of an opcode and, most often, one operand.

An instruction can have no operand, or up to three. Every processor family has its own instruction set, so machine code written for one kind of processor will not run on another.

When designers create an instruction set, they decide:

  • How many bits make up one instruction
  • How many of those bits are the opcode
  • how many operands there are, and how many bits each one gets
  • whether the opcode sits in the most significant bits or the least significant bits

This chapter uses a simple system: a 16-bit address bus and just one general-purpose register, the accumulator (ACC). Its instructions are 24 bits long.

The instruction format Figure 6.01

Opcode (8 bits, most significant)Operand
Operation
4 bits
Address mode
2 bits
Register addressing
2 bits
16 bits

Four bits of operation allow 16 different operations, and each can be used with up to four addressing modes (two bits). The last two opcode bits pick a register.

In the decode stage of the fetch–execute cycle (Chapter 5) the control unit reads just the opcode. In register transfer notation that is:

CU ← [CIR(23:16)]

Bits 23 down to 16 of the current instruction register are the 8 opcode bits.

🎮 Lab: decode the machine code

A 24-bit instruction from the book's opcode table (Table 6.04) is shown as opcode | operand. Which instruction is it?

🔤 6.02 Assembly language

Writing raw binary is slow and easy to get wrong. A programmer can work at the same level, one instruction per machine instruction, but with readable text instead.

Assembly language: a low-level language. Each opcode is written as a mnemonic (a short memorable name) and each operand is written in characters instead of binary.
Assembler: the program that translates assembly language into machine code.
Directive: an instruction to the assembler itself. It is not translated into a machine code instruction.

An assembly instruction has the same two parts as a machine code instruction: a mnemonic for the opcode, and a character representation of the operand. On top of that, an assembler usually lets the programmer use:

  • Comments, to explain the code
  • Symbolic names for constants
  • Labels in place of addresses
  • macros: a named sequence of instructions that is written once and used more than once
  • directives, such as where in memory to start the program
💬 Discussion Point: Hardly anyone writes whole programs in assembly language any more. What arguments are there for and against using it today?

For: complete control of the hardware; very small, very fast code, which matters for device drivers, embedded systems with tiny memories, and the hottest loops in games or codecs; access to special processor instructions a compiler may not use; understanding what a compiler produces, which helps when debugging and in security work.

Against: slow to write and hard to read; easy to make mistakes; not portable, because it is tied to one instruction set; modern optimising compilers often produce code as good as a person's; a high-level language has libraries, type checking and tools that save huge amounts of time.

🏷️ 6.03 Symbolic, relative and absolute addressing

The same program can be written with three styles of address. The program below takes a number typed at the keyboard as MAX, then reads and adds up that many more single-digit numbers.

Symbolic addressing Table 6.01

Labels name addresses. A label ends with a colon where it is defined; the colon is left off where it is used.

        IN
        SUB #48
        STO MAX
        LDM #0
        STO TOTAL
        STO COUNT
STRTLP: IN
        SUB #48
        ADD TOTAL
        STO TOTAL
        LDD COUNT
        INC ACC
        CMP MAX
        JPN STRTLP
        END
MAX:
TOTAL:
COUNT:
🐞 Spot the bug: after INC ACC the new count is never stored back in COUNT, so COUNT stays 0 and the loop never ends. A fixed version adds STO COUNT straight after INC ACC. You can run both versions in the simulator tab.
📝 Task 6.01 Look up an ASCII code table. Why does SUB #48 appear in the program?

IN puts the ASCII code of the key pressed in ACC, not the number itself. The digit characters '0' to '9' have codes 48 to 57, so taking away 48 turns the character code into the digit's value. For example, '7' is 55, and 55 − 48 = 7.

Relative and absolute addressing Table 6.02

With relative addressing, every address is an offset from the address of the first instruction. That start address is held in a base register, BR, so [BR] + 15 means "15 places after the start". With absolute addressing, the program is fixed at real addresses, here 200 to 217.

OffsetRelativeAddressAbsolute
0IN200IN
1SUB #48201SUB #48
2STO [BR] + 15202STO 215
3LDM #0203LDM #0
4STO [BR] + 16204STO 216
5STO [BR] + 17205STO 217
6IN206IN
7SUB #48207SUB #48
8ADD [BR] + 16208ADD 216
9STO [BR] + 16209STO 216
10LDD [BR] + 17210LDD 217
11INC ACC211INC ACC
12CMP [BR] + 15212CMP 215
13JPN [BR] + 6213JPN 206
14END214END
15MAX215MAX
16TOTAL216TOTAL
17COUNT217COUNT
📖 A note on the book: the coursebook prints the loop jump as [BR] + 7 and JPN 207. Counting from offset 0, the line labelled STRTLP is at offset 6, and the book's own machine code for JPN STRTLP (Table 6.05) has operand 0110 = 6, so 6 is used here.

A relative program can be loaded anywhere: only BR changes. An absolute program only works at the addresses it was written for.

⚙️ 6.04 The two-pass assembler

Before translation starts, the assembler pre-processes the source:

  • Comments are removed
  • macros are expanded: each use of a macro name is replaced by its instructions
  • directives are removed and their information stored for the assembler to use

The problem is the forward reference. STO MAX is the third instruction, but MAX is not defined until the end of the program. When the assembler first meets MAX it has no idea what address it stands for. The answer is to read the program twice.

Pass 1: read every line and count the offset of each one. Build a symbol table: each label gets an entry, and when its definition is found its offset is filled in.
Pass 2: translate each line. The opcode comes from an opcode lookup table; each symbolic address comes from the symbol table.

Symbol table Table 6.03

SymbolOffset
MAX+15
TOTAL+16
COUNT+17
STRTLP+6

The book prints +7 for STRTLP; see the note above.

Opcode lookup Table 6.04

MnemonicOpcode
IN0001 0000
SUB #0110 0001
STO0100 0100
LDM #0010 0001
ADD0100 0101
LDD0010 0101
INC ACC0101 0101
CMP1000 0100
JPN1010 0100
END1111 1111

🔬 Lab: watch the two passes Tables 6.03 – 6.05

Step through pass 1 to build the symbol table. A ? marks a forward reference that is not resolved yet. Then step through pass 2 to produce the machine code (opcode | 16-bit operand).

OffLabelInstructionMachine code
SymbolOffset

The assembled program Table 6.05

The lab above produces the book's Table 6.05. Points to notice:

  • Most operands are 16-bit addresses, but for SUB #48 and LDM #0 the operand is the value itself.
  • IN and END have no operand. INC ACC has none either, because the register is coded inside the opcode.
  • Addresses start at 0. This is valid output from an assembler but it cannot run as it stands: the addresses must be adjusted when the program is loaded into its real place in memory.
  • The last three words are the zeroed storage for MAX, TOTAL and COUNT.

🎮 Your turn: build the symbol table

A fresh program each time. Work out the address of every label, as pass 1 would.

 

🎯 6.05 Addressing modes

Addressing mode: the way the operand is used to find the value an instruction works on.

The four modes Table 6.06

ModeWhat the operand isExample
ImmediateThe value itselfSUB #48
DirectThe address that holds the valueADD TOTAL
IndirectAn address that holds the address of the valueLDI 106
IndexedAn address; add the index register (IX) to it to get the address of the valueLDX 102

An immediate value can be written three ways. These all mean the same number:

Written asBase
#48denary
#B00110000binary
#&30hexadecimal

Relative addressing (section 6.03) is a fifth way to find an address: the operand is an offset added to the base register.

💡 Tip: count the memory look-ups. Immediate needs none, direct needs one, indirect needs two. Indexed needs one, after an addition.

🎮 Name the mode

🧪 Addressing-mode drill

A new memory snapshot every time. Work out what ends up in the accumulator, then check. The path the processor follows is highlighted.

AddressContents

🧰 6.06 Assembly language instructions

The instructions here are typical of a simple processor. They do not belong to any real one, but exam questions use this set. The mnemonic alone tells you the type of instruction, which register it uses and which addressing mode.

Data movement Table 6.07

InstructionWhat it does
LDM #nLoad the number n into ACC (immediate)
LDR #nLoad the number n into IX (immediate)
LDD <address>Copy the contents of the address into ACC (direct)
LDI <address>The address holds a second address; copy the contents of that second address into ACC (indirect)
LDX <address>Add IX to the address to form a new address; copy its contents into ACC (indexed)
MOV <register>Copy the contents of ACC into the register (IX)
STO <address>Store the contents of ACC at the address

Worked examples on one memory snapshot Figure 6.02

AddressContents
100234
101208
102201
103110
104108
105206
106101
107102
INDEXVALUE3
  • LDD 103 copies 110 into ACC.
  • LDI 106: address 106 holds 101, and address 101 holds 208, so ACC becomes 208.
  • STO 106 then writes 208 into address 106.
  • LDD INDEXVALUE puts 3 into ACC.
  • MOV IX copies the 3 into the index register.
  • LDX 102: 102 + 3 = 105, which holds 206, so ACC becomes 206.

Load the Figure 6.02 program in the simulator tab to watch these happen one by one.

Input and output

  • IN waits for a key press and stores that character's ASCII code in ACC.
  • OUT displays the character whose ASCII code is in ACC.

Compare and jump Table 6.08

InstructionWhat it does
JMP <address>Jump to the address (unconditional)
CMP <address>Compare ACC with the contents of the address
CMP #nCompare ACC with the number n
CMI <address>Compare ACC with the contents of the address held at the address (indirect)
JPE <address>After a compare, jump if the compare was True (equal)
JPN <address>After a compare, jump if the compare was False (not equal)

A compare only tests for equality. The True/False result is kept as a flag in the status register. A jump works by overwriting the program counter, which was already incremented during the fetch.

Arithmetic Table 6.09

InstructionWhat it does
ADD <address>Add the contents of the address to ACC
ADD #nAdd the number n to ACC
SUB <address>Subtract the contents of the address from ACC
SUB #nSubtract the number n from ACC
INC <register>Add 1 to ACC or IX
DEC <register>Subtract 1 from ACC or IX

There is no multiply or divide. You have to build them from adds and loops, as in Figure 6.03, which finds how many times 5 goes into 75:

100 LDD 200   ; ACC = 0
101 STO 202   ; count = 0
102 STO 203   ; running total = 0
103 LDD 202   ; loop starts here
104 INC ACC
105 STO 202   ; count + 1
106 LDD 203
107 ADD 201
108 STO 203   ; total + 5
109 CMP 204   ; reached 75?
110 JPN 103   ; no: go round again
111 LDD 202
112 OUT       ; output the count
113 END
200 0
201 5
202
203
204 75
  • 100–102 set up: the count and the total both start at 0.
  • 103 is where each loop starts.
  • 104–105 add 1 to the count.
  • 106–108 add 5 to the total.
  • 109–110 check whether the total has reached 75; if not, jump back.
  • 111–113 output the count, 15, and stop.

Load Figure 6.03 in the simulator. Notice that OUT sends ASCII code 15, which is a control character, not the digits "15". The simulator shows the code so you can see it.

Shift instructions

InstructionWhat it does
LSL #nShift the bits in ACC n places to the left; zeros enter on the right
LSR #nShift the bits in ACC n places to the right; zeros enter on the left
Logical shift: bits move left or right and a zero fills each vacated place. The last bit shifted out goes into the carry bit.
  • A logical shift left by one multiplies an unsigned number by 2, as long as the top bit was 0.
  • A logical shift right by one is integer division by 2; the remainder ends up in the carry bit. For example, 0011 0001 (49) becomes 0001 1000 (24) with carry 1.
  • Logical shifts do not work for signed (two's complement) numbers, because the sign bit gets changed.
Cyclic shift: the bit that drops off one end comes back in at the other end, so no bits are lost.
Arithmetic shift: the sign bit is kept, so a two's complement number keeps its sign when it is halved or doubled.

Bitwise logic Table 6.10

InstructionWhat it does
AND #Bn / AND <address>Bitwise AND of ACC with the operand; result in ACC
XOR #Bn / XOR <address>Bitwise XOR of ACC with the operand; result in ACC
OR #Bn / OR <address>Bitwise OR of ACC with the operand; result in ACC

The operand is called a mask. AND with a 1 keeps a bit and with a 0 clears it; OR with a 1 sets a bit; XOR with a 1 flips it. You will use masks properly in Chapter 7 (section 7.03).

🔬 Lab: the 8-bit register

Tap bits to set the value, then shift or mask it. The dashed box is the carry bit.

🎮 Predict the result

🎮 Which group?

Sort each instruction into its group.

🔍 6.07 Further consideration of the instructions

Register transfer notation

RTN from section 6.01 can describe what an instruction does. For LDD:

ACC ← [[CIR(15:0)]]

Only the 16-bit operand in the CIR matters here. It is an address; the contents of that address are copied into the accumulator.

📝 Task 6.02 Use register transfer notation to describe how an LDI instruction executes.
ACC ← [[[CIR(15:0)]]]

Read it from the inside out: CIR(15:0) is the operand address; one pair of brackets gives the contents of that address, which is a second address; the next pair gives the contents of that second address, which is copied into ACC. One more level of brackets than LDD, because indirect addressing needs one more memory look-up.

Computer arithmetic and the status register

Chapter 1 (section 1.03) showed that arithmetic can overflow and give a wrong answer. Chapter 5 (section 5.02) introduced the status register. Three of its flags let the processor spot an overflow:

  • C, the carry flag: set to 1 if there is a carry out of the top bit
  • N, the negative flag: set to 1 if the result is negative
  • V, the overflow flag: set to 1 if overflow is detected

Worked Example 6.01 · Using the status register in an arithmetic operation

1 Add 66 and 68 in 8-bit two's complement Figure 6.04

  0100 0010   (66)
+ 0100 0100   (68)
  ---------
  1000 0110   (-122)     Flags: N V C = 1 1 0

Two positive numbers have produced a negative answer, which is impossible. The negative flag and the overflow flag are both 1; the processor checks the flags, spots the problem and generates an interrupt.

2 Add −66 and −68 Figure 6.05

   1011 1110   (-66)
+  1011 1100   (-68)
   ---------
(1)0111 1010   (+122)    Flags: N V C = 0 1 1

Two negatives have given a positive. This time the negative flag is 0 while overflow and carry are both 1.

🧠 Extension Question 6.01 Do the same calculation for −66 + 68. What should the processor do with the carry bit?
   1011 1110   (-66)
+  0100 0100   (68)
   ---------
(1)0000 0010   (+2)      Flags: N V C = 0 0 1

The 8-bit answer, 2, is correct. There is a carry out of the top bit, but no overflow, because a positive and a negative number can never overflow when added. For signed (two's complement) arithmetic the processor should simply ignore the carry; it is the V flag that signals an error. The carry only matters for unsigned arithmetic, or when adding numbers bigger than one byte in several steps.

🔬 Lab: flags after an 8-bit addition

🎮 Predict the flags

Set the flags that will be 1:

🖥️ The accumulator machine

This runs the book's instruction set. Choose one of the book's programs, or write your own, then Step through it one instruction at a time. Memory, ACC, IX and the program counter update as you go, and every step is added to the trace table underneath.

  • One instruction or data value per line. A line can start with an address (100 LDD 200) or a label (STRTLP: IN), or both. Lines without an address follow on from the line before.
  • A data line is just a value (204 75, TOTAL: 0). A label or address on its own is an empty word.
  • Values can be denary 48, binary B0011 or hex &30; immediate operands start with #.
  • ; starts a comment. .ACC n and .IX n set the registers before the run; .START a sets where it begins.
  • IN takes from the Input box. Choose whether each key gives its ASCII code, or whether the box holds whole numbers.
  • Shifts and logic work on 8 bits, like the book's examples.

ACC
IX
PC
Last instruction
Compare
AddrLabelContents
StepAddrInstructionACCIXMemoryOutput

🧾 Tracing an assembly language program

A dry run checks a program for errors by following it by hand. The main thing to record is how the accumulator changes, in a trace table.

Worked Example 6.02 · Tracing a program

The trace table needs a column for the accumulator, one for each of two memory locations, and one for output. The inputs are 15, then 27, then 31.

AddressInstruction
100IN
101STO 200
102IN
103STO 201
104IN
105ADD 200
106STO 200
107ADD 201
108INC ACC
109OUT
110END
ACC200201Output
15
15
27
27
31
46
46
73
74
74

Figure 6.06 (program) and Figure 6.07 (trace table)

Here each instruction gets its own row, which makes checking easy. It is also correct to write each value in the next free space in its column, so the 200 column could just read 15, 46. You only record changes: if an instruction leaves a column alone, you do not copy the old value down.

Worked Example 6.03 · A trace with a jump

Instructions are in 100 upwards and 4-bit data values in 200 upwards. ACC already holds 1000 from an earlier instruction.

AddressContents
100LDD 200
101INC ACC
102ADD 201
103CMP 202
104JPE 106
105DEC ACC
106INC ACC
107STO 203
2000001
2010011
2020101
203
PCACC203
1001000
1010001
1020010
1030101
104
106
1070110
1080110

Figure 6.08 (memory before the run) and Figure 6.09 (trace table)

Because there is a jump, the program counter gets a column too.

  • Row 1 is the state before this part runs: ACC holds a value left by an earlier instruction.
  • Row 2: the instruction at 100 loads ACC, and the PC is incremented automatically.
  • Rows 3 and 4: the instructions at 101 and 102 change ACC, and the PC goes up each time.
  • Row 5: just a compare, so ACC does not change, but the PC still increments.
  • Row 6: the PC jumps to 106, because the JPE found the compare was True.
  • Row 7: the instruction at 106 has incremented ACC.
  • Row 8: the value has been stored in 203.
❓ Question 6.01 Can you follow the changes in the trace table for Worked Example 6.03? Could the program change what is stored in one of the locations 100–107 while it runs?

Yes, it could. Instructions and data share the same memory (the von Neumann model), so a STO with an address between 100 and 107 would overwrite an instruction with a data value. This program does not do that, because its only store is to 203. Try adding STO 105 in the simulator: it warns you when an instruction gets overwritten.

📝 Task 6.03 Without looking back at the explanations, trace the program in Table 6.01. Use 3 for MAX, then 7, 8 and 9 as the inputs.

The keys typed are '3', '7', '8', '9', which arrive as ASCII 51, 55, 56, 57. MAX becomes 3. TOTAL goes 0 → 7 → 15 → 24.

COUNT is the catch. It is loaded (0), incremented to 1 and compared with MAX, but it is never stored back. Every loop it is reloaded as 0, so it never reaches 3: after the third input the program waits for a fourth key, forever. With STO COUNT added after INC ACC, COUNT goes 1, 2, 3, the compare is True after the third number and the program ends with TOTAL = 24.

Load Table 6.01 and Table 6.01 (fixed) in the simulator to compare the two traces.

🎮 Trace it yourself

A new program and data every time. Fill in ACC after each instruction, and the value written by each STO. Leave ACC blank when it does not change, as in the book.

 
AddrInstructionACCStored
🪞 Reflection Point: This chapter keeps pointing back to earlier ones: binary and two's complement (Chapter 1), the fetch–execute cycle, registers and the status register (Chapter 5). Have you gone back over those sections to check you can see how the topics connect?

📌 Summary

  • A machine code instruction is made of an opcode and an operand.
  • An assembly language program holds assembly instructions plus directives that give information to the assembler.
  • In its first pass, a two-pass assembler works out the relative addresses of the symbolic addresses.
  • The processor's addressing modes are immediate, direct, indirect and indexed.
  • Instructions fall into groups: data movement, input/output, compare and jump, arithmetic, shift and logical.

🃏 Key-term flashcards

Tap a card to flip it.

✅ Quick quiz

📝 Exam-style questions

Write your answer first, then open the model answer. These are my mark-scheme-style points, not official mark schemes.

Question 1 uses three instructions for a processor whose only general-purpose register is the accumulator: LDD <address> (direct), LDI <address> (indirect) and LDX <address> (indexed). All values are denary. Memory and registers are:

AddressContent
100116
101114
102112
103110
104108
105106
106104
107102

Accumulator: empty

Index register: 3

(i) An arrow from the operand 103 to memory address 103; an arrow from the contents of 103 (110) into the accumulator.

(ii) 110

(i) Arrow from the operand to address 107; its contents, 102, are used as an address, so an arrow from 107's contents to address 102; an arrow from the contents of 102 (112) into the accumulator.

(ii) 112

(i) Arrow from the index register (3) and the operand 103 to an addition: 103 + 3 = 106; an arrow to address 106; an arrow from its contents (104) into the accumulator.

(ii) 104

Any three, each named (1) and its use described (1):

  • Comments: notes that explain what the code does, for people reading it; removed before translation.
  • Directives: instructions to the assembler, e.g. the address to load the program at, or reserving and initialising memory for data; acted on by the assembler, not translated.
  • Macros: a named block of instructions defined once; each use of the name is replaced (expanded) by the full block before translation.
  • Labels / symbolic addresses: names for addresses that are swapped for real (relative) addresses using the symbol table.
  • Symbolic constants: names given to fixed values, replaced by the values during assembly.
100 LDD 201
101 INC ACC
102 STO 202
103 LDI 203
104 DEC ACC
105 STO 201
106 ADD 204
107 STO 201
108 END
201 10
202 0
203 204
204 5
ACC201202203204
01002045
10
11
11
5
4
4
9
9

LDI 203: 203 holds 204, and 204 holds 5, so ACC = 5. The book's listing numbers two lines 105; the second is 106. Try it as an auto-marked trace in the simulator tab (Exam question 2b).

Question 3 refers to this program:

           IN
           STO CHARACTER
           IN
           SUB #48
START:     CMP #0
           JPN OUTPUT
           END
OUTPUT:    OUT
           DEC ACC
           JMP START
CHARACTER:
  • Two key presses.
  • The first is any character; its ASCII code is stored in CHARACTER.
  • The second should be a digit, 0–9.
  • 48 is subtracted from its ASCII code to turn it into the number it represents, which is used as a counter.
  • The loop runs once for each count from the digit down to 1, so it outputs that many characters.
  • If the digit is 0, nothing is output.
  • The intended output is the first character repeated that many times (e.g. "A" then "3" gives AAA).
🔎 Look closely: as printed, OUT sends whatever is in ACC, which is the counter, not CHARACTER. So it actually outputs the characters with ASCII codes n, n−1, … 1 (non-printing control codes). To print the character you would need to keep the counter in memory and LDD CHARACTER before OUT. Run both versions in the simulator to see the difference. Either reading should earn the marks if you explain it.
LabelAddress
START4
OUTPUT7
CHARACTER10

Count the lines from 0: IN (0), STO (1), IN (2), SUB (3), CMP (4) is START, JPN (5), END (6), OUT (7) is OUTPUT, DEC (8), JMP (9), and CHARACTER is the next word, 10.

Question 4 uses this instruction set for a processor with one general-purpose register, the accumulator (ACC), and an index register (IX):

Op codeOperandExplanation
LDD<address>Direct addressing: load the contents of the address into ACC
LDX<address>Indexed addressing: form the address from <address> + IX, then copy the contents of that address into ACC
STO<address>Store ACC at the address
ADD<address>Add the contents of the address to ACC
INC<register>Add 1 to ACC or IX
DEC<register>Subtract 1 from ACC or IX
CMP<address>Compare ACC with the contents of the address
JPE<address>After a compare, jump to the address if it was True
JPN<address>After a compare, jump to the address if it was False
JMP<address>Jump to the address
OUTOutput the character whose ASCII value is in ACC
ENDReturn control to the operating system
AddressContents
600011 0010
610101 1101
620000 0100
631111 1001
640101 0101
651101 1111
660000 1101
670100 1101
680100 0101
690100 0011
…
10000110 1001

Index register: 0000 1000

Accumulator: 0100 0101

IX holds 0000 1000 = 8. The address used is 60 + 8 = 68, and address 68 holds 0100 0101, which is copied into ACC.

Index register: 0000 0111 (8 − 1 = 7)

Cambridge International AS & A Level Computer Science 9608, Paper 11 Q9a, June 2016

Guru Jazzy · Cambridge AS & A Level Computer Science · Chapter 6 Assembly Language Programming · Opener photo from the Cambridge coursebook (Langfield & Duddell)