# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

'''Code representing the registers, windows etc. for a block'''

import re
from typing import Callable, Dict, List, Optional, Sequence, Union

from reggen.alert import Alert
from reggen.access import SWAccess, HWAccess
from reggen.bus_interfaces import BusInterfaces
from reggen.clocking import Clocking, ClockingItem
from reggen.field import Field
from reggen.signal import Signal
from reggen.lib import check_int, check_list, check_str_dict, check_str
from reggen.multi_register import MultiRegister
from reggen.params import ReggenParams
from reggen.register import Register
from reggen.window import Window


class RegBlock:
    def __init__(self, reg_width: int, params: ReggenParams):

        self._addrsep = (reg_width + 7) // 8
        self._reg_width = reg_width
        self._params = params

        self.name = ""  # type: str
        self.clocks = {}  # type: Dict[str, ClockingItem]
        self.offset = 0
        self.multiregs = []  # type: List[MultiRegister]
        self.registers = []  # type: List[Register]
        self.windows = []  # type: List[Window]

        # Boolean indication whether ANY window in regblock has data integrity passthrough
        self.has_data_intg_passthru = False

        # A list of all registers, expanding multiregs, ordered by offset
        self.flat_regs = []  # type: List[Register]

        # A list of registers and multiregisters (unexpanded)
        self.all_regs = []  # type: List[Union[Register, MultiRegister]]

        # A list of all the underlying register types used in the block. This
        # has one entry for each actual Register, plus a single entry giving
        # the underlying register for each MultiRegister.
        self.type_regs = []  # type: List[Register]

        # A list with everything in order
        self.entries = []  # type: List[object]

        # A dict of named entries, mapping name to offset
        self.name_to_offset = {}  # type: Dict[str, int]

        # A dict of all registers (expanding multiregs), mapping name to the
        # register object
        self.name_to_flat_reg = {}  # type: Dict[str, Register]

        # A list of all write enable names
        self.wennames = []  # type: List[str]

        # Boolean indication that the block is fully asynchronous
        self.async_if = False

    @staticmethod
    def build_blocks(block: 'RegBlock',
                     raw: object,
                     bus: BusInterfaces,
                     clocks: Clocking,
                     is_alias: bool) -> Dict[Optional[str], 'RegBlock']:
        '''Build a dictionary of blocks for a 'registers' field in the hjson

        There are two different syntaxes we might see here. The simple syntax
        just consists of a list of entries (register, multireg, window,
        skipto). If we see that, each entry gets added to init_block and then
        we return {None: init_block}.

        The more complicated syntax is a dictionary. This parses from hjson as
        an OrderedDict which we walk in document order. Entries from the first
        key/value pair in the dictionary will be added to init_block. Later
        key/value pairs start empty RegBlocks. The return value is a dictionary
        mapping the keys we saw to their respective RegBlocks.

        The flag is_alias determines whether these blocks contain alias
        register definitions. If that flag is set, the individual register
        definitions must contain the alias_target key, which specifies the
        name of the generic register to override.
        '''
        if isinstance(raw, list):
            # This is the simple syntax
            block.add_raw_registers(raw,
                                    'registers field at top-level',
                                    clocks,
                                    bus.device_async.get(None),
                                    is_alias)
            return {None: block}

        # This is the more complicated syntax
        if not isinstance(raw, dict):
            raise ValueError('registers field at top-level is '
                             'neither a list or a dictionary.')

        ret = {}  # type: Dict[Optional[str], RegBlock]
        for idx, (r_key, r_val) in enumerate(raw.items()):
            if idx > 0:
                block = RegBlock(block._reg_width, block._params)

            rb_key = check_str(r_key,
                               'the key for item {} of '
                               'the registers dictionary at top-level'
                               .format(idx + 1))
            rb_val = check_list(r_val,
                                'the value for item {} of '
                                'the registers dictionary at top-level'
                                .format(idx + 1))

            block.add_raw_registers(rb_val,
                                    'item {} of the registers '
                                    'dictionary at top-level'
                                    .format(idx + 1),
                                    clocks,
                                    bus.device_async.get(r_key),
                                    is_alias)
            block.validate()

            assert rb_key not in ret
            block.name = rb_key
            ret[rb_key] = block

        return ret

    def add_raw_registers(self,
                          raw: object,
                          what: str,
                          clocks: Clocking,
                          async_if: Optional[str],
                          is_alias: bool) -> None:

        # the interface is fully asynchronous
        if async_if:
            self.async_if = True
            self.clocks[async_if] = clocks.get_by_clock(async_if)

        rl = check_list(raw, 'registers field at top-level')
        for entry_idx, entry_raw in enumerate(rl):
            where = ('entry {} of the top-level registers field'
                     .format(entry_idx + 1))
            self.add_raw(where, entry_raw, clocks, is_alias)

    def add_raw(self,
                where: str,
                raw: object,
                clocks: Clocking,
                is_alias: bool) -> None:
        entry = check_str_dict(raw, where)

        handlers = {
            'register': self._handle_register,
            'reserved': self._handle_reserved,
            'skipto': self._handle_skipto,
            'window': self._handle_window,
            'multireg': self._handle_multireg
        }

        entry_type = 'register'
        entry_body = entry  # type: object

        for t in ['reserved', 'skipto', 'window', 'multireg']:
            t_body = entry.get(t)
            if t_body is not None:
                # Special entries look like { window: { ... } }, so if we
                # get a hit, this should be the only key in entry. Note
                # that this also checks that nothing has more than one
                # entry type.
                if len(entry) != 1:
                    other_keys = [k for k in entry if k != t]
                    assert other_keys
                    raise ValueError('At offset {:#x}, {} has key {}, which '
                                     'should give its type. But it also has '
                                     'other keys too: {}.'
                                     .format(self.offset,
                                             where, t, ', '.join(other_keys)))
                entry_type = t
                entry_body = t_body

        entry_where = ('At offset {:#x}, {}, type {!r}'
                       .format(self.offset, where, entry_type))

        handlers[entry_type](entry_where, entry_body, clocks, is_alias)

    def _validate_async(self, name: Optional[str], clk: object) -> None:
        '''Check for async definition consistency

        If a reg block is marked fully asynchronous through its bus interface,
        its register definition cannot also mark individual registers with
        asynchronous designations.

        The two asynchronous regfile schemes are mutually exclusive.
        '''

        if self.name:
            block_name = self.name
        else:
            block_name = "Default"

        if self.async_if and name:
            raise ValueError(f'''
            {block_name} register block has incompatible async definitions.
            The corresponding device interface is marked fully async, however
            there are individual registers that also contain the async_clk
            designation, this is not allowed.

            Either remove all register async_clk designations, or remove
            async designation of the bus interface.
            ''')

        # If there is an asynchronous clock defined, then the clock must be a
        # valid clocking item
        if name:
            assert isinstance(clk, ClockingItem)
            self.clocks[name] = clk

    def _handle_register(self,
                         where: str,
                         body: object,
                         clocks: Clocking,
                         is_alias: bool) -> None:
        reg = Register.from_raw(self._reg_width,
                                self.offset,
                                self._params,
                                body,
                                clocks,
                                is_alias)

        self._validate_async(reg.async_name, reg.async_clk)

        self.add_register(reg)

    def _handle_reserved(self,
                         where: str,
                         body: object,
                         clocks: Optional[Clocking],
                         is_alias: bool) -> None:
        if is_alias:
            raise ValueError('Aliasing reserved regions is not supported yet')
        nreserved = check_int(body, 'body of ' + where)
        if nreserved <= 0:
            raise ValueError('Reserved count in {} is {}, '
                             'which is not positive.'
                             .format(where, nreserved))

        self.offset += self._addrsep * nreserved

    def _handle_skipto(self,
                       where: str,
                       body: object,
                       clocks: Optional[Clocking],
                       is_alias: bool) -> None:
        if is_alias:
            raise ValueError('The skipto command is not supported in '
                             'alias register definitions')

        skipto = check_int(body, 'body of ' + where)
        if skipto < self.offset:
            raise ValueError('Destination of skipto in {} is {:#x}, '
                             'is less than the current offset, {:#x}.'
                             .format(where, skipto, self.offset))
        if skipto % self._addrsep:
            raise ValueError('Destination of skipto in {} is {:#x}, '
                             'not a multiple of addrsep, {:#x}.'
                             .format(where, skipto, self._addrsep))
        self.offset = skipto

    def _handle_window(self,
                       where: str,
                       body: object,
                       clocks: Optional[Clocking],
                       is_alias: bool) -> None:
        if is_alias:
            raise ValueError('Aliasing window regions is not supported yet')

        window = Window.from_raw(self.offset,
                                 self._reg_width, self._params, body)
        if window.name is not None:
            lname = window.name.lower()
            if lname in self.name_to_offset:
                raise ValueError('Window {} (at offset {:#x}) has the '
                                 'same name as something at offset {:#x}.'
                                 .format(window.name, window.offset,
                                         self.name_to_offset[lname]))
        self.add_window(window)

    def _handle_multireg(self,
                         where: str,
                         body: object,
                         clocks: Clocking,
                         is_alias: bool) -> None:
        mr = MultiRegister(self.offset,
                           self._addrsep,
                           self._reg_width,
                           self._params,
                           body,
                           clocks,
                           is_alias)

        # validate async schemes
        self._validate_async(mr.async_name, mr.async_clk)

        for reg in mr.regs:
            lname = reg.name.lower()
            if lname in self.name_to_offset:
                raise ValueError('Multiregister {} (at offset {:#x}) expands '
                                 'to a register with name {} (at offset '
                                 '{:#x}), but this already names something at '
                                 'offset {:#x}.'
                                 .format(mr.reg.name, mr.reg.offset,
                                         reg.name, reg.offset,
                                         self.name_to_offset[lname]))
            self._add_flat_reg(reg)
            if mr.dv_compact is False:
                self.type_regs.append(reg)

        self.multiregs.append(mr)
        self.all_regs.append(mr)
        if mr.dv_compact is True:
            self.type_regs.append(mr.reg)
        self.entries.append(mr)
        self.offset = mr.next_offset(self._addrsep)

    def add_register(self, reg: Register) -> None:
        assert reg.offset == self.offset

        lname = reg.name.lower()
        if lname in self.name_to_offset:
            raise ValueError('Register {} (at offset {:#x}) has the same '
                             'name as something at offset {:#x}.'
                             .format(reg.name, reg.offset,
                                     self.name_to_offset[lname]))
        self._add_flat_reg(reg)

        self.registers.append(reg)
        self.all_regs.append(reg)
        self.type_regs.append(reg)
        self.entries.append(reg)
        self.offset = reg.next_offset(self._addrsep)

        if reg.regwen is not None and reg.regwen not in self.wennames:
            self.wennames.append(reg.regwen)

    def _add_flat_reg(self, reg: Register) -> None:
        lname = reg.name.lower()
        # The first assertion is checked at the call site (where we can print
        # out a nicer message for multiregs). The second assertion should be
        # implied by the first.
        assert lname not in self.name_to_offset
        assert lname not in self.name_to_flat_reg

        self.flat_regs.append(reg)
        self.name_to_flat_reg[lname] = reg
        self.name_to_offset[lname] = reg.offset

    def _rename_flat_reg(self, old_name: str, new_name: str) -> None:
        '''Renames keys in name_to_offset and name_to_flat_reg dicts'''
        old_lname = old_name.lower()
        new_lname = new_name.lower()
        # Only existing regs can be renamed, and new reg name must be unique.
        assert old_lname in self.name_to_offset
        assert old_lname in self.name_to_flat_reg
        assert new_lname not in self.name_to_offset
        assert new_lname not in self.name_to_flat_reg

        # Remove old key and reinsert register with new key name.
        self.name_to_flat_reg[new_lname] = self.name_to_flat_reg.pop(old_lname)
        self.name_to_offset[new_lname] = self.name_to_offset.pop(old_lname)

    def add_window(self, window: Window) -> None:
        if window.name is not None:
            lname = window.name.lower()
            assert lname not in self.name_to_offset
            self.name_to_offset[lname] = window.offset

        self.windows.append(window)
        self.entries.append(window)
        assert self.offset <= window.offset
        self.offset = window.next_offset(self._addrsep)

        self.has_data_intg_passthru |= window.data_intg_passthru

    def validate(self) -> None:
        '''Run this to check consistency after all registers have been added'''

        # Check that every write-enable register has a good name, a valid reset
        # value, and valid access permissions.
        for wenname in self.wennames:
            # check the REGWEN naming convention
            if re.fullmatch(r'(.+_)*REGWEN(_[0-9]+)?', wenname) is None:
                raise ValueError("Regwen name {} must have the suffix '_REGWEN'"
                                 .format(wenname))

            wen_reg = self.name_to_flat_reg.get(wenname.lower())
            if wen_reg is None:
                raise ValueError('One or more registers use {} as a '
                                 'write-enable, but there is no such register.'
                                 .format(wenname))

            wen_reg.check_valid_regwen()

    def get_n_bits(self, bittype: List[str] = ["q"]) -> int:
        '''Returns number of bits in registers in this block.

        This includes those expanded from multiregs. See Field.get_n_bits for a
        description of the bittype argument.

        '''
        return sum(reg.get_n_bits(bittype) for reg in self.flat_regs)

    def as_dicts(self) -> List[object]:
        entries = []  # type: List[object]
        offset = 0
        for entry in self.entries:
            assert (isinstance(entry, Register) or
                    isinstance(entry, MultiRegister) or
                    isinstance(entry, Window))

            next_off = entry.offset
            assert offset <= next_off
            res_bytes = next_off - offset
            if res_bytes:
                assert res_bytes % self._addrsep == 0
                entries.append({'reserved': res_bytes // self._addrsep})

            entries.append(entry)
            offset = entry.next_offset(self._addrsep)

        return entries

    _FieldFormatter = Callable[[bool, str], str]

    def _add_intr_alert_reg(self,
                            signals: Sequence[Signal],
                            reg_name: str,
                            reg_desc: str,
                            field_desc_fmt: Optional[Union[str, _FieldFormatter]],
                            swaccess: str,
                            hwaccess: str,
                            is_testreg: bool,
                            reg_tags: List[str]) -> None:
        swaccess_obj = SWAccess('RegBlock._make_intr_alert_reg()', swaccess)
        hwaccess_obj = HWAccess('RegBlock._make_intr_alert_reg()', hwaccess)

        fields = []
        for signal in signals:
            if field_desc_fmt is None:
                field_desc = signal.desc
            elif isinstance(field_desc_fmt, str):
                field_desc = field_desc_fmt
            else:
                width = signal.bits.width()
                field_desc = field_desc_fmt(width > 1, signal.name)

            fields.append(Field(signal.name,
                                None,  # no alias target
                                field_desc or signal.desc,
                                tags=[],
                                swaccess=swaccess_obj,
                                hwaccess=hwaccess_obj,
                                hwqe=is_testreg,
                                bits=signal.bits,
                                resval=0,
                                enum=None,
                                mubi=False))

        reg = Register(self.offset,
                       reg_name,
                       None,  # no alias target
                       reg_desc,
                       async_name="",
                       async_clk=None,
                       hwext=is_testreg,
                       hwqe=is_testreg,
                       hwre=False,
                       regwen=None,
                       tags=reg_tags,
                       resval=None,
                       shadowed=False,
                       fields=fields,
                       update_err_alert=None,
                       storage_err_alert=None)
        self.add_register(reg)

    def make_intr_regs(self, interrupts: Sequence[Signal]) -> None:
        assert interrupts
        assert interrupts[-1].bits.msb < self._reg_width

        self._add_intr_alert_reg(interrupts,
                                 'INTR_STATE',
                                 'Interrupt State Register',
                                 None,
                                 'rw1c',
                                 'hrw',
                                 False,
                                 # Some POR routines have the potential to
                                 # unpredictably set some `intr_state` fields
                                 # for various IPs, so we exclude all
                                 # `intr_state` accesses from CSR checks to
                                 # prevent this from occurring.
                                 #
                                 # An example of an `intr_state` mismatch error
                                 # occurring due to a POR routine can be seen in
                                 # issue #6888.
                                 ["excl:CsrAllTests:CsrExclAll"])
        self._add_intr_alert_reg(interrupts,
                                 'INTR_ENABLE',
                                 'Interrupt Enable Register',
                                 lambda w, n: ('Enable interrupt when '
                                               '{}!!INTR_STATE.{} is set.'
                                               .format('corresponding bit in '
                                                       if w else '',
                                                       n)),
                                 'rw',
                                 'hro',
                                 False,
                                 [])
        self._add_intr_alert_reg(interrupts,
                                 'INTR_TEST',
                                 'Interrupt Test Register',
                                 lambda w, n: ('Write 1 to force '
                                               '{}!!INTR_STATE.{} to 1.'
                                               .format('corresponding bit in '
                                                       if w else '',
                                                       n)),
                                 'wo',
                                 'hro',
                                 True,
                                 # intr_test csr is WO so reads back 0s
                                 ["excl:CsrNonInitTests:CsrExclWrite"])

    def make_alert_regs(self, alerts: List[Alert]) -> None:
        assert alerts
        assert len(alerts) < self._reg_width
        self._add_intr_alert_reg(alerts,
                                 'ALERT_TEST',
                                 'Alert Test Register',
                                 ('Write 1 to trigger '
                                  'one alert event of this kind.'),
                                 'wo',
                                 'hro',
                                 True,
                                 [])

    def get_addr_width(self) -> int:
        '''Calculate the number of bits to address every byte of the block'''
        return (self.offset - 1).bit_length()

    def has_shadowed_reg(self) -> bool:
        '''Returns true if reg block contains shadowed regs'''
        for r in self.flat_regs:
            if r.shadowed:
                return True

        return False

    def has_internal_shadowed_reg(self) -> bool:
        '''Returns true if reg block contains shadowed regs in internal regs'''
        for r in self.flat_regs:
            if r.shadowed and not r.hwext:
                return True

        return False

    def apply_alias(self, alias_block: 'RegBlock', where: str) -> None:
        '''Validates alias description and overrides values in this block.

        This updates the overridable register and field attributes with the
        alias values and ensures that all non-overridable attributes have
        identical values.
        '''
        # Before doing anything, check that the new alias names do not exist.
        intersection = (alias_block.name_to_flat_reg.keys() &
                        self.name_to_flat_reg.keys())
        if intersection:
            raise ValueError('Alias register names {} are not unique in alias '
                             ' {}'.format(list(intersection), where))

        # Build a name map for regwens so that we can check correspondence.
        alias_wennames = {}
        for name in self.wennames:
            alias_wennames.update(
                {name: self.name_to_flat_reg[name.lower()].alias_target})

        # Loop over registers, validate the structure and update the generic
        # register data structure. Since the internal register
        # lists "registers", "flat_regs", "all_regs", "type_regs"
        # and "entries" use references to the reg objects, everything stays in
        # sync - except when multiregs are involved. To that end, another
        # update loop over multiregs is required further below.
        for alias_reg in alias_block.registers:
            # First, check existence of the register to be aliased
            if alias_reg.alias_target is None:
                raise ValueError('No alias target register defined for '
                                 'alias name {} in {}'
                                 .format(alias_reg.name, where))

            target = alias_reg.alias_target.lower()
            if target not in self.name_to_flat_reg:
                raise ValueError('Aliased target register {} with alias '
                                 'name {} does not exist in reg '
                                 'block {} ({}).'
                                 .format(target,
                                         alias_reg.name,
                                         self.name,
                                         where))

            # This is the register we want to alias over.
            reg = self.name_to_flat_reg[target]

            # Make sure the wenreg referenced is the same.
            if alias_reg.regwen is not None and reg.regwen is not None:
                alias_wenreg =\
                    alias_block.name_to_flat_reg[alias_reg.regwen.lower()]
                if alias_wenreg.alias_target != reg.regwen:
                    raise ValueError('Alias wenreg {} with generic name {} '
                                     'is not the same register as generic '
                                     'wenreg {} in aliased target register {} '
                                     'with alias name {} in reg block {} ({}).'
                                     .format(alias_reg.name,
                                             alias_wenreg.alias_target,
                                             reg.regwen,
                                             target,
                                             alias_reg.name,
                                             self.name,
                                             where))

            elif alias_reg.regwen is not None or reg.regwen is not None:
                raise ValueError('Missing regwen define in aliased target '
                                 'register {} with alias name {} in reg '
                                 'block {} ({}).'
                                 .format(target,
                                         alias_reg.name,
                                         self.name,
                                         where))

            # Check that the non-overridable attributes match, and override the
            # attributes.
            reg.apply_alias(alias_reg, where)

        # Build a local index of all multiregs. We don't store this in the
        # class since it is only used once here.
        name_to_multiregs = {mr.name.lower(): mr for mr in self.multiregs}

        # Loop over multiregisters, validate the structure and update the
        # generic multiregister data structure.
        for alias_mr in alias_block.multiregs:
            # First, check existence of the register to be aliased
            if alias_mr.alias_target is None:
                raise ValueError('No alias target multiregister defined for '
                                 'alias name {} in {}'
                                 .format(alias_mr.name, where))

            target = alias_mr.alias_target.lower()
            if target not in name_to_multiregs:
                raise ValueError('Aliased target multiregister {} with alias '
                                 'name {} does not exist in reg '
                                 'block {} ({}).'
                                 .format(target,
                                         alias_mr.name,
                                         self.name,
                                         where))

            # This is the register we want to alias over. Check that the
            # non-overridable attributes match, and override the attributes.
            mr = name_to_multiregs[target]
            mr.apply_alias(alias_mr, where)

        # Finally, we loop over the flat registers (which includes expanded
        # multiregs) and update the name_to_offset and name_to_flat_reg maps.
        for alias_name, alias_reg in alias_block.name_to_flat_reg.items():
            assert (alias_reg.alias_target)
            self._rename_flat_reg(alias_reg.alias_target, alias_name)

    def scrub_alias(self, where: str) -> None:
        '''Replaces sensitive fields in reg block with generic names

        This function can be used to create the generic register descriptions
        from full alias hjson definitions. It will only work on reg blocks
        where the alias_target keys are defined, and otherwise throw an error.
        '''
        # First build a name map for regwens so that we can replace them below.
        alias_wennames = {}
        for name in self.wennames:
            alias_wennames.update(
                {name: self.name_to_flat_reg[name.lower()].alias_target})

        # Loop over registers, and scrub information.
        for reg in self.registers:
            if reg.alias_target is None:
                raise ValueError('No alias target register defined for '
                                 'alias name {} in {}'
                                 .format(reg.name, where))
            reg.scrub_alias(where)
            # Replace regwen name also.
            if reg.regwen is not None:
                reg.regwen = alias_wennames[reg.regwen]

        # Loop over multiregisters, and scrub information.
        for alias_mr in self.multiregs:
            # First, check existence of the register to be aliased
            if alias_mr.alias_target is None:
                raise ValueError('No alias target multiregister defined for '
                                 'alias name {} in {}'
                                 .format(alias_mr.name, where))
            alias_mr.scrub_alias(where)

        # Make a shallow copy of this dict, since we are about to modify the
        # name mapping below.
        name_to_flat_reg_copy = self.name_to_flat_reg.copy()
        # Replace all alias with generic names.
        # Note that the scrubbing above assigns .alias_target to .name.
        for alias_name, reg in name_to_flat_reg_copy.items():
            self._rename_flat_reg(alias_name, reg.name)
