Commit 88bd9e01 authored by TerryE's avatar TerryE
Browse files

LFS patch updates following review

parent 4ae52c23
......@@ -34,7 +34,8 @@ static int listing=0; /* list bytecodes? */
static int dumping=1; /* dump bytecodes? */
static int stripping=0; /* strip debug information? */
static int flash=0; /* output flash image */
static int lookup=0; /* output lookup-style master combination header */
static lu_int32 address=0; /* output flash image at absolute location */
static int lookup=0; /* output lookup-style master combination header */
static char Output[]={ OUTPUT }; /* default output file name */
static const char* output=Output; /* actual output file name */
static const char* execute; /* executed a Lua file */
......@@ -69,6 +70,7 @@ static void usage(const char* message)
" -o name output to file " LUA_QL("name") " (default is \"%s\")\n"
" -e name execute a lua source file\n"
" -f output a flash image file\n"
" -a addr generate an absolute, rather than position independent flash image file\n"
" -i generate lookup combination master (default with option -f)\n"
" -p parse only\n"
" -s strip debug information\n"
......@@ -79,6 +81,8 @@ static void usage(const char* message)
}
#define IS(s) (strcmp(argv[i],s)==0)
#define IROM0_SEG 0x40210000ul
#define IROM0_SEGMAX 0x00100000ul
static int doargs(int argc, char* argv[])
{
......@@ -105,8 +109,15 @@ static int doargs(int argc, char* argv[])
}
else if (IS("-f")) /* Flash image file */
{
flash=1;
lookup=1;
flash=lookup=1;
}
else if (IS("-a")) /* Absolue flash image file */
{
flash=lookup=1;
address=strtol(argv[++i],NULL,0);
size_t offset = (unsigned) (address -IROM0_SEG);
if (offset > IROM0_SEGMAX)
usage(LUA_QL("-e") " absolute address must be valid flash address");
}
else if (IS("-i")) /* lookup */
lookup = 1;
......@@ -159,7 +170,7 @@ static TString *corename(lua_State *L, const TString *filename)
* then luac generates a main function to reference all sub-main prototypes.
* This is one of two types:
* Type 0 The standard luac combination main
* Type 1 A lookup wrapper that facilitates indexing into the gernated protos
* Type 1 A lookup wrapper that facilitates indexing into the generated protos
*/
static const Proto* combine(lua_State* L, int n, int type)
{
......@@ -167,64 +178,76 @@ static const Proto* combine(lua_State* L, int n, int type)
return toproto(L,-1);
else
{
int i,pc,stacksize;
Instruction *code;
int i;
Instruction *pc;
Proto* f=luaF_newproto(L);
setptvalue2s(L,L->top,f); incr_top(L);
f->source=luaS_newliteral(L,"=(" PROGNAME ")");
f->p=luaM_newvector(L,n,Proto*);
f->sizep=n;
for (i=0; i<n; i++) f->p[i]=toproto(L,i-n-1);
for (i=0; i<n; i++)
f->p[i]=toproto(L,i-n-1);
pc=0;
if (type == 0)
{
if (type == 0) {
/*
* Type 0 is as per the standard luac, which is just a main routine which
* invokes all of the compiled functions sequentially. This is fine if
* they are self registering modules, but useless otherwise.
*/
stacksize = 1;
code=luaM_newvector(L,2*n+1,Instruction);
for (i=0; i<n; i++)
{
code[pc++]=CREATE_ABx(OP_CLOSURE,0,i);
code[pc++]=CREATE_ABC(OP_CALL,0,1,1);
f->numparams = 0;
f->maxstacksize = 1;
f->sizecode = 2*n + 1 ;
f->sizek = 0;
f->code = luaM_newvector(L, f->sizecode , Instruction);
f->k = luaM_newvector(L,f->sizek,TValue);
for (i=0, pc = f->code; i<n; i++) {
*pc++ = CREATE_ABx(OP_CLOSURE,0,i);
*pc++ = CREATE_ABC(OP_CALL,0,1,1);
}
code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
}
else
{
*pc++ = CREATE_ABC(OP_RETURN,0,1,0);
} else {
/*
* The Type 1 main() is a lookup which takes a single argument, the name to
* be resolved. If this matches root name of one of the compiled files then
* a closure to this file main is returned. If the name is "list": then the
* list of root names is returned, else a nil return.
* a closure to this file main is returned. Otherwise the Unixtime of the
* compile and the list of root names is returned.
*/
lua_assert(n<LFIELDS_PER_FLUSH);
stacksize = n+2;
code=luaM_newvector(L,5*n+3 ,Instruction);
f->k=luaM_newvector(L,n+1,TValue);
f->sizek=n+1;
setnvalue(f->k, (lua_Number) time(NULL));
for (i=0; i<n; i++)
if (n > LFIELDS_PER_FLUSH) {
#define NO_MOD_ERR_(n) ": Number of modules > " #n
#define NO_MOD_ERR(n) NO_MOD_ERR_(n)
usage(LUA_QL("-f") NO_MOD_ERR(LFIELDS_PER_FLUSH));
}
f->numparams = 1;
f->maxstacksize = n + 3;
f->sizecode = 5*n + 5 ;
f->sizek = n + 1;
f->sizelocvars = 0;
f->code = luaM_newvector(L, f->sizecode , Instruction);
f->k = luaM_newvector(L,f->sizek,TValue);
for (i=0, pc = f->code; i<n; i++)
{
/* if arg1 == FnameA then return function (...) -- funcA -- end end */
setsvalue2n(L,f->k+i+1,corename(L, f->p[i]->source));
code[pc++]=CREATE_ABC(OP_EQ,0,0,RKASK(i+1));
code[pc++]=CREATE_ABx(OP_JMP,0,MAXARG_sBx+2);
code[pc++]=CREATE_ABx(OP_CLOSURE,1,i);
code[pc++]=CREATE_ABC(OP_RETURN,1,2,0);
setsvalue2n(L,f->k+i,corename(L, f->p[i]->source));
*pc++ = CREATE_ABC(OP_EQ,0,0,RKASK(i));
*pc++ = CREATE_ABx(OP_JMP,0,MAXARG_sBx+2);
*pc++ = CREATE_ABx(OP_CLOSURE,1,i);
*pc++ = CREATE_ABC(OP_RETURN,1,2,0);
}
for (i=0; i<=n; i++) code[pc++]=CREATE_ABx(OP_LOADK,i+1,i);
/* should be a block loop */
code[pc++]=CREATE_ABC(OP_RETURN,1,2+n,0);
code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
setnvalue(f->k+n, (lua_Number) time(NULL));
*pc++ = CREATE_ABx(OP_LOADK,1,n);
*pc++ = CREATE_ABC(OP_NEWTABLE,2,luaO_int2fb(i),0);
for (i=0; i<n; i++)
*pc++ = CREATE_ABx(OP_LOADK,i+3,i);
*pc++ = CREATE_ABC(OP_SETLIST,2,i,1);
*pc++ = CREATE_ABC(OP_RETURN,1,3,0);
*pc++ = CREATE_ABC(OP_RETURN,0,1,0);
}
f->numparams=1;
f->maxstacksize=stacksize;
f->code=code;
f->sizecode=pc;
lua_assert((pc-f->code) == f->sizecode);
return f;
}
}
......@@ -240,7 +263,8 @@ struct Smain {
char** argv;
};
extern uint dumpToFlashImage (lua_State* L,const Proto *main, lua_Writer w, void* data, int strip);
extern uint dumpToFlashImage (lua_State* L,const Proto *main, lua_Writer w,
void* data, int strip, lu_int32 address);
static int pmain(lua_State* L)
{
......@@ -278,7 +302,7 @@ static int pmain(lua_State* L)
lua_lock(L);
if (flash)
{
result=dumpToFlashImage(L,f,writer, D, stripping);
result=dumpToFlashImage(L,f,writer, D, stripping, address);
} else
{
result=luaU_dump_crosscompile(L,f,writer,D,stripping,target);
......
......@@ -38,6 +38,11 @@
#define LUA_WIN
#endif
#if defined(LUA_CROSS_COMPILER)
#define LUA_USE_LINUX
#endif
#if defined(LUA_USE_LINUX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
......@@ -59,7 +64,7 @@
#if defined(LUA_USE_POSIX)
#define LUA_USE_MKSTEMP
#define LUA_USE_ISATTY
#define LUA_USE_POPEN
//#define LUA_USE_POPEN
#define LUA_USE_ULONGJMP
#endif
......
......@@ -575,27 +575,25 @@ static const LUA_REG_TYPE node_task_map[] = {
{ LSTRKEY( "HIGH_PRIORITY" ), LNUMVAL( TASK_PRIORITY_HIGH ) },
{ LNILKEY, LNILVAL }
};
#ifdef LUA_FLASH_STORE
static const LUA_REG_TYPE node_flash_map[] = {
{ LSTRKEY( "reload" ), LFUNCVAL( luaN_reload_reboot ) },
{ LSTRKEY( "index" ), LFUNCVAL( luaN_index ) },
{ LNILKEY, LNILVAL }
};
#endif
static const LUA_REG_TYPE node_map[] =
{
{ LSTRKEY( "heap" ), LFUNCVAL( node_heap ) },
{ LSTRKEY( "info" ), LFUNCVAL( node_info ) },
{ LSTRKEY( "task" ), LROVAL( node_task_map ) },
#ifdef LUA_FLASH_STORE
{ LSTRKEY( "flashreload" ), LFUNCVAL( luaN_reload_reboot ) },
{ LSTRKEY( "flashindex" ), LFUNCVAL( luaN_index ) },
#endif
{ LSTRKEY( "restart" ), LFUNCVAL( node_restart ) },
{ LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) },
#ifdef PMSLEEP_ENABLE
{ LSTRKEY( "sleep" ), LFUNCVAL( node_sleep ) },
PMSLEEP_INT_MAP,
#endif
{ LSTRKEY( "info" ), LFUNCVAL( node_info ) },
{ LSTRKEY( "chipid" ), LFUNCVAL( node_chipid ) },
{ LSTRKEY( "flashid" ), LFUNCVAL( node_flashid ) },
{ LSTRKEY( "flashsize" ), LFUNCVAL( node_flashsize) },
{ LSTRKEY( "heap" ), LFUNCVAL( node_heap ) },
{ LSTRKEY( "input" ), LFUNCVAL( node_input ) },
{ LSTRKEY( "output" ), LFUNCVAL( node_output ) },
// Moved to adc module, use adc.readvdd33()
......@@ -609,12 +607,8 @@ static const LUA_REG_TYPE node_map[] =
{ LSTRKEY( "random" ), LFUNCVAL( node_random) },
#ifdef LUA_OPTIMIZE_DEBUG
{ LSTRKEY( "stripdebug" ), LFUNCVAL( node_stripdebug ) },
#endif
#ifdef LUA_FLASH_STORE
{ LSTRKEY( "flash") , LROVAL( node_flash_map ) },
#endif
{ LSTRKEY( "egc" ), LROVAL( node_egc_map ) },
{ LSTRKEY( "task" ), LROVAL( node_task_map ) },
#ifdef DEVELOPMENT_TOOLS
{ LSTRKEY( "osprint" ), LFUNCVAL( node_osprint ) },
#endif
......
......@@ -145,6 +145,36 @@ none
#### Returns
flash ID (number)
## node.flashindex()
Returns the function reference for a function in the LFS (Lua Flash Store).
#### Syntax
`node.flashindex()`
#### Parameters
`modulename` The name of the module to be loaded. If this is `nil` or invalid then an info list is returned
#### Returns
- In the case where the LFS in not loaded, `node.flashindex` evaluates to `nil`, followed by the flash and mapped base addresss of the LFS
- If the LFS is loaded and the function is called with the name of a valid module in the LFS, then the function is returned in the same way the `load()` and the other Lua load functions do.
- Otherwise an extended info list is returned: the Unix time of the LFS build, the flash and mapped base addresses of the LFS and its current length, and an array of the valid module names in the LFS.
## node.flashreload()
Reload the LFS (Lua Flash Store) with the flash image provided. Flash images are generated on the host machine using the `luac.cross`commnad.
#### Syntax
`node.flashreload(imageName)`
#### Parameters
`imageName` The of name of a image file in the filesystem to be loaded into the LFS.
#### Returns
If the LFS image has the incorrect signature or size, then `false` is returned.
In the case of the `imagename` being a valid LFS image, this is then loaded into flash. The ESP is then immediately rebooted so control is not returned to the calling application.
## node.flashsize()
Returns the flash chip size in bytes. On 4MB modules like ESP-12 the return value is 4194304 = 4096KB.
......@@ -496,37 +526,6 @@ provides more detailed information on the EGC.
`node.egc.setmode(node.egc.ALWAYS, 4096) -- This is the default setting at startup.`
`node.egc.setmode(node.egc.ON_ALLOC_FAILURE) -- This is the fastest activeEGC mode.`
# node.flash module
## node.flash.index()
Returns the function reference for a function in the LFS (Lua Flash Store).
#### Syntax
`node.flash.index()`
#### Parameters
None
#### Returns
- In the case where the LFS in not loaded, `node.flash.index` evaluates to `nil`
- If the LFS is loaded, this returns the index function within the LFS which indexes its contents. This index function can itself to called to interrogate or access the LFS contents:
- In that case where the function is called with the name of a valid module in the LFS, the function is returned in the same way the `load()` and the other Lua load functions do.
- Otherwise the function returns a list of module names in the LFS. Note that the first entry in the list is the Unix datetime of he build.
## node.flash.reload()
Reload the LFS (Lua Flash Store) with the flash image provided. Flash images are generated on the host machine using the `luac.cross`commnad.
#### Syntax
`node.flash.rebuild(imageName)`
#### Parameters
`imageName` The of name of a image file in the filesystem to be loaded into the LFS.
#### Returns
_Not applicable_. The ESP will load the LFS image and immediately reboot. Control is not returned to the calling application.
# node.task module
## node.task.post()
......
-- First time image boot to discover the confuration
--
-- If you want to use absolute address LFS load or SPIFFS imaging, then boot the
-- image for the first time bare, that is without either LFS or SPIFFS preloaded
-- then enter the following commands interactively through the UART:
--
local _,mapa,fa=node.flashindex(); return ('0x%x, 0x%x, 0x%x'):format(
mapa,fa,file.fscfg())
--
-- This will print out 3 hex constants: the absolute address used in the
-- 'luac.cross -a' options and the flash adresses of the LFS and SPIFFS.
--
--[[ So you would need these commands to image your ESP module:
USB=/dev/ttyUSB0 # or whatever the device of your USB is
NODEMCU=~/nodemcu # The root of your NodeMCU file hierarchy
SRC=$NODEMCU/local/lua # your source directory for your LFS Lua files.
BIN=$NODEMCU/bin
ESPTOOL=$NODEMCU/tools/esptool.py
$ESPTOOL --port $USB erase_flash # Do this is you are having load funnies
$ESPTOOL --port $USB --baud 460800 write_flash -fm dio 0x00000 \
$BIN/0x00000.bin 0x10000 $BIN/0x10000.bin
#
# Now restart your module and use whatever your intective tool is to do the above
# cmds, so if this outputs 0x4027b000, -0x7b000, 0x100000 then you can do
#
$NODEMCU/luac.cross -a 0x4027b000 -o $BIN/0x7b000-flash.img $SRC/*.lua
$ESPTOOL --port $USB --baud 460800 write_flash -fm dio 0x7b000 \
$BIN/0x7b000-flash.img
# and if you've setup a SPIFFS then
$ESPTOOL --port $USB --baud 460800 write_flash -fm dio 0x100000 \
$BIN/0x100000-0x10000.img
# and now you are good to go
]]
-----------------------------------------------------------------------------------
--
-- It is a good idea to add an _init.lua module to your LFS and do most of the
-- LFS module related initialisaion in this. This example uses standard Lua
-- features to simplify the LFS API.
--
-- The first adds a 'LFS' table to _G and uses the __index metamethod to resolve
-- functions in the LFS, so you can execute the main function of module 'fred'
-- by doing LFS.fred(params)
--
-- The second adds the LFS to the require searchlist so that you can require a
-- Lua module 'jean' in the LFS by simply doing require "jean". However not that
-- this is at the search entry following the FS searcher, so if you also have
-- jean.lc or jean.lua in SPIFFS, then this will get preferentially loaded,
-- albeit into RAM. (Useful, for development).
--
do
local index = node.flashindex
local lfs_t = { __index = function(_, name)
local fn, ba = index(name)
if not ba then return fn end -- or return nil implied
end}
getfenv().LFS = setmetatable(lfs_t,lfs_t)
local function loader_flash(module)
local fn, ba = index(module)
return ba and "Module not in LFS" or fn
end
package.loaders[3] = loader_flash
end
-----------------------------------------------------------------------------------
--
-- File: init.lua
--
-- With the previous example you still need an init.lua to bootstrap the _init
-- module in LFS. Here is an example. It's a good idea either to use a timer
-- delay or a GPIO pin during development, so that you as developer can break into
-- the boot sequence if there is a problem with the _init bootstrap that is causing
-- a panic loop. Here is one example of how you might do this. You have a second to
-- inject tmr.stop(0) into UART0. Extend if your reactions can't meet this.
--
-- You also want to do autoload the LFS, for example by adding the following:
--
if node.flashindex() == nil then
node.flashreload('flash.img')
end
tmr.alarm(0, 1000, tmr.ALARM_SINGLE,
function()
local fi=node.flashindex; return pcall(fi and fi'_init')
end)
-----------------------------------------------------------------------------------
--
-- The debug.getstrings function can be used to get a listing of the RAM (or ROM
-- if LFS is loaded), as per the following example, so you can do this at the
-- interactive prompt or call it as a debug function during a running application.
--
do
local a=debug.getstrings'RAM'
for i =1, #a do a[i] = ('%q'):format(a[i]) end
print ('local preload='..table.concat(a,','))
end
-----------------------------------------------------------------------------------
--
-- File: LFS_dummy_strings.lua
--
-- luac.cross -f will generate a ROM string table that includes all strings
-- referenced in the loaded modules. If you want to preload other string constants
-- hen the trick is to include a dummy module in the LFS. You never need to call
-- this. It's inclusion is enough to add the strings to the ROM table. Once in
-- the ROM table, then you can use them in your application without incuring any
-- RAM or Lua Garbage Collector (LGC) overhead. Here is a useful starting point,
-- but you can add to this for your application.
--
-- The trick is to build the LFS as normal then run the previous example from your
-- running application and append these lines to this file.
--
local preload = "?.lc;?.lua", "@init.lua", "_G", "_LOADED", "_LOADLIB", "__add",
"__call", "__concat", "__div", "__eq", "__gc", "__index", "__le", "__len", "__lt",
"__mod", "__mode", "__mul", "__newindex", "__pow", "__sub", "__tostring", "__unm",
"collectgarbage", "cpath", "debug", "file", "file.obj", "file.vol", "flash",
"getstrings", "index", "ipairs", "list", "loaded", "loader", "loaders", "loadlib",
"module", "net.tcpserver", "net.tcpsocket", "net.udpsocket", "newproxy", "package",
"pairs", "path", "preload", "reload", "require", "seeall", "wdclr"
......@@ -34,6 +34,7 @@ else
FLASH_FS_LOC := $(shell printf "0x%x" $(FLASH_FS_LOC))
endif
LFSSOURCES := $(wildcard $(LUASOURCE)/*.lua)
#############################################################
# Rules base
......@@ -68,9 +69,14 @@ spiffsscript: remove-image LFSimage spiffsimg/spiffsimg
@$(foreach f, $(SPIFFSFILES), echo "import $(FSSOURCE)$(f) $(f)" >> ./spiffsimg/spiffs.lst ;)
$(foreach sz, $(FLASHSIZE), spiffsimg/spiffsimg -f ../bin/0x%x-$(sz).img $(FLASH_SW) $(sz) -U $(FLASH_FS_LOC) -r ./spiffsimg/spiffs.lst -d; )
@$(foreach sz, $(FLASHSIZE), if [ -r ../bin/spiffs-$(sz).dat ]; then echo Built $$(cat ../bin/spiffs-$(sz).dat)-$(sz).bin; fi; )
LFSimage: $(LUASOURCE)*.lua
../luac.cross -f -o $(FSSOURCE)flash.img $(LUASOURCE)*.lua
ifneq ($(LFSSOURCES),)
LFSimage: $(LFSSOURCES)
../luac.cross -f -o $(FSSOURCE)flash.img $(LFSSOURCES)
else
LFSimage:
rm -f $(FSSOURCE)flash.img
endif
remove-image:
$(foreach sz, $(FLASHSIZE), if [ -r ../bin/spiffs-$(sz).dat ]; then rm -f ../bin/$$(cat ../bin/spiffs-$(sz).dat)-$(sz).bin; fi; )
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment