CHAPTER 5: ANATOMY OF A PASCAL/MT+ PROGRAM

5.1 DATA TYPES

This section describes how the standard and extended Pascal data types are implemented in Pascal/MT+. A summary of the data types appears in the following table.

Data typeSizeRange
CHAR1 8-bit-byte0..255
BOOLEAN 1 8-bit-bytefalse..true
INTEGER 1 8-bit-byte0..255
INTEGER 2 8-bit-bytes-32768..32767
BYTE 1 8-bit-byte0..255
WORD 2 8-bit-bytes0..65535
BCD REAL 10 8-bit-bytes18 digits,4 decimal
FLOATING REAL 4 8-bit-bytes10E-17..10E+17
STRING 1..256 bytes----------------
SET 32 8-bit-bytes0..255

5.1.1 CHAR

The data type CHAR is implemented using one 8-bit byte for each character. The reserved word PACKED is assumed on arrays of CHAR. CHAR variables may have the range of CHR(0) .. CHR(255). When pushed on the stack a CHAR variable is 16 bits with the high order byte containing 00. This is to allow ORD, ODD, CHR and WRD to all work together.

5.1.2 BOOLEAN

The data type BOOLEAN is implemented using one 8-bit byte for each BOOLEAN variable. When pushed on the stack ,8 bits of 0 are pushed to provide compatibility with built in operators and routines. The reserved word PACKED is allowed but does not compress the data structure any more than one byte per element (this occurs with and without the packed instruction). ORD(TRUE) = 0001 and ORD(FALSE) = 0000. The BOOLEAN operators AND, OR and NOT operate only on ONE byte. The user is refered to the &, ! and ~ operators (see Section 7.8) for 16-bit boolean operators.

    ___________________
    |X|X|X|X|X|X|X|0/1|     (X means don't care)
    -------------------

5.1.3 INTEGER

The data type INTEGER is implemented using two 8-bit bytes for each INTEGER variable. The order of the bytes is CPU dependent. In the 8080, 8085, Z80, 8086 and 8088 the low byte is in lower numbered address and the high order 8 bits are in the higher numbered address. MAXINT = 32767 and INTEGERS can have the range -32768.. 32767. An integer subrange declared to be within the 0.. 255 occupies only one byte of memory instead of two bytes. Integer constants may be hexadecimal numbers by preceeding the hex number with a dollar sign (e.g. $0F3B).

5.1.4 REAL

The implementation of the data type REAL in Pascal/MT+ has been done in two different ways to serve the needs of two different market areas.

For business applications the REAL data type has been implemented in binary coded decimal (BCD) with 18 digits and 4 fixed decimal places. Automatic rounding is done after the fourth place during calculations and also at the specified place if formatted output is used. The format of a REAL BCD number is: bytes 1.9 are digits packed two to the byte, and byte 10 contains the sign: 0 for positive and $FF for negative. The B switch in the compiler (Section 2.2) must be used to tell the compiler to save 10 bytes for each real number rather than the default four bytes. The file BCDREALS.ERL must be linked when using the BCD format. This format does not support the transcendental routines or the square root function.

             _____________________________________________
             | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8  | 9 | 10   |
    low mem  |d|d|d|d|d|d|d|d|d|d|d|d|d|d|.d|d|d|d| sign | hi mem
             ---------------------------------------------

For scientific and engineering applications the REAL data type has been implemented using binary floating point. The floating point used in Pascal/MT+ is fully compatible with the AMD 9511 hardware floating point unit. Thirty-two (32) bits (4-bytes) of data are required to implement a floating point number. The first byte contains the mantissa sign, the exponent sign and the exponent. The remaining three bytes contain the mantissa. The precision of this format is approximately 6.5 digits. The reader is referred to the AMD 9511 hardware manual for further details regarding the binary format.

            _______________________________________________
            |                               |    |    |    |
    low mem |exp sign/mantissa sign/exponent| ms |    | ls | high mem
            |                               |    |    |    |
            ------------------------------------------------

            ms = most significant bits
            ls = least significant bits

The floating point format is the default used by the compiler when real numbers are used in a program.

Pascal/MT+ implements this floating point data type in both software and hardware. The standard floating point package system comes with software run-time (FPREALS.ERL). The file named AMDIO.SRC is used to modify port addresses for the 9511 to adapt this version of the run-time package to the user's system. See the appendix on 9511 interface for more details about configuring the software to use the 9511 chip.

5.1.5 BYTE

The BYTE data type occupies a single byte. It is compatible with both INTEGER and CHAR types. This can be very useful when manipulating control characters, handling character arithmetic, etc. Characters and integers may be assigned to a BYTE.

5.1.6 WORD

WORD is an unsigned native machine word. All arithmetic performed on expressions of type WORD is unsigned. In addition, all comparisons are also unsigned. The WORD data type is designed such that it is always the same size as the pointer data type.

5.1.7 STRING

5.1.7.1 Definition

The pre-declared type STRING is like a packed array of characters in which the byte 0 contains the dynamic length of the string and bytes 1 through n contain the characters. Strings may be up to 255 characters in length. The default length is 80 characters which may be altered when a variable of type string is declared (see example below).

The string "This is a Wottle" is sixteen characters in length. The following diagram shows how these characters are stored in a string declared to be 20 characters in length.

            ____________________________________________
    low mem |16|T|h|i|s| |i|s| |a| |W|o|t|t|l|e|?|?|?|?|  high mem
            --------------------------------------------

If the number of characters in the string is less than the declared length, those bytes on the end are not defined. Note that the length is stored in the first byte and the total number of bytes required for the string is 17.

EXAMPLE:

VAR
  LONG_STR:       STRING;        {This may contain up to 80 characters}
  SHORT_STR:      STRING[10];    {This may contain up to 10 characters}
  VERY_LONG_STR: STRING[255];    {This may contain up to 255 characters,
                                  the maximum allowed. }

5.1.7.2 Assignment

Assignment to a string variable may be made via the assignment statement, reading into a string variable using READ or READLN, or the pre-defined string functions and procedures.

EXAMPLE:

PROCEDURE ASSIGN;
VAR
  LONG_STR  : STRING;
  SHORT_STR : STRING[12];
BEGIN

  LONG_STR := 'This string may contain as many as eighty characters';
  WRITELN(LONG_STR);

  WRITE('type in a string 10 characters or less : ');
  READLN(SHORT STR);
  WRITELN(SHORT_STR);

  SHORT_STR := COPY(LONG_STR,1,11);
  WRITELN('COPY(LONG_STR..)=',SHORT_STR);
END;

Output:

This string may contain as many as eighty characters
type in a string 10 characters or less : {123456}  (USER INPUT)
123456
COPY(LONG_STR..)=This string m

Individual characters in a string variable are accessed as if the string is an array of characters. Thus, normal array subscripting via constants, variables, and expressions allows assignment and access to individual bytes within the string. Access to the string over its entire declared length is legal and does not cause a run-time error even if an access is made to a portion of the string which is beyond the current dynamic length. If the string is actually 20 characters long and the declared length is 30 then STRING[25] is accessible.

EXAMPLE

PROCEDURE ACCESS;
VAR
  I : INTEGER;
BEGIN
  I := 15;
  LONG_STR := '123456789abcdef';
  WRITELN(LONG_STR);
  WRITELN(LONG_STR[6], LONG_STR[ i-5 ]);
  LONG_STR[16] := '*';
  WRITELN(LONG_STR [16]);
  WRITELN(LONG_STR);  (* will still only write 15-characters *)
END;

Output:

123456789abcdef
6a
*
123456789abcdef

5.1.7.3 Comparisons

Comparisons are valid between two variables of type string (regardless of their length) or between a variable and a literal string. Literal strings are sequences of characters between single quote marks. Comparisons may also be made between a string and a character. The compiler 'forces' the character to become a string by using the CONCAT buffer, therefore comparison of the result of the CONCAT function and a character is not meaningful as this would result in an always equal comparison.

EXAMPLE

PROCEDURE COMPARE;

VAR
  S1,S2 : STRING[10];
  CH1   : CHAR;

BEGIN
  S1 := '012345678';
  S1 := '222345678';

  IF S1 < S1 THEN
        WRITELN(S1,' is less than ',s2);

  S1 := 'alpha beta';
  IF S1 = 'alpha beta    ' THEN
    WRITELN('trailing blanks dont matter')
  ELSE
    WRITELN('trailing blanks count');
  IF S1 = '     alpha beta' THEN
    WRITELN('blanks in front don''t matter')
  ELSE
    WRITELN('blanks in front do matter');
  IF S1 = 'alpha beta' THEN
    WRITELN(S1,' = ',S1);
  S1 := 'Z';
  CH1 := 'Z';
  IF S1 = CH1 THEN
    WRITELN('strings and chars may be compared');
END;

Output:

012345678 < 222345678
trailing blanks don't matter
blanks in front do matter
alpha beta = alpha beta
strings and chars may be compared

5.1.7.4 Reading and Writing Strings

Strings may be written to a text file using the WRITE or WRITELN procedure. WRITELN will put a carriage-return line-feed following the string. Reading a string is always done via the READLN statement because strings are terminated with a carriage-return line-feed. Using READ will not work because the end-of-line characters are incorrectly processed. Tabs are expanded when they are read into a variable of the string data type.

5.1.8 SET

The SET data type is always stored as a 32 byte item. Each element of the set is stored as one bit. The low order bit of each byte is the first bit in that byte of the set. Shown below is the set 'A'..'Z' (bits 65..122)

    Byte number 00 01 02 03 04 05 06 07 08 09 OA 0B 0C ... 1F
                -- -- -- -- -- -- -- -- -- -- -- -- --     --
    Contents    00 00 00 00 00 00 00 00 FE FF FF 07 00 ... 00

5.2 EXECUTION TIME .COM FILE STRUCTURE

5.2.1 MEMORY LAYOUT AND SYSTEM VARIABLES

The memory layout for a program which has been compiled, linked and loaded into memory for execution by CP/M is shown below. If the user did not specify the /D switch when using the linker then the code area contains both code and data.

Memory Layout:

+----+-----///-------+----///-------+----->   <----+<----+-----------+
|low | program code  | program data | heap   local | H/W | CP/M BDOS |
|mem | area including|     area     | area   var   | stk | and BIOS  |
|    | run-time lib. | with /D:     |        stack*|     |           |
+----+-----///-------+----///-------+----->   <----+<----+-----------+
^    ^                              ^              ^     ^           ^
0    100H                         SYSMEM-->    <--@SFP  bdos        mem

*       Only used in recursive environments.

The symbol /// indicates variable size area output from the linker. The heap grows toward high memory and the local variable stack grows toward low memory. The local variable stack is used only in programs which contain the $S+ switch (for recursion). The hardware stack contains the procedure return addresses and the temporary evaluation stack for expressions. The local variable stack contains parameters and local procedural variables. The external integer SYSMEM points to the "top" of the heap and is initialized to point to the first location following the data area. SYSMEM is updated by the NEW routine. The external integer @SFP points to the "top" of the local variable stack and is initialized to be the top of the hardware stack minus 128 bytes and is updated by the @LNK (allocate stack frame) and @ULK (deallocate stack frame) routine. The built-in function MEMAVAIL (in systems which do not use FULLHEAP) is calculated by (@SFP - SYSMEM).

5.2.2 HARDWARE STACK SIZE

The hardware stack is initialized to 128 bytes but the user may change this by manipulating the run-time variable @SFP as an external integer and subtracting the desired additional space (or adding if you want to make it smaller) required for the hardware stack from @SFP. See the example below:

    VAR @SFP:EXTERNAL INTEGER,
            .
            .

    (* in main program only!!! *)

    @SFP := @SFP - MORE_HW_STACK_SPACE_IN_BYTES;

If the code is being run on an interrupt driven system it is often necessary to increase the size of the hardware stack.

5.2.3 PROGRAM STRUCTURE

The Pascal/MT+ compiler generates program modules which have a very simple structure. At the beginning of the module is located a jump table containing a jump to each procedure or function in the module. Space is reserved at the beginning of the jump table for the jump instruction to the main program. This jump is unused if the module is a MODULE and not a PROGRAM. In addition, in a PROGRAM there are 16-bytes of header information (in non-overlayed programs these are NOPs) which are used for overlay information. At the beginning of the main program the compiler generates code to load the stack pointer based upon the contents of location 6 which is the CP/M standard. Users of ROM based object code must use the $Z switch to set the initial stack pointer for their ROM requirements. Also the compiler generates a call to the @INI routine which initializes the INPUT and OUTPUT text files and the stack frame pointer used when the $S+ toggle is activated. Again ROM based users will typically wish to re-write the @INI routine to suit their needs.