**PowerPC assembly language
beginners guide.**

**Logical Operations**

**AND**

Logical operations are quite simple to understand and form
a useful tool within the programmers armory. An "and"
operation simply says if both A **and** B are equal to a logical
1, then set the result to a 1. Logical operations work at a bit
level - each bit of both operands is logically tested and the
same numbered bit in the destination is set or cleared as a result
of the logical operation as applied to each bit. We humans can
work them out serially; by starting at the first bit of each operand
and making a note of the result of each operation. The CPU operates
on all bits in parallel, hence all logical operations (in common
with most PowerPC instructions) have an effective processing time
of one cycle. The exception to this timing are integer multiplies
and divides - avoid these like the plague if you can or use the
FPU which is a multiply-add unit and can perform single sized
(32 bit) multiplies in one clock cycle effectively and double
sized (64 bit) multiplies in two.

Back to the logic...

Suppose we "and" 1 and 9. If we look at the number in binary, 1 is 0001 and 9 is 1001. When these two numbers are anded, the processor looks at the numbers like this:

`3210 <- Bit number`

0001 <- 1 in binary

1001 <- 9 in binary

0001 <- result

First it will look at both bit 3's. It says I have a 1 and a 0, so I don't have two 1's. Therefore the result is zero. Then it looks at bit 2's, which are both zero, so the result is zero. Bits 1 are both zero, so the result is zero. Bits 0 are both 1. It says if I have a 1 "and" a 1 then the result is 1, so bit zero result is 1.

The result of 9 anded with 1 is 1.

The and operation can be summarised by saying "only if both bits are set will the result be set"

Examine the following examples, to see if you can spot the main use of the "and" instruction.

What is the result of 0xFA anded with 0x0F?

0xFA = 11111010 0x0F = 00001111 AND = 00001010 = 0x0A

What is the result of 0xF1 anded with 0x0F?

0xF1 = 11110001 0x0F = 00001111 AND = 00000001 = 0x01

What is the result of 0x1220 anded with 0x00FF

0x1220 = 0001001000100000 0x00FF = 0000000011111111 AND = 0000000000100000 = 0x0020

The **and** instruction is mostly used to mask off wanted
data in a register. By setting bits in the *mask *that identifies
the bits you want to keep, and then anding this mask with the
data, the bits you are not interested in will be set to zero.

For example if you had a routine that returns the ASCII value of a key pressed on the keyboard, and it returned the key in r3. The key can be specified in a byte, but there may be data from earlier processing in the upper three bytes of r3 - so to ensure you don't create errors further in the program, the byte can be masked off with the and instruction as follows:

andi. r3,r3,0xff

Irrespective of how much garbage is in the upper 24 bits of r3, after this instruction all that will be left in r3 is the byte defining the key press, the lower 8 bits. Note in particular the trinary operands and the dot at the end of the instruction.

If we wanted we could leave the contents of r3 intact and place the results of the AND operation in another register, say r4, with an instruction such as:

andi. r4,r3,0xff

The dot means that this instruction always affects the condition code register; a note is made of the result of the operation. If for example, the result of the AND was that all bits were cleared, then the Z (or zero) flag inthe condition code register was set. We will examine the condition code register in more detail later, but for now just note that there are 8 integer condition register "fields". An instruction followed by a dot means that the condition code register field 0 is affected - it notes the result of the operation. NOTE also that immediate type instructions such as andi. always work with 16 bit unsigned immediate data. There are shifted forms of the instructions which will affect the upper 16 bits of a 32 bit register, as an example see the movei macro from chapter 2.

Examples of possible **and** instructions:

AND - **and[.] rx,ry,rz**

The contents of register rz is anded with register ry and the
resultant 32 bit pattern is stored in rx.

AND with complement - **andc[.] rx,ry,rz**

The contents of register ry are anded with the complement of rz
and the resultant 32 bit pattern is stored in rx. Complement means
the inverse of - for example %1010 when complemented becomes %0101.
Not to be confused with two's complement which is how computers
subtract via addition. Two complement means to invert the data
and then add 1.

AND Immediate - **andi. rx,ry,ui**

The contents of register ry are anded with the ui and the result
stored in rx. Note that in this case, the upper 16 bits of the
result will be cleared because ui is a 16 bit quantity! Note that
this instruction is always dotted.

AND Immediate shifted - **andis. rx,ry,ui**

This is basically the same as andi, except the ui is shifted left
16 bits before being anded with ry, so the lower 16 bits of rx
will always be cleared after this instruction.

**OR**

The OR instruction works like this:

If either or both of the bits are 1, then the result bit is a 1. The other way of looking at it is "If both bits are a zero then the result is a zero, otherwise its a 1".

