📄 synth_intr.c
字号:
voidhal_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);}voidhal_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);}voidhal_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);}voidhal_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);}voidhal_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);}voidhal_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 voidsynth_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 };voidhal_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 voidsynth_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_uint32hal_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// when it requires attention, i.e. when one or more of the devices// want to raise an interrupt. Finding out exactly which interrupt(s)// are currently pending in the auxiliary requires communication with// the auxiliary.//// If interrupts are currently disabled then the signal cannot be// handled immediately. In particular SIGIO cannot be handled because// there may already be ongoing communication with the auxiliary.// Instead some volatile flags are used to keep track of which signals// were raised while interrupts were disabled. //// It might be better to perform the interaction with the auxiliary// as soon as possible, i.e. either in the SIGIO handler or when the// current communication completes. That way the mask of pending// interrupts would remain up to date even when interrupts are// disabled, thus allowing applications to run in polled mode.// A little utility called when the auxiliary has been asked to exit,// implicitly affecting this application as well. The sole purpose// of this function is to put a suitably-named function on the stack// to make it more obvious from inside gdb what is happening.static voidsynth_io_handle_shutdown_request_from_auxiliary(void){ cyg_hal_sys_exit(0);}static voidsynth_io_sighandler(int sig){ CYG_PRECONDITION((CYG_HAL_SYS_SIGIO == sig), "Only SIGIO should be handled here"); if (!hal_interrupts_enabled) { synth_sigio_pending = true; return; } // Interrupts were enabled, but must be blocked before any further processing. hal_interrupts_enabled = false; // Update the interrupt status "register" to match pending interrupts // Contact the auxiliary to find out what interrupts are currently pending there. // If there is no auxiliary at present, e.g. because it has just terminated // and things are generally somewhat messy, ignore it. // // This code also deals with the case where the user has requested program // termination. It would be wrong for the auxiliary to just exit, since the // application could not distinguish that case from a crash. Instead the // auxiliary can optionally return an additional byte of data, and if that // byte actually gets sent then that indicates pending termination. if (synth_auxiliary_running) { int result; int actual_len; unsigned char dummy[1]; synth_auxiliary_xchgmsg(SYNTH_DEV_AUXILIARY, SYNTH_AUXREQ_GET_IRQPENDING, 0, 0, (const unsigned char*) 0, 0, // The auxiliary does not need any additional data &result, dummy, &actual_len, 1); synth_pending_isrs |= result; if (actual_len) { // The auxiliary has been asked to terminate by the user. This // request has now been passed on to the eCos application. synth_io_handle_shutdown_request_from_auxiliary(); } } // If any of the pending interrupts are not masked, invoke the VSR 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");}// ----------------------------------------------------------------------------// Here we define an action to do in the idle thread. For the// synthetic target it makes no sense to spin eating processor time// that other processes could make use of. Instead we call select. The// itimer will still go off and kick the scheduler back into life,// giving us an escape path from the select. There is one problem: in// some configurations, e.g. when preemption is disabled, the idle// thread must yield continuously rather than blocking.voidhal_idle_thread_action(cyg_uint32 loop_count){#ifndef CYGIMP_HAL_IDLE_THREAD_SPIN cyg_hal_sys__newselect(0, (struct cyg_hal_sys_fd_set*) 0, (struct cyg_hal_sys_fd_set*) 0, (struct cyg_hal_sys_fd_set*) 0, (struct cyg_hal_sys_timeval*) 0);#endif CYG_UNUSED_PARAM(cyg_uint32, loop_count);}// ----------------------------------------------------------------------------// The I/O auxiliary.//// I/O happens via an auxiliary process. During startup this code attempts// to locate and execute a program ecosynth which should be installed in// ../libexec/ecosynth relative to some directory on the search path.// Subsequent I/O operations involve interacting with this auxiliary.#define MAKESTRING1(a) #a#define MAKESTRING2(a) MAKESTRING1(a)#define AUXILIARY "../libexec/ecos/hal/synth/arch/" MAKESTRING2(CYGPKG_HAL_SYNTH) "/ecosynth"// Is the auxiliary up and running?cyg_bool synth_auxiliary_running = false;// The pipes to and from the auxiliary.static int to_aux = -1;static int from_aux = -1;// Attempt to start up the auxiliary. Note that this happens early on// during system initialization so it is "known" that the world is// still simple, e.g. that no other files have been opened.static voidsynth_start_auxiliary(void){#define BUFSIZE 256
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -