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 = {
cpu = 'lm3s8962',
cpu = 'stm32f103',
config = {
extram = { start = 0, size = 256 * 1024 },
vtmr = { num = 4, freq = 10 },
egc = { mode = "full", limit = 40 * 1024 }
},
components = {
wofs = true,
romfs = true,
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 ) )

View File

@ -5,13 +5,17 @@ module( ..., package.seeall )
local sf = string.format
local ct = require "constants"
local at = require "attributes"
local gen = require "generators"
local components = {}
local conf = {}
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 desc = components[ name ]
local attrs = desc.attrs or {}
@ -20,29 +24,36 @@ local function config( name, data )
local elmeta = attrs[ attr ]
if not elmeta then error( sf( "attribute '%s' is not defined for component '%s'", attr, name ) ) end
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 ) )
else
-- The validator can also change the attribute's value
v = res
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,
conf[ elmeta.macro ].value, v, name ) )
end
conf[ elmeta.macro ] = { desc = elmeta, value = v }
print( sf( "SET -> '%s' = '%s'", elmeta.macro, v ) )
-- print( sf( "SET -> '%s' = '%s'", elmeta.macro, v ) )
end
-- Set default values where needed
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 }
print( sf( "DEFAULT -> '%s' = '%s'", data.macro, data.default ) )
-- print( sf( "DEFAULT -> '%s' = '%s'", data.macro, data.default ) )
end
end
-- Mark this component as configured
enabled[ name ] = true
print( sf( "ENABLED -> %s", name ) )
-- print( sf( "ENABLED -> %s", name ) )
end
-------------------------------------------------------------------------------
-- Configuration checkers
-- Helper: shell configuration consistency checker
-- Returns 'true' if consistent, (false, errmsg) otherwise
local function shell_confcheck( compdesc, vals )
@ -63,27 +74,23 @@ local function shell_confcheck( compdesc, vals )
return true
end
-- Returns a new timer option with the given macro and default (systmr if not specified)
local function timer_attr( macro, default )
default = default or ct.systmr
return { macro = macro, default = default, gen = TODO_tmr_gen }
end
-------------------------------------------------------------------------------
-- Component-specific generators
-- Formatted print for "#define"
local 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
-- Generator for the shell component
local function shell_gen( desc, conf, generated )
generated._SHELL_TRANSPORT = true
local gstr = ''
local shtype = conf._SHELL_TRANSPORT.value
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
s = s .. v .. "\n"
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 )
return gstr
end
-------------------------------------------------------------------------------
@ -91,15 +98,26 @@ end
-- Build all components needed by eLua, save them in the "components" table
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
components.xmodem = {
macro = 'BUILD_XMODEM',
attrs =
{
uart = { macro = 'CON_UART_ID' },
speed = { macro = 'CON_UART_SPEED' },
timer = timer_attr( 'CON_TIMER_ID' ),
flow = { macro = 'CON_FLOW_TYPE', default = ct.uart_flow.none }
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')
}
}
-- Shell
@ -107,13 +125,54 @@ function init()
macro = 'BUILD_SHELL',
confcheck = shell_confcheck,
gen = shell_gen,
attrs =
{
transport = { macro = '_SHELL_TRANSPORT', default = 'serial' },
uart = { macro = 'CON_UART_ID' },
speed = { macro = 'CON_UART_SPEED' },
timer = timer_attr( 'CON_TIMER_ID' ),
flow = { macro = 'CON_FLOW_TYPE', default = ct.uart_flow.none }
attrs = {
transport = at.choice_attr( '_SHELL_TRANSPORT', { 'serial', 'tcpip' }, 'serial' ),
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' )
}
}
-- 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
@ -125,18 +184,28 @@ end
-- Generate configuration data starting from the input dictionary
function gen_config( d )
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
local comps = d.components
if not comps then return false, "unable to find components in the board description" end
-- Configure each component in turn, doing validation as required
for compname, compval in pairs( comps ) do
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 ] = {}
compval = comps[ compname ]
end
config( compname, compval )
if compval then config( compname, compval ) end
end
-- Step 2: basic consistency check
@ -160,7 +229,7 @@ function gen_config( d )
-- Step 3: actual generation of code
-- 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
-- keys that were already generated
local generated = {}
@ -173,17 +242,15 @@ function gen_config( d )
genstr = genstr .. desc:gen( conf, generated )
else
for aname, adesc in pairs( attrs ) do
if not generated[ adesc.macro ] then
genstr = genstr .. simple_gen( adesc.macro )
generated[ adesc.macro ] = true
end
genstr = genstr .. gen.simple_gen( adesc.macro, conf, generated )
end
end
-- 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
-- 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
return genstr

View File

@ -12,6 +12,11 @@ uart_flow =
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
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 )
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__