A confusing and tedious aspect of machine language programming, sprite making, or character set redefinition is converting the contents of memory into BASIC DATA statements that can be typed in easily. This program—for any Commodore computer with a disk drive—will do all the work for you. It also provides valuable insight into how the computer stores program files on disk.
In the past there have been programs that created DATA statements by PEEKing the contents of memory and using the dynamic keyboard technique to fool the computer into thinking that someone had typed in the lines. The problem with these programs was that occasionally the resulting DATA statements, or perhaps even the datamaker program itself, would need to occupy the area of memory being PEEKed, destroying the data that needed to be transformed.
If, however, the data is stored on disk, it would not need to be in memory as well. It could just be read from a file. Then I decided there was no reason to use the dynamic keyboard technique either, since a BASIC program could be created right on the disk. The result is "Disk Datamaker" (Program 1); it causes no memory conflicts—because neither the original chunk of data, nor the BASIC program created by Datamaker, is ever in the computer's memory.
In addition to creating DATA statements, the Datamaker program creates the necessary lines of BASIC to READ and POKE the DATA items back into memory. Program 2 is a short example of a program created by the Datamaker. It consists of the DATA statements for one sprite shaped like a Commodore 64.
Suppose you have written a machine language (ML) program. Sophisticated assembler programs such as MAE, the Commodore assembler, and the PAL assembler all allow you to store the object code on disk. If you use a simple assembler like Supermon or Micromon, you can SAVE a copy of the section of memory that contains your ML program. Then all you have to do is LOAD the Disk Datamaker program, give it the name of your object and program files, and it will take care of everything.
Suppose you have just created sprite data with a sprite editor. If you have the Commodore Sprite Editor, all you have to do is press the S key to invoke the SAVE command, which puts your sprite data on disk. If you are using some other editor, you could use a monitor to SAVE a copy of the section of memory containing the sprite data. Disk Datamaker could then turn that file into DATA statements.
Manipulating PRG Files
All this is possible because PRG (program) files on disk can be OPENed and used just like SEQ (sequential) data files. To OPEN a PRG file for writing, you can either put a ",P,W" after the filename, or you can OPEN with a secondary address of 1, which is reserved for SAVE. These two lines produce identical results:
OPEN 8,8,1,"filename" OPEN 8,8,8,"filename,P,W"
To OPEN a PRG file for reading, just OPEN another ",P" file or use a secondary address of 0. These two lines are also identical:
OPEN 8,8,0,"filename" OPEN 8,8,8,"filename,P,R"
Using this knowledge, it is possible to read the PRG file that holds the data, and to write a PRG file that contains a BASIC program.
The other knowledge necessary to understand Disk Datamaker is the structure of a BASIC program. Each line of BASIC contains four header bytes. The first two are a pointer to the beginning of the next BASIC line in memory. The address is in standard low-byte/high-byte format. The next two bytes are the line number, also in low-byte/high-byte format. Next is the tokenized version of the BASIC line, followed by a zero to denote the end of the line in memory. If the pointer to the next line is two zeros in a row, the computer knows it has reached the end of the program.
Lines 10–90 OPEN the PRG file from which the data will come and the one to which the BASIC program will be written. The subroutine at 10000 will print the appropriate error message if either of the files cannot be OPENed.
Line 100 GETs the first two bytes from the file containing the data. In Commodore PRG files, these bytes always contain the starting address (again in low-byte/high-byte format) of the area of memory where the data was located when it was originally saved. Line 110 writes the first two bytes to the file which will be the new BASIC program. The numbers chosen, 1 and 4, specify a starting address of 1 + (4*256) or 1025. This starting address will allow the BASIC program created to LOAD correctly into a PET/CBM. The starting address is not critical for the VIC and 64 since they automatically relocate any program to their particular starting addresses when it is LOADed.
Line 120 defines the values for the pointer bytes to the next program line. Rather than attempting to calculate the proper addresses for each pointer, Datamaker arbitrarily sets all these bytes to ones. This can be done because Commodore computers automatically redo these pointers whenever a BASIC program is LOADed. Line 130 writes the pointer for the first BASIC line to the disk, and line 140 writes the first four numbers from the DATA statement in line 170. These provide the line number (10) and the tokens for I = Line 150 uses the value for the starting address found in line 100 to write the value for I to the disk. If you want to relocate your data, simply change the value for I in line 10 of the BASIC loader program once it is created.
Line 160 reads the rest of the DATA from lines 170–200 of Program 1 and writes it to the disk, which creates lines 20 and 30 of the new BASIC program (see Program 2, for example). These lines READ the DATA statements created from your data and POKE the values back into memory.
Line 210 calculates the line number to be used for the first DATA statement. This is the same as the address in memory of the first DATA item. Note this feature of Datamaker: The line number of each DATA line is equal to the address into which the first number in that line will be POKEd, unless you change the value of I to relocate the data. Line 220 writes out the pointer bytes and the line number for each DATA line, and line 230 writes the tokens for DATA and a space.
Lines 250–300 constitute a loop to read eight bytes from the data file and write them as eight DATA items, separated by commas, to the BASIC program file. Line 310 checks the variable S, set in line 250 to the value of the built-in status variable ST, to detect whether the end of the data file on disk has been reached. (See Larry Isaacs' "64 Explorer" column in the October and November 1983 issues of COMPUTE! for more information on detecting an end-of-file with the ST variable.)
If the end has not been reached, line 320 calculates the next DATA line number, and line 330 writes out a zero to mark the end of the current BASIC line. If the end has been reached, line 340 adds a DATA item with the value of 256 to the end of the DATA statements. This is the value checked for as an end-of-data marker in line 20 of the created BASIC program. The three zeros in a row written by line 340 mark the end of the BASIC program. Line 350 CLOSEs the two PRG files and logical file 15, used to detect disk errors, for a clean exit from the program.