#!/usr/bin/env python3
#
# Copyright (C) 2024-2025 Texas Instruments Incorporated - ALL RIGHTS RESERVED
#
# NOTE: requires python 3.10 or later to get bit_count

import click


class BasedIntParamType(click.ParamType):
    name = "integer"

    def convert(self, value, param, ctx):
        if isinstance(value, int):
            return value

        try:
            if value[:2].lower() == "0x":
                return int(value[2:], 16)
            elif value[:1] == "0":
                return int(value, 8)
            return int(value, 10)
        except ValueError:
            self.fail(f"{value!r} is not a valid integer", param, ctx)


# bit 0 mask
bit0_dataMask = 0xB4D1B4D14B2E4B2E
bit0_addrMask = 0x2AA750

# bit 1 mask
bit1_dataMask = 0x1557155715571557
bit1_addrMask = 0x5D688

# bit 2 mask
bit2_dataMask = 0xA699A699A699A699
bit2_addrMask = 0x154DA8

# bit 3 mask
bit3_dataMask = 0x38E338E338E338E3
bit3_addrMask = 0x353C68

# bit 4 mask
bit4_dataMask = 0xC0FCC0FCC0FCC0FC
bit4_addrMask = 0xCFC18
0x3FC000
# bit 5 mask
bit5_dataMask = 0xFF00FF00FF00FF00
bit5_addrMask = 0x3FC00

# bit 6 mask
bit6_dataMask = 0xFF0000FFFF0000FF
bit6_addrMask = 0x3FFC00

# bit 7 mask
bit7_dataMask = 0x00FFFF00FF0000FF
bit7_addrMask = 0x3F8


def calculate_ecc(data_in, addr_in):
    bit0_bitCount = (data_in & bit0_dataMask).bit_count() + (
        addr_in & bit0_addrMask
    ).bit_count()
    bit0 = (bit0_bitCount & 0x1) << 0
    bit1_bitCount = (data_in & bit1_dataMask).bit_count() + (
        addr_in & bit1_addrMask
    ).bit_count()
    bit1 = (bit1_bitCount & 0x1) << 1
    bit2_bitCount = (
        (data_in & bit2_dataMask).bit_count()
        + (addr_in & bit2_addrMask).bit_count()
        + 1
    )
    bit2 = (bit2_bitCount & 0x1) << 2
    bit3_bitCount = (
        (data_in & bit3_dataMask).bit_count()
        + (addr_in & bit3_addrMask).bit_count()
        + 1
    )
    bit3 = (bit3_bitCount & 0x1) << 3
    bit4_bitCount = (
        (data_in & bit4_dataMask).bit_count()
        + (addr_in & bit4_addrMask).bit_count()
        + 1
    )
    bit4 = (bit4_bitCount & 0x1) << 4
    bit5_bitCount = (
        (data_in & bit5_dataMask).bit_count()
        + (addr_in & bit5_addrMask).bit_count()
        + 1
    )
    bit5 = (bit5_bitCount & 0x1) << 5
    bit6_bitCount = (
        (data_in & bit6_dataMask).bit_count()
        + (addr_in & bit6_addrMask).bit_count()
        + 1
    )
    bit6 = (bit6_bitCount & 0x1) << 6
    bit7_bitCount = (
        (data_in & bit7_dataMask).bit_count()
        + (addr_in & bit7_addrMask).bit_count()
        + 1
    )
    bit7 = (bit7_bitCount & 0x1) << 7

    ecc = bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0

    return ecc


@click.command()
@click.option(
    "--data",
    default=0xAAAAAAAAAAAAAAAA,
    type=BasedIntParamType(),
    help="64-bit data to be used as basis for CRC",
)
@click.option(
    "--addr",
    default=0x12000,
    type=BasedIntParamType(),
    help="starting address for flash writes",
)
def calculate_three_eccs(data, addr):
    ecc1 = calculate_ecc(data, addr)
    print("Addr: %x Ecc: %x " % (addr, ecc1))
    addr = addr + 8
    ecc2 = calculate_ecc(data, addr)
    print("Addr: %x Ecc: %x " % (addr, ecc2))
    addr = addr + 8
    ecc3 = calculate_ecc(data, addr)
    print("Addr: %x Ecc: %x " % (addr, ecc3))


@click.command()
@click.option(
    "--data",
    default=0xFFFFFFFFFFFFFFFF,
    type=BasedIntParamType(),
    help="64-bit data to be used as basis for CRC",
)
@click.option(
    "--addr",
    default=0xF0200000,
    type=BasedIntParamType(),
    help="starting address for flash writes",
)
def calculate_one_ecc(data, addr):
    ecc1 = calculate_ecc(data, addr)
    print("Addr: %x Ecc: %x " % (addr, ecc1))
    addr = addr + 8


data_all_1 = 0xFFFFFFFFFFFFFFFF
addr_end = 0x20000

def calculate_0xFF_ecc(data):
    addr0 = 0x0
    ecc0 = 0
    total_ECC_0xFF= 0
    rate = 0
    print("ECC calculation for %x" % (data))
    while addr0 < addr_end:
        ecc0 = calculate_ecc(data, addr0)
        if (ecc0 == 0xFF):
            total_ECC_0xFF += 1
            print("Addr: %x Ecc: %x " % (addr0, ecc0))
        addr0 = addr0 + 8
    print("(%x)Total Addr Number for 0xFF ECC: %d" % (data,total_ECC_0xFF))
    rate = float(total_ECC_0xFF) / float(addr_end)
    print("(%x)Addr Percentage: %f" % (data,rate))
    print("====================================")


if __name__ == "__main__":
    # calculate_three_eccs()
    print("Program Start...")
    calculate_0xFF_ecc(data_all_1)
    test_data = 0x1
    while (test_data <= 0x8000000000000000):
        calculate_0xFF_ecc(data_all_1-test_data)
        test_data = test_data * 2



    
    
