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

'''Code representing the entire chip for reggen'''

from typing import Dict, List, Optional, Tuple, Union

from .ip_block import IpBlock
from .params import ReggenParams
from .reg_block import RegBlock
from .window import Window

_IFName = Tuple[str, Optional[str]]
_Triple = Tuple[int, str, IpBlock]


class Top:
    '''An object representing the entire chip, as seen by reggen.

    This contains instances of some blocks (possibly multiple instances of each
    block), starting at well-defined base addresses. It may also contain some
    windows. These are memories that don't have their own comportable IP (so
    aren't defined in a block), but still take up address space.

    '''

    def __init__(self,
                 regwidth: int,
                 blocks: Dict[str, IpBlock],
                 instances: Dict[str, str],
                 if_addrs: Dict[Tuple[str, Optional[str]], int],
                 windows: List[Window]):
        '''Class initializer.

        regwidth is the width of the registers (which must match for all the
        blocks) in bits.

        blocks is a map from block name to IpBlock object.

        instances is a map from instance name to the name of the block it
        instantiates. Every block name that appears in instances must be a key
        of blocks.

        if_addrs is a dictionary that maps the name of a device interface on
        some instance of some block to its base address. A key of the form (n,
        i) means "the device interface called i on an instance called n". If i
        is None, this is an unnamed device interface. Every instance name (n)
        that appears in connections must be a key of instances.

        windows is a list of windows (these contain base addresses already).

        '''

        self.regwidth = regwidth
        self.blocks = blocks
        self.instances = instances
        self.if_addrs = if_addrs

        self.window_block = RegBlock(regwidth, ReggenParams())

        # Generate one list of base addresses and objects (with each object
        # either a block name and interface name or a window). While we're at
        # it, construct inst_to_block_name and if_addrs.
        merged = []  # type: List[Tuple[int, Union[_IFName, Window]]]
        for full_if_name, addr in if_addrs.items():
            merged.append((addr, full_if_name))

            inst_name, if_name = full_if_name

            # The instance name must match some key in instances, whose value
            # should in turn match some key in blocks.
            assert inst_name in instances
            block_name = instances[inst_name]
            assert block_name in blocks

            # Check that if_name is indeed the name of a device interface for
            # that block.
            block = blocks[block_name]
            assert block.bus_interfaces.has_interface(False, if_name)

        for window in sorted(windows, key=lambda w: w.offset):
            merged.append((window.offset, window))
            self.window_block.add_window(window)

        # A map from block name to the list of its instances. These instances
        # are listed in increasing order of the lowest base address of one of
        # their interfaces. The entries are added into the dict in the same
        # order, so an iteration over items() will give blocks ordered by their
        # first occurrence in the address map.
        self.block_instances = {}  # type: Dict[str, List[str]]

        # Walk the merged list in order of increasing base address. Check for
        # overlaps and construct block_instances.
        offset = 0
        for base_addr, item in sorted(merged, key=lambda pr: pr[0]):
            # Make sure that this item doesn't overlap with the previous one
            assert offset <= base_addr, item

            if isinstance(item, Window):
                addrsep = (regwidth + 7) // 8
                offset = item.next_offset(addrsep)
                continue

            inst_name, if_name = item
            block_name = instances[inst_name]
            block = blocks[block_name]

            lst = self.block_instances.setdefault(block_name, [])
            if inst_name not in lst:
                lst.append(inst_name)

            # This should be guaranteed by the fact that we've already checked
            # the existence of a device interface.
            assert if_name in block.reg_blocks
            reg_block = block.reg_blocks[if_name]

            offset = base_addr + reg_block.offset
