📄 hal_if.c
字号:
//=============================================================================
//
// hal_if.c
//
// ROM/RAM interfacing functions
//
//=============================================================================
//####COPYRIGHTBEGIN####
//
// -------------------------------------------
// The contents of this file are subject to the Red Hat eCos Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.redhat.com/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations under
// the License.
//
// The Original Code is eCos - Embedded Configurable Operating System,
// released September 30, 1998.
//
// The Initial Developer of the Original Code is Red Hat.
// Portions created by Red Hat are
// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
// All Rights Reserved.
// -------------------------------------------
//
//####COPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jskov
// Contributors:jskov
// Date: 2000-06-07
//
//####DESCRIPTIONEND####
//
//=============================================================================
#include <pkgconf/hal.h>
#ifdef CYGPKG_KERNEL
# include <pkgconf/kernel.h>
#endif
#include <cyg/infra/cyg_ass.h> // assertions
#include <cyg/hal/hal_arch.h> // set/restore GP
#include <cyg/hal/hal_io.h> // IO macros
#include <cyg/hal/hal_if.h> // our interface
#include <cyg/hal/hal_diag.h> // Diag IO
#include <cyg/hal/hal_misc.h> // User break
#include <cyg/hal/hal_stub.h> // stub functionality
#include <cyg/hal/hal_intr.h> // hal_vsr_table and others
#ifdef CYGPKG_REDBOOT
#include <pkgconf/redboot.h>
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
#include <redboot.h>
#include <flash_config.h>
#endif
#endif
//--------------------------------------------------------------------------
externC void patch_dbg_syscalls(void * vector);
externC void init_thread_syscall(void * vector);
//--------------------------------------------------------------------------
// Implementations and function wrappers for monitor services
// flash config state queries
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
static __call_if_flash_cfg_op_fn_t flash_config_op;
static cyg_bool
flash_config_op( int op, char * key, void *val, int type)
{
switch ( op ) {
case CYGNUM_CALL_IF_FLASH_CFG_GET:
return flash_get_config( key, val, type );
default:
// nothing else supported yet - though it is expected that "set"
// will fit the same set of arguments, potentially.
break;
}
return 0;
}
#endif
//----------------------------
// Delay uS
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US
static __call_if_delay_us_t delay_us;
static void
delay_us(cyg_int32 usecs)
{
CYGARC_HAL_SAVE_GP();
#ifdef CYGPKG_KERNEL
{
cyg_int32 start, elapsed;
cyg_int32 usec_ticks, slice;
// How many ticks total we should wait for.
usec_ticks = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
usec_ticks /= CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000;
do {
// Spin in slices of 1/2 the RTC period. Allows interrupts
// time to run without messing up the algorithm. If we spun
// for 1 period (or more) of the RTC, there'd be also problems
// figuring out when the timer wrapped. We may lose a tick or
// two for each cycle but it shouldn't matter much.
slice = usec_ticks % (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD / 2);
HAL_CLOCK_READ(&start);
do {
HAL_CLOCK_READ(&elapsed);
elapsed = (elapsed - start); // counts up!
if (elapsed < 0)
elapsed += CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
} while (elapsed < slice);
// Adjust by elapsed, not slice, since an interrupt may have
// been stalling us for some time.
usec_ticks -= elapsed;
} while (usec_ticks > 0);
}
#else // CYGPKG_KERNEL
#ifdef HAL_DELAY_US
// Use a HAL feature if defined
HAL_DELAY_US(usecs);
#else
// If no accurate delay mechanism, just spin for a while. Having
// an inaccurate delay is much better than no delay at all. The
// count of 10 should mean the loop takes something resembling
// 1us on most CPUs running between 30-100MHz [depends on how many
// instructions this compiles to, how many dispatch units can be
// used for the simple loop, actual CPU frequency, etc]
while (usecs-- > 0) {
int i;
for (i = 0; i < 10; i++);
}
#endif // HAL_DELAY_US
#endif // CYGPKG_KERNEL
CYGARC_HAL_RESTORE_GP();
}
#endif // CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US
// Reset functions
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_RESET
static __call_if_reset_t reset;
static void
reset(void)
{
CYGARC_HAL_SAVE_GP();
// With luck, the platform defines some magic that will cause a hardware
// reset.
HAL_PLATFORM_RESET();
#ifdef HAL_PLATFORM_RESET_ENTRY
// If that's not the case (above is an empty statement) there may
// be defined an address we can jump to - and effectively
// reinitialize the system. Not quite as good as a reset, but it
// is often enough.
goto *HAL_PLATFORM_RESET_ENTRY;
#else
#error " no RESET_ENTRY"
#endif
CYGARC_HAL_RESTORE_GP();
}
// This is the system's default kill signal routine. Unless overridden
// by the application, it will cause a board reset when GDB quits the
// connection. (The user can avoid the reset by using the GDB 'detach'
// command instead of 'kill' or 'quit').
static int
kill_by_reset(int __irq_nr, void* __regs)
{
CYGARC_HAL_SAVE_GP();
reset();
CYGARC_HAL_RESTORE_GP();
return 0;
}
#endif
//------------------------------------
// NOP service
#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_INIT_WHOLE_TABLE) || \
defined(CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS)
static int
nop_service(void)
{
// This is the default service. It always returns false (0), and
// _does not_ trigger any assertions. Clients must either cope
// with the service failure or assert.
return 0;
}
#endif
//----------------------------------
// Comm controls
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS
#ifdef CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS
#define CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS \
(CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS+CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS)
#else
#define CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS \
CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
#endif
static hal_virtual_comm_table_t comm_channels[CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS+1];
static int
set_debug_comm(int __comm_id)
{
static int __selected_id = CYGNUM_CALL_IF_SET_COMM_ID_EMPTY;
hal_virtual_comm_table_t* __chan;
int interrupt_state = 0;
int res = 1, update = 0;
CYGARC_HAL_SAVE_GP();
CYG_ASSERT(__comm_id >= CYGNUM_CALL_IF_SET_COMM_ID_MANGLER
&& __comm_id < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS,
"Invalid channel");
switch (__comm_id) {
case CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT:
if (__selected_id > 0)
res = __selected_id-1;
else if (__selected_id == 0)
res = CYGNUM_CALL_IF_SET_COMM_ID_MANGLER;
else
res = __selected_id;
break;
case CYGNUM_CALL_IF_SET_COMM_ID_EMPTY:
CYGACC_CALL_IF_DEBUG_PROCS_SET(0);
__selected_id = __comm_id;
break;
case CYGNUM_CALL_IF_SET_COMM_ID_MANGLER:
__comm_id = 0;
update = 1;
break;
default:
__comm_id++; // skip mangler entry
update = 1;
break;
}
if (update) {
// Find the interrupt state of the channel.
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
if (__chan)
interrupt_state = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
__selected_id = __comm_id;
CYGACC_CALL_IF_DEBUG_PROCS_SET(comm_channels[__comm_id]);
// Set interrupt state on the new channel.
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
if (interrupt_state)
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_ENABLE);
else
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
}
CYGARC_HAL_RESTORE_GP();
return res;
}
static int
set_console_comm(int __comm_id)
{
static int __selected_id = CYGNUM_CALL_IF_SET_COMM_ID_EMPTY;
int res = 1, update = 0;
CYGARC_HAL_SAVE_GP();
CYG_ASSERT(__comm_id >= CYGNUM_CALL_IF_SET_COMM_ID_MANGLER
&& __comm_id < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS,
"Invalid channel");
switch (__comm_id) {
case CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT:
if (__selected_id > 0)
res = __selected_id-1;
else if (__selected_id == 0)
res = CYGNUM_CALL_IF_SET_COMM_ID_MANGLER;
else
res = __selected_id;
break;
case CYGNUM_CALL_IF_SET_COMM_ID_EMPTY:
CYGACC_CALL_IF_CONSOLE_PROCS_SET(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -