mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-23 16:32:44 +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>
|
||||
/// <remarks>
|
||||
/// 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>
|
||||
private const int NON_ADDR = -1025;
|
||||
public const int NON_ADDR = -1025;
|
||||
|
||||
#region Structural
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
using CommonUtil;
|
||||
|
||||
namespace PluginCommon {
|
||||
@ -37,6 +38,8 @@ namespace PluginCommon {
|
||||
/// access to data that is split into multiple regions.
|
||||
/// </remarks>
|
||||
public class AddressTranslate {
|
||||
public const int NON_ADDR = AddressMap.NON_ADDR;
|
||||
|
||||
private AddressMap mAddrMap;
|
||||
|
||||
public AddressTranslate(AddressMap addrMap) {
|
||||
|
@ -190,7 +190,11 @@ namespace PluginCommon {
|
||||
IPlugin ipl = kvp.Value;
|
||||
ipl.Prepare(appRef, mFileData, addrTrans);
|
||||
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>
|
||||
/// Gathers a list of platform symbols from the project's symbol table.
|
||||
/// Gathers a list of symbols from the project's symbol table.
|
||||
/// </summary>
|
||||
private List<PlSymbol> GeneratePlSymbolList() {
|
||||
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
|
||||
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
|
||||
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.
|
||||
@ -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
|
||||
where the project file lives. Attempts to load them from other locations
|
||||
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>
|
||||
|
||||
<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
|
||||
built into .NET only handles that. C# 6 and later require installing an
|
||||
additional package ("Roslyn"), so SourceGen does not support this.</p>
|
||||
<p>A number of scripts are distributed with SourceGen, and may be used
|
||||
freely by projects. Most are tailored for a specific platform, e.g.
|
||||
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
|
||||
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>
|
||||
<p>The label prefixes currently defined by the script are:</p>
|
||||
<ul>
|
||||
<li><code>InAZ_</code> : inline ASCII null-terminated string</li>
|
||||
<li><code>InA1_</code> : inline ASCII length-delimited string</li>
|
||||
<li><code>InPZ_</code> : inline PETSCII null-terminated string</li>
|
||||
<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
|
||||
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
|
||||
<code>PluginCommon.Util</code> class, which is available to plugins. These
|
||||
call into the CommonUtil library, which is shared with SourceGen.
|
||||
While plugins could use CommonUtil directly, they should avoid doing so. The
|
||||
APIs there are not guaranteed to be stable, so plugins that rely on them
|
||||
may break in a subsequent release of SourceGen.</p>
|
||||
While plugins could technically use CommonUtil directly, they should avoid
|
||||
doing so. The APIs there are not guaranteed to be stable, so plugins
|
||||
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>
|
||||
|
||||
|
@ -174,7 +174,11 @@ using the <samp>Help > Help</samp> menu item or by hitting
|
||||
<li><a href="advanced.html">Advanced Topics</a>
|
||||
<ul>
|
||||
<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#overlap">Overlapping Address Spaces</a></li>
|
||||
<li><a href="advanced.html#reloc-data">OMF Relocation Dictionaries</a></li>
|
||||
|
Loading…
Reference in New Issue
Block a user