TOC PREV NEXT INDEX DOC LIST MASTER INDEX



Assembly Statements

This utility is available only with Rational Apex for Rational Exec and Rational Apex Embedded for Tornado.

Rational Software Corporation provides the asm.h include file for Rational Exec as a machine language interface to the target processor. For Tornado you must use the VxWorks supplied asm.h file

Note: Assembly statements are supported only in the Apex Duo product for the PowerPC.

ASM statements provide, from within the C and C++ languages, low-level access to the processor that is normally available only from assembly language.

Use of ASM statements is necessary in programs that need to reference the hardware directly. They are also useful for optimizing time-critical sections beyond the capabilities of the compiler.

ASM statements can be intermixed with normal C/C++ statements and provide features such as the full range of addressing modes and parameters that enable the programmer to integrate the machine code into surrounding code with minimal effort.

ASM statements are, however, a non-portable, processor-dependent feature of the language. The compiler cannot perform certain types of error checks that are performed for normal procedures (such as the enforcement of strong-typing). Machine code should be used with discretion and only where absolutely necessary.


PowerPC Assembly Statements

ASM Statements

An ASM statement is used to specify the machine instruction and any operands needed by the instruction. The form of this construct is:

Opcodes

Type Opcode is an enumeration type declared in asm.h. The type provides all of the instructions for the PowerPC. Instructions are named by their standard mnemonics, except for the instructions abs, and, or and xor which are appended by _op. Instructions that set the OE bit, are appended by _o. Instructions that set the Rc bit, are appended by _r. Instructions that set both the OE and Rc bit are appended by _o_r.

Operands

Type Operand is an intrinsic type declared in asm.h. This file also provides constants of the type Operand and functions that return values of type Operand.

All the PowerPC registers are provided as enumeration constants.

All the PowerPC Addressing modes are made available by functions that denote values of type Operand. The following table summarizes the available addressing modes and the functions used to support them.

Table 1 Addressing Modes
Mode
Notation
Function
Register
reg
N/A
Based Address
disp(reg)
ADDR(reg)
ADDR(disp)
ADDR(reg+disp)
ADDR(reg-disp)

Immediate
value
N/A
External Symbol
name
name + disp

EXT(name)
EXT(name, disp)

