
/*-----------------------------------------------------------------------
-------------------------------------------------------------------------

   FILE:	SI_user.c

   PURPOSE:	Contains the user's directly related SI functions:
		   - User-defined command button functions 
		   - Display squares variable mappings

   AUTHOR:	Tan Phan
   DATE:	Spring 1989

   USAGE:	This is the C source code for the user-defined command 
		buttons.

   HISTORY:	Spring 1989	-- Creation

   Copyright 1990-1991 North Carolina State University. All Rights Reserved.

 
-------------------------------------------------------------------------
------------------------------------------------------------------------*/
#include "SI.h"
#include <X11/keysym.h>

#include "sim.h"


/*-----------------------------------------------------------------------
-------------------------------------------------------------------------
   Global data definitions:
------------------------------------------------------------------------*/

memory			SI_memory;
mw			SI_mw_wwindow[512];
mw			SI_mw_awindow[16];
int			SI_mw_pane[16];
int			SI_mw_old_pane[16];

Window			SI_mw_toplevel,
			SI_mw_com_window,
			SI_mw_com_up_window,
			SI_mw_com_down_window,
			SI_mw_com_dump_window,
			SI_mw_com_clear_window,
			SI_mw_com_setbpt_window,
			SI_mw_com_clrbpt_window,
			SI_mw_com_quit_window;
Window			SI_prompt_window;
XSizeHints		SI_mw_hint;

int			SI_ndigit,SI_nline,SI_wline;
int			SI_mw_base;
int			SI_mw_w_width,SI_mw_w_height,
			SI_mw_a_width,SI_mw_a_height,
			SI_mw_txt_offset;
int			SI_mw_width,SI_mw_height,
			SI_mw_org_x,SI_mw_org_y;
int			SI_mw_cb_width,SI_mw_cb_height,
			SI_mw_com_width,SI_mw_com_height;
int			SI_mw_com_right_x,SI_mw_com_left_x;
int			SI_mw_mapped;
int			SI_prompt_width,SI_prompt_height,
			SI_prompt_txt_offset;
char			SI_promptstr[100];
char			SI_code_filename[100];
unsigned int		SI_range_start_address,
			SI_range_end_address;
unsigned int		SI_memory_wsize=SI_MEMORY_WSIZE;

int			hpadding,	/* spacing between words	*/
			vpadding;	/* spacing between rows		*/

int			SI_mw_setbpt_selected,
			SI_mw_clrbpt_selected;




/*-----------------------------------------------------------------------
-------------------------------------------------------------------------
   SI_map_address:

   Map the address of the user's variables to be displayed on each DS.
   This routine MUST be modified by the user when customizing the 
   simulator.

   Mapping the address of the user's variables allows readily access 
   to the DS values.  Thus, the user only has to do this once.

   In order for SI to work, the variables in which the user has assigned
   to each DS must not be changed (the content may but the variable address
   may not).  The user's variable must be statically defined in the user's
   sim.h file.

   To map the address of a variable of type unsigned int or int or char ,
   just replace the 'dummy' with the variable name.  For example:
		... = &(my_sim_PC);
		... = &(my_sim_SP);
		... = &(register[0]);
		... = &(register[7]);
		... = &(carry_flag);

   To map the address of an array of char, replace the '&(dummy)' with
   the array name.  For example:
		... = status;
		... = my_sim_char_array;

   If a DS is not defined (ie. the first number of the DS in file DS_data
   is 0), the address for that DS is not needed to be mapped and can be
   ignored.  Note that whether a DS is defined or not is STATICALLY defined
   in file SI_data and this definition can not be changed while the SI
   is running.


   Region DS5 can not have values:					
      The 8 DS in this region are used for simulator status flags such as
      'TraceOn', 'SingleStepOn',...

      Instead of having variable content, the DS in this region can change
      between 2 states:  SI_SACTIVE (1)  and SI_SINACTIVE (2).

      If a DS is active (1), it is displayed with a thick border inside a 
      thin border on the SI window.

      If a DS is inactive (2), it is displayed with only a thin border on
      the SI window.	

      The intial state of a defined DS in DS5 is the third number of each
      DS in file SI_data.

      The state of a defined DS in DS5 can be changed dynamicaly
      (ie . while SI is running) by calling SI_toggle_state_DS5() with a
      DS number (0 to 7).  See SI_toggle_state_DS5().
------------------------------------------------------------------------*/
void SI_map_address()
{  static unsigned int		dummy;

   /* Map the address of values for the DS1 region:			*/
   SI_window.DS1[0].addr_value = (int *)&(reg[D0]);
   SI_window.DS1[1].addr_value = (int *)&(reg[D1]);
   SI_window.DS1[2].addr_value = (int *)&(reg[D2]);
   SI_window.DS1[3].addr_value = (int *)&(reg[D3]);
   SI_window.DS1[4].addr_value = (int *)&(reg[D4]);
   SI_window.DS1[5].addr_value = (int *)&(reg[D5]);
   SI_window.DS1[6].addr_value = (int *)&(reg[D6]);
   SI_window.DS1[7].addr_value = (int *)&(reg[D7]);
   SI_window.DS1[8].addr_value = (int *)&(reg[A0]);
   SI_window.DS1[9].addr_value = (int *)&(reg[A1]);
   SI_window.DS1[10].addr_value = (int *)&(reg[A2]);
   SI_window.DS1[11].addr_value = (int *)&(reg[A3]);
   SI_window.DS1[12].addr_value = (int *)&(reg[A4]);
   SI_window.DS1[13].addr_value = (int *)&(reg[A5]);
   SI_window.DS1[14].addr_value = (int *)&(reg[A6]);
   SI_window.DS1[15].addr_value = (int *)&(reg[A7]);
   SI_window.DS1[16].addr_value = (int *)&(dummy);
   SI_window.DS1[17].addr_value = (int *)&(dummy);
   SI_window.DS1[18].addr_value = (int *)&(dummy);
   SI_window.DS1[19].addr_value = (int *)&(dummy);
   SI_window.DS1[20].addr_value = (int *)&(dummy);
   SI_window.DS1[21].addr_value = (int *)&(dummy);
   SI_window.DS1[22].addr_value = (int *)&(dummy);
   SI_window.DS1[23].addr_value = (int *)&(reg[SSP]);
   SI_window.DS1[24].addr_value = (int *)&(dummy);
   SI_window.DS1[25].addr_value = (int *)&(dummy);
   SI_window.DS1[26].addr_value = (int *)&(dummy);
   SI_window.DS1[27].addr_value = (int *)&(dummy);
   SI_window.DS1[28].addr_value = (int *)&(dummy);
   SI_window.DS1[29].addr_value = (int *)&(dummy);
   SI_window.DS1[30].addr_value = (int *)&(dummy);
   SI_window.DS1[31].addr_value = (int *)&(reg[USP]);
   SI_window.DS1[32].addr_value = (int *)&(dummy);
   SI_window.DS1[33].addr_value = (int *)&(dummy);
   SI_window.DS1[34].addr_value = (int *)&(dummy);
   SI_window.DS1[35].addr_value = (int *)&(dummy);
   SI_window.DS1[36].addr_value = (int *)&(dummy);
   SI_window.DS1[37].addr_value = (int *)&(dummy);
   SI_window.DS1[38].addr_value = (int *)&(dummy);
   SI_window.DS1[39].addr_value = (int *)&(dummy);

   /* Map the address of values for the DS2 region:			*/
   SI_window.DS2[0].addr_value = (int *)&(Tbit);
   SI_window.DS2[1].addr_value = (int *)(Un6);
   SI_window.DS2[2].addr_value = (int *)&(Sbit);
   SI_window.DS2[3].addr_value = (int *)(Un5);
   SI_window.DS2[4].addr_value = (int *)(Un4);
   SI_window.DS2[5].addr_value = (int *)&(I2Bit);
   SI_window.DS2[6].addr_value = (int *)&(I1Bit);
   SI_window.DS2[7].addr_value = (int *)&(I0Bit);
   SI_window.DS2[8].addr_value = (int *)(Un3);
   SI_window.DS2[9].addr_value = (int *)(Un2);
   SI_window.DS2[10].addr_value = (int *)(Un1);
   SI_window.DS2[11].addr_value = (int *)&(f_X);
   SI_window.DS2[12].addr_value = (int *)&(f_N);
   SI_window.DS2[13].addr_value = (int *)&(f_Z);
   SI_window.DS2[14].addr_value = (int *)&(f_V);
   SI_window.DS2[15].addr_value = (int *)&(f_C);

   /* Map the address of values for DS3 region:				*/
   SI_window.DS3[0].addr_value = (int *)&(dummy);
   SI_window.DS3[1].addr_value = (int *)&(dummy);
   SI_window.DS3[2].addr_value = (int *)&(dummy);
   SI_window.DS3[3].addr_value = (int *)&(dummy);

   /* Map the address of values for DS4 region:				*/
   SI_window.DS4[0].addr_value = (int *)&(dummy);
   SI_window.DS4[1].addr_value = (int *)&(dummy);
   SI_window.DS4[2].addr_value = (int *)&(dummy);
   SI_window.DS4[3].addr_value = (int *)&(programCounter);

}


/*-----------------------------------------------------------------------
   SI_toggle_state_DS5:

   Toggle the state of the given DS in DS5.

   If the current state is inactive (2), this routine changes the DS
   state to active (1).

   If the current state is active (1), this routine changes the DS state
   to inactive (2).

   The user passes the target DS id number of the DS in DS5.  The DS id 
   number are from 0 to 7, where 0 is for the left most DS in DS5 and
   7 if the right most DS in DS5.
------------------------------------------------------------------------*/
void SI_toggle_state_DS5(ds5id)
int			ds5id;
{

   if (SI_window.DS5[ds5id].defined)
   {  if (SI_window.DS5[ds5id].attr.state==SI_SACTIVE)
	 SI_window.DS5[ds5id].attr.state = SI_SINACTIVE;
      else
	 SI_window.DS5[ds5id].attr.state = SI_SACTIVE;

      /* Change the actual display on the SI window:			*/
      SI_change_state(&SI_window.DS5[ds5id]);
   };
}
   

/*-----------------------------------------------------------------------
   SI_do_single_step_on:

   Turn the single step mode on.
------------------------------------------------------------------------*/
void SI_do_single_step_on()
{

   if (!sstep_on)
   {  sstep_on = true;
      SI_toggle_state_DS5(SSTEP_ON_DS);
      if (SI_window.CB1[START_SIM_CB].attr.state==SI_SINACTIVE)
      {  SI_window.CB1[TAKE_STEP_CB].attr.state = SI_SACTIVE;
         SI_change_state(&SI_window.CB1[TAKE_STEP_CB]);
      };
      SI_window.CB1[SSTEP_ON_CB].attr.state = SI_SINACTIVE;
      SI_window.CB1[SSTEP_OFF_CB].attr.state = SI_SACTIVE;
      SI_change_state(&SI_window.CB1[SSTEP_ON_CB]);
      SI_change_state(&SI_window.CB1[SSTEP_OFF_CB]);
   };
}
   

/*-----------------------------------------------------------------------
   SI_do_single_step_off:

   Turn the single step mode off.
------------------------------------------------------------------------*/
void SI_do_single_step_off()
{

   if (sstep_on)
   {  sstep_on = false;
      SI_toggle_state_DS5(SSTEP_ON_DS);
      SI_window.CB1[TAKE_STEP_CB].attr.state = SI_SINACTIVE;
      SI_change_state(&SI_window.CB1[TAKE_STEP_CB]);
      SI_window.CB1[SSTEP_OFF_CB].attr.state = SI_SINACTIVE;
      SI_window.CB1[SSTEP_ON_CB].attr.state = SI_SACTIVE;
      SI_change_state(&SI_window.CB1[SSTEP_ON_CB]);
      SI_change_state(&SI_window.CB1[SSTEP_OFF_CB]);
   };
}
   

/*-----------------------------------------------------------------------
   SI_do_start_sim:

   Set up start simulation flags.
------------------------------------------------------------------------*/
void SI_do_start_sim()
{

   SI_toggle_state_DS5(START_SIM_DS);
   if (sstep_on && (SI_window.CB1[TAKE_STEP_CB].attr.state==SI_SINACTIVE))
   {  SI_window.CB1[TAKE_STEP_CB].attr.state = SI_SACTIVE;
      SI_change_state(&SI_window.CB1[TAKE_STEP_CB]);
   };
   SI_window.CB1[EXIT_PROG_CB].attr.state = SI_SINACTIVE;
   SI_window.CB1[START_SIM_CB].attr.state = SI_SINACTIVE;
   SI_window.CB1[HALT_SIM_CB].attr.state = SI_SACTIVE;
   SI_window.CB1[LOAD_CODE_CB].attr.state = SI_SINACTIVE;
   SI_change_state(&SI_window.CB1[EXIT_PROG_CB]);
   SI_change_state(&SI_window.CB1[START_SIM_CB]);
   SI_change_state(&SI_window.CB1[HALT_SIM_CB]);
   SI_change_state(&SI_window.CB1[LOAD_CODE_CB]);
}
   

/*-----------------------------------------------------------------------
   SI_do_halt_sim:

   Set up halt simulation flags.
------------------------------------------------------------------------*/
void SI_do_halt_sim()
{

   SI_toggle_state_DS5(START_SIM_DS);
   if (SI_window.CB1[TAKE_STEP_CB].attr.state==SI_SACTIVE)
   {  SI_window.CB1[TAKE_STEP_CB].attr.state = SI_SINACTIVE;
      SI_change_state(&SI_window.CB1[TAKE_STEP_CB]);
   };
   SI_window.CB1[EXIT_PROG_CB].attr.state = SI_SACTIVE;
   SI_window.CB1[HALT_SIM_CB].attr.state = SI_SINACTIVE;
   SI_window.CB1[START_SIM_CB].attr.state = SI_SACTIVE;
   SI_window.CB1[LOAD_CODE_CB].attr.state = SI_SACTIVE;
   SI_change_state(&SI_window.CB1[EXIT_PROG_CB]);
   SI_change_state(&SI_window.CB1[START_SIM_CB]);
   SI_change_state(&SI_window.CB1[HALT_SIM_CB]);
   SI_change_state(&SI_window.CB1[LOAD_CODE_CB]);
}


/*-----------------------------------------------------------------------
   SI_mem_fetch:

   Read a word from memory.
   If memory is out of range, return 0xf0f0f0f0.
------------------------------------------------------------------------*/
unsigned int SI_mem_fetch(loc)
int			loc;
{  unsigned int			val;

   if (loc<0 || loc>=MAX_MEM_SIZE)
      val = 0xf0f0f0f0;
   else
      val = SI_memory.space[loc];

   switch (SI_memory_wsize)
   {  case 8:
	 return (val & 0xff);
	 break;
      case 16:
	 return (val & 0xffff);
	 break;
      case 32:
	 return (val & 0xffffffff);
	 break;
   };
}


/*-----------------------------------------------------------------------
   SI_mem_fetch_bp:

   Return true if the specified memory location is a break point.
   If the address is out of range, return false.
------------------------------------------------------------------------*/
int SI_mem_fetch_bp(loc)
int			loc;
{  unsigned int		val;

   if (loc<0 || loc>=MAX_MEM_SIZE)
      return (false);
   else
      return (SI_memory.brkpt[loc]);
}


/*-----------------------------------------------------------------------
   SI_mem_write:

   Write a word to memory.
   If memory is out of range, do nothing.
------------------------------------------------------------------------*/
void SI_mem_write(loc,val)
int			loc;
unsigned int		val;
{  void			SI_mem_quick_update();

   if (loc<0 || loc>=MAX_MEM_SIZE)
      return;
   else
   {  switch (SI_memory_wsize)
      {  case 8:
	    SI_memory.space[loc] = (val & 0xff);
	    break;
         case 16:
	    SI_memory.space[loc] = (val & 0xffff);
	    break;
         case 32:
	    SI_memory.space[loc] = (val & 0xffffffff);
	    break;
      };

      /* If memory window is mapped, update any values in window:	*/
      if (SI_mw_mapped)
         SI_mem_quick_update(loc,val);
   };
   return;
}


/*-----------------------------------------------------------------------
   SI_mem_write_bp:

   Change the breakpoint status of a memory location.
   If memory is out of range, do nothing.
------------------------------------------------------------------------*/
void SI_mem_write_bp(loc,val)
int			loc;
int			val;
{  void			SI_mem_quick_update();
   unsigned int		content;

   if (loc<0 || loc>=MAX_MEM_SIZE)
      return;
   else
   {  SI_memory.brkpt[loc] = val;

      /* If memory window is mapped, update any values in window:	*/
      content = SI_memory.space[loc];
      if (SI_mw_mapped)
         SI_mem_quick_update(loc,content);
   };
   return;
}
   

/*-----------------------------------------------------------------------
   SI_calc_mem_window:

   Calc the sizes for the memory display window.
   Memory will be displayed in hex.
------------------------------------------------------------------------*/
void SI_calc_mem_window()
{  char			dummy_string[MAXB_LEN+1];
   int			i,j,ii;
   unsigned int		key;

   /* Init the dummy string:						*/
   for (i=0; i<12; i++)
      dummy_string[i] = '0';
   dummy_string[i] = '\0';

   /* Define memory window (mw) main parameters:			*/
   hpadding = 2;
   vpadding = 1;
   SI_nline = 16;
   SI_mw_base = 16;			/* display all number in hex	*/

   /* Determine the height of the command buttons:			*/
   SI_mw_cb_height = vpadding + SI_font2_struct->max_bounds.ascent +
		    SI_font2_struct->max_bounds.descent + vpadding;
   SI_mw_cb_width = hpadding + XTextWidth(SI_font2_struct,dummy_string,
					6) + hpadding;

   /* Determine how many words to be displayed per line:		*/
   switch (SI_memory_wsize)
   {  case 8:
	 SI_wline = 32;
	 SI_ndigit = 2;
	 break;
      case 16:
	 SI_wline = 16;
	 SI_ndigit = 4;
	 break;
      case 32:
	 SI_wline = 8;
	 SI_ndigit = 8;
	 break;
   };

   /* Approximate the maximum size of the digit string:			*/
   SI_mw_w_width = hpadding + XTextWidth(SI_font4_struct,dummy_string,
					SI_ndigit) + hpadding;
   SI_mw_w_height = vpadding + SI_font4_struct->max_bounds.ascent +
		    SI_font4_struct->max_bounds.descent + vpadding;
   SI_mw_txt_offset = vpadding + SI_font4_struct->max_bounds.ascent;
	
   /* Approximate the width of the displayed address:			*/
   SI_mw_a_width = hpadding + XTextWidth(SI_font4_struct,dummy_string,
					5) + hpadding;
   SI_mw_a_height = SI_mw_w_height;

   /* Determine the size of command window:				*/
   SI_mw_com_height = 5 + vpadding + SI_mw_cb_height + vpadding + 5;

   /* Approximate the maximum size of mw:				*/
   SI_mw_width = hpadding + SI_mw_a_width + SI_wline*SI_mw_w_width + 
		 hpadding; 
   SI_mw_height = SI_mw_com_height + 2*vpadding + 
			SI_nline*SI_mw_w_height + vpadding;
   SI_mw_com_width = SI_mw_width-2;

   /* Start of words and addresses:					*/
   SI_mw_org_x = hpadding;
   SI_mw_org_y = SI_mw_com_height + 2*vpadding;

   /* Init the positions of the addresses and words windows:		*/
   key = 0;
   for (i=0; i<SI_nline; i++)
   {  for (j=0; j<SI_wline; j++)
      {  ii = i*SI_wline + j;
         SI_mw_wwindow[ii].x = SI_mw_org_x + SI_mw_a_width +
					j*SI_mw_w_width;
         SI_mw_wwindow[ii].y = SI_mw_org_y + i*SI_mw_w_height;
	 SI_mw_wwindow[ii].type = SI_MW_TDATA;
	 SI_mw_wwindow[ii].value = -5;
	 key++;
      };
      SI_mw_awindow[i].x = SI_mw_org_x;
      SI_mw_awindow[i].y = SI_mw_org_y + i*SI_mw_a_height;
      SI_mw_awindow[i].type = SI_MW_TADDR;
      SI_mw_awindow[i].value = i*SI_wline;
   };
}


/*-----------------------------------------------------------------------
   SI_create_mem_window:

   Create the actual memory window and child windows for displaying 
   memory words.
------------------------------------------------------------------------*/
void SI_create_mem_window()
{  unsigned long		valuemask;
   int				i,j,ii;
   void				SI_mem_draw_com();


   /* Create the toplevel for memory display:				*/
   SI_mw_hint.x = SI_high_x - SI_mw_width - 10;
   SI_mw_hint.y = SI_high_y - SI_mw_height - 10;
   SI_mw_hint.width = SI_mw_width;
   SI_mw_hint.height = SI_mw_height;
   SI_mw_hint.min_width = SI_mw_width;
   SI_mw_hint.min_height = SI_mw_height;
   SI_mw_hint.max_width = SI_mw_width;
   SI_mw_hint.max_height = SI_mw_height;
   SI_mw_hint.flags = PPosition | PSize | PMinSize | PMaxSize;

   SI_mw_toplevel = XCreateSimpleWindow(SI_display,
			DefaultRootWindow(SI_display),
			SI_mw_hint.x,SI_mw_hint.y,
			SI_mw_hint.width,SI_mw_hint.height,2,0,1);
   XSetStandardProperties(SI_display,SI_mw_toplevel,"ViewMemory",
				"ViewMemory",None,0,0,&SI_mw_hint);
   valuemask = ExposureMask | ButtonPressMask;
   XSelectInput(SI_display,SI_mw_toplevel,valuemask);

   /* Create the addresses and words windows:				*/
   for (i=0; i<SI_nline; i++)
   {  for (j=0; j<SI_wline; j++)
      {  ii = i*SI_wline + j;
         SI_mw_wwindow[ii].ds = 
		XCreateSimpleWindow(SI_display,SI_mw_toplevel,
				    SI_mw_wwindow[ii].x,
				    SI_mw_wwindow[ii].y,
				    SI_mw_w_width,SI_mw_w_height,0,0,1);
         valuemask = ButtonPressMask | KeyPressMask;
         XSelectInput(SI_display,SI_mw_wwindow[ii].ds,valuemask);
         XDefineCursor(SI_display,SI_mw_wwindow[ii].ds,SI_ptr_cursor);
         XMapWindow(SI_display,SI_mw_wwindow[ii].ds);
	 SI_mw_wwindow[ii].bp = false;
      };
      SI_mw_pane[i] = 0;
      SI_mw_old_pane[i] = 1;
      SI_mw_awindow[i].ds = 
		XCreateSimpleWindow(SI_display,SI_mw_toplevel,
				    SI_mw_awindow[i].x,
				    SI_mw_awindow[i].y,
				    SI_mw_a_width,SI_mw_a_height,0,0,1);
      valuemask = ButtonPressMask | KeyPressMask;
      XSelectInput(SI_display,SI_mw_awindow[i].ds,valuemask);
      XDefineCursor(SI_display,SI_mw_awindow[i].ds,SI_ptr_cursor);
      XMapWindow(SI_display,SI_mw_awindow[i].ds);
   };

   /* Create the command window for the memory window:			*/
   SI_mw_com_window = XCreateSimpleWindow(SI_display,SI_mw_toplevel,
			    	0,0,
				SI_mw_com_width,SI_mw_com_height,
				1,0,1);
   valuemask = NoEventMask;
   XSelectInput(SI_display,SI_mw_com_window,valuemask);
   XDefineCursor(SI_display,SI_mw_com_window,SI_cursor);
   XSetWindowBackgroundPixmap(SI_display,SI_mw_com_window,SI_bgrd4);
   XMapWindow(SI_display,SI_mw_com_window);

   /* Create the 'UP' button:						*/
   SI_mw_com_up_window = XCreateSimpleWindow(SI_display,SI_mw_com_window,
			    	hpadding,5 + vpadding,
				SI_mw_cb_width,SI_mw_cb_height,
				1,0,1);
   valuemask = ButtonPressMask;
   XSelectInput(SI_display,SI_mw_com_up_window,valuemask);
   XDefineCursor(SI_display,SI_mw_com_up_window,SI_CB_cursor);
   XMapWindow(SI_display,SI_mw_com_up_window);

   /* Create the 'DOWN' button:						*/
   SI_mw_com_down_window = XCreateSimpleWindow(SI_display,SI_mw_com_window,
			    	hpadding + SI_mw_cb_width + 3*hpadding +
					hpadding,
				5 + vpadding,
				SI_mw_cb_width,SI_mw_cb_height,
				1,0,1);

   valuemask = ButtonPressMask;
   XSelectInput(SI_display,SI_mw_com_down_window,valuemask);
   XDefineCursor(SI_display,SI_mw_com_down_window,SI_CB_cursor);
   XMapWindow(SI_display,SI_mw_com_down_window);

   /* Create the 'DUMP' button:						*/
   SI_mw_com_dump_window = XCreateSimpleWindow(SI_display,SI_mw_com_window,
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
					hpadding,
				5 + vpadding,
				SI_mw_cb_width,SI_mw_cb_height,
				1,0,1);

   valuemask = ButtonPressMask;
   XSelectInput(SI_display,SI_mw_com_dump_window,valuemask);
   XDefineCursor(SI_display,SI_mw_com_dump_window,SI_CB_cursor);
   XMapWindow(SI_display,SI_mw_com_dump_window);


   /* Create the 'CLEAR' button:					*/
   SI_mw_com_clear_window = XCreateSimpleWindow(SI_display,SI_mw_com_window,
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
					hpadding,
				5 + vpadding,
				SI_mw_cb_width,SI_mw_cb_height,
				1,0,1);

   valuemask = ButtonPressMask;
   XSelectInput(SI_display,SI_mw_com_clear_window,valuemask);
   XDefineCursor(SI_display,SI_mw_com_clear_window,SI_CB_cursor);
   XMapWindow(SI_display,SI_mw_com_clear_window);


   /* Create the 'SetBPt' button:					*/
   SI_mw_com_setbpt_window = XCreateSimpleWindow(SI_display,SI_mw_com_window,
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
					hpadding,
				5 + vpadding,
				SI_mw_cb_width,SI_mw_cb_height,
				1,0,1);

   valuemask = ButtonPressMask;
   XSelectInput(SI_display,SI_mw_com_setbpt_window,valuemask);
   XDefineCursor(SI_display,SI_mw_com_setbpt_window,SI_CB_cursor);
   XMapWindow(SI_display,SI_mw_com_setbpt_window);


   /* Create the 'ClrBPt' button:					*/
   SI_mw_com_clrbpt_window = XCreateSimpleWindow(SI_display,SI_mw_com_window,
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
			    	hpadding + SI_mw_cb_width + 3*hpadding +
					hpadding,
				5 + vpadding,
				SI_mw_cb_width,SI_mw_cb_height,
				1,0,1);

   valuemask = ButtonPressMask;
   XSelectInput(SI_display,SI_mw_com_clrbpt_window,valuemask);
   XDefineCursor(SI_display,SI_mw_com_clrbpt_window,SI_CB_cursor);
   XMapWindow(SI_display,SI_mw_com_clrbpt_window);

   /* Calc the empty space between the buttons:				*/
   SI_mw_com_left_x = hpadding
			+ SI_mw_cb_width + 3*hpadding + hpadding 
			+ SI_mw_cb_width + 3*hpadding + hpadding
			+ SI_mw_cb_width + 3*hpadding + hpadding
			+ SI_mw_cb_width + 3*hpadding + hpadding
			+ SI_mw_cb_width + 3*hpadding + hpadding
			+ SI_mw_cb_width;

   /* Create the 'QUIT' button:						*/
   SI_mw_com_quit_window = XCreateSimpleWindow(SI_display,SI_mw_com_window,
				SI_mw_com_width - hpadding - 
					SI_mw_cb_width - hpadding,
				5 + vpadding,
				SI_mw_cb_width,SI_mw_cb_height,
				1,0,1);

   /* Calc the empty space between the buttons:				*/
   SI_mw_com_right_x = SI_mw_com_width - hpadding - SI_mw_cb_width - hpadding;

   valuemask = ButtonPressMask;
   XSelectInput(SI_display,SI_mw_com_quit_window,valuemask);
   XDefineCursor(SI_display,SI_mw_com_quit_window,SI_CB_cursor);
   XMapWindow(SI_display,SI_mw_com_quit_window);

   /* Display the memory window:					*/
   XMapWindow(SI_display,SI_mw_toplevel);
   SI_mem_draw_com(true,true,true,true,true,false,false,true);
}



/*-----------------------------------------------------------------------
   SI_map_mem_window:

   Map the memory window.
   The memory window must have already been created.
------------------------------------------------------------------------*/
void SI_map_mem_window()
{

   XMapWindow(SI_display,SI_mw_toplevel);
}


/*-----------------------------------------------------------------------
   SI_unmap_mem_window:

   Unmap the memory window.
   When unmap, the memory window can be called later at little cost.
------------------------------------------------------------------------*/
void SI_unmap_mem_window()
{

   XUnmapWindow(SI_display,SI_mw_toplevel);
}


/*-----------------------------------------------------------------------
   SI_mw_display_value:

   Display the value (address or memory) into the specified window with
   specified text offset.

   The value is converted to a text string before output.
------------------------------------------------------------------------*/
void SI_mw_display_value(square,txt_offset,bpset)
mw			*square;
int			txt_offset,
			bpset;
{  int	 		slen,dlen;
   int			base,center;
   int			txt_width;
   char			str[MAXB_LEN+1];
   Font			font;
   XFontStruct		*font_struct;


   /* Determine the # of digits for conversion:				*/
   switch (square->type)
   {  case SI_MW_TADDR:			/* address			*/
	 slen = 4;
	 break;
      case SI_MW_TDATA:			/* data				*/
	 slen = SI_ndigit;
	 break;
   };

   /* Convert the value:						*/
   base = SI_mw_base;
   SI_number2str(square->value,base,str,slen);

   /* Append a colon to the address:					*/
   if (square->type==SI_MW_TADDR)
   {  str[slen] = ':';
      str[slen+1] = '\0';
   };

   /* Select which font based on breakpoint:				*/
   if (bpset)
   {  font = SI_font6;
      font_struct = SI_font6_struct;
   } 
   else
   {  font = SI_font4;
      font_struct = SI_font4_struct;
   };

   /* Center the text:							*/
   dlen = strlen(str);
   txt_width = XTextWidth(font_struct,str,dlen);
   switch (square->type)
   {  case SI_MW_TADDR:
	 center = (SI_mw_a_width - txt_width)/2;
	 break;
      case SI_MW_TDATA:
	 center = (SI_mw_w_width - txt_width)/2;
	 break;
   };

   /* Print it:								*/
   XSetFont(SI_display,SI_gc,font);
   XClearWindow(SI_display,square->ds);
   XDrawImageString(SI_display,square->ds,SI_gc,center,txt_offset,str,dlen);
}


/*-----------------------------------------------------------------------
   SI_mem_draw_com:

   Draw the commands of the memory command buttons.
------------------------------------------------------------------------*/
void SI_mem_draw_com(newbgrd,upon,downon,dumpon,clearon,setbpon,
							clrbpon,quiton)
int			newbgrd,
			upon,
			downon,
			dumpon,
			clearon,
			setbpon,
			clrbpon,
			quiton;
{  int			txt_width,center,txt_offset;

   /* Calc the text offset:						*/
   txt_offset = vpadding + SI_font2_struct->max_bounds.ascent;

   /* Draw the names of the command buttons:				*/
   txt_width = XTextWidth(SI_font2_struct,"Up",2);
   center = (SI_mw_cb_width - txt_width)/2;
   if (newbgrd)
      if (upon)
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_up_window,
								SI_bgrd3);
      else
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_up_window,
								SI_bgrd4);
   XClearWindow(SI_display,SI_mw_com_up_window);
   XSetFont(SI_display,SI_gc,SI_font2);
   XDrawString(SI_display,SI_mw_com_up_window,SI_gc,center,
		txt_offset,"Up",2);

   txt_width = XTextWidth(SI_font2_struct,"Down",4);
   center = (SI_mw_cb_width - txt_width)/2;
   if (newbgrd)
      if (downon)
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_down_window,
								SI_bgrd3);
      else
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_down_window,
								SI_bgrd4);
   XClearWindow(SI_display,SI_mw_com_down_window);
   XSetFont(SI_display,SI_gc,SI_font2);
   XDrawString(SI_display,SI_mw_com_down_window,SI_gc,center,
		txt_offset,"Down",4);

   txt_width = XTextWidth(SI_font2_struct,"Dump",4);
   center = (SI_mw_cb_width - txt_width)/2;
   if (newbgrd)
      if (dumpon)
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_dump_window,
								SI_bgrd3);
      else
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_dump_window,
								SI_bgrd4);
   XClearWindow(SI_display,SI_mw_com_dump_window);
   XSetFont(SI_display,SI_gc,SI_font2);
   XDrawString(SI_display,SI_mw_com_dump_window,SI_gc,center,
		txt_offset,"Dump",4);

   txt_width = XTextWidth(SI_font2_struct,"Clear",5);
   center = (SI_mw_cb_width - txt_width)/2;
   if (newbgrd)
      if (clearon)
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_clear_window,
								SI_bgrd3);
      else
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_clear_window,
								SI_bgrd4);
   XClearWindow(SI_display,SI_mw_com_clear_window);
   XSetFont(SI_display,SI_gc,SI_font2);
   XDrawString(SI_display,SI_mw_com_clear_window,SI_gc,center,
		txt_offset,"Clear",5);

   txt_width = XTextWidth(SI_font2_struct,"SetBPt",6);
   center = (SI_mw_cb_width - txt_width)/2;
   if (newbgrd)
      if (setbpon)
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_setbpt_window,
								SI_bgrd3);
      else
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_setbpt_window,
								SI_bgrd4);
   XClearWindow(SI_display,SI_mw_com_setbpt_window);
   XSetFont(SI_display,SI_gc,SI_font2);
   XDrawString(SI_display,SI_mw_com_setbpt_window,SI_gc,center,
		txt_offset,"SetBPt",6);

   txt_width = XTextWidth(SI_font2_struct,"ClrBPt",6);
   center = (SI_mw_cb_width - txt_width)/2;
   if (newbgrd)
      if (clrbpon)
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_clrbpt_window,
								SI_bgrd3);
      else
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_clrbpt_window,
								SI_bgrd4);
   XClearWindow(SI_display,SI_mw_com_clrbpt_window);
   XSetFont(SI_display,SI_gc,SI_font2);
   XDrawString(SI_display,SI_mw_com_clrbpt_window,SI_gc,center,
		txt_offset,"ClrBPt",6);

   txt_width = XTextWidth(SI_font2_struct,"Quit",4);
   center = (SI_mw_cb_width - txt_width)/2;
   if (newbgrd)
      if (quiton)
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_quit_window,
								SI_bgrd3);
      else
         XSetWindowBackgroundPixmap(SI_display,SI_mw_com_quit_window,
								SI_bgrd4);
   XClearWindow(SI_display,SI_mw_com_quit_window);
   XSetFont(SI_display,SI_gc,SI_font2);
   XDrawString(SI_display,SI_mw_com_quit_window,SI_gc,center,
		txt_offset,"Quit",4);
}


/*-----------------------------------------------------------------------
   SI_mem_quick_update:

   Scan through the display window quickly and determine if any location
   need to be changed based on the given memory location and content.
------------------------------------------------------------------------*/
void SI_mem_quick_update(address,memvalue)
unsigned int			address;
unsigned int			memvalue;
{  int			i,j,ii;
   unsigned int		addr;
   int			membp;

      for (i=0; i<SI_nline; i++)
      {  addr = SI_mw_awindow[i].value;
	 if (address>=addr && address<(addr+SI_wline))
         {  ii = i*SI_wline + (address-addr);
	    membp = SI_mem_fetch_bp(address);
	    if (memvalue!=SI_mw_wwindow[ii].value ||
		membp!=SI_mw_wwindow[ii].bp)
	    {  SI_mw_wwindow[ii].value = memvalue;
	       SI_mw_wwindow[ii].bp = membp;
	       SI_mw_display_value(&SI_mw_wwindow[ii],SI_mw_txt_offset,
								membp);
	    };
         };
      };
}


/*-----------------------------------------------------------------------
   SI_mem_display:

   Print the content of word windows and address windows.
   Only update the values that have been changed.  Exception is when all
   forces every values to be redisplayed.
------------------------------------------------------------------------*/
void SI_mem_display(all)
int			all;		/* true if display all		*/
{  int			i,j,ii;
   unsigned int		addr,
			memvalue;
   int			new_pane,
			membp;

   if (SI_mw_mapped)
   {  /* Redraw the values of memory:					*/
      for (i=0; i<SI_nline; i++)
      {  new_pane = false;

	 /* If there is a break in the addresses, signal new pane:	*/
	 if (SI_mw_old_pane[i]!=SI_mw_pane[i])
	 {  SI_mw_old_pane[i] = SI_mw_pane[i];
	    new_pane = true;
	    if (SI_mw_pane[i]==0)
	       XSetWindowBackgroundPixmap(SI_display,SI_mw_awindow[i].ds,
								SI_bgrd3);
	    else
	       XSetWindowBackgroundPixmap(SI_display,SI_mw_awindow[i].ds,
								SI_bgrd5);
	 };

	 /* Print new address:						*/
	 addr = SI_mw_awindow[i].value;
         SI_mw_display_value(&SI_mw_awindow[i],SI_mw_txt_offset,false);

	 /* Update the words on each line, if neccessary:		*/
	 for (j=0; j<SI_wline; j++)
         {  ii = i*SI_wline + j;
	    memvalue = SI_mem_fetch(addr);
	    membp = SI_mem_fetch_bp(addr);
	    addr++;
	    if (all || memvalue!=SI_mw_wwindow[ii].value || new_pane ||
		membp!=SI_mw_wwindow[ii].bp)
	    {  SI_mw_wwindow[ii].value = memvalue;
	       SI_mw_wwindow[ii].bp = membp;
	       if (SI_mw_pane[i]==0)
	          XSetWindowBackgroundPixmap(SI_display,SI_mw_wwindow[ii].ds,
					 SI_bgrd3);
	       else
	          XSetWindowBackgroundPixmap(SI_display,SI_mw_wwindow[ii].ds,
					 SI_bgrd5);
	       SI_mw_display_value(&SI_mw_wwindow[ii],SI_mw_txt_offset,membp);
	    };
         };
      };
   };
}


/*-----------------------------------------------------------------------
   SI_mem_up:

   Move the memory window up.
   This action uncovers the lower memory locations by shifting the values
   down.
------------------------------------------------------------------------*/
void SI_mem_up()
{  int			key1;
   int			i,j;


   /* Shift all rows down by one:					*/
   for (i=SI_nline-1; i>0; i--)
   {  SI_mw_awindow[i].value = SI_mw_awindow[i-1].value;
      SI_mw_pane[i] = SI_mw_pane[i-1];
   };

   /* Load in new upper row:						*/
   key1 = SI_mw_awindow[0].value - SI_wline;
   SI_mw_awindow[0].value = key1 & 0x0000ffff;
   SI_mw_pane[0] = SI_mw_pane[1];

   /* Display new values:						*/
   SI_mem_display(false);
}


/*-----------------------------------------------------------------------
   SI_mem_down:

   Move the memory window down.
   This action uncovers the upper memory locations by shifting the values
   down.
------------------------------------------------------------------------*/
void SI_mem_down()
{  int			key1;
   int			i,j;


   /* Shift all rows up by one:						*/
   for (i=0; i<SI_nline-1; i++)
   {  SI_mw_awindow[i].value = SI_mw_awindow[i+1].value;
      SI_mw_pane[i] = SI_mw_pane[i+1];
   };

   /* Load in new bottom row:						*/
   key1 = SI_mw_awindow[SI_nline-1].value + SI_wline;
   SI_mw_awindow[SI_nline-1].value = key1 & 0x0000ffff;
   SI_mw_pane[SI_nline-1] = SI_mw_pane[SI_nline-2];

   /* Display new values:						*/
   SI_mem_display(false);
}


/*-----------------------------------------------------------------------
   SI_mem_dump_memory:

   Dump the memory range to trace dump file.
------------------------------------------------------------------------*/
void SI_mem_dump_memory(start,end)
unsigned int		start,
			end;
{  int			i,
			count;

   /* Open trace dump file is not already opened:			*/
   if (!SI_TraceDumpOn)
      SI_TD_ofp = fopen(SI_DUMP_FNAME,"a");

   /* Print header:							*/
   fprintf(SI_TD_ofp,"----------Memory Dump-----------------------------------------------------------");

   /* Loop and dump:							*/
   count = SI_wline;
   for (i=start; i<=end; i++)
   {  if (count>=SI_wline)
      {  count = 0;
	 fprintf(SI_TD_ofp,"\n%04x: ",i);
      };

      switch (SI_mw_base)
      {  case 8:
            fprintf(SI_TD_ofp,"%02x ",SI_mem_fetch(i));
	    break;

	 case 16:
            fprintf(SI_TD_ofp,"%04x ",SI_mem_fetch(i));
	    break;

	 case 32:
            fprintf(SI_TD_ofp,"%08x ",SI_mem_fetch(i));
	    break;
      };
      count++;
   };
   fprintf(SI_TD_ofp,"\n");
   fprintf(SI_TD_ofp,"--------------------------------------------------------------------------------\n");

   /* Restore trace file back to original state:			*/
   if (!SI_TraceDumpOn)
      fclose(SI_TD_ofp);
}


/*-----------------------------------------------------------------------
   SI_mem_dump:

   Dump the content of an user-specified memory range to trace dump file.
------------------------------------------------------------------------*/
int SI_mem_dump()
{  char				str[20];
   static int			first_time=true;
   int				esc;
   int				SI_prompt_get_str();
   void				SI_prompt_error();

   /* Get the start range address:					*/
   if (first_time)
   {  SI_range_start_address = 0;
      SI_range_end_address = 0x0f;
      first_time = false;
   };

   SI_number2str(SI_range_start_address,SI_mw_base,str,4);
   esc = SI_prompt_get_str("Memory Dump Start Address",str,4,0,
			&SI_range_start_address,SI_mw_base);
   if (esc)	return;
   SI_number2str(SI_range_end_address,SI_mw_base,str,4);
   esc = SI_prompt_get_str("Memory Dump End Address",str,4,0,
			&SI_range_end_address,SI_mw_base);
   if (esc)	return;

   if (SI_range_start_address<=SI_range_end_address && 
					SI_range_start_address>=0)
      SI_mem_dump_memory(SI_range_start_address,SI_range_end_address);
   else
      SI_prompt_error("Sorry, Address Range Error.");
}


/*-----------------------------------------------------------------------
   SI_mem_clear:

   Clear the simulator memory and breakpoints.
------------------------------------------------------------------------*/
void SI_mem_clear()
{  unsigned int		i;

   for (i=0; i<MAX_MEM_SIZE; i++)
   {  SI_mem_write(i,0);
      SI_mem_write_bp(i,false);
   };
}


/*-----------------------------------------------------------------------
   SI_edit_string:

   Edit the given string in the given window.
   The string being edited is centered on the specified window.

   In addition to the text parameters, the caller must also pass a
   pointer to the screen refresh routine.  This screen refresh routine
   is called when an Expose event is encountered.  Since this routine
   can be called from any circumstances, a specific expose event handling
   function is not really efficient.  Thus, individual expose event 
   handling function is necessary.

   Mouse button2 is used to "escape" out of the editing mode.  This 
   escape restore the original content of the values.

   Any other mouse buttons acts as the <return> and terminates the 
   current editing session.

   Unless suppressed by consumed, button pressed events are pushed back 
   onto the event queue for further processing.  Other events are consumed.

   Function returns true if user ESCaped.  ESC is specified by pressing
   Button2 (the middle button).
------------------------------------------------------------------------*/
int SI_edit_string(window,width,txt_offset,font_struct,pix,str,slen,type,
			aint,base,expose_ptr,consumed)
