First, a bit of context. I wrote an interactive disassembler for 6502 code that, among other things, attempts to identify ASCII strings automatically. Appropriate source code for different assemblers is generated. This works well for ASCII and the "high ASCII" often found in Apple II code, but having never worked with Commodore machines I'm at a bit of loss when it comes to PETSCII.
What I know comes from wikipedia, which has a couple of graphics showing the "shifted" and "unshifted" character sets. These show the letters in the 0x41-5a range (upper-case only) or the 0x41-7a range (mixed case, with lower case coming first). The article also mentions "text mode", in which lowercase letters run from 0x41-5a, and uppercase letters run from 0xc1-da. This latter mode seems to be what the 64tass assembler is aware of, e.g. in this example from the manual:
.enc "petscii" ;define an ascii->petscii encoding
[...]
>1000 93 d4 45 58 54 20 49 4e .text "{clr}Text in PETSCII\n"
>1008 20 d0 c5 d4 d3 c3 c9 c9 0d
Confusing me somewhat is an example of using "screen encoding", in which lower-case letters are in the range 0x01-1a:
.enc "screen" ;screen code mode
>1000 13 03 12 05 05 0e 20 03 .text "screen codes"
>1008 0f 04 05 13
This doesn't seem to match up with anything on the wikipedia page.
My goal is to auto-detect PETSCII strings, present them in the disassembled output in a useful way, and generate assembly source code that is readable and generates the correct output. This is clearly important for string constants, but also matters for immediate character operands like:
CMP #'m'
I think there needs to be a general "here there be PETSCII" flag, which
would change the way the disassembler handles character data and be used
to set command-line flags for the cross-assembler (e.g. ca65's -t
flag).
I'm concerned that it might be insufficient. If there are multiple character
sets in use, and they change from one line to the next, then some support
for character set mode tagging may be required.
The ca65 assembler has a PETSCII conversion table that seems to
correspond to "text mode", and is enabled with a command-line switch. However,
the assembler also provides a .charmap
pseudo-op that lets you override
the global setting.
The approach I'm leaning toward mirrors the way cross-assemblers like ca65 and 64tass work, with a global "treat characters as PETSCII" flag. The other character modes would either be handled as hex data or as an explicit special-case format. Before I settle on this I want to be sure my understanding of PETSCII usage is accurate.
Various questions arise:
- How do assembly-language programs on Commodore systems commonly deal with text? Is "text mode" the dominant form?
- Is it common for programs to use multiple encodings, e.g. "screen codes"? Which system does keyboard input use?
- Does regular ASCII get used with any regularity? Is it reasonable to expect that all character data will be some flavor of PETSCII?
EDIT: Just to untangle myself a bit, the C64 has two character sets in ROM. The system starts up with a set that only has upper-case letters and symbols. You can toggle it to a different set where various symbols have been replaced with lower-case letters. I have seen this second mode referred to as "shifted mode" (because you switch to it by holding Shift and then tapping the Commodore key), "lower case mode", or "text mode" (because text looks nicer in mixed case).
The way the characters are stored in the text screen buffer is similar but everything is shuffled around a bit. All of the symbols are represented from 0x00-7f. If the high bit is set, the character is shown with its colors inverted. This is what's meant by "screen codes".
The charts in https://www.aivosto.com/articles/petscii.pdf do a good job of expressing all this.