eLua architecture overview

The overall logical structure of eLua is shown in the image below:

eLua architecture

eLua uses the notion of platform to denote a group of CPUs that share the same core structure, although their specific silicon implementation might differ in terms of integrated peripherals, internal memory and other such attributes. An eLua port implements one or more CPUs from a given platform. For example, the lm3s port of eLua runs on LM3S8962, LM3S6965 and LM3S6918 CPUs, all of them part of the lm3s platform. Refer to the status page for a full list of platforms and CPUs on which eLua runs.

As can be seen from this image, eLua tries to be as portable as possible between different platforms by using a few simple design rules:

Common (generic) code

The following gives an incomplete set of items that can be classified as common code:

This should give you a pretty good idea about what "common code" means in this context. Note that the generic code layer should be as "greedy" as possible; that is, it should absorb as much common code as possible. For example:

When designing and implementing a new component, keep in mind other eLua design goal: flexibility. The user should be able to select which components are part of its eLua binary image (as described here), and the implementation should take this into consideration. The same thing holds for the generic modules: the user must have a way to choose the set of modules he needs.

For maximum portability, make your code work in a variety of scenarios if possible (and if that makes sense from a practical point of view). Take for example the code for stdio/stdout/stderr handling (src/newlib/genstd.c): it acknowledges the fact that a terminal can be implemented over a large variety of physical transports (RS-232 for PC, SPI for a separate LCD/keyboard board, a radio link and so on) so it uses pointers for its send/receive functions (see this link for more details). The impact on speed and resource consumption is minimum, but it matters a lot in the portability department.

Platform interface

Used properly, the platform interface allows writing extremely portable code over a large variety of different platforms, both from C and from Lua. An important property of the platform interface is that it tries to group only common attributes of different platforms (as much as possible). For example, if a platform supported by eLua has an UART that can work in loopback mode, but the others don't, loopback support won't be included in the platform interface.

A special emphasis on the platform interface usage: remember to use it not only for Lua, but also for C. The platform interface is mainly used by the generic modules to allow Lua code to access platform peripherals, but this isn't its only use. It can (and it should) also be used by C code that wants to implement a generic module and neeeds access to peripherals. An example was given in the previous section: implementing a new file system.

The platform interface definition is always in the inc/platform.h header file. For a full description of its functions, check the platform interface documentation.

Platforms and ports

All the platforms that run eLua (and that implement the platform interface) are implemened in this conceptual layer. A port is a full eLua implementation on a given platform. The two terms can generally be used interchangeably.

A port can (and generally will) contain specific peripheral drivers, many times taken directly from the platform's CPU support package. These drivers are used to implement the platform interface. Note that:

A platform implementation might also contain one or more platform dependent modules. As already exaplained, their purpose is to allow Lua to use the full potential of the platform peripherals, not only the functionality covered by the platform interface, as well as functionality that is so specific to the platform that it's not even covered by the platform interface. By convention, all the platform dependent modules should be grouped inside a single module that has the same name as the platform itself. If the platform dependent module augments the functionality of a module already found in the platform interface, it should have the same name, otherwise it should be given a different, but meaningful name. For example:

Structure of a port

All the code for platform name (including peripheral drivers) must reside in a directory called src/platform/<name> (for example src/platform/lm3s for the lm3s platform). Each such platform-specific subdirectory must contain at least these files:

Besides the required files, the most common scenario is to include other platform specific files in your port:

eLua boot process

This is what happens when you power up your eLua board:

  1. the platform initialization code is executed. This is the code that does very low level platform setup (if needed), copies ROM to RAM, zeroes out the BSS section, sets up the stack pointer and jumps to main.
  2. the first thing main does is call the platform specific initialization function (platform_init). platform_init must fully initialize the platform and return a result to main, that can be either PLATFORM_OK if the initialization succeeded or PLATFORM_ERR otherwise. If PLATFORM_ERR is returned, main blocks immediately in an infinite loop.
  3. main then initializes the rest of the system: the ROM file system, XMODEM, and term.
  4. if /rom/autorun.lua (which is a file called autorun.lua in the ROM file system) is found, it is executed. If it returns after execution, or if it isn't found, the boot process continues with the next step.
  5. if boot is set to 'standard' and the shell was compiled in the image, it is started, in the absence of the shell, a standard Lua interpreter is started.
  6. if boot is set to 'luarpc' an rpc server is started.