Allow scripts to handle COP and WDM inlines

The code that allows scripts to catch and handle BRK/JSR/JSL followed
by inline data now also handles COP and WDM.

(issue #177)
This commit is contained in:
Andy McFadden committed 2025-11-30 14:59:39 -08:00
1 parent 5a3d288707
commit 037b982d94
11 files changed
+154 -15

No files matched your search

+28
View File
@@ -134,6 +134,34 @@ namespace PluginCommon {
void CheckBrk(int offset, bool isTwoBytes, out bool noContinue); void CheckBrk(int offset, bool isTwoBytes, out bool noContinue);
} }
/// <summary>
/// Extension scripts that want to handle inline COPs must implement this interface.
/// </summary>
public interface IPlugin_InlineCop {
/// <summary>
/// Checks to see if code/data near a COP instruction should be formatted.
///
/// The file data is only guaranteed to hold the COP opcode byte.
/// </summary>
/// <param name="offset">Offset of the COP instruction.</param>
/// <param name="noContinue">Set to true if the COP doesn't actually return.</param>
void CheckCop(int offset, out bool noContinue);
}
/// <summary>
/// Extension scripts that want to handle inline WDMs must implement this interface.
/// </summary>
public interface IPlugin_InlineWdm {
/// <summary>
/// Checks to see if code/data near a WDM instruction should be formatted.
///
/// The file data is only guaranteed to hold the WDM opcode byte.
/// </summary>
/// <param name="offset">Offset of the WDM instruction.</param>
/// <param name="noContinue">Set to true if the WDM doesn't actually return.</param>
void CheckWdm(int offset, out bool noContinue);
}
/// <summary> /// <summary>
/// Extension scripts that want to generate visualizations must implement this interface. /// Extension scripts that want to generate visualizations must implement this interface.
/// </summary> /// </summary>
+27 -2
View File
@@ -126,7 +126,14 @@ namespace SourceGen {
private IPlugin[] mScriptArray; private IPlugin[] mScriptArray;
[Flags] [Flags]
private enum PluginCap { NONE = 0, JSR = 1 << 0, JSL = 1 << 1, BRK = 1 << 2 }; private enum PluginCap {
NONE = 0,
JSR = 1 << 0,
JSL = 1 << 1,
BRK = 1 << 2,
COP = 1 << 3,
WDM = 1 << 4,
};
private PluginCap[] mPluginCaps; private PluginCap[] mPluginCaps;
/// <summary> /// <summary>
@@ -356,6 +363,12 @@ namespace SourceGen {
if (mScriptArray[i] is IPlugin_InlineBrk) { if (mScriptArray[i] is IPlugin_InlineBrk) {
cap |= PluginCap.BRK; cap |= PluginCap.BRK;
} }
if (mScriptArray[i] is IPlugin_InlineCop) {
cap |= PluginCap.COP;
}
if (mScriptArray[i] is IPlugin_InlineWdm) {
cap |= PluginCap.WDM;
}
mPluginCaps[i] = cap; mPluginCaps[i] = cap;
} }
@@ -788,11 +801,17 @@ namespace SourceGen {
// On first visit, check for JSR/JSL inline call. If it's "no-continue", // On first visit, check for JSR/JSL inline call. If it's "no-continue",
// set a flag and halt here. // set a flag and halt here.
// Also check COP/WDM, since we assume they continue.
if (firstVisit) { if (firstVisit) {
// Currently ignoring OpDef.OpJSR_AbsIndexXInd // Currently ignoring OpDef.OpJSR_AbsIndexXInd
if (op == OpDef.OpJSR_Abs || op == OpDef.OpJSR_AbsLong) { if (op == OpDef.OpJSR_Abs || op == OpDef.OpJSR_AbsLong ||
op == OpDef.OpCOP_StackInt || op == OpDef.OpWDM_WDM) {
bool noContinue = CheckForInlineCall(op, offset, false); bool noContinue = CheckForInlineCall(op, offset, false);
if (noContinue) { if (noContinue) {
// The "NoContinue" attribute can be updated if the code gets
// revisited, so we use a separate flag to ensure the script's
// decision doesn't get lost. See 20180-extension-scripts
// for a test case.
LogD(offset, "Script declared inline call no-continue"); LogD(offset, "Script declared inline call no-continue");
mAnattribs[offset].NoContinueScript = true; mAnattribs[offset].NoContinueScript = true;
break; break;
@@ -1086,6 +1105,12 @@ namespace SourceGen {
} else if (op == OpDef.OpJSR_AbsLong && (mPluginCaps[i] & PluginCap.JSL) != 0) { } else if (op == OpDef.OpJSR_AbsLong && (mPluginCaps[i] & PluginCap.JSL) != 0) {
((IPlugin_InlineJsl)script).CheckJsl(offset, operand, out bool noCont); ((IPlugin_InlineJsl)script).CheckJsl(offset, operand, out bool noCont);
noContinue |= noCont; noContinue |= noCont;
} else if (op == OpDef.OpCOP_StackInt && (mPluginCaps[i] & PluginCap.COP) != 0){
((IPlugin_InlineCop)script).CheckCop(offset, out bool noCont);
noContinue |= noCont;
} else if (op == OpDef.OpWDM_WDM && (mPluginCaps[i] & PluginCap.WDM) != 0) {
((IPlugin_InlineWdm)script).CheckWdm(offset, out bool noCont);
noContinue |= noCont;
} else if ((op == OpDef.OpBRK_Implied || op == OpDef.OpBRK_StackInt) && } else if ((op == OpDef.OpBRK_Implied || op == OpDef.OpBRK_StackInt) &&
(mPluginCaps[i] & PluginCap.BRK) != 0) { (mPluginCaps[i] & PluginCap.BRK) != 0) {
((IPlugin_InlineBrk)script).CheckBrk(offset, op == OpDef.OpBRK_StackInt, ((IPlugin_InlineBrk)script).CheckBrk(offset, op == OpDef.OpBRK_StackInt,
@@ -0,0 +1,63 @@
// Copyright 2025 faddenSoft. All Rights Reserved.
// See the LICENSE.txt file for distribution terms (Apache 2.0).
using System;
using System.Collections.Generic;
using PluginCommon;
// COP/WDM handler
namespace RuntimeData.Test20180 {
public class Test20180C : MarshalByRefObject, IPlugin, IPlugin_InlineCop, IPlugin_InlineWdm {
private IApplication mAppRef;
private byte[] mFileData;
private AddressTranslate mAddrTrans;
public string Identifier {
get {
return "Test 20180-extension-scripts C";
}
}
public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
mAddrTrans = addrTrans;
mAppRef.DebugLog("Test20180-C(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
}
public void Unprepare() {
mAppRef = null;
mFileData = null;
mAddrTrans = null;
}
public void CheckCop(int offset, out bool noContinue) {
HandleString(offset, out noContinue);
}
public void CheckWdm(int offset, out bool noContinue) {
HandleString(offset, out noContinue);
}
private void HandleString(int offset, out bool noContinue) {
const int INSTR_LEN = 2; // opcode + byte
noContinue = false;
// Handle as string with 8-bit length prefix.
if (offset + INSTR_LEN >= mFileData.Length) {
return; // length byte is off end
}
int len = mFileData[offset + INSTR_LEN];
if (offset + INSTR_LEN + 1 + len > mFileData.Length) {
// ran off the end
mAppRef.DebugLog("L1 string ran off end of file at +" +
(offset + INSTR_LEN).ToString("x6"));
return;
}
mAppRef.SetInlineDataFormat(offset + INSTR_LEN, len + 1,
DataType.StringL8, DataSubType.Ascii, null);
}
}
}
Binary file not shown.
@@ -2,7 +2,7 @@
{ {
"_ContentVersion":7, "_ContentVersion":7,
"FileDataLength":544, "FileDataLength":544,
"FileDataCrc32":1948144462, "FileDataCrc32":371480162,
"ProjectProps":{ "ProjectProps":{
"CpuName":"65816", "CpuName":"65816",
"IncludeUndocumentedInstr":false, "IncludeUndocumentedInstr":false,
@@ -20,7 +20,8 @@
"PlatformSymbolFileIdentifiers":["PROJ:20182-extension-scripts.sym65"], "PlatformSymbolFileIdentifiers":["PROJ:20182-extension-scripts.sym65"],
"ExtensionScriptFileIdentifiers":["PROJ:20180-extension-scripts-a.cs", "ExtensionScriptFileIdentifiers":["PROJ:20180-extension-scripts-a.cs",
"PROJ:20180-extension-scripts-b.cs"], "PROJ:20180-extension-scripts-b.cs",
"PROJ:20180-extension-scripts-c.cs"],
"ProjectSyms":{ "ProjectSyms":{
"PrintInlineDciString":{ "PrintInlineDciString":{
"DataDescriptor":{ "DataDescriptor":{
@@ -74,9 +74,14 @@ Next clc
.byte $00 .byte $00
.byte $80 .byte $80
_L10B8 rts _L10B8 cop #$03
.enc "sg_ascii"
.ptext "COP!"
.byte $42,$04
.ptext "WDM!"
rts
.fill 327,$00 .fill 313,$00
.logical $1800 .logical $1800
L1800 jsr PrintInlineNullString L1800 jsr PrintInlineNullString
@@ -89,7 +94,6 @@ L1800 jsr PrintInlineNullString
.byte $01 .byte $01
.here .here
.logical $1840 .logical $1840
.enc "sg_ascii"
.text "string" .text "string"
.byte $00 .byte $00
.byte $60 .byte $60
@@ -68,9 +68,13 @@ Next clc
!byte $00 !byte $00
!byte $80 !byte $80
@L10B8 rts @L10B8 cop $03
!text $04,"COP!"
!byte $42,$04
!text $04,"WDM!"
rts
!fill 327,$00 !fill 313,$00
!pseudopc $1800 { !pseudopc $1800 {
L1800 jsr PrintInlineNullString L1800 jsr PrintInlineNullString
@@ -71,9 +71,13 @@ Next: clc
.byte $00 .byte $00
.byte $80 .byte $80
@L10B8: rts @L10B8: cop $03
.byte $04,"COP!"
wdm $04
.byte $04,"WDM!"
rts
.res 327,$00 .res 313,$00
.org $1800 .org $1800
L1800: jsr PrintInlineNullString L1800: jsr PrintInlineNullString
@@ -63,9 +63,13 @@ Next clc
dfb $00 dfb $00
dfb $80 dfb $80
:L10B8 rts :L10B8 cop $03
str 'COP!'
wdm $04
str 'WDM!'
rts
ds 327 ds 313
org $1800 org $1800
L1800 jsr PrintInlineNullString L1800 jsr PrintInlineNullString
@@ -10,7 +10,7 @@
; check basics ; check basics
jsr PrintInline8String jsr PrintInline8String
asc '01234567' asc '01234567' ;hard-coded to 8 bytes long
jsr PrintInlineRev8String jsr PrintInlineRev8String
asc '76543210' asc '76543210'
jsr PrintInlineNullString jsr PrintInlineNullString
@@ -18,7 +18,7 @@ PrintInlineDciString equ $013000 ;EDIT: add to project symbols
; check basics ; check basics
jsr PrintInline8String jsr PrintInline8String
asc '01234567' asc '01234567' ;hard-coded to 8 bytes long
jsr PrintInlineRev8String jsr PrintInlineRev8String
asc '76543210' asc '76543210'
jsr PrintInlineNullString jsr PrintInlineNullString
@@ -81,6 +81,12 @@ Next
brk $80 brk $80
:BrkNext :BrkNext
; test COP and WDM
cop $03
str 'COP!'
wdm $04
str 'WDM!'
rts rts