#***************************************************************************************
# Copyright (c) 2025 Institute of Computing Technology, Chinese Academy of Sciences
# Copyright (c) 2024-2025 Beijing Institute of Open Source Chip (BOSC)
#
# DiffTest is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#          http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#***************************************************************************************

GSIM_BIN ?= gsim
GSIM_CXX = clang++  # only support clang++14 or above

GSIM_EMU_BUILD_DIR = $(abspath $(BUILD_DIR)/gsim-compile)
GSIM_EMU_TARGET = $(abspath $(GSIM_EMU_BUILD_DIR)/emu)

##############################################
### Running GSIM to generate cpp model
##############################################

GSIM_GEN_CSRC_DIR = $(GSIM_EMU_BUILD_DIR)/model
GSIM_FLAGS = --supernode-max-size=15 --cpp-max-size-KB=8192 --sep-mod=__DOT__ --sep-aggr=__DOT__

$(GSIM_GEN_CSRC_DIR)/$(SIM_TOP)0.cpp: $(RTL_DIR)/$(SIM_TOP).fir
	@mkdir -p $(@D)
	$(GSIM_BIN) $(GSIM_FLAGS) --dir $(@D) $< | tee $(GSIM_EMU_BUILD_DIR)/gsim-gen-cpp.log

gsim-gen-cpp: $(GSIM_GEN_CSRC_DIR)/$(SIM_TOP)0.cpp

##############################################
### Building EMU from cpp model generated by GSIM
##############################################

GSIM_OTHER_CSRC_DIR = $(abspath ./src/test/csrc/gsim)
GSIM_CXXFILES = $(EMU_CXXFILES) $(shell find $(GSIM_OTHER_CSRC_DIR) -name "*.cpp")
# We need to replace extra '\' as this is native in Makefile for GSIM
GSIM_CXXFLAGS = $(subst \\\",\", $(EMU_CXXFLAGS))
GSIM_CXXFLAGS += -I$(GSIM_OTHER_CSRC_DIR) -I$(GSIM_GEN_CSRC_DIR)/ -DGSIM
GSIM_CXXFLAGS += $(EMU_OPTIMIZE) -fbracket-depth=2048 -Wno-parentheses-equality $(PGO_CFLAGS)
GSIM_LDFLAGS =  $(SIM_LDFLAGS) -ldl $(PGO_LDFLAGS)

# $(1): object file
# $(2): source file
# $(3): compile flags
# $(4): object file list
# $(5): extra dependency
define GSIM_CXX_TEMPLATE =
$(1): $(2) $(THIS_MAKEFILE) $(5)
	@mkdir -p $$(@D) && echo + CXX $$<
	@$(GSIM_CXX) $$< $(3) -c -o $$@
$(4) += $(1)
endef

# $(1): object file
# $(2): source file
# $(3): ld flags
define GSIM_LD_TEMPLATE =
$(1): $(2)
	@mkdir -p $$(@D) && echo + LD $$@
	@$(GSIM_CXX) $$^ $(3) -o $$@
endef

$(foreach x, $(GSIM_CXXFILES), $(eval \
	$(call GSIM_CXX_TEMPLATE, $(GSIM_EMU_BUILD_DIR)/other/$(basename $(notdir $(x))).o, $(x), $(GSIM_CXXFLAGS), GSIM_EMU_OBJS,)))

$(foreach x, $(shell find $(GSIM_GEN_CSRC_DIR) -name "*.cpp" 2> /dev/null), $(eval \
	$(call GSIM_CXX_TEMPLATE, $(GSIM_EMU_BUILD_DIR)/model/$(basename $(notdir $(x))).o, $(x), $(GSIM_CXXFLAGS), GSIM_EMU_OBJS,)))

$(eval $(call GSIM_LD_TEMPLATE, $(GSIM_EMU_TARGET), $(GSIM_EMU_OBJS), $(GSIM_LDFLAGS)))

gsim-build-emu: $(GSIM_EMU_TARGET)

gsim-clean-obj:
	-@rm -f $(GSIM_EMU_OBJS) $(GSIM_EMU_TARGET)

# Profile Guided Optimization
gsim-gen-emu:
ifdef PGO_WORKLOAD
	$(MAKE) pgo-build \
		PGO_CLEAN_OBJ=gsim-clean-obj \
		PGO_BUILD_TARGET=gsim-build-emu \
		PGO_TARGET=$(GSIM_EMU_TARGET) \
		PGO_EMU_DIR=$(GSIM_EMU_BUILD_DIR)
else
	@echo "Building emu..."
	@$(MAKE) gsim-build-emu
endif # ifdef PGO_WORKLOAD

gsim-emu:
	$(MAKE) gsim-gen-cpp
	$(MAKE) gsim-gen-emu
