/* SPIM S20 MIPS simulator.
   X interface to SPIM
   (Derived from an earlier work by Alan Siow.)
   Copyright (C) 1990-1994 by James Larus (larus@cs.wisc.edu).
   ALL RIGHTS RESERVED.

   SPIM is distributed under the following conditions:

     You may make copies of SPIM for your own use and modify those copies.

     All copies of SPIM must retain my name and copyright notice.

     You may not sell SPIM or distributed SPIM in conjunction with a
     commerical product or service without the expressed written consent of
     James Larus.

   THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   PURPOSE. */


/* $Header: /home/primost/larus/Software/SPIM/RCS/buttons.c,v 3.38 1994/01/18 03:21:45 larus Exp larus $
 */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/Sme.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Cardinals.h>

#include <stdio.h>
#include <setjmp.h>
#include <ctype.h>

#include "spim.h"
#include "spim-utils.h"
#include "xspim.h"
#include "inst.h"
#include "mem.h"
#include "reg.h"
#include "scanner.h"
#include "sym-tbl.h"
#include "buttons.h"

#ifdef CL_SPIM
#include "cl-cache.h"
#include "cl-cycle.h"
#include "cl-tlb.h"
#include "cl-except.h"
#include "mips-syscall.h"
#endif


/* Local functions: */

#ifdef __STDC__
static void add_breakpoint_action (Widget w, XtPointer client_data,
	XtPointer call_data);
static void add_clear_button (Widget parent);
static void add_mode_button (Widget parent);
static void add_print_button (Widget parent);
static void add_terminal_button (Widget parent);
static void breakpoint_prompt (Widget button, XtPointer client_data,
			       XtPointer call_data);
static void breakpoint_prompt_destroyed (Widget w, XtPointer client_data,
					 XtPointer call_data);
static void clear_program_state_action (Widget w, XtPointer client_data,
					XtPointer call_data);
static void continue_action (Widget w, XtPointer client_data,
			     XtPointer call_data);
static void continue_prompt_destroyed (Widget w, XtPointer client_data,
				       XtPointer call_data);
static void delete_breakpoint_action (Widget w, XtPointer client_data,
				      XtPointer call_data);
static void destroy_popup_prompt (Widget w, XtPointer client_data,
				  XtPointer call_data);
static void help_action (Widget w, XtPointer ignore, XtPointer ignored);
static void init_stack (char *args);
static void load_prompt (Widget button, XtPointer client_data,
			 XtPointer call_data);
static void load_prompt_destroyed (Widget w, XtPointer client_data,
				   XtPointer call_data);
static void list_breakpoint_action (Widget w, XtPointer client_data,
				    XtPointer call_data);
static void noop (void);
static void parse_print_value (Widget w, XtPointer client_data,
			       XtPointer call_data);
static void parse_set_value (Widget w, XtPointer client_data,
			     XtPointer call_data);
static Widget popup_two_field_dialog (Widget button, String name,
				      String field1_label, String field1_value,
				      String field2_label, String field2_value,
				      String action_name,
				      void (*action) (/* ??? */),
				      String action2_name,
				      void (*action2) (/* ??? */),
				      Widget *field1_text,
				      Widget *field2_text);
static void print_mem_prompt (Widget button, XtPointer client_data,
			      XtPointer call_data);
static void print_prompt_destroyed (Widget w, XtPointer client_data,
				    XtPointer call_data);
static void print_symbol_action (Widget w, XtPointer client_data,
				 XtPointer call_data);
static void quit_action (Widget w, XtPointer client_data,XtPointer call_data);
static void quit_prompt (Widget button, XtPointer client_data,
			 XtPointer call_data);
static void quit_prompt_destroyed (Widget w, XtPointer client_data,
				   XtPointer call_data);
static void read_assm_file_action (Widget w, XtPointer client_data,
				   XtPointer call_data);
static void read_exec_file_action (Widget w, XtPointer client_data,
				   XtPointer call_data);
static void run_program_action (Widget w, XtPointer client_data,
				XtPointer call_data);
static void run_prompt (Widget button, XtPointer client_data,
			XtPointer call_data);
static void run_prompt_destroyed (Widget w, XtPointer client_data,
				  XtPointer call_data);
static void select_mode_action (Widget w, XtPointer client_data,
				XtPointer call_data);
static void set_value_action (char *location_str,char *value_str);
static void set_value_prompt (Widget button, XtPointer client_data,
			      XtPointer call_data);
static void set_value_destroyed (Widget w, XtPointer client_data,
				 XtPointer call_data);
static void step_continue_action (Widget w, XtPointer client_data,
				  XtPointer call_data);
static void step_program_action (Widget w, XtPointer client_data,
				 XtPointer call_data);
static void step_prompt (Widget button, XtPointer client_data,
			 XtPointer call_data);
static void step_prompt_destroyed (Widget w, XtPointer client_data,
				   XtPointer call_data);
static void warp_to_second_dialog (Widget widget, XEvent *event,
				   String *params, Cardinal *num_params);

#ifdef CL_SPIM
static void add_cache_button (Widget parent);
static void add_info_button (Widget parent);
static void cl_cycle_mode_action (Widget choice, XtPointer client_data,
				  XtPointer call_data);
static void cl_dcache_mode_action (Widget choice, XtPointer client_data,
				   XtPointer call_data);
static void cl_icache_mode_action (Widget choice, XtPointer client_data,
				   XtPointer call_data);
static void cl_reinit_prompt_destroyed (Widget w, XtPointer client_data,
					XtPointer call_data);
static void cl_reinit_prompt (char *str, void (*callback)());
static void dcache_action (Widget button, XtPointer client_data,
			   XtPointer call_data);
static void icache_action (Widget button, XtPointer client_data,
			   XtPointer call_data);
static void info_action (Widget w, XtPointer client_data, XtPointer call_data);
static void pipe_action (Widget button, XtPointer client_data,
			 XtPointer call_data);
#endif

#else

static void add_breakpoint_action ();
static void add_clear_button ();
static void add_mode_button ();
static void add_print_button ();
static void add_terminal_button ();
static void breakpoint_prompt ();
static void breakpoint_prompt_destroyed ();
static void clear_program_state_action ();
static void continue_action ();
static void continue_prompt_destroyed ();
static void delete_breakpoint_action ();
static void destroy_popup_prompt ();
static void help_action ();
static void init_stack ();
static void load_prompt ();
static void load_prompt_destroyed ();
static void list_breakpoint_action ();
static void noop ();
static void parse_print_value ();
static void parse_set_value ();
static Widget popup_two_field_dialog ();
static void print_mem_prompt ();
static void print_prompt_destroyed ();
static void print_symbol_action ();
static void quit_action ();
static void quit_prompt ();
static void quit_prompt_destroyed ();
static void read_assm_file_action ();
static void read_exec_file_action ();
static void run_program_action ();
static void run_prompt ();
static void run_prompt_destroyed ();
static void select_mode_action ();
static void set_value_action ();
static void set_value_prompt ();
static void set_value_destroyed ();
static void step_continue_action ();
static void step_program_action ();
static void step_prompt ();
static void step_prompt_destroyed ();
static void warp_to_second_dialog ();

#ifdef CL_SPIM
static void add_cache_button ();
static void add_info_button ();
static void cl_cycle_mode_action ();
static void cl_dcache_mode_action ();
static void cl_icache_mode_action ();
static void cl_reinit_prompt_destroyed ();
static void cl_reinit_prompt ();
static void dcache_action ();
static void icache_action ();
static void info_action ();
static void pipe_action ();
#endif

#endif

/* Local variables: */

static Widget breakpointButton;
static void (*confirmAction) () = noop;
static int stack_initialized = 0;
char *xspim_file_name = NULL;	/* Retain last file's name. */



#ifdef __STDC__
void
record_file_name_for_prompt (char *name)
#else
void
record_file_name_for_prompt (name)
     char *name;
#endif
{
  xspim_file_name = str_copy (name);
}


#ifdef __STDC__
void
create_buttons (Widget parent)
#else
void
create_buttons (parent)
     Widget parent;
#endif
{
  Widget button;
  Widget command;
  Arg args[10];


  XtSetArg (args[0], XtNlabel, "quit");
  XtSetArg (args[1], XtNwidth, button_width);
  button = XtCreateManagedWidget ("quitbutton", commandWidgetClass, parent,
				  args, TWO);
  XtAddCallback (button, XtNcallback, quit_prompt, NULL);


  XtSetArg (args[0], XtNlabel, "load");
  XtSetArg (args[1], XtNwidth, button_width);
  command = XtCreateManagedWidget ("loadbutton", commandWidgetClass, parent,
				   args, TWO);
  XtAddCallback (command, XtNcallback, load_prompt, NULL);


  XtSetArg (args[0], XtNlabel, "run");
  XtSetArg (args[1], XtNwidth, button_width);
  button = XtCreateManagedWidget ("runbutton", commandWidgetClass, parent,
				  args, TWO);
  XtAddCallback (button, XtNcallback, run_prompt, NULL);


  XtSetArg (args[0], XtNlabel, "step");
  XtSetArg (args[1], XtNwidth, button_width);
  button = XtCreateManagedWidget ("stepbutton", commandWidgetClass, parent,
				  args, TWO);
  XtAddCallback (button, XtNcallback, step_prompt, NULL);


  add_clear_button (parent);


  XtSetArg (args[0], XtNlabel, "set value");
  XtSetArg (args[1], XtNwidth, button_width);
  button = XtCreateManagedWidget ("setvaluebutton", commandWidgetClass, parent,
				  args, TWO);
  XtAddCallback (button, XtNcallback, set_value_prompt, NULL);


  add_print_button (parent);


  XtSetArg (args[0], XtNlabel, "breakpoints");
  XtSetArg (args[1], XtNwidth, button_width);
  button = XtCreateManagedWidget ("bkptbutton", commandWidgetClass, parent,
				  args, TWO);
  breakpointButton = button;
  XtAddCallback (button, XtNcallback, breakpoint_prompt, NULL);


  XtSetArg (args[0], XtNlabel, "help");
  XtSetArg (args[1], XtNwidth, button_width);
  button = XtCreateManagedWidget ("helpbutton", commandWidgetClass, parent,
				  args, TWO);
  XtAddCallback (button, XtNcallback, help_action, NULL);


  add_terminal_button (parent);


  add_mode_button (parent);


#ifdef CL_SPIM
  XtSetArg (args[0], XtNlabel, "pipeline");
  XtSetArg (args[1], XtNwidth, button_width);
  button = XtCreateManagedWidget ("pipebutton", commandWidgetClass, parent,
				  args, TWO);
  XtAddCallback (button, XtNcallback, pipe_action, NULL);


  add_cache_button (parent);


  add_info_button (parent);
#endif
}



/* *** Quit *** */

static Widget quit_popup = NULL;

#ifdef __STDC__
static void
quit_prompt (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
quit_prompt (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  Widget parent, dialog;
  Arg args[10];
  Position x, y;

  if (quit_popup == NULL)
    {
      parent = XtParent (button);

      XtTranslateCoords (button, (Position) 0, (Position) 0, &x, &y);
      XtSetArg (args[0], XtNx, x);
      XtSetArg (args[1], XtNy, y);
      quit_popup = XtCreatePopupShell ("prompt", transientShellWidgetClass,
				       parent, args, TWO);
      XtAddCallback (quit_popup, XtNdestroyCallback, quit_prompt_destroyed,
		     (XtPointer) 0);

      XtSetArg (args[0], XtNlabel, "quit?");
      dialog = XtCreateManagedWidget ("quit", dialogWidgetClass, quit_popup,
				      args, ONE);

      XawDialogAddButton (dialog, "quit", quit_action, (XtPointer) dialog);
      XawDialogAddButton (dialog, "abort command", destroy_popup_prompt,
			  (XtPointer) dialog);

    }
  confirmAction = quit_action;
  XtPopup (quit_popup, XtGrabNone);
}


#ifdef __STDC__
static void
quit_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
quit_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Widget dialog = (Widget) client_data;

  destroy_popup_prompt (NULL, (XtPointer) dialog, (XtPointer) NULL);
  XtDestroyApplicationContext (XtWidgetToApplicationContext (w));
  exit (0);
}


