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