/* Copyright 2020 Canaan Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _GNNE_H_
#define _GNNE_H_

#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

    typedef enum _gnne_status
    {
        GNNE_STATUS_IDLE,
        GNNE_STATUS_RUNNING,
        GNNE_STATUS_PENDING,
        GNNE_STATUS_ERROR
    } gnne_status_t;

    typedef enum _gnne_reset_status
    {
        GNNE_RESET_STATUS_IDLE,
        GNNE_RESET_STATUS_BIU,
        GNNE_RESET_STATUS_ACT,
        GNNE_RESET_STATUS_HLD
    } gnne_reset_status_t;

    typedef enum
    {
        GNNE_CTRL_ENABLE_SET = (0x0001UL) << 32 | (0x0001),
        GNNE_CTRL_ENABLE_CLEAR = (0x0001UL) << 32 | (0x0000),
        GNNE_CTRL_DSP_RESUME_SET = (0x0040UL) << 32 | (0x0040),
        GNNE_CTRL_DSP_RESUME_CLEAR = (0x0040UL) << 32,
        GNNE_CTRL_CHANGE_PC_ADDR_SET = (0x0020UL) << 32 | (0x0020),
        GNNE_CTRL_CHANGE_PC_ADDR_CLEAR = (0x0020UL) << 32,
        GNNE_CTRL_CG_OFF_SET = (0x0010UL) << 32 | (0x0010),
        GNNE_CTRL_CG_OFF_CLEAR = (0x0010UL) << 32,
        GNNE_CTRL_WAIT_CPU_INTR_CLR_SET = (0x0004UL) << 32 | (0x0004),
        GNNE_CTRL_WAIT_CPU_INTR_CLR_CLEAR = (0x0004UL) << 32,
        GNNE_CTRL_WAIT_DSP_INTR_CLR_SET = (0x0002UL) << 32 | (0x0002),
        GNNE_CTRL_WAIT_DSP_INTR_CLR_CLEAR = (0x0002UL) << 32
    } gnne_ctrl_function_t;

    typedef union
    {
        struct
        {
            uint64_t gnne_enable : 1;
            uint64_t wait_dsp_intr_clr : 1;
            uint64_t wait_cpu_intr_clr : 1;
            uint64_t ctrl_reserved0 : 1;
            uint64_t gnne_cg_off : 1;
            uint64_t change_pc_addr : 1;
            uint64_t dsp_resume : 1;
            uint64_t ctrl_reserved1 : 25;
            uint64_t gnne_enable_wmask : 1;
            uint64_t wait_dsp_intr_clr_wmask : 1;
            uint64_t wait_cpu_intr_clr_wmask : 1;
            uint64_t enable_range_wmask : 1;
            uint64_t gnne_cg_off_wmask : 1;
            uint64_t change_pc_addr_mask : 1;
            uint64_t dsp_resume_mask : 1;
            uint64_t ctrl_reserved2 : 25;
        };
        uint64_t data;
    } gnne_ctrl;

    typedef union
    {
        struct
        {
            uint64_t component_status : 8;
            uint64_t status_reserved0 : 6;
            uint64_t status : 2;
            uint64_t status_reserved1 : 6;
            uint64_t exception : 2;
            uint64_t reset_status : 2;
            uint64_t status_reserved2 : 6;
            uint64_t intr_num : 32;
        };
        uint64_t data;
    } gnne_status;

    typedef struct
    {
        uint64_t ptrmask : 32;
        uint64_t regmask : 32;
    } gnne_dsp_intr_mask;

    typedef union
    {
        struct
        {
            uint64_t load_pc : 32;
            uint64_t store_pc : 32;
        };
        uint64_t data;
    } gnne_load_store_pc;

    typedef union
    {
        struct
        {
            uint64_t tcu_pc : 32;
            uint64_t mfu_pc : 32;
        };
        uint64_t data;
    } gnne_tcu_mfu_pc;

    typedef enum _gnne_component_status
    {
        GNNE_MFU_BUSY = 0b10000000,
        GNNE_TCU_BUSY = 0b01000000,
        GNNE_STORE_BUSY = 0b00100000,
        GNNE_LOAD_BUSY = 0b00010000
    } gnne_component_status_mask_t;

    typedef enum _gnne_exception
    {
        GNNE_EXCEPTION_OK,
        GNNE_EXCEPTION_ILLEGAL_INSTRUCTION,
        GNNE_EXCEPTION_CCR_ERROR
    } gnne_exception_t;

    typedef struct _gnne_reg_file
    {
        uint64_t gpr[32];
        uint64_t pc;
        uint64_t host_mem_base_addr[4];
        // ctrl reg
        gnne_ctrl ctrl;
        // status reg
        gnne_status status;
        gnne_dsp_intr_mask dsp_intr_mask;
        gnne_load_store_pc load_store_pc;
        gnne_tcu_mfu_pc tcu_mfu_pc;
    } gnne_reg_file_t;

    void flush_cache();
    void gnne_set_host_mem_base_addr(int idx, uint64_t addr);
    int gnne_enable(uint64_t pc);
    void gnne_init();
    void gnne_disable();
    void gnne_clear_cpu_intr();
    void gnne_clear_dsp_intr();
    gnne_status gnne_get_status();
    uint64_t gnne_get_pc();
    gnne_ctrl gnne_get_ctrl();
    gnne_load_store_pc gnne_get_load_store_pc();
    gnne_tcu_mfu_pc gnne_get_tcu_mfu_pc();

#ifdef __cplusplus
}
#endif

#endif
