Syllabus coverage
- The basic von Neumann model for a computer system and the stored program concept
- The purpose and role of registers, including the difference between general purpose and special purpose registers
- The role of the special purpose registers: program counter (PC), memory data register (MDR), memory address register (MAR), accumulator (ACC), index register (IX), current instruction register (CIR) and status register
- The purpose and roles of the arithmetic and logic unit (ALU), control unit (CU), system clock and immediate access store (IAS)
- How data are transferred between components using the address bus, data bus and control bus
- Factors that contribute to the performance of a computer system: processor type and number of cores, bus width, clock speed and cache memory
- How different ports provide connection to peripheral devices, including USB, HDMI and VGA
- The stages of the fetch-execute cycle, described and used in register transfer notation
- The purpose of interrupts, including possible causes, applications, the use of an interrupt service routine (ISR), when interrupts are detected during the fetch-execute cycle and how they are handled
- The relationship between assembly language and machine code
- The stages of the assembly process for a two-pass assembler, applied to a simple program, and tracing a simple assembly language program
- Instruction groups: data movement, input and output, arithmetic, unconditional and conditional instructions, and compare instructions
- Addressing modes: immediate, direct, indirect, indexed and relative
- Binary shifts: logical, arithmetic and cyclic, left and right, and bit manipulation to monitor or control a device using bit masking to test and set a bit
Part of the AS & A Level Computer Science syllabus 9618.
The von Neumann model and the stored program concept
Almost every computer you will use is built on the von Neumann model, set out by John von Neumann in 1945. In this model the computer has three main parts: a central processing unit (CPU), main memory, and input and output devices. The CPU itself contains three things: the arithmetic and logic unit (ALU), the control unit (CU) and a set of registers. Everything the computer does is done by moving values between these parts and changing them in the ALU.
The idea that makes the model work is the stored program concept: the instructions of a program and the data it works on are held in the same main memory, in the same binary form, and are fetched one at a time and executed in sequence. Because an instruction is just a pattern of bits in memory, the machine does not have to be rebuilt for a new job - you load a different program and it does a different job. The CPU cannot tell an instruction from a data value by looking at it; it treats a value as an instruction only because the program counter pointed at it during a fetch.
The immediate access store (IAS) is the part of the computer that holds the programs and data currently in use. It is directly accessible by the CPU without any slow transfer from backing store, which is why it is measured in gigabytes and why its contents are lost when the power is switched off. The ALU carries out all the arithmetic (add, subtract, increment, decrement) and all the logical operations (AND, OR, XOR, shifts, comparisons). The control unit directs and coordinates everything: it decodes each instruction, then sends control signals along the control bus to the other components so that the right data is moved at the right time. The system clock produces a continuous series of pulses that synchronise every operation; each stage of the fetch-execute cycle takes a whole number of clock cycles, and the clock speed in gigahertz tells you how many cycles happen each second.
| Component | What it does |
|---|---|
| CPU | Processes instructions: contains the ALU, the control unit and the registers |
| Arithmetic and logic unit (ALU) | Carries out arithmetic operations (add, subtract) and logical operations (AND, OR, XOR, shifts, comparisons) |
| Control unit (CU) | Decodes instructions, directs the fetch-execute cycle and sends control signals along the control bus to the other components |
| System clock | Generates regular pulses that synchronise the components; clock speed is measured in hertz or gigahertz |
| Immediate access store (IAS) | Main memory: holds the program and data currently in use and is directly accessible by the CPU |
| Registers | Very fast storage inside the CPU that holds the values being worked on and the addresses and instructions in use |
Registers: general purpose and special purpose
A register is a small, very fast storage location inside the CPU, built from flip-flops and holding a fixed number of bits, usually the word length of the processor. Registers are far faster than main memory, which is exactly why the values being used at that instant are held in them rather than being fetched from memory every time they are needed.
The difference the syllabus asks for is between general purpose and special purpose registers. A general purpose register holds data or an address while the processor is working on it, and it can be used for any purpose the programmer chooses. A special purpose register has one fixed job given to it by the design of the processor, and you cannot use it for anything else. The syllabus names seven special purpose registers: the program counter (PC), the memory data register (MDR), the memory address register (MAR), the accumulator (ACC), the index register (IX), the current instruction register (CIR) and the status register. In the assembly language of section 4.2 you are told to assume that only one general purpose register is available, the accumulator.
The program counter holds the address of the next instruction to be fetched. During the fetch stage it is incremented so that it always points at the following instruction, and an instruction that jumps (such as JMP) works by loading a new value into it. The memory address register holds the address of the memory location that is about to be read from or written to, and it is connected directly to the address bus. The memory data register holds the data or instruction that has just been read from that location, or the data that is about to be written there, and it is connected directly to the data bus. Since main memory is separate from the CPU, every item that goes in or out passes through the MDR.
The current instruction register holds the instruction that is currently being decoded and executed, split into its opcode (what to do) and its operand (what to do it to). The accumulator holds the data being processed and the result of the operation, so in this instruction set the answer always ends up in the ACC. The index register holds a number used in indexed addressing, where it is added to the operand to form the address to be used. The status register holds the flags set by the last operation in the ALU - for example whether the result was zero, whether it was negative, whether it carried out of the top bit, or whether it overflowed - and those flags are what conditional instructions test.
| Register | What it holds | Why it matters in the fetch-execute cycle |
|---|---|---|
| Program counter (PC) | The address of the next instruction to be fetched | Incremented during the fetch; overwritten by a jump, so it decides which instruction runs next |
| Memory address register (MAR) | The address of the memory location being read from or written to | Connected to the address bus; set from the PC during a fetch and from the operand during an execute |
| Memory data register (MDR) | The data or instruction just read from memory, or about to be written to memory | Connected to the data bus; the buffer between the CPU and main memory |
| Current instruction register (CIR) | The instruction currently being decoded and executed, as opcode and operand | The control unit decodes the opcode held here |
| Accumulator (ACC) | The data being worked on and the result of the last operation | Every arithmetic and logical instruction in this instruction set uses it |
| Index register (IX) | A value added to the operand in indexed addressing | Lets one instruction walk through a table of values |
| Status register | Flags from the last ALU operation, such as zero, negative, carry and overflow | Tested by compare and conditional jump instructions |
The three buses and the fetch-execute cycle
A bus is a set of parallel wires that carries signals between the components of a computer. There are three, and they all connect the CPU to main memory and to the input and output devices. The address bus is unidirectional - the address travels from the CPU out to memory and never the other way - and it carries the address of the location that is being read or written. Its width sets the maximum amount of memory that can be addressed: n address lines give 2^n locations, so 32 lines allow 4 GiB of memory. The data bus is bidirectional and carries the data and the instructions themselves; its width decides how many bits move in one transfer. The control bus carries the individual control signals, such as memory read, memory write, the clock pulses, an interrupt request from a device and a reset signal.
The fetch-execute cycle is the sequence the CPU repeats for every instruction. It has two main stages, fetch and execute, with a decode step in between; some descriptions add a store or write-back stage when a value is written to memory. Examiners ask for the fetch stage in register transfer notation, where square brackets mean 'the contents of' and a statement is read left to right as 'this receives that'.
The fetch stage in register transfer notation is short enough to learn by heart. The address in the program counter is copied to the memory address register, the program counter is incremented so that it points to the next instruction, the instruction is read from memory into the memory data register, and it is then copied into the current instruction register: MAR <- [PC], then PC <- [PC] + 1, then MDR <- [[MAR]], then CIR <- [MDR]. The double brackets mean 'the contents of the location whose address is in the MAR'.
In the decode step the control unit splits the instruction in the CIR into opcode and operand and works out what has to be done. In the execute step the work depends on the instruction: for LDD 200 the address in the operand is copied to the MAR, the data is read into the MDR, and then copied to the ACC; for STO 300 the ACC is copied into the MDR and written to the address in the MAR; for ADD #5 the ALU adds 5 to the ACC; for JMP 40 the value 40 is copied into the PC, which is why the next fetch takes the instruction from a different place.
| Stage | What happens | Register transfer notation |
|---|---|---|
| Fetch - address | The address of the next instruction is copied from the PC to the MAR | MAR <- [PC] |
| Fetch - increment | The PC is incremented so that it points at the following instruction | PC <- [PC] + 1 |
| Fetch - read | The instruction is read from the address in the MAR into the MDR over the data bus | MDR <- [[MAR]] |
| Fetch - store | The instruction is copied from the MDR into the CIR | CIR <- [MDR] |
| Decode | The control unit splits the CIR contents into opcode and operand and identifies the operation | No transfer - the CU decodes [CIR] |
| Execute (LDD 200) | The operand address goes to the MAR, the data is read into the MDR and copied to the ACC | MAR <- 200; MDR <- [[MAR]]; ACC <- [MDR] |
| Execute (ADD 210) | The data at the given address is added to the ACC | MAR <- 210; MDR <- [[MAR]]; ACC <- [ACC] + [MDR] |
| Execute (JMP 40) | The jump address is copied into the PC, so the next fetch starts there | PC <- 40 |
Interrupts: causes, applications and handling
An interrupt is a signal sent to the processor, from hardware or from software, that tells it something needs attention. The processor suspends the program it is running, saves where it had got to, runs a short routine to deal with whatever caused the interrupt, and then carries on as if nothing had happened. Without interrupts the processor would either have to stop and check every device constantly (polling) or ignore the devices until the program finished.
The causes are best grouped as hardware and software. Hardware causes include a key being pressed or a mouse being clicked, a printer running out of paper or its buffer becoming full, a transfer to or from a disk finishing, a pulse from the system clock (the timer interrupt that lets an operating system share the processor between programs), a power failure and a hardware fault. Software causes include a program attempting to divide by zero, an attempt to execute an instruction that does not exist, and a program asking the operating system to do something for it.
The applications follow from those causes. Interrupts let the processor respond to input immediately without wasting time checking devices. They make multitasking possible, because the timer interrupt takes control away from one program and gives it to the next. They allow real-time systems, such as a car's engine management or a hospital monitor, to react within a guaranteed time. They also let errors and hardware failures be handled by the operating system instead of crashing the program that happened to be running.
An interrupt is detected at the end of the execute stage of the fetch-execute cycle, before the next instruction is fetched - never in the middle of an instruction. When one is detected, the processor finishes the instruction it is on, saves the contents of its registers including the PC on the stack, checks the priority of the interrupt (a higher-priority interrupt can interrupt the routine already running), loads the start address of the interrupt service routine (ISR) into the PC, and executes it. The ISR is the short routine written to service that particular device or event. When it finishes, the saved register values and the PC are restored from the stack, so the interrupted program continues from exactly where it stopped.
| Step | What happens |
|---|---|
| 1. Detect | At the end of the execute stage the processor checks whether an interrupt signal is present |
| 2. Complete | The instruction being executed is finished, so that the program is left in a known state |
| 3. Save state | The contents of the registers, including the PC, are pushed onto the stack |
| 4. Check priority | The interrupt is identified and its priority compared with any interrupt already being serviced |
| 5. Branch to the ISR | The start address of the interrupt service routine is loaded into the PC so the ISR runs |
| 6. Service | The ISR deals with the cause - reading the character from the keyboard buffer, refilling the printer buffer, updating the clock |
| 7. Restore | The saved register values and PC are popped from the stack, and the interrupted program resumes |
Factors affecting performance, and ports for peripherals
Clock speed is the number of cycles the system clock produces each second, measured in gigahertz. Every stage of the fetch-execute cycle takes a number of cycles, so a higher clock speed means more cycles per second and therefore more instructions completed per second. The gain is not unlimited: a faster processor still has to wait for slower main memory, and different instructions take different numbers of cycles.
The number of cores matters because each core is effectively a complete processor with its own control unit, ALU and registers. Two cores can be executing two different sets of instructions at the same time, so a program that can be split into parallel threads will finish sooner. The gain depends on the software - a program written as a single sequence of instructions uses one core however many are available - and more cores mean more heat, more power and more competition for the memory and the buses. The processor type covers the rest of the design: the word length it works with, the instruction set, and the size of its caches.
Bus width sets how much can move at once. A wider data bus carries more bits in each transfer, so fewer transfers are needed to move a block of data. A wider address bus means more address lines, and since n lines address 2^n locations, it allows more memory to be fitted. Cache memory is a small amount of very fast memory on or next to the CPU that holds recently used and frequently used instructions and data. Before going to main memory the processor checks the cache; if the value is there - a cache hit - it is obtained far more quickly than a fetch from RAM. Cache is expensive, so it is small compared with main memory, and it is usually organised in levels, with level 1 the smallest and fastest.
- USB (universal serial bus): a general purpose serial port that connects keyboards, mice, printers, cameras and storage devices, is plug and play, can supply power to the device, and can connect several devices through a hub.
- HDMI (high definition multimedia interface): carries high definition digital video and audio to a monitor, projector or television through a single cable.
- VGA (video graphics array): an older port that carries analogue video only, with no audio, to a monitor or projector; it is gradually being replaced by digital connections such as HDMI.
- All three are ports: they provide the physical connection and the agreed set of rules by which a peripheral device exchanges data with the computer.
| Factor | How it improves performance | What limits the gain |
|---|---|---|
| Clock speed | More cycles per second, so more fetch-execute cycles completed per second | Memory cannot supply data as fast as the CPU can use it; more heat; instructions take different numbers of cycles |
| Number of cores | Several sets of instructions are executed at the same time | The software must be written to run in parallel; more power and heat; cores compete for memory and buses |
| Processor type | Word length, instruction set and cache size set the capability of the processor | A better processor costs more and may need different software |
| Bus width | A wider data bus moves more bits per transfer; a wider address bus allows more memory to be addressed | More lines mean more pins, more cost and more power; a wide bus is wasted if memory is slow |
| Cache memory | Frequently used instructions and data are supplied much faster than from main memory | Small capacity and expensive, so only a fraction of the program fits; a cache miss still costs a main memory access |
Assembly language, machine code and the two-pass assembler
Machine code is the set of binary patterns that the processor can execute directly: an opcode that says what to do and an operand that says what to do it to. Assembly language is a low-level language in which each of those instructions is written with a mnemonic (such as LDD or JMP) instead of a binary opcode, and with a symbolic address (such as total) instead of a number. There is essentially a one-to-one relationship between the two: one assembly language instruction is translated into one machine code instruction, which is what makes assembly language different from a high-level language. Because the mnemonics and the instruction set belong to one family of processors, assembly language is machine dependent - a program written for one processor will not run on another without being rewritten - and it must be translated by an assembler before the computer can run it.
The assembler reads the source program twice, which is why it is called a two-pass assembler. The reason is the forward reference: a program frequently jumps to a label that is defined further down the listing, and when the assembler reaches the jump it has not yet met the label and does not know its address. Reading the program twice solves this - the first pass finds out where everything is, and the second pass fills the addresses in.
In pass 1 the assembler sets a location counter to the address where the object code will start, then reads the source line by line. Comments are ignored. Each time it meets a label it adds the label and the current value of the location counter to the symbol table, and it reports an error if a label is defined twice. It then adds the length of the instruction or data item to the location counter and moves on. Data lines, which give a symbolic address to a location holding a constant, are recorded in the same way. Pass 1 produces no machine code at all - its only output is the symbol table.
In pass 2 the assembler reads the source again. For each instruction it looks the mnemonic up in the opcode table to get the binary opcode, takes the operand, and if the operand is a label it looks the label up in the symbol table and substitutes the absolute address it finds there. It then assembles the complete binary instruction and writes it out. Data lines are turned into the binary value they define, and an operand that is not in the symbol table is reported as an undefined label. The output of pass 2 is the object code, which can be loaded and run.
| Pass | What it does | Output |
|---|---|---|
| Pass 1 | Sets the location counter, reads each line, records every label with the current address in the symbol table, checks for duplicate labels, moves the location counter on by the length of each instruction or data item | The symbol table, and a list of any duplicate-label errors. No machine code. |
| Pass 2 | Reads each line again, looks up the mnemonic in the opcode table, replaces every label operand with its absolute address from the symbol table, and assembles the binary instruction or data value | The object code (machine code), plus errors such as an undefined label |
Instruction groups and addressing modes
The instruction set you are given is small, and every question uses it, so learn it as groups rather than as a list. Data movement instructions move values between memory, the accumulator and the index register: LDM, LDD, LDI, LDX, LDR and MOV load, and STO stores. Input and output instructions are IN, which reads a character from the keyboard and stores its ASCII value in the ACC, and OUT, which displays the character whose ASCII value is in the ACC. Arithmetic instructions are ADD, SUB, INC and DEC. On top of those there are the unconditional jump JMP, the conditional jumps JPE and JPN, and the compare instructions CMP and CMI, which set the flags that the conditional jumps test.
The operand is written in a way that tells you what kind of value it is: a # means a denary number, so ADD #12 adds twelve; a B means binary, so AND B00101000 uses that bit pattern; a & means hexadecimal, so LDM &4A loads the value 74. An operand in angle brackets is an address, and it can be written as an absolute address such as 200 or as a symbolic address such as total, which the assembler replaces with a number.
The addressing mode is the rule for working out where the operand comes from, and it is the part of this section that loses the most marks. In immediate addressing the operand is the value: LDM #5 puts 5 in the accumulator. In direct addressing the operand is the address of the location holding the value: LDD 200 reads the contents of address 200. In indirect addressing the operand is the address of a location that itself holds the address to use: LDI 300 looks in address 300, finds an address there, and reads the contents of that second address. In indexed addressing the operand is added to the contents of the index register to form the address: LDX 200 with IX holding 4 reads address 204. In relative addressing the operand is an offset from the address of the current instruction, which the processor adds to the program counter, so the code can be moved in memory without changing the instruction.
- Data movement: LDM #n, LDD address, LDI address, LDX address, LDR #n, MOV register, STO address.
- Input and output: IN reads a character and stores its ASCII value in ACC; OUT displays the character whose ASCII value is in ACC - so OUT prints characters, not the number itself.
- Arithmetic: ADD address or ADD #n, SUB address or SUB #n, INC register, DEC register.
- Unconditional jump: JMP address - always goes there.
- Conditional jumps: JPE address jumps if the preceding compare was true (equal), JPN address jumps if it was false (not equal).
- Compare: CMP address, CMP #n and CMI address compare the ACC with a value and set the flags; they do not change the ACC.
- Only the accumulator and the index register can be named directly, so almost every instruction involves the ACC.
| Mode | The operand is | Example | Address actually used | What ends up in the ACC |
|---|---|---|---|---|
| Immediate | The value itself | LDM #5 | None - no memory access for the operand | 5 |
| Direct | The address of the value | LDD 200 | 200 | The contents of address 200 |
| Indirect | The address of a location that holds the address of the value | LDI 300 | The address stored in address 300 | The contents of that second address |
| Indexed | A base address, to which the index register is added | LDX 200 with IX = 4 | 204 | The contents of address 204 |
| Relative | An offset from the current instruction address | JMP +6 at address 40 | 46 | Not applicable - the offset is added to the PC |
Tracing a simple assembly language program
A trace question gives you a program and asks for the contents of the registers and named memory locations after each instruction, or after the program has finished. The method is always the same: draw a table with a column for the ACC, a column for the IX, and a column for every memory location the program writes to. Work down the program one instruction per row, and after each one ask yourself what actually changed - INC IX, for example, changes only the index register, not the accumulator.
Here is a program that adds three numbers stored at addresses 200, 201 and 202 and stores the total in a memory location named total. The two symbolic addresses, total and count, are given absolute addresses by the assembler, and both locations have to be set to zero before the loop starts.
The loop works like this. LDX 200 uses indexed addressing, so on the first pass it reads address 200, on the second pass 201 (because IX has been incremented) and on the third 202. The value read is added to whatever is already in total and stored back. The IX is then incremented, and a separate counter in memory is incremented and compared with 3 - as soon as the count reaches 3 the compare is true, JPN does not jump, and the program falls through to load the total into the ACC and stop.
- LDM #0 - put 0 in the ACC
- STO total - total = 0
- STO count - count = 0
- LDR #0 - put 0 in the IX
- loop: LDX 200 - ACC = contents of (200 + IX)
- ADD total - ACC = ACC + total
- STO total - total = ACC
- INC IX - IX = IX + 1
- LDD count - ACC = count
- INC ACC - ACC = ACC + 1
- STO count - count = ACC
- CMP #3 - compare the count with 3
- JPN loop - jump back if the compare was false
- LDD total - ACC = the total
- END - return control to the operating system
| Pass through the loop | Value read by LDX 200 | total after STO total | IX after INC IX | count after STO count | ACC at the end of the pass | CMP #3 and JPN loop |
|---|---|---|---|---|---|---|
| Before the loop (after the four set-up instructions) | - | 0 | 0 | 0 | 0 | Not yet executed |
| Pass 1 - reads address 200 | 5 | 5 | 1 | 1 | 1 | 1 is not equal to 3, so false - JPN is taken |
| Pass 2 - reads address 201 | 7 | 12 | 2 | 2 | 2 | 2 is not equal to 3, so false - JPN is taken |
| Pass 3 - reads address 202 | 9 | 21 | 3 | 3 | 3 | 3 is equal to 3, so true - JPN is not taken |
| After LDD total | - | 21 | 3 | 3 | 21 | Unchanged |
Bit manipulation: shifts and masking to test and set bits
A shift moves every bit in a register a given number of places to the left or the right. A logical shift moves the bits and fills the empty positions at the end it has moved away from with zeros; any bit shifted off the other end is lost. LSL #n shifts logically left, so zeros come in on the right, and LSR #n shifts logically right, so zeros come in on the left. Because each place is worth a power of two, a logical left shift multiplies the value by 2 for each place and a logical right shift divides by 2 for each place, throwing away the remainder: B00001010 (10) becomes B00010100 (20) after LSL #1, and B00000101 (5) after LSR #1.
An arithmetic shift is used for numbers held in two's complement, where the leftmost bit is the sign. An arithmetic right shift copies the sign bit into the positions vacated on the left, so the sign of the number is preserved while it is halved: B10010110, which is negative, still begins with 1s after the shift. An arithmetic left shift puts zeros on the right, exactly like a logical left shift, but the bit shifted out of the left-hand end is not just lost - if it was not the same as the new sign bit, the number has overflowed and the result is wrong.
A cyclic shift, also called a rotation, moves the bits that leave at one end back into the empty positions at the other end, so no bit is ever lost. A cyclic left shift moves the top bit round to the bottom, and a cyclic right shift moves the bottom bit round to the top. This matters when every bit carries information that must be preserved, as in serial data transmission and in some encryption and hashing techniques, where losing a bit would corrupt the whole pattern.
A bit mask is a bit pattern used with a logical operation to work on particular bits of a value while leaving the rest untouched. The three logical instructions do three different jobs, and mixing them up is the classic mistake. AND is used to test bits and to clear them, because AND with a 1 keeps a bit and AND with a 0 forces it to 0. OR is used to set bits, because OR with a 1 forces a bit to 1 and OR with a 0 leaves it alone. XOR is used to invert or toggle bits, because XOR with a 1 flips a bit and XOR with a 0 leaves it alone; XOR also gives zero when two patterns are identical, which makes it useful for testing whether a value has changed.
The reason this matters is that a single byte read from or written to a device usually carries several pieces of information at once. A status byte might use bit 0 to report that a door is open, bit 1 for a temperature alarm and bit 2 for a pressure fault; an output byte might use each bit to switch one device on or off. To find out about one sensor you must isolate its bit, and to switch one device you must change its bit without disturbing the others. That is exactly what a mask allows.
To test a bit, AND the value with a mask that has a 1 only in the position you are interested in. Every other bit becomes 0, so the result is either zero (the bit was 0) or the mask itself (the bit was 1). Compare the result with 0 and branch on the answer: JPE jumps when the compare was true, that is when the result was 0, and JPN jumps when it was false, that is when the bit was set. To set a bit, OR the value with a mask that has a 1 only in that position. To clear a bit, AND it with a mask that has a 0 only in that position and 1s everywhere else. To toggle a bit, XOR it with a mask that has a 1 only in that position.
- Test bit 2 of the status byte at address 500: LDD 500 then AND #B00000100 then CMP #0, then JPE if the bit was clear and JPN if it was set.
- Set bit 0 of the output byte, leaving the other seven bits alone: OR #B00000001.
- Clear bit 3, leaving the other seven bits alone: AND #B11110111.
- Toggle bit 5: XOR #B00100000.
- Mask for bit n is 2^n written in binary: bit 0 is B00000001, bit 1 is B00000010, bit 2 is B00000100, bit 3 is B00001000.
- The masking instruction is nearly always followed by CMP #0 when the purpose is to test a bit, because AND on its own does not change the flags in a useful way.
| Shift | Bits brought in | Bits that leave | Effect on the value |
|---|---|---|---|
| Logical left, LSL #n | Zeros on the right | The n leftmost bits are lost | Multiplies by 2^n while no 1 is shifted off the left end |
| Logical right, LSR #n | Zeros on the left | The n rightmost bits are lost | Divides by 2^n, discarding the remainder (rounds down) |
| Arithmetic left | Zeros on the right | The leftmost bit is lost | Doubles the value, but overflow occurs if the sign changes |
| Arithmetic right | Copies of the sign bit on the left | The n rightmost bits are lost | Halves a signed value while keeping its sign |
| Cyclic left | The bits shifted off the left end, entering on the right | Nothing is lost | Rotates the pattern; the value is not a simple multiple |
| Cyclic right | The bits shifted off the right end, entering on the left | Nothing is lost | Rotates the pattern the other way |
Key terms you must be able to define
- Von Neumann architecture
- A computer design in which a single CPU, containing the ALU, control unit and registers, works on instructions and data held in one main memory, with input and output devices attached. Instructions and data travel between the CPU and memory over the same buses.
- Stored program concept
- The principle that the instructions of a program and the data it uses are held together in main memory in binary form, so that the machine can be given a different job simply by loading a different program rather than by changing its hardware.
- Immediate access store (IAS)
- Main memory: the store that holds the programs and data currently in use and can be accessed directly by the CPU without a transfer from backing store. Its contents are lost when the power is turned off.
- Program counter (PC)
- The special purpose register that holds the address of the next instruction to be fetched. It is incremented during the fetch stage and overwritten when a jump is executed.
- Memory address register (MAR)
- The special purpose register that holds the address of the memory location currently being read from or written to. It is connected to the address bus.
- Memory data register (MDR)
- The special purpose register that holds the data or instruction just read from memory, or the data about to be written to memory. It is connected to the data bus and is the buffer between the CPU and main memory.
- Current instruction register (CIR)
- The special purpose register that holds the instruction currently being decoded and executed, divided into its opcode and its operand.
- Index register (IX)
- The special purpose register used in indexed addressing, where its contents are added to the operand to form the address of the location to be used. Incrementing it lets one instruction walk through a table of values.
- Status register
- The special purpose register that holds the flags set by the last operation in the ALU, such as whether the result was zero, negative, or produced a carry or an overflow. Conditional instructions test these flags.
- Interrupt
- A signal sent to the processor from hardware or software that causes the current program to be suspended so that a more urgent event can be dealt with. It is detected at the end of the execute stage of the fetch-execute cycle.
- Interrupt service routine (ISR)
- The short routine written to deal with one particular interrupt - reading a character from the keyboard buffer, for example. Its address is loaded into the PC when the interrupt is handled, and control returns to the interrupted program when it ends.
- Assembly language
- A low-level programming language in which each machine code instruction is written using a mnemonic for the opcode and a symbolic address for the operand. It is machine dependent and must be translated into machine code by an assembler.
- Two-pass assembler
- An assembler that reads the source program twice: the first pass builds the symbol table by recording the address of every label, and the second pass translates each mnemonic into a binary opcode and replaces each label with its absolute address. Two passes are needed because a program may refer to a label before it is defined.
- Bit mask
- A bit pattern used with a logical operation to test, set, clear or toggle particular bits of a value while leaving the other bits unchanged. AND masks test or clear, OR masks set, and XOR masks toggle.
Applied to real systems
9618 sets its questions inside systems you already use - a phone, a school network, a supermarket till, a website, a bank. These show how to apply the theory to a context you have not seen before, then you write your own.
The Arm Cortex-M0+ is a small 32-bit processor used in microcontrollers, the kind of chip that runs a washing machine or a fitness tracker. It has the components of the von Neumann model in the form the syllabus describes: an ALU, a control unit, a program counter, a status register holding condition flags, a stack pointer, and a small number of general purpose registers. Instructions are read from flash memory into the processor, decoded, and executed one at a time, with the PC incremented as each is fetched. It shows why the model is still the right description of a modern processor, and why each register has a job fixed by the hardware rather than by the programmer.
When you press a key while a spreadsheet is recalculating, the spreadsheet does not have to check the keyboard itself. The keyboard controller sends an interrupt request, and at the end of the instruction being executed the processor saves its registers and the PC on the stack and branches to the keyboard driver's interrupt service routine, which reads the scan code and places the character in a buffer. The driver returns, the saved state is restored and the recalculation continues from exactly where it stopped. The same mechanism, driven by the timer interrupt, is what lets the operating system take the processor away from one application and give it to another, which is how multitasking works.
In embedded systems, several devices are often wired to the individual bits of one output port, so a single byte written to that port switches eight things on or off at once - a motor, a pump, a heater, a set of indicator lamps. To switch the heater on, the program reads the current byte, ORs it with a mask containing a 1 only in the heater's bit, and writes it back; to switch it off, the program ANDs the byte with a mask containing a 0 only in that position. Anything that overwrote the whole byte would switch the other seven devices on or off as a side effect, which is why the mask has to leave every other bit alone.
A typical desktop processor has several cores, each with its own small level 1 and level 2 caches and a larger level 3 cache shared between them. The caches are what keep the cores supplied: a fetch from cache takes a fraction of the time of a fetch from main memory, so a program that keeps reusing the same data runs much faster than one that streams through a large file. Adding cores helps a video encoder, which can split a frame into independent blocks, far more than it helps a program that must do one calculation after another. This is the trade-off the performance question is really asking about: each factor helps, but only when the work and the memory system allow it.
Flashcards
Click a card to flip it. Mark honestly — the tracker uses this.
Exam-style questions
8 questions, 27 marks. Write your answer, then reveal the mark scheme and tick each point you actually made. Answering honestly here is what makes the rest of the site useful.
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Exam technique for this topic
- Learn the fetch stage as four register transfer statements in order - MAR <- [PC], PC <- [PC] + 1, MDR <- [[MAR]], CIR <- [MDR] - and use the square bracket notation the mark scheme expects. A sentence such as 'the CPU fetches the instruction from memory' earns nothing, while those four lines usually earn four marks.
- Keep the registers apart by asking what each one holds: an address (PC, MAR), data found at that address (MDR), an instruction (CIR), a value being worked on or a result (ACC), an offset (IX). Most register mistakes are really one register being described as another.
- For a trace question, draw a table before you write anything, with a column for the ACC, one for the IX and one for each memory location that the program writes to. Work one instruction per row, and write the new value even when it has not changed - the row is still evidence for a mark.
- In bit manipulation questions, convert every mask to binary first and check its length: an 8-bit value needs an 8-bit mask. Then choose the operation by purpose - AND to test or clear, OR to set, XOR to toggle - and remember that a test needs a CMP #0 and a conditional jump after the AND.
- For the two-pass assembler, write the answer as two clearly separated paragraphs, one per pass, and say what each pass produces. The mark is usually for the symbol table in pass 1 and for the opcode lookup and label substitution in pass 2, not for the phrase 'it translates the program'.