diff options
author | Damien George <damien.p.george@gmail.com> | 2014-04-19 00:32:25 +0100 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2014-04-19 00:32:25 +0100 |
commit | f20e093b9b20a6308f0cdd6e31cfa3544fc1e115 (patch) | |
tree | f546da8267a373a0f957312331713d81e1ebd140 /stmhal/make-stmconst.py | |
parent | 561f83c9cf62b6470637dfbd51471db63fe5c28d (diff) |
stmhal: Add lots of constants to stm module.
Diffstat (limited to 'stmhal/make-stmconst.py')
-rw-r--r-- | stmhal/make-stmconst.py | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/stmhal/make-stmconst.py b/stmhal/make-stmconst.py new file mode 100644 index 000000000..ba428395c --- /dev/null +++ b/stmhal/make-stmconst.py @@ -0,0 +1,223 @@ +""" +Read in the cmsis/devinc/stm32f405xx.h header, extract relevant constants, +and create modstmconst.c. + +This is not part of the automatic build process because stm32f405xx.h isn't +expected to change. After generating the file, some manual intervention is +needed to copy the new qstr definitions to qstrdefsport.h. +""" + +import argparse +import re + +# given a list of (name,regex) pairs, find the first one that matches the given line +def re_match_first(regexs, line): + for name, regex in regexs: + match = re.match(regex, line) + if match: + return name, match + return None, None + +class LexerError(Exception): + def __init__(self, line): + self.line = line + +class Lexer: + re_io_reg = r'__IO uint(?P<bits>8|16|32)_t +(?P<reg>[A-Z0-9]+)' + re_comment = r'(?P<comment>[A-Za-z0-9 \-/_()]+)' + re_addr_offset = r'Address offset: (?P<offset>0x[0-9A-Z]{2,3})' + regexs = ( + ('#define hex', re.compile(r'#define +(?P<id>[A-Z0-9_]+) +\(\(uint32_t\)(?P<hex>0x[0-9A-F]+)\)($| +/\*)')), + ('#define X', re.compile(r'#define +(?P<id>[A-Z0-9_]+) +(?P<id2>[A-Z0-9_]+)($| +/\*)')), + ('#define X+hex', re.compile(r'#define +(?P<id>[A-Z0-9_]+) +\((?P<id2>[A-Z0-9_]+) \+ (?P<hex>0x[0-9A-F]+)\)($| +/\*)')), + ('#define typedef', re.compile(r'#define +(?P<id>[A-Z0-9_]+) +\(\([A-Za-z0-9_]+_TypeDef \*\) (?P<id2>[A-Z0-9_]+)\)($| +/\*)')), + ('typedef struct', re.compile(r'typedef struct$')), + ('{', re.compile(r'{$')), + ('}', re.compile(r'}$')), + ('} TypeDef', re.compile(r'} *(?P<id>[A-Z][A-Za-z0-9_]+)_(?P<global>(Global)?)TypeDef;$')), + ('IO reg', re.compile(re_io_reg + r'; +/\*!< ' + re_comment + r', +' + re_addr_offset + r' *\*/')), + ('IO reg array', re.compile(re_io_reg + r'\[(?P<array>[2-8])\]; +/\*!< ' + re_comment + r', +' + re_addr_offset + r'-(0x[0-9A-Z]{2,3}) *\*/')), + ) + + def __init__(self, filename): + self.file = open(filename, 'rt') + self.line_number = 0 + + def next_match(self, strictly_next=False): + while True: + line = self.file.readline() + self.line_number += 1 + if len(line) == 0: + return ('EOF', None) + match = re_match_first(Lexer.regexs, line.strip()) + if strictly_next or match[0] is not None: + return match + + def must_match(self, kind): + match = self.next_match(strictly_next=True) + if match[0] != kind: + raise LexerError(self.line_number) + return match + +def parse_file(filename): + lexer = Lexer(filename) + + reg_defs = {} + consts = {} + periphs = [] + while True: + m = lexer.next_match() + if m[0] == 'EOF': + break + elif m[0] == '#define hex': + d = m[1].groupdict() + consts[d['id']] = int(d['hex'], base=16) + elif m[0] == '#define X': + d = m[1].groupdict() + if d['id2'] in consts: + consts[d['id']] = consts[d['id2']] + elif m[0] == '#define X+hex': + d = m[1].groupdict() + if d['id2'] in consts: + consts[d['id']] = consts[d['id2']] + int(d['hex'], base=16) + elif m[0] == '#define typedef': + d = m[1].groupdict() + if d['id2'] in consts: + periphs.append((d['id'], consts[d['id2']])) + elif m[0] == 'typedef struct': + lexer.must_match('{') + m = lexer.next_match() + regs = [] + while m[0] in ('IO reg', 'IO reg array'): + d = m[1].groupdict() + reg = d['reg'] + offset = int(d['offset'], base=16) + bits = int(d['bits']) + comment = d['comment'] + if m[0] == 'IO reg': + regs.append((reg, offset, bits, comment)) + else: + for i in range(int(d['array'])): + regs.append((reg + str(i), offset + i * bits // 8, bits, comment)) + m = lexer.next_match() + if m[0] == '}': + pass + elif m[0] == '} TypeDef': + reg_defs[m[1].groupdict()['id']] = regs + else: + raise LexerError(lexer.line_number) + + return periphs, reg_defs + +def print_periph(periph_name, periph_val, needed_qstrs): + qstr = periph_name.upper() + print('{ MP_OBJ_NEW_QSTR(MP_QSTR_%s), MP_OBJ_NEW_SMALL_INT(%#x) },' % (qstr, periph_val)) + needed_qstrs.add(qstr) + +def print_regs(reg_name, reg_defs, needed_qstrs): + reg_name = reg_name.upper() + for r in reg_defs: + qstr = reg_name + '_' + r[0] + print('{ MP_OBJ_NEW_QSTR(MP_QSTR_%s), MP_OBJ_NEW_SMALL_INT(%#x) }, // %s-bits, %s' % (qstr, r[1], r[2], r[3])) + needed_qstrs.add(qstr) + +# This version of print regs groups registers together into submodules (eg GPIO submodule). +# This makes the qstrs shorter, and makes the list of constants more manageable (since +# they are not all in one big module) but it is then harder to compile the constants, and +# is more cumbersome to access. +# As such, we don't use this version. +# And for the number of constants we have, this function seems to use about the same amount +# of ROM as print_regs. +def print_regs_as_submodules(reg_name, reg_defs, modules, needed_qstrs): + mod_name_lower = reg_name.lower() + '_' + mod_name_upper = mod_name_lower.upper() + modules.append((mod_name_lower, mod_name_upper)) + + print(""" +STATIC const mp_map_elem_t stm_%s_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_%s) }, +""" % (mod_name_lower, mod_name_upper)) + needed_qstrs.add(mod_name_upper) + + for r in reg_defs: + print(' { MP_OBJ_NEW_QSTR(MP_QSTR_%s), MP_OBJ_NEW_SMALL_INT(%#x) }, // %s-bits, %s' % (r[0], r[1], r[2], r[3])) + needed_qstrs.add(r[0]) + + print("""}; + +STATIC const mp_obj_dict_t stm_%s_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(stm_%s_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(stm_%s_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)stm_%s_globals_table, + }, +}; + +const mp_obj_module_t stm_%s_obj = { + .base = { &mp_type_module }, + .name = MP_QSTR_%s, + .globals = (mp_obj_dict_t*)&stm_%s_globals, +}; +""" % (mod_name_lower, mod_name_lower, mod_name_lower, mod_name_lower, mod_name_lower, mod_name_upper, mod_name_lower)) + +def main(): + cmd_parser = argparse.ArgumentParser(description='Extract ST constants from a C header file.') + cmd_parser.add_argument('file', nargs=1, help='input file') + args = cmd_parser.parse_args() + + periphs, reg_defs = parse_file(args.file[0]) + + modules = [] + needed_qstrs = set() + + print("// Automatically generated from %s by make-stmconst.py" % args.file[0]) + print("") + + for periph_name, periph_val in periphs: + print_periph(periph_name, periph_val, needed_qstrs) + + for reg in ( + 'ADC', + #'ADC_Common', + #'CAN_TxMailBox', + #'CAN_FIFOMailBox', + #'CAN_FilterRegister', + #'CAN', + 'CRC', + 'DAC', + 'DBGMCU', + 'DMA_Stream', + 'DMA', + 'EXTI', + 'FLASH', + 'GPIO', + 'SYSCFG', + 'I2C', + 'IWDG', + 'PWR', + 'RCC', + 'RTC', + #'SDIO', + 'SPI', + 'TIM', + 'USART', + 'WWDG', + 'RNG', + ): + print_regs(reg, reg_defs[reg], needed_qstrs) + #print_regs_as_submodules(reg, reg_defs[reg], modules, needed_qstrs) + + #print("#define MOD_STM_CONST_MODULES \\") + #for mod_lower, mod_upper in modules: + # print(" { MP_OBJ_NEW_QSTR(MP_QSTR_%s), (mp_obj_t)&stm_%s_obj }, \\" % (mod_upper, mod_lower)) + + print("") + + for qstr in sorted(needed_qstrs): + print('Q({})'.format(qstr)) + +if __name__ == "__main__": + main() |