diff --git a/srdl2sv/components/addrmap.py b/srdl2sv/components/addrmap.py index 3753f55..62038be 100644 --- a/srdl2sv/components/addrmap.py +++ b/srdl2sv/components/addrmap.py @@ -194,21 +194,39 @@ class AddrMap(Component): def __create_mux_string(self): # 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.process_yaml( AddrMap.templ_dict['read_mux'], - {'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() - ] - ]) - } + {'list_of_cases': '\n'.join(list_of_cases)} ) ) diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index 71e6b53..7f36891 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -68,6 +68,9 @@ class Field(Component): access_rtl['sw_write'] = ([], False) 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') swwel = obj.get_property('swwel') @@ -1005,8 +1008,9 @@ class Field(Component): self.msb = obj.inst.msb 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.writable_by = set() # Determine resets. This includes checking for async/sync resets, # the reset value, and whether the field actually has a reset diff --git a/srdl2sv/components/register.py b/srdl2sv/components/register.py index 3e80158..7ccec5f 100644 --- a/srdl2sv/components/register.py +++ b/srdl2sv/components/register.py @@ -73,7 +73,7 @@ class Register(Component): self.rtl_footer.append("endgenerate\n") # Add assignment of read-wires - self.__add_sw_read_assignments() + self.__add_sw_mux_assignments() # Add wire instantiation if not self.generate_active: @@ -90,22 +90,36 @@ class Register(Component): *self.rtl_header ] - def __add_sw_read_assignments(self): + def __add_sw_mux_assignments(self): accesswidth = self.obj.get_property('accesswidth') - 1 self.rtl_footer.append("") - for x in self.name_addr_mappings: + for na_map in self.name_addr_mappings: current_bit = 0 + + # Start tracking errors + + # Handle fields list_of_fields = [] - for y in self.children.values(): - if x[0] in y.readable_by: - empty_bits = y.lsb - current_bit - current_bit = y.msb + 1 + bytes_read = set() + bytes_written = set() + + 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: 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 @@ -113,28 +127,55 @@ class Register(Component): list_of_fields.append("{}'b0".format(empty_bits)) # 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( - Register.templ_dict['sw_read_assignment_var_name'], - {'path': x[0], + Register.templ_dict['sw_data_assignment_var_name'], + {'path': na_map[0], '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.process_yaml( - Register.templ_dict['sw_read_assignment'], - {'sw_read_assignment_var_name': self.sw_read_assignment_var_name[-1][0], + Register.templ_dict['sw_data_assignment'], + {'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, + 'rdy_condition': "1'b1", + 'err_condition': sw_err_condition, 'list_of_fields': ', '.join(reversed(list_of_fields))} ) ) 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 # dimension once everything is processed if self.total_array_dimensions: @@ -270,7 +311,7 @@ class Register(Component): self.generate_active = glbl_settings['generate_active'] # Empty array for mux-input signals - self.sw_read_assignment_var_name = [] + self.sw_mux_assignment_var_name = [] # Determine dimensions of register if obj.is_array: diff --git a/srdl2sv/components/templates/addrmap.yaml b/srdl2sv/components/templates/addrmap.yaml index 9e51fe5..13d8a89 100644 --- a/srdl2sv/components/templates/addrmap.yaml +++ b/srdl2sv/components/templates/addrmap.yaml @@ -119,7 +119,18 @@ read_mux: end default_mux_case: 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: rtl: |- - 32'd{}: r2b.data = {}; + 32'd{index}: + begin + r2b.data = {r2b_data}; + r2b.err = {r2b_err}; + r2b.rdy = {r2b_rdy}; + end diff --git a/srdl2sv/components/templates/regs.yaml b/srdl2sv/components/templates/regs.yaml index c439e50..3dd4481 100644 --- a/srdl2sv/components/templates/regs.yaml +++ b/srdl2sv/components/templates/regs.yaml @@ -55,15 +55,40 @@ generate_for_end: |- end // of for loop with iterator {dimension} signal_declaration: |- {type:{signal_width}} {name:{name_width}}{unpacked_dim}; -sw_read_assignment_var_name: +sw_data_assignment_var_name: rtl: |- - {path}_rd_mux_in + {path}_data_mux_in signals: - - name: '{path}_rd_mux_in' + - name: '{path}_data_mux_in' 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: |- /************************************** * 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}; diff --git a/srdl2sv/components/widgets/widget_package.sv b/srdl2sv/components/widgets/widget_package.sv new file mode 100644 index 0000000..e938dec --- /dev/null +++ b/srdl2sv/components/widgets/widget_package.sv @@ -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