This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
synthetic target HAL changes
- From: Bart Veer <bartv at ecoscentric dot com>
- To: ecos-patches at sources dot redhat dot com
- Date: Sun, 15 Sep 2002 18:06:25 +0100 (BST)
- Subject: 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)
{