libopencm3/scripts/irq2nvic_h

178 lines
5.6 KiB
Plaintext
Raw Permalink Normal View History

#!/usr/bin/env python3
2012-10-18 10:26:41 +00:00
# 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
2015-12-11 16:46:44 +00:00
method to achieve the same thing with C preprocessor is known to the author.
(Neither is any non-portable method, for that matter.)"""
2012-10-18 10:26:41 +00:00
import sys
import os
import os.path
import json
2012-10-18 10:26:41 +00:00
template_nvic_h = '''\
2012-10-18 10:26:41 +00:00
/* This file is part of the libopencm3 project.
*
* It was generated by the irq2nvic_h script from {sourcefile}
2012-10-18 10:26:41 +00:00
*/
#ifndef {includeguard}
#define {includeguard}
#include <libopencm3/cm3/nvic.h>
/** @defgroup CM3_nvic_defines_irqs User interrupts for {partname_humanreadable}
2012-10-18 10:26:41 +00:00
@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
2012-10-18 10:26:41 +00:00
{isrprototypes}
END_DECLS
2012-10-18 10:26:41 +00:00
/**@}}*/
#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
2012-10-18 10:26:41 +00:00
@{{*/
{isrdecls}
2012-10-18 10:26:41 +00:00
/**@}}*/
/* 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)
2012-10-18 10:26:41 +00:00
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)
2012-10-18 10:26:41 +00:00
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
2012-10-18 10:26:41 +00:00
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))
2012-10-18 10:26:41 +00:00
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))
2012-10-18 10:26:41 +00:00
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'):
2015-12-11 16:46:44 +00:00
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'))
2012-10-18 10:26:41 +00:00
if __name__ == "__main__":
main()