Skip to content

Concept of a new PL for embedded applications

Concept of execution

(Please do not consider this as something final or settled, but rather as an exercise).

Compilation

Builder reads the main application file, which defines target device and uses other application or library files, which, in their turn, may use other files. Builder makes the file dependency tree and start compilation from the top of the tree (from the less depended files – it is expected that architecture or device definition files will be on the top of the tree). Builder compiles files going down on the tree. The last file compiled is the main application file. Compilation stage prepares internal presentation of the sources and list (net) of objects to construct on the next stage.

Construction

For each application at least two objects are created – application object and device object. Complex applications or libraries may define custom objects. These objects may refer to each other making circular references, however, the construction path should not have circularities and can be represented as a tree.
At construction point some dynamic changes can be applied to the objects (fine-tuning, parameterization, etc). For example, a generic architecture library may be self-optimized for a given device.
Construction results to a set of internal objects, though accessible to the developer via whatever facilities they publish. Construction may alter the objects network.
At this point developer can provide custom implementation (code generation) for a particular feature, for which code generation is found not satisfactory.

Enumeration and Elimination

At this point builder starts from the application object and enumerates the network nodes on the usage path. Objects encountered on this path are marked as usable. Unusable objects are destroyed. Also, as a result of this stage, builder creates a graph with node weighted according to object usage (most usable are most ‘heavy’).

Assignation

Objects with explicitly defined resource locations (e.g. SFRs) are assigned to their locations. Any conflict that occurs could be resolved either statically (kind of overlay directive) or dynamically (really?). Unresolved conflicts cause an error.

Weight Ranking

Before code generation, builder sorts objects by their net weight. Developer may influence this process by adjusting weight of an object, possibly using other objects’ weights as references.

Code Generation

Builder ‘executes’ objects. An object, when executed, may write an arbitrary number of data to arbitrary number of binary relocatable sections. Expressions that cannot be resolved at the moment but do not affect execution path are written as ‘closures’ to be resolved later. An irresolvable expression affecting flow of execution causes a recoverable execution error and, as a result of this error, object execution is aborted and produced result is cancelled. Aborted object is then placed after the ‘lightest’ object that was encountered in the irresolvable expression. Developer may provide custom code for handling this kind of error and thus keeping the object in execution.

Resource Allocation

Builder allocates device resources for all generated sections. Developer may influence this process by providing hints on allocations (e.g. align to boundary, put before or after another object, keep set of objects together and similar). Additionally developer may provide a custom function that evaluates to true if allocation is good enough.
Allocated sections are placed into the executable image.
After completing this step, builder may go for another round(s) of code generation and resource allocation for those objects that have failed to complete execution at the first time.

Closure Resolution

Builder evaluates all closures to values and finalizes the executable image by writing values to the corresponding locations.

Image Verification

Builder executes custom code for image verification.

Simulation

This step is performed only when requested and its scope may be refined from a single unit test to a complete integration test. Simulation code may be provided by device definition (for example, it may watch for improper TRIS state on read write to a port), by a library (self control) and by the application (unit test, integration test, etc).
Builder starts simulation and executes the image on the simulator, invoking simulation code when corresponding location is executed or accessed.

Documentation

This step is performed only when requested and its scope is also refinable. It may be used to print general information on a device, a library, the application, usage instructions, cautions from the datasheet, etc. These prints could be conditional, for example, device implementation may detect that application is using read-modify-write instruction on a TRIS and print a caution. Application developer still will be able to suppress all printouts either individually or in a bulk.

Hints

This is a kind of documentation, but intended to be used in an IDE for showing short notices when the user hovers the mouse over an object.

One Comment