#!/usr/bin/make

PROJECT := f4VOICEC
MCUTYPE := stm32f4xx


MAKEFILE_INC = $(wildcard ./Makefile.inc)
ifneq ($(strip ${MAKEFILE_INC}), )
  include ${MAKEFILE_INC}
else
  MAKEFILE_INC = $(wildcard ../Makefile.inc)
  ifneq ($(strip ${MAKEFILE_INC}), )
    include ${MAKEFILE_INC}
  endif
endif


ifeq ($(MCU),F4)
	ON_SRAM := YES
endif
ADDDEFS = _CONFIG_USE_EXT_RTC_CLK_

ADDDEFS += TCXO_RTC_SPI=1  SysClockSource_HSE_EXT  ## external clock from ST-LINKs MCO
## ADDDEFS += TCXO_RTC_I2C=1  SysClockSource_HSE_Xtal  ## external crystal oscillator.


BASESRC = src
ONBUILD = build
SUBDIRS = $(MCUTYPE)
SUBDIRS += ELM_ChaN/xprintf
SUBDIRS += $(MCUTYPE)/TCXO_RTC
SUBDIRS += STmicro
SUBDIRS += STmicro/USB STmicro/USB/VCP
INCDIRS = $(patsubst %, $(BASESRC)/%, $(SUBDIRS)) $(BASESRC)

# EMBEDDED_DATADIR:=
EMBEDDED_DATADIR:= data


CSRCARM:=
ASRCARM:=
VPATH  :=


### Optimization level (0, 1, 2, 3, 4 or s)
OPTIMIZE = s

### C Standard level (c89, gnu89, c99 or gnu99)
CSTD = gnu89

### Processor type and use Thumb(-2) mode for CSRC/ASRC files (YES or NO)
THUMB = YES
BFD_ARCH    :=arm7tdmi
BFD_FORMAT  :=elf32-littlearm
ifeq ($(MCUTYPE),stm32f4xx)
  ARCH  = armc7e-m
  CPU   = cortex-m4
  HAVEFPU = YES
  ##FLOAT_ABI= hard
  FLOAT_ABI= softfp
  MCUDEFS = STM32F4XX
  ### MCUDEFS +=  HSE_VALUE=8000000UL
  MCUDEFS += HSE_VALUE=8000000UL
  MCUDEFS += SysClockPLL_USE
  MCUDEFS += DBGMCU_ENABLE DEBUG_ON_SLEEPING
else
  ifeq ($(MCUTYPE),stm32f0xx)
    ARCH  = armc6-m
    CPU   = cortex-m0
    HAVEFPU = NO
    MCUDEFS = STM32F0XX
    ##MCUDEFS += HSE_VALUE=8000000 SysClockSource_HSE_Xtal
    ##MCUDEFS += SysClockPLL_USE
    ##MCUDEFS += DUMMY_TRAP_HANDLERS
    MCUDEFS += DBGMCU_ENABLE DEBUG_ON_SLEEPING
  else
    ifeq ($(MCUTYPE),stm32f1xx)
      ARCH  = armc7-m
      CPU   = cortex-m3
      HAVEFPU = NO
      MCUDEFS = STM32F10X_MD STM32F1XX
      MCUDEFS += HSE_VALUE=8000000 SysClockSource_HSE_Xtal
      MCUDEFS += SysClockPLL_USE
      MCUDEFS += DBGMCU_ENABLE DEBUG_ON_SLEEPING
      ##MCUDEFS += DUMMY_TRAP_HANDLERS
    endif
  endif
endif

ifeq ($(HAVEFPU),YES)
  ifeq ($(FLOAT_ABI),hard)
    FLOAT_ABI= hard
  else
    FLOAT_ABI= softfp
  endif
else
  FLOAT_ABI= float
endif

### Output file format (ihex, binary or both) and debugger type
OUTPUT	= both
##OUTPUT	= ihex
##OUTPUT	= binary
DEBUG	= dwarf-2

### Linker script for the target MCU
ifeq ($(ON_SRAM),YES)
  ifeq ($(OUTPUT),ihex)
    LINKSCRIPT = ${MCUTYPE}_ram_at0x20000000.ld
  else
    LINKSCRIPT = ${MCUTYPE}_ram.ld
  endif
  DEFS = VECTOR_ON_SRAM
else
##  LINKSCRIPT = ${MCUTYPE}_at0x08000000.ld
  LINKSCRIPT = ${MCUTYPE}.ld
  DEFS =
endif

### Include dirs, library dirs and definitions
MATHLIB	= -lm
LIBS	=
LIBDIRS	= lib
DEFS	+= ${MCUDEFS} ${ADDDEFS}
ADEFS	=

### Warning contorls
WARNINGS = all extra

### Programs to build porject
ifeq ($(FLOAT_ABI),hard)
  PRFIX   = arm-hardfloat-eabi
