/*
 * QEMU model of the ASU_SHA2 Secure Hash Algorithm
 *
 * Copyright (c) 2023, Advanced Micro Devices, 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.
 */

/* Autogenerated by xregqemu.py 2023-03-14.  */

#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/register.h"
#include "qemu/bitops.h"
#include "qemu/log.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
#include "hw/stream.h"
#include "hw/hw.h"
#include "qapi/error.h"
#include "crypto/sha2.h"

#ifndef XILINX_ASU_SHA2_ERR_DEBUG
#define XILINX_ASU_SHA2_ERR_DEBUG 0
#endif

#define TYPE_XILINX_ASU_SHA2 "xlnx.asu_sha2"
#define TYPE_XILINX_ASU_SHA2_V2_1 "xlnx.asu_sha2_v2.1"

#define XILINX_ASU_SHA2(obj) \
     OBJECT_CHECK(ASU_SHA2, (obj), TYPE_XILINX_ASU_SHA2)

/* Describe the current state of the hash block.  */
enum State {
    ASU_SHA2_IDLE = 0,
    ASU_SHA2_RESETING,
    ASU_SHA2_RUNNING,
};

enum ASU_SHA_MODE {
    SHA_MODE_256 = 0,
    SHA_MODE_384 = 1,
    SHA_MODE_512 = 2,
    SHA_MODE_RESERVED = 3,
    SHA_MODE_RESERVED2 = 4,
    SHA_MODE_256_LMS_OTS = 5,
    SHA_MODE_256_SLH_DSA = 6,
};

#define ASU_SHA2_MAX_DIGEST_LEN (512 >> 3)
#define ASU_SHA2_MAX_BLOCK_SIZE (144)
#define ASU_SHA2_MAX_CHAIN_BUF_LEN 64
#define ASU_SHA2_SLH_DSA_HASH_ADDR 0x3C
#define ASU_SHA2_V2_1 0x20001

REG32(SHA_START, 0x0)
    FIELD(SHA_START, VALUE, 0, 1)
REG32(SHA_RESET, 0x4)
    FIELD(SHA_RESET, VALUE, 0, 1)
REG32(SHA_DONE, 0x8)
    FIELD(SHA_DONE, VALUE, 0, 1)
REG32(SHA_DIGEST_0, 0x10)
REG32(SHA_DIGEST_1, 0x14)
REG32(SHA_DIGEST_2, 0x18)
REG32(SHA_DIGEST_3, 0x1c)
REG32(SHA_DIGEST_4, 0x20)
REG32(SHA_DIGEST_5, 0x24)
REG32(SHA_DIGEST_6, 0x28)
REG32(SHA_DIGEST_7, 0x2c)
REG32(SHA_DIGEST_8, 0x30)
REG32(SHA_DIGEST_9, 0x34)
REG32(SHA_DIGEST_10, 0x38)
REG32(SHA_DIGEST_11, 0x3c)
REG32(SHA_DIGEST_12, 0x40)
REG32(SHA_DIGEST_13, 0x44)
REG32(SHA_DIGEST_14, 0x48)
REG32(SHA_DIGEST_15, 0x4c)
REG32(SHA_MODE, 0xa0)
    FIELD(SHA_MODE, VALUE, 0, 3)
REG32(SHA_AUTO_PADDING, 0xa4)
    FIELD(SHA_AUTO_PADDING, ENABLE, 0, 1)
REG32(SHA_SLV_ERR_CTRL, 0xb0)
    FIELD(SHA_SLV_ERR_CTRL, ENABLE, 0, 1)
REG32(SHA_ISR, 0xb4)
    FIELD(SHA_ISR, SLVERR, 1, 1)
    FIELD(SHA_ISR, DONE, 0, 1)
REG32(SHA_IMR, 0xb8)
    FIELD(SHA_IMR, SLVERR, 1, 1)
    FIELD(SHA_IMR, DONE, 0, 1)
REG32(SHA_IER, 0xbc)
    FIELD(SHA_IER, SLVERR, 1, 1)
    FIELD(SHA_IER, DONE, 0, 1)
REG32(SHA_IDR, 0xc0)
    FIELD(SHA_IDR, SLVERR, 1, 1)
    FIELD(SHA_IDR, DONE, 0, 1)
REG32(SHA_CHAIN, 0xc8)
    FIELD(SHA_CHAIN, STEPS, 16, 8)
    FIELD(SHA_CHAIN, START, 0, 8)
REG32(SHA_VERSION, 0xf8)
    FIELD(SHA_VERSION, VALUE, 0, 32)

#define ASU_SHA2_R_MAX (R_SHA_VERSION + 1)

typedef struct ASU_SHA2 {
    SysBusDevice parent_obj;
    MemoryRegion iomem;
    qemu_irq irq_sha_imr;

    uint32_t state;

    uint32_t regs[ASU_SHA2_R_MAX];
    RegisterInfo regs_info[ASU_SHA2_R_MAX];

    /* Hash algorithm latched when start was asserted.  */
    enum ASU_SHA_MODE alg;
    uint8_t chain_buf[ASU_SHA2_MAX_CHAIN_BUF_LEN];
    uint32_t cbuf_offset;
    uint32_t version;

    union {
        struct sha256_ctx sha256;
        struct sha384_ctx sha384;
        struct sha512_ctx sha512;
    } hash_contexts;
} ASU_SHA2;

static void asu_sha2_log_guest_error(ASU_SHA2 *s,
                                     const char *fn,
                                     const char *msg)
{
    char *path = object_get_canonical_path(OBJECT(s));

    qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: %s", path, fn, msg);
    g_free(path);
}

static void asu_sha2_start_postw(RegisterInfo *reg, uint64_t value)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(reg->opaque);

    if (s->state == ASU_SHA2_RESETING) {
        /* Don't do anything while reset.  */
        return;
    }

    if (!ARRAY_FIELD_EX32(s->regs, SHA_START, VALUE)) {
        /* Writing zero to that field doesn't have any effect.  */
        return;
    }

    /* Start bit is self clearing.  */
    ARRAY_FIELD_DP32(s->regs, SHA_START, VALUE, false);

    /*
     * Drop the SHA_DONE bit, driver will need to wait for this one to be set
     * before reading the digest.
     */
    ARRAY_FIELD_DP32(s->regs, SHA_DONE, VALUE, false);

    s->alg = ARRAY_FIELD_EX32(s->regs, SHA_MODE, VALUE);

    switch (s->alg) {
    case SHA_MODE_256_LMS_OTS:
    case SHA_MODE_256_SLH_DSA:
        if (s->regs[R_SHA_VERSION] < ASU_SHA2_V2_1) {
            asu_sha2_log_guest_error(s, __func__, "LMS_OTS/SLH_DSA"
                                                  " not supported");
            return;
        }
        /*
         * Fall through
         */
    case SHA_MODE_256:
        sha256_init(&s->hash_contexts.sha256);
        break;
    case SHA_MODE_384:
        sha384_init(&s->hash_contexts.sha384);
        break;
    case SHA_MODE_512:
        sha512_init(&s->hash_contexts.sha512);
        break;
    default:
        /*
         * Unsupported bit-field, throw a guest error, and don't put the model
         * in RUNNING mode (it won't accept data from the DMA).
         */
        asu_sha2_log_guest_error(s, __func__, "wrong SHA_MODE value\n");
        return;
    }

    /* All is ok.  Indicate the streaming device we can accept data.  */
    s->state = ASU_SHA2_RUNNING;
}

static void asu_sha2_reset(DeviceState *dev)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(dev);
    unsigned int i;

    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
        register_reset(&s->regs_info[i]);
    }
    s->regs[R_SHA_VERSION] = s->version;
}

static void asu_sha2_reset_postw(RegisterInfo *reg, uint64_t value)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(reg->opaque);

    if (ARRAY_FIELD_EX32(s->regs, SHA_RESET, VALUE)) {
        /* Puts the device in reset mode.  */
        s->state = ASU_SHA2_RESETING;
    } else if (s->state == ASU_SHA2_RESETING) {
        /* 1 -> 0 release from reset mode.  */
        asu_sha2_reset(DEVICE(s));
        s->state = ASU_SHA2_IDLE;
    }
}

static void sha_imr_update_irq(ASU_SHA2 *s)
{
    bool pending = s->regs[R_SHA_ISR] & ~s->regs[R_SHA_IMR];
    qemu_set_irq(s->irq_sha_imr, pending);
}

static void sha_isr_postw(RegisterInfo *reg, uint64_t val64)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(reg->opaque);
    sha_imr_update_irq(s);
}

static uint64_t sha_ier_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(reg->opaque);
    uint32_t val = val64;

    s->regs[R_SHA_IMR] &= ~val;
    sha_imr_update_irq(s);
    return 0;
}

static uint64_t sha_idr_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(reg->opaque);
    uint32_t val = val64;

    s->regs[R_SHA_IMR] |= val;
    sha_imr_update_irq(s);
    return 0;
}

static const RegisterAccessInfo asu_sha2_regs_info[] = {
    {   .name = "SHA_START",  .addr = A_SHA_START,
        .post_write = asu_sha2_start_postw,
    },{ .name = "SHA_RESET",  .addr = A_SHA_RESET,
        .reset = 0x1,
        .post_write = asu_sha2_reset_postw,
    },{ .name = "SHA_DONE",  .addr = A_SHA_DONE,
        .ro = 0x1,
    },{ .name = "SHA_DIGEST_0",  .addr = A_SHA_DIGEST_0,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_1",  .addr = A_SHA_DIGEST_1,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_2",  .addr = A_SHA_DIGEST_2,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_3",  .addr = A_SHA_DIGEST_3,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_4",  .addr = A_SHA_DIGEST_4,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_5",  .addr = A_SHA_DIGEST_5,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_6",  .addr = A_SHA_DIGEST_6,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_7",  .addr = A_SHA_DIGEST_7,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_8",  .addr = A_SHA_DIGEST_8,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_9",  .addr = A_SHA_DIGEST_9,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_10",  .addr = A_SHA_DIGEST_10,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_11",  .addr = A_SHA_DIGEST_11,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_12",  .addr = A_SHA_DIGEST_12,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_13",  .addr = A_SHA_DIGEST_13,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_14",  .addr = A_SHA_DIGEST_14,
        .ro = 0xffffffff,
    },{ .name = "SHA_DIGEST_15",  .addr = A_SHA_DIGEST_15,
        .ro = 0xffffffff,
    },{ .name = "SHA_MODE",  .addr = A_SHA_MODE,
    },{ .name = "SHA_AUTO_PADDING",  .addr = A_SHA_AUTO_PADDING,
    },{ .name = "SHA_SLV_ERR_CTRL",  .addr = A_SHA_SLV_ERR_CTRL,
    },{ .name = "SHA_ISR",  .addr = A_SHA_ISR,
        .w1c = 0x3,
        .post_write = sha_isr_postw,
    },{ .name = "SHA_IMR",  .addr = A_SHA_IMR,
        .reset = 0x3,
        .ro = 0x3,
    },{ .name = "SHA_IER",  .addr = A_SHA_IER,
        .pre_write = sha_ier_prew,
    },{ .name = "SHA_IDR",  .addr = A_SHA_IDR,
        .pre_write = sha_idr_prew,
    },{ .name = "SHA_CHAIN",  .addr = A_SHA_CHAIN,
    },{ .name = "SHA_VERSION",  .addr = A_SHA_VERSION,
        .ro = 0xffffffff,
    }
};

static const MemoryRegionOps asu_sha2_ops = {
    .read = register_read_memory,
    .write = register_write_memory,
    .endianness = DEVICE_LITTLE_ENDIAN,
    .valid = {
        .min_access_size = 4,
        .max_access_size = 4,
    },
};

static void asu_sha2_v2_1_init(Object *obj)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(obj);

    s->version = ASU_SHA2_V2_1;
}

static void asu_sha2_init(Object *obj)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(obj);
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    RegisterInfoArray *reg_array;

    memory_region_init(&s->iomem, obj, TYPE_XILINX_ASU_SHA2,
                       ASU_SHA2_R_MAX * 4);
    reg_array =
        register_init_block32(DEVICE(obj), asu_sha2_regs_info,
                              ARRAY_SIZE(asu_sha2_regs_info),
                              s->regs_info, s->regs,
                              &asu_sha2_ops,
                              XILINX_ASU_SHA2_ERR_DEBUG,
                              ASU_SHA2_R_MAX * 4);
    memory_region_add_subregion(&s->iomem,
                                0x0,
                                &reg_array->mem);
    sysbus_init_mmio(sbd, &s->iomem);
    sysbus_init_irq(sbd, &s->irq_sha_imr);
}

static bool asu_sha2_stream_can_push(StreamSink *obj,
                                     StreamCanPushNotifyFn notify,
                                     void *notify_opaque)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(obj);

    return s->state == ASU_SHA2_RUNNING;
}

static size_t asu_sha2_digest_size(ASU_SHA2 *s)
{
    switch (s->alg) {
    case SHA_MODE_256_LMS_OTS:
    case SHA_MODE_256_SLH_DSA:
    case SHA_MODE_256:
        return 256 / 8;
    case SHA_MODE_384:
        return 384 / 8;
    case SHA_MODE_512:
        return 512 / 8;
    default:
        return 0;
    }
}

