📄 jm-insns.c
字号:
/* HOW TO COMPILE:* 32bit build: gcc -Winline -Wall -g -O -mregnames -DHAS_ALTIVEC -maltivec* 64bit build: gcc -Winline -Wall -g -O -mregnames -DHAS_ALTIVEC -maltivec -m64This program is useful, but the register usage conventions init are a complete dog. In particular, _patch_op_imm has tobe inlined, else you wind up with it segfaulting incompletely different places due to corruption (of r20 in thecase I chased).*//* * test-ppc.c: * PPC tests for qemu-PPC CPU emulation checks * * Copyright (c) 2005 Jocelyn Mayer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License V2 * as published by the Free Software Foundation * * 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 *//* * Theory of operations: * a few registers are reserved for the test program: * r14 => r18 * f14 => f18 * I do preload test values in r14 thru r17 (or less, depending on the number * of register operands needed), patch the test opcode if any immediate * operands are required, execute the tested opcode. * XER, CCR and FPSCR are cleared before every test. * I always get the result in r17 and also save XER and CCR for fixed-point * operations. I also check FPSCR for floating points operations. * * Improvments: * a more clever FPSCR management is needed: for now, I always test * the round-to-zero case. Other rounding modes also need to be tested. *//* * Operation details * ----------------- * The 'test' functions (via all_tests[]) are wrappers of single asm instns * * The 'loops' (e.g. int_loops) do the actual work: * - loops over as many arguments as the instn needs (regs | imms) * - sets up the environment (reset cr,xer, assign src regs...) * - maybe modifies the asm instn to test different imm args * - calls the test function * - retrieves relevant register data (rD,cr,xer,...) * - prints argument and result data. * * More specifically... * * all_tests[i] holds insn tests * - of which each holds: {instn_test_arr[], description, flags} * * flags hold 3 instn classifiers: {family, type, arg_type} * * // The main test loop: * do_tests( user_ctl_flags ) { * foreach(curr_test = all_test[i]) { * * // flags are used to control what tests are run: * if (curr_test->flags && !user_ctl_flags) * continue; * * // a 'loop_family_arr' is chosen based on the 'family' flag... * switch(curr_test->flags->family) { * case x: loop_family_arr = int_loops; * ... * } * * // ...and the actual test_loop to run is found by indexing into * // the loop_family_arr with the 'arg_type' flag: * test_loop = loop_family[curr_test->flags->arg_type] * * // finally, loop over all instn tests for this test: * foreach (instn_test = curr_test->instn_test_arr[i]) { * * // and call the test_loop with the current instn_test function,name * test_loop( instn_test->func, instn_test->name ) * } * } * } * * * Details of intruction patching for immediate operands * ----------------------------------------------------- * All the immediate insn test functions are of the form {imm_insn, blr} * In order to patch one of these functions, we simply copy both insns * to a stack buffer, and rewrite the immediate part of imm_insn. * We then execute our stack buffer. * All ppc instructions are 32bits wide, which makes this fairly easy. * * Example: * extern void test_addi (void); * asm(".section \".text\"\n" * " .align 2\n" * " .type test_addi,@function\n" * "test_addi:\n" * " addi\n" * " blr\n" * " .previous\n" * ); * * We are interested only in: * " addi 17, 14, 0\n" * " blr\n" * * In a loop test, we may see: * uint32_t func_buf[2]; // our new stack based 'function' * for imm... // loop over imm * init_function( &func, func_buf ); // copy insns, set func ptr * patch_op_imm16(&func_buf[0], imm); // patch 'addi' insn * ... * (*func)(); // exec our rewritten code * * patch_op_imm16() itself simply takes the uint32_t insn and overwrites * the immediate field with the new value (which, for 'addi', is the * low 16 bits). * * So in the loop test, if 'imm' is currently 9, and p[0] is: * 0x3A2E0000 => addi 17, 14, 0 * * after patch_op_imm16(), func_buf[0] becomes: * 0x3A2E0009 => addi 17, 14, 9 * * Note: init_function() needs to be called on every iteration * - don't ask me why!*//**********************************************************************//* Uncomment to enable many arguments for altivec insns */#define USAGE_SIMPLE/* Uncomment to enable many arguments for altivec insns *///#define ALTIVEC_ARGS_LARGE/* Uncomment to enable output of CR flags for float tests *///#define TEST_FLOAT_FLAGS/* Uncomment to enable debug output *///#define DEBUG_ARGS_BUILD//#define DEBUG_FILTER/* These should be set at build time *///#define NO_FLOAT//#define HAS_ALTIVEC // CFLAGS += -maltivec//#define IS_PPC405/**********************************************************************/#include <stdint.h>#include <sys/mman.h>/* Something of the same size as void*, so can be safely be coerced to/from a pointer type. Also same size as the host's gp registers. */#ifndef __powerpc64__typedef uint32_t HWord_t;#elsetypedef uint64_t HWord_t;#endif // #ifndef __powerpc64__register double f14 __asm__ ("f14");register double f15 __asm__ ("f15");register double f16 __asm__ ("f16");register double f17 __asm__ ("f17");register double f18 __asm__ ("f18");register HWord_t r14 __asm__ ("r14");register HWord_t r15 __asm__ ("r15");register HWord_t r16 __asm__ ("r16");register HWord_t r17 __asm__ ("r17");register HWord_t r18 __asm__ ("r18");#if defined (HAS_ALTIVEC)# include <altivec.h>#endif#include <assert.h>#include <ctype.h> // isspace//#include <fcntl.h>//#include <fenv.h>//#include <math.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h> // getopt#include <malloc.h>#ifndef __powerpc64__#define ASSEMBLY_FUNC(__fname, __insn) \asm(".section \".text\"\n" \ "\t.align 2\n" \ "\t.type "__fname",@function\n" \ __fname":\n" \ "\t"__insn"\n" \ "\tblr\n" \ "\t.previous\n" \ )#else#define ASSEMBLY_FUNC(__fname, __insn) \asm(".section \".text\"\n" \ "\t.align 2\n" \ "\t.global "__fname"\n" \ "\t.section \".opd\",\"aw\"\n" \ "\t.align 3\n" \ ""__fname":\n" \ "\t.quad ."__fname",.TOC.@tocbase,0\n" \ "\t.previous\n" \ "\t.type ."__fname",@function\n" \ "\t.global ."__fname"\n" \ "."__fname":\n" \ "\t"__insn"\n" \ "\tblr\n" \ )#endif // #ifndef __powerpc64__/* Return a pointer to a 1-page area where is is safe to both write and execute instructions. Area is filled with 'trap' insns. */staticuint32_t* get_rwx_area ( void ){ int i; static uint32_t* p = NULL; if (p == NULL) { p = mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); assert(p != MAP_FAILED); } for (i = 0; i < 4096/sizeof(uint32_t); i++) p[i] = 0x7fe00008; /* trap */ return p;}/* -------------- BEGIN #include "test-ppc.h" -------------- *//* * test-ppc.h: * PPC tests for qemu-PPC CPU emulation checks - definitions * * Copyright (c) 2005 Jocelyn Mayer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License V2 * as published by the Free Software Foundation * * 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 */#if !defined (__TEST_PPC_H__)#define __TEST_PPC_H__#include <stdint.h>typedef void (*test_func_t) (void);typedef struct test_t test_t;typedef struct test_table_t test_table_t;struct test_t { test_func_t func; const char *name;};struct test_table_t { test_t *tests; const char *name; uint32_t flags;};typedef void (*test_loop_t) (const char *name, test_func_t func, uint32_t flags);enum test_flags { /* Nb arguments */ PPC_ONE_ARG = 0x00000001, PPC_TWO_ARGS = 0x00000002, PPC_THREE_ARGS = 0x00000003, PPC_CMP_ARGS = 0x00000004, // family: compare PPC_CMPI_ARGS = 0x00000005, // family: compare PPC_TWO_I16 = 0x00000006, // family: arith/logical PPC_SPECIAL = 0x00000007, // family: logical PPC_LD_ARGS = 0x00000008, // family: ldst PPC_LDX_ARGS = 0x00000009, // family: ldst PPC_ST_ARGS = 0x0000000A, // family: ldst PPC_STX_ARGS = 0x0000000B, // family: ldst PPC_NB_ARGS = 0x0000000F, /* Type */ PPC_ARITH = 0x00000100, PPC_LOGICAL = 0x00000200, PPC_COMPARE = 0x00000300, PPC_CROP = 0x00000400, PPC_LDST = 0x00000500, PPC_TYPE = 0x00000F00, /* Family */ PPC_INTEGER = 0x00010000, PPC_FLOAT = 0x00020000, PPC_405 = 0x00030000, PPC_ALTIVEC = 0x00040000, PPC_FALTIVEC = 0x00050000, PPC_FAMILY = 0x000F0000, /* Flags: these may be combined, so use separate bitfields. */ PPC_CR = 0x01000000, PPC_XER_CA = 0x02000000,};#endif /* !defined (__TEST_PPC_H__) *//* -------------- END #include "test-ppc.h" -------------- */#if defined (DEBUG_ARGS_BUILD)#define AB_DPRINTF(fmt, args...) do { fprintf(stderr, fmt , ##args); } while (0)#else#define AB_DPRINTF(fmt, args...) do { } while (0)#endif#if defined (DEBUG_FILTER)#define FDPRINTF(fmt, args...) do { fprintf(stderr, fmt , ##args); } while (0)#else#define FDPRINTF(fmt, args...) do { } while (0)#endif/* Produce the 64-bit pattern corresponding to the supplied double. */static uint64_t double_to_bits ( double d ){ union { uint64_t i; double d; } u; assert(8 == sizeof(uint64_t)); assert(8 == sizeof(double)); assert(8 == sizeof(u)); u.d = d; return u.i;}#if 0static float bits_to_float ( uint32_t i ){ union { uint32_t i; float f; } u; assert(4 == sizeof(uint32_t)); assert(4 == sizeof(float)); assert(4 == sizeof(u)); u.i = i; return u.f;}#endif#if defined (HAS_ALTIVEC)static void AB_DPRINTF_VEC32x4 ( vector unsigned int v ){#if defined (DEBUG_ARGS_BUILD) int i; unsigned int* p_int = (unsigned int*)&v; AB_DPRINTF("val"); for (i=0; i<4; i++) { AB_DPRINTF(" %08x", p_int[i]); } AB_DPRINTF("\n");#endif}#endif#define unused __attribute__ (( unused ))/* -------------- BEGIN #include "ops-ppc.c" -------------- *//* #include "test-ppc.h" */static void test_add (void){ __asm__ __volatile__ ("add 17, 14, 15");}static void test_addo (void){ __asm__ __volatile__ ("addo 17, 14, 15");}static void test_addc (void){ __asm__ __volatile__ ("addc 17, 14, 15");}static void test_addco (void){ __asm__ __volatile__ ("addco 17, 14, 15");}static void test_divw (void){ __asm__ __volatile__ ("divw 17, 14, 15");}static void test_divwo (void){ __asm__ __volatile__ ("divwo 17, 14, 15");}static void test_divwu (void){ __asm__ __volatile__ ("divwu 17, 14, 15");}static void test_divwuo (void){ __asm__ __volatile__ ("divwuo 17, 14, 15");}static void test_mulhw (void){ __asm__ __volatile__ ("mulhw 17, 14, 15");}static void test_mulhwu (void){ __asm__ __volatile__ ("mulhwu 17, 14, 15");}static void test_mullw (void){ __asm__ __volatile__ ("mullw 17, 14, 15");}static void test_mullwo (void){ __asm__ __volatile__ ("mullwo 17, 14, 15");}static void test_subf (void){ __asm__ __volatile__ ("subf 17, 14, 15");}static void test_subfo (void){ __asm__ __volatile__ ("subfo 17, 14, 15");}static void test_subfc (void){ __asm__ __volatile__ ("subfc 17, 14, 15");}static void test_subfco (void){ __asm__ __volatile__ ("subfco 17, 14, 15");}#ifdef __powerpc64__static void test_mulld (void){ __asm__ __volatile__ ("mulld 17, 14, 15");}static void test_mulhd (void){ __asm__ __volatile__ ("mulhd 17, 14, 15");}static void test_mulhdu (void){ __asm__ __volatile__ ("mulhdu 17, 14, 15");}static void test_divd (void){ __asm__ __volatile__ ("divd 17, 14, 15");}static void test_divdu (void){ __asm__ __volatile__ ("divdu 17, 14, 15");}#endif // #ifdef __powerpc64__static test_t tests_ia_ops_two[] = { { &test_add , " add", }, { &test_addo , " addo", }, { &test_addc , " addc", }, { &test_addco , " addco", }, { &test_divw , " divw", }, { &test_divwo , " divwo", }, { &test_divwu , " divwu", }, { &test_divwuo , " divwuo", }, { &test_mulhw , " mulhw", }, { &test_mulhwu , " mulhwu", },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -