mirror of
https://github.com/fadden/6502bench.git
synced 2025-01-11 18:29:53 +00:00
Add "StdInline" extension script
Inline strings and 16-bit addresses are sufficiently common that a general-purpose extension script is useful.
This commit is contained in:
parent
adf5726f62
commit
5ee01ee8a4
@ -82,9 +82,10 @@ namespace CommonUtil {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// MUST match Asm65.Address.NON_ADDR. We can't use the constant directly here because
|
/// MUST match Asm65.Address.NON_ADDR. We can't use the constant directly here because
|
||||||
/// the classes are in different packages that aren't dependent upon each other.
|
/// the classes are in different packages that aren't dependent upon each other. We
|
||||||
|
/// have to make this public because PluginCommon.AddressTranslate needs it as well.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private const int NON_ADDR = -1025;
|
public const int NON_ADDR = -1025;
|
||||||
|
|
||||||
#region Structural
|
#region Structural
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
using CommonUtil;
|
using CommonUtil;
|
||||||
|
|
||||||
namespace PluginCommon {
|
namespace PluginCommon {
|
||||||
@ -37,6 +38,8 @@ namespace PluginCommon {
|
|||||||
/// access to data that is split into multiple regions.
|
/// access to data that is split into multiple regions.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class AddressTranslate {
|
public class AddressTranslate {
|
||||||
|
public const int NON_ADDR = AddressMap.NON_ADDR;
|
||||||
|
|
||||||
private AddressMap mAddrMap;
|
private AddressMap mAddrMap;
|
||||||
|
|
||||||
public AddressTranslate(AddressMap addrMap) {
|
public AddressTranslate(AddressMap addrMap) {
|
||||||
|
@ -190,7 +190,11 @@ namespace PluginCommon {
|
|||||||
IPlugin ipl = kvp.Value;
|
IPlugin ipl = kvp.Value;
|
||||||
ipl.Prepare(appRef, mFileData, addrTrans);
|
ipl.Prepare(appRef, mFileData, addrTrans);
|
||||||
if (ipl is IPlugin_SymbolList) {
|
if (ipl is IPlugin_SymbolList) {
|
||||||
((IPlugin_SymbolList)ipl).UpdateSymbolList(plSyms);
|
try {
|
||||||
|
((IPlugin_SymbolList)ipl).UpdateSymbolList(plSyms);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new Exception("Failed in UpdateSymbolList(" + kvp.Key + ")", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
231
SourceGen/RuntimeData/Common/StdInline.cs
Normal file
231
SourceGen/RuntimeData/Common/StdInline.cs
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 faddenSoft
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PluginCommon;
|
||||||
|
|
||||||
|
namespace RuntimeData.Common {
|
||||||
|
/// <summary>
|
||||||
|
/// Performs inline data formatting for various common situations:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>InAZ_* - inline ASCII null-terminated string</item>
|
||||||
|
/// <item>InA1_* - inline ASCII length-delimited string</item>
|
||||||
|
/// <item>InPZ_* - inline PETSCII null-terminated string</item>
|
||||||
|
/// <item>InP1_* - inline PETSCII length-delimited string</item>
|
||||||
|
/// <item>InW_* - inline 16-bit word</item>
|
||||||
|
/// <item>InWA_* - inline 16-bit address</item>
|
||||||
|
/// <item>InNR_* - non-returning call</item>
|
||||||
|
/// </list>
|
||||||
|
/// Put a label with the appropriate prefix on the address of the subroutine, and all
|
||||||
|
/// calls to it will be formatted automatically. For example, JSRs to the label
|
||||||
|
/// "InAZ_PrintString" will be expected to be followed by null-terminated ASCII string data.
|
||||||
|
///
|
||||||
|
/// ASCII functions work for standard and high ASCII, auto-detecting the encoding based on
|
||||||
|
/// the first character.
|
||||||
|
/// </summary>
|
||||||
|
public class StdInline : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineJsr {
|
||||||
|
private IApplication mAppRef;
|
||||||
|
private byte[] mFileData;
|
||||||
|
|
||||||
|
private class NameMap {
|
||||||
|
public string Prefix { get; private set; }
|
||||||
|
public InlineKind Kind { get; private set; }
|
||||||
|
public NameMap(string prefix, InlineKind kind) {
|
||||||
|
Prefix = prefix;
|
||||||
|
Kind = kind;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private enum InlineKind { Unknown = 0, InAZ, InA1, InPZ, InP1, InW, InWA, InNR };
|
||||||
|
private static NameMap[] sMap = {
|
||||||
|
new NameMap("InNR_", InlineKind.InNR),
|
||||||
|
new NameMap("InAZ_", InlineKind.InAZ),
|
||||||
|
new NameMap("InA1_", InlineKind.InA1),
|
||||||
|
new NameMap("InPZ_", InlineKind.InPZ),
|
||||||
|
new NameMap("InP1_", InlineKind.InP1),
|
||||||
|
new NameMap("InW_", InlineKind.InW),
|
||||||
|
new NameMap("InWA_", InlineKind.InWA),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map of addresses (not offsets) in project to inline data handled by code there.
|
||||||
|
private Dictionary<int, InlineKind> mInlineLabels = new Dictionary<int, InlineKind>();
|
||||||
|
|
||||||
|
// IPlugin
|
||||||
|
public string Identifier {
|
||||||
|
get { return "Standard inline data formatter"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPlugin
|
||||||
|
public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate unused) {
|
||||||
|
mAppRef = appRef;
|
||||||
|
mFileData = fileData;
|
||||||
|
|
||||||
|
mAppRef.DebugLog("StdInline(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPlugin
|
||||||
|
public void Unprepare() {
|
||||||
|
mAppRef = null;
|
||||||
|
mFileData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPlugin_SymbolList
|
||||||
|
public void UpdateSymbolList(List<PlSymbol> plSyms) {
|
||||||
|
mInlineLabels.Clear();
|
||||||
|
|
||||||
|
// Find matching symbols. Save the symbol's value (its address) and the type.
|
||||||
|
// We want an exact match on L1STR_NAME, and prefix matches on the other two.
|
||||||
|
foreach (PlSymbol sym in plSyms) {
|
||||||
|
// We might want to ignore user labels in non-addressable regions, which all
|
||||||
|
// show up with NON_ADDR as their address. In practice it doesn't matter.
|
||||||
|
foreach (NameMap map in sMap) {
|
||||||
|
if (sym.Label.StartsWith(map.Prefix)) {
|
||||||
|
// Multiple offsets could have the same address. Map the first.
|
||||||
|
if (!mInlineLabels.ContainsKey(sym.Value)) {
|
||||||
|
mInlineLabels.Add(sym.Value, map.Kind);
|
||||||
|
} else {
|
||||||
|
mAppRef.DebugLog("Ignoring duplicate address " +
|
||||||
|
sym.Value.ToString("x4"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mAppRef.DebugLog("Found matches for " + mInlineLabels.Count + " labels");
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPlugin_SymbolList
|
||||||
|
public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
|
||||||
|
return DoesLabelMatch(beforeLabel) || DoesLabelMatch(afterLabel);
|
||||||
|
}
|
||||||
|
private static bool DoesLabelMatch(string label) {
|
||||||
|
foreach (NameMap map in sMap) {
|
||||||
|
if (label.StartsWith(map.Prefix)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPlugin_InlineJsr
|
||||||
|
public void CheckJsr(int offset, int operand, out bool noContinue) {
|
||||||
|
noContinue = false;
|
||||||
|
|
||||||
|
InlineKind kind;
|
||||||
|
if (!mInlineLabels.TryGetValue(operand, out kind)) {
|
||||||
|
// JSR destination address not recognized.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += 3; // move past JSR
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
case InlineKind.InAZ:
|
||||||
|
// Null-terminated ASCII string.
|
||||||
|
FormatNullTermString(offset, false);
|
||||||
|
break;
|
||||||
|
case InlineKind.InA1:
|
||||||
|
// Length-delimited ASCII string
|
||||||
|
FormatL1String(offset, false);
|
||||||
|
break;
|
||||||
|
case InlineKind.InPZ:
|
||||||
|
// Null-terminated PETSCII string.
|
||||||
|
FormatNullTermString(offset, true);
|
||||||
|
break;
|
||||||
|
case InlineKind.InP1:
|
||||||
|
// Length-delimited PETSCII string
|
||||||
|
FormatL1String(offset, true);
|
||||||
|
break;
|
||||||
|
case InlineKind.InW:
|
||||||
|
case InlineKind.InWA:
|
||||||
|
// 16-bit value. Start by confirming next two bytes are inside the file bounds.
|
||||||
|
if (!Util.IsInBounds(mFileData, offset, 2)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kind == InlineKind.InW) {
|
||||||
|
// Format 16-bit value as default (hex).
|
||||||
|
mAppRef.SetInlineDataFormat(offset, 2,
|
||||||
|
DataType.NumericLE, DataSubType.None, null);
|
||||||
|
} else {
|
||||||
|
// Format 16-bit value as an address.
|
||||||
|
mAppRef.SetInlineDataFormat(offset, 2,
|
||||||
|
DataType.NumericLE, DataSubType.Address, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InlineKind.InNR:
|
||||||
|
// Non-returning call.
|
||||||
|
noContinue = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormatNullTermString(int offset, bool isPetscii) {
|
||||||
|
if (offset < 0 || offset >= mFileData.Length) {
|
||||||
|
return; // first byte is not inside file
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for the terminating null byte
|
||||||
|
int nullOff = offset;
|
||||||
|
while (nullOff < mFileData.Length) {
|
||||||
|
if (mFileData[nullOff] == 0x00) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nullOff++;
|
||||||
|
}
|
||||||
|
if (nullOff == mFileData.Length) {
|
||||||
|
mAppRef.DebugLog("Unable to find end of null-terminated string at +" +
|
||||||
|
offset.ToString("x6"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSubType stype;
|
||||||
|
if (isPetscii) {
|
||||||
|
stype = DataSubType.C64Petscii;
|
||||||
|
} else if (mFileData[offset] >= 0x80) {
|
||||||
|
stype = DataSubType.HighAscii;
|
||||||
|
} else {
|
||||||
|
stype = DataSubType.Ascii;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAppRef.SetInlineDataFormat(offset, nullOff - offset + 1,
|
||||||
|
DataType.StringNullTerm, stype, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormatL1String(int offset, bool isPetscii) {
|
||||||
|
if (offset < 0 || offset >= mFileData.Length) {
|
||||||
|
return; // length byte is not inside file
|
||||||
|
}
|
||||||
|
int len = mFileData[offset];
|
||||||
|
if (offset + 1 + len > mFileData.Length) {
|
||||||
|
mAppRef.DebugLog("L1 string ran off end of file at +" + offset.ToString("x6"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSubType stype;
|
||||||
|
if (isPetscii) {
|
||||||
|
stype = DataSubType.C64Petscii;
|
||||||
|
} else if (len > 0 && mFileData[offset + 1] >= 0x80) {
|
||||||
|
stype = DataSubType.HighAscii;
|
||||||
|
} else {
|
||||||
|
stype = DataSubType.Ascii;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAppRef.SetInlineDataFormat(offset, len + 1,
|
||||||
|
DataType.StringL8, stype, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
SourceGen/SGTestData/20270-std-inline
Normal file
BIN
SourceGen/SGTestData/20270-std-inline
Normal file
Binary file not shown.
113
SourceGen/SGTestData/20270-std-inline.dis65
Normal file
113
SourceGen/SGTestData/20270-std-inline.dis65
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
### 6502bench SourceGen dis65 v1.0 ###
|
||||||
|
{
|
||||||
|
"_ContentVersion":5,
|
||||||
|
"FileDataLength":210,
|
||||||
|
"FileDataCrc32":-1608872177,
|
||||||
|
"ProjectProps":{
|
||||||
|
"CpuName":"6502",
|
||||||
|
"IncludeUndocumentedInstr":false,
|
||||||
|
"TwoByteBrk":false,
|
||||||
|
"EntryFlags":32702671,
|
||||||
|
"AutoLabelStyle":"Simple",
|
||||||
|
"AnalysisParams":{
|
||||||
|
"AnalyzeUncategorizedData":true,
|
||||||
|
"DefaultTextScanMode":"LowHighAscii",
|
||||||
|
"MinCharsForString":4,
|
||||||
|
"SeekNearbyTargets":true,
|
||||||
|
"UseRelocData":false,
|
||||||
|
"SmartPlpHandling":false,
|
||||||
|
"SmartPlbHandling":true},
|
||||||
|
|
||||||
|
"PlatformSymbolFileIdentifiers":[],
|
||||||
|
"ExtensionScriptFileIdentifiers":["RT:Common/StdInline.cs"],
|
||||||
|
"ProjectSyms":{
|
||||||
|
}},
|
||||||
|
|
||||||
|
"AddressMap":[{
|
||||||
|
"Offset":0,
|
||||||
|
"Addr":4096,
|
||||||
|
"Length":-1024,
|
||||||
|
"PreLabel":"",
|
||||||
|
"IsRelative":false}],
|
||||||
|
"TypeHints":[{
|
||||||
|
"Low":0,
|
||||||
|
"High":0,
|
||||||
|
"Hint":"Code"}],
|
||||||
|
"StatusFlagOverrides":{
|
||||||
|
},
|
||||||
|
|
||||||
|
"Comments":{
|
||||||
|
},
|
||||||
|
|
||||||
|
"LongComments":{
|
||||||
|
},
|
||||||
|
|
||||||
|
"Notes":{
|
||||||
|
},
|
||||||
|
|
||||||
|
"UserLabels":{
|
||||||
|
"3":{
|
||||||
|
"Label":"InAZ_test",
|
||||||
|
"Value":4099,
|
||||||
|
"Source":"User",
|
||||||
|
"Type":"GlobalAddr",
|
||||||
|
"LabelAnno":"None"},
|
||||||
|
|
||||||
|
"4":{
|
||||||
|
"Label":"InA1_test",
|
||||||
|
"Value":4100,
|
||||||
|
"Source":"User",
|
||||||
|
"Type":"GlobalAddr",
|
||||||
|
"LabelAnno":"None"},
|
||||||
|
|
||||||
|
"5":{
|
||||||
|
"Label":"InPZ_test",
|
||||||
|
"Value":4101,
|
||||||
|
"Source":"User",
|
||||||
|
"Type":"GlobalAddr",
|
||||||
|
"LabelAnno":"None"},
|
||||||
|
|
||||||
|
"6":{
|
||||||
|
"Label":"InP1_test",
|
||||||
|
"Value":4102,
|
||||||
|
"Source":"User",
|
||||||
|
"Type":"GlobalAddr",
|
||||||
|
"LabelAnno":"None"},
|
||||||
|
|
||||||
|
"7":{
|
||||||
|
"Label":"InW_test",
|
||||||
|
"Value":4103,
|
||||||
|
"Source":"User",
|
||||||
|
"Type":"GlobalAddr",
|
||||||
|
"LabelAnno":"None"},
|
||||||
|
|
||||||
|
"8":{
|
||||||
|
"Label":"InWA_test",
|
||||||
|
"Value":4104,
|
||||||
|
"Source":"User",
|
||||||
|
"Type":"GlobalAddr",
|
||||||
|
"LabelAnno":"None"},
|
||||||
|
|
||||||
|
"9":{
|
||||||
|
"Label":"InNR_test",
|
||||||
|
"Value":4105,
|
||||||
|
"Source":"User",
|
||||||
|
"Type":"GlobalAddr",
|
||||||
|
"LabelAnno":"None"}},
|
||||||
|
|
||||||
|
"OperandFormats":{
|
||||||
|
},
|
||||||
|
|
||||||
|
"LvTables":{
|
||||||
|
},
|
||||||
|
|
||||||
|
"Visualizations":[],
|
||||||
|
"VisualizationAnimations":[],
|
||||||
|
"VisualizationSets":{
|
||||||
|
},
|
||||||
|
|
||||||
|
"RelocList":{
|
||||||
|
},
|
||||||
|
|
||||||
|
"DbrValues":{
|
||||||
|
}}
|
65
SourceGen/SGTestData/Expected/20270-std-inline_64tass.S
Normal file
65
SourceGen/SGTestData/Expected/20270-std-inline_64tass.S
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
.cpu "6502"
|
||||||
|
.enc "sg_hiascii"
|
||||||
|
.cdef $20,$7e,$a0
|
||||||
|
.enc "sg_ascii"
|
||||||
|
.cdef $20,$7e,$20
|
||||||
|
* = $1000
|
||||||
|
jmp L1040
|
||||||
|
|
||||||
|
InAZ_test rts
|
||||||
|
|
||||||
|
InA1_test rts
|
||||||
|
|
||||||
|
InPZ_test rts
|
||||||
|
|
||||||
|
InP1_test rts
|
||||||
|
|
||||||
|
InW_test rts
|
||||||
|
|
||||||
|
InWA_test rts
|
||||||
|
|
||||||
|
InNR_test rts
|
||||||
|
|
||||||
|
.fill 54,$00
|
||||||
|
|
||||||
|
L1040 nop
|
||||||
|
jsr InAZ_test
|
||||||
|
.null "Test AZ_ low"
|
||||||
|
jsr InAZ_test
|
||||||
|
.enc "sg_hiascii"
|
||||||
|
.null "Test AZ_ high"
|
||||||
|
jsr InA1_test
|
||||||
|
.enc "sg_ascii"
|
||||||
|
.ptext "Test A1_ low"
|
||||||
|
jsr InA1_test
|
||||||
|
.enc "sg_hiascii"
|
||||||
|
.ptext "Test A1_ high"
|
||||||
|
jsr InPZ_test
|
||||||
|
.enc "none"
|
||||||
|
.null "Test PZ",$5f
|
||||||
|
jsr InP1_test
|
||||||
|
.ptext "Test P1",$5f
|
||||||
|
jsr InW_test
|
||||||
|
.word $1234
|
||||||
|
jsr InWA_test
|
||||||
|
.word L1040
|
||||||
|
jsr _L10AD
|
||||||
|
jsr InNR_test
|
||||||
|
|
||||||
|
.byte $ea
|
||||||
|
.byte $00
|
||||||
|
|
||||||
|
_L10AD nop
|
||||||
|
jsr _L10B6
|
||||||
|
jsr _L10C3
|
||||||
|
nop
|
||||||
|
rts
|
||||||
|
|
||||||
|
_L10B6 jsr InA1_test
|
||||||
|
.byte $ff
|
||||||
|
.enc "sg_ascii"
|
||||||
|
.text "too long"
|
||||||
|
.byte $ea
|
||||||
|
|
||||||
|
_L10C3 jsr InAZ_test
|
||||||
|
.text "does not end"
|
56
SourceGen/SGTestData/Expected/20270-std-inline_acme.S
Normal file
56
SourceGen/SGTestData/Expected/20270-std-inline_acme.S
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
!cpu 6502
|
||||||
|
* = $1000
|
||||||
|
jmp L1040
|
||||||
|
|
||||||
|
InAZ_test rts
|
||||||
|
|
||||||
|
InA1_test rts
|
||||||
|
|
||||||
|
InPZ_test rts
|
||||||
|
|
||||||
|
InP1_test rts
|
||||||
|
|
||||||
|
InW_test rts
|
||||||
|
|
||||||
|
InWA_test rts
|
||||||
|
|
||||||
|
InNR_test rts
|
||||||
|
|
||||||
|
!fill 54,$00
|
||||||
|
|
||||||
|
L1040 nop
|
||||||
|
jsr InAZ_test
|
||||||
|
!text "Test AZ_ low",$00
|
||||||
|
jsr InAZ_test
|
||||||
|
!hex d4e5f3f4a0c1dadfa0e8e9e7e800
|
||||||
|
jsr InA1_test
|
||||||
|
!text $0c,"Test A1_ low"
|
||||||
|
jsr InA1_test
|
||||||
|
!hex 0dd4e5f3f4a0c1b1dfa0e8e9e7e8
|
||||||
|
jsr InPZ_test
|
||||||
|
!pet "Test PZ",$5f,$00
|
||||||
|
jsr InP1_test
|
||||||
|
!pet $08,"Test P1",$5f
|
||||||
|
jsr InW_test
|
||||||
|
!word $1234
|
||||||
|
jsr InWA_test
|
||||||
|
!word L1040
|
||||||
|
jsr @L10AD
|
||||||
|
jsr InNR_test
|
||||||
|
|
||||||
|
!byte $ea
|
||||||
|
!byte $00
|
||||||
|
|
||||||
|
@L10AD nop
|
||||||
|
jsr @L10B6
|
||||||
|
jsr @L10C3
|
||||||
|
nop
|
||||||
|
rts
|
||||||
|
|
||||||
|
@L10B6 jsr InA1_test
|
||||||
|
!byte $ff
|
||||||
|
!text "too long"
|
||||||
|
!byte $ea
|
||||||
|
|
||||||
|
@L10C3 jsr InAZ_test
|
||||||
|
!text "does not end"
|
56
SourceGen/SGTestData/Expected/20270-std-inline_cc65.S
Normal file
56
SourceGen/SGTestData/Expected/20270-std-inline_cc65.S
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
.setcpu "6502"
|
||||||
|
.org $1000
|
||||||
|
jmp L1040
|
||||||
|
|
||||||
|
InAZ_test: rts
|
||||||
|
|
||||||
|
InA1_test: rts
|
||||||
|
|
||||||
|
InPZ_test: rts
|
||||||
|
|
||||||
|
InP1_test: rts
|
||||||
|
|
||||||
|
InW_test: rts
|
||||||
|
|
||||||
|
InWA_test: rts
|
||||||
|
|
||||||
|
InNR_test: rts
|
||||||
|
|
||||||
|
.res 54,$00
|
||||||
|
|
||||||
|
L1040: nop
|
||||||
|
jsr InAZ_test
|
||||||
|
.asciiz "Test AZ_ low"
|
||||||
|
jsr InAZ_test
|
||||||
|
.byte $d4,$e5,$f3,$f4,$a0,$c1,$da,$df,$a0,$e8,$e9,$e7,$e8,$00
|
||||||
|
jsr InA1_test
|
||||||
|
.byte $0c,"Test A1_ low"
|
||||||
|
jsr InA1_test
|
||||||
|
.byte $0d,$d4,$e5,$f3,$f4,$a0,$c1,$b1,$df,$a0,$e8,$e9,$e7,$e8
|
||||||
|
jsr InPZ_test
|
||||||
|
.byte $d4,$45,$53,$54,$20,$d0,$da,$5f,$00
|
||||||
|
jsr InP1_test
|
||||||
|
.byte $08,$d4,$45,$53,$54,$20,$d0,$31,$5f
|
||||||
|
jsr InW_test
|
||||||
|
.word $1234
|
||||||
|
jsr InWA_test
|
||||||
|
.word L1040
|
||||||
|
jsr @L10AD
|
||||||
|
jsr InNR_test
|
||||||
|
|
||||||
|
.byte $ea
|
||||||
|
.byte $00
|
||||||
|
|
||||||
|
@L10AD: nop
|
||||||
|
jsr @L10B6
|
||||||
|
jsr @L10C3
|
||||||
|
nop
|
||||||
|
rts
|
||||||
|
|
||||||
|
@L10B6: jsr InA1_test
|
||||||
|
.byte $ff
|
||||||
|
.byte "too long"
|
||||||
|
.byte $ea
|
||||||
|
|
||||||
|
@L10C3: jsr InAZ_test
|
||||||
|
.byte "does not end"
|
9
SourceGen/SGTestData/Expected/20270-std-inline_cc65.cfg
Normal file
9
SourceGen/SGTestData/Expected/20270-std-inline_cc65.cfg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# 6502bench SourceGen generated linker script for 20270-std-inline
|
||||||
|
MEMORY {
|
||||||
|
MAIN: file=%O, start=%S, size=65536;
|
||||||
|
}
|
||||||
|
SEGMENTS {
|
||||||
|
CODE: load=MAIN, type=rw;
|
||||||
|
}
|
||||||
|
FEATURES {}
|
||||||
|
SYMBOLS {}
|
55
SourceGen/SGTestData/Expected/20270-std-inline_merlin32.S
Normal file
55
SourceGen/SGTestData/Expected/20270-std-inline_merlin32.S
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
org $1000
|
||||||
|
jmp L1040
|
||||||
|
|
||||||
|
InAZ_test rts
|
||||||
|
|
||||||
|
InA1_test rts
|
||||||
|
|
||||||
|
InPZ_test rts
|
||||||
|
|
||||||
|
InP1_test rts
|
||||||
|
|
||||||
|
InW_test rts
|
||||||
|
|
||||||
|
InWA_test rts
|
||||||
|
|
||||||
|
InNR_test rts
|
||||||
|
|
||||||
|
ds 54
|
||||||
|
|
||||||
|
L1040 nop
|
||||||
|
jsr InAZ_test
|
||||||
|
asc 'Test AZ_ low',00
|
||||||
|
jsr InAZ_test
|
||||||
|
asc "Test AZ_ high",00
|
||||||
|
jsr InA1_test
|
||||||
|
str 'Test A1_ low'
|
||||||
|
jsr InA1_test
|
||||||
|
str "Test A1_ high"
|
||||||
|
jsr InPZ_test
|
||||||
|
hex d445535420d0da5f00
|
||||||
|
jsr InP1_test
|
||||||
|
hex 08d445535420d0315f
|
||||||
|
jsr InW_test
|
||||||
|
dw $1234
|
||||||
|
jsr InWA_test
|
||||||
|
dw L1040
|
||||||
|
jsr :L10AD
|
||||||
|
jsr InNR_test
|
||||||
|
|
||||||
|
dfb $ea
|
||||||
|
dfb $00
|
||||||
|
|
||||||
|
:L10AD nop
|
||||||
|
jsr :L10B6
|
||||||
|
jsr :L10C3
|
||||||
|
nop
|
||||||
|
rts
|
||||||
|
|
||||||
|
:L10B6 jsr InA1_test
|
||||||
|
dfb $ff
|
||||||
|
asc 'too long'
|
||||||
|
dfb $ea
|
||||||
|
|
||||||
|
:L10C3 jsr InAZ_test
|
||||||
|
asc 'does not end'
|
72
SourceGen/SGTestData/Source/20270-std-inline.S
Normal file
72
SourceGen/SGTestData/Source/20270-std-inline.S
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
; Copyright 2021 faddenSoft. All Rights Reserved.
|
||||||
|
; See the LICENSE.txt file for distribution terms (Apache 2.0).
|
||||||
|
;
|
||||||
|
; Test standard inline script.
|
||||||
|
;
|
||||||
|
; Assembler: ACME
|
||||||
|
; % tass64 --ascii --case-sensitive --nostart 20260-nested-regions.S
|
||||||
|
|
||||||
|
!cpu 6502
|
||||||
|
* = $1000
|
||||||
|
jmp calls
|
||||||
|
|
||||||
|
; EDIT: put appropriate labels on these
|
||||||
|
f_AZ rts
|
||||||
|
f_A1 rts
|
||||||
|
f_PZ rts
|
||||||
|
f_P1 rts
|
||||||
|
f_W rts
|
||||||
|
f_WA rts
|
||||||
|
f_NR rts
|
||||||
|
|
||||||
|
!align 63,0,0
|
||||||
|
calls nop
|
||||||
|
jsr f_AZ
|
||||||
|
!text "Test AZ_ low",$00
|
||||||
|
|
||||||
|
jsr f_AZ
|
||||||
|
!xor $80 {
|
||||||
|
!text "Test AZ_ high"
|
||||||
|
}
|
||||||
|
!byte $00
|
||||||
|
|
||||||
|
jsr f_A1
|
||||||
|
!text 12,"Test A1_ low"
|
||||||
|
|
||||||
|
jsr f_A1
|
||||||
|
!byte 13
|
||||||
|
!xor $80 {
|
||||||
|
!text "Test A1_ high"
|
||||||
|
}
|
||||||
|
|
||||||
|
jsr f_PZ
|
||||||
|
!pet "Test PZ_",$00
|
||||||
|
jsr f_P1
|
||||||
|
!pet 8,"Test P1_"
|
||||||
|
|
||||||
|
jsr f_W
|
||||||
|
!word $1234
|
||||||
|
|
||||||
|
jsr f_WA
|
||||||
|
!word calls
|
||||||
|
|
||||||
|
jsr cont
|
||||||
|
jsr f_NR
|
||||||
|
nop ;check: not formatted as instruction
|
||||||
|
brk
|
||||||
|
cont nop
|
||||||
|
|
||||||
|
; end-of-file error cases
|
||||||
|
jsr end_err1
|
||||||
|
jsr end_err2
|
||||||
|
|
||||||
|
nop
|
||||||
|
rts
|
||||||
|
|
||||||
|
end_err1
|
||||||
|
jsr f_A1
|
||||||
|
!text 255,"too long"
|
||||||
|
nop
|
||||||
|
end_err2
|
||||||
|
jsr f_AZ
|
||||||
|
!text "does not end" ;must be last
|
@ -325,7 +325,7 @@ namespace SourceGen.Sandbox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gathers a list of platform symbols from the project's symbol table.
|
/// Gathers a list of symbols from the project's symbol table.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<PlSymbol> GeneratePlSymbolList() {
|
private List<PlSymbol> GeneratePlSymbolList() {
|
||||||
List<PlSymbol> plSymbols = new List<PlSymbol>();
|
List<PlSymbol> plSymbols = new List<PlSymbol>();
|
||||||
|
@ -157,10 +157,6 @@ import the changes.</p>
|
|||||||
the full .NET Standard 2.0 APIs. They're compiled at run time by SourceGen
|
the full .NET Standard 2.0 APIs. They're compiled at run time by SourceGen
|
||||||
and executed in a sandbox with security restrictions.</p>
|
and executed in a sandbox with security restrictions.</p>
|
||||||
|
|
||||||
<p>SourceGen defines an interface that plugins must implement, and an
|
|
||||||
interface that plugins can use to interact with SourceGen. See
|
|
||||||
Interfaces.cs in the PluginCommon directory.</p>
|
|
||||||
|
|
||||||
<p>The current interfaces can be used to generate visualizations, to
|
<p>The current interfaces can be used to generate visualizations, to
|
||||||
identify inline data that follows JSR, JSL, or BRK instructions, and to
|
identify inline data that follows JSR, JSL, or BRK instructions, and to
|
||||||
format operands. The latter can be used to format code and data, e.g.
|
format operands. The latter can be used to format code and data, e.g.
|
||||||
@ -169,23 +165,62 @@ replacing immediate load operands with symbolic constants.</p>
|
|||||||
<p>Scripts may be loaded from the RuntimeData directory, or from the directory
|
<p>Scripts may be loaded from the RuntimeData directory, or from the directory
|
||||||
where the project file lives. Attempts to load them from other locations
|
where the project file lives. Attempts to load them from other locations
|
||||||
will fail.</p>
|
will fail.</p>
|
||||||
<p>A project may load multiple scripts. The order in which they are
|
<p>A project may load multiple scripts. The order in which functions are
|
||||||
invoked is not defined.</p>
|
invoked is not defined.</p>
|
||||||
|
|
||||||
<h4>Known Issues and Limitations</h4>
|
<h3 id="built-in">Built-In Scripts</h3>
|
||||||
|
|
||||||
<p>Scripts are currently limited to C# version 5, because the compiler
|
<p>A number of scripts are distributed with SourceGen, and may be used
|
||||||
built into .NET only handles that. C# 6 and later require installing an
|
freely by projects. Most are tailored for a specific platform, e.g.
|
||||||
additional package ("Roslyn"), so SourceGen does not support this.</p>
|
Apple II ProDOS calls or Atari 2600 graphics.</p>
|
||||||
|
<p>The <samp>StdInline.cs</samp> script in the <samp>RuntimeData/Common</samp>
|
||||||
|
directory has some general-purpose inline data formatting functions.
|
||||||
|
To use them, add the script to the project, then add an appropriate label
|
||||||
|
to the subroutine that handles the inline data. For example, suppose the
|
||||||
|
code looks like this:</p>
|
||||||
|
<pre>
|
||||||
|
$1000 START JSR L1234
|
||||||
|
$1003 .STR "hello, world!"
|
||||||
|
$1010 .DD1 $00
|
||||||
|
$1011 .DD1 $a9
|
||||||
|
$1012 .DD1 $55
|
||||||
|
[...]
|
||||||
|
$1234 L1234 PLA
|
||||||
|
[...]
|
||||||
|
</pre>
|
||||||
|
<p>The code won't analyze correctly because it will try to follow the
|
||||||
|
code into the string data. If you include the script, and set the label
|
||||||
|
at <code>L1234</code> to <code>InAZ_PrintString</code>, the code will
|
||||||
|
then format correctly:</p>
|
||||||
|
<pre>
|
||||||
|
$1000 START JSR InAZ_PrintString
|
||||||
|
$1003 .ZSTR "hello, world!"
|
||||||
|
$1011 LDA #$55
|
||||||
|
[...]
|
||||||
|
$1234 InAZ_PrintString PLA
|
||||||
|
[...]
|
||||||
|
</pre>
|
||||||
|
|
||||||
<p>When a project is opened, any errors encountered by the script compiler
|
<p>The label prefixes currently defined by the script are:</p>
|
||||||
are reported to the user. If the project is already open, and a script
|
<ul>
|
||||||
is added to the project through the Project Properties editor, compiler
|
<li><code>InAZ_</code> : inline ASCII null-terminated string</li>
|
||||||
messages are silently discarded. (This also applies if you undo/redo across
|
<li><code>InA1_</code> : inline ASCII length-delimited string</li>
|
||||||
the property edit.) Use File > Reload External Files to see the
|
<li><code>InPZ_</code> : inline PETSCII null-terminated string</li>
|
||||||
compiler messages.</p>
|
<li><code>InP1_</code> : inline PETSCII length-delimited string</li>
|
||||||
|
<li><code>InW_</code> : inline 16-bit word</li>
|
||||||
|
<li><code>InWA_</code> : inline 16-bit address</li>
|
||||||
|
<li><code>InNR_</code> : non-returning call (i.e. the JSR acts like
|
||||||
|
a JMP)</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
<h4>Development</h4>
|
<p>Anything more complicated will require a custom script.</p>
|
||||||
|
|
||||||
|
<h3 id="script-dev">Script Development</h3>
|
||||||
|
|
||||||
|
<p>SourceGen defines an interface that plugins must implement, and an
|
||||||
|
interface that plugins can use to interact with SourceGen. See
|
||||||
|
Interfaces.cs in the PluginCommon directory.</p>
|
||||||
|
|
||||||
<p>The easiest way to develop extension scripts is inside the 6502bench
|
<p>The easiest way to develop extension scripts is inside the 6502bench
|
||||||
solution in Visual Studio. This way you have the interfaces available
|
solution in Visual Studio. This way you have the interfaces available
|
||||||
@ -205,9 +240,22 @@ will allow regeneration of the PDB files.</p>
|
|||||||
<p>Some commonly useful functions are defined in the
|
<p>Some commonly useful functions are defined in the
|
||||||
<code>PluginCommon.Util</code> class, which is available to plugins. These
|
<code>PluginCommon.Util</code> class, which is available to plugins. These
|
||||||
call into the CommonUtil library, which is shared with SourceGen.
|
call into the CommonUtil library, which is shared with SourceGen.
|
||||||
While plugins could use CommonUtil directly, they should avoid doing so. The
|
While plugins could technically use CommonUtil directly, they should avoid
|
||||||
APIs there are not guaranteed to be stable, so plugins that rely on them
|
doing so. The APIs there are not guaranteed to be stable, so plugins
|
||||||
may break in a subsequent release of SourceGen.</p>
|
that rely on them may break in a subsequent release of SourceGen.</p>
|
||||||
|
|
||||||
|
<h4>Known Issues and Limitations</h4>
|
||||||
|
|
||||||
|
<p>Scripts are currently limited to C# version 5, because the compiler
|
||||||
|
built into .NET only handles that. C# 6 and later require installing an
|
||||||
|
additional package ("Roslyn"), so SourceGen does not support this.</p>
|
||||||
|
|
||||||
|
<p>When a project is opened, any errors encountered by the script compiler
|
||||||
|
are reported to the user. If the project is already open, and a script
|
||||||
|
is added to the project through the Project Properties editor, compiler
|
||||||
|
messages are silently discarded. (This also applies if you undo/redo across
|
||||||
|
the property edit.) Use File > Reload External Files to see the
|
||||||
|
compiler messages.</p>
|
||||||
|
|
||||||
<h4>PluginDllCache Directory</h4>
|
<h4>PluginDllCache Directory</h4>
|
||||||
|
|
||||||
|
@ -174,7 +174,11 @@ using the <samp>Help > Help</samp> menu item or by hitting
|
|||||||
<li><a href="advanced.html">Advanced Topics</a>
|
<li><a href="advanced.html">Advanced Topics</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="advanced.html#platform-symbols">Platform Symbol Files (.sym65)</a></li>
|
<li><a href="advanced.html#platform-symbols">Platform Symbol Files (.sym65)</a></li>
|
||||||
<li><a href="advanced.html#extension-scripts">Extension Scripts</a></li>
|
<li><a href="advanced.html#extension-scripts">Extension Scripts</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="advanced.html#built-in">Built-In Scripts</a>
|
||||||
|
<li><a href="advanced.html#script-dev">Script Development</a>
|
||||||
|
</ul></li>
|
||||||
<li><a href="advanced.html#multi-bin">Working With Multiple Binaries</a></li>
|
<li><a href="advanced.html#multi-bin">Working With Multiple Binaries</a></li>
|
||||||
<li><a href="advanced.html#overlap">Overlapping Address Spaces</a></li>
|
<li><a href="advanced.html#overlap">Overlapping Address Spaces</a></li>
|
||||||
<li><a href="advanced.html#reloc-data">OMF Relocation Dictionaries</a></li>
|
<li><a href="advanced.html#reloc-data">OMF Relocation Dictionaries</a></li>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user