Programming with Ophis
<<< Previous |  | Next >>>

# 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) `NOP`s. 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.

<<< Previous | Home | Next >>>
Example code |  | Local variables and memory segments