This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

synthetic target HAL changes


Here are the changes to the synthetic target architectural HAL,
target-side code. There are also large changes to the documentation
and a completely new host subdirectory, but for details of those it is
best to use CVS.

A brief summary is:

1) new configuration option CYGIMP_HAL_IDLE_THREAD_SPIN, sometimes
   useful in conjunction with the synthetic watchdog device

2) new functions synth_auxiliary_instantiate() and
   synth_auxiliary_xchgmsg() for interacting with the I/O
   auxiliary

3) updated startup code to fork/exec the I/O auxiliary if the eCos
   application is run with a --io option. This also required some
   new system calls, #define's, etc

4) updated diagnostic console support, to use the I/O auxiliary if
   that is being used
   
Bart

Index: hal_synth.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/arch/current/cdl/hal_synth.cdl,v
retrieving revision 1.3
diff -u -u -r1.3 hal_synth.cdl
--- hal_synth.cdl	23 May 2002 23:05:25 -0000	1.3
+++ hal_synth.cdl	15 Sep 2002 16:55:49 -0000
@@ -98,9 +98,29 @@
         cdl_option CYGNUM_HAL_RTC_PERIOD {
             display       "Real-time clock period"
             flavor        data
-           calculated     10000
+            calculated    10000
         }
     }
+    # What to do when idling
+    cdl_option CYGIMP_HAL_IDLE_THREAD_SPIN {
+	display	"Spin when idle"
+	default_value	CYGIMP_IDLE_THREAD_YIELD
+	description "
+            By default, whenever the eCos application enters the idle thread
+            the synthetic target HAL will make a select() system call. Effectively
+            this causes the application to block until an interrupt occurs,
+            without consuming any cpu resources, as if the hardware supported
+            some sort of IDLE instruction. Usually this behaviour is desirable.
+            However it interferes with the emulation of some hardware. For
+            example the synthetic watchdog timer device can use consumed cpu time
+            rather than wallclock time to determine whether or not the watchdog
+            has triggered, and if the process is spending nearly all its time
+            blocked in select() then the watchdog will not trigger when it should.
+            There are also some kernel configurations which require that the idle
+            thread does not block."
+    }
+    requires	  { CYGIMP_IDLE_THREAD_YIELD implies CYGIMP_HAL_IDLE_THREAD_SPIN }
+    
     cdl_option CYGBLD_LINKER_SCRIPT {
         display "Linker script"
         flavor data
Index: hal_io.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/arch/current/include/hal_io.h,v
retrieving revision 1.6
diff -u -u -r1.6 hal_io.h
--- hal_io.h	4 Aug 2002 23:19:07 -0000	1.6
+++ hal_io.h	15 Sep 2002 16:56:17 -0000
@@ -199,17 +200,33 @@
 #define CYG_HAL_SYS_SIGINT               2
 #define CYG_HAL_SYS_SIGQUIT              3
 #define CYG_HAL_SYS_SIGILL               4
+#define CYG_HAL_SYS_SIGTRAP              5
+#define CYG_HAL_SYS_SIGABRT              6
 #define CYG_HAL_SYS_SIGBUS               7
 #define CYG_HAL_SYS_SIGFPE               8
+#define CYG_HAL_SYS_SIGKILL              9
+#define CYG_HAL_SYS_SIGUSR1             10
 #define CYG_HAL_SYS_SIGSEGV             11
+#define CYG_HAL_SYS_SIGUSR2             12
 #define CYG_HAL_SYS_SIGPIPE             13
 #define CYG_HAL_SYS_SIGALRM             14
 #define CYG_HAL_SYS_SIGTERM             15
+#define CYG_HAL_SYS_SIGSTKFLT           16
 #define CYG_HAL_SYS_SIGCHLD             17
 #define CYG_HAL_SYS_SIGCONT             18
 #define CYG_HAL_SYS_SIGSTOP             19
 #define CYG_HAL_SYS_SIGTSTP             20
+#define CYG_HAL_SYS_SIGTTIN             21
+#define CYG_HAL_SYS_SIGTTOU             22
+#define CYG_HAL_SYS_SIGURG              23
+#define CYG_HAL_SYS_SIGXCPU             24
+#define CYG_HAL_SYS_SIGXFSZ             25
+#define CYG_HAL_SYS_SIGVTALRM           26
+#define CYG_HAL_SYS_SIGPROF             27
+#define CYG_HAL_SYS_SIGWINCH            28
 #define CYG_HAL_SYS_SIGIO               29
+#define CYG_HAL_SYS_SIGPWR              30
+#define CYG_HAL_SYS_SIGSYS              31
 
 #define CYG_HAL_SYS_SA_NOCLDSTOP        0x00000001
 #define CYG_HAL_SYS_SA_NOCLDWAIT        0x00000002
@@ -317,6 +334,13 @@
     struct cyg_hal_sys_timeval  hal_it_value;
 };
 
