mirror of
https://github.com/elua/elua.git
synced 2025-01-08 20:56:17 +08:00
190 lines
7.0 KiB
Lua
190 lines
7.0 KiB
Lua
-- eLua configurations description
|
|
|
|
module( ..., package.seeall )
|
|
|
|
local sf = string.format
|
|
local at = require "attributes"
|
|
local gen = require "generators"
|
|
|
|
local use_multiple_allocator
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- Attribute checkers
|
|
|
|
local function ram_checker( eldesc, vals )
|
|
local startvals = vals.MEM_START_ADDRESS and vals.MEM_START_ADDRESS.value
|
|
local sizevals = vals.MEM_END_ADDRESS and vals.MEM_END_ADDRESS.value
|
|
local ninternal = vals._NUM_INTERNAL_RAMS.value
|
|
if ( not startvals or not sizevals ) and ninternal == 0 then
|
|
return false, "RAM configuration must be defined in element 'ram' of section 'config'"
|
|
end
|
|
if not startvals and not sizevals then return true end
|
|
if not startvals then
|
|
return false, "attribute 'ext_start' must also be specified for element 'ram' of section 'config'"
|
|
elseif not sizevals then
|
|
return false, "attribute 'ext_size' must also be specified for element 'ram' of section 'config'"
|
|
end
|
|
if #startvals == 0 then
|
|
return false, "attribute 'ext_start' of element 'ram' in section 'config' must have at least one element"
|
|
elseif #sizevals == 0 then
|
|
return false, "attribute 'ext_size' of element 'ram' in section 'config' must have at least one element"
|
|
end
|
|
if #startvals ~= #sizevals then
|
|
return false, "attributes 'ext_start' and 'ext_size' of element 'ram' in section 'config' must have the same number of elements"
|
|
end
|
|
return true
|
|
end
|
|
|
|
local egc_mode_map =
|
|
{
|
|
disabled = "EGC_NOT_ACTIVE",
|
|
alloc = "EGC_ON_ALLOC_FAILURE",
|
|
limit = "EGC_ON_MEM_LIMIT",
|
|
always = "EGC_ALWAYS"
|
|
}
|
|
|
|
local function egc_checker( eldesc, vals )
|
|
local modev = vals.EGC_INITIAL_MODE.value
|
|
local limv = vals.EGC_INITIAL_MEMLIMIT and vals.EGC_INITIAL_MEMLIMIT.value
|
|
local allmodes = {}
|
|
for w in modev:gmatch( "(%w+)" ) do allmodes[ #allmodes + 1 ] = w:lower() end
|
|
local has_memlimit
|
|
for k, v in pairs( allmodes ) do
|
|
if not egc_mode_map[ v ] then
|
|
return false, sf( "'%s' is not a valid value for attribute 'mode' of element 'egc' in section 'config'", v )
|
|
end
|
|
if v == "limit" then has_memlimit = true end
|
|
end
|
|
if has_memlimit and not limv then
|
|
return false, sf( "you must specify the 'limit' attribute when using 'limit' as a value for attribute 'mode' of element 'egc' in section 'config'" )
|
|
end
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- Specific generators
|
|
|
|
-- Automatically generates the MEM_START_ADDRESS and MEM_END_ADDRESS macros
|
|
-- Assumes that definitions for INTERNAL_RAMx_FIRST_FREE and INTERNAL_RAMx_LAST_FREE
|
|
-- exist (they should come from <cpu>.h)
|
|
local function ram_generator( desc, vals, generated )
|
|
-- Prepare internal memory configuration first
|
|
local ninternal = vals._NUM_INTERNAL_RAMS.value
|
|
local istart, iend = {}, {}
|
|
for i = 1, ninternal do
|
|
table.insert( istart, sf( "( u32 )( INTERNAL_RAM%d_FIRST_FREE )", i ) )
|
|
table.insert( iend, sf( "( u32 )( INTERNAL_RAM%d_LAST_FREE )", i ) )
|
|
end
|
|
if not vals.MEM_START_ADDRESS then
|
|
-- Generate configuration only for the internal memory
|
|
local gstr = gen.print_define( "MEM_START_ADDRESS", "{ " .. table.concat( istart, "," ) .. " }" )
|
|
gstr = gstr .. gen.print_define( "MEM_END_ADDRESS", "{ " .. table.concat( iend, "," ) .. " }" )
|
|
generated.MEM_START_ADDRESS = true
|
|
generated.MEM_END_ADDRESS = true
|
|
use_multiple_allocator = ninternal > 1
|
|
return gstr
|
|
end
|
|
local function fmtval( s ) return tonumber( s ) and tostring( s ) .. "UL" or ( "( u32 )( " .. s .. " )" ) end
|
|
local startvals, sizevals = vals.MEM_START_ADDRESS.value, vals.MEM_END_ADDRESS.value
|
|
for i = 1, ninternal do
|
|
table.insert( startvals, i, sf( "( u32 )( INTERNAL_RAM%d_FIRST_FREE )", i ) )
|
|
table.insert( sizevals, i, sf( "( u32 )( INTERNAL_RAM%d_LAST_FREE )", i ) )
|
|
end
|
|
for i = ninternal + 1, #sizevals do
|
|
sizevals[ i ] = sf( "( %s + %s - 1 )", fmtval( startvals[ i ] ), fmtval( sizevals[ i ] ) )
|
|
startvals[ i ] = sf( "( %s )", fmtval( startvals[ i ] ) )
|
|
end
|
|
use_multiple_allocator = #startvals > 1
|
|
local gstr = gen.simple_gen( "MEM_START_ADDRESS", vals, generated )
|
|
gstr = gstr .. gen.simple_gen( "MEM_END_ADDRESS", vals, generated )
|
|
if vals.MEM_ERROR_CALLBACK and not generated.MEM_ERROR_CALLBACK and #vals.MEM_ERROR_CALLBACK.value > 0 then
|
|
gstr = gstr .. gen.simple_gen( "MEM_ERROR_CALLBACK", vals, generated )
|
|
gstr = gstr .. sf( "void %s( size_t );\n", vals.MEM_ERROR_CALLBACK.value )
|
|
end
|
|
return gstr
|
|
end
|
|
|
|
local function egc_generator( desc, vals, generated )
|
|
local modev = vals.EGC_INITIAL_MODE.value
|
|
local limv = vals.EGC_INITIAL_MEMLIMIT and vals.EGC_INITIAL_MEMLIMIT.value
|
|
local allmodes = {}
|
|
local has_memlimit, has_always
|
|
for w in modev:gmatch( "(%w+)" ) do
|
|
w = w:lower()
|
|
if w == "limit" then has_memlimit = true end
|
|
if w == "always" then has_always = true end
|
|
allmodes[ #allmodes + 1 ] = w:lower()
|
|
end
|
|
if has_always then
|
|
local gstr = gen.print_define( "EGC_INITIAL_MODE", "EGC_ALWAYS" )
|
|
generated.EGC_INITIAL_MODE = true
|
|
return gstr
|
|
end
|
|
local cmodes = {}
|
|
for k, v in pairs( allmodes ) do
|
|
cmodes[ #cmodes + 1 ] = egc_mode_map[ v ]
|
|
end
|
|
local gstr = gen.print_define( "EGC_INITIAL_MODE", "( " .. table.concat( cmodes, "|" ) .. " )" )
|
|
generated.EGC_INITIAL_MODE = true
|
|
if has_memlimit then gstr = gstr .. gen.simple_gen( "EGC_INITIAL_MEMLIMIT", vals, generated ) end
|
|
return gstr
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- Public interface
|
|
|
|
-- Build the configuration data needed by eLua, save it in the "configs" table
|
|
function init()
|
|
local configs = {}
|
|
|
|
-- Virtual timers
|
|
configs.vtmr = {
|
|
attrs = {
|
|
num = at.int_attr( 'VTMR_NUM_TIMERS', 1 ),
|
|
freq = at.int_attr( 'VTMR_FREQ_HZ', 1 )
|
|
},
|
|
required = { num = 0, freq = 1 }
|
|
}
|
|
|
|
-- EGC
|
|
configs.egc = {
|
|
confcheck = egc_checker,
|
|
gen = egc_generator,
|
|
attrs = {
|
|
mode = at.string_attr( 'EGC_INITIAL_MODE' ),
|
|
limit = at.make_optional( at.int_attr( 'EGC_INITIAL_MEMLIMIT', 1 ) )
|
|
},
|
|
}
|
|
|
|
-- Clocks
|
|
configs.clocks = {
|
|
attrs = {
|
|
external = at.make_optional( at.int_attr( 'ELUA_BOARD_EXTERNAL_CLOCK_HZ', 1 ) ),
|
|
cpu = at.make_optional( at.int_attr( 'ELUA_BOARD_CPU_CLOCK_HZ', 1 ) )
|
|
}
|
|
}
|
|
|
|
-- RAM configuration generator
|
|
configs.ram = {
|
|
gen = ram_generator,
|
|
confcheck = ram_checker,
|
|
attrs = {
|
|
internal_rams = at.int_attr( '_NUM_INTERNAL_RAMS', 0, nil, 1 ),
|
|
ext_start = at.array_of( at.combine_attr( 'MEM_START_ADDRESS', { at.int_attr( '' ), at.string_attr( '' ) } ) ),
|
|
ext_size = at.array_of( at.combine_attr( 'MEM_END_ADDRESS', { at.int_attr( '', 1 ), at.string_attr( '' ) } ) ),
|
|
memory_error_callback = at.string_attr( 'MEM_ERROR_CALLBACK', 120, '' ),
|
|
},
|
|
required = { internal_rams = 1, ext_start = {}, ext_size = {} }
|
|
}
|
|
|
|
-- All done
|
|
return configs
|
|
end
|
|
|
|
-- Returns true if a multiple allocator is needed for this configuration,
|
|
-- false otherwise
|
|
function needs_multiple_allocator()
|
|
return use_multiple_allocator
|
|
end
|
|
|