TOC PREV NEXT INDEX DOC LIST MASTER INDEX



Machine Code Insertions

Rational Software Corporation provides the package Machine_Code described in Section 13.8 of the Ada Language Reference Manual. See the Ada83 and Ada 95 LRM for more information.

The Ada RM specifies the format of a machine code insertion procedure but leaves the actual implementation to the compiler vendor.

Machine code insertions provide, from within the Ada language, low-level access to the processor that is normally available only from an assembly language.

Use of machine code insertions 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.

Apex machine code insertions provide features such as the X'Ref attribute, a full range of addressing modes and parameters that enable the programmer to integrate the machine code into surrounding code with minimal effort.

Machine code insertions 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 insertions should be used with discretion and only where absolutely necessary.

Machine code insertion support is provided for all Apex platforms.

The general structure of machine code insertions is the same for each architecture family. A separate section describes the target-dependent details for each architecture family.


Machine Code Insertions Overview

Package Machine_Code

Machine Code Procedures

Code Statements

Call Statements

Data Statements

Pragmas

Debugging Machine Code

Package Machine_Code

The package Machine_Code defines the types and constants used in machine code insertions.

The specification of package Machine_Code can be found in an appropriate view of the lrm.ss subsystem:

The view name is constructed from the host OS or target variant, Ada variant, and the product version:

The "$APEX_*" meta-names are set when Apex is invoked. Their values can be displayed using Tools > Session > Environment command.

The name of the file depends on the Ada variant:

Ada83
machine_code.1.ada
Ada95
system.machine_code.1.ada

For Ada95, the file machine_code.1.ada provides a rename of the package System.Machine_Code. This allows existing "with" and "use" clauses of Machine_Code in Ada83 source to compile without modification.

Machine Code Procedures

A machine code procedure is restricted to the following, as imposed by the Ada Language Reference manual:

The syntactic form is:

The body of a machine code procedure must be within the context of a with clause that names the package Machine_Code.

Even though this is only a limited form of a subprogram body, it can still be used wherever a subprogram body is allowed, even as a generic or as a separate body. There are no restrictions on the parameter profile. As with other subprograms, pragma Inline can also be applied.

Under most circumstances a machine code procedure should have a single exit point--the end of the procedure. It should not have an explicit return instruction as this would prevent the compiler-generated epilogue code from executing.

The only exception to this would be a non-inlined procedure written with Pragma Implicit_Code(Off).

Code Statements

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

The Type_Mark must be a record type defined in the predefined package Machine_Code. All the usual rules apply in forming an aggregate and all type checking is enforced. For single components, the aggregate must use named notation (cf. RM 4.3(4)).

Package Machine_Code provides the variant record types Code_{0..n}, Data_1, Data_N, Call_0, Call_1 and Call_N.

The Code_n types have a variant of the type Opcode and n components of type Operand.

The Data_n types have a variant of the type Size. Data_1 has one operand component, while Data_N has a component that has a variable number of Operands.

The Call_n types take a subprogram reference of the type Operand and n components of type Operand. while Call_N has a component that has variable number of Operands.

The types Opcode, Operand and Size are declared in the package Machine_Code.

Opcodes

Type Opcode is an enumeration type declared in the package Machine_Code. The type defines all of the supported instructions for an architecture family.

Instructions are named by their standard mnemonics, except where these would conflict with an Ada reserved word (e.g. Abs, And, Or, Xor). In these cases the mnemonic is suffixed with "_Op". In addition, any instruction qualifiers or completers may also be appended to the base mnemonic using an underscore, so that the enumeration is a legal Ada identifier.

Operands

Type Operand is a private type declared in the package Machine_Code.

The package provides constants of the type Operand and functions that return values of type Operand. The Apex-defined attribute X'Ref can be applied to most Ada objects and denotes a value of type Operand.

All the supported registers for an architecture family are provided as operand constants.

Intrinsic functions that return type Operand are provided to combine operands and expressions to form more complex addressing modes.

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

Ada Entities as Operands

It is sometimes necessary to reference Ada constants and variables from within a machine code procedure. It is very tedious and error-prone for a programmer to attempt to calculate these references by hand. Apex provides the attribute X'Ref, which generates a reference to the entity X. The definition is similar to the attribute X'Address.

The value of this attribute is of type Operand defined in the package Machine_Code. It is only valid within the context of a machine code procedure.

For a prefix X that denotes an object, X'Ref yields a reference to the first storage unit associated with X.

For a subprogram X'ref yields a reference suitable for use in a subroutine linkage instruction. The value may refer to a subprogram descriptor, or to the text address of first instruction of the subprogram. In the former case, a intrinsic function is provided to reference the text address, if necessary.

For a label, X'Ref yields a reference to the text address of the statement associated with the label, suitable for use in a branching instruction. The value depends on the context in which the label is referenced, but typically it is a PC-relative offset.

For a constant object with a static expression the value refers to the value of the static expression.

For an enumeration literal the value refers to the integer code associated with the enumeration literal, which is the same as its position number, unless a representation clause is given for the enumeration type.

Const'Ref and Enum'ref should only be used as operands to instructions where an immediate value would be appropriate.

In many cases, using X'Ref will cause more than a single instruction to be generated. This may be because additional code is required to form the address of the referenced object. For example:

In this case additional code may be inserted to load a base register with address of Record1.

The context in which an X'Ref attribute is used may affect the amount additional code needed. For example:

Because the LOAD instruction requires a memory operand, but Arg1 is bound to a register, the compiler must generate code to bind the Arg1 to a stack location in order for the LOAD operation to work. In this case, because we know Arg1 is in a register, it would be more efficient to use a register-to-register move instruction instead of LOAD, or to reference Arg1 directly in the ADD instruction.

Similarly, because the ADD instruction requires three register operands, the compiler may need to allocate temporary registers and generate additional code to load Src'Ref into a register and to store the result register into Dst'Ref.

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 X'Ref attribute to form destinations for these instructions

On architectures that have delay slots, it is not necessary (or possible) to explicitly fill these delay slots when writing Machine Code. At higher levels of optimization, the code generator will attempt to reorganize the instructions to minimize the number of delays. When NOPs are required, the code generator will insert them.

Call Statements

A general form of a subroutine call can be made from within a machine code procedure by using a Call statement. Three formats are provided, Call_0, Call_1 and Call_N to handle the various argument lists needed by a subroutine. The first argument to the call statement is the name of the subroutine suffixed by `Ref to yield a value of type Operand. All subsequent arguments, if any, must also be of type Operand. The number of arguments and their type compatibility are checked.


Warning: The current limitation on the arguments is that they must be of the form Name'Ref. All expressions must be assigned to a named entity before the call.

The three forms are:

CALL_0'(SUBP => P'REF);
CALL_1'(P'REF, ARG'REF);
CALL_N'(P'REF, (ARG1'REF, ..., ARGn'REF));

If P is a procedure, the following Ada procedure calls are equivalent to the statements shown above.

If P is function, the forms are similar but the result is not assigned.

If P is overloaded, an error is generated when using `Ref. The subroutine should be renamed to provide a distinct name.

The effect is to marshall the arguments (if any) into parameter registers or possibly onto the stack, make the call, copy the out parameters (if any) and adjust the sp (if needed). The return value of a function is not copied.

As with any ordinary procedure call, the call to P may be expanded inline, either by the compiler (at higher optimization levels) or at the programmer's request by applying one of the Inline Pragmas to the declaration of P. To avoid auto-inlining of P use Pragma Inline_Never(P), following the declaration of P, since this may not always be possible it may be necessary to program the call explicitly, rather than using a Call statement.

