Source code for peakrdl_halcpp.exporter
import os
from typing import Union, Any, List, Dict
import shutil
from itertools import chain
import logging
import jinja2 as jj
from systemrdl.node import RootNode, AddrmapNode
from .halutils import *
from .halnode import *
[docs]
class HalExporter():
"""HAL C++ PeakRDL plugin top class to generate the C++ HAL from SystemRDL description.
Class methods:
- :func:`copy_base_headers`
- :func:`export`
- :func:`process_template`
"""
[docs]
def __init__(self, **kwargs: Any):
# Check for stray kwargs
if kwargs:
raise TypeError("got an unexpected keyword argument '%s'" %
list(kwargs.keys())[0])
#: HAL C++ copied header library location within the generated files output directory
self.cpp_dir = "include"
filetype = "*.h"
abspaths = os.path.join(os.path.dirname(__file__), self.cpp_dir)
#: HAL C++ headers list (copied into :attr:`~cpp_dir`)
self.base_headers = [f for f in os.listdir(
abspaths) if f.endswith(filetype[1:])]
[docs]
def export(self,
node: 'AddrmapNode',
outdir: str,
list_files: bool = False,
ext_modules: List = [str],
skip_buses: bool = False
):
"""Main function of the plugin extension.
Parameters
----------
node: AddrmapNode
Top AddrmapNode of the SystemRDL description.
outdir: str
Output directory in which the output files are generated.
list_files: bool = False
Don't generate but print the files that would be generated.
ext_modules: List[str]
List of modules (i.e., SystemRDL addrmap objects) with extended functionalities.
skip_buses: bool = False
If True, AddrMapNodes containing only AddrMapNodes (transparent buses)
are removed from the hierarchy and their children are promoted.
"""
# Check the node is an AddrmapNode object
if not isinstance(node, AddrmapNode):
raise TypeError(
"'node' argument expects type AddrmapNode. Got '%s'" % type(node).__name__)
halutils = HalUtils(ext_modules)
# Create top HalAddrmapNode from top AddrmapNode
top = HalAddrmapNode(node)
if not list_files:
# Create the output directory for the generated files
try:
os.makedirs(outdir)
except FileExistsError:
pass
# Copy the base header files (fixed code) to the output directory
self.copy_base_headers(outdir)
# Iterate over all the decendants of the top HalAddrmap object
concatenated_iterable = chain(top.haldescendants(
descendants_type=HalAddrmapNode, skip_buses=skip_buses, unique_orig_type=True), top)
if list_files:
print('INFO: Only listing files (no actual generation)')
for halnode in concatenated_iterable:
# Create the context for the template generation
context = {
'halnode': halnode,
'halutils': halutils,
'skip_buses': skip_buses,
'HalAddrmapNode': HalAddrmapNode,
'HalMemNode': HalMemNode,
'HalRegfileNode': HalRegfileNode,
'HalRegNode': HalRegNode,
'HalFieldNode': HalFieldNode,
}
# The next lines generate the C++ header file for the
# HalAddrmap node using a jinja2 template.
text = self.process_template(context)
# All addrmaps use the original type name (not instance name)
# This ensures include statements match the actual filenames
out_file = os.path.join(
outdir, halnode.orig_type_name_hal.lower() + ".h")
# Generate the files if --list-files parameter is not set
if list_files:
print('INFO: ' + out_file)
else:
print('INFO: Generated file: ' + out_file)
with open(out_file, 'w') as f:
f.write(text)
[docs]
def process_template(self, context: Dict) -> str:
"""Generates a C++ header file based on a jinja2 template.
Parameters
----------
context: Dict
Dictionary containing a HalAddrmapNode and the HalUtils object
(and other variables) passed to the jinja2 env
Returns
-------
str
Text of the generated C++ header for a given HalAddrmap node.
"""
# Create a jinja2 env with the template contained in the templates
# folder located in the same directory than this file
env = jj.Environment(
loader=jj.FileSystemLoader(
'%s/templates/' % os.path.dirname(__file__)),
trim_blocks=True,
lstrip_blocks=True)
# Add the base zip function to the env
env.filters.update({
'zip': zip,
})
# Render the C++ header text using the jinja2 template and the
# specific context
cpp_header_text = env.get_template("addrmap.h.j2").render(context)
return cpp_header_text