* gencode.c (movua.l): Compensate for endianness.
authorCorinna Vinschen <corinna@vinschen.de>
Wed, 8 Sep 2004 09:11:50 +0000 (09:11 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Wed, 8 Sep 2004 09:11:50 +0000 (09:11 +0000)
* interp.c (RAISE_EXCEPTION_IF_IN_DELAY_SLOT): New macro.
(in_delay_slot): New flag variable.
(Delay_Slot): Set in_delay_slot.
(sim_resume): Reset in_delay_slot after leaving code switch.
* gencode.c (op tab): Call RAISE_EXCEPTION_IF_IN_DELAY_SLOT for all
instructions not allowed in delay slots.

Commited by Corinna Vinschen <vinschen@redhat.com>
Introduce SH2a support.
* interp.c: Change type of jump table to short.  Add various macros.
(sim_load): Save the bfd machine code.
(sim_create_inferior): Ditto.
(union saved_state_type): Add tbr, ibnr and ibcr registers.
Move bfd_mach to end of struct.  Add regstack pointer.
(init_dsp): Don't swap contents of sh_dsp_table any more.  Instead
use it directly in its own switch statement.  Allocate space for 512
register banks.
(do_long_move_insn): New function.
(do_blog_insn): Ditto.
(trap): Use trap #13 and trap #14 to set ibnr and ibcr.
* gencode.c: Move movx/movy insns into separate switch statement.
(op tab): Add sh2a insns.  Reject instructions that are disabled
on that chip.
(gensim_caselist): Generate default case here instead of in caller.
(gensim): Generate two separate switch statements.  Call
gensim_caselist once for each (for movsxy_tab and for tab).
Add tokens for r15 and multiple regs.
(conflict_warn, warn_conflicts): Add for debugging.

sim/sh/ChangeLog
sim/sh/gencode.c
sim/sh/interp.c

index 10b4ae217101bf9189973d2b8f153f5cafccf62f..381e1de4ec8005e2bdd65c9ced5e4811c4b94868 100644 (file)
@@ -1,3 +1,41 @@
+2004-09-08  DJ Delorie  <dj@redhat.com>
+
+       Commited by Corinna Vinschen <vinschen@redhat.com>
+       * gencode.c (movua.l): Compensate for endianness.
+
+2004-09-08  Corinna Vinschen  <vinschen@redhat.com>
+
+       * interp.c (RAISE_EXCEPTION_IF_IN_DELAY_SLOT): New macro.
+       (in_delay_slot): New flag variable.
+       (Delay_Slot): Set in_delay_slot.
+       (sim_resume): Reset in_delay_slot after leaving code switch.
+       * gencode.c (op tab): Call RAISE_EXCEPTION_IF_IN_DELAY_SLOT for all
+       instructions not allowed in delay slots.
+
+2004-09-08  Michael Snyder  <msnyder@redhat.com>
+
+       Commited by Corinna Vinschen <vinschen@redhat.com>
+       Introduce SH2a support.
+       * interp.c: Change type of jump table to short.  Add various macros.
+       (sim_load): Save the bfd machine code.
+       (sim_create_inferior): Ditto.
+       (union saved_state_type): Add tbr, ibnr and ibcr registers.
+       Move bfd_mach to end of struct.  Add regstack pointer.
+       (init_dsp): Don't swap contents of sh_dsp_table any more.  Instead
+       use it directly in its own switch statement.  Allocate space for 512
+       register banks.
+       (do_long_move_insn): New function.
+       (do_blog_insn): Ditto.
+       (trap): Use trap #13 and trap #14 to set ibnr and ibcr.
+       * gencode.c: Move movx/movy insns into separate switch statement.
+       (op tab): Add sh2a insns.  Reject instructions that are disabled
+       on that chip.
+       (gensim_caselist): Generate default case here instead of in caller.
+       (gensim): Generate two separate switch statements.  Call
+       gensim_caselist once for each (for movsxy_tab and for tab).
+       Add tokens for r15 and multiple regs.
+       (conflict_warn, warn_conflicts): Add for debugging.
+
 2004-08-18  J"orn Rennecke <joern.rennecke@superh.com>
 
        * gencode.c (tab): For shad snd shld, fix result for
index 155138a2daf7e9649c4ae0a3ba04f1050149178a..f03ba4e341e65d95ec26649426f51f0fa91bed89 100644 (file)
@@ -84,6 +84,7 @@ op tab[] =
   },
 
   { "", "", "bf <bdisp8>", "10001011i8p1....",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "if (!T) {",
     "  SET_NIP (PC + 4 + (SEXT (i) * 2));",
     "  cycles += 2;",
@@ -91,6 +92,7 @@ op tab[] =
   },
 
   { "", "", "bf.s <bdisp8>", "10001111i8p1....",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "if (!T) {",
     "  SET_NIP (PC + 4 + (SEXT (i) * 2));",
     "  cycles += 2;",
@@ -98,19 +100,35 @@ op tab[] =
     "}",
   },
 
+  { "", "n", "bit32 #imm3,@(disp12,<REG_N>)", "0011nnnni8*11001",
+    "/* 32-bit logical bit-manipulation instructions.  */",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "int word2 = RIAT (nip);",
+    "i >>= 4;  /* BOGUS: Using only three bits of 'i'.  */",
+    "/* MSB of 'i' must be zero.  */",
+    "if (i > 7)",
+    "  RAISE_EXCEPTION (SIGILL);",
+    "MA (1);",
+    "do_blog_insn (1 << i, (word2 & 0xfff) + R[n], ",
+    "              (word2 >> 12) & 0xf, memory, maskb);",
+    "SET_NIP (nip + 2);        /* Consume 2 more bytes.  */",
+  },
   { "", "", "bra <bdisp12>", "1010i12.........",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "SET_NIP (PC + 4 + (SEXT12 (i) * 2));",
     "cycles += 2;",
     "Delay_Slot (PC + 2);",
   },
 
   { "", "n", "braf <REG_N>", "0000nnnn00100011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "SET_NIP (PC + 4 + R[n]);",
     "cycles += 2;",
     "Delay_Slot (PC + 2);",
   },
 
   { "", "", "bsr <bdisp12>", "1011i12.........",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "PR = PH2T (PC + 4);",
     "SET_NIP (PC + 4 + (SEXT12 (i) * 2));",
     "cycles += 2;",
@@ -118,6 +136,7 @@ op tab[] =
   },
 
   { "", "n", "bsrf <REG_N>", "0000nnnn00000011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "PR = PH2T (PC) + 4;",
     "SET_NIP (PC + 4 + R[n]);",
     "cycles += 2;",
@@ -125,13 +144,187 @@ op tab[] =
   },
 
   { "", "", "bt <bdisp8>", "10001001i8p1....",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "if (T) {",
     "  SET_NIP (PC + 4 + (SEXT (i) * 2));",
     "  cycles += 2;",
     "}",
   },
+  
+  { "", "m", "bld/st #<imm>, <REG_M>", "10000111mmmmi4*1",
+    "/* MSB of 'i' is true for load, false for store.  */",
+    "if (i <= 7)",
+    "  if (T)",
+    "    R[m] |= (1 << i);",
+    "  else",
+    "    R[m] &= ~(1 << i);",
+    "else",
+    "  SET_SR_T ((R[m] & (1 << (i - 8))) != 0);",
+  },
+  { "m", "m", "bset/clr #<imm>, <REG_M>", "10000110mmmmi4*1",
+    "/* MSB of 'i' is true for set, false for clear.  */",
+    "if (i <= 7)",
+    "  R[m] &= ~(1 << i);",
+    "else",
+    "  R[m] |= (1 << (i - 8));",
+  },
+  { "n", "n", "clips.b <REG_N>", "0100nnnn10010001",
+    "if (R[n] < -128 || R[n] > 127) {",
+    "  L (n);",
+    "  SET_SR_CS (1);",
+    "  if (R[n] > 127)",
+    "    R[n] = 127;",
+    "  else if (R[n] < -128)",
+    "    R[n] = -128;",
+    "}",
+  },
+  { "n", "n", "clips.w <REG_N>", "0100nnnn10010101",
+    "if (R[n] < -32768 || R[n] > 32767) {",
+    "  L (n);",
+    "  SET_SR_CS (1);",
+    "  if (R[n] > 32767)",
+    "    R[n] = 32767;",
+    "  else if (R[n] < -32768)",
+    "    R[n] = -32768;",
+    "}",
+  },
+  { "n", "n", "clipu.b <REG_N>", "0100nnnn10000001",
+    "if (R[n] < -256 || R[n] > 255) {",
+    "  L (n);",
+    "  SET_SR_CS (1);",
+    "  R[n] = 255;",
+    "}",
+  },
+  { "n", "n", "clipu.w <REG_N>", "0100nnnn10000101",
+    "if (R[n] < -65536 || R[n] > 65535) {",
+    "  L (n);",
+    "  SET_SR_CS (1);",
+    "  R[n] = 65535;",
+    "}",
+  },
+  { "n", "0n", "divs R0,<REG_N>", "0100nnnn10010100",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "if (R0 == 0)",
+    "  R[n] = 0x7fffffff;",
+    "else if (R0 == -1 && R[n] == 0x80000000)",
+    "  R[n] = 0x7fffffff;",
+    "else R[n] /= R0;",
+    "L (n);",
+  },
+  { "n", "0n", "divu R0,<REG_N>", "0100nnnn10000100",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "if (R0 == 0)",
+    "  R[n] = 0xffffffff;",
+    "else (unsigned int) R[n] = (unsigned int) R[n] / (unsigned int) R0;",
+    "L (n);",
+  },
+  { "n", "0n", "mulr R0,<REG_N>", "0100nnnn10000000",
+    "R[n] = (R[n] * R0) & 0xffffffff;",
+    "L (n);",
+  },
+  { "0", "n", "ldbank @<REG_N>,R0", "0100nnnn11100101",
+    "int regn = (R[n] >> 2) & 0x1f;",
+    "int bankn = (R[n] >> 7) & 0x1ff;",
+    "if (regn > 19)",
+    "  regn = 19;      /* FIXME what should happen? */",
+    "R0 = saved_state.asregs.regstack[bankn].regs[regn];",
+    "L (0);",
+  },
+  { "", "0n", "stbank R0,@<REG_N>", "0100nnnn11100001",
+    "int regn = (R[n] >> 2) & 0x1f;",
+    "int bankn = (R[n] >> 7) & 0x1ff;",
+    "if (regn > 19)",
+    "  regn = 19;      /* FIXME what should happen? */",
+    "saved_state.asregs.regstack[bankn].regs[regn] = R0;",
+  },
+  { "", "", "resbank", "0000000001011011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    /* FIXME: cdef all */
+    "int i;",
+    "if (BO) { /* Bank Overflow */",
+    /* FIXME: how do we know when to reset BO?  */
+    "  for (i = 0; i <= 14; i++) {",
+    "    R[i] = RLAT (R[15]);",
+    "    MA (1);",
+    "    R[15] += 4;",
+    "  }",
+    "  PR = RLAT (R[15]);",
+    "  R[15] += 4;",
+    "  MA (1);",
+    "  GBR = RLAT (R[15]);",
+    "  R[15] += 4;",
+    "  MA (1);",
+    "  MACH = RLAT (R[15]);",
+    "  R[15] += 4;",
+    "  MA (1);",
+    "  MACL = RLAT (R[15]);",
+    "  R[15] += 4;",
+    "  MA (1);",
+    "}",
+    "else if (BANKN == 0)      /* Bank Underflow */",
+    "  RAISE_EXCEPTION (SIGILL);",     /* FIXME: what exception? */
+    "else {",
+    "  SET_BANKN (BANKN - 1);",
+    "  for (i = 0; i <= 14; i++)",
+    "    R[i] = saved_state.asregs.regstack[BANKN].regs[i];",
+    "  MACH = saved_state.asregs.regstack[BANKN].regs[15];",
+    "  PR   = saved_state.asregs.regstack[BANKN].regs[17];",
+    "  GBR  = saved_state.asregs.regstack[BANKN].regs[18];",
+    "  MACL = saved_state.asregs.regstack[BANKN].regs[19];",
+    "}",
+  },
+  { "f", "f-", "movml.l <REG_N>,@-R15", "0100nnnn11110001",
+    "/* Push Rn...R0 (if n==15, push pr and R14...R0).  */",
+    "do {",
+    "  MA (1);",
+    "  R[15] -= 4;",
+    "  if (n == 15)",
+    "    WLAT (R[15], PR);",
+    "  else",
+    "    WLAT (R[15], R[n]);",
+    "} while (n-- > 0);",    
+  },
+  { "f", "f+", "movml.l @R15+,<REG_N>", "0100nnnn11110101",
+    "/* Pop R0...Rn (if n==15, pop R0...R14 and pr).  */",
+    "int i = 0;\n",
+    "do {",
+    "  MA (1);",
+    "  if (i == 15)",
+    "    PR = RLAT (R[15]);",
+    "  else",
+    "    R[i] = RLAT (R[15]);",
+    "  R[15] += 4;",
+    "} while (i++ < n);",    
+  },
+  { "f", "f-", "movmu.l <REG_N>,@-R15", "0100nnnn11110000",
+    "/* Push pr, R14...Rn (if n==15, push pr).  */",   /* FIXME */
+    "int i = 15;\n",
+    "do {",
+    "  MA (1);",
+    "  R[15] -= 4;",
+    "  if (i == 15)",
+    "    WLAT (R[15], PR);",
+    "  else",
+    "    WLAT (R[15], R[i]);",
+    "} while (i-- > n);",    
+  },
+  { "f", "f+", "movmu.l @R15+,<REG_N>", "0100nnnn11110100",
+    "/* Pop Rn...R14, pr (if n==15, pop pr).  */",     /* FIXME */
+    "do {",
+    "  MA (1);",
+    "  if (n == 15)",
+    "    PR = RLAT (R[15]);",
+    "  else",
+    "    R[n] = RLAT (R[15]);",
+    "  R[15] += 4;",
+    "} while (n++ < 15);",    
+  },
+  { "", "", "nott", "0000000001101000",
+    "SET_SR_T (T == 0);",      
+  },
 
   { "", "", "bt.s <bdisp8>", "10001101i8p1....",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "if (T) {",
     "  SET_NIP (PC + 4 + (SEXT (i) * 2));",
     "  cycles += 2;",
@@ -297,6 +490,8 @@ op tab[] =
     "else",
     "{",
     "  double fsum = 0;",
+    "  if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)",
+    "    RAISE_EXCEPTION (SIGILL);",
     "  /* FIXME: check for nans and infinities.  */",
     "  fsum += FR (v1+0) * FR (v2+0);",
     "  fsum += FR (v1+1) * FR (v2+1);",
@@ -386,6 +581,18 @@ op tab[] =
     "  SET_FI (n, RLAT (R[m]));",
     "}",
   },
+  /* sh2a */
+  { "", "n", "fmov.s @(disp12,<REG_N>), <FREG_M>", "0011nnnnmmmm0001",
+    "/* and fmov.s <FREG_N>, @(disp12,<FREG_M>)",
+    "   and mov.bwl <REG_N>, @(disp12,<REG_M>)",
+    "   and mov.bwl @(disp12,<REG_N>),<REG_M>",
+    "   and movu.bw @(disp12,<REG_N>),<REG_M>.  */",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "int word2 = RIAT (nip);",
+    "SET_NIP (nip + 2);        /* Consume 2 more bytes.  */",
+    "MA (1);",
+    "do_long_move_insn (word2 & 0xf000, word2 & 0x0fff, m, n, &thislock);",
+  },
   /* sh2e */
   { "m", "m", "fmov.s @<REG_M>+,<FREG_N>", "1111nnnnmmmm1001",
     /* sh4 */
@@ -465,6 +672,8 @@ op tab[] =
   { "", "", "frchg", "1111101111111101",
     "if (FPSCR_PR)",
     "  RAISE_EXCEPTION (SIGILL);",
+    "else if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)",
+    "  RAISE_EXCEPTION (SIGILL);",
     "else",
     "  SET_FPSCR (GET_FPSCR () ^ FPSCR_MASK_FR);",
   },
@@ -473,6 +682,8 @@ op tab[] =
   { "", "", "fsca", "1111eeee11111101",
     "if (FPSCR_PR)",
     "  RAISE_EXCEPTION (SIGILL);",
+    "else if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)",
+    "  RAISE_EXCEPTION (SIGILL);",
     "else",
     "  {",
     "    SET_FR (n, fsca_s (FPUL, &sin));",
@@ -494,6 +705,8 @@ op tab[] =
   { "", "", "fsrra <FREG_N>", "1111nnnn01111101",
     "if (FPSCR_PR)",
     "  RAISE_EXCEPTION (SIGILL);",
+    "else if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)",
+    "  RAISE_EXCEPTION (SIGILL);",
     "else",
     "  SET_FR (n, fsrra_s (FR (n)));",
   },
@@ -525,6 +738,8 @@ op tab[] =
     "  RAISE_EXCEPTION (SIGILL);",
     "else",
     "{", 
+    "  if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)",
+    "    RAISE_EXCEPTION (SIGILL);",
     "  /* FIXME not implemented.  */",
     "  printf (\"ftrv xmtrx, FV%d\\n\", v1);",
     "}", 
@@ -542,12 +757,14 @@ op tab[] =
   },
 
   { "", "n", "jmp @<REG_N>", "0100nnnn00101011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "SET_NIP (PT2H (R[n]));",
     "cycles += 2;",
     "Delay_Slot (PC + 2);",
   },
 
   { "", "n", "jsr @<REG_N>", "0100nnnn00001011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "PR = PH2T (PC + 4);",
     "if (~doprofile)",
     "  gotcall (PR, R[n]);",
@@ -555,6 +772,20 @@ op tab[] =
     "cycles += 2;",
     "Delay_Slot (PC + 2);",
   },
+  { "", "n", "jsr/n @<REG_N>", "0100nnnn01001011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "PR = PH2T (PC + 2);",
+    "if (~doprofile)",
+    "  gotcall (PR, R[n]);",
+    "SET_NIP (PT2H (R[n]));",
+  },
+  { "", "", "jsr/n @@(<disp>,TBR)", "10000011i8p4....",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "PR = PH2T (PC + 2);",
+    "if (~doprofile)",
+    "  gotcall (PR, i + TBR);",
+    "SET_NIP (PT2H (i + TBR));",
+  },
 
   { "", "n", "ldc <REG_N>,<CREG_M>", "0100nnnnmmmm1110",
     "CREG (m) = R[n];",
@@ -579,6 +810,12 @@ op tab[] =
     "else",
     "  RAISE_EXCEPTION (SIGILL); /* user mode */",
   },
+  { "", "n", "ldc <REG_N>,TBR", "0100nnnn01001010",
+    "if (SR_MD)",      /* FIXME? */
+    "  TBR = R[n]; /* priv mode */",
+    "else",
+    "  RAISE_EXCEPTION (SIGILL); /* user mode */",
+  },
   { "n", "n", "ldc.l @<REG_N>+,<CREG_M>", "0100nnnnmmmm0111",
     "MA (1);",
     "CREG (m) = RLAT (R[n]);",
@@ -673,6 +910,16 @@ op tab[] =
   { "n", "", "mov #<imm>,<REG_N>", "1110nnnni8*1....",
     "R[n] = SEXT (i);",
   },
+  { "n", "", "movi20 #<imm20>,<REG_N>", "0000nnnni8*10000",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "R[n] = ((i << 24) >> 12) | RIAT (nip);",
+    "SET_NIP (nip + 2);        /* Consume 2 more bytes.  */",
+  },
+  { "n", "", "movi20s #<imm20>,<REG_N>", "0000nnnni8*10001",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "R[n] = ((((i & 0xf0) << 24) >> 12) | RIAT (nip)) << 8;",
+    "SET_NIP (nip + 2);        /* Consume 2 more bytes.  */",
+  },
   { "n", "m", "mov <REG_M>,<REG_N>", "0110nnnnmmmm0011",
     "R[n] = R[m];",
   },
@@ -698,6 +945,12 @@ op tab[] =
     "R[m] += 1;",
     "L (n);",
   },
+  { "0n", "n", "mov.b @-<REG_N>,R0", "0100nnnn11001011",
+    "MA (1);",
+    "R[n] -= 1;",
+    "R0 = RSBAT (R[n]);",
+    "L (0);",
+  },
   { "", "mn", "mov.b <REG_M>,@<REG_N>", "0010nnnnmmmm0000",
     "MA (1);",
     "WBAT (R[n], R[m]);",
@@ -719,6 +972,11 @@ op tab[] =
     "R[n] -= 1;",
     "WBAT (R[n], R[m]);",
   },
+  { "n", "n0", "mov.b R0,@<REG_N>+", "0100nnnn10001011",
+    "MA (1);",
+    "WBAT (R[n], R0);",
+    "R[n] += 1;",
+  },
   { "n", "m", "mov.b @<REG_M>,<REG_N>", "0110nnnnmmmm0000",
     "MA (1);",
     "R[n] = RSBAT (R[m]);",
@@ -751,6 +1009,12 @@ op tab[] =
     "R[m] += 4;",
     "L (n);",
   },
+  { "0n", "n", "mov.l @-<REG_N>,R0", "0100nnnn11101011",
+    "MA (1);",
+    "R[n] -= 4;",
+    "R0 = RLAT (R[n]);",
+    "L (0);",
+  },
   { "n", "m", "mov.l @<REG_M>,<REG_N>", "0110nnnnmmmm0010",
     "MA (1);",
     "R[n] = RLAT (R[m]);",
@@ -773,6 +1037,11 @@ op tab[] =
     "R[n] -= 4;",
     "WLAT (R[n], R[m]);",
   },
+  { "n", "n0", "mov.l R0,@<REG_N>+", "0100nnnn10101011",
+    "MA (1) ;",
+    "WLAT (R[n], R0);",
+    "R[n] += 4;",
+  },
   { "", "nm", "mov.l <REG_M>,@<REG_N>", "0010nnnnmmmm0010",
     "MA (1);",
     "WLAT (R[n], R[m]);",
@@ -804,6 +1073,12 @@ op tab[] =
     "R[m] += 2;",
     "L (n);",
   },
+  { "0n", "n", "mov.w @-<REG_N>,R0", "0100nnnn11011011",
+    "MA (1);",
+    "R[n] -= 2;",
+    "R0 = RSWAT (R[n]);",
+    "L (0);",
+  },
   { "n", "m", "mov.w @<REG_M>,<REG_N>", "0110nnnnmmmm0001",
     "MA (1);",
     "R[n] = RSWAT (R[m]);",
@@ -826,6 +1101,11 @@ op tab[] =
     "R[n] -= 2;",
     "WWAT (R[n], R[m]);",
   },
+  { "n", "0n", "mov.w R0,@<REG_N>+", "0100nnnn10011011",
+    "MA (1);",
+    "WWAT (R[n], R0);",
+    "R[n] += 2;",
+  },
   { "", "nm", "mov.w <REG_M>,@<REG_N>", "0010nnnnmmmm0001",
     "MA (1);",
     "WWAT (R[n], R[m]);",
@@ -863,19 +1143,23 @@ op tab[] =
   { "n", "", "movt <REG_N>", "0000nnnn00101001",
     "R[n] = T;",
   },
-
+  { "", "", "movrt <REG_N>", "0000nnnn00111001",
+    "R[n] = (T == 0);",        
+  },
   { "0", "n", "movua.l @<REG_N>,R0", "0100nnnn10101001",
     "int regn = R[n];",
+    "int e = target_little_endian ? 3 : 0;",
     "MA (1);",
-    "R[0] = (RBAT (regn) << 24) + (RBAT (regn + 1) << 16) + ",
-    "  (RBAT (regn + 2) << 8) + RBAT (regn + 3);",
+    "R[0] = (RBAT (regn + (0^e)) << 24) + (RBAT (regn + (1^e)) << 16) + ",
+    "  (RBAT (regn + (2^e)) << 8) + RBAT (regn + (3^e));",
     "L (0);",
   },
   { "0n", "n", "movua.l @<REG_N>+,R0", "0100nnnn11101001",
     "int regn = R[n];",
+    "int e = target_little_endian ? 3 : 0;",
     "MA (1);",
-    "R[0] = (RBAT (regn) << 24) + (RBAT (regn + 1) << 16) + ",
-    "  (RBAT (regn + 2) << 8) + RBAT (regn + 3);",
+    "R[0] = (RBAT (regn + (0^e)) << 24) + (RBAT (regn + (1^e)) << 16) + ",
+    "  (RBAT (regn + (2^e)) << 8) + RBAT (regn + (3^e));",
     "R[n] += 4;",
     "L (0);",
   },
@@ -1002,6 +1286,7 @@ op tab[] =
     "R[15] += 4;",
     "Delay_Slot (PC + 2);",
 #else
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "SET_SR (SSR);",
     "SET_NIP (PT2H (SPC));",
     "cycles += 2;",
@@ -1010,10 +1295,21 @@ op tab[] =
   },
 
   { "", "", "rts", "0000000000001011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "SET_NIP (PT2H (PR));",
     "cycles += 2;",
     "Delay_Slot (PC + 2);",
   },
+  { "", "", "rts/n", "0000000001101011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "SET_NIP (PT2H (PR));",
+  },
+  { "0", "n", "rtv/n <REG_N>", "0000nnnn01111011",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
+    "R0 = R[n];",
+    "L (0);",
+    "SET_NIP (PT2H (PR));",
+  },
 
   /* sh4a */
   { "", "", "setdmx", "0000000010011000",
@@ -1121,6 +1417,12 @@ op tab[] =
     "else",
     "  RAISE_EXCEPTION (SIGILL); /* user mode */",
   },
+  { "n", "", "stc TBR,<REG_N>", "0000nnnn01001010",
+    "if (SR_MD)",      /* FIXME? */
+    "  R[n] = TBR; /* priv mode */",
+    "else",
+    "  RAISE_EXCEPTION (SIGILL); /* user mode */",
+  },
   { "n", "n", "stc.l <CREG_M>,@-<REG_N>", "0100nnnnmmmm0011",
     "MA (1);",
     "R[n] -= 4;",
@@ -1191,6 +1493,7 @@ op tab[] =
   },
 
   { "0", "", "trapa #<imm>", "11000011i8*1....", 
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "long imm = 0xff & i;",
     "if (i < 20 || i == 33 || i == 34 || i == 0xc3)",
     "  nip += trap (i, &R0, PC, memory, maskl, maskw, endianw);",
@@ -1515,8 +1818,9 @@ op movsxy_tab[] =
     "/* nop */",
   },
   { "", "", "ppi", "1111100000000000",
+    "RAISE_EXCEPTION_IF_IN_DELAY_SLOT ();",
     "ppi_insn (RIAT (nip));",
-    "nip += 2;",
+    "SET_NIP (nip + 2);",
     "iword &= 0xf7ff; goto top;",
   },
 #endif
@@ -2267,6 +2571,58 @@ gengastab ()
 
 static unsigned short table[1 << 16];
 
+static int warn_conflicts = 0;
+
+static void
+conflict_warn (val, i)
+     int val;
+     int i;
+{
+  int ix, key;
+  int j = table[val];
+
+  fprintf (stderr, "Warning: opcode table conflict: 0x%04x (idx %d && %d)\n",
+          val, i, table[val]);
+
+  for (ix = sizeof (tab) / sizeof (tab[0]); ix >= 0; ix--)
+    if (tab[ix].index == i || tab[ix].index == j)
+      {
+       key = ((tab[ix].code[0] - '0') << 3) + 
+         ((tab[ix].code[1] - '0') << 2) + 
+         ((tab[ix].code[2] - '0') << 1) + 
+         ((tab[ix].code[3] - '0'));
+
+       if (val >> 12 == key)
+         fprintf (stderr, "  %s -- %s\n", tab[ix].code, tab[ix].name);
+      }
+
+  for (ix = sizeof (movsxy_tab) / sizeof (movsxy_tab[0]); ix >= 0; ix--)
+    if (movsxy_tab[ix].index == i || movsxy_tab[ix].index == j)
+      {
+       key = ((movsxy_tab[ix].code[0] - '0') << 3) + 
+         ((movsxy_tab[ix].code[1] - '0') << 2) + 
+         ((movsxy_tab[ix].code[2] - '0') << 1) + 
+         ((movsxy_tab[ix].code[3] - '0'));
+
+       if (val >> 12 == key)
+         fprintf (stderr, "  %s -- %s\n", 
+                  movsxy_tab[ix].code, movsxy_tab[ix].name);
+      }
+
+  for (ix = sizeof (ppi_tab) / sizeof (ppi_tab[0]); ix >= 0; ix--)
+    if (ppi_tab[ix].index == i || ppi_tab[ix].index == j)
+      {
+       key = ((ppi_tab[ix].code[0] - '0') << 3) + 
+         ((ppi_tab[ix].code[1] - '0') << 2) + 
+         ((ppi_tab[ix].code[2] - '0') << 1) + 
+         ((ppi_tab[ix].code[3] - '0'));
+
+       if (val >> 12 == key)
+         fprintf (stderr, "  %s -- %s\n", 
+                  ppi_tab[ix].code, ppi_tab[ix].name);
+      }
+}
+
 /* Take an opcode, expand all varying fields in it out and fill all the
    right entries in 'table' with the opcode index.  */
 
@@ -2278,6 +2634,8 @@ expand_opcode (val, i, s)
 {
   if (*s == 0)
     {
+      if (warn_conflicts && table[val] != 0)
+       conflict_warn (val, i);
       table[val] = i;
     }
   else
@@ -2599,6 +2957,12 @@ gensim_caselist (p)
 
              switch (s[1])
                {
+               default:
+                 fprintf (stderr, 
+                          "gensim_caselist: Unknown char '%c' in %s\n",
+                          s[1], s);
+                 exit (1);
+                 break;
                case '4':
                  printf ("f");
                  break;
@@ -2607,7 +2971,6 @@ gensim_caselist (p)
                  break;
                case '1':
                  sextbit = 12;
-
                  printf ("fff");
                  break;
                }
@@ -2615,6 +2978,14 @@ gensim_caselist (p)
 
              switch (s[3])
                {
+               default:
+                 fprintf (stderr, 
+                          "gensim_caselist: Unknown char '%c' in %s\n",
+                          s[3], s);
+                 exit (1);
+                 break;
+               case '.':       /* eg. "i12." */
+                 break;
                case '1':
                  break;
                case '2':
@@ -2646,6 +3017,25 @@ gensim_caselist (p)
        char *r;
        for (r = p->refs; *r; r++)
          {
+           if (*r == 'f') printf ("      CREF (15);\n");
+           if (*r == '-') 
+             {
+               printf ("      {\n");
+               printf ("        int i = n;\n");
+               printf ("        do {\n");
+               printf ("          CREF (i);\n");
+               printf ("        } while (i-- > 0);\n");
+               printf ("      }\n");
+             }
+           if (*r == '+') 
+             {
+               printf ("      {\n");
+               printf ("        int i = n;\n");
+               printf ("        do {\n");
+               printf ("          CREF (i);\n");
+               printf ("        } while (i++ < 14);\n");
+               printf ("      }\n");
+             }
            if (*r == '0') printf ("      CREF (0);\n"); 
            if (*r == '8') printf ("      CREF (8);\n"); 
            if (*r == '9') printf ("      CREF (9);\n"); 
@@ -2669,9 +3059,28 @@ gensim_caselist (p)
        char *r;
        for (r = p->defs; *r; r++) 
          {
-           if (*r == '0') printf("      CDEF (0);\n"); 
-           if (*r == 'n') printf("      CDEF (n);\n"); 
-           if (*r == 'm') printf("      CDEF (m);\n"); 
+           if (*r == 'f') printf ("      CDEF (15);\n");
+           if (*r == '-') 
+             {
+               printf ("      {\n");
+               printf ("        int i = n;\n");
+               printf ("        do {\n");
+               printf ("          CDEF (i);\n");
+               printf ("        } while (i-- > 0);\n");
+               printf ("      }\n");
+             }
+           if (*r == '+') 
+             {
+               printf ("      {\n");
+               printf ("        int i = n;\n");
+               printf ("        do {\n");
+               printf ("          CDEF (i);\n");
+               printf ("        } while (i++ < 14);\n");
+               printf ("      }\n");
+             }
+           if (*r == '0') printf ("      CDEF (0);\n"); 
+           if (*r == 'n') printf ("      CDEF (n);\n"); 
+           if (*r == 'm') printf ("      CDEF (m);\n"); 
          }
       }
 
@@ -2757,6 +3166,9 @@ expand_ppi_code (val, i, s)
       break;
     case 'g':
     case 'z':
+      if (warn_conflicts && table[val] != 0)
+       conflict_warn (val, i);
+
       /* The last four bits are disregarded for the switch table.  */
       table[val] = i;
       return;
@@ -2992,6 +3404,10 @@ main (ac, av)
   /* Now generate the requested data.  */
   if (ac > 1)
     {
+      if (ac > 2 && strcmp (av[2], "-w") == 0)
+       {
+         warn_conflicts = 1;
+       }
       if (strcmp (av[1], "-t") == 0)
        {
          gengastab ();
index b7c77799447291a092e442d7f5a42d1ff6e3e364..5d4a4f558aeb12458817d5403aa853311ade41df 100644 (file)
@@ -65,6 +65,11 @@ int sim_write (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size);
    for a quit. */
 #define POLL_QUIT_INTERVAL 0x60000
 
+typedef struct
+{
+  int regs[20];
+} regstacktype;
+
 typedef union
 {
 
@@ -123,6 +128,9 @@ typedef union
            int dbr;            /* debug base register */
            int sgr;            /* saved gr15 */
            int ldst;           /* load/store flag (boolean) */
+           int tbr;
+           int ibcr;           /* sh2a bank control register */
+           int ibnr;           /* sh2a bank number register */
          } named;
        int i[16];
       } cregs;
@@ -152,6 +160,8 @@ typedef union
     unsigned char *ymem;
     unsigned char *xmem_offset;
     unsigned char *ymem_offset;
+    unsigned long bfd_mach;
+    regstacktype *regstack;
   }
   asregs;
   int asints[40];
@@ -175,6 +185,7 @@ static int maskl = 0;
 
 static SIM_OPEN_KIND sim_kind;
 static char *myname;
+static int   tracing = 0;
 
 
 /* Short hand definitions of the registers */
@@ -191,6 +202,11 @@ static char *myname;
 #define GBR    saved_state.asregs.cregs.named.gbr
 #define VBR    saved_state.asregs.cregs.named.vbr
 #define DBR    saved_state.asregs.cregs.named.dbr
+#define TBR    saved_state.asregs.cregs.named.tbr
+#define IBCR   saved_state.asregs.cregs.named.ibcr
+#define IBNR   saved_state.asregs.cregs.named.ibnr
+#define BANKN  (saved_state.asregs.cregs.named.ibnr & 0x1ff)
+#define ME     ((saved_state.asregs.cregs.named.ibnr >> 14) & 0x3)
 #define SSR    saved_state.asregs.cregs.named.ssr
 #define SPC    saved_state.asregs.cregs.named.spc
 #define SGR    saved_state.asregs.cregs.named.sgr
@@ -213,6 +229,8 @@ static char *myname;
 
 /* Manipulate SR */
 
+#define SR_MASK_BO  (1 << 14)
+#define SR_MASK_CS  (1 << 13)
 #define SR_MASK_DMY (1 << 11)
 #define SR_MASK_DMX (1 << 10)
 #define SR_MASK_M (1 << 9)
@@ -227,6 +245,8 @@ static char *myname;
 #define SR_MASK_RC 0x0fff0000
 #define SR_RC_INCREMENT -0x00010000
 
+#define BO     ((saved_state.asregs.cregs.named.sr & SR_MASK_BO) != 0)
+#define CS     ((saved_state.asregs.cregs.named.sr & SR_MASK_CS) != 0)
 #define M      ((saved_state.asregs.cregs.named.sr & SR_MASK_M) != 0)
 #define Q      ((saved_state.asregs.cregs.named.sr & SR_MASK_Q) != 0)
 #define S      ((saved_state.asregs.cregs.named.sr & SR_MASK_S) != 0)
@@ -249,6 +269,16 @@ do { \
     saved_state.asregs.cregs.named.sr &= ~(BIT); \
 } while (0)
 
+#define SET_SR_BO(EXP) SET_SR_BIT ((EXP), SR_MASK_BO)
+#define SET_SR_CS(EXP) SET_SR_BIT ((EXP), SR_MASK_CS)
+#define SET_BANKN(EXP) \
+do { \
+  IBNR = (IBNR & 0xfe00) | (EXP & 0x1f); \
+} while (0)
+#define SET_ME(EXP) \
+do { \
+  IBNR = (IBNR & 0x3fff) | ((EXP & 0x3) << 14); \
+} while (0)
 #define SET_SR_M(EXP) SET_SR_BIT ((EXP), SR_MASK_M)
 #define SET_SR_Q(EXP) SET_SR_BIT ((EXP), SR_MASK_Q)
 #define SET_SR_S(EXP) SET_SR_BIT ((EXP), SR_MASK_S)
@@ -323,6 +353,9 @@ fail ()
 #define RAISE_EXCEPTION(x) \
   (saved_state.asregs.exception = x, saved_state.asregs.insn_end = 0)
 
+#define RAISE_EXCEPTION_IF_IN_DELAY_SLOT() \
+  if (in_delay_slot) RAISE_EXCEPTION (SIGILL)
+
 /* This function exists mainly for the purpose of setting a breakpoint to
    catch simulated bus errors when running the simulator under GDB.  */
 
@@ -780,7 +813,8 @@ process_rbat_addr (addr)
 
 #define SET_NIP(x) nip = (x); CHECK_INSN_PTR (nip);
 
-#define Delay_Slot(TEMPPC)     iword = RIAT (TEMPPC); goto top;
+static int in_delay_slot = 0;
+#define Delay_Slot(TEMPPC)     iword = RIAT (TEMPPC); in_delay_slot = 1; goto top;
 
 #define CHECK_INSN_PTR(p) \
 do { \
@@ -1181,6 +1215,12 @@ trap (i, regs, insn_ptr, memory, maskl, maskw, endianw)
       }
       break;
 
+    case 13:   /* Set IBNR */
+      IBNR = regs[0] & 0xffff;
+      break;
+    case 14:   /* Set IBCR */
+      IBCR = regs[0] & 0xffff;
+      break;
     case 0xc3:
     case 255:
       raise_exception (SIGTRAP);
@@ -1419,32 +1459,140 @@ macl (regs, memory, n, m)
   MACH = mach;
 }
 
-
-/* GET_LOOP_BOUNDS {EXTENDED}
-   These two functions compute the actual starting and ending point
-   of the repeat loop, based on the RS and RE registers (repeat start, 
-   repeat stop).  The extended version is called for LDRC, and the
-   regular version is called for SETRC.  The difference is that for
-   LDRC, the loop start and end instructions are literally the ones
-   pointed to by RS and RE -- for SETRC, they're not (see docs).  */
-
-static struct loop_bounds
-get_loop_bounds_ext (rs, re, memory, mem_end, maskw, endianw)
-     int rs, re;
-     unsigned char *memory, *mem_end;
-     int maskw, endianw;
+enum {
+  B_BCLR = 0,
+  B_BSET = 1,
+  B_BST  = 2,
+  B_BLD  = 3,
+  B_BAND = 4,
+  B_BOR  = 5,
+  B_BXOR = 6,
+  B_BLDNOT = 11,
+  B_BANDNOT = 12,
+  B_BORNOT = 13,
+  
+  MOVB_RM = 0x0000,
+  MOVW_RM = 0x1000,
+  MOVL_RM = 0x2000,
+  FMOV_RM = 0x3000,
+  MOVB_MR = 0x4000,
+  MOVW_MR = 0x5000,
+  MOVL_MR = 0x6000,
+  FMOV_MR = 0x7000,
+  MOVU_BMR = 0x8000,
+  MOVU_WMR = 0x9000,
+};
+
+/* Do extended displacement move instructions.  */
+void
+do_long_move_insn (int op, int disp12, int m, int n, int *thatlock)
 {
-  struct loop_bounds loop;
-
-  /* FIXME: should I verify RS < RE?  */
-  loop.start = PT2H (RS);      /* FIXME not using the params?  */
-  loop.end   = PT2H (RE & ~1); /* Ignore bit 0 of RE.  */
-  SKIP_INSN (loop.end);
-  if (loop.end >= mem_end)
-    loop.end = PT2H (0);
-  return loop;
+  int memstalls = 0;
+  int thislock = *thatlock;
+  int endianw = global_endianw;
+  int *R = &(saved_state.asregs.regs[0]);
+  unsigned char *memory = saved_state.asregs.memory;
+  int maskb = ~((saved_state.asregs.msize - 1) & ~0);
+  unsigned char *insn_ptr = PT2H (saved_state.asregs.pc);
+
+  switch (op) {
+  case MOVB_RM:                /* signed */
+    WBAT (disp12 * 1 + R[n], R[m]); 
+    break;
+  case MOVW_RM:
+    WWAT (disp12 * 2 + R[n], R[m]); 
+    break;
+  case MOVL_RM:
+    WLAT (disp12 * 4 + R[n], R[m]); 
+    break;
+  case FMOV_RM:                /* floating point */
+    if (FPSCR_SZ) 
+      {
+        MA (1);
+        WDAT (R[n] + 8 * disp12, m);
+      }
+    else 
+      WLAT (R[n] + 4 * disp12, FI (m));
+    break;
+  case MOVB_MR:
+    R[n] = RSBAT (disp12 * 1 + R[m]);
+    L (n); 
+    break;
+  case MOVW_MR:
+    R[n] = RSWAT (disp12 * 2 + R[m]);
+    L (n); 
+    break;
+  case MOVL_MR:
+    R[n] = RLAT (disp12 * 4 + R[m]);
+    L (n); 
+    break;
+  case FMOV_MR:
+    if (FPSCR_SZ) {
+      MA (1);
+      RDAT (R[m] + 8 * disp12, n);
+    }
+    else 
+      SET_FI (n, RLAT (R[m] + 4 * disp12));
+    break;
+  case MOVU_BMR:       /* unsigned */
+    R[n] = RBAT (disp12 * 1 + R[m]);
+    L (n);
+    break;
+  case MOVU_WMR:
+    R[n] = RWAT (disp12 * 2 + R[m]);
+    L (n);
+    break;
+  default:
+    RAISE_EXCEPTION (SIGINT);
+    exit (1);
+  }
+  saved_state.asregs.memstalls += memstalls;
+  *thatlock = thislock;
 }
 
+/* Do binary logical bit-manipulation insns.  */
+void
+do_blog_insn (int imm, int addr, int binop, 
+             unsigned char *memory, int maskb)
+{
+  int oldval = RBAT (addr);
+
+  switch (binop) {
+  case B_BCLR: /* bclr.b */
+    WBAT (addr, oldval & ~imm);
+    break;
+  case B_BSET: /* bset.b */
+    WBAT (addr, oldval | imm);
+    break;
+  case B_BST:  /* bst.b */
+    if (T)
+      WBAT (addr, oldval | imm);
+    else
+      WBAT (addr, oldval & ~imm);
+    break;
+  case B_BLD:  /* bld.b */
+    SET_SR_T ((oldval & imm) != 0);
+    break;
+  case B_BAND: /* band.b */
+    SET_SR_T (T && ((oldval & imm) != 0));
+    break;
+  case B_BOR:  /* bor.b */
+    SET_SR_T (T || ((oldval & imm) != 0));
+    break;
+  case B_BXOR: /* bxor.b */
+    SET_SR_T (T ^ ((oldval & imm) != 0));
+    break;
+  case B_BLDNOT:       /* bldnot.b */
+    SET_SR_T ((oldval & imm) == 0);
+    break;
+  case B_BANDNOT:      /* bandnot.b */
+    SET_SR_T (T && ((oldval & imm) == 0));
+    break;
+  case B_BORNOT:       /* bornot.b */
+    SET_SR_T (T || ((oldval & imm) == 0));
+    break;
+  }
+}
 float
 fsca_s (int in, double (*f) (double))
 {
@@ -1494,6 +1642,32 @@ fsrra_s (float in)
   return upper - result >= result - lower ? upper : lower;
 }
 
+
+/* GET_LOOP_BOUNDS {EXTENDED}
+   These two functions compute the actual starting and ending point
+   of the repeat loop, based on the RS and RE registers (repeat start, 
+   repeat stop).  The extended version is called for LDRC, and the
+   regular version is called for SETRC.  The difference is that for
+   LDRC, the loop start and end instructions are literally the ones
+   pointed to by RS and RE -- for SETRC, they're not (see docs).  */
+
+static struct loop_bounds
+get_loop_bounds_ext (rs, re, memory, mem_end, maskw, endianw)
+     int rs, re;
+     unsigned char *memory, *mem_end;
+     int maskw, endianw;
+{
+  struct loop_bounds loop;
+
+  /* FIXME: should I verify RS < RE?  */
+  loop.start = PT2H (RS);      /* FIXME not using the params?  */
+  loop.end   = PT2H (RE & ~1); /* Ignore bit 0 of RE.  */
+  SKIP_INSN (loop.end);
+  if (loop.end >= mem_end)
+    loop.end = PT2H (0);
+  return loop;
+}
+
 static struct loop_bounds
 get_loop_bounds (rs, re, memory, mem_end, maskw, endianw)
      int rs, re;
@@ -1607,8 +1781,10 @@ init_dsp (abfd)
          saved_state.asregs.xyram_select = new_select;
          free (saved_state.asregs.xmem);
          free (saved_state.asregs.ymem);
-         saved_state.asregs.xmem = (unsigned char *) calloc (1, ram_area_size);
-         saved_state.asregs.ymem = (unsigned char *) calloc (1, ram_area_size);
+         saved_state.asregs.xmem = 
+           (unsigned char *) calloc (1, ram_area_size);
+         saved_state.asregs.ymem = 
+           (unsigned char *) calloc (1, ram_area_size);
 
          /* Disable use of X / Y mmeory if not allocated.  */
          if (! saved_state.asregs.xmem || ! saved_state.asregs.ymem)
@@ -1642,6 +1818,10 @@ init_dsp (abfd)
       saved_state.asregs.yram_start = 1;
     }
 
+  if (saved_state.asregs.regstack == NULL)
+    saved_state.asregs.regstack = 
+      calloc (512, sizeof *saved_state.asregs.regstack);
+
   if (target_dsp != was_dsp)
     {
       int i, tmp;
@@ -1741,7 +1921,11 @@ sim_resume (sd, step, siggnal)
   register int memstalls = 0;
   register int insts = 0;
   register int prevlock;
+#if 1
+  int thislock;
+#else
   register int thislock;
+#endif
   register unsigned int doprofile;
   register int pollcount = 0;
   /* endianw is used for every insn fetch, hence it makes sense to cache it.
@@ -1820,10 +2004,13 @@ sim_resume (sd, step, siggnal)
       insts++;
 #endif
     top:
+      if (tracing)
+       fprintf (stderr, "PC: %08x, insn: %04x\n", PH2T (insn_ptr), iword);
 
 #include "code.c"
 
 
+      in_delay_slot = 0;
       insn_ptr = nip;
 
       if (--pollcount < 0)
@@ -1940,6 +2127,15 @@ sim_read (sd, addr, buffer, size)
   return size;
 }
 
+static int gdb_bank_number;
+enum {
+  REGBANK_MACH = 15,
+  REGBANK_IVN  = 16,
+  REGBANK_PR   = 17,
+  REGBANK_GBR  = 18,
+  REGBANK_MACL = 19
+};
+
 int
 sim_store_register (sd, rn, memory, length)
      SIM_DESC sd;
@@ -2050,6 +2246,12 @@ sim_store_register (sd, rn, memory, length)
     case SIM_SH_R2_BANK0_REGNUM: case SIM_SH_R3_BANK0_REGNUM:
     case SIM_SH_R4_BANK0_REGNUM: case SIM_SH_R5_BANK0_REGNUM:
     case SIM_SH_R6_BANK0_REGNUM: case SIM_SH_R7_BANK0_REGNUM:
+      if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)
+       {
+         rn -= SIM_SH_R0_BANK0_REGNUM;
+         saved_state.asregs.regstack[gdb_bank_number].regs[rn] = val;
+       }
+      else
       if (SR_MD && SR_RB)
        Rn_BANK (rn - SIM_SH_R0_BANK0_REGNUM) = val;
       else
@@ -2059,6 +2261,12 @@ sim_store_register (sd, rn, memory, length)
     case SIM_SH_R2_BANK1_REGNUM: case SIM_SH_R3_BANK1_REGNUM:
     case SIM_SH_R4_BANK1_REGNUM: case SIM_SH_R5_BANK1_REGNUM:
     case SIM_SH_R6_BANK1_REGNUM: case SIM_SH_R7_BANK1_REGNUM:
+      if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)
+       {
+         rn -= SIM_SH_R0_BANK1_REGNUM;
+         saved_state.asregs.regstack[gdb_bank_number].regs[rn + 8] = val;
+       }
+      else
       if (SR_MD && SR_RB)
        saved_state.asregs.regs[rn - SIM_SH_R0_BANK1_REGNUM] = val;
       else
@@ -2070,6 +2278,35 @@ sim_store_register (sd, rn, memory, length)
     case SIM_SH_R6_BANK_REGNUM: case SIM_SH_R7_BANK_REGNUM:
       SET_Rn_BANK (rn - SIM_SH_R0_BANK_REGNUM, val);
       break;
+    case SIM_SH_TBR_REGNUM:
+      TBR = val;
+      break;
+    case SIM_SH_IBNR_REGNUM:
+      IBNR = val;
+      break;
+    case SIM_SH_IBCR_REGNUM:
+      IBCR = val;
+      break;
+    case SIM_SH_BANK_REGNUM:
+      /* This is a pseudo-register maintained just for gdb.
+        It tells us what register bank gdb would like to read/write.  */
+      gdb_bank_number = val;
+      break;
+    case SIM_SH_BANK_MACL_REGNUM:
+      saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_MACL] = val;
+      break;
+    case SIM_SH_BANK_GBR_REGNUM:
+      saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_GBR] = val;
+      break;
+    case SIM_SH_BANK_PR_REGNUM:
+      saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_PR] = val;
+      break;
+    case SIM_SH_BANK_IVN_REGNUM:
+      saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_IVN] = val;
+      break;
+    case SIM_SH_BANK_MACH_REGNUM:
+      saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_MACH] = val;
+      break;
     default:
       return 0;
     }
