Date: Mon, 31 Mar 1997 22:29:43 +0200 (MEST) From: hfwirth@ping.at To: FreeBSD-gnats-submit@freebsd.org Subject: gnu/3157: Support for Pentium MMX instructions in gas and gdb Message-ID: <199703312029.WAA00458@atlantis.ping.at> Resent-Message-ID: <199703312030.MAA08409@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 3157 >Category: gnu >Synopsis: Patches to gas and gdb to support MMX extensions, in shar format >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Class: change-request >Submitter-Id: current-users >Arrival-Date: Mon Mar 31 12:30:01 PST 1997 >Last-Modified: >Originator: Helmut F. Wirth >Organization: Helmut F. Wirth >Release: FreeBSD 2.2-STABLE i386 >Environment: Machine: ASUS P55T2P4 with Pentium MMX 166 Opsys: FreeBSD 2.2-Stable i386 (derived from ctm as of 3/29/97) >Description: I added the MMX instructions to gas and gdb and tested the changes. Because of a comment from Garret Wollman concerning my submission format I resubmit all the patches in shar format. Please see below. the shar contains the patches for FreeBSD-2.1.7 and FreeBSD-2.2 both against stable trees obtained via ctm. >How-To-Repeat: N/A >Fix: Appended to this please find an uuencoded, gzipped tar file containing the following files: as.mmx.diff ... patch for (g)as FreeBSD-2.x gdb.mmx.diff.2.1.7 ... Patch for gdb, FreeBSD-2.1.7 gdb.mmx.diff.2.2 ... patch for gdb, FreeBSD-2.2 how_to_patch ... Install instructions mmx_changes.doc ... Short documention, what I did mmxtest.c ... The test program I used mmxtest.result ... The results from the test program If you have any questions, please feel free to email me! Regards Helmut ------------------------------ cut here ------------------------------- # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # as.mmx.diff # gdb.mmx.diff.2.1.7 # gdb.mmx.diff.2.2 # how_to_patch # mmx_changes.doc # mmxtest.c # mmxtest.result # echo x - as.mmx.diff sed 's/^X//' >as.mmx.diff << 'END-of-as.mmx.diff' Xdiff -c --recursive /usr/src/gnu/usr.bin/as/config/tc-i386.c as/config/tc-i386.c X*** /usr/src/gnu/usr.bin/as/config/tc-i386.c Thu Apr 18 20:54:34 1996 X--- as/config/tc-i386.c Fri Feb 28 21:21:57 1997 X*************** X*** 24,29 **** X--- 24,34 ---- X Please help us make it better. X */ X X+ /* Added support for the MMX instructions: 1997/02/26 Helmut F.Wirth X+ * hfwirth@ping.at. Changes only to lines where the condition X+ * if (Reg|SReg|.. was changed to if (Reg|MmxReg|Sreg| ... X+ */ X+ X #ifndef lint X static char rcsid[] = "$Id: tc-i386.c,v 1.4 1995/05/30 04:47:29 rgrimes Exp $"; X #endif X*************** X*** 889,895 **** X and i.rm.regmem fields. We accomplish this by faking that the X two register operands were given in the reverse order. */ X if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) { X! unsigned int first_reg_operand = (i.types[0] & Reg) ? 0 : 1; X unsigned int second_reg_operand = first_reg_operand + 1; X reg_entry *tmp = i.regs[first_reg_operand]; X i.regs[first_reg_operand] = i.regs[second_reg_operand]; X--- 894,900 ---- X and i.rm.regmem fields. We accomplish this by faking that the X two register operands were given in the reverse order. */ X if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) { X! unsigned int first_reg_operand = (i.types[0] & (Reg|MmxReg)) ? 0 : 1; X unsigned int second_reg_operand = first_reg_operand + 1; X reg_entry *tmp = i.regs[first_reg_operand]; X i.regs[first_reg_operand] = i.regs[second_reg_operand]; X*************** X*** 930,936 **** X implicit registers do not count. */ X if (i.reg_operands == 2) { X unsigned int source, dest; X! source = (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : 1; X dest = source + 1; X i.rm.mode = 3; X /* We must be careful to make sure that all segment/control/test/ X--- 935,941 ---- X implicit registers do not count. */ X if (i.reg_operands == 2) { X unsigned int source, dest; X! source = (i.types[0] & (MmxReg|Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : 1; X dest = source + 1; X i.rm.mode = 3; X /* We must be careful to make sure that all segment/control/test/ X*************** X*** 1052,1059 **** X into the i.rm.reg field. */ X if (i.reg_operands) { X unsigned int o = X! (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : X! (i.types[1] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 1 : 2; X /* If there is an extension opcode to put here, the register number X must be put into the regmem field. */ X if (t->extension_opcode != None) X--- 1057,1064 ---- X into the i.rm.reg field. */ X if (i.reg_operands) { X unsigned int o = X! (i.types[0] & (Reg|MmxReg|SReg2|SReg3|Control|Debug|Test)) ? 0 : X! (i.types[1] & (Reg|MmxReg|SReg2|SReg3|Control|Debug|Test)) ? 1 : 2; X /* If there is an extension opcode to put here, the register number X must be put into the regmem field. */ X if (t->extension_opcode != None) Xdiff -c --recursive /usr/src/gnu/usr.bin/as/config/tc-i386.h as/config/tc-i386.h X*** /usr/src/gnu/usr.bin/as/config/tc-i386.h Thu Apr 18 20:54:34 1996 X--- as/config/tc-i386.h Fri Feb 28 21:22:24 1997 X*************** X*** 21,26 **** X--- 21,29 ---- X * $Id: tc-i386.h,v 1.3 1995/05/30 04:47:31 rgrimes Exp $ X */ X X+ /* Added support for the MMX instructions: 1997/02/26 Helmut F.Wirth X+ hfwirth@ping.at */ X+ X #ifndef TC_I386 X #define TC_I386 1 X X*************** X*** 134,139 **** X--- 137,145 ---- X #define Abs16 0x10000000 X #define Abs32 0x20000000 X #define Abs (Abs8|Abs16|Abs32) X+ X+ /* For P55C MMX extensions */ X+ #define MmxReg 0x40000000 X X #define Byte (Reg8|Imm8|Imm8S) X #define Word (Reg16|Imm16) Xdiff -c --recursive /usr/src/gnu/usr.bin/as/opcode/i386.h as/opcode/i386.h X*** /usr/src/gnu/usr.bin/as/opcode/i386.h Thu Apr 18 20:54:38 1996 X--- as/opcode/i386.h Fri Feb 28 21:19:21 1997 X*************** X*** 19,24 **** X--- 19,27 ---- X X /* $Id: i386.h,v 1.3 1995/05/30 04:48:01 rgrimes Exp $ */ X X+ /* Added support for the MMX instructions: 1997/02/26 Helmut F.Wirth X+ hfwirth@ping.at */ X+ X static const template i386_optab[] = { X X #define _ None X*************** X*** 732,737 **** X--- 735,829 ---- X /* Pentium and late-model 486 extensions */ X {"cpuid", 0, 0x0fa2, _, NoModrm, 0, 0, 0}, X X+ /* MMX extensions for Pentium P55C, added by hfwirth@ping.at, 1997/02/26 X+ * Naming conventions from the INTEL Programmers Reference Manual, X+ * except the move commands. I used MMOVD or MMOVQ here, to avoid conflicts X+ * with the other move instructions. X+ */ X+ X+ {"emms", 0, 0x0f77, _, NoModrm, 0, 0, 0}, X+ X+ {"mmovd", 2, 0x0f7e, _, Modrm, MmxReg, Reg32|Mem, 0}, X+ {"mmovd", 2, 0x0f6e, _, ReverseRegRegmem|Modrm, Reg32|Mem, MmxReg, 0}, X+ /* Aliases for suffix 'l'; not sure if this is really needed */ X+ {"mmovl", 2, 0x0f7e, _, Modrm, MmxReg, Reg32|Mem, 0}, X+ {"mmovl", 2, 0x0f6e, _, ReverseRegRegmem|Modrm, Reg32|Mem, MmxReg, 0}, X+ X+ {"mmovq", 2, 0x0f6f, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"mmovq", 2, 0x0f7f, _, ReverseRegRegmem|Modrm, MmxReg, MmxReg|Mem, 0}, X+ X+ {"packsswb", 2, 0x0f63, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"packssdw", 2, 0x0f6b, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"packuswb", 2, 0x0f67, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"punpckhbw", 2, 0x0f68, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"punpckhwd", 2, 0x0f69, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"punpckhdq", 2, 0x0f6a, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"punpcklbw", 2, 0x0f60, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"punpcklwd", 2, 0x0f61, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"punpckldq", 2, 0x0f62, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"paddb", 2, 0x0ffc, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"paddw", 2, 0x0ffd, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"paddd", 2, 0x0ffe, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"paddsb", 2, 0x0fec, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"paddsw", 2, 0x0fed, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"paddusb", 2, 0x0fdc, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"paddusw", 2, 0x0fdd, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"psubb", 2, 0x0ff8, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psubw", 2, 0x0ff9, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psubd", 2, 0x0ffa, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"psubsb", 2, 0x0fe8, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psubsw", 2, 0x0fe9, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"psubusb", 2, 0x0fd8, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psubusw", 2, 0x0fd9, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"pand", 2, 0x0fdb, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"pandn", 2, 0x0fdf, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"por", 2, 0x0feb, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"pxor", 2, 0x0fef, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"pcmpeqb", 2, 0x0f74, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"pcmpeqw", 2, 0x0f75, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"pcmpeqd", 2, 0x0f76, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"pcmpgtb", 2, 0x0f64, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"pcmpgtw", 2, 0x0f65, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"pcmpgtd", 2, 0x0f66, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"pmaddwd", 2, 0x0ff5, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"pmulhw", 2, 0x0fe5, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"pmullw", 2, 0x0fd5, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ X+ {"psllw", 2, 0x0ff1, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psllw", 2, 0x0f71, 6, Modrm, Imm8, MmxReg, 0}, X+ {"pslld", 2, 0x0ff2, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"pslld", 2, 0x0f72, 6, Modrm, Imm8, MmxReg, 0}, X+ {"psllq", 2, 0x0ff3, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psllq", 2, 0x0f73, 6, Modrm, Imm8, MmxReg, 0}, X+ X+ {"psrlw", 2, 0x0fd1, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psrlw", 2, 0x0f71, 2, Modrm, Imm8, MmxReg, 0}, X+ {"psrld", 2, 0x0fd2, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psrld", 2, 0x0f72, 2, Modrm, Imm8, MmxReg, 0}, X+ {"psrlq", 2, 0x0fd3, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psrlq", 2, 0x0f73, 2, Modrm, Imm8, MmxReg, 0}, X+ X+ {"psraw", 2, 0x0fe1, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psraw", 2, 0x0f71, 4, Modrm, Imm8, MmxReg, 0}, X+ {"psrad", 2, 0x0fe2, _, ReverseRegRegmem|Modrm, MmxReg|Mem, MmxReg, 0}, X+ {"psrad", 2, 0x0f72, 4, Modrm, Imm8, MmxReg, 0}, X+ /* End of P55C MMX extensions */ X+ X {"", 0, 0, 0, 0, 0, 0, 0} /* sentinal */ X }; X #undef _ X*************** X*** 767,773 **** X {"st", FloatReg|FloatAcc, 0}, X {"st(1)", FloatReg, 1}, {"st(2)", FloatReg, 2}, X {"st(3)", FloatReg, 3}, {"st(4)", FloatReg, 4}, {"st(5)", FloatReg, 5}, X! {"st(6)", FloatReg, 6}, {"st(7)", FloatReg, 7} X }; X X #define MAX_REG_NAME_SIZE 8 /* for parsing register names from input */ X--- 859,869 ---- X {"st", FloatReg|FloatAcc, 0}, X {"st(1)", FloatReg, 1}, {"st(2)", FloatReg, 2}, X {"st(3)", FloatReg, 3}, {"st(4)", FloatReg, 4}, {"st(5)", FloatReg, 5}, X! {"st(6)", FloatReg, 6}, {"st(7)", FloatReg, 7}, X! /* MMX register names for P55C */ X! {"mm0", MmxReg, 0}, {"mm1", MmxReg, 1}, {"mm2", MmxReg, 2}, X! {"mm3", MmxReg, 3}, {"mm4", MmxReg, 4}, {"mm5", MmxReg, 5}, X! {"mm6", MmxReg, 6}, {"mm7", MmxReg, 7} X }; X X #define MAX_REG_NAME_SIZE 8 /* for parsing register names from input */ END-of-as.mmx.diff echo x - gdb.mmx.diff.2.1.7 sed 's/^X//' >gdb.mmx.diff.2.1.7 << 'END-of-gdb.mmx.diff.2.1.7' Xdiff -c --recursive /usr/src/gnu/usr.bin/gdb/gdb/i386-dis.c gdb/gdb/i386-dis.c X*** /usr/src/gnu/usr.bin/gdb/gdb/i386-dis.c Thu Apr 18 20:55:25 1996 X--- gdb/gdb/i386-dis.c Fri Feb 28 21:34:14 1997 X*************** X*** 23,28 **** X--- 23,32 ---- X * modified by John Hassey (hassey@dg-rtp.dg.com) X */ X X+ /* Added support for the MMX instructions: 1997/02/26 Helmut F.Wirth X+ * hfwirth@ping.at. I added the cpuid instruction too. X+ */ X+ X /* X * The main tables describing the instructions is essentially a copy X * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 X*************** X*** 102,107 **** X--- 106,118 ---- X #define Dd OP_D, d_mode X #define Td OP_T, d_mode X X+ /* For P55C MMX extensions */ X+ #define Pq OP_P, q_mode X+ #define Pd OP_P, d_mode X+ #define Qq OP_Q, q_mode X+ #define Qd OP_Q, d_mode X+ /* End MMX */ X+ X #define eAX OP_REG, eAX_reg X #define eBX OP_REG, eBX_reg X #define eCX OP_REG, eCX_reg X*************** X*** 143,148 **** X--- 154,161 ---- X int OP_J(), OP_SEG(); X int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C(); X int OP_D(), OP_T(), OP_rm(); X+ /* MMX extensions for P55C */ X+ int OP_P(), OP_Q(); X X static void dofloat (), putop (), append_prefix (), set_op (); X static int get16 (), get32 (); X*************** X*** 151,156 **** X--- 164,171 ---- X #define v_mode 2 X #define w_mode 3 X #define d_mode 4 X+ /* For MMX instructions */ X+ #define q_mode 5 X X #define es_reg 100 X #define cs_reg 101 X*************** X*** 205,210 **** X--- 220,230 ---- X #define GRP6 NULL, NULL, 13 X #define GRP7 NULL, NULL, 14 X #define GRP8 NULL, NULL, 15 X+ /* For P55C MMX Extensions */ X+ #define GRPAw NULL, NULL, 16 X+ #define GRPAd NULL, NULL, 17 X+ #define GRPAq NULL, NULL, 18 X+ /* End MMX extensions */ X X #define FLOATCODE 50 X #define FLOAT NULL, NULL, FLOATCODE X*************** X*** 510,515 **** X--- 530,536 ---- X { GRP5 }, X }; X X+ /* This table was modified for the MMX instructions, they all live here */ X struct dis386 dis386_twobyte[] = { X /* 00 */ X { GRP6 }, X*************** X*** 563,579 **** X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 60 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 68 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 70 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 78 */ X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 80 */ X { "jo", Jv }, X { "jno", Jv }, X--- 584,619 ---- X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 60 */ X! { "punpcklbw", Pq, Qd }, X! { "punpcklwd", Pq, Qd }, X! { "punpckldq", Pq, Qd }, X! { "packsswb", Pq, Qq }, X! { "pcmpgtb", Pq, Qq }, X! { "pcmpgtw", Pq, Qq }, X! { "pcmpgtd", Pq, Qq }, X! { "packuswb", Pq, Qq }, X /* 68 */ X! { "punpckhbw", Pq, Qq }, X! { "punpckhwd", Pq, Qq }, X! { "punpckhdq", Pq, Qq }, X! { "packssdw", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X! { "mmovd", Pq, Ev }, X! { "mmovq", Pq, Qq }, X /* 70 */ X! { "(bad)" }, X! { GRPAw }, X! { GRPAd }, X! { GRPAq }, X! { "pcmpeqb", Pq, Qq }, X! { "pcmpeqw", Pq, Qq }, X! { "pcmpeqd", Pq, Qq }, X! { "emms" }, X /* 78 */ X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, X! { "mmovd", Ev, Pd }, X! { "mmovq", Qq, Pq }, X /* 80 */ X { "jo", Jv }, X { "jno", Jv }, X*************** X*** 613,619 **** X /* a0 */ X { "pushl", fs }, X { "popl", fs }, X! { "(bad)" }, X { "btS", Ev, Gv }, X { "shldS", Ev, Gv, Ib }, X { "shldS", Ev, Gv, CL }, X--- 653,659 ---- X /* a0 */ X { "pushl", fs }, X { "popl", fs }, X! { "cpuid" }, X { "btS", Ev, Gv }, X { "shldS", Ev, Gv, Ib }, X { "shldS", Ev, Gv, CL }, X*************** X*** 661,683 **** X { "bswap", eSI }, X { "bswap", eDI }, X /* d0 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* d8 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* e0 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* e8 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* f0 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* f8 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X }; X X static char obuf[100]; X--- 701,755 ---- X { "bswap", eSI }, X { "bswap", eDI }, X /* d0 */ X! { "(bad)" }, X! { "psrlw", Pq, Qq }, X! { "psrld", Pq, Qq }, X! { "psrlq", Pq, Qq }, X! { "(bad)" }, X! { "pmullw", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X /* d8 */ X! { "psubusb", Pq, Qq }, X! { "psubusw", Pq, Qq }, X! { "(bad)" }, X! { "pand", Pq, Qq }, X! { "paddusb", Pq, Qq }, X! { "paddusw", Pq, Qq }, X! { "(bad)" }, X! { "pandn", Pq, Qq }, X /* e0 */ X! { "(bad)" }, X! { "psraw", Pq, Qq }, X! { "psrad", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X! { "pmulhw", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X /* e8 */ X! { "psubsb", Pq, Qq }, X! { "psubsw", Pq, Qq }, X! { "(bad)" }, X! { "por", Pq, Qq }, X! { "paddsb", Pq, Qq }, X! { "paddsw", Pq, Qq }, X! { "(bad)", Pq, Qq }, X! { "pxor", Pq, Qq }, X /* f0 */ X! { "(bad)" }, X! { "psllw", Pq, Qq }, X! { "pslld", Pq, Qq }, X! { "psllq", Pq, Qq }, X! { "(bad)" }, X! { "pmaddwd", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X /* f8 */ X! { "psubb", Pq, Qq }, X! { "psubw", Pq, Qq }, X! { "psubd", Pq, Qq }, X! { "(bad)" }, X! { "paddb", Pq, Qq }, X! { "paddw", Pq, Qq }, X! { "paddd", Pq, Qq }, X! { "(bad)" }, X }; X X static char obuf[100]; X*************** X*** 880,885 **** X--- 952,991 ---- X { "btsS", Ev, Ib }, X { "btrS", Ev, Ib }, X { "btcS", Ev, Ib }, X+ }, X+ /* The next three groups are needed for the MMX instructions */ X+ /* GRPAw */ X+ { X+ { "(bad)" }, X+ { "(bad)" }, X+ { "psrlw", Qq, Ib }, X+ { "(bad)" }, X+ { "psraw", Qq, Ib }, X+ { "(bad)" }, X+ { "psllw", Qq, Ib }, X+ { "(bad)" }, X+ }, X+ /* GRPAd */ X+ { X+ { "(bad)" }, X+ { "(bad)" }, X+ { "psrld", Qq, Ib }, X+ { "(bad)" }, X+ { "psrad", Qq, Ib }, X+ { "(bad)" }, X+ { "pslld", Qq, Ib }, X+ { "(bad)" }, X+ }, X+ /* GRPAq */ X+ { X+ { "(bad)" }, X+ { "(bad)" }, X+ { "psrlq", Qq, Ib }, X+ { "(bad)" }, X+ { "(bad)" }, X+ { "(bad)" }, X+ { "psllq", Qq, Ib }, X+ { "(bad)" }, X } X }; X X*************** X*** 1957,1959 **** X--- 2063,2188 ---- X } X return (0); X } X+ X+ /* MMX extensions for P55C */ X+ X+ static char *mmxnames[]={ X+ "%mm0","%mm1","%mm2","%mm3", "%mm4","%mm5","%mm6","%mm7", X+ }; X+ X+ int X+ OP_Q (bytemode) X+ int bytemode; X+ { X+ int disp; X+ int havesib; X+ int base; X+ int index; X+ int scale; X+ int havebase; X+ X+ /* skip mod/rm byte */ X+ codep++; X+ X+ havesib = 0; X+ havebase = 0; X+ disp = 0; X+ X+ if (mod == 3) X+ { X+ if (prefixes & PREFIX_DATA) X+ oappend("<Meaningless data size prefix>"); X+ oappend (mmxnames[rm]); X+ return (0); X+ } X+ X+ append_prefix (); X+ if (rm == 4) X+ { X+ havesib = 1; X+ havebase = 1; X+ FETCH_DATA (the_info, codep + 1); X+ scale = (*codep >> 6) & 3; X+ index = (*codep >> 3) & 7; X+ base = *codep & 7; X+ codep++; X+ } X+ X+ switch (mod) X+ { X+ case 0: X+ switch (rm) X+ { X+ case 4: X+ /* implies havesib and havebase */ X+ if (base == 5) { X+ havebase = 0; X+ disp = get32 (); X+ } X+ break; X+ case 5: X+ disp = get32 (); X+ break; X+ default: X+ havebase = 1; X+ base = rm; X+ break; X+ } X+ break; X+ case 1: X+ FETCH_DATA (the_info, codep + 1); X+ disp = *(char *)codep++; X+ if (rm != 4) X+ { X+ havebase = 1; X+ base = rm; X+ } X+ break; X+ case 2: X+ disp = get32 (); X+ if (rm != 4) X+ { X+ havebase = 1; X+ base = rm; X+ } X+ break; X+ } X+ X+ if (mod != 0 || rm == 5 || (havesib && base == 5)) X+ { X+ sprintf (scratchbuf, "0x%x", disp); X+ oappend (scratchbuf); X+ } X+ X+ if (havebase || havesib) X+ { X+ oappend ("("); X+ if (havebase) X+ oappend (names32[base]); X+ if (havesib) X+ { X+ if (index != 4) X+ { X+ sprintf (scratchbuf, ",%s", names32[index]); X+ oappend (scratchbuf); X+ } X+ sprintf (scratchbuf, ",%d", 1 << scale); X+ oappend (scratchbuf); X+ } X+ oappend (")"); X+ } X+ return (0); X+ } X+ X+ int X+ OP_P (bytemode) X+ int bytemode; X+ { X+ if (prefixes & PREFIX_DATA) X+ oappend("<Meaningless data size prefix>"); X+ oappend(mmxnames[reg]); X+ return (0); X+ } X+ X+ X+ END-of-gdb.mmx.diff.2.1.7 echo x - gdb.mmx.diff.2.2 sed 's/^X//' >gdb.mmx.diff.2.2 << 'END-of-gdb.mmx.diff.2.2' X*** i386-dis.c.orig Mon Mar 31 11:20:15 1997 X--- i386-dis.c Mon Mar 31 12:19:13 1997 X*************** X*** 23,28 **** X--- 23,32 ---- X * modified by John Hassey (hassey@dg-rtp.dg.com) X */ X X+ /* Added support for the MMX instructions: 1997/03/30 Helmut F.Wirth X+ * hfwirth@ping.at X+ */ X+ X /* X * The main tables describing the instructions is essentially a copy X * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 X*************** X*** 102,107 **** X--- 106,118 ---- X #define Dd OP_D, d_mode X #define Td OP_T, d_mode X X+ /* For P55C MMX extensions */ X+ #define Pq OP_P, q_mode X+ #define Pd OP_P, d_mode X+ #define Qq OP_Q, q_mode X+ #define Qd OP_Q, d_mode X+ /* End MMX */ X+ X #define eAX OP_REG, eAX_reg X #define eBX OP_REG, eBX_reg X #define eCX OP_REG, eCX_reg X*************** X*** 146,156 **** X--- 157,171 ---- X X static void dofloat (), putop (), append_prefix (), set_op (); X static int get16 (), get32 (); X+ /* MMX extensions for P55C */ X+ int OP_P(), OP_Q(); X X #define b_mode 1 X #define v_mode 2 X #define w_mode 3 X #define d_mode 4 X+ /* For MMX instructions */ X+ #define q_mode 5 X X #define es_reg 100 X #define cs_reg 101 X*************** X*** 206,211 **** X--- 221,232 ---- X #define GRP7 NULL, NULL, 14 X #define GRP8 NULL, NULL, 15 X #define GRP9 NULL, NULL, 16 X+ /* For P55C MMX Extensions */ X+ #define GRPAw NULL, NULL, 17 X+ #define GRPAd NULL, NULL, 18 X+ #define GRPAq NULL, NULL, 19 X+ /* End MMX extensions */ X+ X X #define FLOATCODE 50 X #define FLOAT NULL, NULL, FLOATCODE X*************** X*** 564,580 **** X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 60 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 68 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 70 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 78 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 80 */ X { "jo", Jv }, X { "jno", Jv }, X--- 585,620 ---- X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* 60 */ X! { "punpcklbw", Pq, Qd }, X! { "punpcklwd", Pq, Qd }, X! { "punpckldq", Pq, Qd }, X! { "packsswb", Pq, Qq }, X! { "pcmpgtb", Pq, Qq }, X! { "pcmpgtw", Pq, Qq }, X! { "pcmpgtd", Pq, Qq }, X! { "packuswb", Pq, Qq }, X /* 68 */ X! { "punpckhbw", Pq, Qq }, X! { "punpckhwd", Pq, Qq }, X! { "punpckhdq", Pq, Qq }, X! { "packssdw", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X! { "mmovd", Pq, Ev }, X! { "mmovq", Pq, Qq }, X /* 70 */ X! { "(bad)" }, X! { GRPAw }, X! { GRPAd }, X! { GRPAq }, X! { "pcmpeqb", Pq, Qq }, X! { "pcmpeqw", Pq, Qq }, X! { "pcmpeqd", Pq, Qq }, X! { "emms" }, X /* 78 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, X! { "mmovd", Ev, Pd }, X! { "mmovq", Qq, Pq }, X /* 80 */ X { "jo", Jv }, X { "jno", Jv }, X*************** X*** 666,688 **** X { "bswap", eSI }, X { "bswap", eDI }, X /* d0 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* d8 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* e0 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* e8 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* f0 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X /* f8 */ X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X! { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, X }; X X static const unsigned char onebyte_has_modrm[256] = { X--- 706,760 ---- X { "bswap", eSI }, X { "bswap", eDI }, X /* d0 */ X! { "(bad)" }, X! { "psrlw", Pq, Qq }, X! { "psrld", Pq, Qq }, X! { "psrlq", Pq, Qq }, X! { "(bad)" }, X! { "pmullw", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X /* d8 */ X! { "psubusb", Pq, Qq }, X! { "psubusw", Pq, Qq }, X! { "(bad)" }, X! { "pand", Pq, Qq }, X! { "paddusb", Pq, Qq }, X! { "paddusw", Pq, Qq }, X! { "(bad)" }, X! { "pandn", Pq, Qq }, X /* e0 */ X! { "(bad)" }, X! { "psraw", Pq, Qq }, X! { "psrad", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X! { "pmulhw", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X /* e8 */ X! { "psubsb", Pq, Qq }, X! { "psubsw", Pq, Qq }, X! { "(bad)" }, X! { "por", Pq, Qq }, X! { "paddsb", Pq, Qq }, X! { "paddsw", Pq, Qq }, X! { "(bad)", Pq, Qq }, X! { "pxor", Pq, Qq }, X /* f0 */ X! { "(bad)" }, X! { "psllw", Pq, Qq }, X! { "pslld", Pq, Qq }, X! { "psllq", Pq, Qq }, X! { "(bad)" }, X! { "pmaddwd", Pq, Qq }, X! { "(bad)" }, { "(bad)" }, X /* f8 */ X! { "psubb", Pq, Qq }, X! { "psubw", Pq, Qq }, X! { "psubd", Pq, Qq }, X! { "(bad)" }, X! { "paddb", Pq, Qq }, X! { "paddw", Pq, Qq }, X! { "paddd", Pq, Qq }, X! { "(bad)" }, X }; X X static const unsigned char onebyte_has_modrm[256] = { X*************** X*** 704,709 **** X--- 776,782 ---- X 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 X }; X X+ /* Changes to the table for MMX opcodes */ X static const unsigned char twobyte_has_modrm[256] = { X 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, X 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X*************** X*** 711,726 **** X 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, X 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X! 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X! 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, X 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, X 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, X 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, X! 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X! 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X! 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 X }; X X static char obuf[100]; X--- 784,799 ---- X 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, X 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X! 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, X! 0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, X 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, X 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, X 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, X 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, X 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, X! 0,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1, X! 0,1,1,0,0,1,0,0,1,1,0,1,1,1,0,1, X! 0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0 X }; X X static char obuf[100]; X*************** X*** 937,942 **** X--- 1010,1049 ---- X { "(bad)" }, X { "(bad)" }, X { "(bad)" }, X+ }, X+ /* The next three groups are needed for the MMX instructions */ X+ /* GRPAw */ X+ { X+ { "(bad)" }, X+ { "(bad)" }, X+ { "psrlw", Qq, Ib }, X+ { "(bad)" }, X+ { "psraw", Qq, Ib }, X+ { "(bad)" }, X+ { "psllw", Qq, Ib }, X+ { "(bad)" }, X+ }, X+ /* GRPAd */ X+ { X+ { "(bad)" }, X+ { "(bad)" }, X+ { "psrld", Qq, Ib }, X+ { "(bad)" }, X+ { "psrad", Qq, Ib }, X+ { "(bad)" }, X+ { "pslld", Qq, Ib }, X+ { "(bad)" }, X+ }, X+ /* GRPAq */ X+ { X+ { "(bad)" }, X+ { "(bad)" }, X+ { "psrlq", Qq, Ib }, X+ { "(bad)" }, X+ { "(bad)" }, X+ { "(bad)" }, X+ { "psllq", Qq, Ib }, X+ { "(bad)" }, X } X }; X X*************** X*** 2029,2031 **** X--- 2136,2272 ---- X } X return (0); X } X+ X+ /* MMX extensions for P55C */ X+ X+ static char *mmxnames[]={ X+ "%mm0","%mm1","%mm2","%mm3", "%mm4","%mm5","%mm6","%mm7", X+ }; X+ X+ int X+ OP_Q (bytemode) X+ int bytemode; X+ { X+ int disp; X+ X+ /* skip mod/rm byte */ X+ codep++; X+ X+ if (mod == 3) X+ { X+ if (prefixes & PREFIX_DATA) X+ oappend("<Meaningless data size prefix>"); X+ oappend (mmxnames[rm]); X+ return (0); X+ } X+ X+ disp = 0; X+ append_prefix (); X+ X+ if (aflag) /* 32 bit address mode */ X+ { X+ int havesib; X+ int havebase; X+ int base; X+ int index; X+ int scale; X+ X+ havesib = 0; X+ havebase = 1; X+ base = rm; X+ X+ if (base == 4) X+ { X+ havesib = 1; X+ FETCH_DATA (the_info, codep + 1); X+ scale = (*codep >> 6) & 3; X+ index = (*codep >> 3) & 7; X+ base = *codep & 7; X+ codep++; X+ } X+ X+ switch (mod) X+ { X+ case 0: X+ if (base == 5) X+ { X+ havebase = 0; X+ disp = get32 (); X+ } X+ break; X+ case 1: X+ FETCH_DATA (the_info, codep + 1); X+ disp = *(char *)codep++; X+ break; X+ case 2: X+ disp = get32 (); X+ break; X+ } X+ X+ if (mod != 0 || base == 5) X+ { X+ sprintf (scratchbuf, "0x%x", disp); X+ oappend (scratchbuf); X+ } X+ X+ if (havebase || (havesib && (index != 4 || scale != 0))) X+ { X+ oappend ("("); X+ if (havebase) X+ oappend (names32[base]); X+ if (havesib) X+ { X+ if (index != 4) X+ { X+ sprintf (scratchbuf, ",%s", names32[index]); X+ oappend (scratchbuf); X+ } X+ sprintf (scratchbuf, ",%d", 1 << scale); X+ oappend (scratchbuf); X+ } X+ oappend (")"); X+ } X+ } X+ else X+ { /* 16 bit address mode */ X+ switch (mod) X+ { X+ case 0: X+ if (rm == 6) X+ disp = (short) get16 (); X+ break; X+ case 1: X+ FETCH_DATA (the_info, codep + 1); X+ disp = *(char *)codep++; X+ break; X+ case 2: X+ disp = (short) get16 (); X+ break; X+ } X+ X+ if (mod != 0 || rm == 6) X+ { X+ sprintf (scratchbuf, "0x%x", disp); X+ oappend (scratchbuf); X+ } X+ X+ if (mod != 0 || rm != 6) X+ { X+ oappend ("("); X+ oappend (index16[rm]); X+ oappend (")"); X+ } X+ } X+ return 0; X+ } X+ X+ int X+ OP_P (bytemode) X+ int bytemode; X+ { X+ if (prefixes & PREFIX_DATA) X+ oappend("<Meaningless data size prefix>"); X+ oappend(mmxnames[reg]); X+ return (0); X+ } X+ END-of-gdb.mmx.diff.2.2 echo x - how_to_patch sed 's/^X//' >how_to_patch << 'END-of-how_to_patch' XInstructions for FreeBSD-2.2 X X1) cd to /usr/src/gnu/usr.bin or wherever you have the sources X2) Make backups of the directory 'as' X3) Apply the patch as.mmx.diff with 'patch < ../weherever../as.mmx.diff' X4) cd to /usr/src/contrib/gdb/opcodes X5) Apply the patch gdb.mmx.diff.2.2 to i386-dis.c (patch i386-dis.c gdb.mmx.diff.2.2) X6) Recompile and install X7) Enjoy ! X XInstructions for FreeBSD-2.1.7 X X1) cd to /usr/src/gnu/usr.bin or wherever you have the sources X2) Make backups of the directory 'as' and 'gdb' X3) Apply the patch as.mmx.diff with 'patch < ../weherever../as.mmx.diff' X4) Apply the patch gdb.mmx.diff.2.1.7 with 'patch < ../whereever../gdb.mmx.diff' X5) Recompile and install X6) Enjoy ! X XNote: The patch file for 'as' is the same for both FreeBSD-2.2 and FreeBSD-2.1.7 X XIn both cases there are only 4 files affected by the two patches, X3 in as and one in gdb. X X X END-of-how_to_patch echo x - mmx_changes.doc sed 's/^X//' >mmx_changes.doc << 'END-of-mmx_changes.doc' XWhat I did: X=========== XI wanted support for the new Pentium MMX extension opcodes and so I Xadded them to gas and to gdb. X XMy objective was to change gas and gdb as little as possible. Gas now Xsupports all the MMX instructions and gdb can disassemble them. It is Xpossible to use MMX instruction via __asm statements from cc. (See the Xtest program I included.) X XNeither gas nor gdb actually use MMX instructions themselves, so they Xcan safely be used on any 80x86 prozessor, as before. X XThe names for the registers is as Intel specified: XThere are 8 identical 64 bit registers: X X mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7. X XYou can examine the MMX registers using the 'info float' command. You Xshould ignore all the flags and the exponent part of the values. The Xhex values shown are correct. Maybe I will add a new command 'info mmx' Xlater. You can also watch the effect of 'emms'. X XI added Intel's test for the MMX extensions (via cpuid) to the Xtest program. A application should always test for the existence of the XMMX features before using it. But this simple test won't work for Xan Intel i486 or i386 or for AMD or Cyrix processors. I think we need Xthe MMX functionality added to the sysstat call, especially because Xthis seem to be in more than one of the future processors, at least the Xprocessors from Intel. The MMX extensions are identified by bit 23 Xin the feature flags returned by the cpuid instruction. X XThe names of the mnemonics are identical to Intel's naming, with Xone exception: To avoid confusion and problems with size suffices I Xnamed all the new MMX move commands 'mmov*'. Please note that the Xsize suffices ('b', 'w', 'l',..) are meaningless, because these instructions Xalways operate on 64 bit, with the exception of mmovd, which moves a X32 bit quantity from or to a generic register or from or to memory. For X'mmovd' I added an alias 'mmovl'. X XPlease note too, that data size prefixes in the code are meaningless for Xthe MMX instruction and are ignored. Gdb will warn, if it finds a data Xsize prefix for a MMX command. Address size prefixes will work. X XThe list of mnemonics: Xmmovd, mmovl Xmmovq Xemms Xpacksswb, packssdw, packuswb Xpunpckhbw, punpckhwd, punpckhdq Xpunpcklbw, punpcklwd, punpckldq Xpaddb, paddw, paddd Xpaddsb, paddsw Xpaddusb, paddusw Xpsubb, psubw, psubd Xpsubsb, psubsw Xpsubusb, psubusw Xpand Xpandn Xpor Xpxor Xpcmpeqb, pcmpeqw, pcmpeqd Xpcmpgtb, pcmpgtw, pcmpgtd Xpmaddwd Xpmulhw, pmullw Xpsllw, pslld, psllq Xpsrlw, psrld, psrld, psrlq Xpsraw, psrad X XFor this work I used Intel's Programmers Reference Manual. This manual, the XDevelopers Guide for MMX, application notes and other useful information Xcan be found at Intels web site URL "http://developer.intel.com/drg/mmx/". XPlease refer to these manuals for further information. If you decide to Xtry out some of the application notes, keep in mind, that Intel uses Xthe form "opcode dest, source" in contrast to gas wich uses X"opcode src,dest". X XHere is a short documentation of the changes X============================================ XChanges to gas: (Changed a total of three files) X XIn config/tc-i386.h X X+ Added the new register type MmxReg X XIn config/tc-i386.c X X+ Changed some statements to include the new type MmxReg X XIn opcode/i386.h X X+ Added the names for the mmx registers, Intel notation: mm0,...,mm7 X+ Added the mnemonics and descriptions for all MMX instructions X XChanges to gdb: (Changed one file) X XIn gdb/i386-dis.c X X+ Added new defs for the addressing modes and tables X+ Added new operand size define q_mode X+ Added the MMX instructions to the two byte opcode table X+ Added the cpuid instruction (one will need it to test for MMX CPUs X+ Added the names for the MMX regs: mm0,mm1,...,mm7 X+ Added two short routines for the addressing modes X X XHow I tested the changes: X========================= XI used the test program include to this package, compiled it using the changed Xgas and singlestepped it in the changed debugger. There is a file named Xmmxtest.result. This is the output I got with the test program mmxtest. X XI compiled my kernel twice, one time with the original gas and one time Xwith the patched gas and then compared the results. The only changes were Xsome characters (Compilation date and version number). So it seems that the Xchanges have no influence to the other instructions, as it should be. X XHelmut X Xhfwirth@ping.at X END-of-mmx_changes.doc echo x - mmxtest.c sed 's/^X//' >mmxtest.c << 'END-of-mmxtest.c' X/* Test program for MMX extensions. X * Helmut F. Wirth, hfwirth@ping.at, Thu 970226 X * X * I used this program and some other early stuff to test my changes. X * The program does nothing useful, but it contains all MMX instructions X * used with various addressing modes. The test is not complete in the sense X * that all commands in all possible addressing modes are used, this would X * be much too long. But it does test the algorithms inside gas and gdb. X * I singlestepped through the program and looked at the MMX registers and X * at the disassmebly in gdb. (One can look at the MMX registers using X * info float). X * So I hope there are not too many bugs in my changes and I hope you X * will find them useful. X * X * Compile this with the patched version of as using X * cc -o mmxtest -g mmxtest.c X */ X X X/* The names 'dword' for a long, 'qword' for a 64bit word and 'word' X for short are corresponding to the names in the opcode mnemonics */ X X/* For further information you can find the manuals (Developers Guide and X Programmers Guide), a lot of useful information and application notes X on Intels web site at URL: http://developer.intel.com/drg/mmx/ X */ X X#include <stdio.h> X X/* The different forms MMX data can take */ Xtypedef union X{ X unsigned long long uqword; X long long sqword; X struct X { X long low; X long high; X } dword; X struct X { X unsigned long low; X unsigned long high; X } udword; X struct X { X short w0; X short w1; X short w2; X short w3; X } sword; X struct X { X unsigned short w0; X unsigned short w1; X unsigned short w2; X unsigned short w3; X } usword; X struct X { X char c0; X char c1; X char c2; X char c3; X char c4; X char c5; X char c6; X char c7; X } sbyte; X struct X { X unsigned char c0; X unsigned char c1; X unsigned char c2; X unsigned char c3; X unsigned char c4; X unsigned char c5; X unsigned char c6; X unsigned char c7; X } ubyte; X} mmxdata; X X/* Test data */ X Xmmxdata checker1, checker2; Xmmxdata result1, result2, result3; X Xstruct wpack X{ X long dword1; X long dword2; X}; X Xstruct wpack ddat1, ddat2; X Xstruct bpack X{ X short word1; X short word2; X short word3; X short word4; X}; X Xstruct bpack wdat1, wdat2; X X X/* A quite senseless routine designed for testing the various X instructions and adress formats */ X X/* This is the Intel recommanded way to test MMX presence */ X/* This will return 1, if MMX CPU, else 0 */ X X/* Note: This or a similar routine could be in a system include file defined X static inline int .... It should be used in every application using X MMX extensions to maintain downward compatibility */ X Xstatic int is_mmx() X{ X int result; X __asm __volatile( X "movl $1,%%eax\n" X " cpuid\n" X " andl $0x800000,%%edx\n" X " shrl $23,%%edx\n" X : "=d" (result) :: "ax", "dx"); X return result; X} X Xvoid mmxtest() X{ X X/* First do the test to check if this is a MMX CPU */ X X if (!is_mmx()) X { X printf("Not a MMX CPU, bailing out\n"); X exit(1); X } X X X/* Test load and store via normal registers and via memory */ X checker1.dword.low = checker1.dword.high = 0x03030303; X checker2.dword.low = checker2.dword.high = 0x0c0c0c0c; X X /* Move from generic register to mmx register */ X /* Move number to lower part of mmx register, shift it up X and or it together, then store it to memory */ X printf("Moves:\n"); X __asm __volatile ( X "movl $0x12345678, %%eax\n" X "movl $0xabcdabcd, %%ebx\n" X "mmovd %%eax,%%mm0\n" X "mmovd %%ebx,%%mm6\n" X "mmovd %%mm6,%%eax\n" X "psllq $32,%%mm6\n" X "por %%mm0,%%mm6\n" X "mmovq %%mm6,_result1\n" X ::: "ax", "bx"); X printf("%x:%x\n", result1.udword.high,result1.udword.low); X X /* Move from memory to mmx reg, or it together, store it to X memory. */ X __asm __volatile ( X "mmovq _checker1,%mm2\n" X "mmovq _checker2,%mm3\n" X "por %mm3,%mm2\n" X "mmovq %mm2,_result1\n" X ); X printf("%x:%x\n", result1.udword.high,result1.udword.low); X X /* Move from memory to mmx reg, or it together, store it to X memory. The same as above, but with different address mode */ X __asm __volatile ( X "movl $_checker1,%%ecx\n" X "mmovq (%%ecx),%%mm2\n" X "movl $8, %%esi\n" X "mmovq (%%ecx,%%esi,1),%%mm3\n" X "por %%mm3,%%mm2\n" X "mmovq %%mm2,_result1\n" X ::: "cx", "si"); X printf("%x:%x\n", result1.udword.high,result1.udword.low); X X /* Now the various pack instructions */ X X /* Pack dwords (long) to words with signed saturation */ X X printf("Pack dwords:\n"); X X ddat1.dword1 = 0x01aaaa; /* Will saturate signed or unsigned */ X ddat1.dword2 = 0x008123; /* Will saturate signed only */ X ddat2.dword1 = 0x006543; /* Will not saturate */ X ddat2.dword2 = 0x001111; /* Will not saturate */ X X __asm __volatile ( X "mmovq _ddat1,%mm0\n" X "packssdw _ddat2,%mm0\n" X "mmovq %mm0,_result1\n" X ); X printf("%x:%x:%x:%x\n", result1.sword.w3,result1.sword.w2, X result1.sword.w1,result1.sword.w0); X X /* Pack words (short) to words with signed and unsigned saturation */ X X printf("Pack words:\n"); X X wdat1.word1 = 0x01aa; /* Will saturate signed or unsigned */ X wdat1.word2 = 0x0081; /* Will saturate signed only */ X wdat1.word3 = 0x0065; /* Will not saturate */ X wdat1.word4 = 0x0011; /* Will not saturate */ X X wdat2.word1 = 0x07bb; /* Will saturate signed or unsigned */ X wdat2.word2 = 0x0081; /* Will saturate signed only */ X wdat2.word3 = 0x8065; /* Will saturate signed and unsigned */ X wdat2.word4 = 0x007f; /* Will not saturate */ X X __asm __volatile ( X "mmovq _wdat1,%mm0\n" X "packsswb _wdat2,%mm0\n" X "mmovq %mm0,_result1\n" X "mmovq _wdat1,%mm0\n" X "packuswb _wdat2,%mm0\n" X "mmovq %mm0,_result2\n" X ); X printf("%x:%x:%x:%x:%x:%x:%x:%x\n", X result1.ubyte.c7, result1.ubyte.c6, X result1.ubyte.c5, result1.ubyte.c4, X result1.ubyte.c3, result1.ubyte.c2, X result1.ubyte.c1, result1.ubyte.c0); X X printf("%x:%x:%x:%x:%x:%x:%x:%x\n", X result2.ubyte.c7, result2.ubyte.c6, X result2.ubyte.c5, result2.ubyte.c4, X result2.ubyte.c3, result2.ubyte.c2, X result2.ubyte.c1, result2.ubyte.c0); X X /* Now the add instructions with and without saturation */ X X /* Normal add without saturation for dwords */ X X printf("Add dwords w/o saturation:\n"); X X ddat1.dword1 = 0xffffffff; X ddat2.dword1 = 0x00000001; /* Will wrap around */ X ddat1.dword2 = 0x12345678; X ddat2.dword2 = 0x07654321; /* Will fit */ X X __asm __volatile ( X "mmovq _ddat1,%mm5\n" X "paddd _ddat2,%mm5\n" X "mmovq %mm5,_result1\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X X /* Add words, without and with signed and unsigned saturation */ X X printf("Add words with saturation:\n"); X X wdat1.word1 = 0xff00; /* Will saturate signed or unsigned */ X wdat2.word1 = 0x11bb; X X wdat1.word2 = 0x7fff; /* Will saturate signed only */ X wdat2.word2 = 0x0001; X X wdat1.word3 = 0x2700; /* Will not saturate */ X wdat2.word3 = 0x2111; X X wdat1.word4 = 0x0011; /* Will not saturate */ X wdat2.word4 = 0x007f; X X __asm __volatile ( X "mmovq _wdat1,%mm5\n" X "paddw _wdat2,%mm5\n" X "mmovq %mm5,_result1\n" X "mmovq _wdat1,%mm5\n" X "paddsw _wdat2,%mm5\n" X "mmovq %mm5,_result2\n" X "mmovq _wdat1,%mm5\n" X "paddusw _wdat2,%mm5\n" X "mmovq %mm5,_result3\n" X ); X printf("%x:%x:%x:%x\n", result1.sword.w3,result1.sword.w2, X result1.sword.w1,result1.sword.w0); X printf("%x:%x:%x:%x\n", result2.sword.w3,result2.sword.w2, X result2.sword.w1,result2.sword.w0); X printf("%x:%x:%x:%x\n", result3.sword.w3,result3.sword.w2, X result3.sword.w1,result3.sword.w0); X X /* Once again, but with byte format, using the same data as X above */ X X printf("Add bytes with saturation:\n"); X X __asm __volatile ( X "mmovq _wdat1,%mm5\n" X "paddb _wdat2,%mm5\n" X "mmovq %mm5,_result1\n" X "mmovq _wdat1,%mm5\n" X "paddsb _wdat2,%mm5\n" X "mmovq %mm5,_result2\n" X "mmovq _wdat1,%mm5\n" X "paddusb _wdat2,%mm5\n" X "mmovq %mm5,_result3\n" X ); X X printf("%x:%x:%x:%x:%x:%x:%x:%x\n", X result1.ubyte.c7, result1.ubyte.c6, X result1.ubyte.c5, result1.ubyte.c4, X result1.ubyte.c3, result1.ubyte.c2, X result1.ubyte.c1, result1.ubyte.c0); X X printf("%x:%x:%x:%x:%x:%x:%x:%x\n", X result2.ubyte.c7, result2.ubyte.c6, X result2.ubyte.c5, result2.ubyte.c4, X result2.ubyte.c3, result2.ubyte.c2, X result2.ubyte.c1, result2.ubyte.c0); X X printf("%x:%x:%x:%x:%x:%x:%x:%x\n", X result3.ubyte.c7, result3.ubyte.c6, X result3.ubyte.c5, result3.ubyte.c4, X result3.ubyte.c3, result3.ubyte.c2, X result3.ubyte.c1, result3.ubyte.c0); X X X /* Now the same with the subtract instructions */ X X /* Normal sub without saturation for dwords */ X X printf("Sub dwords w/o saturation:\n"); X X ddat1.dword1 = 0xffffffff; X ddat2.dword1 = 0x0000000f; /* Will fit */ X ddat1.dword2 = 0x12345678; X ddat2.dword2 = 0x07654321; /* Will fit */ X X __asm __volatile ( X "mmovq _ddat1,%mm5\n" X "psubd _ddat2,%mm5\n" X "mmovq %mm5,_result1\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X X /* Sub words, without and with signed and unsigned saturation */ X X printf("Sub words with saturation:\n"); X X wdat1.word1 = 0x0000; /* Will saturate signed or unsigned */ X wdat2.word1 = 0xffff; X X wdat1.word2 = 0x7fff; /* Will saturate signed only */ X wdat2.word2 = 0xffff; X X wdat1.word3 = 0x2700; /* Will not saturate */ X wdat2.word3 = 0x2111; X X wdat1.word4 = 0x0011; /* Will not saturate */ X wdat2.word4 = 0x007f; X X __asm __volatile ( X "mmovq _wdat1,%mm5\n" X "psubw _wdat2,%mm5\n" X "mmovq %mm5,_result1\n" X "mmovq _wdat1,%mm5\n" X "psubsw _wdat2,%mm5\n" X "mmovq %mm5,_result2\n" X "mmovq _wdat1,%mm5\n" X "psubusw _wdat2,%mm5\n" X "mmovq %mm5,_result3\n" X ); X printf("%x:%x:%x:%x\n", result1.sword.w3,result1.sword.w2, X result1.sword.w1,result1.sword.w0); X printf("%x:%x:%x:%x\n", result2.sword.w3,result2.sword.w2, X result2.sword.w1,result2.sword.w0); X printf("%x:%x:%x:%x\n", result3.sword.w3,result3.sword.w2, X result3.sword.w1,result3.sword.w0); X X /* Once again, but with byte format, using the same data as X above */ X X printf("Sub bytes with saturation:\n"); X X __asm __volatile ( X "mmovq _wdat1,%mm5\n" X "psubb _wdat2,%mm5\n" X "mmovq %mm5,_result1\n" X "mmovq _wdat1,%mm5\n" X "psubsb _wdat2,%mm5\n" X "mmovq %mm5,_result2\n" X "mmovq _wdat1,%mm5\n" X "psubusb _wdat2,%mm5\n" X "mmovq %mm5,_result3\n" X ); X X printf("%x:%x:%x:%x:%x:%x:%x:%x\n", X result1.ubyte.c7, result1.ubyte.c6, X result1.ubyte.c5, result1.ubyte.c4, X result1.ubyte.c3, result1.ubyte.c2, X result1.ubyte.c1, result1.ubyte.c0); X X printf("%x:%x:%x:%x:%x:%x:%x:%x\n", X result2.ubyte.c7, result2.ubyte.c6, X result2.ubyte.c5, result2.ubyte.c4, X result2.ubyte.c3, result2.ubyte.c2, X result2.ubyte.c1, result2.ubyte.c0); X X printf("%x:%x:%x:%x:%x:%x:%x:%x\n", X result3.ubyte.c7, result3.ubyte.c6, X result3.ubyte.c5, result3.ubyte.c4, X result3.ubyte.c3, result3.ubyte.c2, X result3.ubyte.c1, result3.ubyte.c0); X X /* Test and not instruction */ X X printf("Inverted and\n"); X X checker1.dword.low = checker1.dword.high = 0x03030303; X checker2.dword.low = checker2.dword.high = 0x0c0c0c0c; X X __asm __volatile ( X "mmovq _checker1,%mm2\n" X "pandn _checker2,%mm2\n" X "mmovq %mm2,_result1\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X X /* Test the compare instructions */ X X /* Compare equal dword, word and byte */ X X printf("Compare dword, word and byte equal:\n"); X X checker1.dword.low = checker1.dword.high = 0x12345678; X checker2.dword.low = 0x12345678; X checker2.dword.high = 0x12345578; X X __asm __volatile ( X "mmovq _checker1,%mm2\n" X "pcmpeqd _checker2,%mm2\n" X "mmovq %mm2,_result1\n" X "mmovq _checker1,%mm2\n" X "pcmpeqw _checker2,%mm2\n" X "mmovq %mm2,_result2\n" X "mmovq _checker1,%mm2\n" X "pcmpeqb _checker2,%mm2\n" X "mmovq %mm2,_result3\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X printf("%x:%x\n", result2.udword.high,result2.udword.low); X printf("%x:%x\n", result3.udword.high,result3.udword.low); X X /* Compare greater than dword, word and byte */ X X printf("Compare dword, word and byte greater than:\n"); X X checker1.dword.low = checker1.dword.high = 0x12345678; X checker2.dword.low = 0x12345678; X checker2.dword.high = 0x12345578; X X __asm __volatile ( X "mmovq _checker1,%mm2\n" X "pcmpgtd _checker2,%mm2\n" X "mmovq %mm2,_result1\n" X "mmovq _checker1,%mm2\n" X "pcmpgtw _checker2,%mm2\n" X "mmovq %mm2,_result2\n" X "mmovq _checker1,%mm2\n" X "pcmpgtb _checker2,%mm2\n" X "mmovq %mm2,_result3\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X printf("%x:%x\n", result2.udword.high,result2.udword.low); X printf("%x:%x\n", result3.udword.high,result3.udword.low); X X /* Test packed multiply and add */ X X printf("Packed multiply and add:\n"); X X wdat1.word1 = 0x2; X wdat2.word1 = 0x2; X X wdat1.word2 = 0x2; X wdat2.word2 = 0x2; X X wdat1.word3 = 0x3; X wdat2.word3 = 0xfffd; X X wdat1.word4 = 0xfffd; X wdat2.word4 = 0xfffd; X X __asm __volatile ( X "mmovq _wdat1,%mm4\n" X "pmaddwd _wdat2,%mm4\n" X "mmovq %mm4,_result1\n" X ); X printf("%x:%x:%x:%x\n", result1.sword.w3,result1.sword.w2, X result1.sword.w1,result1.sword.w0); X X /* Test multiply low/high */ X X printf("Packed multiply low and high:\n"); X X wdat1.word1 = 0x2; X wdat2.word1 = 0x2; X X wdat1.word2 = 0x4000; X wdat2.word2 = 0x3000; X X wdat1.word3 = 0x3; X wdat2.word3 = 0xfffd; X X wdat1.word4 = 0x3888; X wdat2.word4 = 0x1888; X X __asm __volatile ( X "mmovq _wdat1,%mm4\n" X "pmulhw _wdat2,%mm4\n" X "mmovq %mm4,_result1\n" X "mmovq _wdat1,%mm4\n" X "pmullw _wdat2,%mm4\n" X "mmovq %mm4,_result2\n" X ); X printf("%x:%x:%x:%x\n", result1.sword.w3,result1.sword.w2, X result1.sword.w1,result1.sword.w0); X printf("%x:%x:%x:%x\n", result2.sword.w3,result2.sword.w2, X result2.sword.w1,result2.sword.w0); X X /* Shift instructions */ X X printf("Shift left:\n"); X X checker1.dword.low = checker1.dword.high = 0x77777777; X X __asm __volatile ( X "mmovq _checker1,%mm2\n" X "psllq $4,%mm2\n" X "mmovq %mm2,_result1\n" X "mmovq _checker1,%mm2\n" X "pslld $4,%mm2\n" X "mmovq %mm2,_result2\n" X "mmovq _checker1,%mm2\n" X "psllw $4,%mm2\n" X "mmovq %mm2,_result3\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X printf("%x:%x\n", result2.udword.high,result2.udword.low); X printf("%x:%x\n", result3.udword.high,result3.udword.low); X X X /* Try the other form, shift count in mmx register */ X X printf("Shift right logical:\n"); X checker1.dword.low = checker1.dword.high = 0x77777777; X X __asm __volatile ( X "mmovq _checker1,%%mm2\n" X "movl $2,%%eax\n" X "mmovd %%eax,%%mm0\n" X "psrlq %%mm0,%%mm2\n" X "mmovq %%mm2,_result1\n" X "mmovq _checker1,%%mm2\n" X "psrld %%mm0,%%mm2\n" X "mmovq %%mm2,_result2\n" X "mmovq _checker1,%%mm2\n" X "psrlw %%mm0,%%mm2\n" X "mmovq %%mm2,_result3\n" X ::: "ax"); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X printf("%x:%x\n", result2.udword.high,result2.udword.low); X printf("%x:%x\n", result3.udword.high,result3.udword.low); X X X printf("Shift right arithmetic:\n"); X X checker1.dword.low = checker1.dword.high = 0x77777777; X X __asm __volatile ( X "mmovq _checker1,%mm2\n" X "psrad $2,%mm2\n" X "mmovq %mm2,_result1\n" X "mmovq _checker1,%mm2\n" X "psraw $2,%mm2\n" X "mmovq %mm2,_result2\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X printf("%x:%x\n", result2.udword.high,result2.udword.low); X X /* Test the unpack instructions */ X X printf("Unpack low:\n"); X X checker1.dword.low = 0x89abcdef; X checker2.dword.low = 0x01234567; X checker1.dword.high = checker2.dword.high = 0x0; X X __asm __volatile ( X "mmovq _checker1,%mm7\n" X "punpckldq _checker2,%mm7\n" X "mmovq %mm7,_result1\n" X "mmovq _checker1,%mm7\n" X "punpcklwd _checker2,%mm7\n" X "mmovq %mm7,_result2\n" X "mmovq _checker1,%mm7\n" X "punpcklbw _checker2,%mm7\n" X "mmovq %mm7,_result3\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X printf("%x:%x\n", result2.udword.high,result2.udword.low); X printf("%x:%x\n", result3.udword.high,result3.udword.low); X X printf("Unpack high:\n"); X X checker1.dword.high = 0x89abcdef; X checker2.dword.high = 0x01234567; X checker1.dword.low = checker2.dword.low = 0x0; X X __asm __volatile ( X "mmovq _checker1,%mm7\n" X "punpckhdq _checker2,%mm7\n" X "mmovq %mm7,_result1\n" X "mmovq _checker1,%mm7\n" X "punpckhwd _checker2,%mm7\n" X "mmovq %mm7,_result2\n" X "mmovq _checker1,%mm7\n" X "punpckhbw _checker2,%mm7\n" X "mmovq %mm7,_result3\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X printf("%x:%x\n", result2.udword.high,result2.udword.low); X printf("%x:%x\n", result3.udword.high,result3.udword.low); X X /* At last, the xor instruction */ X X printf("Xor:\n"); X X checker1.dword.low = checker1.dword.high = 0x18181818; X checker2.dword.low = checker2.dword.high = 0x10101010; X X __asm __volatile ( X "mmovq _checker1,%mm7\n" X "pxor _checker2,%mm7\n" X "mmovq %mm7,_result1\n" X ); X X printf("%x:%x\n", result1.udword.high,result1.udword.low); X X printf("\nThat's it, folks!\n"); X X /* Properly end usage of MMX */ X __asm __volatile ("emms\n"); X X} X X/* The frame for all */ X Xmain() X{ X mmxtest(); X exit(0); X} END-of-mmxtest.c echo x - mmxtest.result sed 's/^X//' >mmxtest.result << 'END-of-mmxtest.result' XMoves: Xabcdabcd:12345678 Xf0f0f0f:f0f0f0f Xf0f0f0f:f0f0f0f XPack dwords: X1111:6543:7fff:7fff XPack words: X7f:80:7f:7f:11:65:7f:7f X7f:0:81:ff:11:65:81:ff XAdd dwords w/o saturation: X19999999:0 XAdd words with saturation: X90:4811:ffff8000:10bb X90:4811:7fff:10bb X90:4811:ffff8000:ffffffff XAdd bytes with saturation: X0:90:48:11:7f:0:10:bb X0:7f:48:11:7f:0:10:bb X0:90:48:11:7f:ff:ff:bb XSub dwords w/o saturation: Xacf1357:fffffff0 XSub words with saturation: Xffffff92:5ef:ffff8000:1 Xffffff92:5ef:7fff:1 X0:5ef:0:0 XSub bytes with saturation: X0:92:6:ef:80:0:1:1 X0:92:6:ef:7f:0:1:1 X0:0:6:0:0:0:0:0 XInverted and Xc0c0c0c:c0c0c0c XCompare dword, word and byte equal: X0:ffffffff Xffff0000:ffffffff Xffff00ff:ffffffff XCompare dword, word and byte greater than: Xffffffff:0 Xffff:0 Xff00:0 XPacked multiply and add: X0:0:0:8 XPacked multiply low and high: X56a:ffffffff:c00:0 Xffffc840:fffffff7:0:4 XShift left: X77777777:77777770 X77777770:77777770 X77707770:77707770 XShift right logical: X1ddddddd:dddddddd X1ddddddd:1ddddddd X1ddd1ddd:1ddd1ddd XShift right arithmetic: X1ddddddd:1ddddddd X1ddd1ddd:1ddd1ddd XUnpack low: X1234567:89abcdef X12389ab:4567cdef X18923ab:45cd67ef XUnpack high: X1234567:89abcdef X12389ab:4567cdef X18923ab:45cd67ef XXor: X8080808:8080808 X XThat's it, folks! END-of-mmxtest.result exit >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199703312029.WAA00458>