/* THIS FILE HAS NOT HAD ITS COPYRIGHT CHECKED...FSF SHOULD NOT
   DISTRIBUTE IT UNTIL THIS HAPPENS.  */

/* Memory-access and commands for inferior process, for GDB.
*/

#include "defs.h"
#include <sys/errno.h>
#include <setjmp.h>
#include "frame.h"
#include "value.h"
#include "inferior.h"
#include "symtab.h"

#undef WSTOPSIG
#undef WTERMSIG
#include "wait.h"

#ifdef USG
#include <sys/types.h>
#include <fcntl.h>
#endif

#include <signal.h>
#include <sys/file.h>

#include <termios.h>
#define TERMINAL struct termios

#define LONGTIMEOUT 5
#define SHORTTIMEOUT 1

#define KD_MINUTAE 1
#define KD_LINEDISCIPLINE 2
#define KD_RETRY 4
#define KD_BLOCKTRANSFER 8

#ifndef STDIN
#define STDIN 0
#endif

#define GL_READING 0 /* get line is reading data */
#define GL_OK 1 /* Getline saw the "ok" string */
#define GL_SUCCESS 2 /* Get line got data */
#define GL_TIMEOUT 3 /* Get line timed out */
#define GL_OVERRUN 4 /* Get line filled up the buffer */
#define GL_EXCEPTION 5 /* Get line saw "Exception" */
#define GL_PROMLINE 6 /* Get line saw prom specific info */
#define GL_BLANKLINE 7 /* Get line saw a blank line */

static int kiodebug /* = KD_RETRY | KD_BLOCKTRANSFER */;

static CORE_ADDR remote_pc = 0;
static CORE_ADDR remote_next_pc = 0;
static CORE_ADDR remove_thisbp_next_pc = 0;
static CORE_ADDR remove_thisbp_target = 0;

enum showDrainage {DONTSHOW , SHOW} ;


/* Descriptor for I/O to remote machine.  Initialize it to -1 so that
   remote_open knows that we don't have a file open when the program
   starts.  */
int remote_desc = -1;

int dontskipcrs = 0;

#define	PBUFSIZ	400

unsigned char ignorebuf[PBUFSIZ];
#define IGNORE &ignorebuf[0]

/* Maximum number of bytes to read/write at once.  The value here
   is chosen to fill up a packet (the headers account for the 32).  */
#define MAXBUFBYTES ((PBUFSIZ-32)/2)

static void remote_send ();
static void putpkt ();
static int getpkt ();


/* Open a connection to a remote debugger.
   NAME is the filename used for communication.  */
CORE_ADDR breakpoint_regs_addr;


void
remote_open (name, from_tty)
     char *name;
     int from_tty;
{
  extern int frame_file_full_name;
  unsigned char buf[PBUFSIZ];
  TERMINAL sg;

  remote_debugging = 0;

  if (remote_desc >= 0)
    close (remote_desc);

  breakpoint_regs_addr = parse_and_eval_address("&breakpoint_regs");

  dontskipcrs = !frame_file_full_name; /* if we are running inside of
					 emacs, this will be true. 
					 then skip carriage returns */

  remote_desc = open (name, O_RDWR);
  if (remote_desc < 0)
    perror_with_name (name);

  setup_remote();

  if (from_tty)
    printf ("Remote debugging using %s\n", name);
  remote_debugging = 1;


}
static char *boot_cmd = 0;

static print_boot_cmd()
{
    fprintf(stderr, "boot command set to be \"%s\"\n", boot_cmd);
}

remote_start()
{
  WAITTYPE ignoredWaitType;

  if (boot_cmd)
    {
    sendbreak();
    remote_wait (&ignoredWaitType);
    putpkt ("reset");
    sleep(10);
    sendbreak();
    remote_wait (&ignoredWaitType);
    sleep(10);
    print_boot_cmd();
    putpkt(boot_cmd);
    fprintf(stderr, "rgdb and nucleus synchronized, booting....\n");
    }
  else
    {
    error("The boot command is null. Cannot start the remote kernel/nucleus");
    }
}

/* Close the open connection to the remote debugger.
   Use this when you want to detach and do something else
   with your gdb.  */
