A-level Computing 2009/AQA/Processing and Programming Techniques/Machine Operation and Assembly Language

Machine Code
Machine code is a binary programming language and is the form most easily processed by a CPU. Each line of code contains an operator (a binary representation of an instruction) and an operand (the data to be opererated on by the given instruction).

Assembly Language Instructions
Assembly language is an intermediate stage between machine code and high-level language and can usually be converted to machine code by a direct translation. Like machine code, an assembly language instruction contains an operator and one or more operands.

The exact range of instructions available to a processor will vary for each processor. However there are four different types of instructions available to any given processor:

Data Transfer Instructions
Data transfer instructions are used to move data between registers and between registers and main memory.

Arithmetic Instructions
Arithmetic instructions can be used to perform arithmetic functions on the contents of the registers. Some processors allow a range of arithmetic instructions such as addition, subtraction, multiplication, division and incrementation. Some others only allow addition and subtraction.

Logic Instructions
Logic instructions can be used to perform logic functions on the contents of the registers. Some examples of logic instructions are; and, or, xor and not. These can be useful when masking numbers, for instance converting from ASCII to binary representation of numbers or converting from higher to lower case ASCII.

AND
Only when there is the comparison of two 1s is the answer one.

$$\begin{matrix} 1 & 0 & 0 & 1 & 1 & 1 \\ 0 & 0 & 0 & 1 & 0 & 1 \\ - & - & - & - & - & - \\ 0 & 0 & 0 & 1 & 0 & 1 \end{matrix}$$

OR
Only when there are one or more 1s in a comparison is the answer one.

$$\begin{matrix} 1 & 0 & 0 & 1 & 1 & 1 \\ 0 & 0 & 0 & 1 & 0 & 1 \\ - & - & - & - & - & - \\ 1 & 0 & 0 & 1 & 1 & 1 \end{matrix}$$

XOR
or EOR (Exclusive OR / eXclusive OR) Only when there is exactly one 1 in a comparison is the answer one.

$$\begin{matrix} 1 & 0 & 0 & 1 & 1 & 1 \\ 0 & 0 & 0 & 1 & 0 & 1 \\ - & - & - & - & - & - \\ 1 & 0 & 0 & 0 & 1 & 0 \end{matrix}$$

NOT
Flip the 1s to 0s and the 0s to 1s. Useful for Two's Complement.

$$\begin{matrix} 1 & 0 & 0 & 1 & 1 & 1 \\ - & - & - & - & - & - \\ 0 & 1 & 1 & 0 & 0 & 0 \end{matrix}$$

Masking
Example of conversion from ASCII to binary representation of a number: The ASCII representation of the denary number 3 is $$0011\ 0011$$ The binary representation is $$0000\ 0011$$ So to convert from ASCII to binary we need to mask out the first four bits of the binary representation and maintain the last four bits. There are several ways to do this. AND solution $$\begin{matrix} ASCII & 0 & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ mask & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\ - & - & - & - & - & - & - & - & - \\ binary & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \end{matrix}$$ Note that we have set the last four bits to 1, try converting another ASCII number and see if this mask works for all of them? XOR solution $$\begin{matrix} ASCII & 0 & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ mask & 0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 \\ - & - & - & - & - & - & - & - & - \\ binary & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \end{matrix}$$ Note that we only set the two bits different between the ASCII and binary to 1. Try this mask for other ASCII numbers

Rules of Thumb AND, if you want to keep a part of a number, AND 1 with it. If you want to blank out part of a number, AND 0 with it. OR, if you want to keep a part of a number, OR 0 with it. If you want to set part of a number, OR 1 with it. XOR, if you want to keep a part of a number, XOR 0 with it. If you change a one to a zero XOR a 1 with it.