#ifdef __STDC__
static void
quit_prompt_destroyed (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
quit_prompt_destroyed (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  quit_popup = NULL;
}


/* *** Load *** */

static Widget load_popup = NULL;

#ifdef __STDC__
static void
load_prompt (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
load_prompt (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  Widget parent, dialog;
  Arg args[10];
  Position x, y;

  if (load_popup == NULL)
    {
      parent = XtParent (button);

      XtTranslateCoords (button, (Position) 0, (Position) 0, &x, &y);
      XtSetArg (args[0], XtNx, x);
      XtSetArg (args[1], XtNy, y);
      load_popup = XtCreatePopupShell ("popup", transientShellWidgetClass,
				      parent, args, TWO);
      XtAddCallback (load_popup, XtNdestroyCallback, load_prompt_destroyed,
		     (XtPointer) 0);

      if (xspim_file_name == NULL)
	xspim_file_name = str_copy ("");
      XtSetArg (args[0], XtNlabel, "input filename:");
      XtSetArg (args[1], XtNvalue, xspim_file_name);
      dialog = XtCreateManagedWidget ("dialog", dialogWidgetClass, load_popup,
				      args, TWO);

      XawDialogAddButton (dialog, "assembly file", read_assm_file_action,
			  (XtPointer) dialog);
#ifdef mips
      XawDialogAddButton (dialog, "executable file", read_exec_file_action,
			  (XtPointer) dialog);
#endif
      XawDialogAddButton (dialog, "abort command", destroy_popup_prompt,
			  (XtPointer) dialog);
    }

  confirmAction =  read_assm_file_action;
  XtPopup (load_popup, XtGrabNone);
}


#ifdef __STDC__
static void
read_assm_file_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
read_assm_file_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Widget dialog = (Widget) client_data;
  String value = XawDialogGetValueString (dialog);

  free (xspim_file_name);
  xspim_file_name = str_copy (value);
  read_file (value, 1);

  destroy_popup_prompt (NULL, (XtPointer) dialog, (XtPointer) NULL);
}



#ifdef mips
#ifdef __STDC__
static void
read_exec_file_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
read_exec_file_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Widget dialog = (Widget) client_data;
  String value = XawDialogGetValueString (dialog);

  free (xspim_file_name);
  xspim_file_name = str_copy (value);
  read_file (value, 0);

  destroy_popup_prompt (NULL, (XtPointer) dialog, (XtPointer) NULL);
}
#endif


#ifdef __STDC__
static void
load_prompt_destroyed (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
load_prompt_destroyed (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  load_popup = NULL;
}


/* *** Run *** */

static Widget run_popup = NULL;
static Widget run_field1_text, run_field2_text;

#ifdef __STDC__
static void
run_prompt (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
run_prompt (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  char sa[20];

  if (run_popup == NULL)
    {
      sprintf (sa, "0x%08x", starting_address ());
      run_popup = popup_two_field_dialog (button, "run program",
					 "starting address:", sa,
					 "args:", xspim_file_name,
					 "ok", run_program_action,
					 NULL, NULL,
					 &run_field1_text, &run_field2_text);
      XtAddCallback (run_popup, XtNdestroyCallback, run_prompt_destroyed,
		     (XtPointer) 0);
    }
  confirmAction =  run_program_action;
  XtPopup (run_popup, XtGrabNone);
}


#ifdef __STDC__
static void
run_program_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
run_program_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Arg args[10];
  String value1, value2;
  Widget form = XtParent (w);
  mem_addr addr;

  XtSetArg (args[0], XtNstring, &value1);
  XtGetValues (run_field1_text, args, ONE);

  XtSetArg (args[0], XtNstring, &value2);
  XtGetValues (run_field2_text, args, ONE);

  destroy_popup_prompt (NULL, (XtPointer) form, NULL);

#ifdef CL_SPIM
  if (cycle_level) {
    if (cycle_running)
      kill_prog_fds ();
    cl_initialize_world (1);
  }
#endif
  init_stack (value2);
  addr = strtoul (value1, NULL, 16);
  if (addr > 0)
    start_program (addr);
}


#ifdef __STDC__
static void
init_stack (char *args)
#else
static void
init_stack (args)
     char *args;
#endif
{
  int argc = 0;
  char *argv[10000];
  char *a;

  if (stack_initialized)
    return;
  while (*args != '\0')
    {
      /* Skip leading blanks */
      while (*args == ' ' || *args == '\t') args++;
      /* First non-blank char */
      a = args;
      /* Last non-blank, non-null char */
      while (*args != ' ' && *args != '\t' && *args != '\0') args++;
      /* Terminate word */
      if (a != args)
	{
	  if (*args != '\0')
	    *args++ = '\0';	/* Null terminate */
	  argv [argc++] = a;
	}
    }
  initialize_run_stack (argc, argv);
  stack_initialized = 1;
}


#ifdef __STDC__
static void
run_prompt_destroyed (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
run_prompt_destroyed (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  run_popup = NULL;
}


/* *** Step *** */

static char *step_size = NULL;	/* Retain step size */

static Widget step_popup = NULL;
static Widget step_field1_text, step_field2_text;

#ifdef __STDC__
static void
step_prompt (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
step_prompt (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  if (step_popup == NULL)
    {
      if (step_size == NULL)
	step_size = str_copy ("1");
      step_popup = popup_two_field_dialog (button, "step program",
					  "number of steps:", step_size,
					  "args:", xspim_file_name,
					  "step", step_program_action,
					  "continue", step_continue_action,
					  &step_field1_text,
					  &step_field2_text);
      XtAddCallback (step_popup, XtNdestroyCallback, step_prompt_destroyed,
		     (XtPointer) 0);
    }
  confirmAction =  step_program_action;
  XtPopup (step_popup, XtGrabNone);
}


#ifdef __STDC__
static void
step_program_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
step_program_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Arg args[10];
  String value1, value2;
  mem_addr addr;
  int steps;

  XtSetArg (args[0], XtNstring, &value1);
  XtGetValues (step_field1_text, args, ONE);

  XtSetArg (args[0], XtNstring, &value2);
  XtGetValues (step_field2_text, args, ONE);

  steps = atoi (value1);
  free (step_size);
  step_size = str_copy (value1);
  addr = starting_address ();
#ifdef CL_SPIM
  if (!cycle_running && cycle_level) 
    cl_initialize_world (1);
#endif
  init_stack (value2);
  if (steps > 0 && addr > 0)
    execute_program (addr, steps, 1, 1);
  else
    error ("Cannot step %d steps from 0x%x\n", steps, addr);
}


#ifdef __STDC__
static void
step_continue_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
step_continue_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Widget dialog = (Widget) client_data;

  XtPopdown (XtParent (dialog));
  destroy_popup_prompt (NULL, (XtPointer) dialog, (XtPointer) NULL);
  step_popup = NULL;
  execute_program (PC, DEFAULT_RUN_STEPS, 0, 0);
}


#ifdef __STDC__
static void
step_prompt_destroyed (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
step_prompt_destroyed (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  step_popup = NULL;
}


/* *** Clear *** */

#ifdef __STDC__
static void
add_clear_button (Widget parent)
#else
static void
add_clear_button (parent)
     Widget parent;
#endif
{
  Widget command, menu, entry;
  Arg args[2];

  XtSetArg (args[0], XtNwidth, button_width);
  command = XtCreateManagedWidget ("clear", menuButtonWidgetClass,
				   parent, args, ONE);
  menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, command,
			     NULL, ZERO);

  entry = XtCreateManagedWidget ("registers", smeBSBObjectClass, menu,
				 args, ONE);
  XtAddCallback (entry, XtNcallback, clear_program_state_action,
		 (XtPointer) 0);

  entry = XtCreateManagedWidget ("memory & registers", smeBSBObjectClass, menu,
				 args, ONE);
  XtAddCallback (entry, XtNcallback, clear_program_state_action,
		 (XtPointer) 1);
}


#ifdef __STDC__
static void
clear_program_state_action (Widget w, XtPointer client_data,
			    XtPointer call_data)
#else
static void
clear_program_state_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  int clear_world = (int) client_data;

  if (clear_world)
    {
      write_output (message_out, "Memory and registers cleared\n\n");
      initialize_world (load_trap_handler && !bare_machine);
      write_startup_message ();
      stack_initialized = 0;
#ifdef CL_SPIM
      cl_initialize_world (0);
#endif
    }
  else
    {
      write_output (message_out, "Registers cleared\n\n");
#ifdef CL_SPIM
      cl_initialize_world (0);
#else
      initialize_registers ();
#endif
    }
  redisplay_text ();
  redisplay_data ();
}


