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:
Dennis Potter 2021-09-06 00:26:08 -07:00
parent 2f38d30d76
commit c689190080
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
6 changed files with 152 additions and 36 deletions

View File

@ -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()
]
])
}
) )
) )

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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};

View 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