Dealing with don't care
The exam may ask you questions where you have to build a mask for a particular number, checking for ones and zeros as well as ignoring contents of certain cells. Below is a quick crib table (X = don't care about the input)

AND $$\begin{matrix} desired\;input & 0 & 1 & X \\ mask & 1 & 1 & 0 \\ - & - & - & - \\ result & 0 & 1 & 0 \end{matrix}$$

If you place any other input into the equation other than the desired input the result will come out incorrect. You can now compare this with the number $$0 1 0$$ and if equal then you know the correct input was received.

OR $$\begin{matrix} desired\;input & 0 & 1 & X \\ mask & 0 & 0 & 1 \\ - & - & - & - \\ result & 0 & 1 & 1 \end{matrix}$$

If you place any other input into the equation other than the desired input the result will come out incorrect. You can now compare this with the number $$0 1 0$$ and if equal then you know the correct input was received.

Example in assembly

You are allowed to input the following number only $$0 X 1$$, write some assembly language to check that this works correctly.

AND 1 0 1 CMP 0 0 1 BEQ label

Try writing the OR version of the above code.

Shift Operations
If you look at the binary representations of the following numbers you will notice something peculiar:

0001 = 1 0010 = 2 0100 = 4 1000 = 8

Each time we shift the number one space to the left, the value of the number doubles. This doesn't only work for one bit, take a look at this more complicated example.

0001 0101 = 21 0010 1010 = 42

Again, one shift to the left and the number has doubled. On the other hand, one shift to the right halves the value.

Computers are notoriously bad at doing multiplication and division, it takes lots of CPU time and can really slow your code down. To try and get past this problem computers can shift the values in registers and as long as multiplication or division is by powers of 2, then the CPU time is reduced as the action takes only one line of Machine Code. There are three main types of shifts that processors can perform:

Logical Shift
Shifting either left or right, you add a 0 on the empty end.

Arithmetic Shift
You maintain the sign bit of the number being shifted. Generally only shifts right



Please note the Logical shift example is also an example of an arithmetic shift as the sign remains the same

Circular Shift
The bit that is pushed off one end appears on the other

Test and Branch Instructions
Test and branch instructions are used to test whether a given condition is true or not and then branch to a given instruction depending on the outcome of the test. This makes conditional statements and interation possible.

Computer Instructions
Computers understand instructions in things called words. In a computing context a word is the number of bits a computer can execute at one time. You will get processors that can understand different word sizes, for example the processor on the Sony PlayStation had a 32 bit word size. Sony decided to make the PlayStation 2 better than the original and the word size of the PlayStation 2 was 128 bits. Generally larger word sizes mean faster and more complex CPUs.

The word that a computer can understand is made up of two parts. The first is the type of instruction, or the opcode, the second part contains the variable(s) on which the instruction will execute, or the operand. The operand is sometimes called the address and the following section will explain how a computer can use the operand in different ways.

0 address instruction
This type of instruction takes no parameters and involves Assembly code that doesn't need variables. For example:
 * CLC - clear the carry flag
 * EXIT - exit a subroutine
 * INC - increment the accumulator by 1

1 address instruction
This type of instruction is very useful when you are dealing with only one general purpose register (the accumulator) and takes only one operand. For example
 * LDA #34 - load the accumulator with the denary value of 34
 * ADD 234 - add the value stored at memory location 234 to the accumulator

2 address instruction
This type of instruction can accept two operands and the complexity of operations increases. For example ADD R1, R2 - add R1 to R2 and store the result back into R1

Addressing Formats
There are different methods that a processor can use to calculate the memory address of the instruction being processed or the data being operated on. These are referred to as addressing modes.

Immediate Addressing
This is the addressing mode you have been used to using so far, where the data being operated on is given in the instruction.

Like this: LDA	#35	;Load the number 35 immediately into the accumulator.

Direct Addressing
In direct addressing the location of the data will be given in the instruction.

Like this: LDA	35	;Load the contents of location 35 in to the accumulator.

Indirect Addressing
This is similar to direct address, although instead of the instruction giving the address of the data it gives an address where the address to the data is held. For example. If memory location A0 contained “F1” and memory location F1 contained “42” then to load 42 in to the accumulator the instruction would be:

LDA	(&A0)	;Loads the contents of address given at &A0 in to acc

Relative Addressing
This type of addressing gives a memory location in terms of the current location in memory.

For example: JMP	+10	;branch to the instruction held 10 bytes on.

If this instruction was held at location 1 then it would jump to location 11.

Base Register Addressing
This type of addressing combines the specified with the address held in another location.

LDA &12,B	;loads acc with contents of the address formed by adding the contents of B with the hex address 12.

In this example the address &12 would be added to the address held in B to find the address of the data to be loaded in to the accumulator.

Indexed Addressing
This form of addressing is similar to base register addressing, except that the base addresses are held in an index register. If using this addressing format then the address of an operand can be changed by changing the contents of the index register.

LDA	TABLE,X	;Load in to the ACC the contents of TABLE + x

A story to help you tell the difference
There was once a gangster called the Accumulator, pretty cool name huh? He had a lot of 'business' that he was involved in and had to be paid accordingly. He liked to be paid in several different ways. These were immediately, directly, indirectly, indexed and relative.

When he was paid immediately his goon would give him the money there and then, he got it without having to go find it or solve any clues, he got it immediately.


 * "Boss here's the £5" =
 * "LDA #5"

When he was paid directly he had to do a little bit of work, all across town he had lots of Post boxes that his clients would drop off payments in. He would be given the name of a particular post box and know that if he went there he would find the cash he wanted. He was directed to the cash.


 * "Boss the money is in the postbox at address 1023".
 * = "LDA 1023"

You must understand that the Accumulator had other business friends who were up to some dodgy business and preferred to remain as hidden as possible in their business dealings to keep the cops off their tracks. To do this they used a clever system of putting the money in a post box but instead of directly giving the Accumulator the address they instead gave the Accumulator the address of a postbox that contained the address of the real postbox. They gave him the address indirectly. Sounds a little confusing? Don't worry, hopefully this short transcript will sort things out


 * "Boss the address of where the money is, is in the postbox at 304"
 * The Accumulator opens the postbox at 304 and finds a note saying go to 706
 * When he gets to 706 he finds the money he was looking for
 * = "LDA (304)"

Business for a gangster is not always straight forward and occasionally they have to solve a clue or two to get their money, a bit like in the movies. In the case of an Indexed payment, Accumulator is given a clue to solve, he knows the base address and someone provides a value that must be added to the base value. He adds these two together and bingo he finds the address at which the money he is owed is stored.


 * "Boss the base address you need is 7987"
 * "Boss our sources say that the house your money is stored at is 5 houses up from the base address"
 * the Accumulator looks in 7987+5 (7992) and finds the cash he is looking for
 * = LDA TABLE,X

Assembly Code
Computers can understand only 1s and 0s. To get computers to understand what we want them to do we must get our ideas into these 1s and 0s. You can use High level languages or the low level language of Assembly. In Assembly code every line of code will generally transfer into one line of machine code. Assembly is used in industry to program low level routines and functions and the code produced is usually simple but long.

Instruction sets
An instruction set is the range of different instructions that a CPU can understand. There are two schools of thought, the RISC and the CISC. The RISC - reduced instruction set computer has a small number of different instructions it can perform but it generally does them very fast and efficiently. CISC - complex instruction set computer has a large number of different instructions it can perform but often not as fast as executing them as an equivalent RISC.

For the exam you need to know some basic Assembly instructions that a CPU can understand. We will now look at a range of instructions and then some examples of their use.

Basic instructions

 * ADD #34: add a number to the accumulator and store the value in the accumulator
 * SUB #34: take a number from the accumulator and store the value back in the accumulator
 * DEC: take one from the accumulator
 * INC: add one to the accumulator
 * LDA 34: load the accumulator with the value contained in memory location 34
 * STO 34: store the accumulator value into the memory location 34
 * CMP &34: compare the accumulator against the hexadecimal value of 34 and store the details in the status register
 * BNE label1: if the comparison was not equal then jump to label label1
 * BEQ label1: if the accumulator matched the value being compared the jump to label label1
 * BGT label1: if the accumulator is greater than the value compared jump to label label1
 * BLT label1: if the accumulator was less than the value compared jump to label label1
 * JMP label1: jump directly to label label1, similar to the goto function in some high level languages


 * AND 01001001: 'AND' the accumulator with the value 01001001 storing the result in the accumulator
 * OR 01001001: 'OR' the accumulator with the value 01001001 storing the result in the accumulator
 * XOR 01001001: 'XOR' the accumulator with the value 01001001 storing the result in the accumulator
 * NOT :not the accumulator storing the result back in the accumulator


 * MOV R1, R2: Move the contents of register R1 into register R2

add shift instructions here

Labels
You may have noticed that several of the commands above call for the program to 'jump' to a label called label1. This performs the same function as the 'goto' statement in languages like C. Although the goto statement is frowned on in high level languages, it is essential in Assembly to execute loops and conditional statements. labels will appear like this in code:
 * LDA #40
 * label1:
 * INC
 * CMP #46
 * BLT label1
 * STO 1024

this piece of code loads the accumulator with the value 40. The accumulator is then increased by one and tested against the number 46. If the accumulator is less than 46 then you jump to the label1 to keep incrementing the accumulator. What value will be stored in memory location 1024?

Examples
In the examinations you will be often asked to take a piece of pseudo or real code and convert it into assembly. To make sure the examiner knows what you are doing always write comments with your code. Below are some examples of pseudo code along side their assembly equivalents


 * x = x + 1


 * LDA x
 * INC
 * STO x


 * while (x >= 6)
 * x = x + 1
 * y = y + 4
 * end while


 * while:
 * LDA x
 * CMP #6
 * BLT end
 * INC
 * STO x
 * LDA y
 * ADD #4
 * STO y
 * end:

Quick Check Questions
Provide assembly code that will complete the following tasks:

Q0
y = x + y

Q1
working out the negative two's complement of a given binary number x and storing it back in x

Q2
changing a ASCII lower case letter to its binary equivalent

Q3

 * do x= x-1
 * z++
 * while (z != 10)