//===-- M68kInstrFormats.td - M68k Instruction Formats -----*- tablegen -*-===// // The LLVM Compiler Infrastructure // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// /// /// \file /// This file contains M68k instruction formats. /// /// Since M68k has quite a lot memory addressing modes there are more /// instruction prefixes than just i, r and m: /// TSF Since Form Letter Description /// 00 M68000 Dn or An r any register /// 01 M68000 Dn d data register direct /// 02 M68000 An a address register direct /// 03 M68000 (An) j address register indirect /// 04 M68000 (An)+ o address register indirect with postincrement /// 05 M68000 -(An) e address register indirect with predecrement /// 06 M68000 (i,An) p address register indirect with displacement /// 10 M68000 (i,An,Xn.L) f address register indirect with index and scale = 1 /// 07 M68000 (i,An,Xn.W) F address register indirect with index and scale = 1 /// 12 M68020 (i,An,Xn.L,SCALE) g address register indirect with index /// 11 M68020 (i,An,Xn.W,SCALE) G address register indirect with index /// 14 M68020 ([bd,An],Xn.L,SCALE,od) u memory indirect postindexed mode /// 13 M68020 ([bd,An],Xn.W,SCALE,od) U memory indirect postindexed mode /// 16 M68020 ([bd,An,Xn.L,SCALE],od) v memory indirect preindexed mode /// 15 M68020 ([bd,An,Xn.W,SCALE],od) V memory indirect preindexed mode /// 20 M68000 abs.L b absolute long address /// 17 M68000 abs.W B absolute short address /// 21 M68000 (i,PC) q program counter with displacement /// 23 M68000 (i,PC,Xn.L) k program counter with index and scale = 1 /// 22 M68000 (i,PC,Xn.W) K program counter with index and scale = 1 /// 25 M68020 (i,PC,Xn.L,SCALE) l program counter with index /// 24 M68020 (i,PC,Xn.W,SCALE) L program counter with index /// 27 M68020 ([bd,PC],Xn.L,SCALE,od) x program counter memory indirect postindexed mode /// 26 M68020 ([bd,PC],Xn.W,SCALE,od) X program counter memory indirect postindexed mode /// 31 M68020 ([bd,PC,Xn.L,SCALE],od) y program counter memory indirect preindexed mode /// 30 M68020 ([bd,PC,Xn.W,SCALE],od) Y program counter memory indirect preindexed mode /// 32 M68000 #immediate i immediate data /// /// NOTE that long form is always lowercase, word variants are capitalized /// /// Operand can be qualified with size where appropriate to force a particular /// instruction encoding, e.g.: /// (i8,An,Xn.W) f8 1 extension word /// (i16,An,Xn.W) f16 2 extension words /// (i32,An,Xn.W) f32 3 extension words /// /// Form without size qualifier will adapt to operand size automatically, e.g.: /// (i,An,Xn.W) f 1, 2 or 3 extension words /// /// Some forms already imply a particular size of their operands, e.g.: /// (i,An) p 1 extension word and i is 16bit /// /// Operand order follows x86 Intel order(destination before source), e.g.: /// MOV8df MOVE (4,A0,D0), D1 /// /// Number after instruction mnemonics determines the size of the data /// //===----------------------------------------------------------------------===// /// ??? Is it possible to use this stuff for disassembling? /// NOTE 1: In case of conditional beads(DA, DAReg), cond part is able to /// consume any bit, though a more general instructions must be chosen, e.g. /// d -> r, a -> r //===----------------------------------------------------------------------===// // Encoding primitives //===----------------------------------------------------------------------===// class MxBead type, bit b4 = 0, bit b5 = 0, bit b6 = 0, bit b7 = 0> { bits<8> Value = 0b00000000; let Value{3-0} = type; let Value{4} = b4; let Value{5} = b5; let Value{6} = b6; let Value{7} = b7; } /// System beads, allow to control beading flow def MxBeadTerm : MxBead<0x0, 0, 0, 0, 0>; def MxBeadIgnore : MxBead<0x0, 1, 0, 0, 0>; /// Add plain bit to the instruction class MxBead1Bit b> : MxBead<0x1, b>; class MxBead2Bits b> : MxBead<0x2, b{0}, b{1}>; class MxBead3Bits b> : MxBead<0x3, b{0}, b{1}, b{2}>; class MxBead4Bits b> : MxBead<0x4, b{0}, b{1}, b{2}, b{3}>; /// bits<3> o - operand number /// bit a - use alternative, used to select index register or /// outer displacement/immediate /// suffix NP means non-padded class MxBeadDAReg o, bit a = 0> : MxBead<0x5, o{0}, o{1}, o{2}, a>; class MxBeadDA o, bit a = 0> : MxBead<0x6, o{0}, o{1}, o{2}, a>; class MxBeadReg o, bit a = 0> : MxBead<0x7, o{0}, o{1}, o{2}, a>; class MxBeadDReg o, bit a = 0> : MxBead<0x8, o{0}, o{1}, o{2}, a>; class MxBead8Disp o, bit a = 0> : MxBead<0x9, o{0}, o{1}, o{2}, a>; /// Add Immediate to the instruction. 8-bit version is padded with zeros to fit /// the word. class MxBead8Imm o, bit a = 0> : MxBead<0xA, o{0}, o{1}, o{2}, a>; class MxBead16Imm o, bit a = 0> : MxBead<0xB, o{0}, o{1}, o{2}, a>; class MxBead32Imm o, bit a = 0> : MxBead<0xC, o{0}, o{1}, o{2}, a>; /// Encodes an immediate 0-7(alt. 1-8) into 3 bit field class MxBead3Imm o, bit a = 0> : MxBead<0xD, o{0}, o{1}, o{2}, a>; class MxEncoding { bits <192> Value; let Value{7-0} = n0.Value; let Value{15-8} = n1.Value; let Value{23-16} = n2.Value; let Value{31-24} = n3.Value; let Value{39-32} = n4.Value; let Value{47-40} = n5.Value; let Value{55-48} = n6.Value; let Value{63-56} = n7.Value; let Value{71-64} = n8.Value; let Value{79-72} = n9.Value; let Value{87-80} = n10.Value; let Value{95-88} = n11.Value; let Value{103-96} = n12.Value; let Value{111-104} = n13.Value; let Value{119-112} = n14.Value; let Value{127-120} = n15.Value; let Value{135-128} = n16.Value; let Value{143-136} = n17.Value; let Value{151-144} = n18.Value; let Value{159-152} = n19.Value; let Value{167-160} = n20.Value; let Value{175-168} = n21.Value; let Value{183-176} = n22.Value; let Value{191-184} = n23.Value; } class MxEncFixed value> : MxEncoding { let Value{7-0} = MxBead4Bits.Value; let Value{15-8} = MxBead4Bits.Value; let Value{23-16} = MxBead4Bits.Value; let Value{31-24} = MxBead4Bits.Value; } //===----------------------------------------------------------------------===// // Encoding composites // // These must be lowered to MxEncoding by instr specific wrappers // // HERE BE DRAGONS... //===----------------------------------------------------------------------===// class MxEncByte value> : MxEncoding { MxBead4Bits LO = MxBead4Bits; MxBead4Bits HI = MxBead4Bits; } def MxEncEmpty : MxEncoding; /// M68k Standard Effective Address layout: /// /// :-------------------: /// | 5 4 3 | 2 1 0 | /// | mode | reg | /// :-------------------: /// /// If the EA is a direct register mode, bits 4 and 5 are 0, and the register /// number will be encoded in bit 0 - 3. Since the first address register's /// (A0) register number is 8, we can easily tell data registers from /// address registers by only inspecting bit 3 (i.e. if bit 3 is set, it's an /// address register). /// /// /// But MOVE instruction uses reversed layout for destination EA: /// /// :-------------------: /// | 5 4 3 | 2 1 0 | /// | reg | mode | /// :-------------------: /// /// And this complicates things a bit because the DA bit is now separated from /// the register and we have to encode those separately using MxBeadDA /// class MxEncEA { MxBead Reg = reg; MxBead Mode = mode; MxBead DA = da; } class MxEncMemOp { dag EA = (ascend); dag Supplement = (ascend); } // FIXME: Is there a way to factorize the addressing mode suffix (i.e. // 'r', 'd', 'a' etc.) and use something like multiclass to replace? def MxEncEAr_0: MxEncEA, MxBead2Bits<0b00>>; def MxEncEAd_0: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<0>>; def MxEncEAa_0: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<1>>; def MxEncEAj_0: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<0>>; def MxEncEAo_0: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<1>>; def MxEncEAe_0: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<0>>; def MxEncEAp_0: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<1>>; def MxEncEAf_0: MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<0>>; def MxEncEAa_0_reflected : MxEncEA, MxBead3Bits<0b001>>; def MxEncEAr_0_reflected : MxEncEA, MxBead2Bits<0b00>, MxBeadDA<0>>; def MxEncEAr_1: MxEncEA, MxBead2Bits<0b00>>; def MxEncEAd_1: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<0>>; def MxEncEAa_1: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<1>>; def MxEncEAj_1: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<0>>; def MxEncEAo_1: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<1>>; def MxEncEAe_1: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<0>>; def MxEncEAp_1: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<1>>; def MxEncEAf_1: MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<0>>; def MxEncEAr_2: MxEncEA, MxBead2Bits<0b00>>; def MxEncEAd_2: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<0>>; def MxEncEAa_2: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<1>>; def MxEncEAj_2: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<0>>; def MxEncEAo_2: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<1>>; def MxEncEAe_2: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<0>>; def MxEncEAp_2: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<1>>; def MxEncEAf_2: MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<0>>; def MxEncEAb : MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<1>>; def MxEncEAq : MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<1>>; def MxEncEAk : MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<1>>; def MxEncEAi : MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<1>>; class MxEncBriefExt { dag Value = (descend // D/A + REGISTER (operand "$"#reg_opnd, 4), // W/L size_w_l, // SCALE !cond( !eq(scale, 1) : 0b00, !eq(scale, 2) : 0b01, !eq(scale, 4) : 0b10, !eq(scale, 8) : 0b11 ), 0b0, // Displacement (operand "$"#disp_opnd, 8, (encoder disp_encoder)) ); } class MxEncAddrMode_d : MxEncMemOp { let EA = (descend /*MODE*/0b000, /*REGISTER*/(operand "$"#reg_opnd, 3)); } class MxEncAddrMode_a : MxEncMemOp { let EA = (descend /*MODE*/0b001, /*REGISTER*/(operand "$"#reg_opnd, 3)); } class MxEncAddrMode_r : MxEncMemOp { let EA = (descend /*MODE without the last bit*/0b00, /*REGISTER with D/A bit*/(operand "$"#reg_opnd, 4)); } class MxEncAddrMode_k : MxEncMemOp { let EA = (descend /*MODE*/0b111, /*REGISTER*/0b011); let Supplement = MxEncBriefExt">.Value; } class MxEncAddrMode_q : MxEncMemOp { let EA = (descend /*MODE*/0b111, /*REGISTER*/0b010); // 16-bit Displacement let Supplement = (operand "$"#opnd_name, 16, (encoder "encodePCRelImm<16>")); } class MxEncAddrMode_p : MxEncMemOp { let EA = (descend /*MODE*/0b101, /*REGISTER*/(operand "$"#opnd_name#".reg", 3)); // 16-bit Displacement let Supplement = (operand "$"#opnd_name#".disp", 16, (encoder "encodeRelocImm<16>")); } class MxEncAddrMode_f : MxEncMemOp { let EA = (descend /*MODE*/0b110, /*REGISTER*/(operand "$"#opnd_name#".reg", 3)); let Supplement = MxEncBriefExt">.Value; } class MxEncAddrMode_j : MxEncMemOp { let EA = (descend /*MODE*/0b010, /*REGISTER*/(operand "$"#reg_opnd, 3)); } class MxEncAddrMode_i : MxEncMemOp { let EA = (descend /*MODE*/0b111, /*REGISTER*/0b100); // Immediate let Supplement = !cond( !eq(size, 8) : (descend 0b00000000, (operand "$"#opnd_name, 8)), !eq(size, 16) : (operand "$"#opnd_name, 16), !eq(size, 32) : (ascend (slice "$"#opnd_name, 31, 16), (slice "$"#opnd_name, 15, 0)) ); } // abs.W -> size_w_l = false // abs.L -> size_w_l = true class MxEncAddrMode_abs : MxEncMemOp { let EA = (descend /*MODE*/0b111, // Wrap the REGISTER part in another dag to make sure // the dag assigned to EA only has two arguments. Such // that it's easier for MOV instructions to reverse // on its destination part. /*REGISTER*/(descend 0b00, size_w_l)); // Absolute address let Supplement = !if(size_w_l, // abs.L (operand "$"#opnd_name, 32, (encoder "encodeRelocImm<32>")), // abs.W (operand "$"#opnd_name, 16, (encoder "encodeRelocImm<16>")) ); } class MxEncAddrMode_o : MxEncMemOp { let EA = (descend /*MODE*/0b011, /*REGISTER*/(operand "$"#reg_opnd, 3)); } class MxEncAddrMode_e : MxEncMemOp { let EA = (descend /*MODE*/0b100, /*REGISTER*/(operand "$"#reg_opnd, 3)); } // Allows you to specify each bit of opcode class MxEncOpMode { MxBead B0 = b0; MxBead B1 = b1; MxBead B2 = b2; } // op EA, Dn def MxOpMode8dEA : MxEncOpMode>; def MxOpMode16dEA : MxEncOpMode>; def MxOpMode32dEA : MxEncOpMode>; // op EA, An def MxOpMode16aEA : MxEncOpMode>; def MxOpMode32aEA : MxEncOpMode>; // op EA, Rn // As you might noticed this guy is special... Since M68k differentiates // between Data and Address registers we required to use different OPMODE codes // for Address registers DST operands. One way of dealing with it is to use // separate tablegen instructions, but in this case it would force Register // Allocator to use specific Register Classes and eventually will lead to // superfluous moves. Another approach is to use reg-variadic encoding which will // change OPMODE base on Register Class used. Luckily, all the bits that differ go // from 0 to 1 and can be encoded with MxBeadDA. // Basically, if the register used is of Data type these encodings will be // the same as MxOpMode{16,32}dEA above and used with regular instructions(e.g. ADD, // SUB), but if the register is of Address type the appropriate bits will flip and // the instructions become of *A type(e.g ADDA, SUBA). def MxOpMode16rEA : MxEncOpMode, MxBeadDA<0>, MxBead1Bit<0>>; def MxOpMode32rEA : MxEncOpMode, MxBead1Bit<1>, MxBeadDA<0>>; // op Dn, EA def MxOpMode8EAd : MxEncOpMode>; def MxOpMode16EAd : MxEncOpMode>; def MxOpMode32EAd : MxEncOpMode>; // Represents two types of extension word: // - Imm extension word // - Brief extension word class MxEncExt { MxBead Imm = imm; MxBead B8 = b8; MxBead Scale = scale; MxBead WL = wl; MxBead DAReg = daReg; } def MxExtEmpty : MxEncExt; // These handle encoding of displacement fields, absolute addresses and // immediate values, since encoding for these categories is mainly the same, // with exception of some weird immediates. def MxExtI8_0 : MxEncExt>; def MxExtI16_0 : MxEncExt>; def MxExtI32_0 : MxEncExt>; def MxExtI8_1 : MxEncExt>; def MxExtI16_1 : MxEncExt>; def MxExtI32_1 : MxEncExt>; def MxExtI8_2 : MxEncExt>; def MxExtI16_2 : MxEncExt>; def MxExtI32_2 : MxEncExt>; // NOTE They are all using Long Xn def MxExtBrief_0 : MxEncExt, MxBead1Bit<0b0>, MxBead2Bits<0b00>, MxBead1Bit<1>, MxBeadDAReg<0, 1>>; def MxExtBrief_1 : MxEncExt, MxBead1Bit<0b0>, MxBead2Bits<0b00>, MxBead1Bit<1>, MxBeadDAReg<1, 1>>; def MxExtBrief_2 : MxEncExt, MxBead1Bit<0b0>, MxBead2Bits<0b00>, MxBead1Bit<1>, MxBeadDAReg<2, 1>>; def MxExtBrief_3 : MxEncExt, MxBead1Bit<0b0>, MxBead2Bits<0b00>, MxBead1Bit<1>, MxBeadDAReg<3, 1>>; def MxExtBrief_4 : MxEncExt, MxBead1Bit<0b0>, MxBead2Bits<0b00>, MxBead1Bit<1>, MxBeadDAReg<4, 1>>; class MxEncSize value> : MxBead2Bits; def MxEncSize8 : MxEncSize<0b00>; def MxEncSize16 : MxEncSize<0b01>; def MxEncSize32 : MxEncSize<0b10>; def MxEncSize64 : MxEncSize<0b11>; // TODO: Remove "New" in the name after the codebead-based // representation is deprecated. class MxNewEncSize value> { bits<2> Value = value; } def MxNewEncSize8 : MxNewEncSize<0b00>; def MxNewEncSize16 : MxNewEncSize<0b01>; def MxNewEncSize32 : MxNewEncSize<0b10>; def MxNewEncSize64 : MxNewEncSize<0b11>; // M68k INSTRUCTION. Most instructions specify the location of an operand by // using the effective address field in the operation word. The effective address // is composed of two 3-bit fields: the mode field and the register field. The // value in the mode field selects the different address modes. The register // field contains the number of a register. The effective address field may // require additional information to fully specify the operand. This additional // information, called the effective address extension, is contained in the // following word or words and is considered part of the instruction. The // effective address modes are grouped into three categories: register direct, // memory addressing, and special. class MxInst pattern = [], MxEncoding beads = MxEncEmpty, InstrItinClass itin = NoItinerary> : Instruction { let Namespace = "M68k"; let OutOperandList = outs; let InOperandList = ins; let AsmString = asmStr; let Pattern = pattern; let Itinerary = itin; // Byte stream field bits<192> Beads = beads.Value; dag Inst = (ascend); // Number of bytes let Size = 0; let UseLogicalOperandMappings = 1; } // M68k PSEUDO INSTRUCTION class MxPseudo pattern = []> : MxInst { let isPseudo = 1; }