/* *** Set Value *** */

static Widget set_value_popup = NULL;
static Widget set_field1_text, set_field2_text;

#ifdef __STDC__
static void
set_value_prompt (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
set_value_prompt (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  if (set_value_popup == NULL)
    {
      set_value_popup = popup_two_field_dialog (button, "set value",
					   "register/location:", "",
					   "value:", "",
					   "set", parse_set_value,
					   NULL, NULL,
					   &set_field1_text, &set_field2_text);
      XtAddCallback (set_value_popup, XtNdestroyCallback,
		     set_value_destroyed, (XtPointer) 0);
    }
  confirmAction = parse_set_value;
  XtPopup (set_value_popup, XtGrabNone);
}


#ifdef __STDC__
static void
parse_set_value (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
parse_set_value (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Arg args[10];
  String value1, value2;
  Widget form = XtParent (w);

  XtSetArg (args[0], XtNstring, &value1);
  XtGetValues (set_field1_text, args, ONE);

  XtSetArg (args[0], XtNstring, &value2);
  XtGetValues (set_field2_text, args, ONE);

  destroy_popup_prompt (NULL, (XtPointer) form, NULL);

  set_value_action (value1, value2);
}


#ifdef __STDC__
static void
set_value_action (char *location_str, char *value_str)
#else
static void
set_value_action (location_str, value_str)
     char *location_str, *value_str;
#endif
{
  long value;
  int reg_no;

  value = strtol (value_str, NULL, 16);
  reg_no = register_name_to_number (location_str);

  if (reg_no < 0)
    if (*location_str == '$' || *location_str == 'r' || *location_str == 'R')
      reg_no = register_name_to_number (location_str + 1);

  if (reg_no == 0)
    error ("Cannot modify register 0\n");
  else if (reg_no > 0)
    R[reg_no] = value;
  else if (streq (location_str, "Status") || streq (location_str, "status"))
    Status_Reg = value;
  else if (streq (location_str, "PC") || streq (location_str, "pc"))
    PC = value;
  else if (streq (location_str, "EPC") | streq (location_str, "epc"))
    EPC = value;
  else
    {
      char *eptr;
      mem_addr addr;

      /* Try to parse string as a number */
      addr = strtol (location_str, &eptr, 16);
      if (eptr == location_str)
	error ("Unknown register selected: %s\n", location_str);
      else
	SET_MEM_WORD (addr, value);
    }
  redisplay_data ();
}


#ifdef __STDC__
static void
set_value_destroyed (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
set_value_destroyed (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  set_value_popup = NULL;
}


/* *** Print *** */

#ifdef __STDC__
static void
add_print_button (Widget parent)
#else
static void
add_print_button (parent)
     Widget parent;
#endif
{
  Widget command, menu, entry;
  Arg args[2];

  XtSetArg (args[0], XtNwidth, button_width);
  command = XtCreateManagedWidget ("print", menuButtonWidgetClass,
				   parent, args, ONE);
  menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, command,
			     NULL, ZERO);

  entry = XtCreateManagedWidget ("memory location(s)", smeBSBObjectClass, menu,
				 args, ONE);
  XtAddCallback (entry, XtNcallback, print_mem_prompt, NULL);

  entry = XtCreateManagedWidget ("global symbols", smeBSBObjectClass, menu,
				 args, ONE);
  XtAddCallback (entry, XtNcallback, print_symbol_action, NULL);
}


static Widget print_popup = NULL;
static Widget print_field1_text, print_field2_text;

#ifdef __STDC__
static void
print_mem_prompt (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
print_mem_prompt (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  if (print_popup == NULL)
    {
      print_popup = popup_two_field_dialog (XtParent (button), "print memory",
					"from", "",
					"to", "",
					"print", parse_print_value,
					NULL, NULL,
					&print_field1_text,
					&print_field2_text);
      XtAddCallback (print_popup, XtNdestroyCallback, print_prompt_destroyed,
		     (XtPointer) 0);
    }
  confirmAction = parse_print_value;
  XtPopup (print_popup, XtGrabNone);
}


#ifdef __STDC__
static void
parse_print_value (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
parse_print_value (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Arg args[10];
  String value1, value2;
  Widget form = XtParent (w);

  XtSetArg (args[0], XtNstring, &value1);
  XtGetValues (print_field1_text, args, ONE);

  XtSetArg (args[0], XtNstring, &value2);
  XtGetValues (print_field2_text, args, ONE);

  XtPopdown (XtParent (form));
  destroy_popup_prompt (NULL, (XtPointer) form, NULL);

  if (!streq (value1, ""))
    {
      mem_addr from, to;

      from = strtoul (value1, NULL, 16);
      to = strtoul (value2, NULL, 16);
      if (streq (value2, ""))
	print_mem (from);
      else
	for ( ; from <= to; from+= BYTES_PER_WORD)
	  print_mem (from);
    }
}


#ifdef __STDC__
static void
print_symbol_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
print_symbol_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  print_symbols ();
}


#ifdef __STDC__
static void
print_prompt_destroyed (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
print_prompt_destroyed (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  print_popup = NULL;
}


/* *** Breakpoints **** */

static char *breakpoint_addr = NULL; /* Retain last breakpoint address */

static Widget bkpt_popup = NULL;

#ifdef __STDC__
static void
breakpoint_prompt (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
breakpoint_prompt (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  Widget parent, dialog;
  Arg args[10];
  Position x, y;

  if (bkpt_popup == NULL)
    {
      parent = XtParent (button);

      XtTranslateCoords (button, (Position) 0, (Position) 0, &x, &y);
      XtSetArg (args[0], XtNx, x);
      XtSetArg (args[1], XtNy, y);
      bkpt_popup = XtCreatePopupShell ("popup", transientShellWidgetClass,
				      parent, args, TWO);

      if (breakpoint_addr == NULL)
	breakpoint_addr = str_copy ("");
      XtSetArg (args[0], XtNlabel, "address:");
      XtSetArg (args[1], XtNvalue, breakpoint_addr);
      dialog = XtCreateManagedWidget ("dialog", dialogWidgetClass,
				      bkpt_popup,
				      args, TWO);
      XtAddCallback (bkpt_popup, XtNdestroyCallback,
		     breakpoint_prompt_destroyed, (XtPointer) 0);

      XawDialogAddButton (dialog, "add",
			  add_breakpoint_action, (XtPointer) dialog);
      XawDialogAddButton (dialog, "delete",
			  delete_breakpoint_action, (XtPointer) dialog);
      XawDialogAddButton (dialog, "list",
			  list_breakpoint_action, (XtPointer) dialog);
      XawDialogAddButton (dialog, "abort command", destroy_popup_prompt,
			  (XtPointer) dialog);
    }

  confirmAction = add_breakpoint_action;
  XtPopup (bkpt_popup, XtGrabNone);
}


#ifdef __STDC__
static void
add_breakpoint_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
add_breakpoint_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Widget dialog = (Widget) client_data;
  String value = XawDialogGetValueString (dialog);
  mem_addr addr;

  free (breakpoint_addr);
  breakpoint_addr = str_copy (value);

  while (*breakpoint_addr == ' ') breakpoint_addr++;
  if (isdigit (*breakpoint_addr))
    addr = strtoul (value, NULL, 16);
  else
    addr = find_symbol_address (breakpoint_addr);

  add_breakpoint (addr);

  destroy_popup_prompt (NULL, (XtPointer) dialog, (XtPointer) NULL);
}


#ifdef __STDC__
static void
delete_breakpoint_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
delete_breakpoint_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Widget dialog = (Widget) client_data;
  String value = XawDialogGetValueString (dialog);
  mem_addr addr;

  free (breakpoint_addr);
  breakpoint_addr = str_copy (value);
  addr = strtoul (value, NULL, 16);

  delete_breakpoint (addr);

  destroy_popup_prompt (NULL, (XtPointer) dialog, (XtPointer) NULL);
}


#ifdef __STDC__
static void
list_breakpoint_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
list_breakpoint_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  list_breakpoints ();
}


#ifdef __STDC__
static void
breakpoint_prompt_destroyed (Widget w, XtPointer client_data,
			     XtPointer call_data)
#else
static void
breakpoint_prompt_destroyed (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  bkpt_popup = NULL;
}


/* *** Help *** */

#ifdef __STDC__
static void
help_action (Widget w, XtPointer ignore, XtPointer ignored)
#else
static void
help_action (w, ignore, ignored)
     Widget w;
     XtPointer ignore;
     XtPointer ignored;
#endif
{
  static char * msg = "\nSPIM is a MIPS R2000 simulator.\n\
Copyright (C) 1990-1994 by James R. Larus, larus@cs.wisc.edu\n\n\
quit  -- Exit from the simulator\n\
load -- Read a file into memory\n\
run -- Execute a program\n\
step -- Single-step through a program\n\
clear -- Reinitialize registers or memory\n\
set value -- Set the value in register or memory\n\
print -- Print the value in register or memory\n\
breakpoint -- Set or delete a breakpoint\n\
help -- This message\n\
terminal -- Raise or hide console window\n\
mode -- Set SPIM operating modes\n";

  write_output (message_out, msg);
}


/* *** Terminal *** */

#ifdef __STDC__
static void
add_terminal_button (Widget parent)
#else
static void
add_terminal_button (parent)
     Widget parent;
#endif
{
  Widget command, menu, entry;
  Arg args[2];

  XtSetArg (args[0], XtNwidth, button_width);
  command = XtCreateManagedWidget ("terminal", menuButtonWidgetClass,
				   parent, args, ONE);
  menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, command,
			     NULL, ZERO);

  entry = XtCreateManagedWidget ("popup console", smeBSBObjectClass, menu,
				 args, ONE);
  XtAddCallback (entry, XtNcallback, popup_console, NULL);
}


/* *** Mode *** */

static Widget modeCommand;
#ifdef CL_SPIM
static Widget bareflag, quietflag, modeChoice;
static Widget cl_reinitPopup = NULL;
#endif

#ifdef __STDC__
static void
add_mode_button (Widget parent)
#else
static void
add_mode_button (parent)
     Widget parent;
#endif
{
  Widget menu, entry;
  Arg args[2];

  XtSetArg (args[0], XtNwidth, button_width);
  modeCommand = XtCreateManagedWidget ("mode", menuButtonWidgetClass,
				       parent, args, ONE);
  menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, modeCommand,
			     NULL, ZERO);

  XtSetArg (args[0], XtNleftMargin, 20);
  entry = XtCreateManagedWidget ("bare", smeBSBObjectClass, menu, args, ONE);
  XtAddCallback (entry, XtNcallback, select_mode_action, NULL);
  if (bare_machine)
    {
      XtSetArg (args[0], XtNleftBitmap, mark);
      XtSetValues (entry, args, ONE);
    }
#ifdef CL_SPIM
  bareflag = entry;
#endif

  XtSetArg (args[0], XtNleftMargin, 20);
  entry = XtCreateManagedWidget ("quiet", smeBSBObjectClass, menu, args, ONE);
  XtAddCallback (entry, XtNcallback, select_mode_action, NULL);
  if (quiet)
    {
      XtSetArg (args[0], XtNleftBitmap, mark);
      XtSetValues (entry, args, ONE);
    }
#ifdef CL_SPIM
  quietflag = entry;

  XtSetArg (args[0], XtNleftMargin, 20);
  entry = XtCreateManagedWidget ("cycle", smeBSBObjectClass, menu, args, ONE);
  XtAddCallback (entry, XtNcallback, select_mode_action, NULL);
  if (cycle_level)
    {
      XtSetArg (args[0], XtNleftBitmap, mark);
      XtSetValues (entry, args, ONE);
    }

  XtSetArg (args[0], XtNleftMargin, 20);
  entry = XtCreateManagedWidget ("tlb", smeBSBObjectClass, menu, args, ONE);
  XtAddCallback (entry, XtNcallback, select_mode_action, NULL);
  if (tlb_on)
    {
      XtSetArg (args[0], XtNleftBitmap, mark);
      XtSetValues (entry, args, ONE);
    }

  XtSetArg (args[0], XtNleftMargin, 20);
  entry = XtCreateManagedWidget ("icache", smeBSBObjectClass, menu, args, ONE);
  XtAddCallback (entry, XtNcallback, select_mode_action, NULL);
  if (icache_on)
    {
      XtSetArg (args[0], XtNleftBitmap, mark);
      XtSetValues (entry, args, ONE);
    }

  XtSetArg (args[0], XtNleftMargin, 20);
  entry = XtCreateManagedWidget ("dcache", smeBSBObjectClass, menu, args, ONE);
  XtAddCallback (entry, XtNcallback, select_mode_action, NULL);
  if (dcache_on)
    {
      XtSetArg (args[0], XtNleftBitmap, mark);
      XtSetValues (entry, args, ONE);
    }
#endif
}


