mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 15:08:39 +00:00
Add initial support for memory type registers
This commit is contained in:
parent
fd7acae701
commit
4d3f302a54
@ -9,6 +9,7 @@ from systemrdl import node
|
|||||||
from components.component import Component
|
from components.component import Component
|
||||||
from components.regfile import RegFile
|
from components.regfile import RegFile
|
||||||
from components.register import Register
|
from components.register import Register
|
||||||
|
from components.memory import Memory
|
||||||
from . import templates
|
from . import templates
|
||||||
from . import widgets
|
from . import widgets
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ class AddrMap(Component):
|
|||||||
# by name (for example, in case of aliases)
|
# by name (for example, in case of aliases)
|
||||||
self.registers = dict()
|
self.registers = dict()
|
||||||
self.regfiles = dict()
|
self.regfiles = dict()
|
||||||
|
self.mems = dict()
|
||||||
self.regwidth = 0
|
self.regwidth = 0
|
||||||
|
|
||||||
# Traverse through children
|
# Traverse through children
|
||||||
@ -55,8 +57,11 @@ class AddrMap(Component):
|
|||||||
self.logger.info('Found hierarchical addrmap. Entering it...')
|
self.logger.info('Found hierarchical addrmap. Entering it...')
|
||||||
self.logger.error('Child addrmaps are not implemented yet!')
|
self.logger.error('Child addrmaps are not implemented yet!')
|
||||||
elif isinstance(child, node.RegfileNode):
|
elif isinstance(child, node.RegfileNode):
|
||||||
self.regfiles[child.inst_name] = \
|
new_child = RegFile(child, [], [], config, glbl_settings)
|
||||||
RegFile(child, [], [], config, glbl_settings)
|
self.regfiles[child.inst_name] = new_child
|
||||||
|
elif isinstance(child, node.MemNode):
|
||||||
|
new_child = Memory(child, [], [], config, glbl_settings)
|
||||||
|
self.mems[child.inst_name] = new_child
|
||||||
elif isinstance(child, node.RegNode):
|
elif isinstance(child, node.RegNode):
|
||||||
if child.inst.is_alias:
|
if child.inst.is_alias:
|
||||||
# If the node we found is an alias, we shall not create a
|
# If the node we found is an alias, we shall not create a
|
||||||
@ -65,11 +70,11 @@ class AddrMap(Component):
|
|||||||
self.registers[child.inst.alias_primary_inst.inst_name]\
|
self.registers[child.inst.alias_primary_inst.inst_name]\
|
||||||
.add_alias(child)
|
.add_alias(child)
|
||||||
else:
|
else:
|
||||||
self.registers[child.inst_name] = \
|
new_child = Register(child, [], [], config, glbl_settings)
|
||||||
Register(child, [], [], config, glbl_settings)
|
self.registers[child.inst_name] = new_child
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if (regwidth := self.registers[child.inst_name].get_regwidth()) > self.regwidth:
|
if (regwidth := new_child.get_regwidth()) > self.regwidth:
|
||||||
self.regwidth = regwidth
|
self.regwidth = regwidth
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Simply ignore nodes like SignalNodes
|
# Simply ignore nodes like SignalNodes
|
||||||
@ -80,12 +85,12 @@ class AddrMap(Component):
|
|||||||
|
|
||||||
# Add registers to children. This must be done in a last step
|
# Add registers to children. This must be done in a last step
|
||||||
# to account for all possible alias combinations
|
# to account for all possible alias combinations
|
||||||
self.children = {**self.regfiles, **self.registers}
|
self.children = {**self.regfiles, **self.registers, **self.mems}
|
||||||
|
|
||||||
self.logger.info("Done generating all child-regfiles/registers")
|
self.logger.info("Done generating all child-regfiles/registers")
|
||||||
|
|
||||||
# Create RTL of all registers. Registers in regfiles are
|
# Create RTL of all registers. Registers in regfiles are
|
||||||
# already built.
|
# already built and so are memories.
|
||||||
[x.create_rtl() for x in self.registers.values()]
|
[x.create_rtl() for x in self.registers.values()]
|
||||||
|
|
||||||
# Add bus widget ports
|
# Add bus widget ports
|
||||||
@ -119,6 +124,7 @@ class AddrMap(Component):
|
|||||||
|
|
||||||
|
|
||||||
# Input ports
|
# Input ports
|
||||||
|
# Yay for unreadable code....
|
||||||
input_ports_rtl = [
|
input_ports_rtl = [
|
||||||
AddrMap.templ_dict['input_port']['rtl'].format(
|
AddrMap.templ_dict['input_port']['rtl'].format(
|
||||||
name = key,
|
name = key,
|
||||||
@ -215,6 +221,9 @@ class AddrMap(Component):
|
|||||||
self.rtl_footer.append('endmodule')
|
self.rtl_footer.append('endmodule')
|
||||||
|
|
||||||
def __create_mux_string(self):
|
def __create_mux_string(self):
|
||||||
|
#TODO: For optimal synthesis results, think about using 1B offsets rather than awkard 4B.
|
||||||
|
# for byte-access, byte-enables are used anyway
|
||||||
|
|
||||||
# Define default case
|
# Define default case
|
||||||
list_of_cases = [AddrMap.templ_dict['default_mux_case']['rtl']]
|
list_of_cases = [AddrMap.templ_dict['default_mux_case']['rtl']]
|
||||||
|
|
||||||
@ -234,12 +243,17 @@ class AddrMap(Component):
|
|||||||
r2b_data = ''.join([mux_entry[0][0], mux_entry[1][1]])
|
r2b_data = ''.join([mux_entry[0][0], mux_entry[1][1]])
|
||||||
r2b_rdy = ''.join([mux_entry[0][1], mux_entry[1][1]])
|
r2b_rdy = ''.join([mux_entry[0][1], mux_entry[1][1]])
|
||||||
r2b_err = ''.join([mux_entry[0][2], mux_entry[1][1]])
|
r2b_err = ''.join([mux_entry[0][2], mux_entry[1][1]])
|
||||||
index = mux_entry[0][3] + mux_entry[1][0]
|
|
||||||
|
if child.__class__.__name__ == "Memory":
|
||||||
|
index = \
|
||||||
|
f"[{self.config['addrwidth']}'d{mux_entry[0][3][0]}:"\
|
||||||
|
f"{self.config['addrwidth']}'d{mux_entry[0][3][1]}]"
|
||||||
|
else:
|
||||||
|
index = f"{self.config['addrwidth']}'d{mux_entry[0][3] + mux_entry[1][0]}"
|
||||||
|
|
||||||
list_of_cases.append(
|
list_of_cases.append(
|
||||||
AddrMap.templ_dict['list_of_mux_cases']['rtl'].format(
|
AddrMap.templ_dict['list_of_mux_cases']['rtl'].format(
|
||||||
index = index,
|
index = index,
|
||||||
bus_width = self.config['addrwidth'],
|
|
||||||
r2b_data = r2b_data,
|
r2b_data = r2b_data,
|
||||||
r2b_rdy = r2b_rdy,
|
r2b_rdy = r2b_rdy,
|
||||||
r2b_err = r2b_err)
|
r2b_err = r2b_err)
|
||||||
@ -393,13 +407,3 @@ class AddrMap(Component):
|
|||||||
|
|
||||||
def get_regwidth(self) -> int:
|
def get_regwidth(self) -> int:
|
||||||
return self.regwidth
|
return self.regwidth
|
||||||
|
|
||||||
def get_description(self):
|
|
||||||
if self.config['descriptions']['addrmap']:
|
|
||||||
if desc := self.obj.get_property('desc'):
|
|
||||||
return self.process_yaml(
|
|
||||||
AddrMap.templ_dict['addrmap_desc'],
|
|
||||||
{'desc': desc},
|
|
||||||
)
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
@ -247,9 +247,14 @@ class Component():
|
|||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
for x in yaml_obj['signals']:
|
for x in yaml_obj['signals']:
|
||||||
|
try:
|
||||||
|
array_dimensions = [] if x['no_unpacked'] else self.total_array_dimensions
|
||||||
|
except KeyError:
|
||||||
|
array_dimensions = self.total_array_dimensions
|
||||||
|
|
||||||
self.signals[x['name'].format(**values)] =\
|
self.signals[x['name'].format(**values)] =\
|
||||||
(x['signal_type'].format(**values),
|
(x['signal_type'].format(**values),
|
||||||
self.total_array_dimensions)
|
array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -258,9 +263,14 @@ class Component():
|
|||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
for x in yaml_obj['input_ports']:
|
for x in yaml_obj['input_ports']:
|
||||||
|
try:
|
||||||
|
array_dimensions = [] if x['no_unpacked'] else self.total_array_dimensions
|
||||||
|
except KeyError:
|
||||||
|
array_dimensions = self.total_array_dimensions
|
||||||
|
|
||||||
self.ports['input'][x['name'].format(**values)] =\
|
self.ports['input'][x['name'].format(**values)] =\
|
||||||
(x['signal_type'].format(**values),
|
(x['signal_type'].format(**values),
|
||||||
self.total_array_dimensions)
|
array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -269,9 +279,14 @@ class Component():
|
|||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
for x in yaml_obj['output_ports']:
|
for x in yaml_obj['output_ports']:
|
||||||
|
try:
|
||||||
|
array_dimensions = [] if x['no_unpacked'] else self.total_array_dimensions
|
||||||
|
except KeyError:
|
||||||
|
array_dimensions = self.total_array_dimensions
|
||||||
|
|
||||||
self.ports['output'][x['name'].format(**values)] =\
|
self.ports['output'][x['name'].format(**values)] =\
|
||||||
(x['signal_type'].format(**values),
|
(x['signal_type'].format(**values),
|
||||||
self.total_array_dimensions)
|
array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -319,3 +334,12 @@ class Component():
|
|||||||
|
|
||||||
return (owning_addrmap, full_path, path, path_underscored)
|
return (owning_addrmap, full_path, path, path_underscored)
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
if self.config['descriptions'][self.__class__.__name__]:
|
||||||
|
if desc := self.obj.get_property('desc'):
|
||||||
|
return self.process_yaml(
|
||||||
|
self.templ_dict['description'],
|
||||||
|
{'desc': desc},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ''
|
||||||
|
@ -1372,13 +1372,3 @@ class Field(Component):
|
|||||||
self.logger.error("It's not possible to combine the sticky(bit) "\
|
self.logger.error("It's not possible to combine the sticky(bit) "\
|
||||||
"property with the counter property. The counter property "\
|
"property with the counter property. The counter property "\
|
||||||
"will be ignored.")
|
"will be ignored.")
|
||||||
|
|
||||||
def get_description(self):
|
|
||||||
if self.config['descriptions']['field']:
|
|
||||||
if desc := self.obj.get_property('desc'):
|
|
||||||
return self.process_yaml(
|
|
||||||
Field.templ_dict['field_desc'],
|
|
||||||
{'desc': desc},
|
|
||||||
)
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
210
srdl2sv/components/memory.py
Normal file
210
srdl2sv/components/memory.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
import re
|
||||||
|
import importlib.resources as pkg_resources
|
||||||
|
import sys
|
||||||
|
import math
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from systemrdl import node
|
||||||
|
from systemrdl.node import FieldNode
|
||||||
|
from systemrdl.rdltypes import AccessType
|
||||||
|
|
||||||
|
# Local packages
|
||||||
|
from components.component import Component
|
||||||
|
from . import templates
|
||||||
|
|
||||||
|
|
||||||
|
class Memory(Component):
|
||||||
|
# Save YAML template as class variable
|
||||||
|
templ_dict = yaml.load(
|
||||||
|
pkg_resources.read_text(templates, 'memory.yaml'),
|
||||||
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
obj: node.RegfileNode,
|
||||||
|
parents_dimensions: list,
|
||||||
|
parents_stride: list,
|
||||||
|
config: dict,
|
||||||
|
glbl_settings: dict):
|
||||||
|
super().__init__(obj, config)
|
||||||
|
|
||||||
|
# Save and/or process important variables
|
||||||
|
self.__process_variables(obj, parents_dimensions, parents_stride, glbl_settings)
|
||||||
|
|
||||||
|
# Set object to 0 for easy addressing
|
||||||
|
self.obj.current_idx = [0]
|
||||||
|
|
||||||
|
# When in a memory, we are not going to traverse through any of the
|
||||||
|
# children. This is a simple pass-through between software and a
|
||||||
|
# fixed memory block
|
||||||
|
|
||||||
|
self.rtl_header.append(
|
||||||
|
self.process_yaml(
|
||||||
|
Memory.templ_dict['memory_adr_assignments'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'bytes_w': int(self.get_regwidth() / 8),
|
||||||
|
'lower_bound': obj.absolute_address,
|
||||||
|
'upper_bound': obj.absolute_address + obj.total_size,
|
||||||
|
'addr_w': self.mementries.bit_length(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if obj.get_property('sw') in (AccessType.rw, AccessType.r):
|
||||||
|
self.rtl_header.append(
|
||||||
|
self.process_yaml(
|
||||||
|
Memory.templ_dict['memory_rd_assignments'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'data_w': self.get_regwidth() - 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if obj.get_property('sw') in (AccessType.rw, AccessType.w):
|
||||||
|
self.rtl_header.append(
|
||||||
|
self.process_yaml(
|
||||||
|
Memory.templ_dict['memory_wr_assignments'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'data_w': self.get_regwidth() - 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assign variables that go to register bus multiplexer
|
||||||
|
self.__add_sw_mux_assignments()
|
||||||
|
|
||||||
|
# We can/should only do this if there is no encapsulating
|
||||||
|
# regfile which create a generate
|
||||||
|
self.__add_signal_instantiations()
|
||||||
|
|
||||||
|
# Create comment and provide user information about register he/she
|
||||||
|
# is looking at. Also add a description, if applicable
|
||||||
|
self.rtl_header = [
|
||||||
|
self.process_yaml(
|
||||||
|
self.templ_dict['mem_comment'],
|
||||||
|
{'inst_name': obj.inst_name,
|
||||||
|
'type_name': obj.type_name,
|
||||||
|
'memory_width': self.memwidth,
|
||||||
|
'memory_depth': self.mementries,
|
||||||
|
'dimensions': self.dimensions,
|
||||||
|
'depth': self.depth}
|
||||||
|
),
|
||||||
|
self.get_description(),
|
||||||
|
*self.rtl_header
|
||||||
|
]
|
||||||
|
|
||||||
|
def __process_variables(self,
|
||||||
|
obj: node.RegfileNode,
|
||||||
|
parents_dimensions: list,
|
||||||
|
parents_stride: list,
|
||||||
|
glbl_settings: dict):
|
||||||
|
|
||||||
|
self.mementries = obj.get_property('mementries')
|
||||||
|
self.memwidth = obj.get_property('memwidth')
|
||||||
|
self.addr_w = self.mementries.bit_length()
|
||||||
|
|
||||||
|
if not math.log2(self.memwidth).is_integer():
|
||||||
|
self.logger.fatal( "The defined memory width must be a power of 2. "\
|
||||||
|
f"it is now defined as '{self.memwidth}'")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Geneate already started?
|
||||||
|
self.generate_active = glbl_settings['generate_active']
|
||||||
|
|
||||||
|
# Determine dimensions of register
|
||||||
|
if obj.is_array:
|
||||||
|
self.total_array_dimensions = [*parents_dimensions, *self.obj.array_dimensions]
|
||||||
|
self.array_dimensions = self.obj.array_dimensions
|
||||||
|
|
||||||
|
self.logger.warning("The memory is defined as array. The compiler not not "\
|
||||||
|
"provide any hooks to help here and expects that the user "\
|
||||||
|
"handles this outside of the memory block.")
|
||||||
|
|
||||||
|
if self.obj.array_stride != int(self.mementries * self.memwidth / 8):
|
||||||
|
self.logger.warning(f"The memory's stride ({self.obj.array_stride}) "\
|
||||||
|
f"is unequal to the depth of the memory ({self.mementries} "\
|
||||||
|
f"* {self.memwidth} / 8 = "\
|
||||||
|
f"{int(self.mementries * self.memwidth / 8)}). This must be "\
|
||||||
|
"kept in mind when hooking up the memory interface to an "\
|
||||||
|
"external memory block.")
|
||||||
|
else:
|
||||||
|
self.total_array_dimensions = parents_dimensions
|
||||||
|
self.array_dimensions = []
|
||||||
|
self.total_stride = parents_stride
|
||||||
|
|
||||||
|
self.total_dimensions = len(self.total_array_dimensions)
|
||||||
|
self.depth = '[{}]'.format(']['.join(f"{i}" for i in self.array_dimensions))
|
||||||
|
self.dimensions = len(self.array_dimensions)
|
||||||
|
|
||||||
|
def __add_sw_mux_assignments(self):
|
||||||
|
# Create list of mux-inputs to later be picked up by carrying addrmap
|
||||||
|
self.sw_mux_assignment_var_name = [
|
||||||
|
(
|
||||||
|
self.process_yaml(
|
||||||
|
Memory.templ_dict['sw_data_assignment_var_name'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'accesswidth': self.memwidth - 1}
|
||||||
|
),
|
||||||
|
self.process_yaml(
|
||||||
|
Memory.templ_dict['sw_rdy_assignment_var_name'],
|
||||||
|
{'path': self.path_underscored}
|
||||||
|
),
|
||||||
|
self.process_yaml(
|
||||||
|
Memory.templ_dict['sw_err_assignment_var_name'],
|
||||||
|
{'path': self.path_underscored}
|
||||||
|
),
|
||||||
|
(self.obj.absolute_address, self.obj.absolute_address + self.obj.total_size)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
if self.obj.get_property('sw') == AccessType.rw:
|
||||||
|
access_type = 'sw_data_assignment_rw'
|
||||||
|
elif self.obj.get_property('sw') == AccessType.r:
|
||||||
|
access_type = 'sw_data_assignment_ro'
|
||||||
|
else:
|
||||||
|
access_type = 'sw_data_assignment_wo'
|
||||||
|
|
||||||
|
self.rtl_footer = [
|
||||||
|
self.process_yaml(
|
||||||
|
self.templ_dict[access_type],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'sw_data_assignment_var_name': self.sw_mux_assignment_var_name[0][0],
|
||||||
|
'sw_rdy_assignment_var_name': self.sw_mux_assignment_var_name[0][1],
|
||||||
|
'sw_err_assignment_var_name': self.sw_mux_assignment_var_name[0][2],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
''
|
||||||
|
]
|
||||||
|
|
||||||
|
def create_mux_string(self):
|
||||||
|
for mux_tuple in self.sw_mux_assignment_var_name:
|
||||||
|
yield(mux_tuple, (0, ''))
|
||||||
|
|
||||||
|
def get_regwidth(self) -> int:
|
||||||
|
return self.memwidth
|
||||||
|
|
||||||
|
def __add_signal_instantiations(self):
|
||||||
|
# Add wire/register instantiations
|
||||||
|
self.rtl_header = [
|
||||||
|
'',
|
||||||
|
*self.get_signal_instantiations_list(),
|
||||||
|
*self.rtl_header
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_signal_instantiations_list(self):
|
||||||
|
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)
|
||||||
|
|
||||||
|
return [Memory.templ_dict['signal_declaration'].format(
|
||||||
|
name = key,
|
||||||
|
type = value[0],
|
||||||
|
signal_width = signal_width,
|
||||||
|
name_width = name_width,
|
||||||
|
unpacked_dim = '[{}]'.format(
|
||||||
|
']['.join(
|
||||||
|
[str(y) for y in value[1]]))
|
||||||
|
if value[1] else '')
|
||||||
|
for (key, value) in dict_list]
|
@ -60,13 +60,13 @@ class RegFile(Component):
|
|||||||
elif isinstance(child, node.RegfileNode):
|
elif isinstance(child, node.RegfileNode):
|
||||||
self.obj.current_idx = [0]
|
self.obj.current_idx = [0]
|
||||||
|
|
||||||
self.regfiles[child.inst_name] = \
|
new_child = RegFile(
|
||||||
RegFile(
|
|
||||||
child,
|
child,
|
||||||
self.total_array_dimensions,
|
self.total_array_dimensions,
|
||||||
self.total_stride,
|
self.total_stride,
|
||||||
config,
|
config,
|
||||||
glbl_settings)
|
glbl_settings)
|
||||||
|
self.regfiles[child.inst_name] = new_child
|
||||||
elif isinstance(child, node.RegNode):
|
elif isinstance(child, node.RegNode):
|
||||||
if child.inst.is_alias:
|
if child.inst.is_alias:
|
||||||
# If the node we found is an alias, we shall not create a
|
# If the node we found is an alias, we shall not create a
|
||||||
@ -76,16 +76,20 @@ class RegFile(Component):
|
|||||||
.add_alias(child)
|
.add_alias(child)
|
||||||
else:
|
else:
|
||||||
self.obj.current_idx = [0]
|
self.obj.current_idx = [0]
|
||||||
self.registers[child.inst_name] = \
|
new_child = Register(
|
||||||
Register(
|
|
||||||
child,
|
child,
|
||||||
self.total_array_dimensions,
|
self.total_array_dimensions,
|
||||||
self.total_stride,
|
self.total_stride,
|
||||||
config,
|
config,
|
||||||
glbl_settings)
|
glbl_settings)
|
||||||
|
self.registers[child.inst_name] = new_child
|
||||||
|
|
||||||
if (regwidth := self.registers[child.inst_name].get_regwidth()) > self.regwidth:
|
try:
|
||||||
|
if (regwidth := new_child.get_regwidth()) > self.regwidth:
|
||||||
self.regwidth = regwidth
|
self.regwidth = regwidth
|
||||||
|
except KeyError:
|
||||||
|
# Simply ignore nodes like SignalNodes
|
||||||
|
pass
|
||||||
|
|
||||||
# Add registers to children. This must be done in a last step
|
# Add registers to children. This must be done in a last step
|
||||||
# to account for all possible alias combinations
|
# to account for all possible alias combinations
|
||||||
@ -266,13 +270,3 @@ class RegFile(Component):
|
|||||||
|
|
||||||
def get_regwidth(self) -> int:
|
def get_regwidth(self) -> int:
|
||||||
return self.regwidth
|
return self.regwidth
|
||||||
|
|
||||||
def get_description(self):
|
|
||||||
if self.config['descriptions']['regfile']:
|
|
||||||
if desc := self.obj.get_property('desc'):
|
|
||||||
return self.process_yaml(
|
|
||||||
RegFile.templ_dict['regfile_desc'],
|
|
||||||
{'desc': desc},
|
|
||||||
)
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
@ -572,13 +572,3 @@ class Register(Component):
|
|||||||
|
|
||||||
def get_regwidth(self) -> int:
|
def get_regwidth(self) -> int:
|
||||||
return self.obj.get_property('regwidth')
|
return self.obj.get_property('regwidth')
|
||||||
|
|
||||||
def get_description(self):
|
|
||||||
if self.config['descriptions']['register']:
|
|
||||||
if desc := self.obj.get_property('desc'):
|
|
||||||
return self.process_yaml(
|
|
||||||
Register.templ_dict['reg_desc'],
|
|
||||||
{'desc': desc},
|
|
||||||
)
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
@ -120,7 +120,7 @@ read_mux:
|
|||||||
// Read multiplexer
|
// Read multiplexer
|
||||||
always_comb
|
always_comb
|
||||||
begin
|
begin
|
||||||
case(b2r.addr)
|
case (b2r.addr) inside
|
||||||
{list_of_cases}
|
{list_of_cases}
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
@ -135,7 +135,7 @@ default_mux_case:
|
|||||||
end
|
end
|
||||||
list_of_mux_cases:
|
list_of_mux_cases:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
{bus_width}'d{index}:
|
{index}:
|
||||||
begin
|
begin
|
||||||
r2b.data = {r2b_data};
|
r2b.data = {r2b_data};
|
||||||
r2b.err = {r2b_err};
|
r2b.err = {r2b_err};
|
||||||
|
169
srdl2sv/components/templates/memory.yaml
Normal file
169
srdl2sv/components/templates/memory.yaml
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
---
|
||||||
|
mem_comment:
|
||||||
|
rtl: |-
|
||||||
|
/*******************************************************************
|
||||||
|
*******************************************************************
|
||||||
|
* MEMORY INSTANCE NAME : {inst_name}
|
||||||
|
* MEMORY TYPE : {type_name}
|
||||||
|
* MEMORY WIDTH : {memory_width}
|
||||||
|
* MEMORY DEPTH : {memory_depth}
|
||||||
|
* RDL DIMENSION : {dimensions}
|
||||||
|
* DEPTHS (per dimension): {depth}
|
||||||
|
*******************************************************************
|
||||||
|
*******************************************************************/
|
||||||
|
description:
|
||||||
|
rtl: |-
|
||||||
|
|
||||||
|
/**MEMORY DESCRIPTION***********************************************
|
||||||
|
{desc}
|
||||||
|
/*******************************************************************/
|
||||||
|
generate_for_start:
|
||||||
|
rtl: |-
|
||||||
|
for ({iterator} = 0; {iterator} < {limit}; {iterator}++)
|
||||||
|
begin
|
||||||
|
generate_for_end:
|
||||||
|
rtl: |-
|
||||||
|
end // of for loop with iterator {dimension}
|
||||||
|
memory_adr_assignments:
|
||||||
|
rtl: |-
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* Address of memory *
|
||||||
|
**********************************
|
||||||
|
* This interface provides the address of a read/write,
|
||||||
|
* relative to the start of the memory instance.
|
||||||
|
*
|
||||||
|
* The address is divided so that byte-addresses are
|
||||||
|
* translated full memory entries
|
||||||
|
*/
|
||||||
|
assign {path}_mem_address = (b2r.addr - {lower_bound}) / {bytes_w};
|
||||||
|
assign {path}_mem_active = {path}_mem_address >= {lower_bound} && {path}_mem_address < {upper_bound};
|
||||||
|
|
||||||
|
signals:
|
||||||
|
- name: '{path}_mem_active'
|
||||||
|
signal_type: 'logic'
|
||||||
|
no_unpacked: True
|
||||||
|
output_ports:
|
||||||
|
- name: '{path}_mem_address'
|
||||||
|
signal_type: 'logic [{addr_w}:0]'
|
||||||
|
no_unpacked: True
|
||||||
|
memory_rd_assignments:
|
||||||
|
rtl: |-
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* Handle memory read interface *
|
||||||
|
**********************************
|
||||||
|
* The '{path}_mem_r_req' output will be asserted once a read
|
||||||
|
* is requested by the bus and will stay high until '{path}_mem_r_ack'
|
||||||
|
* gets set. During a read, byte-enables will be ignored.
|
||||||
|
*
|
||||||
|
* '{path}_mem_r_ack' shall be held 1'b1 until all fields in the register
|
||||||
|
* acknowledged the read. In practice, this means until '{path}_mem_r_req'
|
||||||
|
* goes back to 1'b0.
|
||||||
|
*
|
||||||
|
* If '{path}_mem_r_err' gets set, it must also be held during the
|
||||||
|
* complete time '{path}_mem_r_ack' is high.
|
||||||
|
*/
|
||||||
|
// Request read signal
|
||||||
|
assign {path}_mem_r_req = {path}_mem_active && b2r.r_vld;
|
||||||
|
input_ports:
|
||||||
|
- name: '{path}_mem_r_data'
|
||||||
|
signal_type: '[{data_w}:0]'
|
||||||
|
no_unpacked: True
|
||||||
|
- name: '{path}_mem_r_ack'
|
||||||
|
signal_type: ''
|
||||||
|
no_unpacked: True
|
||||||
|
- name: '{path}_mem_r_err'
|
||||||
|
signal_type: ''
|
||||||
|
no_unpacked: True
|
||||||
|
output_ports:
|
||||||
|
- name: '{path}_mem_r_req'
|
||||||
|
signal_type: 'logic'
|
||||||
|
no_unpacked: True
|
||||||
|
memory_wr_assignments:
|
||||||
|
rtl: |-
|
||||||
|
|
||||||
|
/***********************************
|
||||||
|
* Handle memory write interface *
|
||||||
|
***********************************
|
||||||
|
* The '{path}_mem_w_req' output will be asserted once a write
|
||||||
|
* is requested by the bus and will stay high until '{path}_mem_w_ack'
|
||||||
|
* gets set. During a write, hardware shall not touch any bits that
|
||||||
|
* are not defined in '{path}_mem_w_mask'.
|
||||||
|
*
|
||||||
|
* '{path}_mem_w_ack' shall be held 1'b1 until all fields in the register
|
||||||
|
* acknowledged the read. In practice, this means until '{path}_mem_w_req'
|
||||||
|
* goes back to 1'b0.
|
||||||
|
*
|
||||||
|
* If '{path}_mem_w_err' gets set, it must also be held during the
|
||||||
|
* complete time '{path}_mem_w_ack' is high.
|
||||||
|
*/
|
||||||
|
// Write request
|
||||||
|
assign {path}_mem_w_req = {path}_mem_active && b2r.w_vld;
|
||||||
|
|
||||||
|
// Assign value from bus to output
|
||||||
|
assign {path}_mem_w_data = b2r.data;
|
||||||
|
output_ports:
|
||||||
|
- name: '{path}_mem_w_req'
|
||||||
|
signal_type: 'logic'
|
||||||
|
no_unpacked: True
|
||||||
|
- name: '{path}_mem_w_data'
|
||||||
|
signal_type: 'logic [{data_w}:0]'
|
||||||
|
no_unpacked: True
|
||||||
|
input_ports:
|
||||||
|
- name: '{path}_mem_w_ack'
|
||||||
|
signal_type: ''
|
||||||
|
no_unpacked: True
|
||||||
|
- name: '{path}_mem_w_err'
|
||||||
|
signal_type: ''
|
||||||
|
no_unpacked: True
|
||||||
|
signal_declaration: |-
|
||||||
|
{type:{signal_width}} {name:{name_width}}{unpacked_dim};
|
||||||
|
sw_data_assignment_var_name:
|
||||||
|
rtl: |-
|
||||||
|
{path}_data_mux_in
|
||||||
|
signals:
|
||||||
|
- name: '{path}_data_mux_in'
|
||||||
|
signal_type: 'logic [{accesswidth}:0]'
|
||||||
|
no_unpacked: True
|
||||||
|
sw_err_assignment_var_name:
|
||||||
|
rtl: |-
|
||||||
|
{path}_err_mux_in
|
||||||
|
signals:
|
||||||
|
- name: '{path}_err_mux_in'
|
||||||
|
signal_type: 'logic'
|
||||||
|
no_unpacked: True
|
||||||
|
sw_rdy_assignment_var_name:
|
||||||
|
rtl: |-
|
||||||
|
{path}_rdy_mux_in
|
||||||
|
signals:
|
||||||
|
- name: '{path}_rdy_mux_in'
|
||||||
|
signal_type: 'logic'
|
||||||
|
no_unpacked: True
|
||||||
|
sw_data_assignment_ro:
|
||||||
|
rtl: |-
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Assign memory to Mux *
|
||||||
|
**************************************/
|
||||||
|
assign {sw_data_assignment_var_name} = {path}_mem_r_data;
|
||||||
|
assign {sw_rdy_assignment_var_name} = {path}_mem_r_ack;
|
||||||
|
assign {sw_err_assignment_var_name} = {path}_mem_r_err;
|
||||||
|
sw_data_assignment_wo:
|
||||||
|
rtl: |-
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Assign memory to Mux *
|
||||||
|
**************************************/
|
||||||
|
assign {sw_data_assignment_var_name} = {{{width}{{{default_val}}};
|
||||||
|
assign {sw_rdy_assignment_var_name} = {path}_mem_w_ack;
|
||||||
|
assign {sw_err_assignment_var_name} = {path}_mem_w_err;
|
||||||
|
sw_data_assignment_rw:
|
||||||
|
rtl: |-
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Assign memory to Mux *
|
||||||
|
**************************************/
|
||||||
|
assign {sw_data_assignment_var_name} = {path}_mem_r_data;
|
||||||
|
assign {sw_rdy_assignment_var_name} = {path}_mem_r_ack || {path}_mem_w_ack;
|
||||||
|
assign {sw_err_assignment_var_name} = ({path}_mem_r_err && {path}_mem_r_ack) || ({path}_mem_w_err && {path}_mem_w_ack);
|
Loading…
Reference in New Issue
Block a user