static void asu_sha2_digest_chaining(ASU_SHA2 *s, size_t digest_len,
                                     uint8_t *digest)
{
    int j;
    uint8_t chain_start = ARRAY_FIELD_EX32(s->regs, SHA_CHAIN, START);
    uint8_t num_steps = ARRAY_FIELD_EX32(s->regs, SHA_CHAIN, STEPS);
    size_t len = 0;
    /*
     * Calculate digest for iteration 0.
     */
    sha256_digest(&s->hash_contexts.sha256, digest_len,
                  digest);
    /*
     * LMS_DSA:
     *     Replace Chain address every time
     *     in the payload and append previous hash.
     */
    for (j = chain_start + 1; j < chain_start + num_steps; j++) {
        switch (s->alg) {
        case SHA_MODE_256_LMS_OTS:
            s->chain_buf[0x16] = j;
            len = 23;
            break;
        case SHA_MODE_256_SLH_DSA:
            *(uint32_t *)&s->chain_buf[ASU_SHA2_SLH_DSA_HASH_ADDR] =
                cpu_to_be32(j);
            len = 64;
            break;
        default:
            g_assert_not_reached();
        }
        sha256_update(&s->hash_contexts.sha256, len, s->chain_buf);
        sha256_update(&s->hash_contexts.sha256, digest_len,
                      digest);
        sha256_digest(&s->hash_contexts.sha256, digest_len,
                      digest);
    }
    s->cbuf_offset = 0;
    memset(s->chain_buf, 0, ASU_SHA2_MAX_CHAIN_BUF_LEN);
}

static void asu_sha2_update_digest(ASU_SHA2 *s)
{
    uint32_t digest[ASU_SHA2_MAX_DIGEST_LEN >> 2] = {0};
    size_t digest_len = asu_sha2_digest_size(s);

    if (ARRAY_FIELD_EX32(s->regs, SHA_AUTO_PADDING, ENABLE)) {
        switch (s->alg) {
        case SHA_MODE_256_SLH_DSA:
        case SHA_MODE_256_LMS_OTS:
            asu_sha2_digest_chaining(s, digest_len,
                                     (uint8_t *)&digest);
            break;
        case SHA_MODE_256:
            sha256_digest(&s->hash_contexts.sha256, digest_len,
                          (uint8_t *)&digest);
            break;
        case SHA_MODE_384:
            sha384_digest(&s->hash_contexts.sha384, digest_len,
                          (uint8_t *)&digest);
            break;
        case SHA_MODE_512:
            sha512_digest(&s->hash_contexts.sha512, digest_len,
                          (uint8_t *)&digest);
            break;
        default:
            break;
        }
    } else {
        switch (s->alg) {
        case SHA_MODE_256_SLH_DSA:
        case SHA_MODE_256_LMS_OTS:
            qemu_log_mask(LOG_GUEST_ERROR, "LMS_OTS & SLH_DSA should have "
                                           "autopadding enabled!");
            break;
        case SHA_MODE_256:
            sha256_digest_no_pad(&s->hash_contexts.sha256, digest_len,
                                 (uint8_t *)&digest);
            break;
        case SHA_MODE_384:
            sha384_digest_no_pad(&s->hash_contexts.sha384, digest_len,
                                 (uint8_t *)&digest);
            break;
        case SHA_MODE_512:
            sha512_digest_no_pad(&s->hash_contexts.sha512, digest_len,
                                 (uint8_t *)&digest);
            break;
        default:
            break;
        }
    }

    memcpy(&s->regs[R_SHA_DIGEST_0], digest, digest_len);
}

static void asu_sha2_chaining_buf_copy(ASU_SHA2 *s,
                                       uint8_t *buf,
                                       size_t len)
{
    uint32_t copy_max = s->alg == SHA_MODE_256_LMS_OTS ? 23 : 64;
    uint32_t copy_len;

    if (s->cbuf_offset < copy_max) {
        copy_len = s->cbuf_offset + len <= copy_max ? len :
                                    copy_max - s->cbuf_offset;
        memcpy(s->chain_buf + s->cbuf_offset, buf, copy_len);
        s->cbuf_offset += copy_len;
        if (s->cbuf_offset == copy_max) {
            if (s->alg == SHA_MODE_256_LMS_OTS) {
                s->chain_buf[0x16] = ARRAY_FIELD_EX32(s->regs, SHA_CHAIN,
                                                      START);
            } else if (s->alg == SHA_MODE_256_SLH_DSA) {
                *(uint32_t *)&s->chain_buf[ASU_SHA2_SLH_DSA_HASH_ADDR] =
                    cpu_to_be32(ARRAY_FIELD_EX32(s->regs, SHA_CHAIN,
                                                 START));
            } else {
                g_assert_not_reached();
            }
            sha256_update(&s->hash_contexts.sha256, copy_max,
                          s->chain_buf);
            sha256_update(&s->hash_contexts.sha256, len - copy_len,
                          buf + copy_len);
        }
    } else {
        sha256_update(&s->hash_contexts.sha256, len, buf);
    }
}

