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

from typing import Dict, List, Optional

from .access import SWAccess
from .lib import (check_keys, check_str, check_bool, check_int,
                  expand_parameter)

REQUIRED_FIELDS = {
    'desc': ['t', "description of the window"],
    'items': ['d', "size in fieldaccess width words of the window"],
    'swaccess': ['s', "software access permitted"],
}

# TODO potential for additional optional to give more type info?
# eg sram-hw-port: "none", "sync", "async"
OPTIONAL_FIELDS = {
    'name': ['s', "Name of the window"],
    'byte-write': [
        's', "True if byte writes are supported. "
        "Defaults to false if not present."
    ],
    'validbits': [
        'd', "Number of valid data bits within "
        "regwidth sized word. "
        "Defaults to regwidth. If "
        "smaller than the regwidth then in each "
        "word of the window bits "
        "[regwidth-1:validbits] are unused and "
        "bits [validbits-1:0] are valid."
    ],
    'unusual': [
        's', "True if window has unusual parameters "
        "(set to prevent Unusual: errors)."
        "Defaults to false if not present."
    ]
}


class Window:
    '''A class representing a memory window'''
    def __init__(self,
                 name: Optional[str],
                 desc: str,
                 unusual: bool,
                 byte_write: bool,
                 validbits: int,
                 items: int,
                 size_in_bytes: int,
                 offset: int,
                 swaccess: SWAccess):
        assert 0 < validbits
        assert 0 < items <= size_in_bytes

        self.name = name
        self.desc = desc
        self.unusual = unusual
        self.byte_write = byte_write
        self.validbits = validbits
        self.items = items
        self.size_in_bytes = size_in_bytes
        self.offset = offset
        self.swaccess = swaccess

        # Check that offset has been adjusted so that the first item in the
        # window has all zeros in the low bits.
        po2_size = 1 << (self.size_in_bytes - 1).bit_length()
        assert not (offset & (po2_size - 1))

    @staticmethod
    def from_raw(offset: int,
                 reg_width: int,
                 params: List[Dict[str, object]],
                 raw: object) -> 'Window':
        rd = check_keys(raw, 'window',
                        list(REQUIRED_FIELDS.keys()),
                        list(OPTIONAL_FIELDS.keys()))

        r_name = rd.get('name')
        wind_desc = 'window at offset {:#x}'.format(offset)
        if r_name is None:
            name = None
        else:
            name = check_str(r_name, wind_desc)
            wind_desc = '{!r} {}'.format(name, wind_desc)

        desc = check_str(rd['desc'], 'desc field for ' + wind_desc)

        unusual = check_bool(rd.get('unusual', False),
                             'unusual field for ' + wind_desc)
        byte_write = check_bool(rd.get('byte-write', False),
                                'byte-write field for ' + wind_desc)

        validbits = check_int(rd.get('validbits', reg_width),
                              'validbits field for ' + wind_desc)
        if validbits <= 0:
            raise ValueError('validbits field for {} is not positive.'
                             .format(wind_desc))
        if validbits > reg_width:
            raise ValueError('validbits field for {} is {}, '
                             'which is greater than {}, the register width.'
                             .format(wind_desc, validbits, reg_width))

        r_items = check_str(rd['items'], 'items field for ' + wind_desc)
        items = expand_parameter(params, r_items,
                                 'expanding items field for ' + wind_desc)
        if items <= 0:
            raise ValueError("Items field for {} is {}, "
                             "which isn't positive."
                             .format(wind_desc, items))

        assert reg_width % 8 == 0
        size_in_bytes = items * (reg_width // 8)

        # Round size_in_bytes up to the next power of 2. The calculation is
        # like clog2 calculations in SystemVerilog, where we start with the
        # last index, rather than the number of elements.
        assert size_in_bytes > 0
        po2_size = 1 << (size_in_bytes - 1).bit_length()

        # A size that isn't a power of 2 is not allowed unless the unusual flag
        # is set.
        if po2_size != size_in_bytes and not unusual:
            raise ValueError('Items field for {} is {}, which gives a size of '
                             '{} bytes. This is not a power of 2 (next power '
                             'of 2 is {}). If you want to do this even so, '
                             'set the "unusual" flag.'
                             .format(wind_desc, items,
                                     size_in_bytes, po2_size))

        # Adjust offset if necessary to make sure the base address of the first
        # item in the window has all zeros in the low bits.
        addr_mask = po2_size - 1
        if offset & addr_mask:
            offset = (offset | addr_mask) + 1
        offset = offset

        swaccess = SWAccess(wind_desc, rd['swaccess'])
        if not (swaccess.value[4] or unusual):
            raise ValueError('swaccess field for {} is {}, which is an '
                             'unusual access type for a window. If you want '
                             'to do this, set the "unusual" flag.'
                             .format(wind_desc, swaccess.key))

        return Window(name, desc, unusual, byte_write,
                      validbits, items, size_in_bytes, offset, swaccess)

    def next_offset(self, addrsep: int) -> int:
        return self.offset + self.size_in_bytes

    def _asdict(self) -> Dict[str, object]:
        rd = {
            'desc': self.desc,
            'items': self.items,
            'swaccess': self.swaccess.key,
            'byte-write': self.byte_write,
            'validbits': self.validbits,
            'unusual': self.unusual
        }
        if self.name is not None:
            rd['name'] = self.name

        return {'window': rd}