Data Statements

Variables visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In some cases, however, it may be necessary to intermix data and generated code. The Data_1 code-statement is used to place a single data item in the code, while the Data_N code-statement is used for multiple data items.

The forms are:

Where Size is an enumeration literal of type Size defined in package Machine_Code. The size may be further restricted by the type of operand. For example, an X'Ref to an absolute address must use the size corresponding to the size of an address.

The supported operands for local data may vary slightly on each platform, but typically include the following:

Immediate and label reference are supported for all platforms.

Examples:

Normally, Data statements should be guarded by a branch or return instruction, so that they are unreachable, otherwise, the processor will attempt to execute the data as if it were code. This will usually result in a hardware exception (e.g. an illegal instruction trap). But occasionally it can be useful to use Data to encode opcodes that are otherwise unavailable in machine code.

Pragmas

There are several pragmas that directly affect the code generated for machine code procedures.

Pragma Inline

Pragma Inline provides a hint to the compiler that a machine_code routine may be inlined at the compiler's discretion. Auto-inlining occurs at higher levels of optimization, but machine_code routines are never candidates for auto-lining, unless explicitly marked with pragma Inline.

It is possible to write machine code that works correctly when called, but does not work correctly when inlined. For example, if the routine directly referenced a parameter register instead of using `Ref. Inline routines must always use `Ref to reference parameters.

For this reason, we recommend that pragma Inline not be used for machine code routines. Instead, we recommend that machine_code routines should be designed as callable routines, or as inline_only routines.

Pragma Inline_Only

Pragma Inline_Only informs the compiler that the routine must always be inline. Note that no callable body for the routine will be generated.

Pragma Inline_Never

Pragma Inline_Never informs the compiler that the routine must never be inlined. This is now redundant for machine_code routines because the policy is not to inline a machine_code routine unless specifically requested.

On the other hand, it may be necessary to apply Pragma Inline_Never to routines called from machine_code using a Call statement (Call_0, Call_1, Call_n), to prevent auto-inlining of those routines at higher optimization levels.

Pragma Implicit_Code(Off)

This pragma 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 unless the routine is inlined.

This means the compiler will not generate any code to save/restore non-volatile registers, or to create/destroy a call frame. It will not allocate any space on the stack for temporaries, and will not generate any Storage_Check for the routine.

Pragma Implicit_Code(Off) should only be used when the programmer requires complete control of the call frame. It should not be used as an optimization.

When it is used, the programmer is responsible for ensuring that the machine_code routine obeys all the linkage conventions required by the routines that will call it. For example, the programmer must explicitly save and restore any registers that the routine uses, if the caller requires them to be preserved across the call.

Implicit code also includes any additional code generated due to the use of the X'Ref attribute (such as code to load a base register).

This implicit code is always generated for a X'Ref attribute which requires it even when Implicit_Code(Off) is specified. A warning message is generated in this case. However, this warning only occurs when additional code is generated for a specific reference (e.g. loading a base register), and not when prologue code is also required for the reference. That is, the code generated for an X'Ref attribute may depend implicitly on prologue code (e.g. to establish a global pointer, to create a stack temporary, or to save a non-volatile register for temporary use), and hence the reference may be invalid, but the compiler will not issue a warning.

For this reason great care must be exercised when using the X'Ref attribute with pragma Implicit_Code(Off). In particular, the following should be avoided:

In general, it is recommended that Implicit_Code(Off) only be used in routines with no parameters, or where parameters are passed in registers, and in those cases the parameters could be referenced directly by register name, rather than with X'Ref.