#ifdef __STDC__
static void
select_mode_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
select_mode_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Arg args[10];
  String name = XtName (w);

#ifdef CL_SPIM
  modeChoice = w;
#endif

  if (streq (name, "bare"))
    {
      bare_machine = !bare_machine;
      if (bare_machine)
	XtSetArg (args[0], XtNleftBitmap, mark);
      else
	XtSetArg (args[0], XtNleftBitmap, None);
      XtSetValues (w, args, ONE);
    }
  else if (streq (name, "quiet"))
    {
      quiet = !quiet;
      if (quiet)
	XtSetArg (args[0], XtNleftBitmap, mark);
      else
	XtSetArg (args[0], XtNleftBitmap, None);
      XtSetValues (w, args, ONE);
    }
#ifdef CL_SPIM
  else if (streq (name, "cycle"))
    cl_reinit_prompt ("Changing cycle mode will reinitialize everything",
		     cl_cycle_mode_action);
  else if (streq (name, "tlb"))
    {
      if (cycle_running && (icache_on || dcache_on))
	write_output (message_out,
		      "Toggling TLB invalidates cache values.\nReinitialize, then set TLB.\n");
      else
	{
	  if (tlb_on)
	    {
	      tlb_on = 0;
	      XtSetArg (args[0], XtNleftBitmap, None);
	    }
	  else
	    {
	      tlb_on = 1;
	      XtSetArg (args[0], XtNleftBitmap, mark);
	      tlb_init ();
	    }
	  XtSetValues (w, args, ONE);
	}
    }
  else if (streq (name, "icache"))
    {
      if (cycle_running)
	cl_reinit_prompt ("Changing cache will invalidate it",
			 cl_icache_mode_action);
      else
	{
	  if (icache_on)
	    {
	      icache_on = 0;
	      XtSetArg (args[0], XtNleftBitmap, None);
	    }
	  else
	    {
	      icache_on = 1;
	      XtSetArg (args[0], XtNleftBitmap, mark);
	      cache_init (mem_system, INST_CACHE);
	    }
	  XtSetValues (w, args, ONE);
	}
    }
  else if (streq (name, "dcache"))
    {
      if (cycle_running)
	cl_reinit_prompt ("Changing cache will invalidate it",
			 cl_dcache_mode_action);
      else
	{
	  if (dcache_on)
	    {
	      dcache_on = 0;
	      XtSetArg (args[0], XtNleftBitmap, None);
	    }
	  else
	    {
	      dcache_on = 1;
	      XtSetArg (args[0], XtNleftBitmap, mark);
	      cache_init (mem_system, DATA_CACHE);
	    }
	  XtSetValues (w, args, ONE);
	}
    }