+// System calls and related constants, or rather the subset that is
+// needed internally.
+#define CYG_HAL_SYS_R_OK    0x04
+#define CYG_HAL_SYS_W_OK    0x02
+#define CYG_HAL_SYS_X_OK    0x01
+#define CYG_HAL_SYS_F_OK    0x00
+
 /* lseek whence flags */
 #define CYG_HAL_SYS_SEEK_SET        0       /* Seek from beginning of file.  */
 #define CYG_HAL_SYS_SEEK_CUR        1       /* Seek from current position.  */
@@ -399,6 +423,13 @@
 externC int             cyg_hal_sys_gettimeofday(struct cyg_hal_sys_timeval*,
                                                  struct cyg_hal_sys_timezone*);
 
+externC int             cyg_hal_sys_access(const char*, int);
+externC int             cyg_hal_sys_fork(void);
+externC int             cyg_hal_sys_execve(const char*, const char* [], const char* []);
+externC int             cyg_hal_sys_pipe(int []);
+externC int             cyg_hal_sys_close(int);
+externC int             cyg_hal_sys_dup2(int, int);
+ 
 // The actual implementation appears to return the new brk() value.
 externC void*           cyg_hal_sys_brk(void*);
 
@@ -416,8 +447,35 @@
 
 // ----------------------------------------------------------------------------
 // Interaction between the application and the auxiliary.
-// Not yet available, but there is a hardware-initialization routine.
-externC void hal_synthetic_target_init(void);
+
+// Is the  auxiliary actually in use/available? This flag should be tested by
+// device drivers prior to attempting any communication with the auxiliary.
+extern cyg_bool synth_auxiliary_running;
+ 
+// The fundamental I/O operation: sending a request to the auxiliary and
+// optionally getting back a reply. A null pointer for the response field
+// indicates that no reply is expected. 
+externC void synth_auxiliary_xchgmsg(int /* devid */, int /* request */,
+                                     int /* arg1  */, int /* arg2 */,
+                                     const unsigned char* /* txdata */, int /* txlen */,
+                                     int* /* response */,
+                                     unsigned char* /* rxdata */,  int* /* actual_rxlen */,
+                                     int /* rxlen */);
+
+// Request that the auxiliary instantiates a given device, loading appropriate
+// support code as required. This function takes the following arguments:
+// 1) the location of the package that should provide this device, e.g.
+//    devs/eth/synth
+// 2) the version of that package currently being used, e.g. "current"
+// 3) the name of the device, e.g. "ethernet". This identifies the
+//    Tcl script that should be loaded to handle requests for this device.
+// 4) the name of the device instance, e.g. "eth0".
+// 5) device-specific initialization data. 
+externC int  synth_auxiliary_instantiate(const char*, const char*, const char*, const char*, const char*);
+
+// Support for generating strings
+#define SYNTH_MAKESTRING1(a) #a
+#define SYNTH_MAKESTRING(a)  SYNTH_MAKESTRING1(a)
  
 //-----------------------------------------------------------------------------
 #endif // ifndef CYGONCE_HAL_HAL_IO_H
Index: synth_entry.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/arch/current/src/synth_entry.c,v
retrieving revision 1.3
diff -u -u -r1.3 synth_entry.c
--- synth_entry.c	23 May 2002 23:05:28 -0000	1.3
+++ synth_entry.c	15 Sep 2002 16:57:02 -0000
@@ -99,6 +100,8 @@
 // startup.
 
 externC void    cyg_start( void );
+externC void    synth_hardware_init(void);
+externC void    synth_hardware_init2(void);
 
 void _linux_entry( void )
 {
@@ -135,9 +138,9 @@
     // "Initialize any global pointer register". There is no such register.
 
     // Perform platform-specific initialization. Actually, all Linux
-    // platforms can share this. It involves setting up signal handlers
-    // and so on.
-    hal_synthetic_target_init();
+    // platforms can share this. It involves setting up signal handlers,
+    // starting the I/O auxiliary, and so on.
+    synth_hardware_init();
 
     // This is not a ROM startup, so no need to worry about copying the
     // .data section.
@@ -149,6 +152,14 @@
     // Invoke the C++ constructors.
     cyg_hal_invoke_constructors();
 
+    // Once the C++ constructors have been invoked, a second stage
+    // of hardware initialization is desirable. At this point all
+    // eCos device drivers should have been initialized so the
+    // I/O auxiliary will have loaded the appropriate support
+    // scripts, and the auxiliary can now map the window(s) on to
+    // the display and generally operate normally.
+    synth_hardware_init2();
+    
     // "Call cyg_start()". OK.
     cyg_start();
 
Index: synth_intr.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/arch/current/src/synth_intr.c,v
retrieving revision 1.3
diff -u -u -r1.3 synth_intr.c
--- synth_intr.c	23 May 2002 23:05:28 -0000	1.3
+++ synth_intr.c	15 Sep 2002 16:57:47 -0000
@@ -50,32 +51,34 @@
 // sigprocmask handling.
 //
 // In the synthetic target interrupts and exceptions are based around
-// POSIX sighandlerals. When the clock ticks a SIGALRM signal is raised.
+// POSIX sighandlers. When the clock ticks a SIGALRM signal is raised.
 // When the I/O auxiliary wants to raise some other interrupt, it
 // sends a SIGIO signal. When an exception occurs this results in
 // signals like SIGILL and SIGSEGV. This implies an implementation
-// where the VSR is the signal handler. Disabling interrupts then
-// means using sigprocmask() to block certain signals, and enabling
-// interrupts means unblocking those signals.
+// where the VSR is the signal handler. Disabling interrupts would
+// then mean using sigprocmask() to block certain signals, and
+// enabling interrupts means unblocking those signals.
 //
 // However there are a few problems. One of these is performance: some
 // bits of the system such as buffered tracing make very extensive use
 // of enabling and disabling interrupts, so making a sigprocmask
 // system call each time adds a lot of overhead. More seriously, there
 // is a subtle discrepancy between POSIX signal handling and hardware
-// interrupts. It is expected that signal handlers return, and then
-// the system automatically passes control back to the foreground thread.
+// interrupts. Signal handlers are expected to return, and then the
+// system automatically passes control back to the foreground thread.
 // In the process, the sigprocmask is manipulated before invoking the
 // signal handler and restored afterwards. Interrupt handlers are
 // different: it is quite likely that an interrupt results in another
-// eCos thread being activated, so the signal handler does not actually
-// return until the interrupted thread gets another chance to run.
+// eCos thread being activated, so the signal handler does not
+// actually return until the interrupted thread gets another chance to
+// run. 
 //
-// The second problem can be addressed by making the sigprocmask part of
-// the thread state, saving and restoring it as part of a context switch.
-// This matches quite nicely onto typical real hardware, where there might
-// be a flag inside some control register that controls whether or not
-// interrupts are enabled. However this adds further to the overhead.
+// The second problem can be addressed by making the sigprocmask part
+// of the thread state, saving and restoring it as part of a context
+// switch (c.f. siglongjmp()). This matches quite nicely onto typical
+// real hardware, where there might be a flag inside some control
+// register that controls whether or not interrupts are enabled.
+// However this adds more system calls to context switch overhead.
 //
 // The alternative approach is to implement interrupt enabling and
 // disabling in software. The sigprocmask is manipulated only once,
@@ -93,14 +96,14 @@
 // interrupts. This is not currently implemented.
 //
 // At first glance it might seem that an interrupt stack could be
-// implemented trivially using sigaltstack. This does not quite work.
-// The problem is that signal handlers do not always return
-// immediately, so the system does not get a chance to clean up the
-// signal handling stack. A separate interrupt stack is possible but
-// would have to be implemented here, in software, e.g. by having the
-// signal handler invoke the VSR on that stack. Unfort
-    // are still pending.
+    // are still pending. The ISR should have either acknowledged or
+    // masked the current interrupt source, to prevent a recursive
+    // call for the current interrupt.
     hal_enable_interrupts();
 
     // Now call interrupt_end() with the result of the isr and the
@@ -225,7 +240,7 @@
     // a context switch to another thread. In the latter case, when
     // the current thread is reactivated we end up back here. The
     // third argument should be a pointer to the saved state, but that
-    // is only relevant for thread-aware debugging which is not
+    // is only relevant for thread-aware debugging which is not yet
     // supported by the synthetic target.
     {
         extern void interrupt_end(cyg_uint32, CYG_ADDRESS, HAL_SavedRegisters*);
@@ -238,7 +253,7 @@
 
 // Enabling interrupts. If a SIGALRM or SIGIO arrived at an inconvenient
 // time, e.g. when already interacting with the auxiliary, then these
-// will have been left pending and must be servied now. Next, enabling
+// will have been left pending and must be serviced now. Next, enabling
 // interrupts means checking the interrupt pending and mask registers
 // and seeing if the VSR should be invoked.
 void
@@ -262,7 +277,7 @@
     // is to raise a signal, e.g. SIGUSR1. That way all interrupts
     // come in via the system's signal handling mechanism, and
     // it might be possible to do something useful with saved contexts
-    // etc.
+    // etc., facilitating thread-aware debugging.
     if (0 != (synth_pending_isrs & ~synth_masked_isrs)) {
         hal_interrupts_enabled = false;
         (*synth_VSR)();
@@ -457,11 +472,12 @@
 // 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 it is necessary to use gettimeofday(). 
+// 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 };
 
@@ -470,7 +486,8 @@
 {
     struct cyg_hal_sys_itimerval    timer;
 
-    // Needed for hal_clock_read()
+    // 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
@@ -508,7 +525,8 @@
     // 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
+    // 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 {
@@ -548,6 +566,22 @@
 // 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

+                        } while ('\0' != filename[i]);
+                    }
+                }
+            }
+        } while(found_dotdot);
+        
+        cyg_hal_sys_argv[0] = filename;
+
+        for (i = 1; i < cyg_hal_sys_argc; i++) {
+            const char* tmp = cyg_hal_sys_argv[i];
+            if (('-' == tmp[0]) && ('-' == tmp[1]) && ('\0' == tmp[2])) {
+                cyg_hal_sys_argv[i] = (const char*) 0;
+                break;
+            }
+        }
+        cyg_hal_sys_execve(filename, cyg_hal_sys_argv, cyg_hal_sys_environ);
+
+        // An execute error has occurred. Report this here, then exit. The
+        // parent will detect a close on the pipe without having received
+        // any data, and it will assume that a suitable diagnostic will have
+        // been displayed already.
+        diag_printf("Error: failed to execute the I/O auxiliary.\n");
+        cyg_hal_sys_exit(1);
+    } else {
+        int     rc;
+        char    buf[1];
+        
+        // Still executing the eCos application.
+        // Do some cleaning-up.
+        to_aux      = to_aux_pipe[1];
+        from_aux    = from_aux_pipe[0];
+        if ((0 != cyg_hal_sys_close(to_aux_pipe[0]))  ||
+            (0 != cyg_hal_sys_close(from_aux_pipe[1]))) {
+            diag_printf("Error: internal error in main process, failed to manipulate pipes.\n");
+            cyg_hal_sys_exit(1);
+        }
+
+        // It is now a good idea to block until the auxiliary is
+        // ready, i.e. give it a chance to read in its configuration
+        // files, load appropriate scripts, pop up windows, ... This
+        // may take a couple of seconds or so. Once the auxiliary is
+        // ready it will write a single byte down the pipe. This is
+        // the only time that the auxiliary will write other than when
+        // responding to a request.
+        do {
+            rc = cyg_hal_sys_read(from_aux, buf, 1);
+        } while (-CYG_HAL_SYS_EINTR == rc);
+
+        if (1 != rc) {
+            // The auxiliary has not started up successfully, so exit
+            // immediately. It should have generated appropriate
+            // diagnostics.
+            cyg_hal_sys_exit(1);
+        }
+    }
+
+    // At this point the auxiliary is up and running. It should not
+    // generate any interrupts just yet since none of the devices have
+    // been initialized. Remember that the auxiliary is now running,
+    // so that the initialization routines for those devices can
+    // figure out that they should interact with the auxiliary rather
+    // than attempt anything manually.
+    synth_auxiliary_running   = true;
+
+    // Make sure that the auxiliary is the right version.
+    synth_auxiliary_xchgmsg(SYNTH_DEV_AUXILIARY, SYNTH_AUXREQ_GET_VERSION, 0, 0,
+                            (const unsigned char*) 0, 0,
+                            &aux_version, (unsigned char*) 0, (int*) 0, 0);
+    if (SYNTH_AUXILIARY_PROTOCOL_VERSION != aux_version) {
+        synth_auxiliary_running = false;
+        diag_printf("Error: an incorrect version of the I/O auxiliary is installed\n"
+                    "    Expected version %d, actual version %d\n"
+                    "    Installed binary is %s\n",
+                    SYNTH_AUXILIARY_PROTOCOL_VERSION, aux_version, filename);
+        cyg_hal_sys_exit(1);
+    }
+}
+
+// Write a request to the I/O auxiliary, and optionally get back a
+// reply. The dev_id is 0 for messages intended for the auxiliary
+// itself, for example a device instantiation or a request for the
+// current interrupt sate. Otherwise it identifies a specific device.
+// The request code is specific to the device, and the two optional
+// arguments are specific to the request.
+void
+synth_auxiliary_xchgmsg(int devid, int reqcode, int arg1, int arg2,
+                        const unsigned char* txdata, int txlen,
+                        int* result, 
+                        unsigned char* rxdata, int* actual_rxlen, int rxlen)
+{
+    unsigned char   request[SYNTH_REQUEST_LENGTH];
+    unsigned char   reply
-// select. The itimer will still go off and kick the scheduler back
-// into life so giving up 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.
-void
-hal_idle_thread_action(cyg_uint32 loop_count)
-{
-#ifndef CYGIMP_IDLE_THREAD_YIELD
-    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);
-}
-// ----------------------------------------------------------------------------
 // Initialization
 
 void
