//===-- DNBRegisterInfo.cpp -------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  Created by Greg Clayton on 8/3/07.
//
//===----------------------------------------------------------------------===//

#include "DNBRegisterInfo.h"
#include "DNBLog.h"
#include <string.h>

DNBRegisterValueClass::DNBRegisterValueClass(const DNBRegisterInfo *regInfo)
{
    Clear();
    if (regInfo)
        info = *regInfo;
}

void
DNBRegisterValueClass::Clear()
{
    memset(&info, 0, sizeof(DNBRegisterInfo));
    memset(&value, 0, sizeof(value));
}

bool
DNBRegisterValueClass::IsValid() const
{
    return
        info.name != NULL &&
        info.type != InvalidRegType &&
        info.size > 0 && info.size <= sizeof(value);
}

#define PRINT_COMMA_SEPARATOR do { if (pos < end) { if (i > 0) { strncpy(pos, ", ", end - pos); pos += 2; } } } while (0)

void
DNBRegisterValueClass::Dump(const char *pre, const char *post) const
{
    if (info.name != NULL)
    {
        char str[1024];
        char *pos;
        char *end = str + sizeof(str);
        if (info.format == Hex)
        {
            switch (info.size)
            {
            case 0:     snprintf(str, sizeof(str), "%s", "error: invalid register size of zero."); break;
            case 1:     snprintf(str, sizeof(str), "0x%2.2x", value.uint8); break;
            case 2:     snprintf(str, sizeof(str), "0x%4.4x", value.uint16); break;
            case 4:     snprintf(str, sizeof(str), "0x%8.8x", value.uint32); break;
            case 8:     snprintf(str, sizeof(str), "0x%16.16llx", value.uint64); break;
            case 16:    snprintf(str, sizeof(str), "0x%16.16llx%16.16llx", value.v_uint64[0], value.v_uint64[1]); break;
            default:
                strncpy(str, "0x", 3);
                pos = str + 2;
                for (uint32_t i=0; i<info.size; ++i)
                {
                    if (pos < end)
                        pos += snprintf(pos, end - pos, "%2.2x", (uint32_t)value.v_uint8[i]);
                }
                break;
            }
        }
        else
        {
            switch (info.type)
            {
            case Uint:
                switch (info.size)
                {
                case 1:     snprintf(str, sizeof(str), "%u", value.uint8); break;
                case 2:     snprintf(str, sizeof(str), "%u", value.uint16); break;
                case 4:     snprintf(str, sizeof(str), "%u", value.uint32); break;
                case 8:     snprintf(str, sizeof(str), "%llu", value.uint64); break;
                default:    snprintf(str, sizeof(str), "error: unsupported uint byte size %d.", info.size); break;
                }
                break;

            case Sint:
                switch (info.size)
                {
                case 1:     snprintf(str, sizeof(str), "%d", value.sint8); break;
                case 2:     snprintf(str, sizeof(str), "%d", value.sint16); break;
                case 4:     snprintf(str, sizeof(str), "%d", value.sint32); break;
                case 8:     snprintf(str, sizeof(str), "%lld", value.sint64); break;
                default:    snprintf(str, sizeof(str), "error: unsupported sint byte size %d.", info.size); break;
                }
                break;

            case IEEE754:
                switch (info.size)
                {
                case 4:     snprintf(str, sizeof(str), "%f", value.float32); break;
                case 8:     snprintf(str, sizeof(str), "%g", value.float64); break;
                default:    snprintf(str, sizeof(str), "error: unsupported float byte size %d.", info.size); break;
                }
                break;

            case Vector:
                if (info.size > 0)
                {
                    switch (info.format)
                    {
                    case VectorOfSInt8:
                        snprintf(str, sizeof(str), "%s", "sint8   { ");
                        pos = str + strlen(str);
                        for (uint32_t i=0; i<info.size; ++i)
                        {
                            PRINT_COMMA_SEPARATOR;
                            if (pos < end)
                                pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint8[i]);
                        }
                        strlcat(str, " }", sizeof(str));
                        break;

                    default:
                        DNBLogError("unsupported vector format %d, defaulting to hex bytes.", info.format);
                    case VectorOfUInt8:
                        snprintf(str, sizeof(str), "%s", "uint8   { ");
                        pos = str + strlen(str);
                        for (uint32_t i=0; i<info.size; ++i)
                        {
                            PRINT_COMMA_SEPARATOR;
                            if (pos < end)
                                pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint8[i]);
                        }
                        break;

                    case VectorOfSInt16:
                        snprintf(str, sizeof(str), "%s", "sint16  { ");
                        pos = str + strlen(str);
                        for (uint32_t i=0; i<info.size/2; ++i)
                        {
                            PRINT_COMMA_SEPARATOR;
                            if (pos < end)
                                pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint16[i]);
                        }
                        break;

                    case VectorOfUInt16:
                        snprintf(str, sizeof(str), "%s", "uint16  { ");
                        pos = str + strlen(str);
                        for (uint32_t i=0; i<info.size/2; ++i)
                        {
                            PRINT_COMMA_SEPARATOR;
                            if (pos < end)
                                pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint16[i]);
                        }
                        break;

                    case VectorOfSInt32:
                        snprintf(str, sizeof(str), "%s", "sint32  { ");
                        pos = str + strlen(str);
                        for (uint32_t i=0; i<info.size/4; ++i)
                        {
                            PRINT_COMMA_SEPARATOR;
                            if (pos < end)
                                pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint32[i]);
                        }
                        break;

                    case VectorOfUInt32:
                        snprintf(str, sizeof(str), "%s", "uint32  { ");
                        pos = str + strlen(str);
                        for (uint32_t i=0; i<info.size/4; ++i)
                        {
                            PRINT_COMMA_SEPARATOR;
                            if (pos < end)
                                pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint32[i]);
                        }
                        break;

                    case VectorOfFloat32:
                        snprintf(str, sizeof(str), "%s", "float32 { ");
                        pos = str + strlen(str);
                        for (uint32_t i=0; i<info.size/4; ++i)
                        {
                            PRINT_COMMA_SEPARATOR;
                            if (pos < end)
                                pos += snprintf(pos, end - pos, "%f", value.v_float32[i]);
                        }
                        break;

                    case VectorOfUInt128:
                        snprintf(str, sizeof(str), "%s", "uint128 { ");
                        pos = str + strlen(str);
                        for (uint32_t i=0; i<info.size/16; ++i)
                        {
                            PRINT_COMMA_SEPARATOR;
                            if (pos < end)
                                pos += snprintf(pos, end - pos, "0x%16.16llx%16.16llx", value.v_uint64[i], value.v_uint64[i+1]);
                        }
                        break;
                    }
                    strlcat(str, " }", sizeof(str));
                }
                else
                {
                    snprintf(str, sizeof(str), "error: unsupported vector size %d.", info.size);
                }
                break;

            default:
                snprintf(str, sizeof(str), "error: unsupported register type %d.", info.type);
                break;
            }
        }

        DNBLog("%s%4s = %s%s", pre ? pre : "", info.name, str, post ? post : "");
    }
}