#endif
}


#ifdef CL_SPIM
#ifdef __STDC__
static void
cl_cycle_mode_action (Widget choice, XtPointer client_data,
		      XtPointer call_data)
#else
static void
cl_cycle_mode_action (choice, client_data, call_data)
  Widget choice;
  XtPointer client_data, call_data;
#endif
{
  Arg args[1];
  String response = XtName (choice);

  if (streq (response, "continue")) {
    if (cycle_level) {
      cycle_level = 0;
      cl_initialize_world (0);
      XtSetArg (args[0], XtNleftBitmap, None);
    }
    else {
      cycle_level = 1;
      bare_machine = 1;
      quiet = 1;
      cl_initialize_world (0);
      XtSetArg (args[0], XtNleftBitmap, mark);
      XtSetValues (bareflag, args, ONE);
      XtSetValues (quietflag, args, ONE);
    }
    XtSetValues (client_data, args, ONE);
  }
  confirmAction = noop;
  XtDestroyWidget (XtParent(XtParent(choice)));
}


#ifdef __STDC__
static void
cl_icache_mode_action (Widget choice, XtPointer client_data,
		       XtPointer call_data)
#else
static void
cl_icache_mode_action (choice, client_data, call_data)
  Widget choice;
  XtPointer client_data, call_data;
#endif
{
  Arg args[1];
  String response = XtName (choice);

  if (streq (response, "continue")) {
    if (icache_on) {
      icache_on = 0;
      XtSetArg (args[0], XtNleftBitmap, None);
    }
    else {
      icache_on = 1;
      cache_init (mem_system, INST_CACHE);
      XtSetArg (args[0], XtNleftBitmap, mark);
    }
    XtSetValues (client_data, args, ONE);
  }
  confirmAction = noop;
  XtDestroyWidget (XtParent(XtParent(choice)));
}


#ifdef __STDC__
static void
cl_dcache_mode_action (Widget choice, XtPointer client_data,
		       XtPointer call_data)
#else
static void
cl_dcache_mode_action (choice, client_data, call_data)
  Widget choice;
  XtPointer client_data, call_data;
#endif
{
  Arg args[1];
  String response = XtName (choice);

  if (streq (response, "continue")) {
    if (dcache_on) {
      dcache_on = 0;
      XtSetArg (args[0], XtNleftBitmap, None);
    }
    else {
      dcache_on = 1;
      cache_init (mem_system, DATA_CACHE);
      XtSetArg (args[0], XtNleftBitmap, mark);
    }
    XtSetValues (client_data, args, ONE);
  }
  confirmAction = noop;
  XtDestroyWidget (XtParent(XtParent(choice)));
}


#ifdef __STDC__
static void
cl_reinit_prompt (char *str, void (*callback)())
#else
static void
cl_reinit_prompt (str, callback)
  char *str;
  void (*callback)();
