| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| '''Support code for bit ranges in reggen''' |
| |
| from typing import Tuple |
| |
| from reggen.lib import check_str |
| from reggen.params import ReggenParams |
| |
| |
| class Bits: |
| def __init__(self, msb: int, lsb: int): |
| assert 0 <= lsb <= msb |
| self.msb = msb |
| self.lsb = lsb |
| |
| def bitmask(self) -> int: |
| return (1 << (self.msb + 1)) - (1 << self.lsb) |
| |
| def width(self) -> int: |
| return 1 + self.msb - self.lsb |
| |
| def max_value(self) -> int: |
| return (1 << self.width()) - 1 |
| |
| def extract_field(self, reg_val: int) -> int: |
| return (reg_val & self.bitmask()) >> self.lsb |
| |
| @staticmethod |
| def from_raw(where: str, |
| reg_width: int, |
| params: ReggenParams, |
| raw: object) -> 'Bits': |
| # Bits should be specified as msb:lsb or as just a single bit index. |
| if isinstance(raw, int): |
| msb = raw |
| lsb = raw |
| else: |
| str_val = check_str(raw, 'bits field for {}'.format(where)) |
| msb, lsb = Bits._parse_str(where, params, str_val) |
| |
| # Check that the bit indices look sensible |
| if msb < lsb: |
| raise ValueError('msb for {} is {}: less than {}, the msb.' |
| .format(where, msb, lsb)) |
| if lsb < 0: |
| raise ValueError('lsb for {} is {}, which is negative.' |
| .format(where, lsb)) |
| if msb >= reg_width: |
| raise ValueError("msb for {} is {}, which doesn't fit in {} bits." |
| .format(where, msb, reg_width)) |
| |
| return Bits(msb, lsb) |
| |
| @staticmethod |
| def _parse_str(where: str, |
| params: ReggenParams, |
| str_val: str) -> Tuple[int, int]: |
| try: |
| idx = int(str_val) |
| return (idx, idx) |
| except ValueError: |
| # Doesn't look like an integer. Never mind: try msb:lsb |
| pass |
| |
| parts = str_val.split(':') |
| if len(parts) != 2: |
| raise ValueError('bits field for {} is not an ' |
| 'integer or of the form msb:lsb. Saw {!r}.' |
| .format(where, str_val)) |
| return (params.expand(parts[0], |
| 'msb of bits field for {}'.format(where)), |
| params.expand(parts[1], |
| 'lsb of bits field for {}'.format(where))) |
| |
| def make_translated(self, bit_offset: int) -> 'Bits': |
| assert 0 <= bit_offset |
| return Bits(self.msb + bit_offset, self.lsb + bit_offset) |
| |
| def as_str(self) -> str: |
| if self.lsb == self.msb: |
| return str(self.lsb) |
| else: |
| assert self.lsb < self.msb |
| return '{}:{}'.format(self.msb, self.lsb) |
| |
| def __eq__(self, other: object) -> bool: |
| if not isinstance(other, Bits): |
| return NotImplemented |
| return (self.lsb == other.lsb) and (self.msb == other.msb) |
| |
| def __str__(self) -> str: |
| return '[{}:{}]'.format(self.msb, self.lsb) |