TOC PREV NEXT INDEX DOC LIST MASTER INDEX



Coding Issues Migrating from VADS to Apex

This section provides the known coding issues that a customer will face transitioning from VADS to Apex, regardless of the target Ada dialect used with Apex. We note where fixes differ for the Ada dialect.

When moving code from VADS to Apex, typically there will be some changes required, particularly in those language areas where compiler implementations are free to interpret the language differently. The first question to be addressed is whether to move the code to Apex Ada 83, or make the complete change to Apex Ada 95 as part of the conversion.

Arguments for simplicity would suggest making changes in small increments,that is, moving only to Apex Ada 83, and then later, if desired, moving to Apex Ada 95. However, there are several areas where code changes to make VADS code work with Apex are easier in the Ada 95 dialect than the Ada 83 dialect. For example, Apex does not support passive tasks. If code performance is critical, then Ada 95 is critical to make use of protected types to replace passive tasks; the translation is straightforward, and the resulting code is faster and more general than what VADS provided with passive tasks.

It is our guarded opinion that converting directly to Apex Ada 95 is marginally more desirable than converting only to Apex Ada 83, or converting in two steps.

The following description was developed based on usage of various Apex 3.0 versions, with some information from the Apex 3.2.x versions. It is possible that subsequent patches and incremental updates to Apex may change the messages that are output, or fix some of the areas where workarounds are particularly difficult. For items labeled "bug", the problem is due to a bug in Apex that we expect to fix in a subsequent version or patch.

Note that we have tried to identify all transition issues in this document. If you encounter an issue that is not covered, you are strongly encouraged to make this known to the support team so we can help you determine the appropriate changes, and also develop changes in Apex to make future transitions easier.

The following topics are covered here:


VADS Addressing Trick Using Erroneous Code

In some versions of embedded VADS, a trick may be used to generate long address references in code. The issue comes about on platforms where subroutines might be located further than the typical short offset might allow. For example, on MIPS targets, the one-instruction jump instructions can jump to any address for which the high-order 4-bits are identical, a memory range of 256MB.

Normally 256MB for the application is sufficient, but some systems are designed with main memory in one 256MB bank and a different kind of memory (such as non-volatile RAM) located in a different bank. When jumping to a subroutine located in a different bank, the normal jumps do not provide sufficient addressing space for the linker to modify the instruction to reach the intended destination.

The linker has a feature for adding patch jump code that uses a longer sequence of instructions (and register saving) to reach the intended destination. However, some customers prefer to have the compiler simply generate the necessary instructions in-line. For VADS, there were various tricks used to force the compiler to generate the appropriate long calls.

One such trick was to use code similar to the following:

Note that this code is nonsense. There is no body for Do_Something, so specifying an address for it is senseless. The Apex compiler properly rejects this code, stating that Do_Something'Address is invalid for the address clause, and also complaining that there is no body to complete Do_Something. It is only a quirk of VADS that permitted this to compile and have the desired effect.

With Apex Ada 95, the appropriate solution is to use an object of an access type to the desired function. The object then has the appropriate width (32-bits on MIPS) to address directly any part of memory. The call then uses the access object, which retains the appropriate 32-bit addressing. For the code above, the solution in Ada 95 would look like this:

With Apex Ada 83, the solution is more complex. For creating the full 32-bit references, objects of type address may be used. However, writing the calls using these address objects is more awkward. The calls must use machine_code procedures and jump to the desired location (letting the referenced routine's return code return to the original caller).


Invalid Code Permitted by VADS

The VADS compiler is not as strict as Apex and occasionally there are code segments that compile in VADS but are rejected by Apex. This section lists those known areas where this occurs.

Incorrect Use of La Instruction in MIPS Machine_Code

In VADS, the following machine_code instruction compiles:

The VADS generated instructions load the constant into R1, not the address of the constant as might be supposed from the load address instruction. Apex rejects this code with the following error message:

Admittedly the error message is of no help, however the fix is quite simple. The instruction simply needs to be changes to a "load immediate" instruction:


Package Math not supported in Apex 3.x (MIPS cross only)

The package Math is not supported in Apex 3.x cross to MIPS, as it was in Apex 2.4.6 and in VADS. Note that the package is provided for all native compilers in vads_compatibility_static.ss. The only embedded target system where VADS provided this package is MIPS.

For Ada 83 under Apex 3.2 and beyond (for MIPS embedded targets), there is currently no good solution to transitioning code from VADS that uses the Math package.

For Ada 95 under Apex 3.2 and beyond (for MIPS embedded targets), a Math package is provided in vads_compatibility_static.ss that is very similar to the VADS Math package. It is simply a pure renaming of the mathematical functions found in the Ada 95 "strict" (Ada 95 code) package Generic_Elementary_Functions and corresponding instances (Elementary_Functions, Long_Elementary_Functions, and Short_Elementary_Functions). It typically requires no application code changes to use. User code could be modified to use the Ada 95 packages directly, but this package allows a transition without any code modifications, and has no execution time impact (no extra instructions).

The only differences from the VADS version of this package are the elimination of the Bessel functions (rarely, if ever, used) and the elimination of the locally defined exceptions. The Ada 95 functions in Apex 3.2 are much faster than the original functions in VADS, so application speed is significantly increased.

For Apex 3.0.1 Ada 95 MIPS cross users, it is possible to obtain a copy of the math.1.ada and math.2.ada sources used in Apex 3.2 and use them with the Apex 3.0 definitions of the *_Elementary_Functions packages. However, the Ada 95 math implementation in Apex 3.0 was significantly slower than with Apex 3.2, and is also slower than VADS. However, the ease of transition may make this desirable, particularly if an upgrade to Apex 3.2 is planned in the near future.


Missing or Changed Pragmas

A number of VADS pragmas are missing or have different interpretations or limitations in Apex. Here is what to do in each known case:

Pragma Suppress (Exception_Tables)
This pragma may simply be removed. In VADS, even if there was no exception handling in the associated code, exception table information would be generated and occupy significant space. In Apex, the penalty for these exception tables is not as great, so the pragma is not needed.
Pragma Passive
This pragma may simply be removed. If converting to Ada 95, then the code can be converted to protected types to achieve the higher speed that the pragma provided with VADS. See the associated section on how to make this conversion.
Pragma Optimize_Code
(<True/False>)

This pragma is valid in both VADS and Apex, but in Apex it can only occur within declarations. Turning optimization on and off dynamically within machine code is not supported in Apex. If dynamic optimization is critical, then the code must be broken into separate procedures with appropriate settings of this switch.
Pragma Inline in the body of units
This pragma is valid in both VADS and Apex, but in VADS it is permissible to locate this pragma in the body of a unit, such as the body of a procedure inside the body of a package. In VADS, this means that the inlining will occur for local usage, and inlining may or may not occur for non-local usage of the subroutine, depending on whether the body is compiled before the remote usage is compiled. For Apex, pragma inline may only be applied to the specification of unit. However, in Apex pragma inline is intended only as permission to inline, not a requirement to inline, so the net effect is similar to inlining within the body in VADS. So the simple solution is to simply move the pragma inline into the specification.
Pragma Inline in the specification of units
This pragma is valid in both VADS and Apex, but the meaning is different. In VADS, it means the unit must be inlined if it is at all possible to compile the body before any usage. In Apex, it means the unit may be inlined, if the compiler determines that inlining would be beneficial (if there are not too many usages and the size is sufficiently small, so the benefits of eliminating calling code definitely outweigh any slowdowns due to code expansion affecting cache performance). If the VADS interpretation is desired, then pragma Inline_Only should be applied to the unit, which in Apex eliminates any question of whether a unit may or may not be inlined.


Non-Static System.Address'Ref

In VADS, System.Address'Ref applied to a static value is itself static. In Apex, it is always dynamic. Typically this has little effect, but at least two cases it can cause compilation problems.

Note that this may also cause slower startup in Apex than VADS for global data and routines, because dynamic value initialization requires code execution, while static initialization is computed at compile time and is part of the loaded image. (This effect only occurs with global data. Data declared in subroutines must always be dynamically initialized because all routines are reentrant in Ada.)

The first problem case occurs when elaboration must be static, such as in the V_Krn_Conf and V_Usr_Conf configuration tables. These tables must be static because they are used before elaboration has completed. Typically the code includes one of the following pragmas:

The typical solution is to change items of type System.Address to some other type that can be initialized with a static value. If that is not feasible, then often the code can be changed so that the offending item no longer is required to be statically initialized.

The second problem case occurs when using System.Address constants with machine_code. The prototypical example (using MIPS instructions) is the following:

The Apex compiler creates an error in this case, referencing the Code'2 line with a message like:

The code may be changed mechanically to work around the problem. A typical change is:

This change requires adding the X_const declaration, expressing the X system.address constant in terms of X_const (so the consistency is clear), and fixing the machine_code operand to use X_const instead of X'ref. The function Immed_Mod32() must be applied to the X_const to make it the correct type for the machine_code instruction.


Passive Tasks to Protected Types

VADS supports "Pragma Passive" applied to a suitable task. This pragma changes all task rendezvous calls into simple function calls, protected by a semaphore. The result is significantly increased speed of rendezvous.

Passive tasks are in essence little more than critical regions guarding a sequence of code. The sequence of code is the accept body. Passive tasks use mutexes to guard the critical region. Under VADS, passive tasks must be individual tasks (not task types) and the body code must have one of the following structures:

Only these two forms are allowed. The select statement cannot contain terminate or delay alternatives, nor can it have an else clause.

The code in the accept bodies must not have any active task actions. Actions such as a blocking call to another task, delay statements, task creation, and the like are prohibited.

For Apex Ada 83, there is no alternative for VADS passive tasks. In Apex Ada 83 the task must be used without pragma Passive,that is, as an active task. This will impact application speed, with the severity depending on how often the task entries are called. Typically passive task calls are made less frequently than programmers suppose, so the net effect in a real application is likely only on the order of a few percent, but could be as much as 10 or 20 percent slowdown.

For Apex Ada 95, a protected type object can be used, and provides even faster speed than obtained with pragma Passive. The Ada 95 construct can be made into a data type so multiple objects with the same structure can be defined just as is possible with passive tasks.

The Ada 95 protected type is a much more powerful construct than Ada 83 VADS passive tasks. For example, procedures and functions can be defined in addition to entries, to allow more access to the declarative items. A buffer "count of items stored" function could be implemented using a function, resulting in much faster execution and less blocking than possible with passive tasks.

For the accept form of a passive task, the transformation is:

Basically the declarative items are moved to the private part of the specification and the entry definition and accept statement are transformed into a procedure call. This is more efficient than using an entry call, and the limited definition permits this to be implemented with a single procedure call. If appropriate the procedure call could be transformed into a function call.

For the select form of the passive task, the transformation is:

Basically the declarative items are moved to the private part of the specification and the accepts within the select loop are changed into protected entry bodies. The conditions of the select are moved to be conditions applied to the individual entries.

The code sequences typically need little, if any work. The one case where changes might be necessary are if there are any explicit mutex actions in the body.

If the passive task has an interrupt mutex associated with it, the same effect may be achieved by using standard Ada 95 constructions:

Note that in Ada 95, the level of interrupt should be set to the highest interrupt that will be using the type, the "Ceiling" priority. That way higher priority interrupts can still occur during calls to the protected type.

Also, since there is no task life associated with protected objects, any reference to it as a task must be deleted. In particular, calls with exception handling of Tasking_Error exceptions can be eliminated, as the calls do not involve a task. Any use of task attributes, for example Pt'Callable or Pt'Terminated should be eliminated. Effectively the routines are always callable and never terminated.

The additional forms of pragma Passive in VADS (Abort_Safe or Abort_Unsafe) may be ignored, as they have no meaning with protected types where there is no task state to be considered. Any abort statements referring to the passive task should be deleted when it is converted to a protected type.


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