diff options
author | nobody <> | 2003-06-27 17:05:59 +0000 |
---|---|---|
committer | nobody <> | 2003-06-27 17:05:59 +0000 |
commit | c8a2fad7b41a8264964233608ae10c35918243fb (patch) | |
tree | 51bfadce02ac30f808dcfb8d118e8a8dd0d2878b | |
parent | 40ea26e40a0f9e36464336daf7972612b3b5fee7 (diff) | |
download | gdb-c8a2fad7b41a8264964233608ae10c35918243fb.zip gdb-c8a2fad7b41a8264964233608ae10c35918243fb.tar.gz gdb-c8a2fad7b41a8264964233608ae10c35918243fb.tar.bz2 |
This commit was manufactured by cvs2svn to create branch
'carlton_dictionary-branch'.
Cherrypick from master 2003-06-27 17:05:58 UTC Elena Zannoni <ezannoni@kwikemart.cygnus.com> '2003-06-27 Elena Zannoni <ezannoni@redhat.com>':
gdb/alpha-mdebug-tdep.c
gdb/config/mips/mips.mt
gdb/config/mips/mips64.mt
gdb/config/powerpc/nm-ppc64-linux.h
gdb/config/powerpc/ppc64-linux.mh
gdb/dwarf2-frame.c
gdb/dwarf2-frame.h
gdb/linux-nat.c
gdb/linux-nat.h
gdb/remote-fileio.c
gdb/remote-fileio.h
gdb/stack.h
gdb/testsuite/gdb.asm/alpha.inc
gdb/testsuite/gdb.base/bang.exp
gdb/testsuite/gdb.base/fileio.c
gdb/testsuite/gdb.base/fileio.exp
gdb/testsuite/gdb.base/gdb_history
gdb/testsuite/gdb.base/shreloc.c
gdb/testsuite/gdb.base/shreloc.exp
gdb/testsuite/gdb.base/shreloc1.c
gdb/testsuite/gdb.base/shreloc2.c
gdb/testsuite/gdb.c++/pr-1210.cc
gdb/testsuite/gdb.c++/pr-1210.exp
gdb/trad-frame.c
gdb/trad-frame.h
include/gdb/fileio.h
sim/h8300/sim-main.h
sim/ppc/altivec.igen
sim/ppc/altivec_expression.h
sim/ppc/altivec_registers.h
sim/ppc/e500.igen
sim/ppc/e500_expression.h
sim/ppc/e500_registers.h
33 files changed, 11639 insertions, 0 deletions
diff --git a/gdb/alpha-mdebug-tdep.c b/gdb/alpha-mdebug-tdep.c new file mode 100644 index 0000000..9eb9c62 --- /dev/null +++ b/gdb/alpha-mdebug-tdep.c @@ -0,0 +1,384 @@ +/* Target-dependent mdebug code for the ALPHA architecture. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "symtab.h" +#include "gdbcore.h" +#include "block.h" +#include "gdb_assert.h" + +#include "alpha-tdep.h" + +/* FIXME: Some of this code should perhaps be merged with mips. */ + +/* *INDENT-OFF* */ +/* Layout of a stack frame on the alpha: + + | | + pdr members: | 7th ... nth arg, | + | `pushed' by caller. | + | | +----------------|-------------------------------|<-- old_sp == vfp + ^ ^ ^ ^ | | + | | | | | | + | |localoff | Copies of 1st .. 6th | + | | | | | argument if necessary. | + | | | v | | + | | | --- |-------------------------------|<-- LOCALS_ADDRESS + | | | | | + | | | | Locals and temporaries. | + | | | | | + | | | |-------------------------------| + | | | | | + |-fregoffset | Saved float registers. | + | | | | F9 | + | | | | . | + | | | | . | + | | | | F2 | + | | v | | + | | -------|-------------------------------| + | | | | + | | | Saved registers. | + | | | S6 | + |-regoffset | . | + | | | . | + | | | S0 | + | | | pdr.pcreg | + | v | | + | ----------|-------------------------------| + | | | + frameoffset | Argument build area, gets | + | | 7th ... nth arg for any | + | | called procedure. | + v | | + -------------|-------------------------------|<-- sp + | | +*/ +/* *INDENT-ON* */ + +#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) +#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset) +#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg) +#define PROC_REG_MASK(proc) ((proc)->pdr.regmask) +#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask) +#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset) +#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset) +#define PROC_PC_REG(proc) ((proc)->pdr.pcreg) +#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff) + +/* Locate the mdebug PDR for the given PC. Return null if one can't + be found; you'll have to fall back to other methods in that case. */ + +static alpha_extra_func_info_t +find_proc_desc (CORE_ADDR pc) +{ + struct block *b = block_for_pc (pc); + alpha_extra_func_info_t proc_desc = NULL; + struct symbol *sym = NULL; + + if (b) + { + CORE_ADDR startaddr; + find_pc_partial_function (pc, NULL, &startaddr, NULL); + + if (startaddr > BLOCK_START (b)) + /* This is the "pathological" case referred to in a comment in + print_frame_info. It might be better to move this check into + symbol reading. */ + sym = NULL; + else + sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0, NULL); + } + + if (sym) + { + proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym); + + /* If we never found a PDR for this function in symbol reading, + then examine prologues to find the information. */ + if (proc_desc->pdr.framereg == -1) + proc_desc = NULL; + } + + return proc_desc; +} + +/* This returns the PC of the first inst after the prologue. If we can't + find the prologue, then return 0. */ + +static CORE_ADDR +alpha_mdebug_after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) +{ + if (proc_desc) + { + /* If function is frameless, then we need to do it the hard way. I + strongly suspect that frameless always means prologueless... */ + if (PROC_FRAME_REG (proc_desc) == ALPHA_SP_REGNUM + && PROC_FRAME_OFFSET (proc_desc) == 0) + return 0; + } + + return alpha_after_prologue (pc); +} + +/* Return non-zero if we *might* be in a function prologue. Return zero + if we are definitively *not* in a function prologue. */ + +static int +alpha_mdebug_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc) +{ + CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc); + return (after_prologue_pc == 0 || pc < after_prologue_pc); +} + + +/* Frame unwinder that reads mdebug PDRs. */ + +struct alpha_mdebug_unwind_cache +{ + alpha_extra_func_info_t proc_desc; + CORE_ADDR vfp; + CORE_ADDR *saved_regs; +}; + +/* Extract all of the information about the frame from PROC_DESC + and store the resulting register save locations in the structure. */ + +static struct alpha_mdebug_unwind_cache * +alpha_mdebug_frame_unwind_cache (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_mdebug_unwind_cache *info; + alpha_extra_func_info_t proc_desc; + ULONGEST vfp; + CORE_ADDR pc, reg_position; + unsigned long mask; + int ireg, returnreg; + + if (*this_prologue_cache) + return *this_prologue_cache; + + info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache); + *this_prologue_cache = info; + pc = frame_pc_unwind (next_frame); + + /* ??? We don't seem to be able to cache the lookup of the PDR + from alpha_mdebug_frame_p. It'd be nice if we could change + the arguments to that function. Oh well. */ + proc_desc = find_proc_desc (pc); + info->proc_desc = proc_desc; + gdb_assert (proc_desc != NULL); + + info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); + + /* The VFP of the frame is at FRAME_REG+FRAME_OFFSET. */ + frame_unwind_unsigned_register (next_frame, PROC_FRAME_REG (proc_desc), &vfp); + vfp += PROC_FRAME_OFFSET (info->proc_desc); + info->vfp = vfp; + + /* Fill in the offsets for the registers which gen_mask says were saved. */ + + reg_position = vfp + PROC_REG_OFFSET (proc_desc); + mask = PROC_REG_MASK (proc_desc); + returnreg = PROC_PC_REG (proc_desc); + + /* Note that RA is always saved first, regardless of its actual + register number. */ + if (mask & (1 << returnreg)) + { + /* Clear bit for RA so we don't save it again later. */ + mask &= ~(1 << returnreg); + + info->saved_regs[returnreg] = reg_position; + reg_position += 8; + } + + for (ireg = 0; ireg <= 31; ++ireg) + if (mask & (1 << ireg)) + { + info->saved_regs[ireg] = reg_position; + reg_position += 8; + } + + reg_position = vfp + PROC_FREG_OFFSET (proc_desc); + mask = PROC_FREG_MASK (proc_desc); + + for (ireg = 0; ireg <= 31; ++ireg) + if (mask & (1 << ireg)) + { + info->saved_regs[ALPHA_FP0_REGNUM + ireg] = reg_position; + reg_position += 8; + } + + return info; +} + +/* Given a GDB frame, determine the address of the calling function's + frame. This will be used to create a new GDB frame struct. */ + +static void +alpha_mdebug_frame_this_id (struct frame_info *next_frame, + void **this_prologue_cache, + struct frame_id *this_id) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + + *this_id = frame_id_build (info->vfp, frame_func_unwind (next_frame)); +} + +/* Retrieve the value of REGNUM in FRAME. Don't give up! */ + +static void +alpha_mdebug_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + + /* The PC of the previous frame is stored in the link register of + the current frame. Frob regnum so that we pull the value from + the correct place. */ + if (regnum == ALPHA_PC_REGNUM) + regnum = PROC_PC_REG (info->proc_desc); + + /* For all registers known to be saved in the current frame, + do the obvious and pull the value out. */ + if (info->saved_regs[regnum]) + { + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = info->saved_regs[regnum]; + *realnump = -1; + if (bufferp != NULL) + get_frame_memory (next_frame, *addrp, bufferp, ALPHA_REGISTER_SIZE); + return; + } + + /* The stack pointer of the previous frame is computed by popping + the current stack frame. */ + if (regnum == ALPHA_SP_REGNUM) + { + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (bufferp != NULL) + store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp); + return; + } + + /* Otherwise assume the next frame has the same register value. */ + frame_register (next_frame, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); +} + +static const struct frame_unwind alpha_mdebug_frame_unwind = { + NORMAL_FRAME, + alpha_mdebug_frame_this_id, + alpha_mdebug_frame_prev_register +}; + +const struct frame_unwind * +alpha_mdebug_frame_p (CORE_ADDR pc) +{ + alpha_extra_func_info_t proc_desc; + + /* If this PC does not map to a PDR, then clearly this isn't an + mdebug frame. */ + proc_desc = find_proc_desc (pc); + if (proc_desc == NULL) + return NULL; + + /* If we're in the prologue, the PDR for this frame is not yet valid. + Say no here and we'll fall back on the heuristic unwinder. */ + if (alpha_mdebug_in_prologue (pc, proc_desc)) + return NULL; + + return &alpha_mdebug_frame_unwind; +} + +static CORE_ADDR +alpha_mdebug_frame_base_address (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + + return info->vfp; +} + +static CORE_ADDR +alpha_mdebug_frame_locals_address (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + + return info->vfp - PROC_LOCALOFF (info->proc_desc); +} + +static CORE_ADDR +alpha_mdebug_frame_args_address (struct frame_info *next_frame, + void **this_prologue_cache) +{ + struct alpha_mdebug_unwind_cache *info + = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache); + + return info->vfp - ALPHA_NUM_ARG_REGS * 8; +} + +static const struct frame_base alpha_mdebug_frame_base = { + &alpha_mdebug_frame_unwind, + alpha_mdebug_frame_base_address, + alpha_mdebug_frame_locals_address, + alpha_mdebug_frame_args_address +}; + +static const struct frame_base * +alpha_mdebug_frame_base_p (CORE_ADDR pc) +{ + alpha_extra_func_info_t proc_desc; + + /* If this PC does not map to a PDR, then clearly this isn't an + mdebug frame. */ + proc_desc = find_proc_desc (pc); + if (proc_desc == NULL) + return NULL; + + return &alpha_mdebug_frame_base; +} + + +void +alpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + frame_unwind_append_predicate (gdbarch, alpha_mdebug_frame_p); + frame_base_append_predicate (gdbarch, alpha_mdebug_frame_base_p); +} diff --git a/gdb/config/mips/mips.mt b/gdb/config/mips/mips.mt new file mode 100644 index 0000000..2d08bcb --- /dev/null +++ b/gdb/config/mips/mips.mt @@ -0,0 +1,5 @@ +# Target: Big-endian SIM monitor board. +TDEPFILES= mips-tdep.o remote-mips.o +TM_FILE= tm-mips.h +SIM_OBS = remote-sim.o +SIM = ../sim/mips/libsim.a diff --git a/gdb/config/mips/mips64.mt b/gdb/config/mips/mips64.mt new file mode 100644 index 0000000..e6a19d8 --- /dev/null +++ b/gdb/config/mips/mips64.mt @@ -0,0 +1,5 @@ +# Target: Big-endian SIM monitor board. +TDEPFILES= mips-tdep.o remote-mips.o +TM_FILE= tm-mips64.h +SIM_OBS = remote-sim.o +SIM = ../sim/mips/libsim.a diff --git a/gdb/config/powerpc/nm-ppc64-linux.h b/gdb/config/powerpc/nm-ppc64-linux.h new file mode 100644 index 0000000..5d1c7b6 --- /dev/null +++ b/gdb/config/powerpc/nm-ppc64-linux.h @@ -0,0 +1,27 @@ +/* IBM PowerPC64 native-dependent macros for GDB, the GNU debugger. + Copyright 2003 Free Software Foundation, Inc. + +This file is part of GDB. + +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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef NM_PPC64_LINUX_H + +#include "config/powerpc/nm-linux.h" + +#define PTRACE_ARG3_TYPE void * +#define PTRACE_XFER_TYPE long + +#endif /* NM_PPC64_LINUX_H */ diff --git a/gdb/config/powerpc/ppc64-linux.mh b/gdb/config/powerpc/ppc64-linux.mh new file mode 100644 index 0000000..dd81586 --- /dev/null +++ b/gdb/config/powerpc/ppc64-linux.mh @@ -0,0 +1,19 @@ +# Host: PowerPC64, running Linux + +XM_FILE= xm-linux.h +XM_CLIBS= + +NAT_FILE= nm-ppc64-linux.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o linux-proc.o \ + ppc-linux-nat.o proc-service.o thread-db.o lin-lwp.o \ + gcore.o linux-nat.o + +# The PowerPC has severe limitations on TOC size, and uses them even +# for non-PIC code. GDB overflows those tables when compiling with +# -mfull-toc (the default), so we need to ask GCC to use as few TOC +# entries as possible. +MH_CFLAGS= -mminimal-toc + +# The dynamically loaded libthread_db needs access to symbols in the +# gdb executable. +LOADLIBES= -ldl -rdynamic diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c new file mode 100644 index 0000000..999cef7 --- /dev/null +++ b/gdb/dwarf2-frame.c @@ -0,0 +1,1336 @@ +/* Frame unwinder for frames with DWARF Call Frame Information. + + Copyright 2003 Free Software Foundation, Inc. + + Contributed by Mark Kettenis. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "dwarf2expr.h" +#include "elf/dwarf2.h" +#include "frame.h" +#include "frame-base.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "gdbtypes.h" +#include "symtab.h" +#include "objfiles.h" +#include "regcache.h" + +#include "gdb_assert.h" +#include "gdb_string.h" + +#include "dwarf2-frame.h" + +/* Call Frame Information (CFI). */ + +/* Common Information Entry (CIE). */ + +struct dwarf2_cie +{ + /* Offset into the .debug_frame section where this CIE was found. + Used to identify this CIE. */ + ULONGEST cie_pointer; + + /* Constant that is factored out of all advance location + instructions. */ + ULONGEST code_alignment_factor; + + /* Constants that is factored out of all offset instructions. */ + LONGEST data_alignment_factor; + + /* Return address column. */ + ULONGEST return_address_register; + + /* Instruction sequence to initialize a register set. */ + unsigned char *initial_instructions; + unsigned char *end; + + /* Encoding of addresses. */ + unsigned char encoding; + + /* True if a 'z' augmentation existed. */ + unsigned char saw_z_augmentation; + + struct dwarf2_cie *next; +}; + +/* Frame Description Entry (FDE). */ + +struct dwarf2_fde +{ + /* CIE for this FDE. */ + struct dwarf2_cie *cie; + + /* First location associated with this FDE. */ + CORE_ADDR initial_location; + + /* Number of bytes of program instructions described by this FDE. */ + CORE_ADDR address_range; + + /* Instruction sequence. */ + unsigned char *instructions; + unsigned char *end; + + struct dwarf2_fde *next; +}; + +static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc); + + +/* Structure describing a frame state. */ + +struct dwarf2_frame_state +{ + /* Each register save state can be described in terms of a CFA slot, + another register, or a location expression. */ + struct dwarf2_frame_state_reg_info + { + struct dwarf2_frame_state_reg + { + union { + LONGEST offset; + ULONGEST reg; + unsigned char *exp; + } loc; + ULONGEST exp_len; + enum { + REG_UNSAVED, + REG_SAVED_OFFSET, + REG_SAVED_REG, + REG_SAVED_EXP, + REG_UNMODIFIED + } how; + } *reg; + int num_regs; + + /* Used to implement DW_CFA_remember_state. */ + struct dwarf2_frame_state_reg_info *prev; + } regs; + + LONGEST cfa_offset; + ULONGEST cfa_reg; + unsigned char *cfa_exp; + enum { + CFA_UNSET, + CFA_REG_OFFSET, + CFA_EXP + } cfa_how; + + /* The PC described by the current frame state. */ + CORE_ADDR pc; + + /* Initial register set from the CIE. + Used to implement DW_CFA_restore. */ + struct dwarf2_frame_state_reg_info initial; + + /* The information we care about from the CIE. */ + LONGEST data_align; + ULONGEST code_align; + ULONGEST retaddr_column; +}; + +/* Store the length the expression for the CFA in the `cfa_reg' field, + which is unused in that case. */ +#define cfa_exp_len cfa_reg + +/* Assert that the register set RS is large enough to store NUM_REGS + columns. If necessary, enlarge the register set. */ + +static void +dwarf2_frame_state_alloc_regs (struct dwarf2_frame_state_reg_info *rs, + int num_regs) +{ + size_t size = sizeof (struct dwarf2_frame_state_reg); + + if (num_regs <= rs->num_regs) + return; + + rs->reg = (struct dwarf2_frame_state_reg *) + xrealloc (rs->reg, num_regs * size); + + /* Initialize newly allocated registers. */ + memset (rs->reg + rs->num_regs, 0, (num_regs - rs->num_regs) * size); + rs->num_regs = num_regs; +} + +/* Copy the register columns in register set RS into newly allocated + memory and return a pointer to this newly created copy. */ + +static struct dwarf2_frame_state_reg * +dwarf2_frame_state_copy_regs (struct dwarf2_frame_state_reg_info *rs) +{ + size_t size = rs->num_regs * sizeof (struct dwarf2_frame_state_reg_info); + struct dwarf2_frame_state_reg *reg; + + reg = (struct dwarf2_frame_state_reg *) xmalloc (size); + memcpy (reg, rs->reg, size); + + return reg; +} + +/* Release the memory allocated to register set RS. */ + +static void +dwarf2_frame_state_free_regs (struct dwarf2_frame_state_reg_info *rs) +{ + if (rs) + { + dwarf2_frame_state_free_regs (rs->prev); + + xfree (rs->reg); + xfree (rs); + } +} + +/* Release the memory allocated to the frame state FS. */ + +static void +dwarf2_frame_state_free (void *p) +{ + struct dwarf2_frame_state *fs = p; + + dwarf2_frame_state_free_regs (fs->initial.prev); + dwarf2_frame_state_free_regs (fs->regs.prev); + xfree (fs->initial.reg); + xfree (fs->regs.reg); + xfree (fs); +} + + +/* Helper functions for execute_stack_op. */ + +static CORE_ADDR +read_reg (void *baton, int reg) +{ + struct frame_info *next_frame = (struct frame_info *) baton; + int regnum; + char *buf; + + regnum = DWARF2_REG_TO_REGNUM (reg); + + buf = (char *) alloca (register_size (current_gdbarch, regnum)); + frame_unwind_register (next_frame, regnum, buf); + return extract_typed_address (buf, builtin_type_void_data_ptr); +} + +static void +read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len) +{ + read_memory (addr, buf, len); +} + +static void +no_get_frame_base (void *baton, unsigned char **start, size_t *length) +{ + internal_error (__FILE__, __LINE__, + "Support for DW_OP_fbreg is unimplemented"); +} + +static CORE_ADDR +no_get_tls_address (void *baton, CORE_ADDR offset) +{ + internal_error (__FILE__, __LINE__, + "Support for DW_OP_GNU_push_tls_address is unimplemented"); +} + +static CORE_ADDR +execute_stack_op (unsigned char *exp, ULONGEST len, + struct frame_info *next_frame, CORE_ADDR initial) +{ + struct dwarf_expr_context *ctx; + CORE_ADDR result; + + ctx = new_dwarf_expr_context (); + ctx->baton = next_frame; + ctx->read_reg = read_reg; + ctx->read_mem = read_mem; + ctx->get_frame_base = no_get_frame_base; + ctx->get_tls_address = no_get_tls_address; + + dwarf_expr_push (ctx, initial); + dwarf_expr_eval (ctx, exp, len); + result = dwarf_expr_fetch (ctx, 0); + + if (ctx->in_reg) + result = read_reg (next_frame, result); + + free_dwarf_expr_context (ctx); + + return result; +} + + +static void +execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end, + struct frame_info *next_frame, + struct dwarf2_frame_state *fs) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + int bytes_read; + + while (insn_ptr < insn_end && fs->pc <= pc) + { + unsigned char insn = *insn_ptr++; + ULONGEST utmp, reg; + LONGEST offset; + + if ((insn & 0xc0) == DW_CFA_advance_loc) + fs->pc += (insn & 0x3f) * fs->code_align; + else if ((insn & 0xc0) == DW_CFA_offset) + { + reg = insn & 0x3f; + insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + offset = utmp * fs->data_align; + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + fs->regs.reg[reg].how = REG_SAVED_OFFSET; + fs->regs.reg[reg].loc.offset = offset; + } + else if ((insn & 0xc0) == DW_CFA_restore) + { + gdb_assert (fs->initial.reg); + reg = insn & 0x3f; + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + fs->regs.reg[reg] = fs->initial.reg[reg]; + } + else + { + switch (insn) + { + case DW_CFA_set_loc: + fs->pc = dwarf2_read_address (insn_ptr, insn_end, &bytes_read); + insn_ptr += bytes_read; + break; + + case DW_CFA_advance_loc1: + utmp = extract_unsigned_integer (insn_ptr, 1); + fs->pc += utmp * fs->code_align; + insn_ptr++; + break; + case DW_CFA_advance_loc2: + utmp = extract_unsigned_integer (insn_ptr, 2); + fs->pc += utmp * fs->code_align; + insn_ptr += 2; + break; + case DW_CFA_advance_loc4: + utmp = extract_unsigned_integer (insn_ptr, 4); + fs->pc += utmp * fs->code_align; + insn_ptr += 4; + break; + + case DW_CFA_offset_extended: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + offset = utmp * fs->data_align; + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + fs->regs.reg[reg].how = REG_SAVED_OFFSET; + fs->regs.reg[reg].loc.offset = offset; + break; + + case DW_CFA_restore_extended: + gdb_assert (fs->initial.reg); + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + fs->regs.reg[reg] = fs->initial.reg[reg]; + break; + + case DW_CFA_undefined: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + fs->regs.reg[reg].how = REG_UNSAVED; + break; + + case DW_CFA_same_value: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + fs->regs.reg[reg].how = REG_UNMODIFIED; + break; + + case DW_CFA_register: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + fs->regs.reg[reg].loc.reg = utmp; + break; + + case DW_CFA_remember_state: + { + struct dwarf2_frame_state_reg_info *new_rs; + + new_rs = XMALLOC (struct dwarf2_frame_state_reg_info); + *new_rs = fs->regs; + fs->regs.reg = dwarf2_frame_state_copy_regs (&fs->regs); + fs->regs.prev = new_rs; + } + break; + + case DW_CFA_restore_state: + { + struct dwarf2_frame_state_reg_info *old_rs = fs->regs.prev; + + gdb_assert (old_rs); + + xfree (fs->regs.reg); + fs->regs = *old_rs; + xfree (old_rs); + } + break; + + case DW_CFA_def_cfa: + insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + fs->cfa_offset = utmp; + fs->cfa_how = CFA_REG_OFFSET; + break; + + case DW_CFA_def_cfa_register: + insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg); + fs->cfa_how = CFA_REG_OFFSET; + break; + + case DW_CFA_def_cfa_offset: + insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_offset); + /* cfa_how deliberately not set. */ + break; + + case DW_CFA_def_cfa_expression: + insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_exp_len); + fs->cfa_exp = insn_ptr; + fs->cfa_how = CFA_EXP; + insn_ptr += fs->cfa_exp_len; + break; + + case DW_CFA_expression: + insn_ptr = read_uleb128 (insn_ptr, insn_end, ®); + dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1); + insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + fs->regs.reg[reg].loc.exp = insn_ptr; + fs->regs.reg[reg].exp_len = utmp; + fs->regs.reg[reg].how = REG_SAVED_EXP; + insn_ptr += utmp; + break; + + case DW_CFA_nop: + break; + + case DW_CFA_GNU_args_size: + /* Ignored. */ + insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp); + break; + + default: + internal_error (__FILE__, __LINE__, "Unknown CFI encountered."); + } + } + } + + /* Don't allow remember/restore between CIE and FDE programs. */ + dwarf2_frame_state_free_regs (fs->regs.prev); + fs->regs.prev = NULL; +} + +struct dwarf2_frame_cache +{ + /* DWARF Call Frame Address. */ + CORE_ADDR cfa; + + /* Saved registers, indexed by GDB register number, not by DWARF + register number. */ + struct dwarf2_frame_state_reg *reg; +}; + +static struct dwarf2_frame_cache * +dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache) +{ + struct cleanup *old_chain; + int num_regs = NUM_REGS + NUM_PSEUDO_REGS; + struct dwarf2_frame_cache *cache; + struct dwarf2_frame_state *fs; + struct dwarf2_fde *fde; + int reg; + + if (*this_cache) + return *this_cache; + + /* Allocate a new cache. */ + cache = FRAME_OBSTACK_ZALLOC (struct dwarf2_frame_cache); + cache->reg = FRAME_OBSTACK_CALLOC (num_regs, struct dwarf2_frame_state_reg); + + /* Allocate and initialize the frame state. */ + fs = XMALLOC (struct dwarf2_frame_state); + memset (fs, 0, sizeof (struct dwarf2_frame_state)); + old_chain = make_cleanup (dwarf2_frame_state_free, fs); + + /* Unwind the PC. + + Note that if NEXT_FRAME is never supposed to return (i.e. a call + to abort), the compiler might optimize away the instruction at + NEXT_FRAME's return address. As a result the return address will + point at some random instruction, and the CFI for that + instruction is probably wortless to us. GCC's unwinder solves + this problem by substracting 1 from the return address to get an + address in the middle of a presumed call instruction (or the + instruction in the associated delay slot). This should only be + done for "normal" frames and not for resume-type frames (signal + handlers, sentinel frames, dummy frames). + + We don't do what GCC's does here (yet). It's not clear how + reliable the method is. There's also a problem with finding the + right FDE; see the comment in dwarf_frame_p. If dwarf_frame_p + selected this frame unwinder because it found the FDE for the + next function, using the adjusted return address might not yield + a FDE at all. The problem isn't specific to DWARF CFI; other + unwinders loose in similar ways. Therefore it's probably + acceptable to leave things slightly broken for now. */ + fs->pc = frame_pc_unwind (next_frame); + + /* Find the correct FDE. */ + fde = dwarf2_frame_find_fde (&fs->pc); + gdb_assert (fde != NULL); + + /* Extract any interesting information from the CIE. */ + fs->data_align = fde->cie->data_alignment_factor; + fs->code_align = fde->cie->code_alignment_factor; + fs->retaddr_column = fde->cie->return_address_register; + + /* First decode all the insns in the CIE. */ + execute_cfa_program (fde->cie->initial_instructions, + fde->cie->end, next_frame, fs); + + /* Save the initialized register set. */ + fs->initial = fs->regs; + fs->initial.reg = dwarf2_frame_state_copy_regs (&fs->regs); + + /* Then decode the insns in the FDE up to our target PC. */ + execute_cfa_program (fde->instructions, fde->end, next_frame, fs); + + /* Caclulate the CFA. */ + switch (fs->cfa_how) + { + case CFA_REG_OFFSET: + cache->cfa = read_reg (next_frame, fs->cfa_reg); + cache->cfa += fs->cfa_offset; + break; + + case CFA_EXP: + cache->cfa = + execute_stack_op (fs->cfa_exp, fs->cfa_exp_len, next_frame, 0); + break; + + default: + internal_error (__FILE__, __LINE__, "Unknown CFA rule."); + } + + /* Save the register info in the cache. */ + for (reg = 0; reg < fs->regs.num_regs; reg++) + { + int regnum; + + /* Skip the return address column. */ + if (reg == fs->retaddr_column) + /* NOTE: cagney/2003-06-07: Is this right? What if the + RETADDR_COLUM corresponds to a real register (and, worse, + that isn't the PC_REGNUM)? I'm guessing that the PC_REGNUM + further down is trying to handle this. That can't be right + though - PC_REGNUM may not be valid (it can be -ve). I + think, instead when RETADDR_COLUM isn't a real register, it + should map itself onto frame_pc_unwind. */ + continue; + + /* Use the GDB register number as index. */ + regnum = DWARF2_REG_TO_REGNUM (reg); + + if (regnum >= 0 && regnum < num_regs) + cache->reg[regnum] = fs->regs.reg[reg]; + } + + /* Store the location of the return addess. If the return address + column (adjusted) is not the same as gdb's PC_REGNUM, then this + implies a copy from the ra column register. */ + if (fs->retaddr_column < fs->regs.num_regs + && fs->regs.reg[fs->retaddr_column].how != REG_UNSAVED) + { + /* See comment above about a possibly -ve PC_REGNUM. If this + assertion fails, it's a problem with this code and not the + architecture. */ + gdb_assert (PC_REGNUM >= 0); + cache->reg[PC_REGNUM] = fs->regs.reg[fs->retaddr_column]; + } + else + { + reg = DWARF2_REG_TO_REGNUM (fs->retaddr_column); + if (reg != PC_REGNUM) + { + /* See comment above about PC_REGNUM being -ve. If this + assertion fails, it's a problem with this code and not + the architecture. */ + gdb_assert (PC_REGNUM >= 0); + cache->reg[PC_REGNUM].loc.reg = reg; + cache->reg[PC_REGNUM].how = REG_SAVED_REG; + } + } + + do_cleanups (old_chain); + + *this_cache = cache; + return cache; +} + +static void +dwarf2_frame_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct dwarf2_frame_cache *cache = + dwarf2_frame_cache (next_frame, this_cache); + + (*this_id) = frame_id_build (cache->cfa, frame_func_unwind (next_frame)); +} + +static void +dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct dwarf2_frame_cache *cache = + dwarf2_frame_cache (next_frame, this_cache); + + switch (cache->reg[regnum].how) + { + case REG_UNSAVED: + *optimizedp = 1; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (regnum == SP_REGNUM) + { + /* GCC defines the CFA as the value of the stack pointer + just before the call instruction is executed. Do other + compilers use the same definition? */ + /* DWARF V3 Draft 7 p102: Typically, the CFA is defined to + be the value of the stack pointer at the call site in the + previous frame (which may be different from its value on + entry to the current frame). */ + /* DWARF V3 Draft 7 p103: The first column of the rules + defines the rule which computes the CFA value; it may be + either a register and a signed offset that are added + together or a DWARF expression that is evaluated. */ + /* FIXME: cagney/2003-07-07: I don't understand this. The + CFI info should have provided unwind information for the + SP register and then pointed ->cfa_reg at it, not the + reverse. Assuming that SP_REGNUM is !-ve, there is a + very real posibility that CFA is an offset from some + other register, having nothing to do with the unwound SP + value. */ + *optimizedp = 0; + if (valuep) + { + /* Store the value. */ + store_typed_address (valuep, builtin_type_void_data_ptr, + cache->cfa); + } + } + else if (valuep) + { + /* In some cases, for example %eflags on the i386, we have + to provide a sane value, even though this register wasn't + saved. Assume we can get it from NEXT_FRAME. */ + frame_unwind_register (next_frame, regnum, valuep); + } + break; + + case REG_SAVED_OFFSET: + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = cache->cfa + cache->reg[regnum].loc.offset; + *realnump = -1; + if (valuep) + { + /* Read the value in from memory. */ + read_memory (*addrp, valuep, + register_size (current_gdbarch, regnum)); + } + break; + + case REG_SAVED_REG: + regnum = DWARF2_REG_TO_REGNUM (cache->reg[regnum].loc.reg); + frame_register_unwind (next_frame, regnum, + optimizedp, lvalp, addrp, realnump, valuep); + break; + + case REG_SAVED_EXP: + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = execute_stack_op (cache->reg[regnum].loc.exp, + cache->reg[regnum].exp_len, + next_frame, cache->cfa); + *realnump = -1; + if (valuep) + { + /* Read the value in from memory. */ + read_memory (*addrp, valuep, + register_size (current_gdbarch, regnum)); + } + break; + + case REG_UNMODIFIED: + frame_register_unwind (next_frame, regnum, + optimizedp, lvalp, addrp, realnump, valuep); + break; + + default: + internal_error (__FILE__, __LINE__, "Unknown register rule."); + } +} + +static const struct frame_unwind dwarf2_frame_unwind = +{ + NORMAL_FRAME, + dwarf2_frame_this_id, + dwarf2_frame_prev_register +}; + +const struct frame_unwind * +dwarf2_frame_p (CORE_ADDR pc) +{ + /* The way GDB works, this function can be called with PC just after + the last instruction of the function we're supposed to return the + unwind methods for. In that case we won't find the correct FDE; + instead we find the FDE for the next function, or we won't find + an FDE at all. There is a possible solution (see the comment in + dwarf2_frame_cache), GDB doesn't pass us enough information to + implement it. */ + if (dwarf2_frame_find_fde (&pc)) + return &dwarf2_frame_unwind; + + return NULL; +} + + +/* There is no explicitly defined relationship between the CFA and the + location of frame's local variables and arguments/parameters. + Therefore, frame base methods on this page should probably only be + used as a last resort, just to avoid printing total garbage as a + response to the "info frame" command. */ + +static CORE_ADDR +dwarf2_frame_base_address (struct frame_info *next_frame, void **this_cache) +{ + struct dwarf2_frame_cache *cache = + dwarf2_frame_cache (next_frame, this_cache); + + return cache->cfa; +} + +static const struct frame_base dwarf2_frame_base = +{ + &dwarf2_frame_unwind, + dwarf2_frame_base_address, + dwarf2_frame_base_address, + dwarf2_frame_base_address +}; + +const struct frame_base * +dwarf2_frame_base_p (CORE_ADDR pc) +{ + if (dwarf2_frame_find_fde (&pc)) + return &dwarf2_frame_base; + + return NULL; +} + +/* A minimal decoding of DWARF2 compilation units. We only decode + what's needed to get to the call frame information. */ + +struct comp_unit +{ + /* Keep the bfd convenient. */ + bfd *abfd; + + struct objfile *objfile; + + /* Linked list of CIEs for this object. */ + struct dwarf2_cie *cie; + + /* Address size for this unit - from unit header. */ + unsigned char addr_size; + + /* Pointer to the .debug_frame section loaded into memory. */ + char *dwarf_frame_buffer; + + /* Length of the loaded .debug_frame section. */ + unsigned long dwarf_frame_size; + + /* Pointer to the .debug_frame section. */ + asection *dwarf_frame_section; + + /* Base for DW_EH_PE_datarel encodings. */ + bfd_vma dbase; +}; + +static unsigned int +read_1_byte (bfd *bfd, char *buf) +{ + return bfd_get_8 (abfd, (bfd_byte *) buf); +} + +static unsigned int +read_4_bytes (bfd *abfd, char *buf) +{ + return bfd_get_32 (abfd, (bfd_byte *) buf); +} + +static ULONGEST +read_8_bytes (bfd *abfd, char *buf) +{ + return bfd_get_64 (abfd, (bfd_byte *) buf); +} + +static ULONGEST +read_unsigned_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr) +{ + ULONGEST result; + unsigned int num_read; + int shift; + unsigned char byte; + + result = 0; + shift = 0; + num_read = 0; + + do + { + byte = bfd_get_8 (abfd, (bfd_byte *) buf); + buf++; + num_read++; + result |= ((byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + + *bytes_read_ptr = num_read; + + return result; +} + +static LONGEST +read_signed_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr) +{ + LONGEST result; + int shift; + unsigned int num_read; + unsigned char byte; + + result = 0; + shift = 0; + num_read = 0; + + do + { + byte = bfd_get_8 (abfd, (bfd_byte *) buf); + buf++; + num_read++; + result |= ((byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + + if ((shift < 32) && (byte & 0x40)) + result |= -(1 << shift); + + *bytes_read_ptr = num_read; + + return result; +} + +static ULONGEST +read_initial_length (bfd *abfd, char *buf, unsigned int *bytes_read_ptr) +{ + LONGEST result; + + result = bfd_get_32 (abfd, (bfd_byte *) buf); + if (result == 0xffffffff) + { + result = bfd_get_64 (abfd, (bfd_byte *) buf + 4); + *bytes_read_ptr = 12; + } + else + *bytes_read_ptr = 4; + + return result; +} + + +/* Pointer encoding helper functions. */ + +/* GCC supports exception handling based on DWARF2 CFI. However, for + technical reasons, it encodes addresses in its FDE's in a different + way. Several "pointer encodings" are supported. The encoding + that's used for a particular FDE is determined by the 'R' + augmentation in the associated CIE. The argument of this + augmentation is a single byte. + + The address can be encoded as 2 bytes, 4 bytes, 8 bytes, or as a + LEB128. This is encoded in bits 0, 1 and 2. Bit 3 encodes whether + the address is signed or unsigned. Bits 4, 5 and 6 encode how the + address should be interpreted (absolute, relative to the current + position in the FDE, ...). Bit 7, indicates that the address + should be dereferenced. */ + +static unsigned char +encoding_for_size (unsigned int size) +{ + switch (size) + { + case 2: + return DW_EH_PE_udata2; + case 4: + return DW_EH_PE_udata4; + case 8: + return DW_EH_PE_udata8; + default: + internal_error (__FILE__, __LINE__, "Unsupported address size"); + } +} + +static unsigned int +size_of_encoded_value (unsigned char encoding) +{ + if (encoding == DW_EH_PE_omit) + return 0; + + switch (encoding & 0x07) + { + case DW_EH_PE_absptr: + return TYPE_LENGTH (builtin_type_void_data_ptr); + case DW_EH_PE_udata2: + return 2; + case DW_EH_PE_udata4: + return 4; + case DW_EH_PE_udata8: + return 8; + default: + internal_error (__FILE__, __LINE__, "Invalid or unsupported encoding"); + } +} + +static CORE_ADDR +read_encoded_value (struct comp_unit *unit, unsigned char encoding, + char *buf, unsigned int *bytes_read_ptr) +{ + CORE_ADDR base; + + /* GCC currently doesn't generate DW_EH_PE_indirect encodings for + FDE's. */ + if (encoding & DW_EH_PE_indirect) + internal_error (__FILE__, __LINE__, + "Unsupported encoding: DW_EH_PE_indirect"); + + switch (encoding & 0x70) + { + case DW_EH_PE_absptr: + base = 0; + break; + case DW_EH_PE_pcrel: + base = bfd_get_section_vma (unit->bfd, unit->dwarf_frame_section); + base += (buf - unit->dwarf_frame_buffer); + break; + case DW_EH_PE_datarel: + base = unit->dbase; + break; + default: + internal_error (__FILE__, __LINE__, "Invalid or unsupported encoding"); + } + + if ((encoding & 0x0f) == 0x00) + encoding |= encoding_for_size (TYPE_LENGTH(builtin_type_void_data_ptr)); + + switch (encoding & 0x0f) + { + case DW_EH_PE_udata2: + *bytes_read_ptr = 2; + return (base + bfd_get_16 (unit->abfd, (bfd_byte *) buf)); + case DW_EH_PE_udata4: + *bytes_read_ptr = 4; + return (base + bfd_get_32 (unit->abfd, (bfd_byte *) buf)); + case DW_EH_PE_udata8: + *bytes_read_ptr = 8; + return (base + bfd_get_64 (unit->abfd, (bfd_byte *) buf)); + case DW_EH_PE_sdata2: + *bytes_read_ptr = 2; + return (base + bfd_get_signed_16 (unit->abfd, (bfd_byte *) buf)); + case DW_EH_PE_sdata4: + *bytes_read_ptr = 4; + return (base + bfd_get_signed_32 (unit->abfd, (bfd_byte *) buf)); + case DW_EH_PE_sdata8: + *bytes_read_ptr = 8; + return (base + bfd_get_signed_64 (unit->abfd, (bfd_byte *) buf)); + default: + internal_error (__FILE__, __LINE__, "Invalid or unsupported encoding"); + } +} + + +/* GCC uses a single CIE for all FDEs in a .debug_frame section. + That's why we use a simple linked list here. */ + +static struct dwarf2_cie * +find_cie (struct comp_unit *unit, ULONGEST cie_pointer) +{ + struct dwarf2_cie *cie = unit->cie; + + while (cie) + { + if (cie->cie_pointer == cie_pointer) + return cie; + + cie = cie->next; + } + + return NULL; +} + +static void +add_cie (struct comp_unit *unit, struct dwarf2_cie *cie) +{ + cie->next = unit->cie; + unit->cie = cie; +} + +/* Find the FDE for *PC. Return a pointer to the FDE, and store the + inital location associated with it into *PC. */ + +static struct dwarf2_fde * +dwarf2_frame_find_fde (CORE_ADDR *pc) +{ + struct objfile *objfile; + + ALL_OBJFILES (objfile) + { + struct dwarf2_fde *fde; + CORE_ADDR offset; + + offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + fde = objfile->sym_private; + while (fde) + { + if (*pc >= fde->initial_location + offset + && *pc < fde->initial_location + offset + fde->address_range) + { + *pc = fde->initial_location + offset; + return fde; + } + + fde = fde->next; + } + } + + return NULL; +} + +static void +add_fde (struct comp_unit *unit, struct dwarf2_fde *fde) +{ + fde->next = unit->objfile->sym_private; + unit->objfile->sym_private = fde; +} + +#ifdef CC_HAS_LONG_LONG +#define DW64_CIE_ID 0xffffffffffffffffULL +#else +#define DW64_CIE_ID ~0 +#endif + +/* Read a CIE or FDE in BUF and decode it. */ + +static char * +decode_frame_entry (struct comp_unit *unit, char *buf, int eh_frame_p) +{ + LONGEST length; + unsigned int bytes_read; + int dwarf64_p = 0; + ULONGEST cie_id = DW_CIE_ID; + ULONGEST cie_pointer; + char *start = buf; + char *end; + + length = read_initial_length (unit->abfd, buf, &bytes_read); + buf += bytes_read; + end = buf + length; + + if (length == 0) + return end; + + if (bytes_read == 12) + dwarf64_p = 1; + + /* In a .eh_frame section, zero is used to distinguish CIEs from + FDEs. */ + if (eh_frame_p) + cie_id = 0; + else if (dwarf64_p) + cie_id = DW64_CIE_ID; + + if (dwarf64_p) + { + cie_pointer = read_8_bytes (unit->abfd, buf); + buf += 8; + } + else + { + cie_pointer = read_4_bytes (unit->abfd, buf); + buf += 4; + } + + if (cie_pointer == cie_id) + { + /* This is a CIE. */ + struct dwarf2_cie *cie; + char *augmentation; + + /* Record the offset into the .debug_frame section of this CIE. */ + cie_pointer = start - unit->dwarf_frame_buffer; + + /* Check whether we've already read it. */ + if (find_cie (unit, cie_pointer)) + return end; + + cie = (struct dwarf2_cie *) + obstack_alloc (&unit->objfile->psymbol_obstack, + sizeof (struct dwarf2_cie)); + cie->initial_instructions = NULL; + cie->cie_pointer = cie_pointer; + + /* The encoding for FDE's in a normal .debug_frame section + depends on the target address size as specified in the + Compilation Unit Header. */ + cie->encoding = encoding_for_size (unit->addr_size); + + /* Check version number. */ + gdb_assert (read_1_byte (unit->abfd, buf) == DW_CIE_VERSION); + buf += 1; + + /* Interpret the interesting bits of the augmentation. */ + augmentation = buf; + buf = augmentation + strlen (augmentation) + 1; + + /* The GCC 2.x "eh" augmentation has a pointer immediately + following the augmentation string, so it must be handled + first. */ + if (augmentation[0] == 'e' && augmentation[1] == 'h') + { + /* Skip. */ + buf += TYPE_LENGTH (builtin_type_void_data_ptr); + augmentation += 2; + } + + cie->code_alignment_factor = + read_unsigned_leb128 (unit->abfd, buf, &bytes_read); + buf += bytes_read; + + cie->data_alignment_factor = + read_signed_leb128 (unit->abfd, buf, &bytes_read); + buf += bytes_read; + + cie->return_address_register = read_1_byte (unit->abfd, buf); + buf += 1; + + cie->saw_z_augmentation = (*augmentation == 'z'); + if (cie->saw_z_augmentation) + { + ULONGEST length; + + length = read_unsigned_leb128 (unit->abfd, buf, &bytes_read); + buf += bytes_read; + cie->initial_instructions = buf + length; + augmentation++; + } + + while (*augmentation) + { + /* "L" indicates a byte showing how the LSDA pointer is encoded. */ + if (*augmentation == 'L') + { + /* Skip. */ + buf++; + augmentation++; + } + + /* "R" indicates a byte indicating how FDE addresses are encoded. */ + else if (*augmentation == 'R') + { + cie->encoding = *buf++; + augmentation++; + } + + /* "P" indicates a personality routine in the CIE augmentation. */ + else if (*augmentation == 'P') + { + /* Skip. */ + buf += size_of_encoded_value (*buf++); + augmentation++; + } + + /* Otherwise we have an unknown augmentation. + Bail out unless we saw a 'z' prefix. */ + else + { + if (cie->initial_instructions == NULL) + return end; + + /* Skip unknown augmentations. */ + buf = cie->initial_instructions; + break; + } + } + + cie->initial_instructions = buf; + cie->end = end; + + add_cie (unit, cie); + } + else + { + /* This is a FDE. */ + struct dwarf2_fde *fde; + + if (eh_frame_p) + { + /* In an .eh_frame section, the CIE pointer is the delta + between the address within the FDE where the CIE pointer + is stored and the address of the CIE. Convert it to an + offset into the .eh_frame section. */ + cie_pointer = buf - unit->dwarf_frame_buffer - cie_pointer; + cie_pointer -= (dwarf64_p ? 8 : 4); + } + + fde = (struct dwarf2_fde *) + obstack_alloc (&unit->objfile->psymbol_obstack, + sizeof (struct dwarf2_fde)); + fde->cie = find_cie (unit, cie_pointer); + if (fde->cie == NULL) + { + decode_frame_entry (unit, unit->dwarf_frame_buffer + cie_pointer, + eh_frame_p); + fde->cie = find_cie (unit, cie_pointer); + } + + gdb_assert (fde->cie != NULL); + + fde->initial_location = + read_encoded_value (unit, fde->cie->encoding, buf, &bytes_read); + buf += bytes_read; + + fde->address_range = + read_encoded_value (unit, fde->cie->encoding & 0x0f, buf, &bytes_read); + buf += bytes_read; + + /* A 'z' augmentation in the CIE implies the presence of an + augmentation field in the FDE as well. The only thing known + to be in here at present is the LSDA entry for EH. So we + can skip the whole thing. */ + if (fde->cie->saw_z_augmentation) + { + ULONGEST length; + + length = read_unsigned_leb128 (unit->abfd, buf, &bytes_read); + buf += bytes_read + length; + } + + fde->instructions = buf; + fde->end = end; + + add_fde (unit, fde); + } + + return end; +} + + +/* FIXME: kettenis/20030504: This still needs to be integrated with + dwarf2read.c in a better way. */ + +/* Imported from dwarf2read.c. */ +extern file_ptr dwarf_frame_offset; +extern unsigned int dwarf_frame_size; +extern asection *dwarf_frame_section; +extern file_ptr dwarf_eh_frame_offset; +extern unsigned int dwarf_eh_frame_size; +extern asection *dwarf_eh_frame_section; + +/* Imported from dwarf2read.c. */ +extern char *dwarf2_read_section (struct objfile *objfile, file_ptr offset, + unsigned int size, asection *sectp); + +void +dwarf2_build_frame_info (struct objfile *objfile) +{ + struct comp_unit unit; + char *frame_ptr; + + /* Build a minimal decoding of the DWARF2 compilation unit. */ + unit.abfd = objfile->obfd; + unit.objfile = objfile; + unit.addr_size = objfile->obfd->arch_info->bits_per_address / 8; + unit.dbase = 0; + + /* First add the information from the .eh_frame section. That way, + the FDEs from that section are searched last. */ + if (dwarf_eh_frame_offset) + { + asection *got; + + unit.cie = NULL; + unit.dwarf_frame_buffer = dwarf2_read_section (objfile, + dwarf_eh_frame_offset, + dwarf_eh_frame_size, + dwarf_eh_frame_section); + + unit.dwarf_frame_size = dwarf_eh_frame_size; + unit.dwarf_frame_section = dwarf_eh_frame_section; + + /* FIXME: kettenis/20030602: This is the DW_EH_PE_datarel base + that for the i386/amd64 target, which currently is the only + target in GCC that supports/uses the DW_EH_PE_datarel + encoding. */ + got = bfd_get_section_by_name (unit.abfd, ".got"); + if (got) + unit.dbase = got->vma; + + frame_ptr = unit.dwarf_frame_buffer; + while (frame_ptr < unit.dwarf_frame_buffer + unit.dwarf_frame_size) + frame_ptr = decode_frame_entry (&unit, frame_ptr, 1); + } + + if (dwarf_frame_offset) + { + unit.cie = NULL; + unit.dwarf_frame_buffer = dwarf2_read_section (objfile, + dwarf_frame_offset, + dwarf_frame_size, + dwarf_frame_section); + unit.dwarf_frame_size = dwarf_frame_size; + unit.dwarf_frame_section = dwarf_frame_section; + + frame_ptr = unit.dwarf_frame_buffer; + while (frame_ptr < unit.dwarf_frame_buffer + unit.dwarf_frame_size) + frame_ptr = decode_frame_entry (&unit, frame_ptr, 0); + } +} diff --git a/gdb/dwarf2-frame.h b/gdb/dwarf2-frame.h new file mode 100644 index 0000000..4b4c1a5 --- /dev/null +++ b/gdb/dwarf2-frame.h @@ -0,0 +1,43 @@ +/* Frame unwinder for frames with DWARF Call Frame Information. + + Copyright 2003 Free Software Foundation, Inc. + + Contributed by Mark Kettenis. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef DWARF2_FRAME_H +#define DWARF2_FRAME_H 1 + +struct objfile; + +/* Return the frame unwind methods for the function that contains PC, + or NULL if it can't be handled by DWARF CFI frame unwinder. */ + +const struct frame_unwind *dwarf2_frame_p (CORE_ADDR pc); + +/* Return the frame base methods for the function that contains PC, or + NULL if it can't be handled by the DWARF CFI frame unwinder. */ + +const struct frame_base *dwarf2_frame_base_p (CORE_ADDR pc); + +/* Register the DWARF CFI for OBJFILE. */ + +void dwarf2_frame_build_info (struct objfile *objfile); + +#endif /* dwarf2-frame.h */ diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c new file mode 100644 index 0000000..61931c6 --- /dev/null +++ b/gdb/linux-nat.c @@ -0,0 +1,219 @@ +/* GNU/Linux native-dependent code common to multiple platforms. + Copyright (C) 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "target.h" + +#include "gdb_wait.h" +#include <sys/ptrace.h> + +#include "linux-nat.h" + +/* If the system headers did not provide the constants, hard-code the normal + values. */ +#ifndef PTRACE_EVENT_FORK + +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 + +/* options set using PTRACE_SETOPTIONS */ +#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 + +/* Wait extended result codes for the above trace options. */ +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 + +#endif /* PTRACE_EVENT_FORK */ + +/* We can't always assume that this flag is available, but all systems + with the ptrace event handlers also have __WALL, so it's safe to use + here. */ +#ifndef __WALL +#define __WALL 0x40000000 /* Wait for any child. */ +#endif + +struct simple_pid_list +{ + int pid; + struct simple_pid_list *next; +}; +struct simple_pid_list *stopped_pids; + +/* This variable is a tri-state flag: -1 for unknown, 0 if PTRACE_O_TRACEFORK + can not be used, 1 if it can. */ + +static int linux_supports_tracefork_flag = -1; + + +/* Trivial list manipulation functions to keep track of a list of + new stopped processes. */ +static void +add_to_pid_list (struct simple_pid_list **listp, int pid) +{ + struct simple_pid_list *new_pid = xmalloc (sizeof (struct simple_pid_list)); + new_pid->pid = pid; + new_pid->next = *listp; + *listp = new_pid; +} + +static int +pull_pid_from_list (struct simple_pid_list **listp, int pid) +{ + struct simple_pid_list **p; + + for (p = listp; *p != NULL; p = &(*p)->next) + if ((*p)->pid == pid) + { + struct simple_pid_list *next = (*p)->next; + xfree (*p); + *p = next; + return 1; + } + return 0; +} + +void +linux_record_stopped_pid (int pid) +{ + add_to_pid_list (&stopped_pids, pid); +} + + +/* A helper function for linux_test_for_tracefork, called after fork (). */ + +static void +linux_tracefork_child (void) +{ + int ret; + + ptrace (PTRACE_TRACEME, 0, 0, 0); + kill (getpid (), SIGSTOP); + fork (); + exit (0); +} + +/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events. We + create a child process, attach to it, use PTRACE_SETOPTIONS to enable + fork tracing, and let it fork. If the process exits, we assume that + we can't use TRACEFORK; if we get the fork notification, and we can + extract the new child's PID, then we assume that we can. */ + +static void +linux_test_for_tracefork (void) +{ + int child_pid, ret, status; + long second_pid; + + child_pid = fork (); + if (child_pid == -1) + perror_with_name ("linux_test_for_tracefork: fork"); + + if (child_pid == 0) + linux_tracefork_child (); + + ret = waitpid (child_pid, &status, 0); + if (ret == -1) + perror_with_name ("linux_test_for_tracefork: waitpid"); + else if (ret != child_pid) + error ("linux_test_for_tracefork: waitpid: unexpected result %d.", ret); + if (! WIFSTOPPED (status)) + error ("linux_test_for_tracefork: waitpid: unexpected status %d.", status); + + linux_supports_tracefork_flag = 0; + + ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK); + if (ret != 0) + { + ptrace (PTRACE_KILL, child_pid, 0, 0); + waitpid (child_pid, &status, 0); + return; + } + + ptrace (PTRACE_CONT, child_pid, 0, 0); + ret = waitpid (child_pid, &status, 0); + if (ret == child_pid && WIFSTOPPED (status) + && status >> 16 == PTRACE_EVENT_FORK) + { + second_pid = 0; + ret = ptrace (PTRACE_GETEVENTMSG, child_pid, 0, &second_pid); + if (ret == 0 && second_pid != 0) + { + int second_status; + + linux_supports_tracefork_flag = 1; + waitpid (second_pid, &second_status, 0); + ptrace (PTRACE_DETACH, second_pid, 0, 0); + } + } + + if (WIFSTOPPED (status)) + { + ptrace (PTRACE_DETACH, child_pid, 0, 0); + waitpid (child_pid, &status, 0); + } +} + +/* Return non-zero iff we have tracefork functionality available. + This function also sets linux_supports_tracefork_flag. */ + +static int +linux_supports_tracefork (void) +{ + if (linux_supports_tracefork_flag == -1) + linux_test_for_tracefork (); + return linux_supports_tracefork_flag; +} + + +int +child_insert_fork_catchpoint (int pid) +{ + if (linux_supports_tracefork ()) + error ("Fork catchpoints have not been implemented yet."); + else + error ("Your system does not support fork catchpoints."); +} + +int +child_insert_vfork_catchpoint (int pid) +{ + if (linux_supports_tracefork ()) + error ("Vfork catchpoints have not been implemented yet."); + else + error ("Your system does not support vfork catchpoints."); +} + +int +child_insert_exec_catchpoint (int pid) +{ + if (linux_supports_tracefork ()) + error ("Exec catchpoints have not been implemented yet."); + else + error ("Your system does not support exec catchpoints."); +} + + diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h new file mode 100644 index 0000000..b0d9600 --- /dev/null +++ b/gdb/linux-nat.h @@ -0,0 +1,73 @@ +/* Native debugging support for GNU/Linux (LWP layer). + Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Structure describing an LWP. */ + +struct lwp_info +{ + /* The process id of the LWP. This is a combination of the LWP id + and overall process id. */ + ptid_t ptid; + + /* Non-zero if this LWP is cloned. In this context "cloned" means + that the LWP is reporting to its parent using a signal other than + SIGCHLD. */ + int cloned; + + /* Non-zero if we sent this LWP a SIGSTOP (but the LWP didn't report + it back yet). */ + int signalled; + + /* Non-zero if this LWP is stopped. */ + int stopped; + + /* Non-zero if this LWP will be/has been resumed. Note that an LWP + can be marked both as stopped and resumed at the same time. This + happens if we try to resume an LWP that has a wait status + pending. We shouldn't let the LWP run until that wait status has + been processed, but we should not report that wait status if GDB + didn't try to let the LWP run. */ + int resumed; + + /* If non-zero, a pending wait status. */ + int status; + + /* Non-zero if we were stepping this LWP. */ + int step; + + /* Next LWP in list. */ + struct lwp_info *next; +}; + +/* Read/write to target memory via the Linux kernel's "proc file + system". */ +struct mem_attrib; +struct target_ops; + +extern int linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len, + int write, struct mem_attrib *attrib, + struct target_ops *target); + +extern void linux_record_stopped_pid (int pid); + +/* Iterator function for lin-lwp's lwp list. */ +struct lwp_info *iterate_over_lwps (int (*callback) (struct lwp_info *, + void *), + void *data); diff --git a/gdb/remote-fileio.c b/gdb/remote-fileio.c new file mode 100644 index 0000000..fd57617 --- /dev/null +++ b/gdb/remote-fileio.c @@ -0,0 +1,1379 @@ +/* Remote File-I/O communications + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* See the GDB User Guide for details of the GDB remote protocol. */ + +#include "defs.h" +#include "gdb_string.h" +#include "gdbcmd.h" +#include "remote.h" +#include "gdb/fileio.h" +#include "gdb_wait.h" +#include "gdb_stat.h" +#include "remote-fileio.h" + +#include <fcntl.h> +#include <sys/time.h> +#ifdef __CYGWIN__ +#include <sys/cygwin.h> /* For cygwin_conv_to_full_posix_path. */ +#endif +#include <signal.h> + +static struct { + int *fd_map; + int fd_map_size; +} remote_fio_data; + +#define FIO_FD_INVALID -1 +#define FIO_FD_CONSOLE_IN -2 +#define FIO_FD_CONSOLE_OUT -3 + +static int remote_fio_system_call_allowed = 0; + +static int +remote_fileio_init_fd_map (void) +{ + int i; + + if (!remote_fio_data.fd_map) + { + remote_fio_data.fd_map = (int *) xmalloc (10 * sizeof (int)); + remote_fio_data.fd_map_size = 10; + remote_fio_data.fd_map[0] = FIO_FD_CONSOLE_IN; + remote_fio_data.fd_map[1] = FIO_FD_CONSOLE_OUT; + remote_fio_data.fd_map[2] = FIO_FD_CONSOLE_OUT; + for (i = 3; i < 10; ++i) + remote_fio_data.fd_map[i] = FIO_FD_INVALID; + } + return 3; +} + +static int +remote_fileio_resize_fd_map (void) +{ + if (!remote_fio_data.fd_map) + return remote_fileio_init_fd_map (); + remote_fio_data.fd_map_size += 10; + remote_fio_data.fd_map = + (int *) xrealloc (remote_fio_data.fd_map, + remote_fio_data.fd_map_size * sizeof (int)); + return remote_fio_data.fd_map_size - 10; +} + +static int +remote_fileio_next_free_fd (void) +{ + int i; + + for (i = 0; i < remote_fio_data.fd_map_size; ++i) + if (remote_fio_data.fd_map[i] == FIO_FD_INVALID) + return i; + return remote_fileio_resize_fd_map (); +} + +static int +remote_fileio_fd_to_targetfd (int fd) +{ + int target_fd = remote_fileio_next_free_fd (); + remote_fio_data.fd_map[target_fd] = fd; + return target_fd; +} + +static int +remote_fileio_map_fd (int target_fd) +{ + remote_fileio_init_fd_map (); + if (target_fd < 0 || target_fd >= remote_fio_data.fd_map_size) + return FIO_FD_INVALID; + return remote_fio_data.fd_map[target_fd]; +} + +static void +remote_fileio_close_target_fd (int target_fd) +{ + remote_fileio_init_fd_map (); + if (target_fd >= 0 && target_fd < remote_fio_data.fd_map_size) + remote_fio_data.fd_map[target_fd] = FIO_FD_INVALID; +} + +static int +remote_fileio_oflags_to_host (long flags) +{ + int hflags = 0; + + if (flags & FILEIO_O_CREAT) + hflags |= O_CREAT; + if (flags & FILEIO_O_EXCL) + hflags |= O_EXCL; + if (flags & FILEIO_O_TRUNC) + hflags |= O_TRUNC; + if (flags & FILEIO_O_APPEND) + hflags |= O_APPEND; + if (flags & FILEIO_O_RDONLY) + hflags |= O_RDONLY; + if (flags & FILEIO_O_WRONLY) + hflags |= O_WRONLY; + if (flags & FILEIO_O_RDWR) + hflags |= O_RDWR; +/* On systems supporting binary and text mode, always open files in + binary mode. */ +#ifdef O_BINARY + hflags |= O_BINARY; +#endif + return hflags; +} + +static mode_t +remote_fileio_mode_to_host (long mode, int open_call) +{ + mode_t hmode = 0; + + if (!open_call) + { + if (mode & FILEIO_S_IFREG) + hmode |= S_IFREG; + if (mode & FILEIO_S_IFDIR) + hmode |= S_IFDIR; + if (mode & FILEIO_S_IFCHR) + hmode |= S_IFCHR; + } + if (mode & FILEIO_S_IRUSR) + hmode |= S_IRUSR; + if (mode & FILEIO_S_IWUSR) + hmode |= S_IWUSR; + if (mode & FILEIO_S_IXUSR) + hmode |= S_IXUSR; + if (mode & FILEIO_S_IRGRP) + hmode |= S_IRGRP; + if (mode & FILEIO_S_IWGRP) + hmode |= S_IWGRP; + if (mode & FILEIO_S_IXGRP) + hmode |= S_IXGRP; + if (mode & FILEIO_S_IROTH) + hmode |= S_IROTH; + if (mode & FILEIO_S_IWOTH) + hmode |= S_IWOTH; + if (mode & FILEIO_S_IXOTH) + hmode |= S_IXOTH; + return hmode; +} + +static LONGEST +remote_fileio_mode_to_target (mode_t mode) +{ + mode_t tmode = 0; + + if (mode & S_IFREG) + tmode |= FILEIO_S_IFREG; + if (mode & S_IFDIR) + tmode |= FILEIO_S_IFDIR; + if (mode & S_IFCHR) + tmode |= FILEIO_S_IFCHR; + if (mode & S_IRUSR) + tmode |= FILEIO_S_IRUSR; + if (mode & S_IWUSR) + tmode |= FILEIO_S_IWUSR; + if (mode & S_IXUSR) + tmode |= FILEIO_S_IXUSR; + if (mode & S_IRGRP) + tmode |= FILEIO_S_IRGRP; + if (mode & S_IWGRP) + tmode |= FILEIO_S_IWGRP; + if (mode & S_IXGRP) + tmode |= FILEIO_S_IXGRP; + if (mode & S_IROTH) + tmode |= FILEIO_S_IROTH; + if (mode & S_IWOTH) + tmode |= FILEIO_S_IWOTH; + if (mode & S_IXOTH) + tmode |= FILEIO_S_IXOTH; + return tmode; +} + +static int +remote_fileio_errno_to_target (int error) +{ + switch (error) + { + case EPERM: + return FILEIO_EPERM; + case ENOENT: + return FILEIO_ENOENT; + case EINTR: + return FILEIO_EINTR; + case EIO: + return FILEIO_EIO; + case EBADF: + return FILEIO_EBADF; + case EACCES: + return FILEIO_EACCES; + case EFAULT: + return FILEIO_EFAULT; + case EBUSY: + return FILEIO_EBUSY; + case EEXIST: + return FILEIO_EEXIST; + case ENODEV: + return FILEIO_ENODEV; + case ENOTDIR: + return FILEIO_ENOTDIR; + case EISDIR: + return FILEIO_EISDIR; + case EINVAL: + return FILEIO_EINVAL; + case ENFILE: + return FILEIO_ENFILE; + case EMFILE: + return FILEIO_EMFILE; + case EFBIG: + return FILEIO_EFBIG; + case ENOSPC: + return FILEIO_ENOSPC; + case ESPIPE: + return FILEIO_ESPIPE; + case EROFS: + return FILEIO_EROFS; + case ENOSYS: + return FILEIO_ENOSYS; + case ENAMETOOLONG: + return FILEIO_ENAMETOOLONG; + } + return FILEIO_EUNKNOWN; +} + +static int +remote_fileio_seek_flag_to_host (long num, int *flag) +{ + if (!flag) + return 0; + switch (num) + { + case FILEIO_SEEK_SET: + *flag = SEEK_SET; + break; + case FILEIO_SEEK_CUR: + *flag = SEEK_CUR; + break; + case FILEIO_SEEK_END: + *flag = SEEK_END; + break; + default: + return -1; + } + return 0; +} + +static int +remote_fileio_extract_long (char **buf, LONGEST *retlong) +{ + char *c; + int sign = 1; + + if (!buf || !*buf || !**buf || !retlong) + return -1; + c = strchr (*buf, ','); + if (c) + *c++ = '\0'; + else + c = strchr (*buf, '\0'); + while (strchr ("+-", **buf)) + { + if (**buf == '-') + sign = -sign; + ++*buf; + } + for (*retlong = 0; **buf; ++*buf) + { + *retlong <<= 4; + if (**buf >= '0' && **buf <= '9') + *retlong += **buf - '0'; + else if (**buf >= 'a' && **buf <= 'f') + *retlong += **buf - 'a' + 10; + else if (**buf >= 'A' && **buf <= 'F') + *retlong += **buf - 'A' + 10; + else + return -1; + } + *retlong *= sign; + *buf = c; + return 0; +} + +static int +remote_fileio_extract_int (char **buf, long *retint) +{ + int ret; + LONGEST retlong; + + if (!retint) + return -1; + ret = remote_fileio_extract_long (buf, &retlong); + if (!ret) + *retint = (long) retlong; + return ret; +} + +static int +remote_fileio_extract_ptr_w_len (char **buf, CORE_ADDR *ptrval, int *length) +{ + char *c; + LONGEST retlong; + + if (!buf || !*buf || !**buf || !ptrval || !length) + return -1; + c = strchr (*buf, '/'); + if (!c) + return -1; + *c++ = '\0'; + if (remote_fileio_extract_long (buf, &retlong)) + return -1; + *ptrval = (CORE_ADDR) retlong; + *buf = c; + if (remote_fileio_extract_long (buf, &retlong)) + return -1; + *length = (int) retlong; + return 0; +} + +/* Convert to big endian */ +static void +remote_fileio_to_be (LONGEST num, char *buf, int bytes) +{ + int i; + + for (i = 0; i < bytes; ++i) + buf[i] = (num >> (8 * (bytes - i - 1))) & 0xff; +} + +static void +remote_fileio_to_fio_int (long num, fio_int_t fnum) +{ + remote_fileio_to_be ((LONGEST) num, (char *) fnum, 4); +} + +static void +remote_fileio_to_fio_uint (long num, fio_uint_t fnum) +{ + remote_fileio_to_be ((LONGEST) num, (char *) fnum, 4); +} + +static void +remote_fileio_to_fio_mode (mode_t num, fio_mode_t fnum) +{ + remote_fileio_to_be (remote_fileio_mode_to_target(num), (char *) fnum, 4); +} + +static void +remote_fileio_to_fio_time (time_t num, fio_time_t fnum) +{ + remote_fileio_to_be ((LONGEST) num, (char *) fnum, 4); +} + +static void +remote_fileio_to_fio_long (LONGEST num, fio_long_t fnum) +{ + remote_fileio_to_be (num, (char *) fnum, 8); +} + +static void +remote_fileio_to_fio_ulong (LONGEST num, fio_ulong_t fnum) +{ + remote_fileio_to_be (num, (char *) fnum, 8); +} + +static void +remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst) +{ + /* `st_dev' is set in the calling function */ + remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino); + remote_fileio_to_fio_mode (st->st_mode, fst->fst_mode); + remote_fileio_to_fio_uint ((long) st->st_nlink, fst->fst_nlink); + remote_fileio_to_fio_uint ((long) st->st_uid, fst->fst_uid); + remote_fileio_to_fio_uint ((long) st->st_gid, fst->fst_gid); + remote_fileio_to_fio_uint ((long) st->st_rdev, fst->fst_rdev); + remote_fileio_to_fio_ulong ((LONGEST) st->st_size, fst->fst_size); + remote_fileio_to_fio_ulong ((LONGEST) st->st_blksize, fst->fst_blksize); + remote_fileio_to_fio_ulong ((LONGEST) st->st_blocks, fst->fst_blocks); + remote_fileio_to_fio_time (st->st_atime, fst->fst_atime); + remote_fileio_to_fio_time (st->st_mtime, fst->fst_mtime); + remote_fileio_to_fio_time (st->st_ctime, fst->fst_ctime); +} + +static void +remote_fileio_to_fio_timeval (struct timeval *tv, struct fio_timeval *ftv) +{ + remote_fileio_to_fio_time (tv->tv_sec, ftv->ftv_sec); + remote_fileio_to_fio_long (tv->tv_usec, ftv->ftv_usec); +} + +static int remote_fio_ctrl_c_flag = 0; +static int remote_fio_no_longjmp = 0; + +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) +static struct sigaction remote_fio_sa; +static struct sigaction remote_fio_osa; +#else +static void (*remote_fio_ofunc)(int); +#endif + +static void +remote_fileio_sig_init (void) +{ +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) + remote_fio_sa.sa_handler = SIG_IGN; + sigemptyset (&remote_fio_sa.sa_mask); + remote_fio_sa.sa_flags = 0; + sigaction (SIGINT, &remote_fio_sa, &remote_fio_osa); +#else + remote_fio_ofunc = signal (SIGINT, SIG_IGN); +#endif +} + +static void +remote_fileio_sig_set (void (*sigint_func)(int)) +{ +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) + remote_fio_sa.sa_handler = sigint_func; + sigemptyset (&remote_fio_sa.sa_mask); + remote_fio_sa.sa_flags = 0; + sigaction (SIGINT, &remote_fio_sa, NULL); +#else + signal (SIGINT, sigint_func); +#endif +} + +static void +remote_fileio_sig_exit (void) +{ +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) + sigaction (SIGINT, &remote_fio_osa, NULL); +#else + signal (SIGINT, remote_fio_ofunc); +#endif +} + +static void +remote_fileio_ctrl_c_signal_handler (int signo) +{ + remote_fileio_sig_set (SIG_IGN); + remote_fio_ctrl_c_flag = 1; + if (!remote_fio_no_longjmp) + throw_exception (RETURN_QUIT); + remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler); +} + +static void +remote_fileio_reply (int retcode, int error) +{ + char buf[32]; + + remote_fileio_sig_set (SIG_IGN); + strcpy (buf, "F"); + if (retcode < 0) + { + strcat (buf, "-"); + retcode = -retcode; + } + sprintf (buf + strlen (buf), "%x", retcode); + if (error || remote_fio_ctrl_c_flag) + { + if (error && remote_fio_ctrl_c_flag) + error = FILEIO_EINTR; + if (error < 0) + { + strcat (buf, "-"); + error = -error; + } + sprintf (buf + strlen (buf), ",%x", error); + if (remote_fio_ctrl_c_flag) + strcat (buf, ",C"); + } + remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler); + putpkt (buf); +} + +static void +remote_fileio_ioerror (void) +{ + remote_fileio_reply (-1, FILEIO_EIO); +} + +static void +remote_fileio_badfd (void) +{ + remote_fileio_reply (-1, FILEIO_EBADF); +} + +static void +remote_fileio_return_errno (int retcode) +{ + remote_fileio_reply (retcode, + retcode < 0 ? remote_fileio_errno_to_target (errno) : 0); +} + +static void +remote_fileio_return_success (int retcode) +{ + remote_fileio_reply (retcode, 0); +} + +/* Wrapper function for remote_write_bytes() which has the disadvantage to + write only one packet, regardless of the requested number of bytes to + transfer. This wrapper calls remote_write_bytes() as often as needed. */ +static int +remote_fileio_write_bytes (CORE_ADDR memaddr, char *myaddr, int len) +{ + int ret = 0, written; + + while (len > 0 && (written = remote_write_bytes (memaddr, myaddr, len)) > 0) + { + len -= written; + memaddr += written; + myaddr += written; + ret += written; + } + return ret; +} + +static void +remote_fileio_func_open (char *buf) +{ + CORE_ADDR ptrval; + int length, retlength; + long num; + int flags, fd; + mode_t mode; + char *pathname; + struct stat st; + + /* 1. Parameter: Ptr to pathname / length incl. trailing zero */ + if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length)) + { + remote_fileio_ioerror (); + return; + } + /* 2. Parameter: open flags */ + if (remote_fileio_extract_int (&buf, &num)) + { + remote_fileio_ioerror (); + return; + } + flags = remote_fileio_oflags_to_host (num); + /* 3. Parameter: open mode */ + if (remote_fileio_extract_int (&buf, &num)) + { + remote_fileio_ioerror (); + return; + } + mode = remote_fileio_mode_to_host (num, 1); + + /* Request pathname using 'm' packet */ + pathname = alloca (length); + retlength = remote_read_bytes (ptrval, pathname, length); + if (retlength != length) + { + remote_fileio_ioerror (); + return; + } + + /* Check if pathname exists and is not a regular file or directory. If so, + return an appropriate error code. Same for trying to open directories + for writing. */ + if (!stat (pathname, &st)) + { + if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode)) + { + remote_fileio_reply (-1, FILEIO_ENODEV); + return; + } + if (S_ISDIR (st.st_mode) + && ((flags & O_WRONLY) == O_WRONLY || (flags & O_RDWR) == O_RDWR)) + { + remote_fileio_reply (-1, FILEIO_EISDIR); + return; + } + } + + remote_fio_no_longjmp = 1; + fd = open (pathname, flags, mode); + if (fd < 0) + { + remote_fileio_return_errno (-1); + return; + } + + fd = remote_fileio_fd_to_targetfd (fd); + remote_fileio_return_success (fd); +} + +static void +remote_fileio_func_close (char *buf) +{ + long num; + int fd; + + /* Parameter: file descriptor */ + if (remote_fileio_extract_int (&buf, &num)) + { + remote_fileio_ioerror (); + return; + } + fd = remote_fileio_map_fd ((int) num); + if (fd == FIO_FD_INVALID) + { + remote_fileio_badfd (); + return; + } + + remote_fio_no_longjmp = 1; + if (fd != FIO_FD_CONSOLE_IN && fd != FIO_FD_CONSOLE_OUT && close (fd)) + remote_fileio_return_errno (-1); + remote_fileio_close_target_fd ((int) num); + remote_fileio_return_success (0); +} + +static void +remote_fileio_func_read (char *buf) +{ + long target_fd, num; + LONGEST lnum; + CORE_ADDR ptrval; + int fd, ret, retlength; + char *buffer; + size_t length; + off_t old_offset, new_offset; + + /* 1. Parameter: file descriptor */ + if (remote_fileio_extract_int (&buf, &target_fd)) + { + remote_fileio_ioerror (); + return; + } + fd = remote_fileio_map_fd ((int) target_fd); + if (fd == FIO_FD_INVALID) + { + remote_fileio_badfd (); + return; + } + /* 2. Parameter: buffer pointer */ + if (remote_fileio_extract_long (&buf, &lnum)) + { + remote_fileio_ioerror (); + return; + } + ptrval = (CORE_ADDR) lnum; + /* 3. Parameter: buffer length */ + if (remote_fileio_extract_int (&buf, &num)) + { + remote_fileio_ioerror (); + return; + } + length = (size_t) num; + + switch (fd) + { + case FIO_FD_CONSOLE_OUT: + remote_fileio_badfd (); + return; + case FIO_FD_CONSOLE_IN: + { + static char *remaining_buf = NULL; + static int remaining_length = 0; + + buffer = (char *) xmalloc (32768); + if (remaining_buf) + { + remote_fio_no_longjmp = 1; + if (remaining_length > length) + { + memcpy (buffer, remaining_buf, length); + memmove (remaining_buf, remaining_buf + length, + remaining_length - length); + remaining_length -= length; + ret = length; + } + else + { + memcpy (buffer, remaining_buf, remaining_length); + xfree (remaining_buf); + remaining_buf = NULL; + ret = remaining_length; + } + } + else + { + ret = ui_file_read (gdb_stdtargin, buffer, 32767); + remote_fio_no_longjmp = 1; + if (ret > 0 && (size_t)ret > length) + { + remaining_buf = (char *) xmalloc (ret - length); + remaining_length = ret - length; + memcpy (remaining_buf, buffer + length, remaining_length); + ret = length; + } + } + } + break; + default: + buffer = (char *) xmalloc (length); + /* POSIX defines EINTR behaviour of read in a weird way. It's allowed + for read() to return -1 even if "some" bytes have been read. It + has been corrected in SUSv2 but that doesn't help us much... + Therefore a complete solution must check how many bytes have been + read on EINTR to return a more reliable value to the target */ + old_offset = lseek (fd, 0, SEEK_CUR); + remote_fio_no_longjmp = 1; + ret = read (fd, buffer, length); + if (ret < 0 && errno == EINTR) + { + new_offset = lseek (fd, 0, SEEK_CUR); + /* If some data has been read, return the number of bytes read. + The Ctrl-C flag is set in remote_fileio_reply() anyway */ + if (old_offset != new_offset) + ret = new_offset - old_offset; + } + break; + } + + if (ret > 0) + { + retlength = remote_fileio_write_bytes (ptrval, buffer, ret); + if (retlength != ret) + ret = -1; /* errno has been set to EIO in remote_fileio_write_bytes() */ + } + + if (ret < 0) + remote_fileio_return_errno (-1); + else + remote_fileio_return_success (ret); + + xfree (buffer); +} + +static void +remote_fileio_func_write (char *buf) +{ + long target_fd, num; + LONGEST lnum; + CORE_ADDR ptrval; + int fd, ret, retlength; + char *buffer; + size_t length; + + /* 1. Parameter: file descriptor */ + if (remote_fileio_extract_int (&buf, &target_fd)) + { + remote_fileio_ioerror (); + return; + } + fd = remote_fileio_map_fd ((int) target_fd); + if (fd == FIO_FD_INVALID) + { + remote_fileio_badfd (); + return; + } + /* 2. Parameter: buffer pointer */ + if (remote_fileio_extract_long (&buf, &lnum)) + { + remote_fileio_ioerror (); + return; + } + ptrval = (CORE_ADDR) lnum; + /* 3. Parameter: buffer length */ + if (remote_fileio_extract_int (&buf, &num)) + { + remote_fileio_ioerror (); + return; + } + length = (size_t) num; + + buffer = (char *) xmalloc (length); + retlength = remote_read_bytes (ptrval, buffer, length); + if (retlength != length) + { + xfree (buffer); + remote_fileio_ioerror (); + return; + } + + remote_fio_no_longjmp = 1; + switch (fd) + { + case FIO_FD_CONSOLE_IN: + remote_fileio_badfd (); + return; + case FIO_FD_CONSOLE_OUT: + ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr, buffer, + length); + gdb_flush (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr); + ret = length; + break; + default: + ret = write (fd, buffer, length); + if (ret < 0 && errno == EACCES) + errno = EBADF; /* Cygwin returns EACCESS when writing to a R/O file.*/ + break; + } + + if (ret < 0) + remote_fileio_return_errno (-1); + else + remote_fileio_return_success (ret); + + xfree (buffer); +} + +static void +remote_fileio_func_lseek (char *buf) +{ + long num; + LONGEST lnum; + int fd, flag; + off_t offset, ret; + + /* 1. Parameter: file descriptor */ + if (remote_fileio_extract_int (&buf, &num)) + { + remote_fileio_ioerror (); + return; + } + fd = remote_fileio_map_fd ((int) num); + if (fd == FIO_FD_INVALID) + { + remote_fileio_badfd (); + return; + } + else if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT) + { + remote_fileio_reply (-1, FILEIO_ESPIPE); + return; + } + + /* 2. Parameter: offset */ + if (remote_fileio_extract_long (&buf, &lnum)) + { + remote_fileio_ioerror (); + return; + } + offset = (off_t) lnum; + /* 3. Parameter: flag */ + if (remote_fileio_extract_int (&buf, &num)) + { + remote_fileio_ioerror (); + return; + } + if (remote_fileio_seek_flag_to_host (num, &flag)) + { + remote_fileio_reply (-1, FILEIO_EINVAL); + return; + } + + remote_fio_no_longjmp = 1; + ret = lseek (fd, offset, flag); + + if (ret == (off_t) -1) + remote_fileio_return_errno (-1); + else + remote_fileio_return_success (ret); +} + +static void +remote_fileio_func_rename (char *buf) +{ + CORE_ADDR ptrval; + int length, retlength; + char *oldpath, *newpath; + int ret, of, nf; + struct stat ost, nst; + + /* 1. Parameter: Ptr to oldpath / length incl. trailing zero */ + if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length)) + { + remote_fileio_ioerror (); + return; + } + /* Request oldpath using 'm' packet */ + oldpath = alloca (length); + retlength = remote_read_bytes (ptrval, oldpath, length); + if (retlength != length) + { + remote_fileio_ioerror (); + return; + } + /* 2. Parameter: Ptr to newpath / length incl. trailing zero */ + if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length)) + { + remote_fileio_ioerror (); + return; + } + /* Request newpath using 'm' packet */ + newpath = alloca (length); + retlength = remote_read_bytes (ptrval, newpath, length); + if (retlength != length) + { + remote_fileio_ioerror (); + return; + } + + /* Only operate on regular files and directories */ + of = stat (oldpath, &ost); + nf = stat (newpath, &nst); + if ((!of && !S_ISREG (ost.st_mode) && !S_ISDIR (ost.st_mode)) + || (!nf && !S_ISREG (nst.st_mode) && !S_ISDIR (nst.st_mode))) + { + remote_fileio_reply (-1, FILEIO_EACCES); + return; + } + + remote_fio_no_longjmp = 1; + ret = rename (oldpath, newpath); + + if (ret == -1) + { + /* Special case: newpath is a non-empty directory. Some systems + return ENOTEMPTY, some return EEXIST. We coerce that to be + always EEXIST. */ + if (errno == ENOTEMPTY) + errno = EEXIST; +#ifdef __CYGWIN__ + /* Workaround some Cygwin problems with correct errnos. */ + if (errno == EACCES) + { + if (!of && !nf && S_ISDIR (nst.st_mode)) + { + if (S_ISREG (ost.st_mode)) + errno = EISDIR; + else + { + char oldfullpath[PATH_MAX + 1]; + char newfullpath[PATH_MAX + 1]; + int len; + + cygwin_conv_to_full_posix_path (oldpath, oldfullpath); + cygwin_conv_to_full_posix_path (newpath, newfullpath); + len = strlen (oldfullpath); + if (newfullpath[len] == '/' + && !strncmp (oldfullpath, newfullpath, len)) + errno = EINVAL; + else + errno = EEXIST; + } + } + } +#endif + + remote_fileio_return_errno (-1); + } + else + remote_fileio_return_success (ret); +} + +static void +remote_fileio_func_unlink (char *buf) +{ + CORE_ADDR ptrval; + int length, retlength; + char *pathname; + int ret; + struct stat st; + + /* Parameter: Ptr to pathname / length incl. trailing zero */ + if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length)) + { + remote_fileio_ioerror (); + return; + } + /* Request pathname using 'm' packet */ + pathname = alloca (length); + retlength = remote_read_bytes (ptrval, pathname, length); + if (retlength != length) + { + remote_fileio_ioerror (); + return; + } + + /* Only operate on regular files (and directories, which allows to return + the correct return code) */ + if (!stat (pathname, &st) && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode)) + { + remote_fileio_reply (-1, FILEIO_ENODEV); + return; + } + + remote_fio_no_longjmp = 1; + ret = unlink (pathname); + + if (ret == -1) + remote_fileio_return_errno (-1); + else + remote_fileio_return_success (ret); +} + +static void +remote_fileio_func_stat (char *buf) +{ + CORE_ADDR ptrval; + int ret, length, retlength; + char *pathname; + LONGEST lnum; + struct stat st; + struct fio_stat fst; + + /* 1. Parameter: Ptr to pathname / length incl. trailing zero */ + if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length)) + { + remote_fileio_ioerror (); + return; + } + /* Request pathname using 'm' packet */ + pathname = alloca (length); + retlength = remote_read_bytes (ptrval, pathname, length); + if (retlength != length) + { + remote_fileio_ioerror (); + return; + } + + /* 2. Parameter: Ptr to struct stat */ + if (remote_fileio_extract_long (&buf, &lnum)) + { + remote_fileio_ioerror (); + return; + } + ptrval = (CORE_ADDR) lnum; + + remote_fio_no_longjmp = 1; + ret = stat (pathname, &st); + + if (ret == -1) + { + remote_fileio_return_errno (-1); + return; + } + /* Only operate on regular files and directories */ + if (!ret && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode)) + { + remote_fileio_reply (-1, FILEIO_EACCES); + return; + } + if (ptrval) + { + remote_fileio_to_fio_stat (&st, &fst); + remote_fileio_to_fio_uint (0, fst.fst_dev); + + retlength = remote_fileio_write_bytes (ptrval, (char *) &fst, sizeof fst); + if (retlength != sizeof fst) + { + remote_fileio_return_errno (-1); + return; + } + } + remote_fileio_return_success (ret); +} + +static void +remote_fileio_func_fstat (char *buf) +{ + CORE_ADDR ptrval; + int fd, ret, retlength; + long target_fd; + LONGEST lnum; + struct stat st; + struct fio_stat fst; + struct timeval tv; + + /* 1. Parameter: file descriptor */ + if (remote_fileio_extract_int (&buf, &target_fd)) + { + remote_fileio_ioerror (); + return; + } + fd = remote_fileio_map_fd ((int) target_fd); + if (fd == FIO_FD_INVALID) + { + remote_fileio_badfd (); + return; + } + /* 2. Parameter: Ptr to struct stat */ + if (remote_fileio_extract_long (&buf, &lnum)) + { + remote_fileio_ioerror (); + return; + } + ptrval = (CORE_ADDR) lnum; + + remote_fio_no_longjmp = 1; + if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT) + { + remote_fileio_to_fio_uint (1, fst.fst_dev); + st.st_mode = S_IFCHR | (fd == FIO_FD_CONSOLE_IN ? S_IRUSR : S_IWUSR); + st.st_nlink = 1; + st.st_uid = getuid (); + st.st_gid = getgid (); + st.st_rdev = 0; + st.st_size = 0; + st.st_blksize = 512; + st.st_blocks = 0; + if (!gettimeofday (&tv, NULL)) + st.st_atime = st.st_mtime = st.st_ctime = tv.tv_sec; + else + st.st_atime = st.st_mtime = st.st_ctime = (time_t) 0; + ret = 0; + } + else + ret = fstat (fd, &st); + + if (ret == -1) + { + remote_fileio_return_errno (-1); + return; + } + if (ptrval) + { + remote_fileio_to_fio_stat (&st, &fst); + + retlength = remote_fileio_write_bytes (ptrval, (char *) &fst, sizeof fst); + if (retlength != sizeof fst) + { + remote_fileio_return_errno (-1); + return; + } + } + remote_fileio_return_success (ret); +} + +static void +remote_fileio_func_gettimeofday (char *buf) +{ + LONGEST lnum; + CORE_ADDR ptrval; + int ret, retlength; + struct timeval tv; + struct fio_timeval ftv; + + /* 1. Parameter: struct timeval pointer */ + if (remote_fileio_extract_long (&buf, &lnum)) + { + remote_fileio_ioerror (); + return; + } + ptrval = (CORE_ADDR) lnum; + /* 2. Parameter: some pointer value... */ + if (remote_fileio_extract_long (&buf, &lnum)) + { + remote_fileio_ioerror (); + return; + } + /* ...which has to be NULL */ + if (lnum) + { + remote_fileio_reply (-1, FILEIO_EINVAL); + return; + } + + remote_fio_no_longjmp = 1; + ret = gettimeofday (&tv, NULL); + + if (ret == -1) + { + remote_fileio_return_errno (-1); + return; + } + + if (ptrval) + { + remote_fileio_to_fio_timeval (&tv, &ftv); + + retlength = remote_fileio_write_bytes (ptrval, (char *) &ftv, sizeof ftv); + if (retlength != sizeof ftv) + { + remote_fileio_return_errno (-1); + return; + } + } + remote_fileio_return_success (ret); +} + +static void +remote_fileio_func_isatty (char *buf) +{ + long target_fd; + int fd; + + /* Parameter: file descriptor */ + if (remote_fileio_extract_int (&buf, &target_fd)) + { + remote_fileio_ioerror (); + return; + } + remote_fio_no_longjmp = 1; + fd = remote_fileio_map_fd ((int) target_fd); + remote_fileio_return_success (fd == FIO_FD_CONSOLE_IN || + fd == FIO_FD_CONSOLE_OUT ? 1 : 0); +} + +static void +remote_fileio_func_system (char *buf) +{ + CORE_ADDR ptrval; + int ret, length, retlength; + char *cmdline; + + /* Check if system(3) has been explicitely allowed using the + `set remote system-call-allowed 1' command. If not, return + EPERM */ + if (!remote_fio_system_call_allowed) + { + remote_fileio_reply (-1, FILEIO_EPERM); + return; + } + + /* Parameter: Ptr to commandline / length incl. trailing zero */ + if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length)) + { + remote_fileio_ioerror (); + return; + } + /* Request commandline using 'm' packet */ + cmdline = alloca (length); + retlength = remote_read_bytes (ptrval, cmdline, length); + if (retlength != length) + { + remote_fileio_ioerror (); + return; + } + + remote_fio_no_longjmp = 1; + ret = system (cmdline); + + if (ret == -1) + remote_fileio_return_errno (-1); + else + remote_fileio_return_success (WEXITSTATUS (ret)); +} + +static struct { + char *name; + void (*func)(char *); +} remote_fio_func_map[] = { + "open", remote_fileio_func_open, + "close", remote_fileio_func_close, + "read", remote_fileio_func_read, + "write", remote_fileio_func_write, + "lseek", remote_fileio_func_lseek, + "rename", remote_fileio_func_rename, + "unlink", remote_fileio_func_unlink, + "stat", remote_fileio_func_stat, + "fstat", remote_fileio_func_fstat, + "gettimeofday", remote_fileio_func_gettimeofday, + "isatty", remote_fileio_func_isatty, + "system", remote_fileio_func_system, + NULL, NULL +}; + +static int +do_remote_fileio_request (struct ui_out *uiout, void *buf_arg) +{ + char *buf = buf_arg; + char *c; + int idx; + + remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler); + + c = strchr (++buf, ','); + if (c) + *c++ = '\0'; + else + c = strchr (buf, '\0'); + for (idx = 0; remote_fio_func_map[idx].name; ++idx) + if (!strcmp (remote_fio_func_map[idx].name, buf)) + break; + if (!remote_fio_func_map[idx].name) /* ERROR: No such function. */ + return RETURN_ERROR; + remote_fio_func_map[idx].func (c); + return 0; +} + +void +remote_fileio_request (char *buf) +{ + int ex; + + remote_fileio_sig_init (); + + remote_fio_ctrl_c_flag = 0; + remote_fio_no_longjmp = 0; + + ex = catch_exceptions (uiout, do_remote_fileio_request, (void *)buf, + NULL, RETURN_MASK_ALL); + switch (ex) + { + case RETURN_ERROR: + remote_fileio_reply (-1, FILEIO_ENOSYS); + break; + case RETURN_QUIT: + remote_fileio_reply (-1, FILEIO_EINTR); + break; + default: + break; + } + + remote_fileio_sig_exit (); +} + +static void +set_system_call_allowed (char *args, int from_tty) +{ + if (args) + { + char *arg_end; + int val = strtoul (args, &arg_end, 10); + if (*args && *arg_end == '\0') + { + remote_fio_system_call_allowed = !!val; + return; + } + } + error ("Illegal argument for \"set remote system-call-allowed\" command"); +} + +static void +show_system_call_allowed (char *args, int from_tty) +{ + if (args) + error ("Garbage after \"show remote system-call-allowed\" command: `%s'", args); + printf_unfiltered ("Calling host system(3) call from target is %sallowed\n", + remote_fio_system_call_allowed ? "" : "not "); +} + +void +initialize_remote_fileio (struct cmd_list_element *remote_set_cmdlist, + struct cmd_list_element *remote_show_cmdlist) +{ + add_cmd ("system-call-allowed", no_class, + set_system_call_allowed, + "Set if the host system(3) call is allowed for the target.\n", + &remote_set_cmdlist); + add_cmd ("system-call-allowed", no_class, + show_system_call_allowed, + "Show if the host system(3) call is allowed for the target.\n", + &remote_show_cmdlist); +} diff --git a/gdb/remote-fileio.h b/gdb/remote-fileio.h new file mode 100644 index 0000000..68c6450 --- /dev/null +++ b/gdb/remote-fileio.h @@ -0,0 +1,38 @@ +/* Remote File-I/O communications + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* See the GDB User Guide for details of the GDB remote protocol. */ + +#ifndef REMOTE_FILEIO_H +#define REMOTE_FILEIO_H + +struct cmd_list_element; + +/* Unified interface to remote fileio, called in remote.c from + remote_wait () and remote_async_wait () */ +extern void remote_fileio_request (char *buf); + +/* Called from _initialize_remote () */ +extern void initialize_remote_fileio ( + struct cmd_list_element *remote_set_cmdlist, + struct cmd_list_element *remote_show_cmdlist); + +#endif diff --git a/gdb/stack.h b/gdb/stack.h new file mode 100644 index 0000000..0891c94 --- /dev/null +++ b/gdb/stack.h @@ -0,0 +1,27 @@ +/* Stack manipulation commands, for GDB the GNU Debugger. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef STACK_H +#define STACK_H + +void select_frame_command (char *level_exp, int from_tty); + +#endif /* #ifndef STACK_H */ diff --git a/gdb/testsuite/gdb.asm/alpha.inc b/gdb/testsuite/gdb.asm/alpha.inc new file mode 100644 index 0000000..f9741c4 --- /dev/null +++ b/gdb/testsuite/gdb.asm/alpha.inc @@ -0,0 +1,62 @@ + comment "subroutine declare" + .macro gdbasm_declare name + .ent \name +\name: + .endm + + comment "subroutine prologue" + .macro gdbasm_enter + .frame $30, 16, $26, 0 + .mask 0x04000000, -16 + ldgp $gp, 0($27) + subq $sp, 16, $sp + stq $26, 0($sp) + .prologue 1 + .endm + + comment "subroutine epilogue" + .macro gdbasm_leave + ldq $26, 0($sp) + addq $sp, 16, $sp + ret + .endm + + comment "subroutine end" + .macro gdbasm_end name + .end \name + .endm + + comment "subroutine call" + /* Can't use ldgp here because the finish-frame test expects the + pc to wind up on the next line. That's ok, we're all local. */ + .macro gdbasm_call subr + jsr $26, \subr + .endm + + .macro gdbasm_several_nops + nop + nop + nop + nop + .endm + + comment "exit (0)" + .macro gdbasm_exit0 + lda $16, 0($31) + lda $0, 1($31) + callsys + .endm + + comment "crt0 startup" + .macro gdbasm_startup + .frame $31, 0, $31, 0 + .prologue + ldgp $gp, 0($27) + .endm + + comment "Declare a data variable" + .macro gdbasm_datavar name value + .data +\name: + .long \value + .endm diff --git a/gdb/testsuite/gdb.base/bang.exp b/gdb/testsuite/gdb.base/bang.exp new file mode 100644 index 0000000..f584074 --- /dev/null +++ b/gdb/testsuite/gdb.base/bang.exp @@ -0,0 +1,41 @@ +# Copyright 2003 Free Software Foundation, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This is a test that verifies that GDB is able to "run" when the name +# of the executable file contains a '!'. + +if $tracelevel then { + strace $tracelevel +} + +set testfile "args" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/bang! + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-w}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# Verify that we can run the program and that it terminates normally. +gdb_test "run" \ + ".*Program exited normally\." \ + "run program" + diff --git a/gdb/testsuite/gdb.base/fileio.c b/gdb/testsuite/gdb.base/fileio.c new file mode 100644 index 0000000..591b3b6 --- /dev/null +++ b/gdb/testsuite/gdb.base/fileio.c @@ -0,0 +1,503 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <errno.h> +#include <sys/wait.h> +/* TESTS : + * - open(const char *pathname, int flags, mode_t mode); +1) Attempt to create file that already exists - EEXIST +2) Attempt to open a directory for writing - EISDIR +3) Pathname does not exist - ENOENT +4) Open for write but no write permission - EACCES + +read(int fd, void *buf, size_t count); +1) Read using invalid file descriptor - EBADF + +write(int fd, const void *buf, size_t count); +1) Write using invalid file descriptor - EBADF +2) Attempt to write to read-only file - EBADF + +lseek(int fildes, off_t offset, int whence); +1) Seeking on an invalid file descriptor - EBADF +2) Invalid "whence" (3rd param) value - EINVAL + +close(int fd); +1) Attempt to close an invalid file descriptor - EBADF + +stat(const char *file_name, struct stat *buf); +1) Pathname is a null string - ENOENT +2) Pathname does not exist - ENOENT + +fstat(int filedes, struct stat *buf); +1) Attempt to stat using an invalid file descriptor - EBADF + +isatty (int desc); +Not applicable. We will test that it returns 1 when expected and a case +where it should return 0. + +rename(const char *oldpath, const char *newpath); +1) newpath is an existing directory, but oldpath is not a directory. - EISDIR +2) newpath is a non-empty directory. - ENOTEMPTY or EEXIST +3) newpath is a subdirectory of old path. - EINVAL +4) oldpath does not exist. - ENOENT + +unlink(const char *pathname); +1) pathname does not have write access. - EACCES +2) pathname does not exist. - ENOENT + +time(time_t *t); +Not applicable. + +system (const char * string); +1) Invalid string/command. - returns 127. */ + +static const char *strerrno (int err); + +#define FILENAME "foo.fileio.test" +#define RENAMED "bar.fileio.test" +#define NONEXISTANT "nofoo.fileio.test" +#define NOWRITE "nowrt.fileio.test" +#define TESTDIR1 "dir1.fileio.test" +#define TESTDIR2 "dir2.fileio.test" +#define TESTSUBDIR "dir1.fileio.test/subdir.fileio.test" + +#define STRING "Hello World" + +int +test_open () +{ + int ret; + + /* Test opening */ + errno = 0; + ret = open (FILENAME, O_CREAT | O_TRUNC | O_RDONLY, S_IWUSR | S_IRUSR); + printf ("open 1: ret = %d, errno = %d %s\n", ret, errno, + ret >= 0 ? "OK" : ""); + if (ret >= 0) + close (ret); + /* Creating an already existing file (created by fileio.exp) */ + errno = 0; + ret = open (FILENAME, O_CREAT | O_EXCL | O_WRONLY, S_IWUSR | S_IRUSR); + printf ("open 2: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + if (ret >= 0) + close (ret); + /* Open directory (for writing) */ + errno = 0; + ret = open (".", O_WRONLY); + printf ("open 3: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + if (ret >= 0) + close (ret); + /* Opening nonexistant file */ + errno = 0; + ret = open (NONEXISTANT, O_RDONLY); + printf ("open 4: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + if (ret >= 0) + close (ret); + /* Open for write but no write permission */ + errno = 0; + ret = open (NOWRITE, O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR); + if (ret >= 0) + { + close (ret); + errno = 0; + ret = open (NOWRITE, O_WRONLY); + printf ("open 5: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + if (ret >= 0) + close (ret); + } + else + printf ("open 5: ret = %d, errno = %d\n", ret, errno); +} + +int +test_write () +{ + int fd, ret; + + /* Test writing */ + errno = 0; + fd = open (FILENAME, O_WRONLY); + if (fd >= 0) + { + errno = 0; + ret = write (fd, STRING, strlen (STRING)); + printf ("write 1: ret = %d, errno = %d %s\n", ret, errno, + ret == strlen (STRING) ? "OK" : ""); + close (fd); + } + else + printf ("write 1: ret = %d, errno = %d\n", ret, errno); + /* Write using invalid file descriptor */ + errno = 0; + ret = write (999, STRING, strlen (STRING)); + printf ("write 2: ret = %d, errno = %d, %s\n", ret, errno, + strerrno (errno)); + /* Write to a read-only file */ + errno = 0; + fd = open (FILENAME, O_RDONLY); + if (fd >= 0) + { + errno = 0; + ret = write (fd, STRING, strlen (STRING)); + printf ("write 3: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + } + else + printf ("write 3: ret = %d, errno = %d\n", ret, errno); +} + +int +test_read () +{ + int fd, ret; + char buf[16]; + + /* Test reading */ + errno = 0; + fd = open (FILENAME, O_RDONLY); + if (fd >= 0) + { + memset (buf, 0, 16); + errno = 0; + ret = read (fd, buf, 16); + buf[15] = '\0'; /* Don't trust anybody... */ + if (ret == strlen (STRING)) + printf ("read 1: %s %s\n", buf, !strcmp (buf, STRING) ? "OK" : ""); + else + printf ("read 1: ret = %d, errno = %d\n", ret, errno); + close (fd); + } + else + printf ("read 1: ret = %d, errno = %d\n", ret, errno); + /* Read using invalid file descriptor */ + errno = 0; + ret = read (999, buf, 16); + printf ("read 2: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); +} + +int +test_lseek () +{ + int fd; + off_t ret = 0; + + /* Test seeking */ + errno = 0; + fd = open (FILENAME, O_RDONLY); + if (fd >= 0) + { + errno = 0; + ret = lseek (fd, 0, SEEK_CUR); + printf ("lseek 1: ret = %ld, errno = %d, %s\n", (long) ret, errno, + ret == 0 ? "OK" : ""); + errno = 0; + ret = lseek (fd, 0, SEEK_END); + printf ("lseek 2: ret = %ld, errno = %d, %s\n", (long) ret, errno, + ret == 11 ? "OK" : ""); + errno = 0; + ret = lseek (fd, 3, SEEK_SET); + printf ("lseek 3: ret = %ld, errno = %d, %s\n", (long) ret, errno, + ret == 3 ? "OK" : ""); + close (fd); + } + else + { + printf ("lseek 1: ret = %d, errno = %d\n", ret, errno); + printf ("lseek 2: ret = %d, errno = %d\n", ret, errno); + printf ("lseek 3: ret = %d, errno = %d\n", ret, errno); + } + /* Seeking on an invalid file descriptor */ + +} + +int +test_close () +{ + int fd, ret; + + /* Test close */ + errno = 0; + fd = open (FILENAME, O_RDONLY); + if (fd >= 0) + { + errno = 0; + ret = close (fd); + printf ("close 1: ret = %d, errno = %d, %s\n", ret, errno, + ret == 0 ? "OK" : ""); + } + else + printf ("close 1: ret = %d, errno = %d\n", ret, errno); + /* Close an invalid file descriptor */ + errno = 0; + ret = close (999); + printf ("close 2: ret = %d, errno = %d, %s\n", ret, errno, + strerrno (errno)); +} + +int +test_stat () +{ + int ret; + struct stat st; + + /* Test stat */ + errno = 0; + ret = stat (FILENAME, &st); + if (!ret) + printf ("stat 1: ret = %d, errno = %d %s\n", ret, errno, + st.st_size == 11 ? "OK" : ""); + else + printf ("stat 1: ret = %d, errno = %d\n", ret, errno); + /* NULL pathname */ + errno = 0; + ret = stat (NULL, &st); + printf ("stat 2: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + /* Empty pathname */ + errno = 0; + ret = stat ("", &st); + printf ("stat 3: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + /* Nonexistant file */ + errno = 0; + ret = stat (NONEXISTANT, &st); + printf ("stat 4: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); +} + +int +test_fstat () +{ + int fd, ret; + struct stat st; + + /* Test fstat */ + errno = 0; + fd = open (FILENAME, O_RDONLY); + if (fd >= 0) + { + errno = 0; + ret = fstat (fd, &st); + if (!ret) + printf ("fstat 1: ret = %d, errno = %d %s\n", ret, errno, + st.st_size == 11 ? "OK" : ""); + else + printf ("fstat 1: ret = %d, errno = %d\n", ret, errno); + close (fd); + } + else + printf ("fstat 1: ret = %d, errno = %d\n", ret, errno); + /* Fstat using invalid file descriptor */ + errno = 0; + ret = fstat (999, &st); + printf ("fstat 2: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); +} + +int +test_isatty () +{ + int fd; + + /* Check std I/O */ + printf ("isatty 1: stdin %s\n", isatty (0) ? "yes OK" : "no"); + printf ("isatty 2: stdout %s\n", isatty (1) ? "yes OK" : "no"); + printf ("isatty 3: stderr %s\n", isatty (2) ? "yes OK" : "no"); + /* Check invalid fd */ + printf ("isatty 4: invalid %s\n", isatty (999) ? "yes" : "no OK"); + /* Check open file */ + fd = open (FILENAME, O_RDONLY); + if (fd >= 0) + { + printf ("isatty 5: file %s\n", isatty (fd) ? "yes" : "no OK"); + close (fd); + } + else + printf ("isatty 5: file couldn't open\n"); +} + + +int +test_system () +{ + /* + * Requires test framework to switch on "set remote system-call-allowed 1" + */ + int ret; + char sys[512]; + + /* This test prepares the directory for test_rename() */ + sprintf (sys, "mkdir -p %s %s", TESTSUBDIR, TESTDIR2); + ret = system (sys); + if (ret == 127) + printf ("system 1: ret = %d /bin/sh unavailable???\n", ret); + else + printf ("system 1: ret = %d %s\n", ret, ret == 0 ? "OK" : ""); + /* Invalid command (just guessing ;-) ) */ + ret = system ("wrtzlpfrmpft"); + printf ("system 2: ret = %d %s\n", ret, WEXITSTATUS (ret) == 127 ? "OK" : ""); +} + +int +test_rename () +{ + int ret; + struct stat st; + + /* Test rename */ + errno = 0; + ret = rename (FILENAME, RENAMED); + if (!ret) + { + errno = 0; + ret = stat (FILENAME, &st); + if (ret && errno == ENOENT) + { + errno = 0; + ret = stat (RENAMED, &st); + printf ("rename 1: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + errno = 0; + } + else + printf ("rename 1: ret = %d, errno = %d\n", ret, errno); + } + else + printf ("rename 1: ret = %d, errno = %d\n", ret, errno); + /* newpath is existing directory, oldpath is not a directory */ + errno = 0; + ret = rename (RENAMED, TESTDIR2); + printf ("rename 2: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + /* newpath is a non-empty directory */ + errno = 0; + ret = rename (TESTDIR2, TESTDIR1); + printf ("rename 3: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + /* newpath is a subdirectory of old path */ + errno = 0; + ret = rename (TESTDIR1, TESTSUBDIR); + printf ("rename 4: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + /* oldpath does not exist */ + errno = 0; + ret = rename (NONEXISTANT, FILENAME); + printf ("rename 5: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); +} + +int +test_unlink () +{ + int ret; + char name[256]; + char sys[512]; + + /* Test unlink */ + errno = 0; + ret = unlink (RENAMED); + printf ("unlink 1: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + /* No write access */ + sprintf (name, "%s/%s", TESTDIR2, FILENAME); + errno = 0; + ret = open (name, O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR); + if (ret >= 0) + { + sprintf (sys, "chmod -w %s", TESTDIR2); + ret = system (sys); + if (!ret) + { + errno = 0; + ret = unlink (name); + printf ("unlink 2: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); + } + else + printf ("unlink 2: ret = %d chmod failed\n", ret, errno); + } + else + printf ("unlink 2: ret = %d, errno = %d\n", ret, errno); + /* pathname doesn't exist */ + errno = 0; + ret = unlink (NONEXISTANT); + printf ("unlink 3: ret = %d, errno = %d %s\n", ret, errno, + strerrno (errno)); +} + +int +test_time () +{ + time_t ret, t; + + errno = 0; + ret = time (&t); + printf ("time 1: ret = %ld, errno = %d, t = %ld %s\n", (long) ret, errno, (long) t, ret == t ? "OK" : ""); + errno = 0; + ret = time (NULL); + printf ("time 2: ret = %ld, errno = %d, t = %ld %s\n", + (long) ret, errno, (long) t, ret >= t && ret < t + 10 ? "OK" : ""); +} + +static const char * +strerrno (int err) +{ + switch (err) + { + case 0: return "OK"; +#ifdef EACCES + case EACCES: return "EACCES"; +#endif +#ifdef EBADF + case EBADF: return "EBADF"; +#endif +#ifdef EEXIST + case EEXIST: return "EEXIST"; +#endif +#ifdef EFAULT + case EFAULT: return "EFAULT"; +#endif +#ifdef EINVAL + case EINVAL: return "EINVAL"; +#endif +#ifdef EISDIR + case EISDIR: return "EISDIR"; +#endif +#ifdef ENOENT + case ENOENT: return "ENOENT"; +#endif +#ifdef ENOTEMPTY + case ENOTEMPTY: return "ENOTEMPTY"; +#endif + default: return "E??"; + } +} + +int +main () +{ + /* Don't change the order of the calls. They partly depend on each other */ + test_open (); + test_write (); + test_read (); + test_lseek (); + test_close (); + test_stat (); + test_fstat (); + test_isatty (); + test_system (); + test_rename (); + test_unlink (); + test_time (); + return 0; +} diff --git a/gdb/testsuite/gdb.base/fileio.exp b/gdb/testsuite/gdb.base/fileio.exp new file mode 100644 index 0000000..279f1ab --- /dev/null +++ b/gdb/testsuite/gdb.base/fileio.exp @@ -0,0 +1,277 @@ +# Copyright 2002 +# Free Software Foundation, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# This file was written by Corinna Vinschen <vinschen@redhat.com> + +if [target_info exists gdb,nointerrupts] { + verbose "Skipping interrupt.exp because of nointerrupts." + continue +} + +if [target_info exists gdb,noinferiorio] { + verbose "Skipping interrupt.exp because of noinferiorio." + return +} + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile "fileio" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +# Create and source the file that provides information about the compiler +# used to compile the test case. + +if [get_compiler_info ${binfile}] { + return -1; +} + +remote_exec build "test -r dir2.fileio.test && chmod -f +w dir2.fileio.test" +remote_exec build "rm -rf *.fileio.test" + +set oldtimeout $timeout +set timeout [expr "$timeout + 60"] + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} +send_gdb "set print sevenbit-strings\n" ; gdb_expect -re "$gdb_prompt $" +send_gdb "set print address off\n" ; gdb_expect -re "$gdb_prompt $" +send_gdb "set width 0\n" ; gdb_expect -re "$gdb_prompt $" + + +if ![runto_main] then { + perror "couldn't run to breakpoint" + continue +} + +send_gdb "tbreak 81\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*open 1:.*OK.*test_open \\(\\) at.*$srcfile:81.*" \ +"Open a file" + +send_gdb "tbreak 88\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*open 2:.*EEXIST.*test_open \\(\\) at.*$srcfile:88.*" \ +"Creating already existing file returns EEXIST" + +send_gdb "tbreak 95\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*open 3:.*EISDIR.*test_open \\(\\) at.*$srcfile:95.*" \ +"Open directory for writing returns EISDIR" + +send_gdb "tbreak 102\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*open 4:.*ENOENT.*test_open \\(\\) at.*$srcfile:102.*" \ +"Opening nonexistant file returns ENOENT" + +send_gdb "tbreak 109\n" ; gdb_expect -re "$gdb_prompt $" +send_gdb "continue\n" ; gdb_expect -re "$gdb_prompt $" +catch "system \"chmod -f -w nowrt.fileio.test\"" + +send_gdb "tbreak 119\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*open 5:.*EACCES.*test_open \\(\\) at.*$srcfile:119.*" \ +"Open for write but no write permission returns EACCES" + +send_gdb "tbreak 140\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*write 1:.*OK.*test_write \\(\\) at.*$srcfile:140.*" \ +"Writing to a file" + +send_gdb "tbreak 145\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*write 2:.*EBADF.*test_write \\(\\) at.*$srcfile:145.*" \ +"Write using invalid file descriptor returns EBADF" + +send_gdb "tbreak 156\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*write 3:.*EBADF.*test_write \\(\\) at.*$srcfile:156.*" \ +"Writing to a read-only file returns EBADF" + +send_gdb "tbreak 182\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*read 1:.*OK.*test_read \\(\\) at.*$srcfile:182.*" \ +"Reading from a file" + +send_gdb "tbreak 186\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*read 2:.*EBADF.*test_read \\(\\) at.*$srcfile:186.*" \ +"Read using invalid file descriptor returns EBADF" + +send_gdb "tbreak 221\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*lseek 1:.*OK.*lseek 2:.*OK.*lseek 3:.*OK.*test_lseek \\(\\) at.*$srcfile:221.*" \ +"Lseeking a file" + +send_gdb "tbreak 241\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*close 1:.*OK.*test_close \\(\\) at.*$srcfile:241.*" \ +"Closing a file" + +send_gdb "tbreak 245\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*close 2:.*EBADF.*test_close \\(\\) at.*$srcfile:245.*" \ +"Closing an invalid file descriptor returns EBADF" + +send_gdb "tbreak 262\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*stat 1:.*OK.*test_stat \\(\\) at.*$srcfile:262.*" \ +"Stat a file" + +send_gdb "tbreak 267\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ + "Continuing\\..*stat 2:.*(ENOENT|EFAULT).*test_stat \\(\\) at.*$srcfile:267.*" \ +"Stat a NULL pathname returns ENOENT or EFAULT" + +send_gdb "tbreak 272\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*stat 3:.*ENOENT.*test_stat \\(\\) at.*$srcfile:272.*" \ +"Stat an empty pathname returns ENOENT" + +send_gdb "tbreak 276\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*stat 4:.*ENOENT.*test_stat \\(\\) at.*$srcfile:276.*" \ +"Stat a nonexistant file returns ENOENT" + +send_gdb "tbreak 301\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*fstat 1:.*OK.*test_fstat \\(\\) at.*$srcfile:301.*" \ +"Fstat an open file" + +send_gdb "tbreak 305\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*fstat 2:.*EBADF.*test_fstat \\(\\) at.*$srcfile:305.*" \ +"Fstat an invalid file descriptor returns EBADF" + +send_gdb "tbreak 314\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*isatty 1:.*OK.*test_isatty \\(\\) at.*$srcfile:314.*" \ +"Isatty (stdin)" + +send_gdb "tbreak 315\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*isatty 2:.*OK.*test_isatty \\(\\) at.*$srcfile:315.*" \ +"Isatty (stdout)" + +send_gdb "tbreak 317\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*isatty 3:.*OK.*test_isatty \\(\\) at.*$srcfile:317.*" \ +"Isatty (stderr)" + +send_gdb "tbreak 319\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*isatty 4:.*OK.*test_isatty \\(\\) at.*$srcfile:319.*" \ +"Isatty (invalid fd)" + +send_gdb "tbreak 327\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*isatty 5:.*OK.*test_isatty \\(\\) at.*$srcfile:327.*" \ +"Isatty (open file)" + +send_gdb "set remote system-call-allowed 1\n"; gdb_expect -re ".*$gdb_prompt $" +send_gdb "tbreak 347\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*system 1:.*OK.*test_system \\(\\) at.*$srcfile:347.*" \ +"System(3) call" + +# Is this ok? POSIX says system returns a waitpid status? +send_gdb "tbreak 349\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*system 2:.*OK.*test_system \\(\\) at.*$srcfile:349.*" \ +"System with invalid command returns 127" + +send_gdb "tbreak 378\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*rename 1:.*OK.*test_rename \\(\\) at.*$srcfile:378.*" \ +"Rename a file" + +send_gdb "tbreak 383\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*rename 2:.*EISDIR.*test_rename \\(\\) at.*$srcfile:383.*" \ +"Renaming a file to existing directory returns EISDIR" + +send_gdb "tbreak 388\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ + "Continuing\\..*rename 3:.*(ENOTEMPTY|EEXIST).*test_rename \\(\\) at.*$srcfile:388.*" \ +"Renaming a directory to a non-empty directory returns ENOTEMPTY or EEXIST" + +send_gdb "tbreak 393\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*rename 4:.*EINVAL.*test_rename \\(\\) at.*$srcfile:393.*" \ +"Renaming a directory to a subdir of itself returns EINVAL" + +send_gdb "tbreak 397\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*rename 5:.*ENOENT.*test_rename \\(\\) at.*$srcfile:397.*" \ +"Renaming a nonexistant file returns ENOENT" + +send_gdb "tbreak 412\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*unlink 1:.*OK.*test_unlink \\(\\) at.*$srcfile:412.*" \ +"Unlink a file" + +send_gdb "tbreak 432\n" ; gdb_expect -re "$gdb_prompt $" +# This test fails on Cygwin because unlink() succeeds on Win32 systems +# in that situation. +if [ishost *cygwin*] { + setup_xfail "*-*-*" +} +gdb_test continue \ +"Continuing\\..*unlink 2:.*EACCES.*test_unlink \\(\\) at.*$srcfile:432.*" \ +"Unlinking a file in a directory w/o write access returns EACCES" + +send_gdb "tbreak 436\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*unlink 3:.*ENOENT.*test_unlink \\(\\) at.*$srcfile:436.*" \ +"Unlinking a nonexistant file returns ENOENT" + +send_gdb "tbreak 446\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*time 1:.*OK.*test_time \\(\\) at.*$srcfile:446.*" \ +"Time(2) call returns the same value as in parameter" + +sleep 2 +send_gdb "tbreak 450\n" ; gdb_expect -re "$gdb_prompt $" +gdb_test continue \ +"Continuing\\..*time 2:.*OK.*test_time \\(\\) at.*$srcfile:450.*" \ +"Time(2) returns feasible values" + +send_gdb "quit\n" +send_gdb "y\n" + +remote_exec build "test -r dir2.fileio.test && chmod -f +w dir2.fileio.test" +remote_exec build "rm -rf *.fileio.test" + +set timeout $oldtimeout +return 0 + diff --git a/gdb/testsuite/gdb.base/gdb_history b/gdb/testsuite/gdb.base/gdb_history new file mode 100644 index 0000000..cc22f69 --- /dev/null +++ b/gdb/testsuite/gdb.base/gdb_history @@ -0,0 +1,256 @@ +add-symbol-file +append +append binary +append memory +append value +append binary memory +append binary value +attach +break +b +br +bre +brea +backtrace +bt +ba +bac +continue +c +call +catch +cd +clear +commands +condition +core-file +d +delete +define +delete breakpoints +delete display +detach +directory +dis +disa +disable +disable breakpoints +disable display +disassemble +display +do +document +down +down-silently +dump +dump binary +dump ihex +dump memory +dump srec +dump tekhex +dump value +dump binary memory +dump binary value +dump ihex memory +dump ihex value +dump srec memory +dump srec value +dump tekhex memory +dump tekhex value +echo +enable breakpoints delete +enable breakpoints once +enable breakpoints +enable delete +enable display +enable once +enable +exec-file +f +frame +fg +file +finish +forward-search +gcore +generate-core-file +h +help +handle +i +info +ignore +info address +info all-registers +info args +info bogus-gdb-command +info breakpoints +info catch +info copying +info display +info f +info frame +info files +info float +info functions +info locals +info program +info registers +info s +info stack +info set +info symbol +info source +info sources +info target +info terminal +info types +info variables +info warranty +info watchpoints +inspect +jump +kill +l +list +load +n +next +ni +nexti +output +overlay +overlay on +overlay manual +overlay auto +overlay off +overlay list +overlay map +overlay unmap +overlay manual +overlay map +overlay unmap +p +print +printf +ptype +pwd +r +run +rbreak +restore +return +reverse-search +s +step +search +section +set annotate +set args +set c +set ch +set check +set check range +set check type +set complaints +set confirm +set environment +set height +set history expansion +set history filename +set history save +set history size +set history +set language +set listsize +set p +set pr +set print +set print address +set print array +set print asm-demangle +set print demangle +set print elements +set print object +set print pretty +set print sevenbit-strings +set print union +set print vtbl +set radix +set symbol-reloading +set variable +set verbose +set width +set write +set +shell echo Hi dad! +show annotate +show args +show c +show ch +show check +show check range +show check type +show commands +show complaints +show confirm +show convenience +show directories +show editing +show height +show history expansion +show history filename +show history save +show history size +show history +show language +show listsize +show p +show pr +show print +show paths +show print address +show print array +show print asm-demangle +show print demangle +show print elements +show print object +show print pretty +show print sevenbit-strings +show print union +show print vtbl +show prompt +show radix +show symbol-reloading +show user +show values +show verbose +show version +show width +show write +show +si +stepi +signal +source +s +step +symbol-file +target child +target procfs +target core +target exec +target remote +target +tbreak +tty +u +until +undisplay +unset environment +unset +up-silently +watch +whatis +where +x diff --git a/gdb/testsuite/gdb.base/shreloc.c b/gdb/testsuite/gdb.base/shreloc.c new file mode 100644 index 0000000..6867362 --- /dev/null +++ b/gdb/testsuite/gdb.base/shreloc.c @@ -0,0 +1,18 @@ +#if defined(_WIN32) || defined(__CYGWIN__) +# define ATTRIBUTES __attribute((__dllimport__)) +#else +# define ATTRIBUTES +#endif + +extern ATTRIBUTES void fn_1 (int); +extern ATTRIBUTES void fn_2 (int); +extern ATTRIBUTES int extern_var_1; +extern ATTRIBUTES int extern_var_2; + +int main () +{ + fn_1 (extern_var_1); + fn_2 (extern_var_2); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/shreloc.exp b/gdb/testsuite/gdb.base/shreloc.exp new file mode 100644 index 0000000..ac48774 --- /dev/null +++ b/gdb/testsuite/gdb.base/shreloc.exp @@ -0,0 +1,257 @@ +# Copyright (C) 2003 Free Software Foundation, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# Tests for shared object file relocation. If two shared objects have +# the same load address (actually, overlapping load spaces), one of +# them gets relocated at load-time. Check that gdb gets the right +# values for the debugging and minimal symbols. + +if $tracelevel then { + strace $tracelevel +} + +# +# This file uses shreloc.c, shreloc1.c and shreloc2.c +# + +set prms_id 0 +set bug_id 0 + +set workdir ${objdir}/${subdir} + +foreach module [list "shreloc" "shreloc1" "shreloc2"] { + if {[gdb_compile "${srcdir}/${subdir}/${module}.c" "${workdir}/${module}.o" object {debug}] != ""} { + untested "Couldn't compile ${module}.c" + return -1 + } +} + +set additional_flags "additional_flags=-shared" + +if {([istarget "*pc-cygwin"] || [istarget "*pc-mingw32"]) } { + set additional_flags "${additional_flags} -Wl,--image-base,0x04000000" +} + +foreach module [list "shreloc1" "shreloc2"] { + if {[gdb_compile "${workdir}/${module}.o" "${workdir}/${module}.dll" executable [list debug $additional_flags]] != ""} { + untested "Couldn't link ${module}.dll" + return -1 + } +} + +if {[gdb_compile [list "${workdir}/shreloc.o" "${workdir}/shreloc1.dll" "${workdir}/shreloc2.dll"] "${workdir}/shreloc" executable debug] != ""} { + untested "Couldn't link shreloc executable" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${workdir}/shreloc + +# Load up the shared objects +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +proc get_var_address { var } { + global gdb_prompt hex + + send_gdb "print &${var}\n" + # Match output like: + # $1 = (int *) 0x0 + # $5 = (int (*)()) 0 + # $6 = (int (*)()) 0x24 <function_bar> + gdb_expect { + -re "\\\$\[0-9\]+ = \\(.*\\) (0|$hex)( <${var}>)?\[\r\n\]+${gdb_prompt} $" + { + pass "get address of ${var}" + if { $expect_out(1,string) == "0" } { + return "0x0" + } else { + return $expect_out(1,string) + } + } + -re "${gdb_prompt} $" + { fail "get address of ${var} (unknown output)" } + timeout + { fail "get address of ${var} (timeout)" } + } + return "" +} + +# +# Check debugging symbol relocations +# + +# Check extern function for relocation +set fn_1_addr [get_var_address fn_1] +set fn_2_addr [get_var_address fn_2] + +if { "${fn_1_addr}" == "${fn_2_addr}" } { + fail "relocated extern functions have different addresses" +} else { + pass "relocated extern functions have different addresses" +} + +# Check extern var for relocation +set extern_var_1_addr [get_var_address extern_var_1] +set extern_var_2_addr [get_var_address extern_var_2] + +if { "${extern_var_1_addr}" == "${extern_var_2_addr}" } { + fail "relocated extern variables have different addresses" +} else { + pass "relocated extern variables have different addresses" +} + +# Check static var for relocation +set static_var_1_addr [get_var_address static_var_1] +set static_var_2_addr [get_var_address static_var_2] + +if { "${static_var_1_addr}" == "${static_var_2_addr}" } { + fail "relocated static variables have different addresses" +} else { + pass "relocated static variables have different addresses" +} + +# +# Check minimal symbol relocations +# + +proc send_gdb_discard { command } { + # Send a command to gdb and discard output up to the next prompt + + global gdb_prompt + + send_gdb "${command}\n" + + # Discard output + gdb_expect { + -re ".*\[\r\n]+${gdb_prompt} $" { + return 1 + } + timeout { + fail "{$command} (timeout)" + return 0 + } + } +} + +proc get_msym_addrs { var msymfile } { + # Extract the list of values for symbols matching var in the + # minimal symbol output file + + global gdb_prompt hex + set result "" + + send_gdb "shell grep -E \" ${var}(\[ \t\]+.*)?\$\" ${msymfile}\n" + + while 1 { + gdb_expect { + -re "\[\[\]\[ 0-9\]+\] . (${hex}) ${var}(\[ \t\]+\[^\r\n\]*)?\[\r\n\]+" { + set result [concat $result $expect_out(1,string)] + } + + -re "$gdb_prompt $" { + pass "get_msym_addrs ${var} (${result})" + return "${result}" + } + + -re "\[^\r\n\]*\[\r\n\]+" { + # Skip + } + + timeout { + fail "get_msym_addrs ${var} (timeout)" + return -1 + } + } + } +} + +proc check_same {var msymfile} { + # Check that the minimal symbol values matching var are the same + + set len [llength [lsort -unique [get_msym_addrs "${var}" "${msymfile}"]]] + + if { $len == 1 } { + return 1 + } else { + return 0 + } +} + +proc check_different {var msymfile} { + # Check that the minimal symbol values matching var are different + + set addr_list [lsort [get_msym_addrs "${var}" "${msymfile}"]] + set prev "" + + if { [llength ${addr_list}] < 2 } { + return 0 + } + + foreach addr ${addr_list} { + if { ${prev} == ${addr} } { + return 0 + } + set prev ${addr} + } + + return 1 +} + +set msymfile "${workdir}/shreloc.txt" + +if [send_gdb_discard "maint print msymbols ${msymfile}"] { + if {[check_different "static_var_\[12\]" "${msymfile}"]} { + pass "(msymbol) relocated static vars have different addresses" + } else { + fail "(msymbol) relocated static vars have different addresses" + } + + if {[check_different "extern_var_\[12\]" "${msymfile}"]} { + pass "(msymbol) relocated extern vars have different addresses" + } else { + fail "(msymbol) relocated extern vars have different addresses" + } + + if {[check_different "fn_\[12\]" "${msymfile}"]} { + pass "(msymbol) relocated functions have different addresses" + } else { + fail "(msymbol) relocated functions have different addresses" + } +} + +if {([istarget "*pc-cygwin"] || [istarget "*pc-mingw32"]) } { + # + # We know the names of some absolute symbols included in the + # portable-executable (DLL) format. Check that they didn't get + # relocated. + # + # A better approach would be include absolute symbols via the assembler. + # + if {[check_same "_minor_os_version__" "${msymfile}"]} { + pass "Absolute symbols not relocated" + } else { + fail "Absolute symbols not relocated" + } +} diff --git a/gdb/testsuite/gdb.base/shreloc1.c b/gdb/testsuite/gdb.base/shreloc1.c new file mode 100644 index 0000000..b1bffde --- /dev/null +++ b/gdb/testsuite/gdb.base/shreloc1.c @@ -0,0 +1,10 @@ +#if defined(_WIN32) || defined(__CYGWIN__) +# define ATTRIBUTES __attribute((__dllexport__)) +#else +# define ATTRIBUTES +#endif + +static int static_var_1; + +ATTRIBUTES void fn_1 (int unused) { } +ATTRIBUTES int extern_var_1 = 0; diff --git a/gdb/testsuite/gdb.base/shreloc2.c b/gdb/testsuite/gdb.base/shreloc2.c new file mode 100644 index 0000000..1459093 --- /dev/null +++ b/gdb/testsuite/gdb.base/shreloc2.c @@ -0,0 +1,10 @@ +#if defined(_WIN32) || defined(__CYGWIN__) +# define ATTRIBUTES __attribute((__dllexport__)) +#else +# define ATTRIBUTES +#endif + +static int static_var_2; + +ATTRIBUTES void fn_2 (int unused) { } +ATTRIBUTES int extern_var_2 = 0; diff --git a/gdb/testsuite/gdb.c++/pr-1210.cc b/gdb/testsuite/gdb.c++/pr-1210.cc new file mode 100644 index 0000000..5747e5d --- /dev/null +++ b/gdb/testsuite/gdb.c++/pr-1210.cc @@ -0,0 +1,19 @@ +class A +{ +}; + +class B : virtual public A +{ +}; + +class C : public A +{ + protected: + B myB; +}; + +int main() +{ + C *obj = new C(); + return 0; +} diff --git a/gdb/testsuite/gdb.c++/pr-1210.exp b/gdb/testsuite/gdb.c++/pr-1210.exp new file mode 100644 index 0000000..3ff850d --- /dev/null +++ b/gdb/testsuite/gdb.c++/pr-1210.exp @@ -0,0 +1,76 @@ +# Copyright 2003 Free Software Foundation, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Tests for PR gdb/1210. + +# This file is part of the gdb testsuite. + +if $tracelevel then { + strace $tracelevel +} + +if { [skip_cplus_tests] } { continue } + +# +# test running programs +# +set prms_id 0 +set bug_id 0 + +set testfile "pr-1210" +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +if [get_compiler_info ${binfile} "c++"] { + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] then { + perror "couldn't run to breakpoint" + continue +} + +gdb_test "next" ".*return 0;" "step past initialization" + +gdb_test_multiple "print *obj" "" { + -re "Cannot access memory.*$gdb_prompt $" { + fail "print *obj" + } + -re " = {<A> = {<No data fields>}, myB = {<A> = {<No data fields>}.*}}\r\n$gdb_prompt $" { + pass "print *obj" + } +} + +gdb_test_multiple "print obj->myB" "" { + -re "Cannot access memory.*$gdb_prompt $" { + fail "print obj->myB" + } + -re " = {<A> = {<No data fields>}.*}\r\n$gdb_prompt $" { + pass "print obj->myB" + } +} + +gdb_exit +return 0 diff --git a/gdb/trad-frame.c b/gdb/trad-frame.c new file mode 100644 index 0000000..92e6f83 --- /dev/null +++ b/gdb/trad-frame.c @@ -0,0 +1,96 @@ +/* Traditional frame unwind support, for GDB the GNU Debugger. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "trad-frame.h" +#include "regcache.h" + +/* A traditional frame is unwound by analysing the function prologue + and using the information gathered to track registers. For + non-optimized frames, the technique is reliable (just need to check + for all potential instruction sequences). */ + +struct trad_frame_saved_reg * +trad_frame_alloc_saved_regs (struct frame_info *next_frame) +{ + int regnum; + struct gdbarch *gdbarch = get_frame_arch (next_frame); + int numregs = NUM_REGS + NUM_PSEUDO_REGS; + struct trad_frame_saved_reg *this_saved_regs + = FRAME_OBSTACK_CALLOC (numregs, struct trad_frame_saved_reg); + for (regnum = 0; regnum < numregs; regnum++) + this_saved_regs[regnum].realnum = regnum; + return this_saved_regs; +} + +void +trad_frame_register_value (struct trad_frame_saved_reg this_saved_regs[], + int regnum, LONGEST val) +{ + /* Make the REALNUM invalid, indicating that the ADDR contains the + register's value. */ + this_saved_regs[regnum].realnum = -1; + this_saved_regs[regnum].addr = val; +} + +void +trad_frame_prev_register (struct frame_info *next_frame, + struct trad_frame_saved_reg this_saved_regs[], + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) +{ + struct gdbarch *gdbarch = get_frame_arch (next_frame); + if (this_saved_regs[regnum].realnum >= 0 + && this_saved_regs[regnum].addr != 0) + { + /* The register was saved in memory. */ + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = this_saved_regs[regnum].addr; + *realnump = -1; + if (bufferp != NULL) + { + /* Read the value in from memory. */ + get_frame_memory (next_frame, this_saved_regs[regnum].addr, bufferp, + register_size (gdbarch, regnum)); + } + } + else if (this_saved_regs[regnum].realnum >= 0 + && this_saved_regs[regnum].addr == 0) + { + /* As the next frame to return the value of the register. */ + frame_register_unwind (next_frame, this_saved_regs[regnum].realnum, + optimizedp, lvalp, addrp, realnump, bufferp); + } + else + { + /* The register's value is available. */ + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (bufferp != NULL) + store_unsigned_integer (bufferp, register_size (gdbarch, regnum), + this_saved_regs[regnum].addr); + } +} diff --git a/gdb/trad-frame.h b/gdb/trad-frame.h new file mode 100644 index 0000000..2b04c7e --- /dev/null +++ b/gdb/trad-frame.h @@ -0,0 +1,70 @@ +/* Traditional frame unwind support, for GDB the GNU Debugger. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TRAD_FRAME_H +#define TRAD_FRAME_H + +struct frame_info; + +/* A traditional saved regs table, indexed by REGNUM, encoding where + the value of REGNUM for the previous frame can be found in this + frame. + + The table is initialized with an identity encoding (ADDR == 0, + REALNUM == REGNUM) indicating that the value of REGNUM in the + previous frame can be found in register REGNUM (== REALNUM) in this + frame. + + The initial encoding can then be changed: + + Modify ADDR (REALNUM >= 0, ADDR != 0) to indicate that the value of + register REGNUM in the previous frame can be found in memory at + ADDR in this frame. + + Modify REALNUM (REALNUM >= 0, ADDR == 0) to indicate that the value + of register REGNUM in the previous frame is found in register + REALNUM in this frame. + + Call trad_frame_register_value (REALNUM < 0) to indicate that the + value of register REGNUM in the previous frame is found in ADDR. */ + +struct trad_frame_saved_reg +{ + LONGEST addr; /* A CORE_ADDR fits in a longest. */ + int realnum; +}; + +/* Convenience function, encode REGNUM's location in the trad-frame. */ +void trad_frame_register_value (struct trad_frame_saved_reg this_saved_regs[], + int regnum, LONGEST val); + +/* Return a freshly allocated (and initialized) trad_frame array. */ +struct trad_frame_saved_reg *trad_frame_alloc_saved_regs (struct frame_info *next_frame); + +/* Given the trad_frame info, return the location of the specified + register. */ +void trad_frame_prev_register (struct frame_info *next_frame, + struct trad_frame_saved_reg this_saved_regs[], + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp); + +#endif diff --git a/include/gdb/fileio.h b/include/gdb/fileio.h new file mode 100644 index 0000000..d844781 --- /dev/null +++ b/include/gdb/fileio.h @@ -0,0 +1,146 @@ +/* Hosted File I/O interface definitions, for GDB, the GNU Debugger. + + Copyright 2003 Free Software Foundation, 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., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef GDB_FILEIO_H_ +#define GDB_FILEIO_H_ + +/* The following flags are defined to be independent of the host + as well as the target side implementation of these constants. + All constants are defined with a leading FILEIO_ in the name + to allow the usage of these constants together with the + corresponding implementation dependent constants in one module. */ + +/* open(2) flags */ +#define FILEIO_O_RDONLY 0x0 +#define FILEIO_O_WRONLY 0x1 +#define FILEIO_O_RDWR 0x2 +#define FILEIO_O_APPEND 0x8 +#define FILEIO_O_CREAT 0x200 +#define FILEIO_O_TRUNC 0x400 +#define FILEIO_O_EXCL 0x800 +#define FILEIO_O_SUPPORTED (FILEIO_O_RDONLY | FILEIO_O_WRONLY| \ + FILEIO_O_RDWR | FILEIO_O_APPEND| \ + FILEIO_O_CREAT | FILEIO_O_TRUNC| \ + FILEIO_O_EXCL) + +/* mode_t bits */ +#define FILEIO_S_IFREG 0100000 +#define FILEIO_S_IFDIR 040000 +#define FILEIO_S_IFCHR 020000 +#define FILEIO_S_IRUSR 0400 +#define FILEIO_S_IWUSR 0200 +#define FILEIO_S_IXUSR 0100 +#define FILEIO_S_IRWXU 0700 +#define FILEIO_S_IRGRP 040 +#define FILEIO_S_IWGRP 020 +#define FILEIO_S_IXGRP 010 +#define FILEIO_S_IRWXG 070 +#define FILEIO_S_IROTH 04 +#define FILEIO_S_IWOTH 02 +#define FILEIO_S_IXOTH 01 +#define FILEIO_S_IRWXO 07 +#define FILEIO_S_SUPPORTED (FILEIO_S_IFREG|FILEIO_S_IFDIR| \ + FILEIO_S_IRWXU|FILEIO_S_IRWXG| \ + FILEIO_S_IRWXO) + +/* lseek(2) flags */ +#define FILEIO_SEEK_SET 0 +#define FILEIO_SEEK_CUR 1 +#define FILEIO_SEEK_END 2 + +/* errno values */ +#define FILEIO_EPERM 1 +#define FILEIO_ENOENT 2 +#define FILEIO_EINTR 4 +#define FILEIO_EIO 5 +#define FILEIO_EBADF 9 +#define FILEIO_EACCES 13 +#define FILEIO_EFAULT 14 +#define FILEIO_EBUSY 16 +#define FILEIO_EEXIST 17 +#define FILEIO_ENODEV 19 +#define FILEIO_ENOTDIR 20 +#define FILEIO_EISDIR 21 +#define FILEIO_EINVAL 22 +#define FILEIO_ENFILE 23 +#define FILEIO_EMFILE 24 +#define FILEIO_EFBIG 27 +#define FILEIO_ENOSPC 28 +#define FILEIO_ESPIPE 29 +#define FILEIO_EROFS 30 +#define FILEIO_ENOSYS 88 +#define FILEIO_ENAMETOOLONG 91 +#define FILEIO_EUNKNOWN 9999 + +/* limits */ +#define FILEIO_INT_MIN -2147483648L +#define FILEIO_INT_MAX 2147483647L +#define FILEIO_UINT_MAX 4294967295UL +#define FILEIO_LONG_MIN -9223372036854775808LL +#define FILEIO_LONG_MAX 9223372036854775807LL +#define FILEIO_ULONG_MAX 18446744073709551615ULL + +/* Integral types as used in protocol. */ +#if 0 +typedef __int32_t fio_int_t; +typedef __uint32_t fio_uint_t, fio_mode_t, fio_time_t; +typedef __int64_t fio_long_t; +typedef __uint64_t fio_ulong_t; +#endif + +#define FIO_INT_LEN 4 +#define FIO_UINT_LEN 4 +#define FIO_MODE_LEN 4 +#define FIO_TIME_LEN 4 +#define FIO_LONG_LEN 8 +#define FIO_ULONG_LEN 8 + +typedef char fio_int_t[FIO_INT_LEN]; +typedef char fio_uint_t[FIO_UINT_LEN]; +typedef char fio_mode_t[FIO_MODE_LEN]; +typedef char fio_time_t[FIO_TIME_LEN]; +typedef char fio_long_t[FIO_LONG_LEN]; +typedef char fio_ulong_t[FIO_ULONG_LEN]; + +/* Struct stat as used in protocol. For complete independence + of host/target systems, it's defined as an array with offsets + to the members. */ + +struct fio_stat { + fio_uint_t fst_dev; + fio_uint_t fst_ino; + fio_mode_t fst_mode; + fio_uint_t fst_nlink; + fio_uint_t fst_uid; + fio_uint_t fst_gid; + fio_uint_t fst_rdev; + fio_ulong_t fst_size; + fio_ulong_t fst_blksize; + fio_ulong_t fst_blocks; + fio_time_t fst_atime; + fio_time_t fst_mtime; + fio_time_t fst_ctime; +}; + +struct fio_timeval { + fio_time_t ftv_sec; + fio_long_t ftv_usec; +}; + +#endif /* GDB_FILEIO_H_ */ diff --git a/sim/h8300/sim-main.h b/sim/h8300/sim-main.h new file mode 100644 index 0000000..6acf901 --- /dev/null +++ b/sim/h8300/sim-main.h @@ -0,0 +1,170 @@ +/* Main header for the Hitachi h8/300 architecture. */ + +#include "bfd.h" + +#ifndef SIM_MAIN_H +#define SIM_MAIN_H + +#define DEBUG + +/* These define the size of main memory for the simulator. + + Note the size of main memory for the H8/300H is only 256k. Keeping it + small makes the simulator run much faster and consume less memory. + + The linker knows about the limited size of the simulator's main memory + on the H8/300H (via the h8300h.sc linker script). So if you change + H8300H_MSIZE, be sure to fix the linker script too. + + Also note that there's a separate "eightbit" area aside from main + memory. For simplicity, the simulator assumes any data memory reference + outside of main memory refers to the eightbit area (in theory, this + can only happen when simulating H8/300H programs). We make no attempt + to catch overlapping addresses, wrapped addresses, etc etc. */ + +#define H8300_MSIZE (1 << 16) + +/* avolkov: + Next 2 macros are ugly for any workstation, but while they're work. + Memory size MUST be configurable. */ +#define H8300H_MSIZE (1 << 18) +#define H8300S_MSIZE (1 << 24) + +#define CSIZE 1024 + +enum h8_regnum { + R0_REGNUM = 0, + R1_REGNUM = 1, + R2_REGNUM = 2, + R3_REGNUM = 3, + R4_REGNUM = 4, + R5_REGNUM = 5, + R6_REGNUM = 6, + R7_REGNUM = 7, + + SP_REGNUM = R7_REGNUM, /* Contains address of top of stack */ + FP_REGNUM = R6_REGNUM, /* Contains address of executing + stack frame */ + CCR_REGNUM = 8, /* Contains processor status */ + PC_REGNUM = 9, /* Contains program counter */ + CYCLE_REGNUM = 10, + EXR_REGNUM = 11, + INST_REGNUM = 12, + TICK_REGNUM = 13, + MACH_REGNUM = 14, + MACL_REGNUM = 15, + SBR_REGNUM = 16, + VBR_REGNUM = 17, + + ZERO_REGNUM = 18 +}; + +enum h8_typecodes { + OP_NULL, + OP_REG, /* Register direct. */ + OP_LOWREG, /* Special reg syntax for "bra". */ + OP_DISP, /* Register indirect w/displacement. */ + /* Note: h8300, h8300h, and h8300s permit only pre-decr and post-incr. */ + OP_PREDEC, /* Register indirect w/pre-decrement. */ + OP_POSTDEC, /* Register indirect w/post-decrement. */ + OP_PREINC, /* Register indirect w/pre-increment. */ + OP_POSTINC, /* Register indirect w/post-increment. */ + OP_PCREL, /* PC Relative. */ + OP_MEM, /* Absolute memory address. */ + OP_CCR, /* Condition Code Register. */ + OP_IMM, /* Immediate value. */ + /*OP_ABS*/ /* Un-used (duplicates op_mem?). */ + OP_EXR, /* EXtended control Register. */ + OP_SBR, /* Vector Base Register. */ + OP_VBR, /* Short-address Base Register. */ + OP_MACH, /* Multiply Accumulator - high. */ + OP_MACL, /* Multiply Accumulator - low. */ + /* FIXME: memory indirect? */ + OP_INDEXB, /* Byte index mode */ + OP_INDEXW, /* Word index mode */ + OP_INDEXL /* Long index mode */ +}; + +#include "sim-basics.h" + +/* Define sim_cia. */ +typedef unsigned32 sim_cia; + +#include "sim-base.h" + +/* Structure used to describe addressing */ + +typedef struct +{ + int type; + int reg; + int literal; +} ea_type; + +/* Struct for instruction decoder. */ +typedef struct +{ + ea_type src; + ea_type dst; + ea_type op3; + int opcode; + int next_pc; + int oldpc; + int cycles; +#ifdef DEBUG + struct h8_opcode *op; +#endif +} decoded_inst; + +struct _sim_cpu { + unsigned int regs[20]; /* 8 GR's plus ZERO, SBR, and VBR. */ + unsigned int pc; + + int macS; /* MAC Saturating mode */ + int macV; /* MAC Overflow */ + int macN; /* MAC Negative */ + int macZ; /* MAC Zero */ + + int delayed_branch; + char **command_line; /* Pointer to command line arguments. */ + + unsigned char *memory; + unsigned char *eightbit; + int mask; + + sim_cpu_base base; +}; + +/* The sim_state struct. */ +struct sim_state { + struct _sim_cpu *cpu; + unsigned int sim_cache_size; + decoded_inst *sim_cache; + unsigned short *cache_idx; + unsigned long memory_size; + int cache_top; + int compiles; +#ifdef ADEBUG + int stats[O_LAST]; +#endif + sim_state_base base; +}; + +/* The current state of the processor; registers, memory, etc. */ + +#define CIA_GET(CPU) (cpu_get_pc (CPU)) +#define CIA_SET(CPU, VAL) (cpu_set_pc ((CPU), (VAL))) +#define STATE_CPU(SD, N) ((SD)->cpu) /* Single Processor. */ +#define cpu_set_pc(CPU, VAL) (((CPU)->pc) = (VAL)) +#define cpu_get_pc(CPU) (((CPU)->pc)) + +/* Magic numbers used to distinguish an exit from a breakpoint. */ +#define LIBC_EXIT_MAGIC1 0xdead +#define LIBC_EXIT_MAGIC2 0xbeef +/* Local version of macros for decoding exit status. + (included here rather than try to find target version of wait.h) +*/ +#define SIM_WIFEXITED(V) (((V) & 0xff) == 0) +#define SIM_WEXITSTATUS(V) ((V) >> 8) + +#endif /* SIM_MAIN_H */ diff --git a/sim/ppc/altivec.igen b/sim/ppc/altivec.igen new file mode 100644 index 0000000..9f10b26 --- /dev/null +++ b/sim/ppc/altivec.igen @@ -0,0 +1,2356 @@ +# Altivec instruction set, for PSIM, the PowerPC simulator. + +# Copyright 2003 Free Software Foundation, Inc. + +# Contributed by Red Hat Inc; developed under contract from Motorola. +# Written by matthew green <mrg@redhat.com>. + +# This file is part of GDB. + +# 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. */ + + +# +# Motorola AltiVec instructions. +# + +:cache:av:::VS:VS: +:cache:av::vreg *:vS:VS:(cpu_registers(processor)->altivec.vr + VS) +:cache:av::unsigned32:VS_BITMASK:VS:(1 << VS) +:cache:av:::VA:VA: +:cache:av::vreg *:vA:VA:(cpu_registers(processor)->altivec.vr + VA) +:cache:av::unsigned32:VA_BITMASK:VA:(1 << VA) +:cache:av:::VB:VB: +:cache:av::vreg *:vB:VB:(cpu_registers(processor)->altivec.vr + VB) +:cache:av::unsigned32:VB_BITMASK:VB:(1 << VB) +:cache:av:::VC:VC: +:cache:av::vreg *:vC:VC:(cpu_registers(processor)->altivec.vr + VC) +:cache:av::unsigned32:VC_BITMASK:VC:(1 << VC) + +# Flags for model.h +::model-macro::: + #define PPC_INSN_INT_VR(OUT_MASK, IN_MASK, OUT_VMASK, IN_VMASK) \ + do { \ + if (CURRENT_MODEL_ISSUE > 0) \ + ppc_insn_int_vr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, OUT_VMASK, IN_VMASK); \ + } while (0) + + #define PPC_INSN_VR(OUT_VMASK, IN_VMASK) \ + do { \ + if (CURRENT_MODEL_ISSUE > 0) \ + ppc_insn_vr(MY_INDEX, cpu_model(processor), OUT_VMASK, IN_VMASK); \ + } while (0) + + #define PPC_INSN_VR_CR(OUT_VMASK, IN_VMASK, CR_MASK) \ + do { \ + if (CURRENT_MODEL_ISSUE > 0) \ + ppc_insn_vr_cr(MY_INDEX, cpu_model(processor), OUT_VMASK, IN_VMASK, CR_MASK); \ + } while (0) + + #define PPC_INSN_VR_VSCR(OUT_VMASK, IN_VMASK) \ + do { \ + if (CURRENT_MODEL_ISSUE > 0) \ + ppc_insn_vr_vscr(MY_INDEX, cpu_model(processor), OUT_VMASK, IN_VMASK); \ + } while (0) + + #define PPC_INSN_FROM_VSCR(VR_MASK) \ + do { \ + if (CURRENT_MODEL_ISSUE > 0) \ + ppc_insn_from_vscr(MY_INDEX, cpu_model(processor), VR_MASK); \ + } while (0) + + #define PPC_INSN_TO_VSCR(VR_MASK) \ + do { \ + if (CURRENT_MODEL_ISSUE > 0) \ + ppc_insn_to_vscr(MY_INDEX, cpu_model(processor), VR_MASK); \ + } while (0) + +# Trace waiting for AltiVec registers to become available +void::model-static::model_trace_altivec_busy_p:model_data *model_ptr, unsigned32 vr_busy + int i; + if (vr_busy) { + vr_busy &= model_ptr->vr_busy; + for(i = 0; i < 32; i++) { + if (((1 << i) & vr_busy) != 0) { + TRACE(trace_model, ("Waiting for register v%d.\n", i)); + } + } + } + if (model_ptr->vscr_busy) + TRACE(trace_model, ("Waiting for VSCR\n")); + +# Trace making AltiVec registers busy +void::model-static::model_trace_altivec_make_busy:model_data *model_ptr, unsigned32 vr_mask, unsigned32 cr_mask + int i; + if (vr_mask) { + for(i = 0; i < 32; i++) { + if (((1 << i) & vr_mask) != 0) { + TRACE(trace_model, ("Register v%d is now busy.\n", i)); + } + } + } + if (cr_mask) { + for(i = 0; i < 8; i++) { + if (((1 << i) & cr_mask) != 0) { + TRACE(trace_model, ("Register cr%d is now busy.\n", i)); + } + } + } + +# Schedule an AltiVec instruction that takes integer input registers and produces output registers +void::model-function::ppc_insn_int_vr:itable_index index, model_data *model_ptr, const unsigned32 out_mask, const unsigned32 in_mask, const unsigned32 out_vmask, const unsigned32 in_vmask + const unsigned32 int_mask = out_mask | in_mask; + const unsigned32 vr_mask = out_vmask | in_vmask; + model_busy *busy_ptr; + + if ((model_ptr->int_busy & int_mask) != 0 || (model_ptr->vr_busy & vr_mask)) { + model_new_cycle(model_ptr); /* don't count first dependency as a stall */ + + while ((model_ptr->int_busy & int_mask) != 0 || (model_ptr->vr_busy & vr_mask)) { + if (WITH_TRACE && ppc_trace[trace_model]) { + model_trace_busy_p(model_ptr, int_mask, 0, 0, PPC_NO_SPR); + model_trace_altivec_busy_p(model_ptr, vr_mask); + } + + model_ptr->nr_stalls_data++; + model_new_cycle(model_ptr); + } + } + + busy_ptr = model_wait_for_unit(index, model_ptr, &model_ptr->timing[index]); + model_ptr->int_busy |= out_mask; + busy_ptr->int_busy |= out_mask; + model_ptr->vr_busy |= out_vmask; + busy_ptr->vr_busy |= out_vmask; + + if (out_mask) + busy_ptr->nr_writebacks = (PPC_ONE_BIT_SET_P(out_vmask)) ? 1 : 2; + + if (out_vmask) + busy_ptr->nr_writebacks += (PPC_ONE_BIT_SET_P(out_vmask)) ? 1 : 2; + + if (WITH_TRACE && ppc_trace[trace_model]) { + model_trace_make_busy(model_ptr, out_mask, 0, 0); + model_trace_altivec_make_busy(model_ptr, vr_mask, 0); + } + +# Schedule an AltiVec instruction that takes vector input registers and produces vector output registers +void::model-function::ppc_insn_vr:itable_index index, model_data *model_ptr, const unsigned32 out_vmask, const unsigned32 in_vmask + const unsigned32 vr_mask = out_vmask | in_vmask; + model_busy *busy_ptr; + + if (model_ptr->vr_busy & vr_mask) { + model_new_cycle(model_ptr); /* don't count first dependency as a stall */ + + while (model_ptr->vr_busy & vr_mask) { + if (WITH_TRACE && ppc_trace[trace_model]) { + model_trace_altivec_busy_p(model_ptr, vr_mask); + } + + model_ptr->nr_stalls_data++; + model_new_cycle(model_ptr); + } + } + + busy_ptr = model_wait_for_unit(index, model_ptr, &model_ptr->timing[index]); + model_ptr->vr_busy |= out_vmask; + busy_ptr->vr_busy |= out_vmask; + if (out_vmask) + busy_ptr->nr_writebacks = (PPC_ONE_BIT_SET_P(out_vmask)) ? 1 : 2; + + if (WITH_TRACE && ppc_trace[trace_model]) { + model_trace_altivec_make_busy(model_ptr, vr_mask, 0); + } + +# Schedule an AltiVec instruction that takes vector input registers and produces vector output registers, touches CR +void::model-function::ppc_insn_vr_cr:itable_index index, model_data *model_ptr, const unsigned32 out_vmask, const unsigned32 in_vmask, const unsigned32 cr_mask + const unsigned32 vr_mask = out_vmask | in_vmask; + model_busy *busy_ptr; + + if ((model_ptr->vr_busy & vr_mask) || (model_ptr->cr_fpscr_busy & cr_mask)) { + model_new_cycle(model_ptr); /* don't count first dependency as a stall */ + + while ((model_ptr->vr_busy & vr_mask) || (model_ptr->cr_fpscr_busy & cr_mask)) { + if (WITH_TRACE && ppc_trace[trace_model]) { + model_trace_busy_p(model_ptr, 0, 0, cr_mask, PPC_NO_SPR); + model_trace_altivec_busy_p(model_ptr, vr_mask); + } + + model_ptr->nr_stalls_data++; + model_new_cycle(model_ptr); + } + } + + busy_ptr = model_wait_for_unit(index, model_ptr, &model_ptr->timing[index]); + model_ptr->cr_fpscr_busy |= cr_mask; + busy_ptr->cr_fpscr_busy |= cr_mask; + model_ptr->vr_busy |= out_vmask; + busy_ptr->vr_busy |= out_vmask; + + if (out_vmask) + busy_ptr->nr_writebacks = (PPC_ONE_BIT_SET_P(out_vmask)) ? 1 : 2; + + if (cr_mask) + busy_ptr->nr_writebacks++; + + if (WITH_TRACE && ppc_trace[trace_model]) + model_trace_altivec_make_busy(model_ptr, vr_mask, cr_mask); + +# Schedule an AltiVec instruction that takes vector input registers and produces vector output registers, touches VSCR +void::model-function::ppc_insn_vr_vscr:itable_index index, model_data *model_ptr, const unsigned32 out_vmask, const unsigned32 in_vmask + const unsigned32 vr_mask = out_vmask | in_vmask; + model_busy *busy_ptr; + + if ((model_ptr->vr_busy & vr_mask) != 0 || model_ptr->vscr_busy != 0) { + model_new_cycle(model_ptr); /* don't count first dependency as a stall */ + + while ((model_ptr->vr_busy & vr_mask) != 0 || model_ptr->vscr_busy != 0) { + if (WITH_TRACE && ppc_trace[trace_model]) + model_trace_altivec_busy_p(model_ptr, vr_mask); + + model_ptr->nr_stalls_data++; + model_new_cycle(model_ptr); + } + } + + busy_ptr = model_wait_for_unit(index, model_ptr, &model_ptr->timing[index]); + model_ptr->vr_busy |= out_vmask; + busy_ptr->vr_busy |= out_vmask; + model_ptr->vscr_busy = 1; + busy_ptr->vscr_busy = 1; + + if (out_vmask) + busy_ptr->nr_writebacks = 1 + (PPC_ONE_BIT_SET_P(out_vmask)) ? 1 : 2; + + if (WITH_TRACE && ppc_trace[trace_model]) + model_trace_altivec_make_busy(model_ptr, vr_mask, 0); + +# Schedule an MFVSCR instruction that VSCR input register and produces an AltiVec output register +void::model-function::ppc_insn_from_vscr:itable_index index, model_data *model_ptr, const unsigned32 vr_mask + model_busy *busy_ptr; + + while ((model_ptr->vr_busy & vr_mask) != 0 || model_ptr->vscr_busy != 0) { + if (WITH_TRACE && ppc_trace[trace_model]) + model_trace_altivec_busy_p(model_ptr, vr_mask); + + model_ptr->nr_stalls_data++; + model_new_cycle(model_ptr); + } + busy_ptr = model_wait_for_unit(index, model_ptr, &model_ptr->timing[index]); + model_ptr->cr_fpscr_busy |= vr_mask; + busy_ptr->cr_fpscr_busy |= vr_mask; + + if (vr_mask) + busy_ptr->nr_writebacks = 1; + + model_ptr->vr_busy |= vr_mask; + if (WITH_TRACE && ppc_trace[trace_model]) + model_trace_altivec_make_busy(model_ptr, vr_mask, 0); + +# Schedule an MTVSCR instruction that one AltiVec input register and produces a vscr output register +void::model-function::ppc_insn_to_vscr:itable_index index, model_data *model_ptr, const unsigned32 vr_mask + model_busy *busy_ptr; + + while ((model_ptr->vr_busy & vr_mask) != 0 || model_ptr->vscr_busy != 0) { + if (WITH_TRACE && ppc_trace[trace_model]) + model_trace_altivec_busy_p(model_ptr, vr_mask); + + model_ptr->nr_stalls_data++; + model_new_cycle(model_ptr); + } + busy_ptr = model_wait_for_unit(index, model_ptr, &model_ptr->timing[index]); + busy_ptr ->vscr_busy = 1; + model_ptr->vscr_busy = 1; + busy_ptr->nr_writebacks = 1; + + TRACE(trace_model,("Making VSCR busy.\n")); + +# The follow are AltiVec saturate operations + +signed8::model-function::altivec_signed_saturate_8:signed16 val, int *sat + signed8 rv; + if (val > 127) { + rv = 127; + *sat = 1; + } else if (val < -128) { + rv = -128; + *sat = 1; + } else { + rv = val; + *sat = 0; + } + return rv; + +signed16::model-function::altivec_signed_saturate_16:signed32 val, int *sat + signed16 rv; + if (val > 32767) { + rv = 32767; + *sat = 1; + } else if (val < -32768) { + rv = -32768; + *sat = 1; + } else { + rv = val; + *sat = 0; + } + return rv; + +signed32::model-function::altivec_signed_saturate_32:signed64 val, int *sat + signed32 rv; + if (val > 2147483647) { + rv = 2147483647; + *sat = 1; + } else if (val < -2147483648LL) { + rv = -2147483648LL; + *sat = 1; + } else { + rv = val; + *sat = 0; + } + return rv; + +unsigned8::model-function::altivec_unsigned_saturate_8:signed16 val, int *sat + unsigned8 rv; + if (val > 255) { + rv = 255; + *sat = 1; + } else if (val < 0) { + rv = 0; + *sat = 1; + } else { + rv = val; + *sat = 0; + } + return rv; + +unsigned16::model-function::altivec_unsigned_saturate_16:signed32 val, int *sat + unsigned16 rv; + if (val > 65535) { + rv = 65535; + *sat = 1; + } else if (val < 0) { + rv = 0; + *sat = 1; + } else { + rv = val; + *sat = 0; + } + return rv; + +unsigned32::model-function::altivec_unsigned_saturate_32:signed64 val, int *sat + unsigned32 rv; + if (val > 4294967295LL) { + rv = 4294967295LL; + *sat = 1; + } else if (val < 0) { + rv = 0; + *sat = 1; + } else { + rv = val; + *sat = 0; + } + return rv; + +# +# Load instructions, 6-14 ... 6-22. +# + +0.31,6.VS,11.RA,16.RB,21.7,31.0:X:av:lvebx %VD, %RA, %RB:Load Vector Element Byte Indexed + unsigned_word b; + unsigned_word EA; + unsigned_word eb; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + eb = EA & 0xf; + (*vS).b[AV_BINDEX(eb)] = MEM(unsigned, EA, 1); + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +0.31,6.VS,11.RA,16.RB,21.39,31.0:X:av:lvehx %VD, %RA, %RB:Load Vector Element Half Word Indexed + unsigned_word b; + unsigned_word EA; + unsigned_word eb; + if (RA_is_0) b = 0; + else b = *rA; + EA = (b + *rB) & ~1; + eb = EA & 0xf; + (*vS).h[AV_HINDEX(eb/2)] = MEM(unsigned, EA, 2); + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +0.31,6.VS,11.RA,16.RB,21.71,31.0:X:av:lvewx %VD, %RA, %RB:Load Vector Element Word Indexed + unsigned_word b; + unsigned_word EA; + unsigned_word eb; + if (RA_is_0) b = 0; + else b = *rA; + EA = (b + *rB) & ~3; + eb = EA & 0xf; + (*vS).w[eb/4] = MEM(unsigned, EA, 4); + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + + +0.31,6.VS,11.RA,16.RB,21.6,31.0:X:av:lvsl %VD, %RA, %RB:Load Vector for Shift Left + unsigned_word b; + unsigned_word addr; + int i, j; + if (RA_is_0) b = 0; + else b = *rA; + addr = b + *rB; + j = addr & 0xf; + for (i = 0; i < 16; i++) + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + (*vS).b[AV_BINDEX(i)] = j++; + else + (*vS).b[AV_BINDEX(15 - i)] = j++; + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +0.31,6.VS,11.RA,16.RB,21.38,31.0:X:av:lvsr %VD, %RA, %RB:Load Vector for Shift Right + unsigned_word b; + unsigned_word addr; + int i, j; + if (RA_is_0) b = 0; + else b = *rA; + addr = b + *rB; + j = 0x10 - (addr & 0xf); + for (i = 0; i < 16; i++) + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + (*vS).b[AV_BINDEX(i)] = j++; + else + (*vS).b[AV_BINDEX(15 - i)] = j++; + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + + +0.31,6.VS,11.RA,16.RB,21.103,31.0:X:av:lvx %VD, %RA, %RB:Load Vector Indexed + unsigned_word b; + unsigned_word EA; + if (RA_is_0) b = 0; + else b = *rA; + EA = (b + *rB) & ~0xf; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) { + (*vS).w[0] = MEM(unsigned, EA + 0, 4); + (*vS).w[1] = MEM(unsigned, EA + 4, 4); + (*vS).w[2] = MEM(unsigned, EA + 8, 4); + (*vS).w[3] = MEM(unsigned, EA + 12, 4); + } else { + (*vS).w[0] = MEM(unsigned, EA + 12, 4); + (*vS).w[1] = MEM(unsigned, EA + 8, 4); + (*vS).w[2] = MEM(unsigned, EA + 4, 4); + (*vS).w[3] = MEM(unsigned, EA + 0, 4); + } + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +0.31,6.VS,11.RA,16.RB,21.359,31.0:X:av:lvxl %VD, %RA, %RB:Load Vector Indexed LRU + unsigned_word b; + unsigned_word EA; + if (RA_is_0) b = 0; + else b = *rA; + EA = (b + *rB) & ~0xf; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) { + (*vS).w[0] = MEM(unsigned, EA + 0, 4); + (*vS).w[1] = MEM(unsigned, EA + 4, 4); + (*vS).w[2] = MEM(unsigned, EA + 8, 4); + (*vS).w[3] = MEM(unsigned, EA + 12, 4); + } else { + (*vS).w[0] = MEM(unsigned, EA + 12, 4); + (*vS).w[1] = MEM(unsigned, EA + 8, 4); + (*vS).w[2] = MEM(unsigned, EA + 4, 4); + (*vS).w[3] = MEM(unsigned, EA + 0, 4); + } + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +# +# Move to/from VSCR instructions, 6-23 & 6-24. +# + +0.4,6.VS,11.0,16.0,21.1540:VX:av:mfvscr %VS:Move from Vector Status and Control Register + (*vS).w[0] = 0; + (*vS).w[1] = 0; + (*vS).w[2] = 0; + (*vS).w[3] = VSCR; + PPC_INSN_FROM_VSCR(VS_BITMASK); + +0.4,6.0,11.0,16.VB,21.1604:VX:av:mtvscr %VB:Move to Vector Status and Control Register + VSCR = (*vB).w[3]; + PPC_INSN_TO_VSCR(VB_BITMASK); + +# +# Store instructions, 6-25 ... 6-29. +# + +0.31,6.VS,11.RA,16.RB,21.135,31.0:X:av:stvebx %VD, %RA, %RB:Store Vector Element Byte Indexed + unsigned_word b; + unsigned_word EA; + unsigned_word eb; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + eb = EA & 0xf; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + STORE(EA, 1, (*vS).b[eb]); + else + STORE(EA, 1, (*vS).b[15-eb]); + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +0.31,6.VS,11.RA,16.RB,21.167,31.0:X:av:stvehx %VD, %RA, %RB:Store Vector Element Half Word Indexed + unsigned_word b; + unsigned_word EA; + unsigned_word eb; + if (RA_is_0) b = 0; + else b = *rA; + EA = (b + *rB) & ~1; + eb = EA & 0xf; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + STORE(EA, 2, (*vS).h[eb/2]); + else + STORE(EA, 2, (*vS).h[7-eb]); + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +0.31,6.VS,11.RA,16.RB,21.199,31.0:X:av:stvewx %VD, %RA, %RB:Store Vector Element Word Indexed + unsigned_word b; + unsigned_word EA; + unsigned_word eb; + if (RA_is_0) b = 0; + else b = *rA; + EA = (b + *rB) & ~3; + eb = EA & 0xf; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + STORE(EA, 4, (*vS).w[eb/4]); + else + STORE(EA, 4, (*vS).w[3-(eb/4)]); + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +0.31,6.VS,11.RA,16.RB,21.231,31.0:X:av:stvx %VD, %RA, %RB:Store Vector Indexed + unsigned_word b; + unsigned_word EA; + if (RA_is_0) b = 0; + else b = *rA; + EA = (b + *rB) & ~0xf; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) { + STORE(EA + 0, 4, (*vS).w[0]); + STORE(EA + 4, 4, (*vS).w[1]); + STORE(EA + 8, 4, (*vS).w[2]); + STORE(EA + 12, 4, (*vS).w[3]); + } else { + STORE(EA + 12, 4, (*vS).w[0]); + STORE(EA + 8, 4, (*vS).w[1]); + STORE(EA + 4, 4, (*vS).w[2]); + STORE(EA + 0, 4, (*vS).w[3]); + } + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +0.31,6.VS,11.RA,16.RB,21.487,31.0:X:av:stvxl %VD, %RA, %RB:Store Vector Indexed LRU + unsigned_word b; + unsigned_word EA; + if (RA_is_0) b = 0; + else b = *rA; + EA = (b + *rB) & ~0xf; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) { + STORE(EA + 0, 4, (*vS).w[0]); + STORE(EA + 4, 4, (*vS).w[1]); + STORE(EA + 8, 4, (*vS).w[2]); + STORE(EA + 12, 4, (*vS).w[3]); + } else { + STORE(EA + 12, 4, (*vS).w[0]); + STORE(EA + 8, 4, (*vS).w[1]); + STORE(EA + 4, 4, (*vS).w[2]); + STORE(EA + 0, 4, (*vS).w[3]); + } + PPC_INSN_INT_VR(0, RA_BITMASK | RB_BITMASK, VS_BITMASK, 0); + +# +# Vector Add instructions, 6-30 ... 6-40. +# + +0.4,6.VS,11.VA,16.VB,21.384:VX:av:vaddcuw %VD, %VA, %VB:Vector Add Carryout Unsigned Word + unsigned64 temp; + int i; + for (i = 0; i < 4; i++) { + temp = (unsigned64)(*vA).w[i] + (unsigned64)(*vB).w[i]; + (*vS).w[i] = temp >> 32; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.10:VX:av:vaddfp %VD, %VA, %VB:Vector Add Floating Point + int i; + unsigned32 f; + sim_fpu a, b, d; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_add (&d, &a, &b); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.768:VX:av:vaddsbs %VD, %VA, %VB:Vector Add Signed Byte Saturate + int i, sat, tempsat; + signed16 temp; + for (i = 0; i < 16; i++) { + temp = (signed16)(signed8)(*vA).b[i] + (signed16)(signed8)(*vB).b[i]; + (*vS).b[i] = altivec_signed_saturate_8(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.832:VX:av:vaddshs %VD, %VA, %VB:Vector Add Signed Half Word Saturate + int i, sat, tempsat; + signed32 temp, a, b; + for (i = 0; i < 8; i++) { + a = (signed32)(signed16)(*vA).h[i]; + b = (signed32)(signed16)(*vB).h[i]; + temp = a + b; + (*vS).h[i] = altivec_signed_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.896:VX:av:vaddsws %VD, %VA, %VB:Vector Add Signed Word Saturate + int i, sat, tempsat; + signed64 temp; + for (i = 0; i < 4; i++) { + temp = (signed64)(signed32)(*vA).w[i] + (signed64)(signed32)(*vB).w[i]; + (*vS).w[i] = altivec_signed_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.0:VX:av:vaddubm %VD, %VA, %VB:Vector Add Unsigned Byte Modulo + int i; + for (i = 0; i < 16; i++) + (*vS).b[i] = ((*vA).b[i] + (*vB).b[i]) & 0xff; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.512:VX:av:vaddubs %VD, %VA, %VB:Vector Add Unsigned Byte Saturate + int i, sat, tempsat; + signed16 temp; + sat = 0; + for (i = 0; i < 16; i++) { + temp = (signed16)(unsigned8)(*vA).b[i] + (signed16)(unsigned8)(*vB).b[i]; + (*vS).b[i] = altivec_unsigned_saturate_8(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.64:VX:av:vadduhm %VD, %VA, %VB:Vector Add Unsigned Half Word Modulo + int i; + for (i = 0; i < 8; i++) + (*vS).h[i] = ((*vA).h[i] + (*vB).h[i]) & 0xffff; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.576:VX:av:vadduhs %VD, %VA, %VB:Vector Add Unsigned Half Word Saturate + int i, sat, tempsat; + signed32 temp; + for (i = 0; i < 8; i++) { + temp = (signed32)(unsigned16)(*vA).h[i] + (signed32)(unsigned16)(*vB).h[i]; + (*vS).h[i] = altivec_unsigned_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.128:VX:av:vadduwm %VD, %VA, %VB:Vector Add Unsigned Word Modulo + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = (*vA).w[i] + (*vB).w[i]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.640:VX:av:vadduws %VD, %VA, %VB:Vector Add Unsigned Word Saturate + int i, sat, tempsat; + signed64 temp; + for (i = 0; i < 4; i++) { + temp = (signed64)(unsigned32)(*vA).w[i] + (signed64)(unsigned32)(*vB).w[i]; + (*vS).w[i] = altivec_unsigned_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +# +# Vector AND instructions, 6-41, 6-42 +# + +0.4,6.VS,11.VA,16.VB,21.1028:VX:av:vand %VD, %VA, %VB:Vector Logical AND + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = (*vA).w[i] & (*vB).w[i]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1092:VX:av:vandc %VD, %VA, %VB:Vector Logical AND with Compliment + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = (*vA).w[i] & ~((*vB).w[i]); + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Average instructions, 6-43, 6-48 +# + +0.4,6.VS,11.VA,16.VB,21.1282:VX:av:vavgsb %VD, %VA, %VB:Vector Average Signed Byte + int i; + signed16 temp, a, b; + for (i = 0; i < 16; i++) { + a = (signed16)(signed8)(*vA).b[i]; + b = (signed16)(signed8)(*vB).b[i]; + temp = a + b + 1; + (*vS).b[i] = (temp >> 1) & 0xff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1346:VX:av:vavgsh %VD, %VA, %VB:Vector Average Signed Half Word + int i; + signed32 temp, a, b; + for (i = 0; i < 8; i++) { + a = (signed32)(signed16)(*vA).h[i]; + b = (signed32)(signed16)(*vB).h[i]; + temp = a + b + 1; + (*vS).h[i] = (temp >> 1) & 0xffff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1410:VX:av:vavgsw %VD, %VA, %VB:Vector Average Signed Word + int i; + signed64 temp, a, b; + for (i = 0; i < 4; i++) { + a = (signed64)(signed32)(*vA).w[i]; + b = (signed64)(signed32)(*vB).w[i]; + temp = a + b + 1; + (*vS).w[i] = (temp >> 1) & 0xffffffff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1026:VX:av:vavgub %VD, %VA, %VB:Vector Average Unsigned Byte + int i; + unsigned16 temp, a, b; + for (i = 0; i < 16; i++) { + a = (*vA).b[i]; + b = (*vB).b[i]; + temp = a + b + 1; + (*vS).b[i] = (temp >> 1) & 0xff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1090:VX:av:vavguh %VD, %VA, %VB:Vector Average Unsigned Half Word + int i; + unsigned32 temp, a, b; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + temp = a + b + 1; + (*vS).h[i] = (temp >> 1) & 0xffff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1154:VX:av:vavguw %VD, %VA, %VB:Vector Average Unsigned Word + int i; + unsigned64 temp, a, b; + for (i = 0; i < 4; i++) { + a = (*vA).w[i]; + b = (*vB).w[i]; + temp = a + b + 1; + (*vS).w[i] = (temp >> 1) & 0xffffffff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +# +# Vector Fixed Point Convert instructions, 6-49, 6-50 +# + +0.4,6.VS,11.UIMM,16.VB,21.842:VX:av:vcfsx %VD, %VB, %UIMM:Vector Convert From Signed Fixed-Point Word + int i; + unsigned32 f; + sim_fpu b, div, d; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_u32to (&div, 2 << UIMM, sim_fpu_round_default); + sim_fpu_div (&d, &b, &div); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.UIMM,16.VB,21.778:VX:av:vcfux %VD, %VA, %UIMM:Vector Convert From Unsigned Fixed-Point Word + int i; + unsigned32 f; + sim_fpu b, d, div; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_u32to (&div, 2 << UIMM, sim_fpu_round_default); + sim_fpu_div (&d, &b, &div); + sim_fpu_to32u (&f, &d, sim_fpu_round_default); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +# +# Vector Compare instructions, 6-51 ... 6-64 +# + +0.4,6.VS,11.VA,16.VB,21.RC,22.966:VXR:av:vcmpbpfpx %VD, %VA, %VB:Vector Compare Bounds Floating Point + int i, le, ge; + sim_fpu a, b, d; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + le = sim_fpu_is_le(&a, &b); + ge = sim_fpu_is_ge(&a, &b); + (*vS).w[i] = (le ? 0 : 1 << 31) | (ge ? 0 : 1 << 30); + } + if (RC) + ALTIVEC_SET_CR6(vS, 0); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.198:VXR:av:vcmpeqfpx %VD, %VA, %VB:Vector Compare Equal-to-Floating Point + int i; + sim_fpu a, b; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + if (sim_fpu_is_eq(&a, &b)) + (*vS).w[i] = 0xffffffff; + else + (*vS).w[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.6:VXR:av:vcmpequbx %VD, %VA, %VB:Vector Compare Equal-to Unsigned Byte + int i; + for (i = 0; i < 16; i++) + if ((*vA).b[i] == (*vB).b[i]) + (*vS).b[i] = 0xff; + else + (*vS).b[i] = 0; + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.70:VXR:av:vcmpequhx %VD, %VA, %VB:Vector Compare Equal-to Unsigned Half Word + int i; + for (i = 0; i < 8; i++) + if ((*vA).h[i] == (*vB).h[i]) + (*vS).h[i] = 0xffff; + else + (*vS).h[i] = 0; + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.134:VXR:av:vcmpequwx %VD, %VA, %VB:Vector Compare Equal-to Unsigned Word + int i; + for (i = 0; i < 4; i++) + if ((*vA).w[i] == (*vB).w[i]) + (*vS).w[i] = 0xffffffff; + else + (*vS).w[i] = 0; + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.454:VXR:av:vcmpgefpx %VD, %VA, %VB:Vector Compare Greater-Than-or-Equal-to Floating Point + int i; + sim_fpu a, b; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + if (sim_fpu_is_ge(&a, &b)) + (*vS).w[i] = 0xffffffff; + else + (*vS).w[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.710:VXR:av:vcmpgtfpx %VD, %VA, %VB:Vector Compare Greater-Than Floating Point + int i; + sim_fpu a, b; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + if (sim_fpu_is_gt(&a, &b)) + (*vS).w[i] = 0xffffffff; + else + (*vS).w[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.774:VXR:av:vcmpgtsbx %VD, %VA, %VB:Vector Compare Greater-Than Signed Byte + int i; + signed8 a, b; + for (i = 0; i < 16; i++) { + a = (*vA).b[i]; + b = (*vB).b[i]; + if (a > b) + (*vS).b[i] = 0xff; + else + (*vS).b[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.838:VXR:av:vcmpgtshx %VD, %VA, %VB:Vector Compare Greater-Than Signed Half Word + int i; + signed16 a, b; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + if (a > b) + (*vS).h[i] = 0xffff; + else + (*vS).h[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.902:VXR:av:vcmpgtswx %VD, %VA, %VB:Vector Compare Greater-Than Signed Word + int i; + signed32 a, b; + for (i = 0; i < 4; i++) { + a = (*vA).w[i]; + b = (*vB).w[i]; + if (a > b) + (*vS).w[i] = 0xffffffff; + else + (*vS).w[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.518:VXR:av:vcmpgtubx %VD, %VA, %VB:Vector Compare Greater-Than Unsigned Byte + int i; + unsigned8 a, b; + for (i = 0; i < 16; i++) { + a = (*vA).b[i]; + b = (*vB).b[i]; + if (a > b) + (*vS).b[i] = 0xff; + else + (*vS).b[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.582:VXR:av:vcmpgtuhx %VD, %VA, %VB:Vector Compare Greater-Than Unsigned Half Word + int i; + unsigned16 a, b; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + if (a > b) + (*vS).h[i] = 0xffff; + else + (*vS).h[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +0.4,6.VS,11.VA,16.VB,21.RC,22.646:VXR:av:vcmpgtuwx %VD, %VA, %VB:Vector Compare Greater-Than Unsigned Word + int i; + unsigned32 a, b; + for (i = 0; i < 4; i++) { + a = (*vA).w[i]; + b = (*vB).w[i]; + if (a > b) + (*vS).w[i] = 0xffffffff; + else + (*vS).w[i] = 0; + } + if (RC) + ALTIVEC_SET_CR6(vS, 1); + PPC_INSN_VR_CR(VS_BITMASK, VA_BITMASK | VB_BITMASK, RC ? 0x000000f0 : 0); + +# +# Vector Convert instructions, 6-65, 6-66. +# + +0.4,6.VS,11.UIMM,16.VB,21.970:VX:av:vctsxs %VD, %VB, %UIMM:Vector Convert to Signed Fixed-Point Word Saturate + int i, sat, tempsat; + signed64 temp; + sim_fpu a, b, m; + sat = 0; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_u32to (&m, 2 << UIMM, sim_fpu_round_default); + sim_fpu_mul (&a, &b, &m); + sim_fpu_to64i (&temp, &a, sim_fpu_round_default); + (*vS).w[i] = altivec_signed_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.UIMM,16.VB,21.906:VX:av:vctuxs %VD, %VB, %UIMM:Vector Convert to Unsigned Fixed-Point Word Saturate + int i, sat, tempsat; + signed64 temp; + sim_fpu a, b, m; + sat = 0; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_u32to (&m, 2 << UIMM, sim_fpu_round_default); + sim_fpu_mul (&a, &b, &m); + sim_fpu_to64u (&temp, &a, sim_fpu_round_default); + (*vS).w[i] = altivec_unsigned_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VB_BITMASK); + +# +# Vector Estimate instructions, 6-67 ... 6-70. +# + +0.4,6.VS,11.0,16.VB,21.394:VX:av:vexptefp %VD, %VB:Vector 2 Raised to the Exponent Estimate Floating Point + int i; + unsigned32 f; + signed32 bi; + sim_fpu b, d; + for (i = 0; i < 4; i++) { + /*HACK!*/ + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_to32i (&bi, &b, sim_fpu_round_default); + bi = 2 ^ bi; + sim_fpu_32to (&d, bi); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR_VSCR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.458:VX:av:vlogefp %VD, %VB:Vector Log2 Estimate Floating Point + int i; + unsigned32 c, u, f; + sim_fpu b, cfpu, d; + for (i = 0; i < 4; i++) { + /*HACK!*/ + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_to32u (&u, &b, sim_fpu_round_default); + for (c = 0; (u /= 2) > 1; c++) + ; + sim_fpu_32to (&cfpu, c); + sim_fpu_add (&d, &b, &cfpu); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR_VSCR(VS_BITMASK, VB_BITMASK); + +# +# Vector Multiply Add instruction, 6-71 +# + +0.4,6.VS,11.VA,16.VB,21.VC,26.46:VAX:av:vmaddfp %VD, %VA, %VB, %VC:Vector Multiply Add Floating Point + int i; + unsigned32 f; + sim_fpu a, b, c, d, e; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_32to (&c, (*vC).w[i]); + sim_fpu_mul (&e, &a, &c); + sim_fpu_add (&d, &e, &b); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + + +# +# Vector Maximum instructions, 6-72 ... 6-78. +# + +0.4,6.VS,11.VA,16.VB,21.1034:VX:av:vmaxfp %VD, %VA, %VB:Vector Maximum Floating Point + int i; + unsigned32 f; + sim_fpu a, b, d; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_max (&d, &a, &b); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.258:VX:av:vmaxsb %VD, %VA, %VB:Vector Maximum Signed Byte + int i; + signed8 a, b; + for (i = 0; i < 16; i++) { + a = (*vA).b[i]; + b = (*vB).b[i]; + if (a > b) + (*vS).b[i] = a; + else + (*vS).b[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.322:VX:av:vmaxsh %VD, %VA, %VB:Vector Maximum Signed Half Word + int i; + signed16 a, b; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + if (a > b) + (*vS).h[i] = a; + else + (*vS).h[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.386:VX:av:vmaxsw %VD, %VA, %VB:Vector Maximum Signed Word + int i; + signed32 a, b; + for (i = 0; i < 4; i++) { + a = (*vA).w[i]; + b = (*vB).w[i]; + if (a > b) + (*vS).w[i] = a; + else + (*vS).w[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.2:VX:av:vmaxub %VD, %VA, %VB:Vector Maximum Unsigned Byte + int i; + unsigned8 a, b; + for (i = 0; i < 16; i++) { + a = (*vA).b[i]; + b = (*vB).b[i]; + if (a > b) + (*vS).b[i] = a; + else + (*vS).b[i] = b; + }; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.66:VX:av:vmaxus %VD, %VA, %VB:Vector Maximum Unsigned Half Word + int i; + unsigned16 a, b; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + if (a > b) + (*vS).h[i] = a; + else + (*vS).h[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.130:VX:av:vmaxuw %VD, %VA, %VB:Vector Maximum Unsigned Word + int i; + unsigned32 a, b; + for (i = 0; i < 4; i++) { + a = (*vA).w[i]; + b = (*vB).w[i]; + if (a > b) + (*vS).w[i] = a; + else + (*vS).w[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Multiple High instructions, 6-79, 6-80. +# + +0.4,6.VS,11.VA,16.VB,21.VC,26.32:VAX:av:vmhaddshs %VD, %VA, %VB, %VC:Vector Multiple High and Add Signed Half Word Saturate + int i, sat, tempsat; + signed16 a, b; + signed32 prod, temp, c; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + c = (signed32)(signed16)(*vC).h[i]; + prod = (signed32)a * (signed32)b; + temp = (prod >> 15) + c; + (*vS).h[i] = altivec_signed_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.VC,26.33:VAX:av:vmhraddshs %VD, %VA, %VB, %VC:Vector Multiple High Round and Add Signed Half Word Saturate + int i, sat, tempsat; + signed16 a, b; + signed32 prod, temp, c; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + c = (signed32)(signed16)(*vC).h[i]; + prod = (signed32)a * (signed32)b; + prod += 0x4000; + temp = (prod >> 15) + c; + (*vS).h[i] = altivec_signed_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + + +# +# Vector Minimum instructions, 6-81 ... 6-87 +# + +0.4,6.VS,11.VA,16.VB,21.1098:VX:av:vminfp %VD, %VA, %VB:Vector Minimum Floating Point + int i; + unsigned32 f; + sim_fpu a, b, d; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_min (&d, &a, &b); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.770:VX:av:vminsb %VD, %VA, %VB:Vector Minimum Signed Byte + int i; + signed8 a, b; + for (i = 0; i < 16; i++) { + a = (*vA).b[i]; + b = (*vB).b[i]; + if (a < b) + (*vS).b[i] = a; + else + (*vS).b[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.834:VX:av:vminsh %VD, %VA, %VB:Vector Minimum Signed Half Word + int i; + signed16 a, b; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + if (a < b) + (*vS).h[i] = a; + else + (*vS).h[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.898:VX:av:vminsw %VD, %VA, %VB:Vector Minimum Signed Word + int i; + signed32 a, b; + for (i = 0; i < 4; i++) { + a = (*vA).w[i]; + b = (*vB).w[i]; + if (a < b) + (*vS).w[i] = a; + else + (*vS).w[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.514:VX:av:vminub %VD, %VA, %VB:Vector Minimum Unsigned Byte + int i; + unsigned8 a, b; + for (i = 0; i < 16; i++) { + a = (*vA).b[i]; + b = (*vB).b[i]; + if (a < b) + (*vS).b[i] = a; + else + (*vS).b[i] = b; + }; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.578:VX:av:vminuh %VD, %VA, %VB:Vector Minimum Unsigned Half Word + int i; + unsigned16 a, b; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + if (a < b) + (*vS).h[i] = a; + else + (*vS).h[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.642:VX:av:vminuw %VD, %VA, %VB:Vector Minimum Unsigned Word + int i; + unsigned32 a, b; + for (i = 0; i < 4; i++) { + a = (*vA).w[i]; + b = (*vB).w[i]; + if (a < b) + (*vS).w[i] = a; + else + (*vS).w[i] = b; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Multiply Low instruction, 6-88 +# + +0.4,6.VS,11.VA,16.VB,21.VC,26.34:VAX:av:vmladduhm %VD, %VA, %VB, %VC:Vector Multiply Low and Add Unsigned Half Word Modulo + int i; + unsigned16 a, b, c; + unsigned32 prod; + for (i = 0; i < 8; i++) { + a = (*vA).h[i]; + b = (*vB).h[i]; + c = (*vC).h[i]; + prod = (unsigned32)a * (unsigned32)b; + (*vS).h[i] = (prod + c) & 0xffff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + + +# +# Vector Merge instructions, 6-89 ... 6-94 +# + +0.4,6.VS,11.VA,16.VB,21.12:VX:av:vmrghb %VD, %VA, %VB:Vector Merge High Byte + int i; + for (i = 0; i < 16; i += 2) { + (*vS).b[AV_BINDEX(i)] = (*vA).b[AV_BINDEX(i/2)]; + (*vS).b[AV_BINDEX(i+1)] = (*vB).b[AV_BINDEX(i/2)]; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.76:VX:av:vmrghh %VD, %VA, %VB:Vector Merge High Half Word + int i; + for (i = 0; i < 8; i += 2) { + (*vS).h[AV_HINDEX(i)] = (*vA).h[AV_HINDEX(i/2)]; + (*vS).h[AV_HINDEX(i+1)] = (*vB).h[AV_HINDEX(i/2)]; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.140:VX:av:vmrghw %VD, %VA, %VB:Vector Merge High Word + int i; + for (i = 0; i < 4; i += 2) { + (*vS).w[i] = (*vA).w[i/2]; + (*vS).w[i+1] = (*vB).w[i/2]; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.268:VX:av:vmrglb %VD, %VA, %VB:Vector Merge Low Byte + int i; + for (i = 0; i < 16; i += 2) { + (*vS).b[AV_BINDEX(i)] = (*vA).b[AV_BINDEX((i/2) + 8)]; + (*vS).b[AV_BINDEX(i+1)] = (*vB).b[AV_BINDEX((i/2) + 8)]; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.332:VX:av:vmrglh %VD, %VA, %VB:Vector Merge Low Half Word + int i; + for (i = 0; i < 8; i += 2) { + (*vS).h[AV_HINDEX(i)] = (*vA).h[AV_HINDEX((i/2) + 4)]; + (*vS).h[AV_HINDEX(i+1)] = (*vB).h[AV_HINDEX((i/2) + 4)]; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.396:VX:av:vmrglw %VD, %VA, %VB:Vector Merge Low Word + int i; + for (i = 0; i < 4; i += 2) { + (*vS).w[i] = (*vA).w[(i/2) + 2]; + (*vS).w[i+1] = (*vB).w[(i/2) + 2]; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Multiply Sum instructions, 6-95 ... 6-100 +# + +0.4,6.VS,11.VA,16.VB,21.VC,26.37:VAX:av:vmsummbm %VD, %VA, %VB, %VC:Vector Multiply Sum Mixed-Sign Byte Modulo + int i, j; + signed32 temp; + signed16 prod, a; + unsigned16 b; + for (i = 0; i < 4; i++) { + temp = (*vC).w[i]; + for (j = 0; j < 4; j++) { + a = (signed16)(signed8)(*vA).b[i*4+j]; + b = (*vB).b[i*4+j]; + prod = a * b; + temp += (signed32)prod; + } + (*vS).w[i] = temp; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.VC,26.40:VAX:av:vmsumshm %VD, %VA, %VB, %VC:Vector Multiply Sum Signed Half Word Modulo + int i, j; + signed32 temp, prod, a, b; + for (i = 0; i < 4; i++) { + temp = (*vC).w[i]; + for (j = 0; j < 2; j++) { + a = (signed32)(signed16)(*vA).h[i*2+j]; + b = (signed32)(signed16)(*vB).h[i*2+j]; + prod = a * b; + temp += prod; + } + (*vS).w[i] = temp; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.VC,26.41:VAX:av:vmsumshs %VD, %VA, %VB, %VC:Vector Multiply Sum Signed Half Word Saturate + int i, j, sat, tempsat; + signed64 temp; + signed32 prod, a, b; + sat = 0; + for (i = 0; i < 4; i++) { + temp = (signed64)(signed32)(*vC).w[i]; + for (j = 0; j < 2; j++) { + a = (signed32)(signed16)(*vA).h[i*2+j]; + b = (signed32)(signed16)(*vB).h[i*2+j]; + prod = a * b; + temp += (signed64)prod; + } + (*vS).w[i] = altivec_signed_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.VC,26.36:VAX:av:vmsumubm %VD, %VA, %VB, %VC:Vector Multiply Sum Unsigned Byte Modulo + int i, j; + unsigned32 temp; + unsigned16 prod, a, b; + for (i = 0; i < 4; i++) { + temp = (*vC).w[i]; + for (j = 0; j < 4; j++) { + a = (*vA).b[i*4+j]; + b = (*vB).b[i*4+j]; + prod = a * b; + temp += prod; + } + (*vS).w[i] = temp; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.VC,26.38:VAX:av:vmsumuhm %VD, %VA, %VB, %VC:Vector Multiply Sum Unsigned Half Word Modulo + int i, j; + unsigned32 temp, prod, a, b; + for (i = 0; i < 4; i++) { + temp = (*vC).w[i]; + for (j = 0; j < 2; j++) { + a = (*vA).h[i*2+j]; + b = (*vB).h[i*2+j]; + prod = a * b; + temp += prod; + } + (*vS).w[i] = temp; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.VC,26.39:VAX:av:vmsumuhs %VD, %VA, %VB, %VC:Vector Multiply Sum Unsigned Half Word Saturate + int i, j, sat, tempsat; + unsigned32 temp, prod, a, b; + sat = 0; + for (i = 0; i < 4; i++) { + temp = (*vC).w[i]; + for (j = 0; j < 2; j++) { + a = (*vA).h[i*2+j]; + b = (*vB).h[i*2+j]; + prod = a * b; + temp += prod; + } + (*vS).w[i] = altivec_unsigned_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + + +# +# Vector Multiply Even/Odd instructions, 6-101 ... 6-108 +# + +0.4,6.VS,11.VA,16.VB,21.776:VX:av:vmulesb %VD, %VA, %VB:Vector Multiply Even Signed Byte + int i; + signed8 a, b; + signed16 prod; + for (i = 0; i < 8; i++) { + a = (*vA).b[AV_BINDEX(i*2)]; + b = (*vB).b[AV_BINDEX(i*2)]; + prod = a * b; + (*vS).h[AV_HINDEX(i)] = prod; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.840:VX:av:vmulesh %VD, %VA, %VB:Vector Multiply Even Signed Half Word + int i; + signed16 a, b; + signed32 prod; + for (i = 0; i < 4; i++) { + a = (*vA).h[AV_HINDEX(i*2)]; + b = (*vB).h[AV_HINDEX(i*2)]; + prod = a * b; + (*vS).w[i] = prod; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.520:VX:av:vmuleub %VD, %VA, %VB:Vector Multiply Even Unsigned Byte + int i; + unsigned8 a, b; + unsigned16 prod; + for (i = 0; i < 8; i++) { + a = (*vA).b[AV_BINDEX(i*2)]; + b = (*vB).b[AV_BINDEX(i*2)]; + prod = a * b; + (*vS).h[AV_HINDEX(i)] = prod; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.584:VX:av:vmuleuh %VD, %VA, %VB:Vector Multiply Even Unsigned Half Word + int i; + unsigned16 a, b; + unsigned32 prod; + for (i = 0; i < 4; i++) { + a = (*vA).h[AV_HINDEX(i*2)]; + b = (*vB).h[AV_HINDEX(i*2)]; + prod = a * b; + (*vS).w[i] = prod; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.264:VX:av:vmulosb %VD, %VA, %VB:Vector Multiply Odd Signed Byte + int i; + signed8 a, b; + signed16 prod; + for (i = 0; i < 8; i++) { + a = (*vA).b[AV_BINDEX((i*2)+1)]; + b = (*vB).b[AV_BINDEX((i*2)+1)]; + prod = a * b; + (*vS).h[AV_HINDEX(i)] = prod; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.328:VX:av:vmulosh %VD, %VA, %VB:Vector Multiply Odd Signed Half Word + int i; + signed16 a, b; + signed32 prod; + for (i = 0; i < 4; i++) { + a = (*vA).h[AV_HINDEX((i*2)+1)]; + b = (*vB).h[AV_HINDEX((i*2)+1)]; + prod = a * b; + (*vS).w[i] = prod; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.8:VX:av:vmuloub %VD, %VA, %VB:Vector Multiply Odd Unsigned Byte + int i; + unsigned8 a, b; + unsigned16 prod; + for (i = 0; i < 8; i++) { + a = (*vA).b[AV_BINDEX((i*2)+1)]; + b = (*vB).b[AV_BINDEX((i*2)+1)]; + prod = a * b; + (*vS).h[AV_HINDEX(i)] = prod; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.72:VX:av:vmulouh %VD, %VA, %VB:Vector Multiply Odd Unsigned Half Word + int i; + unsigned16 a, b; + unsigned32 prod; + for (i = 0; i < 4; i++) { + a = (*vA).h[AV_HINDEX((i*2)+1)]; + b = (*vB).h[AV_HINDEX((i*2)+1)]; + prod = a * b; + (*vS).w[i] = prod; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Negative Multiply-Subtract instruction, 6-109 +# + +0.4,6.VS,11.VA,16.VB,21.VC,26.47:VX:av:vnmsubfp %VD, %VA, %VB, %VC:Vector Negative Multiply-Subtract Floating Point + int i; + unsigned32 f; + sim_fpu a, b, c, d, i1, i2; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_32to (&c, (*vC).w[i]); + sim_fpu_mul (&i1, &a, &c); + sim_fpu_sub (&i2, &i1, &b); + sim_fpu_neg (&d, &i2); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + + +# +# Vector Logical OR instructions, 6-110, 6-111, 6-177 +# + +0.4,6.VS,11.VA,16.VB,21.1284:VX:av:vnor %VD, %VA, %VB:Vector Logical NOR + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = ~((*vA).w[i] | (*vB).w[i]); + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1156:VX:av:vor %VD, %VA, %VB:Vector Logical OR + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = (*vA).w[i] | (*vB).w[i]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1220:VX:av:vxor %VD, %VA, %VB:Vector Logical XOR + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = (*vA).w[i] ^ (*vB).w[i]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Permute instruction, 6-112 +# + +0.4,6.VS,11.VA,16.VB,21.VC,26.43:VX:av:vperm %VD, %VA, %VB, %VC:Vector Permute + int i, who; + for (i = 0; i < 16; i++) { + who = (*vC).b[AV_BINDEX(i)] & 0x1f; + if (who & 0x10) + (*vS).b[AV_BINDEX(i)] = (*vB).b[AV_BINDEX(who & 0xf)]; + else + (*vS).b[AV_BINDEX(i)] = (*vA).b[AV_BINDEX(who & 0xf)]; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + + +# +# Vector Pack instructions, 6-113 ... 6-121 +# + +0.4,6.VS,11.VA,16.VB,21.782:VX:av:vpkpx %VD, %VA, %VB:Vector Pack Pixel32 + int i; + for (i = 0; i < 4; i++) { + (*vS).h[AV_HINDEX(i+4)] = ((((*vB).w[i]) >> 9) & 0xfc00) + | ((((*vB).w[i]) >> 6) & 0x03e0) + | ((((*vB).w[i]) >> 3) & 0x001f); + (*vS).h[AV_HINDEX(i)] = ((((*vA).w[i]) >> 9) & 0xfc00) + | ((((*vA).w[i]) >> 6) & 0x03e0) + | ((((*vA).w[i]) >> 3) & 0x001f); + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.398:VX:av:vpkshss %VD, %VA, %VB:Vector Pack Signed Half Word Signed Saturate + int i, sat, tempsat; + signed16 temp; + sat = 0; + for (i = 0; i < 16; i++) { + if (i < 8) + temp = (*vA).h[AV_HINDEX(i)]; + else + temp = (*vB).h[AV_HINDEX(i-8)]; + (*vS).b[AV_BINDEX(i)] = altivec_signed_saturate_8(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.270:VX:av:vpkshus %VD, %VA, %VB:Vector Pack Signed Half Word Unsigned Saturate + int i, sat, tempsat; + signed16 temp; + sat = 0; + for (i = 0; i < 16; i++) { + if (i < 8) + temp = (*vA).h[AV_HINDEX(i)]; + else + temp = (*vB).h[AV_HINDEX(i-8)]; + (*vS).b[AV_BINDEX(i)] = altivec_unsigned_saturate_8(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.462:VX:av:vpkswss %VD, %VA, %VB:Vector Pack Signed Word Signed Saturate + int i, sat, tempsat; + signed32 temp; + sat = 0; + for (i = 0; i < 8; i++) { + if (i < 4) + temp = (*vA).w[i]; + else + temp = (*vB).w[i-4]; + (*vS).h[AV_HINDEX(i)] = altivec_signed_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.334:VX:av:vpkswus %VD, %VA, %VB:Vector Pack Signed Word Unsigned Saturate + int i, sat, tempsat; + signed32 temp; + sat = 0; + for (i = 0; i < 8; i++) { + if (i < 4) + temp = (*vA).w[i]; + else + temp = (*vB).w[i-4]; + (*vS).h[AV_HINDEX(i)] = altivec_unsigned_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.14:VX:av:vpkuhum %VD, %VA, %VB:Vector Pack Unsigned Half Word Unsigned Modulo + int i; + for (i = 0; i < 16; i++) + if (i < 8) + (*vS).b[AV_BINDEX(i)] = (*vA).h[AV_HINDEX(i)]; + else + (*vS).b[AV_BINDEX(i)] = (*vB).h[AV_HINDEX(i-8)]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.142:VX:av:vpkuhus %VD, %VA, %VB:Vector Pack Unsigned Half Word Unsigned Saturate + int i, sat, tempsat; + signed16 temp; + sat = 0; + for (i = 0; i < 16; i++) { + if (i < 8) + temp = (*vA).h[AV_HINDEX(i)]; + else + temp = (*vB).h[AV_HINDEX(i-8)]; + /* force positive in signed16, ok as we'll toss the bit away anyway */ + temp &= ~0x8000; + (*vS).b[AV_BINDEX(i)] = altivec_unsigned_saturate_8(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.78:VX:av:vpkuwum %VD, %VA, %VB:Vector Pack Unsigned Word Unsigned Modulo + int i; + for (i = 0; i < 8; i++) + if (i < 8) + (*vS).h[AV_HINDEX(i)] = (*vA).w[i]; + else + (*vS).h[AV_HINDEX(i)] = (*vB).w[i-8]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.206:VX:av:vpkuwus %VD, %VA, %VB:Vector Pack Unsigned Word Unsigned Saturate + int i, sat, tempsat; + signed32 temp; + sat = 0; + for (i = 0; i < 8; i++) { + if (i < 4) + temp = (*vA).w[i]; + else + temp = (*vB).w[i-4]; + /* force positive in signed32, ok as we'll toss the bit away anyway */ + temp &= ~0x80000000; + (*vS).h[AV_HINDEX(i)] = altivec_unsigned_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Reciprocal instructions, 6-122, 6-123, 6-131 +# + +0.4,6.VS,11.0,16.VB,21.266:VX:av:vrefp %VD, %VB:Vector Reciprocal Estimate Floating Point + int i; + unsigned32 f; + sim_fpu op, d; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&op, (*vB).w[i]); + sim_fpu_div (&d, &sim_fpu_one, &op); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.330:VX:av:vrsqrtefp %VD, %VB:Vector Reciprocal Square Root Estimate Floating Point + int i; + unsigned32 f; + sim_fpu op, i1, one, d; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&op, (*vB).w[i]); + sim_fpu_sqrt (&i1, &op); + sim_fpu_div (&d, &sim_fpu_one, &i1); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + + +# +# Vector Round instructions, 6-124 ... 6-127 +# + +0.4,6.VS,11.0,16.VB,21.714:VX:av:vrfim %VD, %VB:Vector Round to Floating-Point Integer towards Minus Infinity + int i; + unsigned32 f; + sim_fpu op; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&op, (*vB).w[i]); + sim_fpu_round_32(&op, sim_fpu_round_down, sim_fpu_denorm_default); + sim_fpu_to32 (&f, &op); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.522:VX:av:vrfin %VD, %VB:Vector Round to Floating-Point Integer Nearest + int i; + unsigned32 f; + sim_fpu op; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&op, (*vB).w[i]); + sim_fpu_round_32(&op, sim_fpu_round_near, sim_fpu_denorm_default); + sim_fpu_to32 (&f, &op); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.650:VX:av:vrfip %VD, %VB:Vector Round to Floating-Point Integer towards Plus Infinity + int i; + unsigned32 f; + sim_fpu op; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&op, (*vB).w[i]); + sim_fpu_round_32(&op, sim_fpu_round_up, sim_fpu_denorm_default); + sim_fpu_to32 (&f, &op); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.586:VX:av:vrfiz %VD, %VB:Vector Round to Floating-Point Integer towards Zero + int i; + unsigned32 f; + sim_fpu op; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&op, (*vB).w[i]); + sim_fpu_round_32(&op, sim_fpu_round_zero, sim_fpu_denorm_default); + sim_fpu_to32 (&f, &op); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + + +# +# Vector Rotate Left instructions, 6-128 ... 6-130 +# + +0.4,6.VS,11.VA,16.VB,21.4:VX:av:vrlb %VD, %VA, %VB:Vector Rotate Left Integer Byte + int i; + unsigned16 temp; + for (i = 0; i < 16; i++) { + temp = (unsigned16)(*vA).b[i] << (((*vB).b[i]) & 7); + (*vS).b[i] = (temp & 0xff) | ((temp >> 8) & 0xff); + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.68:VX:av:vrlh %VD, %VA, %VB:Vector Rotate Left Integer Half Word + int i; + unsigned32 temp; + for (i = 0; i < 8; i++) { + temp = (unsigned32)(*vA).h[i] << (((*vB).h[i]) & 0xf); + (*vS).h[i] = (temp & 0xffff) | ((temp >> 16) & 0xffff); + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.132:VX:av:vrlw %VD, %VA, %VB:Vector Rotate Left Integer Word + int i; + unsigned64 temp; + for (i = 0; i < 4; i++) { + temp = (unsigned64)(*vA).w[i] << (((*vB).w[i]) & 0x1f); + (*vS).w[i] = (temp & 0xffffffff) | ((temp >> 32) & 0xffffffff); + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Conditional Select instruction, 6-133 +# + +0.4,6.VS,11.VA,16.VB,21.VC,26.42:VAX:av:vsel %VD, %VA, %VB, %VC:Vector Conditional Select + int i; + unsigned32 c; + for (i = 0; i < 4; i++) { + c = (*vC).w[i]; + (*vS).w[i] = ((*vB).w[i] & c) | ((*vA).w[i] & ~c); + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK | VC_BITMASK); + +# +# Vector Shift Left instructions, 6-134 ... 6-139 +# + +0.4,6.VS,11.VA,16.VB,21.452:VX:av:vsl %VD, %VA, %VB:Vector Shift Left + int sh, i, j, carry, new_carry; + sh = (*vB).b[0] & 7; /* don't bother checking everything */ + carry = 0; + for (j = 3; j >= 0; j--) { + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + i = j; + else + i = (j + 2) % 4; + new_carry = (*vA).w[i] >> (32 - sh); + (*vS).w[i] = ((*vA).w[i] << sh) | carry; + carry = new_carry; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.260:VX:av:vslb %VD, %VA, %VB:Vector Shift Left Integer Byte + int i, sh; + for (i = 0; i < 16; i++) { + sh = ((*vB).b[i]) & 7; + (*vS).b[i] = (*vA).b[i] << sh; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.0,22.SH,26.44:VX:av:vsldol %VD, %VA, %VB:Vector Shift Left Double by Octet Immediate + int i, j; + for (j = 0, i = SH; i < 16; i++) + (*vS).b[j++] = (*vA).b[i]; + for (i = 0; i < SH; i++) + (*vS).b[j++] = (*vB).b[i]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.324:VX:av:vslh %VD, %VA, %VB:Vector Shift Left Half Word + int i, sh; + for (i = 0; i < 8; i++) { + sh = ((*vB).h[i]) & 0xf; + (*vS).h[i] = (*vA).h[i] << sh; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1036:VX:av:vslo %VD, %VA, %VB:Vector Shift Left by Octet + int i, sh; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + sh = ((*vB).b[AV_BINDEX(15)] >> 3) & 0xf; + else + sh = ((*vB).b[AV_BINDEX(0)] >> 3) & 0xf; + for (i = 0; i < 16; i++) { + if (15 - i > sh) + (*vS).b[AV_BINDEX(i)] = (*vA).b[AV_BINDEX(i + sh)]; + else + (*vS).b[AV_BINDEX(i)] = 0; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.388:VX:av:vslw %VD, %VA, %VB:Vector Shift Left Integer Word + int i, sh; + for (i = 0; i < 4; i++) { + sh = ((*vB).w[i]) & 0x1f; + (*vS).w[i] = (*vA).w[i] << sh; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Splat instructions, 6-140 ... 6-145 +# + +0.4,6.VS,11.UIMM,16.VB,21.524:VX:av:vspltb %VD, %VB, %UIMM:Vector Splat Byte + int i; + unsigned8 b; + b = (*vB).b[AV_BINDEX(UIMM & 0xf)]; + for (i = 0; i < 16; i++) + (*vS).b[i] = b; + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.UIMM,16.VB,21.588:VX:av:vsplth %VD, %VB, %UIMM:Vector Splat Half Word + int i; + unsigned16 h; + h = (*vB).h[AV_HINDEX(UIMM & 0x7)]; + for (i = 0; i < 8; i++) + (*vS).h[i] = h; + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.SIMM,16.0,21.780:VX:av:vspltisb %VD, %SIMM:Vector Splat Immediate Signed Byte + int i; + signed8 b = SIMM; + /* manual 5-bit signed extension */ + if (b & 0x10) + b -= 0x20; + for (i = 0; i < 16; i++) + (*vS).b[i] = b; + PPC_INSN_VR(VS_BITMASK, 0); + +0.4,6.VS,11.SIMM,16.0,21.844:VX:av:vspltish %VD, %SIMM:Vector Splat Immediate Signed Half Word + int i; + signed16 h = SIMM; + /* manual 5-bit signed extension */ + if (h & 0x10) + h -= 0x20; + for (i = 0; i < 8; i++) + (*vS).h[i] = h; + PPC_INSN_VR(VS_BITMASK, 0); + +0.4,6.VS,11.SIMM,16.0,21.908:VX:av:vspltisw %VD, %SIMM:Vector Splat Immediate Signed Word + int i; + signed32 w = SIMM; + /* manual 5-bit signed extension */ + if (w & 0x10) + w -= 0x20; + for (i = 0; i < 4; i++) + (*vS).w[i] = w; + PPC_INSN_VR(VS_BITMASK, 0); + +0.4,6.VS,11.UIMM,16.VB,21.652:VX:av:vspltw %VD, %VB, %UIMM:Vector Splat Word + int i; + unsigned32 w; + w = (*vB).w[UIMM & 0x3]; + for (i = 0; i < 4; i++) + (*vS).w[i] = w; + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + + +# +# Vector Shift Right instructions, 6-146 ... 6-154 +# + +0.4,6.VS,11.VA,16.VB,21.708:VX:av:vsr %VD, %VA, %VB:Vector Shift Right + int sh, i, j, carry, new_carry; + sh = (*vB).b[0] & 7; /* don't bother checking everything */ + carry = 0; + for (j = 0; j < 4; j++) { + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + i = j; + else + i = (j + 2) % 4; + new_carry = (*vA).w[i] << (32 - sh); + (*vS).w[i] = ((*vA).w[i] >> sh) | carry; + carry = new_carry; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.772:VX:av:vsrab %VD, %VA, %VB:Vector Shift Right Algebraic Byte + int i, sh; + signed16 a; + for (i = 0; i < 16; i++) { + sh = ((*vB).b[i]) & 7; + a = (signed16)(signed8)(*vA).b[i]; + (*vS).b[i] = (a >> sh) & 0xff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.836:VX:av:vsrah %VD, %VA, %VB:Vector Shift Right Algebraic Half Word + int i, sh; + signed32 a; + for (i = 0; i < 8; i++) { + sh = ((*vB).h[i]) & 0xf; + a = (signed32)(signed16)(*vA).h[i]; + (*vS).h[i] = (a >> sh) & 0xffff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.900:VX:av:vsraw %VD, %VA, %VB:Vector Shift Right Algebraic Word + int i, sh; + signed64 a; + for (i = 0; i < 4; i++) { + sh = ((*vB).w[i]) & 0xf; + a = (signed64)(signed32)(*vA).w[i]; + (*vS).w[i] = (a >> sh) & 0xffffffff; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.516:VX:av:vsrb %VD, %VA, %VB:Vector Shift Right Byte + int i, sh; + for (i = 0; i < 16; i++) { + sh = ((*vB).b[i]) & 7; + (*vS).b[i] = (*vA).b[i] >> sh; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.580:VX:av:vsrh %VD, %VA, %VB:Vector Shift Right Half Word + int i, sh; + for (i = 0; i < 8; i++) { + sh = ((*vB).h[i]) & 0xf; + (*vS).h[i] = (*vA).h[i] >> sh; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1100:VX:av:vsro %VD, %VA, %VB:Vector Shift Right Octet + int i, sh; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + sh = ((*vB).b[AV_BINDEX(15)] >> 3) & 0xf; + else + sh = ((*vB).b[AV_BINDEX(0)] >> 3) & 0xf; + for (i = 0; i < 16; i++) { + if (i < sh) + (*vS).b[AV_BINDEX(i)] = 0; + else + (*vS).b[AV_BINDEX(i)] = (*vA).b[AV_BINDEX(i - sh)]; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.644:VX:av:vsrw %VD, %VA, %VB:Vector Shift Right Word + int i, sh; + for (i = 0; i < 4; i++) { + sh = ((*vB).w[i]) & 0x1f; + (*vS).w[i] = (*vA).w[i] >> sh; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Subtract instructions, 6-155 ... 6-165 +# + +0.4,6.VS,11.VA,16.VB,21.1408:VX:av:vsubcuw %VD, %VA, %VB:Vector Subtract Carryout Unsigned Word + int i; + signed64 temp, a, b; + for (i = 0; i < 4; i++) { + a = (signed64)(unsigned32)(*vA).w[i]; + b = (signed64)(unsigned32)(*vB).w[i]; + temp = a - b; + (*vS).w[i] = ~(temp >> 32) & 1; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.74:VX:av:vsubfp %VD, %VA, %VB:Vector Subtract Floating Point + int i; + unsigned32 f; + sim_fpu a, b, d; + for (i = 0; i < 4; i++) { + sim_fpu_32to (&a, (*vA).w[i]); + sim_fpu_32to (&b, (*vB).w[i]); + sim_fpu_sub (&d, &a, &b); + sim_fpu_to32 (&f, &d); + (*vS).w[i] = f; + } + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1792:VX:av:vsubsbs %VD, %VA, %VB:Vector Subtract Signed Byte Saturate + int i, sat, tempsat; + signed16 temp; + sat = 0; + for (i = 0; i < 16; i++) { + temp = (signed16)(signed8)(*vA).b[i] - (signed16)(signed8)(*vB).b[i]; + (*vS).b[i] = altivec_signed_saturate_8(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1856:VX:av:vsubshs %VD, %VA, %VB:Vector Subtract Signed Half Word Saturate + int i, sat, tempsat; + signed32 temp; + sat = 0; + for (i = 0; i < 8; i++) { + temp = (signed32)(signed16)(*vA).h[i] - (signed32)(signed16)(*vB).h[i]; + (*vS).h[i] = altivec_signed_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1920:VX:av:vsubsws %VD, %VA, %VB:Vector Subtract Signed Word Saturate + int i, sat, tempsat; + signed64 temp; + sat = 0; + for (i = 0; i < 4; i++) { + temp = (signed64)(signed32)(*vA).w[i] - (signed64)(signed32)(*vB).w[i]; + (*vS).w[i] = altivec_signed_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1024:VX:av:vsububm %VD, %VA, %VB:Vector Subtract Unsigned Byte Modulo + int i; + for (i = 0; i < 16; i++) + (*vS).b[i] = (*vA).b[i] - (*vB).b[i]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1536:VX:av:vsububs %VD, %VA, %VB:Vector Subtract Unsigned Byte Saturate + int i, sat, tempsat; + signed16 temp; + sat = 0; + for (i = 0; i < 16; i++) { + temp = (signed16)(unsigned8)(*vA).b[i] - (signed16)(unsigned8)(*vB).b[i]; + (*vS).b[i] = altivec_unsigned_saturate_8(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1088:VX:av:vsubuhm %VD, %VA, %VB:Vector Subtract Unsigned Half Word Modulo + int i; + for (i = 0; i < 8; i++) + (*vS).h[i] = ((*vA).h[i] - (*vB).h[i]) & 0xffff; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1600:VX:av:vsubuhs %VD, %VA, %VB:Vector Subtract Unsigned Half Word Saturate + int i, sat, tempsat; + signed32 temp; + for (i = 0; i < 8; i++) { + temp = (signed32)(unsigned16)(*vA).h[i] - (signed32)(unsigned16)(*vB).h[i]; + (*vS).h[i] = altivec_unsigned_saturate_16(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1152:VX:av:vsubuwm %VD, %VA, %VB:Vector Subtract Unsigned Word Modulo + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = (*vA).w[i] - (*vB).w[i]; + PPC_INSN_VR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1664:VX:av:vsubuws %VD, %VA, %VB:Vector Subtract Unsigned Word Saturate + int i, sat, tempsat; + signed64 temp; + for (i = 0; i < 4; i++) { + temp = (signed64)(unsigned32)(*vA).w[i] - (signed64)(unsigned32)(*vB).w[i]; + (*vS).w[i] = altivec_unsigned_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Sum instructions, 6-166 ... 6-170 +# + +0.4,6.VS,11.VA,16.VB,21.1928:VX:av:vsumsws %VD, %VA, %VB:Vector Sum Across Signed Word Saturate + int i, sat; + signed64 temp; + temp = (signed64)(signed32)(*vB).w[3]; + for (i = 0; i < 4; i++) + temp += (signed64)(signed32)(*vA).w[i]; + (*vS).w[3] = altivec_signed_saturate_32(temp, &sat); + (*vS).w[0] = (*vS).w[1] = (*vS).w[2] = 0; + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1672:VX:av:vsum2sws %VD, %VA, %VB:Vector Sum Across Partial (1/2) Signed Word Saturate + int i, j, sat, tempsat; + signed64 temp; + for (j = 0; j < 4; j += 2) { + temp = (signed64)(signed32)(*vB).w[j+1]; + temp += (signed64)(signed32)(*vA).w[j] + (signed64)(signed32)(*vA).w[j+1]; + (*vS).w[j+1] = altivec_signed_saturate_32(temp, &tempsat); + sat |= tempsat; + } + (*vS).w[0] = (*vS).w[2] = 0; + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1800:VX:av:vsum4sbs %VD, %VA, %VB:Vector Sum Across Partial (1/4) Signed Byte Saturate + int i, j, sat, tempsat; + signed64 temp; + for (j = 0; j < 4; j++) { + temp = (signed64)(signed32)(*vB).w[j]; + for (i = 0; i < 4; i++) + temp += (signed64)(signed8)(*vA).b[i+(j*4)]; + (*vS).w[j] = altivec_signed_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1608:VX:av:vsum4shs %VD, %VA, %VB:Vector Sum Across Partial (1/4) Signed Half Word Saturate + int i, j, sat, tempsat; + signed64 temp; + for (j = 0; j < 4; j++) { + temp = (signed64)(signed32)(*vB).w[j]; + for (i = 0; i < 2; i++) + temp += (signed64)(signed16)(*vA).h[i+(j*2)]; + (*vS).w[j] = altivec_signed_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + +0.4,6.VS,11.VA,16.VB,21.1544:VX:av:vsum4ubs %VD, %VA, %VB:Vector Sum Across Partial (1/4) Unsigned Byte Saturate + int i, j, sat, tempsat; + signed64 utemp; + signed64 temp; + for (j = 0; j < 4; j++) { + utemp = (signed64)(unsigned32)(*vB).w[j]; + for (i = 0; i < 4; i++) + utemp += (signed64)(unsigned16)(*vA).b[i+(j*4)]; + temp = utemp; + (*vS).w[j] = altivec_unsigned_saturate_32(temp, &tempsat); + sat |= tempsat; + } + ALTIVEC_SET_SAT(sat); + PPC_INSN_VR_VSCR(VS_BITMASK, VA_BITMASK | VB_BITMASK); + + +# +# Vector Unpack instructions, 6-171 ... 6-176 +# + +0.4,6.VS,11.0,16.VB,21.846:VX:av:vupkhpx %VD, %VB:Vector Unpack High Pixel16 + int i; + unsigned16 h; + for (i = 0; i < 4; i++) { + h = (*vB).h[AV_HINDEX(i)]; + (*vS).w[i] = ((h & 0x8000) ? 0xff000000 : 0) + | ((h & 0x7c00) << 6) + | ((h & 0x03e0) << 3) + | ((h & 0x001f)); + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.526:VX:av:vupkhsb %VD, %VB:Vector Unpack High Signed Byte + int i; + for (i = 0; i < 8; i++) + (*vS).h[AV_HINDEX(i)] = (signed16)(signed8)(*vB).b[AV_BINDEX(i)]; + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.590:VX:av:vupkhsh %VD, %VB:Vector Unpack High Signed Half Word + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = (signed32)(signed16)(*vB).h[AV_HINDEX(i)]; + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.974:VX:av:vupklpx %VD, %VB:Vector Unpack Low Pixel16 + int i; + unsigned16 h; + for (i = 0; i < 4; i++) { + h = (*vB).h[AV_HINDEX(i + 4)]; + (*vS).w[i] = ((h & 0x8000) ? 0xff000000 : 0) + | ((h & 0x7c00) << 6) + | ((h & 0x03e0) << 3) + | ((h & 0x001f)); + } + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.654:VX:av:vupklsb %VD, %VB:Vector Unpack Low Signed Byte + int i; + for (i = 0; i < 8; i++) + (*vS).h[AV_HINDEX(i)] = (signed16)(signed8)(*vB).b[AV_BINDEX(i + 8)]; + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); + +0.4,6.VS,11.0,16.VB,21.718:VX:av:vupklsh %VD, %VB:Vector Unpack Low Signed Half Word + int i; + for (i = 0; i < 4; i++) + (*vS).w[i] = (signed32)(signed16)(*vB).h[AV_HINDEX(i + 4)]; + PPC_INSN_VR(VS_BITMASK, VB_BITMASK); diff --git a/sim/ppc/altivec_expression.h b/sim/ppc/altivec_expression.h new file mode 100644 index 0000000..6cf2e76 --- /dev/null +++ b/sim/ppc/altivec_expression.h @@ -0,0 +1,50 @@ +/* Altivec expression macros, for PSIM, the PowerPC simulator. + + Copyright 2003 Free Software Foundation, Inc. + + Contributed by Red Hat Inc; developed under contract from Motorola. + Written by matthew green <mrg@redhat.com>. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* AltiVec macro helpers. */ + +#define ALTIVEC_SET_CR6(vS, checkone) \ +do { \ + if (checkone && ((*vS).w[0] == 0xffffffff && \ + (*vS).w[1] == 0xffffffff && \ + (*vS).w[2] == 0xffffffff && \ + (*vS).w[3] == 0xffffffff)) \ + CR_SET(6, 1 << 3); \ + else if ((*vS).w[0] == 0 && \ + (*vS).w[1] == 0 && \ + (*vS).w[2] == 0 && \ + (*vS).w[3] == 0) \ + CR_SET(6, 1 << 1); \ + else \ + CR_SET(6, 0); \ +} while (0) + +#define VSCR_SAT 0x00000001 +#define VSCR_NJ 0x00010000 + +#define ALTIVEC_SET_SAT(sat) \ +do { \ + if (sat) \ + VSCR |= VSCR_SAT; \ +} while (0) diff --git a/sim/ppc/altivec_registers.h b/sim/ppc/altivec_registers.h new file mode 100644 index 0000000..923f5c4 --- /dev/null +++ b/sim/ppc/altivec_registers.h @@ -0,0 +1,63 @@ +/* Altivec registers, for PSIM, the PowerPC simulator. + + Copyright 2003 Free Software Foundation, Inc. + + Contributed by Red Hat Inc; developed under contract from Motorola. + Written by matthew green <mrg@redhat.com>. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Manage this as 4 32-bit entities, 8 16-bit entities or 16 8-bit + entities. */ +typedef union +{ + unsigned8 b[16]; + unsigned16 h[8]; + unsigned32 w[4]; +} vreg; + +typedef unsigned32 vscreg; + +struct altivec_regs { + /* AltiVec Registers */ + vreg vr[32]; + vscreg vscr; +}; + +/* AltiVec registers */ +#define VR(N) cpu_registers(processor)->altivec.vr[N] + +/* AltiVec vector status and control register */ +#define VSCR cpu_registers(processor)->altivec.vscr + +/* AltiVec endian helpers, wrong endian hosts vs targets need to be + sure to get the right bytes/halfs/words when the order matters. + Note that many AltiVec instructions do not depend on byte order and + work on N independant bits of data. This is only for the + instructions that actually move data around. */ + +#if (WITH_HOST_BYTE_ORDER == BIG_ENDIAN) +#define AV_BINDEX(x) ((x) & 15) +#define AV_HINDEX(x) ((x) & 7) +#else +static char endian_b2l_bindex[16] = { 3, 2, 1, 0, 7, 6, 5, 4, + 11, 10, 9, 8, 15, 14, 13, 12 }; +static char endian_b2l_hindex[16] = { 1, 0, 3, 2, 5, 4, 7, 6 }; +#define AV_BINDEX(x) endian_b2l_bindex[(x) & 15] +#define AV_HINDEX(x) endian_b2l_hindex[(x) & 7] +#endif diff --git a/sim/ppc/e500.igen b/sim/ppc/e500.igen new file mode 100644 index 0000000..f4ebfc7 --- /dev/null +++ b/sim/ppc/e500.igen @@ -0,0 +1,3348 @@ +# e500 core instructions, for PSIM, the PowerPC simulator. + +# Copyright 2003 Free Software Foundation, Inc. + +# Contributed by Red Hat Inc; developed under contract from Motorola. +# Written by matthew green <mrg@redhat.com>. + +# This file is part of GDB. + +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# +# e500 Core Complex Instructions +# + +:cache:e500::signed_word *:rAh:RA:(cpu_registers(processor)->e500.gprh + RA) +:cache:e500::signed_word *:rSh:RS:(cpu_registers(processor)->e500.gprh + RS) +:cache:e500::signed_word *:rBh:RB:(cpu_registers(processor)->e500.gprh + RB) + +# Flags for model.h +::model-macro::: + #define PPC_INSN_INT_SPR(OUT_MASK, IN_MASK, SPR) \ + do { \ + if (CURRENT_MODEL_ISSUE > 0) \ + ppc_insn_int_spr(MY_INDEX, cpu_model(processor), OUT_MASK, IN_MASK, SPR); \ + } while (0) + +# Schedule an instruction that takes 2 integer register and produces a special purpose output register plus an integer output register +void::model-function::ppc_insn_int_spr:itable_index index, model_data *model_ptr, const unsigned32 out_mask, const unsigned32 in_mask, const unsigned nSPR + const unsigned32 int_mask = out_mask | in_mask; + model_busy *busy_ptr; + + while ((model_ptr->int_busy & int_mask) != 0 || model_ptr->spr_busy[nSPR] != 0) { + if (WITH_TRACE && ppc_trace[trace_model]) + model_trace_busy_p(model_ptr, int_mask, 0, 0, nSPR); + + model_ptr->nr_stalls_data++; + model_new_cycle(model_ptr); + } + + busy_ptr = model_wait_for_unit(index, model_ptr, &model_ptr->timing[index]); + busy_ptr->int_busy |= out_mask; + model_ptr->int_busy |= out_mask; + busy_ptr->spr_busy = nSPR; + model_ptr->spr_busy[nSPR] = 1; + busy_ptr->nr_writebacks = (PPC_ONE_BIT_SET_P(out_mask)) ? 3 : 2; + TRACE(trace_model,("Making register %s busy.\n", spr_name(nSPR))); + +# +# SPE Modulo Fractional Multiplication handling support +# +:function:e500::unsigned64:ev_multiply16_smf:signed16 a, signed16 b, int *sat + signed32 a32 = a, b32 = b, rv32; + rv32 = a * b; + *sat = (rv32 & (3<<30)) == (3<<30); + return (signed64)rv32 << 1; + +:function:e500::unsigned64:ev_multiply32_smf:signed32 a, signed32 b, int *sat + signed64 rv64, a64 = a, b64 = b; + rv64 = a64 * b64; + *sat = (rv64 & ((signed64)3<<62)) == ((signed64)3<<62); + /* Loses top sign bit. */ + return rv64 << 1; +# +# SPE Saturation handling support +# +:function:e500::signed32:ev_multiply16_ssf:signed16 a, signed16 b, int *sat + signed32 rv32; + if (a == 0xffff8000 && b == 0xffff8000) + { + rv32 = 0x7fffffffL; + * sat = 1; + return rv32; + } + else + { + signed32 a32 = a, b32 = b; + + rv32 = a * b; + * sat = (rv32 & (3<<30)) == (3<<30); + return (signed64)rv32 << 1; + } + +:function:e500::signed64:ev_multiply32_ssf:signed32 a, signed32 b, int *sat + signed64 rv64; + if (a == 0x80000000 && b == 0x80000000) + { + rv64 = 0x7fffffffffffffffLL; + * sat = 1; + return rv64; + } + else + { + signed64 a64 = a, b64 = b; + rv64 = a64 * b64; + *sat = (rv64 & ((signed64)3<<62)) == ((signed64)3<<62); + /* Loses top sign bit. */ + return rv64 << 1; + } + +# +# SPE FP handling support +# + +:function:e500::void:ev_check_guard:sim_fpu *a, int fg, int fx, cpu *processor + unsigned64 guard; + guard = sim_fpu_guard(a, 0); + if (guard & 1) + EV_SET_SPEFSCR_BITS(fg); + if (guard & ~1) + EV_SET_SPEFSCR_BITS(fx); + +:function:e500::void:booke_sim_fpu_32to:sim_fpu *dst, unsigned32 packed + sim_fpu_32to (dst, packed); + + /* Set normally unused fields to allow booke arithmetic. */ + if (dst->class == sim_fpu_class_infinity) + { + dst->normal_exp = 128; + dst->fraction = ((unsigned64)1 << 60); + } + else if (dst->class == sim_fpu_class_qnan + || dst->class == sim_fpu_class_snan) + { + dst->normal_exp = 128; + /* This is set, but without the implicit bit, so we have to or + in the implicit bit. */ + dst->fraction |= ((unsigned64)1 << 60); + } + +:function:e500::int:booke_sim_fpu_add:sim_fpu *d, sim_fpu *a, sim_fpu *b, int inv, int over, int under, cpu *processor + int invalid_operand, overflow_result, underflow_result; + int dest_exp; + + invalid_operand = 0; + overflow_result = 0; + underflow_result = 0; + + /* Treat NaN, Inf, and denorm like normal numbers, and signal invalid + operand if it hasn't already been done. */ + if (EV_IS_INFDENORMNAN (a)) + { + a->class = sim_fpu_class_number; + + EV_SET_SPEFSCR_BITS (inv); + invalid_operand = 1; + } + if (EV_IS_INFDENORMNAN (b)) + { + b->class = sim_fpu_class_number; + + if (! invalid_operand) + { + EV_SET_SPEFSCR_BITS (inv); + invalid_operand = 1; + } + } + + sim_fpu_add (d, a, b); + + dest_exp = booke_sim_fpu_exp (d); + /* If this is a denorm, force to zero, and signal underflow if + we haven't already indicated invalid operand. */ + if (dest_exp <= -127) + { + int sign = d->sign; + + *d = sim_fpu_zero; + d->sign = sign; + if (! invalid_operand) + { + EV_SET_SPEFSCR_BITS (under); + underflow_result = 1; + } + } + /* If this is Inf/NaN, force to pmax/nmax, and signal overflow if + we haven't already indicated invalid operand. */ + else if (dest_exp >= 127) + { + int sign = d->sign; + + *d = sim_fpu_max32; + d->sign = sign; + if (! invalid_operand) + { + EV_SET_SPEFSCR_BITS (over); + overflow_result = 1; + } + } + /* Destination sign is sign of operand with larger magnitude, or + the sign of the first operand if operands have the same + magnitude. Thus if the result is zero, we force it to have + the sign of the first operand. */ + else if (d->fraction == 0) + d->sign = a->sign; + + return invalid_operand || overflow_result || underflow_result; + +:function:e500::unsigned32:ev_fs_add:unsigned32 aa, unsigned32 bb, int inv, int over, int under, int fg, int fx, cpu *processor + sim_fpu a, b, d; + unsigned32 w; + int exception; + + booke_sim_fpu_32to (&a, aa); + booke_sim_fpu_32to (&b, bb); + + exception = booke_sim_fpu_add (&d, &a, &b, inv, over, under, + processor); + + sim_fpu_to32 (&w, &d); + if (! exception) + ev_check_guard(&d, fg, fx, processor); + return w; + +:function:e500::unsigned32:ev_fs_sub:unsigned32 aa, unsigned32 bb, int inv, int over, int under, int fg, int fx, cpu *processor + sim_fpu a, b, d; + unsigned32 w; + int exception; + + booke_sim_fpu_32to (&a, aa); + booke_sim_fpu_32to (&b, bb); + + /* Invert sign of second operand, and add. */ + b.sign = ! b.sign; + exception = booke_sim_fpu_add (&d, &a, &b, inv, over, under, + processor); + + sim_fpu_to32 (&w, &d); + if (! exception) + ev_check_guard(&d, fg, fx, processor); + return w; + +# sim_fpu_exp leaves the normal_exp field undefined for Inf and NaN. +# The booke algorithms require exp values, so we fake them here. +# fixme: It also apparently does the same for zero, but should not. +:function:e500::unsigned32:booke_sim_fpu_exp:sim_fpu *x + int y = sim_fpu_is (x); + if (y == SIM_FPU_IS_PZERO || y == SIM_FPU_IS_NZERO) + return 0; + else if (y == SIM_FPU_IS_SNAN || y == SIM_FPU_IS_QNAN + || y == SIM_FPU_IS_NINF || y == SIM_FPU_IS_PINF) + return 128; + else + return sim_fpu_exp (x); + +:function:e500::unsigned32:ev_fs_mul:unsigned32 aa, unsigned32 bb, int inv, int over, int under, int fg, int fx, cpu *processor + sim_fpu a, b, d; + unsigned32 w; + int sa, sb, ea, eb, ei; + sim_fpu_32to (&a, aa); + sim_fpu_32to (&b, bb); + sa = sim_fpu_sign(&a); + sb = sim_fpu_sign(&b); + ea = booke_sim_fpu_exp(&a); + eb = booke_sim_fpu_exp(&b); + ei = ea + eb + 127; + if (sim_fpu_is_zero (&a) || sim_fpu_is_zero (&b)) + w = 0; + else if (sa == sb) { + if (ei >= 254) { + w = EV_PMAX; + EV_SET_SPEFSCR_BITS(over); + } else if (ei < 1) { + d = sim_fpu_zero; + sim_fpu_to32 (&w, &d); + w &= 0x7fffffff; /* Clear sign bit. */ + } else { + goto normal_mul; + } + } else { + if (ei >= 254) { + w = EV_NMAX; + EV_SET_SPEFSCR_BITS(over); + } else if (ei < 1) { + d = sim_fpu_zero; + sim_fpu_to32 (&w, &d); + w |= 0x80000000; /* Set sign bit. */ + } else { + normal_mul: + if (EV_IS_INFDENORMNAN(&a) || EV_IS_INFDENORMNAN(&b)) + EV_SET_SPEFSCR_BITS(inv); + sim_fpu_mul (&d, &a, &b); + sim_fpu_to32 (&w, &d); + } + } + return w; + +:function:e500::unsigned32:ev_fs_div:unsigned32 aa, unsigned32 bb, int inv, int over, int under, int dbz, int fg, int fx, cpu *processor + sim_fpu a, b, d; + unsigned32 w; + int sa, sb, ea, eb, ei; + + sim_fpu_32to (&a, aa); + sim_fpu_32to (&b, bb); + sa = sim_fpu_sign(&a); + sb = sim_fpu_sign(&b); + ea = booke_sim_fpu_exp(&a); + eb = booke_sim_fpu_exp(&b); + ei = ea - eb + 127; + + /* Special cases to handle behaviour of e500 hardware. + cf case 107543. */ + if (sim_fpu_is_nan (&a) || sim_fpu_is_nan (&b) + || sim_fpu_is_zero (&a) || sim_fpu_is_zero (&b)) + { + if (sim_fpu_is_snan (&a) || sim_fpu_is_snan (&b)) + { + if (bb == 0x3f800000) + w = EV_PMAX; + else if (aa == 0x7fc00001) + w = 0x3fbffffe; + else + goto normal_div; + } + else + goto normal_div; + } + else if (sim_fpu_is_infinity (&a) && sim_fpu_is_infinity (&b)) + { + if (sa == sb) + sim_fpu_32to (&d, 0x3f800000); + else + sim_fpu_32to (&d, 0xbf800000); + sim_fpu_to32 (&w, &d); + } + else if (sa == sb) { + if (ei > 254) { + w = EV_PMAX; + EV_SET_SPEFSCR_BITS(over); + } else if (ei <= 1) { + d = sim_fpu_zero; + sim_fpu_to32 (&w, &d); + w &= 0x7fffffff; /* Clear sign bit. */ + } else { + goto normal_div; + } + } else { + if (ei > 254) { + w = EV_NMAX; + EV_SET_SPEFSCR_BITS(over); + } else if (ei <= 1) { + d = sim_fpu_zero; + sim_fpu_to32 (&w, &d); + w |= 0x80000000; /* Set sign bit. */ + } else { + normal_div: + if (EV_IS_INFDENORMNAN(&a) || EV_IS_INFDENORMNAN(&b)) + EV_SET_SPEFSCR_BITS(inv); + if (sim_fpu_is_zero (&b)) + { + if (sim_fpu_is_zero (&a)) + EV_SET_SPEFSCR_BITS(dbz); + else + EV_SET_SPEFSCR_BITS(inv); + w = sa ? EV_NMAX : EV_PMAX; + } + else + { + sim_fpu_div (&d, &a, &b); + sim_fpu_to32 (&w, &d); + ev_check_guard(&d, fg, fx, processor); + } + } + } + return w; + + +# +# A.2.7 Integer SPE Simple Instructions +# + +0.4,6.RS,11.RA,16.RB,21.512:X:e500:evaddw %RS,%RA,%RB:Vector Add Word + unsigned32 w1, w2; + w1 = *rBh + *rAh; + w2 = *rB + *rA; + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evaddw: *rSh = %08x; *rS = %08x; w1 = %08x w2 = %08x\n", *rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.IMM,16.RB,21.514:X:e500:evaddiw %RS,%RB,%IMM:Vector Add Immediate Word + unsigned32 w1, w2; + w1 = *rBh + IMM; + w2 = *rB + IMM; + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evaddiw: *rSh = %08x; *rS = %08x; w1 = %08x w2 = %08x\n", *rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.516:X:e500:evsubfw %RS,%RA,%RB:Vector Subtract from Word + unsigned32 w1, w2; + w1 = *rBh - *rAh; + w2 = *rB - *rA; + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evsubfw: *rSh = %08x; *rS = %08x; w1 = %08x w2 = %08x\n", *rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.IMM,16.RB,21.518:X:e500:evsubifw %RS,%RB,%IMM:Vector Subtract Immediate from Word + unsigned32 w1, w2; + w1 = *rBh - IMM; + w2 = *rB - IMM; + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evsubifw: *rSh = %08x; *rS = %08x; IMM = %d\n", *rSh, *rS, IMM); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.520:X:e500:evabs %RS,%RA:Vector Absolute Value + signed32 w1, w2; + w1 = *rAh; + if (w1 < 0 && w1 != 0x80000000) + w1 = -w1; + w2 = *rA; + if (w2 < 0 && w2 != 0x80000000) + w2 = -w2; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.521:X:e500:evneg %RS,%RA:Vector Negate + signed32 w1, w2; + w1 = *rAh; + /* the negative most negative number is the most negative number */ + if (w1 != 0x80000000) + w1 = -w1; + w2 = *rA; + if (w2 != 0x80000000) + w2 = -w2; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.522:X:e500:evextsb %RS,%RA:Vector Extend Signed Byte + unsigned64 w1, w2; + w1 = *rAh & 0xff; + if (w1 & 0x80) + w1 |= 0xffffff00; + w2 = *rA & 0xff; + if (w2 & 0x80) + w2 |= 0xffffff00; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK , 0); + +0.4,6.RS,11.RA,16.0,21.523:X:e500:evextsb %RS,%RA:Vector Extend Signed Half Word + unsigned64 w1, w2; + w1 = *rAh & 0xffff; + if (w1 & 0x8000) + w1 |= 0xffff0000; + w2 = *rA & 0xffff; + if (w2 & 0x8000) + w2 |= 0xffff0000; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.529:X:e500:evand %RS,%RA,%RB:Vector AND + unsigned32 w1, w2; + w1 = *rBh & *rAh; + w2 = *rB & *rA; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.535:X:e500:evor %RS,%RA,%RB:Vector OR + unsigned32 w1, w2; + w1 = *rBh | *rAh; + w2 = *rB | *rA; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.534:X:e500:evxor %RS,%RA,%RB:Vector XOR + unsigned32 w1, w2; + w1 = *rBh ^ *rAh; + w2 = *rB ^ *rA; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.542:X:e500:evnand %RS,%RA,%RB:Vector NAND + unsigned32 w1, w2; + w1 = ~(*rBh & *rAh); + w2 = ~(*rB & *rA); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.536:X:e500:evnor %RS,%RA,%RB:Vector NOR + unsigned32 w1, w2; + w1 = ~(*rBh | *rAh); + w2 = ~(*rB | *rA); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.537:X:e500:eveqv %RS,%RA,%RB:Vector Equivalent + unsigned32 w1, w2; + w1 = (~*rBh) ^ *rAh; + w2 = (~*rB) ^ *rA; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.530:X:e500:evandc %RS,%RA,%RB:Vector AND with Compliment + unsigned32 w1, w2; + w1 = (~*rBh) & *rAh; + w2 = (~*rB) & *rA; + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evandc: *rSh = %08x; *rS = %08x\n", *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.539:X:e500:evorc %RS,%RA,%RB:Vector OR with Compliment + unsigned32 w1, w2; + w1 = (~*rBh) | *rAh; + w2 = (~*rB) | *rA; + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evorc: *rSh = %08x; *rS = %08x\n", *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.552:X:e500:evrlw %RS,%RA,%RB:Vector Rotate Left Word + unsigned32 nh, nl, w1, w2; + nh = *rBh & 0x1f; + nl = *rB & 0x1f; + w1 = ((unsigned32)*rAh) << nh | ((unsigned32)*rAh) >> (32 - nh); + w2 = ((unsigned32)*rA) << nl | ((unsigned32)*rA) >> (32 - nl); + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evrlw: nh %d nl %d *rSh = %08x; *rS = %08x\n", nh, nl, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.554:X:e500:evrlwi %RS,%RA,%UIMM:Vector Rotate Left Word Immediate + unsigned32 w1, w2, imm; + imm = (unsigned32)UIMM; + w1 = ((unsigned32)*rAh) << imm | ((unsigned32)*rAh) >> (32 - imm); + w2 = ((unsigned32)*rA) << imm | ((unsigned32)*rA) >> (32 - imm); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.548:X:e500:evslw %RS,%RA,%RB:Vector Shift Left Word + unsigned32 nh, nl, w1, w2; + nh = *rBh & 0x1f; + nl = *rB & 0x1f; + w1 = ((unsigned32)*rAh) << nh; + w2 = ((unsigned32)*rA) << nl; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.550:X:e500:evslwi %RS,%RA,%UIMM:Vector Shift Left Word Immediate + unsigned32 w1, w2, imm = UIMM; + w1 = ((unsigned32)*rAh) << imm; + w2 = ((unsigned32)*rA) << imm; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.545:X:e500:evsrws %RS,%RA,%RB:Vector Shift Right Word Signed + signed32 w1, w2; + unsigned32 nh, nl; + nh = *rBh & 0x1f; + nl = *rB & 0x1f; + w1 = ((signed32)*rAh) >> nh; + w2 = ((signed32)*rA) >> nl; + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evsrws: nh %d nl %d *rSh = %08x; *rS = %08x\n", nh, nl, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.544:X:e500:evsrwu %RS,%RA,%RB:Vector Shift Right Word Unsigned + unsigned32 w1, w2, nh, nl; + nh = *rBh & 0x1f; + nl = *rB & 0x1f; + w1 = ((unsigned32)*rAh) >> nh; + w2 = ((unsigned32)*rA) >> nl; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.547:X:e500:evsrwis %RS,%RA,%UIMM:Vector Shift Right Word Immediate Signed + signed32 w1, w2; + unsigned32 imm = UIMM; + w1 = ((signed32)*rAh) >> imm; + w2 = ((signed32)*rA) >> imm; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.546:X:e500:evsrwiu %RS,%RA,%UIMM:Vector Shift Right Word Immediate Unsigned + unsigned32 w1, w2, imm = UIMM; + w1 = ((unsigned32)*rAh) >> imm; + w2 = ((unsigned32)*rA) >> imm; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.525:X:e500:evcntlzw %RS,%RA:Vector Count Leading Zeros Word + unsigned32 w1, w2, mask, c1, c2; + for (c1 = 0, mask = 0x80000000, w1 = *rAh; + !(w1 & mask) && mask != 0; mask >>= 1) + c1++; + for (c2 = 0, mask = 0x80000000, w2 = *rA; + !(w2 & mask) && mask != 0; mask >>= 1) + c2++; + EV_SET_REG2(*rSh, *rS, c1, c2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.526:X:e500:evcntlsw %RS,%RA:Vector Count Leading Sign Bits Word + unsigned32 w1, w2, mask, sign_bit, c1, c2; + for (c1 = 0, mask = 0x80000000, w1 = *rAh, sign_bit = w1 & mask; + ((w1 & mask) == sign_bit) && mask != 0; + mask >>= 1, sign_bit >>= 1) + c1++; + for (c2 = 0, mask = 0x80000000, w2 = *rA, sign_bit = w2 & mask; + ((w2 & mask) == sign_bit) && mask != 0; + mask >>= 1, sign_bit >>= 1) + c2++; + EV_SET_REG2(*rSh, *rS, c1, c2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.524:X:e500:evrndw %RS,%RA:Vector Round Word + unsigned32 w1, w2; + w1 = ((unsigned32)*rAh + 0x8000) & 0xffff0000; + w2 = ((unsigned32)*rA + 0x8000) & 0xffff0000; + EV_SET_REG2(*rSh, *rS, w1, w2); + //printf("evrndw: *rSh = %08x; *rS = %08x\n", *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.556:X:e500:evmergehi %RS,%RA,%RB:Vector Merge Hi + unsigned32 w1, w2; + w1 = *rAh; + w2 = *rBh; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.557:X:e500:evmergelo %RS,%RA,%RB:Vector Merge Low + unsigned32 w1, w2; + w1 = *rA; + w2 = *rB; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.559:X:e500:evmergelohi %RS,%RA,%RB:Vector Merge Low Hi + unsigned32 w1, w2; + w1 = *rA; + w2 = *rBh; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.558:X:e500:evmergehilo %RS,%RA,%RB:Vector Merge Hi Low + unsigned32 w1, w2; + w1 = *rAh; + w2 = *rB; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.SIMM,16.0,21.553:X:e500:evsplati %RS,%SIMM:Vector Splat Immediate + unsigned32 w; + w = SIMM & 0x1f; + if (w & 0x10) + w |= 0xffffffe0; + EV_SET_REG2(*rSh, *rS, w, w); + PPC_INSN_INT(RS_BITMASK, 0, 0); + +0.4,6.RS,11.SIMM,16.0,21.555:X:e500:evsplatfi %RS,%SIMM:Vector Splat Fractional Immediate + unsigned32 w; + w = SIMM << 27; + EV_SET_REG2(*rSh, *rS, w, w); + PPC_INSN_INT(RS_BITMASK, 0, 0); + +0.4,6.BF,9.0,11.RA,16.RB,21.561:X:e500:evcmpgts %BF,%RA,%RB:Vector Compare Greater Than Signed + signed32 ah, al, bh, bl; + int w, ch, cl; + ah = *rAh; + al = *rA; + bh = *rBh; + bl = *rB; + if (ah > bh) + ch = 1; + else + ch = 0; + if (al > bl) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.BF,9.0,11.RA,16.RB,21.560:X:e500:evcmpgtu %BF,%RA,%RB:Vector Compare Greater Than Unsigned + unsigned32 ah, al, bh, bl; + int w, ch, cl; + ah = *rAh; + al = *rA; + bh = *rBh; + bl = *rB; + if (ah > bh) + ch = 1; + else + ch = 0; + if (al > bl) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.BF,9.0,11.RA,16.RB,21.563:X:e500:evcmplts %BF,%RA,%RB:Vector Compare Less Than Signed + signed32 ah, al, bh, bl; + int w, ch, cl; + ah = *rAh; + al = *rA; + bh = *rBh; + bl = *rB; + if (ah < bh) + ch = 1; + else + ch = 0; + if (al < bl) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.BF,9.0,11.RA,16.RB,21.562:X:e500:evcmpltu %BF,%RA,%RB:Vector Compare Less Than Unsigned + unsigned32 ah, al, bh, bl; + int w, ch, cl; + ah = *rAh; + al = *rA; + bh = *rBh; + bl = *rB; + if (ah < bh) + ch = 1; + else + ch = 0; + if (al < bl) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.BF,9.0,11.RA,16.RB,21.564:X:e500:evcmpeq %BF,%RA,%RB:Vector Compare Equal + unsigned32 ah, al, bh, bl; + int w, ch, cl; + ah = *rAh; + al = *rA; + bh = *rBh; + bl = *rB; + if (ah == bh) + ch = 1; + else + ch = 0; + if (al == bl) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + //printf("evcmpeq: ch %d cl %d BF %d, CR is now %08x\n", ch, cl, BF, CR); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.RS,11.RA,16.RB,21.79,29.CRFS:X:e500:evsel %RS,%RA,%RB,%CRFS:Vector Select + unsigned32 w1, w2; + int cr; + cr = CR_FIELD(CRFS); + if (cr & 8) + w1 = *rAh; + else + w1 = *rBh; + if (cr & 4) + w2 = *rA; + else + w2 = *rB; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.527:X:e500:brinc %RS,%RA,%RB:Bit Reversed Increment + unsigned32 w1, w2, a, d, mask; + mask = (*rB) & 0xffff; + a = (*rA) & 0xffff; + d = EV_BITREVERSE16(1 + EV_BITREVERSE16(a | ~mask)); + *rS = ((*rA) & 0xffff0000) | (d & 0xffff); + //printf("brinc: *rS = %08x\n", *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +# +# A.2.8 Integer SPE Complex Instructions +# + +0.4,6.RS,11.RA,16.RB,21.1031:EVX:e500:evmhossf %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Saturate Fractional + signed16 al, ah, bl, bh; + signed32 tl, th; + int movl, movh; + + al = (signed16) EV_LOHALF (*rA); + ah = (signed16) EV_LOHALF (*rAh); + bl = (signed16) EV_LOHALF (*rB); + bh = (signed16) EV_LOHALF (*rBh); + tl = ev_multiply16_ssf (al, bl, &movl); + th = ev_multiply16_ssf (ah, bh, &movh); + EV_SET_REG2 (*rSh, *rS, EV_SATURATE (movh, 0x7fffffff, th), + EV_SATURATE (movl, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV (movl, movh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1063:EVX:e500:evmhossfa %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Saturate Fractional Accumulate + signed16 al, ah, bl, bh; + signed32 tl, th; + int movl, movh; + + al = (signed16) EV_LOHALF (*rA); + ah = (signed16) EV_LOHALF (*rAh); + bl = (signed16) EV_LOHALF (*rB); + bh = (signed16) EV_LOHALF (*rBh); + tl = ev_multiply16_ssf (al, bl, &movl); + th = ev_multiply16_ssf (ah, bh, &movh); + EV_SET_REG2 (*rSh, *rS, EV_SATURATE (movh, 0x7fffffff, th), + EV_SATURATE (movl, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV (movl, movh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1039:EVX:e500:evmhosmf %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Modulo Fractional + signed16 al, ah, bl, bh; + signed32 tl, th; + int dummy; + + al = (signed16) EV_LOHALF (*rA); + ah = (signed16) EV_LOHALF (*rAh); + bl = (signed16) EV_LOHALF (*rB); + bh = (signed16) EV_LOHALF (*rBh); + tl = ev_multiply16_smf (al, bl, & dummy); + th = ev_multiply16_smf (ah, bh, & dummy); + EV_SET_REG2 (*rSh, *rS, th, tl); + PPC_INSN_INT (RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1071:EVX:e500:evmhosmfa %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Modulo Fractional Accumulate + signed32 al, ah, bl, bh; + signed32 tl, th; + int dummy; + + al = (signed16) EV_LOHALF (*rA); + ah = (signed16) EV_LOHALF (*rAh); + bl = (signed16) EV_LOHALF (*rB); + bh = (signed16) EV_LOHALF (*rBh); + tl = ev_multiply16_smf (al, bl, & dummy); + th = ev_multiply16_smf (ah, bh, & dummy); + EV_SET_REG2_ACC (*rSh, *rS, th, tl); + PPC_INSN_INT (RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1037:EVX:e500:evmhosmi %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Modulo Integer + signed32 al, ah, bl, bh, tl, th; + al = (signed32)(signed16)EV_LOHALF(*rA); + ah = (signed32)(signed16)EV_LOHALF(*rAh); + bl = (signed32)(signed16)EV_LOHALF(*rB); + bh = (signed32)(signed16)EV_LOHALF(*rBh); + tl = al * bl; + th = ah * bh; + EV_SET_REG2(*rSh, *rS, th, tl); + //printf("evmhosmi: *rSh = %08x; *rS = %08x\n", *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1069:EVX:e500:evmhosmia %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Modulo Integer Accumulate + signed32 al, ah, bl, bh, tl, th; + al = (signed32)(signed16)EV_LOHALF(*rA); + ah = (signed32)(signed16)EV_LOHALF(*rAh); + bl = (signed32)(signed16)EV_LOHALF(*rB); + bh = (signed32)(signed16)EV_LOHALF(*rBh); + tl = al * bl; + th = ah * bh; + EV_SET_REG2_ACC(*rSh, *rS, th, tl); + //printf("evmhosmia: ACC = %08x; *rSh = %08x; *rS = %08x\n", ACC, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1036:EVX:e500:evmhoumi %RS,%RA,%RB:Vector Multiply Half Words Odd Unsigned Modulo Integer + unsigned32 al, ah, bl, bh, tl, th; + al = (unsigned32)(unsigned16)EV_LOHALF(*rA); + ah = (unsigned32)(unsigned16)EV_LOHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_LOHALF(*rB); + bh = (unsigned32)(unsigned16)EV_LOHALF(*rBh); + tl = al * bl; + th = ah * bh; + EV_SET_REG2(*rSh, *rS, th, tl); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1068:EVX:e500:evmhoumia %RS,%RA,%RB:Vector Multiply Half Words Odd Unsigned Modulo Integer Accumulate + unsigned32 al, ah, bl, bh, tl, th; + al = (unsigned32)(unsigned16)EV_LOHALF(*rA); + ah = (unsigned32)(unsigned16)EV_LOHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_LOHALF(*rB); + bh = (unsigned32)(unsigned16)EV_LOHALF(*rBh); + tl = al * bl; + th = ah * bh; + EV_SET_REG2_ACC(*rSh, *rS, th, tl); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1027:EVX:e500:evmhessf %RS,%RA,%RB:Vector Multiply Half Words Even Signed Saturate Fractional + signed16 al, ah, bl, bh; + signed32 tl, th; + int movl, movh; + + al = (signed16) EV_HIHALF (*rA); + ah = (signed16) EV_HIHALF (*rAh); + bl = (signed16) EV_HIHALF (*rB); + bh = (signed16) EV_HIHALF (*rBh); + tl = ev_multiply16_ssf (al, bl, &movl); + th = ev_multiply16_ssf (ah, bh, &movh); + EV_SET_REG2 (*rSh, *rS, EV_SATURATE (movh, 0x7fffffff, th), + EV_SATURATE (movl, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV (movl, movh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1059:EVX:e500:evmhessfa %RS,%RA,%RB:Vector Multiply Half Words Even Signed Saturate Fractional Accumulate + signed16 al, ah, bl, bh; + signed32 tl, th; + int movl, movh; + + al = (signed16) EV_HIHALF (*rA); + ah = (signed16) EV_HIHALF (*rAh); + bl = (signed16) EV_HIHALF (*rB); + bh = (signed16) EV_HIHALF (*rBh); + tl = ev_multiply16_ssf (al, bl, &movl); + th = ev_multiply16_ssf (ah, bh, &movh); + EV_SET_REG2_ACC (*rSh, *rS, EV_SATURATE (movh, 0x7fffffff, th), + EV_SATURATE (movl, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV (movl, movh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1035:EVX:e500:evmhesmf %RS,%RA,%RB:Vector Multiply Half Words Even Signed Modulo Fractional + signed16 al, ah, bl, bh; + signed64 tl, th; + int movl, movh; + + al = (signed16) EV_HIHALF (*rA); + ah = (signed16) EV_HIHALF (*rAh); + bl = (signed16) EV_HIHALF (*rB); + bh = (signed16) EV_HIHALF (*rBh); + tl = ev_multiply16_smf (al, bl, &movl); + th = ev_multiply16_smf (ah, bh, &movh); + EV_SET_REG2 (*rSh, *rS, th, tl); + EV_SET_SPEFSCR_OV (movl, movh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1067:EVX:e500:evmhesmfa %RS,%RA,%RB:Vector Multiply Half Words Even Signed Modulo Fractional Accumulate + signed16 al, ah, bl, bh; + signed32 tl, th; + int dummy; + + al = (signed16) EV_HIHALF (*rA); + ah = (signed16) EV_HIHALF (*rAh); + bl = (signed16) EV_HIHALF (*rB); + bh = (signed16) EV_HIHALF (*rBh); + tl = ev_multiply16_smf (al, bl, & dummy); + th = ev_multiply16_smf (ah, bh, & dummy); + EV_SET_REG2_ACC (*rSh, *rS, th, tl); + PPC_INSN_INT (RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1033:EVX:e500:evmhesmi %RS,%RA,%RB:Vector Multiply Half Words Even Signed Modulo Integer + signed16 al, ah, bl, bh; + signed32 tl, th; + + al = (signed16) EV_HIHALF (*rA); + ah = (signed16) EV_HIHALF (*rAh); + bl = (signed16) EV_HIHALF (*rB); + bh = (signed16) EV_HIHALF (*rBh); + tl = al * bl; + th = ah * bh; + EV_SET_REG2 (*rSh, *rS, th, tl); + PPC_INSN_INT (RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1065:EVX:e500:evmhesmia %RS,%RA,%RB:Vector Multiply Half Words Even Signed Modulo Integer Accumulate + signed32 al, ah, bl, bh, tl, th; + al = (signed32)(signed16)EV_HIHALF(*rA); + ah = (signed32)(signed16)EV_HIHALF(*rAh); + bl = (signed32)(signed16)EV_HIHALF(*rB); + bh = (signed32)(signed16)EV_HIHALF(*rBh); + tl = al * bl; + th = ah * bh; + EV_SET_REG2_ACC(*rSh, *rS, th, tl); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1032:EVX:e500:evmheumi %RS,%RA,%RB:Vector Multiply Half Words Even Unsigned Modulo Integer + unsigned32 al, ah, bl, bh, tl, th; + al = (unsigned32)(unsigned16)EV_HIHALF(*rA); + ah = (unsigned32)(unsigned16)EV_HIHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_HIHALF(*rB); + bh = (unsigned32)(unsigned16)EV_HIHALF(*rBh); + tl = al * bl; + th = ah * bh; + EV_SET_REG2(*rSh, *rS, th, tl); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1064:EVX:e500:evmheumia %RS,%RA,%RB:Vector Multiply Half Words Even Unsigned Modulo Integer Accumulate + unsigned32 al, ah, bl, bh, tl, th; + al = (unsigned32)(unsigned16)EV_HIHALF(*rA); + ah = (unsigned32)(unsigned16)EV_HIHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_HIHALF(*rB); + bh = (unsigned32)(unsigned16)EV_HIHALF(*rBh); + tl = al * bl; + th = ah * bh; + EV_SET_REG2_ACC(*rSh, *rS, th, tl); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1287:EVX:e500:evmhossfaaw %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Saturate Fractional and Accumulate into Words + signed16 al, ah, bl, bh; + signed32 t1, t2; + signed64 tl, th; + int movl, movh, ovl, ovh; + + al = (signed16) EV_LOHALF (*rA); + ah = (signed16) EV_LOHALF (*rAh); + bl = (signed16) EV_LOHALF (*rB); + bh = (signed16) EV_LOHALF (*rBh); + t1 = ev_multiply16_ssf (ah, bh, &movh); + t2 = ev_multiply16_ssf (al, bl, &movl); + th = EV_ACCHIGH + EV_SATURATE (movh, 0x7fffffff, t1); + tl = EV_ACCLOW + EV_SATURATE (movl, 0x7fffffff, t2); + ovh = EV_SAT_P_S32 (th); + ovl = EV_SAT_P_S32 (tl); + EV_SET_REG2_ACC (*rSh, *rS, EV_SATURATE_ACC (ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC (ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV (movl | ovl, movh | ovh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1285:EVX:e500:evmhossiaaw %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Saturate Integer and Accumulate into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + int ovl, ovh; + al = (signed32)(signed16)EV_LOHALF(*rA); + ah = (signed32)(signed16)EV_LOHALF(*rAh); + bl = (signed32)(signed16)EV_LOHALF(*rB); + bh = (signed32)(signed16)EV_LOHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH + t1; + tl = EV_ACCLOW + t2; + ovh = EV_SAT_P_S32(th); + ovl = EV_SAT_P_S32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC(ovl, tl, 0x80000000, 0x7fffffff, tl)); + //printf("evmhossiaaw: ovh %d ovl %d al %d ah %d bl %d bh %d t1 %qd t2 %qd tl %qd th %qd\n", ovh, ovl, al, ah, bl, bh, t1, t2, tl, th); + //printf("evmhossiaaw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1295:EVX:e500:evmhosmfaaw %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Modulo Fractional and Accumulate into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + al = (signed32)(signed16)EV_LOHALF(*rA); + ah = (signed32)(signed16)EV_LOHALF(*rAh); + bl = (signed32)(signed16)EV_LOHALF(*rB); + bh = (signed32)(signed16)EV_LOHALF(*rBh); + t1 = ((signed64)ah * bh) << 1; + t2 = ((signed64)al * bl) << 1; + th = EV_ACCHIGH + (t1 & 0xffffffff); + tl = EV_ACCLOW + (t2 & 0xffffffff); + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1293:EVX:e500:evmhosmiaaw %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Modulo Integer and Accumulate into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + al = (signed32)(signed16)EV_LOHALF(*rA); + ah = (signed32)(signed16)EV_LOHALF(*rAh); + bl = (signed32)(signed16)EV_LOHALF(*rB); + bh = (signed32)(signed16)EV_LOHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH + t1; + tl = EV_ACCLOW + t2; + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + //printf("evmhosmiaaw: al %d ah %d bl %d bh %d t1 %qd t2 %qd tl %qd th %qd\n", al, ah, bl, bh, t1, t2, tl, th); + //printf("evmhosmiaaw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1284:EVX:e500:evmhousiaaw %RS,%RA,%RB:Vector Multiply Half Words Odd Unsigned Saturate Integer and Accumulate into Words + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + signed64 tl, th; + int ovl, ovh; + al = (unsigned32)(unsigned16)EV_LOHALF(*rA); + ah = (unsigned32)(unsigned16)EV_LOHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_LOHALF(*rB); + bh = (unsigned32)(unsigned16)EV_LOHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = (signed64)EV_ACCHIGH + (signed64)t1; + tl = (signed64)EV_ACCLOW + (signed64)t2; + ovh = EV_SAT_P_U32(th); + ovl = EV_SAT_P_U32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0, 0xffffffff, th), + EV_SATURATE_ACC(ovl, tl, 0, 0xffffffff, tl)); + //printf("evmhousiaaw: al %u ah %u bl %u bh %u t1 %qu t2 %qu tl %qu th %qu\n", al, ah, bl, bh, t1, t2, tl, th); + //printf("evmhousiaaw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1292:EVX:e500:evmhoumiaaw %RS,%RA,%RB:Vector Multiply Half Words Odd Unsigned Modulo Integer and Accumulate into Words + unsigned32 al, ah, bl, bh; + unsigned32 t1, t2; + signed64 tl, th; + al = (unsigned32)(unsigned16)EV_LOHALF(*rA); + ah = (unsigned32)(unsigned16)EV_LOHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_LOHALF(*rB); + bh = (unsigned32)(unsigned16)EV_LOHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH + t1; + tl = EV_ACCLOW + t2; + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + //printf("evmhoumiaaw: al %u ah %u bl %u bh %u t1 %qu t2 %qu tl %qu th %qu\n", al, ah, bl, bh, t1, t2, tl, th); + //printf("evmhoumiaaw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1283:EVX:e500:evmhessfaaw %RS,%RA,%RB:Vector Multiply Half Words Even Signed Saturate Fractional and Accumulate into Words + signed16 al, ah, bl, bh; + signed32 t1, t2; + signed64 tl, th; + int movl, movh, ovl, ovh; + + al = (signed16) EV_HIHALF (*rA); + ah = (signed16) EV_HIHALF (*rAh); + bl = (signed16) EV_HIHALF (*rB); + bh = (signed16) EV_HIHALF (*rBh); + t1 = ev_multiply16_ssf (ah, bh, &movh); + t2 = ev_multiply16_ssf (al, bl, &movl); + th = EV_ACCHIGH + EV_SATURATE (movh, 0x7fffffff, t1); + tl = EV_ACCLOW + EV_SATURATE (movl, 0x7fffffff, t2); + ovh = EV_SAT_P_S32 (th); + ovl = EV_SAT_P_S32 (tl); + EV_SET_REG2_ACC (*rSh, *rS, EV_SATURATE_ACC (ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC (ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV (movl | ovl, movh | ovh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1281:EVX:e500:evmhessiaaw %RS,%RA,%RB:Vector Multiply Half Words Even Signed Saturate Integer and Accumulate into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + int ovl, ovh; + al = (signed32)(signed16)EV_HIHALF(*rA); + ah = (signed32)(signed16)EV_HIHALF(*rAh); + bl = (signed32)(signed16)EV_HIHALF(*rB); + bh = (signed32)(signed16)EV_HIHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH + t1; + tl = EV_ACCLOW + t2; + ovh = EV_SAT_P_S32(th); + ovl = EV_SAT_P_S32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC(ovl, tl, 0x80000000, 0x7fffffff, tl)); + //printf("evmhessiaaw: ovh %d ovl %d al %d ah %d bl %d bh %d t1 %qd t2 %qd tl %qd th %qd\n", ovh, ovl, al, ah, bl, bh, t1, t2, tl, th); + //printf("evmhessiaaw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1291:EVX:e500:evmhesmfaaw %RS,%RA,%RB:Vector Multiply Half Words Even Signed Modulo Fractional and Accumulate into Words + signed16 al, ah, bl, bh; + signed32 t1, t2, th, tl; + int dummy; + + al = (signed16)EV_HIHALF(*rA); + ah = (signed16)EV_HIHALF(*rAh); + bl = (signed16)EV_HIHALF(*rB); + bh = (signed16)EV_HIHALF(*rBh); + t1 = ev_multiply16_smf (ah, bh, &dummy); + t2 = ev_multiply16_smf (al, bl, &dummy); + th = EV_ACCHIGH + t1; + tl = EV_ACCLOW + t2; + EV_SET_REG2_ACC(*rSh, *rS, th, tl); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1289:EVX:e500:evmhesmiaaw %RS,%RA,%RB:Vector Multiply Half Words Even Signed Modulo Integer and Accumulate into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + al = (signed32)(signed16)EV_HIHALF(*rA); + ah = (signed32)(signed16)EV_HIHALF(*rAh); + bl = (signed32)(signed16)EV_HIHALF(*rB); + bh = (signed32)(signed16)EV_HIHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH + t1; + tl = EV_ACCLOW + t2; + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1280:EVX:e500:evmheusiaaw %RS,%RA,%RB:Vector Multiply Half Words Even Unsigned Saturate Integer and Accumulate into Words + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + signed64 tl, th; + int ovl, ovh; + al = (unsigned32)(unsigned16)EV_HIHALF(*rA); + ah = (unsigned32)(unsigned16)EV_HIHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_HIHALF(*rB); + bh = (unsigned32)(unsigned16)EV_HIHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = (signed64)EV_ACCHIGH + (signed64)t1; + tl = (signed64)EV_ACCLOW + (signed64)t2; + ovh = EV_SAT_P_U32(th); + ovl = EV_SAT_P_U32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0, 0xffffffff, th), + EV_SATURATE_ACC(ovl, tl, 0, 0xffffffff, tl)); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1288:EVX:e500:evmheumiaaw %RS,%RA,%RB:Vector Multiply Half Words Even Unsigned Modulo Integer and Accumulate into Words + unsigned32 al, ah, bl, bh; + unsigned32 t1, t2; + unsigned64 tl, th; + al = (unsigned32)(unsigned16)EV_HIHALF(*rA); + ah = (unsigned32)(unsigned16)EV_HIHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_HIHALF(*rB); + bh = (unsigned32)(unsigned16)EV_HIHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH + t1; + tl = EV_ACCLOW + t2; + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1415:EVX:e500:evmhossfanw %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Saturate Fractional and Accumulate Negative into Words + signed16 al, ah, bl, bh; + signed32 t1, t2; + signed64 tl, th; + int movl, movh, ovl, ovh; + + al = (signed16) EV_LOHALF (*rA); + ah = (signed16) EV_LOHALF (*rAh); + bl = (signed16) EV_LOHALF (*rB); + bh = (signed16) EV_LOHALF (*rBh); + t1 = ev_multiply16_ssf (ah, bh, &movh); + t2 = ev_multiply16_ssf (al, bl, &movl); + th = EV_ACCHIGH - EV_SATURATE (movh, 0x7fffffff, t1); + tl = EV_ACCLOW - EV_SATURATE (movl, 0x7fffffff, t2); + ovh = EV_SAT_P_S32 (th); + ovl = EV_SAT_P_S32 (tl); + EV_SET_REG2_ACC (*rSh, *rS, EV_SATURATE_ACC (ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC (ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV (movl | ovl, movh | ovh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1413:EVX:e500:evmhossianw %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Saturate Integer and Accumulate Negative into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + int ovl, ovh; + al = (signed32)(signed16)EV_LOHALF(*rA); + ah = (signed32)(signed16)EV_LOHALF(*rAh); + bl = (signed32)(signed16)EV_LOHALF(*rB); + bh = (signed32)(signed16)EV_LOHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH - t1; + tl = EV_ACCLOW - t2; + ovh = EV_SAT_P_S32(th); + ovl = EV_SAT_P_S32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC(ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV(ovl, ovh); + //printf("evmhossianw: ACC = %08x; *rSh = %08x; *rS = %08x\n", ACC, *rSh, *rS); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1423:EVX:e500:evmhosmfanw %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Modulo Fractional and Accumulate Negative into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + al = (signed32)(signed16)EV_LOHALF(*rA); + ah = (signed32)(signed16)EV_LOHALF(*rAh); + bl = (signed32)(signed16)EV_LOHALF(*rB); + bh = (signed32)(signed16)EV_LOHALF(*rBh); + t1 = ((signed64)ah * bh) << 1; + t2 = ((signed64)al * bl) << 1; + th = EV_ACCHIGH - (t1 & 0xffffffff); + tl = EV_ACCLOW - (t2 & 0xffffffff); + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1421:EVX:e500:evmhosmianw %RS,%RA,%RB:Vector Multiply Half Words Odd Signed Modulo Integer and Accumulate Negative into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + al = (signed32)(signed16)EV_LOHALF(*rA); + ah = (signed32)(signed16)EV_LOHALF(*rAh); + bl = (signed32)(signed16)EV_LOHALF(*rB); + bh = (signed32)(signed16)EV_LOHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH - t1; + tl = EV_ACCLOW - t2; + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1412:EVX:e500:evmhousianw %RS,%RA,%RB:Vector Multiply Half Words Odd Unsigned Saturate Integer and Accumulate Negative into Words + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + signed64 tl, th; + int ovl, ovh; + al = (unsigned32)(unsigned16)EV_LOHALF(*rA); + ah = (unsigned32)(unsigned16)EV_LOHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_LOHALF(*rB); + bh = (unsigned32)(unsigned16)EV_LOHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = (signed64)EV_ACCHIGH - (signed64)t1; + tl = (signed64)EV_ACCLOW - (signed64)t2; + ovl = EV_SAT_P_U32(tl); + ovh = EV_SAT_P_U32(th); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0, 0xffffffff, th), + EV_SATURATE_ACC(ovl, tl, 0, 0xffffffff, tl)); + //printf("evmhousianw: ovh %d ovl %d al %d ah %d bl %d bh %d t1 %qd t2 %qd tl %qd th %qd\n", ovh, ovl, al, ah, bl, bh, t1, t2, tl, th); + //printf("evmoussianw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1420:EVX:e500:evmhoumianw %RS,%RA,%RB:Vector Multiply Half Words Odd Unsigned Modulo Integer and Accumulate Negative into Words + unsigned32 al, ah, bl, bh; + unsigned32 t1, t2; + unsigned64 tl, th; + al = (unsigned32)(unsigned16)EV_LOHALF(*rA); + ah = (unsigned32)(unsigned16)EV_LOHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_LOHALF(*rB); + bh = (unsigned32)(unsigned16)EV_LOHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH - t1; + tl = EV_ACCLOW - t2; + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1411:EVX:e500:evmhessfanw %RS,%RA,%RB:Vector Multiply Half Words Even Signed Saturate Fractional and Accumulate Negative into Words + signed16 al, ah, bl, bh; + signed32 t1, t2; + signed64 tl, th; + int movl, movh, ovl, ovh; + + al = (signed16) EV_HIHALF (*rA); + ah = (signed16) EV_HIHALF (*rAh); + bl = (signed16) EV_HIHALF (*rB); + bh = (signed16) EV_HIHALF (*rBh); + t1 = ev_multiply16_ssf (ah, bh, &movh); + t2 = ev_multiply16_ssf (al, bl, &movl); + th = EV_ACCHIGH - EV_SATURATE (movh, 0x7fffffff, t1); + tl = EV_ACCLOW - EV_SATURATE (movl, 0x7fffffff, t2); + ovh = EV_SAT_P_S32 (th); + ovl = EV_SAT_P_S32 (tl); + EV_SET_REG2_ACC (*rSh, *rS, EV_SATURATE_ACC (ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC (ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV (movl | ovl, movh | ovh); + PPC_INSN_INT_SPR (RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1409:EVX:e500:evmhessianw %RS,%RA,%RB:Vector Multiply Half Words Even Signed Saturate Integer and Accumulate Negative into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + int ovl, ovh; + al = (signed32)(signed16)EV_HIHALF(*rA); + ah = (signed32)(signed16)EV_HIHALF(*rAh); + bl = (signed32)(signed16)EV_HIHALF(*rB); + bh = (signed32)(signed16)EV_HIHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH - t1; + tl = EV_ACCLOW - t2; + ovh = EV_SAT_P_S32(th); + ovl = EV_SAT_P_S32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC(ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1419:EVX:e500:evmhesmfanw %RS,%RA,%RB:Vector Multiply Half Words Even Signed Modulo Fractional and Accumulate Negative into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + al = (unsigned32)(unsigned16)EV_HIHALF(*rA); + ah = (unsigned32)(unsigned16)EV_HIHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_HIHALF(*rB); + bh = (unsigned32)(unsigned16)EV_HIHALF(*rBh); + t1 = ((signed64)ah * bh) << 1; + t2 = ((signed64)al * bl) << 1; + th = EV_ACCHIGH - (t1 & 0xffffffff); + tl = EV_ACCLOW - (t2 & 0xffffffff); + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1417:EVX:e500:evmhesmianw %RS,%RA,%RB:Vector Multiply Half Words Even Signed Modulo Integer and Accumulate Negative into Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + al = (signed32)(signed16)EV_HIHALF(*rA); + ah = (signed32)(signed16)EV_HIHALF(*rAh); + bl = (signed32)(signed16)EV_HIHALF(*rB); + bh = (signed32)(signed16)EV_HIHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH - t1; + tl = EV_ACCLOW - t2; + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + //printf("evmhesmianw: al %d ah %d bl %d bh %d t1 %qd t2 %qd tl %qd th %qd\n", al, ah, bl, bh, t1, t2, tl, th); + //printf("evmhesmianw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1408:EVX:e500:evmheusianw %RS,%RA,%RB:Vector Multiply Half Words Even Unsigned Saturate Integer and Accumulate Negative into Words + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + signed64 tl, th; + int ovl, ovh; + al = (unsigned32)(unsigned16)EV_HIHALF(*rA); + ah = (unsigned32)(unsigned16)EV_HIHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_HIHALF(*rB); + bh = (unsigned32)(unsigned16)EV_HIHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = (signed64)EV_ACCHIGH - (signed64)t1; + tl = (signed64)EV_ACCLOW - (signed64)t2; + ovl = EV_SAT_P_U32(tl); + ovh = EV_SAT_P_U32(th); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0, 0xffffffff, th), + EV_SATURATE_ACC(ovl, tl, 0, 0xffffffff, tl)); + //printf("evmheusianw: ovh %d ovl %d al %u ah %u bl %u bh %u t1 %qu t2 %qu tl %qd th %qd\n", ovh, ovl, al, ah, bl, bh, t1, t2, tl, th); + //printf("evmheusianw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1416:EVX:e500:evmheumianw %RS,%RA,%RB:Vector Multiply Half Words Even Unsigned Modulo Integer and Accumulate Negative into Words + unsigned32 al, ah, bl, bh; + unsigned32 t1, t2; + unsigned64 tl, th; + al = (unsigned32)(unsigned16)EV_HIHALF(*rA); + ah = (unsigned32)(unsigned16)EV_HIHALF(*rAh); + bl = (unsigned32)(unsigned16)EV_HIHALF(*rB); + bh = (unsigned32)(unsigned16)EV_HIHALF(*rBh); + t1 = ah * bh; + t2 = al * bl; + th = EV_ACCHIGH - t1; + tl = EV_ACCLOW - t2; + EV_SET_REG2_ACC(*rSh, *rS, th & 0xffffffff, tl & 0xffffffff); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1327:EVX:e500:evmhogsmfaa %RS,%RA,%RB:Multiply Half Words Odd Guarded Signed Modulo Fractional and Accumulate + signed32 a, b; + signed64 t1, t2; + a = (signed32)(signed16)EV_LOHALF(*rA); + b = (signed32)(signed16)EV_LOHALF(*rB); + t1 = EV_MUL16_SSF(a, b); + if (t1 & ((unsigned64)1 << 32)) + t1 |= 0xfffffffe00000000; + t2 = ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1325:EVX:e500:evmhogsmiaa %RS,%RA,%RB:Multiply Half Words Odd Guarded Signed Modulo Integer and Accumulate + signed32 a, b; + signed64 t1, t2; + a = (signed32)(signed16)EV_LOHALF(*rA); + b = (signed32)(signed16)EV_LOHALF(*rB); + t1 = (signed64)a * (signed64)b; + t2 = (signed64)ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + //printf("evmhogsmiaa: a %d b %d t1 %qd t2 %qd\n", a, b, t1, t2); + //printf("evmhogsmiaa: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1324:EVX:e500:evmhogumiaa %RS,%RA,%RB:Multiply Half Words Odd Guarded Unsigned Modulo Integer and Accumulate + unsigned32 a, b; + unsigned64 t1, t2; + a = (unsigned32)(unsigned16)EV_LOHALF(*rA); + b = (unsigned32)(unsigned16)EV_LOHALF(*rB); + t1 = a * b; + t2 = ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1323:EVX:e500:evmhegsmfaa %RS,%RA,%RB:Multiply Half Words Even Guarded Signed Modulo Fractional and Accumulate + signed32 a, b; + signed64 t1, t2; + a = (signed32)(signed16)EV_HIHALF(*rA); + b = (signed32)(signed16)EV_HIHALF(*rB); + t1 = EV_MUL16_SSF(a, b); + if (t1 & ((unsigned64)1 << 32)) + t1 |= 0xfffffffe00000000; + t2 = ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1321:EVX:e500:evmhegsmiaa %RS,%RA,%RB:Multiply Half Words Even Guarded Signed Modulo Integer and Accumulate + signed32 a, b; + signed64 t1, t2; + a = (signed32)(signed16)EV_HIHALF(*rA); + b = (signed32)(signed16)EV_HIHALF(*rB); + t1 = (signed64)(a * b); + t2 = ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1320:EVX:e500:evmhegumiaa %RS,%RA,%RB:Multiply Half Words Even Guarded Unsigned Modulo Integer and Accumulate + unsigned32 a, b; + unsigned64 t1, t2; + a = (unsigned32)(unsigned16)EV_HIHALF(*rA); + b = (unsigned32)(unsigned16)EV_HIHALF(*rB); + t1 = a * b; + t2 = ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1455:EVX:e500:evmhogsmfan %RS,%RA,%RB:Multiply Half Words Odd Guarded Signed Modulo Fractional and Accumulate Negative + signed32 a, b; + signed64 t1, t2; + a = (signed32)(signed16)EV_LOHALF(*rA); + b = (signed32)(signed16)EV_LOHALF(*rB); + t1 = EV_MUL16_SSF(a, b); + if (t1 & ((unsigned64)1 << 32)) + t1 |= 0xfffffffe00000000; + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1453:EVX:e500:evmhogsmian %RS,%RA,%RB:Multiply Half Words Odd Guarded Signed Modulo Integer and Accumulate Negative + signed32 a, b; + signed64 t1, t2; + a = (signed32)(signed16)EV_LOHALF(*rA); + b = (signed32)(signed16)EV_LOHALF(*rB); + t1 = (signed64)a * (signed64)b; + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + //printf("evmhogsmian: a %d b %d t1 %qd t2 %qd\n", a, b, t1, t2); + //printf("evmhogsmian: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1452:EVX:e500:evmhogumian %RS,%RA,%RB:Multiply Half Words Odd Guarded Unsigned Modulo Integer and Accumulate Negative + unsigned32 a, b; + unsigned64 t1, t2; + a = (unsigned32)(unsigned16)EV_LOHALF(*rA); + b = (unsigned32)(unsigned16)EV_LOHALF(*rB); + t1 = (unsigned64)a * (unsigned64)b; + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1451:EVX:e500:evmhegsmfan %RS,%RA,%RB:Multiply Half Words Even Guarded Signed Modulo Fractional and Accumulate Negative + signed32 a, b; + signed64 t1, t2; + a = (signed32)(signed16)EV_HIHALF(*rA); + b = (signed32)(signed16)EV_HIHALF(*rB); + t1 = EV_MUL16_SSF(a, b); + if (t1 & ((unsigned64)1 << 32)) + t1 |= 0xfffffffe00000000; + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1449:EVX:e500:evmhegsmian %RS,%RA,%RB:Multiply Half Words Even Guarded Signed Modulo Integer and Accumulate Negative + signed32 a, b; + signed64 t1, t2; + a = (signed32)(signed16)EV_HIHALF(*rA); + b = (signed32)(signed16)EV_HIHALF(*rB); + t1 = (signed64)a * (signed64)b; + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1448:EVX:e500:evmhegumian %RS,%RA,%RB:Multiply Half Words Even Guarded Unsigned Modulo Integer and Accumulate Negative + unsigned32 a, b; + unsigned64 t1, t2; + a = (unsigned32)(unsigned16)EV_HIHALF(*rA); + b = (unsigned32)(unsigned16)EV_HIHALF(*rB); + t1 = (unsigned64)a * (unsigned64)b; + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1095:EVX:e500:evmwhssf %RS,%RA,%RB:Vector Multiply Word High Signed Saturate Fractional + signed32 al, ah, bl, bh; + signed64 t1, t2; + int movl, movh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = ev_multiply32_ssf(al, bl, &movl); + t2 = ev_multiply32_ssf(ah, bh, &movh); + EV_SET_REG2(*rSh, *rS, EV_SATURATE(movh, 0x7fffffff, t2 >> 32), + EV_SATURATE(movl, 0x7fffffff, t1 >> 32)); + EV_SET_SPEFSCR_OV(movl, movh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1127:EVX:e500:evmwhssfa %RS,%RA,%RB:Vector Multiply Word High Signed Saturate Fractional and Accumulate + signed32 al, ah, bl, bh; + signed64 t1, t2; + int movl, movh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = ev_multiply32_ssf(al, bl, &movl); + t2 = ev_multiply32_ssf(ah, bh, &movh); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE(movh, 0x7fffffff, t2 >> 32), + EV_SATURATE(movl, 0x7fffffff, t1 >> 32)); + EV_SET_SPEFSCR_OV(movl, movh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1103:EVX:e500:evmwhsmf %RS,%RA,%RB:Vector Multiply Word High Signed Modulo Fractional + signed32 al, ah, bl, bh; + signed64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = EV_MUL32_SSF(al, bl); + t2 = EV_MUL32_SSF(ah, bh); + EV_SET_REG2(*rSh, *rS, t2 >> 32, t1 >> 32); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1135:EVX:e500:evmwhsmfa %RS,%RA,%RB:Vector Multiply Word High Signed Modulo Fractional and Accumulate + signed32 al, ah, bl, bh; + signed64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = EV_MUL32_SSF(al, bl); + t2 = EV_MUL32_SSF(ah, bh); + EV_SET_REG2_ACC(*rSh, *rS, t2 >> 32, t1 >> 32); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1101:EVX:e500:evmwhsmi %RS,%RA,%RB:Vector Multiply Word High Signed Modulo Integer + signed32 al, ah, bl, bh; + signed64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (signed64)al * (signed64)bl; + t2 = (signed64)ah * (signed64)bh; + EV_SET_REG2(*rSh, *rS, t2 >> 32, t1 >> 32); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1133:EVX:e500:evmwhsmia %RS,%RA,%RB:Vector Multiply Word High Signed Modulo Integer and Accumulate + signed32 al, ah, bl, bh; + signed64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (signed64)al * (signed64)bl; + t2 = (signed64)ah * (signed64)bh; + EV_SET_REG2_ACC(*rSh, *rS, t2 >> 32, t1 >> 32); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1100:EVX:e500:evmwhumi %RS,%RA,%RB:Vector Multiply Word High Unsigned Modulo Integer + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (unsigned64)al * (unsigned64)bl; + t2 = (unsigned64)ah * (unsigned64)bh; + EV_SET_REG2(*rSh, *rS, t2 >> 32, t1 >> 32); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1132:EVX:e500:evmwhumia %RS,%RA,%RB:Vector Multiply Word High Unsigned Modulo Integer and Accumulate + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (unsigned64)al * (unsigned64)bl; + t2 = (unsigned64)ah * (unsigned64)bh; + EV_SET_REG2_ACC(*rSh, *rS, t2 >> 32, t1 >> 32); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1091:EVX:e500:evmwlssf %RS,%RA,%RB:Vector Multiply Word Low Signed Saturate Fractional + signed32 al, ah, bl, bh; + signed64 t1, t2; + int movl, movh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = ev_multiply32_ssf(al, bl, &movl); + t2 = ev_multiply32_ssf(ah, bh, &movh); + EV_SET_REG2(*rSh, *rS, EV_SATURATE(movh, 0xffffffff, t2), + EV_SATURATE(movl, 0xffffffff, t1)); + EV_SET_SPEFSCR_OV(movl, movh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1123:EVX:e500:evmwlssfa %RS,%RA,%RB:Vector Multiply Word Low Signed Saturate Fractional and Accumulate + signed32 al, ah, bl, bh; + signed64 t1, t2; + int movl, movh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = ev_multiply32_ssf(al, bl, &movl); + t2 = ev_multiply32_ssf(ah, bh, &movh); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE(movh, 0xffffffff, t2), + EV_SATURATE(movl, 0xffffffff, t1)); + EV_SET_SPEFSCR_OV(movl, movh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1099:EVX:e500:evmwlsmf %RS,%RA,%RB:Vector Multiply Word Low Signed Modulo Fractional + signed32 al, ah, bl, bh; + signed64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = EV_MUL32_SSF(al, bl); + t2 = EV_MUL32_SSF(ah, bh); + EV_SET_REG2(*rSh, *rS, t2, t1); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1131:EVX:e500:evmwlsmfa %RS,%RA,%RB:Vector Multiply Word Low Signed Modulo Fractional and Accumulate + signed32 al, ah, bl, bh; + signed64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = EV_MUL32_SSF(al, bl); + t2 = EV_MUL32_SSF(ah, bh); + EV_SET_REG2_ACC(*rSh, *rS, t2, t1); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1096:EVX:e500:evmwlumi %RS,%RA,%RB:Vector Multiply Word Low Unsigned Modulo Integer + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (unsigned64)al * (unsigned64)bl; + t2 = (unsigned64)ah * (unsigned64)bh; + EV_SET_REG2(*rSh, *rS, t2, t1); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1128:EVX:e500:evmwlumia %RS,%RA,%RB:Vector Multiply Word Low Unsigned Modulo Integer and Accumulate + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (unsigned64)al * (unsigned64)bl; + t2 = (unsigned64)ah * (unsigned64)bh; + EV_SET_REG2_ACC(*rSh, *rS, t2, t1); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1347:EVX:e500:evmwlssfaaw %RS,%RA,%RB:Vector Multiply Word Low Signed Saturate Fractional and Accumulate in Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + int movl, movh, ovl, ovh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = ev_multiply32_ssf(ah, bh, &movh); + t2 = ev_multiply32_ssf(al, bl, &movl); + th = EV_ACCHIGH + EV_SATURATE(movh, 0xffffffff, t1); + tl = EV_ACCLOW + EV_SATURATE(movl, 0xffffffff, t2); + ovh = EV_SAT_P_S32(th); + ovl = EV_SAT_P_S32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC(ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV(movl | ovl, movh | ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1345:EVX:e500:evmwlssiaaw %RS,%RA,%RB:Vector Multiply Word Low Signed Saturate Integer and Accumulate in Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + int ovl, ovh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (signed64)ah * (signed64)bh; + t2 = (signed64)al * (signed64)bl; + th = EV_ACCHIGH + (t1 & 0xffffffff); + tl = EV_ACCLOW + (t2 & 0xffffffff); + ovh = EV_SAT_P_S32(th); + ovl = EV_SAT_P_S32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC(ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1355:EVX:e500:evmwlsmfaaw %RS,%RA,%RB:Vector Multiply Word Low Signed Modulo Fractional and Accumulate in Words + signed32 al, ah, bl, bh; + signed64 t1, t2; + int mov; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = ev_multiply32_smf(ah, bh, &mov); + t2 = ev_multiply32_smf(al, bl, &mov); + EV_SET_REG2_ACC(*rSh, *rS, EV_ACCHIGH + (t1 & 0xffffffff), + EV_ACCLOW + (t2 & 0xffffffff)); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1353:EVX:e500:evmwlsmiaaw %RS,%RA,%RB:Vector Multiply Word Low Signed Modulo Integer and Accumulate in Words + signed32 al, ah, bl, bh; + signed64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (signed64)ah * (signed64)bh; + t2 = (signed64)al * (signed64)bl; + EV_SET_REG2_ACC(*rSh, *rS, EV_ACCHIGH + (t1 & 0xffffffff), + EV_ACCLOW + (t2 & 0xffffffff)); + //printf("evmwlsmiaaw: al %d ah %d bl %d bh %d t1 %qd t2 %qd\n", al, ah, bl, bh, t1, t2); + //printf("evmwlsmiaaw: *rSh = %08x; *rS = %08x\n", *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1344:EVX:e500:evmwlusiaaw %RS,%RA,%RB:Vector Multiply Word Low Unsigned Saturate Integer and Accumulate in Words + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2, tl, th; + int ovl, ovh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (unsigned64)ah * (unsigned64)bh; + t2 = (unsigned64)al * (unsigned64)bl; + th = EV_ACCHIGH + (t1 & 0xffffffff); + tl = EV_ACCLOW + (t2 & 0xffffffff); + ovh = (th >> 32); + ovl = (tl >> 32); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE(ovh, 0xffffffff, th), + EV_SATURATE(ovl, 0xffffffff, tl)); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1352:EVX:e500:evmwlumiaaw %RS,%RA,%RB:Vector Multiply Word Low Unsigned Modulo Integer and Accumulate in Words + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (unsigned64)ah * (unsigned64)bh; + t2 = (unsigned64)al * (unsigned64)bl; + EV_SET_REG2_ACC(*rSh, *rS, EV_ACCHIGH + (t1 & 0xffffffff), + EV_ACCLOW + (t2 & 0xffffffff)); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1475:EVX:e500:evmwlssfanw %RS,%RA,%RB:Vector Multiply Word Low Signed Saturate Fractional and Accumulate Negative in Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + int movl, movh, ovl, ovh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = ev_multiply32_ssf(ah, bh, &movh); + t2 = ev_multiply32_ssf(al, bl, &movl); + th = EV_ACCHIGH - EV_SATURATE(movh, 0xffffffff, t1); + tl = EV_ACCLOW - EV_SATURATE(movl, 0xffffffff, t2); + ovh = EV_SAT_P_S32(th); + ovl = EV_SAT_P_S32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC(ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV(movl | ovl, movh | ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1473:EVX:e500:evmwlssianw %RS,%RA,%RB:Vector Multiply Word Low Signed Saturate Integer and Accumulate Negative in Words + signed32 al, ah, bl, bh; + signed64 t1, t2, tl, th; + int ovl, ovh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (signed64)ah * (signed64)bh; + t2 = (signed64)al * (signed64)bl; + th = EV_ACCHIGH - (t1 & 0xffffffff); + tl = EV_ACCLOW - (t2 & 0xffffffff); + ovh = EV_SAT_P_S32(th); + ovl = EV_SAT_P_S32(tl); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, th, 0x80000000, 0x7fffffff, th), + EV_SATURATE_ACC(ovl, tl, 0x80000000, 0x7fffffff, tl)); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1483:EVX:e500:evmwlsmfanw %RS,%RA,%RB:Vector Multiply Word Low Signed Modulo Fractional and Accumulate Negative in Words + signed32 al, ah, bl, bh; + signed64 t1, t2; + int mov; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = ev_multiply32_smf(ah, bh, &mov); + t2 = ev_multiply32_smf(al, bl, &mov); + EV_SET_REG2_ACC(*rSh, *rS, EV_ACCHIGH - (t1 & 0xffffffff), + EV_ACCLOW - (t2 & 0xffffffff)); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1481:EVX:e500:evmwlsmianw %RS,%RA,%RB:Vector Multiply Word Low Signed Modulo Integer and Accumulate Negative in Words + signed32 al, ah, bl, bh; + signed64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (signed64)ah * (signed64)bh; + t2 = (signed64)al * (signed64)bl; + EV_SET_REG2_ACC(*rSh, *rS, EV_ACCHIGH - (t1 & 0xffffffff), + EV_ACCLOW - (t2 & 0xffffffff)); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1472:EVX:e500:evmwlusianw %RS,%RA,%RB:Vector Multiply Word Low Unsigned Saturate Integer and Accumulate Negative in Words + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2, tl, th; + int ovl, ovh; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (unsigned64)ah * (unsigned64)bh; + t2 = (unsigned64)al * (unsigned64)bl; + th = EV_ACCHIGH - (t1 & 0xffffffff); + tl = EV_ACCLOW - (t2 & 0xffffffff); + ovh = (th >> 32); + ovl = (tl >> 32); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE(ovh, 0xffffffff, th), + EV_SATURATE(ovl, 0xffffffff, tl)); + //printf("evmwlusianw: ovl %d ovh %d al %d ah %d bl %d bh %d t1 %qd t2 %qd th %qd tl %qd\n", ovl, ovh, al, ah, al, bh, t1, t2, th, tl); + //printf("evmwlusianw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1480:EVX:e500:evmwlumianw %RS,%RA,%RB:Vector Multiply Word Low Unsigned Modulo Integer and Accumulate Negative in Words + unsigned32 al, ah, bl, bh; + unsigned64 t1, t2; + al = *rA; + ah = *rAh; + bl = *rB; + bh = *rBh; + t1 = (unsigned64)ah * (unsigned64)bh; + t2 = (unsigned64)al * (unsigned64)bl; + EV_SET_REG2_ACC(*rSh, *rS, EV_ACCHIGH - (t1 & 0xffffffff), + EV_ACCLOW - (t2 & 0xffffffff)); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1107:EVX:e500:evmwssf %RS,%RA,%RB:Vector Multiply Word Signed Saturate Fractional + signed32 a, b; + signed64 t; + int movl; + a = *rA; + b = *rB; + t = ev_multiply32_ssf(a, b, &movl); + EV_SET_REG1(*rSh, *rS, EV_SATURATE(movl, 0x7fffffffffffffff, t)); + EV_SET_SPEFSCR_OV(movl, 0); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1139:EVX:e500:evmwssfa %RS,%RA,%RB:Vector Multiply Word Signed Saturate Fractional and Accumulate + signed32 a, b; + signed64 t; + int movl; + a = *rA; + b = *rB; + t = ev_multiply32_ssf(a, b, &movl); + EV_SET_REG1_ACC(*rSh, *rS, EV_SATURATE(movl, 0x7fffffffffffffff, t)); + EV_SET_SPEFSCR_OV(movl, 0); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1115:EVX:e500:evmwsmf %RS,%RA,%RB:Vector Multiply Word Signed Modulo Fractional + signed32 a, b; + signed64 t; + int movl; + a = *rA; + b = *rB; + t = ev_multiply32_smf(a, b, &movl); + EV_SET_REG1(*rSh, *rS, t); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1147:EVX:e500:evmwsmfa %RS,%RA,%RB:Vector Multiply Word Signed Modulo Fractional and Accumulate + signed32 a, b; + signed64 t; + int movl; + a = *rA; + b = *rB; + t = ev_multiply32_smf(a, b, &movl); + EV_SET_REG1_ACC(*rSh, *rS, t); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1113:EVX:e500:evmwsmi %RS,%RA,%RB:Vector Multiply Word Signed Modulo Integer + signed32 a, b; + signed64 t; + int movl; + a = *rA; + b = *rB; + t = (signed64)a * (signed64)b; + EV_SET_REG1(*rSh, *rS, t); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1145:EVX:e500:evmwsmia %RS,%RA,%RB:Vector Multiply Word Signed Modulo Integer and Accumulate + signed32 a, b; + signed64 t; + int movl; + a = *rA; + b = *rB; + t = (signed64)a * (signed64)b; + EV_SET_REG1_ACC(*rSh, *rS, t); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1112:EVX:e500:evmwumi %RS,%RA,%RB:Vector Multiply Word Unigned Modulo Integer + unsigned32 a, b; + unsigned64 t; + int movl; + a = *rA; + b = *rB; + t = (signed64)a * (signed64)b; + EV_SET_REG1(*rSh, *rS, t); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1144:EVX:e500:evmwumia %RS,%RA,%RB:Vector Multiply Word Unigned Modulo Integer and Accumulate + unsigned32 a, b; + unsigned64 t; + int movl; + a = *rA; + b = *rB; + t = (signed64)a * (signed64)b; + EV_SET_REG1_ACC(*rSh, *rS, t); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1363:EVX:e500:evmwssfaa %RS,%RA,%RB:Vector Multiply Word Signed Saturate Fractional Add and Accumulate + signed64 t1, t2; + signed32 a, b; + int movl; + a = *rA; + b = *rB; + t1 = ev_multiply32_ssf(a, b, &movl); + t2 = ACC + EV_SATURATE(movl, 0x7fffffffffffffff, t1); + EV_SET_REG1_ACC(*rSh, *rS, t2); + EV_SET_SPEFSCR_OV(movl, 0); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1371:EVX:e500:evmwsmfaa %RS,%RA,%RB:Vector Multiply Word Signed Modulo Fractional Add and Accumulate + signed64 t1, t2; + signed32 a, b; + int movl; + a = *rA; + b = *rB; + t1 = ev_multiply32_smf(a, b, &movl); + t2 = ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1369:EVX:e500:evmwsmiaa %RS,%RA,%RB:Vector Multiply Word Signed Modulo Integer And and Accumulate + signed64 t1, t2; + signed32 a, b; + a = *rA; + b = *rB; + t1 = (signed64)a * (signed64)b; + t2 = ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1368:EVX:e500:evmwumiaa %RS,%RA,%RB:Vector Multiply Word Unsigned Modulo Integer Add and Accumulate + unsigned64 t1, t2; + unsigned32 a, b; + a = *rA; + b = *rB; + t1 = (unsigned64)a * (unsigned64)b; + t2 = ACC + t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.RB,21.1491:EVX:e500:evmwssfan %RS,%RA,%RB:Vector Multiply Word Signed Saturate Fractional and Accumulate Negative + signed64 t1, t2; + signed32 a, b; + int movl; + a = *rA; + b = *rB; + t1 = ev_multiply32_ssf(a, b, &movl); + t2 = ACC - EV_SATURATE(movl, 0x7fffffffffffffff, t1); + EV_SET_REG1_ACC(*rSh, *rS, t2); + EV_SET_SPEFSCR_OV(movl, 0); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.1499:EVX:e500:evmwsmfan %RS,%RA,%RB:Vector Multiply Word Signed Modulo Fractional and Accumulate Negative + signed64 t1, t2; + signed32 a, b; + int movl; + a = *rA; + b = *rB; + t1 = ev_multiply32_smf(a, b, &movl); + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1497:EVX:e500:evmwsmian %RS,%RA,%RB:Vector Multiply Word Signed Modulo Integer and Accumulate Negative + signed64 t1, t2; + signed32 a, b; + a = *rA; + b = *rB; + t1 = (signed64)a * (signed64)b; + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1496:EVX:e500:evmwumian %RS,%RA,%RB:Vector Multiply Word Unsigned Modulo Integer and Accumulate Negative + unsigned64 t1, t2; + unsigned32 a, b; + a = *rA; + b = *rB; + t1 = (unsigned64)a * (unsigned64)b; + t2 = ACC - t1; + EV_SET_REG1_ACC(*rSh, *rS, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.0,21.1217:EVX:e500:evaddssiaaw %RS,%RA:Vector Add Signed Saturate Integer to Accumulator Word + signed64 t1, t2; + signed32 al, ah; + int ovl, ovh; + al = *rA; + ah = *rAh; + t1 = (signed64)EV_ACCHIGH + (signed64)ah; + t2 = (signed64)EV_ACCLOW + (signed64)al; + ovh = EV_SAT_P_S32(t1); + ovl = EV_SAT_P_S32(t2); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, t1 & ((unsigned64)1 << 32), 0x80000000, 0x7fffffff, t1), + EV_SATURATE_ACC(ovl, t2 & ((unsigned64)1 << 32), 0x80000000, 0x7fffffff, t2)); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.0,21.1225:EVX:e500:evaddsmiaaw %RS,%RA:Vector Add Signed Modulo Integer to Accumulator Word + signed64 t1, t2; + signed32 al, ah; + al = *rA; + ah = *rAh; + t1 = (signed64)EV_ACCHIGH + (signed64)ah; + t2 = (signed64)EV_ACCLOW + (signed64)al; + EV_SET_REG2_ACC(*rSh, *rS, t1, t2); + //printf("evaddsmiaaw: al %d ah %d t1 %qd t2 %qd\n", al, ah, t1, t2); + //printf("evaddsmiaaw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.1216:EVX:e500:evaddusiaaw %RS,%RA:Vector Add Unsigned Saturate Integer to Accumulator Word + signed64 t1, t2; + unsigned32 al, ah; + int ovl, ovh; + al = *rA; + ah = *rAh; + t1 = (signed64)EV_ACCHIGH + (signed64)ah; + t2 = (signed64)EV_ACCLOW + (signed64)al; + ovh = EV_SAT_P_U32(t1); + ovl = EV_SAT_P_U32(t2); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE(ovh, 0xffffffff, t1), + EV_SATURATE(ovl, 0xffffffff, t2)); + //printf("evaddusiaaw: ovl %d ovh %d al %d ah %d t1 %qd t2 %qd\n", ovl, ovh, al, ah, t1, t2); + //printf("evaddusiaaw: ACC = %08x.%08x; *rSh = %08x; *rS = %08x\n", (int)(ACC >> 32), (int)ACC, *rSh, *rS); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.0,21.1224:EVX:e500:evaddumiaaw %RS,%RA:Vector Add Unsigned Modulo Integer to Accumulator Word + unsigned64 t1, t2; + unsigned32 al, ah; + al = *rA; + ah = *rAh; + t1 = (unsigned64)EV_ACCHIGH + (unsigned64)ah; + t2 = EV_ACCLOW + al; + EV_SET_REG2_ACC(*rSh, *rS, t1, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + + +0.4,6.RS,11.RA,16.0,21.1219:EVX:e500:evsubfssiaaw %RS,%RA:Vector Subtract Signed Saturate Integer to Accumulator Word + signed64 t1, t2; + signed32 al, ah; + int ovl, ovh; + al = *rA; + ah = *rAh; + t1 = (signed64)EV_ACCHIGH - (signed64)ah; + t2 = (signed64)EV_ACCLOW - (signed64)al; + ovh = EV_SAT_P_S32(t1); + ovl = EV_SAT_P_S32(t2); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE_ACC(ovh, t1, 0x80000000, 0x7fffffff, t1), + EV_SATURATE_ACC(ovl, t2, 0x80000000, 0x7fffffff, t2)); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.0,21.1227:EVX:e500:evsubfsmiaaw %RS,%RA:Vector Subtract Signed Modulo Integer to Accumulator Word + signed64 t1, t2; + signed32 al, ah; + al = *rA; + ah = *rAh; + t1 = (signed64)EV_ACCHIGH - (signed64)ah; + t2 = (signed64)EV_ACCLOW - (signed64)al; + EV_SET_REG2_ACC(*rSh, *rS, t1, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.1218:EVX:e500:evsubfusiaaw %RS,%RA:Vector Subtract Unsigned Saturate Integer to Accumulator Word + signed64 t1, t2; + unsigned32 al, ah; + int ovl, ovh; + + al = *rA; + ah = *rAh; + t1 = (signed64)EV_ACCHIGH - (signed64)ah; + t2 = (signed64)EV_ACCLOW - (signed64)al; + ovh = EV_SAT_P_U32(t1); + ovl = EV_SAT_P_U32(t2); + EV_SET_REG2_ACC(*rSh, *rS, EV_SATURATE(ovh, 0, t1), + EV_SATURATE(ovl, 0, t2)); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.0,21.1226:EVX:e500:evsubfumiaaw %RS,%RA:Vector Subtract Unsigned Modulo Integer to Accumulator Word + unsigned64 t1, t2; + unsigned32 al, ah; + al = *rA; + ah = *rAh; + t1 = (unsigned64)EV_ACCHIGH - (unsigned64)ah; + t2 = (unsigned64)EV_ACCLOW - (unsigned64)al; + EV_SET_REG2_ACC(*rSh, *rS, t1, t2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + + +0.4,6.RS,11.RA,16.0,21.1220:EVX:e500:evmra %RS,%RA:Initialize Accumulator + EV_SET_REG2_ACC(*rSh, *rS, *rAh, *rA); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.1222:EVX:e500:evdivws %RS,%RA,%RB:Vector Divide Word Signed + signed32 dividendh, dividendl, divisorh, divisorl; + signed32 w1, w2; + int ovh, ovl; + dividendh = *rAh; + dividendl = *rA; + divisorh = *rBh; + divisorl = *rB; + if (dividendh < 0 && divisorh == 0) { + w1 = 0x80000000; + ovh = 1; + } else if (dividendh > 0 && divisorh == 0) { + w1 = 0x7fffffff; + ovh = 1; + } else if (dividendh == 0x80000000 && divisorh == -1) { + w1 = 0x7fffffff; + ovh = 1; + } else { + w1 = dividendh / divisorh; + ovh = 0; + } + if (dividendl < 0 && divisorl == 0) { + w2 = 0x80000000; + ovl = 1; + } else if (dividendl > 0 && divisorl == 0) { + w2 = 0x7fffffff; + ovl = 1; + } else if (dividendl == 0x80000000 && divisorl == -1) { + w2 = 0x7fffffff; + ovl = 1; + } else { + w2 = dividendl / divisorl; + ovl = 0; + } + EV_SET_REG2(*rSh, *rS, w1, w2); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK, spr_spefscr); + + +0.4,6.RS,11.RA,16.RB,21.1223:EVX:e500:evdivwu %RS,%RA,%RB:Vector Divide Word Unsigned + unsigned32 dividendh, dividendl, divisorh, divisorl; + unsigned32 w1, w2; + int ovh, ovl; + dividendh = *rAh; + dividendl = *rA; + divisorh = *rBh; + divisorl = *rB; + if (divisorh == 0) { + w1 = 0xffffffff; + ovh = 1; + } else { + w1 = dividendh / divisorh; + ovh = 0; + } + if (divisorl == 0) { + w2 = 0xffffffff; + ovl = 1; + } else { + w2 = dividendl / divisorl; + ovl = 0; + } + EV_SET_REG2(*rSh, *rS, w1, w2); + EV_SET_SPEFSCR_OV(ovl, ovh); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK, spr_spefscr); + + +# +# A.2.9 Floating Point SPE Instructions +# + +0.4,6.RS,11.RA,16.0,21.644:EVX:e500:evfsabs %RS,%RA:Vector Floating-Point Absolute Value + unsigned32 w1, w2; + w1 = *rAh & 0x7fffffff; + w2 = *rA & 0x7fffffff; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.645:EVX:e500:evfsnabs %RS,%RA:Vector Floating-Point Negative Absolute Value + unsigned32 w1, w2; + w1 = *rAh | 0x80000000; + w2 = *rA | 0x80000000; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.646:EVX:e500:evfsneg %RS,%RA:Vector Floating-Point Negate + unsigned32 w1, w2; + w1 = *rAh; + w2 = *rA; + w1 = (w1 & 0x7fffffff) | ((~w1) & 0x80000000); + w2 = (w2 & 0x7fffffff) | ((~w2) & 0x80000000); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.640:EVX:e500:evfsadd %RS,%RA,%RB:Vector Floating-Point Add + unsigned32 w1, w2; + w1 = ev_fs_add (*rAh, *rBh, spefscr_finvh, spefscr_fovfh, spefscr_funfh, spefscr_fgh, spefscr_fxh, processor); + w2 = ev_fs_add (*rA, *rB, spefscr_finv, spefscr_fovf, spefscr_funf, spefscr_fgh, spefscr_fxh, processor); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.641:EVX:e500:evfssub %RS,%RA,%RB:Vector Floating-Point Subtract + unsigned32 w1, w2; + w1 = ev_fs_sub (*rAh, *rBh, spefscr_finvh, spefscr_fovfh, spefscr_funfh, spefscr_fgh, spefscr_fxh, processor); + w2 = ev_fs_sub (*rA, *rB, spefscr_finv, spefscr_fovf, spefscr_funf, spefscr_fgh, spefscr_fxh, processor); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.648:EVX:e500:evfsmul %RS,%RA,%RB:Vector Floating-Point Multiply + unsigned32 w1, w2; + w1 = ev_fs_mul (*rAh, *rBh, spefscr_finvh, spefscr_fovfh, spefscr_funfh, spefscr_fgh, spefscr_fxh, processor); + w2 = ev_fs_mul (*rA, *rB, spefscr_finv, spefscr_fovf, spefscr_funf, spefscr_fgh, spefscr_fxh, processor); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.649:EVX:e500:evfsdiv %RS,%RA,%RB:Vector Floating-Point Divide + signed32 w1, w2; + w1 = ev_fs_div (*rAh, *rBh, spefscr_finvh, spefscr_fovfh, spefscr_funfh, spefscr_fdbzh, spefscr_fgh, spefscr_fxh, processor); + w2 = ev_fs_div (*rA, *rB, spefscr_finv, spefscr_fovf, spefscr_funf, spefscr_fdbz, spefscr_fg, spefscr_fx, processor); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.BF,9./,11.RA,16.RB,21.652:EVX:e500:evfscmpgt %BF,%RA,%RB:Vector Floating-Point Compare Greater Than + sim_fpu al, ah, bl, bh; + int w, ch, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&ah, *rAh); + sim_fpu_32to (&bl, *rB); + sim_fpu_32to (&bh, *rBh); + if (EV_IS_INFDENORMNAN(&al) || EV_IS_INFDENORMNAN(&bl)) + EV_SET_SPEFSCR_BITS(spefscr_finv); + if (EV_IS_INFDENORMNAN(&ah) || EV_IS_INFDENORMNAN(&bh)) + EV_SET_SPEFSCR_BITS(spefscr_finvh); + if (sim_fpu_is_gt(&ah, &bh)) + ch = 1; + else + ch = 0; + if (sim_fpu_is_gt(&al, &bl)) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_SPR(0, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.BF,9./,11.RA,16.RB,21.653:EVX:e500:evfscmplt %BF,%RA,%RB:Vector Floating-Point Compare Less Than + sim_fpu al, ah, bl, bh; + int w, ch, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&ah, *rAh); + sim_fpu_32to (&bl, *rB); + sim_fpu_32to (&bh, *rBh); + if (EV_IS_INFDENORMNAN(&al) || EV_IS_INFDENORMNAN(&bl)) + EV_SET_SPEFSCR_BITS(spefscr_finv); + if (EV_IS_INFDENORMNAN(&ah) || EV_IS_INFDENORMNAN(&bh)) + EV_SET_SPEFSCR_BITS(spefscr_finvh); + if (sim_fpu_is_lt(&ah, &bh)) + ch = 1; + else + ch = 0; + if (sim_fpu_is_lt(&al, &bl)) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_SPR(0, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.BF,9./,11.RA,16.RB,21.654:EVX:e500:evfscmpeq %BF,%RA,%RB:Vector Floating-Point Compare Equal + sim_fpu al, ah, bl, bh; + int w, ch, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&ah, *rAh); + sim_fpu_32to (&bl, *rB); + sim_fpu_32to (&bh, *rBh); + if (EV_IS_INFDENORMNAN(&al) || EV_IS_INFDENORMNAN(&bl)) + EV_SET_SPEFSCR_BITS(spefscr_finv); + if (EV_IS_INFDENORMNAN(&ah) || EV_IS_INFDENORMNAN(&bh)) + EV_SET_SPEFSCR_BITS(spefscr_finvh); + if (sim_fpu_is_eq(&ah, &bh)) + ch = 1; + else + ch = 0; + if (sim_fpu_is_eq(&al, &bl)) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_SPR(0, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.BF,9./,11.RA,16.RB,21.668:EVX:e500:evfststgt %BF,%RA,%RB:Vector Floating-Point Test Greater Than + sim_fpu al, ah, bl, bh; + int w, ch, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&ah, *rAh); + sim_fpu_32to (&bl, *rB); + sim_fpu_32to (&bh, *rBh); + if (sim_fpu_is_gt(&ah, &bh)) + ch = 1; + else + ch = 0; + if (sim_fpu_is_gt(&al, &bl)) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.BF,9./,11.RA,16.RB,21.669:EVX:e500:evfststlt %BF,%RA,%RB:Vector Floating-Point Test Less Than + sim_fpu al, ah, bl, bh; + int w, ch, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&ah, *rAh); + sim_fpu_32to (&bl, *rB); + sim_fpu_32to (&bh, *rBh); + if (sim_fpu_is_lt(&ah, &bh)) + ch = 1; + else + ch = 0; + if (sim_fpu_is_lt(&al, &bl)) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.BF,9./,11.RA,16.RB,21.670:EVX:e500:evfststeq %BF,%RA,%RB:Vector Floating-Point Test Equal + sim_fpu al, ah, bl, bh; + int w, ch, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&ah, *rAh); + sim_fpu_32to (&bl, *rB); + sim_fpu_32to (&bh, *rBh); + if (sim_fpu_is_eq(&ah, &bh)) + ch = 1; + else + ch = 0; + if (sim_fpu_is_eq(&al, &bl)) + cl = 1; + else + cl = 0; + w = ch << 3 | cl << 2 | (ch | cl) << 1 | (ch & cl); + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.RS,11.0,16.RB,21.656:EVX:e500:evfscfui %RS,%RB:Vector Convert Floating-Point from Unsigned Integer + unsigned32 f, w1, w2; + sim_fpu b; + + sim_fpu_u32to (&b, *rBh, sim_fpu_round_default); + sim_fpu_to32 (&w1, &b); + sim_fpu_u32to (&b, *rB, sim_fpu_round_default); + sim_fpu_to32 (&w2, &b); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.664:EVX:e500:evfsctuiz %RS,%RB:Vector Convert Floating-Point to Unsigned Integer with Round toward Zero + unsigned32 w1, w2; + sim_fpu b; + + sim_fpu_32to (&b, *rBh); + sim_fpu_to32u (&w1, &b, sim_fpu_round_zero); + sim_fpu_32to (&b, *rB); + sim_fpu_to32u (&w2, &b, sim_fpu_round_zero); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.657:EVX:e500:evfscfsi %RS,%RB:Vector Convert Floating-Point from Signed Integer + signed32 w1, w2; + sim_fpu b, x, y; + + sim_fpu_i32to (&b, *rBh, sim_fpu_round_default); + sim_fpu_to32 (&w1, &b); + sim_fpu_i32to (&b, *rB, sim_fpu_round_default); + sim_fpu_to32 (&w2, &b); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.658:EVX:e500:evfscfuf %RS,%RB:Vector Convert Floating-Point from Unsigned Fraction + unsigned32 w1, w2, bh, bl; + sim_fpu b, x, y; + bh = *rBh; + if (bh == 0xffffffff) + sim_fpu_to32 (&w1, &sim_fpu_one); + else { + sim_fpu_u64to (&x, 0x100000000, sim_fpu_round_default); + sim_fpu_u32to (&y, bh, sim_fpu_round_default); + sim_fpu_div (&b, &y, &x); + sim_fpu_to32 (&w1, &b); + } + bl = *rB; + if (bl == 0xffffffff) + sim_fpu_to32 (&w2, &sim_fpu_one); + else { + sim_fpu_u64to (&x, 0x100000000, sim_fpu_round_default); + sim_fpu_u32to (&y, bl, sim_fpu_round_default); + sim_fpu_div (&b, &y, &x); + sim_fpu_to32 (&w2, &b); + } + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.659:EVX:e500:evfscfsf %RS,%RB:Vector Convert Floating-Point from Signed Fraction + unsigned32 w1, w2; + sim_fpu b, x, y; + + sim_fpu_u32to (&x, 0x80000000, sim_fpu_round_default); + sim_fpu_i32to (&y, *rBh, sim_fpu_round_default); + sim_fpu_div (&b, &y, &x); + sim_fpu_to32 (&w1, &b); + + sim_fpu_u32to (&x, 0x80000000, sim_fpu_round_default); + sim_fpu_i32to (&y, *rB, sim_fpu_round_default); + sim_fpu_div (&b, &y, &x); + sim_fpu_to32 (&w2, &b); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.660:EVX:e500:evfsctui %RS,%RB:Vector Convert Floating-Point to Unsigned Integer + unsigned32 w1, w2; + sim_fpu b; + + sim_fpu_32to (&b, *rBh); + sim_fpu_to32u (&w1, &b, sim_fpu_round_default); + sim_fpu_32to (&b, *rB); + sim_fpu_to32u (&w2, &b, sim_fpu_round_default); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.661:EVX:e500:evfsctsi %RS,%RB:Vector Convert Floating-Point to Signed Integer + signed32 w1, w2; + sim_fpu b; + + sim_fpu_32to (&b, *rBh); + sim_fpu_to32i (&w1, &b, sim_fpu_round_default); + sim_fpu_32to (&b, *rB); + sim_fpu_to32i (&w2, &b, sim_fpu_round_default); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.666:EVX:e500:evfsctsiz %RS,%RB:Vector Convert Floating-Point to Signed Integer with Round toward Zero + signed32 w1, w2; + sim_fpu b; + + sim_fpu_32to (&b, *rBh); + sim_fpu_to32i (&w1, &b, sim_fpu_round_zero); + sim_fpu_32to (&b, *rB); + sim_fpu_to32i (&w2, &b, sim_fpu_round_zero); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.662:EVX:e500:evfsctuf %RS,%RB:Vector Convert Floating-Point to Unsigned Fraction + unsigned32 w1, w2; + sim_fpu b, x, y; + + sim_fpu_u64to (&x, 0x100000000, sim_fpu_round_default); + sim_fpu_32to (&y, *rBh); + sim_fpu_mul (&b, &y, &x); + sim_fpu_to32u (&w1, &b, sim_fpu_round_default); + + sim_fpu_u64to (&x, 0x100000000, sim_fpu_round_default); + sim_fpu_32to (&y, *rB); + sim_fpu_mul (&b, &y, &x); + sim_fpu_to32u (&w2, &b, sim_fpu_round_default); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.663:EVX:e500:evfsctsf %RS,%RB:Vector Convert Floating-Point to Signed Fraction + signed32 w1, w2; + sim_fpu b, x, y; + + sim_fpu_32to (&y, *rBh); + sim_fpu_u32to (&x, 0x80000000, sim_fpu_round_default); + sim_fpu_mul (&b, &y, &x); + sim_fpu_to32i (&w1, &b, sim_fpu_round_near); + + sim_fpu_32to (&y, *rB); + sim_fpu_u32to (&x, 0x80000000, sim_fpu_round_default); + sim_fpu_mul (&b, &y, &x); + sim_fpu_to32i (&w2, &b, sim_fpu_round_near); + + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.0,21.708:EVX:e500:efsabs %RS,%RA:Floating-Point Absolute Value + unsigned32 w1, w2; + w1 = *rSh; + w2 = *rA & 0x7fffffff; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.709:EVX:e500:efsnabs %RS,%RA:Floating-Point Negative Absolute Value + unsigned32 w1, w2; + w1 = *rSh; + w2 = *rA | 0x80000000; + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.0,21.710:EVX:e500:efsneg %RS,%RA:Floating-Point Negate + unsigned32 w1, w2; + w1 = *rSh; + w2 = (*rA & 0x7fffffff) | ((~*rA) & 0x80000000); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK, 0); + +0.4,6.RS,11.RA,16.RB,21.704:EVX:e500:efsadd %RS,%RA,%RB:Floating-Point Add + unsigned32 w; + w = ev_fs_add (*rA, *rB, spefscr_finv, spefscr_fovf, spefscr_funf, spefscr_fgh, spefscr_fxh, processor); + EV_SET_REG(*rS, w); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.705:EVX:e500:efssub %RS,%RA,%RB:Floating-Point Subtract + unsigned32 w; + w = ev_fs_sub (*rA, *rB, spefscr_finv, spefscr_fovf, spefscr_funf, spefscr_fgh, spefscr_fxh, processor); + EV_SET_REG(*rS, w); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.712:EVX:e500:efsmul %RS,%RA,%RB:Floating-Point Multiply + unsigned32 w; + w = ev_fs_mul (*rA, *rB, spefscr_finv, spefscr_fovf, spefscr_funf, spefscr_fgh, spefscr_fxh, processor); + EV_SET_REG(*rS, w); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.RS,11.RA,16.RB,21.713:EVX:e500:efsdiv %RS,%RA,%RB:Floating-Point Divide + unsigned32 w; + w = ev_fs_div (*rA, *rB, spefscr_finv, spefscr_fovf, spefscr_funf, spefscr_fdbz, spefscr_fg, spefscr_fx, processor); + EV_SET_REG(*rS, w); + PPC_INSN_INT_SPR(RS_BITMASK, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.BF,9./,11.RA,16.RB,21.716:EVX:e500:efscmpgt %BF,%RA,%RB:Floating-Point Compare Greater Than + sim_fpu a, b; + int w, cl; + sim_fpu_32to (&a, *rA); + sim_fpu_32to (&b, *rB); + if (EV_IS_INFDENORMNAN(&a) || EV_IS_INFDENORMNAN(&b)) + EV_SET_SPEFSCR_BITS(spefscr_finv); + if (sim_fpu_is_gt(&a, &b)) + cl = 1; + else + cl = 0; + w = cl << 2 | cl << 1; + CR_SET(BF, w); + PPC_INSN_INT_SPR(0, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.BF,9./,11.RA,16.RB,21.717:EVX:e500:efscmplt %BF,%RA,%RB:Floating-Point Compare Less Than + sim_fpu al, bl; + int w, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&bl, *rB); + if (EV_IS_INFDENORMNAN(&al) || EV_IS_INFDENORMNAN(&bl)) + EV_SET_SPEFSCR_BITS(spefscr_finv); + if (sim_fpu_is_lt(&al, &bl)) + cl = 1; + else + cl = 0; + w = cl << 2 | cl << 1; + CR_SET(BF, w); + PPC_INSN_INT_SPR(0, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.BF,9./,11.RA,16.RB,21.718:EVX:e500:efscmpeq %BF,%RA,%RB:Floating-Point Compare Equal + sim_fpu al, bl; + int w, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&bl, *rB); + if (EV_IS_INFDENORMNAN(&al) || EV_IS_INFDENORMNAN(&bl)) + EV_SET_SPEFSCR_BITS(spefscr_finv); + if (sim_fpu_is_eq(&al, &bl)) + cl = 1; + else + cl = 0; + w = cl << 2 | cl << 1; + CR_SET(BF, w); + PPC_INSN_INT_SPR(0, RA_BITMASK | RB_BITMASK, spr_spefscr); + +0.4,6.BF,9./,11.RA,16.RB,21.732:EVX:e500:efststgt %BF,%RA,%RB:Floating-Point Test Greater Than + sim_fpu al, bl; + int w, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&bl, *rB); + if (sim_fpu_is_gt(&al, &bl)) + cl = 1; + else + cl = 0; + w = cl << 2 | cl << 1; + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.BF,9./,11.RA,16.RB,21.733:EVX:e500:efststlt %BF,%RA,%RB:Floating-Point Test Less Than + sim_fpu al, bl; + int w, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&bl, *rB); + if (sim_fpu_is_lt(&al, &bl)) + cl = 1; + else + cl = 0; + w = cl << 2 | cl << 1; + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.BF,9./,11.RA,16.RB,21.734:EVX:e500:efststeq %BF,%RA,%RB:Floating-Point Test Equal + sim_fpu al, bl; + int w, cl; + sim_fpu_32to (&al, *rA); + sim_fpu_32to (&bl, *rB); + if (sim_fpu_is_eq(&al, &bl)) + cl = 1; + else + cl = 0; + w = cl << 2 | cl << 1; + CR_SET(BF, w); + PPC_INSN_INT_CR(0, RA_BITMASK | RB_BITMASK, BF_BITMASK); + +0.4,6.RS,11.0,16.RB,21.721:EVX:e500:efscfsi %RS,%RB:Convert Floating-Point from Signed Integer + signed32 f, w1, w2; + sim_fpu b; + w1 = *rSh; + sim_fpu_i32to (&b, *rB, sim_fpu_round_default); + sim_fpu_to32 (&w2, &b); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.720:EVX:e500:efscfui %RS,%RB:Convert Floating-Point from Unsigned Integer + unsigned32 w1, w2; + sim_fpu b; + w1 = *rSh; + sim_fpu_u32to (&b, *rB, sim_fpu_round_default); + sim_fpu_to32 (&w2, &b); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.723:EVX:e500:efscfsf %RS,%RB:Convert Floating-Point from Signed Fraction + unsigned32 w1, w2; + sim_fpu b, x, y; + w1 = *rSh; + sim_fpu_u32to (&x, 0x80000000, sim_fpu_round_default); + sim_fpu_i32to (&y, *rB, sim_fpu_round_default); + sim_fpu_div (&b, &y, &x); + sim_fpu_to32 (&w2, &b); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.722:EVX:e500:efscfuf %RS,%RB:Convert Floating-Point from Unsigned Fraction + unsigned32 w1, w2, bl; + sim_fpu b, x, y; + w1 = *rSh; + bl = *rB; + if (bl == 0xffffffff) + sim_fpu_to32 (&w2, &sim_fpu_one); + else { + sim_fpu_u64to (&x, 0x100000000, sim_fpu_round_default); + sim_fpu_u32to (&y, bl, sim_fpu_round_default); + sim_fpu_div (&b, &y, &x); + sim_fpu_to32 (&w2, &b); + } + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.725:EVX:e500:efsctsi %RS,%RB:Convert Floating-Point to Signed Integer + signed64 temp; + signed32 w1, w2; + sim_fpu b; + w1 = *rSh; + sim_fpu_32to (&b, *rB); + sim_fpu_to32i (&w2, &b, sim_fpu_round_default); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.730:EVX:e500:efsctsiz %RS,%RB:Convert Floating-Point to Signed Integer with Round toward Zero + signed64 temp; + signed32 w1, w2; + sim_fpu b; + w1 = *rSh; + sim_fpu_32to (&b, *rB); + sim_fpu_to32i (&w2, &b, sim_fpu_round_zero); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.724:EVX:e500:efsctui %RS,%RB:Convert Floating-Point to Unsigned Integer + unsigned64 temp; + signed32 w1, w2; + sim_fpu b; + w1 = *rSh; + sim_fpu_32to (&b, *rB); + sim_fpu_to32u (&w2, &b, sim_fpu_round_default); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.728:EVX:e500:efsctuiz %RS,%RB:Convert Floating-Point to Unsigned Integer with Round toward Zero + unsigned64 temp; + signed32 w1, w2; + sim_fpu b; + w1 = *rSh; + sim_fpu_32to (&b, *rB); + sim_fpu_to32u (&w2, &b, sim_fpu_round_zero); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.727:EVX:e500:efsctsf %RS,%RB:Convert Floating-Point to Signed Fraction + unsigned32 w1, w2; + sim_fpu b, x, y; + w1 = *rSh; + sim_fpu_32to (&y, *rB); + sim_fpu_u32to (&x, 0x80000000, sim_fpu_round_default); + sim_fpu_mul (&b, &y, &x); + sim_fpu_to32i (&w2, &b, sim_fpu_round_default); + sim_fpu_to32 (&w2, &b); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + +0.4,6.RS,11.0,16.RB,21.726:EVX:e500:efsctuf %RS,%RB:Convert Floating-Point to Unsigned Fraction + unsigned32 w1, w2; + sim_fpu b, x, y; + w1 = *rSh; + sim_fpu_u64to (&x, 0x100000000, sim_fpu_round_default); + sim_fpu_32to (&y, *rB); + sim_fpu_mul (&b, &y, &x); + sim_fpu_to32u (&w2, &b, sim_fpu_round_default); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, RB_BITMASK, 0); + + +# +# A.2.10 Vector Load/Store Instructions +# + +0.4,6.RS,11.RA,16.UIMM,21.769:EVX:e500:evldd %RS,%RA,%UIMM:Vector Load Double Word into Double Word + unsigned64 m; + unsigned_word b; + unsigned_word EA; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + m = MEM(unsigned, EA, 8); + EV_SET_REG1(*rSh, *rS, m); + //printf("evldd(%d<-%d + %u): m %08x.%08x, *rSh %x *rS %x\n", RS, RA, UIMM, (int)(m >> 32), (int)m, *rSh, *rS); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.768:EVX:e500:evlddx %RS,%RA,%RB:Vector Load Double Word into Double Word Indexed + unsigned64 m; + unsigned_word b; + unsigned_word EA; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + m = MEM(unsigned, EA, 8); + EV_SET_REG1(*rSh, *rS, m); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.771:EVX:e500:evldw %RS,%RA,%UIMM:Vector Load Double into Two Words + unsigned_word b; + unsigned_word EA; + unsigned32 w1, w2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + w1 = MEM(unsigned, EA, 4); + w2 = MEM(unsigned, EA + 4, 4); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.770:EVX:e500:evldwx %RS,%RA,%RB:Vector Load Double into Two Words Indexed + unsigned_word b; + unsigned_word EA; + unsigned32 w1, w2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + w1 = MEM(unsigned, EA, 4); + w2 = MEM(unsigned, EA + 4, 4); + EV_SET_REG2(*rSh, *rS, w1, w2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.773:EVX:e500:evldh %RS,%RA,%UIMM:Vector Load Double into 4 Half Words + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + h1 = MEM(unsigned, EA, 2); + h2 = MEM(unsigned, EA + 2, 2); + h3 = MEM(unsigned, EA + 4, 2); + h4 = MEM(unsigned, EA + 6, 2); + EV_SET_REG4(*rSh, *rS, h1, h2, h3, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.772:EVX:e500:evldhx %RS,%RA,%RB:Vector Load Double into 4 Half Words Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h1 = MEM(unsigned, EA, 2); + h2 = MEM(unsigned, EA + 2, 2); + h3 = MEM(unsigned, EA + 4, 2); + h4 = MEM(unsigned, EA + 6, 2); + EV_SET_REG4(*rSh, *rS, h1, h2, h3, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.785:EVX:e500:evlwhe %RS,%RA,%UIMM:Vector Load Word into Two Half Words Even + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 2); + h1 = MEM(unsigned, EA, 2); + h2 = 0; + h3 = MEM(unsigned, EA + 2, 2); + h4 = 0; + EV_SET_REG4(*rSh, *rS, h1, h2, h3, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.784:EVX:e500:evlwhex %RS,%RA,%RB:Vector Load Word into Two Half Words Even Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h1 = MEM(unsigned, EA, 2); + h2 = 0; + h3 = MEM(unsigned, EA + 2, 2); + h4 = 0; + EV_SET_REG4(*rSh, *rS, h1, h2, h3, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.789:EVX:e500:evlwhou %RS,%RA,%UIMM:Vector Load Word into Two Half Words Odd Unsigned zero-extended + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 2); + h1 = 0; + h2 = MEM(unsigned, EA, 2); + h3 = 0; + h4 = MEM(unsigned, EA + 2, 2); + EV_SET_REG4(*rSh, *rS, h1, h2, h3, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.788:EVX:e500:evlwhoux %RS,%RA,%RB:Vector Load Word into Two Half Words Odd Unsigned Indexed zero-extended + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h1 = 0; + h2 = MEM(unsigned, EA, 2); + h3 = 0; + h4 = MEM(unsigned, EA + 2, 2); + EV_SET_REG4(*rSh, *rS, h1, h2, h3, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.791:EVX:e500:evlwhos %RS,%RA,%UIMM:Vector Load Word into Half Words Odd Signed with sign extension + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 2); + h2 = MEM(unsigned, EA, 2); + if (h2 & 0x8000) + h1 = 0xffff; + else + h1 = 0; + h4 = MEM(unsigned, EA + 2, 2); + if (h4 & 0x8000) + h3 = 0xffff; + else + h3 = 0; + EV_SET_REG4(*rSh, *rS, h1, h2, h3, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.790:EVX:e500:evlwhosx %RS,%RA,%RB:Vector Load Word into Half Words Odd Signed Indexed with sign extension + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h2 = MEM(unsigned, EA, 2); + if (h2 & 0x8000) + h1 = 0xffff; + else + h1 = 0; + h4 = MEM(unsigned, EA + 2, 2); + if (h4 & 0x8000) + h3 = 0xffff; + else + h3 = 0; + EV_SET_REG4(*rSh, *rS, h1, h2, h3, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.793:EVX:e500:evlwwsplat %RS,%RA,%UIMM:Vector Load Word into Word and Splat + unsigned_word b; + unsigned_word EA; + unsigned32 w1; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 2); + w1 = MEM(unsigned, EA, 4); + EV_SET_REG2(*rSh, *rS, w1, w1); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.792:EVX:e500:evlwwsplatx %RS,%RA,%RB:Vector Load Word into Word and Splat Indexed + unsigned_word b; + unsigned_word EA; + unsigned32 w1; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + w1 = MEM(unsigned, EA, 4); + EV_SET_REG2(*rSh, *rS, w1, w1); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.797:EVX:e500:evlwhsplat %RS,%RA,%UIMM:Vector Load Word into 2 Half Words and Splat + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 2); + h1 = MEM(unsigned, EA, 2); + h2 = MEM(unsigned, EA + 2, 2); + EV_SET_REG4(*rSh, *rS, h1, h1, h2, h2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.796:EVX:e500:evlwhsplatx %RS,%RA,%RB:Vector Load Word into 2 Half Words and Splat Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h1 = MEM(unsigned, EA, 2); + h2 = MEM(unsigned, EA + 2, 2); + EV_SET_REG4(*rSh, *rS, h1, h1, h2, h2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.777:EVX:e500:evlhhesplat %RS,%RA,%UIMM:Vector Load Half Word into Half Words Even and Splat + unsigned_word b; + unsigned_word EA; + unsigned16 h; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 1); + h = MEM(unsigned, EA, 2); + EV_SET_REG4(*rSh, *rS, h, 0, h, 0); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.776:EVX:e500:evlhhesplatx %RS,%RA,%RB:Vector Load Half Word into Half Words Even and Splat Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h = MEM(unsigned, EA, 2); + EV_SET_REG4(*rSh, *rS, h, 0, h, 0); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.781:EVX:e500:evlhhousplat %RS,%RA,%UIMM:Vector Load Half Word into Half Word Odd Unsigned and Splat + unsigned_word b; + unsigned_word EA; + unsigned16 h; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 1); + h = MEM(unsigned, EA, 2); + EV_SET_REG4(*rSh, *rS, 0, h, 0, h); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.780:EVX:e500:evlhhousplatx %RS,%RA,%RB:Vector Load Half Word into Half Word Odd Unsigned and Splat Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h = MEM(unsigned, EA, 2); + EV_SET_REG4(*rSh, *rS, 0, h, 0, h); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.783:EVX:e500:evlhhossplat %RS,%RA,%UIMM:Vector Load Half Word into Half Word Odd Signed and Splat + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 1); + h2 = MEM(unsigned, EA, 2); + if (h2 & 0x8000) + h1 = 0xffff; + else + h1 = 0; + EV_SET_REG4(*rSh, *rS, h1, h2, h1, h2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.782:EVX:e500:evlhhossplatx %RS,%RA,%RB:Vector Load Half Word into Half Word Odd Signed and Splat Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h2 = MEM(unsigned, EA, 2); + if (h2 & 0x8000) + h1 = 0xffff; + else + h1 = 0; + EV_SET_REG4(*rSh, *rS, h1, h2, h1, h2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + + +0.4,6.RS,11.RA,16.UIMM,21.801:EVX:e500:evstdd %RS,%RA,%UIMM:Vector Store Double of Double + unsigned_word b; + unsigned_word EA; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + STORE(EA, 4, (*rSh)); + STORE(EA + 4, 4, (*rS)); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.800:EVX:e500:evstddx %RS,%RA,%RB:Vector Store Double of Double Indexed + unsigned_word b; + unsigned_word EA; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + STORE(EA, 4, (*rSh)); + STORE(EA + 4, 4, (*rS)); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.803:EVX:e500:evstdw %RS,%RA,%UIMM:Vector Store Double of Two Words + unsigned_word b; + unsigned_word EA; + unsigned32 w1, w2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + w1 = *rSh; + w2 = *rS; + STORE(EA + 0, 4, w1); + STORE(EA + 4, 4, w2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.802:EVX:e500:evstdwx %RS,%RA,%RB:Vector Store Double of Two Words Indexed + unsigned_word b; + unsigned_word EA; + unsigned32 w1, w2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + w1 = *rSh; + w2 = *rS; + STORE(EA + 0, 4, w1); + STORE(EA + 4, 4, w2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.805:EVX:e500:evstdh %RS,%RA,%UIMM:Vector Store Double of Four Half Words + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + h1 = EV_HIHALF(*rSh); + h2 = EV_LOHALF(*rSh); + h3 = EV_HIHALF(*rS); + h4 = EV_LOHALF(*rS); + STORE(EA + 0, 2, h1); + STORE(EA + 2, 2, h2); + STORE(EA + 4, 2, h3); + STORE(EA + 6, 2, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.804:EVX:e500:evstdhx %RS,%RA,%RB:Vector Store Double of Four Half Words Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2, h3, h4; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h1 = EV_HIHALF(*rSh); + h2 = EV_LOHALF(*rSh); + h3 = EV_HIHALF(*rS); + h4 = EV_LOHALF(*rS); + STORE(EA + 0, 2, h1); + STORE(EA + 2, 2, h2); + STORE(EA + 4, 2, h3); + STORE(EA + 6, 2, h4); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.825:EVX:e500:evstwwe %RS,%RA,%UIMM:Vector Store Word of Word from Even + unsigned_word b; + unsigned_word EA; + unsigned32 w; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + w = *rSh; + STORE(EA, 4, w); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.824:EVX:e500:evstwwex %RS,%RA,%RB:Vector Store Word of Word from Even Indexed + unsigned_word b; + unsigned_word EA; + unsigned32 w; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + w = *rSh; + STORE(EA, 4, w); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.829:EVX:e500:evstwwo %RS,%RA,%UIMM:Vector Store Word of Word from Odd + unsigned_word b; + unsigned_word EA; + unsigned32 w; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + w = *rS; + STORE(EA, 4, w); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.828:EVX:e500:evstwwox %RS,%RA,%RB:Vector Store Word of Word from Odd Indexed + unsigned_word b; + unsigned_word EA; + unsigned32 w; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + w = *rS; + STORE(EA, 4, w); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.817:EVX:e500:evstwhe %RS,%RA,%UIMM:Vector Store Word of Two Half Words from Even + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + h1 = EV_HIHALF(*rSh); + h2 = EV_HIHALF(*rS); + STORE(EA + 0, 2, h1); + STORE(EA + 2, 2, h2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.816:EVX:e500:evstwhex %RS,%RA,%RB:Vector Store Word of Two Half Words from Even Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h1 = EV_HIHALF(*rSh); + h2 = EV_HIHALF(*rS); + STORE(EA + 0, 2, h1); + STORE(EA + 2, 2, h2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + +0.4,6.RS,11.RA,16.UIMM,21.821:EVX:e500:evstwho %RS,%RA,%UIMM:Vector Store Word of Two Half Words from Odd + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + (UIMM << 3); + h1 = EV_LOHALF(*rSh); + h2 = EV_LOHALF(*rS); + STORE(EA + 0, 2, h1); + STORE(EA + 2, 2, h2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1), 0); + +0.4,6.RS,11.RA,16.RB,21.820:EVX:e500:evstwhox %RS,%RA,%RB:Vector Store Word of Two Half Words from Odd Indexed + unsigned_word b; + unsigned_word EA; + unsigned16 h1, h2; + if (RA_is_0) b = 0; + else b = *rA; + EA = b + *rB; + h1 = EV_LOHALF(*rSh); + h2 = EV_LOHALF(*rS); + STORE(EA + 0, 2, h1); + STORE(EA + 2, 2, h2); + PPC_INSN_INT(RS_BITMASK, (RA_BITMASK & ~1) | RB_BITMASK, 0); + + +# +# 4.5.1 Integer Select Instruction +# + +0.31,6.RS,11.RA,16.RB,21.CRB,26.30:X:e500:isel %RS,%RA,%RB,%CRB:Integer Select + if (CR & (1 << (31 - (unsigned)CRB))) + if (RA_is_0) + EV_SET_REG1(*rSh, *rS, 0); + else + EV_SET_REG2(*rSh, *rS, *rAh, *rA); + else + EV_SET_REG2(*rSh, *rS, *rBh, *rB); + PPC_INSN_INT(RS_BITMASK, RA_BITMASK | RB_BITMASK, 0); diff --git a/sim/ppc/e500_expression.h b/sim/ppc/e500_expression.h new file mode 100644 index 0000000..c634a1c --- /dev/null +++ b/sim/ppc/e500_expression.h @@ -0,0 +1,173 @@ +/* e500 expression macros, for PSIM, the PowerPC simulator. + + Copyright 2003 Free Software Foundation, Inc. + + Contributed by Red Hat Inc; developed under contract from Motorola. + Written by matthew green <mrg@redhat.com>. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* e500 register dance */ +#define EV_SET_REG4(sh, sl, h0, h1, h2, h3) do { \ + (sh) = (((h0) & 0xffff) << 16) | ((h1) & 0xffff); \ + (sl) = (((h2) & 0xffff) << 16) | ((h3) & 0xffff); \ +} while (0) +#define EV_SET_REG4_ACC(sh, sl, h0, h1, h2, h3) do { \ + (sh) = (((h0) & 0xffff) << 16) | ((h1) & 0xffff); \ + (sl) = (((h2) & 0xffff) << 16) | ((h3) & 0xffff); \ + ACC = ((unsigned64)(sh) << 32) | (sl & 0xffffffff); \ +} while (0) + +#define EV_SET_REG2(sh, sl, dh, dl) do { \ + (sh) = (dh) & 0xffffffff; \ + (sl) = (dl) & 0xffffffff; \ +} while (0) +#define EV_SET_REG2_ACC(sh, sl, dh, dl) do { \ + (sh) = (dh) & 0xffffffff; \ + (sl) = (dl) & 0xffffffff; \ + ACC = ((unsigned64)(sh) << 32) | ((sl) & 0xffffffff); \ +} while (0) + +#define EV_SET_REG1(sh, sl, d) do { \ + (sh) = ((unsigned64)(d) >> 32) & 0xffffffff; \ + (sl) = (d) & 0xffffffff; \ +} while (0) +#define EV_SET_REG1_ACC(sh, sl, d) do { \ + (sh) = ((unsigned64)(d) >> 32) & 0xffffffff; \ + (sl) = (d) & 0xffffffff; \ + ACC = (d); \ +} while (0) + +#define EV_SET_REG(s, d) do { \ + (s) = (d) & 0xffffffff; \ +} while (0) + +/* get the low or high half word of a word */ +#define EV_LOHALF(x) ((unsigned32)(x) & 0xffff) +#define EV_HIHALF(x) (((unsigned32)(x) >> 16) & 0xffff) + +/* partially visible accumulator accessors */ +#define EV_SET_ACC(rh, rl) \ + ACC = ((unsigned64)(rh) << 32) | ((rl) & 0xffffffff) + +#define EV_ACCLOW (ACC & 0xffffffff) +#define EV_ACCHIGH ((ACC >> 32) & 0xffffffff) + +/* bit manipulation macros needed for e500 SPE */ +#define EV_BITREVERSE16(x) \ + (((x) & 0x0001) << 15) \ + | (((x) & 0x0002) << 13) \ + | (((x) & 0x0004) << 11) \ + | (((x) & 0x0008) << 9) \ + | (((x) & 0x0010) << 7) \ + | (((x) & 0x0020) << 5) \ + | (((x) & 0x0040) << 3) \ + | (((x) & 0x0080) << 1) \ + | (((x) & 0x0100) >> 1) \ + | (((x) & 0x0200) >> 3) \ + | (((x) & 0x0400) >> 5) \ + | (((x) & 0x0800) >> 7) \ + | (((x) & 0x1000) >> 9) \ + | (((x) & 0x2000) >> 11) \ + | (((x) & 0x4000) >> 13) \ + | (((x) & 0x8000) >> 15) + +/* saturation helpers */ +#define EV_MUL16_SSF(a,b) ((signed64)((signed32)(signed16)(a) * (signed32)(signed16)(b)) << 1) +/* this one loses the top sign bit; be careful */ +#define EV_MUL32_SSF(a,b) (((signed64)(signed32)(a) * (signed64)(signed32)(b)) << 1) +#define EV_SAT_P_S32(x) ((((signed64)(x)) < -0x80000000LL) || (((signed64)(x)) > 0x7fffffffLL)) +#define EV_SAT_P_U32(x) ((((signed64)(x)) < -0LL) || (((signed64)(x)) > 0xffffffffLL)) + +#define EV_SATURATE(flag, sat_val, val) \ + ((flag) ? (sat_val) : (val)) + +#define EV_SATURATE_ACC(flag, sign, negative_sat_val, positive_sat_val, val) \ + ((flag) ? ((((sign) >> 63) & 1) ? (negative_sat_val) : (positive_sat_val)) : (val)) + +/* SPEFSCR handling. */ + +/* These bits must be clear. */ +#define EV_SPEFSCR_MASK (BIT(40) | BIT(41) | spefscr_mode | BIT(56)) + +/* The Inexact and Divide by zero sticky bits are based on others. */ +#define EV_SET_SPEFSCR(bits) do { \ + int finxs = (bits) & (spefscr_fgh|spefscr_fxh|spefscr_fg|spefscr_fx); \ + int fdbzs = (bits) & (spefscr_fdbzh|spefscr_fdbz); \ + SPREG(spr_spefscr) = ((bits) & ~EV_SPEFSCR_MASK) | \ + (finxs ? spefscr_finxs : 0) | \ + (fdbzs ? spefscr_fdbzs : 0); \ +} while (0) + +#define EV_SET_SPEFSCR_BITS(s) \ + EV_SET_SPEFSCR(SPREG(spr_spefscr) | (s)) + +#define EV_SET_SPEFSCR_OV(l,h) do { \ + unsigned32 _sPefScR = SPREG(spr_spefscr); \ + if (l) \ + _sPefScR |= spefscr_ov | spefscr_sov; \ + else \ + _sPefScR &= ~spefscr_ov; \ + if (h) \ + _sPefScR |= spefscr_ovh | spefscr_sovh; \ + else \ + _sPefScR &= ~spefscr_ovh; \ + EV_SET_SPEFSCR(_sPefScR); \ +} while (0) + +/* SPE floating point helpers. */ + +#define EV_PMAX 0x7f7fffff +#define EV_NMAX 0xff7fffff +#define EV_PMIN 0x00800001 +#define EV_NMIN 0x80800001 + +#define EV_IS_INFDENORMNAN(x) \ + (sim_fpu_is_infinity(x) || sim_fpu_is_denorm(x) || sim_fpu_is_nan(x)) + +/* These aren't used (yet?) For now, SPU is always enabled. + Would be nice if they were generated by igen for e500. */ +#define SPU_BEGIN \ +{ \ + if (MSR & msr_e500_spu_enable) { \ + +#define SPU_END \ + } else { \ + /* FIXME: raise SPU unavailable. */ \ + } \ +} + +/* These are also not yet used. */ +#define SPU_FP_BEGIN \ +{ + +#define SPU_FP_END \ + { \ + unsigned s = SPEFSCR; \ + /* Check SPEFSCR; raise exceptions if any required. */ \ + if (((spefscr_finxe || spefscr_finve) \ + && (s & (spefscr_finvh|spefscr_finv))) \ + || ((spefscr_finxe || spefscr_fdbze) \ + && (s & (spefscr_fdbzh|spefscr_fdbz))) \ + || ((spefscr_finxe || spefscr_funfe) \ + && (s & (spefscr_funfh|spefscr_funf))) \ + || ((spefscr_finxe || spefscr_fovfe) \ + && (s & (spefscr_fovfh|spefscr_fovf)))) \ + /* FIXME: raise exceptions. */; \ + } \ +} diff --git a/sim/ppc/e500_registers.h b/sim/ppc/e500_registers.h new file mode 100644 index 0000000..cd12ab5 --- /dev/null +++ b/sim/ppc/e500_registers.h @@ -0,0 +1,83 @@ +/* e500 registers, for PSIM, the PowerPC simulator. + + Copyright 2003 Free Software Foundation, Inc. + + Contributed by Red Hat Inc; developed under contract from Motorola. + Written by matthew green <mrg@redhat.com>. + + This file is part of GDB. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* e500 accumulator. */ + +typedef unsigned64 accreg; + +enum { + msr_e500_spu_enable = BIT(38) +}; + +/* E500 regsiters. */ + +enum + { + spefscr_sovh = BIT(32), /* summary integer overlow (high) */ + spefscr_ovh = BIT(33), /* int overflow (high) */ + spefscr_fgh = BIT(34), /* FP guard (high) */ + spefscr_fxh = BIT(35), /* FP sticky (high) */ + spefscr_finvh = BIT(36), /* FP invalid operand (high) */ + spefscr_fdbzh = BIT(37), /* FP divide by zero (high) */ + spefscr_funfh = BIT(38), /* FP underflow (high) */ + spefscr_fovfh = BIT(39), /* FP overflow (high) */ + spefscr_finxs = BIT(42), /* FP inexact sticky */ + spefscr_finvs = BIT(43), /* FP invalid operand sticky */ + spefscr_fdbzs = BIT(44), /* FP divide by zero sticky */ + spefscr_funfs = BIT(45), /* FP underflow sticky */ + spefscr_fovfs = BIT(46), /* FP overflow sticky */ + spefscr_mode = BIT(47), /* SPU MODE (read only) */ + spefscr_sov = BIT(48), /* Summary integer overlow (low) */ + spefscr_ov = BIT(49), /* int overflow (low) */ + spefscr_fg = BIT(50), /* FP guard (low) */ + spefscr_fx = BIT(51), /* FP sticky (low) */ + spefscr_finv = BIT(52), /* FP invalid operand (low) */ + spefscr_fdbz = BIT(53), /* FP divide by zero (low) */ + spefscr_funf = BIT(54), /* FP underflow (low) */ + spefscr_fovf = BIT(55), /* FP overflow (low) */ + spefscr_finxe = BIT(57), /* FP inexact enable */ + spefscr_finve = BIT(58), /* FP invalid operand enable */ + spefscr_fdbze = BIT(59), /* FP divide by zero enable */ + spefscr_funfe = BIT(60), /* FP underflow enable */ + spefscr_fovfe = BIT(61), /* FP overflow enable */ + spefscr_frmc0 = BIT(62), /* FP round mode control */ + spefscr_frmc1 = BIT(63), + spefscr_frmc = (spefscr_frmc0 | spefscr_frmc1), +}; + +struct e500_regs { + /* e500 high bits. */ + signed_word gprh[32]; + /* Accumulator */ + accreg acc; +}; + +/* SPE partially visible acculator */ +#define ACC cpu_registers(processor)->e500.acc + +/* e500 register high bits */ +#define GPRH(N) cpu_registers(processor)->e500.gprh[N] + +/* e500 unified vector register */ +#define EVR(N) ((((unsigned64)GPRH(N)) << 32) | GPR(N)) |