Classic Computer Magazine Archive COMPUTE! ISSUE 47 / APRIL 1984 / PAGE 152

Qwikload/Save For VIC And 64

Richard L. Witkover

Here is a BASIC program which can drastically reduce your waiting time when loading or saving large blocks of data.

Have you ever sat staring at your television set while saving or loading large blocks of data? If you use the GET# or INPUT# commands, chances are you have. It may have taken only a few minutes, but it seems like forever. You can do it ten times faster by using the Kernal routines built into your Commodore computer.

First, you must tell the Kernal routine where to load the data, or what section of memory to save. The Kernal looks for this information in the microprocessor's internal registers. These registers can be accessed from BASIC via memory locations 780–782. The SYS command transfers the contents of these locations into the registers before it jumps to the machine language routine. Location 780 corresponds to the accumulator, 781 to the X register, and 782 to the Y register. So, all we need to do is POKE the information into these locations and SYS to the Kernal routine. "Qwikload/Save" uses this technique to access the Kernal routines SETLFS, SETNAM, LOAD, and SAVE.

Qwikload/Save allows you to save any section of memory in the 64 and up to location 32766 ($7FFE) in the VIC. Any files saved by Qwikload/Save can also be loaded by the program into any area in RAM. Either tape or disk may be used. Just type in the program, SAVE it, and RUN it.

How It Works

Lines 100–110 ask the user whether to use tape or disk and store the answer in B$. Lines 120–130 ask whether to save or load, storing the answer in A$. Line 140 INPUTs the filename and stores it in F$. Line 144 INPUTs the starting address of the block to be saved or loaded. Then the high byte (AH) and low byte (AL) of the starting address are calculated. Line 147 branches to line 500 if disk was chosen. Line 150 branches to line 300 if load was chosen.

Lines 160–200 save a block of memory to tape. Line 160 INPUTs the end address of the block and calculates the high byte (BH) and low byte (BL). Line 190 jumps to the subroutine at line 400 to open a file. Then the high byte and low byte of the starting address are POKEd into zero page. Line 200 POKEs location 780 (accumulator) with the zero-page address of the low byte used in line 190. This creates a pointer which tells the computer where to find the starting address. The low byte of the end address is POKEd into location 781 (X register) and the high byte into location 782 (Y register). Then the block is saved by SYSing to the SAVE routine in the Kernal. The file is then closed by jumping to line 330.

Lines 300–330 load a file from tape. Line 300 opens the file. Line 310 specifies a LOAD by POKEing 0 into location 780 (0 = LOAD; 1 = VERIFY). The low byte and high byte of the starting address are POKEd into locations 781 and 782, respectively. Then the file is loaded by SYSing to the LOAD routine. Line 320 checks bits 4 and 5 of the STATUS variable. If either bit is set, the file was not loaded correctly and the message ?LOAD ERROR is printed. Line 330 closes the file and ends the program.

Lines 400–440 comprise a subroutine which opens a file to the cassette recorder similar to the BASIC command OPEN 1,1,0,F$. Line 400 POKEs the length of the filename into location 183. The end-of-arrays pointer is calculated and stored in S. Line 410 POKEs the filename into the free RAM area just above the arrays. Line 420 sets up the logical file by POKEing the file number into location 780, POKEing the device number into location 781, POKEing the secondary address into location 782, and SYSing to the SETLFS routine. Line 430 sets up the filename by POKEing the filename length into location 780, POKEing the low byte of the end-of-arrays pointer into location 781, POKEing the high byte into location 782, and SYSing to the SETNAM routine. Line 440 turns on the tape messages (SEARCHING, FOUND, etc.) by setting bit 7 of location 157.

Line 500 branches to line 700 if a disk load is chosen. Lines 530–660 save a block of memory to disk. Line 530 INPUTs the end address, adds 1 to it, and calculates the low byte and high byte. It is necessary to add 1 to the end address in order to save the last byte of the block. Line 540 OPENs the disk error channel. Line 550 OPENs a program file for writing. Line 560 checks for errors by reading the error channel. Line 570 branches to line 650 if no error occurs. Line 580 prints the error information and jumps to line 760 to end the program if the error number is not 63 (FILE EXISTS ERROR).

Lines 590–610 ask whether the user wants to replace the file on disk with the new file. If not, the program ends by jumping to line 760. Otherwise, the file is replaced by scratching the file on disk and saving the new file. Line 620 scratches the old file. Line 630 returns to line 540 to save the new file. Lines 650–660 save the file by POKEing the starting and ending addresses and SYSing to the SAVE routine.

Lines 700–760 load a file from disk. Line 700 OPENs the error channel. Line 710 OPENs the program file for reading. Line 720 reads the error channel. If any error occurs, line 730 prints the error information and ends the program. Line 750 enables a relocatable load by POKEing a 0 into location 185. Then the file is loaded by POKEing the necessary information and SYSing to the LOAD routine as described for tape. Line 760 closes the files and ends the program.

Qwikload/Save For VIC And 64

Refer to the "Automatic Proofreader" article before typing this program in.

100 PRINT "{CLR}TAPE OR DISK (T/D)?";              :rem 125
105 GETB$ : IFB$ = ""THEN105                       :rem 81
110 IFB$<> "T"ANDB$<> "D"THEN105                   :rem 153
120 PRINTB$ : PRINT"{DOWN} SAVE OR LOAD (S/L)?";   :rem 43
125 GETA$ : IFA$ = "" THEN125                      :rem 83
130 IFA$ <> "S" ANDA$ <> "L"THEN 125               :rem 162
140 PRINTA$ : INPUT"{DOWN}FILENAME";F$             :rem 140
144 INPUT"{DOWN} STARTING ADDRESS" ;X :
             AH = INT(X/256) : AL = X - AH * 256   :rem l88
147 IFB$ = "D"THEN500                              :rem 26
150 IFA$ = "L" THEN300                             :rem 25
159 REM TAPE SAVE                                  :rem 220
160 INPUT"{DOWN} END ADDRESS" ;X : X = X + 1 :
       BH = INT(X/256) : BL = X - BH * 256         :rem l71
190 GOSUB400 : POKE251, AL : POKE252, AH           :rem 31
200 POKE780, 251 : POKE781, BL : POKE782, BH : SYS
        65496 : GOTO330                            :rem 247
299 REM TAPE LOAD                                  :rem 210
300 GOSUB400                                       :rem 167
310 POKE 780, 0 : POKE781, AL : POKE782, AH :
       SYS65493                                    :rem 131
320 IF(ST AND 48) THEN PRINT"{DOWN}? LOAD" :
       PRINT"ERROR"                                :rem 96
330 CLOSE1 : END                                   :rem 78
399 REM OPEN TAPE CHANNEL                          :rem 222
400 L = LEN(F$) : POKE183, L : S = 256 * PEEK(50) +
       PEEK(49)                                    :rem 174
410 FORX = 1TOL : POKES + X - 1, ASC(MID$(F$, X, 1)):
       NEXT                                        :rem 53
420 POKE780, 1 : POKE781, 1 : POKE782, 0 :
       SYS65466                                    :rem 209
430 POKE780, L : POKE781, PEEK(49) : POKE782,
       PEEK(50) : SYS65469                         :rem 77
440 POKE157, 128 :RETURN                           :rem 69
500 IF A$ = "L"THEN 700                            :rem 28
529 REM DISK SAVE                                  :rem 222
530 INPUT "{DOWN} END ADDRESS" ; X : X = X + 1 :
       BH = INT(X/256) : BL = X - BH * 256         :rem 172
540 OPEN15, 8, 15, "I0"                            :rem 16
550 OPEN 3, 8, 1, "0:" + F$ + ", P, W"             :rem 157
560 INPUT # 15, EN, EM$, ET, ES	                   :rem 222
570 IFEN = 0 THEN650                               :rem 245
580 IFEN <> 63 THENPRINTEN ; EM$ ; ET ; ES
       : GOTO 760                                  :rem 153
590 PRINT "FILE EXISTS. {2 SPACES}
       REPLACE (Y/N)?" ;                           :rem 58
600 GETA$ : IFA$ = "" THEN600                      :rem 79
610 PRINTA$ : IFA$ <> "Y" THEN760                  :rem 154
620 PRINT#15, "S0 : " + F$ + ", P, W"              :rem 222
630 CLOSE15 : CLOSE 3 : GOTO540                    :rem 100
650 POKE157, 128 : POKE 251, AL : POKE252, AH      :rem 159
660 POKE780, 251 : POKE781, BL : POKE 782, BH : SYS
       65496 : GOTO760                             :rem 8
699 REM DISK LOAD                                  :rem 215
700 OPEN15, 8, 15, "I0"                            :rem 14
710 OPEN3, 8, 0, "0:" + F$ + ", P, R"              :rem 149
720 INPUT# 15, EN, EM$, ET, ES                     :rem 220
730 IFENTHENPRINTEN ; EM$ ; ET ; ES : GOTO760      :rem 179
750 POKE157, 128 : POKE 185, 0 : POKE 780, 0 :
       POKE 7 81, AL : POKE782, AH : SYS65493      :rem 187
760 CLOSE3 : CLOSE15 : END                         :rem 109