Table 2 Operands
asm(LWZ, R0, ADDR(R1+4));
asm(LWZ, R0, ADDR(R1-16#40000#));
asm(LWZ, R0, ADDR(R1+LABEL));
asm(LWZ, R0, ADDR(4));
asm(LWZ, R0, ADDR(-16#7FFFE#));
asm(LWZ, R0, ADDR(LABEL));
asm(LWZ, R0,LABEL);
asm(LA, R0, SUBP);
asm(LA, R0, EXT(SUBP));
asm(LA, R0, EXT(SUBP, 4));
asm(LA, R0, EXT("_END"));
asm(LA, R0, EXT("_END", 4));

All arguments to machine code functions must be one of the following:

C/C++ Entities as Operands

It is sometimes necessary to reference C/C++ constants and variables from within an ASM function. It is very tedious and error-prone for a programmer to attempt to calculate these references by hand. Apex provides the ADDR() function, which generates a reference to the entity X. The definition is similar to the & operator.

For a prefix X that denotes an object, a program unit, or a label ADDR(X) yields the reference of the first of the storage units allocated to X. For a label or subprogram, the value refers to the machine code associated with the corresponding statement.

In some cases, using ADDR() causes more than a single instruction to be generated.

Given:

Then:

Generates:

When X is constant static, the value used is an immediate literal.

Given:

When the ADDR() function is applied to labels, the addressing mode generated is a branch displacement or evaluates to an address depending on the instruction. For example, the following instruction uses a branch displacement.

The following instruction evaluates the address.

When the address function is applied to subprograms, the reference denotes the subprogram. The following instruction yields the address that references the machine code of the subprogram.

Extended addressing allows a displacement exceeding the range of -32,768 to 32,767 for the following instructions:

Table 3 Extended Addressing
LA
lfdu
lhz
stb
stfsu
LWZ
lfs
lhzu
stbu
sth
lbz
lfsu
lmw
stfd
sthu
lbzu
lha
lwzu
stfdu
stmw
lfd
lhau
stw
stfs
stwu

In most cases involving ADDR(), implicit code is generated. In particular, for any label, external reference or extended addressing.

Program Control

Operands are used to control the flow of execution with instructions such as branching and subroutine linkage. Labels and subroutine names can be used in conjunction with the ADDR() function to form destinations for these instructions.

The following example illustrates an ASM subprogram with typical control flow characteristics. This routine reads a table describing what needs to be copied and then performs the copy.

Subprogram Call

Since you can intermix ASM statements with normal C/C++ statements, it is best to code a call in standard C/C++. When you have to resort to using ASM statements to make the call, you must understand the calling conventions of your compiler.

Parameter Passing in Assembly Subprograms

On RISC machines, Apex passes one or more parameters in registers. It is important to understand exactly how registers are used in parameter passing, especially if you are implementing subprograms that use the ADDR() function on parameters. Attempting to use the ADDR() function on a parameter held in a register in an instruction where a memory reference is required results in the compiler flagging an error. Likewise, using the ADDR() function on a parameter held in a memory location in an instruction requiring a register also results in an error.

ASM expects references to parameters must be consistent with the register usage rules for your system. For example, on PowerPC-based systems, the compiler passes the first 8 scalar parameters in registers r3-r10. The LWZ instruction is used to move a value from a memory location into a register while the mr instruction is used to transfer a value from one register to another. Given the following example:

Since the first 8 scalar parameters are passed in registers, p1 is in a register, while p9 is on the stack. The compiler knows which parameters are on the stack and which are passed in registers.

Local Data

Variables that are visible to a machine code procedure directly or via the ADDR() function can be referenced. In some cases however, it may be necessary to intermix data and generated code. The ASM DATA statement is used to place a single data item in the code.

An Operand is restricted to the following:

Here is an example:

Jump Table via Branch Offsets

A jump table can be constructed by using the data statement and label difference operator. The following program fragment, illustrates the technique.

Floating Point

Floating point operations are invoked directly by machine instructions which access the FPU. ASM statements provide the opcodes and floating point registers so that the FPU can be referenced directly from ASM statements.

The operands consist of the floating point registers fr0-fr31, literals and float and double vars.

The compiler assigns real FP registers for pi and third and initialize them as expected.

Pragmas

Two pragmas directly affect the generation of code for ASM statements: Implicit_Code and Optimize_Code.

#pragma implicit_code

Pragma implicit_code controls the generation of implicit code. Implicit code is code generated for procedure entry and exit to support the calling conventions used by the compiler. (This does not include the return instruction, which is always generated.) Implicit code also includes any additional code generated due to the use of the ADDR() function (such as code to load a base register).

When #pragma implicit_code off is specified, any stack allocation is not generated.

Implicit code is always generated for an ADDR() function which requires it. A warning message is generated when implicit_code off is specified in such a case.

#pragma optimize_code

Pragma optimize_code allows the programmer to specify whether the compiler should attempt to optimize through the machine code insertions. When #pragma optimize_code off is specified, the compiler generates the code as specified.

Debugging Assembly Statements

The Apex debugger supports source-level debugging of ASM statements. Breakpoints can be set at assembly-statements just like any other statements.

Register values can be determined using the reg command or by preceding the register name with a dollar sign and using either the p command or a word dump raw memory command. For example, the register r1 can be examined as a word decimal value using the line-mode command shown below.

The li and wi instructions can be used to disassemble the generated code. In addition, the debugger attempts to disassemble Data_x statements as PowerPC instructions, producing meaningless results.

File asm.h

The following is a listing of the Rational Exec asm.h for the PowerPC.


Rational Software Corporation 
http://www.rational.com
support@rational.com
techpubs@rational.com
Copyright © 1993-2002, Rational Software Corporation. All rights reserved.
TOC PREV NEXT INDEX DOC LIST MASTER INDEX TECHNOTES APEX TIPS