/*
* $Log$
+ * Revision 1.13 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.12 2004/08/01 01:21:17 bernie
* LIKELY(), UNLIKELY(): New compiler-specific macros.
*
/* Simple macros */
-#define ABS(a) (((a) < 0) ? -(a) : (a))
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#if GNUC_PREREQ(2,0)
+ #define ABS(n) ({ \
+ __typeof__(n) _n = (n); \
+ (_n < 0) ? -_n : _n; \
+ })
+ #define MIN(a,b) ({ \
+ __typeof__(a) _a = (a); \
+ __typeof__(b) _b = (b); \
+ (void)(&_a == &_b); /* ensure same type */ \
+ (_a < _b) ? _a : _b; \
+ })
+ #define MAX(a,b) ({ \
+ __typeof__(a) _a = (a); \
+ __typeof__(b) _b = (b); \
+ (void)(&_a == &_b); /* ensure same type */ \
+ (_a > _b) ? _a : _b; \
+ })
+#else /* !GNUC */
+ /* Buggy macros for inferior compilers */
+ #define ABS(a) (((a) < 0) ? -(a) : (a))
+ #define MIN(a,b) (((a) < (b)) ? (a) : (b))
+ #define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif /* !GNUC */
#ifndef BV
/*! Convert a bit value to a binary flag */
/*
* $Log$
+ * Revision 1.10 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.9 2004/07/30 14:24:16 rasky
* Task switching con salvataggio perfetto stato di interrupt (SR)
* Kernel monitor per dump informazioni su stack dei processi
#include "compiler.h"
-//! Initialization value for registers in stack frame
-#define CPU_REG_INIT_VALUE(reg) 0
-
-// Macros for determining CPU endianess
+// Macros for determining CPU endianness
#define CPU_BIG_ENDIAN 0x1234
#define CPU_LITTLE_ENDIAN 0x3412
// Macros to include cpu-specific version of the headers
-#define CPU_HEADER(module) PP_STRINGIZE(PP_CAT4(module, _, CPU_ID, .h))
+#define CPU_HEADER(module) PP_STRINGIZE(PP_CAT3(module, _, CPU_ID).h)
#if CPU_I196
typedef uint8_t cpuflags_t;
typedef uint8_t cpustack_t;
- #define CPU_REGS_CNT 32
- #define CPU_SAVED_REGS_CNT 18
+ /* Register counts include SREG too */
+ #define CPU_REGS_CNT 33
+ #define CPU_SAVED_REGS_CNT 19
#define CPU_STACK_GROWS_UPWARD 0
#define CPU_SP_ON_EMPTY_SLOT 1
#define CPU_BYTE_ORDER CPU_LITTLE_ENDIAN
+
+ /*!
+ * Initialization value for registers in stack frame.
+ * The register index is not directly corrispondent to CPU
+ * register numbers. Index 0 is the SREG register: the initial
+ * value is all 0 but the interrupt bit (bit 7).
+ */
+ #define CPU_REG_INIT_VALUE(reg) (reg == 0 ? 0x80 : 0)
+
+#endif
+
+
+//! Default for macro not defined in the right arch section
+#ifndef CPU_REG_INIT_VALUE
+ #define CPU_REG_INIT_VALUE(reg) 0
#endif
/*
* $Log$
+ * Revision 1.9 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.8 2004/07/30 14:26:33 rasky
* Semplificato l'output dell'ASSERT
* Aggiunta ASSERT2 con stringa di help opzionalmente disattivabile
#elif CPU_AVR
#include <avr/io.h>
#if CONFIG_KDEBUG_PORT == 0
+
+ /* External 485 transceiver on UART0 (to be overridden in "hw.h"). */
+ #if !defined(SER_UART0_485_INIT)
+ #if defined(SER_UART0_485_RX) || defined(SER_UART0_485_TX)
+ #error SER_UART0_485_INIT, SER_UART0_485_RX and SER_UART0_485_TX must be defined together
+ #endif
+ #define SER_UART0_485_INIT do {} while (0)
+ #define SER_UART0_485_TX do {} while (0)
+ #define SER_UART0_485_RX do {} while (0)
+ #elif !defined(SER_UART0_485_RX) || !defined(SER_UART0_485_TX)
+ #error SER_UART0_485_INIT, SER_UART0_485_RX and SER_UART0_485_TX must be defined together
+ #endif
+
#if defined(__AVR_ATmega64__)
#define UCR UCSR0B
#define UDR UDR0
#define UCR UCSRB
#define USR UCSRA
#endif
+
#define KDBG_WAIT_READY() do { loop_until_bit_is_set(USR, UDRE); } while(0)
- #define KDBG_WRITE_CHAR(c) do { UCR |= BV(TXEN); UDR = (c); } while(0)
- #define KDBG_MASK_IRQ(old) do { (old) = UCR & BV(TXCIE); cbi(UCR, TXCIE); } while(0)
- #define KDBG_RESTORE_IRQ(old) do { UCR |= (old); } while(0)
+ #define KDBG_WAIT_TXDONE() do { loop_until_bit_is_set(USR, TXC); } while(0)
+ /*
+ * BUG: before sending a new character the TXC flag is cleared to allow
+ * KDBG_WAIT_TXDONE() to work properly, but, if KDBG_WRITE_CHAR() is called
+ * after the RXC flag is set by hardware, a new TXC could be generated
+ * after we clear it and before the new character is put in UDR. In this
+ * case if a 485 is used the transceiver will be put in RX mode while
+ * transmitting the last char.
+ */
+ #define KDBG_WRITE_CHAR(c) do { USR |= BV(TXC); UDR = (c); } while(0)
+
+ #define KDBG_MASK_IRQ(old) do { \
+ SER_UART0_485_TX; \
+ (old) = UCR; \
+ UCR |= BV(TXEN); \
+ UCR &= ~(BV(TXCIE) | BV(UDRIE)); \
+ } while(0)
+
+ #define KDBG_RESTORE_IRQ(old) do { \
+ KDBG_WAIT_TXDONE(); \
+ SER_UART0_485_RX; \
+ UCR = (old); \
+ } while(0)
+
#elif CONFIG_KDEBUG_PORT == 1
+
+ /* External 485 transceiver on UART1 (to be overridden in "hw.h"). */
+ #ifndef SER_UART1_485_INIT
+ #if defined(SER_UART1_485_RX) || defined(SER_UART1_485_TX)
+ #error SER_UART1_485_INIT, SER_UART1_485_RX and SER_UART1_485_TX must be defined together
+ #endif
+ #define SER_UART1_485_INIT do {} while (0)
+ #define SER_UART1_485_TX do {} while (0)
+ #define SER_UART1_485_RX do {} while (0)
+ #elif !defined(SER_UART1_485_RX) || !defined(SER_UART1_485_TX)
+ #error SER_UART1_485_INIT, SER_UART1_485_RX and SER_UART1_485_TX must be defined together
+ #endif
+
#define KDBG_WAIT_READY() do { loop_until_bit_is_set(UCSR1A, UDRE); } while(0)
- #define KDBG_WRITE_CHAR(c) do { UCSR1B |= BV(TXEN); UDR1 = (c); } while(0)
- #define KDBG_MASK_IRQ(old) do { (old) = UCSR1B & BV(TXCIE); cbi(UCSR1B, TXCIE); } while(0)
- #define KDBG_RESTORE_IRQ(old) do { UCSR1B |= (old); } while(0)
+ #define KDBG_WAIT_TXDONE() do { loop_until_bit_is_set(UCSR1A, TXC); } while(0)
+ #define KDBG_WRITE_CHAR(c) do { UCSR1A |= BV(TXC); UDR1 = (c); } while(0)
+
+ #define KDBG_MASK_IRQ(old) do { \
+ SER_UART1_485_TX; \
+ (old) = UCSR1B; \
+ UCSR1B |= BV(TXEN); \
+ UCSR1B &= ~(BV(TXCIE) | BV(UDRIE)); \
+ } while(0)
+
+ #define KDBG_RESTORE_IRQ(old) do { \
+ KDBG_WAIT_TXDONE(); \
+ SER_UART1_485_RX; \
+ UCSR1B = (old); \
+ } while(0)
+
#else
#error CONFIG_KDEBUG_PORT should be either 0 or 1
#endif
#if CONFIG_KDEBUG_PORT == 0
UBRR0H = (uint8_t)(period>>8);
UBRR0L = (uint8_t)period;
+ SER_UART0_485_INIT;
#elif CONFIG_KDEBUG_PORT == 1
UBRR1H = (uint8_t)(period>>8);
UBRR1L = (uint8_t)period;
+ SER_UART1_485_INIT;
#else
#error CONFIG_KDEBUG_PORT must be either 0 or 1
#endif
UBRRL = (uint8_t)period;
#elif defined(__AVR_ATmega103__)
UBRR = (uint8_t)period;
+ SER_UART0_485_INIT;
#else
#error Unknown arch
#endif
/*
* $Log$
+ * Revision 1.8 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.7 2004/07/30 14:15:53 rasky
* Nuovo supporto unificato per detect della CPU
*
#else
#error unknown architecture
#endif
-
- SER_CNT /**< Number of serial ports */
+ SER_CNT /*!< Number of serial ports */
};
-/* @} */
+/*\}*/
struct SerialHardware;
/*
* $Log$
+ * Revision 1.9 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.8 2004/07/29 22:57:09 bernie
* Several tweaks to reduce code size on ATmega8.
*
#endif
/* External 485 transceiver on UART0 (to be overridden in "hw.h"). */
-#ifndef SER_UART0_485_INIT
-#define SER_UART0_485_INIT do {} while (0)
+#if !defined(SER_UART0_485_INIT)
+ #if defined(SER_UART0_485_RX) || defined(SER_UART0_485_TX)
+ #error SER_UART0_485_INIT, SER_UART0_485_RX and SER_UART0_485_TX must be defined together
+ #endif
+ #define SER_UART0_485_INIT do {} while (0)
+ #define SER_UART0_485_TX do {} while (0)
+ /* SER_UART0_485_RX must not be defined! */
+#elif !defined(SER_UART0_485_RX) || !defined(SER_UART0_485_TX)
+ #error SER_UART0_485_INIT, SER_UART0_485_RX and SER_UART0_485_TX must be defined together
#endif
-#ifndef SER_UART0_485_TX
-#define SER_UART0_485_TX do {} while (0)
+
+/* External 485 transceiver on UART1 (to be overridden in "hw.h"). */
+#ifndef SER_UART1_485_INIT
+ #if defined(SER_UART1_485_RX) || defined(SER_UART1_485_TX)
+ #error SER_UART1_485_INIT, SER_UART1_485_RX and SER_UART1_485_TX must be defined together
+ #endif
+ #define SER_UART1_485_INIT do {} while (0)
+ #define SER_UART1_485_TX do {} while (0)
+ /* SER_UART1_485_RX must not be defined! */
+#elif !defined(SER_UART1_485_RX) || !defined(SER_UART1_485_TX)
+ #error SER_UART1_485_INIT, SER_UART1_485_RX and SER_UART1_485_TX must be defined together
#endif
{
/* Compute baud-rate period */
uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
- DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
#ifndef __AVR_ATmega103__
UBRR0H = (period) >> 8;
#endif
UBRR0L = (period);
+
+ DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
}
static void uart0_setparity(UNUSED(struct SerialHardware *, _hw), int parity)
{
#if CONFIG_SER_TXFILL && (CONFIG_KBUS_PORT == 1)
UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
+#elif defined(SER_UART1_485_TX)
+ /* Disable receiver, enable transmitter, switch 485 transceiver. */
+ UCSR1B = BV(UDRIE) | BV(TXEN);
+ SER_UART1_485_TX;
#else
UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
#endif
#else
UCSR1B = BV(RXCIE) | BV(RXEN);
#endif
-
+ SER_UART1_485_INIT;
RTS_ON;
}
{
/* Compute baud-rate period */
uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
- DB(kprintf("uart1_setbaudrate(rate=%ld): period=%d\n", rate, period);)
UBRR1H = (period) >> 8;
UBRR1L = (period);
+
+ DB(kprintf("uart1_setbaudrate(rate=%ld): period=%d\n", rate, period);)
}
static void uart1_setparity(UNUSED(struct SerialHardware *, _hw), int parity)
*/
UCSR1B &= ~BV(TXB8);
UDR1 = SER_FILL_BYTE;
+#elif defined(SER_UART1_485_RX)
+ /*
+ * - Disable UDR empty interrupt
+ * - Disable the transmitter (the in-progress transfer will complete)
+ * - Enable the transmit complete interrupt for the 485 tranceiver.
+ */
+ UCSR1B = BV(TXCIE);
#else
/* Disable UDR empty interrupt and transmitter */
UCSR1B = BV(RXCIE) | BV(RXEN);
UDR1 = fifo_pop(txfifo);
}
}
+
+#ifdef SER_UART1_485_RX
+/*!
+ * Serial port 1 TX complete interrupt handler.
+ *
+ * \sa port 0 TX complete handler.
+ */
+SIGNAL(SIG_UART1_TRANS)
+{
+ /* Turn the 485 tranceiver into receive mode. */
+ SER_UART1_485_RX;
+
+ /* Enable UART receiver and receive interrupt. */
+ UCSR1B = BV(RXCIE) | BV(RXEN);
+}
+#endif /* SER_UART1_485_RX */
+
#endif // AVR_HAS_UART1
/*
* $Log$
+ * Revision 1.11 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.10 2004/07/30 14:15:53 rasky
* Nuovo supporto unificato per detect della CPU
*
REMOVE((Node *)timer);
/* Execute the associated event */
- event_doIntr(&timer->expire);
+ event_do(&timer->expire);
}
#endif /* CONFIG_TIMER_DISABLE_EVENTS */
/*
* $Log$
+ * Revision 1.13 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.12 2004/07/30 14:34:10 rasky
* Vari fix per documentazione e commenti
* Aggiunte PP_CATn e STATIC_ASSERT
#include <mware/list.h>
/*! Number of timer ticks per second. */
-#define TICKS_PER_SEC 1000
+#define TICKS_PER_SEC ((time_t)1000)
/* Function protos */
extern void timer_init(void);
/* OBSOLETE */
#define timer_gettick_irq timer_tick_unlocked
+
+/*!
+ * Return the minutes passed since timer start.
+ *
+ * The minutes uptime is computed directly from system tick counter:
+ * in case of a 4 bytes time_t after 71582 minutes the value will
+ * wrap around.
+ */
+INLINE time_t timer_minutes(void)
+{
+ return timer_gettick() / (TICKS_PER_SEC * 60);
+}
+
#endif /* DRV_TIMER_H */
/*
* $Log$
+ * Revision 1.10 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.9 2004/07/22 02:01:14 bernie
* Use TIMER_PRESCALER consistently.
*
TIFR = BV(OCF2) | BV(TOV2);
/* Setup Timer/Counter interrupt */
-#warning Aleph, please use TIMER_PRESCALER here
- TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
+ TCCR2 = BV(WGM21)
+ #if TIMER_PRESCALER == 64
+ | BV(CS21) | BV(CS20)
+ #else
+ #error Unsupported value of TIMER_PRESCALER
+ #endif
+ ;
/* Clear on Compare match & prescaler = 64, internal sys clock.
When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
TCNT2 = 0x00; /* initialization of Timer/Counter */
/*
* $Log$
+ * Revision 1.7 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.6 2004/07/30 14:24:16 rasky
* Task switching con salvataggio perfetto stato di interrupt (SR)
* Kernel monitor per dump informazioni su stack dei processi
#include <string.h> /* memset() */
-/*! CPU dependent context switching routines
+/*! CPU dependent context switching routines
* \note This function *MUST* preserve also the status of the interrupts.
*/
extern void asm_switch_context(cpustack_t **new_sp, cpustack_t **save_sp);
static void proc_init_struct(Process* proc)
{
+ /* Avoid warning for unused argument */
+ (void)proc;
+
#if CONFIG_KERN_SIGNALS
proc->sig_recv = 0;
#endif
#endif
}
+
void proc_init(void)
{
INITLIST(&ProcReadyList);
#include <avr/io.h>
+/*
+ * NOTE: At each change of this function affecting proc.c
+ * (i.e. arguments, data stored in the stack) bump up version
+ * number in asm_switch_version().
+ */
+
/* void asm_switch_context(void **new_sp, void **save_sp) */
.globl asm_switch_context
asm_switch_context:
+ in r0,SREG-__SFR_OFFSET
+ push r0
; push r0 caller-save
; push r1 caller-save
push r2
pop r2
; pop r1 caller-save
; pop r0 caller-save
+ pop r0
+ out SREG-__SFR_OFFSET,r0
+
+ ret
+
+/* int asm_switch_version(void) */
+.globl asm_switch_version
+asm_switch_version:
+ ldi r24,lo8(1)
+ ldi r25,hi8(1)
ret
+
/*
* $Log$
+ * Revision 1.12 2004/08/02 20:20:29 aleph
+ * Merge from project_ks
+ *
* Revision 1.11 2004/07/30 14:15:53 rasky
* Nuovo supporto unificato per detect della CPU
*
ENABLE_IRQRESTORE(flags);
}
-#endif /* !__AVR__ */
+#endif /* !CPU_AVR */
/*!