@NewPage @Section[PROGRAM ENVIRONMENT (IMP/PASCAL)] @SubSection(Procedure Call Conventions and Register Usage in IMP /Pascal) @IndexSecondary(Primary="IMP", Secondary="Register Usage") @IndexSecondary(Primary="PASCAL", Secondary="Register Usage") @IndexSecondary(Primary="IMP", Secondary="Procedure call conventions") @IndexSecondary(Primary="PASCAL", Secondary="Procedure call conventions") @SeeAlso(Primary="PASCAL",Other="Program environment") @SeeAlso(Primary="IMP",Other="Program environment") @IndexSecondary(Primary="Program environment", Secondary="Modules") @Paragraph(Modules) The code generated by the IMP/PASCAL compilers is pure and position-independent. A module is an independent compilation unit, corresponding to a main program or a file of external procedures and/or external data. A main program module may also contain external procedures/data; the only distinction is that it has a non-null main block. If a module has any static data (including linkage for external references), the module contains a code sequence to initialise the allocated static data area. This allows a module to be reset without re-loading or re-allocating the static data area. The system provides for automatic linking of modules at load time, or dynamically, at the time of first call. @IndexSecondary(Primary="Program environment", Secondary="Register Usage") @Paragraph(Register Usage) @Begin(FileExample) SP: stack pointer A6: link register for level 1 procedures A5: base for process-global data A4: base for static data (+) - all modules (which have static data) top-level data (-) - main program module (level 0) @End(FileExample) A3-A0: temporaries and parameter passing @Begin(FileExample) D7: unassigned pattern D6: stack limit + 256 D5: line number (if maintained dynamically) D4: Byte accumulator (high order 24 bits kept clear) @End(FileExample) D3-D0: temporaries and parameter passing @IndexSecondary(Primary="Program environment", Secondary="Parameter passing") @Paragraph(Parameter passing) By default, parameters and results are passed in registers, up to the number assigned for this purpose (4 data registers and 4 address registers). Values are passed in data registers and addresses are passed in address registers. Registers in the two groups are assigned starting from D0 and A0, respectively. A value result for a function is passed in D0 (D0 and D1 if two-valued) and an address result in A0. For these purposes a value is any parameters passed into it in registers to local storage as appropriate. (Under optimisation, this may not be necessary in the case of simple procedures.) In the case of structure values passed as addresses, it is the structure content which is stored, not the address, so that the properties of pass-by-value are preserved. When the result of a structure function is returned as an address in A0, it may point to the now released stack frame and the receiving code requires to move the structure elsewhere (eg by pushing it properly onto the stack). Parameters beyond those which can be accommodated in registers of the appropriate group are pushed to the stack in reverse order of occurrence. In this case, the actual value is pushed for all value parameters (including structures), the 32-bit address for %name parameters. There are special unpublicised conventions in the IMP compiler which allow explicit control to be exercised over how many registers are used for parameter passing and hence when the escape to the stack is invoked. @IndexSecondary(Primary="Program environment", Secondary="Procedure call mechanism") @Paragraph(Procedure call mechanism) Internal procedures (ie those local to the module making the call) are called using BSR (possibly reach-extended by one or more BRAs as stepping-stones): @Begin(FileExample, LeftMargin +2) evaluate parameters; BSR dddd; remove any stacked parameters @End(FileExample) Extracode procedures (regarded as hardware extensions) are called by the sequence: @Begin(FileExample, LeftMargin +2) evaluate parameters; JSR aaaa; remove any stacked parameters @End(FileExample) where aaaa is the absolute address of the relevant extracode vector slot. @IndexSecondary(Primary="Program environment", Secondary="System procedures") System procedures are called by the sequence: @Begin(FileExample, LeftMargin +2) evaluate parameters; JSR xxx(A4); remove any stacked parameters @End(FileExample) with the content of the section of the static data area starting at xxxx is initialised at load/link time to: @Begin(FileExample, LeftMargin +2) JMP eeeeeeee @End(FileExample) @IndexSecondary(Primary="Program environment", Secondary="External procedures") External procedures are called by the sequence: @Begin(FileExample, LeftMargin +2) push A4; eval param; JSR xxx(A4); remove param; pop A4 @End(FileExample) with the content of the section of the static data area starting at xxxx initialised at load/link time to: @Begin(FileExample, LeftMargin +2) MOVE>L #newa4,A$; JMP eeeeeeee @End(FileExample) For dynamic external procedures, the call is the same but the 12-byte sequence is initially set to invoke the loader. Note that it is the responsability of the calling sequence to adjust the Stack Pointer to remove any stacked parameters following the call. (Motorola thought of ReTurn and De-Allocate stack too late for the original 68000). There is no general assumption about the preservation of the values of the temporary registers accross procedure calls. The standard entry sequence does not therefore save these registers. In the case of most extracodes and certain system procedures, however, there are stipulated registers involved in each case and other registers are preserved. @IndexSecondary(Primary="Program environment", Secondary="Addressing conventions") @Paragraph(Addressing conventions) The process-global data area maintains the process environment, in particular the input/output context and the exception trap linkage. This is common to all the modules making up a complete program. It is addressed by the Global Base register (A5). @IndexSecondary(Primary="Program environment", Secondary="Static data") Static (own) data, in either main program modules or external modules, is accessed at non-negative dispacements from the Static Base register (A4). Every module which has any static data (required also for linkage for external references) has its own static data area which is private to (a specific incarnation of) the module. (The code of a module is sharable; the data area, in general, not). The calling sequence for an external procedure (or one that might be, eg a procedure parameter) includes code to save and restore the current Static Base and the transfer sequence sets it for the module containing the procedure. This is done without affecting the way in which parameters are handled. In a main program module, the static data area is allocated from the initial stack allocation for the program and addressed in the usual way positively from the Static Base. "Dynamic" data in the main program (top-level) is then allocated on the stack and is addressable negatively from Static Base. Local variables in the current stack frame are accessed SP-relative (positive or zero displacements). This strategy is used since many procedures have variables which are accessed only locally, so that no other form of access requires to be provided. Variables at intermediate levels, neither local nor top-level, are accessed using a version of the "display" technique for multi-level addressing. A single address register (A6) is reserved for level 1 procedures (main program being taken as level 00 and the display for lower levels is held in store (at the start of the process-global area, maximum level 7). The store-held part of the display is slaved into temporary address registers as needed. In most cases the stack extension for a block or procedure is of fixed size. The extension is made incrementally, corresponding to the declaration of individual dynamic variables, but with accumulation of multiple declarations. This strategy allows efficient assignment of initial values and enables the use of SP-relative addressing on a one-pass basis. Where arrays of variable size are involved, the total stack extension is of unknown size. In such cases, the dope information and one or two pointer slots for each array are allocated as part of the fixed stack extension, and the arrays are subsequently allocated at the end of the fixed part. The presence of this section of unknown length prevents the use of SP-relative addressing (except for later declared compiler temporaries), so that local addressing in such cases follows the pattern for intermediate level addressing. Fixed size arrays which are big enough to threaten addressability of the fixed section (max 32k bytes) are treated as if they were of variable size. @IndexSecondary(Primary="Program environment", Secondary="LINK") At procedure entry, a LINK operation (on A6 or stored display slot) is performed if at least one of the following conditions holds: @Begin(FileExample, LeftMargin +2) (a) there are non-local references to variables at this level; (b) there are dynamic (or large) objects declared at this level; (c) there is an event trap statement in the procedure; (d) stack diagnostics are enabled (pending). @End(FileExample) (Although the compilers are one-pass, the entry sequence is generated at the end of a procedure, rather than the beginning.) @SubSection(Object Module Format) @IndexSecondary(Primary="Program environment", Secondary="Object module format") Object module files consist of a number of sections. These are, in order of occurence: @Begin(Description) @IndexSecondary(Primary="Program environment", Secondary="HEADER") HEADER @\Iinformation about complete module and section lengths. @IndexSecondary(Primary="Program environment", Secondary="EXPORTS") EXPORTS @\List of identifiers defined in this module for external use. @IndexSecondary(Primary="Program environment", Secondary="IMPORTS") IMPORTS @\List of external identifiers referenced in this module. @IndexSecondary(Primary="Program environment", Secondary="CODE") CODE @\Binary position-independent code of module. @IndexSecondary(Primary="Program environment", Secondary="DIAG") DIAG @\Diagnostic tables if present. @End(Description) All section sizes are even numbers of bytes. The total length of the object module file is the sum of the sizes of the individual sections. Numeric information is in standard M68000 binary twos-complement representation (MS bytes first). The header section has a fixed size of 32 bytes (for module format V02). Its layout is: @Begin(Group) @Begin(FileExample, LeftMargin +2) 0000 F E 0 2 object module code + version 0002 0 0 0 0 spare 0004 export size size of export section (bytes) 0006 import size size of import section (bytes) 0008 code size of code 000A size section (bytes) 000C reset entry reset entry point (word) [1] 000E main entry main entry point (word) [1] 0010 static data required size for static 0012 size data area (bytes) 0014 stack required size for 0016 size stack (bytes) [2] 0018 diag section size of diagnostic 001A size section 001C 0 0 0 0 spare 001E 0 0 0 0 spare [1] word (16-bits) displacement from start of code section [2] stack size > 0 is actual requirement when known stack size <= 0 is negated minimum requirement @End(FileExample) @End(Group) Both the import and export sections consist of a variable number of consecutive records, one for each identifier. The last record is followed by at least one zero word as an end marker. (This is for processing convenience; the overall section size is as given in the header). The records are of variable size, depending on the length of the identifier. The size of the record is 13 plus the length, evenned up. @Begin(Group) The layout of each record is: @Begin(FileExample) 0000 x x x x flag word [1] 0002 type type [2] 0004 " information 0006 " words 0008 address byte address of 000A " entity or reference [3] 000C+ identifier text of identifier " (length-prefixed string) " [1] relevant bits (MS bit = 15): 15 = 0: last (terminator word) = 1: not-last 14 = 0: internal (to be ignored) = 1: external 13, 12 = 00: data object = 01: system procedure = 10: external procedure = 11: dynamic external procedure [2] {to be specified: not used at present} [3] for a data entry in the export list, the address is the byte displacement of the object relative to the start of thestatic datae area. for a procedure entry in the export list, the address is the byte displacement of the entry-point relative to the start of the code area. for a data entry in the import list, the address is the byte displacement in the static data area of a 4-byte slot to be filled in with the absolute address of the object. for a procedure entry in the import list, the address is the byte displacement in the static data area of a 6-byte (system) or 12-byte (external) call sequence to be set up to call the procedure. @End(FileExample) @End(Group) @NewPage @Paragraph(Example Pascal Program) @Begin(FileExample, LeftMargin +2) PROGRAM simple; PROCEDURE process (a:Integer); EXTERN; VAR i: Integer; BEGIN read(i); process(i); END. @Begin(Group) Complete object module file (no diagnostics) @b[HEADER] 0000 FE02 file-type code (FE), version (02) 0002 0000 [unused] 0004 0000 size of export section (0) 0006 0028 size of import section (40 bytes) 0008 0000 code section size 000A 0044 (68 bytes) 000C 000D reset entry (word 13 = byte 26) 000E 0001 main entry (word 1 = byte 2) 0010 0000 static data requirement 0012 0018 (24 bytes) 0014 FFFF stack requirement 0016 FFF0 (16 bytes) 0018 0000 diag section size 001A 0000 (0) 001C 0000 [unused] 001E 0000 [unused] @Hinge @b[IMPORTS] 0020 D000 System procedure "RINT" 0022 0000 0024 0000 0026 0000 0028 0000 relative address in static 002A 0000 data area of transfer sequence (0) 002C 0452 "R 002E 494E IN 0030 5400 T" + pad 0032 E000 external procedure "process" 0034 0000 0036 0000 0038 0000 003A 0000 relative address in static data 003C 000C area of transfer sequence (=12) 003E 0770 "p 0040 726F ro 0042 6365 ce 0044 7373 ss" 0046 0000 terminator @Hinge @b[CODE] 0048 4E75 004A 206D .... .... 008A 0000 @End(Group) @End(FileExample) @SubSection(Creating object modules in assembly language programming) @IndexSecondary(Primary="Program environment", Secondary="Object modules") An include file is available for use when preparing assembly language programs in a form which is compatible with modules written in IMP or Pascal. By including the statement INCL INC:MODULE.ASM in the assembly language source file, the following macros are made available to allow the assembled output to be in FE02 format suitable for "linking" with modules written in IMP or PASCAL: @Begin(FileExample, LeftMargin +2) @IndexSecondary(Primary="Program environment", Secondary="MODULE") MODULE text-string: The file should contain exactly one call of this text. TEXT-STRING is the module-name, which is ignored except that it appears as the title on every page of the listing. @IndexSecondary(Primary="Program environment", Secondary="EXPORT") EXPORT symbol, mode: For each procedure or data object defined in the module for use from other modules, a call on this should be made. SYMBOL is the name given to the external object, and is also the label which must appear in the code or data section. MODE is one of DATA, EXTERNAL, or SYSTEM. @IndexSecondary(Primary="Program environment", Secondary="IMPORT") IMPORT symbol, mode: For each procedure or data object referenced but not defined in this program, a call on this should be made. SYMBOL is the name of the external object, and the label which must appear in the data section. MODE is one of DATA, EXTERNAL, SYSTEM or DYNAMIC. @IndexSecondary(Primary="Program environment", Secondary="CODE") CODE: This macro should be called if the module contains any code. @IndexSecondary(Primary="Program environment", Secondary="CALL") CALL symbol: This is used to call an external or dynamic procedure. @IndexSecondary(Primary="Program environment", Secondary="SCALL") SCALL symbol: This is used to call a system (data-less external) procedure. @IndexSecondary(Primary="Program environment", Secondary="ADDRESS") ADDRESS symbol, ptr: This is used to address an external data object. @IndexSecondary(Primary="Program environment", Secondary="COPYDATA") COPYDATA: This may be used in the reset procedure to initialise the data are. @IndexSecondary(Primary="Program environment", Secondary="DATA") DATA: This macro should be called if the module contains any static data or any references to external objects. @IndexSecondary(Primary="Program environment", Secondary="VECTOR") symbol VECTOR mode: This macro should be called, in the data section, for every imported object. SYMBOL and MODE are the same as in the IMPORT statement. This generates either a single longword to receive the address of the external object (for DATA references) or the appropriate entry sequence for calling external procedures (6 bytes for SYSTEM procedures, 12 for EXTERNAL and DYNAMIC ones). @IndexSecondary(Primary="Program environment", Secondary="ENDMODULE") ENDMODULE: This should be called last thing, immediately before the END statement. Its effect is to delimit the end of the last section, and to insert dummy export, import, and code sections if they were absent. @End(FileExample) @IndexSecondary(Primary="Program environment", Secondary="Sequencing") @Paragraph(Sequencing of directives) The calls on the macros listed above must be made in the following order, following the order of sections in the object module: @Begin(Enumerate) (optional, once) STACK SET value. This defines the value plugged into the module header which informs the loader of the estimated maximum stack requirement of the procedures in this module. (>0 : known maximum, <0: -guestimate, =0: unknown) (obligatory, once) MODULE name. This generates the header. (optional, repeated) EXPORT name, mode. On the first call, this identifies the start of the export section. It generates a loader record for the symbol. (optional, repeated) IMPORT name, mode. On the first call, this identifies the end of the export section and the start of the import section. It generates a loader record similar to that for the EXPORT directive. (optional, once) CODE. This identifies the end of the import section, and the start of the code section. If the code section is present, it must contain the labels RESET and BEGIN. The RESET procedure will be called by the loader whenever the module but loaded, this procedure should be used to initialise the data section, byt note that external objects may not yet be accessed. The BEGIN procedure is called by the loader (after the RESET one) if the module is being invoked as a main program. (optional, once) DATA. This identifies the end of the code section proper and the beginning of the data initialisation section. It must be present if the module uses any static data or references any external objects. (optional, repeated) name VECTOR mode. This reserves space in the data section for addresses of external data objects or call sequences for external procedures. These may be placed only in the data section, but can appear anywhere within it. i.e. need not appear all together at the front. (obligatory, once) ENDMODULE. This identifies the end of the data section and deals with any sections which may have been absent. @End(Enumerate) @Paragraph(Accessing the static data area) @IndexSecondary(Primary="Program environment", Secondary="Static data") @IndexSecondary(Primary="Program environment", Secondary="DATABEG") @IndexSecondary(Primary="Program environment", Secondary="RESET") It is expected that the RESET procedure will copy the contents of the (read-only) data initialisation area within the code section. (accessed by PC-relative addressing) into the writeable static data area (accessed by A4). The data initialisation area starts at label DATABEG (defined by the DATA macro) and is of size DATASIZE bytes (defined by the ENDMODULE macro). It is expected that code referring to anything in the data area should do so via A4. A reference to the label X should read X-DATABEG(A4). In the code section, the following macros may be used in order to access external objects more conveniently: @Begin(Description, LeftMargin 20, Indent -20) @IndexSecondary(Primary="Program environment", Secondary="ADDRESS") ADDRESS symbol, x @\This puts the address of external data object SYMBOL into X, which will usually be an address register. @IndexSecondary(Primary="Program environment", Secondary="CALL") CALL symbol @\This calls an external (or dynamic) procedure. @IndexSecondary(Primary="Program environment", Secondary="SCALL") SCALL symbol @\This calls a "system" (data-less external) procedure. @IndexSecondary(Primary="Program environment", Secondary="COPYDATA") COPYDATA @\This may be called by the reset routine, it copies DATASIZE bytes from (DATABEG) to (A4). @End(Description) The distinction between EXTERNAL and SYSTEM procedures is that the latter are called by shorter and faster entry sequences. SYSTEM procedures are expected not to have any static data of their own. The standard call sequence for EXTERNAL procedures is @Begin(FileExample, LeftMargin +2) MOVE.L A4,-(SP) JSR label-DATABEG(A4)--+ +-->MOVE.L #,A4 JMP.L --+ +-->RTS--+ MOVE.L (SP) +,A4 <------------------------------------------ @End(FileExample) The call sequence for SYSTEM procedures misses out the code affecting A4, on the understanding that the called module will neither affect nor use A4: @Begin(FileExample, LeftMargin +2) JSR label-DATABEG(A4) --+ +--> JMP.L --+ +--> RTS --+ (straight back) <----------------------------------------------- @End(FileExample) Although SYSTEM procedures may not use any module-own data, they can access the process-global data area addressed via A5 which is common to all modules, but local to the process in which they are executing.