From 84d31469035a8d49567c366e983396232e640088 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Thu, 15 Aug 2019 21:33:10 -0700 Subject: [PATCH] Update source generators to recognize C64 strings For the most part this means explicitly dumping them as hex, though ACME gets to exercise its !pet and !scr operators. --- SourceGen/AsmGen/AsmAcme.cs | 49 ++++++++++++++++++++++++--------- SourceGen/AsmGen/AsmCc65.cs | 42 ++++++++++++++++------------ SourceGen/AsmGen/AsmMerlin32.cs | 44 +++++++++++++++++++++++++++-- SourceGen/AsmGen/AsmTass64.cs | 32 +++++++++++++-------- 4 files changed, 124 insertions(+), 43 deletions(-) diff --git a/SourceGen/AsmGen/AsmAcme.cs b/SourceGen/AsmGen/AsmAcme.cs index ecd1724..01de707 100644 --- a/SourceGen/AsmGen/AsmAcme.cs +++ b/SourceGen/AsmGen/AsmAcme.cs @@ -451,7 +451,7 @@ namespace SourceGen.AsmGen { } } - if (singleValue) { + if (singleValue && length > 1) { string opcodeStr = SourceFormatter.FormatPseudoOp(sDataOpNames.Fill); string operandStr = length + "," + SourceFormatter.FormatHexValue(val, 2); OutputLine(labelStr, opcodeStr, operandStr, commentStr); @@ -532,11 +532,6 @@ namespace SourceGen.AsmGen { } private void OutputString(int offset, string labelStr, string commentStr) { - // Normal ASCII strings are handled with a simple !text directive. - // - // We could probably do something fancy with !xor to - // make high-ASCII work nicely. - Formatter formatter = SourceFormatter; byte[] data = Project.FileData; Anattrib attr = Project.GetAnattrib(offset); @@ -545,9 +540,30 @@ namespace SourceGen.AsmGen { Debug.Assert(dfd.IsString); Debug.Assert(dfd.Length > 0); - if (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii) { - OutputNoJoy(offset, dfd.Length, labelStr, commentStr); - return; + string opcodeStr; + CharEncoding.Convert charConv; + switch (dfd.FormatSubType) { + case FormatDescriptor.SubType.Ascii: + opcodeStr = sDataOpNames.StrGeneric; + charConv = CharEncoding.ConvertAscii; + break; + case FormatDescriptor.SubType.HighAscii: + // Can't !xor the output, because while it works for string data it + // also flips the high bits on unprintable bytes output as raw hex. + OutputNoJoy(offset, dfd.Length, labelStr, commentStr); + return; + case FormatDescriptor.SubType.C64Petscii: + opcodeStr = "!pet"; + charConv = CharEncoding.ConvertC64Petscii; + break; + case FormatDescriptor.SubType.C64Screen: + opcodeStr = "!scr"; + charConv = CharEncoding.ConvertC64ScreenCode; + break; + default: + Debug.Assert(false); + OutputNoJoy(offset, dfd.Length, labelStr, commentStr); + return; } int leadingBytes = 0; @@ -557,11 +573,14 @@ namespace SourceGen.AsmGen { case FormatDescriptor.Type.StringReverse: case FormatDescriptor.Type.StringNullTerm: case FormatDescriptor.Type.StringDci: + // Last byte will be output as hex. break; case FormatDescriptor.Type.StringL8: + // Length byte will be output as hex. leadingBytes = 1; break; case FormatDescriptor.Type.StringL16: + // Length byte will be output as hex. leadingBytes = 2; break; default: @@ -570,17 +589,21 @@ namespace SourceGen.AsmGen { } StringOpFormatter stropf = new StringOpFormatter(SourceFormatter, - Formatter.DOUBLE_QUOTE_DELIM, - StringOpFormatter.RawOutputStyle.CommaSep, MAX_OPERAND_LEN, - CharEncoding.ConvertAscii); + Formatter.DOUBLE_QUOTE_DELIM,StringOpFormatter.RawOutputStyle.CommaSep, + MAX_OPERAND_LEN, charConv); stropf.FeedBytes(data, offset, dfd.Length, leadingBytes, StringOpFormatter.ReverseMode.Forward); - string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric); + //if (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii) { + // OutputLine(string.Empty, "!xor", "$80 {", string.Empty); + //} foreach (string str in stropf.Lines) { OutputLine(labelStr, opcodeStr, str, commentStr); labelStr = commentStr = string.Empty; // only show on first } + //if (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii) { + // OutputLine(string.Empty, "}", string.Empty, string.Empty); + //} } } diff --git a/SourceGen/AsmGen/AsmCc65.cs b/SourceGen/AsmGen/AsmCc65.cs index 43947d0..c6bb871 100644 --- a/SourceGen/AsmGen/AsmCc65.cs +++ b/SourceGen/AsmGen/AsmCc65.cs @@ -485,7 +485,7 @@ namespace SourceGen.AsmGen { } } - if (singleValue) { + if (singleValue && length > 1) { string opcodeStr = SourceFormatter.FormatPseudoOp(sDataOpNames.Fill); string operandStr = length + "," + SourceFormatter.FormatHexValue(val, 2); OutputLine(labelStr, opcodeStr, operandStr, commentStr); @@ -592,14 +592,35 @@ namespace SourceGen.AsmGen { // Some ideas here: // https://groups.google.com/forum/#!topic/comp.sys.apple2.programmer/5Wkw8mUPcU0 - Formatter formatter = SourceFormatter; - byte[] data = Project.FileData; Anattrib attr = Project.GetAnattrib(offset); FormatDescriptor dfd = attr.DataDescriptor; Debug.Assert(dfd != null); Debug.Assert(dfd.IsString); Debug.Assert(dfd.Length > 0); + CharEncoding.Convert charConv; + bool isHighAscii = false; + switch (dfd.FormatSubType) { + case FormatDescriptor.SubType.Ascii: + charConv = CharEncoding.ConvertAscii; + break; + case FormatDescriptor.SubType.HighAscii: + if (dfd.FormatType != FormatDescriptor.Type.StringGeneric) { + OutputNoJoy(offset, dfd.Length, labelStr, commentStr); + return; + } + charConv = CharEncoding.ConvertHighAscii; + isHighAscii = true; + break; + case FormatDescriptor.SubType.C64Petscii: + case FormatDescriptor.SubType.C64Screen: + default: + OutputNoJoy(offset, dfd.Length, labelStr, commentStr); + return; + } + + Formatter formatter = SourceFormatter; + byte[] data = Project.FileData; int leadingBytes = 0; int trailingBytes = 0; @@ -622,19 +643,6 @@ namespace SourceGen.AsmGen { return; } - bool highAscii = (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii); - if (highAscii && dfd.FormatType != FormatDescriptor.Type.StringGeneric) { - OutputNoJoy(offset, dfd.Length, labelStr, commentStr); - return; - } - - CharEncoding.Convert charConv; - if (highAscii) { - charConv = CharEncoding.ConvertHighAscii; - } else { - charConv = CharEncoding.ConvertAscii; - } - StringOpFormatter stropf = new StringOpFormatter(SourceFormatter, Formatter.DOUBLE_QUOTE_DELIM, StringOpFormatter.RawOutputStyle.CommaSep, MAX_OPERAND_LEN, charConv); @@ -643,7 +651,7 @@ namespace SourceGen.AsmGen { string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric); - if (highAscii) { + if (isHighAscii) { // Does this fit the narrow definition of what we can do with a macro? Debug.Assert(dfd.FormatType == FormatDescriptor.Type.StringGeneric); if (stropf.Lines.Count == 1 && !stropf.HasEscapedText) { diff --git a/SourceGen/AsmGen/AsmMerlin32.cs b/SourceGen/AsmGen/AsmMerlin32.cs index a1e1c25..5d21765 100644 --- a/SourceGen/AsmGen/AsmMerlin32.cs +++ b/SourceGen/AsmGen/AsmMerlin32.cs @@ -308,6 +308,33 @@ namespace SourceGen.AsmGen { } } + /// + /// Outputs formatted data in an unformatted way, because the code generator couldn't + /// figure out how to do something better. + /// + private void OutputNoJoy(int offset, int length, string labelStr, string commentStr) { + byte[] data = Project.FileData; + Debug.Assert(length > 0); + Debug.Assert(offset >= 0 && offset < data.Length); + + bool singleValue = true; + byte val = data[offset]; + for (int i = 1; i < length; i++) { + if (data[offset + i] != val) { + singleValue = false; + break; + } + } + + if (singleValue && length > 1) { + string opcodeStr = SourceFormatter.FormatPseudoOp(sDataOpNames.Fill); + string operandStr = length + "," + SourceFormatter.FormatHexValue(val, 2); + OutputLine(labelStr, opcodeStr, operandStr, commentStr); + } else { + OutputDenseHex(offset, length, labelStr, commentStr); + } + } + // IGenerator public string ModifyOpcode(int offset, OpDef op) { if (op.IsUndocumented) { @@ -446,14 +473,27 @@ namespace SourceGen.AsmGen { // have the right pattern. If not, we will generate bad output. This would need // to be scanned and corrected at a higher level. - Formatter formatter = SourceFormatter; - byte[] data = Project.FileData; Anattrib attr = Project.GetAnattrib(offset); FormatDescriptor dfd = attr.DataDescriptor; Debug.Assert(dfd != null); Debug.Assert(dfd.IsString); Debug.Assert(dfd.Length > 0); + // We can sort of do parts of C64 stuff, but it's probably more readable to just + // output a commented blob than something where only the capital letters are readable. + switch (dfd.FormatSubType) { + case FormatDescriptor.SubType.Ascii: + case FormatDescriptor.SubType.HighAscii: + break; + case FormatDescriptor.SubType.C64Petscii: + case FormatDescriptor.SubType.C64Screen: + default: + OutputNoJoy(offset, dfd.Length, labelStr, commentStr); + return; + } + + Formatter formatter = SourceFormatter; + byte[] data = Project.FileData; StringOpFormatter.ReverseMode revMode = StringOpFormatter.ReverseMode.Forward; int leadingBytes = 0; string opcodeStr; diff --git a/SourceGen/AsmGen/AsmTass64.cs b/SourceGen/AsmGen/AsmTass64.cs index 1a894ff..a5539da 100644 --- a/SourceGen/AsmGen/AsmTass64.cs +++ b/SourceGen/AsmGen/AsmTass64.cs @@ -428,7 +428,7 @@ namespace SourceGen.AsmGen { } } - if (singleValue) { + if (singleValue && length > 1) { string opcodeStr = SourceFormatter.FormatPseudoOp(sDataOpNames.Fill); string operandStr = length + "," + SourceFormatter.FormatHexValue(val, 2); OutputLine(labelStr, opcodeStr, operandStr, commentStr); @@ -528,24 +528,34 @@ namespace SourceGen.AsmGen { // // We might be able to define a macro for Reverse. - Formatter formatter = SourceFormatter; - byte[] data = Project.FileData; Anattrib attr = Project.GetAnattrib(offset); FormatDescriptor dfd = attr.DataDescriptor; Debug.Assert(dfd != null); Debug.Assert(dfd.IsString); Debug.Assert(dfd.Length > 0); + CharEncoding.Convert charConv; + CharEncoding.Convert dciConv; + switch (dfd.FormatSubType) { + case FormatDescriptor.SubType.Ascii: + charConv = CharEncoding.ConvertAscii; + dciConv = CharEncoding.ConvertLowAndHighAscii; + break; + case FormatDescriptor.SubType.HighAscii: + case FormatDescriptor.SubType.C64Petscii: + case FormatDescriptor.SubType.C64Screen: + default: + OutputNoJoy(offset, dfd.Length, labelStr, commentStr); + return; + } + + Formatter formatter = SourceFormatter; + byte[] data = Project.FileData; int hiddenLeadingBytes = 0; int shownLeadingBytes = 0; int trailingBytes = 0; string opcodeStr; - if (dfd.FormatSubType == FormatDescriptor.SubType.HighAscii) { - OutputNoJoy(offset, dfd.Length, labelStr, commentStr); - return; - } - switch (dfd.FormatType) { case FormatDescriptor.Type.StringGeneric: case FormatDescriptor.Type.StringReverse: @@ -573,12 +583,12 @@ namespace SourceGen.AsmGen { StringOpFormatter stropf = new StringOpFormatter(SourceFormatter, Formatter.DOUBLE_QUOTE_DELIM,StringOpFormatter.RawOutputStyle.CommaSep, - MAX_OPERAND_LEN, CharEncoding.ConvertAscii); + MAX_OPERAND_LEN, charConv); if (dfd.FormatType == FormatDescriptor.Type.StringDci) { // DCI is awkward because the character encoding flips on the last byte. Rather // than clutter up StringOpFormatter for this rare item, we just accept low/high // throughout. - stropf.CharConv = CharEncoding.ConvertLowAndHighAscii; + stropf.CharConv = dciConv; } // Feed bytes in, skipping over hidden bytes (leading L8, trailing null). @@ -601,7 +611,7 @@ namespace SourceGen.AsmGen { if (stropf.Lines.Count != 1) { // Must be single-line. opcodeStr = sDataOpNames.StrGeneric; - stropf.CharConv = CharEncoding.ConvertAscii; // undo DCI hack + stropf.CharConv = charConv; // undo DCI hack redo = true; } break;