/******************************************************************************
* Copyright (C) 2020 - 2022 Xilinx, Inc.  All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/


/*****************************************************************************/
/**
* @file xaie_sim.c
* @{
*
* This file contains the data structures and routines for low level IO
* operations for simulation backend.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who     Date     Changes
* ----- ------  -------- -----------------------------------------------------
* 1.0   Tejus   06/09/2020 Initial creation.
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifdef __AIESIM__ /* AIE simulator */

#include "main_rts.h"

#endif

#include "xaie_helper.h"
#include "xaie_io.h"
#include "xaie_io_common.h"
#include "xaie_npi.h"

#include "btree4.h"

static AieRC XAie_SimMemFree(XAie_MemInst *MemInst);

#include "btree4.h"

static AieRC XAie_SimMemFree(XAie_MemInst *MemInst);

/****************************** Type Definitions *****************************/
struct XAie_DevMem {
	ssize_t Size;
	struct XAie_DevMem *Next;
	struct XAie_DevMem *Prev;
	uint8_t Free : 1;
	XAie_MemInst MemInst;
};

typedef struct {
	u64 BaseAddr;
	u64 NpiBaseAddr;
	XAie_DevInst *DevInst;
	const XAie_CoreMod *OrigCoreMod;
	XAie_CoreMod CoreModOverride;
	struct XAie_DevMem DevMem;
	struct btree4 btree;
} XAie_SimIO;

/************************** Function Definitions *****************************/
#ifdef __AIESIM__

static int XAie_SimIO_MemInst_Compare(void *a, void *b)
{
	XAie_MemInst *MemA = (XAie_MemInst *)a;
	XAie_MemInst *MemB = (XAie_MemInst *)b;
	uint64_t VAddrA = (uint64_t)MemA->VAddr;
	uint64_t VAddrB = (uint64_t)MemB->VAddr;
	uint64_t VAddrBEnd = VAddrB + MemB->Size;

	if (VAddrA < VAddrB) {
		return -1;
	} else if (VAddrA >= VAddrBEnd) {
		return 1;
	}
	return 0;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to free the global IO instance
*
* @param	IOInst: IO Instance pointer.
*
* @return	None.
*
* @note		The global IO instance is a singleton and freed when
* the reference count reaches a zero. Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_Finish(void *IOInst)
{
	XAie_SimIO *SimIOInst = (XAie_SimIO *)IOInst;
	struct XAie_DevMem *Pos;

	SimIOInst->DevInst->DevProp.DevMod[XAIEGBL_TILE_TYPE_AIETILE].CoreMod = SimIOInst->OrigCoreMod;
	Pos = &SimIOInst->DevMem;
	while (Pos) {
		if (!Pos->Free) {
			XAIE_ERROR("Freeing SimIO while MemInst not freed!\n");
			return XAIE_OK;
		}
		Pos = Pos->Next;
	}
	free(IOInst);
	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to initialize the global IO instance
*
* @param	DevInst: Device instance pointer.
*
* @return	XAIE_OK on success. Error code on failure.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_Init(XAie_DevInst *DevInst)
{
	XAie_SimIO *IOInst;
	struct XAie_DevMem *Head;

	IOInst = (XAie_SimIO *)calloc(1, sizeof(*IOInst));
	if(IOInst == NULL) {
		XAIE_ERROR("Memory allocation failed\n");
		return XAIE_ERR;
	}

	IOInst->BaseAddr = DevInst->BaseAddr;
	IOInst->NpiBaseAddr = XAIE_NPI_BASEADDR;
	IOInst->OrigCoreMod = DevInst->DevProp.DevMod[XAIEGBL_TILE_TYPE_AIETILE].CoreMod;
	IOInst->CoreModOverride = *IOInst->OrigCoreMod;
	BTREE4_INIT(&IOInst->btree, XAie_SimIO_MemInst_Compare);
	DevInst->DevProp.DevMod[XAIEGBL_TILE_TYPE_AIETILE].CoreMod = &IOInst->CoreModOverride;
	IOInst->DevInst = DevInst;
	DevInst->IOInst = IOInst;

	Head = &IOInst->DevMem;
	Head->Free = 1;
	/* 3GB MEM SIZE
	 * 0xfffffffc appears to be max
	 */
	Head->Size = 0xc0000000;
	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to write 32bit data to the specified address.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: Register offset to read from.
* @param	Data: 32-bit data to be written.
*
* @return	None.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_Write32(void *IOInst, u64 RegOff, u32 Value)
{
	XAie_SimIO *SimIOInst = (XAie_SimIO *)IOInst;

	ess_Write32(SimIOInst->BaseAddr + RegOff, Value);

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to read 32bit data from the specified address.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: Register offset to read from.
* @param	Data: Pointer to store the 32 bit value
*
* @return	XAIE_OK on success.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_Read32(void *IOInst, u64 RegOff, u32 *Data)
{
	XAie_SimIO *SimIOInst = (XAie_SimIO *)IOInst;

	*Data = ess_Read32(SimIOInst->BaseAddr + RegOff);

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to write masked 32bit data to the specified
* address.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: Register offset to read from.
* @param	Mask: Mask to be applied to Data.
* @param	Value: 32-bit data to be written.
*
* @return	None.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_MaskWrite32(void *IOInst, u64 RegOff, u32 Mask,
		u32 Value)
{
	u32 RegVal;

	XAie_SimIO_Read32(IOInst, RegOff, &RegVal);

	RegVal &= ~Mask;
	RegVal |= Value;

	XAie_SimIO_Write32(IOInst, RegOff, RegVal);

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to mask poll an address for a value.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: Register offset to read from.
* @param	Mask: Mask to be applied to Data.
* @param	Value: 32-bit value to poll for
* @param	TimeOutUs: Timeout in micro seconds.
*
* @return	XAIE_OK or XAIE_ERR.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_MaskPoll(void *IOInst, u64 RegOff, u32 Mask, u32 Value,
		u32 TimeOutUs)
{
	AieRC Ret = XAIE_ERR;
	u32 RegVal;

	/* Increment Timeout value to 1 if user passed value is 1 */
	if(TimeOutUs == 0U)
		TimeOutUs++;

	while(TimeOutUs > 0U) {
		XAie_SimIO_Read32(IOInst, RegOff, &RegVal);
		if((RegVal & Mask) == Value) {
			Ret = XAIE_OK;
			break;
		}
		usleep(1);
		TimeOutUs--;
	}

	return Ret;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to write a block of data to aie.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: Register offset to read from.
* @param	Data: Pointer to the data buffer.
* @param	Size: Number of 32-bit words.
*
* @return	None.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_BlockWrite32(void *IOInst, u64 RegOff, const u32 *Data,
		u32 Size)
{
	for(u32 i = 0U; i < Size; i++) {
		XAie_SimIO_Write32(IOInst, RegOff + i * 4U, *Data);
		Data++;
	}

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to initialize a chunk of aie address space with
* a specified value.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: Register offset to read from.
* @param	Data: Data to initialize a chunk of aie address space..
* @param	Size: Number of 32-bit words.
*
* @return	None.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_BlockSet32(void *IOInst, u64 RegOff, u32 Data, u32 Size)
{
	for(u32 i = 0U; i < Size; i++)
		XAie_SimIO_Write32(IOInst, RegOff+ i * 4U, Data);

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to initialize a chunk of aie address space with
* a specified value.
*
* @param	IOInst: IO instance pointer
* @param	Col: Column number
* @param	Row: Row number
* @param	Command: Command to write
* @param	CmdWd0: Command word 0
* @param	CmdWd1: Command word 1
* @param	CmdStr: Command string
*
* @return	None.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_CmdWrite(void *IOInst, u8 Col, u8 Row, u8 Command,
		u32 CmdWd0, u32 CmdWd1, const char *CmdStr)
{
	ess_WriteCmd(Command, Col, Row, CmdWd0, CmdWd1, CmdStr);

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the function to write 32 bit value to NPI register address.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: NPI register offset
* @param	RegVal: Value to write to register
*
* @return	None.
*
* @note		Internal only.
*
*******************************************************************************/
static void _XAie_SimIO_NpiWrite32(void *IOInst, u32 RegOff, u32 RegVal)
{
	XAie_SimIO *SimIOInst = (XAie_SimIO *)IOInst;
	u64 RegAddr;

	RegAddr = SimIOInst->NpiBaseAddr + RegOff;
	ess_Write32(RegAddr, RegVal);
	return;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to read 32bit data from the specified NPI
* address.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: Register offset to read from.
* @param	Data: Pointer to store the 32 bit value
*
* @return	XAIE_OK on success.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC XAie_SimIO_NpiRead32(void *IOInst, u64 RegOff, u32 *Data)
{
	(void)IOInst;
	(void)RegOff;
	*Data = 0U;

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory IO function to mask poll a NPI address for a value.
*
* @param	IOInst: IO instance pointer
* @param	RegOff: Register offset to read from.
* @param	Mask: Mask to be applied to Data.
* @param	Value: 32-bit value to poll for
* @param	TimeOutUs: Timeout in micro seconds.
*
* @return	XAIE_OK or XAIE_ERR.
*
* @note		Internal only.
*
*******************************************************************************/
static AieRC _XAie_SimIO_NpiMaskPoll(void *IOInst, u64 RegOff, u32 Mask,
		u32 Value, u32 TimeOutUs)
{
	AieRC Ret = XAIE_ERR;
	u32 RegVal;


	/* Increment Timeout value to 1 if user passed value is 1 */
	if(TimeOutUs == 0U)
		TimeOutUs++;

	while(TimeOutUs > 0U) {
		XAie_SimIO_NpiRead32(IOInst, RegOff, &RegVal);
		if((RegVal & Mask) == Value) {
			Ret = XAIE_OK;
			break;
		}
		usleep(1);
		TimeOutUs--;
	}

	return Ret;
}

static AieRC XAie_SimIO_RunOp(void *IOInst, XAie_DevInst *DevInst,
		XAie_BackendOpCode Op, void *Arg)
{
	(void)DevInst;
	switch(Op) {
	case XAIE_BACKEND_OP_NPIWR32:
	{
		XAie_BackendNpiWrReq *Req = Arg;

		_XAie_SimIO_NpiWrite32(IOInst, Req->NpiRegOff,
				Req->Val);
		break;
	}
	case XAIE_BACKEND_OP_NPIMASKPOLL32:
	{
		XAie_BackendNpiMaskPollReq *Req = Arg;

		return _XAie_SimIO_NpiMaskPoll(IOInst, Req->NpiRegOff,
				Req->Mask, Req->Val, Req->TimeOutUs);
	}
	case XAIE_BACKEND_OP_CONFIG_SHIMDMABD:
	{
		XAie_ShimDmaBdArgs *BdArgs =
			(XAie_ShimDmaBdArgs *)Arg;

		XAie_SimIO_BlockWrite32(IOInst, BdArgs->Addr,
			BdArgs->BdWords, BdArgs->NumBdWords);
		break;
	}
	case XAIE_BACKEND_OP_REQUEST_TILES:
		return _XAie_PrivilegeRequestTiles(DevInst,
				(XAie_BackendTilesArray *)Arg);
	case XAIE_BACKEND_OP_PARTITION_INITIALIZE:
		return _XAie_PrivilegeInitPart(DevInst,
				(XAie_PartInitOpts *)Arg);
	case XAIE_BACKEND_OP_PARTITION_TEARDOWN:
		return _XAie_PrivilegeTeardownPart(DevInst);
	case XAIE_BACKEND_OP_UPDATE_NPI_ADDR:
	{
		XAie_SimIO *SimIOInst = (XAie_SimIO *)IOInst;
		SimIOInst->NpiBaseAddr = *((u64 *)Arg);
		break;
	}
	case XAIE_BACKEND_OP_SET_COLUMN_CLOCK:
		return _XAie_PrivilegeSetColumnClk(DevInst,
				(XAie_BackendColumnReq *)Arg);
	default:
		XAIE_ERROR("Simulation backend doesn't support operation %d\n",
				Op);
		return XAIE_FEATURE_NOT_SUPPORTED;
	}

	return XAIE_OK;
}

static u64 XAie_SimIOGetTid(void)
{
		return (u64)pthread_self();
}

static XAie_MemInst* XAie_SimMemAllocate(XAie_DevInst *DevInst, u64 Size,
		XAie_MemCacheProp Cache)
{
	XAie_SimIO *IOInst = DevInst->IOInst;
	struct XAie_DevMem *Head = &IOInst->DevMem;
	struct XAie_DevMem *Pos;
	u64 Align = Size % 4;
	int Ret;

	if (Align) {
		Size = Size + (4 - Align);
	}

	Pos = Head;
	while (Pos) {
		if (Pos->Free && Pos->Size > Size) {
			struct XAie_DevMem *Node = calloc(1, sizeof(*Node));
			struct XAie_DevMem *Next = Pos->Next;
			XAie_MemInst *MemInst;

			if (!Node)
				return NULL;
			MemInst = &Node->MemInst;
			MemInst->VAddr = malloc(Size);
			if (!MemInst->VAddr) {
				free(Node);
				return NULL;
			}
			MemInst->Size = Size;
			Pos->Size -= Size;
			MemInst->DevAddr = Pos->MemInst.DevAddr + Pos->Size;
			MemInst->Cache = Cache;
			MemInst->DevInst = DevInst;
			Node->Size = Size;
			Node->Prev = Pos;
			Node->Next = Next;
			Pos->Next = Node;
			if (Next) {
				Next->Prev = Node;
			}
			Ret = btree4_insert(&IOInst->btree, MemInst);
			if (Ret) {
				XAie_SimMemFree(MemInst);
				return NULL;
			}
			return MemInst;
		} else if (Pos->Free && Pos->Size == Size) {
			XAie_MemInst *MemInst = &Pos->MemInst;

			Pos->Free = 0;
			MemInst->VAddr = malloc(Size);
			if (!MemInst->VAddr) {
				Pos->Free = 1;
				return NULL;
			}
			MemInst->Size = Size;
			MemInst->Cache = Cache;
			MemInst->DevInst = DevInst;
			if (Ret) {
				XAie_SimMemFree(MemInst);
				return NULL;
			}
			return MemInst;
		}
		Pos = Pos->Next;
	}
	return NULL;
}

ssize_t XAie_SimDevmemFreeSize(XAie_DevInst *DevInst)
{
	XAie_SimIO *IOInst = DevInst->IOInst;
	struct XAie_DevMem *DevMem = &IOInst->DevMem;
	struct XAie_DevMem *Pos;
	ssize_t Free = 0;

	Pos = DevMem;

	while (Pos) {
		if (Pos->Free)
			Free += Pos->Size;
		Pos = Pos->Next;
	}

	return Free;
}

ssize_t XAie_SimDevmemUsedSize(XAie_DevInst *DevInst)
{
	XAie_SimIO *IOInst = DevInst->IOInst;
	struct XAie_DevMem *DevMem = &IOInst->DevMem;
	struct XAie_DevMem *Pos;
	ssize_t use = 0;

	Pos = DevMem;

	while (Pos) {
		if (!Pos->Free)
			use += Pos->Size;
		Pos = Pos->Next;
	}

	return use;

}

void XAie_SimDumpDevMem(XAie_DevInst *DevInst)
{
	XAie_SimIO *IOInst = DevInst->IOInst;
	struct XAie_DevMem *DevMem = &IOInst->DevMem;
	struct XAie_DevMem *Pos;
	ssize_t Free = 0, use = 0;
	int i = 0;

	Pos = DevMem;

	while (Pos) {
		if (Pos->Free)
			Free += Pos->Size;
		else
			use += Pos->Size;
		XAIE_DBG("[%d]: free: %d size: 0x%llx\n", i, Pos->Free, Pos->Size);
		Pos = Pos->Next;
		i++;
	}
	XAIE_DBG("Total Free: 0x%llx, total use: 0x%llx\n", Free, use);
	return;
}

static AieRC XAie_SimMemFree(XAie_MemInst *MemInst)
{
	struct XAie_DevMem *Node, *Next, *Prev;
	XAie_SimIO *IOInst;

	if (!MemInst)
		return XAIE_OK;
	Node = container_of(MemInst, struct XAie_DevMem, MemInst);
	Next = Node->Next;
	Prev = Node->Prev;

	IOInst = (XAie_SimIO *)MemInst->DevInst->IOInst;
	btree4_delete(&IOInst->btree, MemInst);
	Node->Free = 1;
	free(Node->MemInst.VAddr);
	Node->MemInst.VAddr = NULL;
	if (Next && Next->Free) {
		Node->Size += Next->Size;
		Node->Next = Next->Next;
		if (Next->Next)
			Next->Next->Prev = Node;
		free(Next);
		Next = Node->Next;
	}
	if (Prev && Prev->Free) {
		Prev->Size += Node->Size;
		Prev->Next = Next;
		if (Next) {
			Next->Prev = Prev;
		}
		free(Node);
	}
	return XAIE_OK;
}

static AieRC XAie_SimMemFreeVAddr(XAie_DevInst *DevInst, void *VAddr)
{
	XAie_SimIO *IOInst = (XAie_SimIO *)DevInst->IOInst;
	XAie_MemInst MemInst;
	XAie_MemInst *Node;

	MemInst.VAddr = VAddr;
	MemInst.Size = 0;

	Node = btree4_search(&IOInst->btree, &MemInst);
	return XAie_MemFree(Node);
}

AieRC XAie_SimMemSyncForCPUVAddr(XAie_DevInst *DevInst, void *VAddr,
					uint64_t Size)
{
	XAie_SimIO *IOInst = (XAie_SimIO *)DevInst->IOInst;
	XAie_MemInst MemInst;
	XAie_MemInst *Node;
	uint64_t VAddrStart = (uint64_t)VAddr;
	uint64_t VAddrEnd = VAddrStart + Size;
	uint64_t NodeStart, NodeEnd;
	uint64_t Offset;
	uint32_t *pa;
	uint32_t *va = (uint32_t *)VAddr;
	uint64_t i;

	if (Size % 4) {
		return XAIE_INVALID_RANGE;
	}
	MemInst.VAddr = VAddr;
	MemInst.Size = Size;

	Node = btree4_search(&IOInst->btree, &MemInst);
	if (!Node) {
		XAIE_ERROR("Requested Address not found\n");
		return XAIE_INVALID_ADDRESS;
	}
	NodeStart = (uint64_t)Node->VAddr;
	NodeEnd = NodeStart + Node->Size;
	if (!((VAddrStart >= NodeStart) &&
		(VAddrEnd <= NodeEnd)))
		return XAIE_INVALID_RANGE;
	Offset = VAddrStart - NodeStart;
	pa = (uint32_t *)(Node->DevAddr + Offset);
	for (i = 0; i < (Size >> 2); i++) {
		va[i] = ess_Read32(&pa[i]);
	}

	return 0;
}

static AieRC XAie_SimMemSyncForCPU(XAie_MemInst *MemInst)
{
	uint32_t *va = MemInst->VAddr;
	uint32_t *pa = MemInst->DevAddr;
	int i;

	for (i = 0; i < MemInst->Size >> 2; i++) {
		va[i] = ess_Read32(&pa[i]);
	}

	return XAIE_OK;
}

AieRC XAie_SimMemSyncForDevVAddr(XAie_DevInst *DevInst, void *VAddr,
					uint64_t Size)
{
	XAie_SimIO *IOInst = (XAie_SimIO *)DevInst->IOInst;
	XAie_MemInst MemInst;
	XAie_MemInst *Node;
	uint64_t VAddrStart = (uint64_t)VAddr;
	uint64_t VAddrEnd = VAddrStart + Size;
	uint64_t NodeStart, NodeEnd;
	uint64_t Offset;
	uint32_t *pa;
	uint32_t *va = (uint32_t *)VAddr;
	uint64_t i;

	if (Size % 4) {
		return XAIE_INVALID_RANGE;
	}

	MemInst.VAddr = VAddr;
	MemInst.Size = Size;

	Node = btree4_search(&IOInst->btree, &MemInst);
	if (!Node) {
		XAIE_ERROR("Requested Address not found\n");
		return XAIE_INVALID_ADDRESS;
	}
	NodeStart = (uint64_t)Node->VAddr;
	NodeEnd = NodeStart + Node->Size;
	if (!((VAddrStart >= NodeStart) &&
		(VAddrEnd <= NodeEnd)))
		return XAIE_INVALID_RANGE;
	Offset = VAddrStart - NodeStart;
	pa = (uint32_t *)(Node->DevAddr + Offset);
	for (i = 0; i < (Size >> 2); i++) {
		ess_Write32(&pa[i], va[i]);
	}

	return 0;
}


static AieRC XAie_SimMemSyncForDev(XAie_MemInst *MemInst)
{
	uint32_t *pa = MemInst->DevAddr;
	uint32_t *va = MemInst->VAddr;
	int i;

	for (i = 0; i < MemInst->Size >> 2; i++) {
		ess_Write32(&pa[i], va[i]);
	}

	return XAIE_OK;
}

static AieRC XAie_SimMemGetDevAddrFromVAddr(XAie_DevInst *DevInst, void *VAddr,
				   uint64_t *DevAddr)
{
	XAie_SimIO *IOInst = (XAie_SimIO *)DevInst->IOInst;
	XAie_MemInst MemInst;
	XAie_MemInst *Node;
	uint64_t VAddrStart = (uint64_t)VAddr;
	uint64_t NodeStart;
	uint64_t Offset;

	*DevAddr = 0;
	MemInst.VAddr = VAddr;
	MemInst.Size = 0;

	Node = btree4_search(&IOInst->btree, &MemInst);
	if (!Node) {
//		XAIE_ERROR("Requested Address not found\n");
		return XAIE_INVALID_ADDRESS;
	}
	NodeStart = (uint64_t)Node->VAddr;
	Offset = VAddrStart - NodeStart;
	*DevAddr = (Node->DevAddr + Offset);
	return XAIE_OK;
}

#else

static AieRC XAie_SimIO_Finish(void *IOInst)
{
	/* no-op */
	(void)IOInst;
	return XAIE_OK;
}

static AieRC XAie_SimIO_Init(XAie_DevInst *DevInst)
{
	/* no-op */
	(void)DevInst;
	XAIE_ERROR("Driver is not compiled with simulation backend "
			"(__AIESIM__)\n");
	return XAIE_INVALID_BACKEND;
}

static AieRC XAie_SimIO_Write32(void *IOInst, u64 RegOff, u32 Value)
{
	/* no-op */
	(void)IOInst;
	(void)RegOff;
	(void)Value;

	return XAIE_ERR;
}

static AieRC XAie_SimIO_Read32(void *IOInst, u64 RegOff, u32 *Data)
{
	/* no-op */
	(void)IOInst;
	(void)RegOff;
	(void)Data;
	return 0;
}

static AieRC XAie_SimIO_MaskWrite32(void *IOInst, u64 RegOff, u32 Mask,
		u32 Value)
{
	/* no-op */
	(void)IOInst;
	(void)RegOff;
	(void)Mask;
	(void)Value;

	return XAIE_ERR;
}

static AieRC XAie_SimIO_MaskPoll(void *IOInst, u64 RegOff, u32 Mask, u32 Value,
		u32 TimeOutUs)
{
	/* no-op */
	(void)IOInst;
	(void)RegOff;
	(void)Mask;
	(void)Value;
	(void)TimeOutUs;
	return XAIE_ERR;
}

static AieRC XAie_SimIO_BlockWrite32(void *IOInst, u64 RegOff, const u32 *Data,
		u32 Size)
{
	/* no-op */
	(void)IOInst;
	(void)RegOff;
	(void)Data;
	(void)Size;

	return XAIE_ERR;
}

static AieRC XAie_SimIO_BlockSet32(void *IOInst, u64 RegOff, u32 Data, u32 Size)
{
	/* no-op */
	(void)IOInst;
	(void)RegOff;
	(void)Data;
	(void)Size;

	return XAIE_ERR;
}

static AieRC XAie_SimIO_CmdWrite(void *IOInst, u8 Col, u8 Row, u8 Command,
		u32 CmdWd0, u32 CmdWd1, const char *CmdStr)
{
	/* no-op */
	(void)IOInst;
	(void)Col;
	(void)Row;
	(void)Command;
	(void)CmdWd0;
	(void)CmdWd1;
	(void)CmdStr;

	return XAIE_ERR;
}

static AieRC XAie_SimIO_RunOp(void *IOInst, XAie_DevInst *DevInst,
		XAie_BackendOpCode Op, void *Arg)
{
	(void)IOInst;
	(void)DevInst;
	(void)Op;
	(void)Arg;
	return XAIE_FEATURE_NOT_SUPPORTED;
}

static u64 XAie_SimIOGetTid(void)
{
		return 0;
}

static XAie_MemInst* XAie_SimMemAllocate(XAie_DevInst *DevInst, u64 Size,
		XAie_MemCacheProp Cache)
{
	(void)DevInst;
	(void)Size;
	(void)Cache;
	return NULL;
}

ssize_t XAie_SimDevmemFreeSize(XAie_DevInst *DevInst)
{
	(void)DevInst;
	return 0;
}

ssize_t XAie_SimDevmemUsedSize(XAie_DevInst *DevInst)
{
	(void)DevInst;
	return 0;
}

void XAie_SimDumpDevMem(XAie_DevInst *DevInst)
{
	(void)DevInst;
}

static AieRC XAie_SimMemFree(XAie_MemInst *MemInst)
{
	(void)MemInst;
	return XAIE_ERR;
}

static AieRC XAie_SimMemFreeVAddr(XAie_DevInst *DevInst, void *VAddr)
{
	(void)DevInst;
	(void)VAddr;
	return XAIE_ERR;
}

static AieRC XAie_SimMemSyncForCPU(XAie_MemInst *MemInst)
{
	(void)MemInst;
	return XAIE_ERR;
}

static AieRC XAie_SimMemSyncForCPUVAddr(XAie_DevInst *DevInst, void *VAddr,
					uint64_t size)
{
	(void)DevInst;
	(void)VAddr;
	(void)size;
	return XAIE_ERR;
}

static AieRC XAie_SimMemSyncForDev(XAie_MemInst *MemInst)
{
	(void)MemInst;
	return XAIE_ERR;
}

static AieRC XAie_SimMemSyncForDevVAddr(XAie_DevInst *DevInst, void *VAddr,
					uint64_t size)
{
	(void)DevInst;
	(void)VAddr;
	(void)size;
	return XAIE_ERR;
}

static AieRC XAie_SimMemGetDevAddrFromVAddr(XAie_DevInst *DevInst, void *VAddr,
				   uint64_t *DevAddr)
{
	(void)DevInst;
	(void)VAddr;
	(void)DevAddr;
	return XAIE_FEATURE_NOT_SUPPORTED;
}

#endif /* __AIESIM__ */


static AieRC XAie_SimMemAttach(XAie_MemInst *MemInst, u64 MemHandle)
{
	(void)MemInst;
	(void)MemHandle;
	return XAIE_ERR;
}

static AieRC XAie_SimMemDetach(XAie_MemInst *MemInst)
{
	(void)MemInst;
	return XAIE_ERR;
}

static u64 XAie_SimIOGetAttr(void *IOInst, XAie_BackendAttrType Attr) {
	XAie_SimIO *SimIOInst = (XAie_SimIO *)IOInst;
	switch (Attr) {
		case XAIE_BACKEND_ATTR_CORE_PROG_MEM_SIZE:
			return SimIOInst->CoreModOverride.ProgMemSize;
		default:
			return 0L;
	}
}

AieRC XAie_SimIOSetAttr(void *IOInst, XAie_BackendAttrType Attr, u64 AttrVal) {
	XAie_SimIO *SimIOInst = (XAie_SimIO *)IOInst;
	switch (Attr) {
		case XAIE_BACKEND_ATTR_CORE_PROG_MEM_SIZE:
			SimIOInst->CoreModOverride.ProgMemSize = (u32) AttrVal;
			return XAIE_OK;
		default:
			return XAIE_ERR;
	}
}

const XAie_Backend SimBackend =
{
	.Type = XAIE_IO_BACKEND_SIM,
	.Ops.Init = XAie_SimIO_Init,
	.Ops.Finish = XAie_SimIO_Finish,
	.Ops.Write32 = XAie_SimIO_Write32,
	.Ops.Read32 = XAie_SimIO_Read32,
	.Ops.MaskWrite32 = XAie_SimIO_MaskWrite32,
	.Ops.MaskPoll = XAie_SimIO_MaskPoll,
	.Ops.BlockWrite32 = XAie_SimIO_BlockWrite32,
	.Ops.BlockSet32 = XAie_SimIO_BlockSet32,
	.Ops.CmdWrite = XAie_SimIO_CmdWrite,
	.Ops.RunOp = XAie_SimIO_RunOp,
	.Ops.MemAllocate = XAie_SimMemAllocate,
	.Ops.MemFree = XAie_SimMemFree,
	.Ops.MemFreeVAddr = XAie_SimMemFreeVAddr,
	.Ops.MemSyncForCPU = XAie_SimMemSyncForCPU,
	.Ops.MemSyncForCPUVAddr = XAie_SimMemSyncForCPUVAddr,
	.Ops.MemSyncForDev = XAie_SimMemSyncForDev,
	.Ops.MemSyncForDevVAddr = XAie_SimMemSyncForDevVAddr,
	.Ops.MemGetDevAddrFromVAddr = XAie_SimMemGetDevAddrFromVAddr,
	.Ops.MemAttach = XAie_SimMemAttach,
	.Ops.MemDetach = XAie_SimMemDetach,
	.Ops.GetTid = XAie_SimIOGetTid,
	.Ops.GetPartFd = XAie_IODummyGetPartFd,
	.Ops.SubmitTxn = NULL,
	.Ops.GetAttr = XAie_SimIOGetAttr,
	.Ops.SetAttr = XAie_SimIOSetAttr,
	.Ops.AddressPatching = NULL,
	.Ops.ConfigMode = NULL,
	.Ops.WaitUcDMA = NULL,
	.Ops.GetConfigMode = NULL,
	.Ops.SetPadInteger = NULL,
	.Ops.SetPadString = NULL,
};

/** @} */
