Each machine instruction appears as a code statement, which is a record aggregate of a record type that defines the corresponding instruction. Such record definitions will generally be available in a system-dependent library package called MACHINE_CODE. This package must also contain the representation of the record that describes the machine instruction format. Code statements may be used only in procedures whose bodies consist entirely of code statements.
The following example illustrates the use of a set system mask instruction on an IBM 370. The package MACHINE_CODE could be as follows
package MACHINE_CODE is type REGISTER is range 0 .. 16#F#; type DISPLACEMENT is range 0 .. 16#FFF#; type OPCODE is ( ... , SSM, ... ); type RR is ... type RX is ... type SI is record CODE : OPCODE; B : REGISTER; D : DISPLACEMENT; end record; ... for OPCODE use ( ... , SSM => 16#80#, ... ); ... for SI use record CODE at 0 range 0 .. 7; B at 0 range 16 .. 19; -- bits 8 .. 15 unused D at 0 range 20 .. 31; end record; ... end MACHINE_CODE;
We will assume in what follows that the set system mask operation is defined as part of a package, along with similar operations:
package SPECIAL_COMMANDS is ... procedure SET_SYSTEM_MASK(X : MASK); pragma INLINE(SET_SYSTEM_MASK); ... end; with MACHINE_CODE; package body SPECIAL_COMMANDS is ... procedure SET_SYSTEM_MASK(X : MASK) is use MACHINE_CODE; begin SI'(CODE => SSM, B => X'BASE_REG, D => X'DISP); end; ... end SPECIAL_COMMANDS;
For the body of this package, a with clause mentioning MACHINE_CODE is required: this rule will enable programming support environments to enforce certain management rules concerning the use of machine code insertions. This example also shows the need to use implementation- specific predefined attributes in code statements, such as X'BASE_REG (the base register used for X) and X'DISP (the displacement of X). Additional implementation-specific pragmas may be needed to specify the register and linkage conventions.
Obviously such pragmas cannot be machine-independent; the only order that may be brought by a high level language to such a matter is to standardize the conventions to be used for such specifications, and this is what we achieve in Ada by recourse to pragmas. Finally, pragmas can also be used to specify that a subprogram called from an Ada program is written in another language. Consider for example the reuse of functions defined in the Fortran library, from an Ada program. To achieve this, we declare a package
package FORTRAN_LIB is function SQRT (X : FLOAT) return FLOAT; function EXP (X : FLOAT) return FLOAT; ... private pragma INTERFACE(FORTRAN, SQRT); pragma INTERFACE(FORTRAN, EXP); ... end FORTRAN_LIB;
For each function needed we have declared an Ada function in the usual manner, and this function can then be called using the normal Ada syntax. However, the bodies of these functions are not written in Ada and we indicate this by INTERFACE pragmas. These inform the compiler about the corresponding linkage conventions, and also to expect the object code to be provided later (at linkage editing time). Of course compilers may impose restrictions on the form of parameters that are allowed (for example, passing two-dimensional arrays may be complex, given the internal representation used by Fortran). Not all compilers need provide this machine code insertion capability.