I DESCRIPTIVE LANGUAGE FOR EMBEDDED ENVIRONMENTS

This appendix contains the following sections:

Introduction

Getting Started
Introduction
Basic Structure

CPU Part
Introduction
Address Translation: map and mem
Address Spaces
Addressing Modes
Busses
Chips
External Memory

Software Part
Introduction
Load Module
Layout Description
Space Definition
Block Definition
Selecting Sections
Cluster Definition
Amode Definition
Manipulating Sections in Amodes
Section Placing Algorithm

Memory Part
Introduction

Delfee Preprocessing
Introduction
User Defined Macros
File Inclusion
Conditional Statements

Delfee Keyword Reference
Abbreviation of Delfee Keywords
Delfee Keywords Summary

1 Introduction

In an embedded environment an accurate description of available memory and control over the behavior of the locator is crucial for a successful application. For example, it may be necessary to port applications to processors with different memory configurations, or it may be necessary to tune the location of sections to take full advantage of fast memory chips.

For this purpose the DELFEE language, which stands for DEscriptive Language For Embedded Environments, was designed.

2 Getting Started

2.1 Introduction

This section gives a general introduction about the DELFEE description language. The goal is to give you an overview and some basic knowledge what the DELFEE description language is about, and how a basic description file looks. A more detailed description and examples are given in the following sections.

2.2 Basic Structure

The DELFEE language describes where code or data sections should be placed on the actual memory chips. This language has to define the interface between a virtual world (the software) and a physical world (the hardware configuration).

On the one side, in the virtual world, there are the code and data sections which are described by the assembly language. Sections can have names, attributes like writable or read-only and can have an address in the addressing space or an addressing mode describing the range of the address space in which they may be located.

On the other side, the physical world, the actual processor is present which reads instructions from memory chips and interprets these instructions. With the DELFEE language you can instruct the locator to place the code and data sections at the correct addresses, taking into account things like the type of memory chip (rom/ram, fast/slow), availability of memory, etc. The DELFEE language gives the possibility to tune the same application for different hardware configurations.

In the DELFEE language the interface between virtual and physical world is described in three parts:

1. software part (*.dsc)

The software part belongs to the virtual world and describes the ordering of the data and code sections. The software part may vary for different applications and can even be empty.

2. cpu part (*.cpu)

The cpu part is the interface between the virtual world and the real world. It contains the application independent part of the virtual world (the address translation of addressing modes to the addressing space), and the configuration independent part of the physical world (on-chip memory, address busses). The cpu part is independent of application and configuration.

3. memory part (*.mem)

The memory belongs to the physical world. It contains the description of the external memory. The memory part may vary for different configurations and can even be empty (if there is no external memory).

The software part and the memory part can be empty, but that the cpu part must always be defined.

The DELFEE language is used in a special file, which is called the description file. In the DELFEE description language the different parts are defined with the following syntax:

For convenience the cpu part and the memory part can be placed in different files, which makes it possible to have different layout parts for different applications and different memory parts for different configurations. The files can be included using the syntax:

 cpu filename     // include cpu part defined in file filename
 mem filename     // include memory part defined in file filename

3 CPU Part

3.1 Introduction

The cpu part contains the application and configuration independent part of the description file. This part defines the translations of the addresses from the assembler language (virtual addresses) all the way down to the chips (physical addresses). To describe the translations, DELFEE recognizes four main levels:

1. addressing mode(s) definitions. Addressing modes are subsets of an address space. They define address ranges within an address space.

2. address space(s) definitions. The address space is the total range of addresses available.

3. bus(ses) definitions.

4. (on-chip) memory chips definitions.

The address translation is defined from addressing mode via space and bus to the chip. The addressing modes and the busses can be nested, the space and the chip cannot.

Figure I-1: Address translation

The addressing modes and addressing spaces belong to the virtual part, the busses and chips belong to the physical part. The following sections describe the address space and the addressing modes which are subsets of the address space. Then a description of the physical side (hardware configuration) follows, describing the busses and chips that are available.

The following example illustrates how a cpu part could look like. It is a fictitious example, mainly used to illustrate the definitions. You should be able to recognize the addressing mode definitions, address space definition, bus definitions and on-chip memory definition. Each definition is explained in the following sub-sections.

cpu {
   //
   // addressing mode definitions
   //
   amode near_code {
      attribute Y1;
      mau 8;
      map src=0 size=1k dst=0 amode = far_code;
   }
   amode far_code {
      attribute Y2;
      mau 8;
      map src=0 size=32k dst=0 space = address_space;
   }
   amode near_data {
      attribute Y3;
      mau 8;
      map src=0 size=1k dst=0 amode = far_data;
   }
   amode far_data {
      attribute Y4;
      mau 8;
      map src=0 size=32k dst=32k space = address_space;
   }
   //
   // space definitions
   //
   space address_space {
      mau 8;
      map src=0   size=32k dst=0   bus = address_bus label = rom;
      map src=32k size=32k dst=32k bus = address_bus label = ram;
   }
   // 
   // bus definitions
   //
   bus address_bus {
      mau 8;
      mem addr=0   chips=rom_chip;
      map src=0x100 size=0x7f00  dst=0x100 bus = external_rom_bus;
      mem addr=32k chips=ram_chip;
      map src=0x8100 size=0x7f00 dst=0x100 bus = external_ram_bus;
   }
   //
   // internal memory definitions
   //
   chips rom_chip  attr=r mau=8 size=0x100;  // internal rom
   chips ram_chip  attr=w mau=8 size=0x100;  // internal ram
}

3.2 Address Translation: map and mem

In DELFEE there are two ways to describe a memory translation between two levels (the source level and the destination level):

1. map keyword. This is for address translations between amodes, spaces, busses (not chips).

2. mem keyword. This describes the address translation between bus and chip. mem is a simplified case of map.

Figure I-2: Map address translation

The generalized syntax for the map definition is (see figure I-2):

where,

src start address of the source level. In case of an address translation between amodes and spaces, the source level is the amode and the destination level is the space.

size length of the source level.

dst start address at the destination level.

destination_type the destination type depends on the context the mapping is used in and can have three different types:

1. amode allowed in context: amode.

2. space allowed in context: amode.

3. bus allowed in context: space, bus.

optional_specifiers The optional identifiers are also dependent of the context they are used in:

1. label Only allowed in space context and needed as a reference for the block definition in the software part (see section 4.5).

label = name ;

2. align This indicates that every section will be aligned at the specified value.

align = number ;

3. page This indicates that every section should be within a given page size.

page = number ;

Both the source level and the destination level have an address range that is expressed in a number of Minimum Addressable Units (MAU, the minimal amount of storage, in bits, that is accessed using an address). The mapping only describes the range and the destination of the address mapping, the actual transformation also depends on the memory unit that an address can access. If a source level with a minimum addressable unit of 8 bits (mau=8) maps to a destination level with a minimum addressable unit of 16 bits (mau=16), the size of the destination level, expressed in address range, is half the original size. So, according to figure I-2, the size of the destination level is 100.

If a map is present from level1 down to level2, the map definition works as follows:

end_address of level2 = dst + ( size * mau of level1 / mau of level2 )

The mem description is actually a simplified case of the map description. The length of the address translation is taken from the chip size, the destination address is always zero. It is used to map a bus to a chip.

The syntax is:

where,

addr start address location of a chip.

chips the name of the chip that is located at address number.

3.3 Address Spaces

The link between the virtual and the physical world is the description of the address space and the way it maps onto the internal address busses.

The address space is defined by the complete range of addresses that the instruction set can access. Some instruction sets support multiple address spaces (for example a data space and a code space).

An address space is described by the syntax:

where,

space defines the name by which the space can be referenced in the description file.

mau the Minimum Addressable Unit, meaning the minimum amount of storage (in bits) that is accessed using an address.

map this specifies the mapping of a range of addresses in the address space to a bus defined by bus_name. The range of addresses is defined by src and length, the offset on the bus is defined by dst. (The bus you map the address space on, may have a different MAU, which will lead to another length of the range of the bus). An address space can only map onto a bus.

Usually an address in the address space corresponds to the same address on the bus. In that case src and dst have the same value.

In the previous example there is one space definition:

   space address_space {
      mau 8;
      map src=0   size=32k dst=0   bus = address_bus label = rom;
      map src=32k size=32k dst=32k bus = address_bus label = ram;
   }

In this example the space is named address_space. Note that the amod definitions use this name as destination for their mappings. The minimum addressable unit (MAU) is set to 8 bits. The labels rom and ram are used by block definitions in the software part which are discussed in section 4.5.

3.4 Addressing Modes

Addressing modes define address ranges in the addressing space. Addressing modes usually have a special characteristic, like bitaddressable part of memory, parts especially for code sections, zero pages, etc. The addressing modes are defined by the instruction set. The syntax of defining an addressing mode in the DELFEE language is:

An address space is described by the syntax:

where,

amode The name by which the addressing mode can be referenced. In the object file the addressing mode of a section is encoded with an Ynumber. This means that the name given to the addressing mode has only meaning within the description file, not to the sections!

mau the Minimum Addressable Unit, meaning the minimum amount of storage (in bits) that is accessed using an address.

attr Y the addressing mode number. Code or data sections (generated by the assembler) all have a number specifying the addressing mode they belong to. In the DELFEE description file this number is used to identify the addressing mode. This number must never be changed, because the interpretation of the sections will get mixed up.

map defines the mapping of the addressing mode to another addressing mode (amode) or an address space (space).

Below is an example of two addressing mode definitions:

Figure I-3: Addressing mode mapping

In this example the addressing modes are named near_data and far_data. They are identified by the addressing mode numbers Y3 and Y4 respectively. The minimum addressable unit (MAU) is set to 8 bits. Addressing mode near_data maps on addressing mode far_data, and far_data, in its turn, maps on address space address_space. address_space is the space as discussed in the previous section.

3.5 Busses

The bus keyword describes the bus configuration of a cpu. In essence it describes the address translation from the address space to the chip. The syntax is:

where,

bus the name by which the bus can be referenced.

mau the Minimum Addressable Unit, meaning the minimum amount of storage (in bits) that is accessed using an address.

map mapping to another bus.

mem mapping to a memory chip.

Below is an example of a bus definition:

Figure I-4: Bus mapping

In this example the address bus is named address_bus. The minimum addressable unit (MAU) is set to 8 bits. The internal memory chip rom_chip is located at address 0 of the bus, and the chip ram_chip is located at address 32k.

Two address mappings to other busses are present: one to external_rom_bus and one to external_ram_bus.

The first mapping translates addresses 0x100-0x7ff of address_bus (src=0x100 size=0x7f00) onto addresses of external_rom_bus starting at address 0x100 (dst=0x100).

The second mapping translates addresses 0x8100-0xffff of address_bus (src=0x8100 size=0x7f00) onto addresses of external_ram_bus starting at address 0x100 (dst=0x100).

The second mapping maps to RAM, not ROM. That is why both destination addresses are the same.

3.6 Chips

The chips keyword describes the memory chip. The syntax is:

where,

chips the name by which the chip can be referenced.

attr defines the attributes of the chip with a letter code

letter_code one of the following attributes:

r read-only memory.

w writable memory.

s special memory (it must not be located).

mau the Minimum Addressable Unit, meaning the minimum amount of storage (in bits) that is accessed using an address.

size the size of the chip (address range from 0-size).

Below is an example of two chip definitions:

In this example the chips are named rom_chip and ram_chip. The minimum addressable unit (MAU) is set to 8 bits. The size of both chips is 0x100 MAUs (= 256 bytes). Chip rom_chip is read-only and chip ram_chip writable, as you would expect with ROM and RAM.

3.7 External Memory

With the syntax described in the previous sections it would be possible to define mappings from an address space to external memory chips (DELFEE does not actually know, or care, if memory is on-chip). However, this is not advisory. For maintenance and flexibility reasons it is better to keep the internal (static) memory part apart from the external (variable) memory part. The chapter Memory Part describes how to deal with external memory.

In the cpu part you only have to define a mapping to an external bus, which can later be defined in the memory part. The following example contains references to two external busses: external_ram_bus and external_rom_bus.

4 Software Part

4.1 Introduction

The software part has two main parts:

1. load_mod

2. layout description

4.2 Load Module

The keyword load_mod defines the program start label. The program start label is the start of the code and the reset vector should point to this label. The locator generates a warning if this label is not referenced.

4.3 Layout Description

First of all, the layout definition can be omitted. If you omit the layout definition, the locator will generate a layout definition based on the DELFEE description of the amodes (addressing modes) in the cpu part (See section 3). However this does not allow you to control the order in which sections (like stack and heap) are located. If you define the layout part, the locator uses this description.

The layout part is probably the most difficult part of the DELFEE language. It is designed to give the locate algorithm the information it needs to locate the sections correctly. Through some examples you will be shown how to influence the locate algorithm using the DELFEE language.

To give you an idea of where all this will lead to, an example of a layout part is given:

layout {
      space address_space {
            block rom {
                  cluster first_code_clstr {
                        attribute i;
                        amode near_code;
                        amode far_code;
                  }
                  cluster code_clstr {
                        attribute r;
                        amode near_code {
                              section selection=x;
                              section selection=r;
                        }
                        amode far_code {
                              table;
                              section selection=x;
                              section selection=r;
                              copy;       // locate rom copies here
                        }
                  }
            }
            block ram {
                  cluster data_clstr {
                        attribute w;
                        amode near_data {
                              section selection=w;
                        }
                        amode far_data {
                              section selection=w;
                              heap;
                              stack;
                        }
                  }
            }
      }
}

The layout definition is defined with the syntax:

The first thing to notice is the different levels inside the layout definition:

space This level can only occur inside a layout level. There are as much space levels as there are space definitions in the cpu part.

block This level can only occur inside a space level. There are as much block levels as there are mappings defined in the space definition in the cpu part.

cluster This level can only occur inside a block level. There can be multiple clusters inside a block. Their main purpose is to group (code/data) sections. The locator locates each cluster in the specified order.

amode This level can only occur inside a cluster level. An amode corresponds to an amode definition in the cpu part. Within an amode you can specify the order in which data/code sections are located.

The four levels can roughly be divided in two groups. The space and block definition correspond to address ranges and the cluster and amode definition correspond to (groups of) sections.

The following paragraphs first introduce the space and block definition. Then separate paragraphs show how to select certain groups of sections and how this is used in the cluster and amode definition.

4.4 Space Definition

Section 3.3 already defined the address translation of a space in the cpu part. In the example in that section, the following space was defined:

For every space defined in the cpu part you have to provide a description in the layout definition.

The space level should be inside the layout definition and can only contain one or more block levels.

The name of the space must correspond to a space definition in the cpu part.

The syntax is:

Below is an example of a space definition from the software part:

In this example space address_space defines two blocks: block rom and block ram.

4.5 Block Definition

With the block description you can set boundaries to the sections based on chip sizes.

A block references a physical area of memory. Selected sections are only allowed within the range of the block description. In effect a block limits the range in which a section can be located.

The physical address range of a block is actually defined in the cpu part by a labeled mapping:

space address_space {
   mau 8;
   map src=0   size=32k dst=0   bus = address_bus label = rom; //<--
      // --> block name: rom
   map src=32k size=32k dst=32k bus = address_bus label = ram; //<--
      // --> block name: ram
}

The name of the block description must correspond to a label in the map definition of a space definition in the cpu part. The block definition must be inside the space definition and can only contain one or more cluster levels.

The syntax is:

Below is an example of a bus definition from the software part:

In this example block rom defines two clusters: cluster first_code_clstr and cluster code_clstr.

4.6 Selecting Sections

The previous paragraphs explained how the address ranges are defined by block definitions, now it is time to select the sections that should be placed in these blocks. In DELFEE there are two levels in which you can define the order of locating:

1. cluster

2. amode

To define the locating order you need to have some kind of handle to specify a section or a group of sections. DELFEE recognizes the following characteristics of a section:

name of the section This is unique to a specific section.

attribute(s) of a section
The attributes of a section are specified by the assembler or compiler. Possible attributes are defined in table I-1. By selecting an attribute you select a group of sections. The attributes can be grouped to an attribute string, for example: by1w.

addressing mode All sections have an addressing mode (as defined in the cpu part).

attr Meaning Description
W Writable Must be located in ram
R Read only Can be located in rom
X Execute only Can be located in rom
Z Zero page Must be located in the zero page
Ynum Addressing mode Must be located in addressing mode num
A Absolute Already located by the assembler
B Blank Section must be initialized to '0' (cleared)
F Not filled Section is not filled or cleared (scratch)
I Initialize Section must be initialized in rom
N Now Section is located before normal sections (without N or P)
P Postponed Section is located after normal sections (without N or P)

Table I-1: Section Attributes

To specify a (group) of sections, DELFEE has the following syntax:

1. select a group on section attribute:

2. select a section by name:

3. select a special section:

4. create a section:

Instead of selecting a section by an attribute, DELFEE also allows excluding a section by its attribute.

Excluding an attribute is done by placing a '-' (minus sign) in front of attr.

So, the example:

selects a group of sections with attribute attr1 and without attribute attr2.

4.7 Cluster Definition

Clusters are used to place specified sections in a group. The locator will handle the clusters in the order that they are specified. This gives you the possibility to create a group of selected sections and give it a higher locate priority.

There are several possibilities to specify that a section is part of a cluster. The exact rules and their priorities are given in the paragraph Section Placing Algorithm. The three main possibilities are:

1. attribute

2. section selection=

3. amode definition

Examine the following example:

layout {
      space address_space {
            block rom {
                  cluster first_code_clstr {
                        attribute i;
                        amode near_code;
                        amode far_code;
                  }
                  cluster code_clstr {
                        attribute r;
                        amode near_code {
                              section selection=x;
                              section selection=r;
                        }
                        amode far_code {
                              table;
                              section selection=x;
                              section selection=r;
                              copy;     // locate rom copies here
                        }
                  }
            }
      }
}

In this example an extra cluster first_code_cluster was created. Using the placing algorithm (paragraph 4.10) you can see that sections with attribute 'i' will be placed in cluster first_code_clstr and therefore will get a higher priority than sections in cluster code_clstr.

The syntax is:

Within a cluster the sections with the least freedom are located first. Freedom is defined by the possible addresses a section can be located at.

4.8 Amode Definition

Within a cluster you can specify an addressing mode or amode. Although in the cpu part (paragraph 3.4) an address range was assigned to every amode, in the layout part the addressing mode is used to identify groups of sections.

The syntax is:

The order of locating is now determined by the order of specification.

For example, suppose you want to locate all writable sections first, then the heap, followed by the stack. In the DELFEE language this is specified by:

4.9 Manipulating Sections in Amodes

The previous paragraphs explained how to set the order of the sections within an amode definition. DELFEE recognizes an extra set of keywords to further tune the locating of code and data sections.

An amode definition can contain the following keywords:

Keyword Description
section Selects a section, or group of sections
selection Specifies attributes for grouping sections
group Specify the address or page number of a group
attribute Assigns attributes (are past to the cluster)
copy Selects a rom copy of a section by name, or all rom copies in general
fixed Forces a section to be located around a fixed address
gap Creates a gap in the address range where sections will not be located
reserved Reserves a memory area, which can be referenced using locator labels
heap Defines the place and attributes of the heap
stack Defines the place and attributes of the stack
table Defines the place and attributes of the copy table
assert A user defined assertion
length Specifies the length of stack, heap, physical block or reserved space

Table I-2: amode keywords

All keywords are described in section 7, Delfee Keyword Reference.

4.10 Section Placing Algorithm

There are different ways to reference a section. Sections can be referenced as a group based on a certain attribute, or they can be referenced very specific by name. To find out where sections are placed in the layout part, DELFEE uses the following algorithm:

1. First, try to find a selection by section name.

2. If not found, search for a 'section selection=' within a matching amode block.

3. If not found, search for a 'section selection=' not within an amode block.

4. If not found, search for a cluster with a correct 'amode= ..,..,.. ;' and correct attributes.

5. If not found, search for a cluster with correct attributes.

6. If not found, relax attribute checking, and start over again.

Relax attributes using the following rules:

1. If stack, heap or reserved, switch indication off and try again.

2. If attribute 'f' (not filled), switch 'f' off and try again.

3. If attribute 'b' (clear), switch 'b' off and try again.

4. If attribute 'i' (initialize), switch 'i' off and try again.

5. If attribute 'x' (executable code), switch 'x' off and 'r' (read-only) on and try again. (Try to place executable sections in read-only memory).

6. If attribute 'r' (read-only), switch 'r' off 'w' (writable) on and try again. (Try to place read-only sections in writable memory).

5 Memory Part

5.1 Introduction

The memory part defines the variable part of the memory configuration. It can be placed in a different file, which allows to easily switch between different memory configurations. The syntax used for the mappings is the same as used in the cpu part.

As you have seen in the example of the cpu part in section 3, there were two references to external busses:

In the memory part you have to define the description for the busses external_rom_bus and external_ram_bus. Using the description in sections 3.5 and 3.6 for specifying busses and chips, the memory part could look like:

6 Delfee Preprocessing

6.1 Introduction

You can preprocess a DELFEE description file using exactly the same syntax as used by the C preprocessor. This means that all preprocessor directives start with a '#'-sign.

The preprocessor scans the input (description) file looking for macro calls. A macro-call is a request to the preprocessor to replace the call pattern of a built-in or user-defined macro with its definition.

There are two types of macro definitions: 'plain' macros and 'function-like' macros. A plain macro is expanded to a fixed string of characters. A function-like macro looks like a function call. The macro is expanded to its definition, in which the macro parameters are replaced by their co corresponding macro arguments.

6.2 User Defined Macros

You can create macros with the #define preprocessor directive.

Syntax:

When you create a parameterless macro, there are two parts to a #define call: the macro-name and the macro-body. The macro-name defines the name used when the macro is called; the macro-body defines the return value of the call.

The macro-body is usually the return value of the macro call. However, the macro-body may contain calls to other macros. If so, the return value is actually the fully expanded macro-body, including the return values of the call to other macros.

Example:

Every occurrence of ASIZE is expanded to '10'.

If the only function of the macro processor was to perform simple string replacement, then it would not be very useful for the most programming tasks. Each time you want to change even the simplest part of the macro's return value you would have to redefine the macro. Parameters in macro calls allow more general-purpose macros. Parameters leave holes in a macro-body that are filled in when you call the macro. This permits you to design a single macro that produces code for typical operations. The term 'parameters' refers to both the formal parameters that are specified when the macro is defined (the holes), and the actual parameters or argument that are specified when the macro is called (the fill-ins). To define macros with parameters you have to add a formal-parameter-list. The formal-parameter-list is a list of macro identifiers separated by ','. These identifiers comprise the formal parameters used in the macro. The macro identifier for each parameter in the list must be unique.

Example:

After

the call ADD(4, 5) is expanded to 4 + 5.

You can undefine a preprocessor macro with the #undef preprocessor directive:

6.3 File Inclusion

With the #include preprocessor directive:

you can include text from include-file within the input text of the description file. At the occurrence of an #include control line, the preprocessor reads the text from include-file until end-of-file is reached. #include files may be nested. include-file is any file that contains description file information. include-file is searched for in the directory etc directory relative to the installation path of your product.

The ANSI standard defines the following terms for the include directive:

The preprocessor uses the following search rules for include files between " ":

1. search in the directory of the description file

2. search in the directory etc relative to the installation path of your product

Note that if you nest include files, the preprocessor applies the first rule for each level.

Example:

According to rule 1 the preprocessor searches prod2.cpu in the same directory as product.cpu since prod2.cpu is included by product.cpu and not by product.dsc.

The preprocessor searches for include files between < > in the same way as for include files between " ". The difference is that rule 1 does not apply (the directory of the source description file is not searched).

The third form of include directives:

means that the included file name may be a token sequence that has been defined before. After expansion by the preprocessor this should produce a valid include directive as described by the first two forms:

Example:

6.4 Conditional Statements

Some preprocessor directives expect logical expressions in their arguments. Logical expressions follow the same rules as numeric expressions. The difference is in how preprocessor interprets the value that the expression represents. Once the expression has been evaluated to a value, the preprocessor uses the '= 0' comparison to determine whether the expression is TRUE or FALSE (if the value is equal 0 the expression is FALSE else TRUE).

The #if and #elif preprocessor directives evaluate a logical expression, and based on that expression, expand or withhold their statements. The #ifdef and #ifndef preprocessor directives evaluates the existence of a user-defined macro, and based on the result, expand or withhold their statements.

Syntax:

where if-line is one of:

The expression in the #if directive and subsequent #elif directives are evaluated in order until a TRUE value is encountered. If the value is TRUE, then the preprocessor expands the succeeding statements; if the value is FALSE and the optional #else directive is included in the call, then the statements succeeding #else are expanded. If the expression results to FALSE and the #else is not included, the #if call returns the null string.