-hal_synthetic_target_init(void)
+synth_hardware_init(void)
 {
     struct cyg_hal_sys_sigaction action;
     struct cyg_hal_sys_sigset_t  blocked;
@@ -676,8 +1287,8 @@
         CYG_FAIL("Failed to install signal handler for SIGIO");
     }
 
-    // Now install handlers for the various exceptions. For now these
-    // also operate with unchanged sigprocmasks, allowing nested
+    // Install handlers for the various exceptions. For now these also
+    // operate with unchanged sigprocmasks, allowing nested
     // exceptions. It is not clear that this is entirely a good idea,
     // but in practice these exceptions will usually be handled by gdb
     // anyway.
@@ -704,13 +1315,45 @@
         CYG_FAIL("Failed to install signal handler for SIGPIPE");
     }
     action.hal_handler = &synth_chld_sighandler;
+    action.hal_flags  |= CYG_HAL_SYS_SA_NOCLDSTOP | CYG_HAL_SYS_SA_NOCLDWAIT;
     if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGCHLD,  &action, (struct cyg_hal_sys_sigaction*) 0)) {
         CYG_FAIL("Failed to install signal handler for SIGCHLD");
     }
+
+    // Start up the auxiliary process.
+    synth_start_auxiliary();
     
     // All done. At this stage interrupts are still disabled, no ISRs
     // have been installed, and the clock is not yet ticking.
     // Exceptions can come in and will be processed normally. SIGIO
     // and SIGALRM could come in, but nothing has yet been done
     // to make that happen.
+}
+
+// Second-stage hardware init. This is called after all C++ static
+// constructors have been run, which should mean that all device
+// drivers have been initialized and will have performed appropriate
+// interactions with the I/O auxiliary. There should now be a
+// message exchange with the auxiliary to let it know that there will
+// not be any more devices, allowing it to remove unwanted frames,
+// run the user's mainrc.tcl script, and so on. Also this is the
+// time that the various toplevels get mapped on to the display.
+//
+// This request blocks until the auxiliary is ready. The return value
+// indicates whether or not any errors occurred on the auxiliary side,
+// and that those errors have not been suppressed using --keep-going
+
+void
+synth_hardware_init2(void)
+{
+    if (synth_auxiliary_running) {
+        int result;
+        synth_auxiliary_xchgmsg(SYNTH_DEV_AUXILIARY, SYNTH_AUXREQ_CONSTRUCTORS_DONE,
+                               0, 0, (const unsigned char*) 0, 0,
+                               &result,
+                               (unsigned char*) 0, (int*) 0, 0);
+        if ( !result ) {
+            cyg_hal_sys_exit(1);
+        }
+    }
 }
Index: synth_diag.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/arch/current/src/synth_diag.c,v
retrieving revision 1.3
diff -u -u -r1.3 synth_diag.c
--- synth_diag.c	23 May 2002 23:05:28 -0000	1.3
+++ synth_diag.c	15 Sep 2002 16:56:41 -0000
@@ -65,17 +66,25 @@
 #include <cyg/infra/cyg_ass.h>
 
 //-----------------------------------------------------------------------------
