1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00

working on components/attributes/configs/refactoring various platforms

This commit is contained in:
Bogdan Marinescu 2012-06-28 17:42:21 +03:00
parent 00a3fec2a9
commit fff5754d3b
7 changed files with 368 additions and 53 deletions

115
build/attributes.lua Normal file
View File

@ -0,0 +1,115 @@
-- Attributes are used by various parts of the board description
-- system (for example configs and components)
module( ..., package.seeall )
local ct = require "constants"
local sf = string.format
-- Validator for a 'choice' attribute
-- Returns the value if OK, (false, errmsg) for error
-- Needs: attrvals - list of permitted values for this attribute
local function validate_choice( adesc, aname, aval, comp )
aval = aval:lower()
for k, v in pairs( adesc.attrvals ) do
if v == aval then return v end
end
return false, sf( "invalid value '%s' for attribute '%s' of component '%s'\n", aval, aname, comp )
end
-- Validator for a 'number' attribute
-- Returns the value if OK, (false, errmsg) for error
-- Needs: attrtype - the number type ('int' or 'float')
-- attrmin - minimum value (no minimum check will be performed if not specified)
-- attrmax - maximum value (no maximum check will be performed if not specified)
local function validate_number( adesc, aname, aval, comp )
aval = tonumber( aval )
if not aval then return false, sf( "value of attribute '%s' for component '%s' must be a number", aname, comp ) end
if adesc.attrtype == 'int' and math.floor( aval ) ~= aval then
return false, sf( "value of attribute '%s' for component '%s' must be an integer", aname, comp )
end
local minval = adesc.attrmin or aval
local maxval = adesc.attrmax or aval
if aval < minval then
return false, sf( "value of attribute '%s' for component '%s' must be larger than '%s'\n", aname, comp, tostring( minval ) )
end
if aval > maxval then
return false, sf( "value of attribute '%s' for component '%s' must be smaller than '%s'\n", aname, comp, tostring( maxval ) )
end
return aval
end
-- Validator for a log2 number attribute
-- Works like number, but additionaly checks that the value is a power of 2
-- Also changes the attribute value to its log2
local function validate_log2( adesc, aname, aval, comp )
local res, err = validate_number( adesc, aname, aval, comp )
if not res then return res, err end
if aval <= 0 then
return false, sf( "value of attribute '%s' for component '%s' must be larger than 0\n", aname, comp )
end
local thelog = math.log( res ) / math.log( 2 )
if thelog ~= math.floor( thelog ) then
return false, sf( "value of attribute '%s' for component '%s' must be a power of 2\n", aname, comp )
end
return thelog
end
-- Validator for a string attribute
-- Return the string if OK, (false, errmsg) for error
-- Needs: attrmaxsize - maximum size of the string
local function validate_string( adesc, aname, aval, comp )
aval = tostring( aval )
if type( aval ) ~= "string" then
return false, sf( "value of attribute '%s' for component '%s' must be a string", aname, comp )
end
maxsize = adesc.attrmaxsize or math.huge
if #aval > adesc.attrmaxsize then
return false, sf( "value of attribute '%s' for component '%s' must be less than %d chars in length", aname, comp, maxsize )
end
return aval
end
-------------------------------------------------------------------------------
-- Public interface
-- Returns a new timer attribute with the given macro and default (systmr if not specified)
function timer_attr( macro, default )
default = default or ct.systmr
return { macro = macro, default = default }
end
-- Returns a new integer number attribute with the given limits
function int_attr( macro, minv, maxv, default )
return { macro = macro, default = default, validator = validate_number, attrtype = 'int', attrmin = minv, attrmax = maxv }
end
-- Returns a new integer number attribute with the given limits
-- The generated value will be the integer's base 2 logarithm
function int_log2_attr( macro, minv, maxv, default )
local t = int_attr( macro, minv, maxv, default )
t.validator = validate_log2
return t
end
-- Returns a new choice attribute with the given possible values
function choice_attr( macro, values, default )
return { macro = macro, default = default, validator = validate_choice, attrvals = values }
end
-- Returns a new flow control attribute
function flow_control_attr( macro, default )
default = default or ct.uart_flow.none
return choice_attr( macro, ct.uart_flow_vals, default )
end
-- Returns a new string attribute
function string_attr( macro, maxsize, dfault )
return { macro = macro, default = default, validator = validate_string, attrmaxsize = maxsize }
end
-- Make the given attribute optional
function make_optional( attr )
attr.optional = true
return attr
end

View File