The #ifdef tests if the macro-name is a previously defined macro. The #ifndef evaluates its statements if the macro-name is not currently defined.

Each #if, #ifdef and #ifndef directive must have a corresponding #endif.

Example:

This example always expands to: stack length=100;. In this case the #if control line could also be written as:

7 Delfee Keyword Reference

This section contains an alphabetical description of all keywords that can be used in a description file. Some keywords can be abbreviated to a minimum of four characters.

.addr

Syntax:

.addr (Software part)

Description:

The predefined label .addr contains the current address.

Example:

block ram {
 cluster data_clstr {
  attribute w;
  amode near_data {
   section selection=w;
   assert ( .addr < 256, "page overflow");
     // if the condition is false,
     // the locator generates an error with
     // the text as message
  }
  ...
 }
}

address

Syntax:

address = address (all parts)
addr = address (abbreviated form)

Description:

Specify an absolute address in memory.

Example:

Cpu or memory part:

Software part:

The locate order in the amode definition in the example above is fixed. Sections with attribute selection 'x' and/or 'r' are forced to be located before section .string. If this fixed order is not desired, the absolute address specification can be done in a separate amode definition.

Example:

amode

Syntax:

(Cpu or memory part)
amode
identifier[, identifier]... { amod_description } (def)
amode = identifier (ref)

amode
identifier[, identifier]... ; (Software part)
amode identifier[, identifier]... { section_blocks }

Description:

The keyword amode can appear in all parts. In the cpu or memory part you can use amode to map an addressing mode or register bank on a particular address space (definition). When you specify amode=, you map a specific addressing mode on a previously defined addressing mode (reference). The only keywords allowed in an amod_description (cpu part) are attribute, map and mau. The keyword attribute Ynum uniquely identifies the addressing mode.

In the software part you can use amode as part of a cluster definition to change the locating order of sections.

See also 4.10 , Section Placing Algorithm.

Example:

From cpu or memory part:

From software part:

assert

Syntax:

assert ( condition , text ) ; (Software part)
asse ( condition , text ) ; (abbreviated form)

Description:

Test condition of virtual address in memory. Generate an error if the assertion fails and give a message with 'text'. condition is specified as one of:

expr1 and expr2 can be any expression or label. The predefined label .addr contains the current address.

Example:

attribute

Syntax:

attribute attribute_string ; (Software part)
attr attribute_string ; (abbreviated form)
attribute = attribute_string (Software part)
attr = attribute_string (abbreviated form)

Description:

With attribute you can assign attributes to sections, clusters or memory blocks.

See also the keyword selection.

For sections these attributes are pure supplementary to the standard section attributes. The standard section attributes such as zero page (Y1), blank (B) and executable (X) are set by the compiler (or by the assembler in the case of an assembler program).

With an action attribute after a section (attr= ), you can set section attributes or you can disable section attributes with the - (minus) sign.

The attributes have the following meaning:

num (Section only) Align the section at 2num MAUs.

Ynum (amode and sections only) Identify addressing mode. Indicate that sections with this attribute should be allocated in this cluster.

r (Memory and clusters) Indicate this is a read-only cluster or read-only memory.

w (Memory and clusters) Indicate this is a writable cluster or writable memory.

s (Memory only) Indicate this is special memory, it must not be located.

x (Clusters/sections only) Indicate that the cluster/section is executable.

g (Clusters/sections only) Indicate that the cluster/section is global (known in a multi-module environment).

b (Clusters/sections only) Indicate that clusters/sections should be cleared before locating.

i (Sections only) Indicate that clusters/sections should be copied from ROM to RAM.

f (Clusters/sections only) Indicate that clusters/sections should not be filled and not cleared. This is called a scratch cluster/section.

Default attributes if the attribute keyword is omitted:

sections: The attributes as generated from the assembler/compiler.

clusters: The attributes as indicated by the underlaying memory, thus r for rom and w for ram.

memory: If no attributes defined, the default is writable (w).

Example:

From software part:

From cpu part:

block

Syntax:

block identifier { block_description } (Software part)

Description:

With block you define the contents of a physical area of memory. You can make a block description for each chip you use. Each block has a symbolic name as previously defined by the keyword chips. It is allowed to combine two or more memory chips in one block as long as their total address range is linear, without gaps. The identifier indicates that a memory block starts at the specified chip, no matter how many chips are combined.

Example:

layout {
  space address_space {
     block ram
      // Memory block starting at chip ram_chip
       cluster ram {
          ...
       }
     }
  }
}

bus

Syntax:

(Cpu or memory part)
bus
identifier[, identifier]... { bus_description } (def)
bus = identifier (ref)

Description:

With bus you define the physical memory addresses for the chips that are located on the cpu (definition). When you specify bus=, you map a specific address range on a previously defined address bus (reference). The only keywords allowed in an bus description are mem, map and mau.

Example:

cpu {
   space address_space {
      // Specify space 'address_space' for the address_bus
      // address bus.
      mau 8;
      map src=0   size=32k dst=0   bus = address_bus label = rom; 
      map src=32k size=32k dst=32k bus = address_bus label = ram;
                                          // ref
   }

   bus address_bus {  // definition
      mau 8;
      mem addr=0   chips=rom_chip;
      map src=0x100 size=0x7f00  dst=0x100 bus = external_rom_bus;
      mem addr=32k chips=ram_chip;
      map src=0x8100 size=0x7f00 dst=0x100 bus = external_ram_bus;
   }
   ...
}

chips

Syntax:

(Cpu or memory part)
chips
identifier[, identifier]... chips_description (def)
chips = identifier[| identifier]... [, identifier[| identifier]...]...
(ref)

Description:

With chips you describe the chips on the cpu or on your target board (definition). For each chip its size and minimum addressable unit (mau) is specified. With the keyword attr you can define if the memory is read-only. The only three attributes allowed are r for read-only, w for writable, or s for special. If omitted, w is default.

You can use chips= after the keyword mem to specify where a chip is located (reference). You can create chip pairs by separating each chip with a vertical bar '|'.

Example:

cpu {
     bus address_bus {
          mau 8;
          mem addr=0 chips=rom_chip; // ref
          ...
     }
     chips rom_chip  attr=r mau=8 size=0x100;  // def
     chips ram_chip  attr=w mau=8 size=0x100;
     ...
}

