sim/ * bfin: New target subdirectory. * configure.ac: Add bfin target. * configure: Regenerate. sim/bfin/ * acconfig.h: New file. * bfin-dis.c: New file. * bfin-sim.h: New file. * config.in: New file. * configure.ac: New file. * interp.c: New file. * Makefile.in: New file. * syscall.h: New file. diff -r -u -N -x CVS src.orig/sim/bfin/acconfig.h src/sim/bfin/acconfig.h --- src.orig/sim/bfin/acconfig.h 1970-01-01 08:00:00.000000000 +0800 +++ src/sim/bfin/acconfig.h 2004-10-06 00:58:39.000000000 +0800 @@ -0,0 +1,15 @@ + +/* Define to 1 if NLS is requested. */ +#undef ENABLE_NLS + +/* Define as 1 if you have catgets and don't want to use GNU gettext. */ +#undef HAVE_CATGETS + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Define as 1 if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES diff -r -u -N -x CVS src.orig/sim/bfin/bfin-dis.c src/sim/bfin/bfin-dis.c --- src.orig/sim/bfin/bfin-dis.c 1970-01-01 08:00:00.000000000 +0800 +++ src/sim/bfin/bfin-dis.c 2005-12-27 11:12:59.000000000 +0800 @@ -0,0 +1,2690 @@ +/* Simulator for Analog Devices Blackfin processer. + + Copyright (C) 2005 Free Software Foundation, Inc. + Contributed by Analog Devices. + + This file is part of simulators. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include +#include +#include +#include + +#include "opcode/bfin.h" +#include "bfin-sim.h" + +#define M_S2RND 1 +#define M_T 2 +#define M_W32 3 +#define M_FU 4 +#define M_TFU 6 +#define M_IS 8 +#define M_ISS2 9 +#define M_IH 11 +#define M_IU 12 + +#define HOST_LONG_WORD_SIZE (sizeof(long)*8) + +#define SIGNEXTEND(v, n) (((bs32)v << (HOST_LONG_WORD_SIZE - (n))) >> (HOST_LONG_WORD_SIZE - (n))) + +/* For dealing with parallel instructions, we must avoid changing our register + file until all parallel insns have been simulated. This queue of stores + can be used to delay a modification. + @@@ Should go and convert all 32 bit insns to use this. */ +struct store { + bu32 *addr; + bu32 val; +}; + +struct store stores[10]; +int n_stores; + +#define STORE(X,Y) do { \ + stores[n_stores].addr = &(X); \ + stores[n_stores++].val = (Y); \ + } while (0) + +static __attribute__ ((noreturn)) void +unhandled_instruction (char *insn) +{ + fprintf(stderr, "Unhandled instruction \"%s\" ... aborting\n", insn); + raise (SIGILL); + abort (); +} + +static __attribute__ ((noreturn)) void +illegal_instruction () +{ + fprintf(stderr, "Illegal instruction ... aborting\n"); + raise (SIGILL); + abort (); +} + +static void +setflags_nz (bu32 val) +{ + saved_state.az = val == 0; + saved_state.an = val >> 31; +} + +static void +setflags_logical (bu32 val) +{ + setflags_nz (val); + saved_state.ac0 = 0; + saved_state.v = 0; +} + +static bu32 +ashiftrt (bu32 val, int cnt) +{ + int real_cnt = cnt > 32 ? 32 : cnt; + bu32 sgn = ~((val >> 31) - 1); + int sgncnt = 32 - real_cnt; + if (sgncnt > 16) + sgn <<= 16, sgncnt -= 16; + sgn <<= sgncnt; + if (real_cnt > 16) + val >>= 16, real_cnt -= 16; + val >>= real_cnt; + val |= sgn; + saved_state.an = val >> 31; + saved_state.az = val == 0; + /* @@@ */ + saved_state.v = 0; + return val; +} + +static bu32 +lshiftrt (bu32 val, int cnt) +{ + int real_cnt = cnt > 32 ? 32 : cnt; + if (real_cnt > 16) + val >>= 16, real_cnt -= 16; + val >>= real_cnt; + saved_state.an = val >> 31; + saved_state.az = val == 0; + saved_state.v = 0; + return val; +} + +static bu32 +lshift (bu32 val, int cnt) +{ + int real_cnt = cnt > 32 ? 32 : cnt; + if (real_cnt > 16) + val <<= 16, real_cnt -= 16; + val <<= real_cnt; + saved_state.an = val >> 31; + saved_state.az = val == 0; + saved_state.v = 0; + return val; +} + +static bu32 +add32 (bu32 a, bu32 b, int carry) +{ + int flgs = a >> 31; + int flgo = b >> 31; + bu32 v = a + b; + int flgn = v >> 31; + int overflow = (flgs ^ flgn) & (flgo ^ flgn); + saved_state.an = flgn; + saved_state.vs |= overflow; + saved_state.v = overflow; + saved_state.v_internal |= overflow; + saved_state.az = v == 0; + if (carry) + saved_state.ac0 = ~a < b; + return v; +} + +static bu32 +sub32 (bu32 a, bu32 b, int carry) +{ + int flgs = a >> 31; + int flgo = b >> 31; + bu32 v = a - b; + int flgn = v >> 31; + int overflow = (flgs ^ flgo) & (flgn ^ flgs); + saved_state.an = flgn; + saved_state.vs |= overflow; + saved_state.v = overflow; + saved_state.v_internal |= overflow; + saved_state.az = v == 0; + if (carry) + saved_state.ac0 = b <= a; + return v; +} + +static bu32 +min32 (bu32 a, bu32 b) +{ + int val = a; + if ((bs32)a > (bs32)b) + val = b; + setflags_nz (val); + saved_state.v = 0; + return val; +} + +static bu32 +max32 (bu32 a, bu32 b) +{ + int val = a; + if ((bs32)a < (bs32)b) + val = b; + setflags_nz (val); + saved_state.v = 0; + return val; +} + +static bu32 +add_and_shift (bu32 a, bu32 b, int shift) +{ + int v; + saved_state.v_internal = 0; + v = add32 (a, b, 0); + while (shift-- > 0) + { + int x = v >> 30; + if (x == 1 || x == 2) + saved_state.v_internal = 1; + v <<= 1; + } + saved_state.v = saved_state.v_internal; + saved_state.vs |= saved_state.v; + return v; +} + +typedef enum +{ + c_0, c_1, c_4, c_2, c_uimm2, c_uimm3, c_imm3, c_pcrel4, + c_imm4, c_uimm4s4, c_uimm4, c_uimm4s2, c_negimm5s4, c_imm5, c_uimm5, c_imm6, + c_imm7, c_imm8, c_uimm8, c_pcrel8, c_uimm8s4, c_pcrel8s4, c_lppcrel10, + c_pcrel10, + c_pcrel12, c_imm16s4, c_luimm16, c_imm16, c_huimm16, c_rimm16, c_imm16s2, + c_uimm16s4, + c_uimm16, c_pcrel24, +} const_forms_t; + +static struct +{ + char *name; + int nbits; + char reloc; + char issigned; + char pcrel; + char scale; + char offset; + char negative; + char positive; +} constant_formats[] = +{ + { "0", 0, 0, 1, 0, 0, 0, 0, 0}, + { "1", 0, 0, 1, 0, 0, 0, 0, 0}, + { "4", 0, 0, 1, 0, 0, 0, 0, 0}, + { "2", 0, 0, 1, 0, 0, 0, 0, 0}, + { "uimm2", 2, 0, 0, 0, 0, 0, 0, 0}, + { "uimm3", 3, 0, 0, 0, 0, 0, 0, 0}, + { "imm3", 3, 0, 1, 0, 0, 0, 0, 0}, + { "pcrel4", 4, 1, 0, 1, 1, 0, 0, 0}, + { "imm4", 4, 0, 1, 0, 0, 0, 0, 0}, + { "uimm4s4", 4, 0, 0, 0, 2, 0, 0, 1}, + { "uimm4", 4, 0, 0, 0, 0, 0, 0, 0}, + { "uimm4s2", 4, 0, 0, 0, 1, 0, 0, 1}, + { "negimm5s4", 5, 0, 1, 0, 2, 0, 1, 0}, + { "imm5", 5, 0, 1, 0, 0, 0, 0, 0}, + { "uimm5", 5, 0, 0, 0, 0, 0, 0, 0}, + { "imm6", 6, 0, 1, 0, 0, 0, 0, 0}, + { "imm7", 7, 0, 1, 0, 0, 0, 0, 0}, + { "imm8", 8, 0, 1, 0, 0, 0, 0, 0}, + { "uimm8", 8, 0, 0, 0, 0, 0, 0, 0}, + { "pcrel8", 8, 1, 0, 1, 1, 0, 0, 0}, + { "uimm8s4", 8, 0, 0, 0, 2, 0, 0, 0}, + { "pcrel8s4", 8, 1, 1, 1, 2, 0, 0, 0}, + { "lppcrel10", 10, 1, 0, 1, 1, 0, 0, 0}, + { "pcrel10", 10, 1, 1, 1, 1, 0, 0, 0}, + { "pcrel12", 12, 1, 1, 1, 1, 0, 0, 0}, + { "imm16s4", 16, 0, 1, 0, 2, 0, 0, 0}, + { "luimm16", 16, 1, 0, 0, 0, 0, 0, 0}, + { "imm16", 16, 0, 1, 0, 0, 0, 0, 0}, + { "huimm16", 16, 1, 0, 0, 0, 0, 0, 0}, + { "rimm16", 16, 1, 1, 0, 0, 0, 0, 0}, + { "imm16s2", 16, 0, 1, 0, 1, 0, 0, 0}, + { "uimm16s4", 16, 0, 0, 0, 2, 0, 0, 0}, + { "uimm16", 16, 0, 0, 0, 0, 0, 0, 0}, + { "pcrel24", 24, 1, 1, 1, 1, 0, 0, 0},}; + +static bu32 +fmtconst (const_forms_t cf, bu32 x, bu32 pc) +{ + if (0 && constant_formats[cf].reloc) + { + bu32 ea = (((constant_formats[cf].pcrel + ? SIGNEXTEND (x, constant_formats[cf].nbits) + : x) + constant_formats[cf].offset) + << constant_formats[cf].scale); + if (constant_formats[cf].pcrel) + ea += pc; + + return ea; + } + + /* Negative constants have an implied sign bit. */ + if (constant_formats[cf].negative) + { + int nb = constant_formats[cf].nbits + 1; + x = x | (1 << constant_formats[cf].nbits); + x = SIGNEXTEND (x, nb); + } + else if (constant_formats[cf].issigned) + x = SIGNEXTEND (x, constant_formats[cf].nbits); + + x += constant_formats[cf].offset; + x <<= constant_formats[cf].scale; + + return x; +} + +#define uimm16s4(x) fmtconst(c_uimm16s4, x, 0) +#define pcrel4(x) fmtconst(c_pcrel4, x, pc) +#define pcrel8(x) fmtconst(c_pcrel8, x, pc) +#define pcrel8s4(x) fmtconst(c_pcrel8s4, x, pc) +#define pcrel10(x) fmtconst(c_pcrel10, x, pc) +#define pcrel12(x) fmtconst(c_pcrel12, x, pc) +#define negimm5s4(x) fmtconst(c_negimm5s4, x, 0) +#define rimm16(x) fmtconst(c_rimm16, x, 0) +#define huimm16(x) fmtconst(c_huimm16, x, 0) +#define imm16(x) fmtconst(c_imm16, x, 0) +#define uimm2(x) fmtconst(c_uimm2, x, 0) +#define uimm3(x) fmtconst(c_uimm3, x, 0) +#define luimm16(x) fmtconst(c_luimm16, x, 0) +#define uimm4(x) fmtconst(c_uimm4, x, 0) +#define uimm5(x) fmtconst(c_uimm5, x, 0) +#define imm16s2(x) fmtconst(c_imm16s2, x, 0) +#define uimm8(x) fmtconst(c_uimm8, x, 0) +#define imm16s4(x) fmtconst(c_imm16s4, x, 0) +#define uimm4s2(x) fmtconst(c_uimm4s2, x, 0) +#define uimm4s4(x) fmtconst(c_uimm4s4, x, 0) +#define lppcrel10(x) fmtconst(c_lppcrel10, x, pc) +#define imm3(x) fmtconst(c_imm3, x, 0) +#define imm4(x) fmtconst(c_imm4, x, 0) +#define uimm8s4(x) fmtconst(c_uimm8s4, x, 0) +#define imm5(x) fmtconst(c_imm5, x, 0) +#define imm6(x) fmtconst(c_imm6, x, 0) +#define imm7(x) fmtconst(c_imm7, x, 0) +#define imm8(x) fmtconst(c_imm8, x, 0) +#define pcrel24(x) fmtconst(c_pcrel24, x, pc) +#define uimm16(x) fmtconst(c_uimm16, x, 0) + +static bu32 * +get_allreg (int grp, int reg) +{ + int fullreg = (grp << 3) | reg; + /* REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7, + REG_P0, REG_P1, REG_P2, REG_P3, REG_P4, REG_P5, REG_SP, REG_FP, + REG_I0, REG_I1, REG_I2, REG_I3, REG_M0, REG_M1, REG_M2, REG_M3, + REG_B0, REG_B1, REG_B2, REG_B3, REG_L0, REG_L1, REG_L2, REG_L3, + REG_A0x, REG_A0w, REG_A1x, REG_A1w, , , REG_ASTAT, REG_RETS, + , , , , , , , , + REG_LC0, REG_LT0, REG_LB0, REG_LC1, REG_LT1, REG_LB1, REG_CYCLES, + REG_CYCLES2, + REG_USP, REG_SEQSTAT, REG_SYSCFG, REG_RETI, REG_RETX, REG_RETN, REG_RETE, + REG_LASTREG */ + switch (fullreg >> 2) + { + case 0: case 1: return &DREG (reg); break; + case 2: case 3: return &PREG (reg); break; + case 4: return &IREG (reg & 3); break; + case 5: return &MREG (reg & 3); break; + case 6: return &BREG (reg & 3); break; + case 7: return &LREG (reg & 3); break; + default: + switch (fullreg) + { + case 39: return &saved_state.rets; + } + return 0; + } +} + +/* Perform a multiplication, sign- or zero-extending the result to 64 bit. */ +static bu64 +decode_multfunc (int h0, int h1, int src0, int src1, int mmod, int MM) +{ + bu32 s0 = DREG (src0), s1 = DREG (src1); + bu32 sgn0, sgn1; + bu32 val; + bu64 val1; + + if (h0) + s0 >>= 16; + + if (h1) + s1 >>= 16; + + s0 &= 0xffff; + s1 &= 0xffff; + + sgn0 = -(s0 & 0x8000); + sgn1 = -(s1 & 0x8000); + + if (MM) + s0 |= sgn0; + else switch (mmod) + { + case 0: + case M_S2RND: + case M_T: + case M_IS: + case M_ISS2: + case M_IH: + s0 |= sgn0; + s1 |= sgn1; + break; + case M_FU: + case M_IU: + case M_TFU: + break; + default: + abort (); + } + + val = s0 * s1; + /* Perform shift correction if appropriate for the mode. */ + if (mmod == 0 || mmod == M_T || mmod == M_S2RND) + { + if (val == 0x40000000) + val = 0x7fffffff; + else + val <<= 1; + } + + val1 = val; + if (mmod == 0 || mmod == M_IS || mmod == M_T || mmod == M_S2RND + || mmod == M_ISS2 || mmod == M_IH) + val1 |= -(val1 & 0x80000000); + + return val1; +} + +static bu32 +saturate_s32 (bu64 val) +{ + if ((bs64)val < -0x80000000ll) + return 0x80000000; + if ((bs64)val > 0x7fffffff) + return 0x7fffffff; + return val; +} + +static bu32 +saturate_s16 (bu64 val) +{ + if ((bs64)val < -0x8000ll) + return 0x8000; + if ((bs64)val > 0x7fff) + return 0x7fff; + return val; +} + +static bu32 +saturate_u32 (bu64 val) +{ + if (val > 0xffffffff) + return 0xffffffff; + return val; +} + +static bu32 +saturate_u16 (bu64 val) +{ + if (val > 0xffff) + return 0xffff; + return val; +} + +static bu64 +rnd16 (bu64 val) +{ + bu64 sgnbits = val & 0xff00000000000000ull; + /* @@@ Should honour rounding mode. Can this overflow? */ + val += 0x8000; + val >>= 16; + return val | sgnbits; +} + +static bu64 +trunc16 (bu64 val) +{ + bu64 sgnbits = val & 0xff00000000000000ull; + val >>= 16; + return val | sgnbits; +} + +/* Extract a 16 or 32 bit value from a 64 bit multiplication result. + These 64 bits must be sign- or zero-extended properly from the source + we want to extract, either a 32 bit multiply or a 40 bit accumulator. */ + +static bu32 +extract_mult (bu64 res, int mmod, int fullword) +{ + if (fullword) + switch (mmod) + { + case 0: + case M_IS: + return saturate_s32 (res); + case M_FU: + return saturate_u32 (res); + case M_S2RND: + case M_ISS2: + return saturate_s32 (res << 1); + default: + abort (); + } + else + switch (mmod) + { + case 0: + case M_IH: + return saturate_s16 (rnd16 (res)); + case M_IS: + return saturate_s16 (res); + case M_FU: + return saturate_u16 (rnd16 (res)); + case M_IU: + return saturate_u16 (res); + + case M_T: + return saturate_s16 (trunc16 (res)); + case M_TFU: + return saturate_u16 (trunc16 (res)); + + case M_S2RND: + return saturate_s16 (rnd16 (res << 1)); + case M_ISS2: + return saturate_s16 (res << 1); + default: + abort (); + } +} + +static bu32 +decode_macfunc (int which, int op, int h0, int h1, int src0, int src1, + int mmod, int MM, int fullword) +{ + bu64 *accum = which ? &A1REG : &A0REG; + bu64 acc = *accum & 0xFFFFFFFFFFull; + + /* Sign extend accumulator if necessary. */ + if (mmod == 0 || mmod == M_T || mmod == M_IS || mmod == M_ISS2 + || mmod == M_S2RND) + acc |= -(acc & 0x80000000); + + if (op != 3) + { + bu64 res = decode_multfunc (h0, h1, src0, src1, mmod, MM); + + /* Perform accumulation. */ + switch (op) + { + case 0: + *accum = res; + break; + case 1: + *accum = acc + res; + break; + case 2: + *accum = acc - res; + break; + } + + /* Saturate. */ + switch (mmod) + { + case 0: + case M_T: + case M_IS: + case M_ISS2: + case M_S2RND: + if ((bs64)*accum < -0x8000000000ll) + *accum = -0x8000000000ull; + else if ((bs64)*accum >= 0x7fffffffffll) + *accum = 0x7fffffffffull; + break; + case M_TFU: + case M_FU: + case M_IU: + if (*accum > 0xFFFFFFFFFFull) + *accum = 0xFFFFFFFFFFull; + break; + default: + abort (); + } + acc = *accum; + } + + return extract_mult (acc, mmod, fullword); +} + +static void +decode_ProgCtrl_0 (bu16 iw0) +{ + /* ProgCtrl + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |.prgfunc.......|.poprnd........| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int poprnd = ((iw0 >> 0) & 0xf); + int prgfunc = ((iw0 >> 4) & 0xf); + + if (prgfunc == 0 && poprnd == 0) + /* NOP */ + PCREG += 2; + else if (prgfunc == 1 && poprnd == 0) + /* RTS */ + PCREG = saved_state.rets; + else if (prgfunc == 1 && poprnd == 1) + unhandled_instruction ("RTI"); + else if (prgfunc == 1 && poprnd == 2) + unhandled_instruction ("RTX"); + else if (prgfunc == 1 && poprnd == 3) + unhandled_instruction ("RTN"); + else if (prgfunc == 1 && poprnd == 4) + unhandled_instruction ("RTE"); + else if (prgfunc == 2 && poprnd == 0) + unhandled_instruction ("IDLE"); + else if (prgfunc == 2 && poprnd == 3) + unhandled_instruction ("CSYNC"); + else if (prgfunc == 2 && poprnd == 4) + unhandled_instruction ("SSYNC"); + else if (prgfunc == 2 && poprnd == 5) + unhandled_instruction ("EMUEXCPT"); + else if (prgfunc == 3) + unhandled_instruction ("CLI dregs"); + else if (prgfunc == 4) + unhandled_instruction ("STI dregs"); + else if (prgfunc == 5) + { + /* JUMP (pregs) */ + PCREG = PREG (poprnd); + did_jump = 1; + } + else if (prgfunc == 6) + { + /* CALL (pregs) */ + saved_state.rets = PCREG + 2; + PCREG = PREG (poprnd); + did_jump = 1; + } + else if (prgfunc == 7) + { + /* CALL (PC + pregs) */ + saved_state.rets = PCREG + 2; + PCREG = PCREG + PREG (poprnd); + did_jump = 1; + } + else if (prgfunc == 8) + { + /* JUMP (PC + pregs) */ + PCREG = PCREG + PREG (poprnd); + did_jump = 1; + } + else if (prgfunc == 9) + { + /* RAISE uimm4 */ + bfin_trap (); + PCREG += 2; + } + else if (prgfunc == 10) + { + /* EXCPT uimm4 */ + if(uimm4 (poprnd) == 1) + raise_exception(SIGTRAP); + else + unhandled_instruction ("unhandled exception"); + } + else if (prgfunc == 11) + unhandled_instruction ("TESTSET"); + else + illegal_instruction (); +} + +static void +decode_CaCTRL_0 (bu16 iw0) +{ + /* CaCTRL + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |.a.|.op....|.reg.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int a = ((iw0 >> 5) & 0x1); + int reg = ((iw0 >> 0) & 0x7); + int op = ((iw0 >> 3) & 0x3); + + if (a == 0 && op == 0) + unhandled_instruction ("PREFETCH [pregs]"); + else if (a == 0 && op == 1) + unhandled_instruction ("FLUSHINV [pregs]"); + else if (a == 0 && op == 2) + unhandled_instruction ("FLUSH [pregs]"); + else if (a == 0 && op == 3) + unhandled_instruction ("IFLUSH [pregs]"); + else if (a == 1 && op == 0) + unhandled_instruction ("PREFETCH [pregs++]"); + else if (a == 1 && op == 1) + unhandled_instruction ("FLUSHINV [pregs++]"); + else if (a == 1 && op == 2) + unhandled_instruction ("FLUSH [pregs++]"); + else if (a == 1 && op == 3) + unhandled_instruction ("IFLUSH [pregs++]"); + else + illegal_instruction (); + + PCREG += 2; +} + +static void +decode_PushPopReg_0 (bu16 iw0) +{ + /* PushPopReg + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |.W.|.grp.......|.reg.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int grp = ((iw0 >> 3) & 0x7); + int reg = ((iw0 >> 0) & 0x7); + int W = ((iw0 >> 6) & 0x1); + bu32 *whichreg = get_allreg (grp, reg); + + if (whichreg == 0) + unhandled_instruction ("push/pop"); + + if (W == 0) + { + /* allregs = [SP++] */ + *whichreg = get_long (saved_state.memory, PREG (6)); + PREG (6) += 4; + } + else + { + /* [--SP] = allregs */ + PREG (6) -= 4; + put_long (saved_state.memory, PREG (6), *whichreg); + } + PCREG += 2; +} + +static void +decode_PushPopMultiple_0 (bu16 iw0) +{ + /* PushPopMultiple + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 0 | 0 | 1 | 0 |.d.|.p.|.W.|.dr........|.pr........| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int p = ((iw0 >> 7) & 0x1); + int pr = ((iw0 >> 0) & 0x7); + int d = ((iw0 >> 8) & 0x1); + int dr = ((iw0 >> 3) & 0x7); + int W = ((iw0 >> 6) & 0x1); + int i; + bu32 sp = PREG (6); + + if ((d == 0 && p == 0) + || (p && imm5 (pr) > 5)) + illegal_instruction (); + + if (W == 1) + { + if (d) + for (i = dr; i < 8; i++) + { + sp -= 4; + put_long (saved_state.memory, sp, DREG (i)); + } + if (p) + for (i = pr; i < 6; i++) + { + sp -= 4; + put_long (saved_state.memory, sp, PREG (i)); + } + } + else + { + if (p) + for (i = 5; i >= pr; i--) + { + PREG (i) = get_long (saved_state.memory, sp); + sp += 4; + } + if (d) + for (i = 7; i >= dr; i--) + { + DREG (i) = get_long (saved_state.memory, sp); + sp += 4; + } + } + PREG (6) = sp; + PCREG += 2; +} + +static void +decode_ccMV_0 (bu16 iw0) +{ + /* ccMV + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 0 | 0 | 1 | 1 |.T.|.d.|.s.|.dst.......|.src.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src = ((iw0 >> 0) & 0x7); + int dst = ((iw0 >> 3) & 0x7); + int s = ((iw0 >> 6) & 0x1); + int d = ((iw0 >> 7) & 0x1); + int T = ((iw0 >> 8) & 0x1); + int cond = T ? CCREG : ! CCREG; + if (cond) + GREG (dst, d) = GREG (src, s); + PCREG += 2; +} + +static void +decode_CCflag_0 (bu16 iw0) +{ + /* CCflag + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 0 | 1 |.I.|.opc.......|.G.|.y.........|.x.........| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int x = ((iw0 >> 0) & 0x7); + int y = ((iw0 >> 3) & 0x7); + int I = ((iw0 >> 10) & 0x1); + int opc = ((iw0 >> 7) & 0x7); + int G = ((iw0 >> 6) & 0x1); + + if (opc > 4) + { + if (opc == 5 && I == 0 && G == 0) + unhandled_instruction ("CC = A0 == A1"); + else if (opc == 6 && I == 0 && G == 0) + unhandled_instruction ("CC = A0 < A1"); + else if (opc == 7 && I == 0 && G == 0) + unhandled_instruction ("CC = A0 <= A1"); + } + else + { + int issigned = opc < 3; + bu32 srcop = G ? PREG (x) : DREG (x); + bu32 dstop = I ? (issigned ? imm3 (y) : uimm3 (y)) : G ? PREG (y) : DREG (y); + int flgs = srcop >> 31; + int flgo = dstop >> 31; + + bu32 result = srcop - dstop; + int flgn = result >> 31; + int overflow = (flgs ^ flgo) & (flgn ^ flgs); + + saved_state.az = result == 0; + saved_state.an = flgn; + saved_state.ac0 = srcop < dstop; + switch (opc) + { + case 0: /* == */ + CCREG = saved_state.az; + break; + case 1: /* <, signed */ + CCREG = (flgn && !overflow) || (!flgn && overflow); + break; + case 2: /* <=, signed */ + CCREG = (flgn && !overflow) || (!flgn && overflow) || saved_state.az; + break; + case 3: /* <, unsigned */ + CCREG = saved_state.ac0; + break; + case 4: /* <=, unsigned */ + CCREG = saved_state.ac0 | saved_state.az; + break; + } + } + PCREG += 2; +} + +static void +decode_CC2dreg_0 (bu16 iw0) +{ + /* CC2dreg + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |.op....|.reg.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int reg = ((iw0 >> 0) & 0x7); + int op = ((iw0 >> 3) & 0x3); + + if (op == 0) + /* dregs = CC */ + DREG (reg) = CCREG; + else if (op == 1) + /* CC = dregs */ + CCREG = DREG (reg) != 0; + else if (op == 3) + /* CC = !CC */ + CCREG = !CCREG; + else + illegal_instruction (); + PCREG += 2; +} + +static void +decode_CC2stat_0 (bu16 iw0) +{ + /* CC2stat + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |.D.|.op....|.cbit..............| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int cbit = ((iw0 >> 0) & 0x1f); + int D = ((iw0 >> 7) & 0x1); + int op = ((iw0 >> 5) & 0x3); + int *pval; + + switch (cbit) + { + case 0: pval = &saved_state.az; break; + case 1: pval = &saved_state.an; break; + case 6: pval = &saved_state.aq; break; + case 12: pval = &saved_state.ac0; break; + case 13: pval = &saved_state.ac1; break; + case 16: pval = &saved_state.av0; break; + case 17: pval = &saved_state.av0s; break; + case 18: pval = &saved_state.av1; break; + case 19: pval = &saved_state.av1s; break; + case 24: pval = &saved_state.v; break; + case 25: pval = &saved_state.vs; break; + default: + illegal_instruction (); + } + + if (D == 0) + switch (op) + { + case 0: CCREG = *pval; break; + case 1: CCREG |= *pval; break; + case 2: CCREG &= *pval; break; + case 3: CCREG ^= *pval; break; + } + else + switch (op) + { + case 0: *pval = CCREG; break; + case 1: *pval |= CCREG; break; + case 2: *pval &= CCREG; break; + case 3: *pval ^= CCREG; break; + } + PCREG += 2; +} + +static void +decode_BRCC_0 (bu16 iw0, bu32 pc) +{ + /* BRCC + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 0 | 1 |.T.|.B.|.offset................................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int B = ((iw0 >> 10) & 0x1); + int T = ((iw0 >> 11) & 0x1); + int offset = ((iw0 >> 0) & 0x3ff); + + /* B is just the branch predictor hint - we can ignore it. */ + + /* IF CC JUMP pcrel10 */ + if (CCREG == T) + { + PCREG += pcrel10 (offset); + did_jump = 1; + } + else + PCREG += 2; +} + +static void +decode_UJUMP_0 (bu16 iw0, bu32 pc) +{ + /* UJUMP + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 1 | 0 |.offset........................................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int offset = ((iw0 >> 0) & 0xfff); + + /* JUMP.S pcrel12 */ + PCREG += pcrel12 (offset); + did_jump = 1; +} + +static void +decode_REGMV_0 (bu16 iw0) +{ + /* REGMV + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 0 | 1 | 1 |.gd........|.gs........|.dst.......|.src.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src = ((iw0 >> 0) & 0x7); + int gs = ((iw0 >> 6) & 0x7); + int dst = ((iw0 >> 3) & 0x7); + int gd = ((iw0 >> 9) & 0x7); + bu32 *srcreg = get_allreg (gs, src); + bu32 *dstreg = get_allreg (gd, dst); + + if (srcreg == 0 || dstreg == 0) + unhandled_instruction ("reg move"); + + *dstreg = *srcreg; + PCREG += 2; +} + +static void +decode_ALU2op_0 (bu16 iw0) +{ + /* ALU2op + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 1 | 0 | 0 | 0 | 0 |.opc...........|.src.......|.dst.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src = ((iw0 >> 3) & 0x7); + int opc = ((iw0 >> 6) & 0xf); + int dst = ((iw0 >> 0) & 0x7); + + if (opc == 0) + /* dregs >>>= dregs */ + DREG (dst) = ashiftrt (DREG (dst), DREG (src)); + else if (opc == 1) + /* dregs >>= dregs */ + DREG (dst) = lshiftrt (DREG (dst), DREG (src)); + else if (opc == 2) + /* dregs <<= dregs */ + DREG (dst) = lshift (DREG (dst), DREG (src)); + else if (opc == 3) + /* dregs *= dregs */ + DREG (dst) *= DREG (src); + else if (opc == 4) + /* dregs = (dregs + dregs) << 1 */ + DREG (dst) = add_and_shift (DREG (dst), DREG (src), 1); + else if (opc == 5) + /* dregs = (dregs + dregs) << 2 */ + DREG (dst) = add_and_shift (DREG (dst), DREG (src), 2); + else if (opc == 8) + unhandled_instruction ("DIVQ (dregs , dregs)"); + else if (opc == 9) + unhandled_instruction ("DIVS (dregs , dregs)"); + else if (opc == 10) + { + /* dregs = dregs_lo (X) */ + DREG (dst) = (bs32) (bs16) DREG (src); + setflags_logical (DREG (dst)); + } + else if (opc == 11) + { + /* dregs = dregs_lo (Z) */ + DREG (dst) = (bu32) (bu16) DREG (src); + setflags_logical (DREG (dst)); + } + else if (opc == 12) + { + /* dregs = dregs_byte (X) */ + DREG (dst) = (bs32) (bs8) DREG (src); + setflags_logical (DREG (dst)); + } + else if (opc == 13) + { + /* dregs = dregs_byte (Z) */ + DREG (dst) = (bu32) (bu8) DREG (src); + setflags_logical (DREG (dst)); + } + else if (opc == 14) + { + /* dregs = - dregs */ + bu32 val = DREG (src); + DREG (dst) = -val; + setflags_nz (DREG (dst)); + if (val == 0x80000000) + saved_state.v = saved_state.vs = 1; + /* @@@ Documentation isn't entirely clear about av0 and av1. */ + } + else if (opc == 15) + { + /* dregs = ~ dregs */ + DREG (dst) = ~DREG (src); + setflags_logical (DREG (dst)); + } + else + illegal_instruction (); + PCREG += 2; +} + +static void +decode_PTR2op_0 (bu16 iw0) +{ + /* PTR2op + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 1 | 0 | 0 | 0 | 1 | 0 |.opc.......|.src.......|.dst.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src = ((iw0 >> 3) & 0x7); + int opc = ((iw0 >> 6) & 0x7); + int dst = ((iw0 >> 0) & 0x7); + + if (opc == 0) + PREG (dst) -= PREG (src); + else if (opc == 1) + PREG (dst) = PREG (src) << 2; + else if (opc == 3) + PREG (dst) = PREG (src) >> 2; + else if (opc == 4) + PREG (dst) = PREG (src) >> 1; + else if (opc == 5) + unhandled_instruction ("pregs += pregs ( BREV )"); + else if (opc == 6) + PREG (dst) = (PREG (dst) + PREG (src)) << 1; + else if (opc == 7) + PREG (dst) = (PREG (dst) + PREG (src)) << 2; + else + illegal_instruction (); + + PCREG += 2; +} + +static void +decode_LOGI2op_0 (bu16 iw0) +{ + /* LOGI2op + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 1 | 0 | 0 | 1 |.opc.......|.src...............|.dst.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src = ((iw0 >> 3) & 0x1f); + int opc = ((iw0 >> 8) & 0x7); + int dst = ((iw0 >> 0) & 0x7); + + if (opc == 0) + /* CC = ! BITTST (dregs, uimm5) */ + CCREG = (~DREG (dst) >> uimm5 (src)) & 1; + else if (opc == 1) + /* CC = BITTST (dregs, uimm5) */ + CCREG = (DREG (dst) >> uimm5 (src)) & 1; + else if (opc == 2) + { + /* BITSET (dregs, uimm5) */ + DREG (dst) |= 1 << uimm5 (src); + setflags_logical (DREG (dst)); + } + else if (opc == 3) + { + /* BITTGL (dregs, uimm5) */ + DREG (dst) ^= 1 << uimm5 (src); + setflags_logical (DREG (dst)); + } + else if (opc == 4) + { + /* BITCLR (dregs, uimm5) */ + DREG (dst) &= ~(1 << uimm5 (src)); + setflags_logical (DREG (dst)); + } + else if (opc == 5) + /* dregs >>>= uimm5 */ + DREG (dst) = ashiftrt (DREG (dst), uimm5 (src)); + else if (opc == 6) + /* dregs >>= uimm5 */ + DREG (dst) = lshiftrt (DREG (dst), uimm5 (src)); + else if (opc == 7) + /* dregs <<= uimm5 */ + DREG (dst) = lshift (DREG (dst), uimm5 (src)); + + PCREG += 2; +} + +static void +decode_COMP3op_0 (bu16 iw0) +{ + /* COMP3op + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 1 | 0 | 1 |.opc.......|.dst.......|.src1......|.src0......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src0 = ((iw0 >> 0) & 0x7); + int src1 = ((iw0 >> 3) & 0x7); + int opc = ((iw0 >> 9) & 0x7); + int dst = ((iw0 >> 6) & 0x7); + + if (opc == 0) + /* dregs = dregs + dregs */ + DREG (dst) = add32 (DREG (src0), DREG (src1), 1); + else if (opc == 1) + /* dregs = dregs - dregs */ + DREG (dst) = sub32 (DREG (src0), DREG (src1), 1); + else if (opc == 2) + { + /* dregs = dregs & dregs */ + DREG (dst) = DREG (src0) & DREG (src1); + setflags_logical (DREG (dst)); + } + else if (opc == 3) + { + /* dregs = dregs | dregs */ + DREG (dst) = DREG (src0) | DREG (src1); + setflags_logical (DREG (dst)); + } + else if (opc == 4) + { + /* dregs = dregs ^ dregs */ + DREG (dst) = DREG (src0) ^ DREG (src1); + setflags_logical (DREG (dst)); + } + else if (opc == 5) + /* If src0 == src1 this is disassembled as a shift by 1, but this + distinction doesn't matter for our purposes. */ + PREG (dst) = PREG (src0) + PREG (src1); + else if (opc == 6) + PREG (dst) = PREG (src0) + (PREG (src1) << 1); + else if (opc == 7) + PREG (dst) = PREG (src0) + (PREG (src1) << 2); + + PCREG += 2; +} + +static void +decode_COMPI2opD_0 (bu16 iw0) +{ + /* COMPI2opD + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 1 | 1 | 0 | 0 |.op|.isrc......................|.dst.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int isrc = ((iw0 >> 3) & 0x7f); + int dst = ((iw0 >> 0) & 0x7); + int op = ((iw0 >> 10) & 0x1); + + if (op == 0) + DREG (dst) = imm7 (isrc); + else if (op == 1) + DREG (dst) = add32 (DREG (dst), imm7 (isrc), 1); + PCREG += 2; +} + +static void +decode_COMPI2opP_0 (bu16 iw0) +{ + /* COMPI2opP + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 0 | 1 | 1 | 0 | 1 |.op|.src.......................|.dst.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src = ((iw0 >> 3) & 0x7f); + int dst = ((iw0 >> 0) & 0x7); + int op = ((iw0 >> 10) & 0x1); + + if (op == 0) + PREG (dst) = imm7 (src); + else if (op == 1) + PREG (dst) += imm7 (src); + PCREG += 2; +} + +static void +decode_LDSTpmod_0 (bu16 iw0) +{ + /* LDSTpmod + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 0 | 0 | 0 |.W.|.aop...|.reg.......|.idx.......|.ptr.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int aop = ((iw0 >> 9) & 0x3); + int idx = ((iw0 >> 3) & 0x7); + int ptr = ((iw0 >> 0) & 0x7); + int reg = ((iw0 >> 6) & 0x7); + int W = ((iw0 >> 11) & 0x1); + bu32 addr, val; + + if (aop == 1 && W == 0 && idx == ptr) + { + /* dregs_lo = W[pregs] */ + addr = PREG (ptr); + val = get_word (saved_state.memory, addr); + STORE (DREG (reg), (DREG (reg) & 0xFFFF0000) | val); + } + else if (aop == 2 && W == 0 && idx == ptr) + { + /* dregs_hi = W[pregs] */ + addr = PREG (ptr); + val = get_word (saved_state.memory, addr); + STORE (DREG (reg), (DREG (reg) & 0xFFFF) | (val << 16)); + } + else if (aop == 1 && W == 1 && idx == ptr) + { + /* W[pregs] = dregs_lo */ + addr = PREG (ptr); + put_word (saved_state.memory, addr, DREG (reg)); + } + else if (aop == 2 && W == 1 && idx == ptr) + { + /* W[pregs] = dregs_hi */ + addr = PREG (ptr); + put_word (saved_state.memory, addr, DREG (reg) >> 16); + } + else if (aop == 0 && W == 0) + { + /* dregs = [pregs ++ pregs] */ + addr = PREG (ptr); + val = get_long (saved_state.memory, addr); + STORE (DREG (reg), val); + STORE (PREG (ptr), addr + PREG (idx)); + } + else if (aop == 1 && W == 0) + { + /* dregs_lo = W[pregs ++ pregs] */ + addr = PREG (ptr); + val = get_word (saved_state.memory, addr); + STORE (DREG (reg), (DREG (reg) & 0xFFFF0000) | val); + STORE (PREG (ptr), addr + PREG (idx)); + } + else if (aop == 2 && W == 0) + { + /* dregs_hi = W[pregs ++ pregs] */ + addr = PREG (ptr); + val = get_word (saved_state.memory, addr); + STORE (DREG (reg), (DREG (reg) & 0xFFFF) | (val << 16)); + STORE (PREG (ptr), addr + PREG (idx)); + } + else if (aop == 3 && W == 0) + { + /* dregs = W[pregs ++ pregs] (Z) */ + addr = PREG (ptr); + val = get_word (saved_state.memory, addr); + STORE (DREG (reg), val); + STORE (PREG (ptr), addr + PREG (idx)); + } + else if (aop == 3 && W == 1) + { + /* dregs = W [ pregs ++ pregs ] (X) */ + addr = PREG (ptr); + val = get_word (saved_state.memory, addr); + STORE (DREG (reg), (bs32) (bs16) val); + STORE (PREG (ptr), addr + PREG (idx)); + } + else if (aop == 0 && W == 1) + { + /* [pregs ++ pregs] = dregs */ + addr = PREG (ptr); + put_long (saved_state.memory, addr, DREG (reg)); + STORE (PREG (ptr), addr + PREG (idx)); + } + else if (aop == 1 && W == 1) + { + /* W[pregs ++ pregs] = dregs_lo */ + addr = PREG (ptr); + put_word (saved_state.memory, addr, DREG (reg)); + STORE (PREG (ptr), addr + PREG (idx)); + } + else if (aop == 2 && W == 1) + { + /* W[pregs ++ pregs] = dregs_hi */ + addr = PREG (ptr); + put_word (saved_state.memory, addr, DREG (reg) >> 16); + STORE (PREG (ptr), addr + PREG (idx)); + } + else + illegal_instruction (); + + PCREG += 2; +} + +static void +decode_dagMODim_0 (bu16 iw0) +{ + /* dagMODim + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |.br| 1 | 1 |.op|.m.....|.i.....| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int i = ((iw0 >> 0) & 0x3); + int br = ((iw0 >> 7) & 0x1); + int m = ((iw0 >> 2) & 0x3); + int op = ((iw0 >> 4) & 0x1); + + if (op == 0 && br == 1) + unhandled_instruction ("iregs += mregs (BREV)"); + else if (op == 0) + unhandled_instruction ("iregs += mregs"); + else if (op == 1) + unhandled_instruction ("iregs -= mregs"); + else + illegal_instruction (); + PCREG += 2; +} + +static void +decode_dagMODik_0 (bu16 iw0) +{ + /* dagMODik + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |.op....|.i.....| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int i = ((iw0 >> 0) & 0x3); + int op = ((iw0 >> 2) & 0x3); + + if (op == 0) + unhandled_instruction ("iregs += 2"); + else if (op == 1) + unhandled_instruction ("iregs -= 2"); + else if (op == 2) + unhandled_instruction ("iregs += 4"); + else if (op == 3) + unhandled_instruction ("iregs -= 4"); + else + illegal_instruction (); + PCREG += 2; +} + +static void +decode_dspLDST_0 (bu16 iw0) +{ + /* dspLDST + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 0 | 0 | 1 | 1 | 1 |.W.|.aop...|.m.....|.i.....|.reg.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int aop = ((iw0 >> 7) & 0x3); + int i = ((iw0 >> 3) & 0x3); + int m = ((iw0 >> 5) & 0x3); + int reg = ((iw0 >> 0) & 0x7); + int W = ((iw0 >> 9) & 0x1); + bu32 addr; + + if (aop == 0 && W == 0 && m == 0) + { + /* dregs = [iregs++] */ + addr = IREG (i); + STORE (IREG (i), addr + 4); + STORE (DREG (reg), get_long (saved_state.memory, addr)); + } + else if (aop == 0 && W == 0 && m == 1) + { + /* dregs_lo = W[iregs++] */ + addr = IREG (i); + STORE (IREG (i), addr + 2); + STORE (DREG (reg), (DREG (reg) & 0xFFFF0000) | get_word (saved_state.memory, addr)); + } + else if (aop == 0 && W == 0 && m == 2) + { + /* dregs_hi = W[iregs++] */ + addr = IREG (i); + STORE (IREG (i), addr + 2); + STORE (DREG (reg), (DREG (reg) & 0xFFFF) | (get_word (saved_state.memory, addr) << 16)); + } + else if (aop == 1 && W == 0 && m == 0) + { + /* dregs = [iregs--] */ + addr = IREG (i); + STORE (IREG (i), addr - 4); + STORE (DREG (reg), get_long (saved_state.memory, addr)); + } + else if (aop == 1 && W == 0 && m == 1) + { + /* dregs_lo = W[iregs--] */ + addr = IREG (i); + STORE (IREG (i), addr - 2); + STORE (DREG (reg), (DREG (reg) & 0xFFFF0000) | get_word (saved_state.memory, addr)); + } + else if (aop == 1 && W == 0 && m == 2) + { + /* dregs_hi = W[iregs--] */ + addr = IREG (i); + STORE (IREG (i), addr - 2); + STORE (DREG (reg), (DREG (reg) & 0xFFFF) | (get_word (saved_state.memory, addr) << 16)); + } + else if (aop == 2 && W == 0 && m == 0) + { + /* dregs = [iregs] */ + addr = IREG (i); + STORE (DREG (reg), get_long (saved_state.memory, addr)); + } + else if (aop == 2 && W == 0 && m == 1) + { + /* dregs_lo = W[iregs] */ + addr = IREG (i); + STORE (DREG (reg), (DREG (reg) & 0xFFFF0000) | get_word (saved_state.memory, addr)); + } + else if (aop == 2 && W == 0 && m == 2) + { + /* dregs_hi = W[iregs] */ + addr = IREG (i); + STORE (DREG (reg), (DREG (reg) & 0xFFFF) | (get_word (saved_state.memory, addr) << 16)); + } + else if (aop == 0 && W == 1 && m == 0) + { + /* [iregs++] = dregs */ + addr = IREG (i); + STORE (IREG (i), addr + 4); + put_long (saved_state.memory, addr, DREG (reg)); + } + else if (aop == 0 && W == 1 && m == 1) + { + /* W[iregs++] = dregs_lo */ + addr = IREG (i); + STORE (IREG (i), addr + 2); + put_word (saved_state.memory, addr, DREG (reg)); + } + else if (aop == 0 && W == 1 && m == 2) + { + /* W[iregs++] = dregs_hi */ + addr = IREG (i); + STORE (IREG (i), addr + 2); + put_word (saved_state.memory, addr, DREG (reg) >> 16); + } + else if (aop == 1 && W == 1 && m == 0) + { + /* [iregs--] = dregs */ + addr = IREG (i); + STORE (IREG (i), addr - 4); + put_long (saved_state.memory, addr, DREG (reg)); + } + else if (aop == 1 && W == 1 && m == 1) + { + /* W[iregs--] = dregs_lo */ + addr = IREG (i); + STORE (IREG (i), addr - 2); + put_word (saved_state.memory, addr, DREG (reg)); + } + else if (aop == 1 && W == 1 && m == 2) + { + /* W[iregs--] = dregs_hi */ + addr = IREG (i); + STORE (IREG (i), addr - 2); + put_word (saved_state.memory, addr, DREG (reg) >> 16); + } + else if (aop == 2 && W == 1 && m == 0) + { + /* [iregs] = dregs */ + addr = IREG (i); + put_long (saved_state.memory, addr, DREG (reg)); + } + else if (aop == 2 && W == 1 && m == 1) + { + /* W[iregs] = dregs_lo */ + addr = IREG (i); + put_word (saved_state.memory, addr, DREG (reg)); + } + else if (aop == 2 && W == 1 && m == 2) + { + /* W[iregs] = dregs_hi */ + addr = IREG (i); + put_word (saved_state.memory, addr, DREG (reg) >> 16); + } + else if (aop == 3 && W == 0) + { + /* dregs = [iregs ++ mregs] */ + addr = IREG (i); + STORE (IREG (i), addr + MREG (m)); + STORE (DREG (reg), get_long (saved_state.memory, addr)); + } + else if (aop == 3 && W == 1) + { + /* [iregs ++ mregs] = dregs */ + addr = IREG (i); + STORE (IREG (i), addr + MREG (m)); + put_long (saved_state.memory, addr, DREG (reg)); + } + else + illegal_instruction (); + + PCREG += 2; +} + +static void +decode_LDST_0 (bu16 iw0) +{ + /* LDST + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 0 | 0 | 1 |.sz....|.W.|.aop...|.Z.|.ptr.......|.reg.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int aop = ((iw0 >> 7) & 0x3); + int Z = ((iw0 >> 6) & 0x1); + int sz = ((iw0 >> 10) & 0x3); + int reg = ((iw0 >> 0) & 0x7); + int ptr = ((iw0 >> 3) & 0x7); + int W = ((iw0 >> 9) & 0x1); + + if (aop == 3) + illegal_instruction (); + + if (W == 0) + { + if (aop != 2 && sz == 0 && Z == 1 + && ptr == reg) + illegal_instruction (); + + if (sz == 0 && Z == 0) + /* dregs = [pregs] */ + DREG (reg) = get_long (saved_state.memory, PREG (ptr)); + else if (sz == 0 && Z == 1) + /* pregs = [pregs] */ + PREG (reg) = get_long (saved_state.memory, PREG (ptr)); + else if (sz == 1 && Z == 0) + /* dregs = W[pregs] (z) */ + DREG (reg) = get_word (saved_state.memory, PREG (ptr)); + else if (sz == 1 && Z == 1) + /* dregs = W[pregs] (X) */ + DREG (reg) = (bs32) (bs16) get_word (saved_state.memory, PREG (ptr)); + else if (sz == 2 && Z == 0) + /* dregs = B[pregs] (Z) */ + DREG (reg) = get_byte (saved_state.memory, PREG (ptr)); + else if (sz == 2 && Z == 1) + /* dregs = B[pregs] (X) */ + DREG (reg) = (bs32) (bs8) get_byte (saved_state.memory, PREG (ptr)); + + if (aop == 0) + PREG (ptr) += sz == 0 ? 4 : sz == 1 ? 2 : 1; + if (aop == 1) + PREG (ptr) -= sz == 0 ? 4 : sz == 1 ? 2 : 1; + } + else + { + if (sz != 0 && Z == 1) + illegal_instruction (); + + if (sz == 0 && Z == 0) + /* [pregs] = dregs */ + put_long (saved_state.memory, PREG (ptr), DREG (reg)); + else if (sz == 0 && Z == 1) + /* [pregs] = pregs */ + put_long (saved_state.memory, PREG (ptr), PREG (reg)); + else if (sz == 1 && Z == 0) + /* W[pregs] = dregs */ + put_word (saved_state.memory, PREG (ptr), DREG (reg)); + else if (sz == 2 && Z == 0) + /* B[pregs] = dregs */ + put_byte (saved_state.memory, PREG (ptr), DREG (reg)); + + if (aop == 0) + PREG (ptr) += sz == 0 ? 4 : sz == 1 ? 2 : 1; + if (aop == 1) + PREG (ptr) -= sz == 0 ? 4 : sz == 1 ? 2 : 1; + } + + PCREG += 2; +} + +static void +decode_LDSTiiFP_0 (bu16 iw0) +{ + /* LDSTiiFP + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 0 | 1 | 1 | 1 | 0 |.W.|.offset............|.reg...........| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int reg = ((iw0 >> 0) & 0xf); + int offset = ((iw0 >> 4) & 0x1f); + int W = ((iw0 >> 9) & 0x1); + bu32 ea = PREG (7) + negimm5s4 (offset); + + if (W == 0) + DPREG (reg) = get_long (saved_state.memory, ea); + else + put_long (saved_state.memory, ea, DPREG (reg)); + PCREG += 2; +} + +static void +decode_LDSTii_0 (bu16 iw0) +{ + /* LDSTii + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 0 | 1 |.W.|.op....|.offset........|.ptr.......|.reg.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int reg = ((iw0 >> 0) & 0x7); + int ptr = ((iw0 >> 3) & 0x7); + int offset = ((iw0 >> 6) & 0xf); + int op = ((iw0 >> 10) & 0x3); + int W = ((iw0 >> 12) & 0x1); + bu32 ea = PREG (ptr) + (op == 0 || op == 3 ? uimm4s4 (offset) + : uimm4s2 (offset)); + + if (W == 1 && op == 2) + illegal_instruction (); + + if (W == 0) + { + if (op == 0) + /* dregs = [pregs + uimm4s4] */ + DREG (reg) = get_long (saved_state.memory, ea); + else if (op == 1) + /* dregs = W[pregs + uimm4s2] (Z) */ + DREG (reg) = get_word (saved_state.memory, ea); + else if (op == 2) + /* dregs = W[pregs + uimm4s2] (X) */ + DREG (reg) = (bs32) (bs16) get_word (saved_state.memory, ea); + else if (op == 3) + /* pregs = [pregs + uimm4s4] */ + PREG (reg) = get_long (saved_state.memory, ea); + } + else + { + if (op == 0) + /* [pregs + uimm4s4] = dregs */ + put_long (saved_state.memory, ea, DREG (reg)); + else if (op == 1) + /* W[pregs + uimm4s2] = dregs */ + put_word (saved_state.memory, ea, DREG (reg)); + else if (op == 3) + /* [pregs + uimm4s4] = pregs */ + put_long (saved_state.memory, ea, PREG (reg)); + } + PCREG += 2; +} + +static void +decode_LoopSetup_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* LoopSetup + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |.rop...|.c.|.soffset.......| + |.reg...........| - | - |.eoffset...............................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int rop = ((iw0 >> 5) & 0x3); + int soffset = ((iw0 >> 0) & 0xf); + int c = ((iw0 >> 4) & 0x1); + int eoffset = ((iw1 >> 0) & 0x3ff); + int reg = ((iw1 >> 12) & 0xf); + + if (rop == 0) + { + /* LSETUP (pcrel4, lppcrel10) counters */ + saved_state.lt[c] = PCREG + pcrel4 (soffset); + saved_state.lb[c] = PCREG + lppcrel10 (eoffset); + } + else if (rop == 1) + { + /* LSETUP (pcrel4, lppcrel10) counters = pregs */ + saved_state.lt[c] = PCREG + pcrel4 (soffset); + saved_state.lb[c] = PCREG + lppcrel10 (eoffset); + saved_state.lc[c] = PREG (reg); + } + else if (rop == 3) + { + /* LSETUP (pcrel4, lppcrel10) counters = pregs >> 1 */ + saved_state.lt[c] = PCREG + pcrel4 (soffset); + saved_state.lb[c] = PCREG + lppcrel10 (eoffset); + saved_state.lc[c] = PREG (reg) >> 1; + } + else + illegal_instruction (); + + PCREG += 4; +} + +static void +decode_LDIMMhalf_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* LDIMMhalf + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |.Z.|.H.|.S.|.grp...|.reg.......| + |.hword.........................................................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int H = ((iw0 >> 6) & 0x1); + int grp = ((iw0 >> 3) & 0x3); + int Z = ((iw0 >> 7) & 0x1); + int S = ((iw0 >> 5) & 0x1); + int hword = ((iw1 >> 0) & 0xffff); + int reg = ((iw0 >> 0) & 0x7); + + if (H == 0 && S == 1 && Z == 0) + { + bu32 *pval = get_allreg (grp, reg); + /* regs = imm16 (x) */ + *pval = imm16 (hword); + } + else if (H == 0 && S == 0 && Z == 1) + { + bu32 *pval = get_allreg (grp, reg); + /* regs = luimm16 (Z) */ + *pval = luimm16 (hword); + } + else if (H == 0 && S == 0 && Z == 0) + { + bu32 *pval = get_allreg (grp, reg); + /* regs_lo = luimm16 */ + *pval &= 0xFFFF0000; + *pval |= luimm16 (hword); + } + else if (H == 1 && S == 0 && Z == 0) + { + bu32 *pval = get_allreg (grp, reg); + /* regs_hi = huimm16 */ + *pval &= 0xFFFF; + *pval |= luimm16 (hword) << 16; + } + else + illegal_instruction (); + PCREG += 4; +} + +static void +decode_CALLa_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* CALLa + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 1 | 0 | 0 | 0 | 1 |.S.|.msw...........................| + |.lsw...........................................................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int S = ((iw0 >> 8) & 0x1); + int lsw = ((iw1 >> 0) & 0xffff); + int msw = ((iw0 >> 0) & 0xff); + + if (S == 1) + /* CALL pcrel24 */ + saved_state.rets = PCREG + 4; + /* JUMP.L pcrel24 */ + PCREG += pcrel24 (((msw) << 16) | (lsw)); +} + +static void +decode_LDSTidxI_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* LDSTidxI + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 1 | 0 | 0 | 1 |.W.|.Z.|.sz....|.ptr.......|.reg.......| + |.offset........................................................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int Z = ((iw0 >> 8) & 0x1); + int sz = ((iw0 >> 6) & 0x3); + int reg = ((iw0 >> 0) & 0x7); + int ptr = ((iw0 >> 3) & 0x7); + int offset = ((iw1 >> 0) & 0xffff); + int W = ((iw0 >> 9) & 0x1); + + if (sz == 3) + illegal_instruction (); + + if (W == 0) + { + if (sz == 0 && Z == 0) + /* dregs = [pregs + imm16s4] */ + DREG (reg) = get_long (saved_state.memory, PREG (ptr) + imm16s4 (offset)); + else if (sz == 0 && Z == 1) + /* pregs = [pregs + imm16s4] */ + PREG (reg) = get_long (saved_state.memory, PREG (ptr) + imm16s4 (offset)); + else if (sz == 1 && Z == 0) + /* dregs = W[pregs + imm16s2] (Z) */ + DREG (reg) = get_word (saved_state.memory, PREG (ptr) + imm16s2 (offset)); + else if (sz == 1 && Z == 1) + /* dregs = W[pregs + imm16s2] (X) */ + DREG (reg) = (bs32) (bs16) get_word (saved_state.memory, PREG (ptr) + imm16s2 (offset)); + else if (sz == 2 && Z == 0) + /* dregs = B[pregs + imm16] (Z) */ + DREG (reg) = get_byte (saved_state.memory, PREG (ptr) + imm16 (offset)); + else if (sz == 2 && Z == 1) + /* dregs = B[pregs + imm16] (X) */ + DREG (reg) = (bs32) (bs8) get_byte (saved_state.memory, PREG (ptr) + imm16 (offset)); + } + else + { + if (sz != 0 && Z != 0) + illegal_instruction (); + + if (sz == 0 && Z == 0) + /* [pregs + imm16s4] = dregs */ + put_long (saved_state.memory, PREG (ptr) + imm16s4 (offset), DREG (reg)); + else if (sz == 0 && Z == 1) + /* [pregs + imm16s4] = pregs */ + put_long (saved_state.memory, PREG (ptr) + imm16s4 (offset), PREG (reg)); + else if (sz == 1 && Z == 0) + /* W[pregs + imm16s2] = dregs */ + put_word (saved_state.memory, PREG (ptr) + imm16s2 (offset), DREG (reg)); + else if (sz == 2 && Z == 0) + /* B[pregs + imm16] = dregs */ + put_byte (saved_state.memory, PREG (ptr) + imm16 (offset), DREG (reg)); + } + PCREG += 4; +} + +static void +decode_linkage_0 (bu16 iw0, bu16 iw1) +{ + /* linkage + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |.R.| + |.framesize.....................................................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int R = ((iw0 >> 0) & 0x1); + int framesize = ((iw1 >> 0) & 0xffff); + + if (R == 0) + { + bu32 sp = PREG (6); + /* LINK uimm16s4 */ + sp -= 4; + put_long (saved_state.memory, sp, saved_state.rets); + sp -= 4; + put_long (saved_state.memory, sp, PREG (7)); + PREG (7) = sp; + sp -= uimm16s4 (framesize); + PREG (6) = sp; + } + else + { + /* Restore SP from FP. */ + bu32 sp = PREG (7); + /* UNLINK */ + PREG (7) = get_long (saved_state.memory, sp); + sp += 4; + saved_state.rets = get_long (saved_state.memory, sp); + sp += 4; + PREG (6) = sp; + } + PCREG += 4; +} + +static void +decode_dsp32mac_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* dsp32mac + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 0 | 0 |.M.| 0 | 0 |.mmod..........|.MM|.P.|.w1|.op1...| + |.h01|.h11|.w0|.op0...|.h00|.h10|.dst.......|.src0......|.src1......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int op1 = ((iw0 >> 0) & 0x3); + int w1 = ((iw0 >> 2) & 0x1); + int P = ((iw0 >> 3) & 0x1); + int MM = ((iw0 >> 4) & 0x1); + int mmod = ((iw0 >> 5) & 0xf); + int M = ((iw0 >> 11) & 0x1); + + int w0 = ((iw1 >> 13) & 0x1); + int src1 = ((iw1 >> 0) & 0x7); + int src0 = ((iw1 >> 3) & 0x7); + int dst = ((iw1 >> 6) & 0x7); + int h10 = ((iw1 >> 9) & 0x1); + int h00 = ((iw1 >> 10) & 0x1); + int op0 = ((iw1 >> 11) & 0x3); + int h11 = ((iw1 >> 14) & 0x1); + int h01 = ((iw1 >> 15) & 0x1); + + bu32 res0, res1; + + if (w0 == 0 && w1 == 0 && op1 == 3 && op0 == 3) + illegal_instruction (); + + if (op1 == 3 && MM) + illegal_instruction (); + + if (((1 << mmod) & (P ? 0x313 : 0x1b57)) == 0) + illegal_instruction (); + + if (w1 == 1 || op1 != 3) + res1 = decode_macfunc (1, op1, h01, h11, src0, src1, mmod, MM, P); + + if (w0 == 1 || op0 != 3) + res0 = decode_macfunc (0, op0, h00, h10, src0, src1, mmod, 0, P); + + if (w0) + { + if (P) + DREG (dst) = res0; + else + { + if (res0 & 0xffff0000) + abort (); + DREG (dst) = (DREG (dst) & 0xFFFF0000) | res0; + } + } + + if (w1) + { + if (P) + DREG (dst + 1) = res1; + else + { + if (res1 & 0xffff0000) + abort (); + DREG (dst) = (DREG (dst) & 0xFFFF) | (res1 << 16); + } + } + + PCREG += 4; +} + +static void +decode_dsp32mult_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* dsp32mult + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 0 | 0 |.M.| 0 | 1 |.mmod..........|.MM|.P.|.w1|.op1...| + |.h01|.h11|.w0|.op0...|.h00|.h10|.dst.......|.src0......|.src1......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int op1 = ((iw0 >> 0) & 0x3); + int w1 = ((iw0 >> 2) & 0x1); + int P = ((iw0 >> 3) & 0x1); + int MM = ((iw0 >> 4) & 0x1); + int mmod = ((iw0 >> 5) & 0xf); + int M = ((iw0 >> 11) & 0x1); + + int src1 = ((iw1 >> 0) & 0x7); + int src0 = ((iw1 >> 3) & 0x7); + int dst = ((iw1 >> 6) & 0x7); + int h10 = ((iw1 >> 9) & 0x1); + int h00 = ((iw1 >> 10) & 0x1); + int op0 = ((iw1 >> 11) & 0x3); + int w0 = ((iw1 >> 13) & 0x1); + int h01 = ((iw1 >> 15) & 0x1); + int h11 = ((iw1 >> 14) & 0x1); + + bu32 res0, res1; + + if (w1 == 0 && w0 == 0) + illegal_instruction (); + if (((1 << mmod) & (P ? 0x313 : 0x1b57)) == 0) + illegal_instruction (); + + if (w1) + { + bu64 r = decode_multfunc (h01, h11, src0, src1, mmod, MM); + res1 = extract_mult (r, mmod, P); + } + + if (w0) + { + bu64 r = decode_multfunc (h00, h10, src0, src1, mmod, 0); + res0 = extract_mult (r, mmod, P); + } + + if (w0) + { + if (P) + DREG (dst) = res0; + else + { + if (res0 & 0xFFFF0000) + abort (); + DREG (dst) = (DREG (dst) & 0xFFFF0000) | res0; + } + } + + if (w1) + { + if (P) + DREG (dst + 1) = res1; + else + { + if (res1 & 0xFFFF0000) + abort (); + DREG (dst) = (DREG (dst) & 0xFFFF) | (res1 << 16); + } + } + + PCREG += 4; +} + +static void +decode_dsp32alu_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* dsp32alu + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 0 | 0 |.M.| 1 | 0 | - | - | - |.HL|.aopcde............| + |.aop...|.s.|.x.|.dst0......|.dst1......|.src0......|.src1......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int aop = ((iw1 >> 14) & 0x3); + int s = ((iw1 >> 13) & 0x1); + int HL = ((iw0 >> 5) & 0x1); + int x = ((iw1 >> 12) & 0x1); + int src0 = ((iw1 >> 3) & 0x7); + int src1 = ((iw1 >> 0) & 0x7); + int dst0 = ((iw1 >> 9) & 0x7); + int aopcde = ((iw0 >> 0) & 0x1f); + int dst1 = ((iw1 >> 6) & 0x7); + int M = ((iw0 >> 11) & 0x1); + + if (aop == 0 && aopcde == 9 && HL == 0 && s == 0) + unhandled_instruction ("A0.L = dregs_lo"); + else if (aop == 2 && aopcde == 9 && HL == 1 && s == 0) + unhandled_instruction ("A1.H = dregs_hi"); + else if (aop == 2 && aopcde == 9 && HL == 0 && s == 0) + unhandled_instruction ("A1.L = dregs_lo"); + else if (aop == 0 && aopcde == 9 && HL == 1 && s == 0) + unhandled_instruction ("A0.H = dregs_hi"); + else if (x == 1 && HL == 1 && aop == 3 && aopcde == 5) + unhandled_instruction ("dregs_hi = dregs - dregs (RND20)"); + else if (x == 1 && HL == 1 && aop == 2 && aopcde == 5) + unhandled_instruction ("dregs_hi = dregs + dregs (RND20)"); + else if (x == 0 && HL == 0 && aop == 1 && aopcde == 5) + unhandled_instruction ("dregs_lo = dregs - dregs (RND12)"); + else if (x == 0 && HL == 0 && aop == 0 && aopcde == 5) + unhandled_instruction ("dregs_lo = dregs + dregs (RND12)"); + else if (x == 1 && HL == 0 && aop == 3 && aopcde == 5) + unhandled_instruction ("dregs_lo = dregs - dregs (RND20)"); + else if (x == 0 && HL == 1 && aop == 0 && aopcde == 5) + unhandled_instruction ("dregs_hi = dregs + dregs (RND12)"); + else if (x == 1 && HL == 0 && aop == 2 && aopcde == 5) + unhandled_instruction ("dregs_lo = dregs + dregs (RND20)"); + else if (x == 0 && HL == 1 && aop == 1 && aopcde == 5) + unhandled_instruction ("dregs_hi = dregs - dregs (RND12)"); + else if (HL == 1 && aop == 0 && aopcde == 2) + unhandled_instruction ("dregs_hi = dregs_lo + dregs_lo amod1"); + else if (HL == 1 && aop == 1 && aopcde == 2) + unhandled_instruction ("dregs_hi = dregs_lo + dregs_hi amod1"); + else if (HL == 1 && aop == 2 && aopcde == 2) + unhandled_instruction ("dregs_hi = dregs_hi + dregs_lo amod1"); + else if (HL == 1 && aop == 3 && aopcde == 2) + unhandled_instruction ("dregs_hi = dregs_hi + dregs_hi amod1"); + else if (HL == 0 && aop == 0 && aopcde == 3) + unhandled_instruction ("dregs_lo = dregs_lo - dregs_lo amod1"); + else if (HL == 0 && aop == 1 && aopcde == 3) + unhandled_instruction ("dregs_lo = dregs_lo - dregs_hi amod1"); + else if (HL == 0 && aop == 3 && aopcde == 2) + unhandled_instruction ("dregs_lo = dregs_hi + dregs_hi amod1"); + else if (HL == 1 && aop == 0 && aopcde == 3) + unhandled_instruction ("dregs_hi = dregs_lo - dregs_lo amod1"); + else if (HL == 1 && aop == 1 && aopcde == 3) + unhandled_instruction ("dregs_hi = dregs_lo - dregs_hi amod1"); + else if (HL == 1 && aop == 2 && aopcde == 3) + unhandled_instruction ("dregs_hi = dregs_hi - dregs_lo amod1"); + else if (HL == 1 && aop == 3 && aopcde == 3) + unhandled_instruction ("dregs_hi = dregs_hi - dregs_hi amod1"); + else if (HL == 0 && aop == 2 && aopcde == 2) + unhandled_instruction ("dregs_lo = dregs_hi + dregs_lo amod1"); + else if (HL == 0 && aop == 1 && aopcde == 2) + unhandled_instruction ("dregs_lo = dregs_lo + dregs_hi amod1"); + else if (HL == 0 && aop == 2 && aopcde == 3) + unhandled_instruction ("dregs_lo = dregs_hi - dregs_lo amod1"); + else if (HL == 0 && aop == 3 && aopcde == 3) + unhandled_instruction ("dregs_lo = dregs_hi - dregs_hi amod1"); + else if (HL == 0 && aop == 0 && aopcde == 2) + unhandled_instruction ("dregs_lo = dregs_lo + dregs_lo amod1"); + else if (aop == 0 && aopcde == 9 && s == 1) + unhandled_instruction ("A0 = dregs"); + else if (aop == 3 && aopcde == 11 && s == 0) + unhandled_instruction ("A0 -= A1"); + else if (aop == 3 && aopcde == 11 && s == 1) + unhandled_instruction ("A0 -= A1 (W32)"); + else if (aop == 3 && aopcde == 22 && HL == 1) + unhandled_instruction ("dregs = BYTEOP2M (dregs_pair, dregs_pair) (TH,R)"); + else if (aop == 3 && aopcde == 22 && HL == 0) + unhandled_instruction ("dregs = BYTEOP2M (dregs_pair, dregs_pair) (TL,R)"); + else if (aop == 2 && aopcde == 22 && HL == 1) + unhandled_instruction ("dregs = BYTEOP2M (dregs_pair, dregs_pair) (RNDH,R)"); + else if (aop == 2 && aopcde == 22 && HL == 0) + unhandled_instruction ("dregs = BYTEOP2M (dregs_pair, dregs_pair) (RNDL,R)"); + else if (aop == 1 && aopcde == 22 && HL == 1) + unhandled_instruction ("dregs = BYTEOP2P (dregs_pair, dregs_pair) (TH ,R)"); + else if (aop == 1 && aopcde == 22 && HL == 0) + unhandled_instruction ("dregs = BYTEOP2P (dregs_pair, dregs_pair) (TL ,R)"); + else if (aop == 0 && aopcde == 22 && HL == 1) + unhandled_instruction ("dregs = BYTEOP2P (dregs_pair, dregs_pair) (RNDH,R)"); + else if (aop == 0 && aopcde == 22 && HL == 0) + unhandled_instruction ("dregs = BYTEOP2P (dregs_pair, dregs_pair) (RNDL,aligndir)"); + else if (aop == 0 && s == 0 && aopcde == 8) + /* A0 = 0 */ + saved_state.a0 = 0; + else if (aop == 0 && s == 1 && aopcde == 8) + unhandled_instruction ("A0 = A0 (S)"); + else if (aop == 1 && s == 0 && aopcde == 8) + /* A1 = 0 */ + saved_state.a1 = 0; + else if (aop == 1 && s == 1 && aopcde == 8) + unhandled_instruction ("A1 = A1 (S)"); + else if (aop == 2 && s == 0 && aopcde == 8) + /* A1 = A0 = 0 */ + saved_state.a1 = saved_state.a0 = 0; + else if (aop == 2 && s == 1 && aopcde == 8) + unhandled_instruction ("A1 = A1 (S) , A0 = A0 (S)"); + else if (aop == 3 && s == 0 && aopcde == 8) + unhandled_instruction ("A0 = A1"); + else if (aop == 3 && s == 1 && aopcde == 8) + unhandled_instruction ("A1 = A0"); + else if (aop == 1 && aopcde == 9 && s == 0) + unhandled_instruction ("A0.x = dregs_lo"); + else if (aop == 1 && HL == 0 && aopcde == 11) + unhandled_instruction ("dregs_lo = (A0 += A1)"); + else if (aop == 3 && HL == 0 && aopcde == 16) + unhandled_instruction ("A1 = ABS A1, A0 = ABS A0"); + else if (aop == 0 && aopcde == 23 && HL == 1) + unhandled_instruction ("dregs = BYTEOP3P (dregs_pair, dregs_pair) (HI,R)"); + else if (aop == 3 && aopcde == 9 && s == 0) + unhandled_instruction ("A1.x = dregs_lo"); + else if (aop == 1 && HL == 1 && aopcde == 16) + unhandled_instruction ("A1 = ABS A1"); + else if (aop == 0 && HL == 1 && aopcde == 16) + unhandled_instruction ("A1 = ABS A0"); + else if (aop == 2 && aopcde == 9 && s == 1) + unhandled_instruction ("A1 = dregs"); + else if (HL == 0 && aop == 3 && aopcde == 12) + unhandled_instruction ("dregs_lo = dregs (RND)"); + else if (aop == 1 && HL == 0 && aopcde == 16) + unhandled_instruction ("A0 = ABS A1"); + else if (aop == 0 && HL == 0 && aopcde == 16) + unhandled_instruction ("A0 = ABS A0"); + else if (aop == 3 && HL == 0 && aopcde == 15) + unhandled_instruction ("dregs = - dregs (V)"); + else if (aop == 1 && HL == 1 && aopcde == 11) + unhandled_instruction ("dregs_hi = (A0 += A1)"); + else if (aop == 2 && aopcde == 11 && s == 0) + unhandled_instruction ("A0 += A1"); + else if (aop == 2 && aopcde == 11 && s == 1) + unhandled_instruction ("A0 += A1 (W32)"); + else if (aop == 3 && HL == 0 && aopcde == 14) + unhandled_instruction ("A1 = - A1 , A0 = - A0"); + else if (HL == 1 && aop == 3 && aopcde == 12) + unhandled_instruction ("dregs_hi = dregs (RND)"); + else if (aop == 0 && aopcde == 23 && HL == 0) + unhandled_instruction ("dregs = BYTEOP3P (dregs_pair, dregs_pair) (LO,R)"); + else if (aop == 0 && HL == 0 && aopcde == 14) + unhandled_instruction ("A0 = - A0"); + else if (aop == 1 && HL == 0 && aopcde == 14) + unhandled_instruction ("A0 = - A1"); + else if (aop == 0 && HL == 1 && aopcde == 14) + unhandled_instruction ("A1 = - A0"); + else if (aop == 1 && HL == 1 && aopcde == 14) + unhandled_instruction ("A1 = - A1"); + else if (aop == 0 && aopcde == 12) + unhandled_instruction ("dregs_hi=dregs_lo=SIGN(dregs_hi)*dregs_hi + SIGN(dregs_lo)*dregs_lo)"); + else if (aop == 2 && aopcde == 0) + unhandled_instruction ("dregs = dregs -|+ dregs amod0"); + else if (aop == 1 && aopcde == 12) + unhandled_instruction ("dregs = A1.L + A1.H , dregs = A0.L + A0.H"); + else if (aop == 2 && aopcde == 4) + unhandled_instruction ("dregs = dregs + dregs , dregs = dregs - dregs amod1"); + else if (HL == 0 && aopcde == 1) + unhandled_instruction ("dregs = dregs +|+ dregs , dregs = dregs -|- dregs (amod0, amod2)"); + else if (aop == 0 && aopcde == 11) + unhandled_instruction ("dregs = (A0 += A1)"); + else if (aop == 0 && aopcde == 10) + unhandled_instruction ("dregs_lo = A0.x"); + else if (aop == 1 && aopcde == 10) + unhandled_instruction ("dregs_lo = A1.x"); + else if (aop == 1 && aopcde == 0) + unhandled_instruction ("dregs = dregs +|- dregs amod0"); + else if (aop == 3 && aopcde == 0) + unhandled_instruction ("dregs = dregs -|- dregs amod0"); + else if (aop == 1 && aopcde == 4) + unhandled_instruction ("dregs = dregs - dregs amod1"); + else if (aop == 0 && aopcde == 17) + unhandled_instruction ("dregs = A1 + A0, dregs = A1 - A0 amod1"); + else if (aop == 1 && aopcde == 17) + unhandled_instruction ("dregs = A0 + A1, dregs = A0 - A1 amod1"); + else if (aop == 0 && aopcde == 18) + unhandled_instruction ("SAA (dregs_pair, dregs_pair) aligndir"); + else if (aop == 3 && aopcde == 18) + unhandled_instruction ("DISALGNEXCPT"); + else if (aop == 0 && aopcde == 20) + unhandled_instruction ("dregs = BYTEOP1P (dregs_pair, dregs_pair) aligndir"); + else if (aop == 1 && aopcde == 20) + unhandled_instruction ("dregs = BYTEOP1P (dregs_pair, dregs_pair) (T, R)"); + else if (aop == 0 && aopcde == 21) + unhandled_instruction ("(dregs, dregs) = BYTEOP16P (dregs_pair, dregs_pair) aligndir"); + else if (aop == 1 && aopcde == 21) + unhandled_instruction ("(dregs, dregs) = BYTEOP16M (dregs_pair, dregs_pair) aligndir"); + else if (aop == 2 && aopcde == 7) + { + bu32 val = DREG (src0); + /* dregs = ABS dregs */ + if (val >> 31) + val = -val; + /* @@@ The manual is talking about saturation. Check what the hardware + does when it gets 0x80000000. */ + setflags_logical (val); + DREG (dst0) = val; + } + else if (aop == 1 && aopcde == 7) + /* dregs = MIN (dregs, dregs) */ + DREG (dst0) = min32 (DREG (src0), DREG (src1)); + else if (aop == 0 && aopcde == 7) + /* dregs = MAX (dregs, dregs) */ + DREG (dst0) = max32 (DREG (src0), DREG (src1)); + else if (aop == 2 && aopcde == 6) + unhandled_instruction ("dregs = ABS dregs (V)"); + else if (aop == 1 && aopcde == 6) + unhandled_instruction ("dregs = MIN (dregs, dregs) (V)"); + else if (aop == 0 && aopcde == 6) + unhandled_instruction ("dregs = MAX (dregs, dregs) (V)"); + else if (HL == 1 && aopcde == 1) + unhandled_instruction ("dregs = dregs +|- dregs, dregs = dregs -|+ dregs (amod0, amod2)"); + else if (aop == 0 && aopcde == 4) + unhandled_instruction ("dregs = dregs + dregs amod1"); + else if (aop == 0 && aopcde == 0) + unhandled_instruction ("dregs = dregs +|+ dregs amod0"); + else if (aop == 0 && aopcde == 24) + unhandled_instruction ("dregs = BYTEPACK (dregs, dregs)"); + else if (aop == 1 && aopcde == 24) + unhandled_instruction ("(dregs, dregs) = BYTEUNPACK dregs_pair aligndir"); + else if (aopcde == 13) + unhandled_instruction ("(dregs, dregs) = SEARCH dregs (searchmod)"); + else + illegal_instruction (); + PCREG += 4; +} + +static void +decode_dsp32shift_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* dsp32shift + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 0 | 0 |.M.| 1 | 1 | 0 | 0 | - | - |.sopcde............| + |.sop...|.HLs...|.dst0......| - | - | - |.src0......|.src1......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src0 = ((iw1 >> 3) & 0x7); + int src1 = ((iw1 >> 0) & 0x7); + int sop = ((iw1 >> 14) & 0x3); + int dst0 = ((iw1 >> 9) & 0x7); + int M = ((iw0 >> 11) & 0x1); + int sopcde = ((iw0 >> 0) & 0x1f); + int HLs = ((iw1 >> 12) & 0x3); + + if (HLs == 0 && sop == 0 && sopcde == 0) + unhandled_instruction ("dregs_lo = ASHIFT dregs_lo BY dregs_lo"); + else if (HLs == 1 && sop == 0 && sopcde == 0) + unhandled_instruction ("dregs_lo = ASHIFT dregs_hi BY dregs_lo"); + else if (HLs == 2 && sop == 0 && sopcde == 0) + unhandled_instruction ("dregs_hi = ASHIFT dregs_lo BY dregs_lo"); + else if (HLs == 3 && sop == 0 && sopcde == 0) + unhandled_instruction ("dregs_hi = ASHIFT dregs_hi BY dregs_lo"); + else if (HLs == 0 && sop == 1 && sopcde == 0) + unhandled_instruction ("dregs_lo = ASHIFT dregs_lo BY dregs_lo (S)"); + else if (HLs == 1 && sop == 1 && sopcde == 0) + unhandled_instruction ("dregs_lo = ASHIFT dregs_hi BY dregs_lo (S)"); + else if (HLs == 2 && sop == 1 && sopcde == 0) + unhandled_instruction ("dregs_hi = ASHIFT dregs_lo BY dregs_lo (S)"); + else if (HLs == 3 && sop == 1 && sopcde == 0) + unhandled_instruction ("dregs_hi = ASHIFT dregs_hi BY dregs_lo (S)"); + else if (HLs == 0 && sop == 2 && sopcde == 0) + unhandled_instruction ("dregs_lo = LSHIFT dregs_lo BY dregs_lo"); + else if (HLs == 1 && sop == 2 && sopcde == 0) + unhandled_instruction ("dregs_lo = LSHIFT dregs_hi BY dregs_lo"); + else if (HLs == 2 && sop == 2 && sopcde == 0) + unhandled_instruction ("dregs_hi = LSHIFT dregs_lo BY dregs_lo"); + else if (HLs == 3 && sop == 2 && sopcde == 0) + unhandled_instruction ("dregs_hi = LSHIFT dregs_hi BY dregs_lo"); + else if (sop == 2 && sopcde == 3 && HLs == 1) + unhandled_instruction ("A1 = ROT A1 BY dregs_lo"); + else if (sop == 0 && sopcde == 3 && HLs == 0) + unhandled_instruction ("A0 = ASHIFT A0 BY dregs_lo"); + else if (sop == 0 && sopcde == 3 && HLs == 1) + unhandled_instruction ("A1 = ASHIFT A1 BY dregs_lo"); + else if (sop == 1 && sopcde == 3 && HLs == 0) + unhandled_instruction ("A0 = LSHIFT A0 BY dregs_lo"); + else if (sop == 1 && sopcde == 3 && HLs == 1) + unhandled_instruction ("A1 = LSHIFT A1 BY dregs_lo"); + else if (sop == 2 && sopcde == 3 && HLs == 0) + unhandled_instruction ("A0 = ROT A0 BY dregs_lo"); + else if (sop == 1 && sopcde == 1) + unhandled_instruction ("dregs = ASHIFT dregs BY dregs_lo (V,S)"); + else if (sop == 0 && sopcde == 1) + unhandled_instruction ("dregs = ASHIFT dregs BY dregs_lo (V)"); + else if (sop == 0 && sopcde == 2) + unhandled_instruction ("dregs = ASHIFT dregs BY dregs_lo"); + else if (sop == 1 && sopcde == 2) + unhandled_instruction ("dregs = ASHIFT dregs BY dregs_lo (S)"); + else if (sop == 2 && sopcde == 2) + unhandled_instruction ("dregs = SHIFT dregs BY dregs_lo"); + else if (sop == 3 && sopcde == 2) + unhandled_instruction ("dregs = ROT dregs BY dregs_lo"); + else if (sop == 2 && sopcde == 1) + unhandled_instruction ("dregs = SHIFT dregs BY dregs_lo (V)"); + else if (sop == 0 && sopcde == 4) + unhandled_instruction ("dregs = PACK (dregs_lo, dregs_lo)"); + else if (sop == 1 && sopcde == 4) + unhandled_instruction ("dregs = PACK (dregs_lo, dregs_hi)"); + else if (sop == 2 && sopcde == 4) + unhandled_instruction ("dregs = PACK (dregs_hi, dregs_lo)"); + else if (sop == 3 && sopcde == 4) + unhandled_instruction ("dregs = PACK (dregs_hi, dregs_hi)"); + else if (sop == 0 && sopcde == 5) + unhandled_instruction ("dregs_lo = SIGNBITS dregs"); + else if (sop == 1 && sopcde == 5) + unhandled_instruction ("dregs_lo = SIGNBITS dregs_lo"); + else if (sop == 2 && sopcde == 5) + unhandled_instruction ("dregs_lo = SIGNBITS dregs_hi"); + else if (sop == 0 && sopcde == 6) + unhandled_instruction ("dregs_lo = SIGNBITS A0"); + else if (sop == 1 && sopcde == 6) + unhandled_instruction ("dregs_lo = SIGNBITS A1"); + else if (sop == 3 && sopcde == 6) + unhandled_instruction ("dregs_lo = ONES dregs"); + else if (sop == 0 && sopcde == 7) + unhandled_instruction ("dregs_lo = EXPADJ (dregs, dregs_lo)"); + else if (sop == 1 && sopcde == 7) + unhandled_instruction ("dregs_lo = EXPADJ (dregs, dregs_lo) (V)"); + else if (sop == 2 && sopcde == 7) + unhandled_instruction ("dregs_lo = EXPADJ (dregs_lo, dregs_lo)"); + else if (sop == 3 && sopcde == 7) + unhandled_instruction ("dregs_lo = EXPADJ (dregs_hi, dregs_lo)"); + else if (sop == 0 && sopcde == 8) + unhandled_instruction ("BITMUX (dregs, dregs, A0) (ASR)"); + else if (sop == 1 && sopcde == 8) + unhandled_instruction ("BITMUX (dregs, dregs, A0) (ASL)"); + else if (sop == 0 && sopcde == 9) + unhandled_instruction ("dregs_lo = VIT_MAX (dregs) (ASL)"); + else if (sop == 1 && sopcde == 9) + unhandled_instruction ("dregs_lo = VIT_MAX (dregs) (ASR)"); + else if (sop == 2 && sopcde == 9) + unhandled_instruction ("dregs = VIT_MAX (dregs, dregs) (ASL)"); + else if (sop == 3 && sopcde == 9) + unhandled_instruction ("dregs = VIT_MAX (dregs, dregs) (ASR)"); + else if (sop == 0 && sopcde == 10) + unhandled_instruction ("dregs = EXTRACT (dregs, dregs_lo) (Z)"); + else if (sop == 1 && sopcde == 10) + unhandled_instruction ("dregs = EXTRACT (dregs, dregs_lo) (X)"); + else if (sop == 2 && sopcde == 10) + unhandled_instruction ("dregs = DEPOSIT (dregs, dregs)"); + else if (sop == 3 && sopcde == 10) + unhandled_instruction ("dregs = DEPOSIT (dregs, dregs) (X)"); + else if (sop == 0 && sopcde == 11) + unhandled_instruction ("dregs_lo = CC = BXORSHIFT (A0, dregs)"); + else if (sop == 1 && sopcde == 11) + unhandled_instruction ("dregs_lo = CC = BXOR (A0, dregs)"); + else if (sop == 0 && sopcde == 12) + unhandled_instruction ("A0 = BXORSHIFT (A0, A1, CC)"); + else if (sop == 1 && sopcde == 12) + unhandled_instruction ("dregs_lo = CC = BXOR (A0, A1, CC)"); + else if (sop == 0 && sopcde == 13) + /* dregs = ALIGN8 (dregs, dregs) */ + DREG (dst0) = (DREG (src1) << 24) | (DREG (src0) >> 8); + else if (sop == 1 && sopcde == 13) + /* dregs = ALIGN16 (dregs, dregs) */ + DREG (dst0) = (DREG (src1) << 16) | (DREG (src0) >> 16); + else if (sop == 2 && sopcde == 13) + /* dregs = ALIGN24 (dregs , dregs) */ + DREG (dst0) = (DREG (src1) << 8) | (DREG (src0) >> 24); + else + illegal_instruction (); + PCREG += 4; +} + +static void +decode_dsp32shiftimm_0 (bu16 iw0, bu16 iw1, bu32 pc) +{ + /* dsp32shiftimm + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 0 | 0 |.M.| 1 | 1 | 0 | 1 | - | - |.sopcde............| + |.sop...|.HLs...|.dst0......|.immag.................|.src1......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int src1 = ((iw1 >> 0) & 0x7); + int sop = ((iw1 >> 14) & 0x3); + int immag = ((iw1 >> 3) & 0x3f); + int newimmag = (-(iw1 >> 3) & 0x3f); + int dst0 = ((iw1 >> 9) & 0x7); + int M = ((iw0 >> 11) & 0x1); + int sopcde = ((iw0 >> 0) & 0x1f); + int HLs = ((iw1 >> 12) & 0x3); + + if (HLs == 0 && sop == 0 && sopcde == 0) + unhandled_instruction ("dregs_lo = dregs_lo << uimm5"); + else if (HLs == 1 && sop == 0 && sopcde == 0) + unhandled_instruction ("dregs_lo = dregs_hi << uimm5"); + else if (HLs == 2 && sop == 0 && sopcde == 0) + unhandled_instruction ("dregs_hi = dregs_lo << uimm5"); + else if (HLs == 3 && sop == 0 && sopcde == 0) + unhandled_instruction ("dregs_hi = dregs_hi << uimm5"); + else if (HLs == 0 && sop == 1 && sopcde == 0) + unhandled_instruction ("dregs_lo = dregs_lo << imm5 (S)"); + else if (HLs == 1 && sop == 1 && sopcde == 0) + unhandled_instruction ("dregs_lo = dregs_hi << imm5 (S)"); + else if (HLs == 2 && sop == 1 && sopcde == 0) + unhandled_instruction ("dregs_hi = dregs_lo << imm5 (S)"); + else if (HLs == 3 && sop == 1 && sopcde == 0) + unhandled_instruction ("dregs_hi = dregs_hi << imm5 (S)"); + else if (HLs == 0 && sop == 2 && sopcde == 0) + unhandled_instruction ("dregs_lo = dregs_lo >> uimm5"); + else if (HLs == 1 && sop == 2 && sopcde == 0) + unhandled_instruction ("dregs_lo = dregs_hi >> uimm5"); + else if (HLs == 2 && sop == 2 && sopcde == 0) + unhandled_instruction ("dregs_hi = dregs_lo >> uimm5"); + else if (HLs == 3 && sop == 2 && sopcde == 0) + unhandled_instruction ("dregs_hi = dregs_hi >> uimm5"); + else if (sop == 2 && sopcde == 3 && HLs == 1) + unhandled_instruction ("A1 = ROT A1 BY imm6"); + else if (sop == 0 && sopcde == 3 && HLs == 0) + unhandled_instruction ("A0 = A0 << imm6"); + else if (sop == 0 && sopcde == 3 && HLs == 1) + unhandled_instruction ("A1 = A1 << imm6"); + else if (sop == 1 && sopcde == 3 && HLs == 0) + unhandled_instruction ("A0 = A0 >> imm6"); + else if (sop == 1 && sopcde == 3 && HLs == 1) + unhandled_instruction ("A1 = A1 >> imm6"); + else if (sop == 2 && sopcde == 3 && HLs == 0) + unhandled_instruction ("A0 = ROT A0 BY imm6"); + else if (sop == 1 && sopcde == 1) + unhandled_instruction ("dregs = dregs >>> uimm5 (V,S)"); + else if (sop == 2 && sopcde == 1) + unhandled_instruction ("dregs = dregs >> uimm5 (V)"); + else if (sop == 0 && sopcde == 1) + unhandled_instruction ("dregs = dregs << imm5 (V)"); + else if (sop == 1 && sopcde == 2) + unhandled_instruction ("dregs = dregs << imm6 (S)"); + else if (sop == 2 && sopcde == 2) + { + int count = imm6 (newimmag); + /* dregs = dregs >> imm6 */ + if (count < 0) + DREG (dst0) = lshift (DREG (src1), -count); + else + DREG (dst0) = lshiftrt (DREG (src1), count); + } + else if (sop == 3 && sopcde == 2) + { + int t = imm6 (immag); + /* dregs = ROT dregs BY imm6 */ + + /* Reduce everything to rotate left. */ + if (t < 0) + t += 33; + + if (t > 0) + { + int oldcc = CCREG; + bu32 srcval = DREG (src1); + bu32 result; + result = t == 32 ? 0 : srcval << t; + result |= t == 1 ? 0 : srcval >> (33 - t); + result |= oldcc << (t - 1); + DREG (dst0) = result; + CCREG = (srcval >> (32 - t)) & 1; + } + } + else if (sop == 0 && sopcde == 2) + { + int count = imm6 (newimmag); + /* dregs = dregs >>> imm6 */ + if (count < 0) + DREG (dst0) = lshift (DREG (src1), -count); + else + DREG (dst0) = ashiftrt (DREG (src1), count); + } + else + illegal_instruction (); + + PCREG += 4; +} + +static void +decode_psedoDEBUG_0 (bu16 iw0) +{ + /* psedoDEBUG + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |.fn....|.grp.......|.reg.......| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int grp = ((iw0 >> 3) & 0x7); + int fn = ((iw0 >> 6) & 0x3); + int reg = ((iw0 >> 0) & 0x7); + + if (reg == 0 && fn == 3) + unhandled_instruction ("DBG A0"); + else if (reg == 1 && fn == 3) + unhandled_instruction ("DBG A1"); + else if (reg == 3 && fn == 3) + unhandled_instruction ("ABORT"); + else if (reg == 4 && fn == 3) + unhandled_instruction ("HLT"); + else if (reg == 5 && fn == 3) + unhandled_instruction ("DBGHALT"); + else if (reg == 6 && fn == 3) + unhandled_instruction ("DBGCMPLX (dregs)"); + else if (reg == 7 && fn == 3) + unhandled_instruction ("DBG"); + else if (grp == 0 && fn == 2) + unhandled_instruction ("OUTC dregs"); + else if (fn == 0) + unhandled_instruction ("DBG allregs"); + else if (fn == 1) + unhandled_instruction ("PRNT allregs"); + else + illegal_instruction (); + + PCREG += 2; +} + +static void +decode_psedoOChar_0 (bu16 iw0) +{ + /* psedoOChar + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |.ch............................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int ch = ((iw0 >> 0) & 0xff); + + unhandled_instruction ("OUTC uimm8"); + PCREG += 2; +} + +static void +decode_psedodbg_assert_0 (bu16 iw0, bu16 iw1) +{ + /* psedodbg_assert + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ + | 1 | 1 | 1 | 1 | 0 | - | - | - | - | - |.dbgop.....|.regtest...| + |.expected......................................................| + +---+---+---+---|---+---+---+---|---+---+---+---|---+---+---+---+ */ + int expected = ((iw1 >> 0) & 0xffff); + int dbgop = ((iw0 >> 3) & 0x7); + int regtest = ((iw0 >> 0) & 0x7); + + if (dbgop == 0) + unhandled_instruction ("DBGA ( dregs_lo , uimm16 )"); + else if (dbgop == 1) + unhandled_instruction ("DBGA ( dregs_hi , uimm16 )"); + else if (dbgop == 2) + unhandled_instruction ("DBGAL ( dregs , uimm16 )"); + else if (dbgop == 3) + unhandled_instruction ("DBGAH ( dregs , uimm16 )"); + else + illegal_instruction (); + PCREG += 4; +} + +static void +_interp_insn_bfin (bu32 pc) +{ + bu8 buf[4]; + bu16 iw0 = get_word (saved_state.memory, pc); + bu16 iw1 = get_word (saved_state.memory, pc + 2); + + if ((iw0 & 0xf7ff) == 0xc003 && iw1 == 0x1800) + { + /* MNOP. */ + PCREG += 4; + return; + } + if ((iw0 & 0xFF00) == 0x0000) + decode_ProgCtrl_0 (iw0); + else if ((iw0 & 0xFFC0) == 0x0240) + decode_CaCTRL_0 (iw0); + else if ((iw0 & 0xFF80) == 0x0100) + decode_PushPopReg_0 (iw0); + else if ((iw0 & 0xFE00) == 0x0400) + decode_PushPopMultiple_0 (iw0); + else if ((iw0 & 0xFE00) == 0x0600) + decode_ccMV_0 (iw0); + else if ((iw0 & 0xF800) == 0x0800) + decode_CCflag_0 (iw0); + else if ((iw0 & 0xFFE0) == 0x0200) + decode_CC2dreg_0 (iw0); + else if ((iw0 & 0xFF00) == 0x0300) + decode_CC2stat_0 (iw0); + else if ((iw0 & 0xF000) == 0x1000) + decode_BRCC_0 (iw0, pc); + else if ((iw0 & 0xF000) == 0x2000) + decode_UJUMP_0 (iw0, pc); + else if ((iw0 & 0xF000) == 0x3000) + decode_REGMV_0 (iw0); + else if ((iw0 & 0xFC00) == 0x4000) + decode_ALU2op_0 (iw0); + else if ((iw0 & 0xFE00) == 0x4400) + decode_PTR2op_0 (iw0); + else if (((iw0 & 0xF800) == 0x4800)) + decode_LOGI2op_0 (iw0); + else if (((iw0 & 0xF000) == 0x5000)) + decode_COMP3op_0 (iw0); + else if (((iw0 & 0xF800) == 0x6000)) + decode_COMPI2opD_0 (iw0); + else if (((iw0 & 0xF800) == 0x6800)) + decode_COMPI2opP_0 (iw0); + else if (((iw0 & 0xF000) == 0x8000)) + decode_LDSTpmod_0 (iw0); + else if (((iw0 & 0xFF60) == 0x9E60)) + decode_dagMODim_0 (iw0); + else if (((iw0 & 0xFFF0) == 0x9F60)) + decode_dagMODik_0 (iw0); + else if (((iw0 & 0xFC00) == 0x9C00)) + decode_dspLDST_0 (iw0); + else if (((iw0 & 0xF000) == 0x9000)) + decode_LDST_0 (iw0); + else if (((iw0 & 0xFC00) == 0xB800)) + decode_LDSTiiFP_0 (iw0); + else if (((iw0 & 0xE000) == 0xA000)) + decode_LDSTii_0 (iw0); + else if (((iw0 & 0xFF80) == 0xE080) && ((iw1 & 0x0C00) == 0x0000)) + decode_LoopSetup_0 (iw0, iw1, pc); + else if (((iw0 & 0xFF00) == 0xE100) && ((iw1 & 0x0000) == 0x0000)) + decode_LDIMMhalf_0 (iw0, iw1, pc); + else if (((iw0 & 0xFE00) == 0xE200) && ((iw1 & 0x0000) == 0x0000)) + decode_CALLa_0 (iw0, iw1, pc); + else if (((iw0 & 0xFC00) == 0xE400) && ((iw1 & 0x0000) == 0x0000)) + decode_LDSTidxI_0 (iw0, iw1, pc); + else if (((iw0 & 0xFFFE) == 0xE800) && ((iw1 & 0x0000) == 0x0000)) + decode_linkage_0 (iw0, iw1); + else if (((iw0 & 0xF600) == 0xC000) && ((iw1 & 0x0000) == 0x0000)) + decode_dsp32mac_0 (iw0, iw1, pc); + else if (((iw0 & 0xF600) == 0xC200) && ((iw1 & 0x0000) == 0x0000)) + decode_dsp32mult_0 (iw0, iw1, pc); + else if (((iw0 & 0xF7C0) == 0xC400) && ((iw1 & 0x0000) == 0x0000)) + decode_dsp32alu_0 (iw0, iw1, pc); + else if (((iw0 & 0xF7E0) == 0xC600) && ((iw1 & 0x01C0) == 0x0000)) + decode_dsp32shift_0 (iw0, iw1, pc); + else if (((iw0 & 0xF7E0) == 0xC680) && ((iw1 & 0x0000) == 0x0000)) + decode_dsp32shiftimm_0 (iw0, iw1, pc); + else if (((iw0 & 0xFF00) == 0xF800)) + decode_psedoDEBUG_0 (iw0); + else if (((iw0 & 0xFF00) == 0xF900)) + decode_psedoOChar_0 (iw0); + else if (((iw0 & 0xFFC0) == 0xF000) && ((iw1 & 0x0000) == 0x0000)) + decode_psedodbg_assert_0 (iw0, iw1); + else + illegal_instruction (); +} + +void +interp_insn_bfin (bu32 pc) +{ + int i; + bu16 iw0 = get_word (saved_state.memory, pc); + + int is_multiinsn = ((iw0 & 0xc000) == 0xc000 && (iw0 & BIT_MULTI_INS) + && ((iw0 & 0xe800) != 0xe800 /* not linkage */)); + + n_stores = 0; + + _interp_insn_bfin (pc); + + /* Proper display of multiple issue instructions. */ + if (is_multiinsn) + { + _interp_insn_bfin (pc + 4); + _interp_insn_bfin (pc + 6); + } + for (i = 0; i < n_stores; i++) + *stores[i].addr = stores[i].val; +} diff -r -u -N -x CVS src.orig/sim/bfin/bfin-sim.h src/sim/bfin/bfin-sim.h --- src.orig/sim/bfin/bfin-sim.h 1970-01-01 08:00:00.000000000 +0800 +++ src/sim/bfin/bfin-sim.h 2005-12-27 11:13:15.000000000 +0800 @@ -0,0 +1,122 @@ +/* Simulator for Analog Devices Blackfin processer. + + Copyright (C) 2005 Free Software Foundation, Inc. + Contributed by Analog Devices. + + This file is part of simulators. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "gdb/callback.h" +#include "gdb/remote-sim.h" +#include "sim-config.h" +#include "sim-types.h" + +typedef unsigned8 bu8; +typedef unsigned16 bu16; +typedef unsigned32 bu32; +typedef unsigned64 bu64; +typedef signed8 bs8; +typedef signed16 bs16; +typedef signed32 bs32; +typedef signed64 bs64; + +typedef struct +{ + bu32 dpregs[16], iregs[4], mregs[4], bregs[4], lregs[4]; + bu64 a0, a1; + bu32 lt[2], lc[2], lb[2]; + int ac0, ac0_copy, ac1, an, aq; + int av0, av0s, av1, av1s, az, cc, v, v_copy, vs; + int v_internal; + bu32 pc, rets; + + int ticks; + int insts; + + int exception; + + int end_of_registers; + + int msize; + unsigned char *memory; + unsigned long bfd_mach; +} saved_state_type; + +extern saved_state_type saved_state; + +#define GREG(x,i) DPREG ((x) | (i << 3)) +#define DPREG(x) (saved_state.dpregs[x]) +#define DREG(x) (saved_state.dpregs[x]) +#define PREG(x) (saved_state.dpregs[x + 8]) +#define SPREG PREG (6) +#define FPREG PREG (7) +#define IREG(x) (saved_state.iregs[x]) +#define MREG(x) (saved_state.mregs[x]) +#define BREG(x) (saved_state.bregs[x]) +#define LREG(x) (saved_state.lregs[x]) +#define A0REG (saved_state.a0) +#define A1REG (saved_state.a1) +#define CCREG (saved_state.cc) +#define LC0REG (saved_state.lc[0]) +#define LT0REG (saved_state.lt[0]) +#define LB0REG (saved_state.lb[0]) +#define LC1REG (saved_state.lc[1]) +#define LT1REG (saved_state.lt[1]) +#define LB1REG (saved_state.lb[1]) +#define RETSREG (saved_state.rets) +#define PCREG (saved_state.pc) + +extern int did_jump; + +static inline void put_byte (unsigned char *memory, bu32 addr, bu8 v) +{ + memory[addr] = v; +} + +static inline void put_word (unsigned char *memory, bu32 addr, bu16 v) +{ + memory[addr] = v; + memory[addr + 1] = v >> 8; +} + +static inline void put_long (unsigned char *memory, bu32 addr, bu32 v) +{ + memory[addr] = v; + memory[addr + 1] = v >> 8; + memory[addr + 2] = v >> 16; + memory[addr + 3] = v >> 24; +} + +static inline bu8 get_byte (unsigned char *memory, bu32 addr) +{ + return memory[addr]; +} + +static inline bu16 get_word (unsigned char *memory, bu32 addr) +{ + return (memory[addr] | (memory[addr + 1] << 8)); +} + +static inline bu32 get_long (unsigned char *memory, bu32 addr) +{ + return (memory[addr] | (memory[addr + 1] << 8) + | (memory[addr + 2] << 16) | (memory[addr + 3] << 24)); +} + +extern void interp_insn_bfin (bu32); + diff -r -u -N -x CVS src.orig/sim/bfin/config.in src/sim/bfin/config.in --- src.orig/sim/bfin/config.in 1970-01-01 08:00:00.000000000 +0800 +++ src/sim/bfin/config.in 2004-10-06 00:58:39.000000000 +0800 @@ -0,0 +1,158 @@ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if NLS is requested. */ +#undef ENABLE_NLS + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Define as 1 if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define if you have the __argz_count function. */ +#undef HAVE___ARGZ_COUNT + +/* Define if you have the __argz_next function. */ +#undef HAVE___ARGZ_NEXT + +/* Define if you have the __argz_stringify function. */ +#undef HAVE___ARGZ_STRINGIFY + +/* Define if you have the __setfpucw function. */ +#undef HAVE___SETFPUCW + +/* Define if you have the dcgettext function. */ +#undef HAVE_DCGETTEXT + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the getrusage function. */ +#undef HAVE_GETRUSAGE + +/* Define if you have the munmap function. */ +#undef HAVE_MUNMAP + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the setenv function. */ +#undef HAVE_SETENV + +/* Define if you have the setlocale function. */ +#undef HAVE_SETLOCALE + +/* Define if you have the sigaction function. */ +#undef HAVE_SIGACTION + +/* Define if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the time function. */ +#undef HAVE_TIME + +/* Define if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_FPU_CONTROL_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define if you have the header file. */ +#undef HAVE_NL_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the header file. */ +#undef HAVE_VALUES_H diff -r -u -N -x CVS src.orig/sim/bfin/configure.ac src/sim/bfin/configure.ac --- src.orig/sim/bfin/configure.ac 1970-01-01 08:00:00.000000000 +0800 +++ src/sim/bfin/configure.ac 2005-12-15 02:00:10.000000000 +0800 @@ -0,0 +1,12 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.59)dnl +AC_INIT(Makefile.in) +AC_CONFIG_HEADER(config.h:config.in) + +sinclude(../common/aclocal.m4) + +sinclude(../common/common.m4) + +AC_CHECK_HEADERS(unistd.h) + +SIM_AC_OUTPUT diff -r -u -N -x CVS src.orig/sim/bfin/interp.c src/sim/bfin/interp.c --- src.orig/sim/bfin/interp.c 1970-01-01 08:00:00.000000000 +0800 +++ src/sim/bfin/interp.c 2005-12-27 16:24:04.000000000 +0800 @@ -0,0 +1,618 @@ +/* Simulator for Analog Devices Blackfin processer. + + Copyright (C) 2005 Free Software Foundation, Inc. + Contributed by Analog Devices. + + This file is part of simulators. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include "config.h" + +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "sysdep.h" +#include "bfd.h" +#include "gdb/callback.h" +#include "bfin-sim.h" +#include "gdb/sim-bfin.h" + +/* This file is local - if newlib changes, then so should this. */ +#include "syscall.h" + +#include + +#ifdef _WIN32 +#include /* Needed for _isnan(). */ +#define isnan _isnan +#endif + +#ifndef SIGBUS +#define SIGBUS SIGSEGV +#endif + +#ifndef SIGQUIT +#define SIGQUIT SIGTERM +#endif + +#ifndef SIGTRAP +#define SIGTRAP 5 +#endif + +/* Define the rate at which the simulator should poll the host + for a quit. */ +#define POLL_QUIT_INTERVAL 0x60000 + +saved_state_type saved_state; + +static char **prog_argv; +static SIM_OPEN_KIND sim_kind; +static char *myname; +static int tracing = 0; +static host_callback *callback; + +#if defined(__GO32__) || defined(_WIN32) +int sim_memory_size = 19; +#else +int sim_memory_size = 24; +#endif + + +/* Count the number of arguments in an argv. */ +static int +count_argc (char **argv) +{ + int i; + + if (! argv) + return -1; + + for (i = 0; argv[i] != NULL; ++i) + continue; + return i; +} + +/* This function exists mainly for the purpose of setting a breakpoint to + catch simulated bus errors when running the simulator under GDB. */ + +void +raise_exception (int x) +{ + saved_state.exception = x; +} + +void +raise_buserror () +{ + raise_exception (SIGBUS); +} + +static int +get_now () +{ + return time ((long *) 0); +} + +static int +now_persec () +{ + return 1; +} + +/* Simulate a monitor trap, put the result into r0 and errno into r1 + return offset by which to adjust pc. */ + +void +bfin_trap () +{ + int reason = DREG (2); + int sys = DREG (0); + bu32 args = DREG (1); + + switch (sys) + { + case SYS_exit: + saved_state.exception = SIGQUIT; + DREG (0) = get_long (saved_state.memory, args); + return; + case SYS_open: + { + char *arg0 = (char *)(saved_state.memory + get_long (saved_state.memory, args)); + bu32 arg1 = get_long (saved_state.memory, args + 4); + bu32 arg2 = get_long (saved_state.memory, args + 8); + if (strcmp (arg0, ":tt") == 0) + DREG (0) = arg2 == 4 ? 0 : 1; + else + DREG (0) = callback->open (callback, arg0, arg1); + } + return; + + case SYS_write: + { + bu32 arg0 = get_long (saved_state.memory, args); + char *arg1 = (char *)(saved_state.memory + get_long (saved_state.memory, args + 4)); + bu32 arg2 = get_long (saved_state.memory, args + 8); + DREG (0) = callback->write (callback, arg0, arg1, arg2); + } + return; + + case SYS_read: + { + bu32 arg0 = get_long (saved_state.memory, args); + char *arg1 = (char *)(saved_state.memory + get_long (saved_state.memory, args + 4)); + bu32 arg2 = get_long (saved_state.memory, args + 8); + DREG (0) = callback->read (callback, arg0, arg1, arg2); + } + return; + + case SYS_kill: + printf ("Killing with signal %d\n", get_long (saved_state.memory, args + 4)); + raise (SIGABRT); + + case SYS_close: + DREG (0) = callback->close (callback, get_long (saved_state.memory, args)); + return; + case SYS_argc: + DREG (0) = count_argc (prog_argv); + break; + case SYS_argnlen: + { + bu32 arg0 = get_long (saved_state.memory, args); + if (arg0 < count_argc (prog_argv)) + DREG (0) = strlen (prog_argv[arg0]); + else + DREG (0) = -1; + } + return; + case SYS_argn: + { + bu32 arg0 = get_long (saved_state.memory, args); + char *arg1 = (char *)(saved_state.memory + get_long (saved_state.memory, args + 4)); + if (arg0 < count_argc (prog_argv)) + { + /* Include the termination byte. */ + int i = strlen (prog_argv[arg0]) + 1; + DREG (0) = get_long (saved_state.memory, args + 4); + memcpy (arg1, prog_argv[arg0], i); + } + else + DREG (0) = -1; + } + return; + case SYS_time: + DREG (0) = get_now (); + return; + default: + abort (); + } +} + +void +control_c (int sig) +{ + raise_exception (SIGINT); +} + +/* Set the memory size to the power of two provided. */ + +void +sim_size (int power) +{ + saved_state.msize = 1 << power; + + sim_memory_size = power; + + if (saved_state.memory) + free (saved_state.memory); + + saved_state.memory = + (unsigned char *) calloc (64, saved_state.msize / 64); + + if (!saved_state.memory) + { + fprintf (stderr, + "Not enough VM for simulation of %d bytes of RAM\n", + saved_state.msize); + + saved_state.msize = 1; + saved_state.memory = (unsigned char *) calloc (1, 1); + } +} + +static void +init_pointers () +{ + if (saved_state.msize != 1 << sim_memory_size) + sim_size (sim_memory_size); +} + +#define MMASKB ((saved_state.msize -1) & ~0) + +int +sim_stop (SIM_DESC sd) +{ + raise_exception (SIGINT); + return 1; +} + +/* Set by an instruction emulation function if we performed a jump. */ +int did_jump; + +/* Execute a single instruction. */ + +static void +step_once (SIM_DESC sd) +{ + bu32 oldpc = PCREG; + + if (tracing) + fprintf (stderr, "PC: %08x, insn: %04x\n", PCREG, + get_word (saved_state.memory, PCREG)); + + did_jump = 0; + interp_insn_bfin (PCREG); + + /* @@@ Not sure how the hardware really behaves when the last insn + of a loop is a jump. */ + if (!did_jump) + { + if (LC1REG && oldpc == LB1REG && --LC1REG) + PCREG = LT1REG; + else if (LC0REG && oldpc == LB0REG && --LC0REG) + PCREG = LT0REG; + } +} + +void +sim_resume (SIM_DESC sd, int step, int siggnal) +{ + register int insts = 0; + + int tick_start = get_now (); + void (*prev) () = signal (SIGINT, control_c); + void (*prev_fpe) () = signal (SIGFPE, SIG_IGN); + + init_pointers (); + + /* clear exceptions else it will stop */ + saved_state.exception = 0; + + if(step) + { + while(step && saved_state.exception == 0) + { + /* not clear if this will be > 1. Potential problem area */ + step_once(sd); + step--; + } + /* Emulate a hardware single step ... raise an exception */ + saved_state.exception = SIGTRAP; + } + else + while (saved_state.exception == 0) + step_once(sd); + + saved_state.ticks += get_now () - tick_start; + saved_state.insts += insts; + + signal (SIGFPE, prev_fpe); + signal (SIGINT, prev); +} + +int +sim_write (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size) +{ + int i; + + init_pointers (); + + for (i = 0; i < size; i++) + saved_state.memory[(MMASKB & (addr + i))] = buffer[i]; + + return size; +} + +int +sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size) +{ + int i; + + init_pointers (); + + for (i = 0; i < size; i++) + buffer[i] = saved_state.memory[(MMASKB & (addr + i))]; + + return size; +} + +int +sim_trace (SIM_DESC sd) +{ + tracing = 1; + sim_resume (sd, 0, 0); + tracing = 0; + return 1; +} + +void +sim_stop_reason (SIM_DESC sd, enum sim_stop *reason, int *sigrc) +{ + if (saved_state.exception == SIGQUIT) + { + *reason = sim_exited; + *sigrc = DREG (0); + } + else + { + *reason = sim_stopped; + *sigrc = saved_state.exception; + } +} + +void +sim_info (SIM_DESC sd, int verbose) +{ + double timetaken = + (double) saved_state.ticks / (double) now_persec (); + + callback->printf_filtered (callback, "\n\n# instructions executed %10d\n", + saved_state.insts); + callback->printf_filtered (callback, "# real time taken %10.4f\n", + timetaken); +} + +static void +parse_and_set_memory_size (char *str) +{ + int n; + + n = strtol (str, NULL, 10); + if (n > 0 && n <= 24) + sim_memory_size = n; + else + callback->printf_filtered (callback, + "Bad memory size %d; must be 1 to 24, inclusive\n", n); +} + +SIM_DESC +sim_open (SIM_OPEN_KIND kind, host_callback *cb, + struct bfd *abfd, char **argv) +{ + char **p; + + sim_kind = kind; + myname = argv[0]; + callback = cb; + + for (p = argv + 1; *p != NULL; ++p) + if (isdigit (**p)) + parse_and_set_memory_size (*p); + + /* fudge our descriptor for now */ + return (SIM_DESC) 1; +} + +void +sim_close (SIM_DESC sd, int quitting) +{ + /* Nothing to do. */ +} + +SIM_RC +sim_load (SIM_DESC sd, char *prog, bfd *abfd, int from_tty) +{ + extern bfd *sim_load_file (); /* ??? Don't know where this should live. */ + bfd *prog_bfd; + + 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.bfd_mach = bfd_get_mach (prog_bfd); + else if (abfd) + saved_state.bfd_mach = bfd_get_mach (abfd); + else + saved_state.bfd_mach = 0; + + if (prog_bfd == NULL) + return SIM_RC_FAIL; + if (abfd == NULL) + bfd_close (prog_bfd); + return SIM_RC_OK; +} + +SIM_RC +sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, + char **argv, char **env) +{ + /* Clear the registers. */ + memset (&saved_state, 0, + (char*) &saved_state.end_of_registers - (char*) &saved_state); + + /* Set the PC. */ + if (prog_bfd != NULL) + saved_state.pc = bfd_get_start_address (prog_bfd); + + SPREG = saved_state.msize; + /* Set the bfd machine type. */ + if (prog_bfd != NULL) + saved_state.bfd_mach = bfd_get_mach (prog_bfd); + + /* Record the program's arguments. */ + prog_argv = argv; + + return SIM_RC_OK; +} + +void +sim_do_command (SIM_DESC sd, char *cmd) +{ + char *sms_cmd = "set-memory-size"; + int cmdsize; + + if (cmd == NULL || *cmd == '\0') + cmd = "help"; + + cmdsize = strlen (sms_cmd); + if (strncmp (cmd, sms_cmd, cmdsize) == 0 + && strchr (" \t", cmd[cmdsize]) != NULL) + parse_and_set_memory_size (cmd + cmdsize + 1); + else if (strcmp (cmd, "help") == 0) + { + (callback->printf_filtered) (callback, + "List of Blackfin simulator commands:\n\n"); + (callback->printf_filtered) (callback, "help -- Display this information\n"); + (callback->printf_filtered) (callback, "set-memory-size -- Set the number of address bits to use\n"); + (callback->printf_filtered) (callback, "\n"); + } + else + (callback->printf_filtered) (callback, "Error: \"%s\" is not a valid Blackfin simulator command.\n", cmd); +} + +void +sim_set_callbacks (host_callback *p) +{ + callback = p; +} + +int +sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length) +{ + int value; + + init_pointers (); + switch (rn) + { + case SIM_BFIN_R0_REGNUM : value = DREG(0); break; + case SIM_BFIN_R1_REGNUM : value = DREG(1); break; + case SIM_BFIN_R2_REGNUM : value = DREG(2); break; + case SIM_BFIN_R3_REGNUM : value = DREG(3); break; + case SIM_BFIN_R4_REGNUM : value = DREG(4); break; + case SIM_BFIN_R5_REGNUM : value = DREG(5); break; + case SIM_BFIN_R6_REGNUM : value = DREG(6); break; + case SIM_BFIN_R7_REGNUM : value = DREG(7); break; + case SIM_BFIN_P0_REGNUM : value = PREG(0); break; + case SIM_BFIN_P1_REGNUM : value = PREG(1); break; + case SIM_BFIN_P2_REGNUM : value = PREG(2); break; + case SIM_BFIN_P3_REGNUM : value = PREG(3); break; + case SIM_BFIN_P4_REGNUM : value = PREG(4); break; + case SIM_BFIN_P5_REGNUM : value = PREG(5); break; + case SIM_BFIN_SP_REGNUM : value = SPREG; break; + case SIM_BFIN_FP_REGNUM : value = FPREG; break; + case SIM_BFIN_I0_REGNUM : value = IREG(0); break; + case SIM_BFIN_I1_REGNUM : value = IREG(1); break; + case SIM_BFIN_I2_REGNUM : value = IREG(2); break; + case SIM_BFIN_I3_REGNUM : value = IREG(3); break; + case SIM_BFIN_M0_REGNUM : value = MREG(0); break; + case SIM_BFIN_M1_REGNUM : value = MREG(1); break; + case SIM_BFIN_M2_REGNUM : value = MREG(2); break; + case SIM_BFIN_M3_REGNUM : value = MREG(3); break; + case SIM_BFIN_B0_REGNUM : value = BREG(0); break; + case SIM_BFIN_B1_REGNUM : value = BREG(1); break; + case SIM_BFIN_B2_REGNUM : value = BREG(2); break; + case SIM_BFIN_B3_REGNUM : value = BREG(3); break; + case SIM_BFIN_L0_REGNUM : value = LREG(0); break; + case SIM_BFIN_L1_REGNUM : value = LREG(1); break; + case SIM_BFIN_L2_REGNUM : value = LREG(2); break; + case SIM_BFIN_L3_REGNUM : value = LREG(3); break; + case SIM_BFIN_RETS_REGNUM : value = RETSREG; break; + case SIM_BFIN_A0_DOT_X_REGNUM : value = A0REG; break; + case SIM_BFIN_AO_DOT_W_REGNUM : value = A0REG; break; + case SIM_BFIN_A1_DOT_X_REGNUM : value = A1REG; break; + case SIM_BFIN_A1_DOT_W_REGNUM : value = A1REG; break; + case SIM_BFIN_LC0_REGNUM : value = LC0REG; break; + case SIM_BFIN_LT0_REGNUM : value = LT0REG; break; + case SIM_BFIN_LB0_REGNUM : value = LB0REG; break; + case SIM_BFIN_LC1_REGNUM : value = LC1REG; break; + case SIM_BFIN_LT1_REGNUM : value = LT1REG; break; + case SIM_BFIN_LB1_REGNUM : value = LB1REG; break; + case SIM_BFIN_PC_REGNUM : value = PCREG; break; + case SIM_BFIN_CC_REGNUM : value = CCREG; break; + default : + return 0; // will be an error in gdb + break; + } + + *(int *)memory = value; + return -1; // disables size checking in gdb +} + +int +sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length) +{ + int value = *(int *)memory; + + init_pointers (); + switch (rn) + { + case SIM_BFIN_R0_REGNUM : DREG(0) = value; break; + case SIM_BFIN_R1_REGNUM : DREG(1) = value; break; + case SIM_BFIN_R2_REGNUM : DREG(2) = value; break; + case SIM_BFIN_R3_REGNUM : DREG(3) = value; break; + case SIM_BFIN_R4_REGNUM : DREG(4) = value; break; + case SIM_BFIN_R5_REGNUM : DREG(5) = value; break; + case SIM_BFIN_R6_REGNUM : DREG(6) = value; break; + case SIM_BFIN_R7_REGNUM : DREG(7) = value; break; + case SIM_BFIN_P0_REGNUM : PREG(0) = value; break; + case SIM_BFIN_P1_REGNUM : PREG(1) = value; break; + case SIM_BFIN_P2_REGNUM : PREG(2) = value; break; + case SIM_BFIN_P3_REGNUM : PREG(3) = value; break; + case SIM_BFIN_P4_REGNUM : PREG(4) = value; break; + case SIM_BFIN_P5_REGNUM : PREG(5) = value; break; + case SIM_BFIN_SP_REGNUM : SPREG = value; break; + case SIM_BFIN_FP_REGNUM : FPREG = value; break; + case SIM_BFIN_I0_REGNUM : IREG(0) = value; break; + case SIM_BFIN_I1_REGNUM : IREG(1) = value; break; + case SIM_BFIN_I2_REGNUM : IREG(2) = value; break; + case SIM_BFIN_I3_REGNUM : IREG(3) = value; break; + case SIM_BFIN_M0_REGNUM : MREG(0) = value; break; + case SIM_BFIN_M1_REGNUM : MREG(1) = value; break; + case SIM_BFIN_M2_REGNUM : MREG(2) = value; break; + case SIM_BFIN_M3_REGNUM : MREG(3) = value; break; + case SIM_BFIN_B0_REGNUM : BREG(0) = value; break; + case SIM_BFIN_B1_REGNUM : BREG(1) = value; break; + case SIM_BFIN_B2_REGNUM : BREG(2) = value; break; + case SIM_BFIN_B3_REGNUM : BREG(3) = value; break; + case SIM_BFIN_L0_REGNUM : LREG(0) = value; break; + case SIM_BFIN_L1_REGNUM : LREG(1) = value; break; + case SIM_BFIN_L2_REGNUM : LREG(2) = value; break; + case SIM_BFIN_L3_REGNUM : LREG(3) = value; break; + case SIM_BFIN_RETS_REGNUM : RETSREG = value; break; + case SIM_BFIN_A0_DOT_X_REGNUM : A0REG = value; break; + case SIM_BFIN_AO_DOT_W_REGNUM : A0REG = value; break; + case SIM_BFIN_A1_DOT_X_REGNUM : A1REG = value; break; + case SIM_BFIN_A1_DOT_W_REGNUM : A1REG = value; break; + case SIM_BFIN_LC0_REGNUM : LC0REG = value; break; + case SIM_BFIN_LT0_REGNUM : LT0REG = value; break; + case SIM_BFIN_LB0_REGNUM : LB0REG = value; break; + case SIM_BFIN_LC1_REGNUM : LC1REG = value; break; + case SIM_BFIN_LT1_REGNUM : LT1REG = value; break; + case SIM_BFIN_LB1_REGNUM : LB1REG = value; break; + case SIM_BFIN_PC_REGNUM : PCREG = value; break; + case SIM_BFIN_CC_REGNUM : CCREG = value; break; + default : + return 0; // will be an error in gdb + break; + } + + return -1; // disables size checking in gdb +} + diff -r -u -N -x CVS src.orig/sim/bfin/Makefile.in src/sim/bfin/Makefile.in --- src.orig/sim/bfin/Makefile.in 1970-01-01 08:00:00.000000000 +0800 +++ src/sim/bfin/Makefile.in 2005-12-27 10:53:25.000000000 +0800 @@ -0,0 +1,29 @@ +# Makefile template for Configure for the Blackfin simulator. +# Copyright (C) 2005 Free Software Foundation, Inc. +# Written by Analog Devices, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +## COMMON_PRE_CONFIG_FRAG + +SIM_OBJS = interp.o bfin-dis.o sim-load.o + +INCLUDE = bfin-sim.h + +## COMMON_POST_CONFIG_FRAG + +interp.o: interp.c $(INCLUDE) +bfin-dis.o: bfin-dis.c $(INCLUDE) diff -r -u -N -x CVS src.orig/sim/bfin/syscall.h src/sim/bfin/syscall.h --- src.orig/sim/bfin/syscall.h 1970-01-01 08:00:00.000000000 +0800 +++ src/sim/bfin/syscall.h 2005-12-27 16:04:50.000000000 +0800 @@ -0,0 +1,41 @@ +/* This file is copied from newlib. Do not edit this alone. */ + +#define SYS_exit 1 +#define SYS_fork 2 +#define SYS_read 3 +#define SYS_write 4 +#define SYS_open 5 +#define SYS_close 6 +#define SYS_wait4 7 +#define SYS_creat 8 +#define SYS_link 9 +#define SYS_unlink 10 +#define SYS_execv 11 +#define SYS_chdir 12 + +#define SYS_mknod 14 +#define SYS_chmod 15 +#define SYS_chown 16 + +#define SYS_lseek 19 +#define SYS_getpid 20 +#define SYS_isatty 21 +#define SYS_fstat 22 +#define SYS_time 23 +#define SYS_kill 24 + +#define SYS_stat 38 + +#define SYS_pipe 42 + +#define SYS_execve 59 + +#define SYS_truncate 129 +#define SYS_ftruncate 130 + +#define SYS_argc 172 +#define SYS_argnlen 173 +#define SYS_argn 174 + +#define SYS_utime 201 +#define SYS_wait 202 diff -r -u -N -x CVS src.orig/sim/configure src/sim/configure --- src.orig/sim/configure 2005-05-17 22:11:24.000000000 +0800 +++ src/sim/configure 2005-12-27 16:21:31.000000000 +0800 @@ -273,6 +273,7 @@ ac_unique_file="Makefile.in" ac_subdirs_all="$ac_subdirs_all arm" +ac_subdirs_all="$ac_subdirs_all bfin" ac_subdirs_all="$ac_subdirs_all cris" ac_subdirs_all="$ac_subdirs_all d10v" ac_subdirs_all="$ac_subdirs_all frv" @@ -3420,6 +3421,13 @@ testsuite=yes common=yes ;; + bfin-*-*) + + +subdirs="$subdirs bfin" + + common=yes + ;; cris-*-* | crisv32-*-*) diff -r -u -N -x CVS src.orig/sim/configure.ac src/sim/configure.ac --- src.orig/sim/configure.ac 2005-05-17 22:11:24.000000000 +0800 +++ src/sim/configure.ac 2005-12-12 18:01:29.000000000 +0800 @@ -50,6 +50,10 @@ testsuite=yes common=yes ;; + bfin-*-*) + AC_CONFIG_SUBDIRS(bfin) + common=yes + ;; cris-*-* | crisv32-*-*) AC_CONFIG_SUBDIRS(cris) testsuite=yes