# Logging control
LOG_REDIR = >&
TIME=/usr/bin/time --format "Elapsed: %E, Memory: %M KB [Swaps %W]"

# Enable ccache for Verilator compilation
export OBJCACHE = ccache
export CXX = clang++
export CC = clang
export OPT_FAST = -O1
export OPT_SLOW = -O0

# Makefile variables
# Use as many threads as possible while keeping 2 for IO, browsing, etc.
# USE_PROCS = $(( $(shell nproc --all) - 2 ))
KEEP_PROCS=2
TOTAL_PROCS=$(shell nproc --all)
USE_PROCS=$(shell expr $(TOTAL_PROCS) - $(KEEP_PROCS))
PROJ_BASE=$(shell pwd)

# Verilator setup
# VERILATOR_HOME=$(HOME)/git/verilator
VERILATOR_HOME=/usr/share/verilator

# UVM setup
UVM_HOME=$(HOME)/git/uvm-verilator
# UVM_HOME=$(HOME)/git/ca_uvm-verilator
# UVM_HOME=$(HOME)/git/1800.2-2017-1.0

# Make and run project
PROJ=axi

SV_OUT=obj_dir/Vuvm_pkg__verFiles.dat
SV_BUILD_LOG=logs/$(PROJ)_build_sv.log

CPP_OUT=$(PROJ).sim
CPP_BUILD_LOG=logs/$(PROJ)_build_cpp.log

SIM_LOG=$(PROJ)_sim.log

SV_FILES=$(shell ls common/*.sv src/axi/*.sv tb/*.sv)
SV_SRC=$(UVM_HOME)/src/uvm_pkg.sv common/common_pkg.sv src/axi/axi_types.sv src/axi/axi_pkg.sv tb/tb_pkg.sv
DPI_SRC=$(UVM_HOME)/src/dpi/uvm_dpi.cc
DPI_INC=-I$(VERILATOR_HOME)/include
SV_DEPS=$(SV_FILES)

CPP_SRC=sim_$(PROJ).cpp

TIMESCALE= --timescale '1ns/1ns'

ifndef VERI_TRACE_DIS
TB_DEFINES=+define+VERI_TRACE_EN
endif
UVM_DEFINES=+define+UVM_NO_DPI \
            +define+UVM_REPORT_DISABLE_FILE_LINE
DISABLED_WARNINGS=-Wno-WIDTHTRUNC  -Wno-WIDTHEXPAND \
                  -Wno-CASTCONST   -Wno-CONSTRAINTIGN \
                  -Wno-MISINDENT   -Wno-REALCVT \
                  -Wno-SYMRSVDWORD -Wno-CASEINCOMPLETE

BUILD_ARGS=-I$(UVM_HOME)/src -I. \
        -o $(PROJ).sim \
        -j $(USE_PROCS) \
        --error-limit 10 \
        --timing $(TIMESCALE) \
        --trace \
        --x-initial 0 \
        --top tb_top \
        +define+SVA_ON \
        $(TB_DEFINES) \
        $(UVM_DEFINES) \
        $(DISABLED_WARNINGS) \
        +incdir+common +incdir+src/axi +incdir+tb \
        $(SV_SRC)

ifndef TEST_NAME
    TEST_NAME=test_basic
endif

#
# Full build to generate testbench executable (Default target)
#
build: build_cpp
	@echo "Build done"

prepare_area:
	$(info #----------------)
	$(info # Preparing area)
	$(info #----------------)
	@if [ ! -d $(PROJ_BASE)/logs ]; then mkdir -p $(PROJ_BASE)/logs; fi

#
# C code generation from SystemVerilog (optional translation/lint)
#
build_sv: prepare_area $(SV_OUT)

$(PROJ_BASE)/logs:
	@if [ ! -d $(PROJ_BASE)/logs ]; then mkdir -p $(PROJ_BASE)/logs; fi

$(SV_OUT): $(PROJ_BASE)/logs $(SV_DEPS)
	$(info #------------------------)
	$(info # Building SV ($(USE_PROCS) threads))
	$(info #------------------------)
	@$(VERILATOR_HOME)/bin/verilator --cc $(BUILD_ARGS)

#
# C code build to generate testbench executable
#
build_cpp: prepare_area $(CPP_OUT)

$(CPP_OUT): $(SV_DEPS)
	$(info #-------------------------)
	$(info # Building CPP ($(USE_PROCS) threads))
	$(info #-------------------------)
	@$(VERILATOR_HOME)/bin/verilator --binary $(BUILD_ARGS)

#
# Run just lint to detect syntax errors during development
#
lint:
	$(info #--------)
	$(info # Linting)
	$(info #--------)
	@$(VERILATOR_HOME)/bin/verilator --lint-only $(BUILD_ARGS)

#
# Run test. Use TEST_NAME=<test name> on make line to pick the test
#
#run: $(CPP_OUT)
run:
	$(info #---------------------)
	$(info # Running $(TEST_NAME))
	$(info #---------------------)
	@if [ ! -d runs/$(TEST_NAME) ]; then mkdir -p runs/$(TEST_NAME); fi
	cd runs/$(TEST_NAME) && \
        $(PROJ_BASE)/obj_dir/$(PROJ).sim +verilator+seed+2 \
            +UVM_TESTNAME=$(TEST_NAME) \
            +UVM_VERBOSITY=UVM_MEDIUM \
            +uvm_set_verbosity=uvm_test_top.*,_ALL_,UVM_MEDIUM,run \
            +UVM_CONFIG_DB_TRACE |& tee $(SIM_LOG)
	notify-send "[$(PROJ)] Test run done"

build_and_run: $(CPP_OUT) run
	$(info Build and Run done)

info:
	$(info #----------------------)
	$(info # Procs: $(TOTAL_PROCS))
	$(info # Keep: $(KEEP_PROCS))
	$(info # Threads: $(USE_PROCS))
	$(info #----------------------)
#
# Remove generated files
# - This will not remove 'runs' directory that contains simulation run logs
#
clean:
	rm -rf obj_dir logs $(PROJ)*.log