void
remote_close (from_tty)
     int from_tty;
{
  if (!remote_debugging)
    error ("Can't close remote connection: not debugging remotely.");
  
  close (remote_desc);		/* This should never be called if
				   there isn't something valid in
				   remote_desc.  */

  /* Do not try to close remote_desc again, later in the program.  */
  remote_desc = -1;

  if (from_tty)
    printf ("Ending remote debugging\n");

  remote_debugging = 0;
}
 
/* Convert hex digit A to a number.  */

static int
fromhex (a)
     int a;
{
  if (a >= '0' && a <= '9')
    return a - '0';
  else if (a >= 'a' && a <= 'f')
    return a - 'a' + 10;
  else
    error ("Reply contains invalid hex digit");
}

/* Convert number NIB to a hex digit.  */

static int
tohex (nib)
     int nib;
{
  if (nib < 10)
    return '0'+nib;
  else
    return 'a'+nib-10;
}

/* Tell the remote machine to resume.  */

extern int one_stepped;		/* From machine dependent code */
static int remote_set_one_stepped;

int
remote_resume (step, signal)
     int step, signal;
{
  if (step)
    {
      remote_single_step();
    }
  remote_set_one_stepped = step;
  putpkt("go");
}

/* Wait until the remote machine stops, then return,
   storing status in STATUS just as `wait' would.  */

int
remote_wait (status)
     WAITTYPE *status;
{
  char last, this;
  int pend, saveTheOh = 0;

  user_terminal_raw();

  WSETEXIT ((*status), 0177);
  last = this = 0;

  while (1)
      {
	char buf[PBUFSIZ];
	int readUser, readProm, state;

	doselect(&readUser, &readProm);
	if (readProm)
	  {
	    switch (state = getline(buf, PBUFSIZ, SHORTTIMEOUT))
	      {
	      case GL_BLANKLINE:
		if (remote_set_one_stepped)
		  break;
		
		/* fall through */

	      default:
	      case GL_READING:
	      case GL_SUCCESS:
	      case GL_OVERRUN:
	      case GL_TIMEOUT:
		if (kiodebug & KD_LINEDISCIPLINE)
		  fprintf(stderr, "%d<%s>\n", state, buf);
		else
		  {
		    fprintf(stderr, "%s", buf);
		    fflush(stderr);
		  }
		break;
	      case GL_OK:
		remote_cleanup_after_stop();
		WSETSTOP ((*status), SIGTRAP);
		return;
	      case GL_PROMLINE:
		break;
	      }
	  }
	if (readUser)
	  shuffleFromUserToProm();
      }
}
static TERMINAL userterminal;
	
user_terminal_restore()
{
#if 0
  int in_desc = fileno (stdin);
  ioctl (in_desc, TCSETS, &userterminal);
#endif
}
static void set_term_raw();

user_terminal_raw()
{
#if 0
  TERMINAL tempterminal;
  int in_desc = fileno (stdin);
  ioctl (in_desc, TCGETS, &userterminal);
  tempterminal = userterminal;

  tempterminal.c_lflag &= ~(ICANON|ISIG|IEXTEN);
  tempterminal.c_cc[VMIN] = 1;
  tempterminal.c_cc[VTIME] = 0;
  tempterminal.c_iflag &= ~(INPCK|IXON|IXOFF);
  tempterminal.c_oflag = 0;

  ioctl (in_desc, TCSETS, &tempterminal);
#endif
}

doselect(pReadUser, pReadProm)
     int *pReadUser, *pReadProm;
{
  extern FILE *instream;
  int in_desc = fileno (stdin);
  int instreammask = 1 << in_desc;
  int remotemask = 1 << remote_desc;
  int rfds = instreammask | remotemask;

  select (32, &rfds, 0, 0, (struct timeval *) 0); /* 0 = Block indefinitely */
  *pReadUser = (rfds & instreammask) == instreammask;
  *pReadProm = (rfds & remotemask) == remotemask;
}



/* Read the remote registers into the block pRegisters.
implementation copied largely from fetch_inferior_registers () 
in sparc-dep.c */

