mirror of
https://github.com/elua/elua.git
synced 2025-01-08 20:56:17 +08:00
bd1465ca50
Conflicts: SConstruct doc/en/arch_platform.html doc/en/comunity.html doc/en/overview.html doc/en/refman.html doc/en/refman_gen.html doc/en/status.html doc/en/tut_bootstick.html doc/images/lng_pt.png doc/images/minusnode.png doc/images/next.png doc/images/node.png doc/images/nodelast.png doc/images/plusnode.png doc/images/plusnodelast.png doc/images/previous.png doc/images/showall.png doc/images/sync.png doc/images/vertline.png doc/pt/arch.html doc/pt/arch_coding.html doc/pt/arch_con_term.html doc/pt/arch_newport.html doc/pt/arch_overview.html doc/pt/arch_platform.html doc/pt/arch_tcpip.html doc/pt/building.html doc/pt/comunity.html doc/pt/dl_binaries.html doc/pt/dl_old.html doc/pt/dl_sources.html doc/pt/downloads.html doc/pt/examples.html doc/pt/faq.html doc/pt/installing_i386.html doc/pt/installing_lm3s.html doc/pt/news.html doc/pt/overview.html doc/pt/refman_dep.html doc/pt/refman_gen.html doc/pt/status.html doc/pt/tc_386.html doc/pt/toolchains.html doc/pt/tut_openocd.html doc/pt/using.html romfs/LM3S.lua romfs/led.lua romfs/morse.lua romfs/pong.lua src/lua/linit.c src/modules/auxmods.h src/platform/lm3s/platform.c src/platform/lm3s/platform_conf.h src/platform/sim/platform_conf.h
209 lines
18 KiB
HTML
209 lines
18 KiB
HTML
$$HEADER$$
|
|
<a name="structure" /><h3>eLua architecture overview</h3>
|
|
<p>The overall logical structure of <b>eLua</b> is shown in the image below:</p>
|
|
<p style="text-align: center; valign:middle;"><img src="images/elua_arch.png" style="border: 0;" alt="eLua architecture"></img></p>
|
|
<p><b>eLua</b> uses the notion of <b>platform</b> to denote a group of <b>CPUs</b> that share the same core structure, although their specific silicon
|
|
implementation might differ in terms of intergrated peripherals, internal memory and other such attributes. An <b>eLua</b> port implements one or
|
|
more CPUs from a given platform. For example, the <b>lm3s port</b> of <b>eLua</b> runs on LM3S8962, LM3S6965 and LM3S6918 CPUs, all of them part of the
|
|
<b>lm3s</b> platform. Refer to <a href="status.html">the status page</a> for a full list of platforms and CPUs on which <b>eLua</b> runs.</p>
|
|
<p>As can be seen from this image, <b>eLua</b> tries to be as portable as possible between different platforms by using a few simple design
|
|
rules:</p>
|
|
<ul>
|
|
<li>all code that is platform-independent is <b>common code</b> and it should be written in ANSI C as much as possible, this makes it highly portable
|
|
among different architectures and compilers, just like Lua itself. </li>
|
|
<li>all the code that can't possibly be generic (mostly peripheral and CPU specific code) must still be made as portable as possible by using a common
|
|
interface that must be implemented by all platforms on which <b>eLua</b> runs. This interface is called <b>platform interface</b> and is discussed in
|
|
detail <a href="arch_platform.html">here</a> (but please see also <a href="arch_overview.html#platform">"The platform interface"</a>
|
|
paragraph in this document).</li>
|
|
<li>all platforms (and their peripherals) are not created equal and vary greatly in capabilities. As already mentioned, the platform interface tries
|
|
to group only common attributes of different platforms. If one needs to access the specific functionality on a given platform (like the loopback support
|
|
mentioned before) it can do so by using a <b>platform module</b>. These are of course platform specific, and their goal is to fill the gap between the
|
|
platform interface and the full set of features provided by a platform.</li>
|
|
</ul>
|
|
<a name="common" /><h3>Common (generic) code</h3>
|
|
<p>The following gives an incomplete set of items that can be classified as <b>common code</b>:</p>
|
|
<ul>
|
|
<li>the Lua code itself (obviously) plus the <a href="arch_ltr.html">LTR patch</a>.</li>
|
|
<li>all the <b>components</b> in <b>eLua</b> (like the ROM file system, the XMODEM receive code, the <b>eLua</b> shell, the TCP/IP stack and others).
|
|
</li>
|
|
<li>all the <b>generic modules</b>, which are Lua modules used to expose the functionality of the platform to Lua.</li>
|
|
<li>generic <b>peripheral support code</b>, like the ADC support code (<i>src/common/elua_adc.c</i>) that is <b>independent</b> of the actual ADC
|
|
hardware.</li>
|
|
<li>libc code (for example allocators and Newlib stubs).</li>
|
|
</ul>
|
|
<p>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:</p>
|
|
<ul>
|
|
<li>if you want to add a new file system to <b>eLua</b>, this should definitely be generic code. It's likely that this kind of code will have
|
|
dependencies related to the physical medium on which this file system resides. If you're lucky, you can solve these dependencies using only the functions
|
|
defined in the <a href="arch_platform.html">platform interface</a> (this would make sense if you're using a SD card controlled over SPI, since the
|
|
platform interface already has a SPI layer). If not, you should group the platform specific functions in a separate interface that will be implemented by
|
|
all platform that want to use your new file system. This gives the code maximum portability.</li>
|
|
<li>if you want to add a driver for a specific ADC chip that works over SPI, the same observations apply: write it as common code as much as you can,
|
|
and use the <a href="arch_platform.html">platform interface</a> for the specific SPI functions you need.</li>
|
|
</ul>
|
|
<p>When designing and implementing a new component, keep in mind other <b>eLua</b> design goal: <b>flexibility</b>. The user should be able to
|
|
select which components are part of its <b>eLua</b> binary image (as described <a href="building.html">here</a>), 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.</p>
|
|
<p>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 (<i>src/newlib/genstd.c</i>): 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 <a href="arch_con_term.html">this link</a> for more details). The impact on speed and resource consumption is minimum, but
|
|
it matters a lot in the portability department.</p>
|
|
<a name="platform" /><h3>Platform interface</h3>
|
|
<p>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 <b>common</b> attributes of different platforms (as much as possible).
|
|
For example, if a platform supported by <b>eLua</b> has an UART that can work in loopback mode, but the others don't, loopback support won't be included
|
|
in the platform interface.</p>
|
|
<p>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.</p>
|
|
<p>The platform interface definition is always in the <i>inc/platform.h</i> header file. For a full description of its functions, check
|
|
<a href="arch_platform.html">the platform interface documentation.</a></p>
|
|
<a name="platforms" /><h3>Platforms and ports</h3>
|
|
<p>All the platforms that run <b>eLua</b> (and that implement the platform interface) are implemened in this conceptual layer. A <b>port</b> is a full
|
|
<b>eLua</b> implementation on a given platform. The two terms can generally be used interchangeably.</p>
|
|
<p>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:</p>
|
|
<ul>
|
|
<li>a port isn't required to implement <b>all</b> the platform interface functions, just the ones it needs. As explained
|
|
<a href="building.html">here</a>, the user must have full control over what's getting built into this <b>eLua</b> image. If you don't need the SPI
|
|
module, for example, you don't need to implement its platform interface.</li>
|
|
<li>a part of the platform interface is implemented (at least partially) in a file that is common for all the platforms (<i>src/common.c</i>). It
|
|
eases the implmentation of some modules (such as the timer module) and also implements common features that are tied to the platform interface,
|
|
but have a common behaviour on all platforms (for example virtual timers, see <a href="arch_platform_timers.html#virtual_timers">here</a> for details). You probably won't need to modify
|
|
if you're writing platform specific code, but it's best to keep in mind what it does.</li>
|
|
</ul>
|
|
<p>A platform implementation might also contain one or more <b>platform dependent modules</b>. 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:</p>
|
|
<ul>
|
|
<li>if implementing new functionality on the UART module of the LM3S platform, the corresponding module should be called <b>lm3s.uart</b>.</li>
|
|
<li>if implementing a peripheral driver that for some reason should be specific to the platform on the LPC2888 platform, for example its dual audio
|
|
DAC, give it a meaningful name, for example <b>lpc288x.audiodac</b>.</li>
|
|
</ul>
|
|
<h2>Structure of a port</h2>
|
|
<p>All the code for platform <i>name</i> (including peripheral drivers) must reside in a directory called <i>src/platform/<name></i> (for example
|
|
<i>src/platform/lm3s</i> for the <i>lm3s</i> platform). Each such platform-specific subdirectory must contain at least these files:</p>
|
|
<ul>
|
|
<li><b>type.h</b>: this defines the "specific data types", which are integer types with a specific size (see <a href="arch_coding.html">coding style</a>
|
|
for details. An example from the <b>i386</b> platform:
|
|
<pre><code>typedef unsigned char u8;
|
|
typedef signed char s8;
|
|
typedef unsigned short u16;
|
|
typedef signed short s16;
|
|
typedef unsigned long u32;
|
|
typedef signed long s32;
|
|
typedef unsigned long long u64;
|
|
typedef signed long long s64;</code></pre>
|
|
</li>
|
|
<li><b>conf.py</b>: this is the platform specific build configuration file, used by the <a href="building.html">build system</a> for a number of purposes:
|
|
<ul>
|
|
<li>to get the list of platform-specific files that will be compiled in the <b>eLua</b> image. They are exported in the <i>specific_files</i> string,
|
|
separated by spaces, and must be prepended with the relative path to the platform subdirectory. An example from the <b>i386</b> platform:
|
|
<pre><code>specific_files = "boot.s common.c descriptor_tables.c gdt.s interrupt.s isr.c kb.c monitor.c timer.c platform.c"
|
|
# Prepend with path
|
|
specific_files = " ".join( [ "src/platform/%s/%s" % ( platform, f ) for f in specific_files.split() ] )</code></pre>
|
|
</li>
|
|
<li>to get the full command lines of the different toolchain utilities (linker, assembler, compiler) used to compile <b>eLua</b>. They must be declared
|
|
inside the <i>tools</i> variable, in a separate dictinoary which key is the same as the platform name, and with specific names for each tool in turn:
|
|
<b>cccom</b> for the compiler, <b>linkcom</b> for the linker and <b>ascom</b> for the assembler.
|
|
For example, this is how the <i>tools</i> variable is defined for the <b>i386</b> platform:
|
|
<pre><code># Toolset data
|
|
tools[ 'i386' ] = {}
|
|
tools[ 'i386' ][ 'cccom' ] = "%s %s %s -march=i386 -mfpmath=387 -m32 -ffunction-sections -fdata-sections -fno-builtin -fno-stack-protector %s -Wall -c $SOURCE -o $TARGET" % ( toolset[ 'compile' ], opt, local_include, cdefs )
|
|
tools[ 'i386' ][ 'linkcom' ] = "%s -nostartfiles -nostdlib -march=i386 -mfpmath=387 -m32 -T %s -Wl,--gc-sections -Wl,-e,start -Wl,--allow-multiple-definition -o $TARGET $SOURCES -lc -lgcc -lm %s" % ( toolset[ 'compile' ], ldscript, local_libs )
|
|
tools[ 'i386' ][ 'ascom' ] = "%s -felf $SOURCE" % toolset[ 'asm' ]</code></pre>
|
|
Note how the definition of <b>tools</b> uses the definition of <b>toolset</b>, a dictionary with the names of the tools in the current toolchain. This
|
|
is also part of the <b>eLua</b> build system and is documented <a href="toolchains.html">here</a>.</li>
|
|
<li>to get the name of a <b>programmning function</b> which receives the name of the <b>eLua</b> executable file (the result of the build step) and
|
|
produces a file suitable for programming on the corresponding hardware platform. The name of this function should also be set in the <i>tools</i>
|
|
dictionary, as shown below (example taken from the <b>str7</b> platform):
|
|
<pre><code># Programming function for STR7
|
|
def progfunc_str7( target, source, env ):
|
|
outname = output + ".elf"
|
|
os.system( "%s %s" % ( toolset[ 'size' ], outname ) )
|
|
print "Generating binary image..."
|
|
os.system( "%s -O binary %s %s.bin" % ( toolset[ 'bin' ], outname, output ) )
|
|
|
|
tools[ 'str7' ][ 'progfunc' ] = progfunc_str7</code></pre>
|
|
Note, once again, how this function uses the same <i>toolset</i> variable mentioned in the previous paragraph.
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><b>stacks.h</b>: by convention, the stack(s) size(s) used in the system are declared in this file. An example taken from the <b>at91sam7x</b> platform is given below:
|
|
<pre><code>#define STACK_SIZE_USR 2048
|
|
#define STACK_SIZE_IRQ 64
|
|
#define STACK_SIZE_TOTAL ( STACK_SIZE_USR + STACK_SIZE_IRQ )</code></pre></li>
|
|
<li><b>platform.c</b>: by convention, the <a href="arch_platform.html">platform interface</a> is implemented in this file. It also contains the platform-specific
|
|
initialization function (<i>platform_init</i>, see the description of the <a href="arch_overview.html#boot">eLua boot process</a> for details).</li>
|
|
<li><b>platform_conf.h</b>: this is the platform configuration file, used to give information about both the platform itself and the build configuration for the
|
|
platform. This is what you can set inside <b>platform_conf.h</b>:
|
|
<ul>
|
|
<li>the list of <b>components</b> that will be part of the build (see <a href="building.html">building eLua</a> for details).</li>
|
|
<li>the list of <b>modules</b> that will be part of the build (see <a href="building.html">building eLua</a> and <a href="arch_ltr.html#config">LTR configuration</a>
|
|
for details.</li>
|
|
<li>the <b>static configuration data</b> (see <a href="building.html">building eLua</a> for details).</li>
|
|
<li>the <b>number of peripherals</b> on your CPU. See an example below (taken from <b>lm3s</b>) that also shows how to differentiate between different CPUs that belong to the same
|
|
platform; the <b>FORxxxx</b> macros are defined in <b>conf.py</b>):
|
|
<pre><code>// Number of resources (0 if not available/not implemented)
|
|
#define NUM_PIO 7
|
|
#define NUM_SPI 1
|
|
#ifdef FORLM3S6965
|
|
#define NUM_UART 3
|
|
#else
|
|
#define NUM_UART 2
|
|
#endif
|
|
#define NUM_TIMER 4
|
|
#ifndef FORLM3S6918
|
|
#define NUM_PWM 6
|
|
#else
|
|
#define NUM_PWM 0
|
|
#endif
|
|
#define NUM_ADC 4</code></pre></li>
|
|
<li><b>specific peripheral configuration</b>: this includes (but it not limited to) enabling buffering on UART, enabling and setting up virtual timers, setting PIO configuration and so on.
|
|
All these parameters are described in detail in the <a href="arch_platform.html">platform interface section</a>.</li>
|
|
<li><b>memory configuration</b>: describes the regions of free RAM in the system, which will be later used by the standard system allocator (malloc/realloc/free). Two macros
|
|
(<b>MEM_START_ADDRESS</b> and <b>MEM_END_ADDRESS</b>) define two arrays with the beginning and the end of all the free RAM memory in the system. If your board has external RAM memory, you
|
|
should define it here. If not, you can only use the internal memory, and you'll generally need to use the linker-defined symbol <b>end</b> to find out where your free memory starts. Following
|
|
is an example from the <b>ATEVK1100</b> (AVR32) board that has both on-chip and external RAM:
|
|
<pre><code>// Allocator data: define your free memory zones here in two arrays
|
|
// (start address and end address)
|
|
#define MEM_START_ADDRESS { ( void* )end, ( void* )SDRAM }
|
|
#define MEM_END_ADDRESS { ( void* )( 0x10000 - STACK_SIZE_TOTAL - 1 ), ( void* )( SDRAM + SDRAM_SIZE - 1 ) }
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
If you want to take a look at a real life example of a <b>platform_conf.h</b> file, see for example <i>src/platform/lm3s/platform_conf.h</i>.
|
|
</li>
|
|
<li><b>networking configuration</b>: if you need TCP/IP on your board, you need to add networking support to <b>eLua</b> (see <a href="building.html">
|
|
building</a> for a list of configuration options related to TCP/IP). You also need to have another file, called <b>uip-conf.h</b> that configures uIP
|
|
(the TCP/IP stack in <b>eLua</b>) for your specific architecture. See <a href="arch_tcpip.html">TCP/IP in eLua</a> for details.</li>
|
|
</ul>
|
|
<p>Besides the required files, the most common scenario is to include other platform specific files in your port:</p>
|
|
<ul>
|
|
<li><b>a "startup sequence"</b>, generally written in assembler, that does very low level
|
|
intialization, sets the stack pointer, zeroes the BSS section, copies ROM to
|
|
RAM for the DATA section, and then jumps to main.</li>
|
|
<li>a <b>linker command file</b>.</li>
|
|
<li>the <b>CPU support package</b> generally comes from the CPU manufacturer, and includes code
|
|
for accessing peripherals, configuring the core, setting up interrupts and so on.</li>
|
|
</ul>
|
|
<a name="boot" /><h3>eLua boot process</h3>
|
|
<p>This is what happens when you power up your <b>eLua</b> board:</p>
|
|
<ol>
|
|
<li>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 <b>main</b>.</li>
|
|
<li>the first thing <b>main</b> does is call the platform specific initialization function (<b>platform_init</b>). <b>platform_init</b> must fully
|
|
initialize the platform and return a result to main, that can be either <b>PLATFORM_OK</b> if the initialization succeded or <b>PLATFORM_ERR</b>
|
|
otherwise. If <b>PLATFORM_ERR</b> is returned, <b>main</b> blocks immediately in an infinite loop.</li>
|
|
<li><b>main</b> then initializes the rest of the system: the ROM file system, XMODEM, and term.</li>
|
|
<li>if <b>/rom/autorun.lua</b> (which is a file called <b>autorun.lua</b> in the <a href="arch_romfs.html">ROM file system</a>) is found, it is
|
|
executed. If it returns after execution, or if it isn't found, the boot process continues with the next step.</li>
|
|
<li>if the <a href="using.html#shell">shell</a> was compiled in the image, it is started, otherwise a standard Lua interpreter is started.</li>
|
|
</ol>
|
|
$$FOOTER$$
|
|
|