else
  ifeq ($(TOOLCHAINS),hardfloat)
    TOOLCHAINS_TYPE=hardfloat
  else
    TOOLCHAINS_TYPE=none
  endif
  PRFIX   = arm-$(TOOLCHAINS_TYPE)-eabi
endif
CC      = ${PRFIX}-gcc
OBJCOPY = ${PRFIX}-objcopy
OBJDUMP = ${PRFIX}-objdump
SIZE    = ${PRFIX}-size
NM      = ${PRFIX}-nm
GDB     = ${PRFIX}-gdb


# Define all object files
MKDIRS  := $(ONBUILD) $(ONBUILD)/.dep $(patsubst %, $(ONBUILD)/%,$(SUBDIRS)) $(ONBUILD)/$(EMBEDDED_DATADIR)
DSRC    := $(wildcard $(EMBEDDED_DATADIR)/*.raw)
DOBJ    := $(patsubst %, $(ONBUILD)/%, $(DSRC:.raw=.o) )

CSRC    := $(subst $(BASESRC)/,,$(wildcard $(BASESRC)/*.c $(patsubst %, $(BASESRC)/%/*.c,$(SUBDIRS))))
ASRC    := $(subst $(BASESRC)/,,$(wildcard $(BASESRC)/*.[Ss] $(patsubst %, $(BASESRC)/%/*.[Ss],$(SUBDIRS))))
COBJ    := $(CSRC:.c=.o)
AOBJ    := $(patsubst %.[Ss], %.o, $(ASRC))
COBJ    := $(patsubst %, $(ONBUILD)/%, $(CSRC:.c=.o) )
AOBJ    := $(patsubst %, $(ONBUILD)/%, $(patsubst %.[Ss], %.o, $(ASRC)) )
COBJARM := $(CSRCARM:.c=.o)
AOBJARM := $(patsubst %.[Ss], %.o, $(ASRCARM))
PROJECT := $(ONBUILD)/$(PROJECT)


### Compiler flags
ifeq ($(THUMB),YES)
THUMBFLAG = -mthumb
THUMBIW = -mthumb-interwork
LD_THUMB =
else
THUMBFLAG =
THUMBIW =
LD_THUMB =
endif

ifeq ($(HAVEFPU),YES)
  ifeq ($(FLOAT_ABI),hard)
    FPUFLAG = -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fipa-sra
  else
    FPUFLAG = -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -fipa-sra
  endif
else
  FPUFLAG = -mfloat-abi=soft -fipa-sra
endif
# -mfloat-abi= option
#    soft:   Full software floating point.
#    (belows are need option -mfpu=fpv4-sp-d16 for cortex-M4F)
#    softfp: Use the FPU, but remain compatible with soft-float code.
#    hard:   Full hardware floating point. 

# Flags for C files
CFLAGS += -std=$(CSTD)
CFLAGS += -g$(DEBUG)
CFLAGS += -fno-schedule-insns2
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -O$(OPTIMIZE)
CFLAGS += $(addprefix -W,$(WARNINGS))
CFLAGS += $(addprefix -I,$(INCDIRS))
CFLAGS += $(addprefix -D,$(DEFS))
CFLAGS += -Wp,-MP,-MT,$(ONBUILD)/$(*F).o,-MM,-MF,$(ONBUILD)/.dep/$(*F).d
## CFLAGS += -Wp,-M,-MF,$(ONBUILD)/.dep/$(*F).d,-MP,-MT,$(ONBUILD)/$(*F).o

## Cѥ -ffunction-sections -fdata-sections ȥ󥫤 --gc-sections 
## ΰ̤ΥˤƻȤƤʤ롣

# Assembler flags
ASFLAGS += $(addprefix -D,$(ADEFS)) -Wa,-g$(DEBUG)


# Linker flags
# LDFLAGS += -nostdlib
# LDFLAGS += -nostartfiles
#LDFLAGS += -Wl,-mcpu=$(CPU)
#LDFLAGS += -Wl,-Map=$(PROJECT).map,--cref,--gc-sections,--print-gc-sections
LDFLAGS += -Wl,-Map=$(PROJECT).map,--cref,--gc-sections
LDFLAGS += -lc -lgcc
LDFLAGS += $(patsubst %,-L%,$(LIBDIRS)) $(patsubst %,-l%,$(LIBS))
LDFLAGS += $(MATHLIB)
LDFLAGS += -T$(LINKSCRIPT)


# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS  = -mcpu=$(CPU) $(THUMBIW) $(FPUFLAG) -I. $(CFLAGS)
ALL_ASFLAGS = -mcpu=$(CPU) $(THUMBIW) $(FPUFLAG) -I. -x assembler-with-cpp $(ASFLAGS)


# Default target.
.PHONY: all
.PHONY: clean
all: begin version build size

begin:
	mkdir -p $(MKDIRS)
	@echo -- ASRC
	@echo -- $(ASRC)
	@echo -- CSRC
	@echo -- $(CSRC)
	@echo -- INCDIRS
	@echo -- $(INCDIRS)
	@echo -- COBJ
	@echo -- $(COBJ)
	@echo -- AOBJ
	@echo -- $(AOBJ)
	@echo -- Embedded data: from $(EMBEDDED_DATADIR)
	@echo -- DSRC
	@echo -- $(DSRC)
	@echo -- DOBJ
	@echo -- $(DOBJ)
##	@echo -- $(wildcard $(ONBUILD)/.dep/*.d)


ifeq ($(OUTPUT),ihex)
build: elf hex lst sym
hex: $(PROJECT).hex
else
ifeq ($(OUTPUT),binary)
build: elf bin lst sym
bin: $(PROJECT).bin
else
ifeq ($(OUTPUT),both)
build: elf hex bin lst sym
hex: $(PROJECT).hex
bin: $(PROJECT).bin
else
$(error "Invalid format: $(OUTPUT)")
endif
endif
endif

elf: $(PROJECT).elf
lst: $(PROJECT).lst
sym: $(PROJECT).sym


# Display compiler version information.
version :
	@$(CC) --version

# Create final output file (.hex or .bin) from ELF output file.
%.hex: %.elf
	@echo
	$(OBJCOPY) -S -O ihex $< $@

%.bin: %.elf
	@echo
	$(OBJCOPY) -S -O binary $< $@

# Create extended listing file from ELF output file.
%.lst: %.elf
	@echo
	$(OBJDUMP) -h -S -C $< > $@
### testޥɤǥ顼ˤʤϡ饤֥ȥ֥ȤΥ⡼ɤۤʤ
### armthumb꤫-mfloat-abiʤɤͤΤreadelfޥɤʤɤ
### ơ饤֥ȥ֥ȤΥ⡼ɤʤɤǧ뤳ȡ
### (cortexM?Ǥ̵ BLX¨̿᤬ƤΤǼµhardfaultˤʤΤɻ)
ifeq ($(THUMB),YES)
	@test 0 -eq `grep '	blx	[^r]' $@ | wc -L` || (echo '*** BLX imm instruction found! ***' && test 0 -ne 0)
endif


# Create a symbol table from ELF output file.
%.sym: %.elf
	@echo
	$(NM) -n $< > $@

# Display size of file.
size:
	@echo
	$(SIZE) -A -x $(PROJECT).elf

# Link: create ELF output file from object files.
%.elf:  $(AOBJARM) $(AOBJ) $(COBJARM) $(COBJ) $(DOBJ)
	@echo
	@echo Linking...
	$(CC) $(THUMBFLAG) $(LD_THUMB) $(ALL_CFLAGS) $(AOBJARM) $(AOBJ) $(COBJARM) $(COBJ) $(DOBJ) --output $@ $(LDFLAGS)

# Compile: create object files from C source files. ARM or Thumb(-2)
$(COBJ) : $(ONBUILD)/%.o : $(BASESRC)/%.c
	@echo
	@echo $< :
	$(CC) -c $(THUMBFLAG) $(ALL_CFLAGS) $< -o $@

# Compile: create object files from C source files. ARM-only
$(COBJARM): $(ONBUILD)/%.o : $(BASESRC)/%.c
	@echo
	@echo $< :
	$(CC) -c $(ALL_CFLAGS) $< -o $@ 

# Assemble: create object files from assembler source files. ARM or Thumb(-2)
$(AOBJ) : $(ONBUILD)/%.o : $(BASESRC)/%.S
	@echo
	@echo $< :
	$(CC) -c $(THUMBFLAG) $(ALL_ASFLAGS) $< -o $@

# Assemble: create object files from assembler source files. ARM-only
$(AOBJARM): $(ONBUILD)/%.o : $(BASESRC)/%.S
	@echo
	@echo $< :
	$(CC) -c $(ALL_ASFLAGS) $< -o $@

# Generate: create object files from raw-data files.
$(DOBJ): $(ONBUILD)/%.o : %.raw
	@echo
	@echo $< :
	$(OBJCOPY) -I binary -O $(BFD_FORMAT) -B $(BFD_ARCH) --rename-section .data=.rodata,contents,readonly,load $< $@

# Target: clean project.
clean:
	@echo
	rm -f -r $(ONBUILD) | exit 0

# Target: upload project.
write: $(PROJECT).elf all
	@echo
	$(GDB) $< -ex 'target remote localhost:3333' -ex 'monitor reset init' -ex 'load' -ex 'disconnect' -ex 'quit'

# Include the dependency files.
-include $(shell mkdir -p $(ONBUILD)/.dep 2>/dev/null) $(wildcard $(ONBUILD)/.dep/*.d)

