1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00
elua/doc/pt/arch_overview.html
James Snyder bd1465ca50 Merge 0.6 branch to trunk.
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
2009-10-13 02:14:27 +00:00

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/&lt;name&gt;</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$$