mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 15:08:39 +00:00
Add support for enumeration encoding
Fields that are encoded as enumerations are now recognized by the application. All relevant information will be saved in the Field Object and the variables and I/O list will be generated accordingly. This commit also adds dynamic padding of the I/O and variable lists. Still lacking is the automatic generation of SV packages.
This commit is contained in:
parent
085e2ea2dc
commit
b7c1a12179
@ -59,28 +59,49 @@ class AddrMap(Component):
|
|||||||
# Start assembling addrmap module
|
# Start assembling addrmap module
|
||||||
self.logger.info("Starting to assemble input/output/inout ports")
|
self.logger.info("Starting to assemble input/output/inout ports")
|
||||||
|
|
||||||
|
# Prefetch dictionaries in local array
|
||||||
|
input_dict_list = [(key, value) for (key, value) in self.get_ports('input').items()]
|
||||||
|
output_dict_list = [(key, value) for (key, value) in self.get_ports('output').items()]
|
||||||
|
|
||||||
|
input_signal_width = min(
|
||||||
|
max([len(value[0]) for (_, value) in input_dict_list]), 40)
|
||||||
|
|
||||||
|
input_name_width = min(
|
||||||
|
max([len(key) for (key, _) in input_dict_list]), 40)
|
||||||
|
|
||||||
|
output_signal_width = min(
|
||||||
|
max([len(value[0]) for (_, value) in output_dict_list]), 40)
|
||||||
|
|
||||||
|
output_name_width = min(
|
||||||
|
max([len(key) for (key, _) in output_dict_list]), 40)
|
||||||
|
|
||||||
|
|
||||||
# Input ports
|
# Input ports
|
||||||
input_ports_rtl = [
|
input_ports_rtl = [
|
||||||
AddrMap.templ_dict['input_port'].format(
|
AddrMap.templ_dict['input_port'].format(
|
||||||
name = key,
|
name = key,
|
||||||
signal_type = value[0],
|
signal_type = value[0],
|
||||||
|
signal_width = input_signal_width,
|
||||||
|
name_width = input_name_width,
|
||||||
unpacked_dim = '[{}]'.format(
|
unpacked_dim = '[{}]'.format(
|
||||||
']['.join(
|
']['.join(
|
||||||
[str(y) for y in value[1]]))
|
[str(y) for y in value[1]]))
|
||||||
if value[1] else '')
|
if value[1] else '')
|
||||||
for (key, value) in self.get_ports('input').items()
|
for (key, value) in input_dict_list
|
||||||
]
|
]
|
||||||
|
|
||||||
# Output ports
|
# Output ports
|
||||||
output_ports_rtl = [
|
output_ports_rtl = [
|
||||||
AddrMap.templ_dict['output_port'].format(
|
AddrMap.templ_dict['output_port'].format(
|
||||||
name = key,
|
name = key,
|
||||||
|
signal_width = output_signal_width,
|
||||||
|
name_width = output_name_width,
|
||||||
signal_type = value[0],
|
signal_type = value[0],
|
||||||
unpacked_dim = '[{}]'.format(
|
unpacked_dim = '[{}]'.format(
|
||||||
']['.join(
|
']['.join(
|
||||||
[str(y) for y in value[1]]))
|
[str(y) for y in value[1]]))
|
||||||
if value[1] else '')
|
if value[1] else '')
|
||||||
for (key, value) in self.get_ports('output').items()
|
for (key, value) in output_dict_list
|
||||||
]
|
]
|
||||||
|
|
||||||
# Remove comma from last port entry
|
# Remove comma from last port entry
|
||||||
|
@ -7,19 +7,16 @@ from systemrdl import node
|
|||||||
from log.log import create_logger
|
from log.log import create_logger
|
||||||
|
|
||||||
# Define NamedTuple
|
# Define NamedTuple
|
||||||
class TypeDefMembers(NamedTuple):
|
|
||||||
name: str
|
|
||||||
member_type: str
|
|
||||||
|
|
||||||
class TypeDef(NamedTuple):
|
class TypeDef(NamedTuple):
|
||||||
name: str
|
scope: str
|
||||||
members: list[TypeDefMembers]
|
members: tuple
|
||||||
|
|
||||||
class Component():
|
class Component():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.rtl_header = []
|
self.rtl_header = []
|
||||||
self.rtl_footer = []
|
self.rtl_footer = []
|
||||||
self.children = []
|
self.children = []
|
||||||
|
self.typedef = dict()
|
||||||
self.ports = dict()
|
self.ports = dict()
|
||||||
self.signals = dict()
|
self.signals = dict()
|
||||||
self.ports['input'] = dict()
|
self.ports['input'] = dict()
|
||||||
|
@ -2,12 +2,12 @@ import math
|
|||||||
import importlib.resources as pkg_resources
|
import importlib.resources as pkg_resources
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
|
from systemrdl.node import FieldNode, SignalNode
|
||||||
from systemrdl.node import FieldNode
|
from systemrdl.component import Reg, Regfile, Addrmap, Root
|
||||||
from systemrdl.rdltypes import PrecedenceType, AccessType, OnReadType, OnWriteType
|
from systemrdl.rdltypes import PrecedenceType, AccessType, OnReadType, OnWriteType
|
||||||
|
|
||||||
# Local modules
|
# Local modules
|
||||||
from components.component import Component
|
from components.component import Component, TypeDef
|
||||||
from . import templates
|
from . import templates
|
||||||
|
|
||||||
class Field(Component):
|
class Field(Component):
|
||||||
@ -16,7 +16,7 @@ class Field(Component):
|
|||||||
pkg_resources.read_text(templates, 'fields.yaml'),
|
pkg_resources.read_text(templates, 'fields.yaml'),
|
||||||
Loader=yaml.FullLoader)
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
def __init__(self, obj: node.FieldNode, array_dimensions: list, config:dict):
|
def __init__(self, obj: FieldNode, array_dimensions: list, config:dict):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
# Save and/or process important variables
|
# Save and/or process important variables
|
||||||
@ -26,6 +26,9 @@ class Field(Component):
|
|||||||
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
||||||
self.logger.debug('Starting to process field "{}"'.format(obj.inst_name))
|
self.logger.debug('Starting to process field "{}"'.format(obj.inst_name))
|
||||||
|
|
||||||
|
# Determine field types
|
||||||
|
self.__process_fieldtype()
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
# LIMITATION:
|
# LIMITATION:
|
||||||
# v1.x of the systemrdl-compiler does not support non-homogeneous arrays.
|
# v1.x of the systemrdl-compiler does not support non-homogeneous arrays.
|
||||||
@ -67,7 +70,73 @@ class Field(Component):
|
|||||||
[self.yaml_signals_to_list(Field.templ_dict[i[1]]) for i in operations]
|
[self.yaml_signals_to_list(Field.templ_dict[i[1]]) for i in operations]
|
||||||
|
|
||||||
|
|
||||||
def __process_variables(self, obj: node.RootNode, array_dimensions: list):
|
def __process_fieldtype(self):
|
||||||
|
try:
|
||||||
|
enum = self.obj.get_property('encode')
|
||||||
|
|
||||||
|
# Rules for scope:
|
||||||
|
# - Regfiles or addrmaps have packages
|
||||||
|
# - An enum that is not defined within a register will go into the package
|
||||||
|
# of the first addrmap or regfile that is found when iterating through
|
||||||
|
# the parents
|
||||||
|
# - Regfiles don't need to be unique in a design. Therefore, the packages of
|
||||||
|
# regfiles shall be prepended by the addrmap name.
|
||||||
|
# - When the enum is defined in a register, that register will be prepended
|
||||||
|
# to the name of that enum.
|
||||||
|
#
|
||||||
|
# This procedure is expensive, but None.parent() will not work and therefore
|
||||||
|
# kill the try block in most cases
|
||||||
|
parent_scope = enum.get_parent_scope()
|
||||||
|
|
||||||
|
self.logger.debug("Starting to parse '{}'".format(enum))
|
||||||
|
|
||||||
|
if isinstance(parent_scope, Reg):
|
||||||
|
enum_name = '__'.join([enum.get_scope_path().split('::')[-1], enum.__name__])
|
||||||
|
parent_scope = parent_scope.parent_scope
|
||||||
|
else:
|
||||||
|
enum_name = enum.__name__
|
||||||
|
|
||||||
|
path = []
|
||||||
|
|
||||||
|
# Open up all parent scopes and append it to scope list
|
||||||
|
while 1:
|
||||||
|
if isinstance(parent_scope, Regfile):
|
||||||
|
if parent_scope.is_instance:
|
||||||
|
path.append(parent_scope.inst_name)
|
||||||
|
else:
|
||||||
|
path.append(parent_scope.type_name)
|
||||||
|
|
||||||
|
# That's a lot of parent_scope's...
|
||||||
|
parent_scope = parent_scope.parent_scope
|
||||||
|
else:
|
||||||
|
path.append(self.owning_addrmap)
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
# Create string. Reverse list so that order starts at addrmap
|
||||||
|
scope = '__'.join(reversed(path))
|
||||||
|
|
||||||
|
# Create internal NamedTuple with information on Enum
|
||||||
|
self.typedef[enum_name] = TypeDef (
|
||||||
|
scope=scope,
|
||||||
|
members= [(x.name, x.value) for x in self.obj.get_property('encode')]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Save name of object
|
||||||
|
self.field_type =\
|
||||||
|
'::'.join([scope, enum_name])
|
||||||
|
|
||||||
|
self.logger.info("Parsed enum '{}'".format(enum_name))
|
||||||
|
|
||||||
|
except AttributeError:
|
||||||
|
# In case of an AttributeError, the encode property is None. Hence,
|
||||||
|
# the field has a simple width
|
||||||
|
if self.obj.width > 1:
|
||||||
|
self.field_type = 'logic [{}:0]'.format(self.obj.width-1)
|
||||||
|
else:
|
||||||
|
self.field_type = 'logic'
|
||||||
|
|
||||||
|
def __process_variables(self, obj: FieldNode, array_dimensions: list):
|
||||||
# Save object
|
# Save object
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
|
|
||||||
@ -81,9 +150,6 @@ class Field(Component):
|
|||||||
self.path_underscored = self.path.replace('.', '_')
|
self.path_underscored = self.path.replace('.', '_')
|
||||||
self.path_wo_field = '.'.join(self.path.split('.', -1)[0:-1])
|
self.path_wo_field = '.'.join(self.path.split('.', -1)[0:-1])
|
||||||
|
|
||||||
# Field type
|
|
||||||
self.field_type = 'logic'
|
|
||||||
|
|
||||||
# Save dimensions of unpacked dimension
|
# Save dimensions of unpacked dimension
|
||||||
self.array_dimensions = array_dimensions
|
self.array_dimensions = array_dimensions
|
||||||
|
|
||||||
@ -228,13 +294,13 @@ class Field(Component):
|
|||||||
swwe = self.obj.get_property('swwe')
|
swwe = self.obj.get_property('swwe')
|
||||||
swwel = self.obj.get_property('swwel')
|
swwel = self.obj.get_property('swwel')
|
||||||
|
|
||||||
if isinstance(swwe, (node.FieldNode, node.SignalNode)):
|
if isinstance(swwe, (FieldNode, SignalNode)):
|
||||||
access_rtl['sw_write'].append(
|
access_rtl['sw_write'].append(
|
||||||
Field.templ_dict['sw_access_field_swwe']['rtl'].format(
|
Field.templ_dict['sw_access_field_swwe']['rtl'].format(
|
||||||
path_wo_field = self.path_wo_field,
|
path_wo_field = self.path_wo_field,
|
||||||
genvars = self.genvars_str,
|
genvars = self.genvars_str,
|
||||||
swwe = Component.get_signal_name(swwe)))
|
swwe = Component.get_signal_name(swwe)))
|
||||||
elif isinstance(swwel, (node.FieldNode, node.SignalNode)):
|
elif isinstance(swwel, (FieldNode, SignalNode)):
|
||||||
access_rtl['sw_write'].append(
|
access_rtl['sw_write'].append(
|
||||||
Field.templ_dict['sw_access_field_swwel']['rtl'].format(
|
Field.templ_dict['sw_access_field_swwel']['rtl'].format(
|
||||||
path_wo_field = self.path_wo_field,
|
path_wo_field = self.path_wo_field,
|
||||||
|
@ -70,16 +70,24 @@ class Register(Component):
|
|||||||
self.yaml_signals_to_list(Register.templ_dict[rw_wire_assign_field])
|
self.yaml_signals_to_list(Register.templ_dict[rw_wire_assign_field])
|
||||||
|
|
||||||
# Add wire/register instantiations
|
# Add wire/register instantiations
|
||||||
|
dict_list = [(key, value) for (key, value) in self.get_signals().items()]
|
||||||
|
|
||||||
|
signal_width = min(max([len(value[0]) for (_, value) in dict_list]), 40)
|
||||||
|
|
||||||
|
name_width = min(max([len(key) for (key, _) in dict_list]), 40)
|
||||||
|
|
||||||
self.rtl_header = [
|
self.rtl_header = [
|
||||||
*[
|
*[
|
||||||
Register.templ_dict['signal_declaration'].format(
|
Register.templ_dict['signal_declaration'].format(
|
||||||
name = key,
|
name = key,
|
||||||
type = value[0],
|
type = value[0],
|
||||||
|
signal_width = signal_width,
|
||||||
|
name_width = name_width,
|
||||||
unpacked_dim = '[{}]'.format(
|
unpacked_dim = '[{}]'.format(
|
||||||
']['.join(
|
']['.join(
|
||||||
[str(y) for y in value[1]]))
|
[str(y) for y in value[1]]))
|
||||||
if value[1] else '')
|
if value[1] else '')
|
||||||
for (key, value) in self.get_signals().items()],
|
for (key, value) in dict_list],
|
||||||
'',
|
'',
|
||||||
*self.rtl_header,
|
*self.rtl_header,
|
||||||
]
|
]
|
||||||
|
@ -11,6 +11,6 @@ module_declaration: |-
|
|||||||
{outputs}
|
{outputs}
|
||||||
);
|
);
|
||||||
input_port: |-
|
input_port: |-
|
||||||
input {signal_type:15s}{name:25s} {unpacked_dim},
|
input {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
|
||||||
output_port: |-
|
output_port: |-
|
||||||
output {signal_type:15s}{name:25s} {unpacked_dim},
|
output {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
|
||||||
|
@ -47,4 +47,4 @@ generate_for_start: |-
|
|||||||
generate_for_end: |-
|
generate_for_end: |-
|
||||||
end // of for loop with iterator {dimension}
|
end // of for loop with iterator {dimension}
|
||||||
signal_declaration: |-
|
signal_declaration: |-
|
||||||
{type:10s}{name:20s} {unpacked_dim};
|
{type:{signal_width}} {name:{name_width}}{unpacked_dim};
|
||||||
|
Loading…
Reference in New Issue
Block a user