Window			window;		/* window of the string		*/
int			width,		/* width of the window		*/
			txt_offset;	/* vertical text offset 	*/
XFontStruct		*font_struct;	/* font of the text		*/
Pixmap			pix;		/* original background pixmap	*/
char			*str;		/* the old/new text		*/
unsigned int		slen,		/* maximum length of text	*/
			type,		/* 0=number, 1=ASCII		*/
			*aint,		/* value of string, if valid	*/
			base;		/* numerical base of value, if
						valid			*/
void			(*expose_ptr)();
					/* screen refresh routine	*/
int			consumed;	/* true==consume the button evnt*/
{  KeySym		key;
   char			text[MAXB_LEN+1];
   char			digit;
   int			nb;
   int			center,
			len,
			done,
			fnz,
			stop,
			ndx,
			i,
			txt_width;
   char			str_copy[250];
   unsigned int		intvalue_copy;
   int			esc;


   /* Make a copy of the original values for recovery:			*/
   for (i=0; i<(strlen(str)+1); i++)
      str_copy[i] = str[i];
   if (type==0)
      intvalue_copy = *aint;

   /* For numeric type, extract leading zeroes:				*/
   /* Default the position of the first non-zero:			*/
   if (type==0)
   {  if (strlen(str)>0)
         fnz = strlen(str);
      else
         fnz = 0;

      /* Find first non-zero character:					*/
      stop = false;
      for (i=0; i<strlen(str) && !stop; i++)
         if (str[i]!='0')
         {  fnz = i;
            stop = true;
         };

      /* Ignore the leading zeroes:					*/
      ndx = 0;
      for (i=fnz; i<strlen(str); i++)
      {  str[ndx] = str[i];
         ndx++;
      };
      str[ndx] = '\0';
      len = ndx;
   }
   else
      len = strlen(str);

   /* If the string is NULL, put in a '^' or '0':			*/
   if (len==0 && type==1)
   {  str[0] = '^';
      str[1] = '\0';
   }
   else if (len==0 && type==0)
   {  str[0] = '0';
      str[1] = '\0';
   };

   /* Set up background and font:					*/
   XSetFont(SI_display,SI_gc,font_struct->fid);
   XSetWindowBackgroundPixmap(SI_display,window,SI_bgrd1);

   /* Display new value:						*/
   txt_width = XTextWidth(font_struct,str,strlen(str));
   center = (width - txt_width)/2;
   XClearWindow(SI_display,window);
   XDrawImageString(SI_display,window,SI_gc,center,txt_offset,
		    str,strlen(str));

   esc = false;
   SI_mw_setbpt_selected = false;
   SI_mw_clrbpt_selected = false;

   done = false;
   /* Loop for data:							*/
   while (!done)
   {

      XNextEvent(SI_display,&SI_event);
      switch (SI_event.type)
      {  case Expose:
	    if (SI_event.xexpose.count==0)
	       (*expose_ptr)();
   	       XSetFont(SI_display,SI_gc,font_struct->fid);
   	       XSetWindowBackgroundPixmap(SI_display,window,SI_bgrd1);
               txt_width = XTextWidth(font_struct,str,strlen(str));
               center = (width - txt_width)/2;
               XClearWindow(SI_display,window);
               XDrawImageString(SI_display,window,SI_gc,center,txt_offset,
			         str,strlen(str));
	    break;

	 case ButtonPress:
	    /* Button pressed is equivalent to <return>:		*/
	    /* The button pressed event is but back on queue for other
	       processing:						*/
	    if (SI_event.xbutton.button==Button2)
	    {  /* Restore the old values:				*/
   	       for (i=0; i<(strlen(str_copy)+1); i++)
      	          str[i] = str_copy[i];
   	       if (type==0)
      	          *aint = intvalue_copy;

	       /* Button2 specifies ESC:				*/
	       esc = true;
	    } 
	    else 
	       str[len] = '\0';

	    /* If ESC, do nothing and consume the event:		*/
	    if (!esc)
	    {  /* Set breakpoint button was pressed:			*/
	       if (SI_event.xbutton.window==SI_mw_com_setbpt_window)
	          SI_mw_setbpt_selected = true;

	       /* Clr breakpoint button was pressed:			*/
	       else if (SI_event.xbutton.window==SI_mw_com_clrbpt_window)
	          SI_mw_clrbpt_selected = true;

	       /* Preserve the button pressed event if 
	          1) consumed says so, and
	          2) the 'selected' window is not the editing window:	*/
	       else if (!consumed && SI_event.xbutton.window!=window)
	          XPutBackEvent(SI_display,&SI_event);
	    };

	    done = true;
	    break;

	 case KeyPress:
	    /* Convert to standard key codes:				*/
	    nb = XLookupString(&SI_event.xkey,text,MAXB_LEN,&key,0);

	    /* Delete a character:					*/
	    if (key==XK_Delete)
	    {  if (len>0)
	       {  len--;
		  str[len] = '\0';
		  if (type==0)
		     *aint = *aint/base;

   		  /* If the string is NULL, put in a '^' or '0':	*/
   		  if (len==0 && type==1)
   		  {  str[0] = '^';
      		     str[1] = '\0';
   		  }
		  else if (len==0 && type==0)
   		  {  str[0] = '0';
      		     str[1] = '\0';
   		  };
	       };
	    }

	    /* End of an input:						*/
	    else if (key==XK_Return)
	    {  str[len] = '\0';
	       done = true;
	    } 

	    /* Input for numerical type:				*/
	    else if (nb==1 && type==0 && len<slen &&
			((text[0]>='0' && text[0]<='9') || 
		 	(text[0]>='a' && text[0]<='f')))
	    {  if ((base==10 && text[0]>'9') || 
		   (base==8 && text[0]>'7') ||
		   (base==2 && text[0]>'1'))
		  /* Error, do nothing.					*/
		  ;
	       else
	       {  str[len] = text[0];
	          len++;
	          str[len] = '\0';
	          if (text[0]>'9')
		     digit = text[0] - 'a' + 10;
	          else
		     digit = text[0] - '0';
		  if (*aint==0 && digit==0)
		  {  str[0] = text[0];
		     str[1] = '\0';
		     len = 0;
		     *aint = digit;
		  }
		  else
	             *aint = (*aint)*base + digit;
	       };
	    }

	    /* Input for ASCII type:					*/
	    else if (nb==1 && type==1 && len<slen &&
			((text[0]>='a' && text[0]<='z') ||
			 (text[0]>='A' && text[0]<='Z') ||
			 (text[0]>=' ' && text[0]<='A') ||
			 (text[0]=='_' || text[0]=='~')))
	    {  str[len] = text[0];
	       len++;
	       str[len] = '\0';
	    };

	    /* Display new value:					*/
      	    txt_width = XTextWidth(font_struct,str,strlen(str));
      	    center = (width - txt_width)/2;
      	    XClearWindow(SI_display,window);
      	    XDrawImageString(SI_display,window,SI_gc,center,txt_offset,
				    str,strlen(str));
	    break;
      }; /* end switch							*/
   }; /* end while							*/

   /* Print new value:							*/
   txt_width = XTextWidth(font_struct,str,strlen(str));
   center = (width - txt_width)/2;
   XSetWindowBackgroundPixmap(SI_display,window,pix);
   XClearWindow(SI_display,window);
   XDrawImageString(SI_display,window,SI_gc,center,txt_offset,str,
			strlen(str));

   return(esc);
}


/*-----------------------------------------------------------------------
   SI_mem_edit_expose:

   Take care of window exose events during memory editing.
------------------------------------------------------------------------*/
void SI_mem_edit_expose()
{

       if (SI_event.xexpose.window==SI_mw_toplevel)
       {  SI_mem_display(true);
          SI_mem_draw_com(false,true,true,true,true,false,false,true);
       }
       else if (SI_event.xexpose.window==SI_toplevel ||
		SI_event.xexpose.window==SI_g1_window)
       {  SI_expose_event = true;
	  SI_draw_window();
          SI_expose_event = false;
       };
}


/*-----------------------------------------------------------------------
   SI_mem_edit:

   Edit a value of the address or word.

   Function returns true if user selected ESC.
------------------------------------------------------------------------*/
int SI_mem_edit(square,pix,bpset)
mw			*square;
Pixmap			pix;
int			bpset;
{  int			slen;
   char			str[MAXB_LEN+1];
   int			base;
   unsigned int		intvalue;
   XFontStruct		*font_struct;
   int			esc;

   /* Determine the # of digits for conversion:				*/
   switch (square->type)
   {  case SI_MW_TADDR:			/* address			*/
	 slen = 4;
	 break;
      case SI_MW_TDATA:			/* data				*/
	 slen = SI_ndigit;
	 break;
   };

   /* Find out which font to use:					*/
   if (bpset)
      font_struct = SI_font6_struct;
   else
      font_struct = SI_font4_struct;

   /* Edit value:							*/
   esc = false;
   base = SI_mw_base;
   intvalue = square->value;
   switch (square->type)
   {  case SI_MW_TADDR:
         SI_number2str(square->value,base,str,slen);
	 esc = SI_edit_string(square->ds,SI_mw_a_width,SI_mw_txt_offset,
			font_struct,pix,str,slen,0,&intvalue,base,
			SI_mem_edit_expose,false);
	 if (!esc)
	    square->value = intvalue;
	 SI_mw_display_value(square,SI_mw_txt_offset,false);
	 break;

      case SI_MW_TDATA:
	 SI_number2str(square->value,base,str,slen);
	 esc = SI_edit_string(square->ds,SI_mw_w_width,SI_mw_txt_offset,
			font_struct,pix,str,slen,0,&intvalue,base,
			SI_mem_edit_expose,false);
	 if (!esc)
	    square->value = intvalue;
	 SI_mw_display_value(square,SI_mw_txt_offset,bpset);
	 break;
   };

   return(esc);
}