@ -36,14 +36,35 @@ return {
} }
--]] --]]
--[[ platform_conf.h template
#include various files (buf, type...)
#include ELUA_CPU_HEADER
#include ELUA_BOARD_HEADER
#include "platform_post_config.h"
#include "platform_generic.h"
#include "platform_interrupts.h"
--]]
local test = { local test = {
cpu = 'lm3s8962', cpu = 'stm32f103',
config = {
extram = { start = 0, size = 256 * 1024 },
vtmr = { num = 4, freq = 10 },
egc = { mode = "full", limit = 40 * 1024 }
},
components = { components = {
wofs = true, wofs = true,
romfs = true, romfs = true,
shell = { uart = 0, speed = 115200 }, shell = { uart = 0, speed = 115200 },
xmodem = true xmodem = true,
term = { lines = 25, cols = 80 },
cints = true,
luaints = { queue_size = 32 },
linenoise = { shell_lines = 10, lua_lines = 50 },
rfs = { uart = 1, speed = 115200, buf_size = 512 }
} }
} }
print( comp.gen_config( test ) ) print( comp.gen_config( test ) )

View File

@ -5,13 +5,17 @@ module( ..., package.seeall )
local sf = string.format local sf = string.format
local ct = require "constants" local ct = require "constants"
local at = require "attributes"
local gen = require "generators"
local components = {} local components = {}
local conf = {} local conf = {}
local enabled = {} local enabled = {}
local MACRO_DEF_POS = 41 -------------------------------------------------------------------------------
-- Various helper functions
-- Enables and configures this component -- Enables and configures the given component
local function config( name, data ) local function config( name, data )
local desc = components[ name ] local desc = components[ name ]
local attrs = desc.attrs or {} local attrs = desc.attrs or {}
@ -20,29 +24,36 @@ local function config( name, data )
local elmeta = attrs[ attr ] local elmeta = attrs[ attr ]
if not elmeta then error( sf( "attribute '%s' is not defined for component '%s'", attr, name ) ) end if not elmeta then error( sf( "attribute '%s' is not defined for component '%s'", attr, name ) ) end
if elmeta.validator then if elmeta.validator then
if not elmeta:validator( v ) then local res, err = elmeta:validator( attr, v, name )
if not res then
error( sf( "'%s' is not a valid value for attribute '%s' of component '%s'", v, attr, name ) ) error( sf( "'%s' is not a valid value for attribute '%s' of component '%s'", v, attr, name ) )
else
-- The validator can also change the attribute's value
v = res
end end
end end
if conf[ elmeta.macro ] then if conf[ elmeta.macro ] and tostring( conf[ elmeta.macro ].value ) ~= tostring( v ) then
print( sf( "WARNING: overriding value of '%s' from '%s' to '%s' with component '%s'", elmeta.macro, print( sf( "WARNING: overriding value of '%s' from '%s' to '%s' with component '%s'", elmeta.macro,
conf[ elmeta.macro ].value, v, name ) ) conf[ elmeta.macro ].value, v, name ) )
end end
conf[ elmeta.macro ] = { desc = elmeta, value = v } conf[ elmeta.macro ] = { desc = elmeta, value = v }
print( sf( "SET -> '%s' = '%s'", elmeta.macro, v ) ) -- print( sf( "SET -> '%s' = '%s'", elmeta.macro, v ) )
end end
-- Set default values where needed -- Set default values where needed
for name, data in pairs( attrs ) do for name, data in pairs( attrs ) do
if not conf[ name ] and data.default then if not conf[ data.macro ] and data.default then
conf[ data.macro ] = { desc = data, value = data.default } conf[ data.macro ] = { desc = data, value = data.default }
print( sf( "DEFAULT -> '%s' = '%s'", data.macro, data.default ) ) -- print( sf( "DEFAULT -> '%s' = '%s'", data.macro, data.default ) )
end end
end end
-- Mark this component as configured -- Mark this component as configured
enabled[ name ] = true enabled[ name ] = true
print( sf( "ENABLED -> %s", name ) ) -- print( sf( "ENABLED -> %s", name ) )
end end
-------------------------------------------------------------------------------
-- Configuration checkers
-- Helper: shell configuration consistency checker -- Helper: shell configuration consistency checker
-- Returns 'true' if consistent, (false, errmsg) otherwise -- Returns 'true' if consistent, (false, errmsg) otherwise
local function shell_confcheck( compdesc, vals ) local function shell_confcheck( compdesc, vals )
@ -63,27 +74,23 @@ local function shell_confcheck( compdesc, vals )
return true return true
end end
-- Returns a new timer option with the given macro and default (systmr if not specified) -------------------------------------------------------------------------------
local function timer_attr( macro, default ) -- Component-specific generators
default = default or ct.systmr
return { macro = macro, default = default, gen = TODO_tmr_gen }
end
-- Formatted print for "#define" -- Generator for the shell component
local function print_define( k, v ) local function shell_gen( desc, conf, generated )
v = v or '' generated._SHELL_TRANSPORT = true
local s = sf( "#define %s", k:upper() ) local gstr = ''
if v then local shtype = conf._SHELL_TRANSPORT.value
if #s < MACRO_DEF_POS then s = s .. string.rep( ' ', MACRO_DEF_POS - #s ) end if shtype == 'serial' then
gstr = gstr .. gen.simple_gen( "CON_UART_ID", conf, generated )
gstr = gstr .. gen.simple_gen( "CON_UART_SPEED", conf, generated )
gstr = gstr .. gen.simple_gen( "CON_TIMER_ID", conf, generated )
gstr = gstr .. gen.simple_gen( "CON_FLOW_TYPE", conf, generated )
else
error "TODO: implement shell over TCP/IP generator"
end end
s = s .. v .. "\n" return gstr
return s
end
-- Simple generator for an attribute
local function simple_gen( attrname )
local adesc, aval = conf[ attrname ].desc, conf[ attrname ].value
return print_define( attrname, aval )
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -91,15 +98,26 @@ end
-- Build all components needed by eLua, save them in the "components" table -- Build all components needed by eLua, save them in the "components" table
function init() function init()
-- Serial console
components.sercon = {
macro = 'BUILD_CON_GENERIC',
attrs = {
uart = at.int_attr( 'CON_UART_ID' ),
speed = at.int_attr( 'CON_UART_SPEED' ),
timer = at.timer_attr( 'CON_TIMER_ID' ),
flow = at.flow_control_attr( 'CON_FLOW_TYPE' )
}
}
-- TCP/IP console
components.tcpipcon = { macro = 'BUILD_CON_TCP' }
-- XMODEM -- XMODEM
components.xmodem = { components.xmodem = {
macro = 'BUILD_XMODEM', macro = 'BUILD_XMODEM',
attrs = attrs = {
{ uart = at.int_attr( 'CON_UART_ID' ),
uart = { macro = 'CON_UART_ID' }, speed = at.int_attr( 'CON_UART_SPEED' ),
speed = { macro = 'CON_UART_SPEED' }, timer = at.timer_attr( 'CON_TIMER_ID' ),
timer = timer_attr( 'CON_TIMER_ID' ), flow = at.flow_control_attr( 'CON_FLOW_TYPE')
flow = { macro = 'CON_FLOW_TYPE', default = ct.uart_flow.none }
} }
} }
-- Shell -- Shell
@ -107,13 +125,54 @@ function init()
macro = 'BUILD_SHELL', macro = 'BUILD_SHELL',
confcheck = shell_confcheck, confcheck = shell_confcheck,
gen = shell_gen, gen = shell_gen,
attrs = attrs = {
{ transport = at.choice_attr( '_SHELL_TRANSPORT', { 'serial', 'tcpip' }, 'serial' ),
transport = { macro = '_SHELL_TRANSPORT', default = 'serial' }, uart = at.int_attr( 'CON_UART_ID' ),
uart = { macro = 'CON_UART_ID' }, speed = at.int_attr( 'CON_UART_SPEED' ),
speed = { macro = 'CON_UART_SPEED' }, timer = at.timer_attr( 'CON_TIMER_ID' ),
timer = timer_attr( 'CON_TIMER_ID' ), flow = at.flow_control_attr( 'CON_FLOW_TYPE' )
flow = { macro = 'CON_FLOW_TYPE', default = ct.uart_flow.none } }
}
-- Term
components.term = {
macro = 'BUILD_TERM',
attrs = {
uart = at.int_attr( 'CON_UART_ID' ),
speed = at.int_attr( 'CON_UART_SPEED' ),
timer = at.timer_attr( 'CON_TIMER_ID' ),
flow = at.flow_control_attr( 'CON_FLOW_TYPE' ),
lines = at.int_attr( 'TERM_LINES' ),
cols = at.int_attr( 'TERM_COLS' )
}
}
-- C interrupt support
components.cints = { macro = 'BUILD_C_INT_HANDLERS' }
-- Lua interrupt support
components.luaints = {
macro = 'BUILD_LUA_INT_HANDLERS',
attrs = {
queue_size = at.int_log2_attr( 'PLATFORM_INT_QUEUE_LOG_SIZE', nil, nil, 32 )
}
}
-- Linenoise
components.linenoise = {
macro = 'BUILD_LINENOISE',
attrs = {
shell_lines = at.int_attr( 'LINENOISE_HISTORY_SIZE_SHELL' ),
lua_lines = at.int_attr( 'LINENOISE_HISTORY_SIZE_LUA' ),
autosave_file = at.make_optional( at.string_attr( 'LINENOISE_AUTOSAVE_FNAME', '', 32 ) )
}
}
-- RFS
components.rfs = {
macro = 'BUILD_RFS',
attrs = {
uart = at.int_attr( 'RFS_UART_ID' ),
speed = at.int_attr( 'RFS_UART_SPEED' ),
timer = at.timer_attr( 'RFS_TIMER_ID' ),
flow = at.flow_control_attr( 'RFS_FLOW_TYPE' ),
buf_size = at.int_log2_attr( 'RFS_BUFFER_SIZE', 512 ),
timeout = at.int_attr( 'RFS_TIMEOUT', nil, nil, 100000 )
} }
} }
-- ROMFS -- ROMFS
@ -125,18 +184,28 @@ end
-- Generate configuration data starting from the input dictionary -- Generate configuration data starting from the input dictionary
function gen_config( d ) function gen_config( d )
conf, enabled = {}, {} conf, enabled = {}, {}
local comps = d.components
-- Prerequisites: check for keys that might be needed in 'd', but might not be there
-- At the moment, we need to definer either BUILD_CON_GENERIC or BUILD_CON_TCP (but not both)
-- If none is defined, we default to BUILD_CON_GENERIC
-- If both are defined, we exit with error
if comps.sercon and comps.tcpipcon then
return nil, "serial and TCP/IP console can't be enabled at the same time"
elseif not comps.sercon and not comps.tcpipcon then
comps.sercon = true
end
-- Step 1: interpret data in the input table -- Step 1: interpret data in the input table
local comps = d.components
if not comps then return false, "unable to find components in the board description" end if not comps then return false, "unable to find components in the board description" end
-- Configure each component in turn, doing validation as required -- Configure each component in turn, doing validation as required
for compname, compval in pairs( comps ) do for compname, compval in pairs( comps ) do
if not components[ compname ] then error( sf( "unknown component '%s'", compname ) ) end if not components[ compname ] then error( sf( "unknown component '%s'", compname ) ) end
if type( compval ) ~= "table" then if type( compval ) ~= "table" and compval then
comps[ compname ] = {} comps[ compname ] = {}
compval = comps[ compname ] compval = comps[ compname ]
end end
config( compname, compval ) if compval then config( compname, compval ) end
end end
-- Step 2: basic consistency check -- Step 2: basic consistency check
@ -160,7 +229,7 @@ function gen_config( d )
-- Step 3: actual generation of code -- Step 3: actual generation of code
-- The default generator simply adds '#define KEY VALUE' pairs. A component can overwrite this -- The default generator simply adds '#define KEY VALUE' pairs. A component can overwrite this
-- default verification by specifying its own 'gen' function -- default generation by specifying its own 'gen' function
-- Also, we never generate the same key twice. We ensure this by keeping a table of the -- Also, we never generate the same key twice. We ensure this by keeping a table of the
-- keys that were already generated -- keys that were already generated
local generated = {} local generated = {}
@ -173,17 +242,15 @@ function gen_config( d )
genstr = genstr .. desc:gen( conf, generated ) genstr = genstr .. desc:gen( conf, generated )
else else
for aname, adesc in pairs( attrs ) do for aname, adesc in pairs( attrs ) do
if not generated[ adesc.macro ] then genstr = genstr .. gen.simple_gen( adesc.macro, conf, generated )
genstr = genstr .. simple_gen( adesc.macro )
generated[ adesc.macro ] = true
end
end end
end end
-- Add the "build enable" macro -- Add the "build enable" macro
genstr = genstr .. print_define( desc.macro ) .. "\n" if desc.macro then genstr = genstr .. gen.print_define( desc.macro ) .. "\n" end
end end
-- Step 4: take care of all "special cases" -- Step 4: take care of all "special cases" (if any)
-- TODO: check proper sermux ID assignment for console/RFS
-- All done -- All done
return genstr return genstr

