top - download
⟦53cb1ed8f⟧ Wang Wps File
Length: 21611 (0x546b)
Types: Wang Wps File
Notes: DELCO ADA (058)
Names: »4484A «
Derivation
└─⟦57fb8c09c⟧ Bits:30006028 8" Wang WCS floppy, CR 0392A
└─ ⟦this⟧ »4484A «
WangText
…00……00……00……00……00…G…0a……00……00…G…0b……86…1 …02… …02… …02… …02…
DELCO ADA SYS/84-01-16
Page #
T̲A̲B̲L̲E̲ ̲O̲F̲ ̲C̲O̲N̲T̲E̲N̲T̲S̲
Page
1. THE CHRISTIAN ROVSING A/S ADA PROJECT ......
2. TECHNICAL APPROACH TO THE INTEL 8086
ADA SYSTEM .................................
3. SYSTEM COMPONENTS ..........................
3.1 COMPILER ...............................
3.2 LINKER .................................
3.3 DOMAIN UTILITY .........................
3.4 RUN TIME SYSTEM ........................
3.5 IO SYSTEM ..............................
1 T̲H̲E̲ ̲C̲H̲R̲I̲S̲T̲I̲A̲N̲ ̲R̲O̲V̲S̲I̲N̲G̲ ̲A̲/̲S̲ ̲A̲D̲A̲ ̲P̲R̲O̲J̲E̲C̲T̲
In December 1980 a consortium consisting of Christian
Rovsing A/S, Danish Datamatics Centre (DDC) and Olivetti
(Italy) was awarded a contract from the Commission
of the European Communities (CEC) to produce a Portable
Ada Programming System (PAPS). The system was to be
implemented on the Christian Rovsing A/S CR80 computer
and the Olivetti M40 computer.
The division of work between the three partners is
as follows:
Compiler: DDC and Christian Rovsing A/S
CR80 RTS: Christian Rovsing A/S
MAPSE + M40 RTS: Olivetti
The technical approach taken in the project has been
to define a virtual stack machine - called the A-machine
- for which the compiler generates code. An interpreter
for the A-machine has been implemented in firmware
and software on the CR80.
The compiler has been hosted on the CR80 itself as
well as on the VAX11. Both compilers will be completed
within the next 4 months and DOD validation will then
be initiated.
2 T̲E̲C̲H̲N̲I̲C̲A̲L̲ ̲A̲P̲P̲R̲O̲A̲C̲H̲ ̲T̲O̲ ̲T̲H̲E̲ ̲I̲N̲T̲E̲L̲ ̲8̲0̲8̲6̲ ̲A̲D̲A̲ ̲S̲Y̲S̲T̲E̲M̲
The basic idea is to take the VAX hosted compiler and
retarget it for the 8086 (really, 80186 code will be
generated but we will continue to use the term "8086").
The compiler will be used in connection with the Intel
iAPX-86/88/186 software development package hosted
on the VAX. The iAPX development package is not included
in this proposal. The program development scenario
is sketched below:
Ada source programs are compiled into object modules.
One object module is specified to the Ada linker as
being the main program. The Ada linker will then link
this object module together with all dependent modules
to form one link module in the format required by the
VAX-LINK-86 linker. The VAX linker will then perform
the final linking where the output from the Ada linker
is linked together with the run time system.
It is possible to write an Ada subprogram body, an
Ada task body or an Ada package body in assembly language
if this is necessary f.ex. to obtain better efficiency
or to utilize special hardware features. Such assembly
language modules are included in the final VAX linking.
Certain rules relating to the transfer of subprogram
parameters and results must be obeyed by the assembly
language programmer. These rules are defined by the
run time system and documented in the run time system
documentation.
3 S̲Y̲S̲T̲E̲M̲ ̲C̲O̲M̲P̲O̲N̲E̲N̲T̲S̲
3.1 C̲O̲M̲P̲I̲L̲E̲R̲
The Ada Compiler System offered consists of a number
of logical passes, which are supplemented by an Initialization
Component, an Error Display Component, three listing
components, a Termination Component, and a Fatal-Component.
The passes and the components mentioned above are called
the "logical components" of the compiler.
The logical passes perform the proper compilation,
whereas the Error Display Component displays the errors
that were found in the previous logical pass, if any.
The Initialization Component interprets the user-specified
parameters and initializes common data structures,
whereas the Termination Component removes temporary
files. The three listing components create the source
listing, the cross-reference listing, and the object
code listing. The Fatal-Component is only activated
if the compilation is aborted.
As many of the components perform identical tasks,
e.g. store information for a diagnostic message, about
12 supporting packages have been implemented. Any component
may freely include the packages from which it can take
advantage.
The compiler has been divided into a number of separate
programs, which are called the "physical components"
of the compiler. A physical component may contain one
or more logical components, whereas a logical component
must be contained entirely in one physical component.
The design of the physical component ensures that it
is straightforward to gather two or more logical components
into one physical component, or to split a physical
component containing two or more logical components
into separate physical components.
The physical components are activated by a separate
program called the Multipass Administrator, usually
abbreviated MPA. The resulting structure of the Ada
compiler is shown in Figure 1.:
Figure 1.: The structure of the compiler.
The handling of separate compilation requires a separate
program, which is described below.
From the point of view of the compiler, the supporting
package named the Separate Compilation Handler (SCH)
constitutes the interface between the compiler and
the program library. The program library is contained
in the domain, which is administered by a realtime
program called the domain manager. The domain manager
is used not only by the compiler but also by the linker
and other utility programs that need access to the
domain. The interfaces are sketched below.
Figure 2.: Interfaces between a pass, the domain,
and the native file system.
F̲r̲o̲n̲t̲ ̲E̲n̲d̲
The first six passes of the Ada Compiler constitute
the Front End, which as its main task accepts ANSI
Ada source statements and produces an intermediate
language, which is input to the Back End. The Front
End is target-independent except for some target-dependent
constants. The Front End produces:
- A tree-structured intermediate language called
IML…0f…7…0e…, which is input to the target-dependent Back
End.
- Various tables, such as the symbol table, which
are used by the Back End.
- Diagnostic messages if any syntactic or semantic
errors were found during the analysis.
B̲a̲c̲k̲ ̲E̲n̲d̲
The proposed Back End of the Ada Compiler for the 8086
consists of the Middle Component and the Final Code
Generator. The purpose of the Middle Component is to
accept the IML…0f…7…0e… generated by the Front End and generate
an Abstract A-code, whereas the Final Code Generator
accepts the Abstract A-code and generates the final
code. The Back End is shown in Figure 3 below:
Figure 3.: The Back End of the Ada Compiler.
O̲p̲t̲i̲m̲i̲z̲a̲t̲i̲o̲n̲
One optimization carried out by the Front End is folding
of constants, but additionally the Front End performs
an extensive evaluation of the intermediate text, which
also includes taking full advantage of the symbol table.
The evaluation yields truth values, so-called predicates,
describing properties of the intermediate text. The
predicates are a part of the output (IML…0f…7…0e…) from the
Front End. The predicates are aimed at guiding the
code generator towards good code quality with respect
to code memory space and execution time efficiency.
The areas in which the predicates in particular aid
the code generation are:
- elimination of range checks
- reduction of range checks to only check against
either a lower or an upper bound
- elimination of length checks
- elimination of discriminant checks
- elimination of record field existence checks
- relocation of composite static expressions to constant
areas
- elimination of unnecessarily repeated evaluations
of expressions
- subprogram calls (avoid general parameter set-up)
- allocation of temporary storage in connection with
expression evaluation
- elimination of dead code in connection with if
and for loop statements.
P̲r̲e̲d̲e̲f̲i̲n̲e̲d̲ ̲T̲y̲p̲e̲s̲
The compiler will support the types BOOLEAN, INTEGER,
LONG INTEGER, FLOAT, LONG FLOAT, CHARACTER, STRING,
and DURATION, and one other fixed-point type as predefined
types.
Type BOOLEAN
Array of BOOLEAN will represent each element with a
single bit provided that pragma PACK is applied. Variables
of type BOOLEAN will be stored in (16-bit) word.
Type INTEGER
Variables of type INTEGER will be represented by a
single word. Operations on INTEGER variables will use
16-bit twos-
complement arithmetic.
Type LONG ̲INTEGER
Type LONG ̲INTEGER will be represented by a double-word
value. Operations on LONG ̲INTEGER variables will use
32-bit twos-complement arithmetic.
Type FLOAT
Type FLOAT will be represented by the 32-bit floating-point
arithmetic hardware format. This has a eight-bit exponent,
a sign bit, and a 23-bit mantissa.
Type LONG ̲FLOAT
Type LONG ̲FLOAT will use the 64-bit hardware floating
point format. This is similar to the 32-bit format,
except that it has a 52-bit mantissa and an eleven-bit
exponent.
Type CHARACTER
The type CHARACTER will be represented in one word.
Type STRING
The representation of strings will have one character
per byte.
Type DURATION
The representation of DURATION will be a double-word
integer with an implicit divisor of one thousand.
Additional Predefined Types
There will be at least one predefined fixed point type
in addition to DURATION.
3.2 L̲I̲N̲K̲E̲R̲
In order to utilize the native linker of a computer
system, an Ada Linker Front End will be provided. The
front end performs the Ada-specific parts of the linking,
and in this way the cost of the complete Ada Linker
will be reduced significantly.
Based upon a user-specified "main program" the Ada
Linker Front End checks all units for compliance to
the Ada Reference Manual with respect to compilation
and elaboration order.
The linker then determines an elaboration order and
according to this order, it generates a small object
code initialization program, which is the entry point
of the entire program. The purpose of the initialization
program is to call the elaboration routines of all
compilation units in an appropriate order and finally
call the compilation unit specified as the main program.
In addition, a command file for the native linker is
generated.
The linking is illustrated in figure 4 below:
Figure 4.: Linking of Ada programs.
3.3 D̲O̲M̲A̲I̲N̲ ̲U̲T̲I̲L̲I̲T̲Y̲
A so-called Domain Utility will be provided, which
is able to initialize a program library and which can
be used to inspect library units in the program library.
The package STANDARD is inserted in the program library
by means of a separate tool. The packages SYSTEM, UNCHECKED
̲DEALLOCATION, and UNCHECKED ̲CONVERSION are simply compiled
into the domain.
The Domain Utility is able to list various information
about all library units in a program library including
the date of the latest modification.
3.4 R̲U̲N̲ ̲T̲I̲M̲E̲ ̲S̲Y̲S̲T̲E̲M̲
The run time system supports a target configuration
consisting of one or more 80186 CPU's sharing a common
memory. Interrupt driven communication to the external
world is also supported.
Target Computer
The entire application software in the target computer
comprises one Ada program. If it is desirable to divide
the application into - possibly logically unrelated
- parallel parts, this is done by using the tasking
facility in Ada.
Even though the application software is an Ada program
this does not mean that all of the software must be
written in Ada. As has been mentioned earlier a separately
compiled subprogram body, task body or package body
may be written in assembly language as long as the
programmer obeys the parameter passing rules that are
set forth by the Ada run time system.
The application program is separated into a code part
and a data part. The code size of a separately compiled
module cannot exceed 64KB. However, the code size for
the entire program is not limited to this value. The
size of the data part of the program is limited to
64KB because of the addressing constraints in the 80186.
It is convenient to divide the run time system into
three parts which are described separately below.
3.4.1 N̲o̲n̲-̲t̲a̲s̲k̲i̲n̲g̲ ̲S̲u̲p̲p̲o̲r̲t̲ ̲R̲o̲u̲t̲i̲n̲e̲s̲
This set of routines implements functionality which
it would be inconvenient to obtain by generating in-line
code. The following functionality is included:
3.4.1.1 H̲e̲a̲p̲ ̲M̲a̲n̲a̲g̲e̲m̲e̲n̲t̲
The heap management contains routines for allocating
and releasing memory objects of a given size from a
heap.
The run time system contains one permanent heap called
the system heap. Apart from the system heap other heaps
may be allocated in a stack frame when a block is entered
that contained a length clause of the form
for T use expression
where T is some access type. Such a heap will have
the size expression and objects allocated by an allocator
of the form n̲e̲w̲ T will be allocated on this heap. When
the block is exited the entire heap dissappears together
with the stack frame. Apart from this no automatic
garbage collection is performed. Heap objects allocated
by the run time system itself, such as task control
blocks are of course released when no longer needed.
3.4.1.2 S̲u̲b̲p̲r̲o̲g̲r̲a̲m̲s̲ ̲a̲n̲d̲ ̲B̲l̲o̲c̲k̲s̲
When a subprogram or block is entered a routine is
called to set up a new stack frame. The routine establishes
addressing of the new block and marks it as not having
an associated exception handler. The run time system
distinguishes two kinds of blocks, task-blocks which
can potentially have dependent tasks and nontask-blocks
which cannot have dependent tasks. When a block is
left, a clean up routine is called and only when leaving
a task-block is the tasking kernel called to await
termination of dependent tasks. In this way the overhead
involved in searching for dependent tasks is avoided
in the majority of cases where there cannot be any
dependent tasks.
…86…1 …02… …02… …02… …02…
A function subprogram may be left in two ways. Either
the "normal" way where a function result is taken from
the top of the stack and copied to the stack top of
the calling environment, or a return may be made to
the calling environment without changing the stackpointer.
The latter case is used when the function returns on
object, the size of which is unknown of compile time,
e.g. an array with dynamic bounds. In this case the
function result is left on the top of the stack together
with information about its size and the caller must
then decide how to use it.
3.4.1.3 E̲x̲c̲e̲p̲t̲i̲o̲n̲ ̲H̲a̲n̲d̲l̲i̲n̲g̲
An Ada exception handler is translated to a case-like
construct containing pieces of code corresponding to
individual exceptions to be handled. These code pieces
are preceded by a table, which contains the identification
of each exception in the handler together with the
address of the code for this exception.
The exception handling module contains a routine that
associates an exception handler (i.e. a code address)
with the current block/subprogram. This routine is
called at the end of the declarative part of a block/subprogram
which contains an exception handler.
When an exception occurs, the exception handler searches
the stack backwards for a handler that will handle
the exception.
3.4.1.4 F̲l̲o̲a̲t̲i̲n̲g̲ ̲P̲o̲i̲n̲t̲ ̲A̲r̲i̲t̲h̲m̲e̲t̲i̲c̲
This module implements floating point arithmetic on
32 bit and 64 bit floating point numbers in the format
used by the Intel 8087 numeric processor extension.
If there is a requirement for using the Intel 8087
to obtain faster floating point arithmetic the compiler
could be modified to generate instructions for the
8087 instead of using this run time system module.
However, this option is not moduled in the present
proposal.
3.4.1.5 F̲i̲e̲l̲d̲ ̲H̲a̲n̲d̲l̲i̲n̲g̲
This module manipulates bit fields of width 1, 2, 4,
8 or 16 bits. It is used to move values between packed
arrays (e.g. of booleans) and unpacked variables. It
is also used to handle some compiler generated packed
datastructures.
3.4.2 T̲A̲S̲K̲I̲N̲G̲ ̲K̲E̲R̲N̲E̲L̲
The tasking kernel which implements Ada tasking concepts
relies on the existence of a very simple process concept
on which to build on. This process concept is described
in the next section.
The concepts in the tasking kernel are very close to
those of Ada implying a very straight forward code
generation as regards tasking.
The tasking kernel contains the following functions:
C̲r̲e̲a̲t̲e̲ ̲T̲a̲s̲k̲
Creates a new task and returns its identification (=
its task control block address). A task control block
is created on the system heap and initialized. The
new task remains unactivated. The stack space for the
new task is also allocated on the system heap. The
size of the stack is either some default value or it
may be specified by the programmer by using a length
clause (cf. LRM section 13.2).
It may be specified whether one or more entries in
the task corresponds to external interrupts.
A̲c̲t̲i̲v̲a̲t̲e̲ ̲T̲a̲s̲k̲s̲
Activates a number of tasks and blocks the calling
task until activation is completed.
A̲c̲t̲i̲v̲a̲t̲e̲d̲
Signals that the calling task has completed its activation.
A̲b̲o̲r̲t̲ ̲T̲a̲s̲k̲s̲
Aborts a number of tasks.
D̲e̲l̲a̲y̲
Delays the calling task for a specified duration.
C̲a̲l̲l̲ ̲E̲n̲t̲r̲y̲
Performs an entry call to a specified entry and blocks
the calling task until a rendezvous has been completed.
C̲a̲l̲l̲ ̲E̲n̲t̲r̲y̲ ̲T̲i̲m̲e̲d̲
Same function as Call Entry except that a time out
value is specified.
S̲e̲l̲e̲c̲t̲ ̲E̲n̲t̲r̲y̲
Performs all the functionality of Ada's s̲e̲l̲e̲c̲t̲ statement
including d̲e̲l̲a̲y̲ and t̲e̲r̲m̲i̲n̲a̲t̲e̲ alternatives.
R̲e̲n̲d̲e̲z̲v̲o̲u̲s̲ ̲C̲o̲m̲p̲l̲e̲t̲e̲
Signals that a rendezvous has been completed.
R̲e̲n̲d̲e̲z̲v̲o̲u̲s̲ ̲F̲a̲i̲l̲u̲r̲e̲
Signals that a rendezvous has been completed and that
a specified exception shall be propagated to the caller.
A̲t̲t̲r̲i̲b̲u̲t̲e̲s̲
Returns one of the attributes 'callable', 'teminated'
and 'storage size'.
E̲n̲t̲r̲y̲ ̲C̲o̲u̲n̲t̲
Returns the number of callers queued for a certain
entry.
The tasking kernel operates on a set of task control
blocks which are allocated on the system heap. The
task control blocks are protected by a semaphore so
that only one task at a time has access to the task
control blocks.
3.4.3 P̲r̲o̲c̲e̲s̲s̲ ̲a̲n̲d̲ ̲I̲n̲t̲e̲r̲r̲u̲p̲t̲ ̲K̲e̲r̲n̲e̲l̲
The purpose of the process and interrupt kernel is
to provide a foundation on which the tasking kernel
may be implemented.
It is convenient to distinguish between processes which
is a concept of the target computer and tasks which
is an Ada concept. In this run time system there is
a one-to-one correspondance between these concepts
in that each Ada task is mapped onto a process.
The process and interrupt module contains the following
functionality:
- creation and removal of processes
- distribution of CPU's to processes; each process
has a priority which is the same as the corresponding
task priority. CPU's are delegated to those processes
with highest priority. In case there are more such
processes than CPU's, the CPU's are time sliced
evenly among the processes
- reception of interrupts. If a task entry has been
designated as the receiver of a certain interrupt,
an entry call to this entry will be generated when
the interrupt occurs. Interrupts not corresponding
to any task entry are lost
- implementation of a semaphore concept. It is used
by the tasking kernel to protect the task control
blocks
- a debug interface to the external world. This interface
allows an external debugger to be connected (f.ex.
via an RS232 line) to the target program. The debug
interface allows the external debugger (which is
itself not included in this proposal) to
- read and write memory and registers
- insert breakpoints
- receive notification when certain events, such
as exceptions and rendezvous happens.
It may be that use of the debugging facility restricts
the number of CPU's that can be utilized in a system
to one. However, this issue requires further analysis.
3.5 I̲O̲ ̲S̲Y̲S̲T̲E̲M̲
A 'real' Ada IO system is not provided. However, in
order to adhere to Ada in a formal way, a dummy IO
system will be provided. This dummy system will raise
the 'use-error' exception each time an attempt is made
to open or create a file. Output to the standard output
file is disposed of and a call to read from the standard
input file never returns.