break dcache code out of remote.c
authorK. Richard Pixley <rich@cygnus>
Wed, 1 Sep 1993 00:43:09 +0000 (00:43 +0000)
committerK. Richard Pixley <rich@cygnus>
Wed, 1 Sep 1993 00:43:09 +0000 (00:43 +0000)
gdb/ChangeLog
gdb/Makefile.in
gdb/dcache.c
gdb/dcache.h
gdb/remote.c

index b05f8ad..ed900e8 100644 (file)
@@ -1,5 +1,18 @@
 Tue Aug 31 15:01:27 1993  K. Richard Pixley  (rich@sendai.cygnus.com)
 
+       Break dcache code out of remote.c.
+       * dcache.h: white space changes only.
+       * dcache.c: add user settable variable to set whether data caching
+         is in use.
+       * remote.c: include dcache.h. removed data caching code which is
+         now in dcache.c.  Compile in data caching again.  (data caching
+         is currently off by default.)
+         (remote_read_bytes, remote_write_bytes): change second arg to
+         unsigned char.
+         (remote_dcache): new static variable.
+       * Makefile.in (REMOTE_O): add dcache.o.
+       * config/m88k/m88k.mt (TDEPFILES): removed dcache.o.
+
        Break dcache code out of remote-bug.c into dcache.[hc].
        * Makefile.in (dcache_h): new macro.
          (HFILES): added $(dcache_h).
index ba227cc..e734640 100644 (file)
@@ -189,7 +189,7 @@ SER_HARDWIRE=ser-unix.o
 
 # The `remote' debugging target is supported for most architectures,
 # but not all (e.g. 960)
-REMOTE_O=remote.o
+REMOTE_O = remote.o dcache.o
 
 # Host and target-dependent makefile fragments come in here.
 ####
index 864b068..1b477b0 100644 (file)
@@ -21,10 +21,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "defs.h"
 #include "dcache.h"
+#include "gdbcmd.h"
 
 extern int insque();
 extern int remque();
 
+int remote_dcache = 0;
+
 /* The data cache records all the data read from the remote machine
    since the last time it stopped.
 
@@ -41,17 +44,21 @@ dcache_flush (dcache)
 {
   register struct dcache_block *db;
 
-  while ((db = dcache->dcache_valid.next) != &dcache->dcache_valid)
-    {
-      remque (db);
-      insque (db, &dcache->dcache_free);
-    }
+  if (remote_dcache > 0)
+    while ((db = dcache->dcache_valid.next) != &dcache->dcache_valid)
+      {
+       remque (db);
+       insque (db, &dcache->dcache_free);
+      }
+
+  return;
 }
 
 /*
  * If addr is present in the dcache, return the address of the block
  * containing it.
  */
+static
 struct dcache_block *
 dcache_hit (dcache, addr)
      DCACHE *dcache;
@@ -59,7 +66,8 @@ dcache_hit (dcache, addr)
 {
   register struct dcache_block *db;
 
-  if (addr & 3)
+  if (addr & 3
+      || remote_dcache == 0)
     abort ();
 
   /* Search all cache blocks for one that is at this address.  */
@@ -70,16 +78,19 @@ dcache_hit (dcache, addr)
        return db;
       db = db->next;
     }
+
   return NULL;
 }
 
 /*  Return the int data at address ADDR in dcache block DC.  */
+static
 int
 dcache_value (db, addr)
      struct dcache_block *db;
      unsigned int addr;
 {
-  if (addr & 3)
+  if (addr & 3
+      || remote_dcache == 0)
     abort ();
   return (db->data[XFORM (addr)]);
 }
@@ -91,12 +102,16 @@ dcache_value (db, addr)
    prevents errors from creeping in if a memory retrieval is
    interrupted (which used to put garbage blocks in the valid
    list...).  */
+static
 struct dcache_block *
 dcache_alloc (dcache)
      DCACHE *dcache;
 {
   register struct dcache_block *db;
 
+  if (remote_dcache == 0)
+    abort();
+
   if ((db = dcache->dcache_free.next) == &dcache->dcache_free)
     {
       /* If we can't get one from the free list, take last valid and put
@@ -111,8 +126,8 @@ dcache_alloc (dcache)
   return (db);
 }
 
-/* Return the contents of the word at address ADDR in the remote machine,
-   using the data cache.  */
+/* Using the data cache DCACHE return the contents of the word at
+   address ADDR in the remote machine.  */
 int
 dcache_fetch (dcache, addr)
      DCACHE *dcache;
@@ -120,6 +135,14 @@ dcache_fetch (dcache, addr)
 {
   register struct dcache_block *db;
 
+  if (remote_dcache == 0)
+    {
+      int i;
+
+      (*dcache->read_memory) (addr, (unsigned char *) &i, 4);
+      return(i);
+    }
+
   db = dcache_hit (dcache, addr);
   if (db == 0)
     {
@@ -143,6 +166,12 @@ dcache_poke (dcache, addr, data)
 {
   register struct dcache_block *db;
 
+  if (remote_dcache == 0)
+    {
+      (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
+      return;
+    }
+
   /* First make sure the word is IN the cache.  DB is its cache block.  */
   db = dcache_hit (dcache, addr);
   if (db == 0)
@@ -152,8 +181,8 @@ dcache_poke (dcache, addr, data)
       (*dcache->write_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
       immediate_quit--;
       db->addr = addr & ~LINE_SIZE_MASK;
-      remque (db);             /* Off the free list */
-      insque (db, &dcache->dcache_valid);      /* On the valid list */
+      remque (db); /* Off the free list */
+      insque (db, &dcache->dcache_valid); /* On the valid list */
     }
 
   /* Modify the word in the cache.  */
@@ -188,3 +217,19 @@ dcache_init (reading, writing)
   return(dcache);
 }
 
+void
+_initialitize_dcache ()
+{
+  add_show_from_set
+    (add_set_cmd ("remotecache", class_support, var_boolean,
+                 (char *) &remote_dcache,
+                 "\
+Set cache use for remote targets.\n\
+When on, use data caching for remote targets.  For many remote targets\n\
+this option can offer better throughput for reading target memory.\n\
+Unfortunately, gdb does not currently know anything about volatile\n\
+registers and thus data caching will produce incorrect results with\n\
+volatile registers are in use.  By default, this option is off.", 
+                 &setlist),
+     &showlist);
+}
index 071ac6e..bfc0dd7 100644 (file)
@@ -22,6 +22,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifndef DCACHE_H
 #define DCACHE_H
 
+/* The data cache leads to incorrect results because it doesn't know about
+   volatile variables, thus making it impossible to debug functions which
+   use hardware registers.  Therefore it is #if 0'd out.  Effect on
+   performance is some, for backtraces of functions with a few
+   arguments each.  For functions with many arguments, the stack
+   frames don't fit in the cache blocks, which makes the cache less
+   helpful.  Disabling the cache is a big performance win for fetching
+   large structures, because the cache code fetched data in 16-byte
+   chunks.  */
+
 #define LINE_SIZE_POWER (4)
 /* eg 1<<3 == 8 */
 #define LINE_SIZE (1 << LINE_SIZE_POWER)
@@ -57,8 +67,14 @@ typedef struct {
 
 } DCACHE;
 
+/* Using the data cache DCACHE return the contents of the word at
+   address ADDR in the remote machine.  */
 int dcache_fetch PARAMS((DCACHE *dcache, CORE_ADDR addr));
+
+/* Flush DCACHE. */
 void dcache_flush PARAMS((DCACHE *dcache));
+
+/* Initialize DCACHE. */
 DCACHE *dcache_init PARAMS((memxferfunc reading, memxferfunc writing));
 
 /* Write the word at ADDR both in the data cache and in the remote machine.  */
index 806c60b..43d0f33 100644 (file)
@@ -56,6 +56,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
        read mem        mAA..AA,LLLL    AA..AA is address, LLLL is length.
        reply           XX..XX          XX..XX is mem contents
+                                       Can be fewer bytes than requested
+                                       if able to read only part of the data.
                        or ENN          NN is errno
 
        write mem       MAA..AA,LLLL:XX..XX
@@ -63,7 +65,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
                                        LLLL is number of bytes,
                                        XX..XX is data
        reply           OK              for success
-                       ENN             for an error
+                       ENN             for an error (this includes the case
+                                       where only part of the data was
+                                       written).
 
        cont            cAA..AA         AA..AA is address to resume
                                        If AA..AA is omitted,
@@ -87,7 +91,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
                                        n... = register number
                                        r... = register contents
 
-       kill req        k
+       kill request    k
+
+       toggle debug    d               toggle debug flag (see 386 & 68k stubs)
+       reset           r               reset -- see sparc stub.
+       reserved        <other>         On other requests, the stub should
+                                       ignore the request and send an empty
+                                       response ($#<checksum>).  This way
+                                       we can extend the protocol and GDB
+                                       can tell whether the stub it is
+                                       talking to uses the old or the new.
 */
 
 #include "defs.h"
@@ -102,6 +115,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "terminal.h"
 #include "gdbcmd.h"
 
+#include "dcache.h"
+
 #if !defined(DONT_USE_REMOTE)
 #ifdef USG
 #include <sys/types.h>
@@ -112,11 +127,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* Prototypes for local functions */
 
-static void
-remote_write_bytes PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+static int
+remote_write_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
 
-static void
-remote_read_bytes PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+static int
+remote_read_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len));
 
 static void
 remote_files_info PARAMS ((struct target_ops *ignore));
@@ -132,7 +147,7 @@ static void
 remote_fetch_registers PARAMS ((int regno));
 
 static void
-remote_resume PARAMS ((int step, int siggnal));
+remote_resume PARAMS ((int pid, int step, int siggnal));
 
 static int
 remote_start_remote PARAMS ((char *dummy));
@@ -178,7 +193,6 @@ remote_interrupt_twice PARAMS ((int signo));
 
 extern struct target_ops remote_ops;   /* Forward decl */
 
-static int kiodebug = 0;
 /* This was 5 seconds, which is a long time to sit and wait.
    Unless this is going though some terminal server or multiplexer or
    other form of hairy serial connection, I would think 2 seconds would
@@ -237,6 +251,8 @@ remote_start_remote (dummy)
 /* Open a connection to a remote debugger.
    NAME is the filename used for communication.  */
 
+static DCACHE *remote_dcache;
+
 static void
 remote_open (name, from_tty)
      char *name;
@@ -251,9 +267,7 @@ device is attached to the remote system (e.g. /dev/ttya).");
 
   unpush_target (&remote_ops);
 
-#if 0
-  dcache_init ();
-#endif
+  remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes);
 
   remote_desc = SERIAL_OPEN (name);
   if (!remote_desc)
@@ -339,8 +353,8 @@ tohex (nib)
 /* Tell the remote machine to resume.  */
 
 static void
-remote_resume (step, siggnal)
-     int step, siggnal;
+remote_resume (pid, step, siggnal)
+     int pid, step, siggnal;
 {
   char buf[PBUFSIZ];
 
@@ -358,9 +372,7 @@ remote_resume (step, siggnal)
       target_terminal_inferior ();
     }
 
-#if 0
-  dcache_flush ();
-#endif
+  dcache_flush (remote_dcache);
 
   strcpy (buf, step ? "s": "c");
 
@@ -377,7 +389,7 @@ remote_interrupt (signo)
   /* If this doesn't work, try more severe steps.  */
   signal (signo, remote_interrupt_twice);
   
-  if (kiodebug)
+  if (remote_debug)
     printf ("remote_interrupt called\n");
 
   SERIAL_WRITE (remote_desc, "\003", 1); /* Send a ^C */
@@ -551,7 +563,6 @@ remote_store_registers (regno)
   remote_send (buf);
 }
 
-#if 0
 /* Read a word from remote address ADDR and return it.
    This goes through the data cache.  */
 
@@ -559,6 +570,7 @@ int
 remote_fetch_word (addr)
      CORE_ADDR addr;
 {
+#if 0
   if (icache)
     {
       extern CORE_ADDR text_start, text_end;
@@ -570,7 +582,8 @@ remote_fetch_word (addr)
          return buffer;
        }
     }
-  return dcache_fetch (addr);
+#endif
+  return dcache_fetch (remote_dcache, addr);
 }
 
 /* Write a word WORD into remote address ADDR.
@@ -581,20 +594,22 @@ remote_store_word (addr, word)
      CORE_ADDR addr;
      int word;
 {
-  dcache_poke (addr, word);
+  dcache_poke (remote_dcache, addr, word);
 }
-#endif /* 0 */
+
 \f
 /* Write memory data directly to the remote machine.
    This does not inform the data cache; the data cache uses this.
    MEMADDR is the address in the remote memory space.
    MYADDR is the address of the buffer in our space.
-   LEN is the number of bytes.  */
+   LEN is the number of bytes.
 
-static void
+   Returns number of bytes transferred, or 0 for error.  */
+
+static int
 remote_write_bytes (memaddr, myaddr, len)
      CORE_ADDR memaddr;
-     char *myaddr;
+     unsigned char *myaddr;
      int len;
 {
   char buf[PBUFSIZ];
@@ -617,19 +632,33 @@ remote_write_bytes (memaddr, myaddr, len)
     }
   *p = '\0';
 
-  remote_send (buf);
+  putpkt (buf);
+  getpkt (buf, 0);
+
+  if (buf[0] == 'E')
+    {
+      /* There is no correspondance between what the remote protocol uses
+        for errors and errno codes.  We would like a cleaner way of
+        representing errors (big enough to include errno codes, bfd_error
+        codes, and others).  But for now just return EIO.  */
+      errno = EIO;
+      return 0;
+    }
+  return len;
 }
 
 /* Read memory data directly from the remote machine.
    This does not use the data cache; the data cache uses this.
    MEMADDR is the address in the remote memory space.
    MYADDR is the address of the buffer in our space.
-   LEN is the number of bytes.  */
+   LEN is the number of bytes.
 
-static void
+   Returns number of bytes transferred, or 0 for error.  */
+
+static int
 remote_read_bytes (memaddr, myaddr, len)
      CORE_ADDR memaddr;
-     char *myaddr;
+     unsigned char *myaddr;
      int len;
 {
   char buf[PBUFSIZ];
@@ -640,7 +669,18 @@ remote_read_bytes (memaddr, myaddr, len)
     abort ();
 
   sprintf (buf, "m%x,%x", memaddr, len);
-  remote_send (buf);
+  putpkt (buf);
+  getpkt (buf, 0);
+
+  if (buf[0] == 'E')
+    {
+      /* There is no correspondance between what the remote protocol uses
+        for errors and errno codes.  We would like a cleaner way of
+        representing errors (big enough to include errno codes, bfd_error
+        codes, and others).  But for now just return EIO.  */
+      errno = EIO;
+      return 0;
+    }
 
   /* Reply describes memory byte by byte,
      each byte encoded as two hex characters.  */
@@ -649,10 +689,13 @@ remote_read_bytes (memaddr, myaddr, len)
   for (i = 0; i < len; i++)
     {
       if (p[0] == 0 || p[1] == 0)
-       error ("Remote reply is too short: %s", buf);
+       /* Reply is short.  This means that we were able to read only part
+          of what we wanted to.  */
+       break;
       myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
       p += 2;
     }
+  return i;
 }
 \f
 /* Read or write LEN bytes from inferior memory at MEMADDR, transferring
@@ -668,8 +711,10 @@ remote_xfer_memory(memaddr, myaddr, len, should_write, target)
      int should_write;
      struct target_ops *target;                        /* ignored */
 {
-  int origlen = len;
   int xfersize;
+  int bytes_xferred;
+  int total_xferred = 0;
+
   while (len > 0)
     {
       if (len > MAXBUFBYTES)
@@ -678,14 +723,20 @@ remote_xfer_memory(memaddr, myaddr, len, should_write, target)
        xfersize = len;
 
       if (should_write)
-        remote_write_bytes(memaddr, myaddr, xfersize);
+        bytes_xferred = remote_write_bytes (memaddr, myaddr, xfersize);
       else
-       remote_read_bytes (memaddr, myaddr, xfersize);
-      memaddr += xfersize;
-      myaddr  += xfersize;
-      len     -= xfersize;
+       bytes_xferred = remote_read_bytes (memaddr, myaddr, xfersize);
+
+      /* If we get an error, we are done xferring.  */
+      if (bytes_xferred == 0)
+       break;
+
+      memaddr += bytes_xferred;
+      myaddr  += bytes_xferred;
+      len     -= bytes_xferred;
+      total_xferred += bytes_xferred;
     }
-  return origlen; /* no error possible */
+  return total_xferred;
 }
 
 static void
@@ -765,7 +816,7 @@ putpkt (buf)
 
   while (1)
     {
-      if (kiodebug)
+      if (remote_debug)
        {
          *p = '\0';
          printf ("Sending packet: %s...", buf2);  fflush(stdout);
@@ -781,7 +832,7 @@ putpkt (buf)
          switch (ch)
            {
            case '+':
-             if (kiodebug)
+             if (remote_debug)
                printf("Ack\n");
              return;
            case SERIAL_TIMEOUT:
@@ -791,7 +842,7 @@ putpkt (buf)
            case SERIAL_EOF:
              error ("putpkt: EOF while trying to read ACK");
            default:
-             if (kiodebug)
+             if (remote_debug)
                printf ("%02X %c ", ch&0xFF, ch);
              continue;
            }
@@ -832,7 +883,7 @@ getpkt (buf, forever)
          if (forever)
            continue;
          if (++retries >= MAX_RETRIES)
-           if (kiodebug) puts_filtered ("Timed out.\n");
+           if (remote_debug) puts_filtered ("Timed out.\n");
          goto out;
        }
 
@@ -850,13 +901,13 @@ getpkt (buf, forever)
          c = readchar ();
          if (c == SERIAL_TIMEOUT)
            {
-             if (kiodebug)
+             if (remote_debug)
                puts_filtered ("Timeout in mid-packet, retrying\n");
              goto whole;               /* Start a new packet, count retries */
            } 
          if (c == '$')
            {
-             if (kiodebug)
+             if (remote_debug)
                puts_filtered ("Saw new packet start in middle of old one\n");
              goto whole;               /* Start a new packet, count retries */
            }
@@ -901,163 +952,10 @@ out:
 
   SERIAL_WRITE (remote_desc, "+", 1);
 
-  if (kiodebug)
+  if (remote_debug)
     fprintf (stderr,"Packet received: %s\n", buf);
 }
 \f
-/* The data cache leads to incorrect results because it doesn't know about
-   volatile variables, thus making it impossible to debug functions which
-   use hardware registers.  Therefore it is #if 0'd out.  Effect on
-   performance is some, for backtraces of functions with a few
-   arguments each.  For functions with many arguments, the stack
-   frames don't fit in the cache blocks, which makes the cache less
-   helpful.  Disabling the cache is a big performance win for fetching
-   large structures, because the cache code fetched data in 16-byte
-   chunks.  */
-#if 0
-/* The data cache records all the data read from the remote machine
-   since the last time it stopped.
-
-   Each cache block holds 16 bytes of data
-   starting at a multiple-of-16 address.  */
-
-#define DCACHE_SIZE 64         /* Number of cache blocks */
-
-struct dcache_block {
-       struct dcache_block *next, *last;
-       unsigned int addr;      /* Address for which data is recorded.  */
-       int data[4];
-};
-
-struct dcache_block dcache_free, dcache_valid;
-
-/* Free all the data cache blocks, thus discarding all cached data.  */ 
-
-static void
-dcache_flush ()
-{
-  register struct dcache_block *db;
-
-  while ((db = dcache_valid.next) != &dcache_valid)
-    {
-      remque (db);
-      insque (db, &dcache_free);
-    }
-}
-
-/*
- * If addr is present in the dcache, return the address of the block 
- * containing it.
- */
-
-struct dcache_block *
-dcache_hit (addr)
-{
-  register struct dcache_block *db;
-
-  if (addr & 3)
-    abort ();
-
-  /* Search all cache blocks for one that is at this address.  */
-  db = dcache_valid.next;
-  while (db != &dcache_valid)
-    {
-      if ((addr & 0xfffffff0) == db->addr)
-       return db;
-      db = db->next;
-    }
-  return NULL;
-}
-
-/*  Return the int data at address ADDR in dcache block DC.  */
-
-int
-dcache_value (db, addr)
-     struct dcache_block *db;
-     unsigned int addr;
-{
-  if (addr & 3)
-    abort ();
-  return (db->data[(addr>>2)&3]);
-}
-
-/* Get a free cache block, put it on the valid list,
-   and return its address.  The caller should store into the block
-   the address and data that it describes.  */
-
-struct dcache_block *
-dcache_alloc ()
-{
-  register struct dcache_block *db;
-
-  if ((db = dcache_free.next) == &dcache_free)
-    /* If we can't get one from the free list, take last valid */
-    db = dcache_valid.last;
-
-  remque (db);
-  insque (db, &dcache_valid);
-  return (db);
-}
-
-/* Return the contents of the word at address ADDR in the remote machine,
-   using the data cache.  */
-
-int
-dcache_fetch (addr)
-     CORE_ADDR addr;
-{
-  register struct dcache_block *db;
-
-  db = dcache_hit (addr);
-  if (db == 0)
-    {
-      db = dcache_alloc ();
-      remote_read_bytes (addr & ~0xf, db->data, 16);
-      db->addr = addr & ~0xf;
-    }
-  return (dcache_value (db, addr));
-}
-
-/* Write the word at ADDR both in the data cache and in the remote machine.  */
-
-dcache_poke (addr, data)
-     CORE_ADDR addr;
-     int data;
-{
-  register struct dcache_block *db;
-
-  /* First make sure the word is IN the cache.  DB is its cache block.  */
-  db = dcache_hit (addr);
-  if (db == 0)
-    {
-      db = dcache_alloc ();
-      remote_read_bytes (addr & ~0xf, db->data, 16);
-      db->addr = addr & ~0xf;
-    }
-
-  /* Modify the word in the cache.  */
-  db->data[(addr>>2)&3] = data;
-
-  /* Send the changed word.  */
-  remote_write_bytes (addr, &data, 4);
-}
-
-/* Initialize the data cache.  */
-
-dcache_init ()
-{
-  register i;
-  register struct dcache_block *db;
-
-  db = (struct dcache_block *) xmalloc (sizeof (struct dcache_block) * 
-                                       DCACHE_SIZE);
-  dcache_free.next = dcache_free.last = &dcache_free;
-  dcache_valid.next = dcache_valid.last = &dcache_valid;
-  for (i=0;i<DCACHE_SIZE;i++,db++)
-    insque (db, &dcache_free);
-}
-#endif /* 0 */
-\f
 static void
 remote_kill ()
 {
@@ -1099,7 +997,7 @@ static unsigned char break_insn[] = BREAKPOINT;
    by the caller to be long enough to save sizeof BREAKPOINT bytes (this
    is accomplished via BREAKPOINT_MAX).  */
 
-int
+static int
 remote_insert_breakpoint (addr, contents_cache)
      CORE_ADDR addr;
      char *contents_cache;
@@ -1114,7 +1012,7 @@ remote_insert_breakpoint (addr, contents_cache)
   return val;
 }
 
-int
+static int
 remote_remove_breakpoint (addr, contents_cache)
      CORE_ADDR addr;
      char *contents_cache;
@@ -1172,13 +1070,5 @@ void
 _initialize_remote ()
 {
   add_target (&remote_ops);
-
-  add_show_from_set (
-    add_set_cmd ("remotedebug", no_class, var_boolean, (char *)&kiodebug,
-                  "Set debugging of remote serial I/O.\n\
-When enabled, each packet sent or received with the remote target\n\
-is displayed.", &setlist),
-       &showlist);
 }
-
 #endif