⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 synth_intr.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
    // 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 + -