/*                                                      =====> SDUMP.C       */
/* TIPC Scheme '84 - Diagnostic Dump Routines
   (C) Copyright 1984,1985,1987 by Texas Instruments Incorporated.
   All rights reserved.

   Author:  John Jensen
   Installation:  Texas Instruments Incorporated, Dallas, Texas
   Division:  Central Research Laboratories
   Cost Center:  Computer Science Laboratory
   Project:  Computer Architecture Branch
   Date Written:  11 April 1984
   Modification History:
     ?? 10/10/85 - ??
     rb  9/21/87 - lists, strings/symbols, and array-like data structures
	           print only within user-specified bounds;
		   also, hitting any key exits the printing
*/
#include "scheme.h"
#include "ctype.h"
#include "schars.h"
#include "slist.h"

#define INTR_OUTPUT if (char_rdy()) {(void) getch(); goto bye;}

static char *page_type[NUMTYPES] = {"LIST","FIX" ,"FLO" , "BIG","SYM" ,
                                    "STR" ,"ARY" ,"CONT","CLOS","FREE",
                                    "CODE","REF" ,"PORT","CHAR","ENV"};
/* character strings for getmem/rlsmem error message text */
static char *mem_fmt = "%s:  %smem error\n";
static char *getmem_error = "get";

char *getmem();
char char_rdy();

/**********************************************************************/
/*                 Format a dump of the Page Table                    */
/**********************************************************************/
dump_page_table()
{
  int i;  /* the usual index variable */
  int start, end; /* starting and ending limits of FREE pages */
  int space[NUMPAGES]; /* amount of free space in each page */
  ENTER(dump_page_table);

  /* determine the amount of free space in each page */
  sum_space(space);

  /* Print Page Table Dump Headings */
  printf("\nDump of Scheme Memory Management Page Tables\n\n%s\n%s\n%s\n",
           "Page   Page  Base    Next   Link          Free",
           " No    Type  Para   Avail   Page   Size   Bytes  Attributes",
           "----   ----  ----   -----   ----   ----   -----  ----------");
  start = end = -1;
  for (i = 0; i < nextpage; i++)
  {
    INTR_OUTPUT;
    if (ptype[i] == FREETYPE*2) {
      if (start < 0) start = i;
      end = i;
    }
    else {
      prt_free(&start, &end);
      printf("%4x  %5s   %04x   %4x   %4x%c  %4x   %4x   ", i,
                page_type[ptype[i]>>1], getbase(i*2), nextcell[i],
                pagelink[i], (i == pagelist[CORRPAGE(ptype[i])] ? '<' : ' '),
                psize[i], space[i]);
      /* print attributes for page */
      prt_atr(i);

      /* Flush line to output device */
      printf("\n");
    } /* end: else */
  } /* end:  for (i = 0; i < nextpage; i++) */
  prt_free(&start, &end);

  /* Print summary of pages which are not allocated */
  if (nextpage < NUMPAGES) {
    if (nextpage == NUMPAGES-1)
      printf("Page %x is not allocated\n", nextpage);
    else
      printf("Pages %x-%x are not allocated\n", nextpage, NUMPAGES-1);
  }
bye:
} /* end of function:  dump_page_table() */

/**********************************************************************/
/*                      Print Page Attributes                         */
/*                                                                    */
/* Purpose:  This routine prints the attributes of a page on the      */
/*           current print line.  Attributes are separated by commas. */
/**********************************************************************/
prt_atr(page)
int page;
 {
  unsigned bits;
  static char *things[16] = {"atom","list","fixnum","flonum","bignum",
                             "symbol","string","array","no memory","read only",
                             "continuation","closure","ref","port","code block",
                             "char"};
  char *comma_needed = "";
  int i = 0;
  ENTER(prt_atr);

  bits = w_attrib[page];
  while (bits)
   {
    if (bits & 0x8000)
     {
      printf("%s%s", comma_needed, things[i]);
      comma_needed = ",";
     }
    i++;
    bits = (bits << 1);
   } /* end:  while (bits) */
 }

/**********************************************************************/
/*              Print Free (unused) Pages of Memory                   */
/*                                                                    */
/* Purpose:  Given a range of unused pages of memory, this routine    */
/*           formats a message to indicate the presence of said pages.*/
/**********************************************************************/
prt_free(start, end)
int *start, *end;
 {
  int i;
  ENTER(prt_free);
  if ((i = *start) >= 0)
   {
    if (i == *end)
      printf("%4x   %4s   %04x   %4x   %4x   %4x   %4x   (unused)\n", i,
             page_type[ptype[i]>>1], getbase(i*2), nextcell[i],
             pagelink[i], psize[i], psize[i]);
    else
      printf("Pages %x-%x are allocated, but unused\n",
        i, *end);
    *start = *end = -1;
   }
 }

/**********************************************************************/
/*    Produce a Formatted Dump of an Area of Scheme's Address Space   */
/**********************************************************************/
dump_memory(page, disp, length)
int page;                       /* number of page to dump */
unsigned disp;                  /* starting displacement */
unsigned length;                /* number of bytes to dump */
 {
  int page_type;
  static char *description[NUMTYPES] = {"List Cells","Fixnums","Flonums",
                                        "Bignums","Symbols","Strings",
                                        "Arrays","Continuation Cells",
                                        "Closures","Nothing (unused)",
                                        "Code","Ref Cells","Ports",
                                        "Characters", "Environments"};
  ENTER(dump_memory);
  page_type = ptype[page]>>1;
  if (page_type >= 0 && page_type < NUMTYPES && page_type != FREETYPE)
   {
    printf("Page %x (hex) contains %s\nPage attributes:  ",
           page, description[page_type]);
    prt_atr(page);
    printf("\n");
    switch (page_type)
     {
      case LISTTYPE:
                     dump_list(page, disp, length);
                     break;
/***    Note:  Fixnums and Characters currently handled as immediates
      case CHARTYPE:
      case FIXTYPE:
                     dump_fix(page, disp, length);
                     break;
***/
      case SYMTYPE:
      case STRTYPE:
                     dump_str(page, disp, length);
                     break;

      case CODETYPE:
                     dump_code(page, disp, length);
                     break;

      case ARYTYPE:
      case CLOSTYPE:
      case CONTTYPE:
      case ENVTYPE:
                      dump_ary(page, disp, length);
                      break;

      case FLOTYPE:
/***                 dump_flo(page, disp, length);
                     break;                                     ***/

      case PORTTYPE:
/***                 dump_port(page,disp,length);
                     break;                                     ***/

      case BIGTYPE:
                      dump_hex(page, disp, length);
                      break;

      case REFTYPE:
      default:        printf("***Invalid page type: %d***\n", page_type);
     } /* end:  switch (page_type) */
   } /* end:  if (then clause) */
  else
    printf("***Invalid page type: %d***\n", page_type);
 } /* end of function:  dump_memory(page, disp, length) */


/**********************************************************************/
/*        Produce a Hex Dump of a Page of Scheme's Memory             */
/**********************************************************************/
dump_hex(page, disp, length)
int page, disp, length;
{
  int start, end;               /* delimiters for dump area */
  ENTER(dump_hex);

  start = disp & 0xFFF0;
  end = ((disp + length + 15) & 0xFFF0) - 1;

  while (start <= end) {
    INTR_OUTPUT;
    if ((start & 0x000F) == 0) { /* start of new line */
       printf("\n%2x:%04x  ", page, start);
    }
    printf("%02x ", get_byte(page, start));
    start++;
  }
  /* flush line to output device */
bye:  printf("\n");
}


/**********************************************************************/
/*      Produce Formatted Dump of a Page Containing List Cells        */
/*                                                                    */
/* Note:  the "disp" and "length" parameters currently are not used.  */
/*        (they are now -- rb 9/21/87)                                */
/**********************************************************************/
dump_list(page, disp, length)
int page;
int disp;
int length;
{
  int end_disp = disp + length;
  int count = 0;
  int i,j;                      /* the usual index variables */
  int next;
  int number_of_cells;          /* the number of list cells in current page */
  int page_length;              /* length of current page in bytes */
  int start = -1;
  int end = -1;
  char *unused_cells;
  ENTER(dump_list);

  /* if page zero, print nil */
  if (page == 0)
   {
    printf("000:0000  00 0000   00 0000  nil\n");
   } /* end:  if (page == 0) then ... */
  else /* page != 0 */
   {
    number_of_cells = (page_length = psize[page])/LISTSIZE;
    if (!(unused_cells = getmem(number_of_cells)))
     {
      printf(mem_fmt, rtn_name, getmem_error); goto end_routine;
     }
    /* count up available cells */
    for (i=0; i < number_of_cells; i++) unused_cells[i] = '\0';
    next = nextcell[page];
    while (next != END_LIST) {
      j = next/LISTSIZE;
ASSERT(j >= 0 && j < number_of_cells /* subchk? */ );
      unused_cells[j] = 'x';
      next = get_word(page, next+1);
      count++;
ASSERT(count <= number_of_cells /* infinite loop? */);
    } /* end while */
    printf("%d (decimal) List Cells Unused\n", count);

    /* print active List Cells */
    for (next = 0; next <= page_length - LISTSIZE; next += LISTSIZE) {
      INTR_OUTPUT;
      if (unused_cells[next/LISTSIZE]) { /* unused cell-- make a notation */
        if (start < 0) start = next;
        end = next;
      }
      else {
        if (end >= disp && start <= end_disp)
	  prt_unused(&start, &end);
        if (next+LISTSIZE >= disp && next < end_disp)
          printf("%3x:%04x  %02x %04x   %02x %04x\n", page, next,
                 CORRPAGE(get_byte(page, next)), get_word(page, next+1),
                 CORRPAGE(get_byte(page, next+3)), get_word(page, next+4));
      }
    } /* end for (next=0; ... */
    if (end >= disp && start <= end_disp)
      prt_unused(&start, &end);

    /* release memory for unused cell list */
bye:
    if (rlsmem(unused_cells, number_of_cells))
      rlsmem_error(rtn_name);
   } /* end:  else /* page != 0 */ */
end_routine:
 } /* end of function:  dump_list(page) */


/***** Code for dump_ref turned off 6 July 1985 by John Jensen *****
/**********************************************************************/
/*      Produce Formatted Dump of a Page Containing Reference Cells   */
/*                                                                    */
/* Note:  the "disp" and "length" parameters currently are not used.  */
/**********************************************************************/
dump_ref(page, disp, length)
int page;
int disp;
int length;
 {
  int count = 0;
  int end = -1;
  int i,j;                      /* the usual index variables */
  int next;
  int number_of_cells;          /* the number of cells in current page */
  int page_length;              /* size of the current page in bytes */
  int start = -1;
  char *unused_cells;
  ENTER(dump_ref);

  number_of_cells = (page_length = psize[page])/PTRSIZE;
  if (!(unused_cells = getmem(number_of_cells)))
   {
    printf(mem_fmt, rtn_name, getmem_error);  goto end_routine;
   }
  /* count up available cells */
  for (i=0; i < number_of_cells; i++) unused_cells[i] = '\0';
  next = nextcell[page];
  while (next != END_LIST)
   {
    j = next/PTRSIZE;
ASSERT(j >= 0 && j < number_of_cells /* subchk? */);
    unused_cells[j] = 'x';
    next = get_word(page, next+1);
    count++;
ASSERT(count <= number_of_cells /* infinite loop? */);
   }
  printf("%d (decimal) Reference Cells Unused\n", count);

  /* print active Ref Cells */
  for (next = 0; next <= page_length - PTRSIZE; next += PTRSIZE)
   {
    if (unused_cells[next/PTRSIZE])
     { /* unused cell-- make a notation */
      if (start < 0) start = next;
      end = next;
     }
    else
     {
      prt_unused(&start, &end);
      printf("%3x:%04x  %02x %04x\n", page, next,
      CORRPAGE(get_byte(page, next)), get_word(page, next+1));
     }
   } /* end: for next=0; next<=page_length-PTRSIZE; next+=PTRSIZE) */
  prt_unused(&start, &end);
  if (rlsmem (unused_cells, number_of_cells))
   {
    rlsmem_error(rtn_name);
   }
end_routine:
 } /* end of function:  dump_ref(page) */
***** Code for dump_ref turned off 6 July 1985 by John Jensen *****/

