* SEE THE FILE "stop.h" IN THE NINDY MONITOR SOURCE CODE FOR A LIST
* OF STOP CODES.
*
- ******************************************************************************/
+ ***************************************************************************/
#include "defs.h"
#include <signal.h>
#include "ieee-float.h"
#include "wait.h"
-#include <sys/ioctl.h>
#include <sys/file.h>
#include <ctype.h>
-#include "nindy-share/ttycntl.h"
-#include "nindy-share/demux.h"
+#include "serial.h"
#include "nindy-share/env.h"
#include "nindy-share/stop.h"
+#include "dcache.h"
+#include "remote-utils.h"
+
+static DCACHE *nindy_dcache;
+
extern int unlink();
extern char *getenv();
extern char *mktemp();
extern void generic_mourn_inferior ();
extern struct target_ops nindy_ops;
-extern FILE *instream;
+extern GDB_FILE *instream;
extern struct ext_format ext_format_i960; /* i960-tdep.c */
extern char ninStopWhy ();
+extern int ninMemGet ();
+extern int ninMemPut ();
int nindy_initial_brk; /* nonzero if want to send an initial BREAK to nindy */
int nindy_old_protocol; /* nonzero if want to use old protocol */
#define TRUE 1
#define FALSE 0
-int nindy_fd = 0; /* Descriptor for I/O to NINDY */
+/* From nindy-share/nindy.c. */
+extern serial_t nindy_serial;
+
static int have_regs = 0; /* 1 iff regs read since i960 last halted */
static int regs_changed = 0; /* 1 iff regs were modified since last read */
extern char *exists();
-static void
-dcache_flush (), dcache_poke (), dcache_init();
-
-static int
-dcache_fetch ();
-
static void
nindy_fetch_registers PARAMS ((int));
static void
nindy_store_registers PARAMS ((int));
\f
-/* FIXME, we can probably use the normal terminal_inferior stuff here.
- We have to do terminal_inferior and then set up the passthrough
- settings initially. Thereafter, terminal_ours and terminal_inferior
- will automatically swap the settings around for us. */
-
-/* Restore TTY to normal operation */
-
-static TTY_STRUCT orig_tty; /* TTY attributes before entering passthrough */
-
-static void
-restore_tty()
-{
- ioctl( 0, TIOCSETN, &orig_tty );
-}
-
-
-/* Recover from ^Z or ^C while remote process is running */
-
-static void (*old_ctrlc)(); /* Signal handlers before entering passthrough */
-
-#ifdef SIGTSTP
-static void (*old_ctrlz)();
-#endif
-
-static
-#ifdef USG
-void
-#endif
-cleanup()
-{
- restore_tty();
- signal(SIGINT, old_ctrlc);
-#ifdef SIGTSTP
- signal(SIGTSTP, old_ctrlz);
-#endif
- error("\n\nYou may need to reset the 80960 and/or reload your program.\n");
-}
-\f
-/* Clean up anything that needs cleaning when losing control. */
-
static char *savename;
static void
nindy_close (quitting)
int quitting;
{
- if (nindy_fd)
- close (nindy_fd);
- nindy_fd = 0;
+ if (nindy_serial != NULL)
+ SERIAL_CLOSE (nindy_serial);
+ nindy_serial = NULL;
if (savename)
free (savename);
}
/* Open a connection to a remote debugger.
- FIXME, there should be a way to specify the various options that are
- now specified with gdb command-line options. (baud_rate, old_protocol,
- and initial_brk) */
+ FIXME, there should be "set" commands for the options that are
+ now specified with gdb command-line options (old_protocol,
+ and initial_brk). */
void
nindy_open (name, from_tty)
char *name; /* "/dev/ttyXX", "ttyXX", or "XX": tty to be opened */
int from_tty;
{
+ char baudrate[1024];
if (!name)
error_no_arg ("serial port device name");
target_preopen (from_tty);
-
+
nindy_close (0);
- have_regs = regs_changed = 0;
- dcache_init();
+ have_regs = regs_changed = 0;
+ nindy_dcache = dcache_init(ninMemGet, ninMemPut);
- /* Allow user to interrupt the following -- we could hang if
- * there's no NINDY at the other end of the remote tty.
- */
- immediate_quit++;
- nindy_fd = ninConnect( name, baud_rate? baud_rate: "9600",
- nindy_initial_brk, !from_tty, nindy_old_protocol );
- immediate_quit--;
+ /* Allow user to interrupt the following -- we could hang if there's
+ no NINDY at the other end of the remote tty. */
+ immediate_quit++;
+ /* If baud_rate is -1, then ninConnect will not recognize the baud rate
+ and will deal with the situation in a (more or less) reasonable
+ fashion. */
+ sprintf(baudrate, "%d", baud_rate);
+ ninConnect(name, baudrate,
+ nindy_initial_brk, !from_tty, nindy_old_protocol);
+ immediate_quit--;
- if ( nindy_fd < 0 ){
- nindy_fd = 0;
- error( "Can't open tty '%s'", name );
- }
+ if (nindy_serial == NULL)
+ {
+ perror_with_name (name);
+ }
- savename = savestring (name, strlen (name));
- push_target (&nindy_ops);
- target_fetch_registers(-1);
+ savename = savestring (name, strlen (name));
+ push_target (&nindy_ops);
+ target_fetch_registers(-1);
}
/* User-initiated quit of nindy operations. */
static void
nindy_files_info ()
{
- printf("\tAttached to %s at %s bps%s%s.\n", savename,
- baud_rate? baud_rate: "9600",
+ /* FIXME: this lies about the baud rate if we autobauded. */
+ printf_unfiltered("\tAttached to %s at %d bits per second%s%s.\n", savename,
+ baud_rate,
nindy_old_protocol? " in old protocol": "",
nindy_initial_brk? " with initial break": "");
}
/* Tell the remote machine to resume. */
void
-nindy_resume (step, siggnal)
- int step, siggnal;
+nindy_resume (pid, step, siggnal)
+ int pid, step;
+ enum target_signal siggnal;
{
- if (siggnal != 0 && siggnal != stop_signal)
- error ("Can't send signals to remote NINDY targets.");
+ if (siggnal != TARGET_SIGNAL_0 && siggnal != stop_signal)
+ warning ("Can't send signals to remote NINDY targets.");
- dcache_flush();
+ dcache_flush(nindy_dcache);
if ( regs_changed ){
nindy_store_registers (-1);
regs_changed = 0;
have_regs = 0;
ninGo( step );
}
+\f
+/* FIXME, we can probably use the normal terminal_inferior stuff here.
+ We have to do terminal_inferior and then set up the passthrough
+ settings initially. Thereafter, terminal_ours and terminal_inferior
+ will automatically swap the settings around for us. */
+
+struct clean_up_tty_args {
+ serial_ttystate state;
+ serial_t serial;
+};
+
+static void
+clean_up_tty (ptrarg)
+ PTR ptrarg;
+{
+ struct clean_up_tty_args *args = (struct clean_up_tty_args *) ptrarg;
+ SERIAL_SET_TTY_STATE (args->serial, args->state);
+ free (args->state);
+ warning ("\n\n\
+You may need to reset the 80960 and/or reload your program.\n");
+}
/* Wait until the remote machine stops. While waiting, operate in passthrough
- * mode; i.e., pass everything NINDY sends to stdout, and everything from
+ * mode; i.e., pass everything NINDY sends to gdb_stdout, and everything from
* stdin to NINDY.
*
* Return to caller, storing status in 'status' just as `wait' would.
*/
static int
-nindy_wait( status )
- WAITTYPE *status;
+nindy_wait( pid, status )
+ int pid;
+ struct target_waitstatus *status;
{
- DEMUX_DECL; /* OS-dependent data needed by DEMUX... macros */
- char buf[500]; /* FIXME, what is "500" here? */
- int i, n;
- unsigned char stop_exit;
- unsigned char stop_code;
- TTY_STRUCT tty;
- long ip_value, fp_value, sp_value; /* Reg values from stop */
-
-
- WSETEXIT( (*status), 0 );
-
- /* OPERATE IN PASSTHROUGH MODE UNTIL NINDY SENDS A DLE CHARACTER */
-
- /* Save current tty attributes, set up signals to restore them.
- */
- ioctl( 0, TIOCGETP, &orig_tty );
- old_ctrlc = signal( SIGINT, cleanup );
-#ifdef SIGTSTP
- old_ctrlz = signal( SIGTSTP, cleanup );
-#endif
-
- /* Pass input from keyboard to NINDY as it arrives.
- * NINDY will interpret <CR> and perform echo.
- */
- tty = orig_tty;
- TTY_NINDYTERM( tty );
- ioctl( 0, TIOCSETN, &tty );
-
- while ( 1 ){
- /* Go to sleep until there's something for us on either
- * the remote port or stdin.
- */
-
- DEMUX_WAIT( nindy_fd );
-
- /* Pass input through to correct place */
-
- n = DEMUX_READ( 0, buf, sizeof(buf) );
- if ( n ){ /* Input on stdin */
- write( nindy_fd, buf, n );
- }
+ fd_set fds;
+ char buf[500]; /* FIXME, what is "500" here? */
+ int i, n;
+ unsigned char stop_exit;
+ unsigned char stop_code;
+ struct clean_up_tty_args tty_args;
+ struct cleanup *old_cleanups;
+ long ip_value, fp_value, sp_value; /* Reg values from stop */
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+
+ /* OPERATE IN PASSTHROUGH MODE UNTIL NINDY SENDS A DLE CHARACTER */
+
+ /* Save current tty attributes, and restore them when done. */
+ tty_args.serial = SERIAL_FDOPEN (0);
+ tty_args.state = SERIAL_GET_TTY_STATE (tty_args.serial);
+ old_cleanups = make_cleanup (clean_up_tty, &tty_args);
+
+ /* Pass input from keyboard to NINDY as it arrives. NINDY will interpret
+ <CR> and perform echo. */
+ /* This used to set CBREAK and clear ECHO and CRMOD. I hope this is close
+ enough. */
+ SERIAL_RAW (tty_args.serial);
+
+ while (1)
+ {
+ /* Wait for input on either the remote port or stdin. */
+ FD_ZERO (&fds);
+ FD_SET (0, &fds);
+ FD_SET (nindy_serial->fd, &fds);
+ if (select (nindy_serial->fd + 1, &fds, 0, 0, 0) <= 0)
+ continue;
+
+ /* Pass input through to correct place */
+ if (FD_ISSET (0, &fds))
+ {
+ /* Input on stdin */
+ n = read (0, buf, sizeof (buf));
+ if (n)
+ {
+ SERIAL_WRITE (nindy_serial, buf, n );
+ }
+ }
- n = DEMUX_READ( nindy_fd, buf, sizeof(buf) );
- if ( n ){ /* Input on remote */
- /* Write out any characters in buffer preceding DLE */
- i = non_dle( buf, n );
- if ( i > 0 ){
- write( 1, buf, i );
- }
-
- if ( i != n ){
- /* There *was* a DLE in the buffer */
- stop_exit = ninStopWhy( &stop_code,
- &ip_value, &fp_value, &sp_value);
- if ( !stop_exit && (stop_code==STOP_SRQ) ){
- immediate_quit++;
- ninSrq();
- immediate_quit--;
- } else {
- /* Get out of loop */
- supply_register (IP_REGNUM,
- (char *)&ip_value);
- supply_register (FP_REGNUM,
- (char *)&fp_value);
- supply_register (SP_REGNUM,
- (char *)&sp_value);
- break;
- }
- }
+ if (FD_ISSET (nindy_serial->fd, &fds))
+ {
+ /* Input on remote */
+ n = read (nindy_serial->fd, buf, sizeof (buf));
+ if (n)
+ {
+ /* Write out any characters in buffer preceding DLE */
+ i = non_dle( buf, n );
+ if ( i > 0 )
+ {
+ write (1, buf, i);
}
- }
- signal( SIGINT, old_ctrlc );
-#ifdef SIGTSTP
- signal( SIGTSTP, old_ctrlz );
-#endif
- restore_tty();
-
- if ( stop_exit ){ /* User program exited */
- WSETEXIT( (*status), stop_code );
- } else { /* Fault or trace */
- switch (stop_code){
- case STOP_GDB_BPT:
- case TRACE_STEP:
- /* Make it look like a VAX trace trap */
- stop_code = SIGTRAP;
- break;
- default:
- /* The target is not running Unix, and its
- faults/traces do not map nicely into Unix signals.
- Make sure they do not get confused with Unix signals
- by numbering them with values higher than the highest
- legal Unix signal. code in i960_print_fault(),
- called via PRINT_RANDOM_SIGNAL, will interpret the
- value. */
- stop_code += NSIG;
- break;
+ if (i != n)
+ {
+ /* There *was* a DLE in the buffer */
+ stop_exit = ninStopWhy(&stop_code,
+ &ip_value, &fp_value, &sp_value);
+ if (!stop_exit && (stop_code == STOP_SRQ))
+ {
+ immediate_quit++;
+ ninSrq();
+ immediate_quit--;
+ }
+ else
+ {
+ /* Get out of loop */
+ supply_register (IP_REGNUM,
+ (char *)&ip_value);
+ supply_register (FP_REGNUM,
+ (char *)&fp_value);
+ supply_register (SP_REGNUM,
+ (char *)&sp_value);
+ break;
+ }
}
- WSETSTOP( (*status), stop_code );
+ }
}
- return inferior_pid;
+ }
+
+ do_cleanups (old_cleanups);
+
+ if (stop_exit)
+ {
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = stop_code;
+ }
+ else
+ {
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = i960_fault_to_signal (stop_code);
+ }
+ return inferior_pid;
}
/* Read the remote registers into the block REGS. */
ninRegsGet( (char *) &nindy_regs );
immediate_quit--;
- bcopy (nindy_regs.local_regs, ®isters[REGISTER_BYTE (R0_REGNUM)], 16*4);
- bcopy (nindy_regs.global_regs, ®isters[REGISTER_BYTE (G0_REGNUM)], 16*4);
- bcopy (nindy_regs.pcw_acw, ®isters[REGISTER_BYTE (PCW_REGNUM)], 2*4);
- bcopy (nindy_regs.ip, ®isters[REGISTER_BYTE (IP_REGNUM)], 1*4);
- bcopy (nindy_regs.tcw, ®isters[REGISTER_BYTE (TCW_REGNUM)], 1*4);
+ memcpy (®isters[REGISTER_BYTE (R0_REGNUM)], nindy_regs.local_regs, 16*4);
+ memcpy (®isters[REGISTER_BYTE (G0_REGNUM)], nindy_regs.global_regs, 16*4);
+ memcpy (®isters[REGISTER_BYTE (PCW_REGNUM)], nindy_regs.pcw_acw, 2*4);
+ memcpy (®isters[REGISTER_BYTE (IP_REGNUM)], nindy_regs.ip, 1*4);
+ memcpy (®isters[REGISTER_BYTE (TCW_REGNUM)], nindy_regs.tcw, 1*4);
for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) {
dub = unpack_double (builtin_type_double,
&nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)],
int regno;
{
struct nindy_regs nindy_regs;
- int regnum, inv;
+ int regnum;
double dub;
- bcopy (®isters[REGISTER_BYTE (R0_REGNUM)], nindy_regs.local_regs, 16*4);
- bcopy (®isters[REGISTER_BYTE (G0_REGNUM)], nindy_regs.global_regs, 16*4);
- bcopy (®isters[REGISTER_BYTE (PCW_REGNUM)], nindy_regs.pcw_acw, 2*4);
- bcopy (®isters[REGISTER_BYTE (IP_REGNUM)], nindy_regs.ip, 1*4);
- bcopy (®isters[REGISTER_BYTE (TCW_REGNUM)], nindy_regs.tcw, 1*4);
- /* Float regs. Only works on IEEE_FLOAT hosts. FIXME! */
- for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) {
- ieee_extended_to_double (&ext_format_i960,
- ®isters[REGISTER_BYTE (regnum)], &dub);
- /* dub now in host byte order */
- /* FIXME-someday, the arguments to unpack_double are backward.
- It expects a target double and returns a host; we pass the opposite.
- This mostly works but not quite. */
- dub = unpack_double (builtin_type_double, (char *)&dub, &inv);
- /* dub now in target byte order */
- bcopy ((char *)&dub, &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)],
- 8);
- }
+ memcpy (nindy_regs.local_regs, ®isters[REGISTER_BYTE (R0_REGNUM)], 16*4);
+ memcpy (nindy_regs.global_regs, ®isters[REGISTER_BYTE (G0_REGNUM)], 16*4);
+ memcpy (nindy_regs.pcw_acw, ®isters[REGISTER_BYTE (PCW_REGNUM)], 2*4);
+ memcpy (nindy_regs.ip, ®isters[REGISTER_BYTE (IP_REGNUM)], 1*4);
+ memcpy (nindy_regs.tcw, ®isters[REGISTER_BYTE (TCW_REGNUM)], 1*4);
+ for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++)
+ {
+ ieee_extended_to_double (&ext_format_i960,
+ ®isters[REGISTER_BYTE (regnum)], &dub);
+ store_floating (&nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)],
+ REGISTER_VIRTUAL_SIZE (regnum),
+ dub);
+ }
immediate_quit++;
ninRegsPut( (char *) &nindy_regs );
nindy_fetch_word (addr)
CORE_ADDR addr;
{
- return dcache_fetch (addr);
+ return dcache_fetch (nindy_dcache, addr);
}
/* Write a word WORD into remote address ADDR.
CORE_ADDR addr;
int word;
{
- dcache_poke (addr, word);
+ dcache_poke (nindy_dcache, addr, word);
}
/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
/* Copy data to be written over corresponding part of buffer */
- bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+ memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
/* Write the entire buffer. */
}
/* Copy appropriate bytes out of the buffer. */
- bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+ memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
}
return len;
}
\f
-/* The data cache records all the data read from the remote machine
- since the last time it stopped.
-
- Each cache block holds 16 bytes of data
- starting at a multiple-of-16 address. */
-
-#define DCACHE_SIZE 64 /* Number of cache blocks */
-
-struct dcache_block {
- struct dcache_block *next, *last;
- unsigned int addr; /* Address for which data is recorded. */
- int data[4];
-};
-
-struct dcache_block dcache_free, dcache_valid;
-
-/* Free all the data cache blocks, thus discarding all cached data. */
-static
-void
-dcache_flush ()
-{
- register struct dcache_block *db;
-
- while ((db = dcache_valid.next) != &dcache_valid)
- {
- remque (db);
- insque (db, &dcache_free);
- }
-}
-
-/*
- * If addr is present in the dcache, return the address of the block
- * containing it.
- */
-static
-struct dcache_block *
-dcache_hit (addr)
- unsigned int addr;
-{
- register struct dcache_block *db;
-
- if (addr & 3)
- abort ();
-
- /* Search all cache blocks for one that is at this address. */
- db = dcache_valid.next;
- while (db != &dcache_valid)
- {
- if ((addr & 0xfffffff0) == db->addr)
- return db;
- db = db->next;
- }
- return NULL;
-}
-
-/* Return the int data at address ADDR in dcache block DC. */
-static
-int
-dcache_value (db, addr)
- struct dcache_block *db;
- unsigned int addr;
-{
- if (addr & 3)
- abort ();
- return (db->data[(addr>>2)&3]);
-}
-
-/* Get a free cache block, put or keep it on the valid list,
- and return its address. The caller should store into the block
- the address and data that it describes, then remque it from the
- free list and insert it into the valid list. This procedure
- prevents errors from creeping in if a ninMemGet is interrupted
- (which used to put garbage blocks in the valid list...). */
-static
-struct dcache_block *
-dcache_alloc ()
-{
- register struct dcache_block *db;
-
- if ((db = dcache_free.next) == &dcache_free)
- {
- /* If we can't get one from the free list, take last valid and put
- it on the free list. */
- db = dcache_valid.last;
- remque (db);
- insque (db, &dcache_free);
- }
-
- remque (db);
- insque (db, &dcache_valid);
- return (db);
-}
-
-/* Return the contents of the word at address ADDR in the remote machine,
- using the data cache. */
-static
-int
-dcache_fetch (addr)
- CORE_ADDR addr;
-{
- register struct dcache_block *db;
-
- db = dcache_hit (addr);
- if (db == 0)
- {
- db = dcache_alloc ();
- immediate_quit++;
- ninMemGet(addr & ~0xf, (unsigned char *)db->data, 16);
- immediate_quit--;
- db->addr = addr & ~0xf;
- remque (db); /* Off the free list */
- insque (db, &dcache_valid); /* On the valid list */
- }
- return (dcache_value (db, addr));
-}
-
-/* Write the word at ADDR both in the data cache and in the remote machine. */
-static void
-dcache_poke (addr, data)
- CORE_ADDR addr;
- int data;
-{
- register struct dcache_block *db;
-
- /* First make sure the word is IN the cache. DB is its cache block. */
- db = dcache_hit (addr);
- if (db == 0)
- {
- db = dcache_alloc ();
- immediate_quit++;
- ninMemGet(addr & ~0xf, (unsigned char *)db->data, 16);
- immediate_quit--;
- db->addr = addr & ~0xf;
- remque (db); /* Off the free list */
- insque (db, &dcache_valid); /* On the valid list */
- }
-
- /* Modify the word in the cache. */
- db->data[(addr>>2)&3] = data;
-
- /* Send the changed word. */
- immediate_quit++;
- ninMemPut(addr, (unsigned char *)&data, 4);
- immediate_quit--;
-}
-
-/* The cache itself. */
-struct dcache_block the_cache[DCACHE_SIZE];
-
-/* Initialize the data cache. */
-static void
-dcache_init ()
-{
- register i;
- register struct dcache_block *db;
-
- db = the_cache;
- dcache_free.next = dcache_free.last = &dcache_free;
- dcache_valid.next = dcache_valid.last = &dcache_valid;
- for (i=0;i<DCACHE_SIZE;i++,db++)
- insque (db, &dcache_free);
-}
-
-
static void
nindy_create_inferior (execfile, args, env)
char *execfile;
pid = 42;
-#ifdef CREATE_INFERIOR_HOOK
- CREATE_INFERIOR_HOOK (pid);
-#endif
-
-/* The "process" (board) is already stopped awaiting our commands, and
- the program is already downloaded. We just set its PC and go. */
+ /* The "process" (board) is already stopped awaiting our commands, and
+ the program is already downloaded. We just set its PC and go. */
inferior_pid = pid; /* Needed for wait_for_inferior below */
target_terminal_inferior ();
/* insert_step_breakpoint (); FIXME, do we need this? */
- proceed ((CORE_ADDR)entry_pt, -1, 0); /* Let 'er rip... */
+ /* Let 'er rip... */
+ proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0);
}
static void
char *args;
int from_tty;
{
- if ( !nindy_fd ){
- error( "No target system to reset -- use 'target nindy' command.");
- }
- if ( query("Really reset the target system?",0,0) ){
- send_break( nindy_fd );
- tty_flush( nindy_fd );
- }
+ if (nindy_serial == NULL)
+ {
+ error( "No target system to reset -- use 'target nindy' command.");
+ }
+ if ( query("Really reset the target system?",0,0) )
+ {
+ SERIAL_SEND_BREAK (nindy_serial);
+ tty_flush (nindy_serial);
+ }
}
void
while (current_target != &nindy_ops) { /* remote tty not specified yet */
if ( instream == stdin ){
- printf("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit: ");
- fflush( stdout );
+ printf_unfiltered("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit: ");
+ gdb_flush( gdb_stdout );
}
fgets( ttyname, sizeof(ttyname)-1, stdin );