cluster

Syntax:

(Software part)
cluster
cluster_name { cluster_description }
cluster cluster_name[, cluster_name]... ;

Description:

In the software layout part you can define the cluster name and cluster location order. The attributes as valid for clusters (see attribute) can be specified in the first syntax. If you do not specify any attribute, the default attribute r or w is automatically set.

In a cluster description you can not only determine the locate order of sections within the named cluster, but you can also specify stack and heap size, extra process memory, define labels for the process, etc.

Example:

space address_space {
      block rom {
            cluster first_code_clstr {
             // The default attribute 'r' of cluster
             // text is overruled to  'i'. All
             // sections with attribute 'i' are
             // located here by default.
                  attribute i;
                  amode near_code;
                  amode far_code;
                   // Sections with addressing mode
                   // near_code or far_cdoe are
                   // located here
            }

      block ram {
            cluster data_clstr {
             // default attribute 'w' because the
             // memory is RAM. All writable
             // sections are located here by default.
                  attribute w; // can be omitted
                  amode near_data {
                        section selection=w;
                  }
      }
}

copy

Syntax:

copy section_name [ attr = attribute ] ; (Software part)
copy selection = attribute [ attr = attribute ] ;
copy
;

Description:

The ROM copy of data sections with the attribute i will be copied from ROM to RAM at program startup. With copy you define the placement in memory of these ROM copies. You can specify a specific section by giving the section's name, or select sections with a specific attribute. If you do not specify an argument, the locator locates all ROM copies at the specified location. With attr= you can change the section attributes.

If you do not specify the keyword copy at all, the locator finds a suitable place for ROM copies.

See also the keywords attribute and selection.

Example:

space address_space {
  block rom {  
     ...
     cluster code_clstr {
          attribute r; //cluster attribute
          amode far_code {
            table;
            section selection=x;
            section selection=r;
            copy; // all ROM copies are located here
          }
     }
}

cpu

Syntax:

cpu { cpu_description } (Cpu part)
cpu filename

Description:

The keyword cpu appears together with software and memory at the highest level in a description file. The actual cpu description starts between the curly braces { }. Normally you do not need to change the cpu part because it is delivered with the product and describes the derivative completely.

The second syntax is the so-called include syntax. The locator opens the file filename and reads the actual cpu description from this file. You must start the included file with cpu again. The filename can contain a complete path including a drive letter (Windows). Parts of filename, or the complete filename can be put in a environment variable. The file is first searched for in the current directory, and secondly in the etc directory relative to the installation directory.

Example:

Contents of the description file:

See section 3 for a sample contents of a .cpu file.

dst

Syntax:

dst = address (Cpu or memory part)

Description:

Specify destination address as part of the keyword map in an amode, space or bus description. For address you can use any decimal, hexadecimal or octal number. You can also use the (standard) Delfee suffix k, for kilo (210) or M, for mega (220). The unit of measure depends on the MAU (minimum addressable unit) of the destination memory space.

Example:

fixed

Syntax:

fixed address = address ; (Software part)
fixed addr = address ; (abbreviated form)

Description:

Define a fixed point in the memory map. The locator allocates the section/cluster preceding the fixed definition and the section/cluster following it as close as possible to the fixed point.

Example:

Cluster far_data_clstr will be located with its upper bound at address 0x2000 and cluster near_data_clstr starts at this address. The same can be applied to sections.

gap

Syntax:

gap; (Software part)
gap length = value ;

Description

Reserve a gap with a dynamic size. The locator tries to make the memory space as big as possible. You can use this keyword in a block description to create a gap between clusters, or in a cluster description to create a gap between sections. You can also use the gap keyword in combination with the fixed keyword.

With the second form you can specify a gap of a fixed length. This form can only occur in a block description.

Example:

space address_space {
     block ram {
          cluster data_clstr {
               attr w;
               amode near_data;
          } // low side mapping

          gap;  // balloon
          cluster stck; // high side mapping
     }
}

group

Syntax:

(Software part)
group
identifier [addr = base_address] [page = page_number];
/* either addr or page, not both!! */
group = identifier

Description:

A group is a collection of sections that should be located in the same page. By using the first syntax we can specify the position of the page. The position can be specified by defining the base address of the page (e.g. 0, 64k, 128k, ... for a page size of 64k) or the page number (0, 1, 2, ...).

The syntax can be used within a block, cluster or amode definition.

You can add a section to a group by using the second syntax. All sections in a specific group are located in the same page. Normally you add a section to a group by using the JOIN keyword in the assembler. But for special sections like the stack or heap you should define it in the .dsc file.

Example:

space address_space {
      block ram {
            cluster data_clstr {
                  group groupname1  addr = 64k;
                  / * place all sections in the group groupname1
                     between 64k and 128 k */
                  group groupname2  page = 1;
                  /* page all sections in the group groupname2
                     between 64k and 128 k */
                  amode near_data {
                        ..
                        ..
                  }
            }
      }
}
space address_space {
      block ram {
            cluster data_clstr {
                  amode data {
                        stack group = groupname1;
                        /* specify that the stack should be 
                           located in group groupname1;
                  }
            }
      }
}

See also the locator label _lc_gb_groupname.

heap

Syntax:

heap heap_description ; (Software part)
heap ;

Description:

Like table and stack, heap is another special section. The section is not created from the .out file, but generated at locate time. To control the size of this special section the keyword length is allowed within the heap description. You can use heap to include dynamic memory for a process.

Heap can only be used if a malloc() function has been implemented.

Two locator labels are used to mark begin and end of the heap, __lc_bh for the begin of heap, and __lc_eh for the end of heap.

Note that if the heap keyword is specified in the description file this does not automatically mean that a heap will always be generated. A heap will only be allocated when its section labels (__lc_bh for begin of heap and __lc_eh for end of heap) are used in the program.

The heap description can be a length specification and/or an attribute specification. See the example.

Example:

layout {
     space address_space {
          block ram {
               cluster data_clstr {
                amode far_data {
                    section selection=w;
                    heap length=100; 
                    // Heap of 100 MAUs
                }
               }
          }
     }
}

label

Syntax:

label identifier ; (Software part)
label = identifier ; (All parts)

Description:

The first form can be used stand-alone to specify a virtual address in memory by means of a label. The virtual address is label __lc_u_identifier. Note that at C level, all locator labels start with one underscore (the compiler adds another underscore '_').

The second form can only be used as part of another keyword. As part of the keyword reserved you can assign a label to an address range. The start of the address range is identified by label __lc_ub_ identifier. The end of the address range is identified by label __lc_ue_identifier. The keyword label is also allowed as part of the map keyword to assign a name to a block of memory in a space definition.

Example:

From the software part:

From the cpu part:

space address_space {
       mau 8;
       map src=0   size=32k dst=0   bus = address_bus label=rom;
      map src=32k size=32k dst=32k bus = address_bus label=ram;
}

layout

Syntax:

layout { layout_description } (Software part)
layout filename

Description:

The layout part describes the layout of sections in memory. The layout part groups sections into clusters and you can define the name, number and the order of clusters. The layout part describes how these clusters must be allocated into physical RAM and ROM block. The space and block names used in the layout part must be present in the memory part or the cpu part. The cluster definitions can contain fixed addresses as well as definitions of gaps between sections.

Example:

software {
  layout {
    space address_space {
     block rom { 
       cluster first_code_clstr {
         attribute i;
         amode near_code;
       }
     ....

length

Syntax:

length = length (Cpu, memory and software part)
leng = length (abbreviated form)

Description:

You can use the keyword length to define the length in MAUs (minimum addressable units) of a certain memory area. length must be a numeric value and can be given either in hex, octal or decimal. As usual, hex numbers must start with '0x' and octal numbers must start with '0'. You can use the suffix k which stands for kilo or M which stands for mega.

You can use length to specify the length of the reserved memory or to specify the stack, heap or gap length. For details see the keywords reserved, stack, heap and gap.

Example:

space address_space {
  block ram {
     cluster data_clstr {
        amode far_data {
          stack leng = 2k;
        }
     }
  }
}

load_mod

Syntax:

load_mod identifier start = label; (Software part)
load_mod start = label;

Description:

With load_mod you are introducing a load module description. This keyword is followed by an optional identifier, representing a load module name with or without the .out extension. The load module itself must be supplied to the locator as a parameter in the invocation. If the identifier is omitted, the load module is taken from the command line.

Example:

or:

map

Syntax:

map map_description (Cpu or memory part)

Description:

Map a memory part, specified as a source address and a size, to a destination address of an amode, space or bus. The unit of measure depends on the MAU of the memory space.

Example:

cpu {
  .
  amode far_data {
        attribute Y4;
        mau 8;
        map src=0 size=32k dst=32k space=address_space;
  }
  space address_space {
        mau 8;
        map src=0   size=32k dst=0   bus = address_bus label=rom;
        map src=32k size=32k dst=32k bus = address_bus label=ram;
  }
  bus address_bus {
        mau 8;
        mem addr=0   chips=rom_chip;
        map src=0x100 size=0x7f00  dst=0x100 bus=external_rom_bus;
        mem addr=32k chips=ram_chip;
        map src=0x8100 size=0x7f00 dst=0x100 bus=external_ram_bus;
  }
  .
}

mau

Syntax:

mau number ; (Cpu or memory part)
mau = number

Description:

You can use the keyword mau to specify the minimum addressable unit in bits of a certain memory area. The first form can only be used in an amode, space or bus description. The second form can be used to specify the minimum addressable unit of a chip. Note that mau affects the unit of measure for other keywords. If no mau is specified, the default number is 8 (byte addressable).

Example:

cpu {
  amode near_code {
     attribute Y1;
     mau 8;  // byte addressable
     map src=0 size=1k dst=0 amode=far_code;
     // src is at address 0,
     // size is 1k byte units
     // dst is at address 0
  }
}

mem

Syntax:

mem mem_description ; (Cpu or memory part)

Description:

Define the start address of a chip in memory. The only keywords allowed in a mem description are address and chips.

Example:

cpu {
  ...
  bus internal_bus {
    mau 8;
    mem addr=0    chips=rom_chip;
     // chip 'rom_chip' is located at memory
     // address 0
     ...
    mem addr=32k  chips=ram_chip;
     // chip 'ram_chip' is located at memory
     // address 0x8000
     ...

  }
  chips rom_chip  attr=r mau=8 size=0x100;
  chips ram_chip  attr=w mau=8 size=0x100;

}

memory

Syntax:

memory { memory_description } (Memory part)
memory
filename

Description:

Together with software and cpu, memory introduces a main part of the description file. You can specify the actual memory part between the curly braces { }.

You can use the memory part to describe any additional memory or addresses of peripherals not integrated on the cpu.

The second syntax is the include syntax. In this case, the memory part is defined in a separate file. This included file must start again with memory. The filename can contain a complete path, including a drive letter (Windows). You can put parts of filename, or the complete filename in an environment variable. The file is first searched for in the current directory, and secondly in the etc directory relative to the installation directory.

Example:

software {
     ...
}

cpu target.cpu
memory target.mem     //mem part in separate file

See section 5 for a sample contents of a .mem file.

regsfr

Syntax:

regsfr filename (Cpu or memory part)

Description:

Specify a register file generated by the register manager for use by the CrossView debugger.

Example:

cpu {
     .
     .
     .
     regsfr regfile.dat
     /*
      * Use file regfile.dat generated by
      * register manager for CrossView
      */
}

reserved

Syntax:

reserved reserved_description ; (Software part)
reserved;

Description:

Reserve a fixed amount of memory space or reserve as much memory as possible in the memory space. If no length is specified the size of the memory allocation depends on the size of the memory space or the size is limited by a fixed point definition following the reserved allocation.

You can only use the keywords address, attribute, label and length in the reserved description. You can use the keyword reserved in an amode description.

Example:

space address_space {
     block rom {
          cluster code_clstr {
               amode near_code {
                 // system reserved
                 // (exception vector)
                 reserved length=0x2 addr=0x24;
               }
     }
}

section

Syntax:

(Software part)
section identifier [addr = address ] [attr = attribute ] ;
section selection = attribute [addr = address] [attr = attribute];

Description:

section can be used in the layout part to specify the location order within a cluster.

See also layout .

The identifier is the name of a section.

With addr= you can make a section absolute.

With attr= you can assign new attributes to a section or disable attributes.

See also the keywords address, attribute and selection.

Example:

space address_space {
     block ram {
          cluster data_clstr {
               amode near_data {
                 // locate section .data here and set
                 // attribute 'w'
                 section .data attr=w; 
                 section selection=b attr=-b;
               }
          }
     }
}

selection

Syntax:

selection = attribute

Description:

You can use selection after the keywords section or copy to select all sections with (a) specified attribute(s).

If more attributes are specified, only sections with all attributes are selected. If a minus sign '-' precedes the attribute, only sections not having the attribute are selected.

See also the keywords attribute, copy , and section.

Example:

space address_space {
     block ram {
       cluster data_clstr {
          amode near_data {
           // select sections with w on and not i.
           // (select all writable sections which
           // are not copied from ROM)
           section selection=-iw;
          }
       }
     }
     .
}
...

size

Syntax:

size = size (Cpu or memory part)

Description:

You can use the keyword size to define the size in minimum addressable units (MAU) of a certain memory area. size must be a numeric value and can be given either in hex, octal or decimal. As usual, hex numbers must start with '0x' and octal numbers must start with '0'. You can use the suffix k which stands for kilo or M which stands for mega.

You can use size to specify the size of a part of memory that must be mapped on another part of memory or to specify the the size of a chip. For details see the keywords map and chips.

Example:

cpu {
  amode near_code {
       attribute Y1;  //identify near_code with Y1
       map src=0 size=1k dst=0 amode=far_code;
  }
space address_space {
       mau 8;
       map src=0   size=32k dst=0   bus=address_bus label=rom;
       map src=32k size=32k dst=32k bus=address_bus label=ram;
}
  chips rom_chip attr=r mau=8 size=0x100;
  chips ram_chip attr=w mau=8 size=0x100;
       // size of chips
}

software

Syntax:

software { software_description } (Software part)
software
filename

Description:

The keyword software appears at the highest level in a description file. The actual software description starts between the curly braces { }.

The second syntax is the so called include syntax. The locator will open file filename and read the actual software description from this file. The first keyword in filename must be software again. The filename can contain a complete path including a drive letter (Windows). You can put parts of filename, or the complete filename in an environment variable. The file is first searched for in the current directory, and secondly in the etc directory relative to the installation directory.

Example:

Contents of the description file:

Environment variable MY_OWN_DESCRIPTION contains the name of a file with contents like:

space

Syntax:

space identifier { space_description } (Software part)
(Cpu or memory part)
space
identifier[, identifier]... { space_description }
space = identifier

Description:

The keyword space can be used in the cpu part, memory part and software part. In the cpu or memory part you can use space to describe a physical memory address space. The only keywords allowed in a space description in the cpu or memory part are mau and map.

In the software part you can use space to describe one or more memory blocks. Each space has a symbolic name as previously defined by the keyword space in the cpu or memory part.

Example:

From the cpu part:

From the software part:

src

Syntax:

src = address (Cpu or memory part)

Description:

Specify source address as part of the keyword map in an amode, space or bus description. For address you can use any decimal, hexadecimal or octal number. You can also use the (standard) Delfee suffix k, for kilo (210) or M, for mega (220). The address is specified in the addressing mode's local MAU (minimum addressable unit) size (default 8 bits).

Example:

cpu {
  ...
  amode near_code {
      attribute Y1;
      mau 8; // 8-bit addressable
      map src=0 size=1k dst=0 amode=far_code;
  }
}

stack

Syntax:

stack stack_description ; (Software part)
stack ;

Description:

stack is a special form of a section description. The stack is allocated at locate time. The locator only allocates a stack if one is needed. Two special locator labels are associated with the stack space located with keyword stack. The begin of the stack area can be obtained by the locator label __lc_bs, the end address is accessible by means of label __lc_es.

If the stack grows downwards the begin of stack must be the highest address. To accomplish this, you can keep the length positive and set the stack pointer to end_of_stack, so the formula:

is always true.

You can only use the keywords attribute and length in the stack description. If you specify stack without a description, the locator tries to make the stack as big as possible. If you do not specify the keyword stack at all, the locator also tries to make the stack as big as possible but at least 100 (MAUs).

Example:

space address_space {
     block ram {
          cluster data_clstr {
               amode far_data {
                    section selection=w;
                    stack leng=150; 
                    // stack of 150 MAUs
                    ...
               }
          }
     }
}

start

Syntax:

start = label ; (Software part)

Description:

Define a start label for a process.

You can use start only within a load module description.

Example:

software {
     load_mod start = system_start;
     
     layout {
     .
     .
     }
}

table

Syntax:

table attr = attribute ; (Software part)
table ;

Description:

Like stack and heap also table is a special kind of section. Normal sections are generated at compile time, and passed via the assembler and linker to the locator. The stack and heap sections are generated at locate time, with a user requested size.

table is different. The locator is able to generate a copy table. Normally, this table is put in read-only memory. If you want to steer the table location, you can use the table keyword. With table only attribute is allowed. The length is calculated at locate time. table can occur in a cluster description.

Example:

7.1 Abbreviation of Delfee Keywords

The following Delfee keywords can be abbreviated to unique 4 character words:

Keyword Abbreviation
address addr
assert asse
attribute attr
length leng

Table I-3: Abbreviation of Delfee keywords

7.2 Delfee Keywords Summary

Keyword Description
address Specify absolute memory address
amode Specify the addressing modes
assert Error if assertion failed
attribute Assign attributes to clusters, sections, stack or heap
block Define physical memory area
bus Specify address bus
chips Specify cpu chips
cluster Specify the order and placement of clusters
copy Define placement of ROM-copies of data sections
cpu Define cpu part
dst Destination address
fixed Define fixed point in memory map
gap Reserve dynamic memory gap
group Specify the address or page number of a group
heap Define heap
label Define virtual address label
layout Start of the layout description
length Length of stack, heap, physical block or reserved space
load_mod Define load module (process)
map Map a source address on a destination address
mau Define minimum addressable unit (in bits)
mem Define physical start address of a chip
memory Define memory part
regsfr Specify register file for use by CrossView
reserved Reserve memory
section Define how a section must be located
selection Specify attributes for grouping sections into clusters
size Size of address space or memory
software Define the software part
space Define an addressing space or specify memory blocks
src Source address
stack Define a stack section
start Give an alternative start label
table Define a table section

Table I-4: Overview of Delfee keywords


Copyright © 2000 TASKING, Inc.