/*-----------------------------------------------------------------------
   SI_mem_update:

   Scan and update the 'selected' memory location or address in the 
   memory window.
------------------------------------------------------------------------*/
void SI_mem_update()
{  int			i,j,ii;
   int			row,col;
   int			key;
   Window		child;
   Pixmap 		pix;
   int			bpset;
   int			esc;


   child = SI_event.xbutton.window;
   for (i=0; i<SI_nline; i++)
   {  switch (SI_mw_pane[i])
      {  case 0:
	    pix = SI_bgrd3;
	    break;
	 case 1:
	    pix = SI_bgrd5;
	    break;
      };

      /* Check the words:						*/
      for (j=0; j<SI_wline; j++)
      {  ii = i*SI_wline + j;
	 if (child==SI_mw_wwindow[ii].ds)
	 {  /* Turn on either set or clear breakpoint command:		*/
	    key = SI_mw_awindow[i].value + j;
	    bpset = SI_mem_fetch_bp(key);
	    if (bpset)
               SI_mem_draw_com(true,true,true,true,true,false,true,true);
	    else
               SI_mem_draw_com(true,true,true,true,true,true,false,true);

	    /* Allow the user to edit word:				*/
	    esc = SI_mem_edit(&SI_mw_wwindow[ii],pix,bpset);

	    /* Update memory:						*/
	    key = SI_mw_awindow[i].value + j;
	    SI_mem_write(key,SI_mw_wwindow[ii].value);

	    /* Set/Clear breakpoints properly:				*/
	    if (!bpset && SI_mw_setbpt_selected)
	       SI_mem_write_bp(key,true);
	    else if (bpset && SI_mw_clrbpt_selected)
	       SI_mem_write_bp(key,false);
	       
            SI_mem_draw_com(true,true,true,true,true,false,false,true);
	    SI_mem_display(false);
	    return;
	 };
      };

      /* Check the addresses:						*/
      if (child==SI_mw_awindow[i].ds)
      {  esc = SI_mem_edit(&SI_mw_awindow[i],pix,false);

	 if (!esc)
	 {  /* If there is a break in the address, change pane shading:	*/
	    if (i!=0 && 
	        ((SI_mw_awindow[i-1].value+SI_wline)&0xffff)!=
						SI_mw_awindow[i].value)
	       SI_mw_pane[i] = SI_mw_pane[i-1]^1;

	    /* Update memory:						*/
	    key = SI_mw_awindow[i].value;
	    for (row=i; row<SI_nline; row++)
	    {  SI_mw_awindow[row].value = key & 0x0000ffff;
	       key = key + SI_wline;
	       SI_mw_pane[row] = SI_mw_pane[i];
	    };
	 };
         SI_mem_draw_com(true,true,true,true,true,false,false,true);
	 SI_mem_display(false);
	 return;
      };
   };
}


/*-----------------------------------------------------------------------
   SI_mem_dm_dynamic:

   Process button press events for memory window.
------------------------------------------------------------------------*/
void SI_mem_dm_dynamic()
{

   /* If memory window is active, process like normal:			*/
   if (SI_mw_mapped)
   {  if (SI_event.xbutton.window==SI_mw_com_up_window)
         SI_mem_up();
      else if (SI_event.xbutton.window==SI_mw_com_down_window)
         SI_mem_down();
      else if (SI_event.xbutton.window==SI_mw_com_dump_window)
         SI_mem_dump();
      else if (SI_event.xbutton.window==SI_mw_com_clear_window)
         SI_mem_clear();
      else if (SI_event.xbutton.window==SI_mw_com_quit_window)
      {  SI_unmap_mem_window();
         SI_mw_mapped = false;

   	 /* Turn on button:						*/
   	 SI_window.CB1[VIEW_MEM_CB].attr.state = SI_SACTIVE;
   	 SI_change_state(&SI_window.CB1[VIEW_MEM_CB]);
      }

      /* Check if a word or address of the memory window has been 
	 selected:							*/
      else
         SI_mem_update();
   };
}


/*-----------------------------------------------------------------------
   SI_do_memory_dynamic:
------------------------------------------------------------------------*/
void SI_do_memory_dynamic()
{  static int		first_time=true;

   /* Turn off button:							*/
   SI_window.CB1[VIEW_MEM_CB].attr.state = SI_SINACTIVE;
   SI_change_state(&SI_window.CB1[VIEW_MEM_CB]);

   if (first_time)
   {  SI_calc_mem_window();
      SI_create_mem_window();
      first_time = false;
   }
   else
      SI_map_mem_window();

   SI_mw_mapped = true;
}


/*-----------------------------------------------------------------------
   SI_prompt_get_str_expose:

   Take care of expose events during prompting.
------------------------------------------------------------------------*/
void SI_prompt_get_str_expose()
{   int			width,
			center;

       if (SI_event.xexpose.window==SI_toplevel ||
	   SI_event.xexpose.window==SI_g1_window)
       {  SI_expose_event = true;
	  SI_draw_window();
          SI_expose_event = false;
   
          /* Print the prompt:						*/
          width = XTextWidth(SI_font5_struct,SI_promptstr,
				strlen(SI_promptstr));
          center = (SI_prompt_width - width)/2;
          XSetFont(SI_display,SI_gc,SI_font5);
          XDrawImageString(SI_display,SI_prompt_window,SI_gc,center,
			SI_prompt_txt_offset,SI_promptstr,
			strlen(SI_promptstr));
       };
}


/*-----------------------------------------------------------------------
   SI_prompt_get_str:

   Open a small window, display the prompt, open another window and get 
   a string from the user.

   The input can be either a number or an ASCII string.

   Function returns true if user ESCaped.  Otherwise, it returns false.
------------------------------------------------------------------------*/
int SI_prompt_get_str(prompt,ibuf,slen,type,aint,base)
char			*prompt,
			*ibuf;
int			slen;
int			type;		/* 0== number; 1== ASCII	*/
unsigned int		*aint;		/* value			*/
int			base;		/* base of value		*/
{  Window		ibuf_window;
   int			width,width1,width2,
			ibuf_height,
			center,
			ibuf_txt_offset;
   unsigned long	valuemask;
   int			i;
   int			esc;


   /* Make a copy of prompt message for expose update:			*/
   for (i=0; i<(strlen(prompt)+1); i++)
      SI_promptstr[i] = prompt[i];
  
   SI_prompt_height = 20 + SI_font5_struct->max_bounds.ascent +
		   SI_font5_struct->max_bounds.descent + 20;
   SI_prompt_txt_offset = 20 + SI_font5_struct->max_bounds.ascent;
   width1 = hpadding + XTextWidth(SI_font5_struct,prompt,strlen(prompt)) +
	    hpadding;
   ibuf_height = vpadding + SI_font2_struct->max_bounds.ascent +
		   SI_font2_struct->max_bounds.descent + vpadding;
   ibuf_txt_offset = vpadding + SI_font2_struct->max_bounds.ascent;
   width2 = hpadding + XTextWidth(SI_font2_struct,"mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm",slen) + hpadding;
   width = width1;
   if (width2>width)
      width = width2;

   SI_prompt_width = width;

   /* Create the windows:						*/
   SI_prompt_window = XCreateSimpleWindow(SI_display,SI_toplevel,
			200,350,
			SI_prompt_width,SI_prompt_height,4,0,1);
   valuemask = KeyPressMask;
   XSelectInput(SI_display,SI_prompt_window,valuemask);
   XMapWindow(SI_display,SI_prompt_window);

   ibuf_window = XCreateSimpleWindow(SI_display,SI_toplevel,
			200,350+SI_prompt_height+3,
			width,ibuf_height,4,0,1);
   valuemask = KeyPressMask;
   XSelectInput(SI_display,ibuf_window,valuemask);
   XDefineCursor(SI_display,ibuf_window,SI_ptr_cursor);
   XMapWindow(SI_display,ibuf_window);
   
   /* Print the prompt:						*/
   width = XTextWidth(SI_font5_struct,SI_promptstr,
				strlen(SI_promptstr));
   center = (SI_prompt_width - width)/2;
   XSetFont(SI_display,SI_gc,SI_font5);
   XDrawImageString(SI_display,SI_prompt_window,SI_gc,center,
			SI_prompt_txt_offset,SI_promptstr,
			strlen(SI_promptstr));

   /* Get an input string:						*/
   esc = SI_edit_string(ibuf_window,SI_prompt_width,ibuf_txt_offset,
			SI_font2_struct,SI_bgrd3,ibuf,slen,type,aint,base,
			SI_prompt_get_str_expose,true);

   /* Dispose the windows:						*/
   XUnmapWindow(SI_display,ibuf_window);
   XUnmapWindow(SI_display,SI_prompt_window);
   XDestroyWindow(SI_display,ibuf_window);
   XDestroyWindow(SI_display,SI_prompt_window);

   return(esc);
}


