]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/mcore/interp.c
Copyright updates for 2007.
[thirdparty/binutils-gdb.git] / sim / mcore / interp.c
CommitLineData
0fda6bd2 1/* Simulator for Motorola's MCore processor
6aba47ca 2 Copyright (C) 1999, 2000, 2002, 2003, 2007 Free Software Foundation, Inc.
2d514e6f
SS
3 Contributed by Cygnus Solutions.
4
5This file is part of GDB, the GNU debugger.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License along
18with this program; if not, write to the Free Software Foundation, Inc.,
1959 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21#include <signal.h>
22#include "sysdep.h"
23#include <sys/times.h>
24#include <sys/param.h>
25#include <netinet/in.h> /* for byte ordering macros */
26#include "bfd.h"
3c25f8c7 27#include "gdb/callback.h"
2d514e6f 28#include "libiberty.h"
3c25f8c7 29#include "gdb/remote-sim.h"
2d514e6f
SS
30
31#ifndef NUM_ELEM
32#define NUM_ELEM(A) (sizeof (A) / sizeof (A)[0])
33#endif
34
35
36typedef long int word;
37typedef unsigned long int uword;
38
63a027a3 39static int target_big_endian = 0;
2d514e6f
SS
40static unsigned long heap_ptr = 0;
41host_callback * callback;
42
43
2d514e6f
SS
44unsigned long
45mcore_extract_unsigned_integer (addr, len)
46 unsigned char * addr;
47 int len;
48{
49 unsigned long retval;
50 unsigned char * p;
51 unsigned char * startaddr = (unsigned char *)addr;
52 unsigned char * endaddr = startaddr + len;
53
54 if (len > (int) sizeof (unsigned long))
55 printf ("That operation is not available on integers of more than %d bytes.",
56 sizeof (unsigned long));
57
58 /* Start at the most significant end of the integer, and work towards
59 the least significant. */
60 retval = 0;
cd0fc7c3 61
63a027a3
NC
62 if (! target_big_endian)
63 {
64 for (p = endaddr; p > startaddr;)
65 retval = (retval << 8) | * -- p;
66 }
67 else
cd0fc7c3
SS
68 {
69 for (p = startaddr; p < endaddr;)
70 retval = (retval << 8) | * p ++;
71 }
2d514e6f
SS
72
73 return retval;
74}
75
76void
77mcore_store_unsigned_integer (addr, len, val)
78 unsigned char * addr;
79 int len;
80 unsigned long val;
81{
82 unsigned char * p;
83 unsigned char * startaddr = (unsigned char *)addr;
84 unsigned char * endaddr = startaddr + len;
cd0fc7c3 85
63a027a3
NC
86 if (! target_big_endian)
87 {
88 for (p = startaddr; p < endaddr;)
89 {
90 * p ++ = val & 0xff;
91 val >>= 8;
92 }
93 }
94 else
2d514e6f 95 {
cd0fc7c3
SS
96 for (p = endaddr; p > startaddr;)
97 {
98 * -- p = val & 0xff;
99 val >>= 8;
100 }
2d514e6f
SS
101 }
102}
103
104/* The machine state.
105 This state is maintained in host byte order. The
106 fetch/store register functions must translate between host
cd0fc7c3 107 byte order and the target processor byte order.
2d514e6f
SS
108 Keeping this data in target byte order simplifies the register
109 read/write functions. Keeping this data in native order improves
110 the performance of the simulator. Simulation speed is deemed more
63a027a3 111 important. */
2d514e6f
SS
112
113/* The ordering of the mcore_regset structure is matched in the
114 gdb/config/mcore/tm-mcore.h file in the REGISTER_NAMES macro. */
115struct mcore_regset
116{
117 word gregs [16]; /* primary registers */
118 word alt_gregs [16]; /* alt register file */
119 word cregs [32]; /* control registers */
120 word pc; /* the pc */
121 int ticks;
122 int stalls;
123 int cycles;
124 int insts;
125 int exception;
126 unsigned long msize;
127 unsigned char * memory;
128 word * active_gregs;
129};
130
131union
132{
133 struct mcore_regset asregs;
134 word asints [1]; /* but accessed larger... */
135} cpu;
136
9e086581
JM
137#define LAST_VALID_CREG 32 /* only 0..12 implemented */
138#define NUM_MCORE_REGS (16 + 16 + LAST_VALID_CREG + 1)
2d514e6f
SS
139
140int memcycles = 1;
141
142static SIM_OPEN_KIND sim_kind;
143static char * myname;
144
145static int issue_messages = 0;
146
147#define gr asregs.active_gregs
148#define cr asregs.cregs
149#define sr asregs.cregs[0]
150#define vbr asregs.cregs[1]
151#define esr asregs.cregs[2]
152#define fsr asregs.cregs[3]
153#define epc asregs.cregs[4]
154#define fpc asregs.cregs[5]
155#define ss0 asregs.cregs[6]
156#define ss1 asregs.cregs[7]
157#define ss2 asregs.cregs[8]
158#define ss3 asregs.cregs[9]
159#define ss4 asregs.cregs[10]
160#define gcr asregs.cregs[11]
161#define gsr asregs.cregs[12]
162#define mem asregs.memory
163
164/* maniuplate the carry bit */
cd0fc7c3 165#define C_ON() (cpu.sr & 1)
2d514e6f 166#define C_VALUE() (cpu.sr & 1)
cd0fc7c3
SS
167#define C_OFF() ((cpu.sr & 1) == 0)
168#define SET_C() {cpu.sr |= 1;}
169#define CLR_C() {cpu.sr &= 0xfffffffe;}
170#define NEW_C(v) {CLR_C(); cpu.sr |= ((v) & 1);}
2d514e6f
SS
171
172#define SR_AF() ((cpu.sr >> 1) & 1)
173
174#define TRAPCODE 1 /* r1 holds which function we want */
175#define PARM1 2 /* first parameter */
176#define PARM2 3
177#define PARM3 4
178#define PARM4 5
179#define RET1 2 /* register for return values. */
180
181long
182int_sbrk (inc_bytes)
183 int inc_bytes;
184{
185 long addr;
186
187 addr = heap_ptr;
188
189 heap_ptr += inc_bytes;
190
191 if (issue_messages && heap_ptr>cpu.gr[0])
192 fprintf (stderr, "Warning: heap_ptr overlaps stack!\n");
193
194 return addr;
195}
196
197static void INLINE
198wbat (x, v)
199 word x, v;
200{
201 if (((uword)x) >= cpu.asregs.msize)
202 {
203 if (issue_messages)
204 fprintf (stderr, "byte write to 0x%x outside memory range\n", x);
205
206 cpu.asregs.exception = SIGSEGV;
207 }
208 else
209 {
210 unsigned char *p = cpu.mem + x;
211 p[0] = v;
212 }
213}
214
215static void INLINE
216wlat (x, v)
217 word x, v;
218{
219 if (((uword)x) >= cpu.asregs.msize)
220 {
221 if (issue_messages)
222 fprintf (stderr, "word write to 0x%x outside memory range\n", x);
223
224 cpu.asregs.exception = SIGSEGV;
225 }
226 else
227 {
228 if ((x & 3) != 0)
229 {
230 if (issue_messages)
231 fprintf (stderr, "word write to unaligned memory address: 0x%x\n", x);
232
233 cpu.asregs.exception = SIGBUS;
234 }
63a027a3
NC
235 else if (! target_big_endian)
236 {
237 unsigned char * p = cpu.mem + x;
238 p[3] = v >> 24;
239 p[2] = v >> 16;
240 p[1] = v >> 8;
241 p[0] = v;
242 }
2d514e6f
SS
243 else
244 {
245 unsigned char * p = cpu.mem + x;
246 p[0] = v >> 24;
247 p[1] = v >> 16;
248 p[2] = v >> 8;
249 p[3] = v;
250 }
251 }
252}
253
254static void INLINE
255what (x, v)
256 word x, v;
257{
258 if (((uword)x) >= cpu.asregs.msize)
259 {
260 if (issue_messages)
261 fprintf (stderr, "short write to 0x%x outside memory range\n", x);
262
263 cpu.asregs.exception = SIGSEGV;
264 }
265 else
266 {
267 if ((x & 1) != 0)
268 {
269 if (issue_messages)
cd0fc7c3
SS
270 fprintf (stderr, "short write to unaligned memory address: 0x%x\n",
271 x);
2d514e6f
SS
272
273 cpu.asregs.exception = SIGBUS;
274 }
63a027a3
NC
275 else if (! target_big_endian)
276 {
277 unsigned char * p = cpu.mem + x;
278 p[1] = v >> 8;
279 p[0] = v;
280 }
2d514e6f
SS
281 else
282 {
283 unsigned char * p = cpu.mem + x;
284 p[0] = v >> 8;
285 p[1] = v;
286 }
287 }
288}
289
4cd93614 290/* Read functions. */
2d514e6f
SS
291static int INLINE
292rbat (x)
293 word x;
294{
295 if (((uword)x) >= cpu.asregs.msize)
296 {
297 if (issue_messages)
298 fprintf (stderr, "byte read from 0x%x outside memory range\n", x);
299
300 cpu.asregs.exception = SIGSEGV;
301 return 0;
302 }
303 else
304 {
305 unsigned char * p = cpu.mem + x;
306 return p[0];
307 }
308}
309
310static int INLINE
311rlat (x)
312 word x;
313{
314 if (((uword) x) >= cpu.asregs.msize)
315 {
316 if (issue_messages)
317 fprintf (stderr, "word read from 0x%x outside memory range\n", x);
318
319 cpu.asregs.exception = SIGSEGV;
320 return 0;
321 }
322 else
323 {
324 if ((x & 3) != 0)
325 {
326 if (issue_messages)
327 fprintf (stderr, "word read from unaligned address: 0x%x\n", x);
328
329 cpu.asregs.exception = SIGBUS;
330 return 0;
331 }
63a027a3
NC
332 else if (! target_big_endian)
333 {
334 unsigned char * p = cpu.mem + x;
335 return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
336 }
2d514e6f
SS
337 else
338 {
339 unsigned char * p = cpu.mem + x;
340 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
341 }
342 }
343}
344
345static int INLINE
346rhat (x)
347 word x;
348{
349 if (((uword)x) >= cpu.asregs.msize)
350 {
351 if (issue_messages)
352 fprintf (stderr, "short read from 0x%x outside memory range\n", x);
353
354 cpu.asregs.exception = SIGSEGV;
355 return 0;
356 }
357 else
358 {
359 if ((x & 1) != 0)
360 {
361 if (issue_messages)
362 fprintf (stderr, "short read from unaligned address: 0x%x\n", x);
363
364 cpu.asregs.exception = SIGBUS;
365 return 0;
366 }
63a027a3
NC
367 else if (! target_big_endian)
368 {
369 unsigned char * p = cpu.mem + x;
370 return (p[1] << 8) | p[0];
371 }
2d514e6f
SS
372 else
373 {
374 unsigned char * p = cpu.mem + x;
375 return (p[0] << 8) | p[1];
376 }
377 }
378}
379
380
381#define SEXTB(x) (((x & 0xff) ^ (~ 0x7f)) + 0x80)
382#define SEXTW(y) ((int)((short)y))
383
384static int
385IOMEM (addr, write, value)
386 int addr;
387 int write;
388 int value;
389{
390}
391
4cd93614 392/* Default to a 8 Mbyte (== 2^23) memory space. */
2d514e6f
SS
393static int sim_memory_size = 23;
394
395#define MEM_SIZE_FLOOR 64
396void
397sim_size (power)
398 int power;
399{
400 sim_memory_size = power;
401 cpu.asregs.msize = 1 << sim_memory_size;
402
403 if (cpu.mem)
404 free (cpu.mem);
405
4cd93614
FCE
406 /* Watch out for the '0 count' problem. There's probably a better
407 way.. e.g., why do we use 64 here? */
408 if (cpu.asregs.msize < 64) /* Ensure a boundary. */
2d514e6f
SS
409 cpu.mem = (unsigned char *) calloc (64, (64 + cpu.asregs.msize) / 64);
410 else
411 cpu.mem = (unsigned char *) calloc (64, cpu.asregs.msize / 64);
412
413 if (!cpu.mem)
414 {
415 if (issue_messages)
416 fprintf (stderr,
cd0fc7c3
SS
417 "Not enough VM for simulation of %d bytes of RAM\n",
418 cpu.asregs.msize);
2d514e6f
SS
419
420 cpu.asregs.msize = 1;
421 cpu.mem = (unsigned char *) calloc (1, 1);
422 }
423}
424
425static void
426init_pointers ()
427{
428 if (cpu.asregs.msize != (1 << sim_memory_size))
429 sim_size (sim_memory_size);
430}
431
432static void
433set_initial_gprs ()
434{
435 int i;
436 long space;
437 unsigned long memsize;
438
439 init_pointers ();
440
441 /* Set up machine just out of reset. */
442 cpu.asregs.pc = 0;
443 cpu.sr = 0;
444
445 memsize = cpu.asregs.msize / (1024 * 1024);
446
b83266a0 447 if (issue_messages > 1)
2d514e6f
SS
448 fprintf (stderr, "Simulated memory of %d Mbytes (0x0 .. 0x%08x)\n",
449 memsize, cpu.asregs.msize - 1);
450
451 /* Clean out the GPRs and alternate GPRs. */
452 for (i = 0; i < 16; i++)
453 {
454 cpu.asregs.gregs[i] = 0;
455 cpu.asregs.alt_gregs[i] = 0;
456 }
457
458 /* Make our register set point to the right place. */
459 if (SR_AF())
460 cpu.asregs.active_gregs = &cpu.asregs.alt_gregs[0];
461 else
462 cpu.asregs.active_gregs = &cpu.asregs.gregs[0];
463
464 /* ABI specifies initial values for these registers. */
465 cpu.gr[0] = cpu.asregs.msize - 4;
466
467 /* dac fix, the stack address must be 8-byte aligned! */
468 cpu.gr[0] = cpu.gr[0] - cpu.gr[0] % 8;
469 cpu.gr[PARM1] = 0;
470 cpu.gr[PARM2] = 0;
471 cpu.gr[PARM3] = 0;
472 cpu.gr[PARM4] = cpu.gr[0];
473}
474
475static void
476interrupt ()
477{
478 cpu.asregs.exception = SIGINT;
479}
480
481/* Functions so that trapped open/close don't interfere with the
482 parent's functions. We say that we can't close the descriptors
483 that we didn't open. exit() and cleanup() get in trouble here,
484 to some extent. That's the price of emulation. */
485
486unsigned char opened[100];
487
488static void
489log_open (fd)
490 int fd;
491{
492 if (fd < 0 || fd > NUM_ELEM (opened))
493 return;
494
495 opened[fd] = 1;
496}
497
498static void
499log_close (fd)
500 int fd;
501{
502 if (fd < 0 || fd > NUM_ELEM (opened))
503 return;
504
505 opened[fd] = 0;
506}
507
508static int
509is_opened (fd)
510 int fd;
511{
512 if (fd < 0 || fd > NUM_ELEM (opened))
513 return 0;
514
515 return opened[fd];
516}
517
518static void
519handle_trap1 ()
520{
521 unsigned long a[3];
522
cd0fc7c3 523 switch ((unsigned long) (cpu.gr [TRAPCODE]))
2d514e6f
SS
524 {
525 case 3:
526 a[0] = (unsigned long) (cpu.gr[PARM1]);
527 a[1] = (unsigned long) (cpu.mem + cpu.gr[PARM2]);
528 a[2] = (unsigned long) (cpu.gr[PARM3]);
529 cpu.gr[RET1] = callback->read (callback, a[0], (char *) a[1], a[2]);
530 break;
531
532 case 4:
533 a[0] = (unsigned long) (cpu.gr[PARM1]);
534 a[1] = (unsigned long) (cpu.mem + cpu.gr[PARM2]);
535 a[2] = (unsigned long) (cpu.gr[PARM3]);
536 cpu.gr[RET1] = (int)callback->write (callback, a[0], (char *) a[1], a[2]);
537 break;
538
539 case 5:
540 a[0] = (unsigned long) (cpu.mem + cpu.gr[PARM1]);
541 a[1] = (unsigned long) (cpu.gr[PARM2]);
542 /* a[2] = (unsigned long) (cpu.gr[PARM3]); */
543 cpu.gr[RET1] = callback->open (callback, (char *) a[0], a[1]);
544 log_open (cpu.gr[RET1]);
545 break;
546
547 case 6:
3dfcd3c6 548 a[0] = (unsigned long) (cpu.gr[PARM1]);
2d514e6f
SS
549 /* Watch out for debugger's files. */
550 if (is_opened (a[0]))
551 {
552 log_close (a[0]);
553 cpu.gr[RET1] = callback->close (callback, a[0]);
554 }
555 else
556 {
557 /* Don't let him close it. */
558 cpu.gr[RET1] = (-1);
559 }
560 break;
561
562 case 9:
563 a[0] = (unsigned long) (cpu.mem + cpu.gr[PARM1]);
564 a[1] = (unsigned long) (cpu.mem + cpu.gr[PARM2]);
565 cpu.gr[RET1] = link ((char *) a[0], (char *) a[1]);
566 break;
567
568 case 10:
569 a[0] = (unsigned long) (cpu.mem + cpu.gr[PARM1]);
570 cpu.gr[RET1] = callback->unlink (callback, (char *) a[0]);
571 break;
572
573 case 13:
574 /* handle time(0) vs time(&var) */
575 a[0] = (unsigned long) (cpu.gr[PARM1]);
576 if (a[0])
577 a[0] += (unsigned long) cpu.mem;
578 cpu.gr[RET1] = callback->time (callback, (time_t *) a[0]);
579 break;
580
581 case 19:
582 a[0] = (unsigned long) (cpu.gr[PARM1]);
583 a[1] = (unsigned long) (cpu.gr[PARM2]);
584 a[2] = (unsigned long) (cpu.gr[PARM3]);
585 cpu.gr[RET1] = callback->lseek (callback, a[0], a[1], a[2]);
586 break;
587
588 case 33:
589 a[0] = (unsigned long) (cpu.mem + cpu.gr[PARM1]);
590 a[1] = (unsigned long) (cpu.gr[PARM2]);
591 cpu.gr[RET1] = access ((char *) a[0], a[1]);
592 break;
593
594 case 43:
595 a[0] = (unsigned long) (cpu.mem + cpu.gr[PARM1]);
596#if 0
597 cpu.gr[RET1] = times ((char *)a[0]);
598#else
599 {
600 /* Give him simulated cycles for utime
601 and an instruction count for stime. */
602 struct tms
603 {
604 time_t tms_utime;
605 time_t tms_stime;
606 time_t tms_cutime;
607 time_t tms_cstime;
608 } t;
609
610 t.tms_utime = cpu.asregs.cycles;
611 t.tms_stime = cpu.asregs.insts;
612 t.tms_cutime = t.tms_utime;
613 t.tms_cstime = t.tms_stime;
614
615 memcpy ((struct tms *)(a[0]), &t, sizeof (t));
616
617 cpu.gr[RET1] = cpu.asregs.cycles;
618 }
619#endif
620 break;
621
622 case 69:
623 a[0] = (unsigned long) (cpu.gr[PARM1]);
624 cpu.gr[RET1] = int_sbrk (a[0]);
625 break;
626
627 default:
628 if (issue_messages)
cd0fc7c3
SS
629 fprintf (stderr, "WARNING: sys call %d unimplemented\n",
630 cpu.gr[TRAPCODE]);
2d514e6f
SS
631 break;
632 }
633}
634
635static void
636process_stub (what)
637 int what;
638{
639 /* These values should match those in libgloss/mcore/syscalls.s. */
640 switch (what)
641 {
642 case 3: /* _read */
cd0fc7c3 643 case 4: /* _write */
2d514e6f
SS
644 case 5: /* _open */
645 case 6: /* _close */
646 case 10: /* _unlink */
647 case 19: /* _lseek */
648 case 43: /* _times */
649 cpu.gr [TRAPCODE] = what;
650 handle_trap1 ();
651 break;
652
653 default:
654 if (issue_messages)
655 fprintf (stderr, "Unhandled stub opcode: %d\n", what);
656 break;
657 }
658}
659
660static void
661util (what)
662 unsigned what;
663{
664 switch (what)
665 {
666 case 0: /* exit */
667 cpu.asregs.exception = SIGQUIT;
668 break;
669
670 case 1: /* printf */
671 {
672 unsigned long a[6];
673 unsigned char *s;
674 int i;
675
676 a[0] = (unsigned long)(cpu.mem + cpu.gr[PARM1]);
677
678 for (s = (unsigned char *)a[0], i = 1 ; *s && i < 6 ; s++)
679 {
680 if (*s == '%')
681 {
682 if (*++s == 's')
683 a[i] = (unsigned long)(cpu.mem + cpu.gr[PARM1+i]);
684 else
685 a[i] = cpu.gr[i+PARM1];
686 i++;
687 }
688 }
689
690 cpu.gr[RET1] = printf ((char *)a[0], a[1], a[2], a[3], a[4], a[5]);
691 }
692 break;
693
694 case 2: /* scanf */
695 if (issue_messages)
696 fprintf (stderr, "WARNING: scanf unimplemented\n");
697 break;
698
699 case 3: /* utime */
700 cpu.gr[RET1] = cpu.asregs.insts;
701 break;
702
703 case 0xFF:
cd0fc7c3 704 process_stub (cpu.gr[1]);
2d514e6f
SS
705 break;
706
707 default:
708 if (issue_messages)
709 fprintf (stderr, "Unhandled util code: %x\n", what);
710 break;
711 }
712}
713
714/* For figuring out whether we carried; addc/subc use this. */
715static int
716iu_carry (a, b, cin)
717 unsigned long a;
718 unsigned long b;
719 int cin;
720{
721 unsigned long x;
722
723 x = (a & 0xffff) + (b & 0xffff) + cin;
724 x = (x >> 16) + (a >> 16) + (b >> 16);
725 x >>= 16;
726
727 return (x != 0);
728}
729
730#define WATCHFUNCTIONS 1
731#ifdef WATCHFUNCTIONS
732
733#define MAXWL 80
734word WL[MAXWL];
735char * WLstr[MAXWL];
736
737int ENDWL=0;
738int WLincyc;
739int WLcyc[MAXWL];
740int WLcnts[MAXWL];
741int WLmax[MAXWL];
742int WLmin[MAXWL];
743word WLendpc;
744int WLbcyc;
745int WLW;
746#endif
747
748#define RD (inst & 0xF)
749#define RS ((inst >> 4) & 0xF)
750#define RX ((inst >> 8) & 0xF)
751#define IMM5 ((inst >> 4) & 0x1F)
752#define IMM4 ((inst) & 0xF)
753
754static int tracing = 0;
755
756void
757sim_resume (sd, step, siggnal)
758 SIM_DESC sd;
759 int step, siggnal;
760{
761 int needfetch;
762 word ibuf;
763 word pc;
764 unsigned short inst;
765 void (* sigsave)();
766 int memops;
767 int bonus_cycles;
768 int insts;
769 int w;
770 int cycs;
771 word WLhash;
772
773 sigsave = signal (SIGINT, interrupt);
774 cpu.asregs.exception = step ? SIGTRAP: 0;
775 pc = cpu.asregs.pc;
776
cd0fc7c3 777 /* Fetch the initial instructions that we'll decode. */
2d514e6f
SS
778 ibuf = rlat (pc & 0xFFFFFFFC);
779 needfetch = 0;
780
781 memops = 0;
782 bonus_cycles = 0;
783 insts = 0;
784
785 /* make our register set point to the right place */
786 if (SR_AF ())
787 cpu.asregs.active_gregs = & cpu.asregs.alt_gregs[0];
788 else
789 cpu.asregs.active_gregs = & cpu.asregs.gregs[0];
790
791 /* make a hash to speed exec loop, hope it's nonzero */
792 WLhash = 0xFFFFFFFF;
793
794 for (w = 1; w <= ENDWL; w++)
795 WLhash = WLhash & WL[w];
796
797 do
798 {
cd0fc7c3
SS
799 word oldpc;
800
2d514e6f
SS
801 insts ++;
802
803 if (pc & 02)
804 {
63a027a3
NC
805 if (! target_big_endian)
806 inst = ibuf >> 16;
807 else
cd0fc7c3 808 inst = ibuf & 0xFFFF;
2d514e6f
SS
809 needfetch = 1;
810 }
811 else
812 {
63a027a3
NC
813 if (! target_big_endian)
814 inst = ibuf & 0xFFFF;
815 else
cd0fc7c3 816 inst = ibuf >> 16;
2d514e6f
SS
817 }
818
819#ifdef WATCHFUNCTIONS
820 /* now scan list of watch addresses, if match, count it and
821 note return address and count cycles until pc=return address */
822
823 if ((WLincyc == 1) && (pc == WLendpc))
824 {
825 cycs = (cpu.asregs.cycles + (insts + bonus_cycles +
826 (memops * memcycles)) - WLbcyc);
827
828 if (WLcnts[WLW] == 1)
829 {
830 WLmax[WLW] = cycs;
831 WLmin[WLW] = cycs;
832 WLcyc[WLW] = 0;
833 }
834
835 if (cycs > WLmax[WLW])
836 {
837 WLmax[WLW] = cycs;
838 }
839
840 if (cycs < WLmin[WLW])
841 {
842 WLmin[WLW] = cycs;
843 }
844
845 WLcyc[WLW] += cycs;
846 WLincyc = 0;
847 WLendpc = 0;
848 }
849
cd0fc7c3 850 /* Optimize with a hash to speed loop. */
2d514e6f
SS
851 if (WLincyc == 0)
852 {
853 if ((WLhash == 0) || ((WLhash & pc) != 0))
854 {
855 for (w=1; w <= ENDWL; w++)
856 {
857 if (pc == WL[w])
858 {
859 WLcnts[w]++;
860 WLbcyc = cpu.asregs.cycles + insts
861 + bonus_cycles + (memops * memcycles);
862 WLendpc = cpu.gr[15];
863 WLincyc = 1;
864 WLW = w;
865 break;
866 }
867 }
868 }
869 }
870#endif
871
872 if (tracing)
873 fprintf (stderr, "%.4x: inst = %.4x ", pc, inst);
cd0fc7c3
SS
874
875 oldpc = pc;
876
2d514e6f
SS
877 pc += 2;
878
879 switch (inst >> 8)
880 {
881 case 0x00:
882 switch RS
883 {
884 case 0x0:
885 switch RD
886 {
887 case 0x0: /* bkpt */
888 cpu.asregs.exception = SIGTRAP;
9e086581 889 pc -= 2;
2d514e6f
SS
890 break;
891
892 case 0x1: /* sync */
893 break;
894
895 case 0x2: /* rte */
896 pc = cpu.epc;
897 cpu.sr = cpu.esr;
898 needfetch = 1;
899
cd0fc7c3 900 if (SR_AF ())
2d514e6f
SS
901 cpu.asregs.active_gregs = & cpu.asregs.alt_gregs[0];
902 else
903 cpu.asregs.active_gregs = & cpu.asregs.gregs[0];
904 break;
905
906 case 0x3: /* rfi */
907 pc = cpu.fpc;
908 cpu.sr = cpu.fsr;
909 needfetch = 1;
910
911 if (SR_AF ())
912 cpu.asregs.active_gregs = &cpu.asregs.alt_gregs[0];
913 else
914 cpu.asregs.active_gregs = &cpu.asregs.gregs[0];
915 break;
916
917 case 0x4: /* stop */
918 if (issue_messages)
919 fprintf (stderr, "WARNING: stop unimplemented\n");
920 break;
921
922 case 0x5: /* wait */
923 if (issue_messages)
924 fprintf (stderr, "WARNING: wait unimplemented\n");
925 break;
926
927 case 0x6: /* doze */
928 if (issue_messages)
cd0fc7c3 929 fprintf (stderr, "WARNING: doze unimplemented\n");
2d514e6f
SS
930 break;
931
932 case 0x7:
933 cpu.asregs.exception = SIGILL; /* illegal */
934 break;
935
936 case 0x8: /* trap 0 */
937 case 0xA: /* trap 2 */
938 case 0xB: /* trap 3 */
939 cpu.asregs.exception = SIGTRAP;
940 break;
941
942 case 0xC: /* trap 4 */
943 case 0xD: /* trap 5 */
944 case 0xE: /* trap 6 */
945 cpu.asregs.exception = SIGILL; /* illegal */
946 break;
947
948 case 0xF: /* trap 7 */
949 cpu.asregs.exception = SIGTRAP; /* integer div-by-0 */
950 break;
951
952 case 0x9: /* trap 1 */
953 handle_trap1 ();
954 break;
955 }
956 break;
957
958 case 0x1:
959 cpu.asregs.exception = SIGILL; /* illegal */
960 break;
961
962 case 0x2: /* mvc */
963 cpu.gr[RD] = C_VALUE();
964 break;
965 case 0x3: /* mvcv */
966 cpu.gr[RD] = C_OFF();
967 break;
968 case 0x4: /* ldq */
969 {
970 char *addr = (char *)cpu.gr[RD];
971 int regno = 4; /* always r4-r7 */
972
973 bonus_cycles++;
974 memops += 4;
975 do
976 {
977 cpu.gr[regno] = rlat(addr);
978 addr += 4;
979 regno++;
980 }
981 while ((regno&0x3) != 0);
982 }
983 break;
984 case 0x5: /* stq */
985 {
986 char *addr = (char *)cpu.gr[RD];
987 int regno = 4; /* always r4-r7 */
988
989 memops += 4;
990 bonus_cycles++;
991 do
992 {
993 wlat(addr, cpu.gr[regno]);
994 addr += 4;
995 regno++;
996 }
997 while ((regno & 0x3) != 0);
998 }
999 break;
1000 case 0x6: /* ldm */
1001 {
1002 char *addr = (char *)cpu.gr[0];
1003 int regno = RD;
1004
1005 /* bonus cycle is really only needed if
1006 the next insn shifts the last reg loaded.
1007
1008 bonus_cycles++;
1009 */
1010 memops += 16-regno;
1011 while (regno <= 0xF)
1012 {
1013 cpu.gr[regno] = rlat(addr);
1014 addr += 4;
1015 regno++;
1016 }
1017 }
1018 break;
1019 case 0x7: /* stm */
1020 {
1021 char *addr = (char *)cpu.gr[0];
1022 int regno = RD;
1023
1024 /* this should be removed! */
1025 /* bonus_cycles ++; */
1026
1027 memops += 16 - regno;
1028 while (regno <= 0xF)
1029 {
1030 wlat(addr, cpu.gr[regno]);
1031 addr += 4;
1032 regno++;
1033 }
1034 }
1035 break;
1036
1037 case 0x8: /* dect */
1038 cpu.gr[RD] -= C_VALUE();
1039 break;
1040 case 0x9: /* decf */
1041 cpu.gr[RD] -= C_OFF();
1042 break;
1043 case 0xA: /* inct */
1044 cpu.gr[RD] += C_VALUE();
1045 break;
1046 case 0xB: /* incf */
1047 cpu.gr[RD] += C_OFF();
1048 break;
1049 case 0xC: /* jmp */
1050 pc = cpu.gr[RD];
392a587b
JM
1051 if (tracing && RD == 15)
1052 fprintf (stderr, "Func return, r2 = %x, r3 = %x\n",
1053 cpu.gr[2], cpu.gr[3]);
2d514e6f
SS
1054 bonus_cycles++;
1055 needfetch = 1;
1056 break;
1057 case 0xD: /* jsr */
1058 cpu.gr[15] = pc;
1059 pc = cpu.gr[RD];
1060 bonus_cycles++;
1061 needfetch = 1;
1062 break;
1063 case 0xE: /* ff1 */
1064 {
1065 word tmp, i;
1066 tmp = cpu.gr[RD];
1067 for (i = 0; !(tmp & 0x80000000) && i < 32; i++)
1068 tmp <<= 1;
1069 cpu.gr[RD] = i;
1070 }
1071 break;
1072 case 0xF: /* brev */
1073 {
1074 word tmp;
1075 tmp = cpu.gr[RD];
1076 tmp = ((tmp & 0xaaaaaaaa) >> 1) | ((tmp & 0x55555555) << 1);
1077 tmp = ((tmp & 0xcccccccc) >> 2) | ((tmp & 0x33333333) << 2);
1078 tmp = ((tmp & 0xf0f0f0f0) >> 4) | ((tmp & 0x0f0f0f0f) << 4);
1079 tmp = ((tmp & 0xff00ff00) >> 8) | ((tmp & 0x00ff00ff) << 8);
1080 cpu.gr[RD] = ((tmp & 0xffff0000) >> 16) | ((tmp & 0x0000ffff) << 16);
1081 }
1082 break;
1083 }
1084 break;
1085 case 0x01:
1086 switch RS
1087 {
1088 case 0x0: /* xtrb3 */
1089 cpu.gr[1] = (cpu.gr[RD]) & 0xFF;
1090 NEW_C (cpu.gr[RD] != 0);
1091 break;
1092 case 0x1: /* xtrb2 */
1093 cpu.gr[1] = (cpu.gr[RD]>>8) & 0xFF;
1094 NEW_C (cpu.gr[RD] != 0);
1095 break;
1096 case 0x2: /* xtrb1 */
1097 cpu.gr[1] = (cpu.gr[RD]>>16) & 0xFF;
1098 NEW_C (cpu.gr[RD] != 0);
1099 break;
1100 case 0x3: /* xtrb0 */
1101 cpu.gr[1] = (cpu.gr[RD]>>24) & 0xFF;
1102 NEW_C (cpu.gr[RD] != 0);
1103 break;
1104 case 0x4: /* zextb */
1105 cpu.gr[RD] &= 0x000000FF;
1106 break;
1107 case 0x5: /* sextb */
1108 {
1109 long tmp;
1110 tmp = cpu.gr[RD];
1111 tmp <<= 24;
1112 tmp >>= 24;
1113 cpu.gr[RD] = tmp;
1114 }
1115 break;
1116 case 0x6: /* zexth */
1117 cpu.gr[RD] &= 0x0000FFFF;
1118 break;
1119 case 0x7: /* sexth */
1120 {
1121 long tmp;
1122 tmp = cpu.gr[RD];
1123 tmp <<= 16;
1124 tmp >>= 16;
1125 cpu.gr[RD] = tmp;
1126 }
1127 break;
1128 case 0x8: /* declt */
1129 --cpu.gr[RD];
1130 NEW_C ((long)cpu.gr[RD] < 0);
1131 break;
1132 case 0x9: /* tstnbz */
1133 {
1134 word tmp = cpu.gr[RD];
1135 NEW_C ((tmp & 0xFF000000) != 0 &&
1136 (tmp & 0x00FF0000) != 0 && (tmp & 0x0000FF00) != 0 &&
1137 (tmp & 0x000000FF) != 0);
1138 }
1139 break;
1140 case 0xA: /* decgt */
1141 --cpu.gr[RD];
1142 NEW_C ((long)cpu.gr[RD] > 0);
1143 break;
1144 case 0xB: /* decne */
1145 --cpu.gr[RD];
1146 NEW_C ((long)cpu.gr[RD] != 0);
1147 break;
1148 case 0xC: /* clrt */
1149 if (C_ON())
1150 cpu.gr[RD] = 0;
1151 break;
1152 case 0xD: /* clrf */
1153 if (C_OFF())
1154 cpu.gr[RD] = 0;
1155 break;
1156 case 0xE: /* abs */
1157 if (cpu.gr[RD] & 0x80000000)
1158 cpu.gr[RD] = ~cpu.gr[RD] + 1;
1159 break;
1160 case 0xF: /* not */
1161 cpu.gr[RD] = ~cpu.gr[RD];
1162 break;
1163 }
1164 break;
1165 case 0x02: /* movt */
1166 if (C_ON())
1167 cpu.gr[RD] = cpu.gr[RS];
1168 break;
1169 case 0x03: /* mult */
1170 /* consume 2 bits per cycle from rs, until rs is 0 */
1171 {
1172 unsigned int t = cpu.gr[RS];
1173 int ticks;
1174 for (ticks = 0; t != 0 ; t >>= 2)
1175 ticks++;
1176 bonus_cycles += ticks;
1177 }
1178 bonus_cycles += 2; /* min. is 3, so add 2, plus ticks above */
392a587b
JM
1179 if (tracing)
1180 fprintf (stderr, " mult %x by %x to give %x",
1181 cpu.gr[RD], cpu.gr[RS], cpu.gr[RD] * cpu.gr[RS]);
2d514e6f
SS
1182 cpu.gr[RD] = cpu.gr[RD] * cpu.gr[RS];
1183 break;
1184 case 0x04: /* loopt */
1185 if (C_ON())
1186 {
1187 pc += (IMM4 << 1) - 32;
1188 bonus_cycles ++;
1189 needfetch = 1;
1190 }
1191 --cpu.gr[RS]; /* not RD! */
1192 NEW_C (((long)cpu.gr[RS]) > 0);
1193 break;
1194 case 0x05: /* subu */
1195 cpu.gr[RD] -= cpu.gr[RS];
1196 break;
1197 case 0x06: /* addc */
1198 {
1199 unsigned long tmp, a, b;
1200 a = cpu.gr[RD];
1201 b = cpu.gr[RS];
1202 cpu.gr[RD] = a + b + C_VALUE ();
1203 tmp = iu_carry (a, b, C_VALUE ());
1204 NEW_C (tmp);
1205 }
1206 break;
1207 case 0x07: /* subc */
1208 {
1209 unsigned long tmp, a, b;
1210 a = cpu.gr[RD];
1211 b = cpu.gr[RS];
1212 cpu.gr[RD] = a - b + C_VALUE () - 1;
1213 tmp = iu_carry (a,~b, C_VALUE ());
1214 NEW_C (tmp);
1215 }
1216 break;
1217 case 0x08: /* illegal */
1218 case 0x09: /* illegal*/
1219 cpu.asregs.exception = SIGILL;
1220 break;
1221 case 0x0A: /* movf */
1222 if (C_OFF())
1223 cpu.gr[RD] = cpu.gr[RS];
1224 break;
1225 case 0x0B: /* lsr */
1226 {
1227 unsigned long dst, src;
1228 dst = cpu.gr[RD];
1229 src = cpu.gr[RS];
c5394b80
JM
1230 /* We must not rely solely upon the native shift operations, since they
1231 may not match the M*Core's behaviour on boundary conditions. */
1232 dst = src > 31 ? 0 : dst >> src;
2d514e6f
SS
1233 cpu.gr[RD] = dst;
1234 }
1235 break;
1236 case 0x0C: /* cmphs */
1237 NEW_C ((unsigned long )cpu.gr[RD] >=
1238 (unsigned long)cpu.gr[RS]);
1239 break;
1240 case 0x0D: /* cmplt */
1241 NEW_C ((long)cpu.gr[RD] < (long)cpu.gr[RS]);
1242 break;
1243 case 0x0E: /* tst */
1244 NEW_C ((cpu.gr[RD] & cpu.gr[RS]) != 0);
1245 break;
1246 case 0x0F: /* cmpne */
1247 NEW_C (cpu.gr[RD] != cpu.gr[RS]);
1248 break;
1249 case 0x10: case 0x11: /* mfcr */
1250 {
1251 unsigned r;
1252 r = IMM5;
1253 if (r <= LAST_VALID_CREG)
1254 cpu.gr[RD] = cpu.cr[r];
1255 else
1256 cpu.asregs.exception = SIGILL;
1257 }
1258 break;
1259
1260 case 0x12: /* mov */
1261 cpu.gr[RD] = cpu.gr[RS];
392a587b
JM
1262 if (tracing)
1263 fprintf (stderr, "MOV %x into reg %d", cpu.gr[RD], RD);
2d514e6f
SS
1264 break;
1265
1266 case 0x13: /* bgenr */
1267 if (cpu.gr[RS] & 0x20)
1268 cpu.gr[RD] = 0;
1269 else
1270 cpu.gr[RD] = 1 << (cpu.gr[RS] & 0x1F);
1271 break;
1272
1273 case 0x14: /* rsub */
1274 cpu.gr[RD] = cpu.gr[RS] - cpu.gr[RD];
1275 break;
1276
1277 case 0x15: /* ixw */
1278 cpu.gr[RD] += cpu.gr[RS]<<2;
1279 break;
1280
1281 case 0x16: /* and */
1282 cpu.gr[RD] &= cpu.gr[RS];
1283 break;
1284
1285 case 0x17: /* xor */
1286 cpu.gr[RD] ^= cpu.gr[RS];
1287 break;
1288
1289 case 0x18: case 0x19: /* mtcr */
1290 {
1291 unsigned r;
1292 r = IMM5;
1293 if (r <= LAST_VALID_CREG)
1294 cpu.cr[r] = cpu.gr[RD];
1295 else
1296 cpu.asregs.exception = SIGILL;
1297
1298 /* we might have changed register sets... */
1299 if (SR_AF ())
1300 cpu.asregs.active_gregs = & cpu.asregs.alt_gregs[0];
1301 else
1302 cpu.asregs.active_gregs = & cpu.asregs.gregs[0];
1303 }
1304 break;
1305
1306 case 0x1A: /* asr */
c5394b80
JM
1307 /* We must not rely solely upon the native shift operations, since they
1308 may not match the M*Core's behaviour on boundary conditions. */
1309 if (cpu.gr[RS] > 30)
1310 cpu.gr[RD] = ((long) cpu.gr[RD]) < 0 ? -1 : 0;
1311 else
1312 cpu.gr[RD] = (long) cpu.gr[RD] >> cpu.gr[RS];
2d514e6f
SS
1313 break;
1314
1315 case 0x1B: /* lsl */
c5394b80
JM
1316 /* We must not rely solely upon the native shift operations, since they
1317 may not match the M*Core's behaviour on boundary conditions. */
1318 cpu.gr[RD] = cpu.gr[RS] > 31 ? 0 : cpu.gr[RD] << cpu.gr[RS];
2d514e6f
SS
1319 break;
1320
1321 case 0x1C: /* addu */
1322 cpu.gr[RD] += cpu.gr[RS];
1323 break;
1324
1325 case 0x1D: /* ixh */
1326 cpu.gr[RD] += cpu.gr[RS] << 1;
1327 break;
1328
1329 case 0x1E: /* or */
1330 cpu.gr[RD] |= cpu.gr[RS];
1331 break;
1332
1333 case 0x1F: /* andn */
1334 cpu.gr[RD] &= ~cpu.gr[RS];
1335 break;
1336 case 0x20: case 0x21: /* addi */
1337 cpu.gr[RD] =
1338 cpu.gr[RD] + (IMM5 + 1);
1339 break;
1340 case 0x22: case 0x23: /* cmplti */
1341 {
1342 int tmp = (IMM5 + 1);
1343 if (cpu.gr[RD] < tmp)
1344 {
1345 SET_C();
1346 }
1347 else
1348 {
1349 CLR_C();
1350 }
1351 }
1352 break;
1353 case 0x24: case 0x25: /* subi */
1354 cpu.gr[RD] =
1355 cpu.gr[RD] - (IMM5 + 1);
1356 break;
1357 case 0x26: case 0x27: /* illegal */
1358 cpu.asregs.exception = SIGILL;
1359 break;
1360 case 0x28: case 0x29: /* rsubi */
1361 cpu.gr[RD] =
1362 IMM5 - cpu.gr[RD];
1363 break;
1364 case 0x2A: case 0x2B: /* cmpnei */
1365 if (cpu.gr[RD] != IMM5)
1366 {
1367 SET_C();
1368 }
1369 else
1370 {
1371 CLR_C();
1372 }
1373 break;
1374
1375 case 0x2C: case 0x2D: /* bmaski, divu */
1376 {
1377 unsigned imm = IMM5;
1378
1379 if (imm == 1)
1380 {
1381 int exe;
1382 int rxnlz, r1nlz;
1383 unsigned int rx, r1;
1384
1385 rx = cpu.gr[RD];
1386 r1 = cpu.gr[1];
1387 exe = 0;
1388
1389 /* unsigned divide */
1390 cpu.gr[RD] = (word) ((unsigned int) cpu.gr[RD] / (unsigned int)cpu.gr[1] );
1391
1392 /* compute bonus_cycles for divu */
1393 for (r1nlz = 0; ((r1 & 0x80000000) == 0) && (r1nlz < 32); r1nlz ++)
1394 r1 = r1 << 1;
1395
1396 for (rxnlz = 0; ((rx & 0x80000000) == 0) && (rxnlz < 32); rxnlz ++)
1397 rx = rx << 1;
1398
1399 if (r1nlz < rxnlz)
1400 exe += 4;
1401 else
1402 exe += 5 + r1nlz - rxnlz;
1403
1404 if (exe >= (2 * memcycles - 1))
1405 {
1406 bonus_cycles += exe - (2 * memcycles) + 1;
1407 }
1408 }
1409 else if (imm == 0 || imm >= 8)
1410 {
1411 /* bmaski */
1412 if (imm == 0)
1413 cpu.gr[RD] = -1;
1414 else
1415 cpu.gr[RD] = (1 << imm) - 1;
1416 }
1417 else
1418 {
1419 /* illegal */
1420 cpu.asregs.exception = SIGILL;
1421 }
1422 }
1423 break;
1424 case 0x2E: case 0x2F: /* andi */
1425 cpu.gr[RD] = cpu.gr[RD] & IMM5;
1426 break;
1427 case 0x30: case 0x31: /* bclri */
1428 cpu.gr[RD] = cpu.gr[RD] & ~(1<<IMM5);
1429 break;
1430 case 0x32: case 0x33: /* bgeni, divs */
1431 {
1432 unsigned imm = IMM5;
1433 if (imm == 1)
1434 {
1435 int exe,sc;
1436 int rxnlz, r1nlz;
1437 signed int rx, r1;
1438
1439 /* compute bonus_cycles for divu */
1440 rx = cpu.gr[RD];
1441 r1 = cpu.gr[1];
1442 exe = 0;
1443
1444 if (((rx < 0) && (r1 > 0)) || ((rx >= 0) && (r1 < 0)))
1445 sc = 1;
1446 else
1447 sc = 0;
1448
1449 rx = abs (rx);
1450 r1 = abs (r1);
1451
1452 /* signed divide, general registers are of type int, so / op is OK */
1453 cpu.gr[RD] = cpu.gr[RD] / cpu.gr[1];
1454
1455 for (r1nlz = 0; ((r1 & 0x80000000) == 0) && (r1nlz < 32) ; r1nlz ++ )
1456 r1 = r1 << 1;
1457
1458 for (rxnlz = 0; ((rx & 0x80000000) == 0) && (rxnlz < 32) ; rxnlz ++ )
1459 rx = rx << 1;
1460
1461 if (r1nlz < rxnlz)
1462 exe += 5;
1463 else
1464 exe += 6 + r1nlz - rxnlz + sc;
1465
1466 if (exe >= (2 * memcycles - 1))
1467 {
1468 bonus_cycles += exe - (2 * memcycles) + 1;
1469 }
1470 }
1471 else if (imm >= 7)
1472 {
1473 /* bgeni */
1474 cpu.gr[RD] = (1 << IMM5);
1475 }
1476 else
1477 {
1478 /* illegal */
1479 cpu.asregs.exception = SIGILL;
1480 }
1481 break;
1482 }
1483 case 0x34: case 0x35: /* bseti */
1484 cpu.gr[RD] = cpu.gr[RD] | (1 << IMM5);
1485 break;
1486 case 0x36: case 0x37: /* btsti */
1487 NEW_C (cpu.gr[RD] >> IMM5);
1488 break;
1489 case 0x38: case 0x39: /* xsr, rotli */
1490 {
1491 unsigned imm = IMM5;
1492 unsigned long tmp = cpu.gr[RD];
1493 if (imm == 0)
1494 {
1495 word cbit;
1496 cbit = C_VALUE();
1497 NEW_C (tmp);
1498 cpu.gr[RD] = (cbit << 31) | (tmp >> 1);
1499 }
1500 else
1501 cpu.gr[RD] = (tmp << imm) | (tmp >> (32 - imm));
1502 }
1503 break;
1504 case 0x3A: case 0x3B: /* asrc, asri */
1505 {
1506 unsigned imm = IMM5;
1507 long tmp = cpu.gr[RD];
1508 if (imm == 0)
1509 {
1510 NEW_C (tmp);
1511 cpu.gr[RD] = tmp >> 1;
1512 }
1513 else
1514 cpu.gr[RD] = tmp >> imm;
1515 }
1516 break;
1517 case 0x3C: case 0x3D: /* lslc, lsli */
1518 {
1519 unsigned imm = IMM5;
1520 unsigned long tmp = cpu.gr[RD];
1521 if (imm == 0)
1522 {
1523 NEW_C (tmp >> 31);
1524 cpu.gr[RD] = tmp << 1;
1525 }
1526 else
1527 cpu.gr[RD] = tmp << imm;
1528 }
1529 break;
1530 case 0x3E: case 0x3F: /* lsrc, lsri */
1531 {
1532 unsigned imm = IMM5;
1533 unsigned long tmp = cpu.gr[RD];
1534 if (imm == 0)
1535 {
1536 NEW_C (tmp);
1537 cpu.gr[RD] = tmp >> 1;
1538 }
1539 else
1540 cpu.gr[RD] = tmp >> imm;
1541 }
1542 break;
1543 case 0x40: case 0x41: case 0x42: case 0x43:
1544 case 0x44: case 0x45: case 0x46: case 0x47:
1545 case 0x48: case 0x49: case 0x4A: case 0x4B:
1546 case 0x4C: case 0x4D: case 0x4E: case 0x4F:
1547 cpu.asregs.exception = SIGILL;
1548 break;
1549 case 0x50:
1550 util (inst & 0xFF);
1551 break;
1552 case 0x51: case 0x52: case 0x53:
1553 case 0x54: case 0x55: case 0x56: case 0x57:
1554 case 0x58: case 0x59: case 0x5A: case 0x5B:
1555 case 0x5C: case 0x5D: case 0x5E: case 0x5F:
1556 cpu.asregs.exception = SIGILL;
1557 break;
1558 case 0x60: case 0x61: case 0x62: case 0x63: /* movi */
1559 case 0x64: case 0x65: case 0x66: case 0x67:
1560 cpu.gr[RD] = (inst >> 4) & 0x7F;
1561 break;
1562 case 0x68: case 0x69: case 0x6A: case 0x6B:
1563 case 0x6C: case 0x6D: case 0x6E: case 0x6F: /* illegal */
1564 cpu.asregs.exception = SIGILL;
1565 break;
1566 case 0x71: case 0x72: case 0x73:
1567 case 0x74: case 0x75: case 0x76: case 0x77:
1568 case 0x78: case 0x79: case 0x7A: case 0x7B:
1569 case 0x7C: case 0x7D: case 0x7E: /* lrw */
1570 cpu.gr[RX] = rlat ((pc + ((inst & 0xFF) << 2)) & 0xFFFFFFFC);
1571 if (tracing)
1572 fprintf (stderr, "LRW of 0x%x from 0x%x to reg %d",
1573 rlat ((pc + ((inst & 0xFF) << 2)) & 0xFFFFFFFC),
1574 (pc + ((inst & 0xFF) << 2)) & 0xFFFFFFFC, RX);
1575 memops++;
1576 break;
1577 case 0x7F: /* jsri */
1578 cpu.gr[15] = pc;
392a587b
JM
1579 if (tracing)
1580 fprintf (stderr, "func call: r2 = %x r3 = %x r4 = %x r5 = %x r6 = %x r7 = %x\n",
1581 cpu.gr[2], cpu.gr[3], cpu.gr[4], cpu.gr[5], cpu.gr[6], cpu.gr[7]);
2d514e6f
SS
1582 case 0x70: /* jmpi */
1583 pc = rlat ((pc + ((inst & 0xFF) << 2)) & 0xFFFFFFFC);
1584 memops++;
1585 bonus_cycles++;
1586 needfetch = 1;
1587 break;
1588
1589 case 0x80: case 0x81: case 0x82: case 0x83:
1590 case 0x84: case 0x85: case 0x86: case 0x87:
1591 case 0x88: case 0x89: case 0x8A: case 0x8B:
1592 case 0x8C: case 0x8D: case 0x8E: case 0x8F: /* ld */
1593 cpu.gr[RX] = rlat (cpu.gr[RD] + ((inst >> 2) & 0x003C));
1594 if (tracing)
1595 fprintf (stderr, "load reg %d from 0x%x with 0x%x",
1596 RX,
1597 cpu.gr[RD] + ((inst >> 2) & 0x003C), cpu.gr[RX]);
1598 memops++;
1599 break;
1600 case 0x90: case 0x91: case 0x92: case 0x93:
1601 case 0x94: case 0x95: case 0x96: case 0x97:
1602 case 0x98: case 0x99: case 0x9A: case 0x9B:
1603 case 0x9C: case 0x9D: case 0x9E: case 0x9F: /* st */
1604 wlat (cpu.gr[RD] + ((inst >> 2) & 0x003C), cpu.gr[RX]);
1605 if (tracing)
1606 fprintf (stderr, "store reg %d (containing 0x%x) to 0x%x",
1607 RX, cpu.gr[RX],
1608 cpu.gr[RD] + ((inst >> 2) & 0x003C));
1609 memops++;
1610 break;
1611 case 0xA0: case 0xA1: case 0xA2: case 0xA3:
1612 case 0xA4: case 0xA5: case 0xA6: case 0xA7:
1613 case 0xA8: case 0xA9: case 0xAA: case 0xAB:
1614 case 0xAC: case 0xAD: case 0xAE: case 0xAF: /* ld.b */
1615 cpu.gr[RX] = rbat (cpu.gr[RD] + RS);
1616 memops++;
1617 break;
1618 case 0xB0: case 0xB1: case 0xB2: case 0xB3:
1619 case 0xB4: case 0xB5: case 0xB6: case 0xB7:
1620 case 0xB8: case 0xB9: case 0xBA: case 0xBB:
1621 case 0xBC: case 0xBD: case 0xBE: case 0xBF: /* st.b */
1622 wbat (cpu.gr[RD] + RS, cpu.gr[RX]);
1623 memops++;
1624 break;
1625 case 0xC0: case 0xC1: case 0xC2: case 0xC3:
1626 case 0xC4: case 0xC5: case 0xC6: case 0xC7:
1627 case 0xC8: case 0xC9: case 0xCA: case 0xCB:
1628 case 0xCC: case 0xCD: case 0xCE: case 0xCF: /* ld.h */
1629 cpu.gr[RX] = rhat (cpu.gr[RD] + ((inst >> 3) & 0x001E));
1630 memops++;
1631 break;
1632 case 0xD0: case 0xD1: case 0xD2: case 0xD3:
1633 case 0xD4: case 0xD5: case 0xD6: case 0xD7:
1634 case 0xD8: case 0xD9: case 0xDA: case 0xDB:
1635 case 0xDC: case 0xDD: case 0xDE: case 0xDF: /* st.h */
1636 what (cpu.gr[RD] + ((inst >> 3) & 0x001E), cpu.gr[RX]);
1637 memops++;
1638 break;
1639 case 0xE8: case 0xE9: case 0xEA: case 0xEB:
1640 case 0xEC: case 0xED: case 0xEE: case 0xEF: /* bf */
1641 if (C_OFF())
1642 {
1643 int disp;
1644 disp = inst & 0x03FF;
1645 if (inst & 0x0400)
1646 disp |= 0xFFFFFC00;
1647 pc += disp<<1;
1648 bonus_cycles++;
1649 needfetch = 1;
1650 }
1651 break;
1652 case 0xE0: case 0xE1: case 0xE2: case 0xE3:
1653 case 0xE4: case 0xE5: case 0xE6: case 0xE7: /* bt */
1654 if (C_ON())
1655 {
1656 int disp;
1657 disp = inst & 0x03FF;
1658 if (inst & 0x0400)
1659 disp |= 0xFFFFFC00;
1660 pc += disp<<1;
1661 bonus_cycles++;
1662 needfetch = 1;
1663 }
1664 break;
1665
1666 case 0xF8: case 0xF9: case 0xFA: case 0xFB:
1667 case 0xFC: case 0xFD: case 0xFE: case 0xFF: /* bsr */
1668 cpu.gr[15] = pc;
1669 case 0xF0: case 0xF1: case 0xF2: case 0xF3:
1670 case 0xF4: case 0xF5: case 0xF6: case 0xF7: /* br */
1671 {
1672 int disp;
1673 disp = inst & 0x03FF;
1674 if (inst & 0x0400)
1675 disp |= 0xFFFFFC00;
1676 pc += disp<<1;
1677 bonus_cycles++;
1678 needfetch = 1;
1679 }
1680 break;
1681
1682 }
1683
1684 if (tracing)
1685 fprintf (stderr, "\n");
cd0fc7c3 1686
2d514e6f
SS
1687 if (needfetch)
1688 {
1689 /* Do not let him fetch from a bad address! */
1690 if (((uword)pc) >= cpu.asregs.msize)
1691 {
1692 if (issue_messages)
cd0fc7c3 1693 fprintf (stderr, "PC loaded at 0x%x is outside of available memory! (0x%x)\n", oldpc, pc);
2d514e6f
SS
1694
1695 cpu.asregs.exception = SIGSEGV;
1696 }
1697 else
1698 {
1699 ibuf = rlat (pc & 0xFFFFFFFC);
1700 needfetch = 0;
1701 }
1702 }
1703 }
1704 while (!cpu.asregs.exception);
1705
1706 /* Hide away the things we've cached while executing. */
1707 cpu.asregs.pc = pc;
1708 cpu.asregs.insts += insts; /* instructions done ... */
1709 cpu.asregs.cycles += insts; /* and each takes a cycle */
1710 cpu.asregs.cycles += bonus_cycles; /* and extra cycles for branches */
1711 cpu.asregs.cycles += memops * memcycles; /* and memop cycle delays */
1712
1713 signal (SIGINT, sigsave);
1714}
1715
1716
1717int
1718sim_write (sd, addr, buffer, size)
1719 SIM_DESC sd;
1720 SIM_ADDR addr;
1721 unsigned char * buffer;
1722 int size;
1723{
1724 int i;
1725 init_pointers ();
1726
1727 memcpy (& cpu.mem[addr], buffer, size);
1728
1729 return size;
1730}
1731
1732int
1733sim_read (sd, addr, buffer, size)
1734 SIM_DESC sd;
1735 SIM_ADDR addr;
1736 unsigned char * buffer;
1737 int size;
1738{
1739 int i;
1740 init_pointers ();
1741
1742 memcpy (buffer, & cpu.mem[addr], size);
1743
1744 return size;
1745}
1746
1747
1748int
1749sim_store_register (sd, rn, memory, length)
1750 SIM_DESC sd;
1751 int rn;
1752 unsigned char * memory;
1753 int length;
1754{
1755 init_pointers ();
1756
1757 if (rn < NUM_MCORE_REGS && rn >= 0)
1758 {
1759 if (length == 4)
1760 {
2d514e6f 1761 long ival;
cd0fc7c3
SS
1762
1763 /* misalignment safe */
1764 ival = mcore_extract_unsigned_integer (memory, 4);
2d514e6f
SS
1765 cpu.asints[rn] = ival;
1766 }
1767
1768 return 4;
1769 }
1770 else
1771 return 0;
1772}
1773
1774int
1775sim_fetch_register (sd, rn, memory, length)
1776 SIM_DESC sd;
1777 int rn;
1778 unsigned char * memory;
1779 int length;
1780{
1781 init_pointers ();
1782
1783 if (rn < NUM_MCORE_REGS && rn >= 0)
1784 {
1785 if (length == 4)
1786 {
2d514e6f 1787 long ival = cpu.asints[rn];
cd0fc7c3
SS
1788
1789 /* misalignment-safe */
1790 mcore_store_unsigned_integer (memory, 4, ival);
2d514e6f
SS
1791 }
1792
1793 return 4;
1794 }
1795 else
1796 return 0;
1797}
1798
1799
1800int
1801sim_trace (sd)
1802 SIM_DESC sd;
1803{
1804 tracing = 1;
1805
1806 sim_resume (sd, 0, 0);
1807
1808 tracing = 0;
1809
1810 return 1;
1811}
1812
1813void
1814sim_stop_reason (sd, reason, sigrc)
1815 SIM_DESC sd;
1816 enum sim_stop * reason;
1817 int * sigrc;
1818{
1819 if (cpu.asregs.exception == SIGQUIT)
1820 {
1821 * reason = sim_exited;
1822 * sigrc = cpu.gr[PARM1];
1823 }
1824 else
1825 {
1826 * reason = sim_stopped;
1827 * sigrc = cpu.asregs.exception;
1828 }
1829}
1830
1831
1832int
1833sim_stop (sd)
1834 SIM_DESC sd;
1835{
1836 cpu.asregs.exception = SIGINT;
1837 return 1;
1838}
1839
1840
1841void
1842sim_info (sd, verbose)
1843 SIM_DESC sd;
1844 int verbose;
1845{
1846#ifdef WATCHFUNCTIONS
1847 int w, wcyc;
1848#endif
1849 double virttime = cpu.asregs.cycles / 36.0e6;
1850
cd0fc7c3
SS
1851 callback->printf_filtered (callback, "\n\n# instructions executed %10d\n",
1852 cpu.asregs.insts);
1853 callback->printf_filtered (callback, "# cycles %10d\n",
1854 cpu.asregs.cycles);
1855 callback->printf_filtered (callback, "# pipeline stalls %10d\n",
1856 cpu.asregs.stalls);
1857 callback->printf_filtered (callback, "# virtual time taken %10.4f\n",
1858 virttime);
2d514e6f
SS
1859
1860#ifdef WATCHFUNCTIONS
cd0fc7c3
SS
1861 callback->printf_filtered (callback, "\nNumber of watched functions: %d\n",
1862 ENDWL);
2d514e6f
SS
1863
1864 wcyc = 0;
1865
1866 for (w = 1; w <= ENDWL; w++)
1867 {
1868 callback->printf_filtered (callback, "WL = %s %8x\n",WLstr[w],WL[w]);
cd0fc7c3
SS
1869 callback->printf_filtered (callback, " calls = %d, cycles = %d\n",
1870 WLcnts[w],WLcyc[w]);
2d514e6f
SS
1871
1872 if (WLcnts[w] != 0)
cd0fc7c3
SS
1873 callback->printf_filtered (callback,
1874 " maxcpc = %d, mincpc = %d, avecpc = %d\n",
1875 WLmax[w],WLmin[w],WLcyc[w]/WLcnts[w]);
2d514e6f
SS
1876 wcyc += WLcyc[w];
1877 }
1878
cd0fc7c3
SS
1879 callback->printf_filtered (callback,
1880 "Total cycles for watched functions: %d\n",wcyc);
2d514e6f
SS
1881#endif
1882}
1883
1884struct aout
1885{
1886 unsigned char sa_machtype[2];
1887 unsigned char sa_magic[2];
1888 unsigned char sa_tsize[4];
1889 unsigned char sa_dsize[4];
1890 unsigned char sa_bsize[4];
1891 unsigned char sa_syms[4];
1892 unsigned char sa_entry[4];
1893 unsigned char sa_trelo[4];
1894 unsigned char sa_drelo[4];
1895} aout;
1896
1897#define LONG(x) (((x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
1898#define SHORT(x) (((x)[0]<<8)|(x)[1])
1899
1900SIM_DESC
1901sim_open (kind, cb, abfd, argv)
1902 SIM_OPEN_KIND kind;
1903 host_callback * cb;
6b4a8935 1904 struct bfd * abfd;
2d514e6f
SS
1905 char ** argv;
1906{
1907 int osize = sim_memory_size;
1908 myname = argv[0];
1909 callback = cb;
1910
1911 if (kind == SIM_OPEN_STANDALONE)
1912 issue_messages = 1;
1913
1914 /* Discard and reacquire memory -- start with a clean slate. */
1915 sim_size (1); /* small */
1916 sim_size (osize); /* and back again */
1917
1918 set_initial_gprs (); /* Reset the GPR registers. */
1919
1920 /* Fudge our descriptor for now. */
1921 return (SIM_DESC) 1;
1922}
1923
1924void
1925sim_close (sd, quitting)
1926 SIM_DESC sd;
1927 int quitting;
1928{
1929 /* nothing to do */
1930}
1931
1932SIM_RC
1933sim_load (sd, prog, abfd, from_tty)
1934 SIM_DESC sd;
1935 char * prog;
1936 bfd * abfd;
1937 int from_tty;
1938{
1939 /* Do the right thing for ELF executables; this turns out to be
1940 just about the right thing for any object format that:
1941 - we crack using BFD routines
1942 - follows the traditional UNIX text/data/bss layout
1943 - calls the bss section ".bss". */
1944
1945 extern bfd * sim_load_file (); /* ??? Don't know where this should live. */
1946 bfd * prog_bfd;
1947
1948 {
1949 bfd * handle;
1950 asection * s_bss;
1951 handle = bfd_openr (prog, 0); /* could be "mcore" */
1952
1953 if (!handle)
1954 {
1955 printf("``%s'' could not be opened.\n", prog);
1956 return SIM_RC_FAIL;
1957 }
1958
1959 /* Makes sure that we have an object file, also cleans gets the
1960 section headers in place. */
1961 if (!bfd_check_format (handle, bfd_object))
1962 {
1963 /* wasn't an object file */
1964 bfd_close (handle);
1965 printf ("``%s'' is not appropriate object file.\n", prog);
1966 return SIM_RC_FAIL;
1967 }
cd0fc7c3 1968
2d514e6f
SS
1969 /* Look for that bss section. */
1970 s_bss = bfd_get_section_by_name (handle, ".bss");
1971
1972 if (!s_bss)
1973 {
1974 printf("``%s'' has no bss section.\n", prog);
1975 return SIM_RC_FAIL;
1976 }
1977
1978 /* Appropriately paranoid would check that we have
1979 a traditional text/data/bss ordering within memory. */
1980
1981 /* figure the end of the bss section */
1982#if 0
1983 printf ("bss section at 0x%08x for 0x%08x bytes\n",
9e126dc0
AM
1984 (unsigned long) bfd_get_section_vma (handle, s_bss),
1985 (unsigned long) bfd_section_size (handle, s_bss));
2d514e6f 1986#endif
9e126dc0
AM
1987 heap_ptr = ((unsigned long) bfd_get_section_vma (handle, s_bss)
1988 + (unsigned long) bfd_section_size (handle, s_bss));
2d514e6f
SS
1989
1990 /* Clean up after ourselves. */
1991 bfd_close (handle);
1992
1993 /* XXX: do we need to free the s_bss and handle structures? */
1994 }
1995
1996 /* from sh -- dac */
1997 prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
1998 sim_kind == SIM_OPEN_DEBUG,
1999 0, sim_write);
2000 if (prog_bfd == NULL)
2001 return SIM_RC_FAIL;
2002
63a027a3 2003 target_big_endian = bfd_big_endian (prog_bfd);
cd0fc7c3 2004
2d514e6f
SS
2005 if (abfd == NULL)
2006 bfd_close (prog_bfd);
2007
2008 return SIM_RC_OK;
2009}
2010
2011SIM_RC
2012sim_create_inferior (sd, prog_bfd, argv, env)
2013 SIM_DESC sd;
6b4a8935 2014 struct bfd * prog_bfd;
2d514e6f
SS
2015 char ** argv;
2016 char ** env;
2017{
2018 char ** avp;
2019 int nargs = 0;
2020 int nenv = 0;
2021 int s_length;
2022 int l;
2023 unsigned long strings;
2024 unsigned long pointers;
2025 unsigned long hi_stack;
2026
2027
2028 /* Set the initial register set. */
2029 l = issue_messages;
2030 issue_messages = 0;
2031 set_initial_gprs ();
2032 issue_messages = l;
2033
2034 hi_stack = cpu.asregs.msize - 4;
2035 cpu.asregs.pc = bfd_get_start_address (prog_bfd);
2036
2037 /* Calculate the argument and environment strings. */
2038 s_length = 0;
2039 nargs = 0;
2040 avp = argv;
2041 while (avp && *avp)
2042 {
2043 l = strlen (*avp) + 1; /* include the null */
2044 s_length += (l + 3) & ~3; /* make it a 4 byte boundary */
2045 nargs++; avp++;
2046 }
2047
2048 nenv = 0;
2049 avp = env;
2050 while (avp && *avp)
2051 {
2052 l = strlen (*avp) + 1; /* include the null */
2053 s_length += (l + 3) & ~ 3;/* make it a 4 byte boundary */
2054 nenv++; avp++;
2055 }
2056
2057 /* Claim some memory for the pointers and strings. */
2058 pointers = hi_stack - sizeof(word) * (nenv+1+nargs+1);
2059 pointers &= ~3; /* must be 4-byte aligned */
2060 cpu.gr[0] = pointers;
2061
2062 strings = cpu.gr[0] - s_length;
2063 strings &= ~3; /* want to make it 4-byte aligned */
2064 cpu.gr[0] = strings;
2065 /* dac fix, the stack address must be 8-byte aligned! */
2066 cpu.gr[0] = cpu.gr[0] - cpu.gr[0] % 8;
2067
2068 /* Loop through the arguments and fill them in. */
2069 cpu.gr[PARM1] = nargs;
2070 if (nargs == 0)
2071 {
2072 /* No strings to fill in. */
2073 cpu.gr[PARM2] = 0;
2074 }
2075 else
2076 {
2077 cpu.gr[PARM2] = pointers;
2078 avp = argv;
2079 while (avp && *avp)
2080 {
2081 /* Save where we're putting it. */
2082 wlat (pointers, strings);
2083
2084 /* Copy the string. */
2085 l = strlen (* avp) + 1;
2086 strcpy ((char *)(cpu.mem + strings), *avp);
2087
2088 /* Bump the pointers. */
2089 avp++;
2090 pointers += 4;
2091 strings += l+1;
2092 }
2093
2094 /* A null to finish the list. */
2095 wlat (pointers, 0);
2096 pointers += 4;
2097 }
2098
2099 /* Now do the environment pointers. */
2100 if (nenv == 0)
2101 {
2102 /* No strings to fill in. */
2103 cpu.gr[PARM3] = 0;
2104 }
2105 else
2106 {
2107 cpu.gr[PARM3] = pointers;
2108 avp = env;
2109
2110 while (avp && *avp)
2111 {
2112 /* Save where we're putting it. */
2113 wlat (pointers, strings);
2114
2115 /* Copy the string. */
2116 l = strlen (* avp) + 1;
2117 strcpy ((char *)(cpu.mem + strings), *avp);
2118
2119 /* Bump the pointers. */
2120 avp++;
2121 pointers += 4;
2122 strings += l+1;
2123 }
2124
2125 /* A null to finish the list. */
2126 wlat (pointers, 0);
2127 pointers += 4;
2128 }
2129
2130 return SIM_RC_OK;
2131}
2132
2133void
2134sim_kill (sd)
2135 SIM_DESC sd;
2136{
2137 /* nothing to do */
2138}
2139
2140void
2141sim_do_command (sd, cmd)
2142 SIM_DESC sd;
2143 char * cmd;
2144{
2145 /* Nothing there yet; it's all an error. */
2146
2147 if (cmd != NULL)
2148 {
2149 char ** simargv = buildargv (cmd);
2150
2151 if (strcmp (simargv[0], "watch") == 0)
2152 {
2153 if ((simargv[1] == NULL) || (simargv[2] == NULL))
2154 {
2155 fprintf (stderr, "Error: missing argument to watch cmd.\n");
2156 return;
2157 }
2158
2159 ENDWL++;
2160
2161 WL[ENDWL] = strtol (simargv[2], NULL, 0);
2162 WLstr[ENDWL] = strdup (simargv[1]);
2163 fprintf (stderr, "Added %s (%x) to watchlist, #%d\n",WLstr[ENDWL],
2164 WL[ENDWL], ENDWL);
2165
2166 }
2167 else if (strcmp (simargv[0], "dumpmem") == 0)
2168 {
2169 unsigned char * p;
2170 FILE * dumpfile;
2171
2172 if (simargv[1] == NULL)
2173 fprintf (stderr, "Error: missing argument to dumpmem cmd.\n");
2174
2175 fprintf (stderr, "Writing dumpfile %s...",simargv[1]);
2176
2177 dumpfile = fopen (simargv[1], "w");
2178 p = cpu.mem;
2179 fwrite (p, cpu.asregs.msize-1, 1, dumpfile);
2180 fclose (dumpfile);
2181
2182 fprintf (stderr, "done.\n");
2183 }
2184 else if (strcmp (simargv[0], "clearstats") == 0)
2185 {
2186 cpu.asregs.cycles = 0;
2187 cpu.asregs.insts = 0;
2188 cpu.asregs.stalls = 0;
2189 ENDWL = 0;
2190 }
2191 else if (strcmp (simargv[0], "verbose") == 0)
2192 {
b83266a0 2193 issue_messages = 2;
2d514e6f
SS
2194 }
2195 else
2196 {
2197 fprintf (stderr,"Error: \"%s\" is not a valid M.CORE simulator command.\n",
2198 cmd);
2199 }
2200 }
2201 else
2202 {
2203 fprintf (stderr, "M.CORE sim commands: \n");
2204 fprintf (stderr, " watch <funcname> <addr>\n");
2205 fprintf (stderr, " dumpmem <filename>\n");
2206 fprintf (stderr, " clearstats\n");
2207 fprintf (stderr, " verbose\n");
2208 }
2209}
2210
2211void
2212sim_set_callbacks (ptr)
2213 host_callback * ptr;
2214{
2215 callback = ptr;
2216}