Chapter 3. Storage Mapping
Prev |  | Next

## Chapter 3. Storage Mapping

Storage mapping of Pascal arrays, records, and variant records is described in the first part of this chapter. Ranges are discussed in the second part. Alignment, size and value ranges for the various data types are described in the third part. The last section discusses rules for set sizing.

## Arrays, Records, and Variant Records

Pascal maps arrays and records into storage like C maps arrays and structures.

### Arrays

An array has the same boundary requirements as the data type specified for the array. The size of an array is the size of the data type, multiplied by the number of elements.

For example, for the following declaration,

    x : array [1..2, 1..3] of double;

the size of the resulting array is 48 bytes (2*3*8, where 8 is the size of the double-floating point type in bytes).

### Records

Each member of a record begins at an offset from the record base. The offset corresponds to the order in which a member is declared; the first member is at offset 0.

The size of a record in the object file is the size of its combined members plus padding added, where necessary, by the compiler.

The following rules apply to records:

- Records must align on the same boundary as that required by the member with the most restrictive boundary requirement. These are the boundary requirements, listed by increasing degree of restrictiveness:

  - byte

  - halfword

  - doubleword

- The compiler terminates the record on the same alignment boundary on which it begins. For example, if a record begins on an even-byte boundary, it also ends on an even-byte boundary.

#### Example: Record

This example shows a record in code:

    type S = record
         v : integer;
         n : array [1..10] of char;
    end;

Figure 3-1 shows how it is mapped in storage.

Figure 3-1. Record in Storage, End Padded

Note that the length of the record is 16 bytes, even though the byte count as defined by the v:integer and the n:array[1..10] of char components is only 14. Because `integer` has a stricter boundary requirement (word boundary) than `char` (byte boundary), the record must end on a word boundary (a byte offset divisible by four). The compiler therefore adds two bytes of padding to meet this requirement.

An array of data records illustrates the reason for this requirement. For example, if the above record were the element-type of an array, some of the v:integer components would not be aligned properly without the two-byte pad.

#### Example: Record with Different Alignment

This example shows a record with different alignment in code:

    type S = record
         n : packed array [1..10] of char;
         v : integer;
    end;

Figure 3-2 shows how it is mapped in storage.

Figure 3-2. Record in Storage, Middle Padding

In the example, the alignment requirements cause padding to appear in the middle of the record. Note that the size of the record remains 16 bytes, but two bytes of padding follow the n component to align v on a word boundary.

### Variant Records

A variant record must align on the same boundary as the member with the most restrictive boundary requirement.

These are the boundary requirements, listed by increasing degree of restrictiveness:

- byte

- halfword

- word

- doubleword

For example, a variant record containing `integer`, `char`, and `double` data types must align on a doubleword boundary, as required by the `double` data type.

## Ranges

Ranges in a packed record are packed from the most-significant bit to the least-significant bit in a word.

### Ranges in a Packed Record

This example shows a packed record in code:

    type virtual_address = packed record
        offset : 0..4095;               (* 12 bits *)
        page : 0..1023;                 (* 10 bits *)
        segment : 0..511;               (* 9 bits *)
        supervisor : 0..1;              (* 1 bit *)
    end;

Figure 3-3 shows how it is mapped in storage.

Figure 3-3. Ranges in a Packed Record

### Ranges in an Unpacked Record

Ranges in an unpacked record are packed from the most-significant bit to the least-significant bit, but each range is aligned to the appropriate boundary. This example shows an unpacked record in code:

    type virtual_address = record
        offset : 0..4095;        (* 12 bits *)
        page : 0..1023;          (* 10 bits *)
        segment : 0..511;        (* 9 bits *)
        supervisor : 0..1;       (* 1 bit *)
    end;

Figure 3-4 shows how it is mapped in storage.

Figure 3-4. Ranges in an Unpacked Record

### Non-Ranges Following Ranges in Unpacked Records

For unpacked records, the compiler aligns a non-range element that follows a range declaration to the next boundary appropriate for its type.

This example shows another unpacked record in code:

    var x : record
        a : 0..7;                 (* 3 bits packed *)
        b : char;                 (* 8 bits *)
        c : -32768..32767;        (* 16 bits *)
    end;

Figure 3-5 shows how it is mapped in storage.

Figure 3-5. Non-Range Elements in an Unpacked Record

### Non-Range Elements in a Packed Record

For a packed record, the computer bit-aligns `booleans`, `chars`, and `ranges`. All other types are word or double-word aligned as appropriate for the type. This example shows the same code as above in a packed record and its mapping in storage:

    var x : packed record
        a : 0..7;             (* 3 bits *)
        b : char;             (* 8 bits *)
        c : -32768..32767     (* 16 bits *)
    end;

Figure 3-6 shows how it is mapped in storage.

Figure 3-6. Non-Range Elements in a Packed Record

## Alignment, Size, and Value by Data Type

This section describes how the Pascal compiler implements size, alignment, and value ranges for the various data types.

Table 3-1 shows the value ranges for the Pascal scalar types.

Table 3-1. Value Ranges by Data Type

Scalar Type | Value Ranges
--- | ---
boolean | 0 or 1
char | 0..127
integer | -231..231-1
cardinal | 0..232-1
real | See Note
double | See Note

| Note: See Table 3-2 and Table 3-3 for more data.

Table 3-2 and Table 3-3 show the approximate valid ranges for `real` and `double`. Enumerated types with n elements are treated in the same manner as the integer subrange 0..n-1.

Table 3-2. Real and Double Maximum Values

Type | Maximum Value
--- | ---
real | 3.40282356*1038
double | 1.7976931348623158*10308

Table 3-3. Real and Double Minimum Values

| Minimum Value |
--- | --- | ---
Type | Denormalized | Normalized
real | 1.40129846 * 10-46 | 1.17 549429 * 10-38
double | 4.9406564584124654*10-324 | 2.2250738585072012*10-308

### Set Sizing for Unpacked Records

Table 3-4, following, lists size and alignment parameters for unpacked records. See Section 3.4, “Rules for Set Sizes,” for rules about specifying the upper and lower bounds of s

Table 3-4. Size and Alignment of Data Types in Unpacked Records or Arrays

| Unpacked Records or Arrays (variables or fields) |
--- | --- | ---
Type | Size | Alignment
boolean | 8 | byte
char | 8 | byte
integer | 32 | word
cardinal | 32 | word
pointer | 32 | word
file | 32 | word
real | 32 | word
double | 64 | doubleword
subrange of: |  |
0..255 or -128..127 | 8 | byte
0..65535 or -32768..32767 | 16 | halfword
0..232 - 1 |  |
-231..-231 - 1 | 32 | word
set of char | 128 | word
set of a..b | See note | word

| Note: For unpacked records, the compiler uses the following formula for determining the size of the set of a..b:

           size=[b2⌋ - ⌊a/32⌋ + 1 words

The notation [ x ] indicates the floor of x, which is the largest

integer not greater than x.

### Set Sizing for Packed Arrays by Type

The compiler uses the rules shown in Table 3-5 for aligning packed arrays.

Table 3-5. Size and Alignment of Pascal Packed Arrays

| Packed Arrays |
--- | --- | ---
Scalar Type | Size | Alignment
boolean | 8 | byte
char | 8 | byte
integer | 32 | word
cardinal | 32 | word
pointer | 32 | word
file | 32 | word
real | 32 | word
double | 64 | doubleword
subrange of: |  |
0..1 or -1..0 | 1 | bit
0..3 or -2..1 | 2 | 2-bit
0..15 or -8..7 | 4 | 4-bit
0..255 or -128..127 | 8 | byte
0..65535 or -32768..32767 | 16 | halfword
0..232 - 1 |  |
-231..-231 - 1 | 32 | word
set of char | 128 | word
set of a..b | See note |

| Note: For packed arrays, the compiler uses the minimum number of bits possible in creating the set of a..b.

The following formula is used:

    If
       (b - 32 ⌊a/32⌋ + 1 ) ≤ 32
    then
       size = b - 32 \ξεβ a/32⌋ + 1 bits
    else
       size = ⌊b/32⌋ - \ξεβ a/32⌋ + 1 words

Note that the set of a..b is aligned on an n-bit boundary where n is a power of 2. The value of n is computed as follows:

    n = 2⌈log2(size)⌉

For example, the set of 0..2 has a size of 3 bits as computed above and will align on a 4-bit boundary.

See Section 3.4 at the end of this chapter for rules about specifying the upper and lower bounds of sets.

### Packed Record Alignment

The compiler uses the rules shown in Table 3-6 for aligning packed records.

Table 3-6. Size and Alignment of Pascal Packed Records

| Packed Arrays |
--- | --- | ---
Scalar Type | Size | Alignment
boolean | 8 | byte
char | 8 | byte
integer | 32 | word
cardinal | 32 | word
pointer | 32 | word
file | 32 | word
real | 32 | word
double | 64 | doubleword
subrange of a..b | See note | bit/word

| Note: For packed records, the compiler uses the minimum number of bits possible in creating a subrange field.

For the subrange a..b, this formula is used:

    If  a >= 0  then  size = ⌈log2(b + 1) ⌉ bits

    If a > 0    then  size = max(⌈log2(b + 1)⌉,⌈log2(-a ) ⌉)+1  bits

The notation ⌈ x ⌉ indicates the ceiling of x, which is the smallest integer not less than x.

To avoid crossing a word boundary, the compiler moves data types aligned to bit boundaries in a packed record to the next word.

## Rules for Set Sizes

The maximum number of elements permitted in a set ranges between 481 and 512. This variance is due to the way Pascal implements sets. For efficient accessing of set elements, Pascal expects the lower-bound of a set to be a multiple of 32. If for the set specified:

    set of a..b

a is not a multiple of 32, Pascal adds elements to the set from a down to the next multiple of 32 less than a.

For example, the set:

    set of 5..31

would have internal padding elements 0..4 added. These padding elements are inaccessible to the program. This implementation sacrifices some space for a fast, consistent method of accessing set elements.

The padding required to pad the lower bound down to a multiple of 32 varies between 0 and 31 elements.

For the set of a..b to be a valid set in Pascal, the following conditions must be met:

    size = ( b - 32 ⌊a / 32⌋+ 1 ) < 512

Table 3-7 shows some example sets and whether each set is valid by the above equation.

Table 3-7. Set Specifications

Specification | Lower | Upper | Set Size | Valid Size
--- | --- | --- | --- | ---
set of 1..511 | 0 (padded down to value by Pascal) | 511 | 512 | Yes
set of 0..511 | 0 | 511 | 512 | Yes
set of 1..512 | 0* | 512 | 513 | No
set of 31..512 | 0* | 512 | 513 | No
set of 32..512 | 32 | 512 | 481 | Yes
set of 32..543 | 32 | 543 | 512 | Yes

Prev | Table of Contents | Next
Chapter 2. Compiling, Linking, and Running Pascal Programs |  | Chapter 4. Pascal/C Interface