mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 15:08:39 +00:00
Add proper support for rdy & error indication in read multiplexer
The error indication is generated if: - A non-existent register gets read - An existent register gets read but not a single bit can be succesfully read or written. As soon as 1 bit succeeds don't return an error.
This commit is contained in:
parent
2f38d30d76
commit
c689190080
@ -194,21 +194,39 @@ class AddrMap(Component):
|
|||||||
|
|
||||||
def __create_mux_string(self):
|
def __create_mux_string(self):
|
||||||
# TODO: Add variable for bus width
|
# TODO: Add variable for bus width
|
||||||
|
# Define default case
|
||||||
|
list_of_cases = [AddrMap.templ_dict['default_mux_case']['rtl']]
|
||||||
|
|
||||||
|
# Add an entry for each version of a register
|
||||||
|
for child in self.children.values():
|
||||||
|
for mux_entry in child.create_mux_string():
|
||||||
|
# Data structure of mux_entry:
|
||||||
|
# mux_entry[0] --> names of data/rdy/err wire and start addr
|
||||||
|
# [0] --> data_mux (str)
|
||||||
|
# [1] --> rdy_mux (str)
|
||||||
|
# [2] --> err_mux (str)
|
||||||
|
# [3] --> start_addr (int)
|
||||||
|
# mux_entry[1] --> offsets from start
|
||||||
|
# [0] --> Offset from start_addr of current entry (int)
|
||||||
|
# [1] --> String of array index that represents offset (str)
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
list_of_cases.append(
|
||||||
|
AddrMap.templ_dict['list_of_mux_cases']['rtl'].format(
|
||||||
|
index = index,
|
||||||
|
r2b_data = r2b_data,
|
||||||
|
r2b_rdy = r2b_rdy,
|
||||||
|
r2b_err = r2b_err)
|
||||||
|
)
|
||||||
|
|
||||||
self.rtl_footer.append(
|
self.rtl_footer.append(
|
||||||
self.process_yaml(
|
self.process_yaml(
|
||||||
AddrMap.templ_dict['read_mux'],
|
AddrMap.templ_dict['read_mux'],
|
||||||
{'list_of_cases':
|
{'list_of_cases': '\n'.join(list_of_cases)}
|
||||||
'\n'.join([
|
|
||||||
AddrMap.templ_dict['default_mux_case']['rtl'],
|
|
||||||
*[AddrMap.templ_dict['list_of_mux_cases']['rtl']
|
|
||||||
.format(x[0][1]+x[1][0],
|
|
||||||
''.join(
|
|
||||||
[x[0][0],
|
|
||||||
x[1][1]])) for y in self.children.values() \
|
|
||||||
for x in y.create_mux_string()
|
|
||||||
]
|
|
||||||
])
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,6 +68,9 @@ class Field(Component):
|
|||||||
access_rtl['sw_write'] = ([], False)
|
access_rtl['sw_write'] = ([], False)
|
||||||
|
|
||||||
if obj.get_property('sw') in (AccessType.rw, AccessType.w):
|
if obj.get_property('sw') in (AccessType.rw, AccessType.w):
|
||||||
|
# Append to list of registers that can write
|
||||||
|
self.writable_by.add(path_wo_field)
|
||||||
|
|
||||||
swwe = obj.get_property('swwe')
|
swwe = obj.get_property('swwe')
|
||||||
swwel = obj.get_property('swwel')
|
swwel = obj.get_property('swwel')
|
||||||
|
|
||||||
@ -1005,8 +1008,9 @@ class Field(Component):
|
|||||||
self.msb = obj.inst.msb
|
self.msb = obj.inst.msb
|
||||||
self.lsb = obj.inst.lsb
|
self.lsb = obj.inst.lsb
|
||||||
|
|
||||||
# Set that tells which hierarchies can read this field
|
# Set that tells which hierarchies can read/write this field
|
||||||
self.readable_by = set()
|
self.readable_by = set()
|
||||||
|
self.writable_by = set()
|
||||||
|
|
||||||
# Determine resets. This includes checking for async/sync resets,
|
# Determine resets. This includes checking for async/sync resets,
|
||||||
# the reset value, and whether the field actually has a reset
|
# the reset value, and whether the field actually has a reset
|
||||||
|
@ -73,7 +73,7 @@ class Register(Component):
|
|||||||
self.rtl_footer.append("endgenerate\n")
|
self.rtl_footer.append("endgenerate\n")
|
||||||
|
|
||||||
# Add assignment of read-wires
|
# Add assignment of read-wires
|
||||||
self.__add_sw_read_assignments()
|
self.__add_sw_mux_assignments()
|
||||||
|
|
||||||
# Add wire instantiation
|
# Add wire instantiation
|
||||||
if not self.generate_active:
|
if not self.generate_active:
|
||||||
@ -90,22 +90,36 @@ class Register(Component):
|
|||||||
*self.rtl_header
|
*self.rtl_header
|
||||||
]
|
]
|
||||||
|
|
||||||
def __add_sw_read_assignments(self):
|
def __add_sw_mux_assignments(self):
|
||||||
accesswidth = self.obj.get_property('accesswidth') - 1
|
accesswidth = self.obj.get_property('accesswidth') - 1
|
||||||
self.rtl_footer.append("")
|
self.rtl_footer.append("")
|
||||||
|
|
||||||
for x in self.name_addr_mappings:
|
for na_map in self.name_addr_mappings:
|
||||||
current_bit = 0
|
current_bit = 0
|
||||||
|
|
||||||
|
# Start tracking errors
|
||||||
|
|
||||||
|
# Handle fields
|
||||||
list_of_fields = []
|
list_of_fields = []
|
||||||
for y in self.children.values():
|
bytes_read = set()
|
||||||
if x[0] in y.readable_by:
|
bytes_written = set()
|
||||||
empty_bits = y.lsb - current_bit
|
|
||||||
current_bit = y.msb + 1
|
for field in self.children.values():
|
||||||
|
if na_map[0] in field.readable_by:
|
||||||
|
empty_bits = field.lsb - current_bit
|
||||||
|
current_bit = field.msb + 1
|
||||||
|
|
||||||
if empty_bits > 0:
|
if empty_bits > 0:
|
||||||
list_of_fields.append("{}'b0".format(empty_bits))
|
list_of_fields.append("{}'b0".format(empty_bits))
|
||||||
|
|
||||||
list_of_fields.append("{}_q".format(y.path_underscored))
|
list_of_fields.append("{}_q".format(field.path_underscored))
|
||||||
|
|
||||||
|
# Add to appropriate bytes
|
||||||
|
[bytes_read.add(x) for x in range(field.lsbyte, field.msbyte+1)]
|
||||||
|
|
||||||
|
if na_map[0] in field.writable_by:
|
||||||
|
# Add to appropriate bytes
|
||||||
|
[bytes_written.add(x) for x in range(field.lsbyte, field.msbyte+1)]
|
||||||
|
|
||||||
empty_bits = accesswidth - current_bit + 1
|
empty_bits = accesswidth - current_bit + 1
|
||||||
|
|
||||||
@ -113,28 +127,55 @@ class Register(Component):
|
|||||||
list_of_fields.append("{}'b0".format(empty_bits))
|
list_of_fields.append("{}'b0".format(empty_bits))
|
||||||
|
|
||||||
# Create list of mux-inputs to later be picked up by carrying addrmap
|
# Create list of mux-inputs to later be picked up by carrying addrmap
|
||||||
self.sw_read_assignment_var_name.append(
|
self.sw_mux_assignment_var_name.append(
|
||||||
(
|
(
|
||||||
self.process_yaml(
|
self.process_yaml(
|
||||||
Register.templ_dict['sw_read_assignment_var_name'],
|
Register.templ_dict['sw_data_assignment_var_name'],
|
||||||
{'path': x[0],
|
{'path': na_map[0],
|
||||||
'accesswidth': accesswidth}
|
'accesswidth': accesswidth}
|
||||||
),
|
),
|
||||||
x[1], # Start addr
|
self.process_yaml(
|
||||||
|
Register.templ_dict['sw_rdy_assignment_var_name'],
|
||||||
|
{'path': na_map[0]}
|
||||||
|
),
|
||||||
|
self.process_yaml(
|
||||||
|
Register.templ_dict['sw_err_assignment_var_name'],
|
||||||
|
{'path': na_map[0]}
|
||||||
|
),
|
||||||
|
na_map[1], # Start addr
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Return an error if *no* read or *no* write can be succesful.
|
||||||
|
# If some bits cannot be read/write but others are succesful, don't return
|
||||||
|
# an error.
|
||||||
|
bytes_read_format = ["b2r.byte_en[{}]".format(x) for x in list(map(str, bytes_read))]
|
||||||
|
bytes_written_format = ["b2r.byte_en[{}]".format(x) for x in list(map(str, bytes_written))]
|
||||||
|
|
||||||
|
sw_err_condition = self.process_yaml(
|
||||||
|
Register.templ_dict['sw_err_condition'],
|
||||||
|
{'rd_byte_list_ored':
|
||||||
|
' || '.join(bytes_read_format) if bytes_read else "1'b0",
|
||||||
|
'wr_byte_list_ored':
|
||||||
|
' || '.join(bytes_written_format) if bytes_written else "1'b0"}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assign all values
|
||||||
self.rtl_footer.append(
|
self.rtl_footer.append(
|
||||||
self.process_yaml(
|
self.process_yaml(
|
||||||
Register.templ_dict['sw_read_assignment'],
|
Register.templ_dict['sw_data_assignment'],
|
||||||
{'sw_read_assignment_var_name': self.sw_read_assignment_var_name[-1][0],
|
{'sw_data_assignment_var_name': self.sw_mux_assignment_var_name[-1][0],
|
||||||
|
'sw_rdy_assignment_var_name': self.sw_mux_assignment_var_name[-1][1],
|
||||||
|
'sw_err_assignment_var_name': self.sw_mux_assignment_var_name[-1][2],
|
||||||
'genvars': self.genvars_str,
|
'genvars': self.genvars_str,
|
||||||
|
'rdy_condition': "1'b1",
|
||||||
|
'err_condition': sw_err_condition,
|
||||||
'list_of_fields': ', '.join(reversed(list_of_fields))}
|
'list_of_fields': ', '.join(reversed(list_of_fields))}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def create_mux_string(self):
|
def create_mux_string(self):
|
||||||
for mux_tuple in self.sw_read_assignment_var_name:
|
for mux_tuple in self.sw_mux_assignment_var_name:
|
||||||
# Loop through lowest dimension and add stride of higher
|
# Loop through lowest dimension and add stride of higher
|
||||||
# dimension once everything is processed
|
# dimension once everything is processed
|
||||||
if self.total_array_dimensions:
|
if self.total_array_dimensions:
|
||||||
@ -270,7 +311,7 @@ class Register(Component):
|
|||||||
self.generate_active = glbl_settings['generate_active']
|
self.generate_active = glbl_settings['generate_active']
|
||||||
|
|
||||||
# Empty array for mux-input signals
|
# Empty array for mux-input signals
|
||||||
self.sw_read_assignment_var_name = []
|
self.sw_mux_assignment_var_name = []
|
||||||
|
|
||||||
# Determine dimensions of register
|
# Determine dimensions of register
|
||||||
if obj.is_array:
|
if obj.is_array:
|
||||||
|
@ -119,7 +119,18 @@ read_mux:
|
|||||||
end
|
end
|
||||||
default_mux_case:
|
default_mux_case:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
default: r2b.data = 0;
|
default:
|
||||||
|
begin
|
||||||
|
// In case the address is not found, return an error
|
||||||
|
r2b.data = 0;
|
||||||
|
r2b.err = 1;
|
||||||
|
r2b.rdy = b2r.r_vld || b2r.w_vld;
|
||||||
|
end
|
||||||
list_of_mux_cases:
|
list_of_mux_cases:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
32'd{}: r2b.data = {};
|
32'd{index}:
|
||||||
|
begin
|
||||||
|
r2b.data = {r2b_data};
|
||||||
|
r2b.err = {r2b_err};
|
||||||
|
r2b.rdy = {r2b_rdy};
|
||||||
|
end
|
||||||
|
@ -55,15 +55,40 @@ generate_for_end: |-
|
|||||||
end // of for loop with iterator {dimension}
|
end // of for loop with iterator {dimension}
|
||||||
signal_declaration: |-
|
signal_declaration: |-
|
||||||
{type:{signal_width}} {name:{name_width}}{unpacked_dim};
|
{type:{signal_width}} {name:{name_width}}{unpacked_dim};
|
||||||
sw_read_assignment_var_name:
|
sw_data_assignment_var_name:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
{path}_rd_mux_in
|
{path}_data_mux_in
|
||||||
signals:
|
signals:
|
||||||
- name: '{path}_rd_mux_in'
|
- name: '{path}_data_mux_in'
|
||||||
signal_type: 'logic [{accesswidth}:0]'
|
signal_type: 'logic [{accesswidth}:0]'
|
||||||
sw_read_assignment:
|
sw_err_assignment_var_name:
|
||||||
|
rtl: |-
|
||||||
|
{path}_err_mux_in
|
||||||
|
signals:
|
||||||
|
- name: '{path}_err_mux_in'
|
||||||
|
signal_type: 'logic'
|
||||||
|
sw_rdy_assignment_var_name:
|
||||||
|
rtl: |-
|
||||||
|
{path}_rdy_mux_in
|
||||||
|
signals:
|
||||||
|
- name: '{path}_rdy_mux_in'
|
||||||
|
signal_type: 'logic'
|
||||||
|
sw_err_condition:
|
||||||
|
rtl: |-
|
||||||
|
!((b2r.r_vld && ({rd_byte_list_ored})) || (b2r.w_vld && ({wr_byte_list_ored})))
|
||||||
|
sw_data_assignment:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
/**************************************
|
/**************************************
|
||||||
* Assign all fields to signal to Mux *
|
* Assign all fields to signal to Mux *
|
||||||
**************************************/
|
**************************************/
|
||||||
assign {sw_read_assignment_var_name}{genvars} = {{{list_of_fields}{genvars}}};
|
// Assign all fields. Fields that are not readable are tied to 0.
|
||||||
|
assign {sw_data_assignment_var_name}{genvars} = {{{list_of_fields}{genvars}}};
|
||||||
|
|
||||||
|
// Internal registers are ready immediately
|
||||||
|
assign {sw_rdy_assignment_var_name}{genvars} = {rdy_condition};
|
||||||
|
|
||||||
|
// Return an error if *no* read and *no* write wa be succesful.
|
||||||
|
// If some bits cannot be read/write but others are succesful, don't return
|
||||||
|
// an error. Hence, as long as one action can be succesful, no error will be
|
||||||
|
// returned.
|
||||||
|
assign {sw_err_assignment_var_name}{genvars} = {err_condition};
|
||||||
|
17
srdl2sv/components/widgets/widget_package.sv
Normal file
17
srdl2sv/components/widgets/widget_package.sv
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package srdl2sv_widget_pkg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
logic [31:0] addr;
|
||||||
|
logic [31:0] data;
|
||||||
|
logic w_vld;
|
||||||
|
logic r_vld;
|
||||||
|
logic [ 3:0] byte_en;
|
||||||
|
} b2r_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
logic [31:0] data;
|
||||||
|
logic rdy;
|
||||||
|
logic err;
|
||||||
|
} r2b_t;
|
||||||
|
|
||||||
|
endpackage
|
Loading…
Reference in New Issue
Block a user