#include "defs.h"
#include <signal.h>
#include <sys/types.h>
#include <setjmp.h>
#include "frame.h"
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
#include "target.h"
#include "gdbcore.h"
#include "command.h"
#include "floatformat.h"
#include "regcache.h"
#include <sys/file.h>
#include <ctype.h>
#include "serial.h"
#include "nindy-share/env.h"
#include "nindy-share/stop.h"
#include "remote-utils.h"
extern int unlink ();
extern char *getenv ();
extern char *mktemp ();
extern void generic_mourn_inferior ();
extern struct target_ops nindy_ops;
extern FILE *instream;
extern char ninStopWhy ();
extern int ninMemGet ();
extern int ninMemPut ();
int nindy_initial_brk;
int nindy_old_protocol;
char *nindy_ttyname;
#define DLE '\020'
#define TRUE 1
#define FALSE 0
extern struct serial *nindy_serial;
static int have_regs = 0;
static int regs_changed = 0;
extern char *exists ();
static void nindy_fetch_registers (int);
static void nindy_store_registers (int);
static char *savename;
static void
nindy_close (int quitting)
{
if (nindy_serial != NULL)
serial_close (nindy_serial);
nindy_serial = NULL;
if (savename)
xfree (savename);
savename = 0;
}
void
nindy_open (char *name,
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;
immediate_quit++;
sprintf (baudrate, "%d", baud_rate);
ninConnect (name, baudrate,
nindy_initial_brk, !from_tty, nindy_old_protocol);
immediate_quit--;
if (nindy_serial == NULL)
{
perror_with_name (name);
}
savename = savestring (name, strlen (name));
push_target (&nindy_ops);
target_fetch_registers (-1);
init_thread_list ();
init_wait_for_inferior ();
clear_proceed_status ();
normal_stop ();
}
static void
nindy_detach (char *name, int from_tty)
{
if (name)
error ("Too many arguments");
pop_target ();
}
static void
nindy_files_info (void)
{
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" : "");
}
static
int
non_dle (char *buf, int n)
{
int i;
for (i = 0; i < n; i++)
{
if (buf[i] == DLE)
{
break;
}
}
return i;
}
void
nindy_resume (ptid_t ptid, int step, enum target_signal siggnal)
{
if (siggnal != TARGET_SIGNAL_0 && siggnal != stop_signal)
warning ("Can't send signals to remote NINDY targets.");
if (regs_changed)
{
nindy_store_registers (-1);
regs_changed = 0;
}
have_regs = 0;
ninGo (step);
}
struct clean_up_tty_args
{
serial_ttystate state;
struct serial *serial;
};
static struct clean_up_tty_args tty_args;
static void
clean_up_tty (PTR ptrarg)
{
struct clean_up_tty_args *args = (struct clean_up_tty_args *) ptrarg;
serial_set_tty_state (args->serial, args->state);
xfree (args->state);
warning ("\n\nYou may need to reset the 80960 and/or reload your program.\n");
}
static void (*old_ctrlc) ();
#ifdef SIGTSTP
static void (*old_ctrlz) ();
#endif
static void
clean_up_int (void)
{
serial_set_tty_state (tty_args.serial, tty_args.state);
xfree (tty_args.state);
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");
}
static ptid_t
nindy_wait (ptid_t ptid, struct target_waitstatus *status)
{
fd_set fds;
int c;
char buf[2];
int i, n;
unsigned char stop_exit;
unsigned char stop_code;
struct cleanup *old_cleanups;
long ip_value, fp_value, sp_value;
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
tty_args.serial = serial_fdopen (0);
tty_args.state = serial_get_tty_state (tty_args.serial);
old_ctrlc = signal (SIGINT, clean_up_int);
#ifdef SIGTSTP
old_ctrlz = signal (SIGTSTP, clean_up_int);
#endif
old_cleanups = make_cleanup (clean_up_tty, &tty_args);
serial_raw (tty_args.serial);
while (1)
{
c = serial_readchar (nindy_serial, -1);
if (c == SERIAL_ERROR)
{
error ("Cannot read from serial line");
}
else if (c == 0x1b)
{
c = serial_readchar (nindy_serial, -1);
c &= ~0x40;
}
else if (c != 0x10)
{
buf[0] = (char) c;
write (1, buf, 1);
}
else
{
stop_exit = ninStopWhy (&stop_code,
&ip_value, &fp_value, &sp_value);
if (!stop_exit && (stop_code == STOP_SRQ))
{
immediate_quit++;
ninSrq ();
immediate_quit--;
}
else
{
supply_register (IP_REGNUM,
(char *) &ip_value);
supply_register (FP_REGNUM,
(char *) &fp_value);
supply_register (SP_REGNUM,
(char *) &sp_value);
break;
}
}
}
serial_set_tty_state (tty_args.serial, tty_args.state);
xfree (tty_args.state);
discard_cleanups (old_cleanups);
if (stop_exit)
{
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = stop_code;
}
else
{
if (stop_code == STOP_GDB_BPT)
stop_code = TRACE_STEP;
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = i960_fault_to_signal (stop_code);
}
return inferior_ptid;
}
struct nindy_regs
{
char local_regs[16 * 4];
char global_regs[16 * 4];
char pcw_acw[2 * 4];
char ip[4];
char tcw[4];
char fp_as_double[4 * 8];
};
static void
nindy_fetch_registers (int regno)
{
struct nindy_regs nindy_regs;
int regnum;
immediate_quit++;
ninRegsGet ((char *) &nindy_regs);
immediate_quit--;
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);
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], nindy_regs.fp_as_double, 4 * 8);
registers_fetched ();
}
static void
nindy_prepare_to_store (void)
{
read_register_bytes (0, NULL, REGISTER_BYTES);
}
static void
nindy_store_registers (int regno)
{
struct nindy_regs nindy_regs;
int regnum;
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);
memcpy (nindy_regs.fp_as_double, ®isters[REGISTER_BYTE (FP0_REGNUM)], 8 * 4);
immediate_quit++;
ninRegsPut ((char *) &nindy_regs);
immediate_quit--;
}
int
nindy_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
int should_write, struct mem_attrib *attrib,
struct target_ops *target)
{
int res;
if (len <= 0)
return 0;
if (should_write)
res = ninMemPut (memaddr, myaddr, len);
else
res = ninMemGet (memaddr, myaddr, len);
return res;
}
static void
nindy_create_inferior (char *execfile, char *args, char **env)
{
int entry_pt;
int pid;
if (args && *args)
error ("Can't pass arguments to remote NINDY process");
if (execfile == 0 || exec_bfd == 0)
error ("No executable file specified");
entry_pt = (int) bfd_get_start_address (exec_bfd);
pid = 42;
inferior_ptid = pid_to_ptid (pid);
clear_proceed_status ();
init_wait_for_inferior ();
target_terminal_init ();
target_terminal_inferior ();
proceed ((CORE_ADDR) entry_pt, TARGET_SIGNAL_DEFAULT, 0);
}
static void
reset_command (char *args, int from_tty)
{
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
nindy_kill (char *args, int from_tty)
{
return;
}
void
nindy_mourn_inferior (void)
{
remove_breakpoints ();
unpush_target (&nindy_ops);
generic_mourn_inferior ();
}
static int
nindy_open_stub (char *arg)
{
nindy_open (arg, 1);
return 1;
}
static void
nindy_load (char *filename, int from_tty)
{
asection *s;
bfd *file = bfd_openr (filename, 0);
if (!file)
{
perror_with_name (filename);
return;
}
if (!bfd_check_format (file, bfd_object))
{
error ("can't prove it's an object file\n");
return;
}
for (s = file->sections; s; s = s->next)
{
if (s->flags & SEC_LOAD)
{
char *buffer = xmalloc (s->_raw_size);
bfd_get_section_contents (file, s, buffer, 0, s->_raw_size);
printf ("Loading section %s, size %x vma %x\n",
s->name,
s->_raw_size,
s->vma);
ninMemPut (s->vma, buffer, s->_raw_size);
xfree (buffer);
}
}
bfd_close (file);
}
static int
load_stub (char *arg)
{
target_load (arg, 1);
return 1;
}
void
nindy_before_main_loop (void)
{
char ttyname[100];
char *p, *p2;
while (target_stack->target_ops != &nindy_ops)
{
if (instream == stdin)
{
printf_unfiltered ("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit: ");
gdb_flush (gdb_stdout);
}
fgets (ttyname, sizeof (ttyname) - 1, stdin);
for (p = ttyname; isspace (*p); p++)
{
;
}
if (*p == '\0')
{
return;
}
for (p2 = p; !isspace (*p2) && (*p2 != '\0'); p2++)
{
;
}
*p2 = '\0';
if (STREQ ("quit", p))
{
exit (1);
}
if (catch_errors (nindy_open_stub, p, "", RETURN_MASK_ALL))
{
if (exec_bfd)
{
catch_errors (load_stub, bfd_get_filename (exec_bfd), "",
RETURN_MASK_ALL);
}
}
}
}
struct target_ops nindy_ops;
static void
init_nindy_ops (void)
{
nindy_ops.to_shortname = "nindy";
"Remote serial target in i960 NINDY-specific protocol",
nindy_ops.to_longname = "Use a remote i960 system running NINDY connected by a serial line.\n\
Specify the name of the device the serial line is connected to.\n\
The speed (baud rate), whether to use the old NINDY protocol,\n\
and whether to send a break on startup, are controlled by options\n\
specified when you started GDB.";
nindy_ops.to_doc = "";
nindy_ops.to_open = nindy_open;
nindy_ops.to_close = nindy_close;
nindy_ops.to_attach = 0;
nindy_ops.to_post_attach = NULL;
nindy_ops.to_require_attach = NULL;
nindy_ops.to_detach = nindy_detach;
nindy_ops.to_require_detach = NULL;
nindy_ops.to_resume = nindy_resume;
nindy_ops.to_wait = nindy_wait;
nindy_ops.to_post_wait = NULL;
nindy_ops.to_fetch_registers = nindy_fetch_registers;
nindy_ops.to_store_registers = nindy_store_registers;
nindy_ops.to_prepare_to_store = nindy_prepare_to_store;
nindy_ops.to_xfer_memory = nindy_xfer_inferior_memory;
nindy_ops.to_files_info = nindy_files_info;
nindy_ops.to_insert_breakpoint = memory_insert_breakpoint;
nindy_ops.to_remove_breakpoint = memory_remove_breakpoint;
nindy_ops.to_terminal_init = 0;
nindy_ops.to_terminal_inferior = 0;
nindy_ops.to_terminal_ours_for_output = 0;
nindy_ops.to_terminal_ours = 0;
nindy_ops.to_terminal_info = 0;
nindy_ops.to_kill = nindy_kill;
nindy_ops.to_load = nindy_load;
nindy_ops.to_lookup_symbol = 0;
nindy_ops.to_create_inferior = nindy_create_inferior;
nindy_ops.to_post_startup_inferior = NULL;
nindy_ops.to_acknowledge_created_inferior = NULL;
nindy_ops.to_clone_and_follow_inferior = NULL;
nindy_ops.to_post_follow_inferior_by_clone = NULL;
nindy_ops.to_insert_fork_catchpoint = NULL;
nindy_ops.to_remove_fork_catchpoint = NULL;
nindy_ops.to_insert_vfork_catchpoint = NULL;
nindy_ops.to_remove_vfork_catchpoint = NULL;
nindy_ops.to_has_forked = NULL;
nindy_ops.to_has_vforked = NULL;
nindy_ops.to_can_follow_vfork_prior_to_exec = NULL;
nindy_ops.to_post_follow_vfork = NULL;
nindy_ops.to_insert_exec_catchpoint = NULL;
nindy_ops.to_remove_exec_catchpoint = NULL;
nindy_ops.to_has_execd = NULL;
nindy_ops.to_reported_exec_events_per_exec_call = NULL;
nindy_ops.to_has_exited = NULL;
nindy_ops.to_mourn_inferior = nindy_mourn_inferior;
nindy_ops.to_can_run = 0;
nindy_ops.to_notice_signals = 0;
nindy_ops.to_thread_alive = 0;
nindy_ops.to_stop = 0;
nindy_ops.to_pid_to_exec_file = NULL;
nindy_ops.to_stratum = process_stratum;
nindy_ops.DONT_USE = 0;
nindy_ops.to_has_all_memory = 1;
nindy_ops.to_has_memory = 1;
nindy_ops.to_has_stack = 1;
nindy_ops.to_has_registers = 1;
nindy_ops.to_has_execution = 1;
nindy_ops.to_sections = 0;
nindy_ops.to_sections_end = 0;
nindy_ops.to_magic = OPS_MAGIC;
}
void
_initialize_nindy (void)
{
init_nindy_ops ();
add_target (&nindy_ops);
add_com ("reset", class_obscure, reset_command,
"Send a 'break' to the remote target system.\n\
Only useful if the target has been equipped with a circuit\n\
to perform a hard reset when a break is detected.");
}