diff packages/hal/common/current/src/hal_if.c @ 105:5a0cc6c243a9 ecos-sw-2000-06-30

Merge from eCos master repository on 2000-06-30-08:18:49-BST
author jlarmour
date Fri, 30 Jun 2000 16:27:35 +0000
parents 95f3e12a6327
children 7f461c3a372c
line wrap: on
line diff
--- a/packages/hal/common/current/src/hal_if.c
+++ b/packages/hal/common/current/src/hal_if.c
@@ -41,6 +41,10 @@
 
 #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
@@ -49,26 +53,64 @@
 #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/plf_stub.h>           // reset entry - FIXME, should be moved
 
+#include <cyg/hal/hal_intr.h>           // hal_vsr_table and others
+
 
 //--------------------------------------------------------------------------
 
 externC void patch_dbg_syscalls(void * vector);
 externC void init_thread_syscall(void * vector);
 
-externC CYG_ADDRWORD hal_interrupt_handlers[];
-externC CYG_ADDRWORD hal_vsr_table[];
-
 //--------------------------------------------------------------------------
 // Implementations and function wrappers for monitor services
+
 #ifdef CYGPRI_HAL_IMPLEMENTS_IF_SERVICES
+static void
+delay_us(cyg_int32 usecs)
+{
+#ifdef CYGPKG_KERNEL
+    cyg_int32 start, elapsed;
+    cyg_int32 usec_ticks, slice;
+    CYGARC_HAL_SAVE_GP();
+
+    // 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);
+
+    CYGARC_HAL_RESTORE_GP();
+#endif
+}
 
 static void
 reset(void)
 {
+    CYGARC_HAL_SAVE_GP();
     // With luck, the platform defines some magic that will cause a hardware
     // reset.
     HAL_STUB_PLATFORM_RESET();
@@ -83,6 +125,8 @@ reset(void)
 #else
 #error " no RESET_ENTRY"
 #endif
+
+    CYGARC_HAL_RESTORE_GP();
 }
 
 // This is the system's default kill signal routine. Unless overridden
@@ -92,7 +136,11 @@ reset(void)
 static int
 kill_by_reset(int __irq_nr, void* __regs)
 {
+    CYGARC_HAL_SAVE_GP();
+
     reset();
+
+    CYGARC_HAL_RESTORE_GP();
     return 0;
 }
 
@@ -110,12 +158,14 @@ nop_service(void)
 
 static hal_virtual_comm_table_t comm_channels[CYGNUM_HAL_VIRTUAL_VECTOR_COMM_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_COMM_CHANNELS,
@@ -124,36 +174,56 @@ set_debug_comm(int __comm_id)
     switch (__comm_id) {
     case CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT:
         if (__selected_id > 0)
-            return __selected_id-1;
-        if (__selected_id == 0)
-            return CYGNUM_CALL_IF_SET_COMM_ID_MANGLER;
-        return __selected_id;
+            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;
-        return 1;
+        break;
 
     case CYGNUM_CALL_IF_SET_COMM_ID_MANGLER:
         __comm_id = 0;
+        update = 1;
         break;
 
     default:
         __comm_id++;                    // skip mangler entry
+        update = 1;
         break;
     }
-    
-    __selected_id = __comm_id;
-    
-    CYGACC_CALL_IF_DEBUG_PROCS_SET(comm_channels[__comm_id]);
+
+    if (update) {
+        // Find the interrupt state of the channel.
+        __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+        if (__chan)
+            interrupt_state = CYGACC_COMM_IF_CONTROL(*__chan)(CYGACC_COMM_IF_CH_DATA(*__chan), __COMMCTL_IRQ_DISABLE);
+
+        __selected_id = __comm_id;
+        CYGACC_CALL_IF_DEBUG_PROCS_SET(comm_channels[__comm_id]);
 
-    return 1;
+        // Set interrupt state on the new channel.
+        __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+        if (interrupt_state)
+            CYGACC_COMM_IF_CONTROL(*__chan)(CYGACC_COMM_IF_CH_DATA(*__chan), __COMMCTL_IRQ_ENABLE);
+        else
+            CYGACC_COMM_IF_CONTROL(*__chan)(CYGACC_COMM_IF_CH_DATA(*__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_COMM_CHANNELS,
@@ -162,30 +232,37 @@ set_console_comm(int __comm_id)
     switch (__comm_id) {
     case CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT:
         if (__selected_id > 0)
-            return __selected_id-1;
-        if (__selected_id == 0)
-            return CYGNUM_CALL_IF_SET_COMM_ID_MANGLER;
-        return __selected_id;
+            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);
         __selected_id = __comm_id;
-        return 1;
+        break;
 
     case CYGNUM_CALL_IF_SET_COMM_ID_MANGLER:
         __comm_id = 0;
+        update = 1;
         break;
 
     default:
         __comm_id++;                    // skip mangler entry
+        update = 1;
         break;
     }
     
-    __selected_id = __comm_id;
+    if (update) {
+        __selected_id = __comm_id;
     
-    CYGACC_CALL_IF_CONSOLE_PROCS_SET(comm_channels[__comm_id]);
+        CYGACC_CALL_IF_CONSOLE_PROCS_SET(comm_channels[__comm_id]);
+    }
 
-    return 1;
+    CYGARC_HAL_RESTORE_GP();
+    return res;
 }
 
 //----------------------------------
@@ -194,21 +271,25 @@ set_console_comm(int __comm_id)
 static void
 flush_icache(void *__p, int __nbytes)
 {
+    CYGARC_HAL_SAVE_GP();
 #ifdef HAL_ICACHE_FLUSH
     HAL_ICACHE_FLUSH( __p , __nbytes );
 #elif defined(HAL_ICACHE_INVALIDATE)
     HAL_ICACHE_INVALIDATE();
 #endif
+    CYGARC_HAL_RESTORE_GP();
 }
 
 static void
 flush_dcache(void *__p, int __nbytes)
 {
+    CYGARC_HAL_SAVE_GP();
 #ifdef HAL_DCACHE_FLUSH
     HAL_DCACHE_FLUSH( __p , __nbytes );
 #elif defined(HAL_DCACHE_INVALIDATE)
     HAL_DCACHE_INVALIDATE();
 #endif
+    CYGARC_HAL_RESTORE_GP();
 }
 
 #endif
@@ -222,10 +303,10 @@ flush_dcache(void *__p, int __nbytes)
 // routines for that channel. The platform HAL also has the necessary
 // information to determine if the channel is already initialized by
 // a debug agent (either builtin or in ROM).
-void 
+void
 hal_if_diag_init(void)
 {
-#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+#ifdef CYGPRI_HAL_IMPLEMENTS_IF_SERVICES
     cyg_hal_plf_comms_init();
 #endif
 
@@ -249,6 +330,12 @@ hal_if_diag_write_char(char c)
         __chan = CYGACC_CALL_IF_DEBUG_PROCS();
         CYGACC_COMM_IF_PUTC(*__chan)(CYGACC_COMM_IF_CH_DATA(*__chan), c);
     }
+
+    // Check interrupt flag
+    if (CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG()) {
+        cyg_hal_user_break(0);
+        CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
+    }
 }
 
 void 
@@ -265,6 +352,43 @@ hal_if_diag_read_char(char *c)
 }
 #endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
 
