mirror of
https://github.com/fadden/6502bench.git
synced 2025-02-18 08:30:28 +00:00
Change the way string formats are defined
We used to use type="String", with the sub-type indicating whether the string was null-terminated, prefixed with a length, or whatever. This didn't leave much room for specifying a character encoding, which is orthogonal to the sub-type. What we actually want is to have the type specify the string type, and then have the sub-type determine the character encoding. These sub-types can also be used with the Numeric type to specify the encoding of character operands. This change updates the enum definitions and the various bits of code that use them, but does not add any code for working with non-ASCII character encodings. The project file version number was incremented to 2, since the new FormatDescriptor serialization is mildly incompatible with the old. (Won't explode, but it'll post a complaint and ignore the stuff it doesn't recognize.) While I was at it, I finished removing DciReverse. It's still part of the 2005-string-types regression test, which currently fails because the generated source doesn't match.
This commit is contained in:
parent
89288c4d8c
commit
0d0854bda7
@ -126,7 +126,7 @@ namespace PluginCommon {
|
||||
Unknown = 0,
|
||||
NumericLE,
|
||||
NumericBE,
|
||||
String,
|
||||
StringGeneric,
|
||||
Dense,
|
||||
Fill
|
||||
}
|
||||
|
@ -122,7 +122,6 @@ namespace SourceGen.AsmGen {
|
||||
//StrLen8
|
||||
//StrLen16
|
||||
//StrDci
|
||||
//StrDciReverse
|
||||
};
|
||||
|
||||
|
||||
@ -388,7 +387,12 @@ namespace SourceGen.AsmGen {
|
||||
opcodeStr = operandStr = null;
|
||||
OutputDenseHex(offset, length, labelStr, commentStr);
|
||||
break;
|
||||
case FormatDescriptor.Type.String:
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
multiLine = true;
|
||||
opcodeStr = operandStr = null;
|
||||
OutputString(offset, labelStr, commentStr);
|
||||
@ -532,7 +536,7 @@ namespace SourceGen.AsmGen {
|
||||
Anattrib attr = Project.GetAnattrib(offset);
|
||||
FormatDescriptor dfd = attr.DataDescriptor;
|
||||
Debug.Assert(dfd != null);
|
||||
Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String);
|
||||
Debug.Assert(dfd.IsString);
|
||||
Debug.Assert(dfd.Length > 0);
|
||||
|
||||
bool highAscii = false;
|
||||
@ -541,36 +545,31 @@ namespace SourceGen.AsmGen {
|
||||
bool showLeading = false;
|
||||
bool showTrailing = false;
|
||||
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
trailingBytes = 1;
|
||||
showTrailing = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
break;
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0;
|
||||
leadingBytes = 1;
|
||||
showLeading = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
trailingBytes = 1;
|
||||
showTrailing = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
if (dfd.Length > 1) {
|
||||
highAscii = (data[offset + 1] & 0x80) != 0;
|
||||
}
|
||||
leadingBytes = 1;
|
||||
showLeading = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
if (dfd.Length > 2) {
|
||||
highAscii = (data[offset + 2] & 0x80) != 0;
|
||||
}
|
||||
@ -598,18 +597,17 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric);
|
||||
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
// TODO(someday): something fancy with encodings to handle high-ASCII text?
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
// Fully configured above.
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
// Implement as macro?
|
||||
break;
|
||||
default:
|
||||
|
@ -119,7 +119,6 @@ namespace SourceGen.AsmGen {
|
||||
//StrLen8 // macro with .strlen?
|
||||
//StrLen16
|
||||
//StrDci
|
||||
//StrDciReverse
|
||||
};
|
||||
|
||||
|
||||
@ -414,7 +413,12 @@ namespace SourceGen.AsmGen {
|
||||
opcodeStr = operandStr = null;
|
||||
OutputDenseHex(offset, length, labelStr, commentStr);
|
||||
break;
|
||||
case FormatDescriptor.Type.String:
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
multiLine = true;
|
||||
opcodeStr = operandStr = null;
|
||||
OutputString(offset, labelStr, commentStr);
|
||||
@ -586,7 +590,7 @@ namespace SourceGen.AsmGen {
|
||||
Anattrib attr = Project.GetAnattrib(offset);
|
||||
FormatDescriptor dfd = attr.DataDescriptor;
|
||||
Debug.Assert(dfd != null);
|
||||
Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String);
|
||||
Debug.Assert(dfd.IsString);
|
||||
Debug.Assert(dfd.Length > 0);
|
||||
|
||||
bool highAscii = false;
|
||||
@ -595,36 +599,31 @@ namespace SourceGen.AsmGen {
|
||||
bool showLeading = false;
|
||||
bool showTrailing = false;
|
||||
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
trailingBytes = 1;
|
||||
showTrailing = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
break;
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0;
|
||||
leadingBytes = 1;
|
||||
showLeading = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
trailingBytes = 1;
|
||||
showTrailing = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
if (dfd.Length > 1) {
|
||||
highAscii = (data[offset + 1] & 0x80) != 0;
|
||||
}
|
||||
leadingBytes = 1;
|
||||
showLeading = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
if (dfd.Length > 2) {
|
||||
highAscii = (data[offset + 2] & 0x80) != 0;
|
||||
}
|
||||
@ -652,8 +651,8 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric);
|
||||
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
// Special case for simple short high-ASCII strings. These have no
|
||||
// leading or trailing bytes. We can improve this a bit by handling
|
||||
// arbitrarily long strings by simply breaking them across lines.
|
||||
@ -673,19 +672,18 @@ namespace SourceGen.AsmGen {
|
||||
highAscii = false;
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
// Full configured above.
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
if (gath.NumLinesOutput == 1 && !gath.HasDelimiter) {
|
||||
opcodeStr = sDataOpNames.StrNullTerm;
|
||||
showTrailing = false;
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
// Implement macros?
|
||||
break;
|
||||
default:
|
||||
|
@ -118,7 +118,6 @@ namespace SourceGen.AsmGen {
|
||||
StrLen16Hi = "strl",
|
||||
StrDci = "dci",
|
||||
StrDciHi = "dci",
|
||||
//StrDciReverse
|
||||
};
|
||||
|
||||
|
||||
@ -294,7 +293,12 @@ namespace SourceGen.AsmGen {
|
||||
opcodeStr = operandStr = null;
|
||||
OutputDenseHex(offset, length, labelStr, commentStr);
|
||||
break;
|
||||
case FormatDescriptor.Type.String:
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
multiLine = true;
|
||||
opcodeStr = operandStr = null;
|
||||
OutputString(offset, labelStr, commentStr);
|
||||
@ -460,9 +464,6 @@ namespace SourceGen.AsmGen {
|
||||
// backward order. Also, Merlin doesn't allow hex to be embedded in a REV
|
||||
// operation, so we can't use REV if the string contains a delimiter.
|
||||
//
|
||||
// DciReverse is deprecated, but we can handle it as a Reverse string with a
|
||||
// trailing byte on a following line.
|
||||
//
|
||||
// For aesthetic purposes, zero-length CString, L8String, and L16String
|
||||
// should be output as DFB/DW zeroes rather than an empty string -- makes
|
||||
// it easier to read.
|
||||
@ -472,7 +473,7 @@ namespace SourceGen.AsmGen {
|
||||
Anattrib attr = Project.GetAnattrib(offset);
|
||||
FormatDescriptor dfd = attr.DataDescriptor;
|
||||
Debug.Assert(dfd != null);
|
||||
Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String);
|
||||
Debug.Assert(dfd.IsString);
|
||||
Debug.Assert(dfd.Length > 0);
|
||||
|
||||
bool highAscii = false;
|
||||
@ -483,22 +484,18 @@ namespace SourceGen.AsmGen {
|
||||
bool showTrailing = false;
|
||||
RevMode revMode = RevMode.Forward;
|
||||
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
revMode = RevMode.Reverse;
|
||||
break;
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0;
|
||||
revMode = RevMode.Reverse;
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
if (dfd.Length == 1) {
|
||||
showZeroes = 1; // empty null-terminated string
|
||||
@ -506,7 +503,7 @@ namespace SourceGen.AsmGen {
|
||||
trailingBytes = 1;
|
||||
showTrailing = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
if (dfd.Length > 1) {
|
||||
highAscii = (data[offset + 1] & 0x80) != 0;
|
||||
} else {
|
||||
@ -514,7 +511,7 @@ namespace SourceGen.AsmGen {
|
||||
}
|
||||
leadingBytes = 1;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
if (dfd.Length > 2) {
|
||||
highAscii = (data[offset + 2] & 0x80) != 0;
|
||||
} else {
|
||||
@ -555,11 +552,11 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
string opcodeStr;
|
||||
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
if (gath.NumLinesOutput == 1) {
|
||||
opcodeStr = highAscii ? sDataOpNames.StrDciHi : sDataOpNames.StrDci;
|
||||
} else {
|
||||
@ -568,7 +565,7 @@ namespace SourceGen.AsmGen {
|
||||
showTrailing = true;
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
if (gath.HasDelimiter) {
|
||||
// can't include escaped delimiters in REV
|
||||
opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
|
||||
@ -581,18 +578,11 @@ namespace SourceGen.AsmGen {
|
||||
Debug.Assert(revMode == RevMode.Reverse);
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
// Mostly punt -- output as ASCII with special handling for first byte.
|
||||
opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
|
||||
revMode = RevMode.Forward;
|
||||
leadingBytes = 1;
|
||||
showLeading = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
//opcodeStr = sDataOpNames.StrNullTerm[highAscii ? 1 : 0];
|
||||
opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
if (gath.NumLinesOutput == 1) {
|
||||
opcodeStr = highAscii ? sDataOpNames.StrLen8Hi : sDataOpNames.StrLen8;
|
||||
} else {
|
||||
@ -601,7 +591,7 @@ namespace SourceGen.AsmGen {
|
||||
showLeading = true;
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
if (gath.NumLinesOutput == 1) {
|
||||
opcodeStr = highAscii ? sDataOpNames.StrLen16Hi : sDataOpNames.StrLen16;
|
||||
} else {
|
||||
|
@ -129,7 +129,6 @@ namespace SourceGen.AsmGen {
|
||||
StrLen8 = ".ptext",
|
||||
//StrLen16
|
||||
//StrDci
|
||||
//StrDciReverse
|
||||
};
|
||||
private const string HERE_PSEUDO_OP = ".here";
|
||||
|
||||
@ -360,7 +359,12 @@ namespace SourceGen.AsmGen {
|
||||
opcodeStr = operandStr = null;
|
||||
OutputDenseHex(offset, length, labelStr, commentStr);
|
||||
break;
|
||||
case FormatDescriptor.Type.String:
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
multiLine = true;
|
||||
opcodeStr = operandStr = null;
|
||||
OutputString(offset, labelStr, commentStr);
|
||||
@ -525,7 +529,7 @@ namespace SourceGen.AsmGen {
|
||||
Anattrib attr = Project.GetAnattrib(offset);
|
||||
FormatDescriptor dfd = attr.DataDescriptor;
|
||||
Debug.Assert(dfd != null);
|
||||
Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String);
|
||||
Debug.Assert(dfd.IsString);
|
||||
Debug.Assert(dfd.Length > 0);
|
||||
|
||||
bool highAscii = false;
|
||||
@ -534,36 +538,31 @@ namespace SourceGen.AsmGen {
|
||||
bool showLeading = false;
|
||||
bool showTrailing = false;
|
||||
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
trailingBytes = 1;
|
||||
showTrailing = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
break;
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0;
|
||||
leadingBytes = 1;
|
||||
showLeading = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
trailingBytes = 1;
|
||||
showTrailing = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
if (dfd.Length > 1) {
|
||||
highAscii = (data[offset + 1] & 0x80) != 0;
|
||||
}
|
||||
leadingBytes = 1;
|
||||
showLeading = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
if (dfd.Length > 2) {
|
||||
highAscii = (data[offset + 2] & 0x80) != 0;
|
||||
}
|
||||
@ -591,28 +590,27 @@ namespace SourceGen.AsmGen {
|
||||
|
||||
string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric);
|
||||
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
// TODO(someday): something fancy with encodings to handle high-ASCII text?
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
// Fully configured above.
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
if (gath.NumLinesOutput == 1 && !gath.HasDelimiter) {
|
||||
opcodeStr = sDataOpNames.StrNullTerm;
|
||||
showTrailing = false;
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
if (gath.NumLinesOutput == 1 && !gath.HasDelimiter) {
|
||||
opcodeStr = sDataOpNames.StrLen8;
|
||||
showLeading = false;
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
// Implement as macro?
|
||||
break;
|
||||
default:
|
||||
|
@ -1047,7 +1047,7 @@ namespace SourceGen {
|
||||
return FormatDescriptor.Type.NumericBE;
|
||||
case DataType.Dense:
|
||||
return FormatDescriptor.Type.Dense;
|
||||
case DataType.String:
|
||||
case DataType.StringGeneric:
|
||||
case DataType.Fill:
|
||||
default:
|
||||
// not appropriate for operands, or inline data (?)
|
||||
@ -1068,8 +1068,6 @@ namespace SourceGen {
|
||||
return FormatDescriptor.SubType.Decimal;
|
||||
case DataSubType.Binary:
|
||||
return FormatDescriptor.SubType.Binary;
|
||||
case DataSubType.Ascii:
|
||||
return FormatDescriptor.SubType.Ascii;
|
||||
case DataSubType.Address:
|
||||
return FormatDescriptor.SubType.Address;
|
||||
case DataSubType.Symbol:
|
||||
|
@ -737,7 +737,7 @@ namespace SourceGen {
|
||||
if (asciiLen >= minStringChars) {
|
||||
LogV(start, "ASCII string, len=" + asciiLen + " bytes");
|
||||
mAnattribs[start].DataDescriptor = FormatDescriptor.Create(asciiLen,
|
||||
FormatDescriptor.Type.String, FormatDescriptor.SubType.None);
|
||||
FormatDescriptor.Type.StringGeneric, FormatDescriptor.SubType.Ascii);
|
||||
start += asciiLen;
|
||||
continue;
|
||||
}
|
||||
|
@ -34,27 +34,35 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
public class FormatDescriptor {
|
||||
/// <summary>
|
||||
/// General data type.
|
||||
/// General data type. Generally corresponds to the pseudo-opcode.
|
||||
///
|
||||
/// The UI only allows big-endian values in certain situations. Internally we want
|
||||
/// to be orthogonal in case the policy changes.
|
||||
/// </summary>
|
||||
public enum Type : byte {
|
||||
Unknown = 0,
|
||||
REMOVE, // special type, only used by operand editor
|
||||
Default, // means "unformatted", same effect as not having a FormatDescriptor
|
||||
NumericLE, // 1-4 byte number, little-endian
|
||||
NumericBE, // 1-4 byte number, big-endian
|
||||
String, // character string
|
||||
Dense, // raw data, represented as compactly as possible
|
||||
Fill // fill memory with a value
|
||||
REMOVE, // special type, only used by operand editor
|
||||
Default, // means "unformatted", same as not having a FormatDescriptor
|
||||
|
||||
NumericLE, // 1-4 byte number, little-endian
|
||||
NumericBE, // 1-4 byte number, big-endian
|
||||
|
||||
StringGeneric, // character string
|
||||
StringReverse, // character string, in reverse order
|
||||
StringNullTerm, // C-style null-terminated string
|
||||
StringL8, // string with 8-bit length prefix
|
||||
StringL16, // string with 16-bit length prefix
|
||||
StringDci, // string terminated by flipped high bit (Dextral Char Inverted)
|
||||
|
||||
Dense, // raw data, represented as compactly as possible
|
||||
Fill // fill memory with a value
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Additional data type detail.
|
||||
/// Additional data type detail. Generally affects the operand.
|
||||
///
|
||||
/// Some things are extracted from the data itself, e.g. we don't need to specify if
|
||||
/// a string is high- or low-ASCII, or what value to use for Fill.
|
||||
/// Some things are extracted from the data itself, e.g. we don't need to specify
|
||||
/// what value to use for Fill.
|
||||
/// </summary>
|
||||
public enum SubType : byte {
|
||||
None = 0,
|
||||
@ -63,22 +71,18 @@ namespace SourceGen {
|
||||
Hex,
|
||||
Decimal,
|
||||
Binary,
|
||||
Ascii, // aspirational; falls back on hex if data not suited
|
||||
Address, // wants to be an address, but no symbol defined
|
||||
Symbol, // symbolic ref; replace with Expression, someday?
|
||||
Address, // wants to be an address, but no symbol defined
|
||||
Symbol, // symbolic ref; replace with Expression, someday?
|
||||
|
||||
// String; default is straight text
|
||||
Reverse, // plain ASCII in reverse order
|
||||
CString, // null-terminated
|
||||
L8String, // 8-bit length prefix
|
||||
L16String, // 16-bit length prefix
|
||||
Dci, // Dextral Character Inverted
|
||||
DciReverse, // DCI with string backwards [deprecated -- no asm supports this]
|
||||
// Strings and NumericLE/BE (single character)
|
||||
Ascii, // ASCII (with or without the high bit set)
|
||||
C64Petscii, // C64 PETSCII
|
||||
C64Screen, // C64 screen code
|
||||
|
||||
// Dense; no sub-types
|
||||
|
||||
// Fill; default is non-ignore
|
||||
Ignore // TODO(someday): use this for "don't care" sections
|
||||
Ignore // TODO(someday): use this for "don't care" sections
|
||||
}
|
||||
|
||||
private const int MAX_NUMERIC_LEN = 4;
|
||||
@ -264,6 +268,25 @@ namespace SourceGen {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the FormatDescriptor is a string type.
|
||||
/// </summary>
|
||||
public bool IsString {
|
||||
get {
|
||||
switch (FormatType) {
|
||||
case Type.StringGeneric:
|
||||
case Type.StringReverse:
|
||||
case Type.StringNullTerm:
|
||||
case Type.StringL8:
|
||||
case Type.StringL16:
|
||||
case Type.StringDci:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the FormatDescriptor has a symbol or is Numeric/Address.
|
||||
/// </summary>
|
||||
@ -320,6 +343,48 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
public string ToUiString() {
|
||||
// NOTE: this should be made easier to localize
|
||||
|
||||
if (IsString) {
|
||||
string descr;
|
||||
switch (FormatSubType) {
|
||||
case SubType.Ascii:
|
||||
descr = "ASCII";
|
||||
break;
|
||||
case SubType.C64Petscii:
|
||||
descr = "C64 PETSCII";
|
||||
break;
|
||||
case SubType.C64Screen:
|
||||
descr = "C64 Screen";
|
||||
break;
|
||||
default:
|
||||
descr = "???";
|
||||
break;
|
||||
}
|
||||
switch (FormatType) {
|
||||
case Type.StringGeneric:
|
||||
descr += " string";
|
||||
break;
|
||||
case Type.StringReverse:
|
||||
descr += " string (reverse)";
|
||||
break;
|
||||
case Type.StringNullTerm:
|
||||
descr += " string (null term)";
|
||||
break;
|
||||
case Type.StringL8:
|
||||
descr += " string (1-byte len)";
|
||||
break;
|
||||
case Type.StringL16:
|
||||
descr += " string (2-byte len)";
|
||||
break;
|
||||
case Type.StringDci:
|
||||
descr += " string (DCI)";
|
||||
break;
|
||||
default:
|
||||
descr += " ???";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (FormatSubType) {
|
||||
case SubType.None:
|
||||
switch (FormatType) {
|
||||
@ -328,13 +393,12 @@ namespace SourceGen {
|
||||
return "Numeric (little-endian)";
|
||||
case Type.NumericBE:
|
||||
return "Numeric (big-endian)";
|
||||
case Type.String:
|
||||
return "String (generic)";
|
||||
case Type.Dense:
|
||||
return "Dense";
|
||||
case Type.Fill:
|
||||
return "Fill";
|
||||
default:
|
||||
// strings handled earlier
|
||||
return "???";
|
||||
}
|
||||
case SubType.Hex:
|
||||
@ -343,25 +407,16 @@ namespace SourceGen {
|
||||
return "Numeric, Decimal";
|
||||
case SubType.Binary:
|
||||
return "Numeric, Binary";
|
||||
case SubType.Ascii:
|
||||
return "ASCII";
|
||||
case SubType.Address:
|
||||
return "Address";
|
||||
case SubType.Symbol:
|
||||
return "Symbol \"" + SymbolRef.Label + "\"";
|
||||
|
||||
case SubType.Reverse:
|
||||
return "String (reverse)";
|
||||
case SubType.CString:
|
||||
return "String (null-term)";
|
||||
case SubType.L8String:
|
||||
return "String (1-byte len)";
|
||||
case SubType.L16String:
|
||||
return "String (2-byte len)";
|
||||
case SubType.Dci:
|
||||
return "String (DCI)";
|
||||
case SubType.DciReverse:
|
||||
return "String (RevDCI)";
|
||||
case SubType.Ascii:
|
||||
return "ASCII";
|
||||
case SubType.C64Petscii:
|
||||
return "C64 PETSCII";
|
||||
case SubType.C64Screen:
|
||||
return "C64 Screen";
|
||||
|
||||
default:
|
||||
return "???";
|
||||
|
@ -52,7 +52,7 @@ namespace SourceGen {
|
||||
// ignore stuff that's in one side but not the other. However, if we're opening a
|
||||
// newer file in an older program, it's worth letting the user know that some stuff
|
||||
// may get lost as soon as they save the file.
|
||||
public const int CONTENT_VERSION = 1;
|
||||
public const int CONTENT_VERSION = 2;
|
||||
|
||||
private static readonly bool ADD_CRLF = true;
|
||||
|
||||
@ -669,6 +669,33 @@ namespace SourceGen {
|
||||
dfd = null;
|
||||
FormatDescriptor.Type format;
|
||||
FormatDescriptor.SubType subFormat;
|
||||
|
||||
// File version 1 used a different set of enumerated values for defining strings.
|
||||
// Parse it out here.
|
||||
if ("String".Equals(sfd.Format)) {
|
||||
subFormat = FormatDescriptor.SubType.Ascii;
|
||||
if ("None".Equals(sfd.SubFormat)) {
|
||||
format = FormatDescriptor.Type.StringGeneric;
|
||||
} else if ("Reverse".Equals(sfd.SubFormat)) {
|
||||
format = FormatDescriptor.Type.StringReverse;
|
||||
} else if ("CString".Equals(sfd.SubFormat)) {
|
||||
format = FormatDescriptor.Type.StringNullTerm;
|
||||
} else if ("L8String".Equals(sfd.SubFormat)) {
|
||||
format = FormatDescriptor.Type.StringL8;
|
||||
} else if ("L16String".Equals(sfd.SubFormat)) {
|
||||
format = FormatDescriptor.Type.StringL16;
|
||||
} else if ("Dci".Equals(sfd.SubFormat)) {
|
||||
format = FormatDescriptor.Type.StringDci;
|
||||
} else {
|
||||
// DciReverse no longer supported; output as dense hex
|
||||
format = FormatDescriptor.Type.Dense;
|
||||
subFormat = FormatDescriptor.SubType.None;
|
||||
}
|
||||
Debug.WriteLine("Found v1 string, fmt=" + format + ", sub=" + subFormat);
|
||||
dfd = FormatDescriptor.Create(sfd.Length, format, subFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
format = (FormatDescriptor.Type)Enum.Parse(
|
||||
typeof(FormatDescriptor.Type), sfd.Format);
|
||||
|
@ -87,8 +87,6 @@ namespace SourceGen {
|
||||
public string StrNullTermHi { get; set; }
|
||||
public string StrDci { get; set; }
|
||||
public string StrDciHi { get; set; }
|
||||
public string StrDciReverse { get; set; }
|
||||
public string StrDciReverseHi { get; set; }
|
||||
|
||||
public string GetDefineData(int width) {
|
||||
switch (width) {
|
||||
@ -180,8 +178,6 @@ namespace SourceGen {
|
||||
StrNullTermHi = ".zstrh",
|
||||
StrDci = ".dstr",
|
||||
StrDciHi = ".dstrh",
|
||||
StrDciReverse = ".rdstr",
|
||||
StrDciReverseHi = ".rdstrh",
|
||||
};
|
||||
|
||||
|
||||
@ -192,6 +188,37 @@ namespace SourceGen {
|
||||
/// <param name="dfd">Data format descriptor.</param>
|
||||
/// <returns>Line count.</returns>
|
||||
public static int ComputeRequiredLineCount(Formatter formatter, FormatDescriptor dfd) {
|
||||
if (dfd.IsString) {
|
||||
// Subtract two chars, to leave room for start/end delimiter. We use
|
||||
// non-ASCII delimiters on-screen, so there's nothing to escape there.
|
||||
int maxLen = MAX_OPERAND_LEN - 2;
|
||||
|
||||
// Remove leading length or trailing null byte from string length.
|
||||
int textLen = dfd.Length;
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
break;
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
textLen--;
|
||||
break;
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
textLen -= 2;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
break;
|
||||
}
|
||||
int strLen = (textLen + maxLen - 1) / maxLen;
|
||||
if (strLen == 0) {
|
||||
// Empty string, but we still need to output a line.
|
||||
strLen = 1;
|
||||
}
|
||||
return strLen;
|
||||
}
|
||||
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.Default:
|
||||
case FormatDescriptor.Type.NumericLE:
|
||||
@ -204,37 +231,6 @@ namespace SourceGen {
|
||||
int textLen = dfd.Length * 2;
|
||||
return (textLen + maxLen - 1) / maxLen;
|
||||
}
|
||||
case FormatDescriptor.Type.String: {
|
||||
// Subtract two chars, to leave room for start/end delimiter. We use
|
||||
// non-ASCII delimiters on-screen, so there's nothing to escape there.
|
||||
int maxLen = MAX_OPERAND_LEN - 2;
|
||||
|
||||
// Remove leading length or trailing null byte from string length.
|
||||
int textLen = dfd.Length;
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
textLen--;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
textLen -= 2;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
break;
|
||||
}
|
||||
int strLen = (textLen + maxLen - 1) / maxLen;
|
||||
if (strLen == 0) {
|
||||
// Empty string, but we still need to output a line.
|
||||
strLen = 1;
|
||||
}
|
||||
return strLen;
|
||||
}
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
return 1;
|
||||
@ -274,89 +270,94 @@ namespace SourceGen {
|
||||
// multi-line items.
|
||||
PseudoOut po = new PseudoOut();
|
||||
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.Default:
|
||||
if (length != 1) {
|
||||
// This shouldn't happen.
|
||||
Debug.Assert(false);
|
||||
length = 1;
|
||||
if (dfd.IsString) {
|
||||
// It's hard to do strings in single-line pieces because of prefix lengths,
|
||||
// terminating nulls, DCI polarity, and reverse-order strings. We
|
||||
// really just want to convert the whole thing to a run of chars
|
||||
// and then pull out a chunk. As an optimization we can handle
|
||||
// generic strings more efficiently, which should help if auto-analysis is
|
||||
// creating massive strings (at least until auto-analysis learns how to do
|
||||
// more complex things).
|
||||
//
|
||||
// TODO: consider storing the full string on the first line, then each
|
||||
// subsequent line has a reference to it with offset+length
|
||||
if (dfd.FormatType == FormatDescriptor.Type.StringGeneric) {
|
||||
int maxPerLine = MAX_OPERAND_LEN - 2;
|
||||
offset += subIndex * maxPerLine;
|
||||
length -= subIndex * maxPerLine;
|
||||
if (length > maxPerLine) {
|
||||
length = maxPerLine;
|
||||
}
|
||||
po.Opcode = opNames.GetDefineData(length);
|
||||
int operand = RawData.GetWord(data, offset, length, false);
|
||||
po.Operand = formatter.FormatHexValue(operand, length * 2);
|
||||
break;
|
||||
case FormatDescriptor.Type.NumericLE:
|
||||
po.Opcode = opNames.GetDefineData(length);
|
||||
operand = RawData.GetWord(data, offset, length, false);
|
||||
po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd,
|
||||
operand, length, FormatNumericOpFlags.None);
|
||||
break;
|
||||
case FormatDescriptor.Type.NumericBE:
|
||||
po.Opcode = opNames.GetDefineBigData(length);
|
||||
operand = RawData.GetWord(data, offset, length, true);
|
||||
po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd,
|
||||
operand, length, FormatNumericOpFlags.None);
|
||||
break;
|
||||
case FormatDescriptor.Type.Fill:
|
||||
po.Opcode = opNames.Fill;
|
||||
po.Operand = length + "," + formatter.FormatHexValue(data[offset], 2);
|
||||
break;
|
||||
case FormatDescriptor.Type.Dense: {
|
||||
int maxPerLine = MAX_OPERAND_LEN / 2;
|
||||
offset += subIndex * maxPerLine;
|
||||
length -= subIndex * maxPerLine;
|
||||
if (length > maxPerLine) {
|
||||
length = maxPerLine;
|
||||
}
|
||||
po.Opcode = opNames.Dense;
|
||||
po.Operand = formatter.FormatDenseHex(data, offset, length);
|
||||
//List<PseudoOut> outList = new List<PseudoOut>();
|
||||
//GenerateTextLines(text, "", "", po, outList);
|
||||
//po = outList[subIndex];
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.Type.String:
|
||||
// It's hard to do strings in single-line pieces because of prefix lengths,
|
||||
// terminating nulls, DCI polarity, and reverse-order strings. We
|
||||
// really just want to convert the whole thing to a run of chars
|
||||
// and then pull out a chunk. As an optimization we can handle
|
||||
// generic strings (subtype=None) more efficiently, which should solve
|
||||
// the problem of massive strings created by auto-analysis.
|
||||
if (dfd.FormatSubType == FormatDescriptor.SubType.None) {
|
||||
int maxPerLine = MAX_OPERAND_LEN - 2;
|
||||
offset += subIndex * maxPerLine;
|
||||
length -= subIndex * maxPerLine;
|
||||
if (length > maxPerLine) {
|
||||
length = maxPerLine;
|
||||
}
|
||||
char[] ltext = BytesToChars(formatter, opNames, dfd.FormatSubType, data,
|
||||
offset, length, out string lpopcode, out int unused);
|
||||
po.Opcode = lpopcode;
|
||||
po.Operand = "\u201c" + new string(ltext) + "\u201d";
|
||||
} else {
|
||||
char[] text = BytesToChars(formatter, opNames, dfd.FormatSubType, data,
|
||||
offset, length, out string popcode, out int showHexZeroes);
|
||||
char[] ltext = BytesToChars(formatter, opNames, dfd.FormatType, data,
|
||||
offset, length, out string lpopcode, out int unused);
|
||||
po.Opcode = lpopcode;
|
||||
po.Operand = "\u201c" + new string(ltext) + "\u201d";
|
||||
} else {
|
||||
char[] text = BytesToChars(formatter, opNames, dfd.FormatType, data,
|
||||
offset, length, out string popcode, out int showHexZeroes);
|
||||
|
||||
if (showHexZeroes == 1) {
|
||||
po.Opcode = opNames.DefineData1;
|
||||
po.Operand = formatter.FormatHexValue(0, 2);
|
||||
} else if (showHexZeroes == 2) {
|
||||
po.Opcode = opNames.DefineData2;
|
||||
po.Operand = formatter.FormatHexValue(0, 4);
|
||||
} else {
|
||||
Debug.Assert(showHexZeroes == 0);
|
||||
po.Opcode = popcode;
|
||||
List<PseudoOut> outList = new List<PseudoOut>();
|
||||
GenerateTextLines(text, "\u201c", "\u201d", po, outList);
|
||||
po = outList[subIndex];
|
||||
}
|
||||
if (showHexZeroes == 1) {
|
||||
po.Opcode = opNames.DefineData1;
|
||||
po.Operand = formatter.FormatHexValue(0, 2);
|
||||
} else if (showHexZeroes == 2) {
|
||||
po.Opcode = opNames.DefineData2;
|
||||
po.Operand = formatter.FormatHexValue(0, 4);
|
||||
} else {
|
||||
Debug.Assert(showHexZeroes == 0);
|
||||
po.Opcode = popcode;
|
||||
List<PseudoOut> outList = new List<PseudoOut>();
|
||||
GenerateTextLines(text, "\u201c", "\u201d", po, outList);
|
||||
po = outList[subIndex];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
po.Opcode = ".???";
|
||||
po.Operand = "$" + data[offset].ToString("x2");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (dfd.FormatType) {
|
||||
case FormatDescriptor.Type.Default:
|
||||
if (length != 1) {
|
||||
// This shouldn't happen.
|
||||
Debug.Assert(false);
|
||||
length = 1;
|
||||
}
|
||||
po.Opcode = opNames.GetDefineData(length);
|
||||
int operand = RawData.GetWord(data, offset, length, false);
|
||||
po.Operand = formatter.FormatHexValue(operand, length * 2);
|
||||
break;
|
||||
case FormatDescriptor.Type.NumericLE:
|
||||
po.Opcode = opNames.GetDefineData(length);
|
||||
operand = RawData.GetWord(data, offset, length, false);
|
||||
po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd,
|
||||
operand, length, FormatNumericOpFlags.None);
|
||||
break;
|
||||
case FormatDescriptor.Type.NumericBE:
|
||||
po.Opcode = opNames.GetDefineBigData(length);
|
||||
operand = RawData.GetWord(data, offset, length, true);
|
||||
po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd,
|
||||
operand, length, FormatNumericOpFlags.None);
|
||||
break;
|
||||
case FormatDescriptor.Type.Fill:
|
||||
po.Opcode = opNames.Fill;
|
||||
po.Operand = length + "," + formatter.FormatHexValue(data[offset], 2);
|
||||
break;
|
||||
case FormatDescriptor.Type.Dense: {
|
||||
int maxPerLine = MAX_OPERAND_LEN / 2;
|
||||
offset += subIndex * maxPerLine;
|
||||
length -= subIndex * maxPerLine;
|
||||
if (length > maxPerLine) {
|
||||
length = maxPerLine;
|
||||
}
|
||||
po.Opcode = opNames.Dense;
|
||||
po.Operand = formatter.FormatDenseHex(data, offset, length);
|
||||
//List<PseudoOut> outList = new List<PseudoOut>();
|
||||
//GenerateTextLines(text, "", "", po, outList);
|
||||
//po = outList[subIndex];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
po.Opcode = ".???";
|
||||
po.Operand = "$" + data[offset].ToString("x2");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return po;
|
||||
@ -368,7 +369,7 @@ namespace SourceGen {
|
||||
/// are not shown.
|
||||
/// </summary>
|
||||
/// <param name="formatter">Formatter object.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
/// <param name="formatType">String layout.</param>
|
||||
/// <param name="data">File data.</param>
|
||||
/// <param name="offset">Offset, within data, of start of string.</param>
|
||||
/// <param name="length">Number of bytes to convert.</param>
|
||||
@ -377,7 +378,7 @@ namespace SourceGen {
|
||||
/// length or null-termination) instead of an empty string.</param>
|
||||
/// <returns>Array of characters with string data.</returns>
|
||||
private static char[] BytesToChars(Formatter formatter, PseudoOpNames opNames,
|
||||
FormatDescriptor.SubType subType, byte[] data, int offset, int length,
|
||||
FormatDescriptor.Type formatType, byte[] data, int offset, int length,
|
||||
out string popcode, out int showHexZeroes) {
|
||||
Debug.Assert(length > 0);
|
||||
|
||||
@ -389,32 +390,25 @@ namespace SourceGen {
|
||||
|
||||
showHexZeroes = 0;
|
||||
|
||||
switch (subType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
switch (formatType) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
// High or low ASCII, full width specified by formatter.
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
popcode = highAscii ? opNames.StrGenericHi : opNames.StrGeneric;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
// High or low ASCII, full width specified by formatter.
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
popcode = highAscii ? opNames.StrDciHi : opNames.StrDci;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
// High or low ASCII, full width specified by formatter. Show characters
|
||||
// in reverse order.
|
||||
highAscii = (data[offset + strLen - 1] & 0x80) != 0;
|
||||
popcode = highAscii ? opNames.StrReverseHi : opNames.StrReverse;
|
||||
reverse = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
// High or low ASCII, full width specified by formatter. Show characters
|
||||
// in reverse order.
|
||||
highAscii = (data[offset + strLen - 1] & 0x80) != 0;
|
||||
popcode = highAscii ? opNames.StrDciReverseHi : opNames.StrDciReverse;
|
||||
reverse = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
// High or low ASCII, with a terminating null. Don't show the null. If
|
||||
// it's an empty string, just show the null byte as hex.
|
||||
highAscii = (data[offset] & 0x80) != 0;
|
||||
@ -424,7 +418,7 @@ namespace SourceGen {
|
||||
showHexZeroes = 1;
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
// High or low ASCII, with a leading length byte. Don't show the null.
|
||||
// If it's an empty string, just show the length byte as hex.
|
||||
strOffset++;
|
||||
@ -436,7 +430,7 @@ namespace SourceGen {
|
||||
}
|
||||
popcode = highAscii ? opNames.StrLen8Hi : opNames.StrLen8;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
// High or low ASCII, with a leading length word. Don't show the null.
|
||||
// If it's an empty string, just show the length word as hex.
|
||||
Debug.Assert(strLen > 1);
|
||||
@ -455,6 +449,7 @@ namespace SourceGen {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(petscii): convert character encoding
|
||||
char[] text = new char[strLen];
|
||||
if (!reverse) {
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
@ -547,6 +542,10 @@ namespace SourceGen {
|
||||
case FormatDescriptor.SubType.Binary:
|
||||
return formatter.FormatBinaryValue(operandValue, hexMinLen * 4);
|
||||
case FormatDescriptor.SubType.Ascii:
|
||||
case FormatDescriptor.SubType.C64Petscii:
|
||||
case FormatDescriptor.SubType.C64Screen:
|
||||
// TODO(petscii): convert encoding; use a helper function *not* in
|
||||
// formatter -- pass converted char value in along with operandValue
|
||||
return formatter.FormatAsciiOrHex(operandValue);
|
||||
case FormatDescriptor.SubType.Symbol:
|
||||
if (symbolTable.TryGetValue(dfd.SymbolRef.Label, out Symbol sym)) {
|
||||
|
@ -528,6 +528,9 @@ namespace SourceGen.WpfGui {
|
||||
radioSimpleDataBinary.IsChecked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Ascii:
|
||||
case FormatDescriptor.SubType.C64Petscii:
|
||||
case FormatDescriptor.SubType.C64Screen:
|
||||
// TODO(petscii): update UI
|
||||
radioSimpleDataAscii.IsChecked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Address:
|
||||
@ -560,34 +563,23 @@ namespace SourceGen.WpfGui {
|
||||
// preferred format not enabled; leave Hex/Low checked
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.Type.String:
|
||||
switch (dfd.FormatSubType) {
|
||||
case FormatDescriptor.SubType.None:
|
||||
preferredFormat = radioStringMixed;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Reverse:
|
||||
preferredFormat = radioStringMixedReverse;
|
||||
break;
|
||||
case FormatDescriptor.SubType.CString:
|
||||
preferredFormat = radioStringNullTerm;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L8String:
|
||||
preferredFormat = radioStringLen8;
|
||||
break;
|
||||
case FormatDescriptor.SubType.L16String:
|
||||
preferredFormat = radioStringLen16;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Dci:
|
||||
preferredFormat = radioStringDci;
|
||||
break;
|
||||
case FormatDescriptor.SubType.DciReverse:
|
||||
preferredFormat = radioDefaultFormat;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
preferredFormat = radioDefaultFormat;
|
||||
break;
|
||||
}
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
preferredFormat = radioStringMixed;
|
||||
break;
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
preferredFormat = radioStringMixedReverse;
|
||||
break;
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
preferredFormat = radioStringNullTerm;
|
||||
break;
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
preferredFormat = radioStringLen8;
|
||||
break;
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
preferredFormat = radioStringLen16;
|
||||
break;
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
preferredFormat = radioStringDci;
|
||||
break;
|
||||
case FormatDescriptor.Type.Dense:
|
||||
preferredFormat = radioDenseHex;
|
||||
@ -639,6 +631,7 @@ namespace SourceGen.WpfGui {
|
||||
} else if (radioSimpleDataBinary.IsChecked == true) {
|
||||
subType = FormatDescriptor.SubType.Binary;
|
||||
} else if (radioSimpleDataAscii.IsChecked == true) {
|
||||
// TODO(petscii): configure subType correctly
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else if (radioSimpleDataAddress.IsChecked == true) {
|
||||
subType = FormatDescriptor.SubType.Address;
|
||||
@ -688,26 +681,25 @@ namespace SourceGen.WpfGui {
|
||||
type = FormatDescriptor.Type.Dense;
|
||||
} else if (radioFill.IsChecked == true) {
|
||||
type = FormatDescriptor.Type.Fill;
|
||||
subType = FormatDescriptor.SubType.Ascii; // TODO(petscii): set encoding
|
||||
} else if (radioStringMixed.IsChecked == true) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
type = FormatDescriptor.Type.StringGeneric;
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else if (radioStringMixedReverse.IsChecked == true) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.Reverse;
|
||||
type = FormatDescriptor.Type.StringReverse;
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else if (radioStringNullTerm.IsChecked == true) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.CString;
|
||||
type = FormatDescriptor.Type.StringNullTerm;
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else if (radioStringLen8.IsChecked == true) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.L8String;
|
||||
type = FormatDescriptor.Type.StringL8;
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else if (radioStringLen16.IsChecked == true) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.L16String;
|
||||
type = FormatDescriptor.Type.StringL16;
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else if (radioStringDci.IsChecked == true) {
|
||||
type = FormatDescriptor.Type.String;
|
||||
subType = FormatDescriptor.SubType.Dci;
|
||||
//} else if (radioStringDciReverse.Checked) {
|
||||
// type = FormatDescriptor.Type.String;
|
||||
// subType = FormatDescriptor.SubType.DciReverse;
|
||||
type = FormatDescriptor.Type.StringDci;
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
// default/none
|
||||
@ -720,26 +712,26 @@ namespace SourceGen.WpfGui {
|
||||
while (iter.MoveNext()) {
|
||||
TypedRangeSet.TypedRange rng = iter.Current;
|
||||
|
||||
if (type == FormatDescriptor.Type.String) {
|
||||
// We want to create one FormatDescriptor object per string. That way
|
||||
// each string gets its own line.
|
||||
if ((subType == FormatDescriptor.SubType.None ||
|
||||
subType == FormatDescriptor.SubType.Reverse)) {
|
||||
CreateMixedStringEntries(rng.Low, rng.High, subType);
|
||||
} else if (subType == FormatDescriptor.SubType.CString) {
|
||||
CreateCStringEntries(rng.Low, rng.High, subType);
|
||||
} else if (subType == FormatDescriptor.SubType.L8String ||
|
||||
subType == FormatDescriptor.SubType.L16String) {
|
||||
CreateLengthStringEntries(rng.Low, rng.High, subType);
|
||||
} else if (subType == FormatDescriptor.SubType.Dci ||
|
||||
subType == FormatDescriptor.SubType.DciReverse) {
|
||||
CreateDciStringEntries(rng.Low, rng.High, subType);
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
CreateMixedStringEntries(rng.Low, rng.High, subType); // shrug
|
||||
}
|
||||
} else {
|
||||
CreateSimpleEntries(type, subType, chunkLength, symbolRef, rng.Low, rng.High);
|
||||
// TODO(petscii): handle encoding on all four calls
|
||||
switch (type) {
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
CreateMixedStringEntries(rng.Low, rng.High, type, subType);
|
||||
break;
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
CreateCStringEntries(rng.Low, rng.High, type, subType);
|
||||
break;
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
CreateLengthStringEntries(rng.Low, rng.High, type, subType);
|
||||
break;
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
CreateDciStringEntries(rng.Low, rng.High, type, subType);
|
||||
break;
|
||||
default:
|
||||
CreateSimpleEntries(type, subType, chunkLength, symbolRef,
|
||||
rng.Low, rng.High);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -793,7 +785,7 @@ namespace SourceGen.WpfGui {
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateMixedStringEntries(int low, int high,
|
||||
private void CreateMixedStringEntries(int low, int high, FormatDescriptor.Type type,
|
||||
FormatDescriptor.SubType subType) {
|
||||
int stringStart = -1;
|
||||
int highBit = 0;
|
||||
@ -846,11 +838,12 @@ namespace SourceGen.WpfGui {
|
||||
Debug.Assert(length > 0);
|
||||
if (length == 1) {
|
||||
// single byte, output as single ASCII char rather than 1-byte string
|
||||
// TODO(petscii): low/high?
|
||||
CreateByteFD(offset, FormatDescriptor.SubType.Ascii);
|
||||
} else {
|
||||
FormatDescriptor dfd;
|
||||
dfd = FormatDescriptor.Create(length,
|
||||
FormatDescriptor.Type.String, subType);
|
||||
FormatDescriptor.Type.StringGeneric, subType);
|
||||
Results.Add(offset, dfd);
|
||||
}
|
||||
}
|
||||
@ -873,14 +866,14 @@ namespace SourceGen.WpfGui {
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateCStringEntries(int low, int high,
|
||||
private void CreateCStringEntries(int low, int high, FormatDescriptor.Type type,
|
||||
FormatDescriptor.SubType subType) {
|
||||
int startOffset = low;
|
||||
for (int i = low; i <= high; i++) {
|
||||
if (mFileData[i] == 0x00) {
|
||||
// End of string. Zero-length strings are allowed.
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(
|
||||
i - startOffset + 1, FormatDescriptor.Type.String, subType);
|
||||
i - startOffset + 1, type, subType);
|
||||
Results.Add(startOffset, dfd);
|
||||
startOffset = i + 1;
|
||||
} else {
|
||||
@ -899,20 +892,19 @@ namespace SourceGen.WpfGui {
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateLengthStringEntries(int low, int high,
|
||||
private void CreateLengthStringEntries(int low, int high, FormatDescriptor.Type type,
|
||||
FormatDescriptor.SubType subType) {
|
||||
int i;
|
||||
for (i = low; i <= high;) {
|
||||
int length = mFileData[i];
|
||||
if (subType == FormatDescriptor.SubType.L16String) {
|
||||
if (type == FormatDescriptor.Type.StringL16) {
|
||||
length |= mFileData[i + 1] << 8;
|
||||
length += 2;
|
||||
} else {
|
||||
length++;
|
||||
}
|
||||
// Zero-length strings are allowed.
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(length,
|
||||
FormatDescriptor.Type.String, subType);
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(length, type, subType);
|
||||
Results.Add(i, dfd);
|
||||
i += length;
|
||||
}
|
||||
@ -927,36 +919,25 @@ namespace SourceGen.WpfGui {
|
||||
/// <param name="low">Offset of first byte in range.</param>
|
||||
/// <param name="high">Offset of last byte in range.</param>
|
||||
/// <param name="subType">String sub-type.</param>
|
||||
private void CreateDciStringEntries(int low, int high,
|
||||
private void CreateDciStringEntries(int low, int high, FormatDescriptor.Type type,
|
||||
FormatDescriptor.SubType subType) {
|
||||
int start, end, adj, endMask;
|
||||
if (subType == FormatDescriptor.SubType.Dci) {
|
||||
start = low;
|
||||
end = high + 1;
|
||||
adj = 1;
|
||||
} else if (subType == FormatDescriptor.SubType.DciReverse) {
|
||||
start = high;
|
||||
end = low - 1;
|
||||
adj = -1;
|
||||
} else {
|
||||
Debug.Assert(false);
|
||||
return;
|
||||
}
|
||||
int end, endMask;
|
||||
|
||||
end = high + 1;
|
||||
|
||||
// Zero-length strings aren't a thing for DCI. The analyzer requires that all
|
||||
// strings in a region have the same polarity, so just grab the last byte.
|
||||
endMask = mFileData[end - 1] & 0x80;
|
||||
|
||||
int stringStart = start;
|
||||
for (int i = start; i != end; i += adj) {
|
||||
int stringStart = low;
|
||||
for (int i = low; i != end; i++) {
|
||||
byte val = mFileData[i];
|
||||
if ((val & 0x80) == endMask) {
|
||||
// found the end of a string
|
||||
int length = (i - stringStart) * adj + 1;
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(length,
|
||||
FormatDescriptor.Type.String, subType);
|
||||
int length = (i - stringStart) + 1;
|
||||
FormatDescriptor dfd = FormatDescriptor.Create(length, type, subType);
|
||||
Results.Add(stringStart < i ? stringStart : i, dfd);
|
||||
stringStart = i + adj;
|
||||
stringStart = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,6 +333,7 @@ namespace SourceGen.WpfGui {
|
||||
preview.Append(mFormatter.FormatBinaryValue(mOperandValue, 8));
|
||||
break;
|
||||
case FormatDescriptor.SubType.Ascii:
|
||||
// TODO(petscii): encoding
|
||||
preview.Append(mFormatter.FormatAsciiOrHex(mOperandValue));
|
||||
break;
|
||||
case FormatDescriptor.SubType.Symbol:
|
||||
@ -470,6 +471,7 @@ namespace SourceGen.WpfGui {
|
||||
binaryButton.IsChecked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Ascii:
|
||||
// TODO(petscii): encoding
|
||||
asciiButton.IsChecked = true;
|
||||
break;
|
||||
case FormatDescriptor.SubType.Symbol:
|
||||
@ -499,7 +501,13 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
break;
|
||||
case FormatDescriptor.Type.NumericBE:
|
||||
case FormatDescriptor.Type.String:
|
||||
case FormatDescriptor.Type.StringGeneric:
|
||||
case FormatDescriptor.Type.StringReverse:
|
||||
case FormatDescriptor.Type.StringNullTerm:
|
||||
case FormatDescriptor.Type.StringL8:
|
||||
case FormatDescriptor.Type.StringL16:
|
||||
case FormatDescriptor.Type.StringDci:
|
||||
case FormatDescriptor.Type.Dense:
|
||||
case FormatDescriptor.Type.Fill:
|
||||
default:
|
||||
// Unexpected; used to be data?
|
||||
@ -543,6 +551,7 @@ namespace SourceGen.WpfGui {
|
||||
} else if (binaryButton.IsChecked == true) {
|
||||
subType = FormatDescriptor.SubType.Binary;
|
||||
} else if (asciiButton.IsChecked == true) {
|
||||
// TODO(petscii): encoding
|
||||
subType = FormatDescriptor.SubType.Ascii;
|
||||
} else if (symbolButton.IsChecked == true) {
|
||||
subType = FormatDescriptor.SubType.Symbol;
|
||||
|
Loading…
x
Reference in New Issue
Block a user