/*-----------------------------------------------------------------------
   SI_prompt_error:

   Prompt the error message and wait for the user's confirmation.
------------------------------------------------------------------------*/
void SI_prompt_error(errstr)
char			*errstr;
{  int			errstr_height,
			errstr_txt_offset,
			width,
			center,
			width1;
   Window		errstr_window;
   int			done;
   unsigned long	valuemask;


   errstr_height = 20 + SI_font5_struct->max_bounds.ascent +
		   SI_font5_struct->max_bounds.descent + 20;
   errstr_txt_offset = 20 + SI_font5_struct->max_bounds.ascent;
   width = 20 + XTextWidth(SI_font5_struct,errstr,strlen(errstr)) + 20;

   /* Create the window:						*/
   errstr_window = XCreateSimpleWindow(SI_display,SI_toplevel,
			100,350,
			width,errstr_height,4,0,1);
   valuemask = ButtonPressMask;
   XSelectInput(SI_display,errstr_window,valuemask);
   XDefineCursor(SI_display,errstr_window,SI_CB_cursor);
   XMapWindow(SI_display,errstr_window);
   
   /* Print the error message:						*/
   width1 = XTextWidth(SI_font5_struct,errstr,strlen(errstr));
   center = (width - width1)/2;
   XSetFont(SI_display,SI_gc,SI_font5);
   XDrawImageString(SI_display,errstr_window,SI_gc,center,
			errstr_txt_offset,errstr,strlen(errstr));

   /* Wait for button pressed:						*/
   done = false;
   while (!done)
   {  XNextEvent(SI_display,&SI_event);
      switch (SI_event.type)
      {  case Expose:
	    if (SI_event.xexpose.count==0)
	       if (SI_event.xexpose.window==SI_toplevel ||
		   SI_event.xexpose.window==SI_g1_window)
	       {  SI_expose_event = true;
		  SI_draw_window();
	          SI_expose_event = false;
	       }
	       else if (SI_event.xexpose.window==SI_mw_toplevel)
	       {  if (SI_mw_mapped)
                  {  SI_mem_draw_com(false,true,true,true,true,false,
							false,true);
		     SI_mem_display(true);
		  };
	       };
   	       width1 = XTextWidth(SI_font5_struct,errstr,strlen(errstr));
   	       center = (width - width1)/2;
   	       XSetFont(SI_display,SI_gc,SI_font5);
   	       XDrawImageString(SI_display,errstr_window,SI_gc,center,
			errstr_txt_offset,errstr,strlen(errstr));
	    break;

	 case MappingNotify:
	    XRefreshKeyboardMapping(&SI_event.xmapping);
	    break;

         case ButtonPress:
	    if (SI_event.xbutton.window==errstr_window)
	       done = true;
	    break;
      };
   };

   /* Dispose the windows:						*/
   XUnmapWindow(SI_display,errstr_window);
   XDestroyWindow(SI_display,errstr_window);

}


/*-----------------------------------------------------------------------
   SI_str2bin:

   Convet a hex string into an internal binary code.
------------------------------------------------------------------------*/
int SI_str2bin(ibuf,indx,slen,intvalue)
char			*ibuf;
int			indx;
int			slen;
unsigned int		*intvalue;
{  int			i;
   char			digit;

   *intvalue = 0;
   for (i=indx; i<indx+slen && ibuf[i]!='\0'; i++)
/*   {  if (ibuf[i]>'9')*/
   {  if (ibuf[i]>96)
	 digit = ibuf[i] - 'a' + 10;
      else if ((ibuf[i]>64) && (ibuf[i]<71))
	 digit = ibuf[i] - 'A' + 10;
      else
	 digit = ibuf[i] - '0';
      *intvalue = (*intvalue)*16 + digit;
   };

   if (i==indx && ibuf[i]=='\0')
      return(-1);
   else if (i==(indx+slen))
      return(false);
   else
      return(true);
}


/*-----------------------------------------------------------------------
   SI_parse_ibuf:

   Parse the input data string for start address and following data.
   Also put the data into memory.
------------------------------------------------------------------------*/
int SI_parse_ibuf(ibuf)
char			*ibuf;
{  int			cverr;
   int			i;
   int			indx;
   unsigned int		intvalue,length,
			daddress;
   unsigned int         dlen;

   /* Select the correct word size:                                     */
   dlen = 2;

   indx = 1;
   cverr = SI_str2bin(ibuf,indx,1,&length);
   if (length==9)
	return false;
   indx++;
   cverr = SI_str2bin(ibuf,indx,dlen,&length);
   length-=2;
   indx+=2;
   cverr = SI_str2bin(ibuf,indx,4,&daddress);
   if (cverr)
      return(true);
   else
   {  indx += 4;
      
      /* Loop and get a word until end line:				*/
      for (i=1;i<length;i++)
      {  cverr = SI_str2bin(ibuf,indx,dlen,&intvalue);
         if (cverr==-1)			/* -1 indicates end of data	*/
	    return(false);		/* Reach end of data 		*/
	 else if (!cverr)
	 {  SI_mem_write(daddress,intvalue);
	    daddress++;
	    indx += dlen;
	 }
	 else
	    return(true);
      }
      return false;
   };
}


/*-----------------------------------------------------------------------
   SI_do_load_code:

   Load the oject code.
   The format of the object code is the Motorola S-record
------------------------------------------------------------------------*/
void SI_do_load_code()
{  char			ibuf[250];
   FILE			*difp;
   int			ierr,
			cverr;
   int			done;
   int			esc;
   static int		first_time=true;


   /* Turn off button:							*/
   SI_window.CB1[LOAD_CODE_CB].attr.state = SI_SINACTIVE;
   SI_change_state(&SI_window.CB1[LOAD_CODE_CB]);

   /* Prompt and get a file name:					*/
   if (first_time)
   {  SI_code_filename[0] = '\0';
      first_time = false;
   };
   esc = SI_prompt_get_str("File Name",SI_code_filename,50,1,NULL,0);
   
   /* Open and get data:						*/
   if (!esc && strlen(SI_code_filename)!=0)
   {  difp = fopen(SI_code_filename,"r");
      if (difp==NULL)
         SI_prompt_error("Sorry, File Not Found.");
      else
   
      {  /* Read until end-of-file:					*/
         done = false;
         cverr = false;
         ierr = fscanf(difp,"%s",ibuf); /* Skip first line of S-record*/
         while (!done && !cverr)
         {  ierr = fscanf(difp,"%s",ibuf);
            if (ierr==1)
            {  cverr = SI_parse_ibuf(ibuf);
	       if (cverr)
	          SI_prompt_error("Sorry, File Conversion Error.");
	    }
            else if (feof(difp))
	       done = true;
            else
	    {  SI_prompt_error("Sorry, Read Error.");
	       done = true;
	    };
         };

         /* Close file:							*/
         fclose(difp);
      };
   };

   /* Turn on button:							*/
   SI_window.CB1[LOAD_CODE_CB].attr.state = SI_SACTIVE;
   SI_change_state(&SI_window.CB1[LOAD_CODE_CB]);
}
   

/*-----------------------------------------------------------------------
   SI_do_screen_trace_on:
------------------------------------------------------------------------*/
void SI_do_screen_trace_on()
{

   if (!strace_on)
   {  strace_on = true;
      SI_toggle_state_DS5(STRACE_ON_DS);
      SI_window.CB1[STRACE_ON_CB].attr.state = SI_SINACTIVE;
      SI_window.CB1[STRACE_OFF_CB].attr.state = SI_SACTIVE;
      SI_change_state(&SI_window.CB1[STRACE_ON_CB]);
      SI_change_state(&SI_window.CB1[STRACE_OFF_CB]);
   };
}
   

/*-----------------------------------------------------------------------
   SI_do_screen_trace_off:
------------------------------------------------------------------------*/
void SI_do_screen_trace_off()
{

   if (strace_on)
   {  strace_on = false;
      SI_toggle_state_DS5(STRACE_ON_DS);
      SI_window.CB1[STRACE_ON_CB].attr.state = SI_SACTIVE;
      SI_window.CB1[STRACE_OFF_CB].attr.state = SI_SINACTIVE;
      SI_change_state(&SI_window.CB1[STRACE_ON_CB]);
      SI_change_state(&SI_window.CB1[STRACE_OFF_CB]);
   };
}






