Added explicit IndexRegister-PSI-Element. Major rework to support new DocumentationProvider on registers.

When asking for documentation on registers, a code flow analysis is done.
This commit is contained in:
Chris Hodges 2021-08-02 20:54:30 +02:00
parent 55403f89a6
commit 94001c8b87
35 changed files with 619 additions and 254 deletions

View File

@ -81,6 +81,7 @@ make it work with JUnit 5. Feel free to use the code (in package ```de.platon42.
- New: Added Documentation Provider for symbol definitions (shows assigned declaration).
- New: Added Documentation Provider for mnemonics (simple version, generated out of ISA information).
- Bugfix: Macro definitions with colons and without space supported (as found in P61a source).
- New: When asking for documentation on registers, a code flow analysis is done. Cool stuff!
### V0.3 (28-Jul-21)

View File

@ -68,6 +68,7 @@ patchPluginXml {
<li>New: Added Documentation Provider for symbol definitions (shows assigned declaration).
<li>New: Added Documentation Provider for mnemonics (simple version, generated out of ISA information).
<li>Bugfix: Macro definitions with colons and without space supported (as found in P61a source).
<li>New: When asking for documentation on registers, a code flow analysis is done. Cool stuff!
</ul>
<h4>V0.3 (28-Jul-21)</h4>
<ul>

View File

@ -211,7 +211,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// ROUND_L (expr SEPARATOR)? AddressRegister SEPARATOR DataOrAddressRegister DataWidth? ROUND_R
// ROUND_L (expr SEPARATOR)? AddressRegister SEPARATOR IndexRegister ROUND_R
public static boolean AddressRegisterIndirectWithIndexNewAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexNewAddressingMode")) return false;
if (!nextTokenIsFast(b, ROUND_L)) return false;
@ -221,8 +221,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
r = r && AddressRegisterIndirectWithIndexNewAddressingMode_1(b, l + 1);
r = r && AddressRegister(b, l + 1);
r = r && consumeToken(b, SEPARATOR);
r = r && DataOrAddressRegister(b, l + 1);
r = r && AddressRegisterIndirectWithIndexNewAddressingMode_5(b, l + 1);
r = r && IndexRegister(b, l + 1);
r = r && consumeToken(b, ROUND_R);
exit_section_(b, l, m, r, false, null);
return r;
@ -246,15 +245,8 @@ public class M68kParser implements PsiParser, LightPsiParser {
return r;
}
// DataWidth?
private static boolean AddressRegisterIndirectWithIndexNewAddressingMode_5(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexNewAddressingMode_5")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */
// expr? ROUND_L AddressRegister SEPARATOR DataOrAddressRegister DataWidth? ROUND_R
// expr? ROUND_L AddressRegister SEPARATOR IndexRegister ROUND_R
public static boolean AddressRegisterIndirectWithIndexOldAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexOldAddressingMode")) return false;
boolean r;
@ -263,8 +255,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
r = r && consumeToken(b, ROUND_L);
r = r && AddressRegister(b, l + 1);
r = r && consumeToken(b, SEPARATOR);
r = r && DataOrAddressRegister(b, l + 1);
r = r && AddressRegisterIndirectWithIndexOldAddressingMode_5(b, l + 1);
r = r && IndexRegister(b, l + 1);
r = r && consumeToken(b, ROUND_R);
exit_section_(b, l, m, r, false, null);
return r;
@ -277,13 +268,6 @@ public class M68kParser implements PsiParser, LightPsiParser {
return true;
}
// DataWidth?
private static boolean AddressRegisterIndirectWithIndexOldAddressingMode_5(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "AddressRegisterIndirectWithIndexOldAddressingMode_5")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */
// OPSIZE_W|OPSIZE_L
public static boolean AddressSize(PsiBuilder b, int l) {
@ -547,6 +531,25 @@ public class M68kParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// DataOrAddressRegister DataWidth?
public static boolean IndexRegister(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "IndexRegister")) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, INDEX_REGISTER, "<index register>");
r = DataOrAddressRegister(b, l + 1);
r = r && IndexRegister_1(b, l + 1);
exit_section_(b, l, m, r, false, null);
return r;
}
// DataWidth?
private static boolean IndexRegister_1(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "IndexRegister_1")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */
// AsmInstruction | MacroCall
static boolean Instruction(PsiBuilder b, int l) {
@ -938,7 +941,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// ROUND_L (expr SEPARATOR)? PC SEPARATOR DataOrAddressRegister DataWidth? ROUND_R
// ROUND_L (expr SEPARATOR)? PC SEPARATOR IndexRegister ROUND_R
public static boolean ProgramCounterIndirectWithIndexNewAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexNewAddressingMode")) return false;
if (!nextTokenIsFast(b, ROUND_L)) return false;
@ -947,8 +950,7 @@ public class M68kParser implements PsiParser, LightPsiParser {
r = consumeTokenFast(b, ROUND_L);
r = r && ProgramCounterIndirectWithIndexNewAddressingMode_1(b, l + 1);
r = r && consumeTokens(b, 0, PC, SEPARATOR);
r = r && DataOrAddressRegister(b, l + 1);
r = r && ProgramCounterIndirectWithIndexNewAddressingMode_5(b, l + 1);
r = r && IndexRegister(b, l + 1);
r = r && consumeToken(b, ROUND_R);
exit_section_(b, l, m, r, false, null);
return r;
@ -972,23 +974,15 @@ public class M68kParser implements PsiParser, LightPsiParser {
return r;
}
// DataWidth?
private static boolean ProgramCounterIndirectWithIndexNewAddressingMode_5(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexNewAddressingMode_5")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */
// expr? ROUND_L PC SEPARATOR DataOrAddressRegister DataWidth? ROUND_R
// expr? ROUND_L PC SEPARATOR IndexRegister ROUND_R
public static boolean ProgramCounterIndirectWithIndexOldAddressingMode(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexOldAddressingMode")) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, PROGRAM_COUNTER_INDIRECT_WITH_INDEX_OLD_ADDRESSING_MODE, "<AddressingMode>");
r = ProgramCounterIndirectWithIndexOldAddressingMode_0(b, l + 1);
r = r && consumeTokens(b, 0, ROUND_L, PC, SEPARATOR);
r = r && DataOrAddressRegister(b, l + 1);
r = r && ProgramCounterIndirectWithIndexOldAddressingMode_5(b, l + 1);
r = r && IndexRegister(b, l + 1);
r = r && consumeToken(b, ROUND_R);
exit_section_(b, l, m, r, false, null);
return r;
@ -1001,13 +995,6 @@ public class M68kParser implements PsiParser, LightPsiParser {
return true;
}
// DataWidth?
private static boolean ProgramCounterIndirectWithIndexOldAddressingMode_5(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "ProgramCounterIndirectWithIndexOldAddressingMode_5")) return false;
DataWidth(b, l + 1);
return true;
}
/* ********************************************************** */
// CURRENT_PC_SYMBOL
public static boolean ProgramCounterReference(PsiBuilder b, int l) {

View File

@ -9,13 +9,10 @@ public interface M68kAddressRegisterIndirectWithIndexNewAddressingMode extends M
@NotNull
M68kAddressRegister getAddressRegister();
@NotNull
M68kIndexRegister getIndexRegister();
@Nullable
M68kExpr getDisplacement();
@NotNull
M68kRegister getIndexRegister();
@Nullable
M68kDataWidth getIndexWidth();
}

View File

@ -9,13 +9,10 @@ public interface M68kAddressRegisterIndirectWithIndexOldAddressingMode extends M
@NotNull
M68kAddressRegister getAddressRegister();
@NotNull
M68kIndexRegister getIndexRegister();
@Nullable
M68kExpr getDisplacement();
@NotNull
M68kRegister getIndexRegister();
@Nullable
M68kDataWidth getIndexWidth();
}

View File

@ -0,0 +1,17 @@
// 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 M68kIndexRegister extends M68kPsiElement {
@Nullable
M68kDataWidth getDataWidth();
@NotNull
M68kRegister getRegister();
boolean isLongWidth();
}

View File

@ -6,13 +6,10 @@ import org.jetbrains.annotations.Nullable;
public interface M68kProgramCounterIndirectWithIndexNewAddressingMode extends M68kAddressingMode, M68kWithDisplacement, M68kWithIndexRegister {
@NotNull
M68kIndexRegister getIndexRegister();
@Nullable
M68kExpr getDisplacement();
@NotNull
M68kRegister getIndexRegister();
@Nullable
M68kDataWidth getIndexWidth();
}

View File

@ -6,13 +6,10 @@ import org.jetbrains.annotations.Nullable;
public interface M68kProgramCounterIndirectWithIndexOldAddressingMode extends M68kAddressingMode, M68kWithDisplacement, M68kWithIndexRegister {
@NotNull
M68kIndexRegister getIndexRegister();
@Nullable
M68kExpr getDisplacement();
@NotNull
M68kRegister getIndexRegister();
@Nullable
M68kDataWidth getIndexWidth();
}

View File

@ -48,6 +48,7 @@ public interface M68kTypes {
IElementType EXPR = new M68kElementType("EXPR");
IElementType GLOBAL_LABEL = M68kStubElementTypeFactory.stubFactory("GLOBAL_LABEL");
IElementType IMMEDIATE_DATA = new M68kElementType("IMMEDIATE_DATA");
IElementType INDEX_REGISTER = new M68kElementType("INDEX_REGISTER");
IElementType LITERAL_EXPR = new M68kElementType("LITERAL_EXPR");
IElementType LOCAL_LABEL = new M68kElementType("LOCAL_LABEL");
IElementType MACRO_CALL = new M68kElementType("MACRO_CALL");
@ -212,6 +213,8 @@ public interface M68kTypes {
return new M68kGlobalLabelImpl(node);
} else if (type == IMMEDIATE_DATA) {
return new M68kImmediateDataImpl(node);
} else if (type == INDEX_REGISTER) {
return new M68kIndexRegisterImpl(node);
} else if (type == LITERAL_EXPR) {
return new M68kLiteralExprImpl(node);
} else if (type == LOCAL_LABEL) {

View File

@ -99,6 +99,10 @@ public class M68kVisitor extends PsiElementVisitor {
visitAddressingMode(o);
}
public void visitIndexRegister(@NotNull M68kIndexRegister o) {
visitPsiElement(o);
}
public void visitLocalLabel(@NotNull M68kLocalLabel o) {
visitNamedElement(o);
}

View File

@ -31,22 +31,16 @@ public class M68kAddressRegisterIndirectWithIndexNewAddressingModeImpl extends M
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kAddressRegister.class));
}
@Override
@NotNull
public M68kIndexRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kIndexRegister.class));
}
@Override
@Nullable
public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
}
@Override
@NotNull
public M68kRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class));
}
@Override
@Nullable
public M68kDataWidth getIndexWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
}

View File

@ -31,22 +31,16 @@ public class M68kAddressRegisterIndirectWithIndexOldAddressingModeImpl extends M
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kAddressRegister.class));
}
@Override
@NotNull
public M68kIndexRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kIndexRegister.class));
}
@Override
@Nullable
public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
}
@Override
@NotNull
public M68kRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class));
}
@Override
@Nullable
public M68kDataWidth getIndexWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
}

View File

@ -0,0 +1,45 @@
// This is a generated file. Not intended for manual editing.
package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class M68kIndexRegisterImpl extends ASTWrapperPsiElement implements M68kIndexRegister {
public M68kIndexRegisterImpl(@NotNull ASTNode node) {
super(node);
}
public void accept(@NotNull M68kVisitor visitor) {
visitor.visitIndexRegister(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof M68kVisitor) accept((M68kVisitor) visitor);
else super.accept(visitor);
}
@Override
@Nullable
public M68kDataWidth getDataWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
@Override
@NotNull
public M68kRegister getRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class));
}
@Override
public boolean isLongWidth() {
return M68kPsiImplUtil.isLongWidth(this);
}
}

View File

@ -4,7 +4,10 @@ package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*;
import de.platon42.intellij.plugins.m68k.psi.M68kExpr;
import de.platon42.intellij.plugins.m68k.psi.M68kIndexRegister;
import de.platon42.intellij.plugins.m68k.psi.M68kProgramCounterIndirectWithIndexNewAddressingMode;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -25,22 +28,16 @@ public class M68kProgramCounterIndirectWithIndexNewAddressingModeImpl extends M6
else super.accept(visitor);
}
@Override
@NotNull
public M68kIndexRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kIndexRegister.class));
}
@Override
@Nullable
public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
}
@Override
@NotNull
public M68kRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class));
}
@Override
@Nullable
public M68kDataWidth getIndexWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
}

View File

@ -4,7 +4,10 @@ package de.platon42.intellij.plugins.m68k.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*;
import de.platon42.intellij.plugins.m68k.psi.M68kExpr;
import de.platon42.intellij.plugins.m68k.psi.M68kIndexRegister;
import de.platon42.intellij.plugins.m68k.psi.M68kProgramCounterIndirectWithIndexOldAddressingMode;
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -25,22 +28,16 @@ public class M68kProgramCounterIndirectWithIndexOldAddressingModeImpl extends M6
else super.accept(visitor);
}
@Override
@NotNull
public M68kIndexRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kIndexRegister.class));
}
@Override
@Nullable
public M68kExpr getDisplacement() {
return PsiTreeUtil.getChildOfType(this, M68kExpr.class);
}
@Override
@NotNull
public M68kRegister getIndexRegister() {
return notNullChild(PsiTreeUtil.getChildOfType(this, M68kRegister.class));
}
@Override
@Nullable
public M68kDataWidth getIndexWidth() {
return PsiTreeUtil.getChildOfType(this, M68kDataWidth.class);
}
}

View File

@ -10,7 +10,7 @@ class M68kFileElementType private constructor() : ILightStubFileElementType<PsiF
@JvmField
val INSTANCE = M68kFileElementType()
const val STUB_VERSION = 4
const val STUB_VERSION = 5
const val STUB_EXTERNAL_ID_PREFIX = "MC68000."
const val EXTERNAL_ID = STUB_EXTERNAL_ID_PREFIX + "FILE"
}

View File

@ -28,7 +28,7 @@ enum class Register(val regname: String, val num: Int) {
A7("a7", 7);
companion object {
private val NAME_TO_REG_MAP = values().associateBy { it.regname }
private val NAME_TO_REG_MAP = values().associateBy { it.regname }.plus("sp" to A7)
fun getRegFromName(regname: String) = NAME_TO_REG_MAP[regname.lowercase()]!!
}
@ -60,56 +60,58 @@ 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)
const val RWM_READ_OPSIZE = 0x10
const val RWM_READ_B = 0x11
const val RWM_READ_W = 0x12
const val RWM_READ_L = 0x13
const val RWM_OP_MASK = 0xfff
const val RWM_SIZE_MASK = 0x00e
const val RWM_SET_OPSIZE = 0x20
const val RWM_SET_B = 0x21
const val RWM_SET_W = 0x22
const val RWM_SET_L = 0x23
const val RWM_SET_OPSIZE = 0x008
const val RWM_SET_B = 0x009
const val RWM_SET_W = 0x00b
const val RWM_SET_L = 0x00f
const val RWM_MODIFY_OPSIZE = 0x30
const val RWM_MODIFY_B = 0x31
const val RWM_MODIFY_W = 0x32
const val RWM_MODIFY_L = 0x33
const val RWM_READ_OPSIZE = 0x800
const val RWM_READ_B = 0x900
const val RWM_READ_W = 0xb00
const val RWM_READ_L = 0xf00
const val RWM_MODIFY_OPSIZE = 0x880
const val RWM_MODIFY_B = 0x990
const val RWM_MODIFY_W = 0xbb0
const val RWM_MODIFY_L = 0xff0
const val RWM_OP_MASK = 0xff
const val RWM_OP1_SHIFT = 0
const val RWM_OP2_SHIFT = 8
const val RWM_OP2_SHIFT = 12
const val RWM_READ_OP1_OPSIZE = RWM_READ_OPSIZE shl RWM_OP1_SHIFT
const val RWM_READ_OP1_B = RWM_READ_B shl RWM_OP1_SHIFT
const val RWM_READ_OP1_W = RWM_READ_W shl RWM_OP1_SHIFT
const val RWM_READ_OP1_L = RWM_READ_L shl RWM_OP1_SHIFT
const val RWM_SET_OP1_OPSIZE = RWM_SET_OPSIZE shl RWM_OP1_SHIFT
const val RWM_SET_OP1_B = RWM_SET_B shl RWM_OP1_SHIFT
const val RWM_SET_OP1_W = RWM_SET_W shl RWM_OP1_SHIFT
const val RWM_SET_OP1_L = RWM_SET_L shl RWM_OP1_SHIFT
const val RWM_MODIFY_OP1_OPSIZE = RWM_MODIFY_OPSIZE shl RWM_OP1_SHIFT
const val RWM_MODIFY_OP1_B = RWM_MODIFY_B shl RWM_OP1_SHIFT
const val RWM_MODIFY_OP1_W = RWM_MODIFY_W shl RWM_OP1_SHIFT
const val RWM_MODIFY_OP1_L = RWM_MODIFY_L shl RWM_OP1_SHIFT
const val RWM_SET_OP1_OPSIZE = RWM_SET_OPSIZE shl RWM_OP1_SHIFT
const val RWM_SET_OP1_B = RWM_SET_B shl RWM_OP1_SHIFT
const val RWM_SET_OP1_W = RWM_SET_W shl RWM_OP1_SHIFT
const val RWM_SET_OP1_L = RWM_SET_L shl RWM_OP1_SHIFT
const val RWM_READ_OP2_OPSIZE = RWM_READ_OPSIZE shl RWM_OP2_SHIFT
const val RWM_READ_OP2_B = RWM_READ_B shl RWM_OP2_SHIFT
const val RWM_READ_OP2_W = RWM_READ_W shl RWM_OP2_SHIFT
const val RWM_READ_OP2_L = RWM_READ_L shl RWM_OP2_SHIFT
const val RWM_SET_OP2_OPSIZE = RWM_SET_OPSIZE shl RWM_OP2_SHIFT
const val RWM_SET_OP2_B = RWM_SET_B shl RWM_OP2_SHIFT
const val RWM_SET_OP2_W = RWM_SET_W shl RWM_OP2_SHIFT
const val RWM_SET_OP2_L = RWM_SET_L shl RWM_OP2_SHIFT
const val RWM_MODIFY_OP2_OPSIZE = RWM_MODIFY_OPSIZE shl RWM_OP2_SHIFT
const val RWM_MODIFY_OP2_B = RWM_MODIFY_B shl RWM_OP2_SHIFT
const val RWM_MODIFY_OP2_W = RWM_MODIFY_W shl RWM_OP2_SHIFT
const val RWM_MODIFY_OP2_L = RWM_MODIFY_L shl RWM_OP2_SHIFT
const val RWM_MODIFY_STACK = 0x10000
const val RWM_SET_OP2_OPSIZE = RWM_SET_OPSIZE shl RWM_OP2_SHIFT
const val RWM_SET_OP2_B = RWM_SET_B shl RWM_OP2_SHIFT
const val RWM_SET_OP2_W = RWM_SET_W shl RWM_OP2_SHIFT
const val RWM_SET_OP2_L = RWM_SET_L shl RWM_OP2_SHIFT
const val RWM_MODIFY_STACK = 0x1000000
data class AllowedAdrMode(
val op1: Set<AddressMode>? = null,

View File

@ -36,17 +36,17 @@ class M68kInstructionDocumentationProvider : AbstractDocumentationProvider() {
val defBuilder = createDefinition(isaData)
builder.append(defBuilder.wrapWith(DocumentationMarkup.DEFINITION_ELEMENT))
val bindingRows = HtmlBuilder()
val mnemonicInfoRows = HtmlBuilder()
val headerCells = listOf(
HtmlChunk.text("Mnemonic").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL),
HtmlChunk.text("Op1").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL),
HtmlChunk.text("Op2").wrapWith(DocumentationMarkup.SECTION_HEADER_CELL)
)
bindingRows.append(HtmlChunk.tag("tr").children(headerCells))
mnemonicInfoRows.append(HtmlChunk.tag("tr").children(headerCells))
isaData.modes.forEach { allowedAdrMode ->
val mnemonics = findOpSizeDescriptions(allowedAdrMode.size)
.map { HtmlChunk.text(isaData.mnemonic + it).wrapWith(HtmlChunk.p()) }
bindingRows.append(
.map { HtmlChunk.text(isaData.mnemonic + it).wrapWith(HtmlChunk.div()) }
mnemonicInfoRows.append(
HtmlChunk.tag("tr").children(
DocumentationMarkup.SECTION_CONTENT_CELL.children(mnemonics),
DocumentationMarkup.SECTION_CONTENT_CELL.child(collectAddressModes(allowedAdrMode.op1)),
@ -56,7 +56,7 @@ class M68kInstructionDocumentationProvider : AbstractDocumentationProvider() {
}
val contentBuilder = HtmlBuilder()
contentBuilder.append(bindingRows.br().wrapWith(DocumentationMarkup.SECTIONS_TABLE))
contentBuilder.append(mnemonicInfoRows.wrapWith(DocumentationMarkup.SECTIONS_TABLE))
builder.append(contentBuilder.wrapWith(DocumentationMarkup.CONTENT_ELEMENT))
}
@ -77,7 +77,7 @@ class M68kInstructionDocumentationProvider : AbstractDocumentationProvider() {
val defBuilder = HtmlBuilder()
defBuilder.append(HtmlChunk.text(isaData.description).bold().wrapWith("pre"))
if (isaData.isPrivileged) {
defBuilder.append(HtmlChunk.font("red").addText("(privileged)").wrapWith("p"))
defBuilder.append(HtmlChunk.font("red").addText("(privileged)").wrapWith(HtmlChunk.p()))
}
return defBuilder
}
@ -86,7 +86,7 @@ class M68kInstructionDocumentationProvider : AbstractDocumentationProvider() {
if (addressModes == null) return HtmlChunk.text("")
val modes = HtmlBuilder()
addressModes.sortedBy(AddressMode::ordinal)
.forEach { modes.append(HtmlChunk.text(it.syntax).wrapWith(HtmlChunk.p())) }
.forEach { modes.append(HtmlChunk.text(it.syntax).wrapWith(HtmlChunk.div())) }
return modes.toFragment()
}

View File

@ -1,34 +1,209 @@
package de.platon42.intellij.plugins.m68k.documentation
import com.intellij.lang.documentation.AbstractDocumentationProvider
import com.intellij.lang.documentation.DocumentationMarkup
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.text.HtmlBuilder
import com.intellij.openapi.util.text.HtmlChunk
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.m68k.asm.RWM_OP1_SHIFT
import de.platon42.intellij.plugins.m68k.asm.RWM_OP2_SHIFT
import de.platon42.intellij.plugins.m68k.asm.*
import de.platon42.intellij.plugins.m68k.asm.Register.Companion.getRegFromName
import de.platon42.intellij.plugins.m68k.psi.M68kAddressRegister
import de.platon42.intellij.plugins.m68k.psi.M68kAddressingMode
import de.platon42.intellij.plugins.m68k.psi.M68kAsmInstruction
import de.platon42.intellij.plugins.m68k.psi.M68kDataRegister
import de.platon42.intellij.plugins.m68k.psi.*
import de.platon42.intellij.plugins.m68k.psi.M68kAddressModeUtil.getOtherReadWriteModifyRegisters
import de.platon42.intellij.plugins.m68k.psi.M68kAddressModeUtil.getReadWriteModifyRegisters
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.findExactIsaDataAndAllowedAdrModeForInstruction
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.getOpSizeOrDefault
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.modifyRwmWithOpsize
class M68kRegisterFlowDocumentationProvider : AbstractDocumentationProvider() {
override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? {
if (element is M68kDataRegister || element is M68kAddressRegister) {
val register = getRegFromName(element.text)
val addressingMode = PsiTreeUtil.getParentOfType(element, M68kAddressingMode::class.java) ?: return null
val asmInstruction = PsiTreeUtil.getParentOfType(addressingMode, M68kAsmInstruction::class.java) ?: return null
val (isaData, adrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(asmInstruction) ?: return "unknown instruction"
val opShift = if (asmInstruction.addressingModeList[0] == addressingMode) RWM_OP1_SHIFT else RWM_OP2_SHIFT
val cursorInstRwmRegs = evaluateRegisterUse(asmInstruction, adrMode, register)
val opSize = getOpSizeOrDefault(asmInstruction.asmOp.opSize, adrMode)
return register.regname
val rn = register.regname
val thisInfo = cursorInstRwmRegs
.joinToString(separator = ", ", prefix = "${isaData.mnemonic} instruction ") {
rwmToDisplayText(it, rn)
}
val totalRwm = cursorInstRwmRegs.reduce(Int::or)
val firstOp = asmInstruction.addressingModeList[0] == addressingMode
val cursorRwm = modifyRwmWithOpsize((adrMode.modInfo ushr if (firstOp) RWM_OP1_SHIFT else RWM_OP2_SHIFT) and RWM_OP_MASK, opSize)
val analysisBuilder = HtmlBuilder()
val missingBits = if (cursorRwm and RWM_SET_L != 0) {
if (totalRwm and RWM_SET_L == RWM_SET_L) {
analysisBuilder.append(HtmlChunk.text("Register result is fully defined by this instruction."))
0
} else {
(RWM_SET_L and RWM_SIZE_MASK) and totalRwm.inv()
}
} else {
(RWM_SET_L and RWM_SIZE_MASK) and ((cursorRwm and RWM_MODIFY_L) ushr 8)
}
val backtrace: MutableList<HtmlChunk> = ArrayList()
val initialStatement: M68kStatement = asmInstruction.parent as M68kStatement
if (missingBits > 0) {
val localLabelName = PsiTreeUtil.findChildOfType(initialStatement, M68kLocalLabel::class.java)?.name ?: ""
backtrace.add(
HtmlChunk.tag("tr")
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.text(localLabelName)))
.children(highlightRegister(asmInstruction, register).bold().wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL))
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.text(" ; <--")))
)
}
backtrace.addAll(analyseFlow(register, missingBits, true, initialStatement) { PsiTreeUtil.getPrevSiblingOfType(it, M68kStatement::class.java) })
backtrace.reverse()
val traceBits = (cursorRwm or (cursorRwm ushr 8)) and RWM_SIZE_MASK
backtrace.addAll(analyseFlow(register, traceBits, false, initialStatement) { PsiTreeUtil.getNextSiblingOfType(it, M68kStatement::class.java) })
val statementRows = HtmlBuilder()
backtrace.forEach(statementRows::append)
val builder = HtmlBuilder()
builder.append(HtmlChunk.text(thisInfo).wrapWith(DocumentationMarkup.DEFINITION_ELEMENT))
builder.append(statementRows.wrapWith(DocumentationMarkup.SECTIONS_TABLE.style("padding-left: 8pt; padding-right: 8pt")))
builder.append(analysisBuilder.wrapWith(DocumentationMarkup.CONTENT_ELEMENT))
return builder.toString()
}
return null
}
private fun analyseFlow(
register: Register,
rwmBits: Int,
globalLabelBreaksOnInitialStatement: Boolean,
startingStatement: M68kStatement,
direction: (statement: M68kStatement) -> M68kStatement?
): MutableList<HtmlChunk> {
var missingBits = rwmBits
var currStatement = startingStatement
val backtrace: MutableList<HtmlChunk> = ArrayList()
val rn = register.regname
var addAbrevDots = false
while (missingBits > 0) {
val globalLabel = PsiTreeUtil.findChildOfType(currStatement, M68kGlobalLabel::class.java)
if ((globalLabel != null) && (globalLabelBreaksOnInitialStatement || (currStatement !== startingStatement))) {
backtrace.add(
HtmlChunk.tag("tr")
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.text(globalLabel.name!!).bold()))
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.nbsp()))
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.nbsp()))
)
break
}
currStatement = direction.invoke(currStatement) ?: break
val currAsmInstruction = PsiTreeUtil.getChildOfType(currStatement, M68kAsmInstruction::class.java) ?: continue
if (checkIfInstructionUsesRegister(currAsmInstruction, register)) {
if (addAbrevDots) {
backtrace.add(
HtmlChunk.tag("tr")
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.nbsp()))
.children(
DocumentationMarkup.SECTION_CONTENT_CELL.child(
HtmlChunk.text("[...]").wrapWith(HtmlChunk.div().attr("class", "grayed"))
)
)
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.nbsp()))
)
}
addAbrevDots = false
val (_, currAdrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(currAsmInstruction) ?: continue
val localLabelName = PsiTreeUtil.findChildOfType(currStatement, M68kLocalLabel::class.java)?.name ?: ""
val currRwms = evaluateRegisterUse(currAsmInstruction, currAdrMode, register)
val currTotalRwm = currRwms.reduce(Int::or)
if ((currTotalRwm and RWM_SET_L) > 0) {
missingBits = missingBits and currTotalRwm.inv()
}
val lineInfo = currRwms
.map {
val text = HtmlChunk.text(rwmToDisplayText(it, rn))
if ((missingBits and it) > 0) text.bold() else text.italic()
}
val lineBuilder = HtmlBuilder()
lineBuilder.append(" ; ")
lineBuilder.appendWithSeparators(HtmlChunk.text(", "), lineInfo)
.wrapWith(HtmlChunk.div())
backtrace.add(
HtmlChunk.tag("tr")
.children(DocumentationMarkup.SECTION_CONTENT_CELL.child(HtmlChunk.text(localLabelName)))
.children(highlightRegister(currAsmInstruction, register).wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL))
.children(lineBuilder.wrapWith(DocumentationMarkup.SECTION_CONTENT_CELL))
)
} else {
addAbrevDots = true
}
}
return backtrace
}
private fun highlightRegister(currAsmInstruction: M68kAsmInstruction, register: Register): HtmlChunk {
val builder = HtmlBuilder()
val plainText = currAsmInstruction.text
var startPos = 0
val rn = if (register == Register.A7) listOf(register.regname, "sp") else listOf(register.regname)
do {
val indexPos = plainText.indexOfAny(rn, startPos, ignoreCase = true)
if (indexPos >= 0) {
builder.append(HtmlChunk.text(plainText.substring(startPos until indexPos)))
startPos = indexPos + register.regname.length
builder.append(HtmlChunk.text(plainText.substring(indexPos until startPos)).wrapWith(HtmlChunk.font("red")))
} else {
builder.append(HtmlChunk.text(plainText.substring(startPos)))
}
} while (indexPos >= 0)
return builder.toFragment().code()
}
private fun rwmToDisplayText(rwm: Int, rn: String) =
when (rwm) {
RWM_READ_B -> "reads $rn.b"
RWM_READ_W -> "reads $rn.w"
RWM_READ_L -> "reads $rn.l"
RWM_MODIFY_B -> "modifies $rn.b"
RWM_MODIFY_W -> "modifies $rn.w"
RWM_MODIFY_L -> "modifies $rn.l"
RWM_SET_B -> "sets $rn.b"
RWM_SET_W -> "sets $rn.w"
RWM_SET_L -> "sets $rn.l"
else -> "uhm?"
}
private fun evaluateRegisterUse(
asmInstruction: M68kAsmInstruction,
adrMode: AllowedAdrMode,
register: Register
): List<Int> {
val opSize = getOpSizeOrDefault(asmInstruction.asmOp.opSize, adrMode)
val rwm1 = modifyRwmWithOpsize((adrMode.modInfo ushr RWM_OP1_SHIFT) and RWM_OP_MASK, opSize)
val rwm2 = if (asmInstruction.addressingModeList.size > 1) modifyRwmWithOpsize((adrMode.modInfo ushr RWM_OP2_SHIFT) and RWM_OP_MASK, opSize) else 0
return getReadWriteModifyRegisters(asmInstruction.addressingModeList[0], rwm1).asSequence()
.plus(getReadWriteModifyRegisters(asmInstruction.addressingModeList.getOrNull(1), rwm2))
.plus(getOtherReadWriteModifyRegisters(adrMode.modInfo))
.filter { it.first == register }
.map { it.second }
.toList()
}
private fun checkIfInstructionUsesRegister(instruction: M68kAsmInstruction, register: Register): Boolean {
if (instruction.addressingModeList.isEmpty()) {
return false
}
return instruction.addressingModeList.any { aml -> getReadWriteModifyRegisters(aml, 0).any { it.first == register } }
}
override fun getCustomDocumentationElement(editor: Editor, file: PsiFile, contextElement: PsiElement?, targetOffset: Int): PsiElement? {
if (contextElement == null) return null
if (contextElement is M68kDataRegister || contextElement is M68kAddressRegister) return contextElement

View File

@ -234,6 +234,14 @@ Register ::= DataRegister | AddressRegister | SpecialRegister
private DataOrAddressRegister ::= DataRegister | AddressRegister { name = "data or address register"}
IndexRegister ::= DataOrAddressRegister DataWidth?
{
name = "index register"
methods = [
isLongWidth
]
}
AddressingMode ::= ImmediateData
| AddressRegisterIndirectPreDecAddressingMode
| AddressRegisterIndirectPostIncAddressingMode
@ -279,7 +287,7 @@ AddressRegisterIndirectWithDisplacementNewAddressingMode ::= ROUND_L expr SEPARA
]
}
AddressRegisterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L AddressRegister SEPARATOR DataOrAddressRegister DataWidth? ROUND_R
AddressRegisterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L AddressRegister SEPARATOR IndexRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect"
@ -288,12 +296,10 @@ AddressRegisterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L AddressRegis
]
methods = [
displacement = "expr"
indexRegister = "Register"
indexWidth = "DataWidth"
]
}
AddressRegisterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? AddressRegister SEPARATOR DataOrAddressRegister DataWidth? ROUND_R
AddressRegisterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? AddressRegister SEPARATOR IndexRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithAddressRegisterIndirect"
@ -302,8 +308,6 @@ AddressRegisterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)?
]
methods = [
displacement = "expr"
indexRegister = "Register"
indexWidth = "DataWidth"
]
}
@ -323,7 +327,7 @@ ProgramCounterIndirectWithDisplacementNewAddressingMode ::= ROUND_L expr SEPARAT
]
}
ProgramCounterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L PC SEPARATOR DataOrAddressRegister DataWidth? ROUND_R
ProgramCounterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L PC SEPARATOR IndexRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"
@ -331,12 +335,10 @@ ProgramCounterIndirectWithIndexOldAddressingMode ::= expr? ROUND_L PC SEPARATOR
]
methods = [
displacement = "expr"
indexRegister = "Register"
indexWidth = "DataWidth"
]
}
ProgramCounterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? PC SEPARATOR DataOrAddressRegister DataWidth? ROUND_R
ProgramCounterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? PC SEPARATOR IndexRegister ROUND_R
{
implements = [
"de.platon42.intellij.plugins.m68k.psi.M68kWithDisplacement"
@ -344,8 +346,6 @@ ProgramCounterIndirectWithIndexNewAddressingMode ::= ROUND_L (expr SEPARATOR)? P
]
methods = [
displacement = "expr"
indexRegister = "Register"
indexWidth = "DataWidth"
]
}

View File

@ -27,31 +27,46 @@ object M68kAddressModeUtil {
}
}
fun getReadWriteModifyRegisters(addressingMode: M68kAddressingMode?, rwm: Int): Set<Pair<Register, Int>> {
if (addressingMode == null) return emptySet()
fun getOtherReadWriteModifyRegisters(rwm: Int): List<Pair<Register, Int>> {
if (rwm and RWM_MODIFY_STACK > 0) {
return listOf(Register.A7 to RWM_MODIFY_L)
}
return emptyList()
}
fun getReadWriteModifyRegisters(addressingMode: M68kAddressingMode?, rwm: Int): List<Pair<Register, Int>> {
if (addressingMode == null) return emptyList()
return when (addressingMode) {
is M68kImmediateData -> emptySet()
is M68kAddressRegisterIndirectPostIncAddressingMode -> setOf(Register.getRegFromName(addressingMode.addressRegister.text) to RWM_MODIFY_OP1_L)
is M68kAddressRegisterIndirectPreDecAddressingMode -> setOf(Register.getRegFromName(addressingMode.addressRegister.text) to RWM_MODIFY_OP1_L)
is M68kImmediateData,
is M68kSpecialRegisterDirectAddressingMode,
is M68kProgramCounterIndirectWithDisplacementNewAddressingMode,
is M68kProgramCounterIndirectWithDisplacementOldAddressingMode,
is M68kAbsoluteAddressAddressingMode -> emptyList()
is M68kAddressRegisterIndirectPostIncAddressingMode -> listOf(Register.getRegFromName(addressingMode.addressRegister.text) to RWM_MODIFY_L)
is M68kAddressRegisterIndirectPreDecAddressingMode -> listOf(Register.getRegFromName(addressingMode.addressRegister.text) to RWM_MODIFY_L)
is M68kWithAddressRegisterIndirect -> {
if (addressingMode is M68kWithIndexRegister) {
setOf(
Register.getRegFromName(addressingMode.addressRegister.text) to RWM_READ_OP1_L,
Register.getRegFromName(addressingMode.indexRegister.text) to if (addressingMode.hasLongWidth()) RWM_READ_OP1_L else RWM_READ_OP1_W
listOf(
Register.getRegFromName(addressingMode.addressRegister.text) to RWM_READ_L,
Register.getRegFromName(addressingMode.indexRegister.register.text) to if (addressingMode.indexRegister.isLongWidth) RWM_READ_L else RWM_READ_W
)
} else {
setOf(Register.getRegFromName(addressingMode.addressRegister.text) to RWM_READ_OP1_L)
listOf(Register.getRegFromName(addressingMode.addressRegister.text) to RWM_READ_L)
}
}
is M68kWithIndexRegister -> setOf(Register.getRegFromName(addressingMode.indexRegister.text) to if (addressingMode.hasLongWidth()) RWM_READ_OP1_L else RWM_READ_OP1_W)
is M68kProgramCounterIndirectWithDisplacementNewAddressingMode -> emptySet()
is M68kProgramCounterIndirectWithDisplacementOldAddressingMode -> emptySet()
is M68kSpecialRegisterDirectAddressingMode -> emptySet()
is M68kDataRegisterDirectAddressingMode -> setOf(Register.getRegFromName(addressingMode.dataRegister.text) to rwm)
is M68kAddressRegisterDirectAddressingMode -> setOf(Register.getRegFromName(addressingMode.addressRegister.text) to rwm)
is M68kRegisterListAddressingMode -> addressingMode.registers.map { it to rwm }.toSet()
is M68kAbsoluteAddressAddressingMode -> emptySet()
is M68kWithIndexRegister -> listOf(Register.getRegFromName(addressingMode.indexRegister.register.text) to if (addressingMode.indexRegister.isLongWidth) RWM_READ_L else RWM_READ_W)
is M68kDataRegisterDirectAddressingMode -> listOf(Register.getRegFromName(addressingMode.dataRegister.text) to rwm)
is M68kAddressRegisterDirectAddressingMode -> listOf(Register.getRegFromName(addressingMode.addressRegister.text) to rwm)
is M68kRegisterListAddressingMode -> addressingMode.registers.map { it to rwm }
else -> throw IllegalArgumentException("Unknown addressing mode $addressingMode")
}
}
fun mergeReadWriteModifyRegisters(regset: Set<Pair<Register, Int>>): Set<Pair<Register, Int>> {
if (regset.size <= 1) return regset
return regset.groupBy({ it.first }) { it.second }
.map { it.key to if (it.value.size == 1) it.value.single() else it.value.reduce(Int::or) }
.toSet()
}
}

View File

@ -134,4 +134,10 @@ object M68kPsiImplUtil {
}
return registers
}
// IndexRegister
@JvmStatic
fun isLongWidth(element: M68kIndexRegister): Boolean {
return element.dataWidth?.text.equals(".l", ignoreCase = true)
}
}

View File

@ -1,6 +1,6 @@
package de.platon42.intellij.plugins.m68k.psi
interface M68kWithAddressRegisterIndirect {
interface M68kWithAddressRegisterIndirect : M68kAddressingMode {
val addressRegister: M68kAddressRegister
}

View File

@ -1,6 +1,6 @@
package de.platon42.intellij.plugins.m68k.psi
interface M68kWithDisplacement {
interface M68kWithDisplacement : M68kAddressingMode {
val displacement: M68kExpr?
}

View File

@ -1,12 +1,6 @@
package de.platon42.intellij.plugins.m68k.psi
interface M68kWithIndexRegister {
interface M68kWithIndexRegister : M68kAddressingMode {
val indexRegister: M68kRegister
val indexWidth: M68kDataWidth?
fun hasLongWidth(): Boolean {
return indexWidth?.text.equals(".l", ignoreCase = true)
}
val indexRegister: M68kIndexRegister
}

View File

@ -34,6 +34,42 @@ object M68kIsaUtil {
return matchedIsaData.map { it to M68kIsa.findMatchingAddressMode(it.modes, op1, op2, opSize, specialReg) }
}
fun getOpSizeOrDefault(opSize: Int, adrMode: AllowedAdrMode): Int {
if (opSize == OP_UNSIZED && (adrMode.size != OP_UNSIZED)) {
return if ((adrMode.size and OP_SIZE_W) == OP_SIZE_W) {
OP_SIZE_W
} else {
adrMode.size
}
}
return opSize
}
fun modifyRwmWithOpsize(rwm: Int, opSize: Int): Int {
if (opSize == OP_UNSIZED) return rwm
return when (rwm) {
RWM_READ_OPSIZE -> when (opSize) {
OP_SIZE_B -> RWM_READ_B
OP_SIZE_W -> RWM_READ_W
OP_SIZE_L -> RWM_READ_L
else -> rwm
}
RWM_MODIFY_OPSIZE -> when (opSize) {
OP_SIZE_B -> RWM_MODIFY_B
OP_SIZE_W -> RWM_MODIFY_W
OP_SIZE_L -> RWM_MODIFY_L
else -> rwm
}
RWM_SET_OPSIZE -> when (opSize) {
OP_SIZE_B -> RWM_SET_B
OP_SIZE_W -> RWM_SET_W
OP_SIZE_L -> RWM_SET_L
else -> rwm
}
else -> rwm
}
}
fun findOpSizeDescription(opSize: Int): String {
return when (opSize) {
OP_UNSIZED -> ""
@ -48,17 +84,17 @@ object M68kIsaUtil {
}
}
fun findOpSizeDescriptions(opSize: Int): Set<String> {
fun findOpSizeDescriptions(opSize: Int): List<String> {
return when (opSize) {
OP_UNSIZED -> setOf("")
OP_SIZE_B -> setOf(".b")
OP_SIZE_W -> setOf(".w")
OP_SIZE_L -> setOf(".l")
OP_SIZE_S -> setOf(".s")
OP_SIZE_BWL -> setOf(".b", ".w", ".l")
OP_SIZE_WL -> setOf(".w", ".l")
OP_SIZE_SBW -> setOf(".s", ".b", ".w")
else -> setOf("?")
OP_UNSIZED -> listOf("")
OP_SIZE_B -> listOf(".b")
OP_SIZE_W -> listOf(".w")
OP_SIZE_L -> listOf(".l")
OP_SIZE_S -> listOf(".s")
OP_SIZE_BWL -> listOf(".b", ".w", ".l")
OP_SIZE_WL -> listOf(".w", ".l")
OP_SIZE_SBW -> listOf(".s", ".b", ".w")
else -> listOf("?")
}
}
}

View File

@ -17,8 +17,10 @@ internal class M68kInstructionDocumentationProviderTest : AbstractDocumentationP
mo<caret>veq.l #40,d0
"""
)
assertThat(generateDocumentation(myFixture)).isEqualTo(
"""<div class="definition"><pre><b>Move Quick</b></pre></div><div class="content"><table class="sections"><tr><td class="section" valign="top">Mnemonic</td><td class="section" valign="top">Op1</td><td class="section" valign="top">Op2</td></tr><tr><td valign="top"><p>moveq.l</p></td><td valign="top"><p>#&lt;xxx&gt;</p></td><td valign="top"><p>Dn</p></td></tr><br/></table></div>"""
assertThat(generateDocumentation(myFixture)).isEqualToIgnoringWhitespace(
"""
<div class="definition"><pre><b>Move Quick</b></pre></div><div class="content"><table class="sections"><tr><td class="section" valign="top">Mnemonic</td><td class="section" valign="top">Op1</td><td class="section" valign="top">Op2</td></tr><tr><td valign="top"><div>moveq.l</div></td><td valign="top"><div>#&lt;xxx&gt;</div></td><td valign="top"><div>Dn</div></td></tr></table></div>
"""
)
}
@ -29,8 +31,32 @@ internal class M68kInstructionDocumentationProviderTest : AbstractDocumentationP
bra.<caret>s label
"""
)
assertThat(generateDocumentation(myFixture)).isEqualTo(
"""<div class="definition"><pre><b>Branch</b></pre></div><div class="content"><table class="sections"><tr><td class="section" valign="top">Mnemonic</td><td class="section" valign="top">Op1</td><td class="section" valign="top">Op2</td></tr><tr><td valign="top"><p>bra.s</p><p>bra.b</p><p>bra.w</p></td><td valign="top"><p>(xxx).w|l</p></td><td valign="top"></td></tr><br/></table></div>"""
assertThat(generateDocumentation(myFixture)).isEqualToIgnoringWhitespace(
"""
<div class="definition">
<pre><b>Branch</b></pre>
</div>
<div class="content">
<table class="sections">
<tr>
<td class="section" valign="top">Mnemonic</td>
<td class="section" valign="top">Op1</td>
<td class="section" valign="top">Op2</td>
</tr>
<tr>
<td valign="top">
<div>bra.s</div>
<div>bra.b</div>
<div>bra.w</div>
</td>
<td valign="top">
<div>(xxx).w|l</div>
</td>
<td valign="top"></td>
</tr>
</table>
</div>
"""
)
}
@ -41,9 +67,7 @@ internal class M68kInstructionDocumentationProviderTest : AbstractDocumentationP
<caret>reset
"""
)
assertThat(generateDocumentation(myFixture)).isEqualTo(
"""<div class="definition"><pre><b>Reset External Devices</b></pre><p><font color="red">(privileged)</font></p></div><div class="content"><table class="sections"><tr><td class="section" valign="top">Mnemonic</td><td class="section" valign="top">Op1</td><td class="section" valign="top">Op2</td></tr><tr><td valign="top"><p>reset</p></td><td valign="top"></td><td valign="top"></td></tr><br/></table></div>"""
)
assertThat(generateDocumentation(myFixture)).contains("Reset External Devices", "(privileged)")
}
@Test

View File

@ -11,21 +11,93 @@ import org.junit.jupiter.api.extension.ExtendWith
internal class M68kRegisterFlowDocumentationProviderTest : AbstractDocumentationProviderTest() {
@Test
internal fun check_documentation_for_a_symbol_definition(@MyFixture myFixture: CodeInsightTestFixture) {
internal fun check_documentation_for_a_register_in_code_flow(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByText(
"documentme.asm", """
label
moveq.l #0,d0
add.w #1,d0
move.l d1,-(sp)
move.w d0,d1
move.b d2,d0
addq.b #1,d0
move.w d<caret>0,d1
move.l d0,d2
move.w d1,d2
clr.b d0
moveq.l #0,d0
move.l (sp)+,d1
rts
nextlabel
"""
)
assertThat(generateDocumentation(myFixture)).isEqualTo("d0")
assertThat(generateDocumentation(myFixture))
.isEqualToIgnoringWhitespace(
"""
<div class="definition">move instruction reads d0.w</div>
<table class="sections" style="padding-left: 8pt; padding-right: 8pt">
<tr>
<td valign="top"></td>
<td valign="top"><code>moveq.l #0,<font color="red">d0</font></code></td>
<td valign="top"> ; <i>sets d0.l</i></td>
</tr>
<tr>
<td valign="top"></td>
<td valign="top"><code>add.w #1,<font color="red">d0</font></code></td>
<td valign="top"> ; <i>modifies d0.w</i></td>
</tr>
<tr>
<td valign="top">&nbsp;</td>
<td valign="top">
<div class="grayed">[...]</div>
</td>
<td valign="top">&nbsp;</td>
</tr>
<tr>
<td valign="top"></td>
<td valign="top"><code>move.w <font color="red">d0</font>,d1</code></td>
<td valign="top"> ; <i>reads d0.w</i></td>
</tr>
<tr>
<td valign="top"></td>
<td valign="top"><code>move.b d2,<font color="red">d0</font></code></td>
<td valign="top"> ; <i>sets d0.b</i></td>
</tr>
<tr>
<td valign="top"></td>
<td valign="top"><code>addq.b #1,<font color="red">d0</font></code></td>
<td valign="top"> ; <i>modifies d0.b</i></td>
</tr>
<tr>
<td valign="top"></td>
<td valign="top"><b><code>move.w <font color="red">d0</font>,d1</code></b></td>
<td valign="top"> ; &lt;--</td>
</tr>
<tr>
<td valign="top"></td>
<td valign="top"><code>move.l <font color="red">d0</font>,d2</code></td>
<td valign="top"> ; <i>reads d0.l</i></td>
</tr>
<tr>
<td valign="top">&nbsp;</td>
<td valign="top">
<div class="grayed">[...]</div>
</td>
<td valign="top">&nbsp;</td>
</tr>
<tr>
<td valign="top"></td>
<td valign="top"><code>clr.b <font color="red">d0</font></code></td>
<td valign="top"> ; <i>sets d0.b</i></td>
</tr>
<tr>
<td valign="top"></td>
<td valign="top"><code>moveq.l #0,<font color="red">d0</font></code></td>
<td valign="top"> ; <i>sets d0.l</i></td>
</tr>
</table>
<div class="content"/>
""".trimIndent()
)
}
}

View File

@ -177,9 +177,10 @@ Assembly File: a.asm
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a0')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_L)('.l')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_L)('.l')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.EOL)('\n')

View File

@ -21,8 +21,9 @@ Assembly File: a.asm
PsiElement(M68kTokenType.SEPARATOR)(',')
PsiElement(M68kTokenType.PC)('pc')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a0')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a0')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kProgramCounterIndirectWithIndexNewAddressingModeImpl(PROGRAM_COUNTER_INDIRECT_WITH_INDEX_NEW_ADDRESSING_MODE)
@ -43,9 +44,10 @@ Assembly File: a.asm
PsiElement(M68kTokenType.SEPARATOR)(',')
PsiElement(M68kTokenType.PC)('pc')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d5')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_L)('.l')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d5')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_L)('.l')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.EOL)('\n')

View File

@ -20,10 +20,11 @@ Assembly File: a.asm
PsiElement(M68kTokenType.ROUND_L)('(')
PsiElement(M68kTokenType.PC)('pc')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_W)('.w')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_W)('.w')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kProgramCounterIndirectWithIndexOldAddressingModeImpl(PROGRAM_COUNTER_INDIRECT_WITH_INDEX_OLD_ADDRESSING_MODE)
@ -43,7 +44,8 @@ Assembly File: a.asm
PsiElement(M68kTokenType.ROUND_L)('(')
PsiElement(M68kTokenType.PC)('pc')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a3')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a3')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.EOL)('\n')

View File

@ -11,17 +11,19 @@ Assembly File: a.asm
PsiElement(M68kTokenType.ROUND_L)('(')
PsiElement(M68kTokenType.PC)('pc')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_W)('.w')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_W)('.w')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kProgramCounterIndirectWithIndexNewAddressingModeImpl(PROGRAM_COUNTER_INDIRECT_WITH_INDEX_NEW_ADDRESSING_MODE)
PsiElement(M68kTokenType.ROUND_L)('(')
PsiElement(M68kTokenType.PC)('pc')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a3')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a3')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.EOL)('\n')

View File

@ -22,8 +22,9 @@ Assembly File: a.asm
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.REG_SP)('sp')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a0')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a0')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterIndirectWithIndexNewAddressingModeImpl(ADDRESS_REGISTER_INDIRECT_WITH_INDEX_NEW_ADDRESSING_MODE)
@ -45,9 +46,10 @@ Assembly File: a.asm
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a1')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d5')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_L)('.l')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d5')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_L)('.l')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.EOL)('\n')

View File

@ -21,10 +21,11 @@ Assembly File: a.asm
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.REG_SP)('sp')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_W)('.w')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_W)('.w')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterIndirectWithIndexOldAddressingModeImpl(ADDRESS_REGISTER_INDIRECT_WITH_INDEX_OLD_ADDRESSING_MODE)
@ -45,7 +46,8 @@ Assembly File: a.asm
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a1')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a3')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a3')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.EOL)('\n')

View File

@ -12,10 +12,11 @@ Assembly File: a.asm
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.REG_SP)('sp')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_W)('.w')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kDataRegisterImpl(DATA_REGISTER)
PsiElement(M68kTokenType.DREG)('d0')
M68kDataWidthImpl(DATA_WIDTH)
PsiElement(M68kTokenType.OPSIZE_W)('.w')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterIndirectWithIndexNewAddressingModeImpl(ADDRESS_REGISTER_INDIRECT_WITH_INDEX_NEW_ADDRESSING_MODE)
@ -23,7 +24,8 @@ Assembly File: a.asm
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a1')
PsiElement(M68kTokenType.SEPARATOR)(',')
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a3')
M68kIndexRegisterImpl(INDEX_REGISTER)
M68kAddressRegisterImpl(ADDRESS_REGISTER)
PsiElement(M68kTokenType.AREG)('a3')
PsiElement(M68kTokenType.ROUND_R)(')')
PsiElement(M68kTokenType.EOL)('\n')