/*
 * Callback from the DMA, consume the data..  Store them in data[] block
 * and pass them through the hash algorithm if a block boundary is crossed.
 */
static size_t asu_sha2_stream_push(StreamSink *obj,
                                   uint8_t *buf,
                                   size_t len,
                                   bool eop)
{
    ASU_SHA2 *s = XILINX_ASU_SHA2(obj);

    /* Is the crypto block ready to accept data?  */
    if (s->state != ASU_SHA2_RUNNING) {
        hw_error("%s: crypto block in bad state %d\n",
                 object_get_canonical_path(OBJECT(s)), s->state);
        return 0;
    }

    switch (s->alg) {
    case SHA_MODE_256_LMS_OTS:
        /*
         * Copy the first 23 bytes of the data for chaining reference.
         *  0x00 - 0x10 : I (16 bytes)
         *  0x10 - 0x14 : q (4 bytes)
         *  0x14 - 0x16 : i (2 bytes)
         *  0x16 - 0x17 : j (1 byte, this field is updated during chaining)
         *
         *  Fallthrough
         */
    case SHA_MODE_256_SLH_DSA:
        /*
         * Copy the PK.seed (16 bytes) + ADRS (32 bytes)
         *  0x00 - 0x20: PK.seed
         *  0x20 - 0x40: ADRS
         *     0x20 - 0x24: Layer addr
         *     0x24 - 0x30: Tree addr
         *     0x30 - 0x34: Type
         *     0x34 - 0x38: Key addr
         *     0x38 - 0x3c: Chain addr
         *     0x3c - 0x40: Hash addr (this field is updated during chaining)
         */
        asu_sha2_chaining_buf_copy(s, buf, len);
        break;
    case SHA_MODE_256:
        sha256_update(&s->hash_contexts.sha256, len, buf);
        break;
    case SHA_MODE_384:
        sha384_update(&s->hash_contexts.sha384, len, buf);
        break;
    case SHA_MODE_512:
        sha512_update(&s->hash_contexts.sha512, len, buf);
        break;
    default:
        /* XXX: Shouldn't happen.  */
        asu_sha2_log_guest_error(s, __func__, "wrong SHA_MODE value\n");
        return len;
    }

    if (eop) {
        /* End of data, handle the padding and updat the digest.  */
        asu_sha2_update_digest(s);
        ARRAY_FIELD_DP32(s->regs, SHA_DONE, VALUE, true);
        ARRAY_FIELD_DP32(s->regs, SHA_ISR, DONE, true);
        sha_imr_update_irq(s);
    }

    return len;
}

static const VMStateDescription vmstate_asu_sha2 = {
    .name = TYPE_XILINX_ASU_SHA2,
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32_ARRAY(regs, ASU_SHA2, ASU_SHA2_R_MAX),
        VMSTATE_END_OF_LIST(),
    }
};

static void asu_sha2_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);

    dc->vmsd = &vmstate_asu_sha2;
    dc->reset = asu_sha2_reset;

    ssc->push = asu_sha2_stream_push;
    ssc->can_push = asu_sha2_stream_can_push;
}

static const TypeInfo asu_sha2_info = {
    .name          = TYPE_XILINX_ASU_SHA2,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(ASU_SHA2),
    .class_init    = asu_sha2_class_init,
    .instance_init = asu_sha2_init,
    .interfaces = (InterfaceInfo[]) {
        { TYPE_STREAM_SINK },
        { }
    }
};

static const TypeInfo asu_sha2_v2_1_info = {
    .name = TYPE_XILINX_ASU_SHA2_V2_1,
    .parent = TYPE_XILINX_ASU_SHA2,
    .instance_init = asu_sha2_v2_1_init,
};

static void asu_sha2_register_types(void)
{
    type_register_static(&asu_sha2_info);
    type_register_static(&asu_sha2_v2_1_info);
}

type_init(asu_sha2_register_types)
