// Copyright 2025 RnD Center "ELVEES", JSC

#ifndef ELCORE50_H
#define ELCORE50_H

#include <stdint.h>
#include <stdio.h>
#include <stdlib.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 defined(__Solaris__)
#define E50BASE ((volatile uint8 *)0x10000000)
#define E50BASER ((volatile uint8 *)0x10200000)
#elif defined(__MCom03__)
#define E50BASE ((volatile uint8 *)0x02e00000)
#define E50BASER ((volatile uint8 *)0x02800000)
#endif

#if defined(__Solaris__)
#define __local_mem ((volatile uint8 *)0x10000000)
#elif defined(__MCom03__)
#define __local_mem ((volatile uint8 *)0x2e80000)
#endif

#define XYRAM16B0 E50BASE
#define XYRAM16B1 (E50BASE + 0x40000)
#define XYRAM32B (E50BASE + 0x80000)
#define XYRAM XYRAM32B
#define XYRAM16B_SIZE ((int32)0x40000)
#define XYRAM32B_SIZE ((int32)0x80000)
#define XYRAM_SIZE XYRAM32B_SIZE
#define PRAM (E50BASE + 0x100000)
#define PRAM_SIZE ((int32)0x8000)

#define MemBlks ((volatile MEMORYNBLOCKS *)(E50BASER + 0x800))
#define EvCtrl ((volatile EVENTCONTROLLER *)(E50BASER + 0x22000))
#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))

#define TIC_CNTR ((volatile uint32_t *)(E50BASER + 0x280 + 0x10))
#define INSTR_CNTR ((volatile uint32_t *)(E50BASER + 0x280 + 0x18))
#define PCU12_OFFSET 0x800
#define InvCtrl ((volatile uint32_t *)(E50BASER + PCU12_OFFSET + 0x4))
#define Ctrl ((volatile uint32_t *)(E50BASER + PCU12_OFFSET + 0x0))
#define L1DC_ctrl ((volatile uint32_t *)(E50BASER + 0x34400))
#define L0DC_ctrl ((volatile uint32_t *)(E50BASER + 0x36200))
#define L2DC_ctrl ((volatile uint32_t *)(E50BASER + 0x37000))
#define L2_CACHE_SIZE ((*L2DC_ctrl) >> 19) & 3

void disable_l2_cache();
void enable_l2_cache(uint32_t size);

void change_L1DC_ctrl();
void flush_all_caches();
void count_tics(int *tic_addr, int *instr_addr);

#endif
