BUILD_DIR = ./build
TOPNAME   = NPC
SOC_TOPNAME = ysyxSoCFull
TEST ?= addi_jalr
BOOT_PC ?= 0x0
MAX_CYCLES ?= 256
SOC_MAX_CYCLES ?= 1000000
TRACE ?= 0
ALLOW_NO_TRAP ?= 0
SDB ?= 0
RAND_DELAY ?= 0
ELF ?=
REF_SO ?=
YSYXSOC_HOME ?= $(abspath ../ysyxSoC)
SOC_VERILOG ?= $(abspath $(YSYXSOC_HOME)/build/ysyxSoCFull.v)
SOC_VERILOG_DEFS ?=
VERILOG_DEFS ?=
MROM ?=
FLASH ?=
PERF_BENCH ?= microbench
PERF_SIZE ?= test
AM_HOME ?= $(abspath ../abstract-machine)
AM_KERNELS_HOME ?= $(abspath ../am-kernels)

VERILATOR = verilator
VERILATOR_FLAGS += -MMD --build -cc --sv \
				-O3 --x-assign fast --x-initial fast --noassert \
				--prefix Vdut

OBJ_DIR = $(BUILD_DIR)/obj_dir
BIN = $(BUILD_DIR)/$(TOPNAME)
SOC_BIN = $(BUILD_DIR)/$(SOC_TOPNAME)
REF_SO_BIN = $(BUILD_DIR)/mini-rv32-ref.so

$(shell mkdir -p $(BUILD_DIR))

ALL_VSRCS = $(shell find $(abspath ./vsrc) \( -name "*.v" -o -name "*.sv" \))
VSRCS = $(filter-out $(abspath ./vsrc/npc.sv),$(ALL_VSRCS))
CSRCS = $(filter-out $(abspath ./csrc/mini_ref.cpp) $(abspath ./csrc/soc_main.cpp),$(shell find $(abspath ./csrc) \( -name "*.c" -o -name "*.cc" -o -name "*.cpp" \)))
SOC_CSRCS = $(abspath ./csrc/soc_main.cpp)
SOC_VSRCS = $(SOC_VERILOG) \
            $(shell find $(abspath $(YSYXSOC_HOME)/perip) -name "*.v") \
            $(VSRCS)

CXXFLAGS += -std=c++17
LDFLAGS += -ldl

TRACE_ARG = $(if $(filter 1,$(TRACE)),--trace,)
PERF_ARG = $(if $(filter 1,$(PERF)),--perf,)
ALLOW_NO_TRAP_ARG = $(if $(filter 1,$(ALLOW_NO_TRAP)),--allow-no-trap,)
SDB_ARG = $(if $(filter 1,$(SDB)),--sdb,)
RAND_DELAY_ARG = $(if $(filter 1,$(RAND_DELAY)),--rand-delay,)
ELF_ARG = $(if $(ELF),--elf=$(ELF),)
REF_SO_ARG = $(if $(REF_SO),--diff=$(REF_SO),)
RUN_SEL = $(if $(IMG),--img=$(IMG),--test=$(TEST))
RUN_ARGS = $(RUN_SEL) --boot=$(BOOT_PC) --max-cycles=$(MAX_CYCLES) $(TRACE_ARG) $(PERF_ARG) $(ALLOW_NO_TRAP_ARG) $(SDB_ARG) $(RAND_DELAY_ARG) $(ELF_ARG) $(REF_SO_ARG)
SOC_RUN_ARGS = $(if $(MROM),--mrom=$(MROM),) $(if $(FLASH),--flash=$(FLASH),) --max-cycles=$(SOC_MAX_CYCLES) $(ALLOW_NO_TRAP_ARG) $(PERF_ARG)

clean:
	-rm -rf $(BUILD_DIR)

.PHONY: clean build run sim ref-so soc-build soc-run perf

$(SOC_VERILOG):
	$(MAKE) -C $(YSYXSOC_HOME) verilog

$(BIN): $(VSRCS) $(CSRCS)
	@rm -rf $(OBJ_DIR)
	$(VERILATOR) $(VERILATOR_FLAGS) \
		$(addprefix -D,$(VERILOG_DEFS)) \
		--top-module $(TOPNAME) $^ \
		$(addprefix -CFLAGS , $(CXXFLAGS)) \
		$(addprefix -LDFLAGS , $(LDFLAGS)) \
		--Mdir $(OBJ_DIR) --exe -o $(abspath $(BIN))

build: $(BIN)

$(SOC_BIN): $(SOC_VSRCS) $(SOC_CSRCS)
	@rm -rf $(OBJ_DIR)
	$(VERILATOR) $(VERILATOR_FLAGS) --timescale "1ns/1ns" --no-timing \
		$(addprefix -D,$(SOC_VERILOG_DEFS)) \
		--top-module $(SOC_TOPNAME) $^ \
		-I$(abspath $(YSYXSOC_HOME)/perip/uart16550/rtl) \
		-I$(abspath $(YSYXSOC_HOME)/perip/spi/rtl) \
		$(addprefix -CFLAGS , $(CXXFLAGS)) \
		$(addprefix -LDFLAGS , $(LDFLAGS)) \
		--Mdir $(OBJ_DIR) --exe -o $(abspath $(SOC_BIN))

soc-build: $(SOC_BIN)

$(REF_SO_BIN): $(abspath ./csrc/mini_ref.cpp)
	@mkdir -p $(BUILD_DIR)
	$(CXX) -std=c++17 -O2 -shared -fPIC -o $@ $<

ref-so: $(REF_SO_BIN)

run: $(BIN)
	@$(BIN) $(RUN_ARGS)

sim: run

soc-run: $(SOC_BIN)
	@$(SOC_BIN) $(SOC_RUN_ARGS)

perf:
	@$(MAKE) -C $(AM_KERNELS_HOME)/benchmarks/$(PERF_BENCH) \
		ARCH=riscv32-ysyxsoc mainargs=$(PERF_SIZE) run \
		AM_HOME=$(AM_HOME) NPC_HOME=$(CURDIR) \
		YSYXSOC_BOOT=flash NPC_MAX_CYCLES=$(SOC_MAX_CYCLES) NPC_ALLOW_NO_TRAP=$(ALLOW_NO_TRAP) \
		SOC_VERILOG_DEFS="NPC_FLASH_BOOT" PERF=1

-include ../Makefile
