diff --git a/.gitignore b/.gitignore index fca85992..5fe9c473 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ inc/git_version.h *~ *.*~ luac.cross* +boards/*.h + diff --git a/boards/custom/.gitignore b/boards/custom/.gitignore new file mode 100644 index 00000000..a5baada1 --- /dev/null +++ b/boards/custom/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore + diff --git a/boards/headers/.gitignore b/boards/headers/.gitignore new file mode 100644 index 00000000..a5baada1 --- /dev/null +++ b/boards/headers/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore + diff --git a/boards/known/elua-puc.lua b/boards/known/elua-puc.lua new file mode 100644 index 00000000..9fc8ffc0 --- /dev/null +++ b/boards/known/elua-puc.lua @@ -0,0 +1,26 @@ +-- eLua-PUC board build configuration + +return { + cpu = 'lpc2468', + components = { + sercon = { uart = 0, speed = 115200, buf_size = 128 }, + romfs = true, + shell = true, + term = { lines = 25, cols = 80 }, + cints = true, + luaints = true, + linenoise = { shell_lines = 10, lua_lines = 50 }, + rpc = { uart = 0, speed = 115200 }, + adc = { buf_size = 4, first_timer = 0, num_timers = 4 }, + xmodem = true + }, + config = { + vtmr = { num = 4, freq = 4 }, + extmem = { start = { 0xA0000000 }, size = { 8 * 1048576 } } + }, + modules = { + generic = 'all', + exclude_generic = { "i2c", "net", "spi", "can" }, + } +} + diff --git a/boards/known/et-stm32.lua b/boards/known/et-stm32.lua new file mode 100644 index 00000000..9e04b9b2 --- /dev/null +++ b/boards/known/et-stm32.lua @@ -0,0 +1,29 @@ +-- ET-STM32 build configuration + +return { + cpu = 'stm32f103re', + components = { + sercon = { uart = 0, speed = 115200, buf_size = 128 }, + wofs = true, + romfs = true, + shell = true, + term = { lines = 25, cols = 80 }, + cints = true, + luaints = true, + linenoise = { shell_lines = 10, lua_lines = 50 }, + stm32_enc = true, + rpc = { uart = 0, speed = 115200 }, + adc = { buf_size = 4 }, + xmodem = true + }, + config = { + egc = { mode = "alloc" }, + vtmr = { num = 4, freq = 10 }, + }, + modules = { + generic = 'all', + exclude_generic = { "i2c", "net" }, + platform = 'all', + } +} + diff --git a/boards/known/mod711.lua b/boards/known/mod711.lua new file mode 100644 index 00000000..02c1ef1c --- /dev/null +++ b/boards/known/mod711.lua @@ -0,0 +1,16 @@ +-- MOD711 build configuration + +return { + cpu = 'str711fr2', + components = { + sercon = { uart = 1, speed = 38400, timer = 0 }, + romfs = true, + shell = true, + term = { lines = 25, cols = 80 }, + xmodem = true + }, + modules = { + generic = { 'pio', 'tmr', 'pd', 'pwm', 'uart', 'term', 'pack', 'bit', 'elua', 'cpu', 'math' } + } +} + diff --git a/boards/known/sim.lua b/boards/known/sim.lua new file mode 100644 index 00000000..8b31bcfe --- /dev/null +++ b/boards/known/sim.lua @@ -0,0 +1,16 @@ +-- eLua simulator running on linux + +return { + cpu = 'linux', + components = { + sercon = { uart = 0, speed = 0 }, + wofs = true, + romfs = true, + shell = true, + term = { lines = 25, cols = 80 }, + }, + modules = { + generic = { 'pd', 'math', 'term', 'elua' } + } +} + diff --git a/boards/known/stm3210e-eval.lua b/boards/known/stm3210e-eval.lua new file mode 100644 index 00000000..5b55536c --- /dev/null +++ b/boards/known/stm3210e-eval.lua @@ -0,0 +1,30 @@ +-- STM3210E-EVAL build configuration + +return { + cpu = 'stm32f103ze', + components = { + sercon = { uart = 0, speed = 115200, buf_size = 128 }, + wofs = true, + romfs = true, + shell = true, + term = { lines = 25, cols = 80 }, + cints = true, + luaints = true, + linenoise = { shell_lines = 10, lua_lines = 50 }, + stm32_enc = true, + rpc = { uart = 0, speed = 115200 }, + adc = { buf_size = 4 }, + xmodem = true, + mmcfs = { cs_port = 0, cs_pin = 8, spi = 0 } + }, + config = { + egc = { mode = "alloc" }, + vtmr = { num = 4, freq = 10 }, + }, + modules = { + generic = 'all', + exclude_generic = { "i2c", "net" }, + platform = 'all', + } +} + diff --git a/build_data.lua b/build_data.lua new file mode 100644 index 00000000..7af9e253 --- /dev/null +++ b/build_data.lua @@ -0,0 +1,163 @@ +-- eLua build data +-- This contains various build time information: +-- supported toolchains +-- supported platforms and CPUs + +module( ..., package.seeall ) +local utils = require "utils" + +------------------------------------------------------------------------------- +-- Build data + +-- List of toolchains +local toolchain_list = +{ + [ 'arm-gcc' ] = { + compile = 'arm-elf-gcc', + link = 'arm-elf-ld', + asm = 'arm-elf-as', + bin = 'arm-elf-objcopy', + size = 'arm-elf-size', + cross_cpumode = 'little', + cross_lua = 'float_arm 64', + cross_lualong = 'int 32', + version = '--version' + }, + [ 'arm-eabi-gcc' ] = { + compile = 'arm-eabi-gcc', + link = 'arm-eabi-ld', + asm = 'arm-eabi-as', + bin = 'arm-eabi-objcopy', + size = 'arm-eabi-size', + cross_cpumode = 'little', + cross_lua = 'float 64', + cross_lualong = 'int 32', + version = '--version' + }, + codesourcery = { + compile = 'arm-none-eabi-gcc', + link = 'arm-none-eabi-ld', + asm = 'arm-none-eabi-as', + bin = 'arm-none-eabi-objcopy', + size = 'arm-none-eabi-size', + cross_cpumode = 'little', + cross_lua = 'float 64', + cross_lualong = 'int 32', + version = '--version' + }, + [ 'avr32-gcc' ] = { + compile = 'avr32-gcc', + link = 'avr32-ld', + asm = 'avr32-as', + bin = 'avr32-objcopy', + size = 'avr32-size', + cross_cpumode = 'big', + cross_lua = 'float 64', + cross_lualong = 'int 32', + version = '--version' + }, + [ 'avr32-unknown-none-gcc' ] = { + compile = 'avr32-unknown-none-gcc', + link = 'avr32-unknown-none-ld', + asm = 'avr32-unknown-none-as', + bin = 'avr32-unknown-none-objcopy', + size = 'avr32-unknown-none-size', + cross_cpumode = 'big', + cross_lua = 'float 64', + cross_lualong = 'int 32', + version = '--version' + }, + [ 'i686-gcc' ] = { + compile = 'i686-elf-gcc', + link = 'i686-elf-ld', + asm = 'nasm', + bin = 'i686-elf-objcopy', + size = 'i686-elf-size', + cross_cpumode = 'little', + cross_lua = 'float 64', + cross_lualong = 'int 32', + version = '--version' + } +} + +-- Toolchain Aliases +toolchain_list[ 'devkitarm' ] = toolchain_list[ 'arm-eabi-gcc' ] + +-- List of acrhitectures and their endianness +local arch_data = { + arm = 'little', + cortexm3 = 'little', + cortexm4 = 'little', + avr32 = 'big', + i386 = 'little' +} + +-- Toolchain to arch mapping +local toolchain_map = { + arm = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, + cortexm3 = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, + cortexm4 = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, + avr32 = { 'avr32-gcc', 'avr32-unknown-none-gcc' }, + i386 = { 'i686-gcc' } +} + +-- List of platform/CPU combinations +local platform_list = +{ + at91sam7x = { cpus = { 'AT91SAM7X256', 'AT91SAM7X512' }, arch = 'arm' }, + lm3s = { cpus = { 'LM3S1968', 'LM3S8962', 'LM3S6965', 'LM3S6918', 'LM3S9B92', 'LM3S9D92' }, arch = 'cortexm3' }, + str9 = { cpus = { 'STR912FAW44' }, arch = 'arm' }, + i386 = { cpus = { 'I386' }, arch = 'i386' }, + sim = { cpus = { 'LINUX' }, arch = 'i386' }, + lpc288x = { cpus = { 'LPC2888' }, arch = 'arm' }, + str7 = { cpus = { 'STR711FR2' }, arch = 'arm' }, + stm32 = { cpus = { 'STM32F103ZE', 'STM32F103RE' }, arch = 'cortexm3' }, + avr32 = { cpus = { 'AT32UC3A0128', 'AT32UC3A0256', 'AT32UC3A0512', 'AT32UC3B0256' }, arch = 'avr32' }, + lpc24xx = { cpus = { 'LPC2468' }, arch = 'arm' }, + lpc17xx = { cpus = { 'LPC1768' }, arch = 'cortexm3' } +} + +-- Returns the platform of a given CPU +function get_platform_of_cpu( cpu ) + for p, v in pairs( platform_list ) do + if utils.array_element_index( v.cpus, cpu:upper() ) then return p end + end +end + +-- Return all the CPUs in the 'platform_list' table +function get_all_cpus() + local t = {} + for pl, desc in pairs( platform_list ) do + for _, cpu in pairs( desc.cpus ) do + if not utils.array_element_index( t, cpu ) then t[ #t + 1 ] = cpu end + end + end + return t +end + +-- Returns the complete list of toolchains +function get_all_toolchains() + local t = {} + for arch, chains in pairs( toolchain_map ) do + for _, cname in pairs( chains ) do + if not utils.array_element_index( t, cname ) then t[ #t + 1 ] = cname end + end + end + return t +end + +-- Returns the list of toolchains for a given platform +function get_toolchains_of_platform( platform ) + return toolchain_map[ platform_list[ platform ].arch ] +end + +-- Returns the data of the given toolchain +function get_toolchain_data( name ) + return toolchain_list[ name ] +end + +-- Returns the endianness of the given platform +function get_endianness_of_platform( platform ) + return arch_data[ platform_list[ platform ].arch ] +end + diff --git a/build_elua.lua b/build_elua.lua index b4005805..77c7510b 100755 --- a/build_elua.lua +++ b/build_elua.lua @@ -20,6 +20,10 @@ local args = { ... } local b = require "utils.build" local mkfs = require "utils.mkfs" +local bconf = require "config.config" +local board_base_dir = "boards" +local bd = require "build_data" + builder = b.new_builder() utils = b.utils sf = string.format @@ -75,143 +79,30 @@ function addlib( data ) end ------------------------------------------------------------------------------- --- Build data --- List of toolchains -local toolchain_list = -{ - [ 'arm-gcc' ] = { - compile = 'arm-elf-gcc', - link = 'arm-elf-ld', - asm = 'arm-elf-as', - bin = 'arm-elf-objcopy', - size = 'arm-elf-size', - cross_cpumode = 'little', - cross_lua = 'float_arm 64', - cross_lualong = 'int 32', - version = '--version' - }, - [ 'arm-eabi-gcc' ] = { - compile = 'arm-eabi-gcc', - link = 'arm-eabi-ld', - asm = 'arm-eabi-as', - bin = 'arm-eabi-objcopy', - size = 'arm-eabi-size', - cross_cpumode = 'little', - cross_lua = 'float 64', - cross_lualong = 'int 32', - version = '--version' - }, - codesourcery = { - compile = 'arm-none-eabi-gcc', - link = 'arm-none-eabi-ld', - asm = 'arm-none-eabi-as', - bin = 'arm-none-eabi-objcopy', - size = 'arm-none-eabi-size', - cross_cpumode = 'little', - cross_lua = 'float 64', - cross_lualong = 'int 32', - version = '--version' - }, - [ 'avr32-gcc' ] = { - compile = 'avr32-gcc', - link = 'avr32-ld', - asm = 'avr32-as', - bin = 'avr32-objcopy', - size = 'avr32-size', - cross_cpumode = 'big', - cross_lua = 'float 64', - cross_lualong = 'int 32', - version = '--version' - }, - [ 'avr32-unknown-none-gcc' ] = { - compile = 'avr32-unknown-none-gcc', - link = 'avr32-unknown-none-ld', - asm = 'avr32-unknown-none-as', - bin = 'avr32-unknown-none-objcopy', - size = 'avr32-unknown-none-size', - cross_cpumode = 'big', - cross_lua = 'float 64', - cross_lualong = 'int 32', - version = '--version' - }, - [ 'i686-gcc' ] = { - compile = 'i686-elf-gcc', - link = 'i686-elf-ld', - asm = 'nasm', - bin = 'i686-elf-objcopy', - size = 'i686-elf-size', - cross_cpumode = 'little', - cross_lua = 'float 64', - cross_lualong = 'int 32', - version = '--version' - } -} +-- Return the full path of a board configuration file +local function get_conf_file_path( bname ) + local known_board_name = utils.concat_path( { board_base_dir, "known", bname .. ".lua" } ) + local custom_board_name = utils.concat_path( { board_base_dir, "custom", bname .. ".lua" } ) + if utils.is_file( custom_board_name ) then return custom_board_name end + if utils.is_file( known_board_name ) then return known_board_name end + assert( sf( "board configuration file for board '%s' not found!", bname ) ) +end --- Toolchain Aliases -toolchain_list[ 'devkitarm' ] = toolchain_list[ 'arm-eabi-gcc' ] - --- List of platform/CPU/toolchains combinations --- The first toolchain in the toolchains list is the default one --- (the one that will be used if none is specified) -local platform_list = -{ - at91sam7x = { cpus = { 'AT91SAM7X256', 'AT91SAM7X512' }, toolchains = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, big_endian = false }, - lm3s = { cpus = { 'LM3S1968', 'LM3S8962', 'LM3S6965', 'LM3S6918', 'LM3S9B92', 'LM3S9D92' }, toolchains = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, big_endian = false }, - str9 = { cpus = { 'STR912FAW44' }, toolchains = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, big_endian = false }, - i386 = { cpus = { 'I386' }, toolchains = { 'i686-gcc' }, big_endian = false }, - sim = { cpus = { 'LINUX' }, toolchains = { 'i686-gcc' }, big_endian = false }, - lpc288x = { cpus = { 'LPC2888' }, toolchains = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, big_endian = false }, - str7 = { cpus = { 'STR711FR2' }, toolchains = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, big_endian = false }, - stm32 = { cpus = { 'STM32F103ZE', 'STM32F103RE' }, toolchains = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, big_endian = false }, - avr32 = { cpus = { 'AT32UC3A0128', 'AT32UC3A0256', 'AT32UC3A0512', 'AT32UC3B0256' }, toolchains = { 'avr32-gcc', 'avr32-unknown-none-gcc' }, big_endian = true }, - lpc24xx = { cpus = { 'LPC2468' }, toolchains = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, big_endian = false }, - lpc17xx = { cpus = { 'LPC1768' }, toolchains = { 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' }, big_endian = false } -} - --- List of board/CPU combinations -local board_list = -{ - [ 'SAM7-EX256' ] = { 'AT91SAM7X256', 'AT91SAM7X512' }, - [ 'EK-LM3S1968' ] = { 'LM3S1968' }, - [ 'EK-LM3S8962' ] = { 'LM3S8962' }, - [ 'EK-LM3S6965' ] = { 'LM3S6965' }, - [ 'EK-LM3S9B92' ] = { 'LM3S9B92' }, - [ 'SOLDERCORE' ] = { 'LM3S9D92' }, - [ 'STR9-COMSTICK' ] = { 'STR912FAW44' }, - [ 'STR-E912' ] = { 'STR912FAW44' }, - [ 'PC' ] = { 'I386' }, - [ 'SIM' ] = { 'LINUX' }, - [ 'LPC-H2888' ] = { 'LPC2888' }, - [ 'MOD711' ] = { 'STR711FR2' }, - [ 'STM3210E-EVAL' ] = { 'STM32F103ZE' }, - [ 'ATEVK1100' ] = { 'AT32UC3A0512' }, - [ 'ATEVK1101' ] = { 'AT32UC3B0256' }, - [ 'ET-STM32' ] = { 'STM32F103RE' }, - [ 'EAGLE-100' ] = { 'LM3S6918' }, - [ 'ELUA-PUC' ] = { 'LPC2468' }, - [ 'MBED' ] = { 'LPC1768' }, - [ 'MIZAR32' ] = { 'AT32UC3A0256', 'AT32UC3A0512', 'AT32UC3A0128' }, - [ 'NETDUINO' ] = { 'AT91SAM7X512' }, - [ 'EK-LM3S9D92' ] = { 'LM3S9D92' } -} - --- Build the CPU list starting from the above list -local cpu_list = {} -for k, v in pairs( board_list ) do - local clist = v - for i = 1, #clist do - if not utils.array_element_index( cpu_list, clist[ i ] ) then - table.insert( cpu_list, clist[ i ] ) - end - end +-- Automatically build the list of available boards by scanning the board_base_dir directory +local board_flist = utils.linearize_array( utils.string_to_table( utils.get_files( board_base_dir, "%.lua$" ) ) ) +local board_list = {} +for k, v in pairs( board_flist ) do + local temp = utils.replace_extension( v, '' ) + temp = utils.string_to_table( temp, utils.dir_sep ) + temp = temp[ #temp ] -- now 'temp' contains the actual name of the board + if not utils.array_element_index( board_list, temp ) then board_list[ #board_list + 1 ] = temp end end builder:add_option( 'target', 'build "regular" float lua, 32 bit integer-only "lualong" or 64-bit integer only lua "lualonglong"', 'lua', { 'lua', 'lualong', 'lualonglong' } ) -builder:add_option( 'cpu', 'build for the specified CPU (board will be inferred, if possible)', 'auto', { cpu_list, 'auto' } ) builder:add_option( 'allocator', 'select memory allocator', 'auto', { 'newlib', 'multiple', 'simple', 'auto' } ) -builder:add_option( 'board', 'selects board for target (cpu will be inferred)', 'auto', { utils.table_keys( board_list ), 'auto' } ) -builder:add_option( 'toolchain', 'specifies toolchain to use (auto=search for usable toolchain)', 'auto', { utils.table_keys( toolchain_list ), 'auto' } ) +builder:add_option( 'board', 'selects board for target (cpu will be inferred)', nil, board_list ) +builder:add_option( 'toolchain', 'specifies toolchain to use (auto=search for usable toolchain)', 'auto', { bd.get_all_toolchains(), 'auto' } ) builder:add_option( 'optram', 'enables Lua Tiny RAM enhancements', true ) builder:add_option( 'boot', 'boot mode, standard will boot to shell, luarpc boots to an rpc server', 'standard', { 'standard' , 'luarpc' } ) builder:add_option( 'romfs', 'ROMFS compilation mode', 'verbatim', { 'verbatim' , 'compress', 'compile' } ) @@ -225,83 +116,111 @@ builder:set_build_mode( builder.BUILD_DIR_LINEARIZED ) comp = {} setmetatable( comp, { __index = function( t, key ) return builder:get_option( key ) end } ) --- Variants: board = --- cpu = --- board = cpu= -if comp.board == 'auto' and comp.cpu == 'auto' then - print "You must specify board, cpu, or both" +if not comp.board then + print "You must specify the board" os.exit( -1 ) -elseif comp.board ~= 'auto' and comp.cpu ~= 'auto' then - -- Check if the board, cpu pair is correct - if utils.array_element_index( board_list[ comp.board:upper() ], comp.cpu:upper() ) == nil then - print( sf( "Invalid CPU '%s' for board '%s'" , comp.cpu, comp.board ) ) - os.exit( -1 ) - end -elseif comp.board ~= 'auto' then - -- Find CPU - comp.cpu = board_list[ comp.board:upper() ][ 1 ] -else - -- cpu = - -- Find board name - for b, v in pairs( board_list ) do - if utils.array_element_index( v, comp.cpu:upper() ) then - comp.board = b - break - end - end - if comp.board == 'auto' then - print( sf( "CPU '%s' not found", comp.cpu ) ) - os.exit( -1 ) - end end --- Look for the given CPU in the list of platforms -for p, v in pairs( platform_list ) do - if utils.array_element_index( v.cpus, comp.cpu:upper() ) then - platform = p - break +-- Interpret the board definition file +local bfname = get_conf_file_path( comp.board ) +if not bfname then + io.write( utils.col_red( sf( "[CONFIG] Error: board configuration file for board '%s' not found in '%s'.", comp.board, board_base_dir ) ) ) + os.exit( -1 ) +end +print( utils.col_blue( "[CONFIG] Found board description file at " .. bfname ) ) +local bdata, err = bconf.compile_board( bfname, comp.board ) +if not bdata then + print( utils.col_red( "[CONFIG] Error compiling board description file: " .. err ) ) + do return end +end +-- Check if the file has changed. If not, do not rewrite it. This keeps the compilation time sane. +local bhname = utils.concat_path( { board_base_dir, "headers", "board_" .. comp.board:lower() .. ".h" } ) +if utils.get_hash_of_string( bdata.header ) ~= utils.get_hash_of_file( bhname ) or not utils.is_file( bhname ) then + -- Save the header file + local f = assert( io.open( bhname, "wb" ) ) + f:write( bdata.header ) + f:close() + print( utils.col_blue( "[CONFIG] Generated board header file at " .. bhname ) ) +else + print( utils.col_blue( "[CONFIG] Board header file is unchanged." ) ) +end +-- Define the correct CPU header for inclusion in the platform_conf.h file +addm( 'ELUA_CPU_HEADER="\\"cpu_' .. bdata.cpu:lower() .. '.h\\""' ) +-- Define the correct board header for inclusion in the platform_conf.h file +addm( 'ELUA_BOARD_HEADER="\\"board_' .. comp.board:lower() .. '.h\\""' ) +-- Make available the board directory for the generated header files +addi( utils.concat_path{ board_base_dir, "headers" } ) +-- Force target if needed +if bdata.target and bdata.target ~= comp.target then + if builder:is_user_option( 'target' ) then + print( utils.col_yellow( sf( "[CONFIG] WARNING: changing the target from '%s' to '%s' as specified in the command line", bdata.target, comp.target ) ) ) + else + comp.target = bdata.target end end +-- Force allocator if needed +if bdata.allocator then + if comp.allocator == "auto" then + comp.allocator = bdata.allocator + elseif bdata.allocator ~= comp.allocator then + if builder:is_user_option( 'allocator' ) then + print( utils.col_yellow( sf( "[CONFIG] WARNING: changing the allocator from '%s' to '%s' as specified in the command line", bdata.allocator, comp.allocator ) ) ) + else + comp.allocator = bdata.allocator + end + end +end +-- Automatically set the allocator to 'multiple' if needed +if bdata.multi_alloc and comp.allocator == "newlib" then + io.write( utils.col_yellow( "[CONFIG] WARNING: your board has non-contigous RAM areas, but you specified an allocator ('newlib') that can't handle this configuration." ) ) + print( utils.col_yellow( "Rebuild with another allocator ('multiple' or 'simple')" ) ) +end +if comp.allocator == "auto" and bdata.multi_alloc then comp.allocator = "multiple" end +comp.cpu = bdata.cpu:upper() + +platform = bd.get_platform_of_cpu( comp.cpu ) if not platform then print( "Unable to find platform (this shouldn't happen, check the build script for errors)" ) os.exit( -1 ) end -- Check the toolchain +local usable_chains = bd.get_toolchains_of_platform( platform ) if comp.toolchain ~= 'auto' then - if utils.array_element_index( platform_list[ platform ].toolchains, comp.toolchain ) == nil then + if utils.array_element_index( usable_chains, comp.toolchain ) == nil then print( sf( "Invalid toolchain '%s' for CPU '%s'", comp.toolchain, comp.cpu ) ) + print( sf( "List of accepted toolchains (for %s): %s", comp.cpu, table.concat( usable_chains, "," ) ) ) os.exit( -1 ) end - toolset = toolchain_list[ comp.toolchain ] + toolset = bd.get_toolchain_data( comp.toolchain ) comp.CC = toolset.compile comp.AS = toolset.compile else -- If 'auto' try to match a working toolchain with target - local usable_chains = platform_list[ platform ].toolchains -- Try to execute all compilers, exit when one found local chain for i = 1, #usable_chains do local c = usable_chains[ i ] - local t = toolchain_list[ c ] + local t = bd.get_toolchain_data( c ) local res = utils.check_command( t.compile .. " " .. t.version ) if res == 0 then chain = c break end end if chain then comp.toolchain = chain - comp.CC = toolchain_list[ chain ].compile + toolset = bd.get_toolchain_data( chain ) + comp.CC = toolset.compile comp.AS = comp.CC - toolset = toolchain_list[ chain ] else print "Unable to find an usable toolchain in your path." - print( sf( "List of accepted toolchains (for %s): %s", comp.cpu, table.concat( usable_chains ) ) ) + print( sf( "List of accepted toolchains (for %s): %s", comp.cpu, table.concat( usable_chains, "," ) ) ) os.exit( -1 ) end end -- CPU/allocator mapping (if allocator not specified) +-- TODO: this needs to go away too, since the allocator is now automatically inferred if comp.allocator == 'auto' then - if comp.board:upper() == 'MIZAR32' and comp.cpu:upper() == 'AT32UC3A0128' then + if comp.board:upper() == 'MIZAR32' or comp.cpu:upper() == 'AT32UC3A0128' then comp.allocator = 'simple' elseif utils.array_element_index( { 'LPC-H2888', 'ATEVK1100', 'MIZAR32', 'MBED' }, comp.board:upper() ) then comp.allocator = 'multiple' @@ -314,7 +233,7 @@ end local fscompcmd = '' if comp.romfs == 'compile' then if comp.target == 'lualonglong' then - print "Cross-compilation is not yet supported for 64-bit integer only Lua (lualonglong)." + print "Cross-compilation is not yet supported for 64-bit integer-only Lua (lualonglong)." os.exit( -1 ) end local suffix = '' @@ -341,18 +260,19 @@ if utils.check_command('git describe --always') == 0 then if string.find(elua_vers, "^[+-]?%x+$") then elua_vers = 'dev-' .. elua_vers end - utils.gen_header('git_version',{elua_version=elua_vers, elua_str_version=("\"" .. elua_vers .. "\"")}) + local sver = utils.gen_header_string( 'git_version', { elua_version = elua_vers, elua_str_version = ("\"" .. elua_vers .. "\"" ) } ) + if utils.get_hash_of_string( sver ) ~= utils.get_hash_of_file( utils.concat_path{ 'inc', 'git_version.h' } ) then + utils.gen_header_file( 'git_version', { elua_version = elua_vers, elua_str_version = ("\"" .. elua_vers .. "\"" ) } ) + end else print "WARNING: unable to determine version from repository" elua_vers = "unknown" end - -- Output file -output = 'elua_' .. comp.target .. '_' .. comp.cpu:lower() +output = 'elua_' .. comp.target .. '_' .. comp.board:lower() builder:set_output_dir( ".build" .. utils.dir_sep .. comp.board:lower() ) - -- User report print "" print "*********************************" @@ -389,9 +309,9 @@ if comp.boot == 'luarpc' then addm( "ELUA_BOOT_RPC" ) end if comp.target == 'lualong' or comp.target == 'lualonglong' then addm( "LUA_NUMBER_INTEGRAL" ) end if comp.target == 'lualonglong' then addm( "LUA_INTEGRAL_LONGLONG" ) end if comp.target ~= 'lualong' and comp.target ~= "lualonglong" then addm( "LUA_PACK_VALUE" ) end -if platform_list[ platform ].big_endian then addm( "ELUA_ENDIAN_BIG" ) else addm( "ELUA_ENDIAN_LITTLE" ) end +if bd.get_endianness_of_platform( platform ) == "big" then addm( "ELUA_ENDIAN_BIG" ) else addm( "ELUA_ENDIAN_LITTLE" ) end --- Special macro definitions for the SYM target +-- Special macro definitions for the SIM target if platform == 'sim' then addm( { "ELUA_SIMULATOR", "ELUA_SIM_" .. cnorm( comp.cpu ) } ) end -- Lua source files and include path @@ -430,11 +350,11 @@ romfs_exclude_patterns = { '%.DS_Store', '%.gitignore' } function match_pattern_list( item, list ) for k, v in pairs( list ) do - if item:find(v) then return true end + if item:find(v) then return true end end end -local function make_romfs() +local function make_romfs( target, deps ) print "Building ROM file system ..." local flist = {} flist = utils.string_to_table( utils.get_files( 'romfs', function( fname ) return not match_pattern_list( fname, romfs_exclude_patterns ) end ) ) @@ -491,11 +411,13 @@ builder:set_link_cmd( linkcmd ) builder:set_asm_cmd( ascmd ) builder:set_exe_extension( ".elf" ) --- Create the ROM file system -make_romfs() --- Creaate executable targets +-- Create the ROMFS target +local romfs_target = builder:target( "#phony:romfs", nil, make_romfs ) +romfs_target:force_rebuild( true ) + +-- Create executable targets odeps = builder:create_compile_targets( source_files ) -exetarget = builder:link_target( output, odeps ) +exetarget = builder:link_target( output, { romfs_target, odeps } ) -- This is also the default target builder:default( builder:add_target( exetarget, 'build eLua executable' ) ) diff --git a/config/attributes.lua b/config/attributes.lua new file mode 100644 index 00000000..3b6c2700 --- /dev/null +++ b/config/attributes.lua @@ -0,0 +1,182 @@ +-- 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, elname, sectname ) + aval = tostring( 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 element '%s' in section '%s'", aval, aname, elname, sectname ) +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, elname, sectname ) + aval = tonumber( aval ) + if not aval then return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be a number", aname, elname, sectname ) end + if adesc.attrtype == 'int' and math.floor( aval ) ~= aval then + return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be an integer", aname, elname, sectname ) + 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 element '%s' in section '%s' must be larger than '%s'", aname, elname, sectname, tostring( minval ) ) + end + if aval > maxval then + return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be smaller than '%s'", aname, elname, sectname, 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, elname, sectname ) + local res, err = _validate_number( adesc, aname, aval, elname, sectname ) + if not res then return res, err end + if aval <= 0 then + return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be larger than 0", aname, elname, sectname ) + end + local thelog = math.log( res ) / math.log( 2 ) + if thelog ~= math.floor( thelog ) then + return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be a power of 2", aname, elname, sectname ) + 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, elname, sectname ) + aval = tostring( aval ) + if type( aval ) ~= "string" then + return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be a string", aname, elname, sectname ) + end + maxsize = adesc.attrmaxsize or math.huge + if #aval > maxsize then + return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be less than %d chars in length", aname, elname, sectname, maxsize ) + end + return aval +end + +-- Validator for an IP attribute +-- Return the IP as a table of numbers if OK, (false, errmsg) for error +local function _validate_ip( adesc, aname, aval, elname, sectname ) + if type( aval ) == "string" then -- transform this to table + if aval:sub( -1, -1 ) ~= "." then aval = aval .. "." end -- add a final dot to make parsing easier + local t = {} + for w in aval:gmatch( "(%w+)%." ) do t[ #t + 1 ] = tonumber( w ) end + aval = t + elseif type( aval ) ~= "table" then + return false, sf( "attribute '%s' of element '%s' in section '%s' must be a string or a table", aname, elname, sectname ) + end + if #aval ~= 4 then return false, sf( "invalid IP for attribute '%s' of element '%s' in section '%s'", aname, elname, sectname ) end + for i = 1, 4 do + local e = aval[ i ] + if type( e ) ~= "number" or math.floor( e ) ~= e or e < 0 or e > 255 then + return false, sf( "invalid IP for attribute '%s' of element '%s' in section '%s'", aname, elname, sectname ) + end + end + return aval +end + +-- Builds a validator with the given array element checker +local function build_validator( realvname ) + return function( adesc, aname, aval, elname, sectname ) + if not adesc.is_array then return realvname( adesc, aname, aval, elname, sectname ) end + if type( aval ) ~= "table" then return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be an array", aname, elname, sectname ) end + for i = 1, #aval do + local res, err = realvname( adesc, aname, aval[ i ], elname, sectname ) + if not res then + return false, sf( "error at index %d: %s", i, err ) + else + aval[ i ] = res + end + end + return aval + end +end + +local validate_number = build_validator( _validate_number ) +local validate_choice = build_validator( _validate_choice ) +local validate_log2 = build_validator( _validate_log2 ) +local validate_string = build_validator( _validate_string ) +local validate_ip = build_validator( _validate_ip ) + +------------------------------------------------------------------------------- +-- Public interface + +-- 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 timer attribute with the given macro and default (systmr if not specified) +function timer_attr( macro, default ) + default = default or 'systmr' + local t = choice_attr( macro, utils.table_keys( ct.timer_values ), default ) + t.is_timer, t.mapping = true, ct.timer_values + return t +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 UART attribute +function uart_attr( macro, default ) + local t = choice_attr( macro, utils.table_keys( ct.uart_values ), default ) + t.is_uart, t.mapping = true, ct.uart_values + return t +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 flow control attribute +function flow_control_attr( macro, default ) + default = default or 'none' + local t = choice_attr( macro, utils.table_keys( ct.uart_flow ), default ) + t.mapping = ct.uart_flow + return t +end + +-- Returns a new string attribute +function string_attr( macro, maxsize, default ) + return { macro = macro, default = default, validator = validate_string, attrmaxsize = maxsize } +end + +-- Returns a new IP attribute +function ip_attr( macro, default ) + return { macro = macro, default = default, validator = validate_ip, is_ip = true } +end + +-- Make the given attribute optional +function make_optional( attr ) + attr.optional = true + return attr +end + +-- Mark the given attribute as an array of element of the same type +function array_of( attr ) + attr.is_array = true + return attr +end + + diff --git a/config/components.lua b/config/components.lua new file mode 100644 index 00000000..c95b73c9 --- /dev/null +++ b/config/components.lua @@ -0,0 +1,166 @@ +-- eLua components description + +module( ..., package.seeall ) +local at = require "attributes" +local gen = require "generators" +local sf = string.format + +------------------------------------------------------------------------------- +-- Sermux support + +local function sermux_auxcheck( eldesc, data, enabled ) + local v = data.SERMUX_BUFFER_SIZES.value + if #v < 2 then + return false, sf( "array 'buf_sizes' of element 'sermux' in section 'components' must have at least 2 elements" ) + end + return true +end + +local function sermux_auxgen( eldesc, data, generated ) + local v = data.SERMUX_BUFFER_SIZES.value + return gen.print_define( 'SERMUX_NUM_VUART', #v ) +end + +------------------------------------------------------------------------------- +-- Public interface + +-- Build all components needed by eLua, save them in the "components" table +function init() + local components = {} + + -- Serial console + components.sercon = { + macro = 'BUILD_CON_GENERIC', + attrs = { + uart = at.uart_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' ), + buf_size = at.make_optional( at.int_log2_attr( 'CON_BUF_SIZE' ) ) + } + } + -- TCP/IP console + components.tcpipcon = { macro = 'BUILD_CON_TCP', needs = 'tcpip' } + -- UART buffering + -- Not really a component, not quite a config ... Implementation wise, + -- it is easier to declare it as a component + components.uart_buffers = { macro = 'BUF_ENABLE_UART' } + -- XMODEM + components.xmodem = { + macro = 'BUILD_XMODEM', + attrs = { + uart = at.uart_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'), + buf_size = at.make_optional( at.int_log2_attr( 'CON_BUF_SIZE' ) ) + } + } + -- Shell + components.shell = { macro = 'BUILD_SHELL' } + -- Term + components.term = { + macro = 'BUILD_TERM', + attrs = { + uart = at.uart_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' ), + buf_size = at.make_optional( at.int_log2_attr( 'CON_BUF_SIZE' ) ), + 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, 5 ) + }, + needs = 'cints' + } + -- 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.uart_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', nil, nil, 9 ), + timeout = at.int_attr( 'RFS_TIMEOUT', nil, nil, 100000 ) + } + } + -- MMCFS + components.mmcfs = { + macro = 'BUILD_MMCFS', + attrs = { + cs_port = at.int_attr( 'MMCFS_CS_PORT' ), + cs_pin = at.int_attr( 'MMCFS_CS_PIN' ), + spi = at.int_attr( 'MMCFS_SPI_NUM' ) + } + } + -- RPC + -- (values are optional, since they are required only if booting in RPC mode) + components.rpc = { + macro = 'BUILD_RPC', + attrs = { + uart = at.make_optional( at.uart_attr( 'RPC_UART_ID' ) ), + speed = at.make_optional( at.int_attr( 'RPC_UART_SPEED' ) ), + timer = at.make_optional( at.timer_attr( 'RPC_TIMER_ID' ) ) + } + } + -- TCP/IP + components.tcpip = { + macro = 'BUILD_UIP', + attrs = { + ip = at.ip_attr( 'ELUA_CONF_IPADDR' ), + netmask = at.ip_attr( 'ELUA_CONF_NETMASK' ), + gw = at.ip_attr( 'ELUA_CONF_DEFGW' ), + dns = at.ip_attr( 'ELUA_CONF_DNS' ) + } + } + -- Serial multiplexer + components.sermux = { + macro = 'BUILD_SERMUX', + auxgen = sermux_auxgen, + auxcheck = sermux_auxcheck, + attrs = { + uart = at.uart_attr( 'SERMUX_PHYS_ID' ), + speed = at.int_attr( 'SERMUX_PHYS_SPEED' ), + flow = at.flow_control_attr( 'SERMUX_FLOW_TYPE' ), + buf_sizes = at.array_of( at.int_log2_attr( 'SERMUX_BUFFER_SIZES' ) ) + } + } + -- ADC + components.adc = { + macro = 'BUILD_ADC', + attrs = { + buf_size = at.make_optional( at.int_log2_attr( 'ADC_BUF_SIZE' ) ), + first_timer = at.make_optional( at.int_attr( 'ADC_TIMER_FIRST_ID' ) ), + num_timers = at.make_optional( at.int_attr( 'ADC_NUM_TIMERS' ) ) + } + } + -- DNS client + components.dns = { macro = 'BUILD_DNS', needs = 'tcpip' } + -- DHCP client + components.dhcp = { macro = 'BUILD_DHCPC', needs = 'tcpip' } + -- ROMFS + components.romfs = { macro = 'BUILD_ROMFS' } + -- WOFS + components.wofs = { macro = "BUILD_WOFS" } + -- All done + return components +end + diff --git a/config/config.lua b/config/config.lua new file mode 100644 index 00000000..0d5bb79c --- /dev/null +++ b/config/config.lua @@ -0,0 +1,304 @@ +-- Generate a C configuration starting from a Lua description file +-- for an eLua board + +module( ..., package.seeall ) + +package.path = package.path .. ";utils/?.lua;config/?.lua" + +local comps = require "components" +local cfgs = require "configurations" +local gen = require "generators" +local utils = require "utils" +local bd = require "build_data" +local mgen = require "modules" +local cpuct = require "cpuconstants" +local sects = require "sections" + +local components, configs +local glconf, glen + +------------------------------------------------------------------------------- +-- Various helpers and internal functions + +-- Generator for section 'components' +local function generate_components( data, plconf ) + local compdata = data.components or {} + + -- Prerequisites: check for keys that might be needed in components, but might not be there + -- At the moment, we need to definer either BUILD_CON_GENERIC or BUILD_CON_TCP (but not both) + if compdata.sercon and compdata.tcpipcon then + return nil, "serial and TCP/IP console can't be enabled at the same time in section 'components'" + elseif not compdata.sercon and not compdata.tcpipcon then + return nil, "either serial (sercon) or TCP/IP (tcpipcon) console must be enabled in 'components'" + end + + -- Configure section first + local res, err = sects.configure_section( components, 'components', compdata ) + if not res then return false, err end + -- Let the backend do its validation + if plconf.pre_generate_section then + res, err = plconf.pre_generate_section( components, 'components', compdata, conf, enabled ) + if not res then return false, err end + end + + -- Generate all data for section 'components' + return sects.generate_section( components, 'components', compdata ) +end + +-- Generator for section 'config' +local function generate_config( data, plconf ) + local confdata = data.config or {} + + -- Configure section first + local res, err = sects.configure_section( configs, 'config', confdata ) + if not res then return false, err end + -- Let the backend do its validation + if plconf.pre_generate_section then + res, err = plconf.pre_generate_section( configs, 'config', confdata, conf, enabled ) + if not res then return false, err end + end + + return sects.generate_section( configs, 'config', confdata ) +end + +-- Global sanity checks (data is in 'glconf' and 'glen' +local function check_components_and_config() + -- Check all uart IDs. If VUARTs are specified but sermux is not enabled, return with error + if not glen.sermux then + for _, attrdata in pairs( glconf ) do + local attrval = attrdata.value + if attrdata.desc.is_uart and type( attrval ) == "string" and attrval:find( "^vuart" ) then + return false, sf( "attribute '%s' of element '%s' in section '%s' reffers to a virtual UART, but the serial multiplexer ('sermux') is not enabled", + attrdata.name, attrdata.elname, attrdata.sectname ) + end + end + end + + -- Check all timer IDs. If virtual timers are specified but vtmr is not enabled, return with error + if not glen.vtmr or tostring( glconf.VTMR_NUM_TIMERS.value ) == "0" then + for _, attrdata in pairs( glconf ) do + local attrval = attrdata.value + if attrdata.desc.is_timer and type( attrval ) == "string" and attrval:find( "^vtmr" ) then + return false, sf( "attribute '%s' of element '%s' in section '%s' reffers to a virtual timer, but virtual timers ('vtmr') are not enabled", + attrdata.name, attrdata.elname, attrdata.sectname ) + end + end + end + + -- Check sermux/RFS+console proper UART assignment + if glen.sermux and glen.sercon and glen.rfs then + local rfs_uart_value = tostring( glconf.RFS_UART_ID.value ) + local con_uart_value = tostring( glconf.CON_UART_ID.value ) + if rfs_uart_value:find( "^vuart" ) and rfs_uart_value ~= "vuart0" then + io.write( utils.col_yellow( "[CONFIG] WARNING: you have enabled the serial multiplexer and RFS over a virtual serial port which is not the first virtual serial port ('vuart0')" ) ) + print( utils.col_yellow( "In this configuration, the serial multiplexer will not work in 'rfsmux' mode. Check the serial multiplexer section of the eLua manual for more details." ) ) + elseif rfs_uart_value == "vuart0" and con_uart_value:find( "^vuart" ) and con_uart_value ~= "vuart1" then + io.write( utils.col_yellow( "[CONFIG] WARNING: when using both RFS and the serial console with 'sermux', it's best to set the serial console uart ID to the second virtual serial port ('vuart1')" ) ) + print( utils.col_yellow( "In this configuration, the serial multiplexer will work directly in 'rfsmux' mode with a console. Check the serial multiplexer section of the eLua manual for more details." ) ) + end + end + + return true +end + +-- Default table for backend configuration data +-- If the platform doesn't have a boardconf.lua, this is what we're going to use +local default_platform_conf = { + add_platform_components = function() end, + add_platform_configs = function() end, + get_platform_modules = function() end, + pre_generate_section = function() return true end, +} + +-- Sanity code +-- These are more checks added to the generated header file +-- Some of these are the result of pure paranoia. Nevertheless, they seem to work. + +local sanity_code = [[ +/////////////////////////////////////////////////////////////////////////////// +// Static sanity checks and additional defines + +#if defined( ELUA_BOOT_RPC ) && !defined( BUILD_RPC ) +#define BUILD_RPC +#endif + +#if defined( BUILD_LUA_INT_HANDLERS ) || defined( BUILD_C_INT_HANDLERS ) + #define BUILD_INT_HANDLERS + + #ifndef INT_TMR_MATCH + #define INT_TMR_MATCH ELUA_INT_INVALID_INTERRUPT + #endif +#endif // #if defined( BUILD_LUA_INT_HANDLERS ) || defined( BUILD_C_INT_HANDLERS ) + +#ifndef VTMR_NUM_TIMERS +#define VTMR_NUM_TIMERS 0 +#endif // #ifndef VTMR_NUM_TIMERS + +#ifndef SERMUX_FLOW_TYPE +#define SERMUX_FLOW_TYPE PLATFORM_UART_FLOW_NONE +#endif + +#ifndef CON_FLOW_TYPE +#define CON_FLOW_TYPE PLATFORM_UART_FLOW_NONE +#endif + +#ifndef CON_TIMER_ID +#define CON_TIMER_ID PLATFORM_TIMER_SYS_ID +#endif + +#ifdef ELUA_BOOT_RPC + #ifndef RPC_UART_ID + #define RPC_UART_ID CON_UART_ID + #endif + + #ifndef RPC_TIMER_ID + #define RPC_TIMER_ID PLATFORM_TIMER_SYS_ID + #endif + + #ifndef RPC_UART_SPEED + #define RPC_UART_SPEED CON_UART_SPEED + #endif +#endif // #ifdef ELUA_BOOT_RPC + +#if ( defined( BUILD_RFS ) || defined( BUILD_SERMUX ) || defined( CON_BUF_SIZE ) ) && !defined( BUF_ENABLE_UART ) +#define BUF_ENABLE_UART +#endif + +#if defined( ADC_BUF_SIZE ) && !defined( BUF_ENABLE_ADC ) +#define BUF_ENABLE_ADC +#endif + +#ifndef CPU_FREQUENCY +#define CPU_FREQUENCY 0 +#endif + +]] + +------------------------------------------------------------------------------- +-- Public interface + +-- This code is executed an initialization time (the first 'require') +components = comps.init() +configs = cfgs.init() + +-- Read the Lua description file of a board and return the corresponding header file +-- as a string or (false, error) if an error occured +function compile_board( fname, boardname ) + local cboardname = boardname:upper():gsub( "[%-%.%s]", "_" ) + local header = sf([[ +// Lua board configuration file, automatically generated + +#ifndef __GENERATED_%s_H__ +#define __GENERATED_%s_H__ + +]], cboardname, cboardname ) + local desc, err = dofile( fname ) + if not desc then return false, err end + if not desc.cpu then return false, "cpu not specified in board configuration file" end + + -- Check the keys in 'desc' + local known_keys = { 'cpu', 'components', 'config', 'headers', 'macros', 'modules', 'cpu_constants', 'allocator', 'target' } + for k, _ in pairs( desc ) do + if not utils.array_element_index( known_keys, k ) then return false, sf( "unknown key '%s'", k ) end + end + + -- Check CPU + local cpulist = bd.get_all_cpus() + if not utils.array_element_index( cpulist, desc.cpu:upper() ) then + return false, sf( "unknown cpu '%s'", desc.cpu ) + end + + -- Find and require the platform board configuration file + local platform = bd.get_platform_of_cpu( desc.cpu ) + if not platform then return false, sf( "unable to find the platform of cpu '%s'", desc.cpu ) end + local plconf = default_platform_conf + if utils.is_file( utils.concat_path{ 'src', 'platform', platform, 'build_config.lua' } ) then + plconf = require( "src.platform." .. platform .. ".build_config" ) + print( utils.col_blue( sf( "[CONFIG] Found a backend build configuration file for platform %s", platform ) ) ) + end + + -- Read platform specific components/configs + plconf.add_platform_components( components ) + plconf.add_platform_configs( configs ) + + -- Do we need to include any configured headers? + if type( desc.headers ) == "table" and #desc.headers > 0 then + for _, h in pairs( desc.headers ) do + header = header .. "#include " .. h .. "\n" + end + header = header .. "\n" + end + + -- Do we need to add definitions for any configured macros? + if type( desc.macros ) == "table" and #desc.macros > 0 then + for _, m in pairs( desc.macros ) do + if type( m ) == "string" then -- #define m + header = header .. gen.print_define( m ) + elseif type( m ) == "table" then -- { macro, value } -> #define macro value + header = header .. gen.print_define( m[ 1 ], m[ 2 ] ) + end + end + header = header .. "\n" + end + + -- Generate components first + local gen, err = generate_components( desc, plconf ) + if not gen then return false, err end + header = header .. gen + -- Keep generated data for later use + glconf, glen = sects.conf, sects.enabled + + -- Then configs + gen, err = generate_config( desc, plconf ) + local multi_alloc = cfgs.needs_multiple_allocator() + if not gen then return false, err end + header = header .. gen + -- Accumulate generated data into 'glconf' and 'glen' + utils.concat_tables( glconf, sects.conf ) + utils.concat_tables( glen, sects.enabled ) + + -- Now we have all components and the configuration generated + -- It's a good time for some sanity checks + gen, err = check_components_and_config() + if not gen then return false, err end + + -- Now it's a good time to include the fixed sanity checks + header = header .. sanity_code + + -- Generate module configuration + gen, err = mgen.gen_module_list( desc, plconf, platform ) + if not gen then return false, err end + header = header .. gen + + -- Generate additional CPU constants + gen, err = cpuct.gen_constants( desc ) + if not gen then return false, err end + header = header .. gen + + -- All done, write the header's footer + header = header .. sf( "#endif // #ifndef __GENERATED_%s_H__\n", cboardname ) + + -- We are done with the header, we still need to check the compile flags + local allocator + if desc.allocator then + local allocs = { 'newlib', 'multiple', 'simple' } + if not utils.array_element_index( allocs, desc.allocator ) then + return false, sf( "unknown allocator '%s'", desc.allocator ) + end + allocator = desc.allocator + end + + local target + if desc.target then + local targets = { 'lua', 'lualong', 'lualonglong' } + if not utils.array_element_index( targets, desc.target ) then + return false, sf( "unknown target '%ws'", desc.target ) + end + target = desc.target + end + + -- Return the contents of the header, as well as the name of the CPU used by this + -- board (this information is needed by the builder) and the build information + return { header = header, cpu = desc.cpu, multi_alloc = multi_alloc, allocator = allocator, target = target } +end + diff --git a/config/configurations.lua b/config/configurations.lua new file mode 100644 index 00000000..711cd6b9 --- /dev/null +++ b/config/configurations.lua @@ -0,0 +1,166 @@ +-- 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 mem_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 + if not startvals and not sizevals then return true end + if not startvals then + return false, "attribute 'start' must also be specified for element 'extmem' of section 'config'" + elseif not sizevals then + return false, "attribute 'size' must also be specified for element 'extmem' of section 'config'" + end + if #startvals == 0 then + return false, "attribute 'start' of element 'extmem' in section 'config' must have at least one element" + elseif #sizevals == 0 then + return false, "attribute 'size' of element 'extmem' in section 'config' must have at least one element" + end + if #startvals ~= #sizevals then + return false, "attributes 'start' and 'size' of element 'extmem' 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_RAM_FIRST_FREE and INTERNAL_RAM_LAST_FREE +-- exist (they should come from .h) +local function mem_generator( desc, vals, generated ) + if not vals.MEM_START_ADDRESS and not vals.MEM_END_ADDRESS then + -- Generate configuration only for the internal memory + local gstr = gen.print_define( "MEM_START_ADDRESS", "{ ( u32 )( INTERNAL_RAM_FIRST_FREE ) }" ) + gstr = gstr .. gen.print_define( "MEM_END_ADDRESS", "{ ( u32 )( INTERNAL_RAM_LAST_FREE ) }" ) + generated.MEM_START_ADDRESS = true + generated.MEM_END_ADDRESS = true + return gstr + end + local startvals = vals.MEM_START_ADDRESS.value + local sizevals = vals.MEM_END_ADDRESS.value + table.insert( startvals, 1, "INTERNAL_RAM_FIRST_FREE" ) + table.insert( sizevals, 1, "INTERNAL_RAM_LAST_FREE" ) + -- Transform the data in 'sizevals' to 'last address' (the format accepted by eLua) + for i = 2, #sizevals do + sizevals[ i ] = tonumber( startvals[ i ] ) + tonumber( sizevals[ i ] ) - 1 + end + -- Prefix all the values in the 'start' and 'size' arrays with 'u32' + for i = 1, #sizevals do + startvals[ i ] = "( u32 )( " .. tostring( startvals[ i ] ) .. ( i > 1 and "u" or "" ) .. " )" + sizevals[ i ] = "( u32 )( " .. tostring( sizevals[ i ] ) .. ( i > 1 and "u" or "" ) .. " )" + end + local gstr = gen.simple_gen( "MEM_START_ADDRESS", vals, generated ) + gstr = gstr .. gen.simple_gen( "MEM_END_ADDRESS", vals, generated ) + use_multiple_allocator = #startvals > 1 + 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 ) ) + }, + } + + -- Memory configuration generator + configs.extmem = { + gen = mem_generator, + confcheck = mem_checker, + attrs = { + start = at.array_of( at.int_attr( 'MEM_START_ADDRESS' ) ), + size = at.array_of( at.int_attr( 'MEM_END_ADDRESS', 1 ) ) + }, + required = {} + } + + -- 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 + diff --git a/config/constants.lua b/config/constants.lua new file mode 100644 index 00000000..fb461d4e --- /dev/null +++ b/config/constants.lua @@ -0,0 +1,50 @@ +-- Various constants used by the build descriptor + +module( ..., package.seeall ) +local sf = string.format + +------------------------------------------------------------------------------- +-- UART data + +-- UART flow types +uart_flow = +{ + none = 'PLATFORM_UART_FLOW_NONE', + rts = 'PLATFORM_UART_FLOW_RTS', + cts = 'PLATFORM_UART_FLOW_CTS', + rtscts = '( PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS )' +} + +uart_values = {} + +-- Add a sufficient number of virtual and real UARTs +for i = 0, 127 do + uart_values[ sf( 'vuart%d', i ) ] = sf( '( SERMUX_SERVICE_ID_FIRST + %d )', i ) + uart_values[ tostring( i ) ] = i +end + +------------------------------------------------------------------------------- +-- Timer data + +-- System timer ID +timer_values = +{ + systmr = 'PLATFORM_TIMER_SYS_ID' +} + +-- Add a sufficient number of virtual timers +for i = 0, 127 do + timer_values[ sf( 'vtmr%d', i ) ] = sf( '( VTMR_FIRST_ID + %d )', i ) + timer_values[ tostring( i ) ] = i +end + +------------------------------------------------------------------------------- +-- EGC data + +egc = +{ + alloc_failure = 1, + mem_limit = 2, + always = 4 +} + diff --git a/config/cpuconstants.lua b/config/cpuconstants.lua new file mode 100644 index 00000000..44176a66 --- /dev/null +++ b/config/cpuconstants.lua @@ -0,0 +1,31 @@ +-- CPU constants generator + +module( ..., package.seeall ) +local sf = string.format +local gen = require "generators" + +function gen_constants( desc ) + local ct = desc.cpu_constants + if not ct then return '' end + local gstr = string.rep( "/", 80 ) .. "\n" .. "// Configured CPU constants\n\n" + -- There are two types of macros in cpu_constants: simple (that are already defined somewhere) + -- and full ((macro, def) pairs). We need to iterate over the full list first and define those + -- macros. After that we generate the whole PLATFORM_CPU_CONSTANTS_CONFIGURED macro + for _, m in pairs( ct ) do + if type( m ) == "table" then + local name, val = m[ 1 ], m[ 2 ] + gstr = gstr .. "\n#ifndef " .. name .. "\n" + gstr = gstr .. gen.print_define( name, val ) + gstr = gstr .. "#endif\n\n" + end + end + + gstr = gstr .. "#define PLATFORM_CPU_CONSTANTS_CONFIGURED\\\n" + for _, m in pairs( ct ) do + gstr = gstr .. sf( " _C( %s ),\\\n", type( m ) == "string" and m or m[ 1 ] ) + end + + gstr = gstr .. "\n" + return gstr:gsub( "\n\n\n", "\n\n" ) +end + diff --git a/config/generators.lua b/config/generators.lua new file mode 100644 index 00000000..bee2af7b --- /dev/null +++ b/config/generators.lua @@ -0,0 +1,40 @@ +-- 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 ) + local s = sf( "#define %s", k ) + if v then + if #s < MACRO_DEF_POS then s = s .. string.rep( ' ', MACRO_DEF_POS - #s ) end + else + v = '' + end + s = s .. tostring( 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 + if adesc.is_ip then -- special generation for this one + local s = '' + for i = 1, 4 do + s = s .. print_define( sf( "%s%d", attrname, i - 1 ), aval[ i ] ) + end + return s + end + if adesc.mapping then aval = adesc.mapping[ aval ] end + if adesc.is_array then + -- The element is an array. The default is to define its value as { elements } + aval = "{ " .. table.concat( aval, "," ) .. " }" + end + return print_define( attrname, tostring( aval ) ) +end + diff --git a/config/modules.lua b/config/modules.lua new file mode 100644 index 00000000..a2f72329 --- /dev/null +++ b/config/modules.lua @@ -0,0 +1,194 @@ +-- Build configuration: module selection + +module( ..., package.seeall ) +local sf = string.format +local gen = require "generators" + +-- List of all generic modules and their build guards +-- (if the module guard evaluates to false at compile time, the module is not included in the build) +local generic_modules = { + adc = { "BUILD_ADC", "NUM_ADC > 0" }, + bit = {}, + can = { "NUM_CAN > 0"}, + cpu = {}, + elua = {}, + i2c = { "NUM_I2C > 0" }, + pack = {}, + rpc = { "BUILD_RPC" }, + net = { "BUILD_UIP" }, + pd = {}, + pio = { "NUM_PIO > 0" }, + pwm = { "NUM_PWM > 0" }, + spi = { "NUM_SPI > 0" }, + term = { "BUILD_TERM" }, + tmr = { "NUM_TIMER > 0" }, + uart = { "NUM_UART > 0" }, + math = {} +} + +-- Auxlib names +local auxlibs = { math = "LUA_MATHLIBNAME" } + +-- Open function names +local opennames = {} + +-- Map array names +local mapnames = {} + +-- Return the auxlib name of a given module +local function get_auxlib( m ) + return auxlibs[ m ] or sf( "AUXLIB_%s", m:upper() ) +end + +-- Return the open function name of a given module +local function get_openf_name( m ) + return opennames[ m ] or sf( "luaopen_%s", m:lower() ) +end + +-- Return the map array name of a given module +local function get_map_name( m ) + return mapnames[ m ] or sf( "%s_map", m:lower() ) +end + +-- Generate a condition string starting from a guard +local function gen_cond_string( g ) + local condition = '' + for idx, e in pairs( g ) do + local suffix = idx == #g and "" or " && " + if e:find( '%s' ) then -- if it has a string, add the condition as it was given, between parantheses + condition = condition .. "( " .. e .. " )" + else + condition = condition .. "defined( " .. e .. " )" + end + condition = condition .. suffix + end + return condition +end + +-- Generate the complete module list starting from the board description +function gen_module_list( desc, plconf, platform ) + local mdesc = desc.modules + if not mdesc then return '' end + local gen_list_generic, gen_list_platform = {}, {} + local platform_modules = plconf.get_platform_modules() or {} + local gstr = string.rep( "/", 80 ) .. "\n" .. "// Module configuration\n\n" + local ngenmods, nplmods = 0, 0 + + if mdesc == "all" then -- include all the modules. what a brave, brave soul. + for m, _ in pairs( generic_modules ) do + gen_list_generic[ m ] = true + ngenmods = ngenmods + 1 + end + for m, _ in pairs( platform_modules ) do + gen_list_platform[ m ] = true + nplmods = nplmods + 1 + end + else + -- Include only some modules. Validate their names against the corresponding module list + if mdesc.generic == "all" then -- all generic modules + for m, _ in pairs( generic_modules ) do + gen_list_generic[ m ] = true + ngenmods = ngenmods + 1 + end + elseif mdesc.generic then + for _, m in pairs( mdesc.generic ) do + if not generic_modules[ m ] then return false, sf( "unknown generic module '%s' in section 'modules'", m ) end + gen_list_generic[ m ] = true + ngenmods = ngenmods + 1 + end + end + if mdesc.platform == "all" then -- all platform modules + for m, _ in pairs( platform_modules ) do + gen_list_platform[ m ] = true + nplmods = nplmods + 1 + end + elseif mdesc.platform then + for _, m in pairs( mdesc.platform ) do + if not platform_modules[ m ] then return false, sf( "unknown platform module '%s' in section 'modules'", m ) end + gen_list_platform[ m ] = true + nplmods = nplmods + 1 + end + end + end + -- Need to exclude anything? + if type( mdesc.exclude_generic ) == "table" then + for _, m in pairs( mdesc.exclude_generic ) do + if not gen_list_generic[ m ] then + return false, sf( "module '%s' in exclude_generic not found in the generic module list", m ) + end + gen_list_generic[ m ] = nil + ngenmods = ngenmods - 1 + end + end + if type( mdesc.exclude_platform ) == "table" then + for _, m in pairs( mdesc.exclude_platform ) do + if not gen_list_platform[ m ] then + return false, sf( "module '%s' in exclude_platform not found in the platform specific module list", m ) + end + gen_list_platform[ m ] = nil + nplmods = nplmods - 1 + end + end + if ngenmods + nplmods == 0 then return '' end + + -- Now build all the module lines, starting from the gen_list and the guards + -- First define the platform specific line if needed + if nplmods > 0 then + -- The (hopefully) proper way to generate this is a bit tricky. We enable the + -- platform module if _any_ of the modules in gen_list_platform can be enabled. + -- In order to do this, we gather their guards in a single, long condition + -- Count all guards first + local nguards = 0 + for m, _ in pairs( gen_list_platform ) do nguards = nguards + #platform_modules[ m ] end + if nguards == 0 then -- nothing to guard + gstr = gstr .. gen.print_define( "PLATFORM_MODULES_LINE", sf( '_ROM( "%s", luaopen_platform, platform_map )', platform ) ) + gstr = gstr .. gen.print_define( "PS_LIB_TABLE_NAME", sf( '"%s"', platform ) ) + gstr = gstr .. gen.print_define( "PLATFORM_MODULES_ENABLE" ) + else + -- Gather the composed condition in 'cond' + local cond = '\n#if 0' -- the '0' is included here for an easier generation of the composed condition + for m, _ in pairs( gen_list_platform ) do + local g = platform_modules[ m ] + if #g > 0 then + cond = cond .. " || ( " .. gen_cond_string( g ) .. " )" + end + end + gstr = gstr .. cond .. "\n" + gstr = gstr .. gen.print_define( "PLATFORM_MODULES_LINE", sf( '_ROM( "%s", luaopen_platform, platform_map )', platform ) ) + gstr = gstr .. gen.print_define( "PS_LIB_TABLE_NAME", sf( '"%s"', platform ) ) + gstr = gstr .. gen.print_define( "PLATFORM_MODULES_ENABLE" ) + gstr = gstr .. "#else\n" + gstr = gstr .. gen.print_define( sf( "PLATFORM_MODULES_LINE" ) ) + gstr = gstr .. sf( "#warning Unable to include platform modules in the image\n#endif\n\n" ) + end + else -- no platform modules here, people. move along. + gstr = gstr .. gen.print_define( "PLATFORM_MODULES_LINE" ) + end + for m, _ in pairs( gen_list_generic ) do + local g = generic_modules[ m ] + if #g == 0 then -- no guards + gstr = gstr .. gen.print_define( sf( "MODULE_%s_LINE", m:upper() ), sf( "_ROM( %s, %s, %s )", get_auxlib( m ), get_openf_name( m ), get_map_name( m ) ) ) + else + -- Check the guard. If the guard is not satisfied, issue a compile time warning and set the line as empty + gstr = gstr .. "\n#if " .. gen_cond_string( g ) .. "\n" + gstr = gstr .. gen.print_define( sf( "MODULE_%s_LINE", m:upper() ), sf( "_ROM( %s, %s, %s )", get_auxlib( m ), get_openf_name( m ), get_map_name( m ) ) ) + gstr = gstr .. "#else\n" + gstr = gstr .. gen.print_define( sf( "MODULE_%s_LINE", m:upper() ) ) + gstr = gstr .. sf( "#warning Unable to include module '%s' in the image\n#endif\n\n", m ) + end + end + gstr = gstr .. "\n" + + -- Finally, generate the acutal list of libraries. Phew. + gstr = gstr .. "#define LUA_PLATFORM_LIBS_ROM\\\n PLATFORM_MODULES_LINE" + for m, _ in pairs( gen_list_generic ) do + gstr = gstr .. sf( "\\\n MODULE_%s_LINE", m:upper() ) + end + gstr = gstr .. "\n" + + -- A bit of cosmetic touch ... + gstr = gstr .. "\n" + gstr = gstr:gsub( "\n\n\n", "\n\n" ) + return gstr +end + diff --git a/config/sections.lua b/config/sections.lua new file mode 100644 index 00000000..1d90c3c9 --- /dev/null +++ b/config/sections.lua @@ -0,0 +1,174 @@ +-- Sections (collection of elements) management + +module( ..., package.seeall ) +local sf = string.format +local gen = require "generators" +local utils = require "utils" + +conf, enabled, required = {}, {}, {} + +-- Enables and configures an element (a collection of attributes) +-- section - the section of the element +-- sectname - the name of the section that contains the element (components, config ...) +-- name - name of the element +-- data - values of attributes in the element +-- req: required mode. true if this element's value are forced to its required values, false otherwise +-- Returns true if OK, (false, err) for error +function config_element( section, sectname, name, data, req ) + local desc = section[ name ] + local attrs = desc.attrs or {} + + -- Process each element in 'data' in turn + for attr, v in pairs( data ) do + local attrmeta = attrs[ attr ] + if not attrmeta then return false, sf( "attribute '%s' is not defined for element '%s' in section '%s'", attr, name, sectname ) end + if attrmeta.validator and not req then + local res, err = attrmeta:validator( attr, v, name, sectname ) + if not res then + return false, err + else + -- The validator can also change the attribute's value + v = res + end + end + if conf[ attrmeta.macro ] and tostring( conf[ attrmeta.macro ].value ) ~= tostring( v ) and not conf[ attrmeta.macro ].from_default then + print( utils.col_yellow( sf( "[CONFIG] WARNING: overriding value of attribute '%s' in element '%s' from '%s' to '%s' in section '%s'", + attr, name, conf[ attrmeta.macro ].value, v, sectname ) ) ) + end + conf[ attrmeta.macro ] = { name = attr, desc = attrmeta, value = v, sectname = sectname, elname = name, from_default = false } + end + -- Set default values where needed + for name, data in pairs( attrs ) do + if not conf[ data.macro ] and data.default then + conf[ data.macro ] = { name = name, desc = data, value = data.default, sectname = sectname, elname = name, from_default = true } + end + end + -- Mark this component as configured + enabled[ name ] = true + if req then required[ name ] = true end + return true +end + +-- Configures the given section +-- section: the section that will be compiled +-- sectname: the name of the section +-- data: the data corresponding to the section +-- Returns true if OK, (false, errmsg) for error +function configure_section( section, sectname, data ) + conf, enabled, required = {}, {}, {} + + -- Configure each element in turn, doing validation if required + for elname, elval in pairs( data ) do + if not section[ elname ] then return nil, sf( "unknown element '%s' in section '%s'", elname, sectname ) end + -- Handle the special situation = true (or anything else that is not false) + if type( elval ) ~= "table" and elval then + data[ elname ] = {} + elval = data[ elname ] + end + if elval then + local cres, cerr = config_element( section, sectname, elname, elval ) + if not cres then return false, cerr end + end + end + + -- We also need to generated required elements. A required element is an element that + -- is generated every time, even if it was not specified in the configuration file. + for elname, eldesc in pairs( section ) do + if eldesc.required and not enabled[ elname ] then + config_element( section, sectname, elname, eldesc.required, true ) + end + end + + -- Step 2: basic consistency check + -- For each element, we check that all its required attributes (the ones that don't have + -- an 'optional' key set to true) have a value. An element can overwrite this default + -- verification by specifying its own 'confcheck' function. There is another function called + -- 'auxcheck' that is called AFTER the basic consistency check (if it exists) + for elname, _ in pairs( enabled ) do + if not required[ elname ] then + local desc = section[ elname ] + local attrs = desc.attrs or {} + if desc.confcheck then + local d, err = desc:confcheck( conf, enabled ) + if not d then return false, err end + else + for attr, adesc in pairs( attrs ) do + if not conf[ adesc.macro ] and not adesc.optional then + return false, sf( "required attribute '%s' of component '%s' in section '%s' not specified", attr, elname, sectname ) + end + end + if desc.auxcheck then + local d, err = desc:auxcheck( conf, enabled ) + if not d then return false, err end + end + end + end + end + + return true +end + +-- Generate configuration data for the given section (must be called after configure_section!) +-- section: the section that will be compiled +-- sectname: the name of the section +-- data: the data corresponding to the section +-- Returns the generated header if OK, (false, errmsg) for error +function generate_section( section, sectname, data ) + -- Actual generation of code + -- The default generator simply adds '#define KEY VALUE' pairs. An element can overwrite this + -- default generation by specifying its own 'gen' function. If the element has an 'auxgen' + -- function, it will be called after the default attribute generation + -- Also, we never generate the same key twice. We ensure this by keeping a table of the + -- keys that were already generated + local generated = {} + local genstr = string.rep( "/", 80 ) .. "\n" .. sf( "// Configuration for section '%s'\n\n", sectname ) + for elname, _ in pairs( enabled ) do + local desc = section[ elname ] + local attrs = desc.attrs or {} + genstr = genstr .. sf( "// Configuration for element '%s'\n", elname ) + if desc.gen then + genstr = genstr .. desc:gen( conf, generated ) + else + for aname, adesc in pairs( attrs ) do + genstr = genstr .. gen.simple_gen( adesc.macro, conf, generated ) + end + if desc.auxgen then genstr = genstr .. desc:auxgen( conf, generated ) end + end + -- Add the "build enable" macro + if desc.macro then + genstr = genstr .. gen.print_define( desc.macro ) .. "\n" + else + genstr = genstr .. "\n" + end + end + + -- Finally, check for dependencies + -- For each attribute that has a 'needs' element, check if the dependency is met + -- The attribute can also define the 'depcheck' function for a default dependency check + for elname, _ in pairs( enabled ) do + local desc = section[ elname ] + if desc.depcheck then + local res, err = desc:depcheck( conf, generated ) + if not res then return false, err end + elseif desc.needs then + local needs = type( desc.needs ) == "table" and desc.needs or { desc.needs } + for _, v in pairs( needs ) do + -- Look for negative expressions (not enabled) + local neg + if v:sub( 1, 1 ) == "!" then + neg = true + v = v:sub( 2 ) + end + if not neg and not enabled[ v ] then + return false, sf( "element '%s' in section '%s' needs element '%s' to be enabled", elname, sectname, v ) + elseif neg and enabled[ v ] then + return false, sf( "element '%s' in section '%s' needs element '%s' to be disabled", elname, sectname, v ) + end + end + end + end + + -- All done + return genstr +end + diff --git a/doc/buildall.lua b/doc/buildall.lua index 0b7eba59..4643c5ba 100644 --- a/doc/buildall.lua +++ b/doc/buildall.lua @@ -1,6 +1,9 @@ +package.path = package.path .. ";../utils/?.lua;" + require "lfs" require "eluadoc" require "md5" +local utils = require "utils" -- Uncomment this when generating offline docs local is_offline = true @@ -150,21 +153,6 @@ local function copy_dir_rec( src, dst ) end end --- Remove a directory recusively --- USE WITH CARE!! Doesn't do much checks :) -local function rm_dir_rec( dirname ) - for f in lfs.dir( dirname ) do - local ename = string.format( "%s/%s", dirname, f ) - local attrs = lfs.attributes( ename ) - if attrs.mode == 'directory' and f ~= '.' and f ~= '..' then - rm_dir_rec( ename ) - elseif attrs.mode == 'file' or attrs.mode == 'named pipe' or attrs.mode == 'link' then - os.remove( ename ) - end - end - lfs.rmdir( dirname ) -end - -- Copy a directory to another directory local function copy_dir( src, dst ) local newdir = string.format( "%s/%s", dst, src ) @@ -678,7 +666,7 @@ else print( string.format( "%s is not a directory", destdir ) ) return end - rm_dir_rec( destdir ) + utils.rm_dir_rec( destdir ) lfs.mkdir( destdir ) end @@ -690,7 +678,7 @@ if cleancache then print( "'cache' is not a directory" ) return end - rm_dir_rec( 'cache' ) + utils.rm_dir_rec( 'cache' ) lfs.mkdir( 'cache' ) end end diff --git a/inc/platform_conf.h b/inc/platform_conf.h new file mode 100644 index 00000000..1e256bb6 --- /dev/null +++ b/inc/platform_conf.h @@ -0,0 +1,19 @@ +// Generic platform configuration file + +#ifndef __PLATFORM_CONF_H__ +#define __PLATFORM_CONF_H__ + +#include "buf.h" +#include "sermux.h" +#include "legc.h" +#include "platform.h" +#include "auxmods.h" +#include "elua_int.h" +#include "lualib.h" + +#include ELUA_CPU_HEADER +#include ELUA_BOARD_HEADER +#include "platform_generic.h" // generic platform header (include whatever else is missing here) + +#endif + diff --git a/run_elua_sim.sh b/run_elua_sim.sh index 0bd80940..1bf08e12 100755 --- a/run_elua_sim.sh +++ b/run_elua_sim.sh @@ -4,7 +4,7 @@ stty -echo raw -igncr # Run simulator -./elua_lua$1_linux.elf +./elua_lua$1_sim.elf # Restore terminal to default settings stty echo cooked diff --git a/src/common.c b/src/common.c index d18abef3..ff01106b 100644 --- a/src/common.c +++ b/src/common.c @@ -20,43 +20,14 @@ #include "lapi.h" #include "lauxlib.h" -// [TODO] the new builder should automatically do this -#if defined( BUILD_LUA_INT_HANDLERS ) || defined( BUILD_C_INT_HANDLERS ) -#define BUILD_INT_HANDLERS - -#ifndef INT_TMR_MATCH -#define INT_TMR_MATCH ELUA_INT_INVALID_INTERRUPT -#endif - +#ifdef BUILD_INT_HANDLERS extern const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ]; +#endif // #ifdef BUILD_INT_HANDLERS -#endif // #if defined( BUILD_LUA_INT_HANDLERS ) || defined( BUILD_C_INT_HANDLERS ) - -// [TODO] the new builder should automatically do this -#ifndef VTMR_NUM_TIMERS -#define VTMR_NUM_TIMERS 0 -#endif // #ifndef VTMR_NUM_TIMERS - -// [TODO] the new builder should automatically do this #ifndef CON_BUF_SIZE #define CON_BUF_SIZE 0 #endif // #ifndef CON_BUF_SIZE -// [TODO] the new builder should automatically do this -#ifndef SERMUX_FLOW_TYPE -#define SERMUX_FLOW_TYPE PLATFORM_UART_FLOW_NONE -#endif - -// [TODO] the new builder should automatically do this -#ifndef CON_FLOW_TYPE -#define CON_FLOW_TYPE PLATFORM_UART_FLOW_NONE -#endif - -// [TODO] the new builder should automatically do this -#ifndef CON_TIMER_ID -#define CON_TIMER_ID PLATFORM_TIMER_SYS_ID -#endif - // **************************************************************************** // XMODEM support code @@ -350,12 +321,12 @@ extern char end[]; void* platform_get_first_free_ram( unsigned id ) { - void* mstart[] = MEM_START_ADDRESS; + u32 mstart[] = MEM_START_ADDRESS; u32 p; - if( id >= sizeof( mstart ) / sizeof( void* ) ) + if( id >= sizeof( mstart ) / sizeof( u32 ) ) return NULL; - p = ( u32 )mstart[ id ]; + p = mstart[ id ]; if( p & ( MIN_ALIGN - 1 ) ) p = ( ( p >> MIN_ALIGN_SHIFT ) + 1 ) << MIN_ALIGN_SHIFT; return ( void* )p; @@ -363,12 +334,12 @@ void* platform_get_first_free_ram( unsigned id ) void* platform_get_last_free_ram( unsigned id ) { - void* mend[] = MEM_END_ADDRESS; + u32 mend[] = MEM_END_ADDRESS; u32 p; - if( id >= sizeof( mend ) / sizeof( void* ) ) + if( id >= sizeof( mend ) / sizeof( u32 ) ) return NULL; - p = ( u32 )mend[ id ]; + p = mend[ id ]; if( p & ( MIN_ALIGN - 1 ) ) p = ( ( p >> MIN_ALIGN_SHIFT ) - 1 ) << MIN_ALIGN_SHIFT; return ( void* )p; diff --git a/src/main.c b/src/main.c index ee37d618..bbb09a6d 100644 --- a/src/main.c +++ b/src/main.c @@ -40,21 +40,7 @@ char *boot_order[] = { extern char etext[]; - #ifdef ELUA_BOOT_RPC - -#ifndef RPC_UART_ID - #define RPC_UART_ID CON_UART_ID -#endif - -#ifndef RPC_TIMER_ID - #define RPC_TIMER_ID PLATFORM_TIMER_SYS_ID -#endif - -#ifndef RPC_UART_SPEED - #define RPC_UART_SPEED CON_UART_SPEED -#endif - void boot_rpc( void ) { lua_State *L = lua_open(); @@ -70,7 +56,7 @@ void boot_rpc( void ) lua_pushnumber( L, RPC_TIMER_ID ); lua_pcall( L, 2, 0, 0 ); } -#endif +#endif // #ifdef ELUA_BOOT_RPC // **************************************************************************** // Program entry point diff --git a/src/modules/cpu.c b/src/modules/cpu.c index 2df6c641..ca321f9f 100644 --- a/src/modules/cpu.c +++ b/src/modules/cpu.c @@ -11,6 +11,22 @@ #define _C( x ) { #x, x } #include "platform_conf.h" +#if defined( PLATFORM_CPU_CONSTANTS_INTS ) || defined( PLATFORM_CPU_CONSTANTS_PLATFORM ) || defined( PLATFORM_CPU_CONSTANTS_CONFIGURED ) +#define HAS_CPU_CONSTANTS +#endif + +#if defined( HAS_CPU_CONSTANTS ) && !defined( PLATFORM_CPU_CONSTANTS_INTS ) +#define PLATFORM_CPU_CONSTANTS_INTS +#endif + +#if defined( HAS_CPU_CONSTANTS ) && !defined( PLATFORM_CPU_CONSTANTS_PLATFORM ) +#define PLATFORM_CPU_CONSTANTS_PLATFORM +#endif + +#if defined( HAS_CPU_CONSTANTS ) && !defined( PLATFORM_CPU_CONSTANTS_CONFIGURED ) +#define PLATFORM_CPU_CONSTANTS_CONFIGURED +#endif + // Lua: w32( address, data ) static int cpu_w32( lua_State *L ) { @@ -143,10 +159,12 @@ typedef struct u32 val; } cpu_const_t; -#ifdef PLATFORM_CPU_CONSTANTS +#ifdef HAS_CPU_CONSTANTS static const cpu_const_t cpu_constants[] = { - PLATFORM_CPU_CONSTANTS, + PLATFORM_CPU_CONSTANTS_INTS + PLATFORM_CPU_CONSTANTS_PLATFORM + PLATFORM_CPU_CONSTANTS_CONFIGURED { NULL, 0 } }; @@ -166,7 +184,7 @@ static int cpu_mt_index( lua_State *L ) } return 0; } -#endif +#endif // #ifdef HAS_CPU_CONSTANTS #ifdef BUILD_LUA_INT_HANDLERS @@ -258,10 +276,10 @@ const LUA_REG_TYPE cpu_map[] = { LSTRKEY( "get_int_handler" ), LFUNCVAL( cpu_get_int_handler ) }, { LSTRKEY( "get_int_flag" ), LFUNCVAL( cpu_get_int_flag) }, #endif -#if defined( PLATFORM_CPU_CONSTANTS ) && LUA_OPTIMIZE_MEMORY > 0 +#if defined( HAS_CPU_CONSTANTS ) && LUA_OPTIMIZE_MEMORY > 0 { LSTRKEY( "__metatable" ), LROVAL( cpu_map ) }, #endif -#ifdef PLATFORM_CPU_CONSTANTS +#ifdef HAS_CPU_CONSTANTS { LSTRKEY( "__index" ), LFUNCVAL( cpu_mt_index ) }, #endif { LNILKEY, LNILVAL } @@ -281,11 +299,11 @@ LUALIB_API int luaopen_cpu( lua_State *L ) // Register methods luaL_register( L, AUXLIB_CPU, cpu_map ); -#ifdef PLATFORM_CPU_CONSTANTS +#ifdef HAS_CPU_CONSTANTS // Set table as its own metatable lua_pushvalue( L, -1 ); lua_setmetatable( L, -2 ); -#endif // #ifdef PLATFORM_CPU_CONSTANTS +#endif // #ifdef HAS_CPU_CONSTANTS return 1; #endif // #if LUA_OPTIMIZE_MEMORY > 0 diff --git a/src/platform/lpc24xx/cpu_lpc2468.h b/src/platform/lpc24xx/cpu_lpc2468.h new file mode 100644 index 00000000..00aa12b1 --- /dev/null +++ b/src/platform/lpc24xx/cpu_lpc2468.h @@ -0,0 +1,47 @@ +// LPC2468 CPU definitions + +#ifndef __CPU_LPC2468_H__ +#define __CPU_LPC2468_H__ + +#include "stacks.h" +#include "target.h" +#include "platform_ints.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 + +// ADC Configuration Params +#define ADC_BIT_RESOLUTION 10 + +// 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 + +// Internal RAM +#define SRAM_ORIGIN 0x40000000 +#define SRAM_SIZE 0x10000 // [TODO]: make this 96k? +#define INTERNAL_RAM_FIRST_FREE end +#define INTERNAL_RAM_LAST_FREE ( SRAM_ORIGIN + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) + +// Interrupt list for this CPU +#define PLATFORM_CPU_CONSTANTS_INTS\ + _C( INT_GPIO_POSEDGE ), \ + _C( INT_GPIO_NEGEDGE ), \ + _C( INT_TMR_MATCH ), \ + _C( INT_UART_RX ), + +#endif // #ifndef __CPU_LPC2468_H__ + diff --git a/src/platform/lpc24xx/platform_conf.h b/src/platform/lpc24xx/platform_conf.h deleted file mode 100644 index d39eab91..00000000 --- a/src/platform/lpc24xx/platform_conf.h +++ /dev/null @@ -1,197 +0,0 @@ -// eLua platform configuration - -#ifndef __PLATFORM_CONF_H__ -#define __PLATFORM_CONF_H__ - -#include "auxmods.h" -#include "stacks.h" -#include "target.h" -#include "buf.h" -#include "elua_int.h" -#include "sermux.h" - -// ***************************************************************************** -// Define here what components you want for this platform - -#define BUILD_XMODEM -#define BUILD_SHELL -#define BUILD_ROMFS -#define BUILD_TERM -#define BUILD_CON_GENERIC -#define BUILD_ADC -#define BUILD_RPC -//#define BUILD_RFS -//#define BUILD_SERMUX -#define BUILD_LUA_INT_HANDLERS -#define BUILD_C_INT_HANDLERS - -#define PLATFORM_HAS_SYSTIMER - -// ***************************************************************************** -// UART/Timer IDs configuration data (used in main.c) - -//#define CON_UART_ID ( SERMUX_SERVICE_ID_FIRST + 1 ) -#define CON_UART_ID 0 -#define CON_UART_SPEED 115200 -#define TERM_LINES 25 -#define TERM_COLS 80 - -// ***************************************************************************** -// Auxiliary libraries that will be compiled for this platform - -#ifdef BUILD_ADC -#define ADCLINE _ROM( AUXLIB_ADC, luaopen_adc, adc_map ) -#else -#define ADCLINE -#endif - -#if defined( ELUA_BOOT_RPC ) && !defined( BUILD_RPC ) -#define BUILD_RPC -#endif - -#if defined( BUILD_RPC ) -#define RPCLINE _ROM( AUXLIB_RPC, luaopen_rpc, rpc_map ) -#else -#define RPCLINE -#endif - -#define LUA_PLATFORM_LIBS_ROM\ - _ROM( AUXLIB_PIO, luaopen_pio, pio_map )\ - _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\ - ADCLINE\ - _ROM( AUXLIB_UART, luaopen_uart, uart_map )\ - _ROM( AUXLIB_PIO, luaopen_pio, pio_map )\ - _ROM( AUXLIB_PD, luaopen_pd, pd_map )\ - _ROM( AUXLIB_TERM, luaopen_term, term_map )\ - _ROM( AUXLIB_PACK, luaopen_pack, pack_map )\ - _ROM( AUXLIB_BIT, luaopen_bit, bit_map )\ - _ROM( AUXLIB_CPU, luaopen_cpu, cpu_map )\ - _ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\ - _ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\ - RPCLINE\ - _ROM( LUA_MATHLIBNAME, luaopen_math, math_map ) - -// ***************************************************************************** -// Configuration data - -// Virtual timers (0 if not used) -#define VTMR_NUM_TIMERS 4 -// NOTE: DON'T define VTMR_FREQ_HZ as 0! -#define VTMR_FREQ_HZ 4 - -// 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 -// If virtual timers are enabled, the last timer will be used only for them -#if VTMR_NUM_TIMERS == 0 -#define NUM_TIMER 4 -#else -#define NUM_TIMER 3 -#endif - -// Interrupt data -#define PLATFORM_INT_QUEUE_LOG_SIZE BUF_SIZE_32 -// Enable RX buffering on UART -#define BUF_ENABLE_UART -#define CON_BUF_SIZE BUF_SIZE_128 - -// ADC Configuration Params -#define ADC_BIT_RESOLUTION 10 -#define BUF_ENABLE_ADC -#define ADC_BUF_SIZE BUF_SIZE_2 - -// These should be adjusted to support multiple ADC devices -#define ADC_TIMER_FIRST_ID 0 -#define ADC_NUM_TIMERS 4 - -// RPC boot options -#define RPC_UART_ID CON_UART_ID -#define RPC_UART_SPEED CON_UART_SPEED - -// 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 - -// Remote file system data -/* -#define RFS_BUFFER_SIZE BUF_SIZE_512 -#define RFS_UART_ID ( SERMUX_SERVICE_ID_FIRST ) -#define RFS_TIMEOUT 100000 -#define RFS_UART_SPEED 115200 - -#define SERMUX_PHYS_ID 0 -#define SERMUX_PHYS_SPEED 115200 -#define SERMUX_NUM_VUART 2 -#define SERMUX_BUFFER_SIZES { RFS_BUFFER_SIZE, CON_BUF_SIZE } -*/ - -// Allocator data: define your free memory zones here in two arrays -// (start address and end address) -#define SRAM_ORIGIN 0x40000000 -#define SRAM_SIZE 0x10000 // [TODO]: make this 96k? - -#ifdef ELUA_BOARD_ELUAPUC -#define SDRAM_BASE_ADDR2 0xA0000000 -#define SDRAM_SIZE ( 8 * 1048576 ) -#define MEM_START_ADDRESS { ( void* )end, ( void* )SDRAM_BASE_ADDR2 } -#define MEM_END_ADDRESS { ( void* )( SRAM_ORIGIN + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ), ( void* )( SDRAM_BASE_ADDR2 + SDRAM_SIZE - 1 ) } -//#define MEM_START_ADDRESS { ( void* )SDRAM_BASE_ADDR2 } -//#define MEM_END_ADDRESS { ( void* )( SDRAM_BASE_ADDR2 + SDRAM_SIZE - 1 ) } -#else -#define MEM_START_ADDRESS { ( void* )end } -#define MEM_END_ADDRESS { ( void* )( SRAM_ORIGIN + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) } -#endif - -// ***************************************************************************** -// CPU constants that should be exposed to the eLua "cpu" module - -#define PINSEL_BASE_ADDR 0xE002C000 -#define IO_PINSEL0 ( PINSEL_BASE_ADDR + 0x00 ) -#define IO_PINSEL1 ( PINSEL_BASE_ADDR + 0x04 ) -#define IO_PINSEL2 ( PINSEL_BASE_ADDR + 0x08 ) -#define IO_PINSEL3 ( PINSEL_BASE_ADDR + 0x0C ) -#define IO_PINSEL4 ( PINSEL_BASE_ADDR + 0x10 ) -#define IO_PINSEL5 ( PINSEL_BASE_ADDR + 0x14 ) -#define IO_PINSEL6 ( PINSEL_BASE_ADDR + 0x18 ) -#define IO_PINSEL7 ( PINSEL_BASE_ADDR + 0x1C ) -#define IO_PINSEL8 ( PINSEL_BASE_ADDR + 0x20 ) -#define IO_PINSEL9 ( PINSEL_BASE_ADDR + 0x24 ) -#define IO_PINSEL10 ( PINSEL_BASE_ADDR + 0x28 ) - -// Interrupt list -#define INT_GPIO_POSEDGE ELUA_INT_FIRST_ID -#define INT_GPIO_NEGEDGE ( ELUA_INT_FIRST_ID + 1 ) -#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 2 ) -#define INT_UART_RX ( ELUA_INT_FIRST_ID + 3 ) -#define INT_ELUA_LAST INT_UART_RX - -#define PLATFORM_CPU_CONSTANTS\ - _C( IO_PINSEL0 ),\ - _C( IO_PINSEL1 ),\ - _C( IO_PINSEL2 ),\ - _C( IO_PINSEL3 ),\ - _C( IO_PINSEL4 ),\ - _C( IO_PINSEL5 ),\ - _C( IO_PINSEL6 ),\ - _C( IO_PINSEL7 ),\ - _C( IO_PINSEL8 ),\ - _C( IO_PINSEL9 ),\ - _C( IO_PINSEL10 ),\ - _C( INT_GPIO_POSEDGE ),\ - _C( INT_GPIO_NEGEDGE ),\ - _C( INT_TMR_MATCH ),\ - _C( INT_UART_RX ) - -#endif // #ifndef __PLATFORM_CONF_H__ - diff --git a/src/platform/lpc24xx/platform_generic.h b/src/platform/lpc24xx/platform_generic.h new file mode 100644 index 00000000..9af64f99 --- /dev/null +++ b/src/platform/lpc24xx/platform_generic.h @@ -0,0 +1,44 @@ +// Platform-wide configuration file, included by platform_conf.h + +#ifndef __PLATFORM_GENERIC_H__ +#define __PLATFORM_GENERIC_H__ + +#define PLATFORM_HAS_SYSTIMER + +// If virtual timers are enabled, the last timer will be used only for them +#if VTMR_NUM_TIMERS > 0 +#undef NUM_TIMER +#define NUM_TIMER 3 +#endif + +// ***************************************************************************** +// CPU constants that should be exposed to the eLua "cpu" module + +#define PINSEL_BASE_ADDR 0xE002C000 +#define IO_PINSEL0 ( PINSEL_BASE_ADDR + 0x00 ) +#define IO_PINSEL1 ( PINSEL_BASE_ADDR + 0x04 ) +#define IO_PINSEL2 ( PINSEL_BASE_ADDR + 0x08 ) +#define IO_PINSEL3 ( PINSEL_BASE_ADDR + 0x0C ) +#define IO_PINSEL4 ( PINSEL_BASE_ADDR + 0x10 ) +#define IO_PINSEL5 ( PINSEL_BASE_ADDR + 0x14 ) +#define IO_PINSEL6 ( PINSEL_BASE_ADDR + 0x18 ) +#define IO_PINSEL7 ( PINSEL_BASE_ADDR + 0x1C ) +#define IO_PINSEL8 ( PINSEL_BASE_ADDR + 0x20 ) +#define IO_PINSEL9 ( PINSEL_BASE_ADDR + 0x24 ) +#define IO_PINSEL10 ( PINSEL_BASE_ADDR + 0x28 ) + +#define PLATFORM_CPU_CONSTANTS_PLATFORM\ + _C( IO_PINSEL0 ),\ + _C( IO_PINSEL1 ),\ + _C( IO_PINSEL2 ),\ + _C( IO_PINSEL3 ),\ + _C( IO_PINSEL4 ),\ + _C( IO_PINSEL5 ),\ + _C( IO_PINSEL6 ),\ + _C( IO_PINSEL7 ),\ + _C( IO_PINSEL8 ),\ + _C( IO_PINSEL9 ),\ + _C( IO_PINSEL10 ), + +#endif // #ifndef __PLATFORM_GENERIC_H__ + diff --git a/src/platform/lpc24xx/platform_ints.h b/src/platform/lpc24xx/platform_ints.h new file mode 100644 index 00000000..c3df8e76 --- /dev/null +++ b/src/platform/lpc24xx/platform_ints.h @@ -0,0 +1,15 @@ +// This header lists all interrupts defined for this platform + +#ifndef __PLATFORM_INTS_H__ +#define __PLATFORM_INTS_H__ + +#include "elua_int.h" + +#define INT_GPIO_POSEDGE ELUA_INT_FIRST_ID +#define INT_GPIO_NEGEDGE ( ELUA_INT_FIRST_ID + 1 ) +#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 2 ) +#define INT_UART_RX ( ELUA_INT_FIRST_ID + 3 ) +#define INT_ELUA_LAST INT_UART_RX + +#endif // #ifndef __PLATFORM_INTS_H__ + diff --git a/src/platform/sim/cpu_linux.h b/src/platform/sim/cpu_linux.h new file mode 100644 index 00000000..cfb22173 --- /dev/null +++ b/src/platform/sim/cpu_linux.h @@ -0,0 +1,32 @@ +// Linux "CPU" description for the eLua simulator + +#ifndef __CPU_LINUX_H__ +#define __CPU_LINUX_H__ + +// Number of resources (0 if not available/not implemented) +#define NUM_PIO 0 +#define NUM_SPI 0 +#define NUM_UART 0 +#define NUM_TIMER 0 +#define NUM_PWM 0 +#define NUM_ADC 0 +#define NUM_CAN 0 + +// 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 0 + +// Allocator data: define your free memory zones here in two arrays +// (start address and end address) +extern void *memory_start_address; +extern void *memory_end_address; +#define MEM_LENGTH (1024 * 1024) +#define INTERNAL_RAM_FIRST_FREE ( void* )memory_start_address +#define INTERNAL_RAM_LAST_FREE ( void* )memory_end_address + +#endif + diff --git a/src/platform/sim/platform_conf.h b/src/platform/sim/platform_conf.h deleted file mode 100644 index 7677a580..00000000 --- a/src/platform/sim/platform_conf.h +++ /dev/null @@ -1,78 +0,0 @@ -// eLua platform configuration - -#ifndef __PLATFORM_CONF_H__ -#define __PLATFORM_CONF_H__ - -#include "auxmods.h" -#include "type.h" -#include "stacks.h" -#include "buf.h" - -// ***************************************************************************** -// Define here what components you want for this platform - -#define BUILD_SHELL -#define BUILD_ROMFS -#define BUILD_CON_GENERIC -#define BUILD_TERM -//#define BUILD_RFS -#define BUILD_WOFS - -#define TERM_LINES 25 -#define TERM_COLS 80 - -#define PLATFORM_HAS_SYSTIMER - -// ***************************************************************************** -// Auxiliary libraries that will be compiled for this platform - -#define LUA_PLATFORM_LIBS_ROM\ - _ROM( AUXLIB_PD, luaopen_pd, pd_map )\ - _ROM( LUA_MATHLIBNAME, luaopen_math, math_map )\ - _ROM( AUXLIB_TERM, luaopen_term, term_map )\ - _ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\ - _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\ - -// Bogus defines for common.c -#define CON_UART_ID 0 -#define CON_UART_SPEED 0 - -// ***************************************************************************** -// Configuration data - -// Virtual timers (0 if not used) -#define VTMR_NUM_TIMERS 0 - -// Number of resources (0 if not available/not implemented) -#define NUM_PIO 0 -#define NUM_SPI 0 -#define NUM_UART 0 -#define NUM_TIMER 0 -#define NUM_PWM 0 -#define NUM_ADC 0 -#define NUM_CAN 0 - -// CPU frequency (needed by the CPU module and MMCFS code, 0 if not used) -#define CPU_FREQUENCY 0 - -// 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 0 - -// Allocator data: define your free memory zones here in two arrays -// (start address and end address) -extern void *memory_start_address; -extern void *memory_end_address; -#define MEM_LENGTH (1024 * 1024) -#define MEM_START_ADDRESS { ( void* )memory_start_address } -#define MEM_END_ADDRESS { ( void* )memory_end_address } - -// RFS configuration -#define RFS_TIMEOUT 0 // dummy, always blocking by implementation -#define RFS_BUFFER_SIZE BUF_SIZE_512 - -#endif // #ifndef __PLATFORM_CONF_H__ diff --git a/src/platform/sim/platform_generic.h b/src/platform/sim/platform_generic.h new file mode 100644 index 00000000..a632f6a0 --- /dev/null +++ b/src/platform/sim/platform_generic.h @@ -0,0 +1,9 @@ +// Included by platform_conf.h for platform customizations + +#ifndef __PLATFORM_GENERIC_H__ +#define __PLATFORM_GENERIC_H__ + +#define PLATFORM_HAS_SYSTIMER + +#endif // #ifndef __PLATFORM_GENERIC_H__ + diff --git a/src/platform/stm32/build_config.lua b/src/platform/stm32/build_config.lua new file mode 100644 index 00000000..39fb717d --- /dev/null +++ b/src/platform/stm32/build_config.lua @@ -0,0 +1,19 @@ +-- This is the platform specific board configuration file +-- It is used by the generic board configuration system (config/) + +module( ..., package.seeall ) + +-- Add specific components to the 'components' table +function add_platform_components( t ) + t.stm32_enc = { macro = 'ENABLE_ENC' } +end + +-- Add specific configuration to the 'configs' table +function add_platform_configs( t ) +end + +-- Return an array of all the available platform modules for the given cpu +function get_platform_modules( cpu ) + return { enc = { 'ENABLE_ENC' } } +end + diff --git a/src/platform/stm32/cpu_stm32f103re.h b/src/platform/stm32/cpu_stm32f103re.h new file mode 100644 index 00000000..3bbab727 --- /dev/null +++ b/src/platform/stm32/cpu_stm32f103re.h @@ -0,0 +1,51 @@ +// CPU definition file for STM32F103RE + +#ifndef __CPU_STM32F103RE_H__ +#define __CPU_STM32F103RE_H__ + +#include "type.h" +#include "stacks.h" +#include "stm32f10x.h" +#include "platform_ints.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 + +#define ADC_BIT_RESOLUTION 12 + +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 + +// Internal memory data +#define SRAM_SIZE ( 64 * 1024 ) +#define INTERNAL_RAM_FIRST_FREE end +#define INTERNAL_RAM_LAST_FREE ( 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 + +// Interrupt list for this CPU +#define PLATFORM_CPU_CONSTANTS_INTS\ + _C( INT_GPIO_POSEDGE ), \ + _C( INT_GPIO_NEGEDGE ), \ + _C( INT_TMR_MATCH ), \ + _C( INT_UART_RX ), + +#endif // #ifndef __CPU_STM32F103RE_H__ + diff --git a/src/platform/stm32/cpu_stm32f103ze.h b/src/platform/stm32/cpu_stm32f103ze.h new file mode 100644 index 00000000..aab57355 --- /dev/null +++ b/src/platform/stm32/cpu_stm32f103ze.h @@ -0,0 +1,14 @@ +// CPU definition file for STM32F103ZE +// Use the STM32F103RE description as a base + +#ifndef __CPU_STM32F103ZE_H__ +#define __CPU_STM32F103ZE_H__ + +#include "cpu_stm32f103re.h" + +// 21 ADCs instead of 16 +#undef NUM_ADC +#define NUM_ADC 21 + +#endif // #ifndef __CPU_STM32F103ZE_H__ + diff --git a/src/platform/stm32/platform_conf.h b/src/platform/stm32/platform_conf.h deleted file mode 100755 index a54e0217..00000000 --- a/src/platform/stm32/platform_conf.h +++ /dev/null @@ -1,200 +0,0 @@ -// eLua platform configuration - -#ifndef __PLATFORM_CONF_H__ -#define __PLATFORM_CONF_H__ - -#include "auxmods.h" -#include "type.h" -#include "stacks.h" -#include "stm32f10x.h" -#include "elua_int.h" -#include "sermux.h" - -// ***************************************************************************** -// Define here what components you want for this platform - -#define BUILD_XMODEM -#define BUILD_SHELL -#define BUILD_ROMFS -//#define BUILD_MMCFS -#define BUILD_TERM -//#define BUILD_UIP -//#define BUILD_DHCPC -//#define BUILD_DNS -#define BUILD_CON_GENERIC -#define BUILD_ADC -#define BUILD_RPC -//#define BUILD_RFS -//#define BUILD_CON_TCP -#define BUILD_LINENOISE -#define BUILD_C_INT_HANDLERS -#define BUILD_LUA_INT_HANDLERS -#define ENABLE_ENC - -#define PLATFORM_HAS_SYSTIMER - -// ***************************************************************************** -// UART/Timer IDs configuration data (used in main.c) - -#define CON_UART_ID 0 -#define CON_UART_SPEED 115200 -#define TERM_LINES 25 -#define TERM_COLS 80 - -// ***************************************************************************** -// Auxiliary libraries that will be compiled for this platform - -//#ifdef FORSTM3210E_EVAL -//#define AUXLIB_LCD "stm3210lcd" -//LUALIB_API int ( luaopen_lcd )( lua_State* L ); -//#define LCDLINE _ROM( AUXLIB_LCD, luaopen_lcd, lcd_map ) -//#else -#define LCDLINE -//#endif - -#ifdef ENABLE_ENC -#define PS_LIB_TABLE_NAME "stm32" -#endif - - -#ifdef BUILD_ADC -#define ADCLINE _ROM( AUXLIB_ADC, luaopen_adc, adc_map ) -#else -#define ADCLINE -#endif - -#if defined( ELUA_BOOT_RPC ) && !defined( BUILD_RPC ) -#define BUILD_RPC -#endif - -#if defined( BUILD_RPC ) -#define RPCLINE _ROM( AUXLIB_RPC, luaopen_rpc, rpc_map ) -#else -#define RPCLINE -#endif - -#ifdef PS_LIB_TABLE_NAME -#define PLATLINE _ROM( PS_LIB_TABLE_NAME, luaopen_platform, platform_map ) -#else -#define PLATLINE -#endif - -#define LUA_PLATFORM_LIBS_ROM\ - _ROM( AUXLIB_PIO, luaopen_pio, pio_map )\ - _ROM( AUXLIB_SPI, luaopen_spi, spi_map )\ - _ROM( AUXLIB_PD, luaopen_pd, pd_map )\ - _ROM( AUXLIB_UART, luaopen_uart, uart_map )\ - _ROM( AUXLIB_TERM, luaopen_term, term_map )\ - _ROM( AUXLIB_PACK, luaopen_pack, pack_map )\ - _ROM( AUXLIB_BIT, luaopen_bit, bit_map )\ - _ROM( AUXLIB_CPU, luaopen_cpu, cpu_map )\ - _ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\ - _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\ - ADCLINE\ - _ROM( AUXLIB_CAN, luaopen_can, can_map )\ - _ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\ - RPCLINE\ - LCDLINE\ - _ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\ - _ROM( LUA_MATHLIBNAME, luaopen_math, math_map )\ - PLATLINE - -// ***************************************************************************** -// Configuration data - -#define EGC_INITIAL_MODE 1 - -// Virtual timers (0 if not used) -#define VTMR_NUM_TIMERS 4 -#define VTMR_FREQ_HZ 10 - -// 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 - -// Enable RX buffering on UART -#define BUF_ENABLE_UART -#define CON_BUF_SIZE BUF_SIZE_128 - -// ADC Configuration Params -#define ADC_BIT_RESOLUTION 12 -#define BUF_ENABLE_ADC -#define ADC_BUF_SIZE BUF_SIZE_2 - -// These should be adjusted to support multiple ADC devices -#define ADC_TIMER_FIRST_ID 0 -#define ADC_NUM_TIMERS 4 - -// RPC boot options -#define RPC_UART_ID CON_UART_ID -#define RPC_UART_SPEED CON_UART_SPEED - - - - -// MMCFS Support (FatFs on SD/MMC) -// For STM32F103RET6 - PA5 = CLK, PA6 = MISO, PA7 = MOSI, PA8 = CS -#define MMCFS_CS_PORT 0 -#define MMCFS_CS_PIN 8 -#define MMCFS_SPI_NUM 0 - -// CPU frequency (needed by the CPU module, 0 if not used) -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 - -// Remote file system data -#define RFS_BUFFER_SIZE BUF_SIZE_512 -#define RFS_UART_ID 0 -#define RFS_TIMEOUT 100000 -#define RFS_UART_SPEED 115200 - -// Linenoise buffer sizes -#define LINENOISE_HISTORY_SIZE_LUA 50 -#define LINENOISE_HISTORY_SIZE_SHELL 10 - -// 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 ) } - -// Flash data (only for STM32F103RE for now) -#ifdef ELUA_CPU_STM32F103RE -#define INTERNAL_FLASH_SIZE ( 512 * 1024 ) -#define INTERNAL_FLASH_SECTOR_SIZE 2048 -#define INTERNAL_FLASH_START_ADDRESS 0x08000000 -#define BUILD_WOFS -#endif // #ifdef ELUA_CPU_STM32F103RE - -// Interrupt queue size -#define PLATFORM_INT_QUEUE_LOG_SIZE 5 - -// Interrupt list -#define INT_GPIO_POSEDGE ELUA_INT_FIRST_ID -#define INT_GPIO_NEGEDGE ( ELUA_INT_FIRST_ID + 1 ) -#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 2 ) -#define INT_UART_RX ( ELUA_INT_FIRST_ID + 3 ) -#define INT_ELUA_LAST INT_UART_RX - -#define PLATFORM_CPU_CONSTANTS\ - _C( INT_GPIO_POSEDGE ), \ - _C( INT_GPIO_NEGEDGE ), \ - _C( INT_TMR_MATCH ), \ - _C( INT_UART_RX ) - -#endif // #ifndef __PLATFORM_CONF_H__ - diff --git a/src/platform/stm32/platform_generic.h b/src/platform/stm32/platform_generic.h new file mode 100644 index 00000000..4d5e96b0 --- /dev/null +++ b/src/platform/stm32/platform_generic.h @@ -0,0 +1,9 @@ +// Generic platform-wide header + +#ifndef __PLATFORM_GENERIC_H__ +#define __PLATFORM_GENERIC_H__ + +#define PLATFORM_HAS_SYSTIMER + +#endif // #ifndef __PLATFORM_GENERIC_H__ + diff --git a/src/platform/stm32/platform_ints.h b/src/platform/stm32/platform_ints.h new file mode 100644 index 00000000..c3df8e76 --- /dev/null +++ b/src/platform/stm32/platform_ints.h @@ -0,0 +1,15 @@ +// This header lists all interrupts defined for this platform + +#ifndef __PLATFORM_INTS_H__ +#define __PLATFORM_INTS_H__ + +#include "elua_int.h" + +#define INT_GPIO_POSEDGE ELUA_INT_FIRST_ID +#define INT_GPIO_NEGEDGE ( ELUA_INT_FIRST_ID + 1 ) +#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 2 ) +#define INT_UART_RX ( ELUA_INT_FIRST_ID + 3 ) +#define INT_ELUA_LAST INT_UART_RX + +#endif // #ifndef __PLATFORM_INTS_H__ + diff --git a/src/platform/str7/cpu_str711fr2.h b/src/platform/str7/cpu_str711fr2.h new file mode 100644 index 00000000..79bc6e5a --- /dev/null +++ b/src/platform/str7/cpu_str711fr2.h @@ -0,0 +1,34 @@ +// STR711FR2 CPU description + +#ifndef __CPU_STR711FR2_H__ +#define __CPU_STR711FR2_H__ + +#include "stacks.h" + +// Number of resources (0 if not available/not implemented) +#define NUM_PIO 2 +#define NUM_SPI 0 +#define NUM_UART 4 +#define NUM_TIMER 4 +#define NUM_PWM 3 +#define NUM_ADC 0 +#define NUM_CAN 0 + +// CPU frequency (needed by the CPU module and MMCFS code, 0 if not used) +#define CPU_FREQUENCY 0 + +// 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 16 + +#define SRAM_ORIGIN 0x20000000 +#define SRAM_SIZE 0x10000 +#define INTERNAL_RAM_FIRST_FREE end +#define INTERNAL_RAM_LAST_FREE ( SRAM_ORIGIN + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) + +#endif // #ifndef __CPU_STR711FR2_H__ + diff --git a/src/platform/str7/platform_conf.h b/src/platform/str7/platform_conf.h deleted file mode 100644 index fd095e94..00000000 --- a/src/platform/str7/platform_conf.h +++ /dev/null @@ -1,94 +0,0 @@ -// eLua platform configuration - -#ifndef __PLATFORM_CONF_H__ -#define __PLATFORM_CONF_H__ - -#include "auxmods.h" -#include "stacks.h" - -// ***************************************************************************** -// Define here what components you want for this platform - -#define BUILD_XMODEM -#define BUILD_SHELL -#define BUILD_ROMFS -#define BUILD_TERM -#define BUILD_CON_GENERIC -//#define BUILD_RPC - -// ***************************************************************************** -// UART/Timer IDs configuration data (used in main.c) - -#define CON_UART_ID 1 -#define CON_UART_SPEED 38400 -#define CON_TIMER_ID 0 -#define TERM_LINES 25 -#define TERM_COLS 80 - -// ***************************************************************************** -// Auxiliary libraries that will be compiled for this platform - -#if defined( ELUA_BOOT_RPC ) && !defined( BUILD_RPC ) -#define BUILD_RPC -#endif - -#if defined( BUILD_RPC ) -#define RPCLINE _ROM( AUXLIB_RPC, luaopen_rpc, rpc_map ) -#else -#define RPCLINE -#endif - -#define LUA_PLATFORM_LIBS_ROM\ - _ROM( AUXLIB_PIO, luaopen_pio, pio_map )\ - _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\ - _ROM( AUXLIB_PD, luaopen_pd, pd_map )\ - _ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\ - _ROM( AUXLIB_UART, luaopen_uart, uart_map )\ - _ROM( AUXLIB_TERM, luaopen_term, term_map )\ - _ROM( AUXLIB_PACK, luaopen_pack, pack_map )\ - _ROM( AUXLIB_BIT, luaopen_bit, bit_map )\ - _ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\ - _ROM( AUXLIB_CPU, luaopen_cpu, cpu_map )\ - RPCLINE\ - _ROM( LUA_MATHLIBNAME, luaopen_math, math_map ) - -// ***************************************************************************** -// Configuration data - -// Virtual timers (0 if not used) -#define VTMR_NUM_TIMERS 0 -#define VTMR_FREQ_HZ 4 - -// Number of resources (0 if not available/not implemented) -#define NUM_PIO 2 -#define NUM_SPI 0 -#define NUM_UART 4 -#define NUM_TIMER 4 -#define NUM_PWM 3 -#define NUM_ADC 0 -#define NUM_CAN 0 - -// RPC boot options -#define RPC_UART_ID CON_UART_ID -#define RPC_TIMER_ID CON_TIMER_ID -#define RPC_UART_SPEED CON_UART_SPEED - -// CPU frequency (needed by the CPU module and MMCFS code, 0 if not used) -#define CPU_FREQUENCY 0 - -// 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 16 - -// Allocator data: define your free memory zones here in two arrays -// (start address and end address) -#define SRAM_ORIGIN 0x20000000 -#define SRAM_SIZE 0x10000 -#define MEM_START_ADDRESS { ( void* )end } -#define MEM_END_ADDRESS { ( void* )( SRAM_ORIGIN + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) } - -#endif // #ifndef __PLATFORM_CONF_H__ diff --git a/src/platform/str7/platform_generic.h b/src/platform/str7/platform_generic.h new file mode 100644 index 00000000..34b9bbab --- /dev/null +++ b/src/platform/str7/platform_generic.h @@ -0,0 +1,7 @@ +// Platform customization header + +#ifndef __PLATFORM_GENERIC_H__ +#define __PLATFORM_GENERIC_H__ + +#endif // #ifndef __PLATFORM_GENERIC_H__ + diff --git a/utils/build.lua b/utils/build.lua index cd9e2c81..f06a2678 100644 --- a/utils/build.lua +++ b/utils/build.lua @@ -328,6 +328,7 @@ builder.new = function( build_dir ) self.clean_mode = false self.opts = utils.options_handler() self.args = {} + self.user_args = {} self.build_mode = self.KEEP_DIR self.targets = {} self.targetargs = {} @@ -389,6 +390,7 @@ builder.init = function( self, args ) os.exit( 1 ) end self.args[ k:upper() ] = v + self.user_args[ k:upper() ] = true else -- this must be the target name / target arguments if self.targetname == nil then self.targetname = a @@ -408,6 +410,11 @@ builder.get_option = function( self, optname ) return self.args[ optname:upper() ] end +-- Returns true if the given option was specified by the user on the command line, false otherwise +builder.is_user_option = function( self, optname ) + return self.user_args[ optname:upper() ] +end + -- Show builder help builder._show_help = function( self ) print( "[builder] Valid options:" ) @@ -719,11 +726,11 @@ end builder.build = function( self, target ) local t = self.targetname or self.deftarget if not t then - print( "[builder] Error: build target not specified" ) + print( utils.col_red( "[builder] Error: build target not specified" ) ) os.exit( 1 ) end if not self.targets[ t ] then - print( sf( "[builder] Error: target '%s' not found", t ) ) + print( utils.col_red( sf( "[builder] Error: target '%s' not found", t ) ) ) print( "Available targets: " ) for k, v in pairs( self.targets ) do if not is_phony( k ) then @@ -738,19 +745,19 @@ builder.build = function( self, target ) self:_create_outdir() -- At this point check if we have a change in the state that would require a rebuild if self:_compare_config( 'comp' ) then - print "[builder] Forcing rebuild due to configuration change" + print( utils.col_yellow( "[builder] Forcing rebuild due to configuration change." ) ) self.global_force_rebuild = true else self.global_force_rebuild = false end -- Do the actual build local res = self.targets[ t ].target:build() - if not res then print( sf( '[builder] %s: up to date', t ) ) end + if not res then print( utils.col_yellow( sf( '[builder] %s: up to date', t ) ) ) end if self.clean_mode then os.remove( self.build_dir .. utils.dir_sep .. ".builddata.comp" ) os.remove( self.build_dir .. utils.dir_sep .. ".builddata.link" ) end - print "[builder] Done building target." + print( utils.col_yellow( "[builder] Done building target." ) ) return res end diff --git a/utils/utils.lua b/utils/utils.lua index bb202633..32f41de6 100644 --- a/utils/utils.lua +++ b/utils/utils.lua @@ -4,6 +4,7 @@ module( ..., package.seeall ) local lfs = require "lfs" local sf = string.format +local md5 = require "md5" -- Taken from Lake dir_sep = package.config:sub( 1, 1 ) @@ -37,7 +38,13 @@ end -- Replace the extension of a give file name replace_extension = function( s, newext ) local p, e = split_path( s ) - if e then s = p .. "." .. newext end + if e then + if newext and #newext > 0 then + s = p .. "." .. newext + else + s = p + end + end return s end @@ -111,6 +118,13 @@ table_keys = function( t ) return keys end +-- Return an array with the values of a table +table_values = function( t ) + local vals = {} + foreach( t, function( k, v ) table.insert( vals, v ) end ) + return vals +end + -- Returns true if 'path' is a regular file, false otherwise is_file = function( path ) return lfs.attributes( path, "mode" ) == "file" @@ -168,22 +182,71 @@ foreach = function ( t, cmd ) for k, v in pairs( t ) do cmd( k, v ) end end --- Template header -gen_header = function( name, defines ) - local hname = "inc" .. dir_sep .. name:lower() .. ".h" - local h = assert(io.open(hname, "w")) - h:write("// eLua " .. name:lower() .. " definition\n\n") - h:write("#ifndef __" .. name:upper() .. "_H__\n") - h:write("#define __" .. name:upper() .. "_H__\n\n") +-- Generate header with the given #defines, return result as string +gen_header_string = function( name, defines ) + local s = "// eLua " .. name:lower() .. " definition\n\n" + s = s .. "#ifndef __" .. name:upper() .. "_H__\n" + s = s .. "#define __" .. name:upper() .. "_H__\n\n" for key,value in pairs(defines) do - h:write(string.format("#define %-25s%-19s\n",key:upper(),value)) + s = s .. string.format("#define %-25s%-19s\n",key:upper(),value) end - h:write("\n#endif\n") + s = s .. "\n#endif\n" + return s +end + +-- Generate header with the given #defines, save result to file +gen_header_file = function( name, defines ) + local hname = concat_path{ "inc", name:lower() .. ".h" } + local h = assert( io.open( hname, "w" ) ) + h:write( gen_header_string( name, defines ) ) h:close() end +-- Remove the given elements from an array +remove_array_elements = function( arr, del ) + del = istable( del ) and del or { del } + foreach( del, function( k, v ) + local pos = array_element_index( arr, v ) + if pos then table.remove( arr, pos ) end + end ) +end + +-- Remove a directory recusively +-- USE WITH CARE!! Doesn't do much checks :) +rm_dir_rec = function ( dirname ) + for f in lfs.dir( dirname ) do + local ename = string.format( "%s/%s", dirname, f ) + local attrs = lfs.attributes( ename ) + if attrs.mode == 'directory' and f ~= '.' and f ~= '..' then + rm_dir_rec( ename ) + elseif attrs.mode == 'file' or attrs.mode == 'named pipe' or attrs.mode == 'link' then + os.remove( ename ) + end + end + lfs.rmdir( dirname ) +end + +-- Computes the hash of the given string +get_hash_of_string = function( s ) + return md5.sumhexa( s ) +end + +-- Computes the hash of the given file +get_hash_of_file = function( f ) + local f = io.open( f, "rb" ) + if not f then return end + local d = f:read( "*a" ) + f:close() + return get_hash_of_string( d ) +end + +-- Concatenates the second table into the first one +concat_tables = function( dst, src ) + foreach( src, function( k, v ) dst[ k ] = v end ) +end + ------------------------------------------------------------------------------- -- Color-related funtions -- Currently disabled when running in Windows