Closes #13: I/O ports are now grouped and are tied to the register the belong to

This commit is contained in:
Dennis Potter 2021-11-26 16:15:00 -08:00
parent 9d05c90d50
commit ae83dceb7a
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
6 changed files with 158 additions and 117 deletions

View File

@ -153,81 +153,55 @@ class AddrMap(Component):
for name in self.get_resets()
]
ports_rtl = []
# Prefetch dictionaries in local array
input_dict_list = self.get_ports('input').items()
output_dict_list = self.get_ports('output').items()
port_dict_list = self.get_ports().items()
input_signal_width = min(
max([len(value[0]) for (_, value) in input_dict_list]), 40)
for group, ports in port_dict_list:
ports_rtl.append(f"// Ports for '{group}'")
input_name_width = min(
max([len(key) for (key, _) in input_dict_list]), 40)
# Determine widths for this group
signal_width = max(
max([len(value.datatype) for (_, value) in ports.items()]), 12)
output_signal_width = min(
max([len(value[0]) for (_, value) in output_dict_list]), 40)
name_width = max([len(key) for (key, _) in ports.items()])
output_name_width = min(
max([len(key) for (key, _) in output_dict_list]), 40)
# Input ports
input_ports_rtl = []
for (key, value) in input_dict_list:
# Generate RTL
for (key, port_type) in ports.items():
# TODO: Think about a better way to handle datatypes. Simply replacing them
# is not the most efficient way of handling it.
signal_type = value[0].replace('logic', '').strip()
signal_type = port_type.datatype.replace('logic', '').strip()
if config['unpacked_arrays'] and value[1]:
unpacked_dim = f"[{']['.join([str(y) for y in value[1]])}]"
elif value[1]:
if config['unpacked_arrays'] and port_type.dim:
unpacked_dim = f"[{']['.join([str(y) for y in port_type.dim])}]"
elif port_type.dim:
unpacked_dim = ''
signal_type = ''.join([
f"[{':0]['.join([str(y-1) for y in value[1]])}:0]",
f"[{':0]['.join([str(y-1) for y in port_type.dim])}:0]",
signal_type
])
else:
unpacked_dim = ''
input_ports_rtl.append(
AddrMap.templ_dict['input_port']['rtl'].format(
ports_rtl.append(
AddrMap.templ_dict['port']['rtl'].format(
name = key,
direction = port_type.direction,
signal_type = signal_type,
signal_width = input_signal_width,
name_width = input_name_width,
signal_width = signal_width,
name_width = name_width,
unpacked_dim = unpacked_dim,
)
)
# Output ports
output_ports_rtl = []
for (key, value) in output_dict_list:
# TODO: Think about a better way to handle datatypes. Simply replacing them
# is not the most efficient way of handling it.
signal_type = value[0].replace('logic', '').strip()
if config['unpacked_arrays'] and value[1]:
unpacked_dim = f"[{']['.join([str(y) for y in value[1]])}]"
elif value[1]:
unpacked_dim = ''
signal_type = ''.join([
f"[{':0]['.join([str(y-1) for y in value[1]])}:0]",
signal_type
])
else:
unpacked_dim = ''
output_ports_rtl.append(
AddrMap.templ_dict['output_port']['rtl'].format(
name = key,
signal_type = signal_type,
signal_width = output_signal_width,
name_width = output_name_width,
unpacked_dim = unpacked_dim,
)
)
# Append a new line after every port
ports_rtl.append('')
# Remove last newline
# Remove comma from last port entry
output_ports_rtl[-1] = output_ports_rtl[-1].rstrip(',')
ports_rtl.pop()
ports_rtl[-1] = ports_rtl[-1].rstrip(',')
# Define packages to be included. Always include the
# b2w and w2b defines.
@ -268,8 +242,7 @@ class AddrMap(Component):
name = self.name,
import_package_list = ''.join(import_package_list),
resets = '\n'.join(reset_ports_rtl),
inputs = '\n'.join(input_ports_rtl),
outputs = '\n'.join(output_ports_rtl)))
ports = '\n'.join(ports_rtl)))
# Add description, if applicable
self.rtl_header.append(self.get_description())
@ -321,8 +294,8 @@ class AddrMap(Component):
def __add_signal_instantiation(self):
dict_list = list(self.get_signals(True).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)
signal_width = max(max([len(value.datatype) for (_, value) in dict_list]), 12)
name_width = max([len(key) for (key, _) in dict_list])
self.rtl_header = [
*self.rtl_header,
@ -330,13 +303,13 @@ class AddrMap(Component):
'// Internal signals',
*[AddrMap.templ_dict['signal_declaration'].format(
name = key,
type = value[0],
type = value.datatype,
signal_width = signal_width,
name_width = name_width,
unpacked_dim = '[{}]'.format(
']['.join(
[str(y) for y in value[1]]))
if value[1] else '')
[str(y) for y in value.dim]))
if value.dim else '')
for (key, value) in dict_list],
''
]

