| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| from collections import OrderedDict |
| |
| from .field_enums import HwAccess, SwAccess, SwRdAccess, SwWrAccess |
| |
| |
| # helper funtion that strips trailing _number (used as multireg suffix) 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): |
| if c == "_": |
| return name[0:len(name) - (k + 1)] |
| else: |
| break |
| 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. |
| """ |
| 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(): |
| 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): |
| 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(): |
| def __init__(self): |
| self.base_addr = 0 |
| self.byte_write = 0 |
| self.limit_addr = 0 |
| self.n_bits = 0 |
| self.tags = [] |
| |
| |
| class Block(): |
| def __init__(self): |
| self.width = 32 |
| self.addr_width = 12 |
| # Key is instance name |
| self.base_addr = OrderedDict() |
| 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 |