@@ -2185,6 +2422,12 @@ sim_fetch_register (sd, rn, memory, length)
     case SIM_SH_R2_BANK0_REGNUM: case SIM_SH_R3_BANK0_REGNUM:
     case SIM_SH_R4_BANK0_REGNUM: case SIM_SH_R5_BANK0_REGNUM:
     case SIM_SH_R6_BANK0_REGNUM: case SIM_SH_R7_BANK0_REGNUM:
+      if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)
+       {
+         rn -= SIM_SH_R0_BANK0_REGNUM;
+         val = saved_state.asregs.regstack[gdb_bank_number].regs[rn];
+       }
+      else
       val = (SR_MD && SR_RB
             ? Rn_BANK (rn - SIM_SH_R0_BANK0_REGNUM)
             : saved_state.asregs.regs[rn - SIM_SH_R0_BANK0_REGNUM]);
@@ -2193,6 +2436,12 @@ sim_fetch_register (sd, rn, memory, length)
     case SIM_SH_R2_BANK1_REGNUM: case SIM_SH_R3_BANK1_REGNUM:
     case SIM_SH_R4_BANK1_REGNUM: case SIM_SH_R5_BANK1_REGNUM:
     case SIM_SH_R6_BANK1_REGNUM: case SIM_SH_R7_BANK1_REGNUM:
+      if (saved_state.asregs.bfd_mach == bfd_mach_sh2a)
+       {
+         rn -= SIM_SH_R0_BANK1_REGNUM;
+         val = saved_state.asregs.regstack[gdb_bank_number].regs[rn + 8];
+       }
+      else
       val = (! SR_MD || ! SR_RB
             ? Rn_BANK (rn - SIM_SH_R0_BANK1_REGNUM)
             : saved_state.asregs.regs[rn - SIM_SH_R0_BANK1_REGNUM]);
@@ -2203,6 +2452,35 @@ sim_fetch_register (sd, rn, memory, length)
     case SIM_SH_R6_BANK_REGNUM: case SIM_SH_R7_BANK_REGNUM:
       val = Rn_BANK (rn - SIM_SH_R0_BANK_REGNUM);
       break;
+    case SIM_SH_TBR_REGNUM:
+      val = TBR;
+      break;
+    case SIM_SH_IBNR_REGNUM:
+      val = IBNR;
+      break;
+    case SIM_SH_IBCR_REGNUM:
+      val = IBCR;
+      break;
+    case SIM_SH_BANK_REGNUM:
+      /* This is a pseudo-register maintained just for gdb.
+        It tells us what register bank gdb would like to read/write.  */
+      val = gdb_bank_number;
+      break;
+    case SIM_SH_BANK_MACL_REGNUM:
+      val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_MACL];
+      break;
+    case SIM_SH_BANK_GBR_REGNUM:
+      val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_GBR];
+      break;
+    case SIM_SH_BANK_PR_REGNUM:
+      val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_PR];
+      break;
+    case SIM_SH_BANK_IVN_REGNUM:
+      val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_IVN];
+      break;
+    case SIM_SH_BANK_MACH_REGNUM:
+      val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_MACH];
+      break;
     default:
       return 0;
     }