/**********************************************************************/
/*         Produce a Formatted Dump of a String/Symbol Page           */
/**********************************************************************/
dump_str(page, disp, length)
int page, disp, length;
{
  int end_disp = disp + length; /* display only between disp and end_disp */
  char buffer[70];              /* print line buffer */
  int ch;                       /* character (byte) begin formatted */
  int char_ptr;                 /* pointer into print line buffer */
  int count;                    /* count of bytes in print line buffer */
  int first_time;               /* flag indicating first time through loop */
  int hex_ptr;                  /* pointer into print line buffer */
  int hold_addr;                /* address value to print */
  int i,j;                      /* index variables */
  int incr;                     /* adjustment for header overhead */
  int next = 0;                 /* pointer to next block of memory in page */
  int page_length;              /* length in bytes of the page we're dumping */
  int size;                     /* size of string/symbol in bytes */
  int type;                     /* type code block of memory */
  static char hex_digit[16] = {'0','1','2','3','4','5','6','7','8','9',
                                'A','B','C','D','E','F'};
ENTER(dump_str);

  page_length = psize[page];
  while (next <= page_length - BLK_OVHD) {
    type = (i = get_byte(page, next)) & 0x003F;
    size = get_word(page, next+1);
    if (size < 0) size = BLK_OVHD + PTRSIZE;  /* check for small string */
 ASSERT(size >= 3 && size <= page_length - next /* invalid size */);
    if (next+size >= disp && next <= end_disp) {
      if (type == FREETYPE) {
	printf("%3x:%04x  unused block of %x (hex) bytes\n",
		  page, next, size);
      }
      else /* type != FREETYPE */ {
  printf("%3x:%04x  %02x %04x  block type = %d   size = %d (decimal) bytes\n",
		  page, next, i, size, type, size);
	if (type == SYMTYPE) {
	  printf("   Link:  %02x %04x     Hash Key: %02x\n",
			  get_byte(page,next+3), get_word(page,next+4),
			  get_byte(page,next+6));
	  incr = 7;
	} 
	else incr = 3;
	for (first_time = 1, count = 16, i = next+incr; i < next+size; i++) {
	  INTR_OUTPUT;
	  if (count >= 16) {
	    if (!first_time) printf("%3x:%04x  %s\n", page, hold_addr, buffer);
	    hold_addr = i;
	    for (j = 0; j < sizeof(buffer); j++) buffer[j] = ' ';
	    buffer[49] = buffer[66] = '|';
	    buffer[sizeof(buffer)-1] = '\0';
	    hex_ptr = count = first_time = 0;
	    char_ptr = 50;
	  } /* end:  if (then clause) */
	  if ((ch = get_byte(page, i)) != '\0') buffer[char_ptr] = ch;
	  buffer[hex_ptr] = hex_digit[ch >> 4];
	  buffer[hex_ptr+1] = hex_digit[ch & 0x000F];
	  count++;
	  char_ptr++;
	  hex_ptr += 3;
	} /* end for ... */
	printf("%3x:%04x  %s\n", page, hold_addr, buffer);
      } /* end else */
    } /* end if */
    next += size;
  } /* end:  while (next < page_length) */
bye:
} /* end of function:  dump_str(page, disp, length) */


/**********************************************************************/
/*              Format a Page Containing Code Blocks                  */
/**********************************************************************/
dump_code(page, start, length)
int page, start, length;
{
/*%%int ch;                       /* character (byte) begin formatted */*/
/*%%int char_ptr;                 /* pointer into print line buffer */*/
/*%%int count;                    /* count of bytes in print line buffer */*/
  int disp;
  int end;                      /* end of print range */
  int ent;                      /* entry offset of code */
/*%%int first_time;              /* flag indicating first time through loop */*/
/*%%int hex_ptr;                  /* pointer into print line buffer */*/
/*%%int hold_addr;                /* address value to print */*/
/*%%int i,j;                      /* index variables */*/
  int next = 0;                 /* pointer to next block of memory in page */
  int page_length;              /* length in bytes of the page we're dumping */
  int pc;
  int size;                     /* size of string/symbol in bytes */
  int tag;                      /* page number field of a constant ptr */
  char *title;                  /* pointer to "constants" title */
  int type;                     /* type code block of memory */
/*%%static char hex_digit[16] = {'0','1','2','3','4','5','6','7','8','9',*/
/*%%                            'A','B','C','D','E','F'};*/
ENTER(dump_code);

  end = start + length;
  page_length = psize[page];
  while (next <= page_length - BLK_OVHD) {
    type = get_byte(page, next) & 0x003F;
    size = get_word(page, next+1);
ASSERT(size >= 3 && size <= page_length - next /* invalid size */);
    if (type == FREETYPE) {
      if ((next >= start && next <= end) ||
          (next+size > start && next+size <= end) ||
          (next <= start && next+size-1 >= end)) {
        printf("%3x:%04x  unused block of %d (decimal) bytes\n",
                page, next, size);
      }
    }
    else /* type != FREETYPE */ {
      ent = get_word(page, next+4);
      if (next >= start && next <= end) {
        printf(
          "%3x:%04x  %02x %04x  block type = %d   size = %d (decimal) bytes\n",
          page, next, type, size, type, size);
        printf("Code begins at %d (decimal)\n", ent);
      }
      pc = next + PTRSIZE*2;
      title = "Constants:\n";
      while (pc < next + ent) {
	INTR_OUTPUT;
        if (pc >= start && pc <= end) {
          tag = CORRPAGE(get_byte(page, pc));
          disp = get_word(page, pc+1);
          printf("%s%3x:%04x  ", title, page, pc);
          annotate(tag, disp);  /* describe what's being pointed at */
          title = "";  /* print heading only once */
        }
        pc += PTRSIZE;
      } /* end:  while (pc < next + entry) */

      /* format the instructions in the block */
      while (pc < next + size) {
	INTR_OUTPUT;
        t_inst(page, &pc, 0, (pc >= start && pc <= end));
      } /* end:  while (pc < next + size) */
    } /* end:  else */
    next += size;
   } /* end:  while (next < page_length) */
 bye:
 } /* end of function:  dump_code(page, start, length) */


/**********************************************************************/
/*                        Dump the port page                          */
/*                                                                    */
/*      Note: DISP and LENGTH arguments are not used here.            */
/**********************************************************************/
/*****
dump_port(page,disp,length)
int page,disp,length;
 {
  int c;                        /* Next input character */
  int csrcol;                   /* Port cursor column */
  int i;                        /* Index variable */
  int lnlen;                    /* Port line length */
  int next = 0;                 /* Pointer to next block in page */
  int page_length;              /* Length in bytes of page */
  int ptype;                    /* Type of port */
  int size;                     /* Size of port in bytes */
  int type;                     /* Type code block of memory */

ENTER(dump_port);

  page_length = psize[page];
  while (next < page_length)
   {
    type = get_byte(page,next) & 0x003F;
    size = get_word(page,next+1);
ASSERT(size >= 46 && size <= page_length - next /* invalid size */);
    if (type == FREETYPE)
     {
      printf("%3x:%04x  unused block of %d (decimal) bytes\n",
                page,next,size);
     }
     else /* type != FREETYPE */
     {
      printf(
       "%3x:%04x  %02x %04x  block type = %d   size = %d (decimal) bytes \n",
       page, next, type, size, type, size);
      ptype = get_byte(page,next+3);
      switch (ptype)
       {
        case 0:
          printf("     Output port writing to ");
          break;
        case 1:
          printf("     Input port receiving from ");
          break;
       }
      /* Now print file name */
      i = 10;
      while ((i < 18) && ((c = get_byte(page,next+i)) != ' '))
       {
        printf("%c",toupper(c));
        i++;
       }
      i = 18;
      printf(".");
      while ((i < 21) && ((c = get_byte(page,next+i)) != ' '))
       {
        printf("%c", toupper(c));
        i++;
       }
      printf("\n");
      lnlen = get_word(page,next+4);
      csrcol = get_word(page,next+6);
      switch (ptype)
       {
        case 0:
          printf("     Line length: %d    Print column: %d\n",
                 lnlen, csrcol);
          break;
        case 1:
          c = get_byte(page, next+8);
          printf("    Most recent character: %02x\n",c);
          break;
       }
     } /* End of ELSE */
    next += size;
   } /* End of WHILE */
 } /* End of function:  dump_port(page,disp,length) */
*****/

