# Toolchain settings
CC = riscv-none-elf-gcc
CXX = riscv-none-elf-g++
OBJCOPY = riscv-none-elf-objcopy
OBJDUMP = riscv-none-elf-objdump
SIZE = riscv-none-elf-size
RM = rm -rf
MKDIR = mkdir -p
FIND = find

# MDR1206 or MDR32F02
MCU ?= MDR1206

# FLASH, RAM_TCM_debug, or RAM_TCM_release
CONFIG ?= FLASH


# Project structure
TARGET = $(PROJECT_NAME)
BUILD_DIR = build

CONFIG_CACHE_FILE = $(BUILD_DIR)/current_config.mk
CURRENT_CONFIG = $(MCU)_$(CONFIG)

ifneq (,$(filter clean,$(MAKECMDGOALS)))
    # Don nothing for clean
else
    ifneq ($(shell cat $(CONFIG_CACHE_FILE) 2>/dev/null),$(CURRENT_CONFIG))
        NEED_CLEAN = 1
    endif

    ifdef NEED_CLEAN
        $(info Configuration changed: $(CURRENT_CONFIG). Cleaning build directory...)
        $(shell $(RM) $(BUILD_DIR) 2>/dev/null)
    endif

    $(shell $(MKDIR) $(BUILD_DIR) 2>/dev/null)
    $(shell echo "$(CURRENT_CONFIG)" > $(CONFIG_CACHE_FILE))
endif

ifeq ($(MCU), MDR1206)
ARCH_FLAGS = -march=rv32imc_zicsr_zifencei_zicntr_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh
LDFLAGS = -L"Library/CMSIS/DeviceSupport/src/gcc/MDR1206"
else ifeq ($(MCU), MDR32F02)
ARCH_FLAGS = -march=rv32imc_zicsr_zifencei_zicntr
LDFLAGS = -L"Library/CMSIS/DeviceSupport/src/gcc/MDR32F02"
else
$(error Unknown MCU, should be MDR1206 or MDR32F02)
endif

ifeq ($(CONFIG), FLASH)
LDFLAGS += -T link_FLASH.ld
else ifeq ($(CONFIG), RAM_TCM_debug)
LDFLAGS += -T link_RAM_TCM_debug.ld
else ifeq ($(CONFIG), RAM_TCM_release)
LDFLAGS += -T link_RAM_TCM_release.ld
else
$(error Unknown CONFIG, should be FLASH, RAM_TCM_debug, or RAM_TCM_release)
endif

# Source files
PROGRAM_C_SRCS = src/main.c
LIBRARY_C_SRCS = $(shell $(FIND) Library -name "*.c" -type f)
LIBRARY_ASM_SRCS = $(shell $(FIND) Library -name "*.S" -type f) $(shell $(FIND) Library -name "*.s" -type f)

C_SRCS = $(PROGRAM_C_SRCS) $(LIBRARY_C_SRCS)
ASM_SRCS = $(LIBRARY_ASM_SRCS)

# Include paths
INC_DIRS = \
    Library/CMSIS/DeviceSupport \
    Library/CMSIS/DeviceSupport/inc \
    Library/CMSIS/CoreSupport/inc \
    Library/SPL/inc \
    Library/SPL

INC_FLAGS = $(addprefix -I, $(INC_DIRS))

# Compiler flags

COMMON_FLAGS = $(ARCH_FLAGS) -mabi=ilp32 $(INC_FLAGS) \
    -mcmodel=medany -msmall-data-limit=8 -mno-save-restore \
    -Og -fmessage-length=0 -fsigned-char \
    -ffunction-sections -fdata-sections -fno-move-loop-invariants -Wa,-adhlns="$@.lst" \
	-Wmissing-prototypes -Wstrict-prototypes -Wbad-function-cast

DEP_FLAGS = -MMD -MP -MF"$(BUILD_DIR)/$*.d" -MT"$@"

CFLAGS = $(COMMON_FLAGS) -std=gnu11 \
    -Wall -Wextra -Wunused -Wuninitialized -Wmissing-declarations -Wconversion -Wpointer-arith -Wshadow -Wlogical-op -Waggregate-return -Wfloat-equal \
    -g3 

# CFLAGS += -gdwarf-2

ASFLAGS = $(COMMON_FLAGS) -x assembler-with-cpp

LDFLAGS += $(COMMON_FLAGS) \
    -Xlinker --gc-sections  -Xlinker --enable-non-contiguous-regions -nostartfiles \
    -Wl,-Map="$(BUILD_DIR)/$(TARGET).map" --specs=nano.specs

# Object files
C_OBJS = $(addprefix $(BUILD_DIR)/, $(C_SRCS:.c=.o))
ASM_OBJS = $(patsubst %, $(BUILD_DIR)/%.o, $(basename $(ASM_SRCS)))
OBJS = $(C_OBJS) $(ASM_OBJS)
OBJ_DIRS = $(sort $(dir $(OBJS)))

DEP_FILES = $(C_OBJS:.o=.d)

# Build targets
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).lst
	@$(SIZE) --format=berkeley $(BUILD_DIR)/$(TARGET).elf

$(BUILD_DIR)/$(TARGET).elf: $(OBJS)
	@echo 'Linking: $@'
	@$(CXX) $(LDFLAGS) -o $@ $(OBJS)
	@echo 'Build complete'

$(BUILD_DIR)/$(TARGET).hex: $(BUILD_DIR)/$(TARGET).elf
	@$(OBJCOPY) -O ihex $< $@

$(BUILD_DIR)/$(TARGET).lst: $(BUILD_DIR)/$(TARGET).elf
	@$(OBJDUMP) --source --all-headers --demangle --debugging --disassemble --file-headers --line-numbers --reloc --syms --wide $< > $@

# Object directory creation
$(OBJ_DIRS):
	@$(MKDIR) $@

# Compilation rules
$(BUILD_DIR)/%.o: %.c | $(OBJ_DIRS)
	@echo 'Compiling: $<'
	@$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/%.o: %.S | $(OBJ_DIRS)
	@echo 'Assembling: $<'
	@$(CC) $(ASFLAGS) -c $< -o $@

$(BUILD_DIR)/%.o: %.s | $(OBJ_DIRS)
	@echo 'Assembling: $<'
	@$(CC) $(ASFLAGS) -c $< -o $@

-include $(DEP_FILES)

clean:
	@$(RM) $(BUILD_DIR)
	@echo 'Project cleaned'

.PHONY: all clean