Skip to content

tools: added tool for auto-generating ISR vectors#7553

Closed
haukepetersen wants to merge 4 commits intoRIOT-OS:masterfrom
haukepetersen:add_tool_isrvecgen
Closed

tools: added tool for auto-generating ISR vectors#7553
haukepetersen wants to merge 4 commits intoRIOT-OS:masterfrom
haukepetersen:add_tool_isrvecgen

Conversation

@haukepetersen
Copy link
Copy Markdown
Contributor

Creating the ISR vector tables is error prone and cumbersome, so why don't we just do it automatically?!

This PR proposes a tool that parses CMSIS-style header files and outputs a compact version of vector table(s), for a single CPU or a group of CPU models. I parses the list of CPU(s) from the cpu_conf.h files, using the `#include' statements in those files to find the header files.

The output table style depends on #7535.

I tested the tools for all the STM and the Kinetis CPUs, and the results are valid as far as I can see and test it. But as I am a poor python noob, the code of the tool might be far from perfect... But instead of having a thousand change requests, I would prefer to merge it in the current state and improve it with separate PRs: this way we can already use the tool for cleaning up existing vector definitions while tuning the tool itself...

@haukepetersen haukepetersen added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Area: tools Area: Supplementary tools labels Sep 1, 2017
@haukepetersen haukepetersen added this to the Release 2017.10 milestone Sep 1, 2017
Copy link
Copy Markdown
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks quite good. This tool is definitely useful.
I pointed to mainly small python style issues.
I'll test it when time permits.

"isr_exti[_\d+]+": "isr_exti"
}

def parse_cpuconf( cpuconf ):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8, no space around parameter, here and below

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good to know, will fix.

@@ -0,0 +1,200 @@
#!/usr/bin/env python3
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why making this only python 3 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no idea, thought I'll try to be 'modern' :-)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there still major distros or OSs that do not supply python 3 (it has not to be the default)? Even the grand old ladies Debian and CentOS have python 3 now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think mac OS users have python3 installed by default

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is not needed for building, having python3 as dependency should be fine.

pat_cpu = re.compile("CPU_MODEL_([0-9A-Z]+)")

for m in pat_line.finditer(buf):
header = ("%s/%s" % (path, m.group(5)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parenthesis are useless. Prefer using format

m = re.match(" +([_0-9A-Za-z]+)_IRQn += (-?\d+),? +(/\*!<|/\*\*<) (.+[a-zA-Z0-9]) +\*/", line)
if m:
num = int(m.group(2))
name = ("isr_%s" % (m.group(1).lower()))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parenthesis, here and the line below

headermap = dict()

alias = {
"isr_exti[_\d+]+": "isr_exti"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be on one line

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could, but as this list is meant to be extended, I figured to start with a good style right away. I am thinking about even putting the filters in some external config file in the future...


def parse_header( file, cpus ):
filename = os.path.basename(file)
res = { "cpus": cpus, "vec": {} };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no space after { and before }, here and in other places

for num in common:
for a in alias:
m = re.match(a, common[num]["name"])
if m:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure m is mandatory ?

if re.match(a, common[num]["name"]):
    common[num]["name"] = alias[a]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, will fix

for num in cl["vec"]:
for a in alias:
m = re.match(a, cl["vec"][num]["name"])
if m:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

res += " || \\\n "
elif i & 0x1:
res += " ||"
res += (" defined(%s)" % (cpu))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parenthesis

# read through file and find all lines
with open(file, 'r', encoding = "ISO-8859-1") as f:
for line in f:
m = re.match(" +([_0-9A-Za-z]+)_IRQn += (-?\d+),? +(/\*!<|/\*\*<) (.+[a-zA-Z0-9]) +\*/", line)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is too long (PEP8), it should be 80 characters long max.

@jnohlgard
Copy link
Copy Markdown
Member

I started toying with the idea of unifying the Kinetis K CPUs (k60, k64f, K22f) as a single CPU directory kinetis_k. I have some wip files which I haven't published anywhere yet, and I don't have time to work on it right now, but I can push it later today in case you find a use for it in this PR. The plan for kinetis_k includes generating the isr vectors from the header, and parsing the model name to find the correct ldscript and some other info.

@haukepetersen
Copy link
Copy Markdown
Contributor Author

nice, sharing your starters won't hurt. Would be interesting to see what else we could generate to make porting even more simple

@jnohlgard
Copy link
Copy Markdown
Member

@jnohlgard
Copy link
Copy Markdown
Member

@haukepetersen this is my WIP/experiment branch: https://github.com/gebart/RIOT/commits/wip/kinetis-k not much there so far, other than a sed version of the ISR vector generator and some makefile magic for splitting the model number into separate properties for family, subfamily, memory size, etc.

@haukepetersen
Copy link
Copy Markdown
Contributor Author

fixed python style issues.

Copy link
Copy Markdown
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe adding a README ?

@haukepetersen
Copy link
Copy Markdown
Contributor Author

Sure. Also found some other minor things, will push later today

Copy link
Copy Markdown
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-read the script and found other things:

  • one typo
  • missing docstring
  • some refactoring is needed

A general comment: try to use variables with explicit names. It helps understand the code by improving readability.

@@ -0,0 +1,18 @@
Overivew
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/Overivew/Overview/

from operator import itemgetter

cpulist = set()
headermap = dict()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scope of variable can be reduced: the function parse_cpuconf can return this dict.

import copy
from operator import itemgetter

cpulist = set()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment for this global variable. By the way, the same variable name is used internally in other functions, this looks weird:

for cpulist in specific:
    ...

for example


alias = {"isr_exti[_\d+]+": "isr_exti"}

def parse_cpuconf(cpuconf):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding some docstrings won't hurt



def parse_header(file, cpus):
filename = os.path.basename(file)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstring missing

cl["vec"][num]["name"] = alias[a]


def depstr(cpus, prefix):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstring missing + try to be explicit with function names. We are not writing C code

return res + "\n"


def pull_common_vectors(specific):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstring

specific.append(parse_header(h, headermap[h]))

# list items by CPU name
specific = sorted(specific, key=lambda k: sorted(list(k["cpus"]))[0])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is personal opinion but in general I tend to avoid this kind of oneliner, for code readability reasons.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is perfectly readable and one very good example why lamdas are so useful :-)


if __name__ == "__main__":
# Define some command line args
p = argparse.ArgumentParser()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/p/parser/

return table


if __name__ == "__main__":
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot of code in this block, adding a main function is required:

def main(args):
    ...

# call it with:
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("cpu_conf", help="path to a cpu_conf.h file")
    main(parser.parse_args())

@haukepetersen
Copy link
Copy Markdown
Contributor Author

Hm, this is getting too cumbersome for me, don't see myself putting so much effort into a small helper tool... Will put this tool in its own repo. I welcome anyone to beautify it and move it to the RIOT repo, but I don't see myself spending so much time on this...

@haukepetersen
Copy link
Copy Markdown
Contributor Author

The current version of the tool resides now here:
https://github.com/haukepetersen/riotsandbox/tree/master/tools/isrvecgen

So as said, feel free to copy/adapt/move to RIOT...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: tools Area: Supplementary tools CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants