Classic Computer Magazine Archive COMPUTE! ISSUE 72 / MAY 1986 / PAGE 73

Loading And Linking
Commodore Programs
Part 3

Jim Butterfield, Associate Editor

This month's installment shows how one program can automatically load and link to any other program. The methods described here work on any eight-bit Commodore computer with either disk or tape.


There are three major ways of connecting Commodore programs together. Chaining allows several programs to perform a job, each program continuing the work that a previous program has done. Loadlinking enables one program to activate another, with the new program starting fresh on a new task. Overlaying allows a main program to call in additional subroutines, data tables, or display information. This article discusses load-linking.
    When a first program has finished a job, it may decide to load-link to a second program to do a succeeding task. The new program is not a continuation of the previous program-it's a brand new job and won't share any information from the earlier program unless it happens to use a common data file. Load-linking is harder to achieve on Commodore computers than chaining (see Part 2 of this article, April COMPUTE!). You must do a little extra work to load-link.

Why Load-Linking?
It's common, especially on non-Commodore machines, to have a disk start with a menu program which lets a user pick another program to run. The menu program has to load-link the chosen program, since the new program is not a continuation of the menu. Newcomers to Commodore computers often try to chain from the menu program to the other program. However, chaining requires the first program to be the larger of the two, and menu programs are almost always very short.
    At other times, when a group of programs work with one or several data files, it's common for these programs to run independently of each other. Each may use the files in different ways, with data stored in various kinds of arrays for each job. Independent programs call for load-linking.
    Sometimes, a series of modules are arranged to work together as a unit. There may be a main program, some machine language programs in varying locations, perhaps a high-resolution graphics screen, and possibly a special character set. The Commodore B128 (called the 700 series in Europe, and not to be confused with the Commodore 128) often requires a transfer sequence program in order to run machine language programs. All the various parts need to be arranged in the proper areas of memory. A special program called a bootstrap or boot brings everything in. When the bootstrap program has completed its work, often you want to erase it from memory after it sets the main program into operation. Load-linking can accomplish this job, too.

Two Methods
There are two major ways to load-link programs. One technique is used at the end of the first program, setting up the load of the second. It's a variation of the dynamic keyboard technique. The alternative method is used at the beginning of the second program, cleaning up some of the things that have happened during the loading process.
    The dynamic keyboard method is probably the simplest. Essentially, it simulates a user typing on the keyboard, giving LOAD and RUN commands. When you type LOAD as a direct command, the new program comes in fresh. It scraps the old program and retains no variables or other data. That's what we want with a load-link, of course. RUN then sets the new program off to a fresh start.
    The pointer cleanup method corrects conditions that result from program chaining. The start-of- variables pointer needs to be corrected so it is set directly behind the last byte loaded; then a CLR command erases any leftover variables and fixes up the other pointers. We'll try each method in turn.

Dynamic Keyboard
The dynamic keyboard technique is often described as "making the computer type on its own keyboard." To do this, a program stuffs characters into the computer's keyboard buffer and resets the buffer counter. When the computer discovers these characters in the buffer, it thinks they were actually typed on the keyboard and executes the commands they spell out.
    Since the keyboard buffer normally holds only about nine or ten characters, we can't store a complete load sequence there. But we can use Commodore's screen-editing capability. We print a command on the computer's screen, move the cursor back onto the command line, then store one character (a carriage return, character 13) in the buffer. To perform LOAD followed by RUN, we print two command lines and store two RETURNs in the buffer. The effect is the same as if you typed in the LOAD and RUN commands by hand. The new program starts as a fresh, independent job-you'll have performed a successful load-link.
    The keyboard buffer and its counter occupy various memory locations in different Commodore computers. You'll need to use the appropriate addresses for your machine. The following table will help:
    To execute two command lines with this method, we'll POKE a value of 2 into the counter and a value of 13 (RETURN) into the first two locations of the buffer. The following example uses Commodore 64 addresses.

Dynamic Keyboard Example
Let's write two simple programs and let the menu program select which one to run. Type in this simple square root program:

100 PRINT "TABLE OF SQUARE ROO
   TS"
110 FOR J=1 TO 20
120 PRINT J, SQR(J)
130 NEXT J

    You can try running the program if you want. It's not very exciting, but it does work. Now save it with the filename SQUARE (don't substitute any other filename). Type NEW and enter this simple cube root program:

100 PRINT "TABLE OF CUBE ROOTS
   "
110 X=1/3
120 FOR I=1 TO 20
130 PRINT I, I↑X
140 NEXT I

    Again, you might try running the program. Save it with name CUBE when you're satisfied that it works. Type NEW again. Now we'll write a simple loading program that uses the dynamic keyboard technique to perform load-linking. This program runs as listed on the VIC-20 and Commodore 64. For another type of machine, use the table above to change the POKE addresses in lines 280, 290, and 300.

100 DATA SQUARE,CUBE
110 READ A$(1),A$(2)
120 PRINT "WHICH ROOTS DO YOU
   {SPACE} WANT--"
130 FOR J=1 TO 2
140 PRINT A$(J)
150 NEXT J
160 INPUT "WHICH (1 OR 2)";N
170 IF N<1 OR N>2 GOTO 120
180 PRINT CHR$(147)
190 PRINT
200 PRINT
210 PRINT "LOAD";CHR$(34);A$(N
   );CHR$(34);",8"
220 PRINT
230 PRINT
240 PRINT
250 PRINT
260 PRINT "RUN"
270 PRINT CHR$(19)
280 POKE 198,2
290 POKE 631,13
300 POKE 632,13
310 END

    In this case, the menu program is longer than the programs it loads. But that doesn't matter. This method works the same regardless of the length of the programs involved. You will see the LOAD and RUN commands appear on the screen.

Pointer Cleanup Method
The previous method puts extra commands in the first program to load the second. Now we'll look at another method that adds commands to the start of the second program. At this point, the new program has been chained-the old variables and their pointers still exist. To start out fresh, we must erase the old variables and make sure that new variables go into the proper memory area. What we're doing is changing a chain into a load-link.
    Our task is to set the start-of-variables pointer to the correct address and then perform CLR to erase the old variables. On the B128 and Commodore 128 in 128 mode, there's a slight difference. Here, we don't need to set the start-of-variables, since variables are held in a different memory bank. Instead, we set a different pointer (called end-of-BASIC) which doesn't exist on the other machines.
    Now that we know which pointer to change, we must decide what value to put there. The value will be the address of the last byte loaded, plus one. Immediately after a load, we can find this address still in a pointer. Here's a table to show the various locations:





 Key
Counter


Start of
  Buffer

VIC-20, Commodore 64

  198

  631
Commodore 128 in 128 mode   208
  842
Commodore 16, Plus/4   239
1319
PET/CBM with 4.0 BASIC   158
  623
Original ROM PETs   525
  527
B-128 (Model 700)

  209
  939


Pointer
  to be
changed

  Pointer
where value
  is found

VIC-20, Commodore 64

45/46

 174/175
Commodore 128 in 128 mode
4624/4625  174/175
Commodore 16, Plus/4 45/46
 157/158
PET/CBM with 4.0 BASIC 42/43  201/202
Original ROM PETs 124/125  229/230
B-128 (Model 700)

47/48
 150/151


    After the pointer is fixed, be sure to perform CLR to reset all the other variable pointers. Again, these steps must be taken at the very beginning of the new program.

Pointer Cleanup Example
Here's an example similar to the previous one which demonstrates the second method. This is the menu program:

100 DATA SQUARE1,CUBE1
110 READ A$(1),A$(2)
120 PRINT "WHICH ROOTS DO YOU
   {SPACE}WANT--"
130 FOR J=1 TO 2
140 PRINT A$(J)
150 NEXT J
160 INPUT "WHICH (1 OR 2)";N
170 IF N<1 OR N>2 GOTO 120
180 LOAD A$(N),8

    Notice that this menu program is much shorter than the first example. We'll do the extra work when we write the programs to be loaded. Save the menu program, then enter NEW and type these lines:

70 POKE 45,PEEK(174)
80 POKE 46,PEEK(175)
90 CLR
100 PRINT "TABLE OF SQUARE ROO
   TS"
110 FOR J=1 TO 20
120 PRINT J, SQR(J)
130 NEXT J

    This is similar but not identical to the first square root program. The difference is the three extra lines at the beginning. Don't try to run this program yet; instead, save it with the filename SQUARE1. Enter NEW a second time and enter this simple cube root program:

70 POKE 45,PEEK(174)
80 POKE 46,PEEK(175)
90 CLR
100 PRINT "TABLE OF CUBE ROOTS
   "
110 X=1/3
120 FOR I=1 TO 20
130 PRINT I, IX
140 NEXT I

    Save this program with the filename CUBE1. If you have a computer other than the Commodore 64 or VIC-20, remember to change the POKE and PEEK values in lines 70 and 80 of both these programs according to the table above.
    Now load the menu program and run it. You've seen two different ways to perform load-linking. A program can get another program off to a clean start by using either of these techniques.