PA-RISC Instructions

   

The PA-RISC instruction set can be divided into seven general categories of instructions:

  • Memory reference instructions Instructions that explicitly move data to or from memory.

  • Computation instructions Instructions that perform basic arithmetic, logical operations, shifts and rotates, and bit operations.

  • Branch instructions Instructions to alter the order of instructions execution, either conditionally or unconditionally, with or without saving a link pointer to return to the current instruction stream.

  • Multimedia instructions Instructions that perform multiple parallel operations on 16-bit values packed into a single register. These instructions are designed to speed operations typically used in multimedia applications such as signal processing and compression.

  • Floating-point instructions These instructions perform floating-point operations on values stored in the system's floating-point registers

  • System control instructions These instructions perform control functions such as handling interrupts and managing the cache and TLB.

  • Long immediate instructions Instructions that allow the use of an immediate value.

You don't need to know everything about every instruction available in order to get a good grasp of the kernel, but there are a few instructions that are used commonly or that are important to understanding how procedure calls are handled. We look at the memory reference instructions, branch instructions, and long immediate instructions in more detail. Gerry Kane's PA-RISC 2.0 Architecture book has complete details on all the instructions.

Before we get into the details of the instructions, we should mention the format of the mnemonics. Many of the instructions have a completer to indicate different types of similar instructions. For example, the mnemonic for a branch instruction is simply B. If we want to save a return address, called a branch and link instruction, the mnemonic is B,L. The L is a completer to the branch instruction. Similarly, the store word instruction, STW, can become a store word and modify with a completer of M: STW,M.

Some tools will also use simplified mnemonics. The branch and link instruction is used to call a procedure, so it is sometimes shown in a listing as a CALL instruction. As another example, there is no "no operation" instruction in PA-RISC, but the assembler will use OR 0,0,0 as a no-op, and this instruction is frequently decoded as NOP in assembly listings.

Memory Reference Instructions

The PA-RISC architecture uses explicit LOAD and STORE operations for all memory access. LOAD instructions bring data from memory to registers, and STORE instructions move data from registers to memory. Since PA-RISC uses memory-mapped I/O, the LOAD and STORE instructions are also used for all I/O operations. There are no explicit I/O operations in the instructions set.

LOADs and STOREs can operate on a byte, a halfword, a word, or a doubleword. These instructions are summarized in Table 2-1.

Table 2-1. LOAD and STORE Instructions

Size of Operand

Load Instruction

Store Instruction

8 bits

LDB Load byte

STB Store byte

16 bits

LDH Load halfword

STH Store halfword

32 bits

LDW Load word

STW Store word

64 bits

LDD Load doubleword

STD Store doubleword


The most common addressing mode for memory uses a base register and a displacement to specify the target address. The displacement is added to the contents of the register to get the target address. The data at that address is then copied to the specified register (for a LOAD), or the contents of the register are copied to that address (for a STORE). An example is the instruction

 LDW 4(r31),r27 

This instructs the system to add 4 to the value in GR31, use the resulting sum as an address into memory, and load the value from that address into GR27. This base and displacement technique is frequently used for referencing members of a structure through a pointer a common operation in the kernel. Consider the following code sample:

    struct mystruct {      int           x;          /* 32 bit integers */      int           y;      int           z; }; struct mystruct *s; q = s->z; 

At compile time, the compiler knows that the member z of the structure is 8 bytes past the beginning of the structure. To load the value of s->z into q, it first loads the current value of the pointer into a general register, for example, GR3. The load instruction might then be

 LDW 8(r3), r4 

The displacement portion of the instruction is the offset from the beginning of the structure, which is known at compile time. The base register holds the pointer to the beginning of the structure, which is not known until runtime.

Base Register Modification

Another variation of the STORE and LOAD instructions provides base register modification. That is, in addition to moving data to or from memory, the instruction also modifies the specified base register. If the displacement is positive, then the base register is modified after the load or store is done. This is a post-increment operation. If the displacement is negative, the base register is modified before the load or store is done. This is a pre-decrement operation.

As an example, consider the following instruction:

 STW,M r3,0x80(r30) 

This instruction tells the system to store the value in GR3 at the address specified by GR30, then add 0x80 to GR30.

In contrast, consider the following instruction:

 STW,M r3,-0x80(r30) 

Because the offset is negative, the system first subtracts 0x80 from GR30, then stores the contents of GR3 at that address.

We will frequently see an STW,M instruction at the beginning of each called procedure. The compiler uses this instruction to allocate a stack frame that is, to move the stack pointer forward to allow room for storage of local variables. We'll see this in more detail when we look at stack usage.

Branch Instructions

Branch instructions can be divided into two types: conditional and unconditional. As the names imply, a conditional branch may or may not be taken depending on some condition. An unconditional branch is always taken. Within these two types are several different instructions depending on the range of the branch and whether or not a return address is saved.

Unconditional Branch