Example - OR 1 with 2

`1 = 0001`

2 = 0010

OR= 0011 = 0x03

In PowerPC, the possible instructions are basically the same
as **and** as follows:

OR immediate - **ori rx,ry,ui** (note no dot allowed unlike
andi. which must have one)

OR immediate shifted - **oris rx,ry,ui **(note no dot allowed
unlike andis. which must have one)

OR - **or[.] rx,ry,rz**

OR with complement - **orc[.] rx,ry,rz**

Fantasm uses the ori instruction to provide the "extended mnemonic" nop which stands for NO Operation:

**nop** is the same as ori 0,0,0

The or instruction is used to provide the useful extended mnemonic mr, which means move from one register to another:

**mr rx,ry** - move the contents of ry into rx and is the
same as or rx,ry,ry

**XOR**

The eXclusive OR instruction works like:

"If one bit is a 1 and one bit is 0 then the result is 1, otherwise the result is 0".

Example - XOR 1 with 15

1 = 0001 15 = 1111 XOR= 1110 = decimal 14 or 0x0e

XOR 0 with 1

1 = 0000 0 = 0001 XOR= 0001, so the result is 1.

If we XOR the result with 1 again we get a 0 because both bits are now a 1. This is a neat way of toggling a bit, every time a loop executes for example. Initially the bit is set to 1. Each time round the loop, the bit is XOR'd with 1. Every time the loop executes. if the bit is a 1 its set to a 0, and if its a 0 its set to a 1.

What'sthe use of this? Suppose you want to flash something, say an alien spaceship on the screen between red and yellow. You simply xor the colour control bit with 1 and if it was a 1, use the colour red or if it was a zero use the colour yellow.

Possible XOR instructions:

xor immediate - **xori rx,ry,ui**

xor immediate shifted - **xoris rx,ry,ui**

xor - **xor[.] rx,ry,rz**

**Miscellaneous logical instructions**

**NOR** - NOT OR

NOT means to invert, so NOR performs an OR operation on the two operands, then inverts the result and stores it in the destination register:

**nor[.] rx,ry,rz** - the contents of ry are ORed with the
contents of rz, then the result is inverted and stored in rx.

Fantasm uses the NOR instruction to provide the "extended instruction" NOT:

**not rx,ry** is the same as nor rx,ry,ry

**NAND - NOT AND**

NAND performs and AND operation on the two operands, inverts the result and stores it in the destination register.

**nand[.] rx,ry,rz**

**EQV - Equivalent**

**eqv[.] rx,ry,rz** - the contents of ry are XORed with
the contents of rz, the result is inverted and stored in rx.

**Sign extension instructions**

Extend sign byte, Extend sign halfword, Extend sign word

**extsb[.] rx,ry
extsh[.] rx,ry
extsw[.] rx,ry**

These instructions copy the sized data (byte, half or word) to another or the same register and sign extend the result, so

extsb rx,ry copies the byte out of ry into rx and copies bit
7 to bits 8 through 31 of rx.

extsh rx,ry copies the lower 16 bits out of ry into rx and copies
bit 15 to bits 16 through 31 of rx.

extsw rx,ry is a 64 bit instruction that is illegal on 32 processors
such as 601/3/4. It copies the lower 32 bits out of ry into rx
and copies bit 31 to bits 32 through 63 of rx.

*NOTE that Fantasm 5 will assemble most 64 bit instructions
(i.e. PowerPC 620 processor) just fine - you can turn on warnings
about their use from Fantasm's preferences pane.*

**Count Leading Zeros (Word or Double)**

**cntlzw[.] rx,ry
cntlzd[.] rx,ry**

These two instructions, one for 32 bit architectures and one for 64 bit (the double form) counts how many zeros from the leftmost bit position until the first binary 1 is encountered. The count is stored in the destination register.

We mentioned about the dotted form of some instructions and that if the dot was used the condition flags would be set. Your first question may be why not use them all the time? The answer is simply that to set the condition register flags the processor needs to do more work. Sometimes you may not care if the result of a logical operation was zero or not - you just want the data. In this case you would not use the dotted form. Some times you do need to know so you can make a decision based on the outcome of the operation; in this case you would use the dotted form.

This will form the basis of the next chapter, where we'll be looking at the processor in more detail and examining the condition register and branch processor in general along with a closer look at the whole architecture and introducing the branch processor instructions. We will then have enough information "under our belts" to be able to produce some rudimentary programmes to introduce more integer instructions.

In the mean-time, it would be worthwhile revising the first three chapters and if you're not subscribed to the Fantasm list server maybe you'd like to consider it. Some very useful discussions crop up from time to time.