Skip site navigation (1)Skip section navigation (2)
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>