|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- #!/usr/bin/env python
-
- # This file is part of the libopencm3 project.
- #
- # Copyright (C) 2012 chrysn <chrysn@fsfe.org>
- #
- # This library is free software: you can redistribute it and/or modify
- # it under the terms of the GNU Lesser General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This library is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU Lesser General Public License for more details.
- #
- # You should have received a copy of the GNU Lesser General Public License
- # along with this library. If not, see <http://www.gnu.org/licenses/>.
-
- """Generate an nvic.h header from a small JSON file describing the interrupt
- numbers.
-
- Code generation is chosen here because the resulting C code needs to be very
- repetetive (definition of the IRQ numbers, function prototypes, weak fallback
- definition and vector table definition), all being very repetitive. No portable
- method to achieve the same thing with C preprocessor is known to the author.
- (Neither is any non-portable method, for that matter.)"""
-
- import sys
- import os
- import os.path
- import json
-
- template_nvic_h = '''\
- /* This file is part of the libopencm3 project.
- *
- * It was generated by the irq2nvic_h script from {sourcefile}
- */
-
- #ifndef {includeguard}
- #define {includeguard}
-
- #include <libopencm3/cm3/nvic.h>
-
- /** @defgroup CM3_nvic_defines_irqs User interrupts for {partname_humanreadable}
- @ingroup CM3_nvic_defines
-
- @{{*/
-
- {irqdefinitions}
-
- #define NVIC_IRQ_COUNT {irqcount}
-
- /**@}}*/
-
- /** @defgroup CM3_nvic_isrprototypes_{partname_doxygen} User interrupt service routines (ISR) prototypes for {partname_humanreadable}
- @ingroup CM3_nvic_isrprototypes
-
- @{{*/
-
- BEGIN_DECLS
-
- {isrprototypes}
-
- END_DECLS
-
- /**@}}*/
-
- #endif /* {includeguard} */
- '''
-
- template_vector_nvic_c = '''\
- /* This file is part of the libopencm3 project.
- *
- * It was generated by the irq2nvic_h script.
- *
- * This part needs to get included in the compilation unit where
- * blocking_handler gets defined due to the way #pragma works.
- */
-
-
- /** @defgroup CM3_nvic_isrdecls_{partname_doxygen} User interrupt service routines (ISR) defaults for {partname_humanreadable}
- @ingroup CM3_nvic_isrdecls
-
- @{{*/
-
- {isrdecls}
-
- /**@}}*/
-
- /* Initialization template for the interrupt vector table. This definition is
- * used by the startup code generator (vector.c) to set the initial values for
- * the interrupt handling routines to the chip family specific _isr weak
- * symbols. */
-
- #define IRQ_HANDLERS \\
- {vectortableinitialization}
- '''
-
- template_cmsis_h = '''\
- /* This file is part of the libopencm3 project.
- *
- * It was generated by the irq2nvic_h script.
- *
- * These definitions bend every interrupt handler that is defined CMSIS style
- * to the weak symbol exported by libopencm3.
- */
-
- {cmsisbends}
- '''
-
- def convert(infile, outfile_nvic, outfile_vectornvic, outfile_cmsis):
- data = json.load(infile)
-
- irq2name = list(enumerate(data['irqs']) if isinstance(data['irqs'], list) else data['irqs'].items())
- irqnames = [v for (k,v) in irq2name]
-
- if isinstance(data['irqs'], list):
- data['irqcount'] = len(irq2name)
- else:
- data['irqcount'] = max([int(x) for x in data['irqs'].keys()]) + 1
-
- data['irqdefinitions'] = "\n".join('#define NVIC_%s_IRQ %d'%(v.upper(),int(k)) for (k,v) in irq2name)
- data['isrprototypes'] = "\n".join('void %s_isr(void);'%name.lower() for name in irqnames)
- data['isrdecls'] = "\n".join('void %s_isr(void) __attribute__((weak, alias("blocking_handler")));'%name.lower() for name in irqnames)
- data['vectortableinitialization'] = ', \\\n '.join('[NVIC_%s_IRQ] = %s_isr'%(name.upper(), name.lower()) for name in irqnames)
- data['cmsisbends'] = "\n".join("#define %s_IRQHandler %s_isr"%(name.upper(), name.lower()) for name in irqnames)
- data['sourcefile'] = infile.name
-
- outfile_nvic.write(template_nvic_h.format(**data))
- outfile_vectornvic.write(template_vector_nvic_c.format(**data))
- outfile_cmsis.write(template_cmsis_h.format(**data))
-
- def makeparentdir(filename):
- try:
- os.makedirs(os.path.dirname(filename))
- except OSError:
- # where is my 'mkdir -p'?
- pass
-
- def needs_update(infiles, outfiles):
- timestamp = lambda filename: os.stat(filename).st_mtime
- return any(not os.path.exists(o) for o in outfiles) or max(map(timestamp, infiles)) > min(map(timestamp, outfiles))
-
- def main():
- if sys.argv[1] == '--remove':
- remove = True
- del sys.argv[1]
- else:
- remove = False
- infile = sys.argv[1]
- if not infile.startswith('./include/libopencm3/') or not infile.endswith('/irq.json'):
- raise ValueError("Argument must match ./include/libopencm3/**/irq.json")
- nvic_h = infile.replace('irq.json', 'nvic.h')
- vector_nvic_c = infile.replace('./include/libopencm3/', './lib/').replace('irq.json', 'vector_nvic.c')
- cmsis = infile.replace('irq.json', 'irqhandlers.h').replace('/libopencm3/', '/libopencmsis/')
-
- if remove:
- if os.path.exists(nvic_h):
- os.unlink(nvic_h)
- if os.path.exists(vector_nvic_c):
- os.unlink(vector_nvic_c)
- if os.path.exists(cmsis):
- os.unlink(cmsis)
- sys.exit(0)
-
- if not needs_update([__file__, infile], [nvic_h, vector_nvic_c]):
- sys.exit(0)
-
- makeparentdir(nvic_h)
- makeparentdir(vector_nvic_c)
- makeparentdir(cmsis)
-
- convert(open(infile), open(nvic_h, 'w'), open(vector_nvic_c, 'w'), open(cmsis, 'w'))
-
- if __name__ == "__main__":
- main()
|