/*
** HDL4SE: 软件Verilog综合仿真平台
** Copyright (C) 2021-2021, raoxianhong<raoxianhong@163.net>
** LCOM: 轻量级组件对象模型
** Copyright (C) 2021-2021, raoxianhong<raoxianhong@163.net>
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice,
**   this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice,
**   this list of conditions and the following disclaimer in the documentation
**   and/or other materials provided with the distribution.
** * The name of the author may be used to endorse or promote products
**   derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
** THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
* hdl4sesim.c
  修改记录：
    202105180851: rxh, initial version
	202105241905：rxh, 增加Detector接口
*/
#include "stdlib.h"
#include "stdio.h"
#include "object.h"
#include "bignumber.h"
#include "hdl4secell.h"

#define IMPLEMENT_GUID
#include "hdl4sesim.h"
#undef IMPLEMENT_GUID

#define MAXDEVICES  32
typedef struct _sHDL4SESim {
	OBJECT_HEADER
	INTERFACE_DECLARE(IHDL4SEUnit)
	HDL4SEUNIT_VARDECLARE
	INTERFACE_DECLARE(IHDL4SEDetector)
	HDL4SEDETECTOR_VARDECLARE
	INTERFACE_DECLARE(IHDL4SESimulator)
	HDL4SESIMULATOR_VARDECLARE

	IHDL4SEUnit** topmodule;
	int devicecount;
	int reset;
	IHDL4SEUnit** devices[MAXDEVICES];

}sHDL4SESim;

OBJECT_FUNCDECLARE(hdl4sesim, CLSID_HDL4SESIMULATOR);
HDL4SEUNIT_FUNCDECLARE(hdl4sesim, CLSID_HDL4SESIMULATOR, sHDL4SESim);
HDL4SEDETECTOR_FUNCDECLARE(hdl4sesim, CLSID_HDL4SESIMULATOR, sHDL4SESim);
HDL4SESIMULATOR_FUNCDECLARE(hdl4sesim, CLSID_HDL4SESIMULATOR, sHDL4SESim);

OBJECT_FUNCIMPL(hdl4sesim, sHDL4SESim, CLSID_HDL4SESIMULATOR);

QUERYINTERFACE_BEGIN(hdl4sesim, CLSID_HDL4SESIMULATOR)
QUERYINTERFACE_ITEM(IID_HDL4SEUNIT, IHDL4SEUnit, sHDL4SESim)
QUERYINTERFACE_ITEM(IID_HDL4SEDETECTOR, IHDL4SEDetector, sHDL4SESim)
QUERYINTERFACE_ITEM(IID_HDL4SESIMULATOR, IHDL4SESimulator, sHDL4SESim)
QUERYINTERFACE_END

static const char* hdl4sesimModuleInfo()
{
	return "1.0.0-20210522.1532 HDL4SE simulator";
}

static int hdl4sesimCreate(const PARAMITEM* pParams, int paramcount, HOBJECT* pObject)
{
	sHDL4SESim* pobj;
	int i;
	pobj = (sHDL4SESim*)malloc(sizeof(sHDL4SESim));
	if (pobj == NULL)
		return -1;
	*pObject = 0;
	HDL4SEUNIT_VARINIT(pobj, CLSID_HDL4SESIMULATOR);
	INTERFACE_INIT(IHDL4SEUnit, pobj, hdl4sesim, hdl4se_unit);
	INTERFACE_INIT(IHDL4SEDetector, pobj, hdl4sesim, hdl4se_detector);
	INTERFACE_INIT(IHDL4SESimulator, pobj, hdl4sesim, hdl4se_simulator);

	for (i = 0; i < MAXDEVICES; i++) {
		pobj->devices[i] = NULL;
	}
	pobj->topmodule = 0;
	pobj->reset = 0;
	pobj->devicecount = 0;

	/* 返回生成的对象 */
	OBJECT_RETURN_GEN(hdl4sesim, pobj, pObject, CLSID_HDL4SESIMULATOR);
	return EIID_OK;
}

static void hdl4sesimDestroy(HOBJECT object)
{
	sHDL4SESim* pobj;
	int i;
	pobj = (sHDL4SESim*)objectThis(object);
	for (i = 0; i < MAXDEVICES; i++) {
		objectRelease(pobj->devices[i]);
	}
	objectRelease(pobj->topmodule);

	memset(pobj, 0, sizeof(sHDL4SESim));
	free(pobj);
}

static int hdl4sesimValid(HOBJECT object)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	return 1;
}

static int hdl4sesim_hdl4se_unit_Connect(HOBJECT object, int index, HOBJECT from, int fromindex)
{
	sHDL4SESim* pobj;
	IHDL4SEUnit** unit = NULL;
	pobj = (sHDL4SESim*)objectThis(object);
    /* 
	模拟器不需要记录外部连接，
	通过SetTopModule和AddDevice已经知道连接关系了 
	*/
	return 0;
}

static int hdl4sesim_hdl4se_unit_GetValue(HOBJECT object, int index, int width, IBigNumber** value)
{
	int i;
	int sel;
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	if (index == 0) { /* 0.nwReset */
		objectCall1(value, AssignInt32, pobj->reset);
	} 
	else if (index >= 1 && index <= 6) { /* 1..6 转发到topmodule*/
		objectCall3(pobj->topmodule, GetValue, index, width, value);
	}
	else if (index == 7) { /* 主模块读数据，此时由各个模块来响应 */
		int i;
		for (i = 0; i < pobj->devicecount; i++) {
			objectCall3(pobj->devices[i], GetValue, 7, width, value);
		}
	}
	return 0;
}

static int hdl4sesim_hdl4se_unit_ClkTick(HOBJECT object)
{
	sHDL4SESim* pobj;
	int i;
	pobj = (sHDL4SESim*)objectThis(object);
	objectCall0(pobj->topmodule, ClkTick);
	for (i = 0; i < pobj->devicecount; i++) {
		objectCall0(pobj->devices[i], ClkTick);
	}
	return 0;
}

static int hdl4sesim_hdl4se_unit_Setup(HOBJECT object)
{
	sHDL4SESim* pobj;
	int i;
	pobj = (sHDL4SESim*)objectThis(object);
	objectCall0(pobj->topmodule, Setup);
	for (i = 0; i < pobj->devicecount; i++) {
		objectCall0(pobj->devices[i], Setup);
	}
	return 0;
}

static int hdl4sesim_hdl4se_simulator_SetTopModule(HOBJECT object, IHDL4SEUnit * *topmodule)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	pobj->topmodule = topmodule;
	/*连接topmodule到sim模块，0.nwReset和7.bReadData*/
	objectCall3(topmodule, Connect, 0, object, 0);
	objectCall3(topmodule, Connect, 7, object, 7);
	return 0;
}

static int hdl4sesim_hdl4se_simulator_AddDevice(HOBJECT object, IHDL4SEUnit** device)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	if (pobj->devicecount >= MAXDEVICES)
		return -1;
	pobj->devices[pobj->devicecount] = device;
	pobj->devicecount++;
	objectCall3(device, Connect, 0, object, 0);
	objectCall3(device, Connect, 1, object, 1);
	objectCall3(device, Connect, 2, object, 2);
	objectCall3(device, Connect, 3, object, 3);
	objectCall3(device, Connect, 4, object, 4);
	objectCall3(device, Connect, 5, object, 5);
	objectCall3(device, Connect, 6, object, 6);
	return 0;
}

static int hdl4sesim_hdl4se_simulator_SetReset(HOBJECT object, int reset)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	pobj->reset = reset;
	return 0;
}

static int hdl4sesim_hdl4se_simulator_RunClockTick(HOBJECT object)
{
	int i;
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	hdl4sesim_hdl4se_unit_ClkTick(object);
	hdl4sesim_hdl4se_unit_Setup(object);
	return 0;
}

static int hdl4sesim_hdl4se_detector_GetName(HOBJECT object, const char** pname)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	*pname = "simulator";
	return 0;
}

static int hdl4sesim_hdl4se_detector_GetSignalCount(HOBJECT object)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	return 1;
}

static int hdl4sesim_hdl4se_detector_GetSignalInfo(HOBJECT object, int index, const char** pname, int * width)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	*pname = "nwReset";
	*width = 1;
	return 0;
}

static int hdl4sesim_hdl4se_detector_GetSignalValue(HOBJECT object, int index, IBigNumber** value)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	objectCall1(value, AssignInt32, pobj->reset);
	objectCall2(value, SetWidth, 1, 1);
	return 0;
}

static int hdl4sesim_hdl4se_detector_GetUnitCount(HOBJECT object)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	return pobj->devicecount + 1;
}

static int hdl4sesim_hdl4se_detector_GetUnit(HOBJECT object, int index, HOBJECT* unit)
{
	sHDL4SESim* pobj;
	pobj = (sHDL4SESim*)objectThis(object);
	if (index < 0 || index > pobj->devicecount)
		return -1;
	if (index == 0)
		*unit = pobj->topmodule;
	else
		*unit = pobj->devices[index-1];
	return 0;
}


IHDL4SESimulator** hdl4sesimCreateSimulator()
{
	int ret;
	IHDL4SEUnit** sim;
	A_u_t_o_registor_hdl4sesim();
	ret = objectCreateEx(CLSID_HDL4SESIMULATOR, NULL, 0, IID_HDL4SESIMULATOR, (const void**)&sim);
	return sim;
}
