#
# Copyright (c) 2012-2017 Andes Technology Corporation
# All rights reserved.
#

PROG	?= Demo

ifndef CROSS_COMPILE
	ifeq (riscv32,$(COMPILER))
		CROSS_COMPILE = riscv32-elf-
	endif
endif
ifndef CROSS_COMPILE
	ifeq (riscv64,$(COMPILER))
		CROSS_COMPILE = riscv64-elf-
	endif
endif
ifndef CROSS_COMPILE
$(error You have to specify 'COMPILER' to build ! Ex: make COMPILER=[riscv32|riscv64])
endif

CC	:= $(CROSS_COMPILE)gcc
OBJDUMP	:= $(CROSS_COMPILE)objdump
OBJCOPY := $(CROSS_COMPILE)objcopy
AR	:= $(CROSS_COMPILE)ar
AS	:= $(CROSS_COMPILE)as

ifeq ($(DEBUG),1)
	OPTIM   := -O0 -g3
else
	OPTIM   := -Os -g3
endif

# Mode: LOAD, BURN, XIP
MODE	?= LOAD

# Platform: AE250, AE350, AE450
PLAT	= AE250

# Demo: PLIC, WFI, ECC, SLAVEPORT, PRINTF
DEMO	= PRINTF

PLATNAME = $(shell echo $(PLAT) | tr A-Z a-z)
DEMONAME = $(shell echo $(DEMO) | tr A-Z a-z)

ifeq ($(MODE),XIP)
 ifeq ($(filter $(DEMO), ECC),$(DEMO))
  $(error DEMO "$(DEMO)" + MODE "$(MODE)" is not supported!)
 endif
endif

# Define the directories
ROOT			= ..
SRC_PATH		= ../src
BSP_SOURCE_DIR		= $(SRC_PATH)/bsp
DEMO_SOURCE_DIR		= $(SRC_PATH)/demo

# Define the source files we have

# BSP source files

STARTUP_SRCS = $(BSP_SOURCE_DIR)/start.S
ifeq ($(MODE), BURN)
	STARTUP_SRCS += $(BSP_SOURCE_DIR)/loader.c
endif

BSP_SRCS = \
	$(BSP_SOURCE_DIR)/trap.c \
	$(BSP_SOURCE_DIR)/$(PLATNAME)/$(PLATNAME).c \
	$(BSP_SOURCE_DIR)/$(PLATNAME)/interrupt.c \
	$(BSP_SOURCE_DIR)/$(PLATNAME)/uart.c

LIBC_SRCS = $(BSP_SOURCE_DIR)/lib/printf.c

# Demo source files
DEMO_SRCS = \
        $(DEMO_SOURCE_DIR)/main.c

ifeq ($(DEMO),PRINTF)
	LIBC_SRCS := $(filter-out $(BSP_SOURCE_DIR)/lib/printf.c,$(LIBC_SRCS))
endif


# compilation options

ifeq ($(MODE),XIP)
	LDSCRIPT = $(ROOT)/$(PLATNAME)-xip.ld
else
	LDSCRIPT = $(ROOT)/$(PLATNAME).ld
endif

INCLUDES = \
	-I$(BSP_SOURCE_DIR) \
	-I$(BSP_SOURCE_DIR)/$(PLATNAME) \
	-I$(BSP_SOURCE_DIR)/driver/include \
	-I$(DEMO_SOURCE_DIR)

# Define all object files.
SRCS = $(STARTUP_SRCS) $(BSP_SRCS) $(LIBC_SRCS) $(DEMO_SRCS)
OBJS = $(patsubst %.S,%.o,$(patsubst %.cpp,%.o,$(patsubst %.c,%.o,${SRCS})))

### Use crtbebin1.o and crtend1.o for global constructors

CRTBEGIN_OBJ:=$(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ:=$(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)

### Verbosity control. Use 'make V=1' to get verbose builds.

ifeq ($(V),1)
TRACE_CC  =
TRACE_C++ =
TRACE_LD  =
TRACE_AR  =
TRACE_AS  =
Q=
else
TRACE_CC  = @echo "  CC       " $<
TRACE_C++ = @echo "  C++      " $<
TRACE_LD  = @echo "  LD       " $@
TRACE_AR  = @echo "  AR       " $@
TRACE_AS  = @echo "  AS       " $<
Q=@
endif

# Common compilation options

CFLAGS = \
	-Wall $(OPTIM) $(INCLUDES) $(DEFINES) \
	-fomit-frame-pointer -fno-strict-aliasing -fno-builtin -funroll-loops \
	-ffunction-sections -fdata-sections \
	-DCFG_MAKEFILE -DCFG_$(MODE)

ASFLAGS = -D__ASSEMBLY__ $(CFLAGS) -c

LDFLAGS = -T$(LDSCRIPT) $(OPTIM) -static -nostartfiles -Wl,--gc-sections

ifneq ($(MODE),LOAD)
	LDFLAGS += -mcmodel=medany
	CFLAGS += -mcmodel=medany
endif

GCCVER 	= $(shell $(GCC) --version | grep gcc | cut -d" " -f9)

# Add `-fno-delete-null-pointer-checks` flag if the compiler supports it.
# GCC assumes that programs cannot safely dereference null pointers,
# and that no code or data element resides there.
# However, 0x0 is the vector table memory location, so the test must not be removed.
ifeq ($(shell $(CC) -fno-delete-null-pointer-checks -E - 2>/dev/null >/dev/null </dev/null ; echo $$?),0)
	CFLAGS += -fno-delete-null-pointer-checks
	LDFLAGS += -fno-delete-null-pointer-checks
endif

### Make variables

ifdef SIMU
	CFLAGS += -DCFG_SIMU
endif


# Compilation rules
.SUFFIXES : %.o %.c %.cpp %.S

%.o: %.c
	$(TRACE_CC)
	$(Q)$(CC) -c -MMD $(CFLAGS) -o $@ $<

%.o: %.S
	$(TRACE_CC)
	$(Q)$(CC) -c -MMD $(ASFLAGS) -o $@ $<

all: $(PROG).elf

$(PROG).elf  : $(OBJS) Makefile 
	$(TRACE_LD)
	$(Q)$(CC) -o $@ $(LDFLAGS) $(OBJS)
	$(OBJCOPY) -O binary -S $(PROG).elf $(PROG).bin
	$(OBJDUMP) -d $(PROG).elf > $(PROG).asm
	@echo Completed

clean :
	@rm -f $(OBJS) $(OBJS:.o=.d)
	@rm -f $(PROG).elf 
	@rm -f $(PROG).bin
	@rm -f $(PROG).asm

# Automatic dependency generation
ifneq ($(MAKECMDGOALS),clean)
-include $(OBJS:.o=.d)
endif
