| # Copyright lowRISC contributors. | 
 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | # SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | from .field_enums import HwAccess, SwAccess, SwRdAccess, SwWrAccess | 
 |  | 
 |  | 
 | # helper funtion that strips trailing number from name | 
 | # TODO: this is a workaround, should solve this in validate.py | 
 | def _get_basename(name): | 
 |     for (k, c) in enumerate(name[::-1]): | 
 |         if not str.isdigit(c): | 
 |             return name[0:len(name) - k] | 
 |     return "" | 
 |  | 
 |  | 
 | class Field(): | 
 |     """Field in a register. | 
 |  | 
 |     Field class contains necessary info to generate RTL code. | 
 |     It has two additional (tool generated) fields, swrdaccess and swwraccess, | 
 |     which represent read and write type. This makes RTL generation code simpler. | 
 |     """ | 
 |     name = ""  # required | 
 |     msb = 31  # required | 
 |     lsb = 0  # required | 
 |     resval = 0  # optional | 
 |     swaccess = SwAccess.NONE  # optional | 
 |     swrdaccess = SwRdAccess.NONE | 
 |     swwraccess = SwWrAccess.NONE | 
 |     hwaccess = HwAccess.HRO | 
 |     hwqe = False | 
 |     hwre = False | 
 |     hwext = False | 
 |     tags = [] | 
 |     shadowed = False | 
 |  | 
 |     def __init__(self): | 
 |         self.name = ""  # required | 
 |         self.msb = 31  # required | 
 |         self.lsb = 0  # required | 
 |         self.resval = 0  # optional | 
 |         self.swaccess = SwAccess.NONE  # optional | 
 |         self.swrdaccess = SwRdAccess.NONE | 
 |         self.swwraccess = SwWrAccess.NONE | 
 |         self.hwaccess = HwAccess.HRO | 
 |         self.hwqe = False | 
 |         self.hwre = False | 
 |         self.hwext = False | 
 |         self.tags = [] | 
 |         self.shadowed = False | 
 |  | 
 |     def get_n_bits(self, bittype=["q"]): | 
 |         n_bits = 0 | 
 |         if "q" in bittype and self.hwaccess in [HwAccess.HRW, HwAccess.HRO]: | 
 |             n_bits += self.msb - self.lsb + 1 | 
 |         if "d" in bittype and self.hwaccess in [HwAccess.HRW, HwAccess.HWO]: | 
 |             n_bits += self.msb - self.lsb + 1 | 
 |         if "qe" in bittype and self.hwaccess in [HwAccess.HRW, HwAccess.HRO]: | 
 |             n_bits += self.hwqe | 
 |         if "re" in bittype and self.hwaccess in [HwAccess.HRW, HwAccess.HRO]: | 
 |             n_bits += self.hwre | 
 |         if "de" in bittype and self.hwaccess in [HwAccess.HRW, HwAccess.HWO]: | 
 |             n_bits += not self.hwext | 
 |         return n_bits | 
 |  | 
 |     def get_fields_flat(self): | 
 |         return [self] | 
 |  | 
 |     def get_basename(self): | 
 |         return _get_basename(self.name) | 
 |  | 
 |  | 
 | class Reg(): | 
 |     name = "" | 
 |     offset = 0 | 
 |     hwqe = False | 
 |     hwre = False | 
 |     hwext = False  # External register | 
 |     resval = 0 | 
 |     dvrights = "RO"  # Used by UVM REG only | 
 |     regwen = "" | 
 |     fields = [] | 
 |     width = 0  # indicate register size | 
 |     ishomog = 0 | 
 |     tags = [] | 
 |     shadowed = False | 
 |  | 
 |     def __init__(self, name=""): | 
 |         self.name = name | 
 |         self.offset = 0 | 
 |         self.hwqe = False | 
 |         self.hwre = False | 
 |         self.hwext = False  # External register | 
 |         self.resval = 0 | 
 |         self.dvrights = "RO"  # Used by UVM REG only | 
 |         self.regwen = "" | 
 |         self.fields = [] | 
 |         self.width = 0 | 
 |         self.ishomog = 0 | 
 |         self.tags = [] | 
 |         self.shadowed = False | 
 |  | 
 |     def is_multi_reg(self): | 
 |         """Returns true if this is a multireg""" | 
 |         return False | 
 |  | 
 |     def get_n_bits(self, bittype=["q"]): | 
 |         """Returns number of bits in this register (including all multiregs and | 
 |         fields). By default this function counts read data bits (bittype "q"), | 
 |         but other bits such as "d", qe", "re", "de" can be counted as well by | 
 |         specifying them in the bittype list argument. | 
 |         """ | 
 |         n_bits = 0 | 
 |         for f in self.fields: | 
 |             n_bits += f.get_n_bits(bittype) | 
 |         return n_bits | 
 |  | 
 |     def get_fields_flat(self): | 
 |         """Returns a flat list of all the fields in this register""" | 
 |         fields = [] | 
 |         for f in self.fields: | 
 |             fields += f.get_fields_flat() | 
 |         return fields | 
 |  | 
 |     def get_field_flat(self, linear_idx): | 
 |         """Returns a specific field at a linear index position in | 
 |         the flattened field list""" | 
 |         fields_flat = self.get_fields_flat() | 
 |         return fields_flat[linear_idx] | 
 |  | 
 |     def get_n_fields_flat(self): | 
 |         """Returns the number of fields contained in the flat field list""" | 
 |         return len(self.get_fields_flat()) | 
 |  | 
 |     def get_regs_flat(self): | 
 |         """Returns a flat list containing all | 
 |         registers and subregisters""" | 
 |         if isinstance(self.fields[0], Field): | 
 |             return [self] | 
 |         else: | 
 |             regs = [] | 
 |             for r in self.fields: | 
 |                 regs += r.get_regs_flat() | 
 |             return regs | 
 |  | 
 |     def get_reg_flat(self, linear_index): | 
 |         """Returns a specific register at a linear index position in | 
 |         the flattened regiser list""" | 
 |         regs_flat = self.get_regs_flat() | 
 |         return regs_flat[linear_index] | 
 |  | 
 |     def get_n_regs_flat(self): | 
 |         """Returns the number of registers contained in | 
 |         the flat register list""" | 
 |         return len(self.get_regs_flat()) | 
 |  | 
 |     def get_nested_dims(self): | 
 |         """Recursively get dimensions of nested registers (outputs a list)""" | 
 |         # return length of flattened field array if this is a regular register, | 
 |         # or if this is the last multiregister level in a nested multiregister | 
 |         if not isinstance(self, MultiReg): | 
 |             dims = [len(self.get_fields_flat())] | 
 |         if isinstance(self, MultiReg) and\ | 
 |            not isinstance(self.fields[0], MultiReg): | 
 |             if self.ishomog: | 
 |                 dims = [len(self.get_fields_flat())] | 
 |             else: | 
 |                 dims = [len(self.fields)] | 
 |         else: | 
 |             # nested multiregister case | 
 |             dims = [len(self.fields)] + self.fields[0].get_nested_dims() | 
 |         return dims | 
 |  | 
 |     def get_nested_params(self): | 
 |         """Recursively get parameters of nested registers (outputs a list)""" | 
 |         params = [] | 
 |         if isinstance(self, MultiReg): | 
 |             params += [self.param] | 
 |         if isinstance(self.fields[0], MultiReg): | 
 |             params += self.fields[0].get_nested_params() | 
 |         return params | 
 |  | 
 |     def get_basename(self): | 
 |         return _get_basename(self.name) | 
 |  | 
 |  | 
 | class MultiReg(Reg): | 
 |     param = "" | 
 |  | 
 |     def __init__(self, name): | 
 |         Reg.__init__(self, name) | 
 |         self.param = "" | 
 |  | 
 |     def is_multi_reg(self): | 
 |         """Returns true if this is a multireg""" | 
 |         return True | 
 |  | 
 |  | 
 | class Window(): | 
 |     base_addr = 0 | 
 |     limit_addr = 0 | 
 |     n_bits = 0 | 
 |     tags = [] | 
 |  | 
 |     def __init__(self): | 
 |         self.base_addr = 0 | 
 |         self.limit_addr = 0 | 
 |         self.n_bits = 0 | 
 |         self.tags = [] | 
 |  | 
 |  | 
 | class Block(): | 
 |     width = 32 | 
 |     addr_width = 12 | 
 |     base_addr = 0 | 
 |     name = "" | 
 |     hier_path = "" | 
 |     regs = [] | 
 |     wins = [] | 
 |     blocks = [] | 
 |     params = [] | 
 |     tags = [] | 
 |  | 
 |     def __init__(self): | 
 |         self.width = 32 | 
 |         self.addr_width = 12 | 
 |         self.base_addr = 0 | 
 |         self.name = "" | 
 |         self.hier_path = "" | 
 |         self.regs = [] | 
 |         self.wins = [] | 
 |         self.blocks = [] | 
 |         self.params = [] | 
 |         self.tags = [] | 
 |  | 
 |     def get_regs_flat(self): | 
 |         """Returns flattened register list | 
 |         """ | 
 |         regs = [] | 
 |         for r in self.regs: | 
 |             regs += r.get_regs_flat() | 
 |         return regs | 
 |  | 
 |     def get_n_bits(self, bittype=["q"]): | 
 |         """Returns number of bits in this block (including all multiregs and | 
 |         fields). By default this function counts read data bits (bittype "q"), | 
 |         but other bits such as "d", qe", "re", "de" can be counted as well by | 
 |         specifying them in the bittype list argument. | 
 |         """ | 
 |         n_bits = 0 | 
 |         for r in self.regs: | 
 |             n_bits += r.get_n_bits(bittype) | 
 |         return n_bits | 
 |  | 
 |     def get_n_regs_flat(self): | 
 |         return len(self.get_regs_flat()) | 
 |  | 
 |     def contains_multiregs(self): | 
 |         """Returns true if there are multiregs in this block | 
 |         """ | 
 |         for r in self.regs: | 
 |             if isinstance(r, MultiReg): | 
 |                 return True | 
 |         return False |