From 73d51962f6acf8da2d35a68a310c33dcbe91897b Mon Sep 17 00:00:00 2001 From: gbeauche <> Date: Mon, 24 Nov 2003 23:45:52 +0000 Subject: [PATCH] Merge in-progress PowerPC "JIT1" engine for AMD64, IA-32, PPC. The merge probably got wrong as there are some problems probably due to the experiment begining with CR deferred evaluation. With nbench/ppc, performance improvement was around 2x. With nbench on x86, performance improvement was around 4x on average. Incompatible change: instr_info_t has a new field in the middle. But since insertion of PPC_I(XXX) identifiers is auto-generated, there is no problem. --- SheepShaver/src/kpx_cpu/include/elf-defs.h | 2360 +++++++++++++++++ SheepShaver/src/kpx_cpu/include/nvmemfun.hpp | 28 +- SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp | 7 + .../src/cpu/jit/amd64/dyngen-target-exec.h | 45 + .../src/cpu/jit/amd64/jit-target-cache.hpp | 1 + .../kpx_cpu/src/cpu/jit/basic-dyngen-ops.cpp | 548 ++++ .../src/kpx_cpu/src/cpu/jit/basic-dyngen.cpp | 104 + .../src/kpx_cpu/src/cpu/jit/basic-dyngen.hpp | 315 +++ .../src/kpx_cpu/src/cpu/jit/cxxdemangle.cpp | 32 + .../src/kpx_cpu/src/cpu/jit/cxxdemangle.h | 55 + .../src/cpu/jit/dummy/jit-target-cache.hpp | 28 + .../src/kpx_cpu/src/cpu/jit/dyngen-exec.h | 103 + SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c | 1414 ++++++++++ .../src/kpx_cpu/src/cpu/jit/jit-cache.cpp | 71 + .../src/kpx_cpu/src/cpu/jit/jit-cache.hpp | 112 + .../src/kpx_cpu/src/cpu/jit/jit-config.hpp | 86 + .../src/cpu/jit/ppc/dyngen-target-exec.h | 71 + .../src/cpu/jit/ppc/jit-target-cache.hpp | 44 + .../src/cpu/jit/x86/dyngen-target-exec.h | 39 + .../src/cpu/jit/x86/jit-target-cache.hpp | 1 + .../src/kpx_cpu/src/cpu/ppc/ppc-blockinfo.hpp | 5 + .../src/kpx_cpu/src/cpu/ppc/ppc-config.hpp | 29 + .../src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp | 88 +- .../src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp | 50 +- .../src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp | 173 +- .../kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp | 942 +++++++ .../src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp | 254 ++ .../src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp | 231 ++ .../src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp | 63 +- .../src/kpx_cpu/src/cpu/ppc/ppc-execute.hpp | 134 + .../kpx_cpu/src/cpu/ppc/ppc-instructions.hpp | 204 ++ .../src/kpx_cpu/src/cpu/ppc/ppc-operands.hpp | 9 +- .../src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp | 36 +- .../src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp | 1031 +++++++ .../src/kpx_cpu/src/test/test-powerpc.cpp | 264 +- 35 files changed, 8836 insertions(+), 141 deletions(-) create mode 100644 SheepShaver/src/kpx_cpu/include/elf-defs.h create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/amd64/dyngen-target-exec.h create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/amd64/jit-target-cache.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen-ops.cpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen.cpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/cxxdemangle.cpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/cxxdemangle.h create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/dummy/jit-target-cache.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen-exec.h create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/jit-cache.cpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/jit-cache.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/jit-config.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/ppc/dyngen-target-exec.h create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/ppc/jit-target-cache.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/x86/dyngen-target-exec.h create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/jit/x86/jit-target-cache.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-instructions.hpp create mode 100644 SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp diff --git a/SheepShaver/src/kpx_cpu/include/elf-defs.h b/SheepShaver/src/kpx_cpu/include/elf-defs.h new file mode 100644 index 00000000..8fe6b053 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/include/elf-defs.h @@ -0,0 +1,2360 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef ELF_DEFS_H +#define ELF_DEFS_H 1 + +/* Standard ELF types. */ + +/* Type for a 16-bit quantity. */ +typedef uint16 Elf32_Half; +typedef uint16 Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32 Elf32_Word; +typedef int32 Elf32_Sword; +typedef uint32 Elf64_Word; +typedef int32 Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64 Elf32_Xword; +typedef int64 Elf32_Sxword; +typedef uint64 Elf64_Xword; +typedef int64 Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32 Elf32_Addr; +typedef uint64 Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32 Elf32_Off; +typedef uint64 Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16 Elf32_Section; +typedef uint16 Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_486 6 /* Perhaps disused */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_NUM 95 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 10 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct +{ + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxialiary version information. */ + +typedef struct +{ + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + + +/* Version dependency section. */ + +typedef struct +{ + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + int a_type; /* Entry type */ + union + { + long int a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn) (void); /* Function pointer value */ + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + long int a_type; /* Entry type */ + union + { + long int a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn) (void); /* Function pointer value */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 + + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define ELF_NOTE_ABI 1 + +/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI + note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + + +/* Move records. */ +typedef struct +{ + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +/* Keep this the last entry. */ +#define R_68K_NUM 23 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* Keep this the last entry. */ +#define R_386_NUM 38 + +/* SUN SPARC specific definitions. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +/* Keep this the last entry. */ +#define R_SPARC_NUM 80 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ +#define HWCAP_SPARC_ULTRA3 32 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* The following are non-official names and should not be used. */ + +#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct +{ + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, + 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct +{ + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +/* Keep this the last entry. */ +#define R_MIPS_NUM 38 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in + DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in + DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in + DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta + relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in + DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the + class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in + DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve + function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added + by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +#define DT_MIPS_NUM 0x32 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primerily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#define R_PPC_NUM 37 + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address. */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned. */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address. */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of abs. address. */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of abs. address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned. */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC relative 26 bit, word aligned. */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit. */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2. */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A. */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A). */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A). */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A). */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A). */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A. */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P. */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A. */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P. */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC. */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.). */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.). */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.). */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC. */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A. */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A). */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A). */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A). */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2. */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2. */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2. */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2. */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2. */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2. */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2. */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2. */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2. */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2. */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2. */ +/* Keep this the last entry. */ +#define R_PPC64_NUM 67 + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_NUM 1 + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 + +/* Additional symbol types for Thumb */ +#define STT_ARM_TFUNC 0xd + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base */ + +/* ARM relocs. */ +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS + block. */ + +/* Keep this the last entry. */ +#define R_390_NUM 57 + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset + to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset + to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset + to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ + +#define R_X86_64_NUM 24 + +#endif /* elf.h */ diff --git a/SheepShaver/src/kpx_cpu/include/nvmemfun.hpp b/SheepShaver/src/kpx_cpu/include/nvmemfun.hpp index 59f8a4e8..4d64b7bc 100644 --- a/SheepShaver/src/kpx_cpu/include/nvmemfun.hpp +++ b/SheepShaver/src/kpx_cpu/include/nvmemfun.hpp @@ -45,7 +45,7 @@ class nv_mem_fun_t : public std::unary_function { public: nv_mem_fun_t(pmf_t pmf) : pf(nv_mem_fun_of(pmf)) {} R operator()(T *p) const { return (*pf)(p); } - operator bool () const { return pf; } + pf_t ptr() const { return pf; } }; template< class R, class T > @@ -56,7 +56,7 @@ class const_nv_mem_fun_t : public std::unary_function { public: const_nv_mem_fun_t(pmf_t const pmf) : pf(nv_mem_fun_of(pmf)) {} R operator()(const T *p) const { return (*pf)(p); } - operator bool () const { return pf; } + pf_t ptr() const { return pf; } }; template< class R, class T, class A > @@ -67,7 +67,7 @@ class nv_mem_fun1_t : public std::binary_function { public: nv_mem_fun1_t(pmf_t pmf) : pf(nv_mem_fun_of(pmf)) {} R operator()(T *p, A x) const { return (*pf)(p, x); } - operator bool () const { return pf; } + pf_t ptr() const { return pf; } }; template< class R, class T, class A > @@ -78,45 +78,49 @@ class const_nv_mem_fun1_t : public std::binary_function { public: const_nv_mem_fun1_t(pmf_t const pmf) : pf(nv_mem_fun_of(pmf)) {} R operator()(const T *p, A x) const { return (*pf)(p, x); } - operator bool () const { return pf; } + pf_t ptr() const { return pf; } }; #else template< class R, class T > class nv_mem_fun_t : public std::unary_function { - R (T::*pf)(); + typedef R (T::*pmf_t)(); + pmf_t pf; public: nv_mem_fun_t(R (T::*pmf)()) : pf(pmf) {} R operator()(T *p) const { return (p->*pf)(); } - operator bool () const { return pf; } + pmf_t ptr() const { return pf; } }; template< class R, class T > class const_nv_mem_fun_t : public std::unary_function { - R (T::*pf)() const; + typedef R (T::*pmf_t)() const; + pmf_t pf; public: const_nv_mem_fun_t(R (T::*pmf)() const) : pf(pmf) {} R operator()(const T *p) const { return (p->*pf)(); } - operator bool () const { return pf; } + pmf_t ptr() const { return pf; } }; template< class R, class T, class A > class nv_mem_fun1_t : public std::binary_function { - R (T::*pf)(A); + typedef R (T::*pmf_t)(A); + pmf_t pf; public: nv_mem_fun1_t(R (T::*pmf)(A)) : pf(pmf) {} R operator()(T *p, A x) const { return (p->*pf)(x); } - operator bool () const { return pf; } + pmf_t ptr() const { return pf; } }; template< class R, class T, class A > class const_nv_mem_fun1_t : public std::binary_function { - R (T::*pf)(A) const; + typedef R (T::*pmf_t)(A) const; + pmf_t pf; public: const_nv_mem_fun1_t(R (T::*pmf)(A) const) : pf(pmf) {} R operator()(const T *p, A x) const { return (p->*pf)(x); } - operator bool () const { return pf; } + pmf_t ptr() const { return pf; } }; #endif diff --git a/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp b/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp index 36421118..cb315333 100644 --- a/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp +++ b/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp @@ -30,6 +30,7 @@ #include "sigsegv.h" #include "cpu/ppc/ppc-cpu.hpp" #include "cpu/ppc/ppc-operations.hpp" +#include "cpu/ppc/ppc-instructions.hpp" // Used for NativeOp trampolines #include "video.h" @@ -97,6 +98,11 @@ static sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); * PowerPC emulator glue with special 'sheep' opcodes **/ +enum { + PPC_I(SHEEP) = PPC_I(MAX), + PPC_I(SHEEP_MAX) +}; + class sheepshaver_cpu : public powerpc_cpu { @@ -165,6 +171,7 @@ void sheepshaver_cpu::init_decoder() { "sheep", (execute_pmf)&sheepshaver_cpu::execute_sheep, NULL, + PPC_I(SHEEP), D_form, 6, 0, CFLOW_JUMP | CFLOW_TRAP } }; diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/amd64/dyngen-target-exec.h b/SheepShaver/src/kpx_cpu/src/cpu/jit/amd64/dyngen-target-exec.h new file mode 100644 index 00000000..d620c6c0 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/amd64/dyngen-target-exec.h @@ -0,0 +1,45 @@ +/* + * dyngen defines for micro operation code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DYNGEN_TARGET_EXEC_H +#define DYNGEN_TARGET_EXEC_H + +enum { + /* callee save registers */ +#define AREG0 "rbp" + AREG0_ID = 5, + +#define AREG1 "rbx" + AREG1_ID = 3, + +#define AREG2 "r12" + AREG2_ID = 12, + +#define AREG3 "r13" + AREG3_ID = 13, + +#define AREG4 "r14" + AREG4_ID = 14, + +#define AREG5 "r15" + AREG5_ID = 15, +}; + +#endif /* DYNGEN_TARGET_EXEC_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/amd64/jit-target-cache.hpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/amd64/jit-target-cache.hpp new file mode 100644 index 00000000..bfad07e4 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/amd64/jit-target-cache.hpp @@ -0,0 +1 @@ +#include "cpu/jit/t-dummy/jit-target-cache.hpp" diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen-ops.cpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen-ops.cpp new file mode 100644 index 00000000..01dfcd8c --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen-ops.cpp @@ -0,0 +1,548 @@ +/* + * dyngen-ops.hpp - Synthetic opcodes + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 "sysdeps.h" +#include "cpu/vm.hpp" +#include "cpu/jit/dyngen-exec.h" + +#include + +// We need at least 5 general purpose registers +struct basic_cpu; +#ifdef REG_CPU +register basic_cpu *CPU asm(REG_CPU); +#else +#define CPU ((basic_cpu *)CPUPARAM) +#endif +#if SIZEOF_VOID_P == 8 +#define REG32(X) ((uint32)X) +#else +#define REG32(X) X +#endif +#define A0 REG32(reg_A0) +register uintptr reg_A0 asm(REG_A0); +#define T0 REG32(reg_T0) +register uintptr reg_T0 asm(REG_T0); +#define T1 REG32(reg_T1) +register uintptr reg_T1 asm(REG_T1); +#ifdef REG_T2 +#define T2 REG32(reg_T2) +register uintptr reg_T2 asm(REG_T2); +#endif +#ifdef REG_T3 +#define T3 REG32(reg_T3) +register uintptr reg_T3 asm(REG_T3); +#endif + + +/** + * Native ALU operations optimization + **/ + +#ifndef do_udiv_32 +#define do_udiv_32(x, y) ((uint32)x / (uint32)y) +#endif +#ifndef do_sdiv_32 +#define do_sdiv_32(x, y) ((int32)x / (int32)y) +#endif +#ifndef do_rol_32 +#define do_rol_32(x, y) ((x << y) | (x >> (32 - y))) +#endif +#ifndef do_ror_32 +#define do_ror_32(x, y) ((x >> y) | (x << (32 - y))) +#endif + + +/** + * ALU operations + **/ + +#define DEFINE_OP(NAME, CODE) \ +void OPPROTO op_##NAME(void) \ +{ \ + CODE; \ +} + +// Register moves +DEFINE_OP(mov_32_T0_im, T0 = PARAM1); +DEFINE_OP(mov_32_T0_T1, T0 = T1); +DEFINE_OP(mov_32_T0_A0, T0 = A0); +DEFINE_OP(mov_32_T1_im, T1 = PARAM1); +DEFINE_OP(mov_32_T1_T0, T1 = T0); +DEFINE_OP(mov_32_T1_A0, T1 = A0); +DEFINE_OP(mov_32_A0_im, A0 = PARAM1); +DEFINE_OP(mov_32_A0_T0, A0 = T0); +DEFINE_OP(mov_32_A0_T1, A0 = T1); + +void OPPROTO op_mov_ad_A0_im(void) +{ +#if SIZEOF_VOID_P == 8 +#if defined(__x86_64__) + asm volatile ("movabsq $__op_param1,%" REG_A0); +#else +#error "unsupported 64-bit value move in" +#endif +#else + A0 = PARAM1; +#endif +} + +// Arithmetic operations +DEFINE_OP(add_32_T0_T1, T0 += T1); +DEFINE_OP(add_32_T0_im, T0 += PARAM1); +DEFINE_OP(add_32_T0_1, T0 += 1); +DEFINE_OP(add_32_T0_2, T0 += 2); +DEFINE_OP(add_32_T0_4, T0 += 4); +DEFINE_OP(add_32_T0_8, T0 += 8); +DEFINE_OP(sub_32_T0_T1, T0 -= T1); +DEFINE_OP(sub_32_T0_im, T0 -= PARAM1); +DEFINE_OP(sub_32_T0_1, T0 -= 1); +DEFINE_OP(sub_32_T0_2, T0 -= 2); +DEFINE_OP(sub_32_T0_4, T0 -= 4); +DEFINE_OP(sub_32_T0_8, T0 -= 8); +DEFINE_OP(add_32_T1_T0, T1 += T0); +DEFINE_OP(add_32_T1_im, T1 += PARAM1); +DEFINE_OP(add_32_T1_1, T1 += 1); +DEFINE_OP(add_32_T1_2, T1 += 2); +DEFINE_OP(add_32_T1_4, T1 += 4); +DEFINE_OP(add_32_T1_8, T1 += 8); +DEFINE_OP(sub_32_T1_T0, T1 -= T0); +DEFINE_OP(sub_32_T1_im, T1 -= PARAM1); +DEFINE_OP(sub_32_T1_1, T1 -= 1); +DEFINE_OP(sub_32_T1_2, T1 -= 2); +DEFINE_OP(sub_32_T1_4, T1 -= 4); +DEFINE_OP(sub_32_T1_8, T1 -= 8); +DEFINE_OP(add_32_A0_T1, A0 += T1); +DEFINE_OP(add_32_A0_im, A0 += PARAM1); +DEFINE_OP(add_32_A0_1, A0 += 1); +DEFINE_OP(add_32_A0_2, A0 += 2); +DEFINE_OP(add_32_A0_4, A0 += 4); +DEFINE_OP(add_32_A0_8, A0 += 8); +DEFINE_OP(sub_32_A0_T1, A0 -= T1); +DEFINE_OP(sub_32_A0_im, A0 -= PARAM1); +DEFINE_OP(sub_32_A0_1, A0 -= 1); +DEFINE_OP(sub_32_A0_2, A0 -= 2); +DEFINE_OP(sub_32_A0_4, A0 -= 4); +DEFINE_OP(sub_32_A0_8, A0 -= 8); +DEFINE_OP(umul_32_T0_T1, T0 = (uint32)T0 * (uint32)T1); +DEFINE_OP(smul_32_T0_T1, T0 = (int32)T0 * (int32)T1); +DEFINE_OP(udiv_32_T0_T1, T0 = do_udiv_32(T0, T1)); +DEFINE_OP(sdiv_32_T0_T1, T0 = do_sdiv_32(T0, T1)); +DEFINE_OP(xchg_32_T0_T1, { uint32 tmp = T0; T0 = T1; T1 = tmp; }); +DEFINE_OP(bswap_16_T0, T0 = bswap_16(T0)); +DEFINE_OP(bswap_32_T0, T0 = bswap_32(T0)); + +// Logical operations +DEFINE_OP(neg_32_T0, T0 = -T0); +DEFINE_OP(not_32_T0, T0 = !T0); +DEFINE_OP(not_32_T1, T1 = !T1); +DEFINE_OP(and_32_T0_T1, T0 &= T1); +DEFINE_OP(and_32_T0_im, T0 &= PARAM1); +DEFINE_OP(or_32_T0_T1, T0 |= T1); +DEFINE_OP(or_32_T0_im, T0 |= PARAM1); +DEFINE_OP(xor_32_T0_T1, T0 ^= T1); +DEFINE_OP(xor_32_T0_im, T0 ^= PARAM1); +DEFINE_OP(orc_32_T0_T1, T0 |= ~T1); +DEFINE_OP(andc_32_T0_T1, T0 &= ~T1); +DEFINE_OP(nand_32_T0_T1, T0 = ~(T0 & T1)); +DEFINE_OP(nor_32_T0_T1, T0 = ~(T0 | T1)); +DEFINE_OP(eqv_32_T0_T1, T0 = ~(T0 ^ T1)); +DEFINE_OP(and_logical_T0_T1, T0 = T0 && T1); +DEFINE_OP(or_logical_T0_T1, T0 = T0 || T1); + +// Shift/Rotate operations +DEFINE_OP(lsl_32_T0_T1, T0 = T0 << T1); +DEFINE_OP(lsl_32_T0_im, T0 = T0 << PARAM1); +DEFINE_OP(lsr_32_T0_T1, T0 = T0 >> T1); +DEFINE_OP(lsr_32_T0_im, T0 = T0 >> PARAM1); +DEFINE_OP(asr_32_T0_T1, T0 = ((int32)T0) >> T1); +DEFINE_OP(asr_32_T0_im, T0 = ((int32)T0) >> PARAM1); +DEFINE_OP(rol_32_T0_T1, T0 = do_rol_32(T0, T1)); +DEFINE_OP(rol_32_T0_im, T0 = do_rol_32(T0, PARAM1)); +DEFINE_OP(ror_32_T0_T1, T0 = do_ror_32(T0, T1)); +DEFINE_OP(ror_32_T0_im, T0 = do_ror_32(T0, PARAM1)); + +// Sign-/Zero-extension +DEFINE_OP(se_16_32_T0, T0 = (int32)(int16)T0); +DEFINE_OP(ze_16_32_T0, T0 = (uint32)(uint16)T0); +DEFINE_OP(se_8_32_T0, T0 = (int32)(int8)T0); +DEFINE_OP(ze_8_32_T0, T0 = (uint32)(uint8)T0); + +#undef DEFINE_OP + + +/** + * Native FP operations optimization + **/ + +#ifndef do_fabs +#define do_fabs(x) fabs(x) +#endif +#ifndef do_fadd +#define do_fadd(x, y) x + y +#endif +#ifndef do_fdiv +#define do_fdiv(x, y) x / y +#endif +#ifndef do_fmadd +#define do_fmadd(x, y, z) ((x * y) + z) +#endif +#ifndef do_fmsub +#define do_fmsub(x, y, z) ((x * y) - z) +#endif +#ifndef do_fmul +#define do_fmul(x, y) (x * y) +#endif +#ifndef do_fnabs +#define do_fnabs(x) -fabs(x) +#endif +#ifndef do_fneg +#define do_fneg(x) -x +#endif +#ifndef do_fnmadd +#define do_fnmadd(x, y, z) -((x * y) + z) +#endif +#ifndef do_fnmsub +#define do_fnmsub(x, y, z) -((x * y) - z) +#endif +#ifndef do_fsub +#define do_fsub(x, y) x - y +#endif +#ifndef do_fmov +#define do_fmov(x) x +#endif + + +/** + * FP double operations + **/ + +#if 0 + +double OPPROTO op_lfd(void) +{ + union { double d; uint64 j; } r; + r.j = vm_do_read_memory_8((uint64 *)T1); + return r.d; +} + +float OPPROTO op_lfs(void) +{ + union { float f; uint32 i; } r; + r.i = vm_do_read_memory_4((uint32 *)T1); + return r.f; +} + +#define DEFINE_OP(NAME, OP, ARGS) \ +double OPPROTO op_##NAME(double F0, double F1, double F2) \ +{ \ + return do_##OP ARGS; \ +} + +DEFINE_OP(fmov_F1, fmov, (F1)); +DEFINE_OP(fmov_F2, fmov, (F2)); +DEFINE_OP(fabs, fabs, (F0)); +DEFINE_OP(fadd, fadd, (F0, F1)); +DEFINE_OP(fdiv, fdiv, (F0, F1)); +DEFINE_OP(fmadd, fmadd, (F0, F1, F2)); +DEFINE_OP(fmsub, fmsub, (F0, F1, F2)); +DEFINE_OP(fmul, fmul, (F0, F1)); +DEFINE_OP(fnabs, fnabs, (F0)); +DEFINE_OP(fneg, fneg, (F0)); +DEFINE_OP(fnmadd, fnmadd, (F0, F1, F2)); +DEFINE_OP(fnmsub, fnmsub, (F0, F1, F2)); +DEFINE_OP(fsub, fsub, (F0, F1)); + +#undef DEFINE_OP + + +/** + * FP single operations + **/ + +#define DEFINE_OP(NAME, OP, ARGS) \ +float OPPROTO op_##NAME(float F0, float F1, float F2) \ +{ \ + return do_##OP ARGS; \ +} + +DEFINE_OP(fmovs_F1, fmov, (F1)); +DEFINE_OP(fmovs_F2, fmov, (F2)); +DEFINE_OP(fabss_F0, fabs, (F0)); +DEFINE_OP(fadds_F0_F1, fadd, (F0, F1)); +DEFINE_OP(fdivs_F0_F1, fdiv, (F0, F1)); +DEFINE_OP(fmadds_F0_F1_F2, fmadd, (F0, F1, F2)); +DEFINE_OP(fmsubs_F0_F1_F2, fmsub, (F0, F1, F2)); +DEFINE_OP(fmuls_F0_F1, fmul, (F0, F1)); +DEFINE_OP(fnabss_F0, fnabs, (F0)); +DEFINE_OP(fnegs_F0, fneg, (F0)); +DEFINE_OP(fnmadds_F0_F1_F2, fnmadd, (F0, F1, F2)); +DEFINE_OP(fnmsubs_F0_F1_F2, fnmsub, (F0, F1, F2)); +DEFINE_OP(fsubs_F0_F1, fsub, (F0, F1)); + +#undef DEFINE_OP + +#endif + + +/** + * Load/Store instructions + **/ + +#define im PARAM1 +#define DEFINE_OP(BITS,REG,SIZE,OFFSET) \ +void OPPROTO op_load_u##BITS##_##REG##_A0_##OFFSET(void) \ +{ \ + REG = (uint32)(uint##BITS)vm_read_memory_##SIZE(A0 + OFFSET); \ +} \ +void OPPROTO op_load_s##BITS##_##REG##_A0_##OFFSET(void) \ +{ \ + REG = (int32)(int##BITS)vm_read_memory_##SIZE(A0 + OFFSET); \ +} \ +void OPPROTO op_store_##BITS##_##REG##_A0_##OFFSET(void) \ +{ \ + vm_write_memory_##SIZE(A0 + OFFSET, REG); \ +} + +DEFINE_OP(32,T0,4,0); +DEFINE_OP(32,T0,4,im); +DEFINE_OP(32,T0,4,T1); +DEFINE_OP(16,T0,2,0); +DEFINE_OP(16,T0,2,im); +DEFINE_OP(16,T0,2,T1); +DEFINE_OP(8,T0,1,0); +DEFINE_OP(8,T0,1,im); +DEFINE_OP(8,T0,1,T1); + +#undef im +#undef DEFINE_OP + + +/** + * Control flow + **/ + +#ifdef __i386__ +#define FORCE_RET() asm volatile ("ret") +#endif +#ifdef __x86_64__ +#define FORCE_RET() asm volatile ("ret") +#endif +#ifdef __powerpc__ +#define FORCE_RET() asm volatile ("blr") +#endif +#ifdef __s390__ +#define FORCE_RET() asm volatile ("br %r14") +#endif +#ifdef __alpha__ +#define FORCE_RET() asm volatile ("ret") +#endif +#ifdef __ia64__ +#define FORCE_RET() asm volatile ("br.ret.sptk.many b0;;") +#endif +#ifdef __sparc__ +#define FORCE_RET() asm volatile ("jmpl %i0 + 8, %g0\n" \ + "nop") +#endif +#ifdef __arm__ +#define FORCE_RET() asm volatile ("b exec_loop") +#endif +#ifdef __mc68000 +#define FORCE_RET() asm volatile ("rts") +#endif + +#define SLOW_DISPATCH(TARGET) do { \ + static const void __attribute__((unused)) *label1 = &&dummy_label1; \ + static const void __attribute__((unused)) *label2 = &&dummy_label2; \ + goto *((void *)TARGET); \ + dummy_label1: \ + dummy_label2: \ + dyngen_barrier(); \ +} while (0) + +#if defined(__powerpc__) +#define FAST_DISPATCH(TARGET) asm volatile ("b " #TARGET) +#endif +#if defined(__i386__) || defined(__x86_64__) +#define FAST_DISPATCH(TARGET) asm volatile ("jmp " #TARGET) +#endif + +extern "C" void OPPROTO op_execute(uint8 *entry_point, basic_cpu *this_cpu); +void OPPROTO op_execute(uint8 *entry_point, basic_cpu *this_cpu) +{ + typedef void (*func_t)(void); + func_t func = (func_t)entry_point; +#ifdef REG_CPU + volatile uintptr saved_CPU = (uintptr)CPU; + CPU = this_cpu; +#endif +#ifdef REG_A0 + volatile uintptr saved_A0 = reg_A0; +#endif +#ifdef REG_T0 + volatile uintptr saved_T0 = reg_T0; +#endif +#ifdef REG_T1 + volatile uintptr saved_T1 = reg_T1; +#endif +#ifdef REG_T2 + volatile uintptr saved_T2 = reg_T2; +#endif +#ifdef REG_T3 + volatile uintptr saved_T3 = reg_T3; +#endif + SLOW_DISPATCH(entry_point); + func(); // NOTE: never called, fake to make compiler save return point + asm volatile (".section \".data\""); + asm volatile (".global op_exec_return_offset"); + asm volatile ("op_exec_return_offset:"); + asm volatile (".long 1f-op_execute"); + asm volatile (".size op_exec_return_offset,.-op_exec_return_offset"); + asm volatile (".previous"); + asm volatile ("1:"); +#ifdef REG_T3 + reg_T3 = saved_T3; +#endif +#ifdef REG_T2 + reg_T2 = saved_T2; +#endif +#ifdef REG_T1 + reg_T1 = saved_T1; +#endif +#ifdef REG_T0 + reg_T0 = saved_T0; +#endif +#ifdef REG_A0 + reg_A0 = saved_A0; +#endif +#ifdef REG_CPU + CPU = (basic_cpu *)saved_CPU; +#endif +} + +void OPPROTO op_jmp_slow(void) +{ + SLOW_DISPATCH(PARAM1); +} + +void OPPROTO op_jmp_fast(void) +{ +#ifdef FAST_DISPATCH + FAST_DISPATCH(__op_param1); +#else + SLOW_DISPATCH(PARAM1); +#endif +} + +// Register calling conventions based arches don't need a stack frame +#if defined(__powerpc__) || defined(__x86_64__) +#define DEFINE_OP(NAME, CODE) \ +static void OPPROTO impl_##NAME(void) \ +{ \ + asm volatile (#NAME ":"); \ + CODE; \ + FORCE_RET(); \ + asm volatile ("." #NAME ":"); \ + asm volatile (".size " #NAME ",." #NAME "-" #NAME); \ +} \ +void OPPROTO helper_##NAME(void) __attribute__((weak, alias(#NAME))); +#else +#define DEFINE_OP(NAME, CODE) \ +void OPPROTO NAME(void) \ +{ \ + CODE; \ +} +#endif + +#define CALL(CALL_CODE) CALL_CODE + +DEFINE_OP(op_invoke, { + typedef void (*func_t)(void); + func_t func = (func_t)reg_A0; + CALL(func()); +}); + +DEFINE_OP(op_invoke_T0, { + typedef void (*func_t)(uint32); + func_t func = (func_t)reg_A0; + CALL(func(T0)); +}); + +DEFINE_OP(op_invoke_im, { + typedef void (*func_t)(uint32); + func_t func = (func_t)reg_A0; + CALL(func(PARAM1)); +}); + +DEFINE_OP(op_invoke_CPU, { + typedef void (*func_t)(void *); + func_t func = (func_t)reg_A0; + CALL(func(CPU)); +}); + +DEFINE_OP(op_invoke_CPU_T0, { + typedef void (*func_t)(void *, uint32); + func_t func = (func_t)reg_A0; + CALL(func(CPU, T0)); +}); + +DEFINE_OP(op_invoke_CPU_im, { + typedef void (*func_t)(void *, uint32); + func_t func = (func_t)reg_A0; + CALL(func(CPU, PARAM1)); +}); + +DEFINE_OP(op_invoke_direct, { + typedef void (*func_t)(void); + func_t func = (func_t)PARAM1; + CALL(func()); +}); + +DEFINE_OP(op_invoke_direct_T0, { + typedef void (*func_t)(uint32); + func_t func = (func_t)PARAM1; + CALL(func(T0)); +}); + +DEFINE_OP(op_invoke_direct_im, { + typedef void (*func_t)(uint32); + func_t func = (func_t)PARAM1; + CALL(func(PARAM2)); +}); + +DEFINE_OP(op_invoke_direct_CPU, { + typedef void (*func_t)(void *); + func_t func = (func_t)PARAM1; + CALL(func(CPU)); +}); + +DEFINE_OP(op_invoke_direct_CPU_T0, { + typedef void (*func_t)(void *, uint32); + func_t func = (func_t)PARAM1; + CALL(func(CPU, T0)); +}); + +DEFINE_OP(op_invoke_direct_CPU_im, { + typedef void (*func_t)(void *, uint32); + func_t func = (func_t)PARAM1; + CALL(func(CPU, PARAM2)); +}); + +#undef DEFINE_OP diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen.cpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen.cpp new file mode 100644 index 00000000..999c5357 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen.cpp @@ -0,0 +1,104 @@ +/* + * dyngen-glue.hpp - Glue to QEMU dyngen infrastructure + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 "sysdeps.h" +#include "basic-dyngen.hpp" + +int __op_param1, __op_param2, __op_param3; +int __op_jmp0, __op_jmp1; + +#define DYNGEN_IMPL 1 +#define DEFINE_GEN(NAME,ARGS) void basic_dyngen::NAME ARGS +#include "basic-dyngen-ops.hpp" + +basic_dyngen::basic_dyngen(dyngen_cpu_base cpu) + : parent_cpu(cpu) +{ + execute_func = gen_start(); + gen_op_execute(); + gen_end(); + set_code_start(code_ptr()); +} + +void +basic_dyngen::gen_invoke(void (*func)()) +{ + if (direct_call_possible((uintptr)func)) + gen_op_invoke_direct((uintptr)func); + else { + gen_op_mov_ad_A0_im((uintptr)func); + gen_op_invoke(); + } +} + +void +basic_dyngen::gen_invoke_T0(void (*func)(uint32)) +{ + if (direct_call_possible((uintptr)func)) + gen_op_invoke_direct_T0((uintptr)func); + else { + gen_op_mov_ad_A0_im((uintptr)func); + gen_op_invoke_T0(); + } +} + +void +basic_dyngen::gen_invoke_im(void (*func)(uint32), uint32 value) +{ + if (direct_call_possible((uintptr)func)) + gen_op_invoke_direct_im((uintptr)func, value); + else { + gen_op_mov_ad_A0_im((uintptr)func); + gen_op_invoke_im(value); + } +} + +void +basic_dyngen::gen_invoke_CPU(void (*func)(dyngen_cpu_base)) +{ + if (direct_call_possible((uintptr)func)) + gen_op_invoke_direct_CPU((uintptr)func); + else { + gen_op_mov_ad_A0_im((uintptr)func); + gen_op_invoke_CPU(); + } +} + +void +basic_dyngen::gen_invoke_CPU_T0(void (*func)(dyngen_cpu_base, uint32)) +{ + if (direct_call_possible((uintptr)func)) + gen_op_invoke_direct_CPU_T0((uintptr)func); + else { + gen_op_mov_ad_A0_im((uintptr)func); + gen_op_invoke_CPU_T0(); + } +} + +void +basic_dyngen::gen_invoke_CPU_im(void (*func)(dyngen_cpu_base, uint32), uint32 value) +{ + if (direct_call_possible((uintptr)func)) + gen_op_invoke_direct_CPU_im((uintptr)func, value); + else { + gen_op_mov_ad_A0_im((uintptr)func); + gen_op_invoke_CPU_im(value); + } +} diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen.hpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen.hpp new file mode 100644 index 00000000..8c136f63 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/basic-dyngen.hpp @@ -0,0 +1,315 @@ +/* + * basic-dyngen.hpp - Basic code generator + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 BASIC_DYNGEN_H +#define BASIC_DYNGEN_H + +#include "cpu/jit/jit-config.hpp" +#include "cpu/jit/jit-cache.hpp" +#include JIT_TARGET_INCLUDE(jit-target-cache.hpp) + +#ifdef SHEEPSHAVER +class powerpc_cpu; +typedef powerpc_cpu *dyngen_cpu_base; +#else +class basic_cpu; +typedef basic_cpu *dyngen_cpu_base; +#endif + +class basic_dyngen + : public basic_jit_cache +{ + uint8 *execute_func; + uint8 *gen_code_start; + dyngen_cpu_base parent_cpu; + + // Can we generate a direct call to target function? + bool direct_jump_possible(uintptr target) const; + bool direct_call_possible(uintptr target) const; + + // Generic code generators +# define DEFINE_CST(NAME,VALUE) static const unsigned long NAME = VALUE; +# define DEFINE_GEN(NAME,ARGS) void NAME ARGS; +# include "basic-dyngen-ops.hpp" + +public: + + // Constructor, parent CPU required + basic_dyngen(dyngen_cpu_base cpu); + + // Return CPU context associated to this code generator + dyngen_cpu_base cpu() const + { return parent_cpu; } + + // Start code generation of a new block + // Align on 16-byte boundaries + // Returns pointer to entry point + uint8 *gen_start(); + + // Stop code generation of the block + // Returns FALSE if translation cache is full + bool gen_end() const; + + // Execute compiled function at ENTRY_POINT + void execute(uint8 *entry_point); + + // Return from compiled code + void gen_exec_return(); + + // Function calls + void gen_jmp(const uint8 *target); + void gen_invoke(void (*func)(void)); + void gen_invoke_T0(void (*func)(uint32)); + void gen_invoke_im(void (*func)(uint32), uint32 value); + void gen_invoke_CPU(void (*func)(dyngen_cpu_base)); + void gen_invoke_CPU_T0(void (*func)(dyngen_cpu_base, uint32)); + void gen_invoke_CPU_im(void (*func)(dyngen_cpu_base, uint32), uint32 value); + + // Raw aliases +#define DEFINE_ALIAS_RAW(NAME, ARGLIST, ARGS) \ + void gen_##NAME ARGLIST { gen_op_##NAME ARGS; } + +#define DEFINE_ALIAS_0(NAME) DEFINE_ALIAS_RAW(NAME,(),()) +#define DEFINE_ALIAS_1(NAME) DEFINE_ALIAS_RAW(NAME,(long p1),(p1)) +#define DEFINE_ALIAS_2(NAME) DEFINE_ALIAS_RAW(NAME,(long p1,long p2),(p1,p2)) +#define DEFINE_ALIAS_3(NAME) DEFINE_ALIAS_RAW(NAME,(long p1,long p2,long p3),(p1,p2,p3)) +#define DEFINE_ALIAS(NAME, N) DEFINE_ALIAS_##N(NAME) + + // Register moves + DEFINE_ALIAS(mov_32_T0_im,1); + DEFINE_ALIAS(mov_32_T0_T1,0); + DEFINE_ALIAS(mov_32_T0_A0,0); + DEFINE_ALIAS(mov_32_T1_im,1); + DEFINE_ALIAS(mov_32_T1_T0,0); + DEFINE_ALIAS(mov_32_T1_A0,0); + DEFINE_ALIAS(mov_32_A0_im,1); + DEFINE_ALIAS(mov_32_A0_T0,0); + DEFINE_ALIAS(mov_32_A0_T1,0); + DEFINE_ALIAS(mov_ad_A0_im,1); + + // Arithmetic operations + DEFINE_ALIAS(add_32_T0_T1,0); + void gen_add_32_T0_im(int32 value); + DEFINE_ALIAS(sub_32_T0_T1,0); + void gen_sub_32_T0_im(int32 value); + DEFINE_ALIAS(add_32_T1_T0,0); + void gen_add_32_T1_im(int32 value); + DEFINE_ALIAS(sub_32_T1_T0,0); + void gen_sub_32_T1_im(int32 value); + DEFINE_ALIAS(add_32_A0_T1,0); + void gen_add_32_A0_im(int32 value); + DEFINE_ALIAS(sub_32_A0_T1,0); + void gen_sub_32_A0_im(int32 value); + DEFINE_ALIAS(umul_32_T0_T1,0); + DEFINE_ALIAS(smul_32_T0_T1,0); + DEFINE_ALIAS(udiv_32_T0_T1,0); + DEFINE_ALIAS(sdiv_32_T0_T1,0); + DEFINE_ALIAS(xchg_32_T0_T1,0); + DEFINE_ALIAS(bswap_16_T0,0); + DEFINE_ALIAS(bswap_32_T0,0); + + // Logical operations + DEFINE_ALIAS(neg_32_T0,0); + DEFINE_ALIAS(not_32_T0,0); + DEFINE_ALIAS(not_32_T1,0); + DEFINE_ALIAS(and_32_T0_T1,0); + DEFINE_ALIAS(and_32_T0_im,1); + DEFINE_ALIAS(or_32_T0_T1,0); + DEFINE_ALIAS(or_32_T0_im,1); + DEFINE_ALIAS(xor_32_T0_T1,0); + DEFINE_ALIAS(xor_32_T0_im,1); + DEFINE_ALIAS(orc_32_T0_T1,0); + DEFINE_ALIAS(andc_32_T0_T1,0); + DEFINE_ALIAS(nand_32_T0_T1,0); + DEFINE_ALIAS(nor_32_T0_T1,0); + DEFINE_ALIAS(eqv_32_T0_T1,0); + DEFINE_ALIAS(and_logical_T0_T1,0); + DEFINE_ALIAS(or_logical_T0_T1,0); + + // Shift/Rotate operations + DEFINE_ALIAS(lsl_32_T0_T1,0); + DEFINE_ALIAS(lsl_32_T0_im,1); + DEFINE_ALIAS(lsr_32_T0_T1,0); + DEFINE_ALIAS(lsr_32_T0_im,1); + DEFINE_ALIAS(asr_32_T0_T1,0); + DEFINE_ALIAS(asr_32_T0_im,1); + DEFINE_ALIAS(rol_32_T0_T1,0); + DEFINE_ALIAS(rol_32_T0_im,1); + DEFINE_ALIAS(ror_32_T0_T1,0); + DEFINE_ALIAS(ror_32_T0_im,1); + + // Sign-/Zero-extension + DEFINE_ALIAS(se_16_32_T0,0); + DEFINE_ALIAS(ze_16_32_T0,0); + DEFINE_ALIAS(se_8_32_T0,0); + DEFINE_ALIAS(ze_8_32_T0,0); + + // Jump instructions + DEFINE_ALIAS(jmp_slow,1); + DEFINE_ALIAS(jmp_fast,1); + + // Load/Store instructions + DEFINE_ALIAS(load_u32_T0_A0_T1,0); + void gen_load_u32_T0_A0_im(int32 offset); + DEFINE_ALIAS(load_s32_T0_A0_T1,0); + void gen_load_s32_T0_A0_im(int32 offset); + DEFINE_ALIAS(load_u16_T0_A0_T1,0); + void gen_load_u16_T0_A0_im(int32 offset); + DEFINE_ALIAS(load_s16_T0_A0_T1,0); + void gen_load_s16_T0_A0_im(int32 offset); + DEFINE_ALIAS(load_u8_T0_A0_T1,0); + void gen_load_u8_T0_A0_im(int32 offset); + DEFINE_ALIAS(load_s8_T0_A0_T1,0); + void gen_load_s8_T0_A0_im(int32 offset); + DEFINE_ALIAS(store_32_T0_A0_T1,0); + void gen_store_32_T0_A0_im(int32 offset); + DEFINE_ALIAS(store_16_T0_A0_T1,0); + void gen_store_16_T0_A0_im(int32 offset); + DEFINE_ALIAS(store_8_T0_A0_T1,0); + void gen_store_8_T0_A0_im(int32 offset); + +#undef DEFINE_ALIAS +#undef DEFINE_ALIAS_0 +#undef DEFINE_ALIAS_1 +#undef DEFINE_ALIAS_2 +#undef DEFINE_ALIAS_3 +#undef DEFINE_ALIAS_RAW +}; + +inline bool +basic_dyngen::direct_jump_possible(uintptr target) const +{ +#if defined(__powerpc__) + const uintptr LI_OFFSET_MAX = 1 << 26; + return (((target - (uintptr)code_ptr()) < LI_OFFSET_MAX) || + (((uintptr)code_ptr() - target) < LI_OFFSET_MAX)); +#endif +#if defined(__i386__) + return true; +#endif +#if defined(__x86_64__) + const intptr offset = (intptr)target - (intptr)code_ptr() - sizeof(void *); + return offset <= 0xffffffff; +#endif + return false; +} + +inline void +basic_dyngen::gen_jmp(const uint8 *target_p) +{ + const uintptr target = (uintptr)target_p; + if (direct_jump_possible(target)) + gen_op_jmp_fast(target); + else + gen_op_jmp_slow(target); +} + +inline void +basic_dyngen::execute(uint8 *entry_point) +{ + typedef void (*func_t)(uint8 *, dyngen_cpu_base); + func_t func = (func_t)execute_func; + func(entry_point, parent_cpu); +} + +inline void +basic_dyngen::gen_exec_return() +{ + gen_jmp(execute_func + op_exec_return_offset); +} + +inline bool +basic_dyngen::direct_call_possible(uintptr target) const +{ +#if defined(__powerpc__) + const uintptr LI_OFFSET_MAX = 1 << 26; + return (((target - (uintptr)code_ptr()) < LI_OFFSET_MAX) || + (((uintptr)code_ptr() - target) < LI_OFFSET_MAX)); +#endif +#if defined(__i386__) + return true; +#endif +#if defined(__x86_64__) + const intptr offset = (intptr)target - (intptr)code_ptr() - sizeof(void *); + return offset <= 0xffffffff; +#endif + return false; +} + +inline uint8 * +basic_dyngen::gen_start() +{ + while ((uintptr)code_ptr() & 15) + inc_code_ptr(1); + gen_code_start = code_ptr(); + return gen_code_start; +} + +inline bool +basic_dyngen::gen_end() const +{ + flush_icache_range((unsigned long)gen_code_start, (unsigned long)code_ptr()); + return !full_translation_cache(); +} + +#define DEFINE_OP(OP,REG) \ +inline void \ +basic_dyngen::gen_##OP##_32_##REG##_im(int32 value) \ +{ \ + if (value == 0) return; \ + else if (value == 1) gen_op_##OP##_32_##REG##_1(); \ + else if (value == 2) gen_op_##OP##_32_##REG##_2(); \ + else if (value == 4) gen_op_##OP##_32_##REG##_4(); \ + else if (value == 8) gen_op_##OP##_32_##REG##_8(); \ + else gen_op_##OP##_32_##REG##_im(value); \ +} + +DEFINE_OP(add,A0); +DEFINE_OP(add,T0); +DEFINE_OP(add,T1); +DEFINE_OP(sub,A0); +DEFINE_OP(sub,T0); +DEFINE_OP(sub,T1); + +#undef DEFINE_OP + +#define DEFINE_OP(NAME,REG,SIZE) \ +inline void \ +basic_dyngen::gen_##NAME##_##SIZE##_##REG##_A0_im(int32 offset) \ +{ \ + if (offset == 0) \ + gen_op_##NAME##_##SIZE##_##REG##_A0_0(); \ + else \ + gen_op_##NAME##_##SIZE##_##REG##_A0_im(offset); \ +} + +DEFINE_OP(load,T0,u32); +DEFINE_OP(load,T0,s32); +DEFINE_OP(store,T0,32); +DEFINE_OP(load,T0,u16); +DEFINE_OP(load,T0,s16); +DEFINE_OP(store,T0,16); +DEFINE_OP(load,T0,u8); +DEFINE_OP(load,T0,s8); +DEFINE_OP(store,T0,8); + +#undef DEFINE_OP + +#endif /* BASIC_DYNGEN_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/cxxdemangle.cpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/cxxdemangle.cpp new file mode 100644 index 00000000..13e9c979 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/cxxdemangle.cpp @@ -0,0 +1,32 @@ +/* + * cxxdemangle.cpp - C++ demangler + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 "sysdeps.h" +#include "cxxdemangle.h" + +#if defined(__GNUC__) && (__GXX_ABI_VERSION > 0) +#include + +char * +cxx_demangle(const char *mangled_name, char *buf, size_t *n, int *status) +{ + return abi::__cxa_demangle(mangled_name, buf, n, status); +} +#endif diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/cxxdemangle.h b/SheepShaver/src/kpx_cpu/src/cpu/jit/cxxdemangle.h new file mode 100644 index 00000000..1f833466 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/cxxdemangle.h @@ -0,0 +1,55 @@ +/* + * cxxdemangle.h - C++ demangler + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 CXX_DEMANGLE_H +#define CXX_DEMANGLE_H + +/** + * cxx_demangle + * + * Following GCC 3.0 ABI: + * + * + * - MANGLED-NAME is a pointer to a null-terminated array of + * characters + * + * - BUF may be null. If it is non-null, then N must also be + * nonnull, and BUF is a pointer to an array, of at least *N + * characters, that was allocated using malloc(). + * + * - STATUS points to an int that is used as an error indicator. It + * is permitted to be null, in which case the user just doesn't + * get any detailed error information. + * + * Codes: 0: success + * -1: memory allocation failure + * -2: invalid mangled name + * -3: invalid arguments (e.g. BUG nonnull and N null) + **/ + +#ifdef __cplusplus +extern "C" +#endif +char *cxx_demangle(const char *mangled_name, + char *buf, + size_t *n, + int *status); + +#endif /* CXX_DEMANGLE_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/dummy/jit-target-cache.hpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/dummy/jit-target-cache.hpp new file mode 100644 index 00000000..2587991a --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/dummy/jit-target-cache.hpp @@ -0,0 +1,28 @@ +/* + * jit-target-cache.hpp - Target specific code to invalidate cache + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 JIT_TARGET_CACHE_H +#define JIT_TARGET_CACHE_H + +static inline void flush_icache_range(unsigned long, unsigned long) +{ +} + +#endif /* JIT_TARGET_CACHE_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen-exec.h b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen-exec.h new file mode 100644 index 00000000..eb208ea5 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen-exec.h @@ -0,0 +1,103 @@ +/* + * dyngen defines for micro operation code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DYNGEN_EXEC_H +#define DYNGEN_EXEC_H + +#include "cpu/jit/jit-config.hpp" +#include JIT_TARGET_INCLUDE(dyngen-target-exec.h) + +/* define virtual register set */ +#define REG_A0 AREG0 +#define REG_A0_ID AREG0_ID +#define REG_T0 AREG1 +#define REG_T0_ID AREG1_ID +#define REG_T1 AREG2 +#define REG_T1_ID AREG2_ID +#ifdef AREG3 +#define REG_T2 AREG3 +#define REG_T2_ID AREG3_ID +#endif +#ifdef AREG4 +#define REG_T3 AREG4 +#define REG_T3_ID AREG4_ID +#endif +#ifdef AREG5 +#define REG_CPU AREG5 +#define REG_CPU_ID AREG5_ID +#endif +#ifdef FREG0 +#define REG_F0 FREG0 +#define REG_F0_ID FREG0_ID +#endif +#ifdef FREG1 +#define REG_F1 FREG1 +#define REG_F1_ID FREG1_ID +#endif +#ifdef FREG2 +#define REG_F2 FREG2 +#define REG_F2_ID FREG2_ID +#endif +#ifdef FREG3 +#define REG_F3 FREG3 +#define REG_F3_ID FREG3_ID +#endif + +// Force only one return point +#define dyngen_barrier() asm volatile ("") + +#ifndef OPPROTO +#define OPPROTO +#endif + +#ifdef __alpha__ +/* the symbols are considered non exported so a br immediate is generated */ +#define __hidden __attribute__((visibility("hidden"))) +#else +#define __hidden +#endif + +#ifdef __alpha__ +/* Suggested by Richard Henderson. This will result in code like + ldah $0,__op_param1($29) !gprelhigh + lda $0,__op_param1($0) !gprellow + We can then conveniently change $29 to $31 and adapt the offsets to + emit the appropriate constant. */ +#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; }) +#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; }) +#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; }) +extern int __op_param1 __hidden; +extern int __op_param2 __hidden; +extern int __op_param3 __hidden; +#else +extern int __op_param1, __op_param2, __op_param3; +#define PARAM1 ((long)(&__op_param1)) +#define PARAM2 ((long)(&__op_param2)) +#define PARAM3 ((long)(&__op_param3)) +#endif + +#ifndef REG_CPU +extern int __op_cpuparam; +#define CPUPARAM ((long)(&__op_cpuparam)) +#endif + +extern int __op_jmp0, __op_jmp1; + +#endif /* DYNGEN_EXEC_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c new file mode 100644 index 00000000..b066c9f3 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c @@ -0,0 +1,1414 @@ +/* + * Generic Dynamic compiler generator + * + * Copyright (c) 2003 Fabrice Bellard + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "cxxdemangle.h" + +/* host cpu defs */ + +#if defined(__i386__) +#define HOST_I386 1 +#elif defined(__powerpc__) +#define HOST_PPC 1 +#elif defined(__s390__) +#define HOST_S390 1 +#elif defined(__alpha__) +#define HOST_ALPHA 1 +#elif defined(__ia64__) +#define HOST_IA64 1 +#elif defined(__sparc__) +#define HOST_SPARC 1 +#elif defined(__x86_64__) +#define HOST_AMD64 1 +#endif + + +/* elf format definitions. We use these macros to test the CPU to + allow cross compilation (this tool must be ran on the build + platform) */ +#if defined(HOST_I386) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_386 +#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) +#undef ELF_USES_RELOCA + +#elif defined(HOST_AMD64) + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_X86_64 +#define elf_check_arch(x) ((x) == EM_X86_64) +#define ELF_USES_RELOCA + +#elif defined(HOST_PPC) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_PPC +#define elf_check_arch(x) ((x) == EM_PPC) +#define ELF_USES_RELOCA + +#elif defined(HOST_S390) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_S390 +#define elf_check_arch(x) ((x) == EM_S390) +#define ELF_USES_RELOCA + +#elif defined(HOST_ALPHA) + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_ALPHA +#define elf_check_arch(x) ((x) == EM_ALPHA) +#define ELF_USES_RELOCA + +#elif defined(HOST_IA64) + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_IA_64 +#define elf_check_arch(x) ((x) == EM_IA_64) +#define ELF_USES_RELOCA + +#elif defined(HOST_SPARC) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_SPARC +#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS) +#define ELF_USES_RELOCA + +#elif defined(HOST_SPARC64) + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_SPARCV9 +#define elf_check_arch(x) ((x) == EM_SPARCV9) +#define ELF_USES_RELOCA + +#elif defined(HOST_ARM) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_ARM +#define elf_check_arch(x) ((x) == EM_ARM) +#define ELF_USES_RELOC + +#else +#error unsupported CPU - please update the code +#endif + +#include "elf-defs.h" + +#ifndef ElfW +# if ELF_CLASS == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif +#endif + +#if ELF_CLASS == ELFCLASS32 +typedef int32_t host_long; +typedef uint32_t host_ulong; +#define swabls(x) swab32s(x) +#else +typedef int64_t host_long; +typedef uint64_t host_ulong; +#define swabls(x) swab64s(x) +#endif + +typedef ElfW(Ehdr) elfhdr; +typedef ElfW(Shdr) elf_shdr; +typedef ElfW(Phdr) elf_phdr; +typedef ElfW(Rel) elf_rel; +typedef ElfW(Rela) elf_rela; + +#ifdef ELF_USES_RELOCA +#define ELF_RELOC elf_rela +#define SHT_RELOC SHT_RELA +#else +#define ELF_RELOC elf_rel +#define SHT_RELOC SHT_REL +#endif + +enum { + OUT_GEN_OP, + OUT_CODE, + OUT_INDEX_OP, + OUT_GEN_OP_ALL, +}; + +/* all dynamically generated functions begin with this code */ +#define OP_PREFIX "op_" + +int elf_must_swap(elfhdr *h) +{ + union { + uint32_t i; + uint8_t b[4]; + } swaptest; + + swaptest.i = 1; + return (h->e_ident[EI_DATA] == ELFDATA2MSB) != + (swaptest.b[0] == 0); +} + +void swab16s(uint16_t *p) +{ + *p = bswap_16(*p); +} + +void swab32s(uint32_t *p) +{ + *p = bswap_32(*p); +} + +void swab64s(uint64_t *p) +{ + *p = bswap_64(*p); +} + +void elf_swap_ehdr(elfhdr *h) +{ + swab16s(&h->e_type); /* Object file type */ + swab16s(&h-> e_machine); /* Architecture */ + swab32s(&h-> e_version); /* Object file version */ + swabls(&h-> e_entry); /* Entry point virtual address */ + swabls(&h-> e_phoff); /* Program header table file offset */ + swabls(&h-> e_shoff); /* Section header table file offset */ + swab32s(&h-> e_flags); /* Processor-specific flags */ + swab16s(&h-> e_ehsize); /* ELF header size in bytes */ + swab16s(&h-> e_phentsize); /* Program header table entry size */ + swab16s(&h-> e_phnum); /* Program header table entry count */ + swab16s(&h-> e_shentsize); /* Section header table entry size */ + swab16s(&h-> e_shnum); /* Section header table entry count */ + swab16s(&h-> e_shstrndx); /* Section header string table index */ +} + +void elf_swap_shdr(elf_shdr *h) +{ + swab32s(&h-> sh_name); /* Section name (string tbl index) */ + swab32s(&h-> sh_type); /* Section type */ + swabls(&h-> sh_flags); /* Section flags */ + swabls(&h-> sh_addr); /* Section virtual addr at execution */ + swabls(&h-> sh_offset); /* Section file offset */ + swabls(&h-> sh_size); /* Section size in bytes */ + swab32s(&h-> sh_link); /* Link to another section */ + swab32s(&h-> sh_info); /* Additional section information */ + swabls(&h-> sh_addralign); /* Section alignment */ + swabls(&h-> sh_entsize); /* Entry size if section holds table */ +} + +void elf_swap_phdr(elf_phdr *h) +{ + swab32s(&h->p_type); /* Segment type */ + swabls(&h->p_offset); /* Segment file offset */ + swabls(&h->p_vaddr); /* Segment virtual address */ + swabls(&h->p_paddr); /* Segment physical address */ + swabls(&h->p_filesz); /* Segment size in file */ + swabls(&h->p_memsz); /* Segment size in memory */ + swab32s(&h->p_flags); /* Segment flags */ + swabls(&h->p_align); /* Segment alignment */ +} + +void elf_swap_rel(ELF_RELOC *rel) +{ + swabls(&rel->r_offset); + swabls(&rel->r_info); +#ifdef ELF_USES_RELOCA + swabls(&rel->r_addend); +#endif +} + +/* ELF file info */ +int do_swap; +elf_shdr *shdr; +uint8_t **sdata; +elfhdr ehdr; +ElfW(Sym) *symtab; +int nb_syms; +char *strtab; +int text_shndx; + +uint16_t get16(uint16_t *p) +{ + uint16_t val; + val = *p; + if (do_swap) + val = bswap_16(val); + return val; +} + +uint32_t get32(uint32_t *p) +{ + uint32_t val; + val = *p; + if (do_swap) + val = bswap_32(val); + return val; +} + +void put16(uint16_t *p, uint16_t val) +{ + if (do_swap) + val = bswap_16(val); + *p = val; +} + +void put32(uint32_t *p, uint32_t val) +{ + if (do_swap) + val = bswap_32(val); + *p = val; +} + +void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "dyngen: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + + +elf_shdr *find_elf_section(elf_shdr *shdr, int shnum, const char *shstr, + const char *name) +{ + int i; + const char *shname; + elf_shdr *sec; + + for(i = 0; i < shnum; i++) { + sec = &shdr[i]; + if (!sec->sh_name) + continue; + shname = shstr + sec->sh_name; + if (!strcmp(shname, name)) + return sec; + } + return NULL; +} + +int find_reloc(int sh_index) +{ + elf_shdr *sec; + int i; + + for(i = 0; i < ehdr.e_shnum; i++) { + sec = &shdr[i]; + if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) + return i; + } + return 0; +} + +void *load_data(int fd, long offset, unsigned int size) +{ + char *data; + + data = malloc(size); + if (!data) + return NULL; + lseek(fd, offset, SEEK_SET); + if (read(fd, data, size) != size) { + free(data); + return NULL; + } + return data; +} + +int strstart(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + p = str; + q = val; + while (*q != '\0') { + if (*p != *q) + return 0; + p++; + q++; + } + if (ptr) + *ptr = p; + return 1; +} + +#ifdef HOST_ARM + +int arm_emit_ldr_info(const char *name, unsigned long start_offset, + FILE *outfile, uint8_t *p_start, uint8_t *p_end, + ELF_RELOC *relocs, int nb_relocs) +{ + uint8_t *p; + uint32_t insn; + int offset, min_offset, pc_offset, data_size; + uint8_t data_allocated[1024]; + unsigned int data_index; + + memset(data_allocated, 0, sizeof(data_allocated)); + + p = p_start; + min_offset = p_end - p_start; + while (p < p_start + min_offset) { + insn = get32((uint32_t *)p); + if ((insn & 0x0d5f0000) == 0x051f0000) { + /* ldr reg, [pc, #im] */ + offset = insn & 0xfff; + if (!(insn & 0x00800000)) + offset = -offset; + if ((offset & 3) !=0) + error("%s:%04x: ldr pc offset must be 32 bit aligned", + name, start_offset + p - p_start); + pc_offset = p - p_start + offset + 8; + if (pc_offset <= (p - p_start) || + pc_offset >= (p_end - p_start)) + error("%s:%04x: ldr pc offset must point inside the function code", + name, start_offset + p - p_start); + if (pc_offset < min_offset) + min_offset = pc_offset; + if (outfile) { + /* ldr position */ + fprintf(outfile, " arm_ldr_ptr->ptr = ptr() + %d;\n", + p - p_start); + /* ldr data index */ + data_index = ((p_end - p_start) - pc_offset - 4) >> 2; + fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", + data_index); + fprintf(outfile, " arm_ldr_ptr++;\n"); + if (data_index >= sizeof(data_allocated)) + error("%s: too many data", name); + if (!data_allocated[data_index]) { + ELF_RELOC *rel; + int i, addend, type; + const char *sym_name, *p; + char relname[1024]; + + data_allocated[data_index] = 1; + + /* data value */ + addend = get32((uint32_t *)(p_start + pc_offset)); + relname[0] = '\0'; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset == (pc_offset + start_offset)) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + /* the compiler leave some unnecessary references to the code */ + if (strstart(sym_name, "__op_param", &p)) { + snprintf(relname, sizeof(relname), "param%s", p); + } else { + snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + if (type != R_ARM_ABS32) + error("%s: unsupported data relocation", name); + break; + } + } + fprintf(outfile, " arm_data_ptr[%d] = 0x%x", + data_index, addend); + if (relname[0] != '\0') + fprintf(outfile, " + %s", relname); + fprintf(outfile, ";\n"); + } + } + } + p += 4; + } + data_size = (p_end - p_start) - min_offset; + if (data_size > 0 && outfile) { + fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2); + } + + /* the last instruction must be a mov pc, lr */ + if (p == p_start) + goto arm_ret_error; + p -= 4; + insn = get32((uint32_t *)p); + if ((insn & 0xffff0000) != 0xe91b0000) { + arm_ret_error: + if (!outfile) + printf("%s: invalid epilog\n", name); + } + return p - p_start; +} +#endif + +static void print_code(FILE *outfile, const char *name, const uint8_t *code_p, int code_size) +{ + int i; + fprintf(outfile, " static const uint8 %s_code[] = {", name); + for (i = 0; i < code_size; i++) { + if ((i % 12) == 0) { + if (i != 0) + fprintf(outfile, ","); + fprintf(outfile, "\n "); + } + else + fprintf(outfile, ", "); + fprintf(outfile, "0x%02x", code_p[i]); + } + fprintf(outfile, "\n };\n"); +} + + +#define MAX_ARGS 3 + +/* generate op code */ +void gen_code(const char *name, const char *demangled_name, + host_ulong offset, host_ulong size, + FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, + int gen_switch, const char *prefix) +{ + int copy_size = 0; + uint8_t *p_start, *p_end; + host_ulong start_offset; + int nb_args, i, n; + uint8_t args_present[MAX_ARGS]; + const char *sym_name, *p; + ELF_RELOC *rel; + int op_execute = 0; + + if (strncmp(name, "op_execute", 10) == 0) + op_execute = 1; + + /* Compute exact size excluding prologue and epilogue instructions. + * Increment start_offset to skip epilogue instructions, then compute + * copy_size the indicate the size of the remaining instructions (in + * bytes). + */ + p_start = text + offset; + p_end = p_start + size; + start_offset = offset; + if (op_execute) + copy_size = p_end - p_start; + else + switch(ELF_ARCH) { + case EM_386: + case EM_X86_64: + { + int len; + len = p_end - p_start; + if (len == 0) + error("empty code for %s", name); + if (p_end[-1] == 0xc3) { + len--; + } else { + error("ret or jmp expected at the end of %s", name); + } + copy_size = len; + } + break; + case EM_PPC: + { + uint8_t *p; + p = (void *)(p_end - 4); + if (p == p_start) + error("empty code for %s", name); + if (get32((uint32_t *)p) != 0x4e800020) + error("blr expected at the end of %s", name); + copy_size = p - p_start; + } + break; + case EM_S390: + { + uint8_t *p; + p = (void *)(p_end - 2); + if (p == p_start) + error("empty code for %s", name); + if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4) + error("br %%r14 expected at the end of %s", name); + copy_size = p - p_start; + } + break; + case EM_ALPHA: + { + uint8_t *p; + p = p_end - 4; + if (p == p_start) + error("empty code for %s", name); + if (get32((uint32_t *)p) != 0x6bfa8001) + error("ret expected at the end of %s", name); + copy_size = p - p_start; + } + break; + case EM_IA_64: + { + uint8_t *p; + p = (void *)(p_end - 4); + if (p == p_start) + error("empty code for %s", name); + /* br.ret.sptk.many b0;; */ + /* 08 00 84 00 */ + if (get32((uint32_t *)p) != 0x00840008) + error("br.ret.sptk.many b0;; expected at the end of %s", name); + copy_size = p - p_start; + } + break; + case EM_SPARC: + case EM_SPARC32PLUS: + { + uint32_t start_insn, end_insn1, end_insn2; + uint8_t *p; + p = (void *)(p_end - 8); + if (p <= p_start) + error("empty code for %s", name); + start_insn = get32((uint32_t *)(p_start + 0x0)); + end_insn1 = get32((uint32_t *)(p + 0x0)); + end_insn2 = get32((uint32_t *)(p + 0x4)); + if ((start_insn & ~0x1fff) == 0x9de3a000) { + p_start += 0x4; + start_offset += 0x4; + if ((int)(start_insn | ~0x1fff) < -128) + error("Found bogus save at the start of %s", name); + if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + error("ret; restore; not found at end of %s", name); + } else { + error("No save at the beginning of %s", name); + } +#if 0 + /* Skip a preceeding nop, if present. */ + if (p > p_start) { + skip_insn = get32((uint32_t *)(p - 0x4)); + if (skip_insn == 0x01000000) + p -= 4; + } +#endif + copy_size = p - p_start; + } + break; + case EM_SPARCV9: + { + uint32_t start_insn, end_insn1, end_insn2, skip_insn; + uint8_t *p; + p = (void *)(p_end - 8); + if (p <= p_start) + error("empty code for %s", name); + start_insn = get32((uint32_t *)(p_start + 0x0)); + end_insn1 = get32((uint32_t *)(p + 0x0)); + end_insn2 = get32((uint32_t *)(p + 0x4)); + if ((start_insn & ~0x1fff) == 0x9de3a000) { + p_start += 0x4; + start_offset += 0x4; + if ((int)(start_insn | ~0x1fff) < -256) + error("Found bogus save at the start of %s", name); + if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + error("ret; restore; not found at end of %s", name); + } else { + error("No save at the beginning of %s", name); + } + + /* Skip a preceeding nop, if present. */ + if (p > p_start) { + skip_insn = get32((uint32_t *)(p - 0x4)); + if (skip_insn == 0x01000000) + p -= 4; + } + + copy_size = p - p_start; + } + break; +#ifdef HOST_ARM + case EM_ARM: + if ((p_end - p_start) <= 16) + error("%s: function too small", name); + if (get32((uint32_t *)p_start) != 0xe1a0c00d || + (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 || + get32((uint32_t *)(p_start + 8)) != 0xe24cb004) + error("%s: invalid prolog", name); + p_start += 12; + start_offset += 12; + copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, + relocs, nb_relocs); + break; +#endif + default: + error("unknown ELF architecture"); + } + + /* compute the number of arguments by looking at the relocations */ + for(i = 0;i < MAX_ARGS; i++) + args_present[i] = 0; + + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + (p_end - p_start)) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + n = strtoul(p, NULL, 10); + if (n > MAX_ARGS) + error("too many arguments in %s", name); + args_present[n - 1] = 1; + } + } + } + + nb_args = 0; + while (nb_args < MAX_ARGS && args_present[nb_args]) + nb_args++; + for(i = nb_args; i < MAX_ARGS; i++) { + if (args_present[i]) + error("inconsistent argument numbering in %s", name); + } + + assert(gen_switch == 3); + if (gen_switch == 3) { + const char *func_name = name; + if (prefix && strstr(func_name, prefix) == func_name) + func_name += strlen(prefix); + + fprintf(outfile, "DEFINE_GEN(gen_%s,(", func_name); + if (nb_args == 0) { + fprintf(outfile, "void"); + } else { + for(i = 0; i < nb_args; i++) { + if (i != 0) + fprintf(outfile, ", "); + fprintf(outfile, "long param%d", i + 1); + } + } + fprintf(outfile, "))\n"); + fprintf(outfile, "#ifdef DYNGEN_IMPL\n"); + fprintf(outfile, "{\n"); + print_code(outfile, name, p_start + start_offset - offset, copy_size); + + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + (p_end - p_start)) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (*sym_name && + !strstart(sym_name, "__op_param", NULL) && + !strstart(sym_name, "__op_cpuparam", NULL) && + !strstart(sym_name, "__op_jmp", NULL)) + error("unexpected external symbol %s", sym_name); + } + } + + fprintf(outfile, " copy_block(%s_code, %d);\n", name, copy_size); + + /* emit code offset information */ + { + ElfW(Sym) *sym; + const char *sym_name, *p; + uint32_t val; // FIXME: emulated CPU dependant?! + int n; + + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + sym_name = strtab + sym->st_name; + if (strstart(sym_name, "__op_label", &p)) { + uint8_t *ptr; + unsigned long offset; + + /* test if the variable refers to a label inside + the code we are generating */ + ptr = sdata[sym->st_shndx]; + if (!ptr) + error("__op_labelN in invalid section"); + offset = sym->st_value; + val = *(uint32_t *)(ptr + offset); +#ifdef ELF_USES_RELOCA + { + int reloc_shndx, nb_relocs1, j; + + /* try to find a matching relocation */ + reloc_shndx = find_reloc(sym->st_shndx); + if (reloc_shndx) { + nb_relocs1 = shdr[reloc_shndx].sh_size / + shdr[reloc_shndx].sh_entsize; + rel = (ELF_RELOC *)sdata[reloc_shndx]; + for(j = 0; j < nb_relocs1; j++) { + if (rel->r_offset == offset) { + val = rel->r_addend; + break; + } + rel++; + } + } + } +#endif + + if (val >= start_offset && val < start_offset + copy_size) { + n = strtol(p, NULL, 10); + fprintf(outfile, " label_offsets[%d] = %d + (code_ptr() - gen_code_buf);\n", n, val - start_offset); + } + } + } + } + + /* patch relocations */ +#if defined(HOST_I386) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else if (strstart(sym_name, "__op_cpuparam", &p)) { + snprintf(name, sizeof(name), "(long)(cpu())", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = get32((uint32_t *)(text + rel->r_offset)); + switch(type) { + case R_386_32: + fprintf(outfile, " *(uint32_t *)(code_ptr() + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_386_PC32: + fprintf(outfile, " *(uint32_t *)(code_ptr() + %d) = %s - (long)(code_ptr() + %d) + %d;\n", + rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + break; + default: + error("unsupported i386 relocation (%d)", type); + } + } + } + } +#elif defined(HOST_AMD64) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_X86_64_64: + fprintf(outfile, " *(uintptr *)(code_ptr() + %d) = (uintptr)%s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_X86_64_32: + fprintf(outfile, " *(uint32 *)(code_ptr() + %d) = (uint32)%s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_X86_64_32S: + fprintf(outfile, " *(uint32 *)(code_ptr() + %d) = (int32)%s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_X86_64_PC32: + fprintf(outfile, " *(uint32 *)(code_ptr() + %d) = %s - (long)(code_ptr() + %d) + %d;\n", + rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + break; + default: + error("unsupported AMD64 relocation (%d)", type); + } + } + } + } +#elif defined(HOST_PPC) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_jmp", &p)) { + int n; + n = strtol(p, NULL, 10); + /* __op_jmp relocations are done at + runtime to do translated block + chaining: the offset of the instruction + needs to be stored */ + fprintf(outfile, " jmp_offsets[%d] = %d + (code_ptr() - gen_code_buf);\n", + n, rel->r_offset - start_offset); + continue; + } + + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_PPC_ADDR32: + fprintf(outfile, " *(uint32_t *)(code_ptr() + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_PPC_ADDR16_LO: + fprintf(outfile, " *(uint16_t *)(code_ptr() + %d) = (%s + %d);\n", + rel->r_offset - start_offset, name, addend); + break; + case R_PPC_ADDR16_HI: + fprintf(outfile, " *(uint16_t *)(code_ptr() + %d) = (%s + %d) >> 16;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_PPC_ADDR16_HA: + fprintf(outfile, " *(uint16_t *)(code_ptr() + %d) = (%s + %d + 0x8000) >> 16;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_PPC_REL24: + /* warning: must be at 32 MB distancy */ + fprintf(outfile, " *(uint32_t *)(code_ptr() + %d) = (*(uint32_t *)(code_ptr() + %d) & ~0x03fffffc) | ((%s - (long)(code_ptr() + %d) + %d) & 0x03fffffc);\n", + rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + break; + default: + error("unsupported powerpc relocation (%d)", type); + } + } + } + } +#elif defined(HOST_S390) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_390_32: + fprintf(outfile, " *(uint32_t *)(code_ptr() + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_390_16: + fprintf(outfile, " *(uint16_t *)(code_ptr() + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_390_8: + fprintf(outfile, " *(uint8_t *)(code_ptr() + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + default: + error("unsupported s390 relocation (%d)", type); + } + } + } + } +#elif defined(HOST_ALPHA) + { + for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { + int type; + + type = ELF64_R_TYPE(rel->r_info); + sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; + switch (type) { + case R_ALPHA_GPDISP: + /* The gp is just 32 bit, and never changes, so it's easiest to emit it + as an immediate instead of constructing it from the pv or ra. */ + fprintf(outfile, " immediate_ldah(code_ptr() + %ld, gp);\n", + rel->r_offset - start_offset); + fprintf(outfile, " immediate_lda(code_ptr() + %ld, gp);\n", + rel->r_offset - start_offset + rel->r_addend); + break; + case R_ALPHA_LITUSE: + /* jsr to literal hint. Could be used to optimize to bsr. Ignore for + now, since some called functions (libc) need pv to be set up. */ + break; + case R_ALPHA_HINT: + /* Branch target prediction hint. Ignore for now. Should be already + correct for in-function jumps. */ + break; + case R_ALPHA_LITERAL: + /* Load a literal from the GOT relative to the gp. Since there's only a + single gp, nothing is to be done. */ + break; + case R_ALPHA_GPRELHIGH: + /* Handle fake relocations against __op_param symbol. Need to emit the + high part of the immediate value instead. Other symbols need no + special treatment. */ + if (strstart(sym_name, "__op_param", &p)) + fprintf(outfile, " immediate_ldah(code_ptr() + %ld, param%s);\n", + rel->r_offset - start_offset, p); + break; + case R_ALPHA_GPRELLOW: + if (strstart(sym_name, "__op_param", &p)) + fprintf(outfile, " immediate_lda(code_ptr() + %ld, param%s);\n", + rel->r_offset - start_offset, p); + break; + case R_ALPHA_BRSGP: + /* PC-relative jump. Tweak offset to skip the two instructions that try to + set up the gp from the pv. */ + fprintf(outfile, " fix_bsr(code_ptr() + %ld, (uint8_t *) &%s - (code_ptr() + %ld + 4) + 8);\n", + rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset); + break; + default: + error("unsupported Alpha relocation (%d)", type); + } + } + } + } +#elif defined(HOST_IA64) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF64_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_IA64_LTOFF22: + error("must implemnt R_IA64_LTOFF22 relocation"); + case R_IA64_PCREL21B: + error("must implemnt R_IA64_PCREL21B relocation"); + default: + error("unsupported ia64 relocation (%d)", type); + } + } + } + } +#elif defined(HOST_SPARC) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + if (sym_name[0] == '.') + snprintf(name, sizeof(name), + "(long)(&__dot_%s)", + sym_name + 1); + else + snprintf(name, sizeof(name), + "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_SPARC_32: + fprintf(outfile, " *(uint32_t *)(code_ptr() + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_SPARC_HI22: + fprintf(outfile, + " *(uint32_t *)(code_ptr() + %d) = " + "((*(uint32_t *)(code_ptr() + %d)) " + " & ~0x3fffff) " + " | (((%s + %d) >> 10) & 0x3fffff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, + name, addend); + break; + case R_SPARC_LO10: + fprintf(outfile, + " *(uint32_t *)(code_ptr() + %d) = " + "((*(uint32_t *)(code_ptr() + %d)) " + " & ~0x3ff) " + " | ((%s + %d) & 0x3ff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, + name, addend); + break; + case R_SPARC_WDISP30: + fprintf(outfile, + " *(uint32_t *)(code_ptr() + %d) = " + "((*(uint32_t *)(code_ptr() + %d)) " + " & ~0x3fffffff) " + " | ((((%s + %d) - (long)(code_ptr() + %d))>>2) " + " & 0x3fffffff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, + name, addend, + rel->r_offset - start_offset); + break; + default: + error("unsupported sparc relocation (%d)", type); + } + } + } + } +#elif defined(HOST_SPARC64) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF64_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_SPARC_32: + fprintf(outfile, " *(uint32_t *)(code_ptr() + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_SPARC_HI22: + fprintf(outfile, + " *(uint32_t *)(code_ptr() + %d) = " + "((*(uint32_t *)(code_ptr() + %d)) " + " & ~0x3fffff) " + " | (((%s + %d) >> 10) & 0x3fffff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, + name, addend); + break; + case R_SPARC_LO10: + fprintf(outfile, + " *(uint32_t *)(code_ptr() + %d) = " + "((*(uint32_t *)(code_ptr() + %d)) " + " & ~0x3ff) " + " | ((%s + %d) & 0x3ff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, + name, addend); + break; + case R_SPARC_WDISP30: + fprintf(outfile, + " *(uint32_t *)(code_ptr() + %d) = " + "((*(uint32_t *)(code_ptr() + %d)) " + " & ~0x3fffffff) " + " | ((((%s + %d) - (long)(code_ptr() + %d))>>2) " + " & 0x3fffffff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, + name, addend, + rel->r_offset - start_offset); + break; + default: + error("unsupported sparc64 relocation (%d)", type); + } + } + } + } +#elif defined(HOST_ARM) + { + char name[256]; + int type; + int addend; + + arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end, + relocs, nb_relocs); + + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + /* the compiler leave some unnecessary references to the code */ + if (sym_name[0] == '\0') + continue; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = get32((uint32_t *)(text + rel->r_offset)); + switch(type) { + case R_ARM_ABS32: + fprintf(outfile, " *(uint32_t *)(code_ptr() + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_ARM_PC24: + fprintf(outfile, " arm_reloc_pc24((uint32_t *)(code_ptr() + %d), 0x%x, %s);\n", + rel->r_offset - start_offset, addend, name); + break; + default: + error("unsupported arm relocation (%d)", type); + } + } + } + } +#else +#error unsupported CPU +#endif + fprintf(outfile, " inc_code_ptr(%d);\n", copy_size); + fprintf(outfile, "}\n"); + fprintf(outfile, "#endif\n"); + fprintf(outfile, "\n"); + } +} + +/* load an elf object file */ +int load_elf(const char *filename, FILE *outfile, int out_type) +{ + int fd; + elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec; + int i, j; + ElfW(Sym) *sym; + char *shstr; + uint8_t *text; + ELF_RELOC *relocs; + int nb_relocs; + ELF_RELOC *rel; + elf_shdr *data_sec; + uint8_t *data; + int data_shndx; + + fd = open(filename, O_RDONLY); + if (fd < 0) + error("can't open file '%s'", filename); + + /* Read ELF header. */ + if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) + error("unable to read file header"); + + /* Check ELF identification. */ + if (ehdr.e_ident[EI_MAG0] != ELFMAG0 + || ehdr.e_ident[EI_MAG1] != ELFMAG1 + || ehdr.e_ident[EI_MAG2] != ELFMAG2 + || ehdr.e_ident[EI_MAG3] != ELFMAG3 + || ehdr.e_ident[EI_VERSION] != EV_CURRENT) { + error("bad ELF header"); + } + + do_swap = elf_must_swap(&ehdr); + if (do_swap) + elf_swap_ehdr(&ehdr); + if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) + error("Unsupported ELF class"); + if (ehdr.e_type != ET_REL) + error("ELF object file expected"); + if (ehdr.e_version != EV_CURRENT) + error("Invalid ELF version"); + if (!elf_check_arch(ehdr.e_machine)) + error("Unsupported CPU (e_machine=%d)", ehdr.e_machine); + + /* read section headers */ + shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(elf_shdr)); + if (do_swap) { + for(i = 0; i < ehdr.e_shnum; i++) { + elf_swap_shdr(&shdr[i]); + } + } + + /* read all section data */ + sdata = malloc(sizeof(void *) * ehdr.e_shnum); + memset(sdata, 0, sizeof(void *) * ehdr.e_shnum); + + for(i = 0;i < ehdr.e_shnum; i++) { + sec = &shdr[i]; + if (sec->sh_type != SHT_NOBITS) + sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size); + } + + sec = &shdr[ehdr.e_shstrndx]; + shstr = sdata[ehdr.e_shstrndx]; + + /* swap relocations */ + for(i = 0; i < ehdr.e_shnum; i++) { + sec = &shdr[i]; + if (sec->sh_type == SHT_RELOC) { + nb_relocs = sec->sh_size / sec->sh_entsize; + if (do_swap) { + for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++) + elf_swap_rel(rel); + } + } + } + + /* data section */ + data_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".data"); + if (!data_sec) + error("could not find .data section"); + data_shndx = data_sec - shdr; + data = sdata[data_shndx]; + + /* text section */ + text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text"); + if (!text_sec) + error("could not find .text section"); + text_shndx = text_sec - shdr; + text = sdata[text_shndx]; + + /* find text relocations, if any */ + relocs = NULL; + nb_relocs = 0; + i = find_reloc(text_shndx); + if (i != 0) { + relocs = (ELF_RELOC *)sdata[i]; + nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize; + } + + symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab"); + if (!symtab_sec) + error("could not find .symtab section"); + strtab_sec = &shdr[symtab_sec->sh_link]; + + symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr]; + strtab = sdata[symtab_sec->sh_link]; + + nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); + if (do_swap) { + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + swab32s(&sym->st_name); + swabls(&sym->st_value); + swabls(&sym->st_size); + swab16s(&sym->st_shndx); + } + } + + assert(out_type == OUT_GEN_OP_ALL); + if (out_type == OUT_GEN_OP_ALL) { + /* generate gen_xxx functions */ + int status; + size_t nf, nd = 256; + char *demangled_name, *func_name; + if ((demangled_name = malloc(nd)) == NULL) + return -1; + if ((func_name = malloc(nf = nd)) == NULL) + return -1; + + fprintf(outfile, "#ifndef DEFINE_CST\n"); + fprintf(outfile, "#define DEFINE_CST(NAME, VALUE)\n"); + fprintf(outfile, "#endif\n"); + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + const char *name; + name = strtab + sym->st_name; + /* demangle C++ symbols */ + demangled_name = cxx_demangle(name, demangled_name, &nd, &status); + if (status == 0 && strstart(demangled_name, OP_PREFIX, NULL)) { + /* get real function name */ + char *p = strchr(demangled_name, '('); + if (p && !strstart(p, "()::label", NULL)) { + int func_name_length = p - demangled_name; + if (nd > nf) { + nf = nd; + if ((func_name = realloc(func_name, nf)) == NULL) + return -1; + } + strncpy(func_name, demangled_name, func_name_length); + func_name[func_name_length] = '\0'; + /* emit code generator */ + if (sym->st_shndx != (text_sec - shdr)) + error("invalid section for opcode (%s:0x%x)", name, sym->st_shndx); + gen_code(func_name, demangled_name, sym->st_value, sym->st_size, outfile, + text, relocs, nb_relocs, 3, NULL); + } + } + else if (strstart(name, OP_PREFIX "execute", NULL)) { + strcpy(func_name, name); + if (sym->st_shndx != (text_sec - shdr)) + error("invalid section for opcode (0x%x)", sym->st_shndx); + gen_code(func_name, NULL, sym->st_value, sym->st_size, outfile, + text, relocs, nb_relocs, 3, NULL); + } + else if (strstart(name, OP_PREFIX "exec_return_offset", NULL)) { + host_ulong *long_p; + if (sym->st_shndx != (data_sec - shdr)) + error("invalid section for data (0x%x)", sym->st_shndx); + fprintf(outfile, "DEFINE_CST(%s,0x%xL)\n\n", name, *((host_ulong *)(data + sym->st_value))); + } + else if (strstart(name, OP_PREFIX "invoke", NULL)) { + const char *prefix = "helper_"; + strcpy(func_name, prefix); + strcat(func_name, name); + if (sym->st_shndx != (text_sec - shdr)) + error("invalid section for opcode (0x%x)", sym->st_shndx); + gen_code(func_name, NULL, sym->st_value, sym->st_size, outfile, + text, relocs, nb_relocs, 3, prefix); + } + } + fprintf(outfile, "#undef DEFINE_CST\n"); + fprintf(outfile, "#undef DEFINE_GEN\n"); + + free(func_name); + free(demangled_name); + } + + close(fd); + return 0; +} + +void usage(void) +{ + printf("dyngen (c) 2003 Fabrice Bellard\n" + "usage: dyngen [-o outfile] objfile\n" + "Generate a dynamic code generator from an object file\n" + ); + exit(1); +} + +int main(int argc, char **argv) +{ + int c, out_type; + const char *filename, *outfilename; + FILE *outfile; + + outfilename = "out.c"; + out_type = OUT_GEN_OP_ALL; + for(;;) { + c = getopt(argc, argv, "ho:"); + if (c == -1) + break; + switch(c) { + case 'h': + usage(); + break; + case 'o': + outfilename = optarg; + break; + } + } + if (optind >= argc) + usage(); + filename = argv[optind]; + outfile = fopen(outfilename, "w"); + if (!outfile) + error("could not open '%s'", outfilename); + load_elf(filename, outfile, out_type); + fclose(outfile); + return 0; +} + +/* + Local variables: + tab-width: 4 + indent-tabs-mode: nil + End: + */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-cache.cpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-cache.cpp new file mode 100644 index 00000000..3c57d3b9 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-cache.cpp @@ -0,0 +1,71 @@ +/* + * jit-cache.cpp - Translation cache management + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 "sysdeps.h" +#include "vm_alloc.h" +#include "cpu/jit/jit-cache.hpp" + +#define DEBUG 0 +#include "debug.h" + +basic_jit_cache::basic_jit_cache(uint32 init_cache_size) + : tcode_start(NULL), code_start(NULL), code_p(NULL), code_end(NULL) +{ + init_translation_cache(init_cache_size); +} + +basic_jit_cache::~basic_jit_cache() +{ + kill_translation_cache(); +} + +bool +basic_jit_cache::init_translation_cache(uint32 size) +{ + // Round up translation cache size to next 16 KB boundaries + const uint32 roundup = 16 * 1024; + cache_size = (size + JIT_CACHE_SIZE_GUARD + roundup - 1) & -roundup; + + tcode_start = (uint8 *)vm_acquire(cache_size, VM_MAP_PRIVATE | VM_MAP_32BIT); + if (tcode_start == VM_MAP_FAILED) { + tcode_start = NULL; + return false; + } + + if (vm_protect(tcode_start, cache_size, + VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) { + vm_release(tcode_start, cache_size); + tcode_start = NULL; + return false; + } + + D(bug("basic_jit_cache: Translation cache: %d KB at %p\n", cache_size / 1024, tcode_start)); + code_start = tcode_start; + code_p = code_start; + code_end = code_p + cache_size; + return true; +} + +void +basic_jit_cache::kill_translation_cache() +{ + if (tcode_start) + vm_release(tcode_start, cache_size); +} diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-cache.hpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-cache.hpp new file mode 100644 index 00000000..92830214 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-cache.hpp @@ -0,0 +1,112 @@ +/* + * jit-cache.hpp - Translation cache management + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 JIT_CACHE_H +#define JIT_CACHE_H + +/** + * Basic translation cache + **/ + +class basic_jit_cache +{ + // Default cache size (2 MB) + static const uint32 JIT_CACHE_SIZE = 2 * 1024 * 1024; + static const uint32 JIT_CACHE_SIZE_GUARD = 4096; + uint32 cache_size; + + // Translation cache (allocated base, current pointer, end pointer) + uint8 *tcode_start; + uint8 *code_start; + uint8 *code_p; + uint8 *code_end; + +protected: + + // Initialize translation cache + bool init_translation_cache(uint32 size); + void kill_translation_cache(); + + // Initialize user code start + void set_code_start(uint8 *ptr); + + // Get & increase current position + void inc_code_ptr(int offset) { code_p += offset; } +public: + uint8 *code_ptr() const { return code_p; } + +public: + + // Default constructor & destructor + basic_jit_cache(uint32 init_cache_size = JIT_CACHE_SIZE); + ~basic_jit_cache(); + + // Invalidate translation cache + void invalidate_cache(); + bool full_translation_cache() const + { return code_p >= code_end; } + + // Emit code to translation cache + template< typename T > + void emit_generic(T v); + void emit_8(uint8 v) { emit_generic(v); } + void emit_16(uint16 v) { emit_generic(v); } + void emit_32(uint32 v) { emit_generic(v); } + void emit_64(uint64 v) { emit_generic(v); } + void emit_ptr(uintptr v) { emit_generic(v); } + void copy_block(const uint8 *block, uint32 size); + void emit_block(const uint8 *block, uint32 size); +}; + +inline void +basic_jit_cache::set_code_start(uint8 *ptr) +{ + assert(ptr >= tcode_start && ptr < code_end); + code_start = ptr; +} + +inline void +basic_jit_cache::invalidate_cache() +{ + code_p = code_start; +} + +template< class T > +inline void +basic_jit_cache::emit_generic(T v) +{ + *((T *)code_ptr()) = v; + inc_code_ptr(sizeof(T)); +} + +inline void +basic_jit_cache::copy_block(const uint8 *block, uint32 size) +{ + memcpy(code_ptr(), block, size); +} + +inline void +basic_jit_cache::emit_block(const uint8 *block, uint32 size) +{ + copy_block(block, size); + inc_code_ptr(size); +} + +#endif /* JIT_CACHE_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-config.hpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-config.hpp new file mode 100644 index 00000000..1227922b --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/jit-config.hpp @@ -0,0 +1,86 @@ +/* + * jit-config.hpp - JIT config utils + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 JIT_CONFIG_H +#define JIT_CONFIG_H + +/** + * ENABLE_DYNGEN + * + * Define to enable the portable "JIT1" engine based on code + * inlining technique as implemented in QEMU. + **/ + +#ifndef ENABLE_DYNGEN +#define ENABLE_DYNGEN 0 +#endif + +/** + * DYNGEN_ASM_OPTS + * + * Define to permit host inline asm optimizations. This is + * particularly useful to compute emulated condition code + * registers. + **/ + +#ifndef DYNGEN_ASM_OPTS +#define DYNGEN_ASM_OPTS 1 +#endif + +/** + * Helpers to reach JIT backends headers + **/ + +#if defined(__powerpc__) || defined(__ppc__) +#define JIT_TARGET ppc +#endif +#if defined(__i386__) +#define JIT_TARGET x86 +#endif +#if defined(__x86_64__) +#define JIT_TARGET amd64 +#endif +#if defined(__s390__) +#define JIT_TARGET s390 +#endif +#if defined(__alpha__) +#define JIT_TARGET alpha +#endif +#if defined(__ia64__) +#define JIT_TARGET ia64 +#endif +#if defined(__sparc__) +#define JIT_TARGET sparc +#endif +#if defined(__arm__) +#define JIT_TARGET arm +#endif +#if defined(__mc68000) +#define JIT_TARGET m68k +#endif +#ifndef JIT_TARGET +#error "Unsupport architecture for JIT1" +#endif + +#define JIT_PATH_CONCAT(X, Y) X/Y +#define JIT_MAKE_HEADER(PATH, HEADER) +#define JIT_TARGET_INCLUDE(HEADER) JIT_MAKE_HEADER(JIT_PATH_CONCAT(cpu/jit,JIT_TARGET),HEADER) + +#endif /* JIT_CONFIG_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/ppc/dyngen-target-exec.h b/SheepShaver/src/kpx_cpu/src/cpu/jit/ppc/dyngen-target-exec.h new file mode 100644 index 00000000..e1363e65 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/ppc/dyngen-target-exec.h @@ -0,0 +1,71 @@ +/* + * dyngen defines for micro operation code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DYNGEN_TARGET_EXEC_H +#define DYNGEN_TARGET_EXEC_H + +enum { +#define AREG0 "r27" + AREG0_ID = 27, + +#define AREG1 "r24" + AREG1_ID = 24, + +#define AREG2 "r25" + AREG2_ID = 25, + +#define AREG3 "r26" + AREG3_ID = 26, + +#define AREG4 "r16" + AREG4_ID = 16, + +#define AREG5 "r17" + AREG5_ID = 17, + +#define AREG6 "r18" + AREG6_ID = 18, + +#define AREG7 "r19" + AREG7_ID = 19, + +#define AREG8 "r20" + AREG8_ID = 20, + +#define AREG9 "r21" + AREG9_ID = 21, + +#define AREG10 "r22" + AREG10_ID = 22, + +#define AREG11 "r23" + AREG11_ID = 23, + +#define FREG0 "f1" + FREG0_ID = 1, + +#define FREG1 "f2" + FREG1_ID = 2, + +#define FREG2 "f3" + FREG2_ID = 3, +}; + +#endif /* DYNGEN_TARGET_EXEC_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/ppc/jit-target-cache.hpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/ppc/jit-target-cache.hpp new file mode 100644 index 00000000..57f0211b --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/ppc/jit-target-cache.hpp @@ -0,0 +1,44 @@ +/* + * jit-target-cache.hpp - Target specific code to invalidate cache + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 JIT_TARGET_CACHE_H +#define JIT_TARGET_CACHE_H + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + const int MIN_CACHE_LINE_SIZE = 8; /* conservative value */ + + unsigned long p; + + p = start & ~(MIN_CACHE_LINE_SIZE - 1); + stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); + + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} + +#endif /* JIT_TARGET_CACHE_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/x86/dyngen-target-exec.h b/SheepShaver/src/kpx_cpu/src/cpu/jit/x86/dyngen-target-exec.h new file mode 100644 index 00000000..1f2d260d --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/x86/dyngen-target-exec.h @@ -0,0 +1,39 @@ +/* + * dyngen defines for micro operation code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DYNGEN_TARGET_EXEC_H +#define DYNGEN_TARGET_EXEC_H + +enum { + /* callee save registers */ +#define AREG0 "ebp" + AREG0_ID = 5, + +#define AREG1 "ebx" + AREG1_ID = 3, + +#define AREG2 "esi" + AREG2_ID = 6, + +#define AREG3 "edi" + AREG3_ID = 7, +}; + +#endif /* DYNGEN_TARGET_EXEC_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/x86/jit-target-cache.hpp b/SheepShaver/src/kpx_cpu/src/cpu/jit/x86/jit-target-cache.hpp new file mode 100644 index 00000000..bfad07e4 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/x86/jit-target-cache.hpp @@ -0,0 +1 @@ +#include "cpu/jit/t-dummy/jit-target-cache.hpp" diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-blockinfo.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-blockinfo.hpp index b20129b9..ee3210a8 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-blockinfo.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-blockinfo.hpp @@ -37,7 +37,12 @@ struct powerpc_block_info uint32 opcode; }; +#if PPC_DECODE_CACHE decode_info * di; +#endif +#if PPC_ENABLE_JIT + uint8 * entry_point; +#endif }; #endif /* PPC_BLOCKINFO_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-config.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-config.hpp index 36a8a40a..8f64e91c 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-config.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-config.hpp @@ -90,6 +90,18 @@ #endif +/** + * PPC_ENABLE_JIT + * + * Define to 1 if dynamic translation is used. This requires + * dyngen to be enabled first. + **/ + +#ifndef PPC_ENABLE_JIT +#define PPC_ENABLE_JIT ENABLE_DYNGEN +#endif + + /** * PPC_EXECUTE_DUMP_STATE * @@ -115,6 +127,19 @@ #endif +/** + * PPC_PROFILE_COMPILE_TIME + * + * Define to enable some compile time statistics. This concerns + * time spent into the decoder (PPC_DECODE_CACHE case) or total + * time spent into the dynamic translator (PPC_ENABLE_JIT case). + **/ + +#ifndef PPC_PROFILE_COMPILE_TIME +#define PPC_PROFILE_COMPILE_TIME 0 +#endif + + /** * Sanity checks and features enforcements **/ @@ -124,4 +149,8 @@ #undef PPC_NO_STATIC_II_INDEX_TABLE #endif +#if PPC_ENABLE_JIT +#undef PPC_DECODE_CACHE +#endif + #endif /* PPC_CONFIG_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp index 01145288..6f3ef6ab 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp @@ -22,6 +22,13 @@ #include "vm_alloc.h" #include "cpu/vm.hpp" #include "cpu/ppc/ppc-cpu.hpp" +#ifndef SHEEPSHAVER +#include "basic-kernel.hpp" +#endif + +#if PPC_ENABLE_JIT +#include "cpu/jit/dyngen-exec.h" +#endif #if ENABLE_MON #include "mon.h" @@ -31,9 +38,6 @@ #define DEBUG 0 #include "debug.h" -// Define to gather some compile time statistics -#define PROFILE_COMPILE_TIME 1 - void powerpc_cpu::set_register(int id, any_register const & value) { if (id >= powerpc_registers::GPR(0) && id <= powerpc_registers::GPR(31)) { @@ -198,6 +202,19 @@ void powerpc_cpu::dump_log(const char *filename) } #endif +#if ENABLE_MON +static uint32 mon_read_byte_ppc(uintptr addr) +{ + return *((uint8 *)addr); +} + +static void mon_write_byte_ppc(uintptr addr, uint32 b) +{ + uint8 *m = (uint8 *)addr; + *m = b; +} +#endif + void powerpc_cpu::initialize() { init_flight_recorder(); @@ -210,6 +227,7 @@ void powerpc_cpu::initialize() // Init syscalls handler execute_do_syscall = NULL; + syscall_exit_code = -1; // Init field2mask for (int i = 0; i < 256; i++) { @@ -227,9 +245,11 @@ void powerpc_cpu::initialize() #if ENABLE_MON mon_init(); + mon_read_byte = mon_read_byte_ppc; + mon_write_byte = mon_write_byte_ppc; #endif -#if PROFILE_COMPILE_TIME +#if PPC_PROFILE_COMPILE_TIME compile_count = 0; compile_time = 0; emul_start_time = clock(); @@ -238,10 +258,13 @@ void powerpc_cpu::initialize() powerpc_cpu::~powerpc_cpu() { -#if PROFILE_COMPILE_TIME +#if PPC_PROFILE_COMPILE_TIME clock_t emul_end_time = clock(); const char *type = NULL; +#if PPC_ENABLE_JIT + type = "compile"; +#endif #if PPC_DECODE_CACHE type = "predecode"; #endif @@ -312,6 +335,12 @@ bool powerpc_cpu::check_spcflags() #endif if (spcflags().test(SPCFLAG_CPU_EXEC_RETURN)) { spcflags().clear(SPCFLAG_CPU_EXEC_RETURN); +#ifndef SHEEPSHAVER + // FIXME: add unwind info to the translation cache? Otherwise + // we have to manually handle the exit syscall here + if (syscall_exit_code >= 0) + throw kernel_syscall_exit(syscall_exit_code); +#endif return false; } if (spcflags().test(SPCFLAG_CPU_ENTER_MON)) { @@ -338,10 +367,37 @@ void powerpc_cpu::execute(uint32 entry, bool enable_cache) #if PPC_EXECUTE_DUMP_STATE const bool dump_state = true; #endif +#if PPC_ENABLE_JIT + if (enable_cache) { + for (;;) { + block_info *bi = compile_block(pc()); + + // Execute all cached blocks + for (;;) { + codegen.execute(bi->entry_point); + + if (!spcflags().empty()) { + if (!check_spcflags()) + return; + + // Force redecoding if cache was invalidated + if (spcflags().test(SPCFLAG_JIT_EXEC_RETURN)) { + spcflags().clear(SPCFLAG_JIT_EXEC_RETURN); + break; + } + } + + if ((bi->pc != pc()) && ((bi = block_cache.find(pc())) == NULL)) + break; + } + } + return; + } +#endif #if PPC_DECODE_CACHE if (enable_cache) { for (;;) { -#if PROFILE_COMPILE_TIME +#if PPC_PROFILE_COMPILE_TIME compile_count++; clock_t start_time = clock(); #endif @@ -359,6 +415,7 @@ void powerpc_cpu::execute(uint32 entry, bool enable_cache) if (dump_state) { di->opcode = opcode; di->execute = nv_mem_fun(&powerpc_cpu::dump_instruction); + di++; } #endif #if PPC_FLIGHT_RECORDER @@ -369,7 +426,7 @@ void powerpc_cpu::execute(uint32 entry, bool enable_cache) } #endif di->opcode = opcode; - di->execute = ii->decode ? ii->decode(this, opcode) : ii->execute; + di->execute = ii->decode.ptr() ? ii->decode(this, opcode) : ii->execute; di++; #if PPC_EXECUTE_DUMP_STATE if (dump_state) { @@ -392,7 +449,7 @@ void powerpc_cpu::execute(uint32 entry, bool enable_cache) block_cache.add_to_cl_list(bi); block_cache.add_to_active_list(bi); decode_cache_p += bi->size; -#if PROFILE_COMPILE_TIME +#if PPC_PROFILE_COMPILE_TIME compile_time += (clock() - start_time); #endif @@ -440,7 +497,7 @@ void powerpc_cpu::execute(uint32 entry, bool enable_cache) if (is_logging()) record_step(opcode); #endif - assert(ii->execute != 0); + assert(ii->execute.ptr() != 0); ii->execute(this, opcode); #if PPC_EXECUTE_DUMP_STATE if (dump_state) @@ -476,7 +533,9 @@ void powerpc_cpu::init_decode_cache() // Leave enough room to last calls to dump state functions decode_cache_end_p -= 2; #endif +#endif +#if PPC_DECODE_CACHE || PPC_ENABLE_JIT block_cache.initialize(); #endif } @@ -490,18 +549,23 @@ void powerpc_cpu::kill_decode_cache() void powerpc_cpu::invalidate_cache() { -#if PPC_DECODE_CACHE +#if PPC_DECODE_CACHE || PPC_ENABLE_JIT block_cache.clear(); block_cache.initialize(); - decode_cache_p = decode_cache; spcflags().set(SPCFLAG_JIT_EXEC_RETURN); #endif +#if PPC_ENABLE_JIT + codegen.invalidate_cache(); +#endif +#if PPC_DECODE_CACHE + decode_cache_p = decode_cache; +#endif } void powerpc_cpu::invalidate_cache_range(uintptr start, uintptr end) { D(bug("Invalidate cache block [%08x - %08x]\n", start, end)); -#if PPC_DECODE_CACHE +#if PPC_DECODE_CACHE || PPC_ENABLE_JIT block_cache.clear_range(start, end); #endif } diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp index d46b85f5..74ed9232 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp @@ -29,6 +29,7 @@ #include "cpu/ppc/ppc-bitfields.hpp" #include "cpu/ppc/ppc-blockinfo.hpp" #include "cpu/ppc/ppc-registers.hpp" +#include "cpu/ppc/ppc-dyngen.hpp" #include class powerpc_cpu @@ -139,12 +140,13 @@ protected: // Instruction information structure struct instr_info_t { - char name[8]; // Mnemonic + char name[8]; // Instruction name execute_fn execute; // Semantic routine for this instruction decode_fn decode; // Specialized instruction decoder + uint16 mnemo; // Mnemonic uint16 format; // Instruction format (XO-form, D-form, etc.) - uint16 opcode; // Primary opcode - uint16 xo; // Extended opcode + uint32 opcode:6; // Primary opcode + uint32 xo:10; // Extended opcode uint16 cflow; // Mask of control flow information }; @@ -170,6 +172,7 @@ private: // Syscall callback must return TRUE if no error occurred typedef bool (*syscall_fn)(powerpc_cpu *cpu); syscall_fn execute_do_syscall; + int syscall_exit_code; #ifdef PPC_NO_STATIC_II_INDEX_TABLE #define PPC_STATIC_II_TABLE @@ -202,9 +205,15 @@ public: // Initialization & finalization #ifdef PPC_NO_BASIC_CPU_BASE powerpc_cpu() +#if PPC_ENABLE_JIT + : codegen(this) +#endif #else powerpc_cpu(task_struct *parent_task) : basic_cpu(parent_task) +#if PPC_ENABLE_JIT + , codegen(this) +#endif #endif { initialize(); } void initialize(); @@ -256,6 +265,22 @@ protected: // Init decoder with one instruction info void init_decoder_entry(const instr_info_t * ii); +#if PPC_ENABLE_JIT + // Dynamic translation engine + struct codegen_context_t { + powerpc_dyngen & codegen; + uint32 entry_point; + uint32 pc; + uint32 opcode; + const instr_info_t *instr_info; + + codegen_context_t(powerpc_dyngen & codegen_init) + : codegen(codegen_init) + { } + }; + virtual bool compile1(codegen_context_t & cg_context) { return false; } +#endif + private: // Initializers & destructors @@ -280,6 +305,25 @@ private: block_info::decode_info * decode_cache_p; block_info::decode_info * decode_cache_end_p; +#if PPC_ENABLE_JIT + // Dynamic translation engine + friend class powerpc_dyngen_helper; + friend class powerpc_dyngen; + powerpc_dyngen codegen; + block_info *compile_block(uint32 entry); + powerpc_dyngen *codegen_ptr() { return &codegen; } +#endif + + // Semantic action templates + template< bool SB, bool OE > + uint32 do_execute_divide(uint32, uint32); + template< bool EX, bool CA, bool OE > + uint32 do_execute_addition(uint32, uint32); + template< bool CA, bool OE > + uint32 do_execute_subtract(uint32, uint32); + template< bool OE > + uint32 do_execute_subtract_extended(uint32, uint32); + // Instruction handlers void execute_nop(uint32 opcode); void execute_illegal(uint32 opcode); diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp index 90f7bd11..e9cd5485 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-decode.cpp @@ -22,6 +22,7 @@ #include "cpu/ppc/ppc-bitfields.hpp" #include "cpu/ppc/ppc-operands.hpp" #include "cpu/ppc/ppc-operations.hpp" +#include "cpu/ppc/ppc-instructions.hpp" #define DEBUG 0 #include "debug.h" @@ -105,851 +106,1021 @@ const powerpc_cpu::instr_info_t powerpc_cpu::powerpc_ii_table[] = { { "invalid", EXECUTE_0(illegal), NULL, + PPC_I(INVALID), INVALID_form, 0, 0, CFLOW_TRAP }, { "add", EXECUTE_ADDITION(RA, RB, NONE, CA_BIT_0, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA, RB, NONE, CA_BIT_0), + PPC_I(ADD), XO_form, 31, 266, CFLOW_NORMAL }, { "addc", EXECUTE_ADDITION(RA, RB, NONE, CA_BIT_1, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA, RB, NONE, CA_BIT_1), + PPC_I(ADDC), XO_form, 31, 10, CFLOW_NORMAL }, { "adde", EXECUTE_ADDITION(RA, RB, XER_CA, CA_BIT_1, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA, RB, XER_CA, CA_BIT_1), + PPC_I(ADDE), XO_form, 31, 138, CFLOW_NORMAL }, { "addi", EXECUTE_ADDITION(RA_or_0, SIMM, NONE, CA_BIT_0, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(ADDI), D_form, 14, 0, CFLOW_NORMAL }, { "addic", EXECUTE_ADDITION(RA, SIMM, NONE, CA_BIT_1, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(ADDIC), D_form, 12, 0, CFLOW_NORMAL }, { "addic.", EXECUTE_ADDITION(RA, SIMM, NONE, CA_BIT_1, OE_BIT_0, RC_BIT_1), NULL, + PPC_I(ADDIC_), D_form, 13, 0, CFLOW_NORMAL }, { "addis", EXECUTE_ADDITION(RA_or_0, SIMM_shifted, NONE, CA_BIT_0, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(ADDIS), D_form, 15, 0, CFLOW_NORMAL }, { "addme", EXECUTE_ADDITION(RA, MINUS_ONE, XER_CA, CA_BIT_1, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA, MINUS_ONE, XER_CA, CA_BIT_1), + PPC_I(ADDME), XO_form, 31, 234, CFLOW_NORMAL }, { "addze", EXECUTE_ADDITION(RA, ZERO, XER_CA, CA_BIT_1, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA, ZERO, XER_CA, CA_BIT_1), + PPC_I(ADDZE), XO_form, 31, 202, CFLOW_NORMAL }, { "and", EXECUTE_GENERIC_ARITH(and, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(AND), X_form, 31, 28, CFLOW_NORMAL }, { "andc", EXECUTE_GENERIC_ARITH(andc, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(ANDC), X_form, 31, 60, CFLOW_NORMAL }, { "andi.", EXECUTE_GENERIC_ARITH(and, RA, RS, UIMM, NONE, OE_BIT_0, RC_BIT_1), NULL, + PPC_I(ANDI), D_form, 28, 0, CFLOW_NORMAL }, { "andis.", EXECUTE_GENERIC_ARITH(and, RA, RS, UIMM_shifted, NONE, OE_BIT_0, RC_BIT_1), NULL, + PPC_I(ANDIS), D_form, 29, 0, CFLOW_NORMAL }, { "b", EXECUTE_BRANCH(PC, immediate_value, LI, AA_BIT_G, LK_BIT_G), NULL, + PPC_I(B), I_form, 18, 0, CFLOW_BRANCH }, { "bc", EXECUTE_BRANCH(PC, operand_BO, BD, AA_BIT_G, LK_BIT_G), NULL, + PPC_I(BC), B_form, 16, 0, CFLOW_BRANCH }, { "bcctr", EXECUTE_BRANCH(CTR, operand_BO, ZERO, AA_BIT_0, LK_BIT_G), NULL, + PPC_I(BCCTR), XL_form, 19, 528, CFLOW_BRANCH }, { "bclr", EXECUTE_BRANCH(LR, operand_BO, ZERO, AA_BIT_0, LK_BIT_G), NULL, + PPC_I(BCLR), XL_form, 19, 16, CFLOW_BRANCH }, { "cmp", EXECUTE_COMPARE(RB, int32), NULL, + PPC_I(CMP), X_form, 31, 0, CFLOW_NORMAL }, { "cmpi", EXECUTE_COMPARE(SIMM, int32), NULL, + PPC_I(CMPI), D_form, 11, 0, CFLOW_NORMAL }, { "cmpl", EXECUTE_COMPARE(RB, uint32), NULL, + PPC_I(CMPL), X_form, 31, 32, CFLOW_NORMAL }, { "cmpli", EXECUTE_COMPARE(UIMM, uint32), NULL, + PPC_I(CMPLI), D_form, 10, 0, CFLOW_NORMAL }, { "cntlzw", EXECUTE_GENERIC_ARITH(cntlzw, RA, RS, NONE, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(CNTLZW), X_form, 31, 26, CFLOW_NORMAL }, { "crand", EXECUTE_CR_OP(and), NULL, + PPC_I(CRAND), XL_form, 19, 257, CFLOW_NORMAL }, { "crandc", EXECUTE_CR_OP(andc), NULL, + PPC_I(CRANDC), XL_form, 19, 129, CFLOW_NORMAL }, { "creqv", EXECUTE_CR_OP(eqv), NULL, + PPC_I(CREQV), XL_form, 19, 289, CFLOW_NORMAL }, { "crnand", EXECUTE_CR_OP(nand), NULL, + PPC_I(CRNAND), XL_form, 19, 225, CFLOW_NORMAL }, { "crnor", EXECUTE_CR_OP(nor), NULL, + PPC_I(CRNOR), XL_form, 19, 33, CFLOW_NORMAL }, { "cror", EXECUTE_CR_OP(or), NULL, + PPC_I(CROR), XL_form, 19, 449, CFLOW_NORMAL }, { "crorc", EXECUTE_CR_OP(orc), NULL, + PPC_I(CRORC), XL_form, 19, 417, CFLOW_NORMAL }, { "crxor", EXECUTE_CR_OP(xor), NULL, + PPC_I(CRXOR), XL_form, 19, 193, CFLOW_NORMAL }, { "dcba", EXECUTE_0(nop), NULL, + PPC_I(DCBA), X_form, 31, 758, CFLOW_NORMAL }, { "dcbf", EXECUTE_0(nop), NULL, + PPC_I(DCBF), X_form, 31, 86, CFLOW_NORMAL }, { "dcbi", EXECUTE_0(nop), NULL, + PPC_I(DCBI), X_form, 31, 470, CFLOW_NORMAL }, { "dcbst", EXECUTE_0(nop), NULL, + PPC_I(DCBST), X_form, 31, 54, CFLOW_NORMAL }, { "dcbt", EXECUTE_0(nop), NULL, + PPC_I(DCBT), X_form, 31, 278, CFLOW_NORMAL }, { "dcbtst", EXECUTE_0(nop), NULL, + PPC_I(DCBTST), X_form, 31, 246, CFLOW_NORMAL }, { "dcbz", EXECUTE_2(dcbz, operand_RA_or_0, operand_RB), NULL, + PPC_I(DCBZ), X_form, 31, 1014, CFLOW_NORMAL }, { "divw", EXECUTE_3(divide, true, OE_BIT_G, RC_BIT_G), NULL, + PPC_I(DIVW), XO_form, 31, 491, CFLOW_NORMAL }, { "divwu", EXECUTE_3(divide, false, OE_BIT_G, RC_BIT_G), NULL, + PPC_I(DIVWU), XO_form, 31, 459, CFLOW_NORMAL }, { "eciwx", EXECUTE_0(nop), NULL, + PPC_I(ECIWX), X_form, 31, 310, CFLOW_NORMAL }, { "ecowx", EXECUTE_0(nop), NULL, + PPC_I(ECOWX), X_form, 31, 438, CFLOW_NORMAL }, { "eieio", EXECUTE_0(nop), NULL, + PPC_I(EIEIO), X_form, 31, 854, CFLOW_NORMAL }, { "eqv", EXECUTE_GENERIC_ARITH(eqv, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(EQV), X_form, 31, 284, CFLOW_NORMAL }, { "extsb", EXECUTE_GENERIC_ARITH(sign_extend_8_32, RA, RS, NONE, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(EXTSB), X_form, 31, 954, CFLOW_NORMAL }, { "extsh", EXECUTE_GENERIC_ARITH(sign_extend_16_32, RA, RS, NONE, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(EXTSH), X_form, 31, 922, CFLOW_NORMAL }, { "fabs", EXECUTE_FP_ARITH(fabs, RD, RB, NONE, NONE, RC_BIT_G, false), NULL, + PPC_I(FABS), X_form, 63, 264, CFLOW_NORMAL }, { "fadd", EXECUTE_FP_ARITH(fadd, RD, RA, RB, NONE, RC_BIT_G, true), NULL, + PPC_I(FADD), A_form, 63, 21, CFLOW_NORMAL }, { "fadds", EXECUTE_FP_ARITH(fadds, RD, RA, RB, NONE, RC_BIT_G, true), NULL, + PPC_I(FADDS), A_form, 59, 21, CFLOW_NORMAL }, { "fcmpo", EXECUTE_1(fp_compare, true), NULL, + PPC_I(FCMPO), X_form, 63, 32, CFLOW_NORMAL }, { "fcmpu", EXECUTE_1(fp_compare, false), NULL, + PPC_I(FCMPU), X_form, 63, 0, CFLOW_NORMAL }, { "fctiw", EXECUTE_2(fp_int_convert, operand_FPSCR_RN, RC_BIT_G), NULL, + PPC_I(FCTIW), X_form, 63, 14, CFLOW_NORMAL }, { "fctiwz", EXECUTE_2(fp_int_convert, operand_ONE, RC_BIT_G), NULL, + PPC_I(FCTIWZ), X_form, 63, 15, CFLOW_NORMAL }, { "fdiv", EXECUTE_FP_ARITH(fdiv, RD, RA, RB, NONE, RC_BIT_G, true), NULL, + PPC_I(FDIV), A_form, 63, 18, CFLOW_NORMAL }, { "fdivs", EXECUTE_FP_ARITH(fdivs, RD, RA, RB, NONE, RC_BIT_G, true), NULL, + PPC_I(FDIVS), A_form, 59, 18, CFLOW_NORMAL }, { "fmadd", EXECUTE_FP_ARITH(fmadd, RD, RA, RC, RB, RC_BIT_G, true), NULL, + PPC_I(FMADD), A_form, 63, 29, CFLOW_NORMAL }, { "fmadds", EXECUTE_FP_ARITH(fmadds, RD, RA, RC, RB, RC_BIT_G, true), NULL, + PPC_I(FMADDS), A_form, 59, 29, CFLOW_NORMAL }, { "fmr", EXECUTE_FP_ARITH(fnop, RD, RB, NONE, NONE, RC_BIT_G, false), NULL, + PPC_I(FMR), X_form, 63, 72, CFLOW_NORMAL }, { "fmsub", EXECUTE_FP_ARITH(fmsub, RD, RA, RC, RB, RC_BIT_G, true), NULL, + PPC_I(FMSUB), A_form, 63, 28, CFLOW_NORMAL }, { "fmsubs", EXECUTE_FP_ARITH(fmsubs, RD, RA, RC, RB, RC_BIT_G, true), NULL, + PPC_I(FMSUBS), A_form, 59, 28, CFLOW_NORMAL }, { "fmul", EXECUTE_FP_ARITH(fmul, RD, RA, RC, NONE, RC_BIT_G, true), NULL, + PPC_I(FMUL), A_form, 63, 25, CFLOW_NORMAL }, { "fmuls", EXECUTE_FP_ARITH(fmuls, RD, RA, RC, NONE, RC_BIT_G, true), NULL, + PPC_I(FMULS), A_form, 59, 25, CFLOW_NORMAL }, { "fnabs", EXECUTE_FP_ARITH(fnabs, RD, RB, NONE, NONE, RC_BIT_G, false), NULL, + PPC_I(FNABS), X_form, 63, 136, CFLOW_NORMAL }, { "fneg", EXECUTE_FP_ARITH(fneg, RD, RB, NONE, NONE, RC_BIT_G, false), NULL, + PPC_I(FNEG), X_form, 63, 40, CFLOW_NORMAL }, { "fnmadd", EXECUTE_FP_ARITH(fnmadd, RD, RA, RC, RB, RC_BIT_G, true), NULL, + PPC_I(FNMADD), A_form, 63, 31, CFLOW_NORMAL }, { "fnmadds", EXECUTE_FP_ARITH(fnmadds, RD, RA, RC, RB, RC_BIT_G, true), NULL, + PPC_I(FNMADDS), A_form, 59, 31, CFLOW_NORMAL }, { "fnmsub", EXECUTE_FP_ARITH(fnmsub, RD, RA, RC, RB, RC_BIT_G, true), NULL, + PPC_I(FNMSUB), A_form, 63, 30, CFLOW_NORMAL }, { "fnmsubs", EXECUTE_FP_ARITH(fnmsubs, RD, RA, RC, RB, RC_BIT_G, true), NULL, + PPC_I(FNMSUBS), A_form, 59, 30, CFLOW_NORMAL }, { "frsp", EXECUTE_1(fp_round, RC_BIT_G), NULL, + PPC_I(FRSP), X_form, 63, 12, CFLOW_NORMAL }, { "fsub", EXECUTE_FP_ARITH(fsub, RD, RA, RB, NONE, RC_BIT_G, true), NULL, + PPC_I(FSUB), A_form, 63, 20, CFLOW_NORMAL }, { "fsubs", EXECUTE_FP_ARITH(fsubs, RD, RA, RB, NONE, RC_BIT_G, true), NULL, + PPC_I(FSUBS), A_form, 59, 20, CFLOW_NORMAL }, { "icbi", EXECUTE_2(icbi, operand_RA_or_0, operand_RB), NULL, + PPC_I(ICBI), X_form, 31, 982, CFLOW_NORMAL }, { "isync", EXECUTE_0(isync), NULL, + PPC_I(ISYNC), X_form, 19, 150, CFLOW_NORMAL }, { "lbz", EXECUTE_LOADSTORE(nop, RA_or_0, D, true, 1, false, false), NULL, + PPC_I(LBZ), D_form, 34, 0, CFLOW_NORMAL }, { "lbzu", EXECUTE_LOADSTORE(nop, RA, D, true, 1, true, false), NULL, + PPC_I(LBZU), D_form, 35, 0, CFLOW_NORMAL }, { "lbzux", EXECUTE_LOADSTORE(nop, RA, RB, true, 1, true, false), NULL, + PPC_I(LBZUX), X_form, 31, 119, CFLOW_NORMAL }, { "lbzx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, true, 1, false, false), NULL, + PPC_I(LBZX), X_form, 31, 87, CFLOW_NORMAL }, { "lfd", EXECUTE_FP_LOADSTORE(RA_or_0, D, true, true, false), NULL, + PPC_I(LFD), D_form, 50, 0, CFLOW_NORMAL }, { "lfdu", EXECUTE_FP_LOADSTORE(RA, D, true, true, true), NULL, + PPC_I(LFDU), D_form, 51, 0, CFLOW_NORMAL }, { "lfdux", EXECUTE_FP_LOADSTORE(RA, RB, true, true, true), NULL, + PPC_I(LFDUX), X_form, 31, 631, CFLOW_NORMAL }, { "lfdx", EXECUTE_FP_LOADSTORE(RA_or_0, RB, true, true, false), NULL, + PPC_I(LFDX), X_form, 31, 599, CFLOW_NORMAL }, { "lfs", EXECUTE_FP_LOADSTORE(RA_or_0, D, true, false, false), NULL, + PPC_I(LFS), D_form, 48, 0, CFLOW_NORMAL }, { "lfsu", EXECUTE_FP_LOADSTORE(RA, D, true, false, true), NULL, + PPC_I(LFSU), D_form, 49, 0, CFLOW_NORMAL }, { "lfsux", EXECUTE_FP_LOADSTORE(RA, RB, true, false, true), NULL, + PPC_I(LFSUX), X_form, 31, 567, CFLOW_NORMAL }, { "lfsx", EXECUTE_FP_LOADSTORE(RA_or_0, RB, true, false, false), NULL, + PPC_I(LFSX), X_form, 31, 535, CFLOW_NORMAL }, { "lha", EXECUTE_LOADSTORE(sign_extend_16_32, RA_or_0, D, true, 2, false, false), NULL, + PPC_I(LHA), D_form, 42, 0, CFLOW_NORMAL }, { "lhau", EXECUTE_LOADSTORE(sign_extend_16_32, RA, D, true, 2, true, false), NULL, + PPC_I(LHAU), D_form, 43, 0, CFLOW_NORMAL }, { "lhaux", EXECUTE_LOADSTORE(sign_extend_16_32, RA, RB, true, 2, true, false), NULL, + PPC_I(LHAUX), X_form, 31, 375, CFLOW_NORMAL }, { "lhax", EXECUTE_LOADSTORE(sign_extend_16_32, RA_or_0, RB, true, 2, false, false), NULL, + PPC_I(LHAX), X_form, 31, 343, CFLOW_NORMAL }, { "lhbrx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, true, 2, false, true), NULL, + PPC_I(LHBRX), X_form, 31, 790, CFLOW_NORMAL }, { "lhz", EXECUTE_LOADSTORE(nop, RA_or_0, D, true, 2, false, false), NULL, + PPC_I(LHZ), D_form, 40, 0, CFLOW_NORMAL }, { "lhzu", EXECUTE_LOADSTORE(nop, RA, D, true, 2, true, false), NULL, + PPC_I(LHZU), D_form, 41, 0, CFLOW_NORMAL }, { "lhzux", EXECUTE_LOADSTORE(nop, RA, RB, true, 2, true, false), NULL, + PPC_I(LHZUX), X_form, 31, 311, CFLOW_NORMAL }, { "lhzx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, true, 2, false, false), NULL, + PPC_I(LHZX), X_form, 31, 279, CFLOW_NORMAL }, { "lmw", EXECUTE_LOADSTORE_MULTIPLE(RA_or_0, D, true), NULL, + PPC_I(LMW), D_form, 46, 0, CFLOW_NORMAL }, { "lswi", EXECUTE_LOAD_STRING(RA_or_0, true, NB), NULL, + PPC_I(LSWI), X_form, 31, 597, CFLOW_NORMAL }, { "lswx", EXECUTE_LOAD_STRING(RA_or_0, false, XER_COUNT), NULL, + PPC_I(LSWX), X_form, 31, 533, CFLOW_NORMAL }, { "lwarx", EXECUTE_1(lwarx, operand_RA_or_0), NULL, + PPC_I(LWARX), X_form, 31, 20, CFLOW_NORMAL }, { "lwbrx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, true, 4, false, true), NULL, + PPC_I(LWBRX), X_form, 31, 534, CFLOW_NORMAL }, { "lwz", EXECUTE_LOADSTORE(nop, RA_or_0, D, true, 4, false, false), NULL, + PPC_I(LWZ), D_form, 32, 0, CFLOW_NORMAL }, { "lwzu", EXECUTE_LOADSTORE(nop, RA, D, true, 4, true, false), NULL, + PPC_I(LWZU), D_form, 33, 0, CFLOW_NORMAL }, { "lwzux", EXECUTE_LOADSTORE(nop, RA, RB, true, 4, true, false), NULL, + PPC_I(LWZUX), X_form, 31, 55, CFLOW_NORMAL }, { "lwzx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, true, 4, false, false), NULL, + PPC_I(LWZX), X_form, 31, 23, CFLOW_NORMAL }, { "mcrf", EXECUTE_0(mcrf), NULL, + PPC_I(MCRF), XL_form, 19, 0, CFLOW_NORMAL }, { "mfcr", EXECUTE_GENERIC_ARITH(nop, RD, CR, NONE, NONE, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(MFCR), X_form, 31, 19, CFLOW_NORMAL }, { "mffs", EXECUTE_1(mffs, RC_BIT_G), NULL, + PPC_I(MFFS), X_form, 63, 583, CFLOW_NORMAL }, { "mfmsr", EXECUTE_0(mfmsr), NULL, + PPC_I(MFMSR), X_form, 31, 83, CFLOW_NORMAL }, { "mfspr", EXECUTE_1(mfspr, operand_SPR), NULL, + PPC_I(MFSPR), XFX_form, 31, 339, CFLOW_NORMAL }, { "mftb", EXECUTE_1(mftbr, operand_TBR), NULL, + PPC_I(MFTB), XFX_form, 31, 371, CFLOW_NORMAL }, { "mtcrf", EXECUTE_0(mtcrf), NULL, + PPC_I(MTCRF), XFX_form, 31, 144, CFLOW_NORMAL }, { "mtfsb0", EXECUTE_2(mtfsb, immediate_value<0>, RC_BIT_G), NULL, + PPC_I(MTFSB0), X_form, 63, 70, CFLOW_NORMAL }, { "mtfsb1", EXECUTE_2(mtfsb, immediate_value<1>, RC_BIT_G), NULL, + PPC_I(MTFSB1), X_form, 63, 38, CFLOW_NORMAL }, { "mtfsf", EXECUTE_3(mtfsf, operand_FM, operand_fp_dw_RB, RC_BIT_G), NULL, + PPC_I(MTFSF), XFL_form, 63, 711, CFLOW_NORMAL }, { "mtfsfi", EXECUTE_2(mtfsfi, operand_IMM, RC_BIT_G), NULL, + PPC_I(MTFSFI), X_form, 63, 134, CFLOW_NORMAL }, { "mtspr", EXECUTE_1(mtspr, operand_SPR), NULL, + PPC_I(MTSPR), XFX_form, 31, 467, CFLOW_NORMAL }, { "mulhw", EXECUTE_4(multiply, true, true, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(MULHW), XO_form, 31, 75, CFLOW_NORMAL }, - { "mulhuw", + { "mulhwu", EXECUTE_4(multiply, true, false, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(MULHWU), XO_form, 31, 11, CFLOW_NORMAL }, { "mulli", EXECUTE_GENERIC_ARITH(smul, RD, RA, SIMM, NONE, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(MULLI), D_form, 7, 0, CFLOW_NORMAL }, { "mullw", EXECUTE_4(multiply, false, true, OE_BIT_G, RC_BIT_G), NULL, + PPC_I(MULLW), XO_form, 31, 235, CFLOW_NORMAL }, { "nand", EXECUTE_GENERIC_ARITH(nand, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(NAND), X_form, 31, 476, CFLOW_NORMAL }, { "neg", EXECUTE_GENERIC_ARITH(neg, RD, RA, NONE, NONE, OE_BIT_G, RC_BIT_G), NULL, + PPC_I(NEG), XO_form, 31, 104, CFLOW_NORMAL }, { "nor", EXECUTE_GENERIC_ARITH(nor, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(NOR), XO_form, 31, 124, CFLOW_NORMAL }, { "or", EXECUTE_GENERIC_ARITH(or, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(OR), XO_form, 31, 444, CFLOW_NORMAL }, { "orc", EXECUTE_GENERIC_ARITH(orc, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(ORC), XO_form, 31, 412, CFLOW_NORMAL }, { "ori", EXECUTE_GENERIC_ARITH(or, RA, RS, UIMM, NONE, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(ORI), D_form, 24, 0, CFLOW_NORMAL }, { "oris", EXECUTE_GENERIC_ARITH(or, RA, RS, UIMM_shifted, NONE, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(ORIS), D_form, 25, 0, CFLOW_NORMAL }, { "rlwimi", EXECUTE_3(rlwimi, operand_SH, operand_MASK, RC_BIT_G), NULL, + PPC_I(RLWIMI), M_form, 20, 0, CFLOW_NORMAL }, { "rlwinm", EXECUTE_GENERIC_ARITH(ppc_rlwinm, RA, RS, SH, MASK, OE_BIT_0, RC_BIT_G), DECODE_RLWINM(RA, RS), + PPC_I(RLWINM), M_form, 21, 0, CFLOW_NORMAL }, { "rlwnm", EXECUTE_GENERIC_ARITH(ppc_rlwnm, RA, RS, RB, MASK, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(RLWNM), M_form, 23, 0, CFLOW_NORMAL }, { "sc", EXECUTE_0(syscall), NULL, + PPC_I(SC), SC_form, 17, 0, CFLOW_NORMAL }, { "slw", EXECUTE_SHIFT(shll, RA, RS, RB, andi<0x3f>, CA_BIT_0, RC_BIT_G), NULL, + PPC_I(SLW), X_form, 31, 24, CFLOW_NORMAL }, { "sraw", EXECUTE_SHIFT(shra, RA, RS, RB, andi<0x3f>, CA_BIT_1, RC_BIT_G), NULL, + PPC_I(SRAW), X_form, 31, 792, CFLOW_NORMAL }, { "srawi", EXECUTE_SHIFT(shra, RA, RS, SH, andi<0x1f>, CA_BIT_1, RC_BIT_G), NULL, + PPC_I(SRAWI), X_form, 31, 824, CFLOW_NORMAL }, { "srw", EXECUTE_SHIFT(shrl, RA, RS, RB, andi<0x3f>, CA_BIT_0, RC_BIT_G), NULL, + PPC_I(SRW), X_form, 31, 536, CFLOW_NORMAL }, { "stb", EXECUTE_LOADSTORE(nop, RA_or_0, D, false, 1, false, false), NULL, + PPC_I(STB), D_form, 38, 0, CFLOW_NORMAL }, { "stbu", EXECUTE_LOADSTORE(nop, RA, D, false, 1, true, false), NULL, + PPC_I(STBU), D_form, 39, 0, CFLOW_NORMAL }, { "stbux", EXECUTE_LOADSTORE(nop, RA, RB, false, 1, true, false), NULL, + PPC_I(STBUX), X_form, 31, 247, CFLOW_NORMAL }, { "stbx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, false, 1, false, false), NULL, + PPC_I(STBX), X_form, 31, 215, CFLOW_NORMAL }, { "stfd", EXECUTE_FP_LOADSTORE(RA_or_0, D, false, true, false), NULL, + PPC_I(STFD), D_form, 54, 0, CFLOW_NORMAL }, { "stfdu", EXECUTE_FP_LOADSTORE(RA, D, false, true, true), NULL, + PPC_I(STFDU), D_form, 55, 0, CFLOW_NORMAL }, { "stfdux", EXECUTE_FP_LOADSTORE(RA, RB, false, true, true), NULL, + PPC_I(STFDUX), X_form, 31, 759, CFLOW_NORMAL }, { "stfdx", EXECUTE_FP_LOADSTORE(RA_or_0, RB, false, true, false), NULL, + PPC_I(STFDX), X_form, 31, 727, CFLOW_NORMAL }, { "stfs", EXECUTE_FP_LOADSTORE(RA_or_0, D, false, false, false), NULL, + PPC_I(STFS), D_form, 52, 0, CFLOW_NORMAL }, { "stfsu", EXECUTE_FP_LOADSTORE(RA, D, false, false, true), NULL, + PPC_I(STFSU), D_form, 53, 0, CFLOW_NORMAL }, { "stfsux", EXECUTE_FP_LOADSTORE(RA, RB, false, false, true), NULL, + PPC_I(STFSUX), X_form, 31, 695, CFLOW_NORMAL }, { "stfsx", EXECUTE_FP_LOADSTORE(RA_or_0, RB, false, false, false), NULL, + PPC_I(STFSX), X_form, 31, 663, CFLOW_NORMAL }, { "sth", EXECUTE_LOADSTORE(nop, RA_or_0, D, false, 2, false, false), NULL, + PPC_I(STH), D_form, 44, 0, CFLOW_NORMAL }, { "sthbrx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, false, 2, false, true), NULL, + PPC_I(STHBRX), X_form, 31, 918, CFLOW_NORMAL }, { "sthu", EXECUTE_LOADSTORE(nop, RA, D, false, 2, true, false), NULL, + PPC_I(STHU), D_form, 45, 0, CFLOW_NORMAL }, { "sthux", EXECUTE_LOADSTORE(nop, RA, RB, false, 2, true, false), NULL, + PPC_I(STHUX), X_form, 31, 439, CFLOW_NORMAL }, { "sthx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, false, 2, false, false), NULL, + PPC_I(STHX), X_form, 31, 407, CFLOW_NORMAL }, { "stmw", EXECUTE_LOADSTORE_MULTIPLE(RA_or_0, D, false), NULL, + PPC_I(STMW), D_form, 47, 0, CFLOW_NORMAL }, { "stswi", EXECUTE_STORE_STRING(RA_or_0, true, NB), NULL, + PPC_I(STSWI), X_form, 31, 725, CFLOW_NORMAL }, { "stswx", EXECUTE_STORE_STRING(RA_or_0, false, XER_COUNT), NULL, + PPC_I(STSWX), X_form, 31, 661, CFLOW_NORMAL }, { "stw", EXECUTE_LOADSTORE(nop, RA_or_0, D, false, 4, false, false), NULL, + PPC_I(STW), D_form, 36, 0, CFLOW_NORMAL }, { "stwbrx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, false, 4, false, true), NULL, + PPC_I(STWBRX), X_form, 31, 662, CFLOW_NORMAL }, { "stwcx.", EXECUTE_1(stwcx, operand_RA_or_0), NULL, + PPC_I(STWCX), X_form, 31, 150, CFLOW_NORMAL }, { "stwu", EXECUTE_LOADSTORE(nop, RA, D, false, 4, true, false), NULL, + PPC_I(STWU), D_form, 37, 0, CFLOW_NORMAL }, { "stwux", EXECUTE_LOADSTORE(nop, RA, RB, false, 4, true, false), NULL, + PPC_I(STWUX), X_form, 31, 183, CFLOW_NORMAL }, { "stwx", EXECUTE_LOADSTORE(nop, RA_or_0, RB, false, 4, false, false), NULL, + PPC_I(STWX), X_form, 31, 151, CFLOW_NORMAL }, { "subf", EXECUTE_ADDITION(RA_compl, RB, ONE, CA_BIT_0, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA_compl, RB, ONE, CA_BIT_0), + PPC_I(SUBF), XO_form, 31, 40, CFLOW_NORMAL }, { "subfc", EXECUTE_ADDITION(RA_compl, RB, ONE, CA_BIT_1, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA_compl, RB, ONE, CA_BIT_1), + PPC_I(SUBFC), XO_form, 31, 8, CFLOW_NORMAL }, { "subfe", EXECUTE_ADDITION(RA_compl, RB, XER_CA, CA_BIT_1, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA_compl, RB, XER_CA, CA_BIT_1), + PPC_I(SUBFE), XO_form, 31, 136, CFLOW_NORMAL }, { "subfic", EXECUTE_ADDITION(RA_compl, SIMM, ONE, CA_BIT_1, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(SUBFIC), D_form, 8, 0, CFLOW_NORMAL }, { "subfme", EXECUTE_ADDITION(RA_compl, XER_CA, MINUS_ONE, CA_BIT_1, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA_compl, XER_CA, MINUS_ONE, CA_BIT_1), + PPC_I(SUBFME), XO_form, 31, 232, CFLOW_NORMAL }, { "subfze", EXECUTE_ADDITION(RA_compl, XER_CA, ZERO, CA_BIT_1, OE_BIT_G, RC_BIT_G), DECODE_ADDITION(RA_compl, XER_CA, ZERO, CA_BIT_1), + PPC_I(SUBFZE), XO_form, 31, 200, CFLOW_NORMAL }, { "sync", EXECUTE_0(nop), NULL, + PPC_I(SYNC), X_form, 31, 598, CFLOW_NORMAL }, { "xor", EXECUTE_GENERIC_ARITH(xor, RA, RS, RB, NONE, OE_BIT_0, RC_BIT_G), NULL, + PPC_I(XOR), X_form, 31, 316, CFLOW_NORMAL }, { "xori", EXECUTE_GENERIC_ARITH(xor, RA, RS, UIMM, NONE, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(XORI), D_form, 26, 0, CFLOW_NORMAL }, { "xoris", EXECUTE_GENERIC_ARITH(xor, RA, RS, UIMM_shifted, NONE, OE_BIT_0, RC_BIT_0), NULL, + PPC_I(XORIS), D_form, 27, 0, CFLOW_NORMAL } }; diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp new file mode 100644 index 00000000..43286924 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen-ops.cpp @@ -0,0 +1,942 @@ +/* + * ppc-dyngen-ops.hpp - PowerPC synthetic instructions + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 "sysdeps.h" +#include "cpu/vm.hpp" +#include "cpu/jit/dyngen-exec.h" +#define NO_DEFINE_ALIAS 1 +#include "cpu/ppc/ppc-cpu.hpp" +#include "cpu/ppc/ppc-bitfields.hpp" +#include "cpu/ppc/ppc-registers.hpp" +#include "cpu/ppc/ppc-operations.hpp" + +// We need at least 4 general purpose registers +#ifdef REG_CPU +register struct powerpc_cpu *CPU asm(REG_CPU); +#else +#define CPU ((powerpc_cpu *)CPUPARAM) +#endif +register uint32 A0 asm(REG_A0); +register uint32 T0 asm(REG_T0); +register uint32 T1 asm(REG_T1); +#ifdef REG_T2 +register uint32 CC_LHS asm(REG_T2); +#else +#define CC_LHS powerpc_dyngen_helper::cc_lhs() +#endif +#ifdef REG_T3 +register uint32 CC_RHS asm(REG_T3); +#else +#define CC_RHS powerpc_dyngen_helper::cc_rhs() +#endif + +// Semantic action templates +#define DYNGEN_OPS +#include "ppc-execute.hpp" + + +/** + * Helper class to access protected CPU context + **/ + +struct powerpc_dyngen_helper { + static inline uint32 get_pc() { return CPU->pc(); } + static inline void set_pc(uint32 value) { CPU->pc() = value; } + static inline void inc_pc(int32 offset) { CPU->pc() += offset; } + static inline uint32 get_lr() { return CPU->lr(); } + static inline void set_lr(uint32 value) { CPU->lr() = value; } + static inline uint32 get_ctr() { return CPU->ctr(); } + static inline void set_ctr(uint32 value) { CPU->ctr() = value; } + static inline uint32 get_cr() { return CPU->cr().get(); } + static inline void set_cr(uint32 value) { CPU->cr().set(value); } + static inline uint32 get_xer() { return CPU->xer().get(); } + static inline void set_xer(uint32 value) { CPU->xer().set(value); } + static inline void record(int crf, int32 v) { CPU->record_cr(crf, v); } + static inline powerpc_cr_register & cr() { return CPU->cr(); } + static inline powerpc_xer_register & xer() { return CPU->xer(); } + static inline uint32 & cc_lhs() { return CPU->codegen_ptr()->rc_cache.cc_lhs; } + static inline uint32 & cc_rhs() { return CPU->codegen_ptr()->rc_cache.cc_rhs; } +}; + + +/** + * Load/store general purpose registers + **/ + +#define DEFINE_OP(REG, N) \ +void OPPROTO op_load_##REG##_GPR##N(void) \ +{ \ + REG = CPU->gpr(N); \ +} \ +void OPPROTO op_store_##REG##_GPR##N(void) \ +{ \ + CPU->gpr(N) = REG; \ +} +#define DEFINE_REG(N) \ +DEFINE_OP(A0,N); \ +DEFINE_OP(T0,N); \ +DEFINE_OP(T1,N); + +DEFINE_REG(0); +DEFINE_REG(1); +DEFINE_REG(2); +DEFINE_REG(3); +DEFINE_REG(4); +DEFINE_REG(5); +DEFINE_REG(6); +DEFINE_REG(7); +DEFINE_REG(8); +DEFINE_REG(9); +DEFINE_REG(10); +DEFINE_REG(11); +DEFINE_REG(12); +DEFINE_REG(13); +DEFINE_REG(14); +DEFINE_REG(15); +DEFINE_REG(16); +DEFINE_REG(17); +DEFINE_REG(18); +DEFINE_REG(19); +DEFINE_REG(20); +DEFINE_REG(21); +DEFINE_REG(22); +DEFINE_REG(23); +DEFINE_REG(24); +DEFINE_REG(25); +DEFINE_REG(26); +DEFINE_REG(27); +DEFINE_REG(28); +DEFINE_REG(29); +DEFINE_REG(30); +DEFINE_REG(31); + +#undef DEFINE_REG +#undef DEFINE_OP + + +/** + * Condition Registers + **/ + +void OPPROTO op_load_T0_CR(void) +{ + T0 = powerpc_dyngen_helper::get_cr(); +} + +void OPPROTO op_store_T0_CR(void) +{ + powerpc_dyngen_helper::set_cr(T0); +} + +void OPPROTO op_load_T0_XER(void) +{ + T0 = powerpc_dyngen_helper::get_xer(); +} + +void OPPROTO op_store_T0_XER(void) +{ + powerpc_dyngen_helper::set_xer(T0); +} + +#define DEFINE_OP(REG, N) \ +void OPPROTO op_load_##REG##_crb##N(void) \ +{ \ + REG = bit_field::extract(powerpc_dyngen_helper::get_cr()); \ +} \ +void OPPROTO op_store_##REG##_crb##N(void) \ +{ \ + uint32 cr = powerpc_dyngen_helper::get_cr(); \ + bit_field::insert(cr, REG); \ + powerpc_dyngen_helper::set_cr(cr); \ +} +#define DEFINE_REG(N) \ +DEFINE_OP(T0, N); \ +DEFINE_OP(T1, N); + +DEFINE_REG(0); +DEFINE_REG(1); +DEFINE_REG(2); +DEFINE_REG(3); +DEFINE_REG(4); +DEFINE_REG(5); +DEFINE_REG(6); +DEFINE_REG(7); +DEFINE_REG(8); +DEFINE_REG(9); +DEFINE_REG(10); +DEFINE_REG(11); +DEFINE_REG(12); +DEFINE_REG(13); +DEFINE_REG(14); +DEFINE_REG(15); +DEFINE_REG(16); +DEFINE_REG(17); +DEFINE_REG(18); +DEFINE_REG(19); +DEFINE_REG(20); +DEFINE_REG(21); +DEFINE_REG(22); +DEFINE_REG(23); +DEFINE_REG(24); +DEFINE_REG(25); +DEFINE_REG(26); +DEFINE_REG(27); +DEFINE_REG(28); +DEFINE_REG(29); +DEFINE_REG(30); +DEFINE_REG(31); + +#undef DEFINE_REG +#undef DEFINE_OP + +#define DEFINE_OP(CRF, REG) \ +void OPPROTO op_load_##REG##_cr##CRF(void) \ +{ \ + T0 = powerpc_dyngen_helper::cr().get(CRF); \ +} \ +void OPPROTO op_store_##REG##_cr##CRF(void) \ +{ \ + powerpc_dyngen_helper::cr().set(CRF, REG); \ +} + +DEFINE_OP(0, T0); +DEFINE_OP(1, T0); +DEFINE_OP(2, T0); +DEFINE_OP(3, T0); +DEFINE_OP(4, T0); +DEFINE_OP(5, T0); +DEFINE_OP(6, T0); +DEFINE_OP(7, T0); + +#undef DEFINE_OP + +#define DEFINE_OP(CRF) \ +void OPPROTO op_commit_so_cache_cr##CRF(void) \ +{ \ + int so = powerpc_dyngen_helper::xer().get_so(); \ + powerpc_dyngen_helper::cr().set_so(CRF, so); \ +} + +DEFINE_OP(0); +DEFINE_OP(1); +DEFINE_OP(2); +DEFINE_OP(3); +DEFINE_OP(4); +DEFINE_OP(5); +DEFINE_OP(6); +DEFINE_OP(7); + +#undef DEFINE_OP + +#define DEFINE_OP_1(NAME,TYPE,CRF) \ +void OPPROTO op_##NAME##_rc_cache_cr##CRF(void) \ +{ \ + uint32 cr = powerpc_dyngen_helper::get_cr(); \ + cr &= ~(CR_LT_field::mask() | \ + CR_GT_field::mask() | \ + CR_EQ_field::mask()); \ + \ + if ((TYPE)CC_LHS < (TYPE)CC_RHS) \ + cr |= CR_LT_field::mask(); \ + else if ((TYPE)CC_LHS > (TYPE)CC_RHS) \ + cr |= CR_GT_field::mask(); \ + else \ + cr |= CR_EQ_field::mask(); \ + \ + powerpc_dyngen_helper::set_cr(cr); \ + dyngen_barrier(); \ +} +#define DEFINE_OP(CRF) \ +DEFINE_OP_1(commit,int32,CRF); \ +DEFINE_OP_1(commit_logical,uint32,CRF) + +DEFINE_OP(0); +DEFINE_OP(1); +DEFINE_OP(2); +DEFINE_OP(3); +DEFINE_OP(4); +DEFINE_OP(5); +DEFINE_OP(6); +DEFINE_OP(7); + +#undef DEFINE_OP +#undef DEFINE_OP_1 + + +/** + * Special purpose registers + **/ + +void OPPROTO op_load_T0_PC(void) +{ + T0 = powerpc_dyngen_helper::get_pc(); +} + +void OPPROTO op_store_T0_PC(void) +{ + powerpc_dyngen_helper::set_pc(T0); +} + +void OPPROTO op_set_PC_im(void) +{ + powerpc_dyngen_helper::set_pc(PARAM1); +} + +void OPPROTO op_set_PC_T1(void) +{ + powerpc_dyngen_helper::set_pc(T1); +} + +void OPPROTO op_inc_PC(void) +{ + powerpc_dyngen_helper::inc_pc(PARAM1); +} + +void OPPROTO op_load_T0_LR(void) +{ + T0 = powerpc_dyngen_helper::get_lr(); +} + +void OPPROTO op_store_T0_LR(void) +{ + powerpc_dyngen_helper::set_lr(T0); +} + +void OPPROTO op_load_T0_CTR(void) +{ + T0 = powerpc_dyngen_helper::get_ctr(); +} + +void OPPROTO op_load_T1_CTR(void) +{ + T1 = powerpc_dyngen_helper::get_ctr(); +} + +void OPPROTO op_store_T0_CTR(void) +{ + powerpc_dyngen_helper::set_ctr(T0); +} + +void OPPROTO op_store_T1_CTR(void) +{ + powerpc_dyngen_helper::set_ctr(T1); +} + +void OPPROTO op_load_T1_PC(void) +{ + T1 = powerpc_dyngen_helper::get_pc(); +} + +void OPPROTO op_load_T1_LR(void) +{ + T1 = powerpc_dyngen_helper::get_lr(); +} + +void OPPROTO op_store_im_LR(void) +{ + powerpc_dyngen_helper::set_lr(PARAM1); +} + + +/** + * Branch instructions + **/ + +void OPPROTO op_decrement_ctr_T1(void) +{ + T1 = powerpc_dyngen_helper::get_ctr() - 1; + powerpc_dyngen_helper::set_ctr(T1); +} + +void OPPROTO op_branch_if_T0(void) +{ + if (T0) + powerpc_dyngen_helper::set_pc(PARAM1); + else + powerpc_dyngen_helper::set_pc(PARAM2); + dyngen_barrier(); +} + +void OPPROTO op_branch_if_not_T0(void) +{ + if (!T0) + powerpc_dyngen_helper::set_pc(PARAM1); + else + powerpc_dyngen_helper::set_pc(PARAM2); + dyngen_barrier(); +} + +void OPPROTO op_branch_if_T1(void) +{ + if (T1) + powerpc_dyngen_helper::set_pc(PARAM1); + else + powerpc_dyngen_helper::set_pc(PARAM2); + dyngen_barrier(); +} + +void OPPROTO op_branch_if_not_T1(void) +{ + if (!T1) + powerpc_dyngen_helper::set_pc(PARAM1); + else + powerpc_dyngen_helper::set_pc(PARAM2); + dyngen_barrier(); +} + +void OPPROTO op_branch_if_T0_T1(void) +{ + if (T0 && T1) + powerpc_dyngen_helper::set_pc(PARAM1); + else + powerpc_dyngen_helper::set_pc(PARAM2); + dyngen_barrier(); +} + +void OPPROTO op_branch_T1_if_T0(void) +{ + if (T0) + powerpc_dyngen_helper::set_pc(T1); + else + powerpc_dyngen_helper::set_pc(PARAM1); + dyngen_barrier(); +} + +template< class branch_cond, class ctr_cond > +static inline void do_execute_branch(uint32 tpc, uint32 npc) +{ + if (branch_cond::test() && ctr_cond::test()) + powerpc_dyngen_helper::set_pc(PARAM1); + else + powerpc_dyngen_helper::set_pc(PARAM2); + dyngen_barrier(); +} + +struct LT_comparator { static inline bool test() { return T0 < 0; } }; +struct GT_comparator { static inline bool test() { return T0 > 0; } }; +struct EQ_comparator { static inline bool test() { return T0 == 0; } }; + +template< int crb > +struct CR_comparator { static inline bool test() { return (T0 & crb); } }; + +template< bool br_true, class comparator > +struct bool_condition { + static inline bool test() { + return br_true ? comparator::test() : !comparator::test(); + } +}; + +typedef bool_condition< true, CR_comparator<8> > blt_condition; +typedef bool_condition > bnlt_condition; +typedef bool_condition< true, CR_comparator<4> > bgt_condition; +typedef bool_condition > bngt_condition; +typedef bool_condition< true, CR_comparator<2> > beq_condition; +typedef bool_condition > bneq_condition; +typedef bool_condition< true, CR_comparator<1> > bso_condition; +typedef bool_condition > bnso_condition; + +struct ctr_0x_condition { + static inline bool test() { + return true; + } +}; + +struct ctr_10_condition { + static inline bool test() { + uint32 ctr = powerpc_dyngen_helper::get_ctr() - 1; + powerpc_dyngen_helper::set_ctr(ctr); + return ctr != 0; + } +}; + +struct ctr_11_condition { + static inline bool test() { + uint32 ctr = powerpc_dyngen_helper::get_ctr() - 1; + powerpc_dyngen_helper::set_ctr(ctr); + return ctr == 0; + } +}; + +#define DEFINE_OP_CTR(COND,CTR) \ +void OPPROTO op_##COND##_##CTR(void) \ +{ \ + do_execute_branch(PARAM1, PARAM2); \ +} +#define DEFINE_OP(COND) \ +DEFINE_OP_CTR(COND,0x); \ +DEFINE_OP_CTR(COND,10); \ +DEFINE_OP_CTR(COND,11) + +DEFINE_OP(blt); +DEFINE_OP(bgt); +DEFINE_OP(beq); +DEFINE_OP(bso); +DEFINE_OP(bnlt); +DEFINE_OP(bngt); +DEFINE_OP(bneq); +DEFINE_OP(bnso); + +#undef DEFINE_OP +#undef DEFINE_OP_CTR + + +/** + * Compare & Record instructions + **/ + +void OPPROTO op_record_nego_T0(void) +{ + powerpc_dyngen_helper::xer().set_ov(T0 == 0x80000000); + dyngen_barrier(); +} + +void OPPROTO op_record_cr0_T0(void) +{ + uint32 cr = powerpc_dyngen_helper::get_cr(); + cr &= ~(CR_LT_field<0>::mask() | + CR_GT_field<0>::mask() | + CR_EQ_field<0>::mask() | + CR_SO_field<0>::mask()); + +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 v; + asm volatile ("cmpwi 0,%1,0 ; mfcr %0" : "=r" (v) : "r" (T0) : "cr0"); + cr |= (v & (0xe0000000)); + cr |= (powerpc_dyngen_helper::xer().get_so() << (31 - 3)); + goto end; +#endif +#endif + + if (powerpc_dyngen_helper::xer().get_so()) + cr |= CR_SO_field<0>::mask(); + if ((int32)T0 < 0) + cr |= CR_LT_field<0>::mask(); + else if ((int32)T0 > 0) + cr |= CR_GT_field<0>::mask(); + else + cr |= CR_EQ_field<0>::mask(); + + end: + powerpc_dyngen_helper::set_cr(cr); + dyngen_barrier(); +} + +#define im PARAM1 + +#define DEFINE_OP(LHS, RHS) \ +void OPPROTO op_compare_##LHS##_##RHS(void) \ +{ \ + CC_LHS = LHS; \ + CC_RHS = RHS; \ +} +DEFINE_OP(T0,T1); +DEFINE_OP(T0,im); +DEFINE_OP(T0,0); +#undef DEFINE_OP + +#if DYNGEN_ASM_OPTS && defined(__powerpc__) + +#define DEFINE_OP(NAME, COMP, LHS, RHST, RHS) \ +void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ +{ \ + uint32 cr = powerpc_dyngen_helper::xer().get_so(); \ + uint32 v; \ + asm volatile (COMP " 7,%1,%2 ; mfcr %0" : "=r" (v) : "r" (LHS), RHST (RHS) : "cr7"); \ + T0 = cr | (v & 0xe); \ +} + +DEFINE_OP(do_compare,"cmpw",T0,"r",T1); +DEFINE_OP(do_compare,"cmpw",T0,"r",im); +DEFINE_OP(do_compare,"cmpwi",T0,"i",0); +DEFINE_OP(do_compare_logical,"cmplw",T0,"r",T1); +DEFINE_OP(do_compare_logical,"cmplw",T0,"r",im); +DEFINE_OP(do_compare_logical,"cmplwi",T0,"i",0); + +#else + +#define DEFINE_OP(NAME, TYPE, LHS, RHS) \ +void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ +{ \ + uint32 cr = powerpc_dyngen_helper::xer().get_so(); \ + if ((TYPE)LHS < (TYPE)RHS) \ + cr |= standalone_CR_LT_field::mask(); \ + else if ((TYPE)LHS > (TYPE)RHS) \ + cr |= standalone_CR_GT_field::mask(); \ + else \ + cr |= standalone_CR_EQ_field::mask(); \ + T0 = cr; \ + dyngen_barrier(); \ +} + +DEFINE_OP(do_compare,int32,T0,T1); +DEFINE_OP(do_compare,int32,T0,im); +DEFINE_OP(do_compare,int32,T0,0); +DEFINE_OP(do_compare_logical,uint32,T0,T1); +DEFINE_OP(do_compare_logical,uint32,T0,im); +DEFINE_OP(do_compare_logical,uint32,T0,0); + +#endif + +#undef im +#undef DEFINE_OP + + +/** + * Divide instructions + **/ + +#if DYNGEN_ASM_OPTS && defined(__powerpc__) +#define get_ov() ({ uint32 xer; asm volatile ("mfxer %0" : "=r" (xer)); XER_OV_field::extract(xer); }) +#endif + +void OPPROTO op_divw_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + asm volatile ("divw %0,%0,%1" : "=r" (T0) : "r" (T1)); + return; +#endif +#endif + T0 = do_execute_divide(T0, T1); +} + +void OPPROTO op_divwo_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + asm volatile ("divwo %0,%0,%1" : "=r" (T0) : "r" (T1)); + powerpc_dyngen_helper::xer().set_ov(get_ov()); + return; +#endif +#endif + T0 = do_execute_divide(T0, T1); +} + +void OPPROTO op_divwu_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + asm volatile ("divwu %0,%0,%1" : "=r" (T0) : "r" (T1)); + return; +#endif +#endif + T0 = do_execute_divide(T0, T1); +} + +void OPPROTO op_divwuo_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + asm volatile ("divwuo %0,%0,%1" : "=r" (T0) : "r" (T1)); + powerpc_dyngen_helper::xer().set_ov(get_ov()); + return; +#endif +#endif + T0 = do_execute_divide(T0, T1); +} + + +/** + * Multiply instructions + **/ + +void OPPROTO op_mulhw_T0_T1(void) +{ + T0 = (((int64)(int32)T0) * ((int64)(int32)T1)) >> 32; +} + +void OPPROTO op_mulhwu_T0_T1(void) +{ + T0 = (((uint64)T0) * ((uint64)T1)) >> 32; +} + +void OPPROTO op_mulli_T0_im(void) +{ + T0 = (int32)T0 * (int32)PARAM1; +} + +void OPPROTO op_mullwo_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + asm volatile ("mullwo %0,%0,%1" : "=r" (T0) : "r" (T1)); + powerpc_dyngen_helper::xer().set_ov(get_ov()); + return; +#endif +#endif + int64 RD = (int64)(int32)T0 * (int64)(int32)T1; + powerpc_dyngen_helper::xer().set_ov((int32)RD != RD); + T0 = RD; + dyngen_barrier(); +} + + +/** + * Shift/Rotate instructions + **/ + +void OPPROTO op_slw_T0_T1(void) +{ + T0 = T0 << (T1 & 0x3f); +} + +void OPPROTO op_srw_T0_T1(void) +{ + T0 = T0 >> (T1 & 0x3f); +} + +void OPPROTO op_sraw_T0_T1(void) +{ + const uint32 n = T1 & 0x3f; + const uint32 RD = ((int32)T0) >> n; + const bool ca = (((int32)T0) < 0) && (T0 & ~(0xffffffff << n)); + powerpc_dyngen_helper::xer().set_ca(ca); + T0 = RD; + dyngen_barrier(); +} + +void OPPROTO op_sraw_T0_im(void) +{ + const uint32 n = PARAM1; + const uint32 RD = ((int32)T0) >> n; + const bool ca = (((int32)T0) < 0) && (T0 & ~(0xffffffff << n)); + powerpc_dyngen_helper::xer().set_ca(ca); + T0 = RD; + dyngen_barrier(); +} + +void OPPROTO op_rlwimi_T0_T1(void) +{ + T0 = op_ppc_rlwimi::apply(T1, PARAM1, PARAM2, T0); +} + +void OPPROTO op_rlwinm_T0_T1(void) +{ + T0 = op_rotl::apply(T0, PARAM1) & PARAM2; +} + +void OPPROTO op_rlwnm_T0_T1(void) +{ + T0 = op_rotl::apply(T0, T1) & PARAM1; +} + +void OPPROTO op_cntlzw_32_T0(void) +{ + uint32 n; + uint32 m = 0x80000000; + for (n = 0; n < 32; n++, m >>= 1) + if (T0 & m) + break; + T0 = n; + dyngen_barrier(); +} + + +/** + * Addition/Subtraction + **/ + +void OPPROTO op_addo_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer; + asm volatile ("addo %0,%0,%2 ; mfxer %1" : "=r" (T0), "=r" (xer) : "r" (T1)); + powerpc_dyngen_helper::xer().set_ov(XER_OV_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, T1); +} + +void OPPROTO op_addc_T0_im(void) +{ + T0 = do_execute_addition(T0, PARAM1); +} + +void OPPROTO op_addc_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer; + asm volatile ("addc %0,%0,%2 ; mfxer %1" : "=r" (T0), "=r" (xer) : "r" (T1)); + powerpc_dyngen_helper::xer().set_ca(XER_CA_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, T1); +} + +void OPPROTO op_addco_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer; + asm volatile ("addco %0,%0,%2 ; mfxer %1" : "=r" (T0), "=r" (xer) : "r" (T1)); + powerpc_dyngen_helper::xer().set_ca(XER_CA_field::extract(xer)); + powerpc_dyngen_helper::xer().set_ov(XER_OV_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, T1); +} + +void OPPROTO op_adde_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer, ca = powerpc_dyngen_helper::xer().get_ca(); + asm volatile ("li 0,-1 ; addc 0,%0,0" : : "r" (ca) : "r0"); + asm volatile ("adde %0,%0,%2 ; mfxer %1" : "=r" (T0), "=r" (xer) : "r" (T1)); + powerpc_dyngen_helper::xer().set_ca(XER_CA_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, T1); +} + +void OPPROTO op_addeo_T0_T1(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer, ca = powerpc_dyngen_helper::xer().get_ca(); + asm volatile ("li 0,-1 ; addc 0,%0,0" : : "r" (ca) : "r0"); + asm volatile ("addeo %0,%0,%2 ; mfxer %1" : "=r" (T0), "=r" (xer) : "r" (T1)); + powerpc_dyngen_helper::xer().set_ca(XER_CA_field::extract(xer)); + powerpc_dyngen_helper::xer().set_ov(XER_OV_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, T1); +} + +void OPPROTO op_addme_T0(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer, ca = powerpc_dyngen_helper::xer().get_ca(); + asm volatile ("li 0,-1 ; addc 0,%0,0" : : "r" (ca) : "r0"); + asm volatile ("addme %0,%0 ; mfxer %1" : "=r" (T0), "=r" (xer)); + powerpc_dyngen_helper::xer().set_ca(XER_CA_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, 0xffffffff); +} + +void OPPROTO op_addmeo_T0(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer, ca = powerpc_dyngen_helper::xer().get_ca(); + asm volatile ("li 0,-1 ; addc 0,%0,0" : : "r" (ca) : "r0"); + asm volatile ("addmeo %0,%0 ; mfxer %1" : "=r" (T0), "=r" (xer)); + powerpc_dyngen_helper::xer().set_ca(XER_CA_field::extract(xer)); + powerpc_dyngen_helper::xer().set_ov(XER_OV_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, 0xffffffff); +} + +void OPPROTO op_addze_T0(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer, ca = powerpc_dyngen_helper::xer().get_ca(); + asm volatile ("li 0,-1 ; addc 0,%0,0" : : "r" (ca) : "r0"); + asm volatile ("addze %0,%0 ; mfxer %1" : "=r" (T0), "=r" (xer)); + powerpc_dyngen_helper::xer().set_ca(XER_CA_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, 0); +} + +void OPPROTO op_addzeo_T0(void) +{ +#if DYNGEN_ASM_OPTS +#if defined(__powerpc__) + uint32 xer, ca = powerpc_dyngen_helper::xer().get_ca(); + asm volatile ("li 0,-1 ; addc 0,%0,0" : : "r" (ca) : "r0"); + asm volatile ("addzeo %0,%0 ; mfxer %1" : "=r" (T0), "=r" (xer)); + powerpc_dyngen_helper::xer().set_ca(XER_CA_field::extract(xer)); + powerpc_dyngen_helper::xer().set_ov(XER_OV_field::extract(xer)); + return; +#endif +#endif + T0 = do_execute_addition(T0, 0); +} + +void OPPROTO op_subf_T0_T1(void) +{ + T0 = T1 - T0; +} + +void OPPROTO op_subfo_T0_T1(void) +{ + T0 = do_execute_subtract(T0, T1); +} + +void OPPROTO op_subfc_T0_im(void) +{ + T0 = do_execute_subtract(T0, PARAM1); +} + +void OPPROTO op_subfc_T0_T1(void) +{ + T0 = do_execute_subtract(T0, T1); +} + +void OPPROTO op_subfco_T0_T1(void) +{ + T0 = do_execute_subtract(T0, T1); +} + +void OPPROTO op_subfe_T0_T1(void) +{ + T0 = do_execute_subtract_extended(T0, T1); +} + +void OPPROTO op_subfeo_T0_T1(void) +{ + T0 = do_execute_subtract_extended(T0, T1); +} + +void OPPROTO op_subfme_T0(void) +{ + T0 = do_execute_subtract_extended(T0, 0xffffffff); +} + +void OPPROTO op_subfmeo_T0(void) +{ + T0 = do_execute_subtract_extended(T0, 0xffffffff); +} + +void OPPROTO op_subfze_T0(void) +{ + T0 = do_execute_subtract_extended(T0, 0); +} + +void OPPROTO op_subfzeo_T0(void) +{ + T0 = do_execute_subtract_extended(T0, 0); +} diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp new file mode 100644 index 00000000..a4f8e335 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp @@ -0,0 +1,254 @@ +/* + * ppc-dyngen.cpp - PowerPC dynamic translation + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 "sysdeps.h" +#include "cpu/ppc/ppc-dyngen.hpp" +#include "cpu/ppc/ppc-bitfields.hpp" + +#include +#include + +#define DYNGEN_IMPL 1 +#define DEFINE_GEN(NAME,ARGS) void powerpc_dyngen::NAME ARGS +#include "ppc-dyngen-ops.hpp" + +void powerpc_dyngen::invalidate_so_cache() +{ + rc_cache.so_status = RC_cache::STATUS_TRASH; +} + +void powerpc_dyngen::invalidate_cr_cache() +{ + invalidate_so_cache(); + rc_cache.val_status = RC_cache::STATUS_TRASH; + rc_cache.crf = -1; +} + +void powerpc_dyngen::do_gen_commit_cr() +{ + gen_commit_so(); + switch (rc_cache.val_status) { + case RC_cache::STATUS_VALID: + gen_commit_rc_cache_cr(rc_cache.crf); + break; + case RC_cache::STATUS_VALID_LOGICAL: + gen_commit_logical_rc_cache_cr(rc_cache.crf); + break; + default: + abort(); + } + invalidate_cr_cache(); +} + +void powerpc_dyngen::do_gen_commit_so() +{ + gen_commit_so_cache_cr(rc_cache.crf); + invalidate_so_cache(); +} + +void powerpc_dyngen::gen_commit_cr() +{ + if (rc_cache.val_status != RC_cache::STATUS_TRASH) { + assert(rc_cache.crf != -1); + do_gen_commit_cr(); + } +} + +void powerpc_dyngen::gen_commit_so() +{ + if (rc_cache.so_status != RC_cache::STATUS_TRASH) { + assert(rc_cache.crf != -1); + do_gen_commit_so(); + } +} + +void powerpc_dyngen::gen_compare_T0_T1(int crf) +{ + if (!rc_cache.has_field(crf)) + gen_commit_cr(); + gen_op_compare_T0_T1(); + rc_cache.cache_field(crf); +} + +void powerpc_dyngen::gen_compare_T0_im(int crf, int32 value) +{ + if (!rc_cache.has_field(crf)) + gen_commit_cr(); + if (value == 0) + gen_op_compare_T0_0(); + else + gen_op_compare_T0_im(value); + rc_cache.cache_field(crf); +} + +void powerpc_dyngen::gen_compare_logical_T0_T1(int crf) +{ + if (!rc_cache.has_field(crf)) + gen_commit_cr(); + gen_op_compare_T0_T1(); + rc_cache.cache_field(crf, RC_cache::STATUS_VALID_LOGICAL); +} + +void powerpc_dyngen::gen_compare_logical_T0_im(int crf, int32 value) +{ + if (!rc_cache.has_field(crf)) + gen_commit_cr(); + if (value == 0) + gen_op_compare_T0_0(); + else + gen_op_compare_T0_im(value); + rc_cache.cache_field(crf, RC_cache::STATUS_VALID_LOGICAL); +} + +/** + * Load/store registers + **/ + +#define DEFINE_INSN(OP, REG, REGT) \ +void powerpc_dyngen::gen_##OP##_##REG##_##REGT(int i) \ +{ \ + switch (i) { \ + case 0: gen_op_##OP##_##REG##_##REGT##0(); break; \ + case 1: gen_op_##OP##_##REG##_##REGT##1(); break; \ + case 2: gen_op_##OP##_##REG##_##REGT##2(); break; \ + case 3: gen_op_##OP##_##REG##_##REGT##3(); break; \ + case 4: gen_op_##OP##_##REG##_##REGT##4(); break; \ + case 5: gen_op_##OP##_##REG##_##REGT##5(); break; \ + case 6: gen_op_##OP##_##REG##_##REGT##6(); break; \ + case 7: gen_op_##OP##_##REG##_##REGT##7(); break; \ + case 8: gen_op_##OP##_##REG##_##REGT##8(); break; \ + case 9: gen_op_##OP##_##REG##_##REGT##9(); break; \ + case 10: gen_op_##OP##_##REG##_##REGT##10(); break; \ + case 11: gen_op_##OP##_##REG##_##REGT##11(); break; \ + case 12: gen_op_##OP##_##REG##_##REGT##12(); break; \ + case 13: gen_op_##OP##_##REG##_##REGT##13(); break; \ + case 14: gen_op_##OP##_##REG##_##REGT##14(); break; \ + case 15: gen_op_##OP##_##REG##_##REGT##15(); break; \ + case 16: gen_op_##OP##_##REG##_##REGT##16(); break; \ + case 17: gen_op_##OP##_##REG##_##REGT##17(); break; \ + case 18: gen_op_##OP##_##REG##_##REGT##18(); break; \ + case 19: gen_op_##OP##_##REG##_##REGT##19(); break; \ + case 20: gen_op_##OP##_##REG##_##REGT##20(); break; \ + case 21: gen_op_##OP##_##REG##_##REGT##21(); break; \ + case 22: gen_op_##OP##_##REG##_##REGT##22(); break; \ + case 23: gen_op_##OP##_##REG##_##REGT##23(); break; \ + case 24: gen_op_##OP##_##REG##_##REGT##24(); break; \ + case 25: gen_op_##OP##_##REG##_##REGT##25(); break; \ + case 26: gen_op_##OP##_##REG##_##REGT##26(); break; \ + case 27: gen_op_##OP##_##REG##_##REGT##27(); break; \ + case 28: gen_op_##OP##_##REG##_##REGT##28(); break; \ + case 29: gen_op_##OP##_##REG##_##REGT##29(); break; \ + case 30: gen_op_##OP##_##REG##_##REGT##30(); break; \ + case 31: gen_op_##OP##_##REG##_##REGT##31(); break; \ + default: abort(); \ + } \ +} + +// General purpose registers +DEFINE_INSN(load, A0, GPR); +DEFINE_INSN(load, T0, GPR); +DEFINE_INSN(load, T1, GPR); +DEFINE_INSN(store, A0, GPR); +DEFINE_INSN(store, T0, GPR); +DEFINE_INSN(store, T1, GPR); + +// Condition register bitfield +DEFINE_INSN(load, T0, crb); +DEFINE_INSN(load, T1, crb); +DEFINE_INSN(store, T0, crb); +DEFINE_INSN(store, T1, crb); + +#undef DEFINE_INSN + +#define DEFINE_INSN(OP, REG) \ +void powerpc_dyngen::gen_##OP##_##REG##_cr(int crf) \ +{ \ + switch (crf) { \ + case 0: gen_op_##OP##_##REG##_cr0(); break; \ + case 1: gen_op_##OP##_##REG##_cr1(); break; \ + case 2: gen_op_##OP##_##REG##_cr2(); break; \ + case 3: gen_op_##OP##_##REG##_cr3(); break; \ + case 4: gen_op_##OP##_##REG##_cr4(); break; \ + case 5: gen_op_##OP##_##REG##_cr5(); break; \ + case 6: gen_op_##OP##_##REG##_cr6(); break; \ + case 7: gen_op_##OP##_##REG##_cr7(); break; \ + default: abort(); \ + } \ +} + +DEFINE_INSN(load, T0); +DEFINE_INSN(store, T0); +DEFINE_INSN(commit, so_cache); +DEFINE_INSN(commit, rc_cache); +DEFINE_INSN(commit_logical, rc_cache); + +#undef DEFINE_INSN + +void powerpc_dyngen::gen_record_cr0_T0(void) +{ + gen_compare_T0_im(0, 0); +} + +void powerpc_dyngen::gen_bc(int bo, int bi, uint32 tpc, uint32 npc) +{ + gen_commit_cr(); + if (BO_CONDITIONAL_BRANCH(bo)) { + enum { lt, gt, eq, so }; + gen_load_T0_cr(bi / 4); + const int n = ((bi % 4) << 2) | ((bo >> 1) & 3); +#define _(CR,DCTR,CTR0) (((CR) << 2) | ((DCTR) ? 0 : 2) | ((CTR0) ? 1 : 0)) + if (BO_BRANCH_IF_TRUE(bo)) { + switch (n) { +#define C(CR) \ + case _(CR,0,0): gen_b##CR##_0x(tpc, npc); break; \ + case _(CR,0,1): gen_b##CR##_0x(tpc, npc); break; \ + case _(CR,1,0): gen_b##CR##_10(tpc, npc); break; \ + case _(CR,1,1): gen_b##CR##_11(tpc, npc); break; + C(lt); C(gt); C(eq); C(so); +#undef C + } + } + else { + switch (n) { +#define C(CR) \ + case _(CR,0,0): gen_bn##CR##_0x(tpc, npc); break; \ + case _(CR,0,1): gen_bn##CR##_0x(tpc, npc); break; \ + case _(CR,1,0): gen_bn##CR##_10(tpc, npc); break; \ + case _(CR,1,1): gen_bn##CR##_11(tpc, npc); break; + C(lt); C(gt); C(eq); C(so); +#undef C + } + } +#undef _ + } + else { + if (BO_DECREMENT_CTR(bo)) { + gen_decrement_ctr_T1(); + if (BO_BRANCH_IF_CTR_ZERO(bo)) + gen_branch_if_not_T1(tpc, npc); + else + gen_branch_if_T1(tpc, npc); + } + else { + // Branch always + gen_set_PC_im(tpc); + } + } +} diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp new file mode 100644 index 00000000..a8ef4ef0 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp @@ -0,0 +1,231 @@ +/* + * ppc-dyngen.hpp - PowerPC dynamic translation + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 PPC_DYNGEN_H +#define PPC_DYNGEN_H + +#include "sysdeps.h" +#include "cpu/ppc/ppc-config.hpp" + +#if PPC_ENABLE_JIT +#include "cpu/jit/jit-config.hpp" +#include "cpu/jit/basic-dyngen.hpp" + +class powerpc_dyngen + : public basic_dyngen +{ + // Code generators for PowerPC synthetic instructions +#ifndef NO_DEFINE_ALIAS +# define DEFINE_GEN(NAME,ARGS) void NAME ARGS; +# include "ppc-dyngen-ops.hpp" +#endif + + struct RC_cache { + enum { + STATUS_TRASH, + STATUS_VALID, + STATUS_VALID_LOGICAL + }; + int val_status; + int so_status; + int crf; + + // Used only by generated code if not enough native registers + // are available to cache them all + uint32 cc_lhs; + uint32 cc_rhs; + + RC_cache() + : val_status(STATUS_TRASH), so_status(STATUS_TRASH), crf(-1) + { } + + bool has_field(int test_crf) + { return val_status != STATUS_TRASH && crf == test_crf; } + + void cache_field(int new_crf, int new_status = STATUS_VALID) + { val_status = so_status = new_status; crf = new_crf; } + }; + RC_cache rc_cache; + +public: + + // Make rc_cache accessible to codegen helper + friend class powerpc_dyngen_helper; + + // Default constructor + powerpc_dyngen(dyngen_cpu_base cpu) + : basic_dyngen(cpu) + { } + + // Load/store registers + void gen_load_A0_GPR(int i); + void gen_load_T0_GPR(int i); + void gen_load_T1_GPR(int i); + void gen_store_A0_GPR(int i); + void gen_store_T0_GPR(int i); + void gen_store_T1_GPR(int i); + + // Raw aliases +#define DEFINE_ALIAS_RAW(NAME, PRE, POST, ARGLIST, ARGS) \ + void gen_##NAME ARGLIST { PRE; gen_op_##NAME ARGS; POST; } + +#define DEFINE_ALIAS_0(NAME,PRE,POST) DEFINE_ALIAS_RAW(NAME,PRE,POST,(),()) +#define DEFINE_ALIAS_1(NAME,PRE,POST) DEFINE_ALIAS_RAW(NAME,PRE,POST,(long p1),(p1)) +#define DEFINE_ALIAS_2(NAME,PRE,POST) DEFINE_ALIAS_RAW(NAME,PRE,POST,(long p1,long p2),(p1,p2)) +#define DEFINE_ALIAS_3(NAME,PRE,POST) DEFINE_ALIAS_RAW(NAME,PRE,POST,(long p1,long p2,long p3),(p1,p2,p3)) +#ifdef NO_DEFINE_ALIAS +#define DEFINE_ALIAS(NAME,N) +#define DEFINE_ALIAS_CLOBBER_SO(NAME,N) +#define DEFINE_ALIAS_CLOBBER_CR(NAME,N) +#else +#define DEFINE_ALIAS(NAME,N) DEFINE_ALIAS_##N(NAME,,) +#define DEFINE_ALIAS_CLOBBER_CR(NAME,N) DEFINE_ALIAS_##N(NAME,gen_commit_cr(),) +#define DEFINE_ALIAS_CLOBBER_SO(NAME,N) DEFINE_ALIAS_##N(NAME,gen_commit_so(),) +#endif + + // Condition registers +private: + void do_gen_commit_so(); + void do_gen_commit_cr(); + void gen_commit_so_cache_cr(int crf); + void gen_commit_rc_cache_cr(int crf); + void gen_commit_logical_rc_cache_cr(int crf); +public: + void invalidate_so_cache(); + void invalidate_cr_cache(); + void gen_commit_so(); + void gen_commit_cr(); + DEFINE_ALIAS_CLOBBER_CR(load_T0_CR,0); + DEFINE_ALIAS_CLOBBER_CR(store_T0_CR,0); + DEFINE_ALIAS(load_T0_XER,0); + DEFINE_ALIAS(store_T0_XER,0); + void gen_load_T0_crb(int i); + void gen_load_T1_crb(int i); + void gen_store_T0_crb(int i); + void gen_store_T1_crb(int i); + void gen_load_T0_cr(int crf); + void gen_store_T0_cr(int crf); + + // Special purpose registers + DEFINE_ALIAS(load_T0_PC,0); + DEFINE_ALIAS(store_T0_PC,0); + DEFINE_ALIAS(set_PC_T1,0); + DEFINE_ALIAS(set_PC_im,1); + DEFINE_ALIAS(inc_PC,1); + DEFINE_ALIAS(load_T0_LR,0); + DEFINE_ALIAS(store_T0_LR,0); + DEFINE_ALIAS(load_T0_CTR,0); + DEFINE_ALIAS(load_T1_CTR,0); + DEFINE_ALIAS(store_T0_CTR,0); + DEFINE_ALIAS(store_T1_CTR,0); + DEFINE_ALIAS(load_T1_PC,0); + DEFINE_ALIAS(load_T1_LR,0); + DEFINE_ALIAS(store_im_LR,1); + + // Control Flow + DEFINE_ALIAS(decrement_ctr_T1,0); + DEFINE_ALIAS(branch_if_T0,2); + DEFINE_ALIAS(branch_if_T1,2); + DEFINE_ALIAS(branch_if_not_T0,2); + DEFINE_ALIAS(branch_if_not_T1,2); + DEFINE_ALIAS(branch_if_T0_T1,2); + DEFINE_ALIAS(branch_T1_if_T0,1); + + // Compare & Record instructions + DEFINE_ALIAS_CLOBBER_SO(record_nego_T0,0); + void gen_record_cr0_T0(); + DEFINE_ALIAS(compare_T0_T1,0); + DEFINE_ALIAS(compare_T0_0,0); + DEFINE_ALIAS(compare_T0_im,1); + void gen_compare_T0_T1(int crf); + void gen_compare_T0_im(int crf, int32 value); + void gen_compare_logical_T0_T1(int crf); + void gen_compare_logical_T0_im(int crf, int32 value); + + // Multiply/Divide instructions + DEFINE_ALIAS(mulhw_T0_T1,0); + DEFINE_ALIAS(mulhwu_T0_T1,0); + DEFINE_ALIAS(mulli_T0_im,1); + DEFINE_ALIAS_CLOBBER_SO(mullwo_T0_T1,0); + DEFINE_ALIAS(divw_T0_T1,0); + DEFINE_ALIAS_CLOBBER_SO(divwo_T0_T1,0); + DEFINE_ALIAS(divwu_T0_T1,0); + DEFINE_ALIAS_CLOBBER_SO(divwuo_T0_T1,0); + + // Shift/Rotate instructions + DEFINE_ALIAS(slw_T0_T1,0); + DEFINE_ALIAS(srw_T0_T1,0); + DEFINE_ALIAS(sraw_T0_T1,0); + DEFINE_ALIAS(sraw_T0_im,1); + DEFINE_ALIAS(rlwimi_T0_T1,2); + DEFINE_ALIAS(rlwinm_T0_T1,2); + DEFINE_ALIAS(rlwnm_T0_T1,1); + DEFINE_ALIAS(cntlzw_32_T0,0); + + // Add/Sub related instructions + DEFINE_ALIAS(addo_T0_T1,0); + DEFINE_ALIAS(addc_T0_im,1); + DEFINE_ALIAS(addc_T0_T1,0); + DEFINE_ALIAS_CLOBBER_SO(addco_T0_T1,0); + DEFINE_ALIAS(adde_T0_T1,0); + DEFINE_ALIAS_CLOBBER_SO(addeo_T0_T1,0); + DEFINE_ALIAS(addme_T0,0); + DEFINE_ALIAS_CLOBBER_SO(addmeo_T0,0); + DEFINE_ALIAS(addze_T0,0); + DEFINE_ALIAS_CLOBBER_SO(addzeo_T0,0); + DEFINE_ALIAS(subf_T0_T1,0); + DEFINE_ALIAS_CLOBBER_SO(subfo_T0_T1,0); + DEFINE_ALIAS(subfc_T0_im,1); + DEFINE_ALIAS(subfc_T0_T1,0); + DEFINE_ALIAS_CLOBBER_SO(subfco_T0_T1,0); + DEFINE_ALIAS(subfe_T0_T1,0); + DEFINE_ALIAS_CLOBBER_SO(subfeo_T0_T1,0); + DEFINE_ALIAS(subfme_T0,0); + DEFINE_ALIAS_CLOBBER_SO(subfmeo_T0,0); + DEFINE_ALIAS(subfze_T0,0); + DEFINE_ALIAS_CLOBBER_SO(subfzeo_T0,0); + + // Branch instructions + void gen_bc(int bo, int bi, uint32 tpc, uint32 npc); +#define DEFINE_ALIAS_GRP_1(CR,CTR) \ + DEFINE_ALIAS(b##CR##_##CTR,2); \ + DEFINE_ALIAS(bn##CR##_##CTR,2); +#define DEFINE_ALIAS_GRP_2(CR) \ + DEFINE_ALIAS_GRP_1(CR,0x); \ + DEFINE_ALIAS_GRP_1(CR,10); \ + DEFINE_ALIAS_GRP_1(CR,11); + DEFINE_ALIAS_GRP_2(lt); + DEFINE_ALIAS_GRP_2(gt); + DEFINE_ALIAS_GRP_2(eq); + DEFINE_ALIAS_GRP_2(so); +#undef DEFINE_ALAIS_GRP_2 +#undef DEFINE_ALIAS_GRP_1 + +#undef DEFINE_ALIAS +#undef DEFINE_ALIAS_0 +#undef DEFINE_ALIAS_1 +#undef DEFINE_ALIAS_2 +#undef DEFINE_ALIAS_3 +#undef DEFINE_ALIAS_RAW +}; + +#endif /* PPC_ENABLE_JIT */ + +#endif /* PPC_DYNGEN_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp index 34835790..8219c6ff 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.cpp @@ -28,6 +28,11 @@ #include "cpu/ppc/ppc-bitfields.hpp" #include "cpu/ppc/ppc-operands.hpp" #include "cpu/ppc/ppc-operations.hpp" +#include "cpu/ppc/ppc-execute.hpp" + +#ifndef SHEEPSHAVER +#include "basic-kernel.hpp" +#endif #if ENABLE_MON #include "mon.h" @@ -378,22 +383,11 @@ void powerpc_cpu::execute_divide(uint32 opcode) const uint32 b = operand_RB::get(this, opcode); uint32 d; - if (b == 0 || (SB && a == 0x80000000 && b == 0xffffffff)) { - // Reference manual says rD is undefined - d = 0; - if (SB) { - // However, checking against a real PowerPC (7410) yields - // that rD gets all bits set to rA MSB - d = -(a >> 31); - } - if (OE::test(opcode)) - xer().set_ov(1); - } - else { - d = SB ? (int32)a/(int32)b : a/b; - if (OE::test(opcode)) - xer().set_ov(0); - } + // Specialize divide semantic action + if (OE::test(opcode)) + d = do_execute_divide(a, b); + else + d = do_execute_divide(a, b); // Set CR0 (LT, GT, EQ, SO) if instruction has Rc set if (Rc::test(opcode)) @@ -926,8 +920,21 @@ void powerpc_cpu::execute_fp_round(uint32 opcode) void powerpc_cpu::execute_syscall(uint32 opcode) { - cr().set_so(0, execute_do_syscall && !execute_do_syscall(this)); +#ifdef SHEEPSHAVER + D(bug("syscall\n")); increment_pc(4); +#else + try { + cr().set_so(0, execute_do_syscall && !execute_do_syscall(this)); + increment_pc(4); + } + catch (kernel_syscall_exit & sc_exit) { + // FIXME: add unwind info to the translation cache? Otherwise + // we have to manually forward the exception to execution loop + syscall_exit_code = sc_exit.status; + spcflags().set(SPCFLAG_CPU_EXEC_RETURN); + } +#endif } /** @@ -1026,17 +1033,15 @@ void powerpc_cpu::execute_mfmsr(uint32 opcode) template< class SPR > void powerpc_cpu::execute_mfspr(uint32 opcode) { - uint32 spr = SPR::get(this, opcode); + const uint32 spr = SPR::get(this, opcode); uint32 d; switch (spr) { - case 1: d = xer().get(); break; - case 8: d = lr(); break; - case 9: d = ctr(); break; + case powerpc_registers::SPR_XER: d = xer().get();break; + case powerpc_registers::SPR_LR: d = lr(); break; + case powerpc_registers::SPR_CTR: d = ctr(); break; #ifdef SHEEPSHAVER - case 25: // SDR1 - d = 0xdead001f; - break; - case 287: { // PVR + case powerpc_registers::SPR_SDR1: d = 0xdead001f; break; + case powerpc_registers::SPR_PVR: { extern uint32 PVR; d = PVR; break; @@ -1053,13 +1058,13 @@ void powerpc_cpu::execute_mfspr(uint32 opcode) template< class SPR > void powerpc_cpu::execute_mtspr(uint32 opcode) { - uint32 spr = SPR::get(this, opcode); + const uint32 spr = SPR::get(this, opcode); const uint32 s = operand_RS::get(this, opcode); switch (spr) { - case 1: xer().set(s); break; - case 8: lr() = s; break; - case 9: ctr() = s; break; + case powerpc_registers::SPR_XER: xer().set(s); break; + case powerpc_registers::SPR_LR: lr() = s; break; + case powerpc_registers::SPR_CTR: ctr() = s; break; #ifndef SHEEPSHAVER default: execute_illegal(opcode); #endif diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.hpp new file mode 100644 index 00000000..633af6e7 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-execute.hpp @@ -0,0 +1,134 @@ +/* + * ppc-execute.hpp - PowerPC semantic action templates + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 PPC_EXECUTE_H +#define PPC_EXECUTE_H + +// This file is designed to be included from implementation files only. +#ifdef DYNGEN_OPS +#define PPC_CPU powerpc_dyngen_helper +#define DEFINE_HELPER(NAME, ARGS) static inline uint32 NAME ARGS +#define RETURN(VAL) dyngen_barrier(); return (VAL) +#else +#define PPC_CPU powerpc_cpu +#define DEFINE_HELPER(NAME, ARGS) inline uint32 powerpc_cpu::NAME ARGS +#define RETURN(VAL) return (VAL) +#endif + + +template< bool SB > struct register_value { typedef uint32 type; }; +template< > struct register_value< true > { typedef int32 type; }; + +/** + * Add instruction templates + **/ + +template< bool EX, bool CA, bool OE > +DEFINE_HELPER(do_execute_addition, (uint32 RA, uint32 RB)) +{ + uint32 RD = RA + RB + (EX ? PPC_CPU::xer().get_ca() : 0); + + const bool _RA = ((int32)RA) < 0; + const bool _RB = ((int32)RB) < 0; + const bool _RD = ((int32)RD) < 0; + + if (EX) { + const bool ca = _RB ^ ((_RB ^ _RA) & (_RA ^ _RD)); + PPC_CPU::xer().set_ca(ca); + } + else if (CA) { + const bool ca = (uint32)RD < (uint32)RA; + PPC_CPU::xer().set_ca(ca); + } + + if (OE) + PPC_CPU::xer().set_ov((_RB ^ _RD) & (_RA ^ _RD)); + + RETURN(RD); +} + +/** + * Subtract instruction templates + **/ + +template< bool CA, bool OE > +DEFINE_HELPER(do_execute_subtract, (uint32 RA, uint32 RB)) +{ + uint32 RD = RB - RA; + + const bool _RA = ((int32)RA) < 0; + const bool _RB = ((int32)RB) < 0; + const bool _RD = ((int32)RD) < 0; + + if (CA) + PPC_CPU::xer().set_ca((uint32)RD <= (uint32)RB); + + if (OE) + PPC_CPU::xer().set_ov((_RA ^ _RB) & (_RD ^ _RB)); + + RETURN(RD); +} + +template< bool OE > +DEFINE_HELPER(do_execute_subtract_extended, (uint32 RA, uint32 RB)) +{ + const uint32 RD = ~RA + RB + PPC_CPU::xer().get_ca(); + + const bool _RA = ((int32)RA) < 0; + const bool _RB = ((int32)RB) < 0; + const bool _RD = ((int32)RD) < 0; + + const bool ca = !_RA ^ ((_RA ^ _RD) & (_RB ^ _RD)); + PPC_CPU::xer().set_ca(ca); + + if (OE) + PPC_CPU::xer().set_ov((_RA ^ _RB) & (_RD ^ _RB)); + + RETURN(RD); +} + +/** + * Divide instruction templates + **/ + +template< bool SB, bool OE > +DEFINE_HELPER(do_execute_divide, (uint32 RA, uint32 RB)) +{ + typename register_value::type a = RA; + typename register_value::type b = RB; + uint32 RD; + + if (b == 0 || (SB && a == 0x80000000 && b == -1)) { + // Reference manual says result is undefined but it gets all + // bits set to MSB on a real processor + RD = SB ? ((int32)RA >> 31) : 0; + if (OE) + PPC_CPU::xer().set_ov(1); + } + else { + RD = a / b; + if (OE) + PPC_CPU::xer().set_ov(0); + } + + RETURN(RD); +} + +#endif /* PPC_EXECUTE_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-instructions.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-instructions.hpp new file mode 100644 index 00000000..da8aa780 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-instructions.hpp @@ -0,0 +1,204 @@ +/* + * ppc-instructions.hpp - PowerPC instructions IDs + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 PPC_INSTRUCTIONS_H +#define PPC_INSTRUCTIONS_H + +/** + * Define PowerPC instruction types + **/ + +#define PPC_I(X) powerpc_instruction_##X + +enum powerpc_instruction { + PPC_I(INVALID), + PPC_I(ADD), + PPC_I(ADDC), + PPC_I(ADDE), + PPC_I(ADDI), + PPC_I(ADDIC), + PPC_I(ADDIC_), + PPC_I(ADDIS), + PPC_I(ADDME), + PPC_I(ADDZE), + PPC_I(AND), + PPC_I(ANDC), + PPC_I(ANDI), + PPC_I(ANDIS), + PPC_I(B), + PPC_I(BC), + PPC_I(BCCTR), + PPC_I(BCLR), + PPC_I(CMP), + PPC_I(CMPI), + PPC_I(CMPL), + PPC_I(CMPLI), + PPC_I(CNTLZW), + PPC_I(CRAND), + PPC_I(CRANDC), + PPC_I(CREQV), + PPC_I(CRNAND), + PPC_I(CRNOR), + PPC_I(CROR), + PPC_I(CRORC), + PPC_I(CRXOR), + PPC_I(DCBA), + PPC_I(DCBF), + PPC_I(DCBI), + PPC_I(DCBST), + PPC_I(DCBT), + PPC_I(DCBTST), + PPC_I(DCBZ), + PPC_I(DIVW), + PPC_I(DIVWU), + PPC_I(ECIWX), + PPC_I(ECOWX), + PPC_I(EIEIO), + PPC_I(EQV), + PPC_I(EXTSB), + PPC_I(EXTSH), + PPC_I(FABS), + PPC_I(FADD), + PPC_I(FADDS), + PPC_I(FCMPO), + PPC_I(FCMPU), + PPC_I(FCTIW), + PPC_I(FCTIWZ), + PPC_I(FDIV), + PPC_I(FDIVS), + PPC_I(FMADD), + PPC_I(FMADDS), + PPC_I(FMR), + PPC_I(FMSUB), + PPC_I(FMSUBS), + PPC_I(FMUL), + PPC_I(FMULS), + PPC_I(FNABS), + PPC_I(FNEG), + PPC_I(FNMADD), + PPC_I(FNMADDS), + PPC_I(FNMSUB), + PPC_I(FNMSUBS), + PPC_I(FRSP), + PPC_I(FSUB), + PPC_I(FSUBS), + PPC_I(ICBI), + PPC_I(ISYNC), + PPC_I(LBZ), + PPC_I(LBZU), + PPC_I(LBZUX), + PPC_I(LBZX), + PPC_I(LFD), + PPC_I(LFDU), + PPC_I(LFDUX), + PPC_I(LFDX), + PPC_I(LFS), + PPC_I(LFSU), + PPC_I(LFSUX), + PPC_I(LFSX), + PPC_I(LHA), + PPC_I(LHAU), + PPC_I(LHAUX), + PPC_I(LHAX), + PPC_I(LHBRX), + PPC_I(LHZ), + PPC_I(LHZU), + PPC_I(LHZUX), + PPC_I(LHZX), + PPC_I(LMW), + PPC_I(LSWI), + PPC_I(LSWX), + PPC_I(LWARX), + PPC_I(LWBRX), + PPC_I(LWZ), + PPC_I(LWZU), + PPC_I(LWZUX), + PPC_I(LWZX), + PPC_I(MCRF), + PPC_I(MFCR), + PPC_I(MFFS), + PPC_I(MFMSR), + PPC_I(MFSPR), + PPC_I(MFTB), + PPC_I(MTCRF), + PPC_I(MTFSB0), + PPC_I(MTFSB1), + PPC_I(MTFSF), + PPC_I(MTFSFI), + PPC_I(MTSPR), + PPC_I(MULHW), + PPC_I(MULHWU), + PPC_I(MULLI), + PPC_I(MULLW), + PPC_I(NAND), + PPC_I(NEG), + PPC_I(NOR), + PPC_I(OR), + PPC_I(ORC), + PPC_I(ORI), + PPC_I(ORIS), + PPC_I(RLWIMI), + PPC_I(RLWINM), + PPC_I(RLWNM), + PPC_I(SC), + PPC_I(SLW), + PPC_I(SRAW), + PPC_I(SRAWI), + PPC_I(SRW), + PPC_I(STB), + PPC_I(STBU), + PPC_I(STBUX), + PPC_I(STBX), + PPC_I(STFD), + PPC_I(STFDU), + PPC_I(STFDUX), + PPC_I(STFDX), + PPC_I(STFS), + PPC_I(STFSU), + PPC_I(STFSUX), + PPC_I(STFSX), + PPC_I(STH), + PPC_I(STHBRX), + PPC_I(STHU), + PPC_I(STHUX), + PPC_I(STHX), + PPC_I(STMW), + PPC_I(STSWI), + PPC_I(STSWX), + PPC_I(STW), + PPC_I(STWBRX), + PPC_I(STWCX), + PPC_I(STWU), + PPC_I(STWUX), + PPC_I(STWX), + PPC_I(SUBF), + PPC_I(SUBFC), + PPC_I(SUBFE), + PPC_I(SUBFIC), + PPC_I(SUBFME), + PPC_I(SUBFZE), + PPC_I(SYNC), + PPC_I(XOR), + PPC_I(XORI), + PPC_I(XORIS), + PPC_I(MAX) // Total number of instruction types +}; + +#endif /* PPC_INSTRUCTIONS_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-operands.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-operands.hpp index 76921816..227a21eb 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-operands.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-operands.hpp @@ -120,13 +120,16 @@ struct immediate_value { }; struct mask_operand { - static inline uint32 get(powerpc_cpu *, uint32 opcode) { - const uint32 mb = MB_field::extract(opcode); - const uint32 me = ME_field::extract(opcode); + static inline uint32 compute(uint32 mb, uint32 me) { return ((mb > me) ? ~(((uint32)-1 >> mb) ^ ((me >= 31) ? 0 : (uint32)-1 >> (me + 1))) : (((uint32)-1 >> mb) ^ ((me >= 31) ? 0 : (uint32)-1 >> (me + 1)))); } + static inline uint32 get(powerpc_cpu *, uint32 opcode) { + const uint32 mb = MB_field::extract(opcode); + const uint32 me = ME_field::extract(opcode); + return compute(mb, me); + } }; /** diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp index 813a0be8..e693bee2 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp @@ -105,27 +105,27 @@ powerpc_cr_register::test(int condition) const class powerpc_xer_register { - bool so; - bool ov; - bool ca; - uint32 byte_count; + uint8 so; + uint8 ov; + uint8 ca; + uint8 byte_count; public: powerpc_xer_register(); void set(uint32 xer); uint32 get() const; - void set_so(bool v) { so = v; } - bool get_so() const { return so; } - void set_ov(bool v) { ov = v; if (v) so = true; } - bool get_ov() const { return ov; } - void set_ca(bool v) { ca = v; } - bool get_ca() const { return ca; } - void set_count(uint32 v) { byte_count = v; } - uint32 get_count() const { return byte_count; } + void set_so(int v) { so = v; } + int get_so() const { return so; } + void set_ov(int v) { ov = v; so |= v; } + int get_ov() const { return ov; } + void set_ca(int v) { ca = v; } + int get_ca() const { return ca; } + void set_count(int v) { byte_count = v; } + int get_count() const { return byte_count; } }; inline powerpc_xer_register::powerpc_xer_register() - : so(false), ov(false), ca(false), byte_count(0) + : so(0), ov(0), ca(0), byte_count(0) { } inline uint32 @@ -178,7 +178,15 @@ struct powerpc_registers PC, SP = GPR_BASE + 1 }; - + + enum { + SPR_XER = 1, + SPR_LR = 8, + SPR_CTR = 9, + SPR_SDR1 = 25, + SPR_PVR = 287, + }; + static inline int GPR(int r) { return GPR_BASE + r; } static inline int FPR(int r) { return FPR_BASE + r; } diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp new file mode 100644 index 00000000..8925fcc5 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp @@ -0,0 +1,1031 @@ +/* + * ppc-translate.cpp - PowerPC dynamic translation + * + * Kheperix (C) 2003 Gwenole Beauchesne + * + * 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 "sysdeps.h" +#include "cpu/ppc/ppc-cpu.hpp" +#include "cpu/ppc/ppc-instructions.hpp" +#include "cpu/ppc/ppc-operands.hpp" + +#include + +#define DEBUG 1 +#include "debug.h" + +#if ENABLE_MON +#include "mon.h" +#include "mon_disass.h" +#endif + + +/** + * Basic block disassemblers + **/ + +#define TARGET_M68K 0 +#define TARGET_POWERPC 1 +#define TARGET_X86 2 +#define TARGET_AMD64 3 +#if defined(i386) || defined(__i386__) +#define TARGET_NATIVE TARGET_X86 +#endif +#if defined(x86_64) || defined(__x86_64__) +#define TARGET_NATIVE TARGET_AMD64 +#endif +#if defined(powerpc) || defined(__powerpc__) +#define TARGET_NATIVE TARGET_POWERPC +#endif + +static void disasm_block(int target, uint8 *start, uint32 length) +{ +#if ENABLE_MON + char disasm_str[200]; + sprintf(disasm_str, "%s $%x $%x", + target == TARGET_M68K ? "d68" : + target == TARGET_X86 ? "d86" : + target == TARGET_AMD64 ? "d8664" : + target == TARGET_POWERPC ? "d" : "x", + start, start + length - 1); + + char *arg[] = {"mon", +#ifdef SHEEPSHAVER + "-m", +#endif + "-r", disasm_str, NULL}; + mon(sizeof(arg)/sizeof(arg[0]) - 1, arg); +#endif +} + +static void disasm_translation(uint32 src_addr, uint32 src_len, + uint8* dst_addr, uint32 dst_len) +{ + printf("### Block at %08x translated to %p (%d bytes)\n", src_addr, dst_addr, dst_len); + printf("IN:\n"); + disasm_block(TARGET_POWERPC, vm_do_get_real_address(src_addr), src_len); + printf("OUT:\n"); + disasm_block(TARGET_NATIVE, dst_addr, dst_len); +} + + +/** + * DynGen dynamic code translation + **/ + +#if PPC_ENABLE_JIT +powerpc_cpu::block_info * +powerpc_cpu::compile_block(uint32 entry_point) +{ +#if DEBUG + bool disasm = false; +#else + const bool disasm = false; +#endif + +#if PPC_PROFILE_COMPILE_TIME + compile_count++; + clock_t start_time = clock(); +#endif + block_info *bi = block_cache.new_blockinfo(); + bi->init(entry_point); + + again: + powerpc_dyngen & dg = codegen; + bi->entry_point = dg.gen_start(); + const instr_info_t *ii; + + codegen_context_t cg_context(dg); + cg_context.entry_point = entry_point; + + uint32 dpc = entry_point - 4; + int pc_offset = 0; + do { + uint32 opcode = vm_read_memory_4(dpc += 4); + ii = decode(opcode); +#if PPC_FLIGHT_RECORDER + if (is_logging()) + dg.gen_invoke_CPU_im(nv_mem_fun(&powerpc_cpu::record_step).ptr(), opcode); +#endif + + union operands_t { + struct { + int size, sign; + int do_update; + int do_indexed; + } mem; + }; + operands_t op; + + pc_offset += 4; + switch (ii->mnemo) { + case PPC_I(LBZ): // Load Byte and Zero + op.mem.size = 1; + op.mem.sign = 0; + op.mem.do_update = 0; + op.mem.do_indexed = 0; + goto do_load; + case PPC_I(LBZU): // Load Byte and Zero with Update + op.mem.size = 1; + op.mem.sign = 0; + op.mem.do_update = 1; + op.mem.do_indexed = 0; + goto do_load; + case PPC_I(LBZUX): // Load Byte and Zero with Update Indexed + op.mem.size = 1; + op.mem.sign = 0; + op.mem.do_update = 1; + op.mem.do_indexed = 1; + goto do_load; + case PPC_I(LBZX): // Load Byte and Zero Indexed + op.mem.size = 1; + op.mem.sign = 0; + op.mem.do_update = 0; + op.mem.do_indexed = 1; + goto do_load; + case PPC_I(LHA): // Load Half Word Algebraic + op.mem.size = 2; + op.mem.sign = 1; + op.mem.do_update = 0; + op.mem.do_indexed = 0; + goto do_load; + case PPC_I(LHAU): // Load Half Word Algebraic with Update + op.mem.size = 2; + op.mem.sign = 1; + op.mem.do_update = 1; + op.mem.do_indexed = 0; + goto do_load; + case PPC_I(LHAUX): // Load Half Word Algebraic with Update Indexed + op.mem.size = 2; + op.mem.sign = 1; + op.mem.do_update = 1; + op.mem.do_indexed = 1; + goto do_load; + case PPC_I(LHAX): // Load Half Word Algebraic Indexed + op.mem.size = 2; + op.mem.sign = 1; + op.mem.do_update = 0; + op.mem.do_indexed = 1; + goto do_load; + case PPC_I(LHZ): // Load Half Word and Zero + op.mem.size = 2; + op.mem.sign = 0; + op.mem.do_update = 0; + op.mem.do_indexed = 0; + goto do_load; + case PPC_I(LHZU): // Load Half Word and Zero with Update + op.mem.size = 2; + op.mem.sign = 0; + op.mem.do_update = 1; + op.mem.do_indexed = 0; + goto do_load; + case PPC_I(LHZUX): // Load Half Word and Zero with Update Indexed + op.mem.size = 2; + op.mem.sign = 0; + op.mem.do_update = 1; + op.mem.do_indexed = 1; + goto do_load; + case PPC_I(LHZX): // Load Half Word and Zero Indexed + op.mem.size = 2; + op.mem.sign = 0; + op.mem.do_update = 0; + op.mem.do_indexed = 1; + goto do_load; + case PPC_I(LWZ): // Load Word and Zero + op.mem.size = 4; + op.mem.sign = 0; + op.mem.do_update = 0; + op.mem.do_indexed = 0; + goto do_load; + case PPC_I(LWZU): // Load Word and Zero with Update + op.mem.size = 4; + op.mem.sign = 0; + op.mem.do_update = 1; + op.mem.do_indexed = 0; + goto do_load; + case PPC_I(LWZUX): // Load Word and Zero with Update Indexed + op.mem.size = 4; + op.mem.sign = 0; + op.mem.do_update = 1; + op.mem.do_indexed = 1; + goto do_load; + case PPC_I(LWZX): // Load Word and Zero Indexed + op.mem.size = 4; + op.mem.sign = 0; + op.mem.do_update = 0; + op.mem.do_indexed = 1; + goto do_load; + { + do_load: + // Extract RZ operand + const int rA = rA_field::extract(opcode); + if (rA == 0 && !op.mem.do_update) + dg.gen_mov_32_A0_im(0); + else + dg.gen_load_A0_GPR(rA); + + // Extract index operand + if (op.mem.do_indexed) + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + + switch (op.mem.size) { + case 1: + if (op.mem.do_indexed) + dg.gen_load_u8_T0_A0_T1(); + else + dg.gen_load_u8_T0_A0_im(operand_D::get(this, opcode)); + break; + case 2: + if (op.mem.do_indexed) { + if (op.mem.sign) + dg.gen_load_s16_T0_A0_T1(); + else + dg.gen_load_u16_T0_A0_T1(); + } + else { + const int32 offset = operand_D::get(this, opcode); + if (op.mem.sign) + dg.gen_load_s16_T0_A0_im(offset); + else + dg.gen_load_u16_T0_A0_im(offset); + } + break; + case 4: + if (op.mem.do_indexed) { + dg.gen_load_u32_T0_A0_T1(); + } + else { + const int32 offset = operand_D::get(this, opcode); + dg.gen_load_u32_T0_A0_im(offset); + } + break; + } + + // Commit result + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + + // Update RA + if (op.mem.do_update) { + if (op.mem.do_indexed) + dg.gen_add_32_A0_T1(); + else + dg.gen_add_32_A0_im(operand_D::get(this, opcode)); + dg.gen_store_A0_GPR(rA); + } + break; + } + case PPC_I(STB): // Store Byte + op.mem.size = 1; + op.mem.do_update = 0; + op.mem.do_indexed = 0; + goto do_store; + case PPC_I(STBU): // Store Byte with Update + op.mem.size = 1; + op.mem.do_update = 1; + op.mem.do_indexed = 0; + goto do_store; + case PPC_I(STBUX): // Store Byte with Update Indexed + op.mem.size = 1; + op.mem.do_update = 1; + op.mem.do_indexed = 1; + goto do_store; + case PPC_I(STBX): // Store Byte Indexed + op.mem.size = 1; + op.mem.do_update = 0; + op.mem.do_indexed = 1; + goto do_store; + case PPC_I(STH): // Store Half Word + op.mem.size = 2; + op.mem.do_update = 0; + op.mem.do_indexed = 0; + goto do_store; + case PPC_I(STHU): // Store Half Word with Update + op.mem.size = 2; + op.mem.do_update = 1; + op.mem.do_indexed = 0; + goto do_store; + case PPC_I(STHUX): // Store Half Word with Update Indexed + op.mem.size = 2; + op.mem.do_update = 1; + op.mem.do_indexed = 1; + goto do_store; + case PPC_I(STHX): // Store Half Word Indexed + op.mem.size = 2; + op.mem.do_update = 0; + op.mem.do_indexed = 1; + goto do_store; + case PPC_I(STW): // Store Word + op.mem.size = 4; + op.mem.do_update = 0; + op.mem.do_indexed = 0; + goto do_store; + case PPC_I(STWU): // Store Word with Update + op.mem.size = 4; + op.mem.do_update = 1; + op.mem.do_indexed = 0; + goto do_store; + case PPC_I(STWUX): // Store Word with Update Indexed + op.mem.size = 4; + op.mem.do_update = 1; + op.mem.do_indexed = 1; + goto do_store; + case PPC_I(STWX): // Store Word Indexed + op.mem.size = 4; + op.mem.do_update = 0; + op.mem.do_indexed = 1; + goto do_store; + { + do_store: + // Extract RZ operand + const int rA = rA_field::extract(opcode); + if (rA == 0 && !op.mem.do_update) + dg.gen_mov_32_A0_im(0); + else + dg.gen_load_A0_GPR(rA); + + // Extract index operand + if (op.mem.do_indexed) + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + + // Load register to commit to memory + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + + switch (op.mem.size) { + case 1: + if (op.mem.do_indexed) + dg.gen_store_8_T0_A0_T1(); + else + dg.gen_store_8_T0_A0_im(operand_D::get(this, opcode)); + break; + case 2: + if (op.mem.do_indexed) + dg.gen_store_16_T0_A0_T1(); + else + dg.gen_store_16_T0_A0_im(operand_D::get(this, opcode)); + break; + case 4: + if (op.mem.do_indexed) + dg.gen_store_32_T0_A0_T1(); + else + dg.gen_store_32_T0_A0_im(operand_D::get(this, opcode)); + break; + } + + // Update RA + if (op.mem.do_update) { + if (op.mem.do_indexed) + dg.gen_add_32_A0_T1(); + else + dg.gen_add_32_A0_im(operand_D::get(this, opcode)); + dg.gen_store_A0_GPR(rA); + } + break; + } + case PPC_I(BC): // Branch Conditional + { + const int bo = BO_field::extract(opcode); + const int bi = BI_field::extract(opcode); + + const uint32 npc = dpc + 4; + if (LK_field::test(opcode)) + dg.gen_store_im_LR(npc); + + uint32 tpc = ((AA_field::test(opcode) ? 0 : dpc) + operand_BD::get(this, opcode)) & -4; + dg.gen_bc(bo, bi, tpc, npc); +// disasm = true; + break; + } + case PPC_I(BCCTR): // Branch Conditional to Count Register + case PPC_I(BCLR): // Branch Conditional to Link Register +// case PPC_I(BC): // Branch Conditional + { + dg.gen_commit_cr(); + + bool ctr_cond = false; + bool branch_cond = false; + + const int bo = BO_field::extract(opcode); + if (BO_DECREMENT_CTR(bo)) { + ctr_cond = true; + dg.gen_load_T1_CTR(); + dg.gen_sub_32_T1_im(1); + dg.gen_store_T1_CTR(); + if (BO_BRANCH_IF_CTR_ZERO(bo)) + dg.gen_not_32_T1(); + } + + if (BO_CONDITIONAL_BRANCH(bo)) { + branch_cond = true; + dg.gen_load_T0_crb(BI_field::extract(opcode)); + if (!BO_BRANCH_IF_TRUE(bo)) + dg.gen_not_32_T0(); + } + + const uint32 npc = dpc + 4; + if (ii->mnemo == PPC_I(BC) && AA_field::test(opcode)) { + const uint32 tpc = (dpc + operand_BD::get(this, opcode)) & -4; + if (ctr_cond && branch_cond) { + dg.gen_and_logical_T0_T1(); + dg.gen_branch_if_T0(tpc, npc); + } + else if (ctr_cond) + dg.gen_branch_if_T1(tpc, npc); + else if (branch_cond) + dg.gen_branch_if_T0(tpc, npc); + else + dg.gen_set_PC_im(tpc); + } + else { + if (ctr_cond && branch_cond) + dg.gen_and_logical_T0_T1(); + else if (ctr_cond) + dg.gen_mov_32_T0_T1(); + switch (ii->mnemo) { + case PPC_I(BCCTR): + dg.gen_load_T1_CTR(); + break; + case PPC_I(BCLR): + dg.gen_load_T1_LR(); + break; + case PPC_I(BC): { + const uint32 tpc = (dpc + operand_BD::get(this, opcode)) & -4; + dg.gen_mov_32_T1_im(tpc); + break; + } + } + if (ctr_cond && branch_cond) + dg.gen_branch_T1_if_T0(npc); + else if (ctr_cond) + dg.gen_branch_T1_if_T0(npc); + else if (branch_cond) + dg.gen_branch_T1_if_T0(npc); + else + dg.gen_set_PC_T1(); + } + + if (LK_field::test(opcode)) + dg.gen_store_im_LR(npc); + break; + } + case PPC_I(B): // Branch + { + dg.gen_commit_cr(); + uint32 tpc = AA_field::test(opcode) ? 0 : dpc; + tpc = (tpc + operand_LI::get(this, opcode)) & -4; + if (LK_field::test(opcode)) + dg.gen_store_im_LR(dpc + 4); + dg.gen_set_PC_im(tpc); + break; + } + case PPC_I(CMP): // Compare + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + dg.gen_compare_T0_T1(crfD_field::extract(opcode)); + break; + } + case PPC_I(CMPI): // Compare Immediate + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + dg.gen_compare_T0_im(crfD_field::extract(opcode), operand_SIMM::get(this, opcode)); + break; + } + case PPC_I(CMPL): // Compare Logical + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + dg.gen_compare_logical_T0_T1(crfD_field::extract(opcode)); + break; + } + case PPC_I(CMPLI): // Compare Logical Immediate + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + dg.gen_compare_logical_T0_im(crfD_field::extract(opcode), operand_UIMM::get(this, opcode)); + break; + } + case PPC_I(CRAND): // Condition Register AND + case PPC_I(CRANDC): // Condition Register AND with Complement + case PPC_I(CREQV): // Condition Register Equivalent + case PPC_I(CRNAND): // Condition Register NAND + case PPC_I(CRNOR): // Condition Register NOR + case PPC_I(CROR): // Condition Register OR + case PPC_I(CRORC): // Condition Register OR with Complement + case PPC_I(CRXOR): // Condition Register XOR + { + dg.gen_commit_cr(); + dg.gen_load_T0_crb(crbA_field::extract(opcode)); + dg.gen_load_T1_crb(crbB_field::extract(opcode)); + switch (ii->mnemo) { + case PPC_I(CRAND): dg.gen_and_32_T0_T1(); break; + case PPC_I(CRANDC): dg.gen_andc_32_T0_T1(); break; + case PPC_I(CREQV): dg.gen_eqv_32_T0_T1(); break; + case PPC_I(CRNAND): dg.gen_nand_32_T0_T1(); break; + case PPC_I(CRNOR): dg.gen_nor_32_T0_T1(); break; + case PPC_I(CROR): dg.gen_or_32_T0_T1(); break; + case PPC_I(CRORC): dg.gen_orc_32_T0_T1(); break; + case PPC_I(CRXOR): dg.gen_xor_32_T0_T1(); break; + default: abort(); + } + dg.gen_store_T0_crb(crbD_field::extract(opcode)); + break; + } + case PPC_I(AND): // AND + case PPC_I(ANDC): // AND with Complement + case PPC_I(EQV): // Equivalent + case PPC_I(NAND): // NAND + case PPC_I(NOR): // NOR + case PPC_I(ORC): // ORC + case PPC_I(XOR): // XOR + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + switch (ii->mnemo) { + case PPC_I(AND): dg.gen_and_32_T0_T1(); break; + case PPC_I(ANDC): dg.gen_andc_32_T0_T1(); break; + case PPC_I(EQV): dg.gen_eqv_32_T0_T1(); break; + case PPC_I(NAND): dg.gen_nand_32_T0_T1(); break; + case PPC_I(NOR): dg.gen_nor_32_T0_T1(); break; + case PPC_I(ORC): dg.gen_orc_32_T0_T1(); break; + case PPC_I(XOR): dg.gen_xor_32_T0_T1(); break; + default: abort(); + } + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(OR): // OR + { + const int rS = rS_field::extract(opcode); + const int rB = rB_field::extract(opcode); + const int rA = rA_field::extract(opcode); + dg.gen_load_T0_GPR(rS); + if (rS != rB) { // Not MR case + dg.gen_load_T1_GPR(rB); + dg.gen_or_32_T0_T1(); + } + dg.gen_store_T0_GPR(rA); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(ORI): // OR Immediate + { + const int rA = rA_field::extract(opcode); + const int rS = rS_field::extract(opcode); + const uint32 val = operand_UIMM::get(this, opcode); + if (val == 0) { + if (rA != rS) { // Skip NOP, handle register move + dg.gen_load_T0_GPR(rS); + dg.gen_store_T0_GPR(rA); + } + } + else { + dg.gen_load_T0_GPR(rS); + dg.gen_or_32_T0_im(val); + dg.gen_store_T0_GPR(rA); + } + break; + } + case PPC_I(XORI): // XOR Immediate + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_xor_32_T0_im(operand_UIMM::get(this, opcode)); + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + break; + } + case PPC_I(ORIS): // OR Immediate Shifted + case PPC_I(XORIS): // XOR Immediate Shifted + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + uint32 val = operand_UIMM_shifted::get(this, opcode); + switch (ii->mnemo) { + case PPC_I(ORIS): dg.gen_or_32_T0_im(val); break; + case PPC_I(XORIS): dg.gen_xor_32_T0_im(val); break; + default: abort(); + } + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + break; + } + case PPC_I(ANDI): // AND Immediate + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_and_32_T0_im(operand_UIMM::get(this, opcode)); + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(ANDIS): // AND Immediate Shifted + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_and_32_T0_im(operand_UIMM_shifted::get(this, opcode)); + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(EXTSB): // Extend Sign Byte + case PPC_I(EXTSH): // Extend Sign Half Word + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + switch (ii->mnemo) { + case PPC_I(EXTSB): dg.gen_se_8_32_T0(); break; + case PPC_I(EXTSH): dg.gen_se_16_32_T0(); break; + default: abort(); + } + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(NEG): // Negate + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + if (OE_field::test(opcode)) + dg.gen_record_nego_T0(); + dg.gen_neg_32_T0(); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + break; + } + case PPC_I(MFCR): // Move from Condition Register + { + dg.gen_commit_cr(); + dg.gen_load_T0_CR(); + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + break; + } + case PPC_I(MFSPR): // Move from Special-Purpose Register + { + const int spr = operand_SPR::get(this, opcode); + switch (spr) { + case powerpc_registers::SPR_XER: + dg.gen_load_T0_XER(); + break; + case powerpc_registers::SPR_LR: + dg.gen_load_T0_LR(); + break; + case powerpc_registers::SPR_CTR: + dg.gen_load_T0_CTR(); + break; +#ifdef SHEEPSHAVER + case powerpc_registers::SPR_SDR1: + dg.gen_mov_32_T0_im(0xdead001f); + break; + case powerpc_registers::SPR_PVR: { + extern uint32 PVR; + dg.gen_mov_32_T0_im(PVR); + break; + } + default: + dg.gen_mov_32_T0_im(0); + break; +#else + default: goto do_illegal; +#endif + } + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + break; + } + case PPC_I(MTSPR): // Move to Special-Purpose Register + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + const int spr = operand_SPR::get(this, opcode); + switch (spr) { + case powerpc_registers::SPR_XER: + dg.gen_store_T0_XER(); + break; + case powerpc_registers::SPR_LR: + dg.gen_store_T0_LR(); + break; + case powerpc_registers::SPR_CTR: + dg.gen_store_T0_CTR(); + break; +#ifndef SHEEPSHAVER + default: goto do_illegal; +#endif + } + break; + } + case PPC_I(ADD): // Add + case PPC_I(ADDC): // Add Carrying + case PPC_I(ADDE): // Add Extended + case PPC_I(SUBF): // Subtract From + case PPC_I(SUBFC): // Subtract from Carrying + case PPC_I(SUBFE): // Subtract from Extended + case PPC_I(MULLW): // Multiply Low Word + case PPC_I(DIVW): // Divide Word + case PPC_I(DIVWU): // Divide Word Unsigned + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + if (OE_field::test(opcode)) { + switch (ii->mnemo) { + case PPC_I(ADD): dg.gen_addo_T0_T1(); break; + case PPC_I(ADDC): dg.gen_addco_T0_T1(); break; + case PPC_I(ADDE): dg.gen_addeo_T0_T1(); break; + case PPC_I(SUBF): dg.gen_subfo_T0_T1(); break; + case PPC_I(SUBFC): dg.gen_subfco_T0_T1(); break; + case PPC_I(SUBFE): dg.gen_subfeo_T0_T1(); break; + case PPC_I(MULLW): dg.gen_mullwo_T0_T1(); break; + case PPC_I(DIVW): dg.gen_divwo_T0_T1(); break; + case PPC_I(DIVWU): dg.gen_divwuo_T0_T1(); break; + default: abort(); + } + } + else { + switch (ii->mnemo) { + case PPC_I(ADD): dg.gen_add_32_T0_T1(); break; + case PPC_I(ADDC): dg.gen_addc_T0_T1(); break; + case PPC_I(ADDE): dg.gen_adde_T0_T1(); break; + case PPC_I(SUBF): dg.gen_subf_T0_T1(); break; + case PPC_I(SUBFC): dg.gen_subfc_T0_T1(); break; + case PPC_I(SUBFE): dg.gen_subfe_T0_T1(); break; + case PPC_I(MULLW): dg.gen_umul_32_T0_T1(); break; + case PPC_I(DIVW): dg.gen_divw_T0_T1(); break; + case PPC_I(DIVWU): dg.gen_divwu_T0_T1(); break; + default: abort(); + } + } + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + break; + } + case PPC_I(ADDIC): // Add Immediate Carrying + case PPC_I(ADDIC_): // Add Immediate Carrying and Record + case PPC_I(SUBFIC): // Subtract from Immediate Carrying + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + const uint32 val = operand_SIMM::get(this, opcode); + switch (ii->mnemo) { + case PPC_I(ADDIC): + dg.gen_addc_T0_im(val); + break; + case PPC_I(ADDIC_): + dg.gen_addc_T0_im(val); + dg.gen_record_cr0_T0(); + break; + case PPC_I(SUBFIC): + dg.gen_subfc_T0_im(val); + break; + defautl: + abort(); + } + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + break; + } + case PPC_I(ADDME): // Add to Minus One Extended + case PPC_I(ADDZE): // Add to Zero Extended + case PPC_I(SUBFME): // Subtract from Minus One Extended + case PPC_I(SUBFZE): // Subtract from Zero Extended + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + if (OE_field::test(opcode)) { + switch (ii->mnemo) { + case PPC_I(ADDME): dg.gen_addmeo_T0(); break; + case PPC_I(ADDZE): dg.gen_addzeo_T0(); break; + case PPC_I(SUBFME): dg.gen_subfmeo_T0(); break; + case PPC_I(SUBFZE): dg.gen_subfzeo_T0(); break; + default: abort(); + } + } + else { + switch (ii->mnemo) { + case PPC_I(ADDME): dg.gen_addme_T0(); break; + case PPC_I(ADDZE): dg.gen_addze_T0(); break; + case PPC_I(SUBFME): dg.gen_subfme_T0(); break; + case PPC_I(SUBFZE): dg.gen_subfze_T0(); break; + default: abort(); + } + } + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + break; + } + case PPC_I(ADDI): // Add Immediate + { + const int rA = rA_field::extract(opcode); + const int rD = rD_field::extract(opcode); + if (rA == 0) // li rD,value + dg.gen_mov_32_T0_im(operand_SIMM::get(this, opcode)); + else { + dg.gen_load_T0_GPR(rA); + dg.gen_add_32_T0_im(operand_SIMM::get(this, opcode)); + } + dg.gen_store_T0_GPR(rD); + break; + } + case PPC_I(ADDIS): // Add Immediate Shifted + { + const int rA = rA_field::extract(opcode); + const int rD = rD_field::extract(opcode); + if (rA == 0) // lis rD,value + dg.gen_mov_32_T0_im(operand_SIMM_shifted::get(this, opcode)); + else { + dg.gen_load_T0_GPR(rA); + dg.gen_add_32_T0_im(operand_SIMM_shifted::get(this, opcode)); + } + dg.gen_store_T0_GPR(rD); + break; + } + case PPC_I(RLWIMI): // Rotate Left Word Immediate then Mask Insert + { + const int rA = rA_field::extract(opcode); + const int rS = rS_field::extract(opcode); + const int SH = SH_field::extract(opcode); + const int MB = MB_field::extract(opcode); + const int ME = ME_field::extract(opcode); + dg.gen_load_T0_GPR(rA); + dg.gen_load_T1_GPR(rS); + const uint32 m = mask_operand::compute(MB, ME); + dg.gen_rlwimi_T0_T1(SH, m); + dg.gen_store_T0_GPR(rA); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(RLWINM): // Rotate Left Word Immediate then AND with Mask + { + const int rS = rS_field::extract(opcode); + const int rA = rA_field::extract(opcode); + const int SH = SH_field::extract(opcode); + const int MB = MB_field::extract(opcode); + const int ME = ME_field::extract(opcode); + dg.gen_load_T0_GPR(rS); + if (MB == 0 && ME == 31) { + // rotlwi rA,rS,SH + if (SH > 0) + dg.gen_rol_32_T0_im(SH); + } + else if (MB == 0 && (ME == (31 - SH))) { + // slwi rA,rS,SH + dg.gen_lsl_32_T0_im(SH); + } + else { + const uint32 m = mask_operand::compute(MB, ME); + if (SH == 0) { + // andi rA,rS,MASK(MB,ME) + dg.gen_and_32_T0_im(m); + } + else { + // rlwinm rA,rS,SH,MB,ME + dg.gen_rlwinm_T0_T1(SH, m); + } + } + dg.gen_store_T0_GPR(rA); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(RLWNM): // Rotate Left Word then AND with Mask + { + const int rS = rS_field::extract(opcode); + const int rB = rB_field::extract(opcode); + const int rA = rA_field::extract(opcode); + const uint32 m = operand_MASK::get(this, opcode); + dg.gen_load_T0_GPR(rS); + dg.gen_load_T1_GPR(rB); + dg.gen_rlwnm_T0_T1(m); + dg.gen_store_T0_GPR(rA); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(CNTLZW): // Count Leading Zeros Word + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_cntlzw_32_T0(); + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(SLW): // Shift Left Word + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + dg.gen_slw_T0_T1(); + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(SRW): // Shift Right Word + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + dg.gen_srw_T0_T1(); + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(SRAW): // Shift Right Algebraic Word + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + dg.gen_sraw_T0_T1(); + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(SRAWI): // Shift Right Algebraic Word Immediate + { + dg.gen_load_T0_GPR(rS_field::extract(opcode)); + dg.gen_sraw_T0_im(SH_field::extract(opcode)); + dg.gen_store_T0_GPR(rA_field::extract(opcode)); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(MULHW): // Multiply High Word + case PPC_I(MULHWU): // Multiply High Word Unsigned + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + dg.gen_load_T1_GPR(rB_field::extract(opcode)); + if (ii->mnemo == PPC_I(MULHW)) + dg.gen_mulhw_T0_T1(); + else + dg.gen_mulhwu_T0_T1(); + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + if (Rc_field::test(opcode)) + dg.gen_record_cr0_T0(); + break; + } + case PPC_I(MULLI): // Multiply Low Immediate + { + dg.gen_load_T0_GPR(rA_field::extract(opcode)); + dg.gen_mulli_T0_im(operand_SIMM::get(this, opcode)); + dg.gen_store_T0_GPR(rD_field::extract(opcode)); + break; + } + default: // Direct call to instruction handler + { + typedef void (*func_t)(dyngen_cpu_base, uint32); + func_t func; + do_generic: +// printf("UNHANDLED: %s\n", ii->name); + func = (func_t)ii->execute.ptr(); + goto do_invoke; + do_illegal: + func = (func_t)nv_mem_fun(&powerpc_cpu::execute_illegal).ptr(); + goto do_invoke; + do_invoke: + cg_context.pc = dpc; + cg_context.opcode = opcode; + cg_context.instr_info = ii; + if (!compile1(cg_context)) { + pc_offset -= 4; + if (pc_offset) { + dg.gen_inc_PC(pc_offset); + pc_offset = 0; + } + dg.gen_commit_cr(); + dg.gen_invoke_CPU_im(func, opcode); + } + } + } + assert(!dg.full_translation_cache()); + } while ((ii->cflow & CFLOW_END_BLOCK) == 0); + dg.gen_commit_cr(); + dg.gen_exec_return(); + if (!dg.gen_end()) { + // Invalidate cache and start again + D(bug("Translation cache full. Invalidate and retranslate\n")); + invalidate_cache(); + goto again; + } + bi->end_pc = dpc; + bi->size = dg.code_ptr() - bi->entry_point; +#if defined(__powerpc__) && 0 + double ratio = double(bi->size) / double(dpc - entry_point + 4); + if (ratio >= 10) + disasm = true; +#endif + if (disasm) + disasm_translation(entry_point, dpc - entry_point + 4, bi->entry_point, bi->size); + block_cache.add_to_cl_list(bi); + block_cache.add_to_active_list(bi); +#if PPC_PROFILE_COMPILE_TIME + compile_time += (clock() - start_time); +#endif + return bi; +} +#endif diff --git a/SheepShaver/src/kpx_cpu/src/test/test-powerpc.cpp b/SheepShaver/src/kpx_cpu/src/test/test-powerpc.cpp index 70542c7b..1b81c9f4 100644 --- a/SheepShaver/src/kpx_cpu/src/test/test-powerpc.cpp +++ b/SheepShaver/src/kpx_cpu/src/test/test-powerpc.cpp @@ -21,10 +21,13 @@ #include #include "sysdeps.h" #include "cpu/ppc/ppc-cpu.hpp" +#include "cpu/ppc/ppc-instructions.hpp" // Disassemblers needed for debugging purposes +#if ENABLE_MON #include "mon.h" #include "mon_disass.h" +#endif #define TEST_ADD 1 #define TEST_SUB 1 @@ -86,6 +89,10 @@ static void inline flush_icache_range(uint32 *start_p, uint32 length) asm volatile ("sync" : : : "memory"); asm volatile ("isync" : : : "memory"); } +#else +static void inline flush_icache_range(uint32 *start_p, uint32 length) +{ +} #endif struct exec_return { }; @@ -105,6 +112,7 @@ class powerpc_test_cpu void emul_set_cr(uint32 value) { cr().set(value); } +#if defined(__powerpc__) uint32 native_get_xer() const { uint32 xer; asm volatile ("mfxer %0" : "=r" (xer)); return xer; } @@ -116,6 +124,10 @@ class powerpc_test_cpu void native_set_cr(uint32 cr) const { asm volatile ("mtcr %0" : : "r" (cr)); } +#endif + + void flush_icache_range(uint32 *start, uint32 size) + { invalidate_cache(); ::flush_icache_range(start, size); } void init_decoder(); void print_flags(uint32 cr, uint32 xer, int crf = 0) const; @@ -124,12 +136,8 @@ class powerpc_test_cpu public: - powerpc_test_cpu() - : powerpc_cpu(NULL) - { mon_init(); init_decoder(); } - - ~powerpc_test_cpu() - { mon_exit(); } + powerpc_test_cpu(); + ~powerpc_test_cpu(); bool test(void); @@ -154,11 +162,13 @@ private: static const uint32 msk_values[]; void test_one(uint32 *code, const char *insn, uint32 a1, uint32 a2, uint32 a3, uint32 a0 = 0); + void test_instruction_CNTLZ(const char *insn, uint32 opcode); void test_instruction_RR___(const char *insn, uint32 opcode); void test_instruction_RRI__(const char *insn, uint32 opcode); #define test_instruction_RRK__ test_instruction_RRI__ void test_instruction_RRS__(const char *insn, uint32 opcode); void test_instruction_RRR__(const char *insn, uint32 opcode); + void test_instruction_RRRSH(const char *insn, uint32 opcode); void test_instruction_RRIII(const char *insn, uint32 opcode); void test_instruction_RRRII(const char *insn, uint32 opcode); void test_instruction_CRR__(const char *insn, uint32 opcode); @@ -178,9 +188,25 @@ private: void test_load_multiple(void); }; +powerpc_test_cpu::powerpc_test_cpu() + : powerpc_cpu(NULL) +{ +#if ENABLE_MON + mon_init(); +#endif + init_decoder(); +} + +powerpc_test_cpu::~powerpc_test_cpu() +{ +#if ENABLE_MON + mon_exit(); +#endif +} + void powerpc_test_cpu::execute_return(uint32 opcode) { - throw exec_return(); + spcflags().set(SPCFLAG_CPU_EXEC_RETURN); } void powerpc_test_cpu::init_decoder() @@ -196,7 +222,8 @@ void powerpc_test_cpu::init_decoder() { "return", (execute_pmf)&powerpc_test_cpu::execute_return, NULL, - D_form, 6, 0, CFLOW_TRAP + PPC_I(MAX), + D_form, 6, 0, CFLOW_JUMP } }; @@ -211,16 +238,11 @@ void powerpc_test_cpu::init_decoder() void powerpc_test_cpu::execute(uint32 *code_p) { static uint32 code[] = { POWERPC_BLR | 1, POWERPC_EMUL_OP }; - lr() = (uint32)code_p; + assert((uintptr)code <= INT_MAX); + lr() = (uintptr)code_p; - try { - invalidate_cache(); - pc() = (uintptr)code; - powerpc_cpu::execute(); - } - catch (exec_return const &) { - // Nothing, simply return - } + pc() = (uintptr)code; + powerpc_cpu::execute(); } void powerpc_test_cpu::print_flags(uint32 cr, uint32 xer, int crf) const @@ -242,6 +264,7 @@ void powerpc_test_cpu::print_flags(uint32 cr, uint32 xer, int crf) const void powerpc_test_cpu::test_one(uint32 *code, const char *insn, uint32 a1, uint32 a2, uint32 a3, uint32 a0) { +#if defined(__powerpc__) // Invoke native code const uint32 save_xer = native_get_xer(); const uint32 save_cr = native_get_cr(); @@ -254,6 +277,12 @@ void powerpc_test_cpu::test_one(uint32 *code, const char *insn, uint32 a1, uint3 const uint32 native_cr = native_get_cr(); native_set_xer(save_xer); native_set_cr(save_cr); +#else + // FIXME: Restore context from results file + const uint32 native_rd = 0; + const uint32 native_xer = 0; + const uint32 native_cr = 0; +#endif // Invoke emulated code emul_set_xer(init_xer); @@ -284,7 +313,9 @@ void powerpc_test_cpu::test_one(uint32 *code, const char *insn, uint32 a1, uint3 } if (!ok || verbose) { +#if ENABLE_MON disass_ppc(stdout, (uintptr)code, code[0]); +#endif #define PRINT_OPERANDS(PREFIX) do { \ printf(" %08x, %08x, %08x, %08x => %08x [", \ a0, a1, a2, a3, PREFIX##_rd); \ @@ -333,6 +364,34 @@ const uint32 powerpc_test_cpu::msk_values[] = { 30, 31 }; +void powerpc_test_cpu::test_instruction_CNTLZ(const char *insn, uint32 opcode) +{ + // Test code + static uint32 code[] = { + POWERPC_ILLEGAL, POWERPC_BLR, + POWERPC_MR(0, RA), POWERPC_ILLEGAL, POWERPC_BLR + }; + + // Input values + const int n_values = sizeof(reg_values)/sizeof(reg_values[0]); + + code[0] = code[3] = opcode; // RD,RA,RB + rA_field::insert(code[3], 0); // RD,R0,RB + flush_icache_range(code, sizeof(code)); + + for (uint32 mask = 0x800000000; mask != 0; mask >>= 1) { + uint32 ra = mask; + test_one(&code[0], insn, ra, 0, 0); + test_one(&code[2], insn, ra, 0, 0); + } + // random values (including zero) + for (int i = 0; i < n_values; i++) { + uint32 ra = reg_values[i]; + test_one(&code[0], insn, ra, 0, 0); + test_one(&code[2], insn, ra, 0, 0); + } +} + void powerpc_test_cpu::test_instruction_RR___(const char *insn, uint32 opcode) { // Test code @@ -431,6 +490,31 @@ void powerpc_test_cpu::test_instruction_RRR__(const char *insn, uint32 opcode) } } +void powerpc_test_cpu::test_instruction_RRRSH(const char *insn, uint32 opcode) +{ + // Test code + static uint32 code[] = { + POWERPC_ILLEGAL, POWERPC_BLR, + POWERPC_MR(0, RA), POWERPC_ILLEGAL, POWERPC_BLR + }; + + // Input values + const int n_values = sizeof(reg_values)/sizeof(reg_values[0]); + + code[0] = code[3] = opcode; // RD,RA,RB + rA_field::insert(code[3], 0); // RD,R0,RB + flush_icache_range(code, sizeof(code)); + + for (int i = 0; i < n_values; i++) { + const uint32 ra = reg_values[i]; + for (int j = 0; j <= 64; j++) { + const uint32 rb = j; + test_one(&code[0], insn, ra, rb, 0); + test_one(&code[2], insn, ra, rb, 0); + } + } +} + void powerpc_test_cpu::test_instruction_RRIII(const char *insn, uint32 opcode) { // Test code @@ -590,55 +674,81 @@ void powerpc_test_cpu::test_instruction_CCC__(const char *insn, uint32 opcode) void powerpc_test_cpu::test_add(void) { #if TEST_ADD - TEST_INSTRUCTION(RRR__,"add", _XO(31,RD,RA,RB,0,266,0)); - TEST_INSTRUCTION(RRR__,"add.", _XO(31,RD,RA,RB,0,266,1)); - TEST_INSTRUCTION(RRR__,"addo", _XO(31,RD,RA,RB,1,266,0)); - TEST_INSTRUCTION(RRR__,"addo." , _XO(31,RD,RA,RB,1,266,1)); - TEST_INSTRUCTION(RRR__,"addc.", _XO(31,RD,RA,RB,0, 10,1)); - TEST_INSTRUCTION(RRR__,"addco.", _XO(31,RD,RA,RB,1, 10,1)); - TEST_INSTRUCTION(RRR__,"adde.", _XO(31,RD,RA,RB,0,138,1)); - TEST_INSTRUCTION(RRR__,"addeo.", _XO(31,RD,RA,RB,1,138,1)); - TEST_INSTRUCTION(RRI__,"addi", _D (14,RD,RA,00)); - TEST_INSTRUCTION(RRI__,"addic", _D (12,RD,RA,00)); - TEST_INSTRUCTION(RRI__,"addic.", _D (13,RD,RA,00)); - TEST_INSTRUCTION(RRI__,"addis", _D (15,RD,RA,00)); - TEST_INSTRUCTION(RR___,"addme.", _XO(31,RD,RA,00,0,234,1)); - TEST_INSTRUCTION(RR___,"addmeo.", _XO(31,RD,RA,00,1,234,1)); - TEST_INSTRUCTION(RR___,"addze.", _XO(31,RD,RA,00,0,202,1)); - TEST_INSTRUCTION(RR___,"addzeo.", _XO(31,RD,RA,00,1,202,1)); - init_xer |= XER_CA_field::mask(); - TEST_INSTRUCTION(RRR__,"adde.", _XO(31,RD,RA,RB,0,138,1)); - TEST_INSTRUCTION(RRR__,"addeo.", _XO(31,RD,RA,RB,1,138,1)); - TEST_INSTRUCTION(RR___,"addme.", _XO(31,RD,RA,00,0,234,1)); - TEST_INSTRUCTION(RR___,"addmeo.", _XO(31,RD,RA,00,1,234,1)); - TEST_INSTRUCTION(RR___,"addze.", _XO(31,RD,RA,00,0,202,1)); - TEST_INSTRUCTION(RR___,"addzeo.", _XO(31,RD,RA,00,1,202,1)); - init_xer &= ~XER_CA_field::mask(); + const int n_xer_values = 3; + uint32 xer_values[n_xer_values]; + xer_values[0] = init_xer; + xer_values[1] = init_xer | XER_OV_field::mask(); + xer_values[2] = init_xer | XER_CA_field::mask(); + + // Iterate over some specific XER values so that we make sure we + // only update them when actually needed + for (int i = 0; i < n_xer_values; i++) { + const uint32 saved_xer = init_xer; + init_xer = xer_values[i]; + TEST_INSTRUCTION(RRR__,"add", _XO(31,RD,RA,RB,0,266,0)); + TEST_INSTRUCTION(RRR__,"add.", _XO(31,RD,RA,RB,0,266,1)); + TEST_INSTRUCTION(RRR__,"addo", _XO(31,RD,RA,RB,1,266,0)); + TEST_INSTRUCTION(RRR__,"addo." , _XO(31,RD,RA,RB,1,266,1)); + TEST_INSTRUCTION(RRR__,"addc.", _XO(31,RD,RA,RB,0, 10,1)); + TEST_INSTRUCTION(RRR__,"addco.", _XO(31,RD,RA,RB,1, 10,1)); + TEST_INSTRUCTION(RRR__,"adde", _XO(31,RD,RA,RB,0,138,0)); + TEST_INSTRUCTION(RRR__,"adde.", _XO(31,RD,RA,RB,0,138,1)); + TEST_INSTRUCTION(RRR__,"addeo", _XO(31,RD,RA,RB,1,138,0)); + TEST_INSTRUCTION(RRR__,"addeo.", _XO(31,RD,RA,RB,1,138,1)); + TEST_INSTRUCTION(RRI__,"addi", _D (14,RD,RA,00)); + TEST_INSTRUCTION(RRI__,"addic", _D (12,RD,RA,00)); + TEST_INSTRUCTION(RRI__,"addic.", _D (13,RD,RA,00)); + TEST_INSTRUCTION(RRI__,"addis", _D (15,RD,RA,00)); + TEST_INSTRUCTION(RR___,"addme", _XO(31,RD,RA,00,0,234,0)); + TEST_INSTRUCTION(RR___,"addme.", _XO(31,RD,RA,00,0,234,1)); + TEST_INSTRUCTION(RR___,"addmeo", _XO(31,RD,RA,00,1,234,0)); + TEST_INSTRUCTION(RR___,"addmeo.", _XO(31,RD,RA,00,1,234,1)); + TEST_INSTRUCTION(RR___,"addze", _XO(31,RD,RA,00,0,202,0)); + TEST_INSTRUCTION(RR___,"addze.", _XO(31,RD,RA,00,0,202,1)); + TEST_INSTRUCTION(RR___,"addzeo", _XO(31,RD,RA,00,1,202,0)); + TEST_INSTRUCTION(RR___,"addzeo.", _XO(31,RD,RA,00,1,202,1)); + init_xer = saved_xer; + } #endif } void powerpc_test_cpu::test_sub(void) { #if TEST_SUB - TEST_INSTRUCTION(RRR__,"subf.", _XO(31,RD,RA,RB,0, 40,1)); - TEST_INSTRUCTION(RRR__,"subfo.", _XO(31,RD,RA,RB,1, 40,1)); - TEST_INSTRUCTION(RRR__,"subfc.", _XO(31,RD,RA,RB,0, 8,1)); - TEST_INSTRUCTION(RRR__,"subfco.", _XO(31,RD,RA,RB,1, 8,1)); - TEST_INSTRUCTION(RRR__,"subfe.", _XO(31,RD,RA,RB,0,136,1)); - TEST_INSTRUCTION(RRR__,"subfeo.", _XO(31,RD,RA,RB,1,136,1)); - TEST_INSTRUCTION(RRI__,"subfic", _D ( 8,RD,RA,00)); - TEST_INSTRUCTION(RR___,"subfme.", _XO(31,RD,RA,00,0,232,1)); - TEST_INSTRUCTION(RR___,"subfmeo.", _XO(31,RD,RA,00,1,232,1)); - TEST_INSTRUCTION(RR___,"subfze.", _XO(31,RD,RA,00,0,200,1)); - TEST_INSTRUCTION(RR___,"subfzeo.", _XO(31,RD,RA,00,1,200,1)); - init_xer |= XER_CA_field::mask(); - TEST_INSTRUCTION(RRR__,"subfe.", _XO(31,RD,RA,RB,0,136,1)); - TEST_INSTRUCTION(RRR__,"subfeo.", _XO(31,RD,RA,RB,1,136,1)); - TEST_INSTRUCTION(RR___,"subfme.", _XO(31,RD,RA,00,0,232,1)); - TEST_INSTRUCTION(RR___,"subfmeo.", _XO(31,RD,RA,00,1,232,1)); - TEST_INSTRUCTION(RR___,"subfze.", _XO(31,RD,RA,00,0,200,1)); - TEST_INSTRUCTION(RR___,"subfzeo.", _XO(31,RD,RA,00,1,200,1)); - init_xer &= ~XER_CA_field::mask(); + const int n_xer_values = 3; + uint32 xer_values[n_xer_values]; + xer_values[0] = init_xer; + xer_values[1] = init_xer | XER_OV_field::mask(); + xer_values[2] = init_xer | XER_CA_field::mask(); + + // Iterate over some specific XER values so that we make sure we + // only update them when actually needed + for (int i = 0; i < n_xer_values; i++) { + const uint32 saved_xer = init_xer; + init_xer = xer_values[i]; + TEST_INSTRUCTION(RRR__,"subf", _XO(31,RD,RA,RB,0, 40,0)); + TEST_INSTRUCTION(RRR__,"subf.", _XO(31,RD,RA,RB,0, 40,1)); + TEST_INSTRUCTION(RRR__,"subfo", _XO(31,RD,RA,RB,1, 40,0)); + TEST_INSTRUCTION(RRR__,"subfo.", _XO(31,RD,RA,RB,1, 40,1)); + TEST_INSTRUCTION(RRR__,"subfc", _XO(31,RD,RA,RB,0, 8,0)); + TEST_INSTRUCTION(RRR__,"subfc.", _XO(31,RD,RA,RB,0, 8,1)); + TEST_INSTRUCTION(RRR__,"subfco", _XO(31,RD,RA,RB,1, 8,0)); + TEST_INSTRUCTION(RRR__,"subfco.", _XO(31,RD,RA,RB,1, 8,1)); + TEST_INSTRUCTION(RRR__,"subfe", _XO(31,RD,RA,RB,0,136,0)); + TEST_INSTRUCTION(RRR__,"subfe.", _XO(31,RD,RA,RB,0,136,1)); + TEST_INSTRUCTION(RRR__,"subfeo", _XO(31,RD,RA,RB,1,136,0)); + TEST_INSTRUCTION(RRR__,"subfeo.", _XO(31,RD,RA,RB,1,136,1)); + TEST_INSTRUCTION(RRI__,"subfic", _D ( 8,RD,RA,00)); + TEST_INSTRUCTION(RR___,"subfme", _XO(31,RD,RA,00,0,232,0)); + TEST_INSTRUCTION(RR___,"subfme.", _XO(31,RD,RA,00,0,232,1)); + TEST_INSTRUCTION(RR___,"subfmeo", _XO(31,RD,RA,00,1,232,0)); + TEST_INSTRUCTION(RR___,"subfmeo.", _XO(31,RD,RA,00,1,232,1)); + TEST_INSTRUCTION(RR___,"subfze", _XO(31,RD,RA,00,0,200,0)); + TEST_INSTRUCTION(RR___,"subfze.", _XO(31,RD,RA,00,0,200,1)); + TEST_INSTRUCTION(RR___,"subfzeo", _XO(31,RD,RA,00,1,200,0)); + TEST_INSTRUCTION(RR___,"subfzeo.", _XO(31,RD,RA,00,1,200,1)); + init_xer = saved_xer; + } #endif } @@ -674,22 +784,35 @@ void powerpc_test_cpu::test_div(void) void powerpc_test_cpu::test_logical(void) { #if TEST_LOGICAL + TEST_INSTRUCTION(RRR__,"and", _X (31,RA,RD,RB,28,0)); TEST_INSTRUCTION(RRR__,"and.", _X (31,RA,RD,RB,28,1)); + TEST_INSTRUCTION(RRR__,"andc", _X (31,RA,RD,RB,60,0)); TEST_INSTRUCTION(RRR__,"andc.", _X (31,RA,RD,RB,60,1)); TEST_INSTRUCTION(RRK__,"andi.", _D (28,RA,RD,00)); TEST_INSTRUCTION(RRK__,"andis.", _D (29,RA,RD,00)); - TEST_INSTRUCTION(RR___,"cntlzw.", _X (31,RA,RD,00,26,1)); + TEST_INSTRUCTION(CNTLZ,"cntlzw", _X (31,RA,RD,00,26,0)); + TEST_INSTRUCTION(CNTLZ,"cntlzw.", _X (31,RA,RD,00,26,1)); + TEST_INSTRUCTION(RRR__,"eqv", _X (31,RA,RD,RB,284,0)); TEST_INSTRUCTION(RRR__,"eqv.", _X (31,RA,RD,RB,284,1)); + TEST_INSTRUCTION(RR___,"extsb", _X (31,RA,RD,00,954,0)); TEST_INSTRUCTION(RR___,"extsb.", _X (31,RA,RD,00,954,1)); + TEST_INSTRUCTION(RR___,"extsh", _X (31,RA,RD,00,922,0)); TEST_INSTRUCTION(RR___,"extsh.", _X (31,RA,RD,00,922,1)); + TEST_INSTRUCTION(RRR__,"nand", _X (31,RA,RD,RB,476,0)); TEST_INSTRUCTION(RRR__,"nand.", _X (31,RA,RD,RB,476,1)); + TEST_INSTRUCTION(RR___,"neg", _XO(31,RD,RA,RB,0,104,0)); TEST_INSTRUCTION(RR___,"neg.", _XO(31,RD,RA,RB,0,104,1)); + TEST_INSTRUCTION(RR___,"nego", _XO(31,RD,RA,RB,1,104,0)); TEST_INSTRUCTION(RR___,"nego.", _XO(31,RD,RA,RB,1,104,1)); + TEST_INSTRUCTION(RRR__,"nor", _X (31,RA,RD,RB,124,0)); TEST_INSTRUCTION(RRR__,"nor.", _X (31,RA,RD,RB,124,1)); + TEST_INSTRUCTION(RRR__,"or", _X (31,RA,RD,RB,444,0)); TEST_INSTRUCTION(RRR__,"or.", _X (31,RA,RD,RB,444,1)); + TEST_INSTRUCTION(RRR__,"orc", _X (31,RA,RD,RB,412,0)); TEST_INSTRUCTION(RRR__,"orc.", _X (31,RA,RD,RB,412,1)); TEST_INSTRUCTION(RRK__,"ori", _D (24,RA,RD,00)); TEST_INSTRUCTION(RRK__,"oris", _D (25,RA,RD,00)); + TEST_INSTRUCTION(RRR__,"xor", _X (31,RA,RD,RB,316,0)); TEST_INSTRUCTION(RRR__,"xor.", _X (31,RA,RD,RB,316,1)); TEST_INSTRUCTION(RRK__,"xori", _D (26,RA,RD,00)); TEST_INSTRUCTION(RRK__,"xoris", _D (27,RA,RD,00)); @@ -699,22 +822,25 @@ void powerpc_test_cpu::test_logical(void) void powerpc_test_cpu::test_shift(void) { #if TEST_SHIFT - TEST_INSTRUCTION(RRR__,"slw", _X (31,RA,RD,RB, 24,0)); - TEST_INSTRUCTION(RRR__,"slw.", _X (31,RA,RD,RB, 24,1)); - TEST_INSTRUCTION(RRR__,"sraw", _X (31,RA,RD,RB,792,0)); - TEST_INSTRUCTION(RRR__,"sraw.", _X (31,RA,RD,RB,792,1)); + TEST_INSTRUCTION(RRRSH,"slw", _X (31,RA,RD,RB, 24,0)); + TEST_INSTRUCTION(RRRSH,"slw.", _X (31,RA,RD,RB, 24,1)); + TEST_INSTRUCTION(RRRSH,"sraw", _X (31,RA,RD,RB,792,0)); + TEST_INSTRUCTION(RRRSH,"sraw.", _X (31,RA,RD,RB,792,1)); TEST_INSTRUCTION(RRS__,"srawi", _X (31,RA,RD,00,824,0)); TEST_INSTRUCTION(RRS__,"srawi.", _X (31,RA,RD,00,824,1)); - TEST_INSTRUCTION(RRR__,"srw", _X (31,RA,RD,RB,536,0)); - TEST_INSTRUCTION(RRR__,"srw.", _X (31,RA,RD,RB,536,1)); + TEST_INSTRUCTION(RRRSH,"srw", _X (31,RA,RD,RB,536,0)); + TEST_INSTRUCTION(RRRSH,"srw.", _X (31,RA,RD,RB,536,1)); #endif } void powerpc_test_cpu::test_rotate(void) { #if TEST_ROTATE + TEST_INSTRUCTION(RRIII,"rlwimi", _M (20,RA,RD,00,00,00,0)); TEST_INSTRUCTION(RRIII,"rlwimi.", _M (20,RA,RD,00,00,00,1)); + TEST_INSTRUCTION(RRIII,"rlwinm", _M (21,RA,RD,00,00,00,0)); TEST_INSTRUCTION(RRIII,"rlwinm.", _M (21,RA,RD,00,00,00,1)); + TEST_INSTRUCTION(RRRII,"rlwnm", _M (23,RA,RD,RB,00,00,0)); TEST_INSTRUCTION(RRRII,"rlwnm.", _M (23,RA,RD,RB,00,00,1)); #endif } @@ -759,8 +885,12 @@ bool powerpc_test_cpu::test(void) { // Tests initialization tests = errors = 0; +#if defined(__powerpc__) init_cr = native_get_cr() & ~CR_field<0>::mask(); init_xer = native_get_xer() & ~(XER_OV_field::mask() | XER_CA_field::mask()); +#else + init_cr = init_xer = 0; +#endif // Tests execution test_add();