sim: mcore/microblaze: clean up a bit
[external/binutils.git] / sim / microblaze / interp.c
1 /* Simulator for Xilinx MicroBlaze processor
2    Copyright 2009-2015 Free Software Foundation, Inc.
3
4    This file is part of GDB, the GNU debugger.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
18
19 #include "config.h"
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/times.h>
24 #include <sys/param.h>
25 #include <unistd.h>
26 #include "bfd.h"
27 #include "gdb/callback.h"
28 #include "libiberty.h"
29 #include "gdb/remote-sim.h"
30 #include "run-sim.h"
31 #include "sim-main.h"
32 #include "sim-utils.h"
33 #include "microblaze-dis.h"
34
35
36 #ifndef NUM_ELEM
37 #define NUM_ELEM(A) (sizeof (A) / sizeof (A)[0])
38 #endif
39
40 static int target_big_endian = 1;
41 static unsigned long heap_ptr = 0;
42 static unsigned long stack_ptr = 0;
43 host_callback *callback;
44
45 static unsigned long
46 microblaze_extract_unsigned_integer (unsigned char *addr, int len)
47 {
48   unsigned long retval;
49   unsigned char *p;
50   unsigned char *startaddr = (unsigned char *)addr;
51   unsigned char *endaddr = startaddr + len;
52
53   if (len > (int) sizeof (unsigned long))
54     printf ("That operation is not available on integers of more than "
55             "%zu bytes.", sizeof (unsigned long));
56
57   /* Start at the most significant end of the integer, and work towards
58      the least significant.  */
59   retval = 0;
60
61   if (!target_big_endian)
62     {
63       for (p = endaddr; p > startaddr;)
64         retval = (retval << 8) | * -- p;
65     }
66   else
67     {
68       for (p = startaddr; p < endaddr;)
69         retval = (retval << 8) | * p ++;
70     }
71
72   return retval;
73 }
74
75 static void
76 microblaze_store_unsigned_integer (unsigned char *addr, int len,
77                                    unsigned long val)
78 {
79   unsigned char *p;
80   unsigned char *startaddr = (unsigned char *)addr;
81   unsigned char *endaddr = startaddr + len;
82
83   if (!target_big_endian)
84     {
85       for (p = startaddr; p < endaddr;)
86         {
87           *p++ = val & 0xff;
88           val >>= 8;
89         }
90     }
91   else
92     {
93       for (p = endaddr; p > startaddr;)
94         {
95           *--p = val & 0xff;
96           val >>= 8;
97         }
98     }
99 }
100
101 struct sim_state microblaze_state;
102
103 int memcycles = 1;
104
105 static SIM_OPEN_KIND sim_kind;
106 static char *myname;
107
108 static int issue_messages = 0;
109
110 static void /* INLINE */
111 wbat (word x, word v)
112 {
113   if (((uword)x) >= CPU.msize)
114     {
115       if (issue_messages)
116         fprintf (stderr, "byte write to 0x%x outside memory range\n", x);
117
118       CPU.exception = SIGSEGV;
119     }
120   else
121     {
122       unsigned char *p = CPU.memory + x;
123       p[0] = v;
124     }
125 }
126
127 static void /* INLINE */
128 wlat (word x, word v)
129 {
130   if (((uword)x) >= CPU.msize)
131     {
132       if (issue_messages)
133         fprintf (stderr, "word write to 0x%x outside memory range\n", x);
134
135       CPU.exception = SIGSEGV;
136     }
137   else
138     {
139       if ((x & 3) != 0)
140         {
141           if (issue_messages)
142             fprintf (stderr, "word write to unaligned memory address: 0x%x\n", x);
143
144           CPU.exception = SIGBUS;
145         }
146       else if (!target_big_endian)
147         {
148           unsigned char *p = CPU.memory + x;
149           p[3] = v >> 24;
150           p[2] = v >> 16;
151           p[1] = v >> 8;
152           p[0] = v;
153         }
154       else
155         {
156           unsigned char *p = CPU.memory + x;
157           p[0] = v >> 24;
158           p[1] = v >> 16;
159           p[2] = v >> 8;
160           p[3] = v;
161         }
162     }
163 }
164
165 static void /* INLINE */
166 what (word x, word v)
167 {
168   if (((uword)x) >= CPU.msize)
169     {
170       if (issue_messages)
171         fprintf (stderr, "short write to 0x%x outside memory range\n", x);
172
173       CPU.exception = SIGSEGV;
174     }
175   else
176     {
177       if ((x & 1) != 0)
178         {
179           if (issue_messages)
180             fprintf (stderr, "short write to unaligned memory address: 0x%x\n",
181                      x);
182
183           CPU.exception = SIGBUS;
184         }
185       else if (!target_big_endian)
186         {
187           unsigned char *p = CPU.memory + x;
188           p[1] = v >> 8;
189           p[0] = v;
190         }
191       else
192         {
193           unsigned char *p = CPU.memory + x;
194           p[0] = v >> 8;
195           p[1] = v;
196         }
197     }
198 }
199
200 /* Read functions.  */
201 static int /* INLINE */
202 rbat (word x)
203 {
204   if (((uword)x) >= CPU.msize)
205     {
206       if (issue_messages)
207         fprintf (stderr, "byte read from 0x%x outside memory range\n", x);
208
209       CPU.exception = SIGSEGV;
210       return 0;
211     }
212   else
213     {
214       unsigned char *p = CPU.memory + x;
215       return p[0];
216     }
217 }
218
219 static int /* INLINE */
220 rlat (word x)
221 {
222   if (((uword) x) >= CPU.msize)
223     {
224       if (issue_messages)
225         fprintf (stderr, "word read from 0x%x outside memory range\n", x);
226
227       CPU.exception = SIGSEGV;
228       return 0;
229     }
230   else
231     {
232       if ((x & 3) != 0)
233         {
234           if (issue_messages)
235             fprintf (stderr, "word read from unaligned address: 0x%x\n", x);
236
237           CPU.exception = SIGBUS;
238           return 0;
239         }
240       else if (! target_big_endian)
241         {
242           unsigned char *p = CPU.memory + x;
243           return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
244         }
245       else
246         {
247           unsigned char *p = CPU.memory + x;
248           return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
249         }
250     }
251 }
252
253 static int /* INLINE */
254 rhat (word x)
255 {
256   if (((uword)x) >= CPU.msize)
257     {
258       if (issue_messages)
259         fprintf (stderr, "short read from 0x%x outside memory range\n", x);
260
261       CPU.exception = SIGSEGV;
262       return 0;
263     }
264   else
265     {
266       if ((x & 1) != 0)
267         {
268           if (issue_messages)
269             fprintf (stderr, "short read from unaligned address: 0x%x\n", x);
270
271           CPU.exception = SIGBUS;
272           return 0;
273         }
274       else if (!target_big_endian)
275         {
276           unsigned char *p = CPU.memory + x;
277           return (p[1] << 8) | p[0];
278         }
279       else
280         {
281           unsigned char *p = CPU.memory + x;
282           return (p[0] << 8) | p[1];
283         }
284     }
285 }
286
287 /* Default to a 8 Mbyte (== 2^23) memory space.  */
288 static int sim_memory_size = 1 << 23;
289
290 #define MEM_SIZE_FLOOR  64
291 void
292 sim_size (int size)
293 {
294   sim_memory_size = size;
295   CPU.msize = sim_memory_size;
296
297   if (CPU.memory)
298     free (CPU.memory);
299
300   CPU.memory = (unsigned char *) calloc (1, CPU.msize);
301
302   if (!CPU.memory)
303     {
304       if (issue_messages)
305         fprintf (stderr,
306                  "Not enough VM for simulation of %ld bytes of RAM\n",
307                  CPU.msize);
308
309       CPU.msize = 1;
310       CPU.memory = (unsigned char *) calloc (1, 1);
311     }
312 }
313
314 static void
315 init_pointers (void)
316 {
317   if (CPU.msize != (sim_memory_size))
318     sim_size (sim_memory_size);
319 }
320
321 static void
322 set_initial_gprs (void)
323 {
324   int i;
325   long space;
326   unsigned long memsize;
327
328   init_pointers ();
329
330   /* Set up machine just out of reset.  */
331   PC = 0;
332   MSR = 0;
333
334   memsize = CPU.msize / (1024 * 1024);
335
336   if (issue_messages > 1)
337     fprintf (stderr, "Simulated memory of %ld Mbytes (0x0 .. 0x%08lx)\n",
338              memsize, CPU.msize - 1);
339
340   /* Clean out the GPRs */
341   for (i = 0; i < 32; i++)
342     CPU.regs[i] = 0;
343   CPU.insts = 0;
344   CPU.cycles = 0;
345   CPU.imm_enable = 0;
346 }
347
348 #define WATCHFUNCTIONS 1
349 #ifdef WATCHFUNCTIONS
350
351 #define MAXWL 80
352 word WL[MAXWL];
353 char *WLstr[MAXWL];
354
355 int ENDWL=0;
356 int WLincyc;
357 int WLcyc[MAXWL];
358 int WLcnts[MAXWL];
359 int WLmax[MAXWL];
360 int WLmin[MAXWL];
361 word WLendpc;
362 int WLbcyc;
363 int WLW;
364 #endif
365
366 static int tracing = 0;
367
368 void
369 sim_resume (SIM_DESC sd, int step, int siggnal)
370 {
371   int needfetch;
372   word inst;
373   enum microblaze_instr op;
374   int memops;
375   int bonus_cycles;
376   int insts;
377   int w;
378   int cycs;
379   word WLhash;
380   ubyte carry;
381   int imm_unsigned;
382   short ra, rb, rd;
383   long immword;
384   uword oldpc, newpc;
385   short delay_slot_enable;
386   short branch_taken;
387   short num_delay_slot; /* UNUSED except as reqd parameter */
388   enum microblaze_instr_type insn_type;
389
390   CPU.exception = step ? SIGTRAP : 0;
391
392   memops = 0;
393   bonus_cycles = 0;
394   insts = 0;
395   
396   do
397     {
398       /* Fetch the initial instructions that we'll decode. */
399       inst = rlat (PC & 0xFFFFFFFC);
400
401       op = get_insn_microblaze (inst, &imm_unsigned, &insn_type, 
402                                 &num_delay_slot);
403
404       if (op == invalid_inst)
405         fprintf (stderr, "Unknown instruction 0x%04x", inst);
406
407       if (tracing)
408         fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
409
410       rd = GET_RD;
411       rb = GET_RB;
412       ra = GET_RA;
413       /*      immword = IMM_W; */
414
415       oldpc = PC;
416       delay_slot_enable = 0;
417       branch_taken = 0;
418       if (op == microblaze_brk)
419         CPU.exception = SIGTRAP;
420       else if (inst == MICROBLAZE_HALT_INST)
421         {
422           CPU.exception = SIGQUIT;
423           insts += 1;
424           bonus_cycles++;
425         }
426       else
427         {
428           switch(op)
429             {
430 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION)         \
431             case NAME:                                  \
432               ACTION;                                   \
433               break;
434 #include "microblaze.isa"
435 #undef INSTRUCTION
436
437             default:
438               CPU.exception = SIGILL;
439               fprintf (stderr, "ERROR: Unknown opcode\n");
440             }
441           /* Make R0 consistent */
442           CPU.regs[0] = 0;
443
444           /* Check for imm instr */
445           if (op == imm)
446             IMM_ENABLE = 1;
447           else
448             IMM_ENABLE = 0;
449
450           /* Update cycle counts */
451           insts ++;
452           if (insn_type == memory_store_inst || insn_type == memory_load_inst)
453             memops++;
454           if (insn_type == mult_inst)
455             bonus_cycles++;
456           if (insn_type == barrel_shift_inst)
457             bonus_cycles++;
458           if (insn_type == anyware_inst)
459             bonus_cycles++;
460           if (insn_type == div_inst)
461             bonus_cycles += 33;
462
463           if ((insn_type == branch_inst || insn_type == return_inst)
464               && branch_taken) 
465             {
466               /* Add an extra cycle for taken branches */
467               bonus_cycles++;
468               /* For branch instructions handle the instruction in the delay slot */
469               if (delay_slot_enable) 
470                 {
471                   newpc = PC;
472                   PC = oldpc + INST_SIZE;
473                   inst = rlat (PC & 0xFFFFFFFC);
474                   op = get_insn_microblaze (inst, &imm_unsigned, &insn_type,
475                                             &num_delay_slot);
476                   if (op == invalid_inst)
477                     fprintf (stderr, "Unknown instruction 0x%04x", inst);
478                   if (tracing)
479                     fprintf (stderr, "%.4x: inst = %.4x ", PC, inst);
480                   rd = GET_RD;
481                   rb = GET_RB;
482                   ra = GET_RA;
483                   /*          immword = IMM_W; */
484                   if (op == microblaze_brk)
485                     {
486                       if (issue_messages)
487                         fprintf (stderr, "Breakpoint set in delay slot "
488                                  "(at address 0x%x) will not be honored\n", PC);
489                       /* ignore the breakpoint */
490                     }
491                   else if (insn_type == branch_inst || insn_type == return_inst)
492                     {
493                       if (issue_messages)
494                         fprintf (stderr, "Cannot have branch or return instructions "
495                                  "in delay slot (at address 0x%x)\n", PC);
496                       CPU.exception = SIGILL;
497                     }
498                   else
499                     {
500                       switch(op)
501                         {
502 #define INSTRUCTION(NAME, OPCODE, TYPE, ACTION)         \
503                         case NAME:                      \
504                           ACTION;                       \
505                           break;
506 #include "microblaze.isa"
507 #undef INSTRUCTION
508
509                         default:
510                           CPU.exception = SIGILL;
511                           fprintf (stderr, "ERROR: Unknown opcode at 0x%x\n", PC);
512                         }
513                       /* Update cycle counts */
514                       insts++;
515                       if (insn_type == memory_store_inst
516                           || insn_type == memory_load_inst) 
517                         memops++;
518                       if (insn_type == mult_inst)
519                         bonus_cycles++;
520                       if (insn_type == barrel_shift_inst)
521                         bonus_cycles++;
522                       if (insn_type == anyware_inst)
523                         bonus_cycles++;
524                       if (insn_type == div_inst)
525                         bonus_cycles += 33;
526                     }
527                   /* Restore the PC */
528                   PC = newpc;
529                   /* Make R0 consistent */
530                   CPU.regs[0] = 0;
531                   /* Check for imm instr */
532                   if (op == imm)
533                     IMM_ENABLE = 1;
534                   else
535                     IMM_ENABLE = 0;
536                 }
537               else
538                 /* no delay slot: increment cycle count */
539                 bonus_cycles++;
540             }
541         }
542
543       if (tracing)
544         fprintf (stderr, "\n");
545     }
546   while (!CPU.exception);
547
548   /* Hide away the things we've cached while executing.  */
549   /*  CPU.pc = pc; */
550   CPU.insts += insts;           /* instructions done ... */
551   CPU.cycles += insts;          /* and each takes a cycle */
552   CPU.cycles += bonus_cycles;   /* and extra cycles for branches */
553   CPU.cycles += memops;         /* and memop cycle delays */
554 }
555
556
557 int
558 sim_write (SIM_DESC sd, SIM_ADDR addr, const unsigned char *buffer, int size)
559 {
560   int i;
561   init_pointers ();
562
563   memcpy (&CPU.memory[addr], buffer, size);
564
565   return size;
566 }
567
568 int
569 sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size)
570 {
571   int i;
572   init_pointers ();
573
574   memcpy (buffer, &CPU.memory[addr], size);
575
576   return size;
577 }
578
579
580 int
581 sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
582 {
583   init_pointers ();
584
585   if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
586     {
587       if (length == 4)
588         {
589           /* misalignment safe */
590           long ival = microblaze_extract_unsigned_integer (memory, 4);
591           if (rn < NUM_REGS)
592             CPU.regs[rn] = ival;
593           else
594             CPU.spregs[rn-NUM_REGS] = ival;
595           return 4;
596         }
597       else
598         return 0;
599     }
600   else
601     return 0;
602 }
603
604 int
605 sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
606 {
607   long ival;
608   init_pointers ();
609
610   if (rn < NUM_REGS + NUM_SPECIAL && rn >= 0)
611     {
612       if (length == 4)
613         {
614           if (rn < NUM_REGS)
615             ival = CPU.regs[rn];
616           else
617             ival = CPU.spregs[rn-NUM_REGS];
618
619           /* misalignment-safe */
620           microblaze_store_unsigned_integer (memory, 4, ival);
621           return 4;
622         }
623       else
624         return 0;
625     }
626   else
627     return 0;
628 }
629
630
631 int
632 sim_trace (SIM_DESC sd)
633 {
634   tracing = 1;
635
636   sim_resume (sd, 0, 0);
637
638   tracing = 0;
639
640   return 1;
641 }
642
643 void
644 sim_stop_reason (SIM_DESC sd, enum sim_stop *reason, int *sigrc)
645 {
646   if (CPU.exception == SIGQUIT)
647     {
648       *reason = sim_exited;
649       *sigrc = RETREG;
650     }
651   else
652     {
653       *reason = sim_stopped;
654       *sigrc = CPU.exception;
655     }
656 }
657
658
659 int
660 sim_stop (SIM_DESC sd)
661 {
662   CPU.exception = SIGINT;
663   return 1;
664 }
665
666
667 void
668 sim_info (SIM_DESC sd, int verbose)
669 {
670 #ifdef WATCHFUNCTIONS
671   int w, wcyc;
672 #endif
673
674   callback->printf_filtered (callback, "\n\n# instructions executed  %10d\n",
675                              CPU.insts);
676   callback->printf_filtered (callback, "# cycles                 %10d\n",
677                              (CPU.cycles) ? CPU.cycles+2 : 0);
678
679 #ifdef WATCHFUNCTIONS
680   callback->printf_filtered (callback, "\nNumber of watched functions: %d\n",
681                              ENDWL);
682
683   wcyc = 0;
684
685   for (w = 1; w <= ENDWL; w++)
686     {
687       callback->printf_filtered (callback, "WL = %s %8x\n",WLstr[w],WL[w]);
688       callback->printf_filtered (callback, "  calls = %d, cycles = %d\n",
689                                  WLcnts[w],WLcyc[w]);
690
691       if (WLcnts[w] != 0)
692         callback->printf_filtered (callback,
693                                    "  maxcpc = %d, mincpc = %d, avecpc = %d\n",
694                                    WLmax[w],WLmin[w],WLcyc[w]/WLcnts[w]);
695       wcyc += WLcyc[w];
696     }
697
698   callback->printf_filtered (callback,
699                              "Total cycles for watched functions: %d\n",wcyc);
700 #endif
701 }
702
703 struct  aout
704 {
705   unsigned char  sa_machtype[2];
706   unsigned char  sa_magic[2];
707   unsigned char  sa_tsize[4];
708   unsigned char  sa_dsize[4];
709   unsigned char  sa_bsize[4];
710   unsigned char  sa_syms[4];
711   unsigned char  sa_entry[4];
712   unsigned char  sa_trelo[4];
713   unsigned char  sa_drelo[4];
714 } aout;
715
716 #define LONG(x)         (((x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
717 #define SHORT(x)        (((x)[0]<<8)|(x)[1])
718
719 SIM_DESC
720 sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
721 {
722   /*  SIM_DESC sd = sim_state_alloc(kind, alloc);*/
723
724   int osize = sim_memory_size;
725   myname = argv[0];
726   callback = cb;
727
728   if (kind == SIM_OPEN_STANDALONE)
729     issue_messages = 1;
730
731   /* Discard and reacquire memory -- start with a clean slate.  */
732   sim_size (1);         /* small */
733   sim_size (osize);     /* and back again */
734
735   set_initial_gprs ();  /* Reset the GPR registers.  */
736
737   return ((SIM_DESC) 1);
738 }
739
740 void
741 sim_close (SIM_DESC sd, int quitting)
742 {
743   if (CPU.memory)
744     {
745       free(CPU.memory);
746       CPU.memory = NULL;
747       CPU.msize = 0;
748     }
749 }
750
751 SIM_RC
752 sim_load (SIM_DESC sd, const char *prog, bfd *abfd, int from_tty)
753 {
754   /* Do the right thing for ELF executables; this turns out to be
755      just about the right thing for any object format that:
756        - we crack using BFD routines
757        - follows the traditional UNIX text/data/bss layout
758        - calls the bss section ".bss".   */
759
760   extern bfd *sim_load_file (); /* ??? Don't know where this should live.  */
761   bfd *prog_bfd;
762
763   {
764     bfd *handle;
765     asection *s;
766     int found_loadable_section = 0;
767     bfd_vma max_addr = 0;
768     handle = bfd_openr (prog, 0);
769
770     if (!handle)
771       {
772         printf("``%s'' could not be opened.\n", prog);
773         return SIM_RC_FAIL;
774       }
775
776     /* Makes sure that we have an object file, also cleans gets the
777        section headers in place.  */
778     if (!bfd_check_format (handle, bfd_object))
779       {
780         /* wasn't an object file */
781         bfd_close (handle);
782         printf ("``%s'' is not appropriate object file.\n", prog);
783         return SIM_RC_FAIL;
784       }
785
786     for (s = handle->sections; s; s = s->next)
787       {
788         if (s->flags & SEC_ALLOC)
789           {
790             bfd_vma vma = 0;
791             int size = bfd_get_section_size (s);
792             if (size > 0)
793               {
794                 vma = bfd_section_vma (handle, s);
795                 if (vma >= max_addr)
796                   {
797                     max_addr = vma + size;
798                   }
799               }
800             if (s->flags & SEC_LOAD)
801               found_loadable_section = 1;
802           }
803       }
804
805     if (!found_loadable_section)
806       {
807         /* No loadable sections */
808         bfd_close(handle);
809         printf("No loadable sections in file %s\n", prog);
810         return SIM_RC_FAIL;
811       }
812
813     sim_memory_size = (unsigned long) max_addr;
814
815     /* Clean up after ourselves.  */
816     bfd_close (handle);
817
818   }
819
820   /* from sh -- dac */
821   prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
822                             /* sim_kind == SIM_OPEN_DEBUG, */
823                             1,
824                             0, sim_write);
825   if (prog_bfd == NULL)
826     return SIM_RC_FAIL;
827
828   target_big_endian = bfd_big_endian (prog_bfd);
829   PC = bfd_get_start_address (prog_bfd);
830
831   if (abfd == NULL)
832     bfd_close (prog_bfd);
833
834   return SIM_RC_OK;
835 }
836
837 SIM_RC
838 sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env)
839 {
840   char **avp;
841   int nargs = 0;
842   int nenv = 0;
843   int s_length;
844   int l;
845   unsigned long strings;
846   unsigned long pointers;
847   unsigned long hi_stack;
848
849
850   /* Set the initial register set.  */
851   l = issue_messages;
852   issue_messages = 0;
853   set_initial_gprs ();
854   issue_messages = l;
855
856   hi_stack = CPU.msize - 4;
857   PC = bfd_get_start_address (prog_bfd);
858
859   /* For now ignore all parameters to the program */
860
861   return SIM_RC_OK;
862 }
863
864 void
865 sim_do_command (SIM_DESC sd, const char *cmd)
866 {
867   /* Nothing there yet; it's all an error.  */
868
869   if (cmd != NULL)
870     {
871       char ** simargv = buildargv (cmd);
872
873       if (strcmp (simargv[0], "watch") == 0)
874         {
875           if ((simargv[1] == NULL) || (simargv[2] == NULL))
876             {
877               fprintf (stderr, "Error: missing argument to watch cmd.\n");
878               freeargv (simargv);
879               return;
880             }
881
882           ENDWL++;
883
884           WL[ENDWL] = strtol (simargv[2], NULL, 0);
885           WLstr[ENDWL] = strdup (simargv[1]);
886           fprintf (stderr, "Added %s (%x) to watchlist, #%d\n",WLstr[ENDWL],
887                    WL[ENDWL], ENDWL);
888
889         }
890       else if (strcmp (simargv[0], "dumpmem") == 0)
891         {
892           unsigned char * p;
893           FILE * dumpfile;
894
895           if (simargv[1] == NULL)
896             fprintf (stderr, "Error: missing argument to dumpmem cmd.\n");
897
898           fprintf (stderr, "Writing dumpfile %s...",simargv[1]);
899
900           dumpfile = fopen (simargv[1], "w");
901           p = CPU.memory;
902           fwrite (p, CPU.msize-1, 1, dumpfile);
903           fclose (dumpfile);
904
905           fprintf (stderr, "done.\n");
906         }
907       else if (strcmp (simargv[0], "clearstats") == 0)
908         {
909           CPU.cycles = 0;
910           CPU.insts = 0;
911           ENDWL = 0;
912         }
913       else if (strcmp (simargv[0], "verbose") == 0)
914         {
915           issue_messages = 2;
916         }
917       else
918         {
919           fprintf (stderr,"Error: \"%s\" is not a valid M.CORE simulator command.\n",
920                    cmd);
921         }
922
923       freeargv (simargv);
924     }
925   else
926     {
927       fprintf (stderr, "M.CORE sim commands: \n");
928       fprintf (stderr, "  watch <funcname> <addr>\n");
929       fprintf (stderr, "  dumpmem <filename>\n");
930       fprintf (stderr, "  clearstats\n");
931       fprintf (stderr, "  verbose\n");
932     }
933 }
934
935 void
936 sim_set_callbacks (host_callback *ptr)
937 {
938   callback = ptr;
939 }
940
941 char **
942 sim_complete_command (SIM_DESC sd, const char *text, const char *word)
943 {
944   return NULL;
945 }