##
# Copyright (c) 2021 Xilinx, Inc.
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
# associated documentation files (the "Software"), to deal in the Software without restriction, including 
# without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to 
# the following conditions: 
# 
# The above copyright notice and this permission notice shall be included in all copies or substantial 
# portions of the Software. 
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
#
##
import os,inspect
import re
from pymongo import MongoClient
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
apidir = os.path.join(parentdir,"api")

client = MongoClient("mongodb://localhost:27017/xregv")
db=client["xregv"]

version="xregv_ps_S80_ES1_VCK180"

AM012 = {
    "hw_name": "AM012",
    "instance_name": [
        "CFRAME00_REG",
        "APU_GIC_DIST_MAIN",
        "CFRAME02_REG",
        "APU_GIC_REDIST_CTLLPI_0",
        "APU_GIC_REDIST_SGISPI_0",
        "CFRAME01_REG",
        "APU_GIC_ITS_TRANS",
        "APU_GIC_CPUIF",
        "APU_GIC_REDIST_SGISPI_1",
        "APU_GIC_DIST_MBSPI",
        "APU_GIC_VIFCTL",
        "APU_DUAL_CSR",
        "CANFD0",
        "CANFD1",
        "APU_GIC_VCPUIF",
        "APU_GIC_ITS_CTL",
        "APU_GIC_REDIST_CTLLPI_1",
        "DPC_DMA_CSR",
        "CFRAME04_REG",
        "CFRAME08_REG",
        "FPD_CCI_CSR",
        "FPD_SLCR_SECURE",
        "FPD_CCI_CORE",
        "LPD_DMA_CH5",
        "FPD_INT_CSR",
        "LPD_DMA_CH0",
        "FPD_SMMU_CSR",
        "CFRAME05_REG",
        "CFRAME03_REG",
        "CFRAME11_REG",
        "CFRAME07_REG",
        "LPD_DMA_CH1",
        "LPD_DMA_CH3",
        "CFRAME09_REG",
        "LPD_DMA_CH2",
        "CFRAME13_REG",
        "RPU_DUAL_CSR",
        "CRL",
        "CRP",
        "LPD_DMA_CH4",
        "RPU_GIC_PL390",
        "CFRAME_BCAST_REG",
        "FPD_SLCR",
        "CFRAME10_REG",
        "CFRAME12_REG",
        "CFRAME14_REG",
        "CFU_CSR",
        "DPC_AURORA",
        "CFRAME06_REG",
        "CRF",
        "TTC0",
        "LPD_IOP_SLCR_SECURE",
        "PPU_ICACHE_CTRL",
        "PMC_DMA0_CSR",
        "LPD_GPIO",
        "PMC_JTAG_CSR",
        "LPD_IOP_SLCR",
        "LPD_SLCR_SECURE",
        "SD_eMMC1",
        "XRAM_XMPU2",
        "DBG_APU0_ETM",
        "DBG_FPD_CTI1B",
        "PMC_INT_GPV",
        "DBG_CPM_ELA2A",
        "DBG_LPD_GPR",
        "DBG_FPD_REPL",
        "LPD_IOP_INT_GPV",
        "PL_AXI_LPD_CSR",
        "PPU_DCACHE_CTRL",
        "PMC_GLOBAL",
        "PMC_IOP_SLCR",
        "PSM_INT_GPV",
        "XRAM_CTRL1",
        "PSM_GLOBAL",
        "LPD_INT_CSR",
        "PPU_TMR_INJECT",
        "PLM_RTCA",
        "PMC_GPIO",
        "PMC_SBI_CSR",
        "PMC_XPPU",
        "UART1",
        "XRAM_XMPU3",
        "DBG_CPM_ELA2B",
        "XRAM_CTRL3",
        "DBG_CPM_ROM",
        "DBG_PMC_GPR",
        "DBG_RPU0_DBG",
        "IPI",
        "SPI0",
        "SD_eMMC0",
        "SPI1",
        "TTC2",
        "PL_AXI_FPD_CSR",
        "DBG_APU1_CTI",
        "PPU_MDM",
        "PMC_IOP_SLCR_SECURE",
        "PMC_RTC",
        "XRAM_INT_GPV",
        "OSPI",
        "PSM_TMR_TRACE",
        "DBG_APU1_ETM",
        "LPD_I2C1",
        "XRAM_SLCR",
        "LPD_INT_GPV",
        "DBG_RPU1_CTI",
        "DBG_CPM_ELA2C",
        "SCNTR",
        "LPD_SLCR",
        "PSM_TMR_INJECT",
        "PMC_EFUSE_CTRL",
        "PMC_IOP_INT_GPV",
        "PSM_LOCAL",
        "XRAM_XMPU0",
        "SCNTR_SECURE",
        "FPD_SWDT",
        "PL_ACELITE_FPD_CSR",
        "PSM_MDM",
        "PSM_ICACHE_ECC",
        "PSM_TMR_MANAGER",
        "DBG_CPM_ELA2D",
        "PMC_LOCAL",
        "PMC_RAM_CSR",
        "USB2_XHCI",
        "LPD_DMA_CH6",
        "DBG_APU1_DBG",
        "DBG_FPD_FUN",
        "DBG_FPD_GPR",
        "OCM_CSR",
        "LPD_XPPU",
        "QSPI",
        "LPD_I2C0",
        "PMC_I2C",
        "UART0",
        "PMC_XMPU",
        "XRAM_CTRL2",
        "DBG_PMC_CTI",
        "DBG_FPD_CTI1C",
        "PPU_TMR_MANAGER",
        "XRAM_XMPU1",
        "XRAM_CTRL0",
        "DBG_APU1_PMU",
        "DBG_CPM_CTI2D",
        "DBG_RPU1_ETM",
        "DBG_RPU0_ETM",
        "LPD_DMA_CH7",
        "GEM1",
        "GEM0",
        "TTC1",
        "TTC3",
        "PPU_TMR_TRACE",
        "PMC_ANLG",
        "PMC_INT_CSR",
        "PMC_SYSMON_CSR",
        "DBG_APU0_DBG",
        "DBG_APU0_PMU",
        "PPU_IOMODULE",
        "PSM_IOMODULE",
        "PSM_DCACHE_ECC",
        "PMC_EFUSE_CACHE",
        "PSM_INT_CSR",
        "USB2_CSR",
        "DBG_LPD_CTI",
        "DBG_APU_CTI",
        "DBG_FPD_ROM",
        "DBG_LPD_FUN",
        "DBG_PMC_ROM",
        "DBG_APU0_CTI",
        "DBG_RPU0_CTI",
        "DBG_FPD_CTI1D",
        "DBG_APU_ELA",
        "DBG_FPD_ETR",
        "DBG_RPU1_DBG",
        "LPD_SWDT",
        "PMC_DMA1_CSR",
        "PMC_XPPU_NPI",
        "FPD_XMPU",
        "OCM_XMPU",
        "DBG_CPM_CTI2A",
        "DBG_FPD_ETF",
        "DBG_APU_ETF",
        "DBG_LPD_ROM",
        "CPM4_ADDRREMAP",
        "CPM4_XDMA_CSR",
        "CPM4_DVSEC1",
        "CPM5_INT_CSR",
        "DBG_TSG_RW",
        "CPM5_CRX",
        "CPM4_DVSEC0",
        "CPM5_INT_GPV",
        "CPM4_L2_CSR",
        "CPM4_DMA_ATTR",
        "DBG_CPM_FUN",
        "CPM4_CRX",
        "CPM4_INT_CSR",
        "CPM5_SLCR",
        "CPM5_SLCR_SECURE",
        "CPM_PCSR",
        "CPM5_CMN",
        "CPM4_PCIE0_ATTR",
        "CPM4_SLCR",
        "CPM5_L20_CSR",
        "CPM5_ADDRREMAP",
        "DBG_FPD_TPIU",
        "CPM4_INT_GPV",
        "DBG_STM",
        "DBG_APU_FUN",
        "CPM4_SLCR_SECURE",
        "CPM5_PCIE0_CSR",
        "CPM4_CMN",
        "CPM4_PCIE1_ATTR",
        "CPM5_PCIE0_ATTR",
        "CPM5_L21_CSR",
        "CPM5_PCIE1_CSR",
        "CPM5_DVSEC0",
        "CPM5_DMA0_ATTR",
        "CPM5_PCIE1_ATTR",
        "CPM5_DPLL0_ATTR",
        "CPM5_DMA1_ATTR",
        "CPM5_DVSEC1",
        "CPM5_DPLL1_ATTR",
        "CPM5_DMA1_CSR",
        "CPM5_DMA0_CSR"
    ]
}

