mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 06:58:41 +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.regfile import RegFile
|
||||
from components.register import Register
|
||||
from components.memory import Memory
|
||||
from . import templates
|
||||
from . import widgets
|
||||
|
||||
@ -45,6 +46,7 @@ class AddrMap(Component):
|
||||
# by name (for example, in case of aliases)
|
||||
self.registers = dict()
|
||||
self.regfiles = dict()
|
||||
self.mems = dict()
|
||||
self.regwidth = 0
|
||||
|
||||
# Traverse through children
|
||||
@ -55,8 +57,11 @@ class AddrMap(Component):
|
||||
self.logger.info('Found hierarchical addrmap. Entering it...')
|
||||
self.logger.error('Child addrmaps are not implemented yet!')
|
||||
elif isinstance(child, node.RegfileNode):
|
||||
self.regfiles[child.inst_name] = \
|
||||
RegFile(child, [], [], config, glbl_settings)
|
||||
new_child = 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):
|
||||
if child.inst.is_alias:
|
||||
# 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]\
|
||||
.add_alias(child)
|
||||
else:
|
||||
self.registers[child.inst_name] = \
|
||||
Register(child, [], [], config, glbl_settings)
|
||||
new_child = Register(child, [], [], config, glbl_settings)
|
||||
self.registers[child.inst_name] = new_child
|
||||
|
||||
try:
|
||||
if (regwidth := self.registers[child.inst_name].get_regwidth()) > self.regwidth:
|
||||
if (regwidth := new_child.get_regwidth()) > self.regwidth:
|
||||
self.regwidth = regwidth
|
||||
except KeyError:
|
||||
# Simply ignore nodes like SignalNodes
|
||||
@ -80,12 +85,12 @@ class AddrMap(Component):
|
||||
|
||||
# Add registers to children. This must be done in a last step
|
||||
# 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")
|
||||
|
||||
# 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()]
|
||||
|
||||
# Add bus widget ports
|
||||
@ -119,6 +124,7 @@ class AddrMap(Component):
|
||||
|
||||
|
||||
# Input ports
|
||||
# Yay for unreadable code....
|
||||
input_ports_rtl = [
|
||||
AddrMap.templ_dict['input_port']['rtl'].format(
|
||||
name = key,
|
||||
@ -215,6 +221,9 @@ class AddrMap(Component):
|
||||
self.rtl_footer.append('endmodule')
|
||||
|
||||
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
|
||||
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_rdy = ''.join([mux_entry[0][1], 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(
|
||||
AddrMap.templ_dict['list_of_mux_cases']['rtl'].format(
|
||||
index = index,
|
||||
bus_width = self.config['addrwidth'],
|
||||
r2b_data = r2b_data,
|
||||
r2b_rdy = r2b_rdy,
|
||||
r2b_err = r2b_err)
|
||||
@ -393,13 +407,3 @@ class AddrMap(Component):
|
||||
|
||||
def get_regwidth(self) -> int:
|
||||
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
|
||||
|
||||
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)] =\
|
||||
(x['signal_type'].format(**values),
|
||||
self.total_array_dimensions)
|
||||
array_dimensions)
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
|
||||
@ -258,9 +263,14 @@ class Component():
|
||||
raise KeyError
|
||||
|
||||
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)] =\
|
||||
(x['signal_type'].format(**values),
|
||||
self.total_array_dimensions)
|
||||
array_dimensions)
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
|
||||
@ -269,9 +279,14 @@ class Component():
|
||||
raise KeyError
|
||||
|
||||
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)] =\
|
||||
(x['signal_type'].format(**values),
|
||||
self.total_array_dimensions)
|
||||
array_dimensions)
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
|
||||
@ -319,3 +334,12 @@ class Component():
|
||||
|
||||
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) "\
|
||||
"property with the counter property. The counter property "\
|
||||
"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):
|
||||
self.obj.current_idx = [0]
|
||||
|
||||
self.regfiles[child.inst_name] = \
|
||||
RegFile(
|
||||
new_child = RegFile(
|
||||
child,
|
||||
self.total_array_dimensions,
|
||||
self.total_stride,
|
||||
config,
|
||||
glbl_settings)
|
||||
self.regfiles[child.inst_name] = new_child
|
||||
elif isinstance(child, node.RegNode):
|
||||
if child.inst.is_alias:
|
||||
# If the node we found is an alias, we shall not create a
|
||||
@ -76,16 +76,20 @@ class RegFile(Component):
|
||||
.add_alias(child)
|
||||
else:
|
||||
self.obj.current_idx = [0]
|
||||
self.registers[child.inst_name] = \
|
||||
Register(
|
||||
new_child = Register(
|
||||
child,
|
||||
self.total_array_dimensions,
|
||||
self.total_stride,
|
||||
config,
|
||||
glbl_settings)
|
||||
self.registers[child.inst_name] = new_child
|
||||
|
||||
if (regwidth := self.registers[child.inst_name].get_regwidth()) > self.regwidth:
|
||||
self.regwidth = regwidth
|
||||
try:
|
||||
if (regwidth := new_child.get_regwidth()) > self.regwidth:
|
||||
self.regwidth = regwidth
|
||||
except KeyError:
|
||||
# Simply ignore nodes like SignalNodes
|
||||
pass
|
||||
|
||||
# Add registers to children. This must be done in a last step
|
||||
# to account for all possible alias combinations
|
||||
@ -266,13 +270,3 @@ class RegFile(Component):
|
||||
|
||||
def get_regwidth(self) -> int:
|
||||
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:
|
||||
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
|
||||
always_comb
|
||||
begin
|
||||
case(b2r.addr)
|
||||
case (b2r.addr) inside
|
||||
{list_of_cases}
|
||||
endcase
|
||||
end
|
||||
@ -135,7 +135,7 @@ default_mux_case:
|
||||
end
|
||||
list_of_mux_cases:
|
||||
rtl: |-
|
||||
{bus_width}'d{index}:
|
||||
{index}:
|
||||
begin
|
||||
r2b.data = {r2b_data};
|
||||
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