+// If the auxiliary exists, hal_diag_init() will try to contact it and
+// instantiate a console device. Subsequent console writes will be
+// redirected to that device, as long as the auxiliary is up and running.
+// If the auxiliary is not being used or has exited, console writes
+// will instead go to stdout.
+//
+// This code also contains an implementation of hal_diag_read_char()
+// which is probably not very useful. Currently it works by reading
+// from stdin, but no attempt is made to set the tty into raw mode
+// or anything like that. 
 
-// When the auxiliary exists, hal_diag_init() will need to contact it and
-// get hold of a suitable console device.
-//
-// When interacting with stdin/stdout, arguably there should be some
-// manipulation of tty settings e.g. to support single character
-// input. However it is not clear which settings would be preferable
-// to the default.
+static int auxiliary_console_id = -1;
 
 void hal_diag_init( void )
 {
+    if (synth_auxiliary_running) {
+        auxiliary_console_id = synth_auxiliary_instantiate("hal/synth/arch", SYNTH_MAKESTRING(CYGPKG_HAL_SYNTH), "console",
+                                                      (const char*) 0, (const char*) 0);
+    }
 }
 
 // Output a single character.
@@ -86,39 +95,53 @@
 // I/O intensive facilities like unbuffered tracing). Therefore
 // this code will buffer lines up to 128 characters before
 // doing the I/O.
+//
+// NOTE: one problem is that there is no support for flushing buffers
+// at this level. Therefore if say C library stdio ends up mapped to
+// HAL diagnostics I/O then functions like fflush() and setvbuf() will
+// not behave the way they should. There is no simple workaround at
+// this level, the required information is not available.
 
 void hal_diag_write_char(char c)
 {
     static int  diag_index = 0;
-    static char diag_buffer[128];
+    static unsigned char diag_buffer[128];
 
     CYG_ASSERT(diag_index < 128, "Diagnostic buffer overflow");
     
-    diag_buffer[diag_index++] = c;
+    diag_buffer[diag_index++] = (unsigned char) c;
     if (('\n' == c) || (128 == diag_index)) {
-        int     written;
-        char*   next    = diag_buffer;
-
-        while (diag_index > 0) {
-            written = cyg_hal_sys_write(1, next, diag_index);
-            if (written > 0) {
-                diag_index -= written;
-                next       += written;
-            } else if ((-CYG_HAL_SYS_EINTR != written) && (-CYG_HAL_SYS_EAGAIN != written)) {
-                CYG_FAIL("Unexpected error writing to stdout.");
-                diag_index = 0;
-                break;
+        if ((-1 != auxiliary_console_id) && synth_auxiliary_running) {
+            synth_auxiliary_xchgmsg(auxiliary_console_id, 0, 0, 0, diag_buffer, diag_index, (int *) 0, (unsigned char*) 0, (int *)0, 0);
+            diag_index = 0;
+        } else {
+            int     written;
+            char*   next    = diag_buffer;
+
+            while (diag_index > 0) {
+                written = cyg_hal_sys_write(1, next, diag_index);
+                if (written > 0) {
+                    diag_index -= written;
+                    next       += written;
+                } else if ((-CYG_HAL_SYS_EINTR != written) && (-CYG_HAL_SYS_EAGAIN != written)) {
+                    CYG_FAIL("Unexpected error writing to stdout.");
+                    diag_index = 0;
+                    break;
+                }
             }
+            CYG_ASSERT(0 == diag_index, "All data should have been written out");
+            diag_index = 0;
+            cyg_hal_sys_fdatasync(1);
         }
-        CYG_ASSERT(0 == diag_index, "All data should have been written out");
-        diag_index = 0;
-        cyg_hal_sys_fdatasync(1);
     }
 }
 
-// Diagnostic input. It is not clear that this is actually useful. The
-// read syscall will get woken up by the itimer alarm, but we don't
-// want to stop reading if that's the case
+// Diagnostic input. It is not clear that this is actually useful,
+// input would normally go to gdb rather than to the application. If
+// keyboard input really is required then that should be handled via a
+// suitable device driver interacting with the auxiliary, not at the
+// HAL level. The read syscall will get woken up by the itimer alarm,
+// but we don't want to stop reading if that's the case
 
 void hal_diag_read_char(char *c)
 {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]