Table 2-2 shows the types of unconditional branches. The external branches are used to branch to a location in a different space; the vectored branches branch to an address held in a register; and the link branches save the return address in a register.

Table 2-2. Unconditional Branches

Instruction

Definition

B

Branch

B,L

Branch and link

BLR

Branch and link register

BV

Branch vectored

BVE

Branch vectored external

BE

Branch external

BE,L

Branch external and link


When the L completer is used on an instruction, the instruction must specify which register is the link register that is, which register is to get the return address. Typically, GR2 is used for calls within the space and GR31 for calls to another space. The reason GR2 is used for the B,L instruction is that there is a version of B,L that implicitly uses GR2 as the link register. By doing this, the 5 bits in the instruction that specify the link register can be used to specify the branch target. When using GR2 as the link register, the B,L instruction has a range of ±8 MB from the current instruction. Register GR2 is commonly called rp, for return pointer.

The BLR and BV instructions are used for branches to target addresses that are farther than 8 MB from the current instruction but still within the same space. BLR computes the target address by adding an offset to any of the general registers. This address is then used relative to the current instruction. This extends the range of the branch. The BV instruction is not relative to the current instruction it uses two registers, a base register and a displacement register, to compute the target address. A common use of the BV instruction is to return from a procedure call. By using GR0 (which is always zero) as a displacement and rp as the base, we branch back to the return address saved by the B,L instruction that made the call. This instruction is sometimes seen as BV r0(rp) and sometimes just as RET.

The "external" versions of the branch instruction are essentially the same. The key differences are that they allow the specification of both space and offset as the target address, and they save both space and offset of the return address. They also store the offset of the return address into GR31 rather than GR2.

Conditional Branch

There are four types of conditional branches in PA-RISC:

  • Move and branch

  • Compare and branch

  • Add and branch

  • Branch on bits

Each has two forms: one that compares two registers and another that compares a register and an immediate value. The immediate value is 5 bits, giving it a range of 16 to +15. The conditions for branching are specified as completers to the branch instruction. The mnemonics for these instructions are shown in Table 2-3.

Table 2-3. Conditional Branch Instructions

Instruction

Definition

MOVB

Move and branch

MOVIB

Move immediate and branch

CMPB

Compare and branch

CMPIB

Compare immediate and branch

ADDB

Add and branch

ADDIB

Add immediate and branch

BB

Branch on bit


The MOVB and MOVIB instructions either copy a register to another register or copy an immediate value to a register. They then branch to the target address if the specified condition is true based on the value that was moved. Table 2-4 lists the possible conditions for the MOV and MOVIB instructions.

Table 2-4. MOVB and MOVIB Instruction Conditions

Condition

Definition

 

Never

=

All bits in word are 0

<

Leftmost bit in word is 1

OD

Rightmost bit in word is 1

TR

Always

<>

Some bits in word are 1

>=

Leftmost bit of word is 0

EV

Rightmost bit of word is 0


For example, the instruction MOVB,= r4,r5,main+0x16 would move the contents of GR4 into GR5. If the value moved was zero, a branch would be taken to the address main+0x16; otherwise, execution would continue in sequence.

The CMPB and CMPIB instructions either compare two registers or compare an immediate value and a register. The instruction then branches to the target address if the specified condition is true; otherwise execution continues in sequence. Table 2-5 shows the possible conditions for the CMP and CMPIB instructions.

Table 2-5. Conditions for CMP and CMPIB Instructions

Condition

Definition

 

Never

=

Operand 1 is equal to operand 2

<

Operand 1 is less than operand 2 (signed)

<=

Operand 1 is less than or equal to operand 2 (signed)

<<

Operand 1 is less than operand 2 (unsigned)

<<=

Operand 1 is less than or equal to operand 2 (unsigned)

SV

Operand 1 minus operand 2 overflows (signed)

OD

Operand 1 minus operand 2 is odd

TR

Always

<>

Operand 1 is not equal to operand 2

>=

Operand 1 is greater than or equal to operand 2 (signed)

>

Operand 1 is greater than operand 2 (signed)

>>=

Operand 1 is greater than or equal to operand 2 (unsigned)

>>

Operand 1 is greater than operand 2 (unsigned)

NSV

Operand 1 minus operand 2 does not overflow (signed)

EV

Operand 1 minus operand 2 is even


For example, the instruction CMPIB,<= 7,r3,main+0x18 would compare the value in GR3 to the immediate value 7. If 7 <= GR3 (or, to put it another way, if GR3 > 7), the instruction would branch to main+0x18.

The ADDB and ADDIB either add two registers or add an immediate value to a register. If the result satisfies the condition, then the branch is taken. Table 2-6 lists possible conditions for the ADDB and ADDIB instructions.

Table 2-6. Conditions for ADDB and ADDIB

Condition

Definition

 

Never

=

Operand 1 is equal to negative of operand 2

<

Operand 1 is less than negative of operand 2 (signed)

<=

Operand 1 is less than or equal to negative of operand 2 (signed)

