Making a chart of your Commodore 64 character sets. (Commodore's port) John Michael Lane.
We all agree that the Commodore 64 offers great graphics. With sprites, programmable characters, bit mapped screens and a variety of mulit-color modes, the programmer can choose exactly what he wants.
There is one small problem, however. While the graphics on the screen are terrific, it is often difficult to convey a representation of the characters that compose them without a TV. C64 graphics just don't lend themselves to hardcopy. We can't solve that problem here, but we can tackle one small area--that of programmable characters. The program presented here will print out enlarged images of all characters in a programmed character set. Unfortunately, with a black and white printer, we can't tackle multi-colored character sets.
First, you need a printer that is capable of printing block graphics. Many dot matrix printers have these block characters and most use the same ASCII character numbers for them. Figure 1 shows the block characters and ASCII numbers for a Gemini 10-X printer. Look for a chart in your printer manual displaying all of its character sets.
If your printer has the block characters, chances are that it also has adjustable line spacing. Block images on the Gemini 10-X have only a 6 x 6 dot image. At standard spacing, there is a space between any two lines. With the line spacing adjusted to 6/72 of an inch, printed lines will just touch one another, leaving no space between. On the Gemini 10-X the appropriate line spacing can be set by either of the following sequences: PRINT#4,CHR$(27)+ "1" + CHR$(12) PRINT#4,CHR$(27)+ "A" + CHR$(6)
If you have block characters on your printer and can set the appropriate line spacing, you need only one more thing: a printer interface that can pass characters from your computer to your printer without ASCII correction. On the Cardco printer interfaces, this is accomplished by using a secondary address in the OPEN statement. The statement OPEN 4,4,4 will open the printer interface without correction of ASCII data. Without this feature, the printer interface would translate the ASCII values of the block characters (and the printer initialization routines) into standard Commodore 64 graphic characters.
While this may seem an intimidating list of requirements, many dot matrix printers offer block characters and almost all printer interfaces allow you to lock out the ASCII correction.
Creating Character Sets
If you are interested in printing hardcopy images of your programmed character sets, you probably already know how to access that feature of the C64. If you don't, have a look at Figure 2, which provides an overview of the way in which character images are translated from numerical data and vice versa.
In its default mode, the C64 fetches character data from ROM. There are two 226-character sets stored in 4K of ROM. Each character requires eight bytes to store its image. Values in the screen memory act as pointers that direct the Commodore to the appropriate data in ROM to form each character. For example, a pointer value of 26 points to the data for the character Z. The complete list of characters is given in Appendix E of the Commodore 64 User's Guide, Screen Display Codes.
Programmed characters are created by directing the C64 away from data in the character ROMs and toward user created data stored in RAM. Since character data are now stored in RAM, you can create new character patterns.
There have been many articles and books written on using programmed characters, so we need not repeat that information here. If you are interested in programmed characters, you can consult one of those sources or the Programmer's Reference Guide.
Using the Program
This program can be used to print hardcopies of the standard character sets in ROM, of any user-created character set, and of character sets used in programs created by others.
However, this program cannot load or create the character sets, except the ROM character sets. Thus you must rely on your program to create and load the character set data. To load and transfer control to the Patterns program, you must be able to stop the program with the custom character set and return to Basic without turning your computer off. This is usually easy to accomplish with programs you have written, but can be difficult or impossible with machine language programs. In the latter case, you can choose one of two approaches.
First, you can just let the program terminate, if it returns to Basic after completion. Then load and run the Patterns program. Second, you can press RUN/STOP or RUN/STOP-RESTORE. You should do this after the program begins to use the custom character set. Some programs disable these keys, so this method cannot be used. If you can return to the READY prompt, however, just load and run the Patterns program. If you know how to reset your computer or have added a reset key, you can also use that method.
Some programs appear to be "hung up" after you press RUN/STOP-RESTORE, but, in reality, are not. If your program switches the 16K memory bank addressed by the Vic-II chip, pressing these keys together will produce a new screen, but pressing them separately will produce no response. If this is the case, try typing RETURN POKE 648,4 RETURN. This will not show on the screen, but may solve the problem.
If programmed characters have been selected, you need two pieces of information to find them.
First, you need to know which bank the Vic-II chip is addressing. The video chip in the Commodore 64 can look at only 16K of memory at one time. In most cases, the chip is addressing the first 16K of memory, which is the default mode. If you are working with a really long propgram, the first 16K of RAM becomes full of program data and leaves no room for character data. In such a case, you must switch to another bank to squeeze in the character data. If all this sounds like Greek to you, you are undoubtedly using bank zero.
Second, you need to know the location of the character set within that 16K block of RAM. The C64 uses a pointer stored in register 53272 to point the way toward the character set in RAM. If you can create custom characters, you know what this value is. If not, look over the program listing for a statement that looks like: POKE 53272, (PEEK(53272) AND 240)+12 or: POKE 53272,(PEEK(53272) AND 240)OR 12
Sometimes the value 53272 is represented as a variable, such as: 10 V = 53248 20 POKE V + 24,(PEEK(V + 24)) AND 240)+12 In all these cases 12 is the value of the pointer for which you are looking. If the value is odd, simply reduce it by one.
Sometimes you can find the value of the 16K bank and the character set pointer by stopping the operation of the program with the RUN/STOP key. If you can do this successfully, typing: PRINT PEEK53272) AND 15 will yield the value of the character set pointer, and: PRINT 3-PEEK(56578) AND 3 will uield the value of the 16K bank addressed by the Vic-II chip.
The rest of the program is simple. Just specify how many of the characters you want printed and the number of the character with which you want to start. (The first character in the character set is character 0.) This program is not terribly fast; it will take about 45 minutes to print all 256 characters in a set. The program automatically formats your output and numbers the pages.
You may find that your printer has block characters, but the CHR$( ) numbers do not match those in this article. In this case simply substitute your values in the DATA statement on line 160. Enter the number in the same order as the block characters in Figure 1. If your printer or interface requires different command sequences, insert those sequences where appropriate. All interface and printer commands are labeled with REM statements.
Understanding the Program
The program is fairly well documented with REM statements, so you may already have figured out how it works. The main idea is rather simple. You take the 8 x 8 pixel character image and divide it into 16 2 x 2 pixel images. The block characters on the printer offer all possible combinations of 2 x 2 images. It is not difficult to figure out how to print the block characters so that they form one large image; the problem is how to select the correct block character to match the character image in memory.
At the time this program was written, I had just finished working on a short tutorial on binary numbers. As I wondered "How can I match the RAM pattern with the corresponding block character?" binary numbers leapt out at me.
Imagine that each block character is a binary number. The bit sequence is shown in Figure 3. If you evaluate the block character according to this sequence, each block character has a unique numeric value ranging from 0 to 15. You load the ASCII value of each character into the P array [P(I)] in the order of the value of its binary image. If you want to print the character that has the binary image of 12, just issue the instruction: PRINT CHR$(P(12))
The actual matching of block characters is done in lines 840 through 900. The variable Q is used in the calculation and is incremented by the appropriate binary value (1, 2, 4, or 8) if the corresponding bit in RAM is set to 1 (lines 860 through 880). The statement: PRINT#4, CHR$(P(Q)); in line 890 prints the correct block character.
The Commodore 64 and Commodore printers offer block graphics as well, although it is necessary to use reverse video to get them all. I find it convenient to add 256 to the ASCII value of those characters that requires a reversed image. Then, when printing the characters, the following sequence: 900 IF P(Q)> 255 THEN PRINT CHR$(18) +CHR$(P(Q)-256) +CHR$(146): GOTO 920 910 PRINT CHR$(P(Q)) selects the right character. (CHR$(18) and CHR$(146) are REVERSE ON and REVERSE OFF.)
It would make the programming task a little easier if you printed the characters one at a time. It would be more useful, however, if you could print more than one character in a row. This program prints five characters in a row. This means that you must print the top portion of one character, the top portion of another character, etc., and then proceed to the next portion. When you are analyzing the program, note carefully the FOR/NEXT loop nesting which makes this possible. I have also included a border around the character images, for a more finished appearance.
To the extent possible, I have used full variable names in the program (BANK, NUMBER, PAGES, LINES, etc.) While the Commodore 64 allows variable names of any length, it looks only at the first two letters of any variable. Thus, BANK is really BA. I have used the full names to add clarity to the program. In some lines, however, I revert to the two character names to fit an equation on the 80-character line, (as in lines 860 through 880).
Additional Applications
If you understand the technique for pattern matching, block characters offer several other graphics applications. The same technique can be used on sprites to print hardcopies of two-color sprite images. Simply divide the 24 x 21 pixel image into 2 x 2 block characters. You will have to add a blank line on the bottom to make it come out properly.
If you are really ambitious you can even tackle a screen dump of a portion of a bit-mapped screen using block characters. Using 12 pitch, a standard sheet of paper can hold a 192 x 264 pixel image running lengthwise.