void
remote_fetch_registers(ignored)
int *ignored;
{
  struct regs inferior_registers;
  extern char registers[];
  CORE_ADDR breakpoint_regs_target;

  if (breakpoint_regs_addr == 0)
    {
      error("no address for breakpoint_regs\n");
      return;
    }
  remote_read_inferior_memory(breakpoint_regs_addr, &breakpoint_regs_target,
			      sizeof(breakpoint_regs_target));

  bzero(registers, REGISTER_BYTES);
  registers[REGISTER_BYTE (0)] = 0;

  if (breakpoint_regs_target)
    {
      remote_read_inferior_memory(breakpoint_regs_target, &inferior_registers,
				  sizeof(inferior_registers));
      registers[REGISTER_BYTE (0)] = 0;
      bcopy (&inferior_registers.r_g1, &registers[REGISTER_BYTE (1)], 15 * 4);
      *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; 
      *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
      *(int *)&registers[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc;
      *(int *)&registers[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y;
      remote_pc =  inferior_registers.r_pc; 
      remote_next_pc =  inferior_registers.r_npc; 
      remote_read_inferior_memory (inferior_registers.r_sp,
				   &registers[REGISTER_BYTE (16)],
				   16*4);
    }
  else
    {
      error("breakpoint_regs == 0\n");
    }
}




/* Write memory data directly to the remote machine.
   This does not inform the data cache; the data cache uses this.
   MEMADDR is the address in the remote memory space.
   MYADDR is the address of the buffer in our space.
   LEN is the number of bytes.  */

int
remote_write_bytes (memaddr, myaddr, len)
     CORE_ADDR memaddr;
     unsigned char *myaddr;
     int len;
{
  char buf[PBUFSIZ];
  int i;

  /* Command describes registers byte by byte,
     each byte encoded as two hex characters.  */

  for (i = 0; i < len; i++)
    {
    sprintf(buf, "%x %x c!", myaddr[i], memaddr + i); 
    remote_send (buf, buf);
    if (strstr(buf, "Exception"))
      {
	return EFAULT;	  
      }
    }
  return 0;	  
}

/* Copy LEN bytes of data from debugger memory at MYADDR
   to inferior's memory at MEMADDR.  Returns errno value.  */
int
remote_write_inferior_memory (memaddr, myaddr, len)
     CORE_ADDR memaddr;
     char *myaddr;
     int len;
{
  int xfersize;
  int retval;

  while (len > 0)
    {
      if (len > MAXBUFBYTES)
	xfersize = MAXBUFBYTES;
      else
	xfersize = len;
      
      retval = remote_write_bytes(memaddr, myaddr, xfersize);
      if (retval)
	return retval; /* error */
      
      memaddr += xfersize;
      myaddr  += xfersize;
      len     -= xfersize;
    }
  return 0; /* no error */
}


/* read a single character */

static int
readCharFromProm ()
{
  char buf;

  buf = '\0';
  /* termio does the timeout for us.  */
  read (remote_desc, &buf, 1);
  return buf & 0x7f;
}

/* Send the command in BUF to the remote machine,
   and read the reply into BUF.
   Report an error if we get an error reply.  */

static void
remote_send (buf, buf2)
     char *buf, *buf2;
{
  putpkt (buf);
  getpkt (buf2);
}

/* Send a single character out over the wire */

static void
putcharacter (ch)
     char ch;
{

  while (1)
    {
      int i;

      write(remote_desc, &ch, 1);
      for (i = 0; i < 100; i++)
	{
	  char nch = 0;

	  if (read (remote_desc, &nch, 1) == 0)
	    i++;
	  if ((ch == nch)
	      || (ch == '\n' && nch == '\r')
	      || (ch == '\r' && nch == '\n'))
	    return;
	  if (kiodebug & KD_MINUTAE)
	    fprintf (stderr, "Sent %c(%d) Received %c(%d)\n", ch, ch, nch, nch);
	}
    }
}

/* Send a packet to the remote machine, with error checking.
   The data of the packet is in BUF.  */

static void
putpkt (buf)
     char *buf;
{
  int i;
  int cnt = strlen (buf);
  char ch;

  if (kiodebug & KD_LINEDISCIPLINE)
    fprintf(stderr, "putpkt(%s)\n", buf);

  for (i = 0; i < cnt; i++)
      putcharacter (buf[i]);
  putcharacter ('\n');
}

jmp_buf getline_jmpbuf;

/* Read a line from the remote machine, and store it in BUF.  */
getline_timer()
{
  alarm(0);
  
  if (kiodebug & KD_RETRY)
    fprintf(stderr, "getline timed out\n");
  longjmp(getline_jmpbuf, 1);
}

static int
getline (buf, size, timeout)
     char *buf;
     int size, timeout;
{
  int cnt = 0;
  int state;
  int isspace_state = 1;

  if ((void (*)) signal (SIGALRM, getline_timer) == (void (*)) -1)
    perror ("remote_open: error in signal");

  --size; /* back it up one so that we can read */

  state = GL_READING;

  if (setjmp(getline_jmpbuf))
    state = GL_TIMEOUT;
  else
    {
      alarm (timeout);
      do
	{
	  char ch = readCharFromProm();
	  isspace_state = isspace_state && isspace(ch);
	  if (ch && (dontskipcrs || ch != '\r'))
	    {
	      buf[cnt++] = ch;
	      buf[cnt] = '\0';
	    }
	  if (kiodebug & KD_MINUTAE)
	    fprintf (stderr,"letter received :%c\n", buf[cnt - 1]);
	  if (cnt >= 2 && buf[cnt - 2] == 'o' && buf[cnt - 1] == 'k')
	      state = GL_OK;
	  else if (buf[cnt - 1] == '\n' )
	    state = isspace_state ?  GL_BLANKLINE : GL_SUCCESS;
	  else if (cnt == size)
	    state = GL_OVERRUN;
	  else if (strstr(buf, "Type  'go' to resume"))
	    state = GL_PROMLINE;
	  else if (strstr(buf, "Type  help  for more information"))
	    state = GL_PROMLINE;
	  else if (strstr(buf, "Exception"))
	    state = GL_EXCEPTION;
	}
      while (state == GL_READING);
    }
  alarm (0);
  
  if (kiodebug & KD_LINEDISCIPLINE)
    fprintf (stderr,"Line received :%s\n", buf);
  return state;
}


/* Read a packet from the remote machine, and store it in BUF.  */

static int
getpkt (buf)
     char *buf;
{
  int cnt = 0;

    do
      {
      char ch = readCharFromProm();
      if (ch)
	buf[cnt++] = ch;
      if (kiodebug & KD_MINUTAE)
	fprintf (stderr,"letter received :%c\n", buf[cnt - 1]);
      }
    while (cnt < 2 ||
      buf[cnt - 2] != 'o' &&
      buf[cnt - 1] != 'k');

    buf[cnt] = '\0';
    if (kiodebug& KD_LINEDISCIPLINE)
      fprintf (stderr,"Packet received :%s\n", buf);
    return cnt;
}

void remote_fetch_word (addr)
     CORE_ADDR addr;
{
  error ("Internal error: remote_fetch_word is obsolete.\n");
}
void remote_store_word (addr)
     CORE_ADDR addr;
{
  error ("Internal error: remote_store_word is obsolete.\n");
}
#include <termio.h>

draininput(showit)
enum showDrainage showit;
{
  unsigned char buf[PBUFSIZ];
  int cnt;

  while ((cnt = read(remote_desc, buf, PBUFSIZ)) > 0)
    {
      buf[cnt] = 0;
      if (kiodebug& KD_LINEDISCIPLINE)
	fprintf (stderr,"Draining :%s\n", buf);
      else
	if (showit == SHOW)
	  fprintf (stderr,"%s", buf);
    }
  if (kiodebug& KD_LINEDISCIPLINE)
    fprintf (stderr,"Drained\n");
}
sendbreak()
{
  if (kiodebug & KD_RETRY)
    fprintf (stderr,"rgdb sending break to target...\n");
  else
    {
      fprintf (stderr,"=");
      fflush(stderr);
    }
    
  ioctl (remote_desc, TCSBRK, 0);
  sleep(5);
}


/* shuffle a character from the user to remote debugger */

int 
shuffleFromUserToProm()
{
  char ch;
  static int escape = 0;
    
  extern FILE *instream;
  
  ch = 0;
  if (read(STDIN, &ch , 1) != 1 || ch == 0)
    return;

  if (escape) {
    if (ch == '#')
      sendbreak();
    else if (ch == '.')
	{
	  while (ch != '\n')	
	    read(STDIN, &ch , 1);
	  return 1;
	}
    else {
      static char tilde = '~';

      putcharacter(tilde);
      putcharacter(ch);
    }
    escape = 0;
  } else /* not escape */ {
    if (ch == '~')
      escape = 1;
    else
      putcharacter(ch);
  }
  return 0;
}
  
  

/* Tell  the Prom put a breakpoint at memaddr */
remote_insert_breakpoint(memaddr)
     CORE_ADDR memaddr;
{
  char buf[PBUFSIZ];

  /* Command describes registers byte by byte,
     each byte encoded as two hex characters.  */

  sprintf(buf, "%x +bp", memaddr);
  remote_send(buf, buf);
  if (strstr(buf, "Exception"))
    {
      return EFAULT;	  
    }
  else
    {
      return 0;	  
    }
}

/* Tell  the Prom remove the the breakpoint at memaddr */
remote_remove_breakpoint(memaddr)
     CORE_ADDR memaddr;
{
  char buf[PBUFSIZ];

  /* Command describes registers byte by byte,
     each byte encoded as two hex characters.  */

  sprintf(buf, "%x -bp", memaddr);
  remote_send(buf, buf);
  if (strstr(buf, "Exception"))
    {
      return EFAULT;	  
    }
  else
    {
      return 0;	  
    }
}





/* Read memory data directly from the remote machine.
   This does not use the data cache; the data cache uses this.
   MEMADDR is the address in the remote memory space.
   MYADDR is the address of the buffer in our space.
   LEN is the number of words.  */

long
remote_read(memaddr, myaddr, len, increment, promcommand)
     CORE_ADDR memaddr;
     unsigned char *myaddr;
     int len, increment;
     char *promcommand;
{
  char buf[PBUFSIZ];
  char buf2[PBUFSIZ];
  int i;
  unsigned long num;

  /* Command describes registers byte by byte,
     each byte encoded as two hex characters.  */

  for (i = 0; i < len; i += increment)
    {
      sprintf(buf, promcommand, memaddr + i) ;
      remote_send(buf, buf2);
      remote_send(".", buf);
      if (strstr(buf2, "Exception"))
	{
	  bzero(&myaddr[i], len - i);
	  return -i;	  
	}
      else
	{
	  char *pBuf;
	  for (pBuf = &buf[0]; *pBuf == '\r' || *pBuf == '\n'; pBuf++)
	    ;
	  sscanf(pBuf, "%x\n", &num);
	  switch (increment)
	    {
	    case 1: myaddr[i] = num;
	      if (num > 255)
		fprintf(stderr, "number out of bounds %x truncating to %x\n",
			num, myaddr[i]);
	      break;
	    case 4: {unsigned long *p;
		     p = (unsigned long *) &myaddr[i];
		     *p = num;
		     }
	      break;
	    default: fprintf(stderr, "unknown increment\n"); break;
	    }
	}
    }
  return i;
}



/* Read LEN bytes from inferior memory at MEMADDR.  Put the result
   at debugger address MYADDR.  Returns errno value.  */
int
remote_read_inferior_memory(memaddr, myaddr, len)
     CORE_ADDR memaddr;
     char *myaddr;
     int len;
{
  int xfersize;
  while (len > 0)
    {
      int mod;

      if (len > MAXBUFBYTES)
	xfersize = MAXBUFBYTES;
      else
	xfersize = len;

      mod = memaddr % 4;
      if  (mod == 0 && xfersize >= 4)
	if  (mod == 0 && xfersize >= 16)
	  {
	    xfersize = remote_read_many(memaddr, myaddr, (len & ~3));
	    getpkt(IGNORE);
	  }
	else
	  xfersize = remote_read(memaddr, myaddr, 4, 4, "%x @");
      else
	xfersize = remote_read(memaddr, myaddr, max(mod, 1), 1, "%x c@");
      if (xfersize <= 0)
	return EFAULT; /* error */
      memaddr += xfersize;
      myaddr  += xfersize;
      len     -= xfersize;
    }
  return 0; /* no error */
}
static int baud_rate=B38400;

static void set_term_raw(pTermio)
     TERMINAL *pTermio;
{
  pTermio->c_cflag &= (CREAD|HUPCL|CLOCAL);
  pTermio->c_cflag |= baud_rate | CS8;
  pTermio->c_iflag = ISTRIP /* | IXON | IXOFF */;
  pTermio->c_oflag = 0;
  pTermio->c_lflag = 0;
  pTermio->c_cc[VMIN] = 0;
  pTermio->c_cc[VTIME] = 1;
}

/* setup the remote termio stream */
setup_remote()
{
  TERMINAL temptempio;

  ioctl(remote_desc, TCGETS, &temptempio);
  set_term_raw(&temptempio);
  ioctl(remote_desc, TCSETS, &temptempio);
}

/* step one machine instruction */
remote_single_step ()
{
  CORE_ADDR next_pc, npc4, target, pc;
  typedef enum
    {
      Error, not_branch, bicc, bicca, ba, baa, ticc, ta
    } branch_type;
  branch_type br, isannulled();

  npc4 = remote_next_pc + 4; /* branch not taken */

  /* Always set breakpoint for NPC.  */

  remote_insert_breakpoint(remote_next_pc);
  remove_thisbp_next_pc = remote_next_pc;

  /* printf ("set break at %x\n",remote_next_pc); */
  
  br = isannulled (remote_pc, &target);
  
  if (br == bicca)
    {
      /* Conditional annulled branch will either end up at
	 npc (if taken) or at npc+4 (if not taken).
	 Trap npc+4.  */
      remote_insert_breakpoint(npc4);
      remove_thisbp_target = npc4;
    }
  else if (br == baa && target != remote_next_pc)
    {
      /* Unconditional annulled branch will always end up at
	 the target.  */
      remote_insert_breakpoint(target);
      remove_thisbp_target = target;
    }
}




/* read many words of memory */
long
remote_read_many(memaddr, myaddr, len)
     CORE_ADDR memaddr;
     unsigned char *myaddr;
     int len;
{
#define BLOCKSIZE 1024
  static int max_number_of_blocks = 24;

  char buf[PBUFSIZ];
  char buf2[PBUFSIZ];
  int i;
  unsigned long *p;
/* Command describes registers byte by byte,
     each byte encoded as two hex characters.  */

  len = min(len, max_number_of_blocks * BLOCKSIZE);

  sprintf(buf, "%x %x do i @ . cr 4 +loop", memaddr + len, memaddr);
  putpkt(buf);
  getline(buf2, PBUFSIZ, LONGTIMEOUT); /* I don't care */

  p = (unsigned long *) myaddr;
  for (i = 0; i < len; i += 4, p++)
    {
      extern int InspectIt;

      if (!InspectIt && ((i % BLOCKSIZE) == 0))
	  fprintf(stderr, "+"); /* let 'em know that we are working */
      switch (getline(buf2, PBUFSIZ, LONGTIMEOUT))
	{
	default:
	case GL_PROMLINE:
	case GL_READING:
	case GL_OK:
	case GL_OVERRUN:
	case GL_TIMEOUT:
	case GL_BLANKLINE:
	  /* resync and retry */
	  max_number_of_blocks = max(1, i / BLOCKSIZE);
	  fprintf(stderr, "-"); /* let 'em know that we are working */
	  
	  if (kiodebug & KD_BLOCKTRANSFER)
	    fprintf(stderr, "failed read_many %d %d/%d (%s)\n",
		    max_number_of_blocks, i, len, buf2);
	  sendbreak();
	  return remote_read_many(memaddr, myaddr, len);
	case GL_EXCEPTION:
	  return -i;	  
	case GL_SUCCESS:
	  sscanf(buf2, "%x\n", p);
	  break;
	}
    }
  if (kiodebug & KD_BLOCKTRANSFER)
    fprintf(stderr, "success read_many %d %d/%d (%s)\n", max_number_of_blocks,
	    i, len, buf2);
  return i;
}
/*
 * allow the user to type directly to the prom ! 
 */
prom_command()
{
  int readUser, readProm;

  user_terminal_raw();
  fprintf(stderr, "entering prom mode...\n");
  while (1)
    {
      doselect(&readUser, &readProm);
      if (readUser)
	if (shuffleFromUserToProm())
	  {
	  fprintf(stderr, "exiting prom mode\n");
	  user_terminal_restore();
	  return;
	}
      if (readProm)
	fprintf(stderr, "%c", readCharFromProm ());
    }
}
static char *boot_set_msg = "boot needs a string in quotes of the form \"boot vmunix\"  ";
static char *baud_set_msg = "baud rate should be of the form \"set baud=9600\"";

static void
set_boot (arg, from_tty)
     char *arg;
     int from_tty;
{
  int h, i;

  if (!arg)
    {
    print_boot_cmd();
    error_no_arg (boot_set_msg);
    }
  
  arg = tilde_expand (arg);
  make_cleanup (free, arg);

  i = strlen (arg) - 1;
  
  free (boot_cmd);
  
  h = 0;
  while (*arg && h < i && (arg[h] == ' ' || arg[h] == '\t'))
    {
    h++;
    arg++;
    }
  while (i > 0 && (arg[i] == ' ' || arg[i] == '\t'))
    i--;

  if (h >= i || !*arg || arg[h] != '"' || arg[i] != '"')
    error (boot_set_msg);
  else
    {
    boot_cmd = savestring (++arg, i);
    boot_cmd[i - 1] = '\0';
    }
 if (from_tty)
    print_boot_cmd();
}

static int bauds[] = {
	0, 50, 75, 110, 134, 150, 200, 300, 600,
	1200, 1800, 2400, 4800, 9600, 19200, 38400, -1
};


static int convert_to_baud_B(n)
	int n;
{
	register int *p;

	for (p = bauds; *p != -1;  p++)
		if (*p != 0 && *p == n)
			return (p - bauds);
	return (NULL);
}

static void print_acceptable_bauds()
{
	register int *p;

	for (p = bauds; *p != -1;  p++)
		if (*p != 0 )
			fprintf(stderr, "%d\n", *p);
}

static void print_baud()
{
fprintf(stderr, "the baud rate is now %d\n", bauds[baud_rate]);
}

static void
set_baud (arg, from_tty)
     char *arg;
     int from_tty;
{
  int temp_baud_rate;

  if (!arg)
    {
    print_baud();
    print_acceptable_bauds();
    error_no_arg (baud_set_msg);
    return;
    }

  while (*arg && !isdigit(*arg))
    arg++;
  
  if (*arg  && (temp_baud_rate = convert_to_baud_B(atoi(arg))) != NULL)
    {
	baud_rate = temp_baud_rate;
	if (remote_debugging)
	  setup_remote();
    }
  else
    {
      fprintf(stderr, "bad baud rate %s, acceptable values are\n", arg);
      print_acceptable_bauds();
    }

  print_baud();
}




void
_initialize_remote()
{
/* Chain containing all defined set subcommands */

extern struct cmd_list_element *setlist;


  add_com ("prom", class_obscure, prom_command,
	   "Conduct a dialogue directly with the prom. \
only useful after an attach\n\
Terminate by typing ~.");

  add_cmd ("boot_cmd", class_support, set_boot, boot_set_msg, &setlist);

  add_cmd ("baud", class_support, set_baud, baud_set_msg, &setlist);

  set_boot ("\"boot nucleus -d\"", 0);
  }


/* Store the remote registers from the contents of the block REGS.  */

void
remote_store_registers (registers)
     char *registers;
{
  CORE_ADDR core;
  struct regs inferior_registers;

  core = parse_and_eval_address("breakpoint_regs");

  bcopy (&registers[REGISTER_BYTE (1)],
	 &inferior_registers.r_g1, 15 * 4);

  inferior_registers.r_ps =
    *(int *)&registers[REGISTER_BYTE (PS_REGNUM)];
  inferior_registers.r_pc =
    *(int *)&registers[REGISTER_BYTE (PC_REGNUM)];
  inferior_registers.r_npc =
    *(int *)&registers[REGISTER_BYTE (NPC_REGNUM)];
  inferior_registers.r_y =
    *(int *)&registers[REGISTER_BYTE (Y_REGNUM)];

  remote_write_inferior_memory (*(int *)&registers[REGISTER_BYTE (SP_REGNUM)],
				&registers[REGISTER_BYTE (16)],
				16*4);
  remote_write_inferior_memory (core,
				&inferior_registers, 
				sizeof(inferior_registers));
}



/* we have stopped. do some cleanup */
remote_cleanup_after_stop()
{
  if (remove_thisbp_next_pc)
    {
      remote_remove_breakpoint (remove_thisbp_next_pc);
      remove_thisbp_next_pc = 0;
    }
  if (remove_thisbp_target)
    {
      remote_remove_breakpoint (remove_thisbp_target);
      remove_thisbp_target = 0;
    }
  user_terminal_restore();
  
  one_stepped = remote_set_one_stepped;
}
