diff --git a/README.md b/README.md
index 800375e..b29005a 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/build.gradle b/build.gradle
index bf3f918..dc80e7d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -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 {
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.
diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java b/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java
index 06bcecd..5d37a24 100644
--- a/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java
+++ b/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java
@@ -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)) return false;
boolean r;
- Marker m = enter_section_(b);
+ Marker m = enter_section_(b, l, _NONE_, ASM_OP, "");
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;
}
diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kAsmOp.java b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kAsmOp.java
index 1f7d5be..3b8d330 100644
--- a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kAsmOp.java
+++ b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kAsmOp.java
@@ -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();
+
}
diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kOperandSize.java b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kOperandSize.java
index 62cd8c6..86a48a8 100644
--- a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kOperandSize.java
+++ b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kOperandSize.java
@@ -3,4 +3,6 @@ package de.platon42.intellij.plugins.m68k.psi;
public interface M68kOperandSize extends M68kPsiElement {
+ int getSize();
+
}
diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kAsmOpImpl.java b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kAsmOpImpl.java
index 179ce43..1dc2dfd 100644
--- a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kAsmOpImpl.java
+++ b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kAsmOpImpl.java
@@ -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);
+ }
+
}
diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kOperandSizeImpl.java b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kOperandSizeImpl.java
index 2a07c99..146db93 100644
--- a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kOperandSizeImpl.java
+++ b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kOperandSizeImpl.java
@@ -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);
+ }
+
}
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/asm/M68kIsa.kt b/src/main/java/de/platon42/intellij/plugins/m68k/asm/M68kIsa.kt
index dd5c322..7efd1e4 100644
--- a/src/main/java/de/platon42/intellij/plugins/m68k/asm/M68kIsa.kt
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/asm/M68kIsa.kt
@@ -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? = null,
+ val op2: Set? = 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 = emptyList(),
val conditionCodes: List = emptyList(),
val id: String = mnemonic,
- val opSize: String = "bWl",
val isPrivileged: Boolean = false,
- val hasOps: Boolean = true
+ val hasOps: Boolean = true,
+ val modes: List = 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 {
+ 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, op1: AddressMode?, op2: AddressMode?, opSize: Int?, specialReg: String?): List {
+ return candidates.filter {
+ it.modes.any { am ->
+ isAddressModeMatching(am, op1, op2, specialReg)
+ && ((opSize == null) || ((opSize and am.size) == opSize))
+ }
+ }
+ }
+
+ fun findMatchingOpModeIgnoringSize(candidates: List, op1: AddressMode?, op2: AddressMode?, specialReg: String?): List {
+ return candidates.filter {
+ it.modes.any { am -> isAddressModeMatching(am, op1, op2, specialReg) }
+ }
+ }
+
+ fun findSupportedOpSizes(candidates: List, 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)))
}
\ No newline at end of file
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/inspections/AbstractBaseM68kLocalInspectionTool.kt b/src/main/java/de/platon42/intellij/plugins/m68k/inspections/AbstractBaseM68kLocalInspectionTool.kt
new file mode 100644
index 0000000..98ef2a3
--- /dev/null
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/inspections/AbstractBaseM68kLocalInspectionTool.kt
@@ -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? = null
+
+ protected open fun checkAsmInstruction(asmInstruction: M68kAsmInstruction, manager: InspectionManager, isOnTheFly: Boolean): Array? =
+ null
+
+ protected open fun checkMacroCall(macroCall: M68kMacroCall, manager: InspectionManager, isOnTheFly: Boolean): Array? = null
+
+ protected open fun checkDirective(directive: M68kPreprocessorDirective, manager: InspectionManager, isOnTheFly: Boolean): Array? = null
+
+ protected open fun checkRegister(register: M68kRegister, manager: InspectionManager, isOnTheFly: Boolean): Array? = 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?) {
+ descriptors?.forEach(holder::registerProblem)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/inspections/M68kSyntaxInspection.kt b/src/main/java/de/platon42/intellij/plugins/m68k/inspections/M68kSyntaxInspection.kt
new file mode 100644
index 0000000..7e72f8b
--- /dev/null
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/inspections/M68kSyntaxInspection.kt
@@ -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? {
+ 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()
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf b/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf
index c394839..21bc3e8 100644
--- a/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf
@@ -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"
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kAddressModeUtil.kt b/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kAddressModeUtil.kt
new file mode 100644
index 0000000..93f6c02
--- /dev/null
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kAddressModeUtil.kt
@@ -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")
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt b/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt
index b754ad4..a092405 100644
--- a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt
@@ -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
-}
\ No newline at end of file
+ // 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}")
+ }
+}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 21d02f6..d743475 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -40,6 +40,9 @@
+
+
diff --git a/src/main/resources/inspectionDescriptions/M68kSyntax.html b/src/main/resources/inspectionDescriptions/M68kSyntax.html
new file mode 100644
index 0000000..901e3a8
--- /dev/null
+++ b/src/main/resources/inspectionDescriptions/M68kSyntax.html
@@ -0,0 +1,14 @@
+
+
+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.
+
+
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.
+
+
+
\ No newline at end of file
diff --git a/src/test/java/de/platon42/intellij/plugins/m68k/inspections/AbstractInspectionTest.kt b/src/test/java/de/platon42/intellij/plugins/m68k/inspections/AbstractInspectionTest.kt
new file mode 100644
index 0000000..74fdda8
--- /dev/null
+++ b/src/test/java/de/platon42/intellij/plugins/m68k/inspections/AbstractInspectionTest.kt
@@ -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"))
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/platon42/intellij/plugins/m68k/inspections/M68kSyntaxInspectionTest.kt b/src/test/java/de/platon42/intellij/plugins/m68k/inspections/M68kSyntaxInspectionTest.kt
new file mode 100644
index 0000000..52bb715
--- /dev/null
+++ b/src/test/java/de/platon42/intellij/plugins/m68k/inspections/M68kSyntaxInspectionTest.kt
@@ -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'")
+ }
+}
\ No newline at end of file