#!/usr/bin/python

# Copyright CERN, 2013
# Author: Matthieu Cattin (CERN)
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications: 17/12/2013

# Import standard modules
import sys
import time

# Import specific modules


# Class to decode SDB records

class SDBDeviceOperationError(Exception):
    def __init__(self, msg):
        self.msg = msg
    def __str__(self):
        return ("[SDB] %s" %(self.msg))

class interconnect_record:

    def __init__(self):
        self.magic
        self.nb_records
        self.version
        self.bus_type
        self.component

class device_record:

    def __init__(self):
        self.abi_class
        self.abi_ver_maj
        self.abi_ver_min
        self.bus_flags
        self.component

class bridge_record:

    def __init__(self):
        self.child
        self.component

class repository_record:

    def __init__(self):
        self.repo_url
        self.type

class synthesis_record:

    def __init__(self):
        self.syn_name
        self.commit_id
        self.tool_name
        self.tool_ver
        self.date
        self.user_name
        self.type

class component:

    def __init__(self):
        self.addr_first
        self.addr_last
        self.product

class product:

    def __init__(self):
        self.vendor_id
        self.device_id
        self.version
        self.date
        self.name
        self.rec_type

class CSDB:
    record_types = {0x00: "INTERCONNECT",
                    0x01: "DEVICE",
                    0x02: "BRIDGE",
                    0x80: "INTEGRATION",
                    0x81: "REPO_URL",
                    0x82: "SYNTHESIS",
                    0xFF: "EMPTY"}

    vids = {0x0000000000000651: "GSI",
            0x000000000000CE42: "CERN"}

    dids = {0x441c5143: "gpio_port",
            0x123c5443: "i2c_master",
            0x779c5443: "onewire_master",
            0xe503947e: "spi",
            0x00000013: "vic",
            0xb77a5045: "serial_lcd",
            0xcababa56: "streaming_dma",
            0x00006603: "fmc_adc_svec_csr",
            0x00000604: "fmc_adc_timetag_core",
            0x00000605: "fmc_adc_irq_ctrl (legacy)",
            0x10006610: "fmc_adc_ddr_data",
            0x10006611: "fmc_adc_ddr_address",
            0x00000601: "gn4124_dma_ctrl",
            0x00000603: "fmc_adc_spec_csr",
            0xd5735ab4: "gn4124_dma_eic",
            0x26ec6086: "fmc_adc_eic",
            0x00000608: "fmc_adc_csr",
            0xe6a542c9: "crossbar",
            0xeef0b198: "bridge"}

    def __init__(self, csr):
        self.csr = csr
        self.interconnect = self.get_record(0)
        self.nb_rec = self.get_nb_records()
        self.records = []
        for i in range(self.nb_rec):
            self.records.append(self.get_record(i))

    def dump(self):
        print("\nDumping SDB records:")
        for rec in range(len(self.records)):
            rec_type = self.get_record_type(self.records[rec])
            print("-----------------------------------------------------")
            print("  Record: %d                 %s"%(rec, self.record_types[rec_type]))
            if not(rec_type & 0x80):
                print("")
                vid = (self.records[rec][6] << 32) + self.records[rec][7]
                print("  Vendor ID: 0x%016X: %s"%(vid, self.vids[vid]))
                did = self.records[rec][8]
                print("  Device ID: 0x%08X        : %s"%(did, self.dids[did]))
                print("")
            for i in range(len(self.records[rec])):
                print("    addr: 0x%02X: 0x%08X"%(i * 0x4, self.records[rec][i]))

    def get_record(self, rec_nb):
        rec = []
        start_addr = rec_nb * 0x40
        end_addr = start_addr + 0x40
        for addr in range(start_addr, end_addr, 4):
            rec.append(self.csr.rd_reg(addr))
            #print("addr: 0x%02X: 0x%08X"%(addr, rec[-1]))
        return rec

    def get_record_type(self, rec):
        rec_type = rec[-1] & 0xff
        #print("Record type: 0x%02X"%(rec_type))
        return rec_type

    def get_nb_records(self):
        nb_rec = (self.interconnect[1] >> 16) & 0xffff
        #print("Number of records: %d (0x%04X)"%(nb_rec, nb_rec))
        return nb_rec
