| /* mmix-opc.c -- MMIX opcode table | 
 |    Copyright (C) 2001-2025 Free Software Foundation, Inc. | 
 |    Written by Hans-Peter Nilsson (hp@bitrange.com) | 
 |  | 
 |    This file is part of the GNU opcodes library. | 
 |  | 
 |    This library is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3, or (at your option) | 
 |    any later version. | 
 |  | 
 |    It is distributed in the hope that it will be useful, but WITHOUT | 
 |    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 
 |    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public | 
 |    License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this file; see the file COPYING.  If not, write to the | 
 |    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include "opcode/mmix.h" | 
 | #include "symcat.h" | 
 |  | 
 | /* Register-name-table for special registers.  */ | 
 | const struct mmix_spec_reg mmix_spec_regs[] = | 
 |  { | 
 |    /* Keep rJ at top; it's the most frequently used one.  */ | 
 |    {"rJ", 4}, | 
 |    {"rA", 21}, | 
 |    {"rB", 0}, | 
 |    {"rC", 8}, | 
 |    {"rD", 1}, | 
 |    {"rE", 2}, | 
 |    {"rF", 22}, | 
 |    {"rG", 19}, | 
 |    {"rH", 3}, | 
 |    {"rI", 12}, | 
 |    {"rK", 15}, | 
 |    {"rL", 20}, | 
 |    {"rM", 5}, | 
 |    {"rN", 9}, | 
 |    {"rO", 10}, | 
 |    {"rP", 23}, | 
 |    {"rQ", 16}, | 
 |    {"rR", 6}, | 
 |    {"rS", 11}, | 
 |    {"rT", 13}, | 
 |    {"rU", 17}, | 
 |    {"rV", 18}, | 
 |    {"rW", 24}, | 
 |    {"rX", 25}, | 
 |    {"rY", 26}, | 
 |    {"rZ", 27}, | 
 |    {"rBB", 7}, | 
 |    {"rTT", 14}, | 
 |    {"rWW", 28}, | 
 |    {"rXX", 29}, | 
 |    {"rYY", 30}, | 
 |    {"rZZ", 31}, | 
 |    {NULL, 0} | 
 |  }; | 
 |  | 
 | /* Opcode-table.  In order to cut down on redundant contents, we use helper | 
 |    macros.  */ | 
 |  | 
 | /* All bits in the opcode-byte are significant.  Add "| ..." expressions | 
 |    to add zero-bits.  */ | 
 | #undef O | 
 | #define O(m) ((unsigned long) (m) << 24UL), ((~(unsigned long) (m) & 255) << 24) | 
 |  | 
 | /* Bits 7..1 of the opcode are significant.  */ | 
 | #undef Z | 
 | #define Z(m) ((unsigned long) (m) << 24), ((~(unsigned long) (m) & 254) << 24) | 
 |  | 
 | /* For easier overview of the table.  */ | 
 | #define N mmix_type_normal | 
 | #define B mmix_type_branch | 
 | #define C mmix_type_condbranch | 
 | #define MB mmix_type_memaccess_byte | 
 | #define MW mmix_type_memaccess_wyde | 
 | #define MT mmix_type_memaccess_tetra | 
 | #define MO mmix_type_memaccess_octa | 
 | #define M mmix_type_memaccess_block | 
 | #define J mmix_type_jsr | 
 | #define P mmix_type_pseudo | 
 |  | 
 | #define OP(y) XCONCAT2 (mmix_operands_,y) | 
 |  | 
 | /* Groups of instructions specified here must, if all are matching the | 
 |    same instruction, be consecutive, in order more-specific to | 
 |    less-specific match.  */ | 
 |  | 
 | const struct mmix_opcode mmix_opcodes[] = | 
 |  { | 
 |    {"trap",	O (0),		OP (xyz_opt),		J}, | 
 |    {"fcmp",	O (1),		OP (regs),		N}, | 
 |    {"flot",	Z (8),		OP (roundregs_z),	N}, | 
 |  | 
 |    {"fun",	O (2),		OP (regs),		N}, | 
 |    {"feql",	O (3),		OP (regs),		N}, | 
 |    {"flotu",	Z (10),		OP (roundregs_z),	N}, | 
 |  | 
 |    {"fadd",	O (4),		OP (regs),		N}, | 
 |    {"fix",	O (5),		OP (roundregs),		N}, | 
 |    {"sflot",	Z (12),		OP (roundregs_z),	N}, | 
 |  | 
 |    {"fsub",	O (6),		OP (regs),		N}, | 
 |    {"fixu",	O (7),		OP (roundregs),		N}, | 
 |    {"sflotu",	Z (14),		OP (roundregs_z),	N}, | 
 |  | 
 |    {"fmul",	O (16),		OP (regs),		N}, | 
 |    {"fcmpe",	O (17),		OP (regs),		N}, | 
 |    {"mul",	Z (24),		OP (regs_z),		N}, | 
 |  | 
 |    {"fune",	O (18),		OP (regs),		N}, | 
 |    {"feqle",	O (19),		OP (regs),		N}, | 
 |    {"mulu",	Z (26),		OP (regs_z),		N}, | 
 |  | 
 |    {"fdiv",	O (20),		OP (regs),		N}, | 
 |    {"fsqrt",	O (21),		OP (roundregs),		N}, | 
 |    {"div",	Z (28),		OP (regs_z),		N}, | 
 |  | 
 |    {"frem",	O (22),		OP (regs),		N}, | 
 |    {"fint",	O (23),		OP (roundregs),		N}, | 
 |    {"divu",	Z (30),		OP (regs_z),		N}, | 
 |  | 
 |    {"add",	Z (0x20),	OP (regs_z),		N}, | 
 |    {"2addu",	Z (0x28),	OP (regs_z),		N}, | 
 |  | 
 |    {"addu",	Z (0x22),	OP (regs_z),		N}, | 
 |    /* Synonym for ADDU.  Put after ADDU, since we don't prefer it for | 
 |       disassembly.  It's supposed to be used for addresses, so we make it | 
 |       a memory block reference for purposes of assembly.  */ | 
 |    {"lda",	Z (0x22),	OP (regs_z_opt),	M}, | 
 |    {"4addu",	Z (0x2a),	OP (regs_z),		N}, | 
 |  | 
 |    {"sub",	Z (0x24),	OP (regs_z),		N}, | 
 |    {"8addu",	Z (0x2c),	OP (regs_z),		N}, | 
 |  | 
 |    {"subu",	Z (0x26),	OP (regs_z),		N}, | 
 |    {"16addu",	Z (0x2e),	OP (regs_z),		N}, | 
 |  | 
 |    {"cmp",	Z (0x30),	OP (regs_z),		N}, | 
 |    {"sl",	Z (0x38),	OP (regs_z),		N}, | 
 |  | 
 |    {"cmpu",	Z (0x32),	OP (regs_z),		N}, | 
 |    {"slu",	Z (0x3a),	OP (regs_z),		N}, | 
 |  | 
 |    {"neg",	Z (0x34),	OP (neg),		N}, | 
 |    {"sr",	Z (0x3c),	OP (regs_z),		N}, | 
 |  | 
 |    {"negu",	Z (0x36),	OP (neg),		N}, | 
 |    {"sru",	Z (0x3e),	OP (regs_z),		N}, | 
 |  | 
 |    {"bn",	Z (0x40),	OP (regaddr),		C}, | 
 |    {"bnn",	Z (0x48),	OP (regaddr),		C}, | 
 |  | 
 |    {"bz",	Z (0x42),	OP (regaddr),		C}, | 
 |    {"bnz",	Z (0x4a),	OP (regaddr),		C}, | 
 |  | 
 |    {"bp",	Z (0x44),	OP (regaddr),		C}, | 
 |    {"bnp",	Z (0x4c),	OP (regaddr),		C}, | 
 |  | 
 |    {"bod",	Z (0x46),	OP (regaddr),		C}, | 
 |    {"bev",	Z (0x4e),	OP (regaddr),		C}, | 
 |  | 
 |    {"pbn",	Z (0x50),	OP (regaddr),		C}, | 
 |    {"pbnn",	Z (0x58),	OP (regaddr),		C}, | 
 |  | 
 |    {"pbz",	Z (0x52),	OP (regaddr),		C}, | 
 |    {"pbnz",	Z (0x5a),	OP (regaddr),		C}, | 
 |  | 
 |    {"pbp",	Z (0x54),	OP (regaddr),		C}, | 
 |    {"pbnp",	Z (0x5c),	OP (regaddr),		C}, | 
 |  | 
 |    {"pbod",	Z (0x56),	OP (regaddr),		C}, | 
 |    {"pbev",	Z (0x5e),	OP (regaddr),		C}, | 
 |  | 
 |    {"csn",	Z (0x60),	OP (regs_z),		N}, | 
 |    {"csnn",	Z (0x68),	OP (regs_z),		N}, | 
 |  | 
 |    {"csz",	Z (0x62),	OP (regs_z),		N}, | 
 |    {"csnz",	Z (0x6a),	OP (regs_z),		N}, | 
 |  | 
 |    {"csp",	Z (0x64),	OP (regs_z),		N}, | 
 |    {"csnp",	Z (0x6c),	OP (regs_z),		N}, | 
 |  | 
 |    {"csod",	Z (0x66),	OP (regs_z),		N}, | 
 |    {"csev",	Z (0x6e),	OP (regs_z),		N}, | 
 |  | 
 |    {"zsn",	Z (0x70),	OP (regs_z),		N}, | 
 |    {"zsnn",	Z (0x78),	OP (regs_z),		N}, | 
 |  | 
 |    {"zsz",	Z (0x72),	OP (regs_z),		N}, | 
 |    {"zsnz",	Z (0x7a),	OP (regs_z),		N}, | 
 |  | 
 |    {"zsp",	Z (0x74),	OP (regs_z),		N}, | 
 |    {"zsnp",	Z (0x7c),	OP (regs_z),		N}, | 
 |  | 
 |    {"zsod",	Z (0x76),	OP (regs_z),		N}, | 
 |    {"zsev",	Z (0x7e),	OP (regs_z),		N}, | 
 |  | 
 |    {"ldb",	Z (0x80),	OP (regs_z_opt),	MB}, | 
 |    {"ldt",	Z (0x88),	OP (regs_z_opt),	MT}, | 
 |  | 
 |    {"ldbu",	Z (0x82),	OP (regs_z_opt),	MB}, | 
 |    {"ldtu",	Z (0x8a),	OP (regs_z_opt),	MT}, | 
 |  | 
 |    {"ldw",	Z (0x84),	OP (regs_z_opt),	MW}, | 
 |    {"ldo",	Z (0x8c),	OP (regs_z_opt),	MO}, | 
 |  | 
 |    {"ldwu",	Z (0x86),	OP (regs_z_opt),	MW}, | 
 |    {"ldou",	Z (0x8e),	OP (regs_z_opt),	MO}, | 
 |  | 
 |    {"ldsf",	Z (0x90),	OP (regs_z_opt),	MT}, | 
 |  | 
 |    /* This doesn't seem to access memory, just the TLB.  */ | 
 |    {"ldvts",	Z (0x98),	OP (regs_z_opt),	M}, | 
 |  | 
 |    {"ldht",	Z (0x92),	OP (regs_z_opt),	MT}, | 
 |  | 
 |    /* Neither does this per-se.  */ | 
 |    {"preld",	Z (0x9a),	OP (x_regs_z),		N}, | 
 |  | 
 |    {"cswap",	Z (0x94),	OP (regs_z_opt),	MO}, | 
 |    {"prego",	Z (0x9c),	OP (x_regs_z),		N}, | 
 |  | 
 |    {"ldunc",	Z (0x96),	OP (regs_z_opt),	MO}, | 
 |    {"go",	Z (GO_INSN_BYTE), | 
 | 				OP (regs_z_opt),	B}, | 
 |  | 
 |    {"stb",	Z (0xa0),	OP (regs_z_opt),	MB}, | 
 |    {"stt",	Z (0xa8),	OP (regs_z_opt),	MT}, | 
 |  | 
 |    {"stbu",	Z (0xa2),	OP (regs_z_opt),	MB}, | 
 |    {"sttu",	Z (0xaa),	OP (regs_z_opt),	MT}, | 
 |  | 
 |    {"stw",	Z (0xa4),	OP (regs_z_opt),	MW}, | 
 |    {"sto",	Z (0xac),	OP (regs_z_opt),	MO}, | 
 |  | 
 |    {"stwu",	Z (0xa6),	OP (regs_z_opt),	MW}, | 
 |    {"stou",	Z (0xae),	OP (regs_z_opt),	MO}, | 
 |  | 
 |    {"stsf",	Z (0xb0),	OP (regs_z_opt),	MT}, | 
 |    {"syncd",	Z (0xb8),	OP (x_regs_z),		M}, | 
 |  | 
 |    {"stht",	Z (0xb2),	OP (regs_z_opt),	MT}, | 
 |    {"prest",	Z (0xba),	OP (x_regs_z),		M}, | 
 |  | 
 |    {"stco",	Z (0xb4),	OP (x_regs_z),		MO}, | 
 |    {"syncid",	Z (0xbc),	OP (x_regs_z),		M}, | 
 |  | 
 |    {"stunc",	Z (0xb6),	OP (regs_z_opt),	MO}, | 
 |    {"pushgo",	Z (PUSHGO_INSN_BYTE), | 
 | 				OP (pushgo),		J}, | 
 |  | 
 |    /* Synonym for OR with a zero Z.  */ | 
 |    {"set",	O (0xc1) | 
 | 		  | 0xff,	OP (set),		N}, | 
 |  | 
 |    {"or",	Z (0xc0),	OP (regs_z),		N}, | 
 |    {"and",	Z (0xc8),	OP (regs_z),		N}, | 
 |  | 
 |    {"orn",	Z (0xc2),	OP (regs_z),		N}, | 
 |    {"andn",	Z (0xca),	OP (regs_z),		N}, | 
 |  | 
 |    {"nor",	Z (0xc4),	OP (regs_z),		N}, | 
 |    {"nand",	Z (0xcc),	OP (regs_z),		N}, | 
 |  | 
 |    {"xor",	Z (0xc6),	OP (regs_z),		N}, | 
 |    {"nxor",	Z (0xce),	OP (regs_z),		N}, | 
 |  | 
 |    {"bdif",	Z (0xd0),	OP (regs_z),		N}, | 
 |    {"mux",	Z (0xd8),	OP (regs_z),		N}, | 
 |  | 
 |    {"wdif",	Z (0xd2),	OP (regs_z),		N}, | 
 |    {"sadd",	Z (0xda),	OP (regs_z),		N}, | 
 |  | 
 |    {"tdif",	Z (0xd4),	OP (regs_z),		N}, | 
 |    {"mor",	Z (0xdc),	OP (regs_z),		N}, | 
 |  | 
 |    {"odif",	Z (0xd6),	OP (regs_z),		N}, | 
 |    {"mxor",	Z (0xde),	OP (regs_z),		N}, | 
 |  | 
 |    {"seth",	O (0xe0),	OP (reg_yz),		N}, | 
 |    {"setmh",	O (0xe1),	OP (reg_yz),		N}, | 
 |    {"orh",	O (0xe8),	OP (reg_yz),		N}, | 
 |    {"ormh",	O (0xe9),	OP (reg_yz),		N}, | 
 |  | 
 |    {"setml",	O (0xe2),	OP (reg_yz),		N}, | 
 |    {"setl",	O (SETL_INSN_BYTE), | 
 | 				OP (reg_yz),		N}, | 
 |    {"orml",	O (0xea),	OP (reg_yz),		N}, | 
 |    {"orl",	O (0xeb),	OP (reg_yz),		N}, | 
 |  | 
 |    {"inch",	O (INCH_INSN_BYTE), | 
 | 				OP (reg_yz),		N}, | 
 |    {"incmh",	O (INCMH_INSN_BYTE), | 
 | 				OP (reg_yz),		N}, | 
 |    {"andnh",	O (0xec),	OP (reg_yz),		N}, | 
 |    {"andnmh",	O (0xed),	OP (reg_yz),		N}, | 
 |  | 
 |    {"incml",	O (INCML_INSN_BYTE), | 
 | 				OP (reg_yz),		N}, | 
 |    {"incl",	O (0xe7),	OP (reg_yz),		N}, | 
 |    {"andnml",	O (0xee),	OP (reg_yz),		N}, | 
 |    {"andnl",	O (0xef),	OP (reg_yz),		N}, | 
 |  | 
 |    {"jmp",	Z (0xf0),	OP (jmp),		B}, | 
 |    {"pop",	O (0xf8),	OP (pop),		B}, | 
 |    {"resume",	O (0xf9) | 
 | 		  | 0xffff00,	OP (resume),		B}, | 
 |  | 
 |    {"pushj",	Z (0xf2),	OP (pushj),		J}, | 
 |    {"save",	O (0xfa) | 
 | 		  | 0xffff,	OP (save),		M}, | 
 |    {"unsave",	O (0xfb) | 
 | 		  | 0xffff00,	OP (unsave),		M}, | 
 |  | 
 |    {"geta",	Z (0xf4),	OP (regaddr),		N}, | 
 |    {"sync",	O (0xfc),	OP (sync),		N}, | 
 |    {"swym",	O (SWYM_INSN_BYTE), | 
 | 				OP (xyz_opt),		N}, | 
 |  | 
 |    {"put", Z (0xf6) | 0xff00,	OP (put),		N}, | 
 |    {"get", O (0xfe) | 0xffe0,	OP (get),		N}, | 
 |    {"trip",	O (0xff),	OP (xyz_opt),		J}, | 
 |  | 
 |    /* We have mmixal pseudos in the ordinary instruction table so we can | 
 |       avoid the "set" vs. ".set" ambiguity that would be the effect if we | 
 |       had pseudos handled "normally" and defined NO_PSEUDO_DOT. | 
 |  | 
 |       Note that IS and GREG are handled fully by md_start_line_hook, so | 
 |       they're not here.  */ | 
 |    {"loc",	~0, ~0,		OP (loc),		P}, | 
 |    {"prefix",	~0, ~0,		OP (prefix),		P}, | 
 |    {"byte",	~0, ~0,		OP (byte),		P}, | 
 |    {"wyde",	~0, ~0,		OP (wyde),		P}, | 
 |    {"tetra",	~0, ~0,		OP (tetra),		P}, | 
 |    {"octa",	~0, ~0,		OP (octa),		P}, | 
 |    {"local",	~0, ~0,		OP (local),		P}, | 
 |    {"bspec",	~0, ~0,		OP (bspec),		P}, | 
 |    {"espec",	~0, ~0,		OP (espec),		P}, | 
 |  | 
 |    {NULL, ~0, ~0, OP (none), N} | 
 |  }; |