From: Chris Demetriou Date: Sun, 2 Jun 2002 07:39:26 +0000 (+0000) Subject: 2002-06-02 Chris Demetriou X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f4f1b9f1029e0b2645a9ed13f6241518f7df1e0a;p=binutils-gdb.git 2002-06-02 Chris Demetriou Ed Satterthwaite * mips.igen (mdmx): New (pseudo-)model. * mdmx.c, mdmx.igen: New files. * Makefile.in (SIM_OBJS): Add mdmx.o. * sim-main.h (MDMX_accumulator, MX_fmtsel, signed24, signed48): New typedefs. (ACC, MX_Add, MX_AddA, MX_AddL, MX_And, MX_C_EQ, MX_C_LT, MX_Comp) (MX_FMT_OB, MX_FMT_QH, MX_Max, MX_Min, MX_Msgn, MX_Mul, MX_MulA) (MX_MulL, MX_MulS, MX_MulSL, MX_Nor, MX_Or, MX_Pick, MX_RAC) (MX_RAC_H, MX_RAC_L, MX_RAC_M, MX_RNAS, MX_RNAU, MX_RND_AS) (MX_RND_AU, MX_RND_ES, MX_RND_EU, MX_RND_ZS, MX_RND_ZU, MX_RNES) (MX_RNEU, MX_RZS, MX_RZU, MX_SHFL, MX_ShiftLeftLogical) (MX_ShiftRightArith, MX_ShiftRightLogical, MX_Sub, MX_SubA, MX_SubL) (MX_VECT_ADD, MX_VECT_ADDA, MX_VECT_ADDL, MX_VECT_AND) (MX_VECT_MAX, MX_VECT_MIN, MX_VECT_MSGN, MX_VECT_MUL, MX_VECT_MULA) (MX_VECT_MULL, MX_VECT_MULS, MX_VECT_MULSL, MX_VECT_NOR) (MX_VECT_OR, MX_VECT_SLL, MX_VECT_SRA, MX_VECT_SRL, MX_VECT_SUB) (MX_VECT_SUBA, MX_VECT_SUBL, MX_VECT_XOR, MX_WACH, MX_WACL, MX_Xor) (SIM_ARGS, SIM_STATE, UnpredictableResult, fmt_mdmx, ob_fmtsel) (qh_fmtsel): New macros. (_sim_cpu): New member "acc". (mdmx_acc_op, mdmx_cc_op, mdmx_cpr_op, mdmx_pick_op, mdmx_rac_op) (mdmx_round_op, mdmx_shuffle, mdmx_wach, mdmx_wacl): New functions. --- diff --git a/sim/mips/ChangeLog b/sim/mips/ChangeLog index 388753966c5..5de700fd8fb 100644 --- a/sim/mips/ChangeLog +++ b/sim/mips/ChangeLog @@ -1,3 +1,29 @@ +2002-06-02 Chris Demetriou + Ed Satterthwaite + + * mips.igen (mdmx): New (pseudo-)model. + * mdmx.c, mdmx.igen: New files. + * Makefile.in (SIM_OBJS): Add mdmx.o. + * sim-main.h (MDMX_accumulator, MX_fmtsel, signed24, signed48): + New typedefs. + (ACC, MX_Add, MX_AddA, MX_AddL, MX_And, MX_C_EQ, MX_C_LT, MX_Comp) + (MX_FMT_OB, MX_FMT_QH, MX_Max, MX_Min, MX_Msgn, MX_Mul, MX_MulA) + (MX_MulL, MX_MulS, MX_MulSL, MX_Nor, MX_Or, MX_Pick, MX_RAC) + (MX_RAC_H, MX_RAC_L, MX_RAC_M, MX_RNAS, MX_RNAU, MX_RND_AS) + (MX_RND_AU, MX_RND_ES, MX_RND_EU, MX_RND_ZS, MX_RND_ZU, MX_RNES) + (MX_RNEU, MX_RZS, MX_RZU, MX_SHFL, MX_ShiftLeftLogical) + (MX_ShiftRightArith, MX_ShiftRightLogical, MX_Sub, MX_SubA, MX_SubL) + (MX_VECT_ADD, MX_VECT_ADDA, MX_VECT_ADDL, MX_VECT_AND) + (MX_VECT_MAX, MX_VECT_MIN, MX_VECT_MSGN, MX_VECT_MUL, MX_VECT_MULA) + (MX_VECT_MULL, MX_VECT_MULS, MX_VECT_MULSL, MX_VECT_NOR) + (MX_VECT_OR, MX_VECT_SLL, MX_VECT_SRA, MX_VECT_SRL, MX_VECT_SUB) + (MX_VECT_SUBA, MX_VECT_SUBL, MX_VECT_XOR, MX_WACH, MX_WACL, MX_Xor) + (SIM_ARGS, SIM_STATE, UnpredictableResult, fmt_mdmx, ob_fmtsel) + (qh_fmtsel): New macros. + (_sim_cpu): New member "acc". + (mdmx_acc_op, mdmx_cc_op, mdmx_cpr_op, mdmx_pick_op, mdmx_rac_op) + (mdmx_round_op, mdmx_shuffle, mdmx_wach, mdmx_wacl): New functions. + 2002-05-01 Chris Demetriou * interp.c: Use 'deprecated' rather than 'depreciated.' diff --git a/sim/mips/Makefile.in b/sim/mips/Makefile.in index 5d0a3364e8f..d95fbbc2b1c 100644 --- a/sim/mips/Makefile.in +++ b/sim/mips/Makefile.in @@ -43,6 +43,7 @@ SIM_OBJS = \ $(MIPS_EXTRA_OBJS) \ cp1.o \ interp.o \ + mdmx.o \ sim-main.o \ sim-hload.o \ sim-engine.o \ @@ -71,6 +72,7 @@ SIM_RUN_OBJS = nrun.o interp.o: $(srcdir)/interp.c config.h sim-main.h itable.h cp1.o: $(srcdir)/cp1.c config.h sim-main.h +mdmx.o: $(srcdir)/mdmx.c $(srcdir)/sim-main.h ../igen/igen: cd ../igen && $(MAKE) diff --git a/sim/mips/mdmx.c b/sim/mips/mdmx.c new file mode 100644 index 00000000000..2b0892288c9 --- /dev/null +++ b/sim/mips/mdmx.c @@ -0,0 +1,1449 @@ +/* Simulation code for the MIPS MDMX ASE. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Broadcom Corporation (SiByte). + +This file is part of GDB, the GNU debugger. + +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, 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., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include + +#include "sim-main.h" + +/* Within mdmx.c we refer to the sim_cpu directly. */ +#define CPU cpu +#define SD (CPU_STATE(CPU)) +#define SD_ cpu, cia, -1 + +/* MDMX Representations + + An 8-bit packed byte element (OB) is always unsigned. + The 24-bit accumulators are signed and are represented as 32-bit + signed values, which are reduced to 24-bit signed values prior to + Round and Clamp operations. + + A 16-bit packed halfword element (QH) is always signed. + The 48-bit accumulators are signed and are represented as 64-bit + signed values, which are reduced to 48-bit signed values prior to + Round and Clamp operations. + + The code below assumes a 2's-complement representation of signed + quantities. Care is required to clear extended sign bits when + repacking fields. + + The code (and the code for arithmetic shifts in mips.igen) also makes + the (not guaranteed portable) assumption that right shifts of signed + quantities in C do sign extension. */ + +typedef unsigned64 unsigned48; +#define MASK48 (UNSIGNED64 (0xffffffffffff)) + +typedef unsigned32 unsigned24; +#define MASK24 (UNSIGNED32 (0xffffff)) + +typedef enum { + mdmx_ob, /* OB (octal byte) */ + mdmx_qh /* QH (quad half-word) */ +} MX_fmt; + +typedef enum { + sel_elem, /* element select */ + sel_vect, /* vector select */ + sel_imm /* immediate select */ +} VT_select; + +#define OB_MAX ((unsigned8)0xFF) +#define QH_MIN ((signed16)0x8000) +#define QH_MAX ((signed16)0x7FFF) + +#define OB_CLAMP(x) ((unsigned8)((x) > OB_MAX ? OB_MAX : (x))) +#define QH_CLAMP(x) ((signed16)((x) < QH_MIN ? QH_MIN : \ + ((x) > QH_MAX ? QH_MAX : (x)))) + +#define MX_FMT(fmtsel) (((fmtsel) & 0x1) == 0 ? mdmx_ob : mdmx_qh) +#define MX_VT(fmtsel) (((fmtsel) & 0x10) == 0 ? sel_elem : \ + (((fmtsel) & 0x18) == 0x10 ? sel_vect : sel_imm)) + +#define QH_ELEM(v,fmtsel) \ + ((signed16)(((v) >> (((fmtsel) & 0xC) << 2)) & 0xFFFF)) +#define OB_ELEM(v,fmtsel) \ + ((unsigned8)(((v) >> (((fmtsel) & 0xE) << 2)) & 0xFF)) + + +typedef signed16 (*QH_FUNC)(signed16, signed16); +typedef unsigned8 (*OB_FUNC)(unsigned8, unsigned8); + +/* vectorized logical operators */ + +static signed16 +AndQH(signed16 ts, signed16 tt) +{ + return (signed16)((unsigned16)ts & (unsigned16)tt); +} + +static unsigned8 +AndOB(unsigned8 ts, unsigned8 tt) +{ + return ts & tt; +} + +static signed16 +NorQH(signed16 ts, signed16 tt) +{ + return (signed16)(((unsigned16)ts | (unsigned16)tt) ^ 0xFFFF); +} + +static unsigned8 +NorOB(unsigned8 ts, unsigned8 tt) +{ + return (ts | tt) ^ 0xFF; +} + +static signed16 +OrQH(signed16 ts, signed16 tt) +{ + return (signed16)((unsigned16)ts | (unsigned16)tt); +} + +static unsigned8 +OrOB(unsigned8 ts, unsigned8 tt) +{ + return ts | tt; +} + +static signed16 +XorQH(signed16 ts, signed16 tt) +{ + return (signed16)((unsigned16)ts ^ (unsigned16)tt); +} + +static unsigned8 +XorOB(unsigned8 ts, unsigned8 tt) +{ + return ts ^ tt; +} + +static signed16 +SLLQH(signed16 ts, signed16 tt) +{ + unsigned32 s = (unsigned32)tt & 0xF; + return (signed16)(((unsigned32)ts << s) & 0xFFFF); +} + +static unsigned8 +SLLOB(unsigned8 ts, unsigned8 tt) +{ + unsigned32 s = tt & 0x7; + return (ts << s) & 0xFF; +} + +static signed16 +SRLQH(signed16 ts, signed16 tt) +{ + unsigned32 s = (unsigned32)tt & 0xF; + return (signed16)((unsigned16)ts >> s); +} + +static unsigned8 +SRLOB(unsigned8 ts, unsigned8 tt) +{ + unsigned32 s = tt & 0x7; + return ts >> s; +} + + +/* Vectorized arithmetic operators. */ + +static signed16 +AddQH(signed16 ts, signed16 tt) +{ + signed32 t = (signed32)ts + (signed32)tt; + return QH_CLAMP(t); +} + +static unsigned8 +AddOB(unsigned8 ts, unsigned8 tt) +{ + unsigned32 t = (unsigned32)ts + (unsigned32)tt; + return OB_CLAMP(t); +} + +static signed16 +SubQH(signed16 ts, signed16 tt) +{ + signed32 t = (signed32)ts - (signed32)tt; + return QH_CLAMP(t); +} + +static unsigned8 +SubOB(unsigned8 ts, unsigned8 tt) +{ + signed32 t; + t = (signed32)ts - (signed32)tt; + if (t < 0) + t = 0; + return (unsigned8)t; +} + +static signed16 +MinQH(signed16 ts, signed16 tt) +{ + return (ts < tt ? ts : tt); +} + +static unsigned8 +MinOB(unsigned8 ts, unsigned8 tt) +{ + return (ts < tt ? ts : tt); +} + +static signed16 +MaxQH(signed16 ts, signed16 tt) +{ + return (ts > tt ? ts : tt); +} + +static unsigned8 +MaxOB(unsigned8 ts, unsigned8 tt) +{ + return (ts > tt ? ts : tt); +} + +static signed16 +MulQH(signed16 ts, signed16 tt) +{ + signed32 t = (signed32)ts * (signed32)tt; + return QH_CLAMP(t); +} + +static unsigned8 +MulOB(unsigned8 ts, unsigned8 tt) +{ + unsigned32 t = (unsigned32)ts * (unsigned32)tt; + return OB_CLAMP(t); +} + +/* "msgn" and "sra" are defined only for QH format. */ + +static signed16 +MsgnQH(signed16 ts, signed16 tt) +{ + signed16 t; + if (ts < 0) + t = (tt == QH_MIN ? QH_MAX : -tt); + else if (ts == 0) + t = 0; + else + t = tt; + return t; +} + + +static signed16 +SRAQH(signed16 ts, signed16 tt) +{ + unsigned32 s = (unsigned32)tt & 0xF; + return (signed16)((signed32)ts >> s); +} + + +/* Dispatch tables for operations that update a CPR. */ + +static const QH_FUNC qh_func[] = { + AndQH, NorQH, OrQH, XorQH, SLLQH, SRLQH, + AddQH, SubQH, MinQH, MaxQH, + MulQH, MsgnQH, SRAQH, NULL, NULL +}; + +static const OB_FUNC ob_func[] = { + AndOB, NorOB, OrOB, XorOB, SLLOB, SRLOB, + AddOB, SubOB, MinOB, MaxOB, + MulOB, NULL, NULL, NULL, NULL +}; + +/* Auxiliary functions for CPR updates. */ + +/* Vector mapping for QH format. */ +static unsigned64 +qh_vector_op(unsigned64 v1, unsigned64 v2, QH_FUNC func) +{ + unsigned64 result = 0; + int i; + signed16 h, h1, h2; + + for (i = 0; i < 64; i += 16) + { + h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16; + h2 = (signed16)(v2 & 0xFFFF); v2 >>= 16; + h = (*func)(h1, h2); + result |= ((unsigned64)((unsigned16)h) << i); + } + return result; +} + +static unsigned64 +qh_map_op(unsigned64 v1, signed16 h2, QH_FUNC func) +{ + unsigned64 result = 0; + int i; + signed16 h, h1; + + for (i = 0; i < 64; i += 16) + { + h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16; + h = (*func)(h1, h2); + result |= ((unsigned64)((unsigned16)h) << i); + } + return result; +} + + +/* Vector operations for OB format. */ + +static unsigned64 +ob_vector_op(unsigned64 v1, unsigned64 v2, OB_FUNC func) +{ + unsigned64 result = 0; + int i; + unsigned8 b, b1, b2; + + for (i = 0; i < 64; i += 8) + { + b1 = v1 & 0xFF; v1 >>= 8; + b2 = v2 & 0xFF; v2 >>= 8; + b = (*func)(b1, b2); + result |= ((unsigned64)b << i); + } + return result; +} + +static unsigned64 +ob_map_op(unsigned64 v1, unsigned8 b2, OB_FUNC func) +{ + unsigned64 result = 0; + int i; + unsigned8 b, b1; + + for (i = 0; i < 64; i += 8) + { + b1 = v1 & 0xFF; v1 >>= 8; + b = (*func)(b1, b2); + result |= ((unsigned64)b << i); + } + return result; +} + + +/* Primary entry for operations that update CPRs. */ +unsigned64 +mdmx_cpr_op(sim_cpu *cpu, + address_word cia, + int op, + unsigned64 op1, + int vt, + MX_fmtsel fmtsel) +{ + unsigned64 op2; + unsigned64 result = 0; + + switch (MX_FMT (fmtsel)) + { + case mdmx_qh: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + result = qh_map_op(op1, QH_ELEM(op2, fmtsel), qh_func[op]); + break; + case sel_vect: + result = qh_vector_op(op1, ValueFPR(vt, fmt_mdmx), qh_func[op]); + break; + case sel_imm: + result = qh_map_op(op1, vt, qh_func[op]); + break; + } + break; + case mdmx_ob: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + result = ob_map_op(op1, OB_ELEM(op2, fmtsel), ob_func[op]); + break; + case sel_vect: + result = ob_vector_op(op1, ValueFPR(vt, fmt_mdmx), ob_func[op]); + break; + case sel_imm: + result = ob_map_op(op1, vt, ob_func[op]); + break; + } + break; + default: + Unpredictable (); + } + + return result; +} + + +/* Operations that update CCs */ + +static void +qh_vector_test(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int cond) +{ + int i; + signed16 h1, h2; + int boolean; + + for (i = 0; i < 4; i++) + { + h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16; + h2 = (signed16)(v2 & 0xFFFF); v2 >>= 16; + boolean = ((cond & MX_C_EQ) && (h1 == h2)) || + ((cond & MX_C_LT) && (h1 < h2)); + SETFCC(i, boolean); + } +} + +static void +qh_map_test(sim_cpu *cpu, unsigned64 v1, signed16 h2, int cond) +{ + int i; + signed16 h1; + int boolean; + + for (i = 0; i < 4; i++) + { + h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16; + boolean = ((cond & MX_C_EQ) && (h1 == h2)) || + ((cond & MX_C_LT) && (h1 < h2)); + SETFCC(i, boolean); + } +} + +static void +ob_vector_test(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int cond) +{ + int i; + unsigned8 b1, b2; + int boolean; + + for (i = 0; i < 8; i++) + { + b1 = v1 & 0xFF; v1 >>= 8; + b2 = v2 & 0xFF; v2 >>= 8; + boolean = ((cond & MX_C_EQ) && (b1 == b2)) || + ((cond & MX_C_LT) && (b1 < b2)); + SETFCC(i, boolean); + } +} + +static void +ob_map_test(sim_cpu *cpu, unsigned64 v1, unsigned8 b2, int cond) +{ + int i; + unsigned8 b1; + int boolean; + + for (i = 0; i < 8; i++) + { + b1 = (unsigned8)(v1 & 0xFF); v1 >>= 8; + boolean = ((cond & MX_C_EQ) && (b1 == b2)) || + ((cond & MX_C_LT) && (b1 < b2)); + SETFCC(i, boolean); + } +} + + +void +mdmx_cc_op(sim_cpu *cpu, + address_word cia, + int cond, + unsigned64 v1, + int vt, + MX_fmtsel fmtsel) +{ + unsigned64 op2; + + switch (MX_FMT (fmtsel)) + { + case mdmx_qh: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + qh_map_test(cpu, v1, QH_ELEM(op2, fmtsel), cond); + break; + case sel_vect: + qh_vector_test(cpu, v1, ValueFPR(vt, fmt_mdmx), cond); + break; + case sel_imm: + qh_map_test(cpu, v1, vt, cond); + break; + } + break; + case mdmx_ob: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + ob_map_test(cpu, v1, OB_ELEM(op2, fmtsel), cond); + break; + case sel_vect: + ob_vector_test(cpu, v1, ValueFPR(vt, fmt_mdmx), cond); + break; + case sel_imm: + ob_map_test(cpu, v1, vt, cond); + break; + } + break; + default: + Unpredictable (); + } +} + + +/* Pick operations. */ + +static unsigned64 +qh_vector_pick(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int tf) +{ + unsigned64 result = 0; + int i, s; + unsigned16 h; + + s = 0; + for (i = 0; i < 4; i++) + { + h = ((GETFCC(i) == tf) ? (v1 & 0xFFFF) : (v2 & 0xFFFF)); + v1 >>= 16; v2 >>= 16; + result |= ((unsigned64)h << s); + s += 16; + } + return result; +} + +static unsigned64 +qh_map_pick(sim_cpu *cpu, unsigned64 v1, signed16 h2, int tf) +{ + unsigned64 result = 0; + int i, s; + unsigned16 h; + + s = 0; + for (i = 0; i < 4; i++) + { + h = (GETFCC(i) == tf) ? (v1 & 0xFFFF) : (unsigned16)h2; + v1 >>= 16; + result |= ((unsigned64)h << s); + s += 16; + } + return result; +} + +static unsigned64 +ob_vector_pick(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int tf) +{ + unsigned64 result = 0; + int i, s; + unsigned8 b; + + s = 0; + for (i = 0; i < 8; i++) + { + b = (GETFCC(i) == tf) ? (v1 & 0xFF) : (v2 & 0xFF); + v1 >>= 8; v2 >>= 8; + result |= ((unsigned64)b << s); + s += 8; + } + return result; +} + +static unsigned64 +ob_map_pick(sim_cpu *cpu, unsigned64 v1, unsigned8 b2, int tf) +{ + unsigned64 result = 0; + int i, s; + unsigned8 b; + + s = 0; + for (i = 0; i < 8; i++) + { + b = (GETFCC(i) == tf) ? (v1 & 0xFF) : b2; + v1 >>= 8; + result |= ((unsigned64)b << s); + s += 8; + } + return result; +} + + +unsigned64 +mdmx_pick_op(sim_cpu *cpu, + address_word cia, + int tf, + unsigned64 v1, + int vt, + MX_fmtsel fmtsel) +{ + unsigned64 result = 0; + unsigned64 op2; + + switch (MX_FMT (fmtsel)) + { + case mdmx_qh: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + result = qh_map_pick(cpu, v1, QH_ELEM(op2, fmtsel), tf); + break; + case sel_vect: + result = qh_vector_pick(cpu, v1, ValueFPR(vt, fmt_mdmx), tf); + break; + case sel_imm: + result = qh_map_pick(cpu, v1, vt, tf); + break; + } + break; + case mdmx_ob: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + result = ob_map_pick(cpu, v1, OB_ELEM(op2, fmtsel), tf); + break; + case sel_vect: + result = ob_vector_pick(cpu, v1, ValueFPR(vt, fmt_mdmx), tf); + break; + case sel_imm: + result = ob_map_pick(cpu, v1, vt, tf); + break; + } + break; + default: + Unpredictable (); + } + return result; +} + + +/* Accumulators. */ + +typedef void (*QH_ACC)(signed48 *a, signed16 ts, signed16 tt); + +static void +AccAddAQH(signed48 *a, signed16 ts, signed16 tt) +{ + *a += (signed48)ts + (signed48)tt; +} + +static void +AccAddLQH(signed48 *a, signed16 ts, signed16 tt) +{ + *a = (signed48)ts + (signed48)tt; +} + +static void +AccMulAQH(signed48 *a, signed16 ts, signed16 tt) +{ + *a += (signed48)ts * (signed48)tt; +} + +static void +AccMulLQH(signed48 *a, signed16 ts, signed16 tt) +{ + *a = (signed48)ts * (signed48)tt; +} + +static void +SubMulAQH(signed48 *a, signed16 ts, signed16 tt) +{ + *a -= (signed48)ts * (signed48)tt; +} + +static void +SubMulLQH(signed48 *a, signed16 ts, signed16 tt) +{ + *a = -((signed48)ts * (signed48)tt); +} + +static void +AccSubAQH(signed48 *a, signed16 ts, signed16 tt) +{ + *a += (signed48)ts - (signed48)tt; +} + +static void +AccSubLQH(signed48 *a, signed16 ts, signed16 tt) +{ + *a = (signed48)ts - (signed48)tt; +} + + +typedef void (*OB_ACC)(signed24 *acc, unsigned8 ts, unsigned8 tt); + +static void +AccAddAOB(signed24 *a, unsigned8 ts, unsigned8 tt) +{ + *a += (signed24)ts + (signed24)tt; +} + +static void +AccAddLOB(signed24 *a, unsigned8 ts, unsigned8 tt) +{ + *a = (signed24)ts + (signed24)tt; +} + +static void +AccMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt) +{ + *a += (signed24)ts * (signed24)tt; +} + +static void +AccMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt) +{ + *a = (signed24)ts * (signed24)tt; +} + +static void +SubMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt) +{ + *a -= (signed24)ts * (signed24)tt; +} + +static void +SubMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt) +{ + *a = -((signed24)ts * (signed24)tt); +} + +static void +AccSubAOB(signed24 *a, unsigned8 ts, unsigned8 tt) +{ + *a += (signed24)ts - (signed24)tt; +} + +static void +AccSubLOB(signed24 *a, unsigned8 ts, unsigned8 tt) +{ + *a = (signed24)ts - (signed24)tt; +} + + +/* Dispatch tables for operations that update a CPR. */ + +static const QH_ACC qh_acc[] = { + AccAddAQH, AccAddAQH, AccMulAQH, AccMulLQH, + SubMulAQH, SubMulLQH, AccSubAQH, AccSubLQH +}; + +static const OB_ACC ob_acc[] = { + AccAddAOB, AccAddLOB, AccMulAOB, AccMulLOB, + SubMulAOB, SubMulLOB, AccSubAOB, AccSubLOB +}; + + +static void +qh_vector_acc(signed48 a[], unsigned64 v1, unsigned64 v2, QH_ACC acc) +{ + int i; + signed16 h1, h2; + + for (i = 0; i < 4; i++) + { + h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16; + h2 = (signed16)(v2 & 0xFFFF); v2 >>= 16; + (*acc)(&a[i], h1, h2); + } +} + +static void +qh_map_acc(signed48 a[], unsigned64 v1, signed16 h2, QH_ACC acc) +{ + int i; + signed16 h1; + + for (i = 0; i < 4; i++) + { + h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16; + (*acc)(&a[i], h1, h2); + } +} + +static void +ob_vector_acc(signed24 a[], unsigned64 v1, unsigned64 v2, OB_ACC acc) +{ + int i; + unsigned8 b1, b2; + + for (i = 0; i < 8; i++) + { + b1 = v1 & 0xFF; v1 >>= 8; + b2 = v2 & 0xFF; v2 >>= 8; + (*acc)(&a[i], b1, b2); + } +} + +static void +ob_map_acc(signed24 a[], unsigned64 v1, unsigned8 b2, OB_ACC acc) +{ + int i; + unsigned8 b1; + + for (i = 0; i < 8; i++) + { + b1 = v1 & 0xFF; v1 >>= 8; + (*acc)(&a[i], b1, b2); + } +} + + +/* Primary entry for operations that accumulate */ +void +mdmx_acc_op(sim_cpu *cpu, + address_word cia, + int op, + unsigned64 op1, + int vt, + MX_fmtsel fmtsel) +{ + unsigned64 op2; + + switch (MX_FMT (fmtsel)) + { + case mdmx_qh: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + qh_map_acc(ACC.qh, op1, QH_ELEM(op2, fmtsel), qh_acc[op]); + break; + case sel_vect: + qh_vector_acc(ACC.qh, op1, ValueFPR(vt, fmt_mdmx), qh_acc[op]); + break; + case sel_imm: + qh_map_acc(ACC.qh, op1, vt, qh_acc[op]); + break; + } + break; + case mdmx_ob: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + ob_map_acc(ACC.ob, op1, OB_ELEM(op2, fmtsel), ob_acc[op]); + break; + case sel_vect: + ob_vector_acc(ACC.ob, op1, ValueFPR(vt, fmt_mdmx), ob_acc[op]); + break; + case sel_imm: + ob_map_acc(ACC.ob, op1, op2, ob_acc[op]); + break; + } + break; + default: + Unpredictable (); + } +} + + +/* Reading and writing accumulator (no conversion). */ + +unsigned64 +mdmx_rac_op(sim_cpu *cpu, + address_word cia, + int op, + int fmt) +{ + unsigned64 result; + unsigned int shift; + int i; + + shift = op; /* L = 00, M = 01, H = 10. */ + result = 0; + + switch (fmt) + { + case MX_FMT_QH: + shift <<= 4; /* 16 bits per element. */ + for (i = 3; i >= 0; --i) + { + result <<= 16; + result |= ((ACC.qh[i] >> shift) & 0xFFFF); + } + break; + case MX_FMT_OB: + shift <<= 3; /* 8 bits per element. */ + for (i = 7; i >= 0; --i) + { + result <<= 8; + result |= ((ACC.ob[i] >> shift) & 0xFF); + } + break; + default: + Unpredictable (); + } + return result; +} + +void +mdmx_wacl(sim_cpu *cpu, + address_word cia, + int fmt, + unsigned64 vs, + unsigned64 vt) +{ + int i; + + switch (fmt) + { + case MX_FMT_QH: + for (i = 0; i < 4; i++) + { + signed32 s = (signed16)(vs & 0xFFFF); + ACC.qh[i] = ((signed48)s << 16) | (vt & 0xFFFF); + vs >>= 16; vt >>= 16; + } + break; + case MX_FMT_OB: + for (i = 0; i < 8; i++) + { + signed16 s = (signed8)(vs & 0xFF); + ACC.ob[i] = ((signed24)s << 8) | (vt & 0xFF); + vs >>= 8; vt >>= 8; + } + break; + default: + Unpredictable (); + } +} + +void +mdmx_wach(sim_cpu *cpu, + address_word cia, + int fmt, + unsigned64 vs) +{ + int i; + + switch (fmt) + { + case MX_FMT_QH: + for (i = 0; i < 4; i++) + { + signed32 s = (signed16)(vs & 0xFFFF); + ACC.qh[i] &= ~((signed48)0xFFFF << 32); + ACC.qh[i] |= ((signed48)s << 32); + vs >>= 16; + } + break; + case MX_FMT_OB: + for (i = 0; i < 8; i++) + { + ACC.ob[i] &= ~((signed24)0xFF << 16); + ACC.ob[i] |= ((signed24)(vs & 0xFF) << 16); + vs >>= 8; + } + break; + default: + Unpredictable (); + } +} + + +/* Reading and writing accumulator (rounding conversions). + Enumerating function guarantees s >= 0 for QH ops. */ + +typedef signed16 (*QH_ROUND)(signed48 a, signed16 s); + +#define QH_BIT(n) ((unsigned48)1 << (n)) +#define QH_ONES(n) (((unsigned48)1 << (n))-1) + +static signed16 +RNASQH(signed48 a, signed16 s) +{ + signed48 t; + signed16 result = 0; + + if (s > 48) + result = 0; + else + { + t = (a >> s); + if ((a & QH_BIT(47)) == 0) + { + if (s > 0 && ((a >> (s-1)) & 1) == 1) + t++; + if (t > QH_MAX) + t = QH_MAX; + } + else + { + if (s > 0 && ((a >> (s-1)) & 1) == 1) + { + if (s > 1 && ((unsigned48)a & QH_ONES(s-1)) != 0) + t++; + } + if (t < QH_MIN) + t = QH_MIN; + } + result = (signed16)t; + } + return result; +} + +static signed16 +RNAUQH(signed48 a, signed16 s) +{ + unsigned48 t; + signed16 result; + + if (s > 48) + result = 0; + else if (s == 48) + result = ((unsigned48)a & MASK48) >> 47; + else + { + t = ((unsigned48)a & MASK48) >> s; + if (s > 0 && ((a >> (s-1)) & 1) == 1) + t++; + if (t > 0xFFFF) + t = 0xFFFF; + result = (signed16)t; + } + return result; +} + +static signed16 +RNESQH(signed48 a, signed16 s) +{ + signed48 t; + signed16 result = 0; + + if (s > 47) + result = 0; + else + { + t = (a >> s); + if (s > 0 && ((a >> (s-1)) & 1) == 1) + { + if (s == 1 || (a & QH_ONES(s-1)) == 0) + t += t & 1; + else + t += 1; + } + if ((a & QH_BIT(47)) == 0) + { + if (t > QH_MAX) + t = QH_MAX; + } + else + { + if (t < QH_MIN) + t = QH_MIN; + } + result = (signed16)t; + } + return result; +} + +static signed16 +RNEUQH(signed48 a, signed16 s) +{ + unsigned48 t; + signed16 result; + + if (s > 48) + result = 0; + else if (s == 48) + result = ((unsigned48)a > QH_BIT(47) ? 1 : 0); + else + { + t = ((unsigned48)a & MASK48) >> s; + if (s > 0 && ((a >> (s-1)) & 1) == 1) + { + if (s > 1 && (a & QH_ONES(s-1)) != 0) + t++; + else + t += t & 1; + } + if (t > 0xFFFF) + t = 0xFFFF; + result = (signed16)t; + } + return result; +} + +static signed16 +RZSQH(signed48 a, signed16 s) +{ + signed48 t; + signed16 result = 0; + + if (s > 47) + result = 0; + else + { + t = (a >> s); + if ((a & QH_BIT(47)) == 0) + { + if (t > QH_MAX) + t = QH_MAX; + } + else + { + if (t < QH_MIN) + t = QH_MIN; + } + result = (signed16)t; + } + return result; +} + +static signed16 +RZUQH(signed48 a, signed16 s) +{ + unsigned48 t; + signed16 result = 0; + + if (s > 48) + result = 0; + else if (s == 48) + result = ((unsigned48)a > QH_BIT(47) ? 1 : 0); + else + { + t = ((unsigned48)a & MASK48) >> s; + if (t > 0xFFFF) + t = 0xFFFF; + result = (signed16)t; + } + return result; +} + + +typedef unsigned8 (*OB_ROUND)(signed24 a, unsigned8 s); + +#define OB_BIT(n) ((unsigned24)1 << (n)) +#define OB_ONES(n) (((unsigned24)1 << (n))-1) + +static unsigned8 +RNAUOB(signed24 a, unsigned8 s) +{ + unsigned8 result; + unsigned24 t; + + if (s > 24) + result = 0; + else if (s == 24) + result = ((unsigned24)a & MASK24) >> 23; + else + { + t = ((unsigned24)a & MASK24) >> s; + if (s > 0 && ((a >> (s-1)) & 1) == 1) + t ++; + result = OB_CLAMP(t); + } + return result; +} + +static unsigned8 +RNEUOB(signed24 a, unsigned8 s) +{ + unsigned8 result; + unsigned24 t; + + if (s > 24) + result = 0; + else if (s == 24) + result = (((unsigned24)a & MASK24) > OB_BIT(23) ? 1 : 0); + else + { + t = ((unsigned24)a & MASK24) >> s; + if (s > 0 && ((a >> (s-1)) & 1) == 1) + { + if (s > 1 && (a & OB_ONES(s-1)) != 0) + t++; + else + t += t & 1; + } + result = OB_CLAMP(t); + } + return result; +} + +static unsigned8 +RZUOB(signed24 a, unsigned8 s) +{ + unsigned8 result; + unsigned24 t; + + if (s >= 24) + result = 0; + else + { + t = ((unsigned24)a & MASK24) >> s; + result = OB_CLAMP(t); + } + return result; +} + + +static const QH_ROUND qh_round[] = { + RNASQH, RNAUQH, RNESQH, RNEUQH, RZSQH, RZUQH +}; + +static const OB_ROUND ob_round[] = { + NULL, RNAUOB, NULL, RNEUOB, NULL, RZUOB +}; + + +static unsigned64 +qh_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, QH_ROUND round) +{ + unsigned64 result = 0; + int i, s; + signed16 h, h2; + + s = 0; + for (i = 0; i < 4; i++) + { + h2 = (signed16)(v2 & 0xFFFF); + if (h2 >= 0) + h = (*round)(ACC.qh[i], h2); + else + { + UnpredictableResult (); + h = 0xdead; + } + v2 >>= 16; + result |= ((unsigned64)((unsigned16)h) << s); + s += 16; + } + return result; +} + +static unsigned64 +qh_map_round(sim_cpu *cpu, address_word cia, signed16 h2, QH_ROUND round) +{ + unsigned64 result = 0; + int i, s; + signed16 h; + + s = 0; + for (i = 0; i < 4; i++) + { + if (h2 >= 0) + h = (*round)(ACC.qh[i], h2); + else + { + UnpredictableResult (); + h = 0xdead; + } + result |= ((unsigned64)((unsigned16)h) << s); + s += 16; + } + return result; +} + +static unsigned64 +ob_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, OB_ROUND round) +{ + unsigned64 result = 0; + int i, s; + unsigned8 b, b2; + + s = 0; + for (i = 0; i < 8; i++) + { + b2 = v2 & 0xFF; v2 >>= 8; + b = (*round)(ACC.ob[i], b2); + result |= ((unsigned64)b << s); + s += 8; + } + return result; +} + +static unsigned64 +ob_map_round(sim_cpu *cpu, address_word cia, unsigned8 b2, OB_ROUND round) +{ + unsigned64 result = 0; + int i, s; + unsigned8 b; + + s = 0; + for (i = 0; i < 8; i++) + { + b = (*round)(ACC.ob[i], b2); + result |= ((unsigned64)b << s); + s += 8; + } + return result; +} + + +unsigned64 +mdmx_round_op(sim_cpu *cpu, + address_word cia, + int rm, + int vt, + MX_fmtsel fmtsel) +{ + unsigned64 op2; + unsigned64 result = 0; + + switch (MX_FMT (fmtsel)) + { + case mdmx_qh: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + result = qh_map_round(cpu, cia, QH_ELEM(op2, fmtsel), qh_round[rm]); + break; + case sel_vect: + op2 = ValueFPR(vt, fmt_mdmx); + result = qh_vector_round(cpu, cia, op2, qh_round[rm]); + break; + case sel_imm: + result = qh_map_round(cpu, cia, vt, qh_round[rm]); + break; + } + break; + case mdmx_ob: + switch (MX_VT (fmtsel)) + { + case sel_elem: + op2 = ValueFPR(vt, fmt_mdmx); + result = ob_map_round(cpu, cia, OB_ELEM(op2, fmtsel), ob_round[rm]); + break; + case sel_vect: + op2 = ValueFPR(vt, fmt_mdmx); + result = ob_vector_round(cpu, cia, op2, ob_round[rm]); + break; + case sel_imm: + result = ob_map_round(cpu, cia, vt, ob_round[rm]); + break; + } + break; + default: + Unpredictable (); + } + + return result; +} + + +/* Shuffle operation. */ + +typedef struct { + enum {vs, ss, vt} source; + unsigned int index; +} sh_map; + +static const sh_map ob_shuffle[][8] = { + /* MDMX 2.0 encodings (3-4, 6-7). */ + /* vr5400 encoding (5), otherwise. */ + { }, /* RSVD */ + {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* RSVD */ + {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}}, /* RSVD */ + {{vs,0}, {ss,0}, {vs,1}, {ss,1}, {vs,2}, {ss,2}, {vs,3}, {ss,3}}, /* upsl */ + {{vt,1}, {vt,3}, {vt,5}, {vt,7}, {vs,1}, {vs,3}, {vs,5}, {vs,7}}, /* pach */ + {{vt,0}, {vt,2}, {vt,4}, {vt,6}, {vs,0}, {vs,2}, {vs,4}, {vs,6}}, /* pacl */ + {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* mixh */ + {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}} /* mixl */ +}; + +static const sh_map qh_shuffle[][4] = { + {{vt,2}, {vs,2}, {vt,3}, {vs,3}}, /* mixh */ + {{vt,0}, {vs,0}, {vt,1}, {vs,1}}, /* mixl */ + {{vt,1}, {vt,3}, {vs,1}, {vs,3}}, /* pach */ + { }, /* RSVD */ + {{vt,1}, {vs,0}, {vt,3}, {vs,2}}, /* bfla */ + { }, /* RSVD */ + {{vt,2}, {vt,3}, {vs,2}, {vs,3}}, /* repa */ + {{vt,0}, {vt,1}, {vs,0}, {vs,1}} /* repb */ +}; + + +unsigned64 +mdmx_shuffle(sim_cpu *cpu, + address_word cia, + int shop, + unsigned64 op1, + unsigned64 op2) +{ + unsigned64 result = 0; + int i, s; + int op; + + if ((shop & 0x3) == 0x1) /* QH format. */ + { + op = shop >> 2; + s = 0; + for (i = 0; i < 4; i++) + { + unsigned64 v; + + switch (qh_shuffle[op][i].source) + { + case vs: + v = op1; + break; + case vt: + v = op2; + break; + default: + Unpredictable (); + v = 0; + } + result |= (((v >> 16*qh_shuffle[op][i].index) & 0xFFFF) << s); + s += 16; + } + } + else if ((shop & 0x1) == 0x0) /* OB format. */ + { + op = shop >> 1; + s = 0; + for (i = 0; i < 8; i++) + { + unsigned8 b; + unsigned int ishift = 8*ob_shuffle[op][i].index; + + switch (ob_shuffle[op][i].source) + { + case vs: + b = (op1 >> ishift) & 0xFF; + break; + case ss: + b = ((op1 >> ishift) & 0x80) ? 0xFF : 0; + break; + case vt: + b = (op2 >> ishift) & 0xFF; + break; + default: + Unpredictable (); + b = 0; + } + result |= ((unsigned64)b << s); + s += 8; + } + } + else + Unpredictable (); + + return result; +} diff --git a/sim/mips/mdmx.igen b/sim/mips/mdmx.igen new file mode 100644 index 00000000000..ddc075c6aea --- /dev/null +++ b/sim/mips/mdmx.igen @@ -0,0 +1,550 @@ +// -*- C -*- + +// Simulator definition for the MIPS MDMX ASE. +// Copyright (C) 2002 Free Software Foundation, Inc. +// Contributed by Broadcom Corporation (SiByte). +// +// This file is part of GDB, the GNU debugger. +// +// 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, 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., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// Reference: MIPS64 Architecture Volume IV-b: +// The MDMX Application-Specific Extension + +// Notes on "format selectors" (FMTSEL): +// +// A selector with final bit 0 indicates OB format. +// A selector with final bits 01 indicates QH format. +// A selector with final bits 11 has UNPREDICTABLE result per the spec. +// +// Similarly, for the single-bit fields which differentiate between +// formats (FMTOP), 0 is OB format and 1 is QH format. + + +// Helper: +// +// Check whether MDMX is usable, and if not signal an appropriate exception. +// + +:function:::void:check_mdmx:instruction_word insn +*mdmx: +{ + if (! COP_Usable (1)) + SignalExceptionCoProcessorUnusable (1); + if ((SR & (status_MX|status_FR)) != (status_MX|status_FR)) + SignalExceptionMDMX (); + check_u64 (SD_, insn); +} + + +// Helper: +// +// Check whether a given MDMX format selector indicates a valid and usable +// format, and if not signal an appropriate exception. +// + +:function:::int:check_mdmx_fmtsel:instruction_word insn, int fmtsel +*mdmx: +{ + switch (fmtsel & 0x03) + { + case 0x00: /* ob */ + case 0x02: + case 0x01: /* qh */ + return 1; + case 0x03: /* UNPREDICTABLE */ + SignalException (ReservedInstruction, insn); + return 0; + } + return 0; +} + + +// Helper: +// +// Check whether a given MDMX format bit indicates a valid and usable +// format, and if not signal an appropriate exception. +// + +:function:::int:check_mdmx_fmtop:instruction_word insn, int fmtop +*mdmx: +{ + switch (fmtop & 0x01) + { + case 0x00: /* ob */ + case 0x01: /* qh */ + return 1; + } + return 0; +} + + +:%s::::FMTSEL:int fmtsel +*mdmx: +{ + if ((fmtsel & 0x1) == 0) + return "ob"; + else if ((fmtsel & 0x3) == 1) + return "qh"; + else + return "?"; +} + + +:%s::::FMTOP:int fmtop +*mdmx: +{ + switch (fmtop) + { + case 0: return "ob"; + case 1: return "qh"; + default: return "?"; + } +} + + +:%s::::SHOP:int shop +*mdmx: +{ + if ((shop & 0x11) == 0x00) + switch ((shop >> 1) & 0x07) + { + case 3: return "upsl.ob"; + case 4: return "pach.ob"; + case 6: return "mixh.ob"; + case 7: return "mixl.ob"; + default: return "?"; + } + else if ((shop & 0x03) == 0x01) + switch ((shop >> 2) & 0x07) + { + case 0: return "mixh.qh"; + case 1: return "mixl.qh"; + case 2: return "pach.qh"; + case 4: return "bfla.qh"; + case 6: return "repa.qh"; + case 7: return "repb.qh"; + default: return "?"; + } + else + return "?"; +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,001011:MDMX:64::ADD.fmt +"add.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Add(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,0,0000,110111:MDMX:64::ADDA.fmt +"adda.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_AddA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,1,0000,110111:MDMX:64::ADDL.fmt +"addl.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_AddL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL); +} + + +011110,00,3.IMM,5.VT,5.VS,5.VD,0110,1.FMTOP,0:MDMX:64::ALNI.fmt +"alni.%s v, v, v, " +*mdmx: +{ + unsigned64 result; + int s; + check_mdmx (SD_, instruction_0); + check_mdmx_fmtop (SD_, instruction_0, FMTOP); + s = (IMM << 3); + result = ValueFPR(VS,fmt_mdmx) << s; + if (s != 0) // x86 gcc treats >> 64 as >> 0 + result |= ValueFPR(VT,fmt_mdmx) >> (64 - s); + StoreFPR(VD,fmt_mdmx,result); +} + + +011110,5.RS,5.VT,5.VS,5.VD,0110,1.FMTOP,1:MDMX:64::ALNV.fmt +"alnv.%s v, v, v, r" +*mdmx: +{ + unsigned64 result; + int s; + check_mdmx (SD_, instruction_0); + check_mdmx_fmtop (SD_, instruction_0, FMTOP); + s = ((GPR[RS] & 0x7) << 3); + result = ValueFPR(VS,fmt_mdmx) << s; + if (s != 0) // x86 gcc treats >> 64 as >> 0 + result |= ValueFPR(VT,fmt_mdmx) >> (64 - s); + StoreFPR(VD,fmt_mdmx,result); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,001100:MDMX:64::AND.fmt +"and.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_And(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,00000,000001:MDMX:64::C.EQ.fmt +"c.eq.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_EQ,VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,00000,000101:MDMX:64::C.LE.fmt +"c.le.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_LT|MX_C_EQ,VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,00000,000100:MDMX:64::C.LT.fmt +"c.lt.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_LT,VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,000111:MDMX:64::MAX.fmt +"max.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Max(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,000110:MDMX:64::MIN.fmt +"min.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Min(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,3.SEL,01,5.VT,5.VS,5.VD,000000:MDMX:64::MSGN.QH +"msgn.qh v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + StoreFPR(VD,fmt_mdmx,MX_Msgn(ValueFPR(VS,fmt_mdmx),VT,qh_fmtsel(SEL))); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,110000:MDMX:64::MUL.fmt +"mul.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Mul(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,0,0000,110011:MDMX:64::MULA.fmt +"mula.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_MulA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,1,0000,110011:MDMX:64::MULL.fmt +"mull.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_MulL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,0,0000,110010:MDMX:64::MULS.fmt +"muls.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_MulS(ValueFPR(VS,fmt_mdmx),VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,1,0000,110010:MDMX:64::MULSL.fmt +"mulsl.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_MulSL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,001111:MDMX:64::NOR.fmt +"nor.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Nor(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,001110:MDMX:64::OR.fmt +"or.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Or(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,000010:MDMX:64::PICKF.fmt +"pickf.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Pick(0,ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,000011:MDMX:64::PICKT.fmt +"pickt.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Pick(1,ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,1000,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACH.fmt +"rach.%s v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + check_mdmx_fmtop (SD_, instruction_0, FMTOP); + StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_H,FMTOP)); +} + + +011110,0000,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACL.fmt +"racl.%s v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + check_mdmx_fmtop (SD_, instruction_0, FMTOP); + StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_L,FMTOP)); +} + + +011110,0100,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACM.fmt +"racm.%s v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + check_mdmx_fmtop (SD_, instruction_0, FMTOP); + StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_M,FMTOP)); +} + + +011110,3.SEL,01,5.VT,00000,5.VD,100101:MDMX:64::RNAS.QH +"rnas.qh v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + StoreFPR(VD,fmt_mdmx,MX_RNAS(VT,qh_fmtsel(SEL))); +} + + +011110,5.FMTSEL,5.VT,00000,5.VD,100001:MDMX:64::RNAU.fmt +"rnau.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_RNAU(VT,FMTSEL)); +} + + +011110,3.SEL,01,5.VT,00000,5.VD,100110:MDMX:64::RNES.QH +"rnes.qh v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + StoreFPR(VD,fmt_mdmx,MX_RNES(VT,qh_fmtsel(SEL))); +} + + +011110,5.FMTSEL,5.VT,00000,5.VD,100010:MDMX:64::RNEU.fmt +"rneu.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_RNEU(VT,FMTSEL)); +} + + +011110,3.SEL,01,5.VT,00000,5.VD,100100:MDMX:64::RZS.QH +"rzs.qh v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + StoreFPR(VD,fmt_mdmx,MX_RZS(VT,qh_fmtsel(SEL))); +} + + +011110,5.FMTSEL,5.VT,00000,5.VD,100000:MDMX:64::RZU.fmt +"rzu.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_RZU(VT,FMTSEL)); +} + + +011110,5.SHOP,5.VT,5.VS,5.VD,011111:MDMX:64::SHFL.op.fmt +"shfl.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, SHOP)) + StoreFPR(VD,fmt_mdmx,MX_SHFL(SHOP,ValueFPR(VS,fmt_mdmx),ValueFPR(VT,fmt_mdmx))); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,010000:MDMX:64::SLL.fmt +"sll.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_ShiftLeftLogical(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,3.SEL,01,5.VT,5.VS,5.VD,010011:MDMX:64::SRA.QH +"sra.qh v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + StoreFPR(VD,fmt_mdmx,MX_ShiftRightArith(ValueFPR(VS,fmt_mdmx),VT,qh_fmtsel(SEL))); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,010010:MDMX:64::SRL.fmt +"srl.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_ShiftRightLogical(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,001010:MDMX:64::SUB.fmt +"sub.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Sub(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} + + +011110,5.FMTSEL,5.VT,5.VS,0,0000,110110:MDMX:64::SUBA.fmt +"suba.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_SubA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL); +} + + +011110,5.FMTSEL,5.VT,5.VS,1,0000,110110:MDMX:64::SUBL.fmt +"subl.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + MX_SubL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL); +} + + +011110,1000,1.FMTOP,00000,5.VS,00000,111110:MDMX:64::WACH.fmt +"wach.%s v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + check_mdmx_fmtop (SD_, instruction_0, FMTOP); + MX_WACH(FMTOP,ValueFPR(VS,fmt_mdmx)); +} + + +011110,0000,1.FMTOP,5.VT,5.VS,00000,111110:MDMX:64::WACL.fmt +"wacl.%s v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + check_mdmx_fmtop (SD_, instruction_0, FMTOP); + MX_WACL(FMTOP,ValueFPR(VS,fmt_mdmx),ValueFPR(VT,fmt_mdmx)); +} + + +011110,5.FMTSEL,5.VT,5.VS,5.VD,001101:MDMX:64::XOR.fmt +"xor.%s v, v, v" +*mdmx: +{ + check_mdmx (SD_, instruction_0); + if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL)) + StoreFPR(VD,fmt_mdmx,MX_Xor(ValueFPR(VS,fmt_mdmx),VT,FMTSEL)); +} diff --git a/sim/mips/mips.igen b/sim/mips/mips.igen index cd96766d885..5416f068228 100644 --- a/sim/mips/mips.igen +++ b/sim/mips/mips.igen @@ -61,7 +61,9 @@ // MIPS Application Specific Extensions (ASEs) // // Instructions for the ASEs are in separate .igen files. +// ASEs add instructions on to a base ISA. :model:::mips16:mips16: // m16.igen (and m16.dc) +:model:::mdmx:mdmx: // mdmx.igen // Pseudo instructions known by IGEN @@ -5054,6 +5056,7 @@ :include:::m16.igen +:include:::mdmx.igen :include:::tx.igen :include:::vr.igen diff --git a/sim/mips/sim-main.h b/sim/mips/sim-main.h index bcdcd80e3fd..08d2e608b4e 100644 --- a/sim/mips/sim-main.h +++ b/sim/mips/sim-main.h @@ -296,6 +296,24 @@ enum float_operation }; +/* The internal representation of an MDMX accumulator. + Note that 24 and 48 bit accumulator elements are represented in + 32 or 64 bits. Since the accumulators are 2's complement with + overflow suppressed, high-order bits can be ignored in most contexts. */ + +typedef signed32 signed24; +typedef signed64 signed48; + +typedef union { + signed24 ob[8]; + signed48 qh[4]; +} MDMX_accumulator; + + +/* Conventional system arguments. */ +#define SIM_STATE sim_cpu *cpu, address_word cia +#define SIM_ARGS CPU, cia + struct _sim_cpu { @@ -439,6 +457,10 @@ struct _sim_cpu { pending_write_queue pending; + /* The MDMX accumulator (used only for MDMX ASE). */ + MDMX_accumulator acc; +#define ACC ((CPU)->acc) + /* LLBIT = Load-Linked bit. A bit of "virtual" state used by atomic read-write instructions. It is set when a linked load occurs. It is tested and cleared by the conditional store. It is cleared @@ -707,6 +729,107 @@ decode_coproc (SD, CPU, cia, (instruction)) int sim_monitor (SIM_DESC sd, sim_cpu *cpu, address_word cia, unsigned int arg); +/* MDMX access. */ + +typedef unsigned int MX_fmtsel; /* MDMX format select field (5 bits). */ +#define ob_fmtsel(sel) (((sel)<<1)|0x0) +#define qh_fmtsel(sel) (((sel)<<2)|0x1) + +#define fmt_mdmx fmt_uninterpreted + +#define MX_VECT_AND (0) +#define MX_VECT_NOR (1) +#define MX_VECT_OR (2) +#define MX_VECT_XOR (3) +#define MX_VECT_SLL (4) +#define MX_VECT_SRL (5) + +#define MX_VECT_ADD (6) +#define MX_VECT_SUB (7) +#define MX_VECT_MIN (8) +#define MX_VECT_MAX (9) +#define MX_VECT_MUL (10) +#define MX_VECT_MSGN (11) +#define MX_VECT_SRA (12) + +unsigned64 mdmx_cpr_op (SIM_STATE, int op, unsigned64 op1, int vt, MX_fmtsel fmtsel); +#define MX_Add(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_ADD, op1, vt, fmtsel) +#define MX_And(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_AND, op1, vt, fmtsel) +#define MX_Max(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_MAX, op1, vt, fmtsel) +#define MX_Min(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_MIN, op1, vt, fmtsel) +#define MX_Msgn(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_MSGN, op1, vt, fmtsel) +#define MX_Mul(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_MUL, op1, vt, fmtsel) +#define MX_Nor(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_NOR, op1, vt, fmtsel) +#define MX_Or(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_OR, op1, vt, fmtsel) +#define MX_ShiftLeftLogical(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_SLL, op1, vt, fmtsel) +#define MX_ShiftRightArith(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_SRA, op1, vt, fmtsel) +#define MX_ShiftRightLogical(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_SRL, op1, vt, fmtsel) +#define MX_Sub(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_SUB, op1, vt, fmtsel) +#define MX_Xor(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_XOR, op1, vt, fmtsel) + +#define MX_C_EQ 0x1 +#define MX_C_LT 0x4 + +void mdmx_cc_op (SIM_STATE, int cond, unsigned64 op1, int vt, MX_fmtsel fmtsel); +#define MX_Comp(op1,cond,vt,fmtsel) mdmx_cc_op(SIM_ARGS, cond, op1, vt, fmtsel) + +unsigned64 mdmx_pick_op (SIM_STATE, int tf, unsigned64 op1, int vt, MX_fmtsel fmtsel); +#define MX_Pick(tf,op1,vt,fmtsel) mdmx_pick_op(SIM_ARGS, tf, op1, vt, fmtsel) + +#define MX_VECT_ADDA (0) +#define MX_VECT_ADDL (1) +#define MX_VECT_MULA (2) +#define MX_VECT_MULL (3) +#define MX_VECT_MULS (4) +#define MX_VECT_MULSL (5) +#define MX_VECT_SUBA (6) +#define MX_VECT_SUBL (7) + +void mdmx_acc_op (SIM_STATE, int op, unsigned64 op1, int vt, MX_fmtsel fmtsel); +#define MX_AddA(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_ADDA, op1, vt, fmtsel) +#define MX_AddL(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_ADDL, op1, vt, fmtsel) +#define MX_MulA(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_MULA, op1, vt, fmtsel) +#define MX_MulL(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_MULL, op1, vt, fmtsel) +#define MX_MulS(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_MULS, op1, vt, fmtsel) +#define MX_MulSL(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_MULSL, op1, vt, fmtsel) +#define MX_SubA(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_SUBA, op1, vt, fmtsel) +#define MX_SubL(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_SUBL, op1, vt, fmtsel) + +#define MX_FMT_OB (0) +#define MX_FMT_QH (1) + +/* The following codes chosen to indicate the units of shift. */ +#define MX_RAC_L (0) +#define MX_RAC_M (1) +#define MX_RAC_H (2) + +unsigned64 mdmx_rac_op (SIM_STATE, int, int); +#define MX_RAC(op,fmt) mdmx_rac_op(SIM_ARGS, op, fmt) + +void mdmx_wacl (SIM_STATE, int, unsigned64, unsigned64); +#define MX_WACL(fmt,vs,vt) mdmx_wacl(SIM_ARGS, fmt, vs, vt) +void mdmx_wach (SIM_STATE, int, unsigned64); +#define MX_WACH(fmt,vs) mdmx_wach(SIM_ARGS, fmt, vs) + +#define MX_RND_AS (0) +#define MX_RND_AU (1) +#define MX_RND_ES (2) +#define MX_RND_EU (3) +#define MX_RND_ZS (4) +#define MX_RND_ZU (5) + +unsigned64 mdmx_round_op (SIM_STATE, int, int, MX_fmtsel); +#define MX_RNAS(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_AS, vt, fmt) +#define MX_RNAU(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_AU, vt, fmt) +#define MX_RNES(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_ES, vt, fmt) +#define MX_RNEU(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_EU, vt, fmt) +#define MX_RZS(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_ZS, vt, fmt) +#define MX_RZU(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_ZU, vt, fmt) + +unsigned64 mdmx_shuffle (SIM_STATE, int, unsigned64, unsigned64); +#define MX_SHFL(shop,op1,op2) mdmx_shuffle(SIM_ARGS, shop, op1, op2) + + /* Memory accesses */ @@ -774,6 +897,7 @@ prefetch (SD, CPU, cia, CCA, pAddr, vAddr, DATA, hint) void unpredictable_action (sim_cpu *cpu, address_word cia); #define NotWordValue(val) not_word_value (SD_, (val)) #define Unpredictable() unpredictable (SD_) +#define UnpredictableResult() /* For now, do nothing. */ INLINE_SIM_MAIN (unsigned32) ifetch32 PARAMS ((SIM_DESC sd, sim_cpu *cpu, address_word cia, address_word vaddr)); #define IMEM32(CIA) ifetch32 (SD, CPU, (CIA), (CIA))