# Copyright 2023 Google LLC
# Copyright lowRISC contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

""" Utility functions for topgen
"""

import logging as log
import sys
from collections import OrderedDict
from mako.template import Template
from typing import Dict, Tuple

from reggen.ip_block import IpBlock
from topgen import lib as lib
from topgen.c import TopGenC
from topgen.c_test import TopGenCTest


class TopGenMatchaC(TopGenC):
    """ A class to add the Opentitan TopGenC with extra plic rendering methods.
    """

    def __init__(self, top_info, name_to_block: Dict[str, IpBlock]):
        super().__init__(top_info, name_to_block)
        # Update plic CEnum objects with appended smc suffix in the name
        # for the first and last elements to avoid naming collision.
        self.plic_sources.constants[0][0].parts.append("smc")
        self.plic_sources.constants[-1][0].parts.append("smc")
        self.plic_targets.constants[0][0].parts.append("smc")
        self.plic_targets.constants[-1][0].parts.append("smc")
        self.plic_interrupts.constants[0][0].parts.append("smc")
        self.plic_interrupts.constants[-1][0].parts.append("smc")

    def smc_plic_sources_render(self):
        return self._smc_c_enum_render(self.plic_sources)

    def smc_plic_targets_render(self):
        return self._smc_c_enum_render(self.plic_targets)

    def smc_plic_interrupts_render(self):
        return self._smc_c_enum_render(self.plic_interrupts)

    def smc_plic_interrupts_define_render(self):
        return self._smc_c_define_render(self.plic_interrupts)

    def smc_plic_mapping_render_declaration(self):
        template = (
            "extern const ${mapping.output_type_name.as_snake_case()}_smc_t\n"
            "    ${mapping.name.as_snake_case()}_smc[${len(mapping.mapping)}];")
        return Template(template).render(mapping=self.plic_mapping)

    def smc_plic_mapping_render_definition(self):
        template = (
            "const ${mapping.output_type_name.as_snake_case()}_smc_t\n"
            "    ${mapping.name.as_snake_case()}_smc[${len(mapping.mapping)}] = {\n"
            "% for in_name, out_name in mapping.mapping.items():\n"
            "  [${in_name.as_c_enum()}] = ${out_name.as_c_enum()},\n"
            "% endfor\n"
            "};\n")
        return Template(template).render(mapping=self.plic_mapping)

    def _smc_c_enum_render(self, enum):
        """ Add the c_helper CEnum rendering code for smc."""
        template = ("typedef enum ${enum.name.as_snake_case()}_smc {\n"
                    "% for name, value, docstring in enum.constants:\n"
                    "  ${name.as_c_enum()} = ${value}, /**< ${docstring} */\n"
                    "% endfor\n"
                    "} ${enum.name.as_snake_case()}_smc_t;")
        return Template(template).render(enum=enum)

    def _smc_c_define_render(self, enum):
        """ Add the c_helper CDefine rendering code for smc."""
        template = ("% for name, value, docstring in enum.constants:\n"
                    "#define ${name.as_c_define()} ${value} /**< ${docstring} */\n"
                    "% endfor\n")
        return Template(template).render(enum=enum)

def _separate_interrupt_modules(top: OrderedDict, name_to_block: Dict[str,
                                                                      IpBlock],
                                intr_to_smc_list: list):
    """Populate top["interrupt_module"] if necessary

    Do this by adding each module in top['modules'] that defines at least one
    interrupt.
    """
    if ("sec_interrupt_module" in top) or ("smc_interrupt_module" in top):
        return

    modules_sec = []
    modules_smc = []
    for module in top["module"]:
        block = name_to_block[module["type"]]
        if block.interrupts:
            if module["name"] in intr_to_smc_list:
                modules_smc.append(module["name"])
            else:
                modules_sec.append(module["name"])
    log.info("the genreate modules_sec is: ", modules_sec)
    top["sec_interrupt_module"] = modules_sec
    log.info("the genreate modules_smc is: ", modules_smc)
    top["smc_interrupt_module"] = modules_smc


def create_smc_c_helper(helper: TopGenCTest, topcfg: OrderedDict,
                        name_to_block: Dict[str, IpBlock]) -> TopGenCTest:
    """ Create the smc-specific c-code helper object.

    A workaround to append the smc-specific helper rendering functions in
    addition to the OpenTitan c_helper class.
    """
    smc_helper = TopGenMatchaC(topcfg, name_to_block)
    helper.smc_helper = smc_helper
    return helper


def create_separate_interrupt_topcfg(
    top: OrderedDict,) -> Tuple[OrderedDict, OrderedDict]:
    """ Create two topcfg dictionaries from separated interrupt groups.

    This is a workaround to use the Opentitan utility infrastructure to generate
    the c template helpers, which assumes one interrupt list at the top level.
    """
    interrupt_group = ["sec_interrupt", "smc_interrupt", "interrupt"]
    if not all(x in top for x in interrupt_group):
        log.error(
            f"Need to have 'sec_interrupt', 'smc_interrupt, 'interrupt' keys "
            f"in topcfg")
        sys.exit(1)
    sec_topcfg = top.copy()
    sec_topcfg["interrupt"] = sec_topcfg["sec_interrupt"]
    sec_topcfg["interrupt_module"] = sec_topcfg["sec_interrupt_module"]
    smc_topcfg = top.copy()
    smc_topcfg["num_cores"] = 1  # used to define plic targets.
    smc_topcfg["interrupt"] = smc_topcfg["smc_interrupt"]
    smc_topcfg["interrupt_module"] = smc_topcfg["smc_interrupt_module"]
    return sec_topcfg, smc_topcfg


def amend_separate_interrupt(top: OrderedDict, name_to_block: Dict[str,
                                                                   IpBlock],
                             intr_to_smc_list: list) -> OrderedDict:
    """Check interrupt_module if exists, or just use all modules
    """
    _separate_interrupt_modules(top, name_to_block, intr_to_smc_list)

    if "sec_interrupt" not in top or top["sec_interrupt"] == "":
        top["sec_interrupt"] = []

    if "smc_interrupt" not in top or top["smc_interrupt"] == "":
        top["smc_interrupt"] = []

    interrupt_module_list = [
        top["sec_interrupt_module"], top["smc_interrupt_module"]
    ]
    interrupt_list = [top["sec_interrupt"], top["smc_interrupt"]]
    for idx, l in enumerate(interrupt_module_list):
        for m in l:
            ips = list(filter(lambda module: module["name"] == m,
                              top["module"]))
            if len(ips) == 0:
                log.warning(
                    "Cannot find IP %s which is used in the interrupt_module" %
                    m)
                continue

            ip = ips[0]
            block = name_to_block[ip["type"]]

            log.info("Adding interrupts from module %s" % ip["name"])
            for signal in block.interrupts:
                sig_dict = signal.as_nwt_dict('interrupt')
                qual = lib.add_module_prefix_to_signal(sig_dict,
                                                       module=m.lower())
                interrupt_list[idx].append(qual)
    return top