#endif
{
  Widget parent, dialog;
  Arg args[10];
  Position x, y;

  if (cl_reinitPopup == NULL)
    {
      parent = modeCommand;

      XtTranslateCoords (XtParent(modeChoice), (Position) 0, (Position) 0,
			 &x, &y);
      XtSetArg (args[0], XtNx, x);
      XtSetArg (args[1], XtNy, y);
      cl_reinitPopup = XtCreatePopupShell ("prompt", transientShellWidgetClass,
					   parent, args, TWO);
      XtAddCallback (cl_reinitPopup, XtNdestroyCallback,
		     cl_reinit_prompt_destroyed, (XtPointer) 0);

      XtSetArg (args[0], XtNlabel, str);
      dialog = XtCreateManagedWidget ("reinit", dialogWidgetClass,
				      cl_reinitPopup, args, ONE);

      XawDialogAddButton (dialog,"continue", callback, (XtPointer)modeChoice);
      XawDialogAddButton (dialog,"abort command",callback,
			  (XtPointer)modeChoice);
    }
  confirmAction = callback;
  XtPopup (cl_reinitPopup, XtGrabNone);
}


#ifdef __STDC__
static void
cl_reinit_prompt_destroyed (Widget w, XtPointer client_data,
			    XtPointer call_data)
#else
static void
cl_reinit_prompt_destroyed (w, client_data, call_data)
  Widget w;
  XtPointer client_data, call_data;
#endif
{
  cl_reinitPopup = NULL;
}


/* *** Pipeline *** */

#ifdef __STDC__
static void
pipe_action (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
pipe_action (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  if (!cycle_level)
    write_output (message_out, "Cannot view pipeline -- not in cycle level simulation.\n");
  else popup_pipeline (button, client_data, call_data);
}


/* *** Cache *** */

#ifdef __STDC__
static void
add_cache_button (Widget parent)
#else
static void
add_cache_button (parent)
  Widget parent;
#endif
{
  Widget command, menu, entry;
  Arg args[2];

  XtSetArg (args[0], XtNwidth, button_width);
  command = XtCreateManagedWidget ("cache", menuButtonWidgetClass,
				   parent, args, ONE);
  menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, command,
			     NULL, ZERO);

  XtSetArg (args[0], XtNleftMargin, 20);
  entry = XtCreateManagedWidget ("data", smeBSBObjectClass, menu, args, ONE);
  XtAddCallback (entry, XtNcallback, dcache_action, NULL);

  XtSetArg (args[0], XtNleftMargin, 20);
  entry = XtCreateManagedWidget ("inst", smeBSBObjectClass, menu, args, ONE);
  XtAddCallback (entry, XtNcallback, icache_action, NULL);
}


#ifdef __STDC__
static void
dcache_action (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
dcache_action (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  if (!cycle_level)
    write_output (message_out, "Cannot view data cache -- not in cycle level simulation.\n");
  else if (!dcache_on)
    write_output (message_out, "Data cache not on.\n");
  else pop_dcache (button, client_data, call_data);
}


#ifdef __STDC__
static void
icache_action (Widget button, XtPointer client_data, XtPointer call_data)
#else
static void
icache_action (button, client_data, call_data)
     Widget button;
     XtPointer client_data, call_data;
#endif
{
  if (!cycle_level)
    write_output (message_out, "Cannot view intruction cache -- not in cycle level simulation.\n");
  else if (!icache_on)
    write_output (message_out, "Instruction cache not on.\n");
  else pop_icache (button, client_data, call_data);
}


/* *** Info *** */

#ifdef __STDC__
static void
add_info_button (Widget parent)
#else
static void
add_info_button (parent)
  Widget parent;
#endif
{
  Widget infoCommand, menu, entry;
  Arg args[2];

  XtSetArg (args[0], XtNwidth, button_width);
  infoCommand = XtCreateManagedWidget ("info", menuButtonWidgetClass,
				       parent, args, ONE);
  menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, infoCommand,
			     NULL, ZERO);

  XtSetArg (args[0], XtNleftMargin, 20);

  entry = XtCreateManagedWidget("exceptions",smeBSBObjectClass,menu,args,ONE);
  XtAddCallback (entry, XtNcallback, info_action, NULL);

  entry = XtCreateManagedWidget("signals",smeBSBObjectClass, menu, args,ONE);
  XtAddCallback (entry, XtNcallback, info_action, NULL);

  entry = XtCreateManagedWidget ("syscalls",smeBSBObjectClass,menu, args,ONE);
  XtAddCallback (entry, XtNcallback, info_action, NULL);
}


#ifdef __STDC__
static void
info_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
info_action (w, client_data, call_data)
  Widget w;
  XtPointer client_data, call_data;
#endif
{
  String name = XtName(w);

  if (streq (name, "exceptions"))
    print_except_stats ();
  else if (streq (name, "signals"))
    print_signal_status (ALL_SIGNALS);
  else if (streq (name, "syscalls"))
    print_syscall_usage ();
}
#endif


/* *** Continue *** */

static Widget continue_popup = NULL;

#ifdef __STDC__
void
continue_prompt (int interrupt_seen)
#else
void
continue_prompt (interrupt_seen)
     int interrupt_seen;
#endif
{
  Widget dialog;
  Arg args[10];
  Position x, y;
  char msg[256];

  if (continue_popup != NULL)
    XtDestroyWidget (continue_popup);
  XtTranslateCoords (breakpointButton, (Position) 0, (Position) 0, &x, &y);
  XtSetArg (args[0], XtNx, x);
  XtSetArg (args[1], XtNy, y);
  continue_popup = XtCreatePopupShell ("prompt", transientShellWidgetClass,
				      breakpointButton, args, TWO);
  XtAddCallback (continue_popup, XtNdestroyCallback,
		 continue_prompt_destroyed, (XtPointer) 0);

  if (interrupt_seen)
    sprintf (msg, "execution interrupt at 0x%08x", PC);
  else
    sprintf (msg, "breakpoint encountered at 0x%08x", PC);
  XtSetArg (args[0], XtNlabel, msg);
  dialog = XtCreateManagedWidget ("continue", dialogWidgetClass,
				  continue_popup, args, ONE);

  XawDialogAddButton (dialog, "continue", continue_action,
		      (XtPointer) dialog);
  XawDialogAddButton (dialog, "abort command", destroy_popup_prompt,
		      (XtPointer) dialog);

  confirmAction = continue_action;
  XtPopup (continue_popup, XtGrabNone);
}