+//=============================================================================
+// CtrlC support
+//=============================================================================
+
+#if defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT) \
+    || defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT)
+
+struct Hal_SavedRegisters *hal_saved_interrupt_state;
+
+void
+hal_ctrlc_isr_init(void)
+{
+    hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+
+#if 1 // Prevents crash on older stubs
+    if (CYGNUM_CALL_IF_TABLE_VERSION != CYGACC_CALL_IF_VERSION())
+        return;
+#endif
+
+    CYGACC_COMM_IF_CONTROL(*__chan)(CYGACC_COMM_IF_CH_DATA(*__chan), 
+                                    __COMMCTL_IRQ_ENABLE);
+}
+
+cyg_uint32
+hal_ctrlc_isr(CYG_ADDRWORD vector, CYG_ADDRWORD data)
+{
+    hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+    int isr_ret, ctrlc = 0;
+
+    isr_ret = CYGACC_COMM_IF_DBG_ISR(*__chan)(CYGACC_COMM_IF_CH_DATA(*__chan),
+                                              &ctrlc, vector, data);
+    if (ctrlc)
+        cyg_hal_user_break( (CYG_ADDRWORD *)hal_saved_interrupt_state );
+    return isr_ret;
+}
+#endif // CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT || CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
+
 //--------------------------------------------------------------------------
 // Init function. It should be called from the platform initialization code.
 // For monitor configurations it will initialize the calling interface table,
@@ -298,9 +422,10 @@ hal_if_init(void)
         CYGACC_CALL_IF_ICTRL_TABLE_SET(hal_interrupt_handlers);
         CYGACC_CALL_IF_EXC_TABLE_SET(hal_vsr_table);
 
-        // Reset and kill vector
+        // Miscellaneous services with wrappers in this file.
         CYGACC_CALL_IF_RESET_SET(reset);
         CYGACC_CALL_IF_KILL_VECTOR_SET(kill_by_reset);
+        CYGACC_CALL_IF_DELAY_US_SET(delay_us);
 
         // Comm controls
         CYGACC_CALL_IF_SET_DEBUG_COMM_SET(set_debug_comm);
@@ -310,11 +435,12 @@ hal_if_init(void)
         CYGACC_CALL_IF_FLUSH_ICACHE_SET(flush_icache);
         CYGACC_CALL_IF_FLUSH_DCACHE_SET(flush_dcache);
 
-        // Clear console procs entry. If platform has been configured
-        // to use a separate console port, it will be set up later
-        // (hal_diag_init). Alternatively (if this is a stub) it will
-        // be initialized with the output mangler (O-packetizer for
-        // GDB) which uses the debug comms.
+        // Clear debug and console procs entries. If platform has been
+        // configured to use a separate console port, it will be set
+        // up later (hal_diag_init). Alternatively (if this is a stub)
+        // it will be initialized with the output mangler
+        // (O-packetizer for GDB) which uses the debug comms.
+        set_debug_comm(CYGNUM_CALL_IF_SET_COMM_ID_EMPTY);
         set_console_comm(CYGNUM_CALL_IF_SET_COMM_ID_EMPTY);
 
         // Data entries not currently supported in eCos
@@ -324,6 +450,9 @@ hal_if_init(void)
     }
 #endif
 
+    // Reset console interrupt flag.
+    CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
+
     // Set up services provided by clients
 #if defined(CYGFUN_HAL_COMMON_KERNEL_SUPPORT)   &&  \
     ( defined(CYGSEM_HAL_USE_ROM_MONITOR_GDB_stubs) \