Implicit_Code(Off) should not be used on machine code routines that are inlined. Inlined routines do not include entry/exit code, and require that parameters be referenced with `Ref.

If the Implicit_Code(Off) pragma is used, then the runtime it has no knowledge of the stack contents for that frame, therefore the runtime cannot unwind that frame. The result of this is that machine code routines using Implicit_Code(Off), do not propagate to the caller exceptions raised by machine code instructions or by any routines called by these routines.

When used, this pragma should be placed in the declarative section of the machine code procedure.

Pragma Optimize_Code

This pragma allows the programmer to specify whether the compiler should attempt to optimize through the machine code insertions. When pragma Optimize_Code(OFF) is specified most optimizations on machine_code will be suppressed. Some code transformations may still occur on some architectures (e.g. instruction scheduling and the filling of delay slots).

When used, this pragma should be placed in the declarative section of the machine code.

Pragma Suppress

This pragma has its normal effect of suppressing the generation of runtime checks. Runtime checks may be generated to perform an elaboration check at the start of the procedure and to perform constraint checks on objects accessed using X'Ref. These checks only ensure that the reference is valid; they do not check whether the value assigned is valid. For example, the code-statement

would generate an access check to ensure that X is not null but would not generate a check to ensure that the value moved to the referenced location was in the range of the type of X.All.

Debugging Machine Code

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

Register values can be determined using the Windows > Registers command from the GUI or the reg command in line mode or through the Command Pane.

Register values can also be displayed by preceding the register name with a dollar sign and using either the p command or a raw memory display command (e.g. $reg:<size><fmt>).

The Disassembly button (GUI) or the li and wi instructions (line-mode and Command Pane) can be used to disassemble the generated code.

There are some potential problems with debugging machine code.

A machine code routine may not have a standard frame or valid procedure descriptor (c.f. pragma Implicit_Code). This may prevent the debugger from correctly unwinding the call stack, because it is unable locate the return address, or properly restore the context of the calling routine.

The debugger will attempt to disassemble local Data statements as instructions, producing meaningless results, or worse. On machines with variable length instructions (e.g. X86, M68k) Data statements may disrupt the disassembly of the rest of the routine.


Machine Code Insertions - RS/6000

This section covers the details of machine code insertions for the IBM RS/6000. Be sure to read the Machine Code Insertions Overview before proceeding with this section.

Opcodes

Type Opcode is an enumeration type declared in the package Machine_Code. The type provides all of the supported instructions for the RISC System/6000.

Instructions are named by their standard mnemonics, except where these would conflict with an Ada reserved word (e.g. Abs, And, Or, Xor). In those cases the mnemonic is suffixed with "_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 and Addressing Modes

Operands

Type Operand is a private type declared in the package Machine_Code. The package also provides constants of the type Operand and functions that return values of type Operand. The Apex-defined attribute X'Ref can be applied to most Ada objects and denotes a value of type Operand.

Each of the supported RISC System/6000 registers are provided as operand constants.

Each of the supported RISC System/6000 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 6 RS/6000 Addressing Modes
Mode
Notation
Function
Register
reg
N/A
Based Address
disp(reg)
BASE(reg)


BASE(disp)


BASE(reg+disp)


BASE(reg-disp)
Immediate
value
IMMED(value)


"+"(value)


"-"(value)


UIU(value)


UIL(value)


SIU(value)


SIL(value)


Mod32_Hi (Mod32)


Integer_Hi (Val)


Mod32_Hiadj (Val)


Integer_Hiadj (Val)


Mod32_Lo (Val : Mod32)


Integer_Lo (Val : Integer)
External Symbol
name
EXT(name)

name + disp
EXT(name, disp)

name
CODE(name'REF)



Special-Purpose
spr
SPR(spr_id)
Register


Examples:

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

Special Purpose Registers

Package Machine_Code defines a subset of special-purpose as operand constants. All other special-purpose registers can be referenced using the Spr() function and an Spr_Id value (0..1023).

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute.

In many cases, using X'Ref will cause more than a single instruction to be generated to form the address of the referenced object.

Labels

When the X'Ref attribute is applied a label it yields a reference to the text address of the statement associated with the label. The addressing mode generated depends on the instruction.

Subprograms

When the X'Ref attribute is applied to subprograms, the reference denotes the subprogram descriptor. The Machine Code intrinsic function Code() yields the address that references the text of the subprogram.

Code_2'(Cal, R2, Subp'Ref); -- Address of descriptor

Code_2'(Cal, R2, Code(Subp'Ref)); -- Address of text

Extended Addressing

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

Table 7 Extended Addressing
cal
lfdu
lhz
stb
stfsu
l
lfs
lhzu
stbu
sth
lbz
lfsu
lm
stfd
sthu
lbzu
lha
lu
stfdu
stm
lfd
lhau
st
stfs
stu

In most cases involving X'Ref, implicit code is generated to form the address.

Floating-Point

Floating-point operations are invoked directly by machine instructions which access the RISC System/6000 FPU. The package Machine_Code provides the opcodes and floating-point registers so that the FPU can be referenced directly from machine-code insertions.

The operands consist of the floating-point registers Fr0-Fr31, literals and X'Ref (where applicable).

In addition, an immediate can be used in LFS and LFD instructions.

Programming Examples

Start-Up Routine

The following example illustrates a hypothetical start-up routine for an Ada program. Its function is to call an initialization routine, and then invoke each entry in the elaboration table that is constructed by the linker.


Machine Code Insertions - Sun SPARC

This section covers the details of machine code insertions for the SPARC Architecture Family. Be sure to read the Machine Code Insertions Overview before proceeding with this section.

Opcodes

Type Opcode is an enumeration type declared in package Machine_Code. This type provides all of the supported instructions for the SPARC, including the additional pseudo-instructions described later. Instructions are named by their standard mnemonics, except where those mnemonics that would conflict with an Ada reserved word (e.g. Abs, And, Or, Xor). In those cases the mnemonic is suffixed with "_Op".

Pseudo-Instructions

A set of pseudo-instructions are supported which are mapped to hardware instructions, as the following table describes.

Table 8 Pseudo-Instruction Mapping
Pseudo Instruction
Hardware Equivalent(s)
nop

sethi
0, %g0
cmp
reg, reg_or_imm
subcc
reg, reg_or_imm, %g0
jmp
address
jmpl
address, %g0
call
reg_or_imm
jmpl
reg_or_imm, %o7
jmpl
label, %o7
call
label
tst
reg
orcc
reg, %g0, %g0
ret

jmpl
%i7+8, %g0
retl

jmpl
%o7+8, %g0
restore

restore
%g0, %g0, %g0
save

save
%g0, %g0, %g0
not
reg1, reg2
xnor
reg1, %g0 , reg2
not
reg
xnor
reg, %g0 , reg
neg
reg1, reg2
sub
%g0 , reg1, reg2
neg
reg
sub
%g0, reg, reg
inc
reg
add
reg, 1, reg
inc
const13, reg
add
reg, const13, reg
inccc
reg
addcc
reg, 1, reg
dec
reg
sub
reg, 1, reg
dec
const13, reg
sub
reg, const13, reg
deccc
reg
subcc
reg, 1, reg
btst
reg_or_imm, reg
andcc
reg, reg_or_imm, %g0
bset
reg_or_imm, reg
or
reg, reg_or_imm, reg
bclr
reg_or_imm, reg
andn
reg, reg_or_imm, reg
btog
reg_or_imm, reg
xor
reg, reg_or_imm, reg
clr
reg
or
%g0, reg_or_imm, reg
clrb
[address]
stb
%g0, [address]
clrh
[address]
sth
%g0, [address]
clr
[address]
st
%g0, [address]
mov
reg_or_imm, reg
or
%g0, reg_or_imm, reg
mov
%y, reg
rd
%y, reg
mov
%psr, reg
rd
%psr, reg
mov
%wim, reg
rd
%wim, reg
mov
%tbr, reg
rd
%tbr, reg
mov
reg_or_imm, %y
wr
%g0, reg_or_imm, %y
mov
reg_or_imm, %psr
wr
%g0, reg_or_imm, %psr
mov
reg_or_imm, %wim
wr
%g0, reg_or_imm, %wim
mov
reg_or_imm, %tbr
wr
%g0, reg_or_imm, %tbr
set
value, reg
(if -4096 <= value <= 4095)

or
%g0, value, reg
set
value, reg
(if ((value&0x1ff) == 0))

sethi
%hi(value), reg
set
value, reg
sethi
%hi(value), reg;


or
reg, %lo(value), reg

(otherwise)


Sparc-V9 Pseudo-Instructions

SPARC-V9 extends the SPARC architecture to 64-bits. In order to aid the writing of machine code that is easily portable between 32-bit and 64-bit programs, or between PIC and non-PIC models, APEX Ada provides the LDGP and LEA pseudo-instructions in machine code.

LDGP - Load Global Pointer

In SPARC PIC mode (32-bit and 64-bit) the local register%l7 is used as the Global Offset Table pointer, also called the "GP". The LDGP pseudo-instruction allows the machine code programmer to insert code to establish a valid GP, if required.

LEA - Load Effective Address

The LEA pseudo-instruction provides a convenient way of loading the address of an object into a register, without have to know whether the code will be compiled for 32-bit or 64-bit modes, or for PIC or non-PIC modes.

The table below shows the instruction sequences generated for LDGP and LEA under each programming model.

In 32-bit non-PIC

ldgp
*** ignored ***
lea Ext("foo"), %g1
sethi (foo), %g1 or %g1, (foo), %g1
lea Foo'Ref, %g1
*** same as above ***
In 32-bit PIC

ldgp
call $08

sethi $_GLOBAL_OFFSET_TABLE_+04, %l7
or %l7, $_GLOBAL_OFFSET_TABLE_+08, %l7
add %l7, %o7, %l7

lea Ext("foo"), %g1
sethi (foo), %g1
or %g1, (foo), %g1
ld (%g1)[%l7], %g1

lea Foo'ref, %g1
*** same as above ***
In 64-bit non-PIC

ldgp
*** ignored ***
lea
Ext("foo"), %g1 sethi (foo), %g1
sethi (foo), %g5
or %g1, (foo), %g1
sllx %g1, $020, %g1
or %g1, %g5, %g1
or %g1, (foo), %g1

lea Foo'Ref, %g1
*** same as above ***
In 64-bit PIC

ldgp
call $08
sethi $_GLOBAL_OFFSET_TABLE_+04, %l7
sethi $_GLOBAL_OFFSET_TABLE_+08, %g5
or %l7, $_GLOBAL_OFFSET_TABLE_+0c, %l7
sllx %l7, $020, %l7
or %l7, %g5, %l7
or %l7, $_GLOBAL_OFFSET_TABLE_+018, %l7
add %l7, %o7, %l7

lea Ext("foo"), %g1
sethi (foo), %g1
or %g1, (foo), %g1
ldx (%g1)[%l7], %g1

lea Foo'Ref, %g1
*** same as above ***

Operands and Addressing Modes

Type Operand is a private type declared in the package Machine_Code. This package also provides constants of type Operand and functions that return values of type Operand. The Apex-defined attribute X'Ref can be applied to most Ada objects and denotes a value of type Operand.

All SPARC registers are provided as operand constants.

All SPARC 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 9 Machine Code Operands
Mode
Notation
Function
Register
%reg
N/A
Memory Address
[address]
Addr (address)
Memory Address ASI
[regaddr] asi
Addr (regaddr, asi)
Register Displacement
%reg + %reg
%reg + const13
%reg - const13

"+" (reg, reg)
"+" (reg, const13)
"-" (reg, const13)

Immediate
value
Immed (value)
Immed_Int (s32)
Immed_Mod32 (u32)
"+" (value)
"-" (value)

Extract High 22 Bits
of upper word

%hh(value)
%hh (value + disp)
%uhi (value)

Hh (value)
Hh (value + disp)
Hh_Mod64 (u64)

Extract Low 10 Bits
of upper word

%hm (value)
%hm (value + disp)
%ulo (value)

Hm (value)
Hm ( alue + disp)
Hm_Mod64 (u64)

Extract High 22 Bits
of lower word

%lm (value)
%lm (value + disp)

Lm (value)
Lm (value + disp)
Lm_Mod64 (u64)

Extract High 22 Bits
of 32-bit value

%hi (value)
%hi (value + disp)

Hi (value)
Hi (name, disp)
Hi_Int (int)
Hi_Mod32 (u32)

Extract Low 10 Bits
%lo (value)
%lo (value + disp)

Lo (u32)
Lo (name, disp)|
Lo_Int (int)
Lo_Mod32 (u32)
Lo _Mod64 (u64

External Symbol
name
name + disp

Ext (name)
Ext (name, disp)

-----------------------------------------------------------------------------

A Regaddr and Address are formed as follows:

A Const13 is a signed constant which fits in 13 bits:

The operators HI and LO accept the following kinds of arguments:

The operators Hi, Lo and Ext, allow an additional displacement to be added to an external symbol.

The operator Hi is only allowed in a sethi instruction. The operator Ext is only allowed in a call and set instruction.

SPARC-V9 extends the SPARC architecture to 64-bits. The operators Hh, Hm, Lm, are analogous to Hi and Lo, but operate on 64-bit operands. The suggested assembly syntax for SPARC-V9 defines the SETX synthetic instruction to load a 64-bit constant. Currently Apex Ada does not support this form. To load a 64-bit value a temporary register is needed, and in the most general case requires six instructions.

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

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In many cases, using X'Ref will cause more than a single instruction to be generated.

Labels

When the X'Ref attribute is applied a label it yields a reference to

the text address of the statement associated with the label. The

addressing mode generated depends on the instruction.

Subprograms

When the X'Ref attribute is applied to a subprogram, the reference denotes the address of the subprogram.

Programming Examples

In the ensuing discussions, we use the SPARC 32-bit model, unless otherwise specified.

Program Control

Labels and subroutine names are used in conjunction with the X'Ref attribute to form destinations for branch and subroutine linkage instructions.

The following example illustrates a typical startup routine for an Ada program. Its function is to call an initialization routine, elaborate the library units, call the main program and call an exit routine.

Note the use of NOP instructions following branch and call instructions.This is necessary to fill the branch delay slots for these instructions.

Jump Table via Absolute Addresses

A jump table can be constructed by building a table of absolute addresses. The table is built by using the data statement, where the operands consist of label references to the selected entry points. An absolute address mode specifying the physical address can also be used. The following program fragment illustrates the technique.

Each code segment in the table must branch to the end of the routine so that the compiler-generated epilogue code for the routine is executed.

Replacing the branch with a return instruction would not be correct, unless the routine was written with Pragma Implicit_Code(Off). In which case it would be entirely up to the programmer to handle the subroutine linkage.


Machine Code Insertions - SGI MIPS

This section covers the details of machine code insertions for the SGI MIPS processor. Be sure to read theMachine Code Insertions Overview before proceeding with this section.

Opcodes

Type Opcode is an enumeration type declared in the package Machine_Code. The type defines all of supported the instructions for the MIPS, including additional pseudo-instructions described later.

Instructions are named by their standard mnemonics, except where these would conflict with an Ada reserved word (e.g. Abs, And, Or, Xor). In those cases the mnemonic is suffixed with "_Op".

Pseudo Instructions

A subset of the MIPS defined pseudo-ops, also called synthetic instructions, are supported. Following is a list of these instructions with the MIPS name in parenthesis when the names are not identical.

abs_op (abs), div, divu, la, li, move, nop, seq, sne, ulh, ulhu, ulw, ush, usw.

Operands and Addressing Modes

The type Operand is a private type declared in the package Machine_Code. The package also provides constants of the type Operand and functions that return values of type Operand. The Apex-defined attribute X'Ref can be applied to most Ada objects and denotes a value of type Operand.

All the supported MIPS registers are provided as Operand constants.

All the supported MIPS addressing modes are made available by functions that denote values of type Operand. Table 29 summarizes the available addressing modes and the functions used to support them.

Table 10 Addressing Modes
Mode
Notation
Function
Register
reg
N/A
Base Address
(reg)
BASE(reg)
Based Address
disp(reg)
DISP(reg, disp)


reg + disp


reg - disp
Immediate
value
IMMED(value)

"+"(value)


"-"(value)

External Symbol
name
EXT(name)

name + disp
EXT(name, disp)

Examples

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

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In many cases, using X'Ref will cause more than a single instruction to be generated to form the address of the referenced object.

Labels

When the X'Ref attribute is applied a label it yields a reference to the text address of the statement associated with the label. The addressing mode generated depends on the instruction.

Subprograms

When the X'Ref attribute is applied to a subprogram, the reference denotes the address of the subprogram.

Extended Addressing

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

lw
lh
lhu
lb
lbu
sw
sh
sb
lwl
lwr
swl
swr

In most cases involving X'REF, implicit code is generated to form the address.

Floating-Point

Floating-point operations are invoked directly by machine instructions which access the MIPS floating point coprocessor. The Machine_Code package provides the opcodes and floating-point registers so that the coprocessor can be referenced directly from machine-code insertions.

Parameters

The operands consist of the floating-point registers f0-f31, general purpose registers, based addressing, literals and X'Ref (where applicable).

Note that for double-precision, a register pair (even-odd) is used. For single-precision, only even registers may be used. Only those instructions which load and store floating point registers may use odd-numbered registers.

In addition, an immediate can be used in LI_D and LI_S instructions. For example,

Programming Examples

Start-Up Routine

The following example illustrates a hypothetical start-up routine for an Ada program. Its function is to call an initialization routine, and then invoke each entry in the elaboration table that is constructed by the pre-linker.

When writing in machine code, it is not possible to fill delay slots, nor is it necessary to add NOP instructions when they would normally be needed. The code generator will attempt to reorganize the instructions to minimize the number of delays. When NOPs are needed, the code generator will insert them.

In this case, since Pragma Optimize_Code(Off) is used, the code generator will not attempt to reorganize the code to fill delay slots. All delay slots will be filled with NOPs.

Jump Table via Addresses

A jump table can be constructed by building a table of addresses. The table is built by using the Data statement, where the operands consist of label references to the selected entry points.

The following program fragment illustrates the technique.

Each code segment in the table must branch to the end of the routine so that the compiler-generated epilogue code for the routine is executed.

Replacing the branch with a return instruction would not be correct, unless the routine was written with Pragma Implicit_Code(Off). In which case it would be entirely up to the programmer to handle the subroutine linkage.


Machine Code Insertions - HP-PA

This section covers the details of machine code insertions for the HP-PA processor. Be sure to read the Machine Code Insertions Overview before proceeding with this section

Opcodes

Type Opcode is an enumeration type declared in the package Machine_Code. The type provides all of the supported instructions for the PA-RISC processor.

Instructions are named by their standard mnemonics, except where these would conflict with an Ada reserved word (e.g. And, Or, Xor). In those cases the mnemonic is suffixed with "_Op". The various completers are appended to the base mnemonic and separated by an underscore.

The following table maps assembly completers to alphanumeric counterparts that can legally comprise an identifier.

Table 11 Arithmetic/Logical Conditions
=
eq
<>
ne
<
lt
>=
ge
<=
le
>
gt
<<
ltu
>>=
geu
<<=
leu
>>
gtu
false?
f
!?<=
ogt
false
sf
>
gt
?
ngle
?>
ugt
!<=>
un
!<=
nle
=
eq
!?<
oge
=T
seq
>=
ge
?=
ueq
?>=
uge
!<>
ngl
!<
nlt
!?>=
olt
!?=
ogl
<
lt
<>
gl
?<
ult
!=
ne
!>=
nge
!=T
sne
!?>
ole
!?
or
<=
le
<=>
gle
?<=
ule
true?
t
!>
ngt
true
st
* x



Note: The 64-bit form of the above predicates have a `*' prefixed to them. Machine code instructions replace the `*' with an `x'. For example, `*=' will be `xeq' (`eq' is for `='), *<< will be `xltu' (`ltu' is for `<<`), etc.

COPR and SPOP instructions

For these instructions the SFU/UID and SOP opcode completers are specified as immediate values in the first and second operands respectively.

Operands and Addressing Modes

Type Operand is a private type declared in package Machine_Code. The package also provides constants of type Operand and functions that return values of type Operand. The Apex-defined attribute X'Ref can be applied to most Ada objects and denotes a value of type Operand.

All the supported PA-RISC registers are provided as operand constants.

All the supported PA-RISC 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 implement them.

Table 12 Addressing Modes and Functions
Mode
Notation
Function



Register
reg
N/A
Based Address
(base)
ADDR(base)

(sid,base)
ADDR(sid, base)

disp(base)
ADDR(base+disp)


ADDR(base-disp)

disp(sid,base)
ADDR(sid, base+disp)


ADDR(sid, base-disp)

index(base)
ADDR(base+index)

index(sid,base)
ADDR(sid, base+index)

(sreg,base)
ADDR(sreg, base)

index(sreg,base)
ADDR(sreg, base+index)

disp(sreg,base)
ADDR(sreg, base+disp)


ADDR(sreg, base-disp)
Immediate
value
IMMED(value)


"+"(value)


"-"(value)
External Symbol
name
EXT(name)

name + disp
EXT(name, disp)

subprogram name
SUBP_EXT(name)

Examples

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

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In many cases, using X'Ref will cause more than a single instruction to be generated to form the address of the referenced object.

Labels

When the X'Ref attribute 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.

Subprograms

When the X'Ref attribute is applied to subprograms, the reference denotes the machine code of the subprogram.

The functions Ext and Subp_Ext are used to reference external names. The function Ext is used for data references. The function Subp_Ext is used for subprogram references.

Extended Addressing

Extended addressing allows a displacement exceeding the range of -8192 to 8191 for the following instructions:

ldb
ldh
ldw
stb
sth
stw
ldwm
stwm
ldo

Extended addressing allows a displacement exceeding the range of -16 to 15 for the following instructions:

ldbs ldhs ldws ldwas ldcws ldsid stws stws_bc sths
sths_bc stbs stbs_bc stwas stwas_bc stbys stbys_b stbys_bc stbys_b_bc
stbys_e stbys_e_bc fldws fldds fstws fstds

In most cases involving X'Ref, implicit code is generated to form the extended address.

Floating-Point

Floating-point operations are invoked directly by machine instructions which access the PA-RISC FPU. Package Machine_Code provides the opcodes and floating-point registers so that the FPU can be referenced directly from machine code insertions.

The operands consist of the floating-point registers Fr0-Fr31, Fr0L-Fr31L, Fr0R-Fr31R, literals, and X'Ref (where applicable).

Programming Examples

Start-Up Routine

The following example illustrates a hypothetical start-up routine for an Ada program. Its function is to call an initialization routine, and then invoke each entry in the elaboration table that is constructed by the linker.


Machine Code Insertions - PowerPC

This section covers the details of machine code insertions for the PowerPC processor. Be sure to read the Machine Code Insertions Overview before proceeding with this section.

Opcodes

Type Opcode is an enumeration type declared in the package Machine_Code. The type provides all of the supported instructions for the PowerPC processors. The opcode mnemonics and operand structure are taken directly from the PowerPC User Manuals with the following modifications:

Operands and Addressing Modes

All the supported PowerPC registers are provided as Operand constants (including all of the control registers). For example, the following code-statement moves the contents of R2 to R1.

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

Table 13 Operands
Mode
Notation
Function



Register
reg
N/A
Based Address
disp(reg)
BASE(reg)


BASE(disp)


BASE(reg+disp)


BASE(reg-disp)
Immediate
value
IMMED(value)


"+"(value)


"-"(value)


UIU(value)


UIL(value)


SIU(value)


SIL(value)
External Symbol
name
EXT(name)

name + disp
EXT(name, disp)

name
CODE(name'REF)
Special-Purpose
spr
SPR(spr_id)
Register


Examples

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

Special Purpose Registers

Package Machine_Code defines a subset of special-purpose as operand constants. All other special-purpose registers can be referenced using the Spr() function and an Spr_Id value (0..1023). In addition, Package machine_code also defines some model-specific SPRs as named constants of type Spr_Id.

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In many cases, using X'Ref will cause more than a single instruction to be generated to form the address of the referenced object.

Labels

When the X'Ref attribute is applied a label it yields a reference to the text address of the statement associated with the label. The addressing mode generated depends on the instruction.

Subprograms

When the X'Ref attribute is applied to a subprogram, the reference denotes the address of the subprogram.

Floating-Point

Floating-point operations are invoked directly by machine instructions which access the PowerPC FPU. package Machine_Code provides the opcodes and floating-point registers so that the FPU can be referenced directly from machine-code insertions.

The operands consist of the floating-point registers Fr0-Fr31, literals and X'Ref (where applicable).

Programming Examples

Start-Up Routine

The following example illustrates a hypothetical start-up routine for an Ada program. Its function is to call an initialization routine, and then invoke each entry in the elaboration table that is constructed by the pre-linker.


Machine Code Insertions - Alpha Architecture

This section covers the details of machine code insertions for the Alpha Architecture. Be sure to read the Machine Code Insertions Overview before proceeding with this section.

Opcodes

Type Opcode is an enumeration type declared in the package Machine_Code. The type defines all of the supported instructions for the Alpha architecture, including additional pseudo-instructions described later.

Instructions are named by their standard mnemonics, except where those mnemonics that would conflict with an Ada reserved word (e.g. Abs, And, Or, Xor). In those cases the mnemonic is suffixed with "_Op".

Operands and Addressing Modes

Type Operand is a private type declared in the package Machine_Code. The package also provides constants of the type Operand and functions that return values of type Operand. The Apex-defined attribute X'Ref can be applied to most Ada objects and denotes a value of type Operand.

All the supported ALPHA registers are provided as operand constants.

All the supported ALPHA 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 14 Addressing Modes for DEC ALPHA Family Processors
Mode
Notation
Function
Register
  reg
 N/A
Base Address
  (reg)
 BASE(reg)
Based Address
 disp(reg)
DISP(reg, disp)
    reg + disp
    reg - disp

Immediate 
value
"+"(value)
 "-"(value)

IMMED(value)

External Symbol
name 
name + disp 

 EXT(name)
 EXT(name, disp)

Examples

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

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In many cases, using X'Ref will cause more than a single instruction to be generated.

Labels

When the X'Ref attribute is applied a label it yields a reference to the text address of the statement associated with the label. The addressing mode generated depends on the instruction.

Subprograms

When the X'Ref attribute is applied to a subprogram, the reference denotes the address of the subprogram.

Extended Addressing

Extended addressing allows displacements up to 32-bits, for the following memory format instructions:

In most cases involving X'REF, implicit code is generated to form the address.

Floating-Point

An implementation of the Alpha Architecture may provide either VAX or IEEE floating-point operations, both, or none.

Floating-point operations are accessible via machine code insertions in the same way that integer operations are. The Machine_Code package provides the opcodes and operands for all the floating point operations described in the Alpha Architecture Manual.

Internally, the compiler uses IEEE floating-point types to represent Ada float types.

Valid operands consist of the floating-point registers (F0-F31), general purpose registers, literals and X'Ref, where applicable.

Consider the following example of floating-point operands:

Lines A, B, and C are all illegal.

Line A is illegal because Pi'ref is a constant float value, not a memory reference as required by LDT.

Line B is illegal because E'ref is a memory reference, not a constant float value as required by LDIT.

Line C is illegal because Arg1'ref is a register reference, not a memory reference as required by LDT.

Lines A1-C1 show legal code statements corresponding to lines A-B.

Line D shows another way to load an literal float value.

Pseudo-Instructions

Apex supports all the pseudo-operations (stylized code forms) described in the Alpha Architecture Reference Manual, although the names may vary slightly. For example, OR_OP is used instead of OR, because OR is an Ada reserved word. These instructions are typically mapped to a single machine instruction.

Apex also supports most of the synthetic pseudo-instructions described in the Assembly Language Programmer's Guide (http://tru64unix.compaq.com/faqs/publications/pub_page/PRG_DOCS.HTM). These instructions typically generate more than one machine instruction.

Apex also support additional pseudo-instructions which are described in the sections that follow.

ALIGN

This instruction generates zero to three NOPs, so that the low-order N bits of the address of the machine_code instruction that follows will be zero.

Acceptable values of N are 0, 1, 2, 3, and 4. However, since machine_code instructions are naturally 4-byte aligned, the only values which make sense are 3 (quadword aligned) and 4 (octaword aligned).

For example, to force data to be quadword aligned:

LA (Load Address)

This instruction generates one or more machine instructions to load the effective address of an external or X'Ref operand into a register.

For example:

An implicit LA instruction may be generated by for X'Ref or external operands in other machine_code instructions.

A warning is generated for these implicit LA instructions if pragma Implicit_Code(off) is used.

Implicit Register Use

Register R28 (AT) is reserved by the compiler for use as a temporary register.

Most of the synthetic pseudo-instructions require additional temporary registers. The instructions and the registers they used are shown in the table below.

Instruction
Registers Used
ldb
AT,t9
ldbu
AT,t9
ldw
AT,t9
ldwu
AT,t9
uldw
AT,t9, t10
uldwu
AT,t9, t10
uldl
AT,t9, t10
uldq
AT,t9, t10
stb
AT,t9, t10
stw
AT,t9, t10
ustw
AT,t9, t10, t11, t12
ustl
AT,t9, t10, t11, t12
ustq
AT,t9, t10, t11, t12
divl
AT,t9, t10, t11, t12
divq
AT,t9, t10, t11, t12
divlu
AT,t9, t10, t11, t12
divqu
AT,t9, t10, t11, t12
reml
AT,t9, t10, t11, t12
remq
AT,t9, t10, t11, t12
remlu
AT,t9, t10, t11, t12
remqu
AT,t9, t10, t11, t12

Programming Examples

Program Control

Labels and subroutine names are used in conjunction with the X'Ref attribute to form destinations for branch and subroutine linkage instructions.

An arbitrary call interface can be set up using JSR (or BSR). For example:

It is up to the programmer to establish the correct parameter interface expected by the called routine (in this case, passing a value in a0).

The compiler will automatically code to load the address of the called procedure into the procedure value register (PV). It will also generate code to restore the global pointer register (GP), after the call, if GP addressing is used in the routine.

The following example illustrates a hypothetical start-up routine for an Ada program. Its function is to call an initialization routine, and then invoke each entry in the elaboration table that is constructed by the pre-linker.

Jump Table via Addresses

A jump table can be constructed by building a table of addresses. The table is built by using the data statement, where the operands consist of label references to the selected entry points. The following program fragment illustrates the technique.

Each code segment in the table must branch to the end of the routine so that the compiler-generated epilogue code for the routine is executed.

Replacing the branch with a return instruction would not be correct, unless the routine was written with Pragma Implicit_Code(Off). In which case, it would be entirely up to the programmer to handle the subroutine linkage.


Machine Code Insertions - Intel Architecture

This section covers the details of machine code insertions for the IA-32 architecture. Be sure to read the Machine Code Insertions Overview before proceeding with this section.

Opcodes

The type Opcode is an enumeration type declared in the package Machine_Code. The type defines all of the supported instructions for the IA-32 architecture.

Instructions are named by their standard mnemonics, except where those mnemonics would conflict with an Ada reserved word (e.g. AND, IN, LOOP, NOT, OR, OUT and XOR). In those cases the mnemonic is suffixed with "_Op".

Operands and Addressing Modes

The type Operand is a private type declared in the package Machine_Code. The package also provides constants of type Operand and functions that return values of type Operand. The Apex-defined attribute X\QRef can be applied to most Ada objects and denotes a value of type Operand.

All the supported IA-32 registers are provided as Operand constants, including the segment registers, control registers, debug registers, and test registers.

All the supported IA-32 addressing modes are made available by functions that denote values of the type Operand. For example, the following code-statement stores the value in EBX at the address pointed to by EAX

The following table summarizes the available addressing modes and the functions used to implement them.

Table 15 Intel Architecture Addressing Modes
Form
Function
Displacement
DISP(disp)
Base
BASE(breg)
Base + Displacement
BASE(breg, disp)
(Index*Scale) + Displacement
NDEX(ireg, scale, disp)
Base + Index + Displacement
BASE_INDEX(breg, ireg, disp)
Base + (Index*Scale) + Displacement
BASE_INDEX(breg, ireg, scale, disp)
Segment
SEGMENT(sreg, mem)
Immediate
IMMED(value)

IMMED_INT(int)

IMMED_INT(int)

+value

-value
External Symbol
EXT(name, disp)

There are a set of type operators which specify the access size of a memory address. The following table summarizes the available operators and their access size.

Table 16 Available Functions and Access Size
Function
Access Size
BYTE(mem)
8-bits
WORD(mem)
16-bits
DWORD(mem)
32-bits
PWORD(mem)
48-bits
QWORD(mem)
64-bits
TBYTE(mem)
80-bits
UNTYPED(mem)
N/A

The type operator Untyped can only be used if the context already indicates the access size. This is useful for those instructions (e.g. FLDENV, FRSTOR, FSAVE and FNSAVE) whose access size does not fall into one of the sized categories.

The following forms show the syntax of forming an addressing mode:

Examples

The operands are used to determine which instruction is to be selected. For example,

provides enough information to determine that the instruction is a move immediate dword to a register, because the register EAX indicates that the operation type is dword. The following example,

is now ambiguous, because an anonymous access type is specified and the immediate value can be of any size. The address mode must specify the access size. The following example chooses the instruction move immediate byte indirect through a register.

The following example,

does not require that an access type be specified, since the register AX, determines that it is a word (i.e. 16-bit) operation.

The Base, Index and Base_Index functions are overloaded to allow the displacement to be specified as a numeric (integer) or as a label reference (operand). Specifying a negative numeric reference, such as -4, can be interpreted as an integer or an operand, due to the overloading of "-". Use qualification or named notation within the function to resolve the overloading of Base, Index and Base_Index. For example,

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

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In many cases, using X'Ref will cause more than a single instruction to be generated.

Labels

When the X\QRef attribute is applied to labels, the address generated is an offset or a branch displacement depending on the instruction. For example, the following instructions generate an offset for Label'Ref. Note that the first instruction is used to obtain the address of Label. The second instruction moves the double word at location Label.

The following instruction uses a branch displacement.

Subprograms

When the X\QRef attribute is applied to subprograms, the address generated is an offset.

Prefix Overrides

A prefix override can be inserted into the code stream by using a data statement with the appropriate value, preceding the code statement. For example,

Floating Point

Floating-point operations are invoked directly by machine instructions which access the IA-32 FPU. The package Machine_Code provides the opcodes and floating-point registers so that the FPU can be referenced directly from machine-code insertions.

For example, the FPU provides instructions that perform trigonometric functions. The Ada function below returns the partial tangent of a value given in degrees. It calls a machine code procedure that uses the FPU to first convert the degrees to radians and then to take the partial tangent using the FPTAN instruction.

Note: In the Apex Ada types Float and Short_Float correspond to a Short Real on the IA-32 FPU, while the type Long_Float corresponds to a Long Real. No Apex Ada type corresponds to Temporary Real.

Programming Examples

Start-Up Routine

Operands are used to control the flow of execution with instructions such as Call, Jcc and Loop/Loopcond. Labels and subroutine names can be used in conjunction with the X\QRef attribute to form destinations for these instructions.

The following example illustrates a hypothetical start-up routine for an Ada program. Its function is to call an initialization routine, and then invoke each entry in the elaboration table that is constructed by the pre-linker.


Machine Code Insertions - M68k Family

This section covers the details of machine code insertions for the Motorola M68K Architecture Family. Be sure to read the Machine Code Insertions Overview before proceeding with this section.

Opcodes

The type Opcode is an enumeration type declared in the package Machine_Code. The type provides all of the supported instructions for the M68000 Family, as well as the instructions for the MC68851 and MC68881/MC68882. Instructions are named by their standard mnemonics with a suffix of _size where applicable. For example, the three TST instructions are represented by the enumeration values TST_B, TST_W and TST_L. The branch instructions Bcc, BRA, cpBcc, cpDBcc and DBcc do not use a _size suffix. The operand determines the size of the instruction.

Operands and Addressing Modes

The type Operand is a private type declared in the package Machine_Code. The package also provides constants of type Operand and functions that return values of type Operand. The Apex-defined attribute X'Ref can be applied to most Ada objects and denotes a value of type Operand.

All the M68000 family, MC68851 and MC68881/MC68882 registers are provided as Operand constants (including registers such as the CCR, SR and the CACR). For example, the following code-statement moves the contents of the CCR to D0:

All the M68000 addressing modes are made available by functions that denote values of type Operand. For example, the following code-statement stores the contents of the location pointed to by A1 at the absolute address 16#BF#.

Using an addressing mode that is not allowed on your processor will cause an illegal instruction exception to be raised at run-time.

The following tables summarize the available addressing modes and the functions used to implement them. The first table covers the addressing modes available on all M68000 family processors. The second table lists addressing modes available only on the MC68020/30/40/60 processors.

Table 17

Mode
Notation
Function
Data Register Direct
Dn
N/A, use Dn
Address Register Direct
An
N/A use An
Address Register Indirect
(An)
INDR(An)
Address Register Indirect Post-Increment
(An)+
INCR(An)
Address Register Indirect Pre-Decrement
-(An)
DECR(An)
Address Register Indirect with Offset
d(An)
DISP(An, d)
PC addressing with offset
d(PC)
DISP(PC, d)
Address Register Indirect with Offset and Index
d(An,Xn.SIZE*SCALE)
SIZE = W or L
SCALE = 1, 2, 4 or 8

INDEX(An, d, Xn, SIZE)
INDEX(An, d, Xn, SIZE,
SCALE

PC Addressing with Offset and Index
d(PC,Xn.SIZE*SCALE)
SIZE = W or L
SCALE = 1, 2, 4 or 8

INDEX(PC, d, Xn, SIZE) INDEX(PC, d, Xn, SIZE, SCALE)
Absolute
(addr).SIZE
SIZE = W or L

Absol(addr, size)
Absol_Int(addr, size)
Absol_Mod32(addr, size)

Immediate
value
+value
-value

Immed(uint_val)
Immed_Int(int_val)
Immed_Mod32(uint_val)

External
name
Ext(name, disp)
Ext_Text(name, disp)
Ext_Const(name, disp)
Ext_Data(name, disp)

Register List
<reg.list>
Rn/Rn/../Rn
Label Difference

label'REF-label'REF
Addressing Modes for M68000 Family Processors

Table 18 Addressing Modes for M68020/40/60 Processors
Mode
Notation
Function
Memory
([bd,An],Xn.SIZE*SCALE,od)
MEMORY(INDR(An), Xn, SIZE)
Indirect
SIZE = W or L
MEMORY(INDR(An), Xn, SIZE, SCALE)
Post-Indexed
SCALE = 1, 2, 4 or 8
MEMORY(INDR(An), Xn, SIZE, SCALE, od)


MEMORY(DISP(An, bd),Xn, SIZE)


MEMORY(DISP(An, bd),Xn, SIZE, SCALE)


MEMORY(DISP(An, bd),Xn, SIZE, SCALE, od)
Memory
([bd,An,Xn.SIZE*SCALE],od)
MEMORY(INDEX(An, bd,Xn, SIZE))
Indirect
SIZE = W or L
MEMORY(INDEX(An, bd,Xn, SIZE), od)
Pre-Indexed
SCALE = 1, 2, 4 or 8



MEMORY(INDEX(An, bd,Xn, SIZE, SCALE))


MEMORY(INDEX(An, bd,Xn, SIZE, SCALE), od)
PC Memory
([bd,PC],Xn.SIZE*SCALE,od)
MEMORY(DISP(PC, bd),Xn, SIZE))
Indirect
SIZE = W or L
MEMORY(DISP(PC, bd),Xn, SIZE,
Post-Indexed
SCALE = 1, 2, 4 or 8
SCALE)


MEMORY(DISP(PC, bd), Xn, SIZE,


SCALE, od)
PC Memory
([bd,PC,Xn.SIZE*SCALE],od)
MEMORY(INDEX(PC, bd,Xn, SIZE))
Indirect
SIZE = W or L
MEMORY(INDEX(PC, bd,Xn, SIZE),
Pre-Indexed
SCALE = 1, 2, 4 or 8
od)


MEMORY(INDEX(PC, bd,Xn, SIZE, SCALE))


MEMORY(INDEX(PC, bd,Xn, SIZE, SCALE), od)

Examples

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

The Disp and Index functions are overloaded to allow the displacement to be specified as a numeric (integer) or as a label reference (operand). The latter is useful in generating PC-relative addresses. Specifying a negative numeric reference, such as -4, can be interpreted as an integer or an operand, due to the overloading of "-". Use qualification or named notation within the function to resolve the overloading of Disp or Index. For example:

For the index and memory-indirect addressing modes of the MC68020, the address-register and/or index-register can be suppressed. The suppressed register mnemonics ZA0-ZA7, ZD0-ZD7 and ZPC are supplied for this purpose. For example, if a data register (Dn) is used as the index register and the address register is suppressed, then a <#007F>data register indirect" access can be generated.

Instructions that use a bit field selector ({offset:width}) or a pair designator (Rn:Rn) use no special syntax in a machine code statement, each component is specified as a single operand. For example, the instruction BFEXTU has the following syntax:

is specified as

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In many cases, using X'Ref will cause more than a single instruction to be generated.

Labels

When the X'Ref attribute is applied to labels, the addressing mode generated is PC-relative or a branch displacement depending on the instruction. For example, the following instructions generate a PC-relative addressing mode for Label'Ref. Note that the first instruction is used to obtain the address of Label. The second instruction moves the long word at location Label. The third instruction jumps to location Label.

The following instruction uses a branch displacement. Note that the size of the instruction is determined by the size of the displacement.

Floating-Point

The Apex compiler generates hardware floating point instructions when compiling against the MC68881, MC68040 or MC68060 standard libraries, and package machine_code includes the opcodes and registers for the M68k floating-point instruction set. For example, the MC68881 provides instructions that perform trigonometric functions. The Ada function below returns the sine of a value given in degrees. It calls a machine code procedure that uses the MC68881 to first convert the degrees to radians and then to determine the sine using the FSIN instruction.

Note: In Apex Ada the type Long_Float corresponds to double precision on the MC68881/MC6882, while the types Short_Float and Float correspond to single precision.

The MC68040 and MC68060 do not support the entire MC68881/2 instruction set. Instructions that are not directly supported are emulated in software through traps to the kernel.

Programming Examples

Device I/O

One of the primary reasons to use machine code insertions is to write an interface to a hardware device.

For example, suppose a board provides an I/O routine that has the following interface specification.

The following code shows how machine code insertions could be used to output a string of characters to this I/O routine. Note that the code in this example is not written to be efficient, but to demonstrate different aspects of machine_code insertions.

Bit Operations

Another valid reason to use machine code insertions is to directly access hardware instructions in order to generate efficient code.

The follow example shows how to write efficient interface to use hardware instructions to perform common bit operations.


Machine Code Insertions - RH-32

This section covers the details of machine code insertions for the RH32 processor. Be sure to read the Machine Code Insertions Overview before proceeding with this section

Opcodes

The type Opcode is an enumeration type declared in the package Machine_Code. The type provides all of the instructions for the RH32 processor, including additional pseudo-instructions described below.

Instructions are named by their standard mnemonics, except where these would conflict with an Ada reserved word (e.g. Abs). In those cases the mnemonic is suffixed with "_Op".

Pseudo-Instructions

The Apex compiler accepts a series of "pseudo-instructions", which are either "macro instructions" that expand into one or more machine instructions, or instructions that control various details of code generation.

A subset of the RH32 defined instructions are really macro instructions; they are realized by one or more machine instructions. The Apex compiler will accept all of the RH32-defined macro instructions, though a small subset of them are currently unsupported and will generate a trap instruction. Also, a few additional macro instructions have been added to make machine code programming more convenient.

Following is a list of these macro instructions:

abs_op
div
fbgt
fbo
fint
ld_b
nor
st_b
abs2
divo
fble
fbuo
frem
ld_h
putio
st_h
call
fbe
fblt
fcvt_1750
fsqrt
mul
rem_op

calli
fbge
fbne
fcvt_754
getio
mulo
return

Operands and Addressing Modes

Type Operand is a private type declared in the package Machine_Code. The package also provides constants of the type Operand and functions that return values of type Operand. The Apex defined attribute X'Ref can be applied to most Ada objects and denotes a value of type Operand.

All the supported RH32 registers are provided as Operand constants.

All the supported RH32 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.

Mode
Notation
Function
Register
reg
N/A
Base Address
(reg)
BASE(reg)
Based Address
disp(reg)
reg + disp
reg - disp

DISP(reg, disp)
Immediate
value
IMMED(value)
"+"(value)
"-"(value)

Large Unsigned Immediate
value
IMMED_MOD32(value)
External Symbol
external_name
EXT("external_name")

Examples

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

Ada Entities as Operands

Objects visible to a machine code procedure (either in packages or enclosing subprograms) can be referenced using the X'Ref attribute. In many cases, using X'Ref will cause more than a single instruction to be generated to form the address of the referenced object.

Labels

When the X'Ref attribute is applied to labels, the addressing mode generated is a branch displacement or evaluates to an address depending on the instruction.

Subprograms

When the X'Ref attribute is applied to subprograms, the reference denotes the address of the subprogram.

Code_1'(Call, Subp'Ref);

Extended Addressing

RH32 instructions that reference memory, or generate memory addresses, use a (base + displacement) calculation to generate the memory address. The basic memory reference instruction is encoded in 32 bits with 16 bits used to hold the displacement value. In situations where the desired displacement exceeds the range -32,768..32,767, we call the address an extended address. When the Ada compiler detects an extended address, it generates additional machine instructions to properly calculate the (base + displacement). Extended addressing allows a displacement exceeding the range of -32,768 to 32,767 for the following instructions:

fld
fst
ld_d
ld_b
st
st_
getio
linkm
fld_d
fst_d
ld
lda
ld_h
st_d
st_h
putio

In most cases involving X'REF, implicit code is generated to form the address.

Floating Point

Floating-point operations are invoked directly by machine instructions which access the RH32 floating point coprocessor. The Machine_Code package provides the opcodes and floating-point registers so that the coprocessor can be referenced directly from machine code insertions.

The operands consist of the general purpose registers, special purpose registers (e.g. Hop, Lop, Cpu_Detail), floating-point registers F0-F15, based addressing, literals and X'Ref (where applicable).

Assembly Language Correspondence

The RH32 instruction set has a rich set of instructions of varying length. Often, there are several instructions that can be used to achieve the same purpose. The RH32 assembly language is defined in a way that most of the choices for the best machine instruction sequence is made by the assembler program, unless the programmer provides an explicit override. For example, if the following assembly language instruction was coded:

This would generate a 16-bit instruction that uses the immediate form to access the immediate value of 5. However, if the programmer wanted the 32-bit form of the add immediate instruction, they would write:

Where the "*" above indicates an override to the assembler, telling the assembler to use the longer form of the Add instruction, even if a shorter instruction might calculate the same value. Often, this override is used to explicitly select a 32-bit instruction when filling a branch delay slot.

As noted above, Apex always fills delay slots, and has no method to let you explicitly fill a delay slot. However, there may be other times when you want to closely control the instructions generated by a given machine code instruction. For this reason, the Apex machine code package has been defined in such a way that most of possible assembly language constructs can be written as an Ada machine code insertion.

The Apex machine code definition places some restrictions on the method that a particular assembly language instruction can be expressed in Ada. Namely:

The RH32 machine code package deals with the difficulties by inventing unique opcode names, when the same machine operation may have a differing number of operands, or where the size of the operands (as in the case of immediate values) might generate different machine instructions.

Programming Examples

Block Compare

The following example compares two blocks of memory and returns 0 if the blocks are equal, or the signed difference of the first bytes that differ.

Jump Table via Addresses

A jump table can be constructed by building a table of addresses. The table is built by using the data statement, where the operands consist of label references to the selected entry points. The following program fragment illustrates the technique.

Each code segment in the table must branch to the end of the routine so that the compiler-generated epilogue code for the routine is executed.

Replacing the branch with a return instruction would not be correct, unless the routine was written with Pragma Implicit_Code(Off). In which case it would be entirely up to the programmer to handle the subroutine linkage.


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