@@ -2214,7 +2492,10 @@ int
 sim_trace (sd)
      SIM_DESC sd;
 {
-  return 0;
+  tracing = 1;
+  sim_resume (sd, 0, 0);
+  tracing = 0;
+  return 1;
 }
 
 void
@@ -2381,6 +2662,15 @@ sim_load (sd, prog, abfd, from_tty)
   prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
                            sim_kind == SIM_OPEN_DEBUG,
                            0, sim_write);
+
+  /* Set the bfd machine type.  */
+  if (prog_bfd)
+    saved_state.asregs.bfd_mach = bfd_get_mach (prog_bfd);
+  else if (abfd)
+    saved_state.asregs.bfd_mach = bfd_get_mach (abfd);
+  else
+    saved_state.asregs.bfd_mach = 0;
+
   if (prog_bfd == NULL)
     return SIM_RC_FAIL;
   if (abfd == NULL)
@@ -2403,6 +2693,10 @@ sim_create_inferior (sd, prog_bfd, argv, env)
   if (prog_bfd != NULL)
     saved_state.asregs.pc = bfd_get_start_address (prog_bfd);
 
+  /* Set the bfd machine type.  */
+  if (prog_bfd != NULL)
+    saved_state.asregs.bfd_mach = bfd_get_mach (prog_bfd);
+
   /* Record the program's arguments. */
   prog_argv = argv;