View File

@ -12,6 +12,11 @@ uart_flow =
rtscts = '( PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS )' rtscts = '( PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS )'
} }
uart_flow_vals = {}
for k, v in pairs( uart_flow ) do
uart_flow_vals[ #uart_flow_vals + 1 ] = v
end
-- System timer ID -- System timer ID
systmr = 'PLATFORM_TIMER_SYS_ID' systmr = 'PLATFORM_TIMER_SYS_ID'
@ -20,3 +25,8 @@ for i = 0, 31 do
_G[ sf( 'vtmr%d', i ) ] = sf( '( VTMR_FIRST_ID + %d )', i ) _G[ sf( 'vtmr%d', i ) ] = sf( '( VTMR_FIRST_ID + %d )', i )
end end
-- Add a sufficient number of virtual UARTs
for i = 0, 31 do
_G[ sf( 'vuart%d', i ) ] = sf( '( SERMUX_SERVICE_ID_FIRST + %d )', i )
end

27
build/generators.lua Normal file
View File

@ -0,0 +1,27 @@
-- Code generators for various attributes and other constructs
module( ..., package.seeall )
local sf = string.format
local MACRO_DEF_POS = 41
-- Formatted print for "#define"
function print_define( k, v )
v = v or ''
local s = sf( "#define %s", k:upper() )
if v then
if #s < MACRO_DEF_POS then s = s .. string.rep( ' ', MACRO_DEF_POS - #s ) end
end
s = s .. v .. "\n"
return s
end
-- Simple generator for an attribute
function simple_gen( attrname, conf, gentable )
if gentable[ attrname ] then return '' end
if not conf[ attrname ] then return '' end
local adesc, aval = conf[ attrname ].desc, conf[ attrname ].value
gentable[ attrname ] = true
return print_define( attrname, aval )
end

View File

@ -0,0 +1,35 @@
// LPC2468 CPU definitions
#ifndef __LPC2468_H__
#define __LPC2468_H__
#include "target.h"
// Number of resources (0 if not available/not implemented)
#define NUM_PIO 5
#define NUM_SPI 0
#define NUM_UART 4
#define NUM_PWM 12
#define NUM_ADC 8
#define NUM_CAN 0
#define NUM_TIMER 4
// CPU frequency (needed by the CPU module and MMCFS code, 0 if not used)
#define CPU_FREQUENCY Fcclk
// PIO prefix ('0' for P0, P1, ... or 'A' for PA, PB, ...)
#define PIO_PREFIX '0'
// Pins per port configuration:
// #define PIO_PINS_PER_PORT (n) if each port has the same number of pins, or
// #define PIO_PIN_ARRAY { n1, n2, ... } to define pins per port in an array
// Use #define PIO_PINS_PER_PORT 0 if this isn't needed
#define PIO_PINS_PER_PORT 32
#define SRAM_ORIGIN 0x40000000
#define SRAM_SIZE 0x10000 // [TODO]: make this 96k?
#define INTERNAL_FLASH_START_ADDRESS 0
#define INTERNAL_FLASH_SIZE ( 512 * 1024 )
#endif // #ifndef __LPC2468_H__

View File

@ -0,0 +1,40 @@
// CPU definition file for STM32F103
#ifndef __STM32F103_H__
#define __STM32F103_H__
#include "type.h"
// Number of resources (0 if not available/not implemented)
#define NUM_PIO 7
#define NUM_SPI 2
#define NUM_UART 5
#define NUM_TIMER 5
#define NUM_PHYS_TIMER 5
#define NUM_PWM 4
#define NUM_ADC 16
#define NUM_CAN 1
u32 platform_s_cpu_get_frequency();
#define CPU_FREQUENCY platform_s_cpu_get_frequency()
// PIO prefix ('0' for P0, P1, ... or 'A' for PA, PB, ...)
#define PIO_PREFIX 'A'
// Pins per port configuration:
// #define PIO_PINS_PER_PORT (n) if each port has the same number of pins, or
// #define PIO_PIN_ARRAY { n1, n2, ... } to define pins per port in an array
// Use #define PIO_PINS_PER_PORT 0 if this isn't needed
#define PIO_PINS_PER_PORT 16
// Allocator data: define your free memory zones here in two arrays
// (start address and end address)
#define SRAM_SIZE ( 64 * 1024 )
#define MEM_START_ADDRESS { ( void* )end }
#define MEM_END_ADDRESS { ( void* )( SRAM_BASE + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) }
#define INTERNAL_FLASH_SIZE ( 512 * 1024 )
#define INTERNAL_FLASH_SECTOR_SIZE 2048
#define INTERNAL_FLASH_START_ADDRESS 0x08000000
#endif //#ifndef __STM32F103_H__