#ifdef __STDC__
static void
continue_action (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
continue_action (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Widget dialog = (Widget) client_data;

  XtPopdown (XtParent (dialog));
  destroy_popup_prompt (NULL, (XtPointer) dialog, (XtPointer) NULL);
  continue_popup = NULL;
  execute_program (PC, 1, 0, 1); /* Step over breakpoint */
  execute_program (PC, DEFAULT_RUN_STEPS - 1, 0, 0);
}


#ifdef __STDC__
static void
continue_prompt_destroyed (Widget w, XtPointer client_data,
			   XtPointer call_data)
#else
static void
continue_prompt_destroyed (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  continue_popup = NULL;
}




#ifdef __STDC__
void
confirm (Widget widget, XEvent *event, String *params, Cardinal *num_params)
#else
void
confirm (widget, event, params, num_params)
     Widget widget;
     XEvent *event;
     String *params;
     Cardinal *num_params;
#endif
{
  Widget dialog = XtParent (widget);
  (*confirmAction) (widget, (XtPointer) dialog, (XtPointer) NULL);
}


#ifdef __STDC__
static void
destroy_popup_prompt (Widget w, XtPointer client_data, XtPointer call_data)
#else
static void
destroy_popup_prompt (w, client_data, call_data)
     Widget w;
     XtPointer client_data, call_data;
#endif
{
  Widget popup = XtParent ((Widget) client_data);

  confirmAction = noop;
  XtDestroyWidget (popup);
}


#ifdef __STDC__
static void
noop (void)
#else
static void
noop ()
#endif
{
}


#ifdef __STDC__
static Widget
popup_two_field_dialog (Widget button, String name, String field1_label,
			String field1_value, String field2_label,
			String field2_value, String action_name,
			void (*action) (/* ??? */), String action2_name,
			void (*action2) (/* ??? */), Widget *field1_text,
			Widget *field2_text)
#else
static Widget
popup_two_field_dialog (button, name, field1_label, field1_value,
		     field2_label, field2_value, action_name, action,
		     action2_name, action2, field1_text, field2_text)
     Widget button;
     String name, field1_label, field1_value, field2_label, field2_value,
       action_name, action2_name;
     void (*action) (), (*action2) ();
     Widget *field1_text, *field2_text;
#endif
{
  Widget popup, form;
  Widget labelx, field1, field2;
  Widget button1, button2, cancelbutton;
  Widget parent = XtParent (button);
  Arg args[10];
  Position x, y;
  static XtActionsRec action_table []
    = {{"warp_to_second_dialog", warp_to_second_dialog},};

  XtTranslateCoords (button, (Position) 0, (Position) 0, &x, &y);

  XtSetArg (args[0], XtNx, x);
  XtSetArg (args[1], XtNy, y);
  popup = XtCreatePopupShell ("prompt", transientShellWidgetClass, parent,
			      args, TWO);

  form = XtCreateManagedWidget ("form", formWidgetClass, popup, NULL, ZERO);

  XtSetArg (args[0], XtNlabel, name);
  XtSetArg (args[1], XtNborderWidth, 0);
  labelx = XtCreateManagedWidget ("label", labelWidgetClass, form, args, TWO);

  XtSetArg (args[0], XtNfromVert, labelx);
  XtSetArg (args[1], XtNborderWidth, 0);
  XtSetArg (args[2], XtNlabel, field1_label);
  field1 = XtCreateManagedWidget ("field1", labelWidgetClass, form, args,
				  THREE);

  XtSetArg (args[0], XtNfromHoriz, field1);
  XtSetArg (args[1], XtNfromVert, labelx);
  XtSetArg (args[2], XtNeditType, "edit");
  XtSetArg (args[3], XtNstring, field1_value);
  XtSetArg (args[4], XtNtype, XawAsciiString);
  *field1_text = XtCreateManagedWidget ("field1_text", asciiTextWidgetClass,
					form, args, FIVE);
  XtOverrideTranslations (*field1_text,
			  XtParseTranslationTable
			  ("#override \n <Key>Return:warp_to_second_dialog()"));
  XtAppAddActions (app_context, action_table, XtNumber (action_table));

  XtSetArg (args[0], XtNfromVert, *field1_text);
  XtSetArg (args[1], XtNborderWidth, 0);
  XtSetArg (args[2], XtNlabel, field2_label);
  field2 = XtCreateManagedWidget ("field2", labelWidgetClass, form, args,
				  THREE);

  XtSetArg (args[0], XtNfromHoriz, field1);
  XtSetArg (args[1], XtNfromVert, *field1_text);
  XtSetArg (args[2], XtNeditType, "edit");
  XtSetArg (args[3], XtNstring, field2_value);
  XtSetArg (args[4], XtNtype, XawAsciiString);
  *field2_text = XtCreateManagedWidget ("field2_text", asciiTextWidgetClass,
					form, args, FIVE);
  XtOverrideTranslations (*field2_text,
			  XtParseTranslationTable
			  ("#override \n <Key>Return: confirm()"));

  XtSetArg (args[0], XtNfromVert, *field2_text);
  button1 = XtCreateManagedWidget (action_name, commandWidgetClass, form,
				   args, ONE);
  XtAddCallback (button1, XtNcallback, action, (XtPointer) form);

  if (action2 != NULL)
    {
      XtSetArg (args[0], XtNfromHoriz, button1);
      XtSetArg (args[1], XtNfromVert, *field2_text);
      button2 = XtCreateManagedWidget (action2_name, commandWidgetClass, form,
				       args, TWO);
      XtAddCallback (button2, XtNcallback, action2, (XtPointer) form);
    }

  XtSetArg (args[0], XtNfromHoriz, action2 == NULL ? button1 : button2);
  XtSetArg (args[1], XtNfromVert, *field2_text);
  cancelbutton = XtCreateManagedWidget ("abort command", commandWidgetClass,
					form, args, TWO);
  XtAddCallback (cancelbutton, XtNcallback, destroy_popup_prompt,
		 (XtPointer) form);

  return (popup);
}


#ifdef __STDC__
static void
warp_to_second_dialog (Widget widget, XEvent *event, String *params,
		       Cardinal *num_params)
#else
static void
warp_to_second_dialog (widget, event, params, num_params)
     Widget widget;
     XEvent *event;
     String *params;
     Cardinal *num_params;
#endif
{
  Widget form = XtParent (widget);
  Widget second_dialog;

  second_dialog = XtNameToWidget (form, "field2_text");
  if (second_dialog)
    XWarpPointer (XtDisplay (second_dialog), None, XtWindow (second_dialog),
		  0, 0, 0, 0, 0, 10);
}
