Massively reworked and extended ISA-Description class.
Added inspection to validate the correctness of a MC68000 instruction regarding operation size and address modes.
This commit is contained in:
parent
128330d2c7
commit
3aeb415974
@ -71,12 +71,13 @@ make it work with JUnit 5. Feel free to use the code (in package ```de.platon42.
|
||||
### V0.4 (unreleased)
|
||||
|
||||
- Enhancement: Added Structure View filters.
|
||||
- New: Added inspection to validate the correctness of a MC68000 instruction regarding operation size and address modes.
|
||||
|
||||
### V0.3 (28-Jul-21)
|
||||
|
||||
- Enhancement: Macro contents are no longer parsed, added syntax highlighting options for macros.
|
||||
- Enhancement: Macro definitions are now word and stub indexed, macro calls reference to definition.
|
||||
- Enhancement: Macro definition refactoring and find usages support.
|
||||
- New: Macro definition refactoring and find usages support.
|
||||
- Enhancement: Structural View also shows macro definitions.
|
||||
- Bugfix: Missing REPT and ENDR assembler directives added.
|
||||
- Cosmetics: Changed or added some icons at various places.
|
||||
|
@ -7,7 +7,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = 'de.platon42'
|
||||
version = '0.3'
|
||||
version = '0.4'
|
||||
sourceCompatibility = "1.8"
|
||||
targetCompatibility = "1.8"
|
||||
|
||||
@ -60,12 +60,13 @@ patchPluginXml {
|
||||
<h4>V0.4 (unreleased)</h4>
|
||||
<ul>
|
||||
<li>Enhancement: Added Structure View filters.
|
||||
<li>New: Added inspection to validate the correctness of a MC68000 instruction regarding operation size and address modes.
|
||||
</ul>
|
||||
<h4>V0.3 (28-Jul-21)</h4>
|
||||
<ul>
|
||||
<li>Enhancement: Macro contents are no longer parsed, added syntax highlighting options for macros.
|
||||
<li>Enhancement: Macro definitions are now word and stub indexed, macro calls reference to definition.
|
||||
<li>Enhancement: Macro definition refactoring and find usages support.
|
||||
<li>New: Macro definition refactoring and find usages support.
|
||||
<li>Enhancement: Structural View also shows macro definitions.
|
||||
<li>Bugfix: Missing REPT and ENDR assembler directives added.
|
||||
<li>Cosmetics: Changed or added some icons at various places.
|
||||
|
@ -364,12 +364,12 @@ public class M68kParser implements PsiParser, LightPsiParser {
|
||||
// MNEMONIC OperandSize?
|
||||
public static boolean AsmOp(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "AsmOp")) return false;
|
||||
if (!nextTokenIs(b, MNEMONIC)) return false;
|
||||
if (!nextTokenIs(b, "<mnemonic>", MNEMONIC)) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b);
|
||||
Marker m = enter_section_(b, l, _NONE_, ASM_OP, "<mnemonic>");
|
||||
r = consumeToken(b, MNEMONIC);
|
||||
r = r && AsmOp_1(b, l + 1);
|
||||
exit_section_(b, m, ASM_OP, r);
|
||||
exit_section_(b, l, m, r, false, null);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package de.platon42.intellij.plugins.m68k.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface M68kAsmOp extends M68kPsiElement {
|
||||
@ -8,4 +9,9 @@ public interface M68kAsmOp extends M68kPsiElement {
|
||||
@Nullable
|
||||
M68kOperandSize getOperandSize();
|
||||
|
||||
@NotNull
|
||||
String getMnemonic();
|
||||
|
||||
int getOpSize();
|
||||
|
||||
}
|
||||
|
@ -3,4 +3,6 @@ package de.platon42.intellij.plugins.m68k.psi;
|
||||
|
||||
public interface M68kOperandSize extends M68kPsiElement {
|
||||
|
||||
int getSize();
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kAsmOp;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kOperandSize;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kPsiImplUtil;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -33,4 +34,15 @@ public class M68kAsmOpImpl extends ASTWrapperPsiElement implements M68kAsmOp {
|
||||
return PsiTreeUtil.getChildOfType(this, M68kOperandSize.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getMnemonic() {
|
||||
return M68kPsiImplUtil.getMnemonic(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpSize() {
|
||||
return M68kPsiImplUtil.getOpSize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kOperandSize;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kPsiImplUtil;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -24,4 +25,9 @@ public class M68kOperandSizeImpl extends ASTWrapperPsiElement implements M68kOpe
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return M68kPsiImplUtil.getSize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,39 @@ enum class Machine {
|
||||
MC68060
|
||||
}
|
||||
|
||||
enum class AddressMode {
|
||||
IMMEDIATE_DATA,
|
||||
ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
ADDRESS_REGISTER_INDIRECT,
|
||||
ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
PROGRAM_COUNTER_INDIRECT_WITH_INDEX,
|
||||
SPECIAL_REGISTER_DIRECT,
|
||||
DATA_REGISTER_DIRECT,
|
||||
ADDRESS_REGISTER_DIRECT,
|
||||
REGISTER_LIST,
|
||||
ABSOLUTE_ADDRESS
|
||||
}
|
||||
|
||||
const val OP_UNSIZED = 0
|
||||
const val OP_SIZE_B = 1
|
||||
const val OP_SIZE_W = 2
|
||||
const val OP_SIZE_L = 4
|
||||
const val OP_SIZE_S = 8
|
||||
|
||||
const val OP_SIZE_BWL = (OP_SIZE_B or OP_SIZE_W or OP_SIZE_L)
|
||||
const val OP_SIZE_WL = (OP_SIZE_W or OP_SIZE_L)
|
||||
const val OP_SIZE_SBW = (OP_SIZE_B or OP_SIZE_S or OP_SIZE_W)
|
||||
|
||||
data class AllowedAdrMode(
|
||||
val op1: Set<AddressMode>? = null,
|
||||
val op2: Set<AddressMode>? = null,
|
||||
val size: Int = OP_SIZE_BWL,
|
||||
val specialReg: String? = null
|
||||
)
|
||||
|
||||
data class IsaData(
|
||||
val mnemonic: String,
|
||||
val description: String,
|
||||
@ -16,141 +49,502 @@ data class IsaData(
|
||||
val altMnemonics: List<String> = emptyList(),
|
||||
val conditionCodes: List<String> = emptyList(),
|
||||
val id: String = mnemonic,
|
||||
val opSize: String = "bWl",
|
||||
val isPrivileged: Boolean = false,
|
||||
val hasOps: Boolean = true
|
||||
val hasOps: Boolean = true,
|
||||
val modes: List<AllowedAdrMode> = listOf(AllowedAdrMode())
|
||||
)
|
||||
|
||||
object M68kIsa {
|
||||
val conditionCodes =
|
||||
listOf("cc", "ls", "cs", "lt", "eq", "mi", "f", "ne", "ge", "pl", "gt", "t", "hi", "vc", "le", "vs")
|
||||
val conditionCodesBcc = conditionCodes.filterNot { it == "f" || it == "t" }
|
||||
|
||||
val isaData = listOf(
|
||||
private val NO_OPS_UNSIZED = listOf(AllowedAdrMode(size = OP_UNSIZED))
|
||||
|
||||
private val ALL_68000_MODES = setOf(
|
||||
AddressMode.DATA_REGISTER_DIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_DIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS,
|
||||
AddressMode.IMMEDIATE_DATA,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX,
|
||||
)
|
||||
|
||||
private val ALL_EXCEPT_IMMEDIATE_AND_PC_REL = setOf(
|
||||
AddressMode.DATA_REGISTER_DIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_DIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS
|
||||
)
|
||||
|
||||
private val ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL = setOf(
|
||||
AddressMode.DATA_REGISTER_DIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS
|
||||
)
|
||||
|
||||
private val ALL_EXCEPT_AREG_AND_IMMEDIATE = setOf(
|
||||
AddressMode.DATA_REGISTER_DIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX,
|
||||
)
|
||||
|
||||
private val ALL_EXCEPT_AREG = setOf(
|
||||
AddressMode.DATA_REGISTER_DIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS,
|
||||
AddressMode.IMMEDIATE_DATA,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX,
|
||||
)
|
||||
|
||||
private val INDIRECT_MODES = setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS
|
||||
)
|
||||
|
||||
private val AREG_ONLY = setOf(AddressMode.ADDRESS_REGISTER_DIRECT)
|
||||
private val DREG_ONLY = setOf(AddressMode.DATA_REGISTER_DIRECT)
|
||||
|
||||
private val ADD_SUB_MODES = listOf(
|
||||
AllowedAdrMode(ALL_EXCEPT_AREG, setOf(AddressMode.DATA_REGISTER_DIRECT)),
|
||||
AllowedAdrMode(setOf(AddressMode.ADDRESS_REGISTER_DIRECT), setOf(AddressMode.DATA_REGISTER_DIRECT), OP_SIZE_WL),
|
||||
AllowedAdrMode(setOf(AddressMode.DATA_REGISTER_DIRECT), INDIRECT_MODES),
|
||||
)
|
||||
|
||||
private val ASD_LSD_ROD_ROXD_MODES = listOf(
|
||||
AllowedAdrMode(DREG_ONLY, DREG_ONLY),
|
||||
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), DREG_ONLY),
|
||||
AllowedAdrMode(INDIRECT_MODES, null),
|
||||
)
|
||||
|
||||
private val BTST_BCHG_BCLR_BSET_MODES = listOf(
|
||||
AllowedAdrMode(DREG_ONLY, ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, OP_SIZE_L),
|
||||
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), DREG_ONLY, OP_SIZE_L),
|
||||
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), INDIRECT_MODES, OP_SIZE_B),
|
||||
)
|
||||
|
||||
private val conditionCodes =
|
||||
listOf("cc", "ls", "cs", "lt", "eq", "mi", "f", "ne", "ge", "pl", "gt", "t", "hi", "vc", "le", "vs")
|
||||
|
||||
private val conditionCodesBcc = conditionCodes.filterNot { it == "f" || it == "t" }
|
||||
|
||||
private val isaData = listOf(
|
||||
|
||||
// Data Movement Instructions
|
||||
IsaData("move", "Move"),
|
||||
IsaData("movea", "Move Address", altMnemonics = listOf("move"), opSize = "L"),
|
||||
IsaData("movem", "Move Multiple Registers", opSize = "Wl"),
|
||||
IsaData("movep", "Move Peripheral", opSize = ""),
|
||||
IsaData("moveq", "Move Quick", opSize = "L"),
|
||||
IsaData(
|
||||
"move", "Move",
|
||||
modes = listOf(AllowedAdrMode(ALL_68000_MODES, ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL))
|
||||
),
|
||||
IsaData(
|
||||
"movea", "Move Address", altMnemonics = listOf("move"),
|
||||
modes = listOf(AllowedAdrMode(ALL_68000_MODES, AREG_ONLY, OP_SIZE_WL))
|
||||
),
|
||||
IsaData(
|
||||
"movem", "Move Multiple Registers",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(
|
||||
setOf(AddressMode.REGISTER_LIST),
|
||||
setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS
|
||||
),
|
||||
OP_SIZE_WL
|
||||
),
|
||||
AllowedAdrMode(
|
||||
setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS
|
||||
),
|
||||
setOf(AddressMode.REGISTER_LIST),
|
||||
OP_SIZE_WL
|
||||
),
|
||||
// according to Yann, specifying the registers as bitmask is also valid
|
||||
AllowedAdrMode(
|
||||
setOf(AddressMode.IMMEDIATE_DATA),
|
||||
setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS
|
||||
),
|
||||
OP_SIZE_WL
|
||||
),
|
||||
AllowedAdrMode(
|
||||
setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS
|
||||
),
|
||||
setOf(AddressMode.IMMEDIATE_DATA),
|
||||
OP_SIZE_WL
|
||||
),
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"movep", "Move Peripheral",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(
|
||||
DREG_ONLY,
|
||||
setOf(AddressMode.ADDRESS_REGISTER_INDIRECT, AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT),
|
||||
OP_SIZE_WL
|
||||
),
|
||||
AllowedAdrMode(
|
||||
setOf(AddressMode.ADDRESS_REGISTER_INDIRECT, AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT),
|
||||
DREG_ONLY,
|
||||
OP_SIZE_WL
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
IsaData("exg", "Exchange Registers", opSize = "L"),
|
||||
IsaData("lea", "Load Effective Address", opSize = ""),
|
||||
IsaData("pea", "Push Effective Address", opSize = ""),
|
||||
IsaData("link", "Link and Allocate", opSize = ""),
|
||||
IsaData("unlk", "Unlink", opSize = ""),
|
||||
IsaData(
|
||||
"moveq", "Move Quick",
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), DREG_ONLY, OP_SIZE_L))
|
||||
),
|
||||
|
||||
IsaData(
|
||||
"exg", "Exchange Registers",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(
|
||||
setOf(AddressMode.DATA_REGISTER_DIRECT, AddressMode.ADDRESS_REGISTER_DIRECT),
|
||||
setOf(AddressMode.DATA_REGISTER_DIRECT, AddressMode.ADDRESS_REGISTER_DIRECT),
|
||||
OP_SIZE_L
|
||||
)
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"lea", "Load Effective Address",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(
|
||||
setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX,
|
||||
),
|
||||
AREG_ONLY,
|
||||
OP_SIZE_L
|
||||
)
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"pea", "Push Effective Address",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(
|
||||
setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX,
|
||||
),
|
||||
null,
|
||||
OP_SIZE_L
|
||||
)
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"link", "Link and Allocate",
|
||||
modes = listOf(AllowedAdrMode(AREG_ONLY, setOf(AddressMode.IMMEDIATE_DATA), OP_SIZE_W))
|
||||
),
|
||||
IsaData(
|
||||
"unlk", "Unlink",
|
||||
modes = listOf(AllowedAdrMode(AREG_ONLY, null, OP_UNSIZED))
|
||||
),
|
||||
|
||||
// Integer Arithmetic Instructions
|
||||
IsaData("add", "Add"),
|
||||
IsaData("adda", "Add Address", altMnemonics = listOf("add"), opSize = "Wl"),
|
||||
IsaData("addi", "Add Immediate", altMnemonics = listOf("add")),
|
||||
IsaData("addq", "Add Quick"),
|
||||
IsaData("addx", "Add with Extend"),
|
||||
IsaData("add", "Add", modes = ADD_SUB_MODES),
|
||||
IsaData("adda", "Add Address", altMnemonics = listOf("add"), modes = listOf(AllowedAdrMode(ALL_68000_MODES, AREG_ONLY, OP_SIZE_WL))),
|
||||
IsaData(
|
||||
"addi", "Add Immediate", altMnemonics = listOf("add"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL))
|
||||
),
|
||||
IsaData(
|
||||
"addq", "Add Quick", modes = listOf(
|
||||
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL),
|
||||
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), AREG_ONLY, size = OP_SIZE_WL)
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"addx", "Add with Extend",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(DREG_ONLY, DREG_ONLY),
|
||||
AllowedAdrMode(setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC), setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC))
|
||||
)
|
||||
),
|
||||
|
||||
IsaData("sub", "Subtract"),
|
||||
IsaData("suba", "Subtract Address", altMnemonics = listOf("sub")),
|
||||
IsaData("subi", "Subtract Immediate", altMnemonics = listOf("sub")),
|
||||
IsaData("subq", "Subtract Quick"),
|
||||
IsaData("subx", "Subtract with Extend"),
|
||||
IsaData("sub", "Subtract", modes = ADD_SUB_MODES),
|
||||
IsaData("suba", "Subtract Address", altMnemonics = listOf("sub"), modes = listOf(AllowedAdrMode(ALL_68000_MODES, AREG_ONLY, OP_SIZE_WL))),
|
||||
IsaData(
|
||||
"subi", "Subtract Immediate", altMnemonics = listOf("sub"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL))
|
||||
),
|
||||
IsaData(
|
||||
"subq", "Subtract Quick", modes = listOf(
|
||||
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL),
|
||||
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), AREG_ONLY, size = OP_SIZE_WL)
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"subx", "Subtract with Extend",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(DREG_ONLY, DREG_ONLY),
|
||||
AllowedAdrMode(setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC), setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC))
|
||||
)
|
||||
),
|
||||
|
||||
IsaData("neg", "Negate"),
|
||||
IsaData("negx", "Negate with Extend"),
|
||||
IsaData("neg", "Negate", modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, null))),
|
||||
IsaData("negx", "Negate with Extend", modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, null))),
|
||||
|
||||
IsaData("clr", "Clear"),
|
||||
IsaData("clr", "Clear", modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, null))),
|
||||
|
||||
IsaData("cmp", "Compare"),
|
||||
IsaData("cmpa", "Compare Address", altMnemonics = listOf("cmp"), opSize = "Wl"),
|
||||
IsaData("cmpi", "Compare Immediate", altMnemonics = listOf("cmp")),
|
||||
IsaData("cmpm", "Compare Memory to Memory", altMnemonics = listOf("cmp")),
|
||||
IsaData(
|
||||
"cmp", "Compare", modes = listOf(
|
||||
AllowedAdrMode(ALL_EXCEPT_AREG, setOf(AddressMode.DATA_REGISTER_DIRECT)),
|
||||
AllowedAdrMode(setOf(AddressMode.ADDRESS_REGISTER_DIRECT), setOf(AddressMode.DATA_REGISTER_DIRECT), OP_SIZE_WL),
|
||||
)
|
||||
),
|
||||
IsaData("cmpa", "Compare Address", altMnemonics = listOf("cmp"), modes = listOf(AllowedAdrMode(ALL_68000_MODES, AREG_ONLY, OP_SIZE_WL))),
|
||||
IsaData(
|
||||
"cmpi", "Compare Immediate", altMnemonics = listOf("cmp"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_AND_IMMEDIATE))
|
||||
),
|
||||
IsaData(
|
||||
"cmpm", "Compare Memory to Memory", altMnemonics = listOf("cmp"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC), setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC)))
|
||||
),
|
||||
|
||||
IsaData("muls", "Signed Multiply", opSize = "W"),
|
||||
IsaData("mulu", "Unsigned Multiply", opSize = "W"),
|
||||
IsaData("divs", "Signed Divide", opSize = "W"),
|
||||
IsaData("divu", "Unsigned Divide", opSize = "W"),
|
||||
IsaData("muls", "Signed Multiply", modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, DREG_ONLY, OP_SIZE_W))),
|
||||
IsaData("mulu", "Unsigned Multiply", modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, DREG_ONLY, OP_SIZE_W))),
|
||||
IsaData("divs", "Signed Divide", modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, DREG_ONLY, OP_SIZE_W))),
|
||||
IsaData("divu", "Unsigned Divide", modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, DREG_ONLY, OP_SIZE_W))),
|
||||
|
||||
IsaData("ext", "Sign Extend", opSize = "Wl"),
|
||||
IsaData("ext", "Sign Extend", modes = listOf(AllowedAdrMode(DREG_ONLY, null, OP_SIZE_WL))),
|
||||
|
||||
// Logical Instructions
|
||||
IsaData("and", "Logical AND"),
|
||||
IsaData("andi", "Logical AND Immediate", altMnemonics = listOf("and")),
|
||||
IsaData("eor", "Logical Exclusive-OR"),
|
||||
IsaData("eori", "Logical Exclusive-OR Immediate", altMnemonics = listOf("eor")),
|
||||
IsaData("not", "Logical Complement"),
|
||||
IsaData("or", "Logical Inclusive-OR"),
|
||||
IsaData("ori", "Logical Inclusive-OR Immediate", altMnemonics = listOf("or")),
|
||||
IsaData(
|
||||
"and", "Logical AND",
|
||||
modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, DREG_ONLY), AllowedAdrMode(DREG_ONLY, INDIRECT_MODES))
|
||||
),
|
||||
IsaData(
|
||||
"andi", "Logical AND Immediate", altMnemonics = listOf("and"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL))
|
||||
),
|
||||
IsaData(
|
||||
"eor", "Logical Exclusive-OR",
|
||||
modes = listOf(AllowedAdrMode(DREG_ONLY, ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL))
|
||||
),
|
||||
IsaData(
|
||||
"eori", "Logical Exclusive-OR Immediate", altMnemonics = listOf("eor"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL))
|
||||
),
|
||||
IsaData(
|
||||
"or", "Logical Inclusive-OR",
|
||||
modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, DREG_ONLY), AllowedAdrMode(DREG_ONLY, INDIRECT_MODES))
|
||||
),
|
||||
IsaData(
|
||||
"ori", "Logical Inclusive-OR Immediate", altMnemonics = listOf("or"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL))
|
||||
),
|
||||
IsaData(
|
||||
"not", "Logical Complement",
|
||||
modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, null))
|
||||
),
|
||||
|
||||
// Shift and Rotate Instructions
|
||||
IsaData("asl", "Arithmetic Shift Left"),
|
||||
IsaData("asr", "Arithmetic Shift Right"),
|
||||
IsaData("lsl", "Logical Shift Left"),
|
||||
IsaData("lsr", "Logical Shift Right"),
|
||||
IsaData("rol", "Rotate Left"),
|
||||
IsaData("ror", "Rotate Right"),
|
||||
IsaData("roxl", "Rotate with Extend Left"),
|
||||
IsaData("roxr", "Rotate with Extend Right"),
|
||||
IsaData("swap", "Swap Register Words", opSize = ""),
|
||||
IsaData("asl", "Arithmetic Shift Left", modes = ASD_LSD_ROD_ROXD_MODES),
|
||||
IsaData("asr", "Arithmetic Shift Right", modes = ASD_LSD_ROD_ROXD_MODES),
|
||||
IsaData("lsl", "Logical Shift Left", modes = ASD_LSD_ROD_ROXD_MODES),
|
||||
IsaData("lsr", "Logical Shift Right", modes = ASD_LSD_ROD_ROXD_MODES),
|
||||
IsaData("rol", "Rotate Left", modes = ASD_LSD_ROD_ROXD_MODES),
|
||||
IsaData("ror", "Rotate Right", modes = ASD_LSD_ROD_ROXD_MODES),
|
||||
IsaData("roxl", "Rotate with Extend Left", modes = ASD_LSD_ROD_ROXD_MODES),
|
||||
IsaData("roxr", "Rotate with Extend Right", modes = ASD_LSD_ROD_ROXD_MODES),
|
||||
IsaData("swap", "Swap Register Words", modes = listOf(AllowedAdrMode(DREG_ONLY, null, OP_SIZE_W))),
|
||||
|
||||
// Bit Manipulation Instructions
|
||||
IsaData("bchg", "Test Bit and Change", opSize = "Bl"),
|
||||
IsaData("bclr", "Test Bit and Clear", opSize = "Bl"),
|
||||
IsaData("bset", "Test Bit and Set", opSize = "Bl"),
|
||||
IsaData("btst", "Test Bit", opSize = "Bl"),
|
||||
IsaData("bchg", "Test Bit and Change", modes = BTST_BCHG_BCLR_BSET_MODES),
|
||||
IsaData("bclr", "Test Bit and Clear", modes = BTST_BCHG_BCLR_BSET_MODES),
|
||||
IsaData("bset", "Test Bit and Set", modes = BTST_BCHG_BCLR_BSET_MODES),
|
||||
IsaData("btst", "Test Bit", modes = BTST_BCHG_BCLR_BSET_MODES),
|
||||
|
||||
// Binary-Coded Decimal Instructions
|
||||
IsaData("abcd", "Add Decimal with Extend", opSize = ""),
|
||||
IsaData("sbcd", "Subtract Decimal with Extend", opSize = ""),
|
||||
IsaData("nbcd", "Negate Decimal with Extend", opSize = ""),
|
||||
IsaData(
|
||||
"abcd", "Add Decimal with Extend",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(DREG_ONLY, DREG_ONLY, OP_SIZE_B),
|
||||
AllowedAdrMode(setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC), setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC), OP_SIZE_B)
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"sbcd", "Subtract Decimal with Extend",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(DREG_ONLY, DREG_ONLY, OP_SIZE_B),
|
||||
AllowedAdrMode(setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC), setOf(AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC), OP_SIZE_B)
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"nbcd", "Negate Decimal with Extend",
|
||||
modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, null, OP_SIZE_B))
|
||||
),
|
||||
|
||||
// Program Control Instructions
|
||||
IsaData("bCC", "Branch Conditionally", conditionCodes = conditionCodesBcc, opSize = "bsW"),
|
||||
IsaData("bra", "Branch", opSize = "bsW"),
|
||||
IsaData("bsr", "Branch to Subroutine", opSize = "bsW"),
|
||||
IsaData(
|
||||
"bCC", "Branch Conditionally", conditionCodes = conditionCodesBcc,
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.ABSOLUTE_ADDRESS), null, OP_SIZE_SBW))
|
||||
),
|
||||
IsaData("bra", "Branch", modes = listOf(AllowedAdrMode(setOf(AddressMode.ABSOLUTE_ADDRESS), null, OP_SIZE_SBW))),
|
||||
IsaData("bsr", "Branch to Subroutine", modes = listOf(AllowedAdrMode(setOf(AddressMode.ABSOLUTE_ADDRESS), null, OP_SIZE_SBW))),
|
||||
|
||||
IsaData(
|
||||
"dbCC",
|
||||
"Test Condition, Decrement, and Branch",
|
||||
altMnemonics = listOf("dbra"),
|
||||
conditionCodes = conditionCodes, opSize = "W"
|
||||
conditionCodes = conditionCodes,
|
||||
modes = listOf(AllowedAdrMode(DREG_ONLY, setOf(AddressMode.ABSOLUTE_ADDRESS), OP_SIZE_W))
|
||||
),
|
||||
IsaData(
|
||||
"sCC", "Set Conditionally", conditionCodes = conditionCodes,
|
||||
modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, null, OP_SIZE_B))
|
||||
),
|
||||
IsaData("sCC", "Set Conditionally", conditionCodes = conditionCodes, opSize = ""),
|
||||
|
||||
IsaData("jmp", "Jump", opSize = ""),
|
||||
IsaData("jsr", "Jump to Subroutine", opSize = ""),
|
||||
IsaData("nop", "No Operation", opSize = "", hasOps = false),
|
||||
IsaData(
|
||||
"jmp", "Jump",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(
|
||||
setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX
|
||||
), null, OP_UNSIZED
|
||||
)
|
||||
)
|
||||
),
|
||||
IsaData(
|
||||
"jsr", "Jump to Subroutine",
|
||||
modes = listOf(
|
||||
AllowedAdrMode(
|
||||
setOf(
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX,
|
||||
AddressMode.ABSOLUTE_ADDRESS,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT,
|
||||
AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX
|
||||
), null, OP_UNSIZED
|
||||
)
|
||||
)
|
||||
),
|
||||
IsaData("nop", "No Operation", hasOps = false, modes = NO_OPS_UNSIZED),
|
||||
|
||||
IsaData("rtr", "Return and Restore", hasOps = false),
|
||||
IsaData("rts", "Return from Subroutine", hasOps = false),
|
||||
IsaData("rtr", "Return and Restore", hasOps = false, modes = NO_OPS_UNSIZED),
|
||||
IsaData("rts", "Return from Subroutine", hasOps = false, modes = NO_OPS_UNSIZED),
|
||||
|
||||
IsaData("tst", "Test Operand"),
|
||||
IsaData("tst", "Test Operand", modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, null))),
|
||||
|
||||
// System Control Instructions
|
||||
IsaData("andi", "AND Immediate to Status Register", id = "andi to SR", altMnemonics = listOf("and"), isPrivileged = true),
|
||||
IsaData("eori", "Exclusive-OR Immediate to Status Register", id = "eori to SR", altMnemonics = listOf("eor"), isPrivileged = true),
|
||||
IsaData("ori", "Inclusive-OR Immediate to Status Register", id = "ori to SR", altMnemonics = listOf("or"), isPrivileged = true),
|
||||
IsaData("move", "Move from Status Register", id = "move from SR"),
|
||||
IsaData("move", "Move to Status Register", id = "move to SR", isPrivileged = true),
|
||||
IsaData("move", "Move User Stack Pointer", id = "move USP", isPrivileged = true),
|
||||
IsaData(
|
||||
"andi", "AND Immediate to Status Register", id = "andi to SR", altMnemonics = listOf("and"), isPrivileged = true,
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_W, "sr"))
|
||||
),
|
||||
IsaData(
|
||||
"eori", "Exclusive-OR Immediate to Status Register", id = "eori to SR", altMnemonics = listOf("eor"), isPrivileged = true,
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_W, "sr"))
|
||||
),
|
||||
IsaData(
|
||||
"ori", "Inclusive-OR Immediate to Status Register", id = "ori to SR", altMnemonics = listOf("or"), isPrivileged = true,
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_W, "sr"))
|
||||
),
|
||||
IsaData(
|
||||
"move", "Move from Status Register", id = "move from SR",
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.SPECIAL_REGISTER_DIRECT), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, OP_SIZE_W, "sr"))
|
||||
),
|
||||
IsaData(
|
||||
"move", "Move to Status Register", id = "move to SR", isPrivileged = true,
|
||||
modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_W, "sr"))
|
||||
),
|
||||
IsaData(
|
||||
"move", "Move User Stack Pointer", id = "move USP", isPrivileged = true,
|
||||
modes = listOf(
|
||||
AllowedAdrMode(setOf(AddressMode.SPECIAL_REGISTER_DIRECT), AREG_ONLY, OP_SIZE_L, "usp"),
|
||||
AllowedAdrMode(AREG_ONLY, setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_L, "usp"),
|
||||
)
|
||||
),
|
||||
|
||||
IsaData("reset", "Reset External Devices", opSize = "", isPrivileged = true, hasOps = false),
|
||||
IsaData("rte", "Return from Exception", isPrivileged = true, hasOps = false),
|
||||
IsaData("stop", "Stop", opSize = "", isPrivileged = true),
|
||||
IsaData("reset", "Reset External Devices", isPrivileged = true, hasOps = false, modes = NO_OPS_UNSIZED),
|
||||
IsaData("rte", "Return from Exception", isPrivileged = true, hasOps = false, modes = NO_OPS_UNSIZED),
|
||||
IsaData(
|
||||
"stop", "Stop", isPrivileged = true,
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), null, OP_UNSIZED))
|
||||
),
|
||||
|
||||
IsaData("chk", "Check Register Against Bound"),
|
||||
IsaData("illegal", "Take Illegal Instruction Trap", opSize = "", hasOps = false),
|
||||
IsaData("trap", "Trap", opSize = ""),
|
||||
IsaData("trapv", "Trap on Overflow", opSize = ""),
|
||||
|
||||
IsaData("andi", "AND Immediate to Condition Code Register", id = "andi to CCR", altMnemonics = listOf("and")),
|
||||
IsaData("eori", "Exclusive-OR Immediate to Condition Code Register", id = "eori to CCR", altMnemonics = listOf("eor")),
|
||||
IsaData("ori", "Inclusive-OR Immediate to Condition Code Register", id = "ori to CCR", altMnemonics = listOf("or")),
|
||||
IsaData("move", "Move to Condition Code Register", id = "move to CCR"),
|
||||
IsaData(
|
||||
"chk", "Check Register Against Bound",
|
||||
modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, DREG_ONLY, OP_SIZE_W))
|
||||
),
|
||||
IsaData("illegal", "Take Illegal Instruction Trap", hasOps = false, modes = NO_OPS_UNSIZED),
|
||||
IsaData("trap", "Trap", modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), null, OP_UNSIZED))),
|
||||
IsaData("trapv", "Trap on Overflow", hasOps = false, modes = NO_OPS_UNSIZED),
|
||||
|
||||
IsaData(
|
||||
"andi", "AND Immediate to Condition Code Register", id = "andi to CCR", altMnemonics = listOf("and"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_W, "ccr"))
|
||||
),
|
||||
IsaData(
|
||||
"eori", "Exclusive-OR Immediate to Condition Code Register", id = "eori to CCR", altMnemonics = listOf("eor"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_W, "ccr"))
|
||||
),
|
||||
IsaData(
|
||||
"ori", "Inclusive-OR Immediate to Condition Code Register", id = "ori to CCR", altMnemonics = listOf("or"),
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_W, "ccr"))
|
||||
),
|
||||
IsaData(
|
||||
"move", "Move to Condition Code Register", id = "move to CCR",
|
||||
modes = listOf(AllowedAdrMode(ALL_EXCEPT_AREG, setOf(AddressMode.SPECIAL_REGISTER_DIRECT), OP_SIZE_W, "ccr"))
|
||||
),
|
||||
|
||||
// Multiprocessor Instructions
|
||||
IsaData("tas", "Test Operand and Set", opSize = "B"),
|
||||
|
||||
)
|
||||
IsaData("tas", "Test Operand and Set", modes = listOf(AllowedAdrMode(ALL_EXCEPT_IMMEDIATE_AND_PC_REL, null, OP_SIZE_B)))
|
||||
)
|
||||
|
||||
val mnemonics =
|
||||
isaData.asSequence()
|
||||
@ -161,4 +555,47 @@ object M68kIsa {
|
||||
})
|
||||
}
|
||||
.toSet()
|
||||
|
||||
fun findMatchingInstruction(mnemonic: String): List<IsaData> {
|
||||
val lowerMnemonic = mnemonic.lowercase()
|
||||
return isaData
|
||||
.filter {
|
||||
if (it.conditionCodes.isEmpty()) {
|
||||
(it.mnemonic == lowerMnemonic) || it.altMnemonics.any { altMnemonic -> altMnemonic == lowerMnemonic }
|
||||
} else {
|
||||
it.altMnemonics.any { altMnemonic -> altMnemonic == lowerMnemonic } ||
|
||||
it.conditionCodes.any { cc ->
|
||||
it.mnemonic.replace("CC", cc) == lowerMnemonic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun findMatchingOpMode(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, opSize: Int?, specialReg: String?): List<IsaData> {
|
||||
return candidates.filter {
|
||||
it.modes.any { am ->
|
||||
isAddressModeMatching(am, op1, op2, specialReg)
|
||||
&& ((opSize == null) || ((opSize and am.size) == opSize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun findMatchingOpModeIgnoringSize(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, specialReg: String?): List<IsaData> {
|
||||
return candidates.filter {
|
||||
it.modes.any { am -> isAddressModeMatching(am, op1, op2, specialReg) }
|
||||
}
|
||||
}
|
||||
|
||||
fun findSupportedOpSizes(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, specialReg: String?): Int {
|
||||
return candidates.fold(OP_UNSIZED) { acc, isaData ->
|
||||
acc or isaData.modes.fold(OP_UNSIZED) { am_acc, am ->
|
||||
if (isAddressModeMatching(am, op1, op2, specialReg)) am_acc or am.size else am_acc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAddressModeMatching(am: AllowedAdrMode, op1: AddressMode?, op2: AddressMode?, specialReg: String?) =
|
||||
((((op1 == null) && (am.op1 == null)) || am.op1?.contains(op1) ?: false)
|
||||
&& (((op2 == null) && (am.op2 == null)) || am.op2?.contains(op2) ?: false)
|
||||
&& ((specialReg == null) || (specialReg == am.specialReg)))
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package de.platon42.intellij.plugins.m68k.inspections
|
||||
|
||||
import com.intellij.codeInspection.InspectionManager
|
||||
import com.intellij.codeInspection.LocalInspectionTool
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import de.platon42.intellij.plugins.m68k.psi.*
|
||||
|
||||
abstract class AbstractBaseM68kLocalInspectionTool : LocalInspectionTool() {
|
||||
|
||||
protected open fun checkStatement(statement: M68kStatement, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? = null
|
||||
|
||||
protected open fun checkAsmInstruction(asmInstruction: M68kAsmInstruction, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? =
|
||||
null
|
||||
|
||||
protected open fun checkMacroCall(macroCall: M68kMacroCall, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? = null
|
||||
|
||||
protected open fun checkDirective(directive: M68kPreprocessorDirective, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? = null
|
||||
|
||||
protected open fun checkRegister(register: M68kRegister, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? = null
|
||||
|
||||
override fun getGroupDisplayName() = "M68k"
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
return object : M68kVisitor() {
|
||||
override fun visitStatement(statement: M68kStatement) = addDescriptors(checkStatement(statement, holder.manager, isOnTheFly))
|
||||
|
||||
override fun visitAsmInstruction(asmInstruction: M68kAsmInstruction) =
|
||||
addDescriptors(checkAsmInstruction(asmInstruction, holder.manager, isOnTheFly))
|
||||
|
||||
override fun visitMacroCall(macroCall: M68kMacroCall) = addDescriptors(checkMacroCall(macroCall, holder.manager, isOnTheFly))
|
||||
|
||||
override fun visitPreprocessorDirective(directive: M68kPreprocessorDirective) =
|
||||
addDescriptors(checkDirective(directive, holder.manager, isOnTheFly))
|
||||
|
||||
override fun visitRegister(register: M68kRegister) = addDescriptors(checkRegister(register, holder.manager, isOnTheFly))
|
||||
|
||||
private fun addDescriptors(descriptors: Array<ProblemDescriptor>?) {
|
||||
descriptors?.forEach(holder::registerProblem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
package de.platon42.intellij.plugins.m68k.inspections
|
||||
|
||||
import com.intellij.codeInspection.InspectionManager
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import de.platon42.intellij.plugins.m68k.asm.*
|
||||
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingInstruction
|
||||
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingOpMode
|
||||
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingOpModeIgnoringSize
|
||||
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findSupportedOpSizes
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kAddressModeUtil.getAddressModeForType
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kAsmInstruction
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kSpecialRegisterDirectAddressingMode
|
||||
|
||||
class M68kSyntaxInspection : AbstractBaseM68kLocalInspectionTool() {
|
||||
|
||||
companion object {
|
||||
private const val DISPLAY_NAME = "Assembly instruction validity"
|
||||
|
||||
private const val INSTRUCTION_NOT_FOUND_MSG = "Instruction '#ref' not supported on selected cpu"
|
||||
private const val OPERANDS_UNEXPECTED_MSG_TEMPLATE = "No operands expected for '%s'"
|
||||
private const val SECOND_OP_UNEXPECTED_MSG_TEMPLATE = "Second operand '#ref' unexpected for '%s'"
|
||||
private const val UNSUPPORTED_ADDRESSING_MODE_MSG_TEMPLATE = "Unsupported addressing mode for '%s'"
|
||||
private const val UNSUPPORTED_ADDRESSING_MODE_OP1_MSG_TEMPLATE = "Unsupported addressing mode '#ref' for first operand of '%s'"
|
||||
private const val UNSUPPORTED_ADDRESSING_MODE_OP2_MSG_TEMPLATE = "Unsupported addressing mode '#ref' for second operand of '%s'"
|
||||
private const val UNSUPPORTED_ADDRESSING_MODE_FLIP_MSG_TEMPLATE = "Unsupported addressing modes for operands in this order for '%s'"
|
||||
private const val UNSUPPORTED_SIZE_UNSIZED_MSG_TEMPLATE = "Instruction '%s' is unsized"
|
||||
private const val UNSUPPORTED_SIZE_MSG_TEMPLATE = "Operation size '#ref' unsupported for '%s"
|
||||
private const val UNSUPPORTED_SIZE_BYTE_MSG = "Operation size '#ref' unsupported (should be .b)"
|
||||
private const val UNSUPPORTED_SIZE_WORD_MSG = "Operation size '#ref' unsupported (should be .w)"
|
||||
private const val UNSUPPORTED_SIZE_LONG_MSG = "Operation size '#ref' unsupported (should be .l)"
|
||||
private const val UNSUPPORTED_SIZE_WORD_OR_LONG_MSG = "Operation size '#ref' unsupported (should be .w or .l)"
|
||||
}
|
||||
|
||||
override fun getDisplayName() = DISPLAY_NAME
|
||||
|
||||
override fun checkAsmInstruction(asmInstruction: M68kAsmInstruction, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? {
|
||||
val asmOp = asmInstruction.asmOp
|
||||
val mnemonicWithSize = asmOp.text
|
||||
val isaData = findMatchingInstruction(asmOp.mnemonic)
|
||||
if (isaData.isEmpty()) {
|
||||
return arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmOp,
|
||||
INSTRUCTION_NOT_FOUND_MSG,
|
||||
null as LocalQuickFix?,
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
}
|
||||
if (asmInstruction.addressingModeList.isNotEmpty() && isaData.none { it.hasOps }) {
|
||||
return arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction.addressingModeList.first(),
|
||||
asmInstruction.addressingModeList.last(),
|
||||
OPERANDS_UNEXPECTED_MSG_TEMPLATE.format(mnemonicWithSize),
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
}
|
||||
val op1 = getAddressModeForType(asmInstruction.addressingModeList.getOrNull(0))
|
||||
val op2 = getAddressModeForType(asmInstruction.addressingModeList.getOrNull(1))
|
||||
val specialReg1 = (asmInstruction.addressingModeList.getOrNull(0) as? M68kSpecialRegisterDirectAddressingMode)?.specialRegister?.text
|
||||
val specialReg2 = (asmInstruction.addressingModeList.getOrNull(1) as? M68kSpecialRegisterDirectAddressingMode)?.specialRegister?.text
|
||||
val opSize = asmOp.opSize
|
||||
val matchingModeIsaData = findMatchingOpMode(isaData, op1, op2, opSize, specialReg1 ?: specialReg2)
|
||||
if (matchingModeIsaData.isEmpty()) {
|
||||
val matchingModeIsaDataIgnoringSize = findMatchingOpModeIgnoringSize(isaData, op1, op2, specialReg1 ?: specialReg2)
|
||||
if (matchingModeIsaDataIgnoringSize.isEmpty()) {
|
||||
val matchingModeIsaDataSwapped = findMatchingOpModeIgnoringSize(isaData, op2, op1, specialReg1 ?: specialReg2)
|
||||
val supportedModesOp1 = isaData.flatMap { it.modes.flatMap { am -> am.op1 ?: emptySet() } }.toSet()
|
||||
val supportedModesOp2 = isaData.flatMap { it.modes.flatMap { am -> am.op2 ?: emptySet() } }.toSet()
|
||||
|
||||
if (matchingModeIsaDataSwapped.isNotEmpty()) {
|
||||
return arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction,
|
||||
UNSUPPORTED_ADDRESSING_MODE_FLIP_MSG_TEMPLATE.format(mnemonicWithSize),
|
||||
null as LocalQuickFix?, // TODO add flipping quickfix
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if ((op2 != null)) {
|
||||
if (supportedModesOp2.isEmpty()) {
|
||||
return arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction.addressingModeList[1],
|
||||
SECOND_OP_UNEXPECTED_MSG_TEMPLATE.format(mnemonicWithSize),
|
||||
null as LocalQuickFix?,
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
}
|
||||
if (supportedModesOp1.contains(op1) && !supportedModesOp2.contains(op2)) {
|
||||
return arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction.addressingModeList[1],
|
||||
UNSUPPORTED_ADDRESSING_MODE_OP2_MSG_TEMPLATE.format(mnemonicWithSize),
|
||||
null as LocalQuickFix?,
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
}
|
||||
if (supportedModesOp2.contains(op2) && !supportedModesOp1.contains(op1)) {
|
||||
return arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction.addressingModeList[0],
|
||||
UNSUPPORTED_ADDRESSING_MODE_OP1_MSG_TEMPLATE.format(mnemonicWithSize),
|
||||
null as LocalQuickFix?,
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction.addressingModeList.firstOrNull() ?: asmInstruction,
|
||||
asmInstruction.addressingModeList.lastOrNull() ?: asmInstruction,
|
||||
UNSUPPORTED_ADDRESSING_MODE_MSG_TEMPLATE.format(mnemonicWithSize),
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val supportedOpSizes = findSupportedOpSizes(matchingModeIsaDataIgnoringSize, op1, op2, specialReg1 ?: specialReg2)
|
||||
return arrayOf(
|
||||
when (supportedOpSizes) {
|
||||
OP_UNSIZED ->
|
||||
manager.createProblemDescriptor(
|
||||
asmOp.operandSize ?: asmOp,
|
||||
UNSUPPORTED_SIZE_UNSIZED_MSG_TEMPLATE.format(asmOp.mnemonic),
|
||||
null as LocalQuickFix?, // TODO remove size quickfix?
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
OP_SIZE_B ->
|
||||
manager.createProblemDescriptor(
|
||||
asmOp.operandSize ?: asmOp,
|
||||
UNSUPPORTED_SIZE_BYTE_MSG,
|
||||
null as LocalQuickFix?, // TODO change size to .b?
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
OP_SIZE_W ->
|
||||
manager.createProblemDescriptor(
|
||||
asmOp.operandSize ?: asmOp,
|
||||
UNSUPPORTED_SIZE_WORD_MSG,
|
||||
null as LocalQuickFix?, // TODO change size to .w?
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
OP_SIZE_L ->
|
||||
manager.createProblemDescriptor(
|
||||
asmOp.operandSize ?: asmOp,
|
||||
UNSUPPORTED_SIZE_LONG_MSG,
|
||||
null as LocalQuickFix?, // TODO change size to .l?
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
OP_SIZE_WL ->
|
||||
manager.createProblemDescriptor(
|
||||
asmOp.operandSize ?: asmOp,
|
||||
UNSUPPORTED_SIZE_WORD_OR_LONG_MSG,
|
||||
null as LocalQuickFix?,
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
else ->
|
||||
manager.createProblemDescriptor(
|
||||
asmOp.operandSize ?: asmOp,
|
||||
UNSUPPORTED_SIZE_MSG_TEMPLATE.format(asmOp.mnemonic),
|
||||
null as LocalQuickFix?, // TODO remove size quickfix?
|
||||
ProblemHighlightType.ERROR,
|
||||
isOnTheFly
|
||||
)
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
return emptyArray()
|
||||
}
|
||||
}
|
@ -161,11 +161,17 @@ GlobalLabel ::= GLOBAL_LABEL_DEF COLON* {
|
||||
|
||||
private Label ::= LocalLabel | GlobalLabel
|
||||
|
||||
OperandSize ::= (OPSIZE_BS|OPSIZE_W|OPSIZE_L) { name = ".s|.b|.w|.l" }
|
||||
OperandSize ::= (OPSIZE_BS|OPSIZE_W|OPSIZE_L) {
|
||||
name = ".s|.b|.w|.l"
|
||||
methods = [getSize]
|
||||
}
|
||||
AddressSize ::= (OPSIZE_W|OPSIZE_L) { name = ".w|.l" }
|
||||
DataWidth ::= (OPSIZE_W|OPSIZE_L) { name = ".w|.l" }
|
||||
|
||||
AsmOp ::= MNEMONIC OperandSize?
|
||||
AsmOp ::= MNEMONIC OperandSize? {
|
||||
name = "mnemonic"
|
||||
methods = [getMnemonic getOpSize]
|
||||
}
|
||||
|
||||
PreprocessorDirective ::= Label? (DATA_DIRECTIVE | OTHER_DIRECTIVE)
|
||||
PreprocessorOperands?
|
||||
@ -174,7 +180,7 @@ MacroPlainLine ::= MACRO_LINE
|
||||
MacroNameDefinition ::= MACRO_NAME
|
||||
|
||||
MacroDefinition ::= ((MacroNameDefinition MACRO_TAG)|(MACRO_TAG MacroNameDefinition)) MacroPlainLine* MACRO_END_TAG {
|
||||
pin=1
|
||||
pin = 1
|
||||
name = "macro definition"
|
||||
implements = "de.platon42.intellij.plugins.m68k.psi.M68kNamedElement"
|
||||
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinitionMixin"
|
||||
|
@ -0,0 +1,29 @@
|
||||
package de.platon42.intellij.plugins.m68k.psi
|
||||
|
||||
import de.platon42.intellij.plugins.m68k.asm.AddressMode
|
||||
|
||||
object M68kAddressModeUtil {
|
||||
fun getAddressModeForType(addressingMode: M68kAddressingMode?): AddressMode? {
|
||||
if (addressingMode == null) return null
|
||||
return when (addressingMode) {
|
||||
is M68kImmediateData -> AddressMode.IMMEDIATE_DATA
|
||||
is M68kAddressRegisterIndirectAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT
|
||||
is M68kAddressRegisterIndirectPostIncAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_POST_INC
|
||||
is M68kAddressRegisterIndirectPreDecAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_PRE_DEC
|
||||
is M68kAddressRegisterIndirectWithDisplacementNewAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT
|
||||
is M68kAddressRegisterIndirectWithDisplacementOldAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_DISPLACEMENT
|
||||
is M68kAddressRegisterIndirectWithIndexNewAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX
|
||||
is M68kAddressRegisterIndirectWithIndexOldAddressingMode -> AddressMode.ADDRESS_REGISTER_INDIRECT_WITH_INDEX
|
||||
is M68kProgramCounterIndirectWithDisplacementNewAddressingMode -> AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT
|
||||
is M68kProgramCounterIndirectWithDisplacementOldAddressingMode -> AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_DISPLACEMENT
|
||||
is M68kProgramCounterIndirectWithIndexNewAddressingMode -> AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX
|
||||
is M68kProgramCounterIndirectWithIndexOldAddressingMode -> AddressMode.PROGRAM_COUNTER_INDIRECT_WITH_INDEX
|
||||
is M68kSpecialRegisterDirectAddressingMode -> AddressMode.SPECIAL_REGISTER_DIRECT
|
||||
is M68kDataRegisterDirectAddressingMode -> AddressMode.DATA_REGISTER_DIRECT
|
||||
is M68kAddressRegisterDirectAddressingMode -> AddressMode.ADDRESS_REGISTER_DIRECT
|
||||
is M68kRegisterListAddressingMode -> AddressMode.REGISTER_LIST
|
||||
is M68kAbsoluteAddressAddressingMode -> AddressMode.ABSOLUTE_ADDRESS
|
||||
else -> throw IllegalArgumentException("Unknown addressing mode $addressingMode")
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package de.platon42.intellij.plugins.m68k.psi
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import de.platon42.intellij.plugins.m68k.asm.*
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createGlobalLabel
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createLocalLabel
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createMacroDefinition
|
||||
@ -94,4 +95,22 @@ object M68kPsiImplUtil {
|
||||
@JvmStatic
|
||||
fun getMacroName(element: M68kMacroCall): String = element.firstChild.text
|
||||
|
||||
}
|
||||
// AsmOp
|
||||
@JvmStatic
|
||||
fun getMnemonic(element: M68kAsmOp): String = element.firstChild.text
|
||||
|
||||
@JvmStatic
|
||||
fun getOpSize(element: M68kAsmOp): Int = element.operandSize?.size ?: OP_UNSIZED
|
||||
|
||||
// OperandSize
|
||||
@JvmStatic
|
||||
fun getSize(element: M68kOperandSize): Int =
|
||||
when (element.text) {
|
||||
null -> OP_UNSIZED
|
||||
".w" -> OP_SIZE_W
|
||||
".l" -> OP_SIZE_L
|
||||
".b" -> OP_SIZE_B
|
||||
".s" -> OP_SIZE_S
|
||||
else -> throw IllegalArgumentException("Unknown op size ${element.text}")
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,9 @@
|
||||
<psi.referenceContributor implementation="de.platon42.intellij.plugins.m68k.refs.M68kReferenceContributor"/>
|
||||
<gotoSymbolContributor implementation="de.platon42.intellij.plugins.m68k.refs.M68kChooseByNameContributor"/>
|
||||
<renameInputValidator implementation="de.platon42.intellij.plugins.m68k.psi.M68kRenameInputValidator"/>
|
||||
|
||||
<localInspection implementationClass="de.platon42.intellij.plugins.m68k.inspections.M68kSyntaxInspection"
|
||||
enabledByDefault="true" level="ERROR"/>
|
||||
</extensions>
|
||||
|
||||
<actions>
|
||||
|
14
src/main/resources/inspectionDescriptions/M68kSyntax.html
Normal file
14
src/main/resources/inspectionDescriptions/M68kSyntax.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports wrong use of assembler instruction syntax.
|
||||
|
||||
The parser allows more combinations than supported by the target CPU.
|
||||
This inspection does a strict verification on the allowed addressing modes
|
||||
and operation size for each assembly mnemonic.
|
||||
<!-- tooltip end -->
|
||||
<p>Several different error messages may be the result of this verification,
|
||||
giving hints whether the first or the second addressing mode is unsupported,
|
||||
or if the operands should be swapped to make it a legal instruction.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,18 @@
|
||||
package de.platon42.intellij.plugins.m68k.inspections
|
||||
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import de.platon42.intellij.jupiter.LightCodeInsightExtension
|
||||
import de.platon42.intellij.jupiter.TestDataPath
|
||||
import de.platon42.intellij.plugins.m68k.AbstractM68kTest
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Condition
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
|
||||
@ExtendWith(LightCodeInsightExtension::class)
|
||||
@TestDataPath("src/test/resources/inspections")
|
||||
abstract class AbstractInspectionTest : AbstractM68kTest() {
|
||||
protected fun assertHighlightings(myFixture: CodeInsightTestFixture, count: Int, snippet: String) {
|
||||
assertThat(myFixture.doHighlighting())
|
||||
.areExactly(count, Condition({ it.description?.contains(snippet) ?: false }, "containing"))
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package de.platon42.intellij.plugins.m68k.inspections
|
||||
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import de.platon42.intellij.jupiter.MyFixture
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class M68kSyntaxInspectionTest : AbstractInspectionTest() {
|
||||
|
||||
@Test
|
||||
internal fun shows_error_on_instruction_with_unexpected_operands(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " rts d0")
|
||||
assertHighlightings(myFixture, 1, "No operands expected for 'rts'")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_on_instruction_with_unexpected_second_operand(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " jmp label,d0")
|
||||
assertHighlightings(myFixture, 1, "Second operand 'd0' unexpected")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_unsupported_addressing_mode_in_first_operand(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " moveq.l 123,d0")
|
||||
assertHighlightings(myFixture, 1, "Unsupported addressing mode '123' for first operand")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_unsupported_addressing_mode_in_second_operand(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " moveq.l #123,a0")
|
||||
assertHighlightings(myFixture, 1, "Unsupported addressing mode 'a0' for second operand")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_unsupported_swapped_addressing_mode(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " cmp.l d0,(a0)")
|
||||
assertHighlightings(myFixture, 1, "Unsupported addressing modes for operands in this order for 'cmp.l'")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_on_unsized_instruction_with_size(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " rts.l")
|
||||
assertHighlightings(myFixture, 1, "Instruction 'rts' is unsized")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_on_unsupported_op_size_for_b(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " btst.l #5,(a0)")
|
||||
assertHighlightings(myFixture, 1, "Operation size '.l' unsupported (should be .b)")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_on_unsupported_op_size_for_w(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " divu.b #5,d0")
|
||||
assertHighlightings(myFixture, 1, "Operation size '.b' unsupported (should be .w)")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_on_unsupported_op_size_for_l(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " moveq.w #5,d0")
|
||||
assertHighlightings(myFixture, 1, "Operation size '.w' unsupported (should be .l)")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_on_unsupported_op_size_for_w_or_l(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " addq.b #5,a0")
|
||||
assertHighlightings(myFixture, 1, "Operation size '.b' unsupported (should be .w or .l)")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_on_unsupported_op_size_for_other(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " bsr.l label")
|
||||
assertHighlightings(myFixture, 1, "Operation size '.l' unsupported")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_wrong_mode_on_instruction_with_special_reg(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " move.l usp,d0")
|
||||
assertHighlightings(myFixture, 1, "Unsupported addressing mode for 'move.l'")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_error_wrong_register_on_instruction_with_special_reg(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kSyntaxInspection::class.java)
|
||||
myFixture.configureByText("syntax.asm", " move.l vbr,a0")
|
||||
assertHighlightings(myFixture, 1, "Unsupported addressing mode for 'move.l'")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user