// Copyright 2025 RnD Center "ELVEES", JSC

#ifndef ELCORE50_H
#define ELCORE50_H

typedef char int8;
typedef unsigned char uint8;
typedef short int16;
typedef unsigned short uint16;
typedef int int32;
typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
typedef short float16;
typedef float float32;
typedef double float64;

typedef union {
  int8 b[8];
  uint8 ub[8];
  int16 h[4];
  uint16 uh[4];
  int32 l[2];
  uint32 ul[2];
  int64 d;
  uint64 ud;
  float16 hf[4];
  float32 f[2];
  float64 df;
} REG;

#pragma pack(push, 1)

typedef struct {
  uint32 run : 1;
  uint32 done : 1;
  uint32 init_que : 1;
  uint32 init_imm : 1;
  uint32 init_rif : 1;
  uint32 irq : 1;
  uint32 irqm : 1;
  uint32 busy : 1;
  uint32 actv : 1;
  uint32 reserved : 23;
} VDMACSR;

typedef struct {
  uint32 dir : 1;  // 0 - ext->int, 1 - ext<-int
  uint32 prt : 2;
  uint32 cache_ai : 4;
  uint32 cache_ae : 4;
  uint32 size : 3;  // 2^size bytes
  uint32 task_id : 8;
  uint32 event_en : 1;
  uint32 reserved : 9;
} VDMACFG;

typedef struct {
  uint32 ae_l, ae_h;
  uint32 ai_l, ai_h;
  int32 offset_e, offset_i;
  uint16 acnt, bcnt;
  uint32 run, done, init, irq, irqm, irqt;
  VDMACFG cfg;
  VDMACSR csr;
  uint32 a_init_l, a_init_h;
  uint8 reserved[0x3c];
} VDMACHANNEL;

typedef struct {
  VDMACHANNEL ch[4];
  uint8 reserved[0x600];
  uint32 run, busy, actv, done, irq, rsvd, mode;
  uint32 task_id, task_data_l, task_data_h;
} VDMACONTROLLER;

typedef struct {
  uint32 ae_l, ae_h;
  uint32 ai_l, ai_h;
  int32 offset_e, offset_i;
  uint16 acnt, bcnt;
  VDMACFG cfg;
  uint32 a_init_l, a_init_h;
  VDMACSR csr;
  uint8 reserved[4];
} VDMAINIT;

typedef struct {
  uint32 ctrl;
  uint32 invctrl, invaddr;
  uint32 asid;
  uint32 cregions, mregions;
  uint32 blks;
  uint32 swait[2];
  uint32 vwait[2];
} MEMORYNBLOCKS;

typedef struct {
  uint32 events;
  uint32 emsk;
  uint32 csr;
  uint32 trace;
  uint32 tmsk;
} EVENTCONTROLLER;

#pragma pack(pop)

#if (MCom03 == 1)
#define E50BASER ((volatile uint8 *)0x2800000)
#define E50BASE ((uint8 *)0x2E00000)
#define DSP_BASE_ADDR 0x2E80000
#define DSP_XRAM_SIZE 0x80000
#define DSP_MAX_ADDR 0x2FFFFFF
#elif (Sim3x == 1 || Solaris == 1)
#define E50BASER ((volatile uint8 *)0x10200000)
#define E50BASE ((uint8 *)0x10000000)
#define DSP_BASE_ADDR 0x10080000
#define DSP_XRAM_SIZE 0x80000
#define DSP_MAX_ADDR 0x10ffffff
#endif

#define PCU12_OFFSET 0x800
#define InvCtrl ((volatile uint32 *)(E50BASER + PCU12_OFFSET + 0x4))

#define XYRAM E50BASE
#define XYRAM_SIZE 0x100000
#define PRAM (E50BASE + 0x100000)
#define PRAM_SIZE 0x8000

#define VDMACtrl ((volatile VDMACONTROLLER *)(E50BASER + 0x23000))
#define VDMACh0 ((volatile VDMACHANNEL *)(E50BASER + 0x23000))
#define VDMACh1 ((volatile VDMACHANNEL *)(E50BASER + 0x23080))
#define VDMACh2 ((volatile VDMACHANNEL *)(E50BASER + 0x23100))
#define VDMACh3 ((volatile VDMACHANNEL *)(E50BASER + 0x23180))

#define CACHE_L0_OFFSET 0x36200
#define CACHE_L1_OFFSET 0x34400
#define CACHE_L2_OFFSET 0x37000

#define L0DC ((volatile uint32 *)(E50BASER + CACHE_L0_OFFSET))
#define L1DC ((volatile uint32 *)(E50BASER + CACHE_L1_OFFSET))
#define L2DC ((volatile uint32 *)(E50BASER + CACHE_L2_OFFSET))

// workaround for #MCOM03SW-4148
#define CCHINV_WORKAROUND      \
  asm volatile("mbar 0xffaf"); \
  asm volatile("nop");         \
  asm volatile("nop");

#define FLUSH_ALL_CACHES()            \
  do {                                \
    CCHINV_WORKAROUND;                \
    asm volatile("cchinv 0xfffc, 0"); \
    asm volatile("nop");              \
    asm volatile("nop");              \
    asm volatile("mbar 0");           \
    asm volatile("nop");              \
    asm volatile("nop");              \
  } while (0)

/// Изменение значения L2DC для выключения L2-cache
void disable_l2_cache();
/// Изменение значения L2DC для включения L2-cache
void enable_l2_cache();

#define ticks_counter(ticks, instrs)          \
  asm volatile(                               \
      "tcr tic_cntr, r18     trl %0, r6\n   \
         tcr instr_cntr, r19   trl %1, r7\n   \
         stl r18, (r6)         stl r19, (r7)" \
      :                                       \
      : "r"(ticks), "r"(instrs))

#endif
