From 86bff5907fb5e7bda0aa4d621e93844ecaec8986 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sat, 10 Nov 2012 08:33:54 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4812 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/ports/common/MSP430X/chcore.c | 111 +++++++++++++ os/ports/common/MSP430X/chcore.h | 316 ++++++++++++++++++++++++++++++++++++++ os/ports/common/MSP430X/chtypes.h | 81 ++++++++++ os/ports/common/MSP430X/port.dox | 95 ++++++++++++ os/ports/common/MSP430X/port.mk | 6 + os/ports/common/MSP430X/rules.mk | 87 +++++++++++ 6 files changed, 696 insertions(+) create mode 100644 os/ports/common/MSP430X/chcore.c create mode 100644 os/ports/common/MSP430X/chcore.h create mode 100644 os/ports/common/MSP430X/chtypes.h create mode 100644 os/ports/common/MSP430X/port.dox create mode 100644 os/ports/common/MSP430X/port.mk create mode 100644 os/ports/common/MSP430X/rules.mk diff --git a/os/ports/common/MSP430X/chcore.c b/os/ports/common/MSP430X/chcore.c new file mode 100644 index 000000000..c86dfffac --- /dev/null +++ b/os/ports/common/MSP430X/chcore.c @@ -0,0 +1,111 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file MSP430/chcore.c + * @brief MSP430 architecture port code. + * + * @addtogroup MSP430_CORE + * @{ + */ + +#include "ch.h" + +/** + * @brief Performs a context switch between two threads. + * @details This is the most critical code in any port, this function + * is responsible for the context switch between 2 threads. + * @note The implementation of this code affects directly the context + * switch performance so optimize here as much as you can. + * @note The function is declared as a weak symbol, it is possible to + * redefine it in your application code. + * + * @param[in] ntp the thread to be switched in + * @param[in] otp the thread to be switched out + */ +#if defined(__IAR_SYSTEMS_ICC__) +#if !defined(__DOXYGEN__) +#pragma no_epilogue +#endif +void port_switch(Thread *ntp, Thread *otp) { + + asm ("pushm.a #8, r11"); + asm ("mova sp, 10(r13)"); /* Save the current stack pointer (otp-Thread). */ + asm ("mova 10(r12), sp"); /* Restore old pointer (of ntp-Thread). */ + asm ("popm.a #8, r11"); +} +#else +#if !defined(__DOXYGEN__) +__attribute__((naked, weak)) +#endif +void port_switch(Thread *ntp, Thread *otp) { + register struct intctx *sp asm("r1"); + + asm volatile ("pushm.a #8, r11" : : : "memory"); + otp->p_ctx.sp = sp; + sp = ntp->p_ctx.sp; + asm volatile ("popm.a #8, r11 \n\t" \ + "reta" : : "r" (sp) : "memory"); +} +#endif + +/** + * @brief Halts the system. + * @details This function is invoked by the operating system when an + * unrecoverable error is detected (for example because a programming + * error in the application code that triggers an assertion while in + * debug mode). + * @note The function is declared as a weak symbol, it is possible to + * redefine it in your application code. + */ +#if !defined(__DOXYGEN__) +#if !defined(__IAR_SYSTEMS_ICC__) +__attribute__((weak)) +#endif +#endif +void port_halt(void) { + + port_disable(); + while (TRUE) { + } +} + +#if defined(__IAR_SYSTEMS_ICC__) +#pragma required=chThdExit /* http://tech.groups.yahoo.com/group/msp430/message/32860 */ +#endif + +/** + * @brief Start a thread by invoking its work function. + * @details If the work function returns @p chThdExit() is automatically + * invoked. + */ +void _port_thread_start(void) { + + chSysUnlock(); + #if defined(__IAR_SYSTEMS_ICC__) + asm("mova r11, r12"); /* Pass arg to thread (with IAR-Compiler). */ + #else + asm("mova r11, r15"); /* Pass arg to thread (with GCC-Compiler). */ + #endif + asm("calla r10"); /* Start thread. */ + asm("calla #chThdExit"); /* Perform clean up on thread return. */ +} + +/** @} */ diff --git a/os/ports/common/MSP430X/chcore.h b/os/ports/common/MSP430X/chcore.h new file mode 100644 index 000000000..b6f1dd9c9 --- /dev/null +++ b/os/ports/common/MSP430X/chcore.h @@ -0,0 +1,316 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file MSP430/chcore.h + * @brief MSP430 architecture port macros and structures. + * + * @addtogroup MSP430_CORE + * @{ + */ + +#ifndef _CHCORE_H_ +#define _CHCORE_H_ + +#include +#include "chtypes.h" + +#if CH_DBG_ENABLE_STACK_CHECK +#error "option CH_DBG_ENABLE_STACK_CHECK not supported by this port" +#endif + +/** + * @brief Enables the use of a wait state in the idle thread loop. + */ +#ifndef ENABLE_WFI_IDLE +#define ENABLE_WFI_IDLE 0 +#endif + +/** + * @brief Macro defining the MSP430 architecture. + */ +#define CH_ARCHITECTURE_MSP430 + +/** + * @brief Name of the implemented architecture. + */ +#define CH_ARCHITECTURE_NAME "MSP430" + +/** + * @brief Name of the architecture variant (optional). + */ +#define CH_CORE_VARIANT_NAME "MSP430X" + +/** + * @brief Name of the compiler supported by this port. + */ +#if defined(__IAR_SYSTEMS_ICC__) +#define CH_COMPILER_NAME __VERSION__ +#elif defined(__GNUC__) +#define CH_COMPILER_NAME "GCC "__VERSION__ +#else +#error "Unsupported compiler in use." +#endif + +/** + * @brief Port-specific information string. + */ +#define CH_PORT_INFO "None" + +/** + * @brief 16 bits stack and memory alignment enforcement. + */ +typedef uint16_t stkalign_t; + +/** + * @brief Generic MSP430 register. + */ +typedef void *regmsp_t; + +/** + * @brief Interrupt saved context. + * @details This structure represents the stack frame saved during a + * preemption-capable interrupt handler. + */ +struct extctx { + regmsp_t r12; + regmsp_t r13; + regmsp_t r14; + regmsp_t r15; + regmsp_t sr; + regmsp_t pc; +}; + +/** + * @brief System saved context. + * @details This structure represents the inner stack frame during a context + * switching. + */ +struct intctx { + regmsp_t r4; + regmsp_t r5; + regmsp_t r6; + regmsp_t r7; + regmsp_t r8; + regmsp_t r9; + regmsp_t r10; + regmsp_t r11; + regmsp_t pc; +}; + +/** + * @brief Platform dependent part of the @p Thread structure. + * @details This structure usually contains just the saved stack pointer + * defined as a pointer to a @p intctx structure. + */ +struct context { + struct intctx *sp; +}; + +/** + * @brief Platform dependent part of the @p chThdCreateI() API. + * @details This code usually setup the context switching frame represented + * by an @p intctx structure. + */ +#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \ + tp->p_ctx.sp = (struct intctx *)((uint8_t *)workspace + \ + wsize - \ + sizeof(struct intctx)); \ + tp->p_ctx.sp->r10 = (regmsp_t)pf; \ + tp->p_ctx.sp->r11 = arg; \ + tp->p_ctx.sp->pc = (regmsp_t)_port_thread_start; \ +} + +/** + * @brief Stack size for the system idle thread. + * @details This size depends on the idle thread implementation, usually + * the idle thread should take no more space than those reserved + * by @p PORT_INT_REQUIRED_STACK. + */ +#ifndef PORT_IDLE_THREAD_STACK_SIZE +#define PORT_IDLE_THREAD_STACK_SIZE 0 +#endif + +/** + * @brief Per-thread stack overhead for interrupts servicing. + * @details This constant is used in the calculation of the correct working + * area size. + * This value can be zero on those architecture where there is a + * separate interrupt stack and the stack space between @p intctx and + * @p extctx is known to be zero. + * @note In this port the default is 32 bytes per thread. + */ +#ifndef PORT_INT_REQUIRED_STACK +#define PORT_INT_REQUIRED_STACK 32 +#endif + +/** + * @brief Enforces a correct alignment for a stack area size value. + */ +#define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1) + +/** + * @brief Computes the thread working area global size. + */ +#define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \ + sizeof(struct intctx) + \ + sizeof(struct extctx) + \ + (n) + (PORT_INT_REQUIRED_STACK)) + +/** + * @brief Static working area allocation. + * @details This macro is used to allocate a static thread working area + * aligned as both position and size. + */ +#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)] + +/** + * @brief IRQ prologue code. + * @details This macro must be inserted at the start of all IRQ handlers + * enabled to invoke system APIs. + */ +#define PORT_IRQ_PROLOGUE() + +/** + * @brief IRQ epilogue code. + * @details This macro must be inserted at the end of all IRQ handlers + * enabled to invoke system APIs. + */ +#define PORT_IRQ_EPILOGUE() { \ + dbg_check_lock(); \ + if (chSchIsPreemptionRequired()) \ + chSchDoReschedule(); \ + dbg_check_unlock(); \ +} + +#define ISRNAME(pre, id) pre##id + +/** + * @brief IRQ handler function declaration. + * @note @p id can be a function name or a vector number depending on the + * port implementation. + */ +#if defined(__IAR_SYSTEMS_ICC__) +#define STRINGVECTOR(x) #x +#define VECTOR_ID(x) STRINGVECTOR( vector=x##_VECTOR ) +#define PORT_IRQ_HANDLER(id) \ +_Pragma( VECTOR_ID(id) ) \ +__interrupt void ISRNAME(vect,id)(void) +#else +//#define PORT_IRQ_HANDLER(id) ISR(id,vect##id) +#define PORT_IRQ_HANDLER(id) void __attribute__((__interrupt__ (id##_VECTOR))) ISRNAME(vect,id)(void) +#endif + +/** + * @brief Port-related initialization code. + * @note This function is empty in this port. + */ +#define port_init() + +/** + * @brief Kernel-lock action. + * @details Usually this function just disables interrupts but may perform more + * actions. + * @note Implemented as global interrupt disable. + */ +#define port_lock() __disable_interrupt() + +/** + * @brief Kernel-unlock action. + * @details Usually this function just enables interrupts but may perform more + * actions. + * @note Implemented as global interrupt enable. + */ +#define port_unlock() __enable_interrupt() + +/** + * @brief Kernel-lock action from an interrupt handler. + * @details This function is invoked before invoking I-class APIs from + * interrupt handlers. The implementation is architecture dependent, + * in its simplest form it is void. + * @note This function is empty in this port. + */ +#define port_lock_from_isr() + +/** + * @brief Kernel-unlock action from an interrupt handler. + * @details This function is invoked after invoking I-class APIs from interrupt + * handlers. The implementation is architecture dependent, in its + * simplest form it is void. + * @note This function is empty in this port. + */ +#define port_unlock_from_isr() + +/** + * @brief Disables all the interrupt sources. + * @note Of course non-maskable interrupt sources are not included. + * @note Implemented as global interrupt disable. + */ +#define port_disable() __disable_interrupt() + +/** + * @brief Disables the interrupt sources below kernel-level priority. + * @note Interrupt sources above kernel level remains enabled. + * @note Same as @p port_disable() in this port, there is no difference + * between the two states. + */ +#define port_suspend() __disable_interrupt() + +/** + * @brief Enables all the interrupt sources. + * @note Implemented as global interrupt enable. + */ +#define port_enable() __enable_interrupt() + +/** + * @brief Enters an architecture-dependent IRQ-waiting mode. + * @details The function is meant to return when an interrupt becomes pending. + * The simplest implementation is an empty function or macro but this + * would not take advantage of architecture-specific power saving + * modes. + * @note This port function is implemented as inlined code for performance + * reasons. + * @note The port code does not define a low power mode, this macro has to + * be defined externally. The default implementation is a "nop", not + * a real low power mode. + */ +#if ENABLE_WFI_IDLE != 0 +#ifndef port_wait_for_interrupt +#define port_wait_for_interrupt() { \ + __no_operation(); \ +} +#endif +#else +#define port_wait_for_interrupt() +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void port_switch(Thread *ntp, Thread *otp); + void port_halt(void); + void _port_thread_start(void); +#ifdef __cplusplus +} +#endif + +#endif /* _CHCORE_H_ */ + +/** @} */ diff --git a/os/ports/common/MSP430X/chtypes.h b/os/ports/common/MSP430X/chtypes.h new file mode 100644 index 000000000..0ea946c1c --- /dev/null +++ b/os/ports/common/MSP430X/chtypes.h @@ -0,0 +1,81 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file MSP430/chtypes.h + * @brief MSP430 architecture port system types. + * + * @addtogroup MSP430_CORE + * @{ + */ + +#ifndef _CHTYPES_H_ +#define _CHTYPES_H_ + +#define __need_NULL +#define __need_size_t +#define __need_ptrdiff_t +#include + +#if !defined(_STDINT_H) && !defined(__STDINT_H_) +#include +#endif + +typedef int16_t bool_t; /**< Fast boolean type. */ +typedef uint8_t tmode_t; /**< Thread flags. */ +typedef uint8_t tstate_t; /**< Thread state. */ +typedef uint8_t trefs_t; /**< Thread references counter. */ +typedef uint16_t tprio_t; /**< Thread priority. */ +typedef int16_t msg_t; /**< Inter-thread message. */ +typedef int16_t eventid_t; /**< Event Id. */ +typedef uint16_t eventmask_t; /**< Events mask. */ +typedef uint16_t systime_t; /**< System time. */ +typedef int16_t cnt_t; /**< Resources counter. */ + +/** + * @brief Inline function modifier. + */ +#define INLINE inline + +/** + * @brief ROM constant modifier. + * @note It is set to use the "const" keyword in this port. + */ +#define ROMCONST const + +/** + * @brief Packed structure modifier (within). + * @note It uses the "packed" GCC attribute. + */ +#define PACK_STRUCT_STRUCT __attribute__((packed)) + +/** + * @brief Packed structure modifier (before). + */ +#define PACK_STRUCT_BEGIN #pragma pack(1) + +/** + * @brief Packed structure modifier (after). + */ +#define PACK_STRUCT_END #pragma pack() + +#endif /* _CHTYPES_H_ */ + +/** @} */ diff --git a/os/ports/common/MSP430X/port.dox b/os/ports/common/MSP430X/port.dox new file mode 100644 index 000000000..8c30582ec --- /dev/null +++ b/os/ports/common/MSP430X/port.dox @@ -0,0 +1,95 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @defgroup MSP430 MSP430 + * @details MSP430 port for the GCC/IAR compiler. + * + * @section MSP430_INTRO Introduction + * This port supports all the cores implementing the MSP430 architecture. + * + * @section MSP430_STATES Mapping of the System States in the MSP430 port + * The ChibiOS/RT logical @ref system_states are mapped as follow in the MSP430 + * port: + * - Init. This state is represented by the startup code and the + * initialization code before @p chSysInit() is executed. It has not a + * special hardware state associated. + * - Normal. This is the state the system has after executing + * @p chSysInit(). Interrupts are enabled. + * - Suspended. Interrupts are disabled. + * - Disabled. Interrupts are disabled. This state is equivalent to the + * Suspended state because there are no fast interrupts in this architecture. + * - Sleep. Not yet implemented. + * - S-Locked. Interrupts are disabled. + * - I-Locked. This state is equivalent to the SRI state, the + * @p chSysLockI() and @p chSysUnlockI() APIs do nothing (still use them in + * order to formally change state because this may change). + * - Serving Regular Interrupt. Normal interrupt service code. + * - Serving Fast Interrupt. Not present in this architecture. + * - Serving Non-Maskable Interrupt. The MSP430 has several non + * maskable interrupt sources that can be associated to this state. + * - Halted. Implemented as an infinite loop with interrupts disabled. + * . + * @section MSP430_NOTES The MSP430 port notes + * - The MSP430 does not have a dedicated interrupt stack, make sure to reserve + * enough stack space for interrupts in each thread stack. This can be done + * by modifying the @p INT_REQUIRED_STACK configuration options. + * - The state of the hardware multiplier is not saved in the thread context, + * make sure to use it in Suspended state (interrupts masked). + * - The port code does not define the switch to a low power mode for the + * idle thread because the MSP430 has several low power modes. You can + * select the proper low power mode for you application by defining the + * macro @p port_wait_for_interrupt(). + * . + * @ingroup gcc + */ + +/** + * @defgroup MSP430_CONF Configuration Options + * @details MSP430 Configuration Options. The MSP430 port allows some + * architecture-specific configurations settings that can be overridden + * by redefining them in @p chconf.h. Usually there is no need to change + * the default values. + * - @p INT_REQUIRED_STACK, this value represent the amount of stack space + * used by the interrupt handlers.
+ * The default for this value is @p 32, this space is allocated for each + * thread so be careful in order to not waste precious RAM space. + * - @p IDLE_THREAD_STACK_SIZE, stack area size to be assigned to the IDLE + * thread. Usually there is no need to change this value unless inserting + * code in the IDLE thread hook macro. + * . + * @ingroup MSP430 + */ + +/** + * @defgroup MSP430_CORE Core Port Implementation + * @details MSP430 specific port code, structures and macros. + * + * @ingroup MSP430 + */ + + /** + * @defgroup MSP430_STARTUP Startup Support + * @details ChibiOS/RT doed not provide startup files for the MSP430, there + * are no special startup requirement so the normal toolchain-provided + * startup files can be used. + * + * @ingroup MSP430 + */ diff --git a/os/ports/common/MSP430X/port.mk b/os/ports/common/MSP430X/port.mk new file mode 100644 index 000000000..a3263b171 --- /dev/null +++ b/os/ports/common/MSP430X/port.mk @@ -0,0 +1,6 @@ +# List of the ChibiOS/RT MSP430 port files. +PORTSRC = ${CHIBIOS}/os/ports/common/MSP430X/chcore.c + +PORTASM = + +PORTINC = ${CHIBIOS}/os/ports/common/MSP430X diff --git a/os/ports/common/MSP430X/rules.mk b/os/ports/common/MSP430X/rules.mk new file mode 100644 index 000000000..e5df10916 --- /dev/null +++ b/os/ports/common/MSP430X/rules.mk @@ -0,0 +1,87 @@ +# MSP430 makefile scripts and rules. + +# Automatic compiler options +OPT = $(USE_OPT) +COPT = $(USE_COPT) +CPPOPT = $(USE_CPPOPT) +ifeq ($(USE_LINK_GC),yes) + OPT += -ffunction-sections -fdata-sections +endif + +# Source files groups +SRC = $(CSRC)$(CPPSRC) + +# Object files groups +COBJS = $(CSRC:.c=.o) +CPPOBJS = $(CPPSRC:.cpp=.o) +ASMOBJS = $(ASMSRC:.s=.o) +OBJS = $(ASMOBJS) $(COBJS) $(CPPOBJS) + +# Paths +IINCDIR = $(patsubst %,-I%,$(INCDIR) $(DINCDIR) $(UINCDIR)) +LLIBDIR = $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR)) + +# Macros +DEFS = $(DDEFS) $(UDEFS) +ADEFS = $(DADEFS) $(UADEFS) + +# Libs +LIBS = $(DLIBS) $(ULIBS) + +MCFLAGS = -mmcu=$(MCU) +ODFLAGS = -x --syms +ASFLAGS = $(MCFLAGS) -Wa,-amhls=$(<:.s=.lst) $(ADEFS) +CPFLAGS = $(MCFLAGS) $(OPT) $(COPT) $(WARN) -Wa,-alms=$(<:.c=.lst) $(DEFS) +ifeq ($(LINK_GC),yes) + LDFLAGS = $(MCFLAGS) -T$(LDSCRIPT) -Wl,-Map=$(PROJECT).map,--cref,--no-warn-mismatch,--gc-sections $(LLIBDIR) +else + LDFLAGS = $(MCFLAGS) -T$(LDSCRIPT) -Wl,-Map=$(PROJECT).map,--cref,--no-warn-mismatch $(LLIBDIR) +endif + +# Generate dependency information +CPFLAGS += -MD -MP -MF .dep/$(@F).d + +# +# Makefile rules +# +all: $(OBJS) $(PROJECT).elf $(PROJECT).hex $(PROJECT).bin $(PROJECT).dmp MAKE_ALL_RULE_HOOK + +MAKE_ALL_RULE_HOOK: + +$(CPPOBJS) : %.o : %.cpp + @echo + $(CPPC) -c $(CPPFLAGS) -I . $(IINCDIR) $< -o $@ + +$(COBJS) : %.o : %.c + @echo + $(CC) -c $(CPFLAGS) -I . $(IINCDIR) $< -o $@ + +$(ASMOBJS) : %.o : %.s + @echo + $(AS) -c $(ASFLAGS) -I . $(IINCDIR) $< -o $@ + +%elf: $(OBJS) + @echo + $(LD) $(OBJS) $(LDFLAGS) $(LIBS) -o $@ + +%hex: %elf + $(HEX) $< $@ + +%bin: %elf + $(BIN) $< $@ + +%dmp: %elf + $(OD) $(ODFLAGS) $< > $@ + +clean: + -rm -f $(OBJS) + -rm -f $(CSRC:.c=.lst) $(CPPSRC:.cpp=.lst) $(ASMSRC:.s=.lst) + -rm -f $(PROJECT).elf $(PROJECT).dmp $(PROJECT).map $(PROJECT).hex $(PROJECT).bin + -rm -fR .dep + +# +# Include the dependency files, should be the last of the makefile +# +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + +# *** EOF *** -- cgit v1.2.3