View File

@ -3,6 +3,7 @@ import math
import sys
from typing import NamedTuple, Optional
from dataclasses import dataclass
from enum import Enum
from systemrdl import node
@ -27,6 +28,15 @@ class SWMuxEntryDimensioned():
mux_entry: SWMuxEntry
dim: str
class SignalType(NamedTuple):
datatype: str
dim: list
class PortType(NamedTuple):
datatype: str
dim: list
direction: str # String "input" or "output"
class Component():
def __init__(
self,
@ -42,8 +52,6 @@ class Component():
self.ports = {}
self.resets = set()
self.signals = {}
self.ports['input'] = {}
self.ports['output'] = {}
self.field_type = ''
# Save object
@ -146,13 +154,19 @@ class Component():
return self.resets
def get_ports(self, port_type: str):
def get_ports(self):
self.logger.debug("Return port list")
for child in self.children.values():
self.ports[port_type] |= child.get_ports(port_type)
for key, value in child.get_ports().items():
if key in self.ports:
self.logger.debug("Group '%s' already present in port list")
self.ports[key] |= value
else:
self.logger.debug("Adding group '%s' to port list")
self.ports |= {key: value}
return self.ports[port_type]
return self.ports
def get_max_dim_depth(self) -> int:
self.logger.debug("Return depth '%s' for dimensions (including parents) '%s'.",
@ -285,8 +299,12 @@ class Component():
name.append('_q')
elif isinstance(obj, node.SignalNode):
# Must add it to signal list
self.ports['input'][obj.inst_name] =\
("logic" if obj.width == 1 else f"logic [{obj.width}:0]", [])
self.ports['Signals'][obj.inst_name] =\
PortType (
datatype = "logic" if obj.width == 1 else f"logic [{obj.width}:0]",
dim = [],
direction = "input"
)
else:
name.append('_')
name.append(obj.name)
@ -325,8 +343,10 @@ class Component():
array_dimensions = self.total_array_dimensions
self.signals[signal['name'].format(**values)] =\
(signal['signal_type'].format(**values),
array_dimensions)
SignalType (
datatype = signal['signal_type'].format(**values),
dim = array_dimensions,
)
except (TypeError, KeyError):
pass
@ -341,9 +361,29 @@ class Component():
except KeyError:
array_dimensions = self.total_array_dimensions
self.ports['input'][input_p['name'].format(**values)] =\
(input_p['signal_type'].format(**values),
array_dimensions)
try:
group = input_p['group'].format(**values)
except KeyError:
group = self.path_underscored_wo_field
name = input_p['name'].format(**values)
if group not in self.ports:
self.ports[group] = {
name:
PortType (
datatype = input_p['signal_type'].format(**values),
dim = array_dimensions,
direction = "input",
)
}
elif name not in self.ports[group]:
self.ports[group][name] =\
PortType (
datatype = input_p['signal_type'].format(**values),
dim = array_dimensions,
direction = "input",
)
except (TypeError, KeyError):
pass
@ -358,9 +398,29 @@ class Component():
except KeyError:
array_dimensions = self.total_array_dimensions
self.ports['output'][output_p['name'].format(**values)] =\
(output_p['signal_type'].format(**values),
array_dimensions)
try:
group = output_p['group'].format(**values)
except KeyError:
group = self.path_underscored_wo_field
name = output_p['name'].format(**values)
if group not in self.ports:
self.ports[group] = {
name:
PortType (
datatype = output_p['signal_type'].format(**values),
dim = array_dimensions,
direction = "output",
)
}
elif name not in self.ports[group]:
self.ports[group][name] =\
PortType (
datatype = output_p['signal_type'].format(**values),
dim = array_dimensions,
direction = "output",
)
except (TypeError, KeyError):
pass
@ -371,6 +431,9 @@ class Component():
self.owning_addrmap, self.full_path, self.path, self.path_underscored =\
Component.create_underscored_path_static(self.obj)
# By default, this is identical to path_underscored. Fields will override this
self.path_underscored_wo_field = self.path_underscored
@staticmethod
def create_underscored_path_static(obj):
owning_addrmap = obj.owning_addrmap.inst_name

View File

@ -110,10 +110,11 @@ class Field(Component):
else:
path = self.path
path_wo_field = '__'.join(path.split('.', -1)[0:-1])
# This is different than self.path_underscored_wo_field
path_underscored_wo_field = '__'.join(path.split('.', -1)[0:-1])
# path_wo_field_vec & path_undrescored_vec only used for external registers
self.path_wo_field_vec.append(path_wo_field)
self.path_wo_field_vec.append(path_underscored_wo_field)
self.path_underscored_vec.append(alias_path_underscored if alias else self.path_underscored)
# Define software access (if applicable)
@ -121,7 +122,7 @@ class Field(Component):
if self.properties['sw_wr']:
# Append to list of registers that can write
self.writable_by.add(path_wo_field)
self.writable_by.add(path_underscored_wo_field)
# This will need a wire to indicate that a write is taking place
self.properties['sw_wr_wire'] = True
@ -133,7 +134,7 @@ class Field(Component):
access_rtl['sw_write'][0].append(
self._process_yaml(
Field.templ_dict['sw_access_field_swwe'],
{'path_wo_field': path_wo_field,
{'path_wo_field': path_underscored_wo_field,
'genvars': self.genvars_str,
'swwe': self.get_signal_name(swwe),
'field_type': self.field_type}
@ -143,7 +144,7 @@ class Field(Component):
access_rtl['sw_write'][0].append(
self._process_yaml(
Field.templ_dict['sw_access_field_swwel'],
{'path_wo_field': path_wo_field,
{'path_wo_field': path_underscored_wo_field,
'genvars': self.genvars_str,
'swwel': self.get_signal_name(swwel),
'field_type': self.field_type}
@ -153,7 +154,7 @@ class Field(Component):
access_rtl['sw_write'][0].append(
self._process_yaml(
Field.templ_dict['sw_access_field'],
{'path_wo_field': path_wo_field,
{'path_wo_field': path_underscored_wo_field,
'genvars': self.genvars_str,
'field_type': self.field_type}
)
@ -211,7 +212,7 @@ class Field(Component):
if obj.get_property('sw') in (AccessType.rw, AccessType.r):
# Append to list of registers that can read
self.readable_by.add(path_wo_field)
self.readable_by.add(path_underscored_wo_field)
self.properties['sw_rd'] = True
@ -224,7 +225,7 @@ class Field(Component):
access_rtl['sw_read'][0].append(
self._process_yaml(
Field.templ_dict['sw_read_access_field'],
{'path_wo_field': path_wo_field,
{'path_wo_field': path_underscored_wo_field,
'genvars': self.genvars_str,
'field_type': self.field_type}
)
@ -711,7 +712,7 @@ class Field(Component):
self._process_yaml(
Field.templ_dict['swmod_assign'],
{'path': self.path_underscored,
'path_wo_field': self.path_wo_field,
'path_wo_field': self.path_underscored_wo_field,
'genvars': self.genvars_str,
'rd_wr': 'rd',
'msbyte': self.msbyte,
@ -727,7 +728,7 @@ class Field(Component):
self._process_yaml(
Field.templ_dict['swmod_assign'],
{'path': self.path_underscored,
'path_wo_field': self.path_wo_field,
'path_wo_field': self.path_underscored_wo_field,
'genvars': self.genvars_str,
'rd_wr': 'wr',
'msbyte': self.msbyte,
@ -762,7 +763,7 @@ class Field(Component):
swacc_props = self._process_yaml(
Field.templ_dict['swacc_assign'],
{'path': self.path_underscored,
'path_wo_field': self.path_wo_field,
'path_wo_field': self.path_underscored_wo_field,
'genvars': self.genvars_str,
'msbyte': self.msbyte,
'lsbyte': self.lsbyte,
@ -1349,7 +1350,7 @@ class Field(Component):
self,
obj: FieldNode):
# Create full name
self.path_wo_field = '__'.join(self.path.split('.', -1)[0:-1])
self.path_underscored_wo_field = '__'.join(self.path.split('.', -1)[0:-1])
self.register_name = ''.join([self.path_underscored, '_q'])
self.path_underscored_vec = []
@ -1451,7 +1452,7 @@ class Field(Component):
external = self.config['external'],
lsb = self.obj.lsb,
msb = self.obj.msb,
path_wo_field = self.path_wo_field,
path_wo_field = self.path_underscored_wo_field,
storage_type = self.storage_type,
)

View File

@ -511,20 +511,18 @@ class Register(Component):
def get_signal_instantiations_list(self):
dict_list = list(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)
signal_width = max(max([len(value.datatype) for (_, value) in dict_list]), 12)
name_width = max([len(key) for (key, _) in dict_list])
return [Register.templ_dict['signal_declaration'].format(
name = key,
type = value[0],
type = value.datatype,
signal_width = signal_width,
name_width = name_width,
unpacked_dim = '[{}]'.format(
']['.join(
[str(y) for y in value[1]]))
if value[1] else '')
[str(y) for y in value.dim]))
if value.dim else '')
for (key, value) in dict_list]
def add_alias(self, obj: node.RegNode):

View File

@ -75,14 +75,11 @@ module_declaration:
<<UNINDENT>>
(
<<INDENT>>
// Resets
// Reset signals declared for registers
{resets}
// Inputs
{inputs}
{ports}
// Outputs
{outputs}
<<UNINDENT>>
);
import_package:
@ -91,12 +88,9 @@ import_package:
reset_port:
rtl:
input {name},
input_port:
rtl:
input {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
output_port:
rtl:
output {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
port:
rtl: |-
{direction:6} {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
signal_declaration: |-
{type:{signal_width}} {name:{name_width}}{unpacked_dim};
package_declaration:

View File

@ -40,26 +40,38 @@ module_instantiation:
input_ports:
- name: 'clk'
signal_type: ''
group: 'General Clock'
- name: 'HRESETn'
signal_type: ''
group: 'AHB Protocol'
- name: 'HADDR'
signal_type: '[31:0]'
group: 'AHB Protocol'
- name: 'HWRITE'
signal_type: ''
group: 'AHB Protocol'
- name: 'HSIZE'
signal_type: '[2:0]'
group: 'AHB Protocol'
- name: 'HPROT'
signal_type: '[3:0]'
group: 'AHB Protocol'
- name: 'HTRANS'
signal_type: '[1:0]'
group: 'AHB Protocol'
- name: 'HWDATA'
signal_type: '[{bus_width}-1:0]'
group: 'AHB Protocol'
- name: 'HSEL'
signal_type: ''
group: 'AHB Protocol'
output_ports:
- name: 'HREADYOUT'
signal_type: ''
group: 'AHB Protocol'
- name: 'HRESP'
signal_type: ''
group: 'AHB Protocol'
- name: 'HRDATA'
signal_type: '[{bus_width}-1:0]'
group: 'AHB Protocol'