📄 synth_intr.c
字号:
// come in via the system's signal handling mechanism, and
// it might be possible to do something useful with saved contexts
// etc., facilitating thread-aware debugging.
if (0 != (synth_pending_isrs & ~synth_masked_isrs)) {
hal_interrupts_enabled = false;
(*synth_VSR)();
CYG_ASSERT( hal_interrupts_enabled, "Interrupts should still be enabled on return from the VSR");
}
}
// ----------------------------------------------------------------------------
// Other interrupt-related routines. Mostly these just involve
// updating some of the statics, but they may be called while
// interrupts are still enabled so care has to be taken.
cyg_bool_t
hal_interrupt_in_use(cyg_vector_t vec)
{
CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only attach to valid ISR vectors");
return synth_default_isr != synth_isr_handlers[vec].isr;
}
void
hal_interrupt_attach(cyg_vector_t vec, cyg_ISR_t* isr, CYG_ADDRWORD data, CYG_ADDRESS obj)
{
CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only attach to valid ISR vectors");
CYG_CHECK_FUNC_PTR( isr, "A valid ISR must be supplied");
// The object cannot be validated, it may be NULL if chained
// interrupts are enabled.
CYG_ASSERT( synth_isr_handlers[vec].isr == &synth_default_isr, "Only one ISR can be attached to a vector at the HAL level");
CYG_ASSERT( (false == hal_interrupts_enabled) || (0 != (synth_masked_isrs & (0x01 << vec))), "ISRs should only be attached when it is safe");
// The priority will have been installed shortly before this call.
synth_isr_handlers[vec].isr = isr;
synth_isr_handlers[vec].data = data;
synth_isr_handlers[vec].obj = obj;
}
void
hal_interrupt_detach(cyg_vector_t vec, cyg_ISR_t* isr)
{
CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only detach from valid ISR vectors");
CYG_CHECK_FUNC_PTR( isr, "A valid ISR must be supplied");
CYG_ASSERT( isr != &synth_default_isr, "An ISR must be attached before it can be detached");
CYG_ASSERT( (false == hal_interrupts_enabled) || (0 != (synth_masked_isrs & (0x01 << vec))), "ISRs should only be detached when it is safe");
// The Cyg_Interrupt destructor does an unconditional detach, even if the
// isr is not currently attached.
if (isr == synth_isr_handlers[vec].isr) {
synth_isr_handlers[vec].isr = &synth_default_isr;
synth_isr_handlers[vec].data = (CYG_ADDRWORD) 0;
synth_isr_handlers[vec].obj = (CYG_ADDRESS) 0;
}
// The priority is not updated here. This should be ok, if another
// isr is attached then the appropriate priority will be installed
// first.
}
void (*hal_vsr_get(cyg_vector_t vec))(void)
{
CYG_ASSERT( (CYGNUM_HAL_VSR_MIN <= vec) && (vec <= CYGNUM_HAL_VSR_MAX), "Can only get valid VSR vectors");
return synth_VSR;
}
void
hal_vsr_set(cyg_vector_t vec, void (*new_vsr)(void), void (**old_vsrp)(void))
{
cyg_bool_t old;
CYG_ASSERT( (CYGNUM_HAL_VSR_MIN <= vec) && (vec <= CYGNUM_HAL_VSR_MAX), "Can only get valid VSR vectors");
CYG_CHECK_FUNC_PTR( new_vsr, "A valid VSR must be supplied");
// There is a theoretical possibility of two hal_vsr_set calls at
// the same time. The old and new VSRs must be kept in synch.
HAL_DISABLE_INTERRUPTS(old);
if (0 != old_vsrp) {
*old_vsrp = synth_VSR;
}
synth_VSR = new_vsr;
HAL_RESTORE_INTERRUPTS(old);
}
void
hal_interrupt_mask(cyg_vector_t which)
{
CYG_PRECONDITION( !hal_interrupts_enabled, "Interrupts should be disabled on entry to hal_interrupt_mask");
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
synth_masked_isrs |= (0x01 << which);
}
void
hal_interrupt_unmask(cyg_vector_t which)
{
CYG_PRECONDITION( !hal_interrupts_enabled, "Interrupts should be disabled on entry to hal_interrupt_unmask");
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
synth_masked_isrs &= ~(0x01 << which);
}
void
hal_interrupt_acknowledge(cyg_vector_t which)
{
cyg_bool_t old;
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
// Acknowledging an interrupt means clearing the bit in the
// interrupt pending "register".
// NOTE: does the auxiliary need to keep track of this? Probably
// not, the auxiliary can just raise SIGIO whenever a device wants
// attention. There may be a trade off here between additional
// communication and unnecessary SIGIOs.
HAL_DISABLE_INTERRUPTS(old);
synth_pending_isrs &= ~(0x01 << which);
HAL_RESTORE_INTERRUPTS(old);
}
void
hal_interrupt_configure(cyg_vector_t which, cyg_bool_t level, cyg_bool_t up)
{
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
// The synthetic target does not currently distinguish between
// level and edge interrupts. Possibly this information will have
// to be passed on to the auxiliary in future.
CYG_UNUSED_PARAM(cyg_vector_t, which);
CYG_UNUSED_PARAM(cyg_bool_t, level);
CYG_UNUSED_PARAM(cyg_bool_t, up);
}
void
hal_interrupt_set_level(cyg_vector_t which, cyg_priority_t level)
{
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
// The legal values for priorities are not defined at this time.
// Manipulating the interrupt priority level currently has no
// effect. The information is stored anyway, for future use.
synth_isr_handlers[which].pri = level;
}
// ----------------------------------------------------------------------------
// Exception handling. Typically this involves calling into the kernel,
// translating the POSIX signal number into a HAL exception number. In
// practice these signals will generally be caught in the debugger and
// will not have to be handled by eCos itself.
static void
synth_exception_sighandler(int sig)
{
CYG_WORD ecos_exception_number = 0;
cyg_bool_t old;
// There is no need to save state, that will have been done by the
// system as part of the signal delivery process.
// Disable interrupts. Performing e.g. an interaction with the
// auxiliary after a SIGSEGV is dubious.
HAL_DISABLE_INTERRUPTS(old);
// Now decode the signal and turn it into an eCos exception.
switch(sig) {
case CYG_HAL_SYS_SIGILL:
ecos_exception_number = CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION;
break;
case CYG_HAL_SYS_SIGBUS:
case CYG_HAL_SYS_SIGSEGV:
ecos_exception_number = CYGNUM_HAL_EXCEPTION_DATA_ACCESS;
break;
case CYG_HAL_SYS_SIGFPE:
ecos_exception_number = CYGNUM_HAL_EXCEPTION_FPU;
break;
default:
CYG_FAIL("Unknown signal");
break;
}
#ifdef CYGPKG_KERNEL_EXCEPTIONS
// Deliver the signal, usually to the kernel, possibly to the
// common HAL. The second argument should be the current
// savestate, but that is not readily accessible.
cyg_hal_deliver_exception(ecos_exception_number, (CYG_ADDRWORD) 0);
// It is now necessary to restore the machine state, including
// interrupts. In theory higher level code may have manipulated
// the machine state to prevent any recurrence of the exception.
// In practice the machine state is not readily accessible.
HAL_RESTORE_INTERRUPTS(old);
#else
CYG_FAIL("Exception!!!");
for (;;);
#endif
}
// ----------------------------------------------------------------------------
// The clock support. This can be implemented using the setitimer()
// and getitimer() calls. The kernel will install a suitable interrupt
// handler for CYGNUM_HAL_INTERRUPT_RTC, but it depends on the HAL
// for low-level manipulation of the clock hardware.
//
// There is a problem with HAL_CLOCK_READ(). The obvious
// implementation would use getitimer(), but that has the wrong
// behaviour: it is intended for fairly coarse intervals and works in
// terms of system clock ticks, as opposed to a fine-grained
// implementation that actually examines the system clock. Instead use
// gettimeofday().
static struct cyg_hal_sys_timeval synth_clock = { 0, 0 };
void
hal_clock_initialize(cyg_uint32 period)
{
struct cyg_hal_sys_itimerval timer;
// Needed for hal_clock_read(), if HAL_CLOCK_READ() is used before
// the first clock interrupt.
cyg_hal_sys_gettimeofday(&synth_clock, (struct cyg_hal_sys_timezone*) 0);
// The synthetic target clock resolution is in microseconds. A typical
// value for the period will be 10000, corresponding to one timer
// interrupt every 10ms. Set up a timer to interrupt in period us,
// and again every period us after that.
CYG_ASSERT( period < 1000000, "Clock interrupts should happen at least once per second");
timer.hal_it_interval.hal_tv_sec = 0;
timer.hal_it_interval.hal_tv_usec = period;
timer.hal_it_value.hal_tv_sec = 0;
timer.hal_it_value.hal_tv_usec = period;
if (0 != cyg_hal_sys_setitimer(CYG_HAL_SYS_ITIMER_REAL, &timer, (struct cyg_hal_sys_itimerval*) 0)) {
CYG_FAIL("Failed to initialize the clock itimer");
}
}
static void
synth_alrm_sighandler(int sig)
{
CYG_PRECONDITION((CYG_HAL_SYS_SIGALRM == sig), "Only SIGALRM should be handled here");
if (!hal_interrupts_enabled) {
synth_sigalrm_pending = true;
return;
}
// Interrupts were enabled, but must be blocked before any further processing.
hal_interrupts_enabled = false;
// Update the cached value of the clock for hal_clock_read()
cyg_hal_sys_gettimeofday(&synth_clock, (struct cyg_hal_sys_timezone*) 0);
// Update the interrupt status "register" to match pending interrupts
// A timer signal means that IRQ 0 needs attention.
synth_pending_isrs |= 0x01;
// If any of the pending interrupts are not masked, invoke the
// VSR. That will reenable interrupts.
if (0 != (synth_pending_isrs & ~synth_masked_isrs)) {
(*synth_VSR)();
} else {
hal_interrupts_enabled = true;
}
// The VSR will have invoked interrupt_end() with interrupts
// enabled, and they should still be enabled.
CYG_ASSERT( hal_interrupts_enabled, "Interrupts should still be enabled on return from the VSR");
}
// Implementing hal_clock_read(). gettimeofday() in conjunction with
// synth_clock gives the time since the last clock tick in
// microseconds, the correct unit for the synthetic target.
cyg_uint32
hal_clock_read(void)
{
int elapsed;
struct cyg_hal_sys_timeval now;
cyg_hal_sys_gettimeofday(&now, (struct cyg_hal_sys_timezone*) 0);
elapsed = (1000000 * (now.hal_tv_sec - synth_clock.hal_tv_sec)) + (now.hal_tv_usec - synth_clock.hal_tv_usec);
return elapsed;
}
// ----------------------------------------------------------------------------
// The signal handler for SIGIO. This can also be invoked by
// hal_enable_interrupts() to catch up with any signals that arrived
// while interrupts were disabled. SIGIO is raised by the auxiliary
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -