Character maps

Now we will close the gap between the Commodore's version of ASCII and the real one. We'll also add a time-delay routine to slow down the output. This routine isn't really of interest to us right now, so we'll add a subroutine called delay that executes 2,560*(accumulator) NOPs. By the time the program is finished, we'll have executed 768,000 no-ops.

There actually are better ways of getting a time-delay on the Commodore 64; we'll deal with those in the Chapter called Local variables and memory segments. As a result, there isn't really a lot to discuss here. The later tutorials will be building off of tutor4a.oph, so you may want to get familiar with that. Note also the change to the body of the greet macro.

On to the topic at hand. Let's change the code to use mixed case. We defined the upper'case and lower'case aliases back in the Chapter called Headers, Libraries, and Macros as part of the standard kernal.oph header, so we can add this before our invocations of the greet macro:

          lda #lower'case
          jsr chrout

And that will put us into mixed case mode. So, now we just need to redefine the data so that it uses the mixed-case:

hello1:   .byte "Hello, ",0
hello2:   .byte "!", 13, 0

target1:  .byte "programmer", 0
target2:  .byte "room", 0
target3:  .byte "building", 0
target4:  .byte "neighborhood", 0
target5:  .byte "city", 0
target6:  .byte "nation", 0
target7:  .byte "world", 0
target8:  .byte "Solar System", 0
target9:  .byte "Galaxy", 0
target10: .byte "Universe", 0

The code that does this is in tutor4b.oph. If you assemble and run it, you will notice that the output is not what we want. In particular, upper and lowercase are reversed, so we have messages like hELLO, sOLAR sYSTEM!. For the specific case of PETSCII, we can just fix our strings, but that's less of an option if we're writing for the Apple II's character set, or targeting a game console that puts its letters in arbitrary locations. We need to remap how strings are turned into byte values. The .charmap and .charmapbin directives do what we need.

The .charmap directive usually takes two arguments; a byte (usually in character form) indicating the ASCII value to start remapping from, and then a string giving the new values. To do our case-swapping, we write two directives before defining any string constants:

.charmap 'A, "abcdefghijklmnopqrstuvwxyz"
.charmap 'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

Note that the 'a constant in the second directive refers to the "a" character in the source, not in the current map.

The fixed code is in tutor4c.oph, and will produce the expected results when run.

An alternative is to use a .charmapbin directive to replace the entire character map directly. This specifies an external file, 256 bytes long, that is loaded in at that point. A binary character map for the Commodore 64 is provided with the sample programs as petscii.map. There are also three files, a2normal.map, a2inverse.map, and a2blink.map that handle the Apple II's very nonstandard character encodings.