DB_Lookup = db["db_lookup"]
DB_Lookup = DB_Lookup.find_one()
blocks = [AM012]
for dataDict in blocks:
    block_name= dataDict["hw_name"]
    db1="xregv_ps_S80_ES1_VCK180"

    common_path = apidir
    outputname = ""
    block = f"{dataDict['hw_name']}"
    block_path = os.path.join(common_path, block)
    if not os.path.exists(block_path):
        os.makedirs(block_path)
    if "hw_name" in dataDict:
        outputname = outputname + dataDict["hw_name"]
    if dataDict["hw_name"] == "DDR":
        matchfilter = {"instance_name": {"$in": [re.compile(r'DDRMC'), re.IGNORECASE]}}
    if dataDict["hw_name"] == "NPI":
        matchfilter = {"instance_name": {"$nin": [re.compile(r'DDR'), re.IGNORECASE]}}
    if dataDict["hw_name"] == "PMC":
        matchfilter = {"instance_name": {"$in": [re.compile(r'PMC'), re.IGNORECASE]}}
    if dataDict["hw_name"] == "CPM":
        matchfilter = {"instance_name": {
            "$in": [re.compile(r'CPM'), re.compile(r'XDMA'), re.compile(r'PCIEA'), re.IGNORECASE, ]}}
    if dataDict["hw_name"] == "PS":
        matchfilter = {"instance_name": {
            "$nin": [re.compile(r'PMC'), re.compile(r'CPM'), re.compile(r'XDMA'), re.compile(r'PCIEA'),
                     re.IGNORECASE, ]}}
    if "instance_name" in dataDict and type(dataDict["instance_name"]) != list:
        outputname = outputname + "_" + dataDict["instance_name"]
        matchfilter = {"instance_name": dataDict["instance_name"]}
    if "instance_name" in dataDict and type(dataDict["instance_name"]) == list:
        matchfilter = {"instance_name": {"$in": dataDict["instance_name"]}}

    db1 = db[db1]
    resultcursor = list(db1.aggregate([{"$match": matchfilter}, {
        "$project": {"_id": 0, "instance_name": 1, "base_address": 1, "registers": 1}},
                                      {"$unwind": "$registers"}, {
                                          "$project": {"registers.name": 1, "registers.address": 1,
                                                       "instance_name": 1, "base_address": 1,
                                                       "registers.fields": 1,
                                                       "registers.reset_value": 1, "registers.width": 1}}]))
    instance_data = {}
    for entry in resultcursor:
        instance_name = entry['instance_name']
        if instance_name not in instance_data:
            instance_data[instance_name] = []
        instance_data[instance_name].append(entry)
    for instance_name, data_list in instance_data.items():
        tcl_content = ""
        base_address = data_list[0]['base_address']
        for entry in data_list:
            register_name = entry['registers']['name']
            address = entry['registers']['address']
            reset_value = entry['registers']['reset_value']
            absolute_address = hex(int(base_address, 16) + int(address, 16))
            if int(entry['registers']['width']) < 32 and absolute_address[-1] not in ['0','4','8','c']:
                tcl_content += f"lappend results [mem_read16 {absolute_address}]\n"
            else:
                tcl_content += f"lappend results [mem_read {absolute_address}]\n"

        os.chdir(block_path)
        with open(f"{instance_name}.tcl", "w") as tcl_file:
            tcl_file.write(f"# Instance: {instance_name}\n")
            tcl_file.write("set results {}\n")
            tcl_file.write("proc mem_read {add} {\n")
            tcl_file.write("    if {[catch {mrd $add} err]} {\n")
            tcl_file.write("        return \"$add: $err\"\n")
            tcl_file.write("    } else {\n")
            tcl_file.write("        return $err\n")
            tcl_file.write("    }\n")
            tcl_file.write("}\n")
            tcl_file.write("proc mem_read16 {add} {\n")                                                   
            tcl_file.write("    if {[catch {mrd -size h $add} err]} {\n")                                       
            tcl_file.write("        return \"$add: $err\"\n")                                          
            tcl_file.write("    } else {\n")                                                           
            tcl_file.write("        return $err\n")                                                    
            tcl_file.write("    }\n")                                                                       
            tcl_file.write("}\n")
            tcl_file.write(tcl_content)
        os.chmod(f"{instance_name}.tcl", 0o775)
    print(f"tcl files generated sucessfully for {block_name} block")