NUV

Operand 1 plus operand 2 does not overflow (unsigned)

ZNV

Operand 1 plus operand 2 is zero or no overflow (unsigned)

SV

Operand 1 plus operand 2 overflows (signed)

OD

Operand 1 plus operand 2 is odd

TR

Always

<>

Operand 1 is not equal to negative of operand 2

>=

Operand 1 is greater than or equal to negative of operand 2 (signed)

>

Operand 1 is greater than negative of operand 2 (signed)

UV

Operand 1 plus operand 2 overflows (unsigned)

VNZ

Operand 1 plus operand 2 is nonzero and overflows (unsigned)

NSV

Operand 1 plus operand 2 does not overflow (signed)

EV

Operand 1 plus operand 2 is even


As an example, consider the instruction ADDIB,OD 17,r4,main+0x18. The value 17 is added to the contents of GR4, and the result is placed in GR4. If the result is odd, then the branch to main+0x18 will be taken.

The branch on bit instruction examines a bit in a register and conditionally branches based on that bit. The arguments to the instruction are the register, the position of the bit, and the target address. Table 2-7 lists the possible conditions for the BB instruction. The position argument can be a fixed bit position, or it can be SAR, which refers to the Shift Amount Register (CR11).

Table 2-7. Conditions for BB Instruction

Condition

Definition

<

Leftmost bit in word is 1

>=

Leftmost bit in word is 0


Delayed Branching

All branching in PA-RISC uses a feature known as delayed branching. This means that the instruction immediately following the branch will be executed even if the branch is taken. This instruction following a branch is called the delay slot. Consider the following code:

 LDW0x20(r30), r2 COMIB,>10,r2,main+80 LDW0x24(r30), r3 

The first instruction loads the value from 0x20 past GR30 into GR2. Next, the compare instruction compares that value to 10 and branches to main+80 if GR2 < 10. The next LDW instruction is the instruction in the delay slot. This instruction will be executed even if the branch is taken. So, if GR2 is in fact less than 10 and we branch to main+80, GR3 will get loaded from 0x24 past GR30 before we execute the instruction at main+80. Of course, the load will also get executed if we don't take the branch we'll fall through to it as the next instructions following the branch.

This applies also to a branch and link instruction used for a procedure call. Very frequently you'll find one of the call arguments being loaded by the instruction in the delay slot. For example, consider a call to func1(x,y), where x is at 0x24(r30) and y is at 0x28(r30). The resulting instructions might look like this:

 LDW0x24(r30),r26 B,L       func1,r2 LDW       0x28(r30),r25 

The LDW instruction in the delay slot loads the second argument into a register before making the procedure call.

The instruction in the delay slot can be ignored or nullified by using the,N completer on a branch. The instruction in the delay slot may or may not be nullified based on whether the branch is taken and the direction of the branch. If the branch is a forward branch, then the instruction in the delay slot is nullified if the branch is taken. This is because for a forward branch, the construct is usually "if this condition is true, skip forward over the following code." The instruction in the delay slot is part of the code that is skipped if the condition is true. In the normal case where the condition is not met, we fall through to the next instruction as expected.

If the branch is backwards, the delay slot is nullified if the instruction is not taken. The reasoning is that a backward branch is typically at the bottom of a loop. The compiler will generally copy the first instruction in the loop into the delay slot of the test at the end. Then the branch back to the top of the loop will branch to the second instruction of the loop. By doing this, we take advantage of the speed gained by using the delay slot. If the test fails and the branch is not taken, we continue on, nullifying the instruction in the delay slot.

Immediate Instructions

An immediate instruction is one in which one of the operands is a constant value, encoded as part of the instruction. Because the PA-RISC architecture uses a fixed instruction size of 32 bits, the size of an immediate operand is limited to only 21 bits. PA-RISC has some interesting tricks for dealing with this limitation, and we look at those here.

The most common example is the add immediate left instruction (ADDIL). ADDIL takes the 21-bit immediate value, shifts it left by 11 bits, then adds it to a specified register. The result is always placed in GR1. This gives the system a way to load the upper portion of a 32-bit value as an immediate.

In the kernel, this is commonly seen when loading a global. The address of the global is calculated by the compiler relative to the data pointer (GR27). The compiler then generates an ADDIL instruction to load the upper portion of the address into GR1, then an LDW relative to GR1 to add the lower portion of the address. For example,

 ADDIL    -0x2000,dp LDW      0x328(r1),rp 

This loads the value from dp-0x2000+0x328 or dp-0x1cd6 into register GR2. Some of the disassembly tools recognize this combination of instructions and identify the address that is being loaded. For example,

 ADDIL    -0x2000,dp           ; r1 = 0x891c40 LDW      0x328(r1),rp         ; rp = st_logging_enabled 



HP-UX 11i Internals
HP-UX 11i Internals
ISBN: 0130328618
EAN: 2147483647
Year: 2006
Pages: 167

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net