/**********************************************************************/
/*      Format a Page Containing Arrays or Continuations              */
/**********************************************************************/
dump_ary(page, disp, length)
int page, disp, length;
{
/*%%int ent;                      /* entry offset of code */*/
  int start_disp = disp;        /* only values in range start_disp..end_disp
	                           are displayed */
  int end_disp = disp + length; 
  int i;
  unsigned next = 0;            /* pointer to next block of memory in page */
  unsigned page_length;         /* length of the current page in bytes */
  int pc;
  unsigned size;                /* size of string/symbol in bytes */
  int tag;                      /* page number field of a constant ptr */
  int type;                     /* type code block of memory */
ENTER(dump_ary);

  page_length = psize[page];
  while (next <= page_length - BLK_OVHD) {
    type = get_byte(page, next) & 0x003F;
    size = get_word(page, next+1);
ASSERT(size >= 3 && size <= page_length - next /* invalid size */);
    if (next+size >= start_disp && next <= end_disp) {
      if (type == FREETYPE) {
	printf("%3x:%04x  unused block of %d (decimal) bytes\n",
		  page, next, size);
      }
      else /* type != FREETYPE */ {
	printf(
	  "%3x:%04x  %02x %04x  tag = %d (%s)   size = %d (decimal) bytes\n",
	  page, next, type, size, type, page_type[type], size);
	pc = next + PTRSIZE;
	while (pc < next + size) {
	  INTR_OUTPUT;
	  tag = CORRPAGE(get_byte(page, pc));
	  disp = get_word(page, pc+1);
	  /* see if following array entries are same as the current one */
	  for (i = pc + PTRSIZE; i < next + size; i += PTRSIZE) {
	    if (tag != CORRPAGE(get_byte(page, i)) ||
		disp != get_word(page, i+1)) break;
          } /* end for (i = pc + PTRSIZE; ... */
          if (i >= start_disp && pc+PTRSIZE <= end_disp) {
	    if (i > pc + PTRSIZE) { /* consecutive entries with same value? */
	                            /* if so, print address range */
	      printf("%3x:%04x-%2x:%04x  ", page, pc, page, i-PTRSIZE);
	    }
	    else /* no consecutive entries with same value */ {
	      printf("%3x:%04x          ", page, pc);
	    } /* end else */
            annotate(tag, disp);  /* describe what's being pointed at */
          } /* end if (i >= disp ... */
	  pc = i;
        } /* end while (pc < next + size) */
      } /* end else */
    } /* end if */
    next += size;
  } /* end:  while (next < page_length) */
bye:
} /* end of function:  dump_ary(page, disp, length) */


/**********************************************************************/
/*                      Dump the runtime stack                        */
/**********************************************************************/
dump_stk()
{
  int next;
  int ptr_disp, ptr_page;
  ENTER(dump_stk);

  /* print the value of PREV_reg and the stack base */
  prt_reg(-4);
  printf("BASE     %04x (%u decimal)\n", BASE, BASE);

  /* print active Stack Cells */
  for (next = 0; next <= TOS; next += PTRSIZE) {
    INTR_OUTPUT;
    ptr_page = CORRPAGE(S_stack[next]);
    ptr_disp = (S_stack[next+2]<<8) + S_stack[next+1];
    printf("%s%04x  ", (next==FP ? "FP->" : "    "), next + BASE);

    /* for values, show the value the stack entry points to */
    annotate(ptr_page, ptr_disp);

  } /* end: for (next = 0; next <= TOS; next += PTRSIZE) */
bye:
} /* end of function:  dump_stk() */


prt_unused(start, end)
int *start, *end;
 {
  ENTER(prt_unused);
  if (*start >= 0)
   {
    if (*start == *end)
      printf("Location %04x unused\n", *start);
    else
      printf("Locations %04x-%04x unused\n", *start, *end);
    *start = *end = -1;
   }
 } /* end of function:  prt_unused(start, end) */


/**********************************************************************/
/*                      Dump the VM's Registers                       */
/**********************************************************************/
dump_regs()
{
  int i;                /* the usual index variable */
  int *reg_page, *reg_disp;
  int pc = S_pc;
  long unbound;         /* an "unbound" pointer */
  
  long make_ptr();

  unbound = make_ptr(UN_PAGE, UN_DISP);

  /* Print the Contents of the general purpose registers */
  reg_page = &reg0_page;
  reg_disp = &reg0_disp;
  for (i = 0; i < NUM_REGS; i++, reg_page+=2, reg_disp+=2)
    if (regs[i] != unbound) prt_reg(i);

  prt_reg(-1);  /* print FNV */
  prt_reg(-3);  /* print GNV */
  prt_reg(-2);  /* print CB  */
  if(tmp_page & 1)printf("odd tmp_page\n");
    printf("tmp_reg "); annotate(CORRPAGE(tmp_page), tmp_disp);
  (void) t_inst(CORRPAGE(CB_pag), &pc, 
                /* run= */ FALSE, /* display= */ TRUE);
} /* end of function:  dump_regs() */

prt_reg(reg)
int reg;        /* register number to print (-2=CB, -1=FNV) */
{
  int *disp;
  int *page;

  page = &reg0_page + reg + reg;
  disp = &reg0_disp + reg + reg;

  /* print the register name and contents */
  switch (reg) {
    case -1:  printf("FNV  ");
              page = &FNV_pag;
              disp = &FNV_dis;
              break;
    case -2:  printf("CB   ");
              page = &CB_pag;
              disp = &CB_dis;
              break;
    case -3:  printf("GNV  ");
              page = &GNV_pag;
              disp = &GNV_dis;
              break;
    case -4:  printf("PREV ");
              page = &PREV_pag;
              disp = &PREV_dis;
              break;
    default:  printf("R%d  ", reg);
  }

  /* expound on what pointer is */
  annotate(CORRPAGE(*page), *disp);
}

/*     Print information about what a pointer points to     */
annotate(page, disp)
int page, disp;
 {
  int ch;
  int count;
  char dlm = '\"';              /* string/symbol delimiter */
  int i;                        /* index variable */
  int incr = 3;                 /* adjustment for string/symbol header */
  char *str;                    /* pointer to a character string */
  int type;                     /* object type code */
  double get_flo();

  type = ptype[page]>>1;

  printf("%2x:%04x   %s", page, disp, page_type[type]);

  /* for values, show the value the register points to */
  switch (type)
   {
    case SYMTYPE:  incr = 7; /* note:  control falls through STRTYPE */
                   dlm = '|';

    case STRTYPE:  count = get_word(page, disp+1) - incr;
                   if (count > 40) count = 40;
                   disp += incr;
                   printf(" %c",dlm);
                   while (count > 0)
                    {
                     ch = get_byte(page, disp);
                     printf("%c", ch);  disp++;  count--;
                    }
                   printf("%c\n",dlm);
                   break;

    case FIXTYPE:  printf(" %d\n", get_fix(page, disp));
                   break;

    case FLOTYPE:  printf(" %g\n", get_flo(page,disp));
                   break;

    case CHARTYPE: ch = get_char(page, disp);
                   str = " ";
                   *str = ch;
                   for (i = 0; i < test_num; i++)
                    {
                     if (ch == test_char[i])
                      {
                       str = test_string[i];
                       break;
                      }
                    }
                   printf(" #\\%s\n", str);
                   break;

    case LISTTYPE:  if (page == 0) printf(" nil");
    default:       printf("\n");
   } /* end:  switch (type) */
 } /* end of function:  annotate(page, disp) */

/************************************************************************/
/*                          Dump Environment                            */
/************************************************************************/

dump_environment(page, disp)
int page;               /* page number of current environment entry */
int disp;               /* displacement of current environment entry */
{
  extern int display;
  extern int show;
  int search[2];
  int pair[2];
  int sym[2];
  char *symbol;         /* globally bound symbol (character representation) */

  char *symbol_name();  /* retrieves a symbol's print name */

  search[C_PAGE] = page;
  search[C_DISP] = disp;
  while (search[C_PAGE]) {
    INTR_OUTPUT;

    /* fetch pointer to symbol/value pair */
    mov_reg(pair, search);
    take_car(pair);

    /* fetch pointer to symbol */
    mov_reg(sym, pair);
    take_car(sym);

    /* retrieve symbol's print name and print said */
    symbol = symbol_name(CORRPAGE(sym[C_PAGE]), sym[C_DISP]);
    printf("%s\n", symbol);
    rlsstr(symbol);

    /* display the value currently bound to the symbol */
    take_cdr(pair);
    annotate(CORRPAGE(pair[C_PAGE]), pair[C_DISP]);
    ssetadr(ADJPAGE(OUT_PAGE), OUT_DISP);
    display = show = 1;
    sprint(CORRPAGE(pair[C_PAGE]), pair[C_DISP], ADJPAGE(OUT_PAGE),
                                  OUT_DISP);

    outchar('\015');
    outchar('\015');

    /* follow linked list in cdr field */
    take_cdr(search);

  } /* end:  while (search[C_PAGE]) */
bye:
} /* end of function:  dump_environment() */
