Classic Computer Magazine Archive COMPUTE! ISSUE 34 / MARCH 1983 / PAGE 150

Direct Atari Disk Access

Andrew Lieberman

Here are three programs that make disk access easier, display the contents of any sector on disk, and allow you to save screen displays to disk. Caution: these techniques write directly to disk. Be certain that you fully understand how to use these methods or you risk damaging existing disk files. The program opens the door to many interesting and valuable applications. And it's only 67 bytes long.

Even with a fast-formatted disk, the Atari disk drive is slow for many applications if BASIC commands like INPUT, PRINT, PUT, and GET are used. With the machine language subroutine in this article, you can transfer the contents of a specified area of memory to disk, and vice versa, quickly and easily, eliminating the need for the slower BASIC commands.

Program 1 is the source code for the program. Type in the program on your Assembler/Editor, assemble it, and save it with "SAVE#D:SECRAM. OBJ < 601,643". If you do not have the Assembler/Editor, use Program 2. Type in the program, save it, run it, go to DOS, and use option K, binary save, by typing: D:SECRAM.OBJ < 601,643″. It may be a good idea to lock the file.

To use this subroutine in a BASIC program, just add Program 2 to the BASIC program. Be sure the DATA has been put into memory before the routine is used; otherwise, you will crash the system. To call the routine, simply type: I = USR (1537,RAM,SECTOR,NUMSEC,DCOMD).

"I" can be any variable; RAM is the starting memory location; SECTOR is the first sector to be read from or written to. Each disk has 720 sectors, numbered from 1 to 720. The computer fills these sectors starting with 1 and works up, so you should plan to use sectors from 650 to 720 depending upon how many you need.

These sectors are not protected; if the disk starts getting full, your information may be overwritten. Program 3, which is described later, will be a help in preserving your data. NUMSEC is the number of sectors to be copied. There are 128 bytes to a sector and eight sectors to a kilobyte. DCOMD refers to read or write. An 82 here means read from disk to RAM, and 87 means copy memory to disk.

Let's look at an example of all this. Suppose you wanted to copy a modified character set to disk. Suppose further that your character set is located in memory locations 30720 through 31743 and you wanted it stored starting at sector 700. You would first have to calculate that you need eight sectors for the 1024 bytes of character set. Then simply type I = USR(1537,30720,700,8,87). If you did not understand this example, go back and look at what each number means; it should then be clear.

Saving Data And Graphics Displays

There are many applications for this program. Program 3 will display the contents of any sector on a disk. Another application that you are sure to find useful is saving screen displays to disk for quick recovery from within a program. Suppose you wanted to save your current Graphics 0 screen to disk. Simply type: I = USR(1537,PEEK(88) + PEEK(89)*256,680,8,87). Clear the screen and then type: I = USR(1537,PEEK(88) + PEEK(89)* 256,680,8,82).

Voilà! After eight beeps you recover your old screen. If you have a customized display list, you may want to save it also by using: PEEK(560) + PEEK(561)*256 instead of PEEK(88) + PEEK(89)* 256.

You should also find that this program works well when saving and loading character sets and player/missile data. The program should be used in any situation in which the contents of any area of memory should be the same every time, like a character set or a graphics display.

Program 3 is a simple program that copies the contents of a disk sector into a string and then prints the string on the screen. RETURNS are printed as "(RET)", and other editing characters are printed as their graphics symbols, i.e., with an ESCape printed first. This is very useful for finding free space on a disk for saving DATA. If, for example, you wanted to check sectors 700 to 710 to make sure they are empty, just RUN the program, start with 700, then use the right arrow to see what is on 701, etc.

A whole string of hearts (CHR$(0)) indicates an empty sector. Anything else means there is DATA on that sector. This program may also be used to modify DOS and other programs that cannot normally be modified. Look at sector 43 of any DOS II disk. It should be the top of the menu. If it isn't, find the correct sector. Now, BREAK the program and type "PRINT A$". It will be the same as what appeared on the screen except RETURNs and CLEAR SCREENs will be printed.

Try making some changes in the middle of the string. For example, type: A$(71,87) = "A. DISK MENU ". Then save this modified string back to the disk by typing: I = USR(1537, ADR(A$), 43, 1, 87). Now go to DOS, and if all went correctly your change has been made.

Now that you know how to use this program, you probably want to know how it works. Lines 1 through 40 should be fairly obvious. Line 50 clears the keyboard of any key pressed earlier. Line 60 reads the keyboard. A 7 means the right arrow was hit, so the variable SEC is incremented. Line 70 checks for a left arrow in the same way. If no key has been pressed, the program jumps back to line 60 to wait for a key to be pressed. If a key other than left or right arrow was pressed, line 90 accepts the input.

Lines 100 and 110 check to make sure the sector is within the legal limit. Line 130 loads the requested sector into the RAM area of string A$. Instead of just printing the string to the screen, each character is printed one at a time. Before the character is printed, it is checked for being a RETURN (CHR$(155)); if it is a RETURN, "(RET)" is printed instead. Furthermore, an ESCape is printed before each character. If these precautions were not taken, many sectors would clear the screen and do other strange, undesirable things when printed. The extra spaces are printed at the end of the sector to clear away any loose ends left over from the last sector.

Easy Programming

Now for the good stuff: how does this program work in only 67 bytes? The real key to this program is the Operating System subroutine at $E453. Each time it is JSRed to, it takes the information in the lower page three memory locations and processes it, and it does that very quickly. There are many handy subroutines in the Operating System for things like print to the screen, plot, drawto, set up VBLANK, change graphics modes, etc. For more information on how to use the graphics subroutines, get the February 1982 issue of COMPUTE! and look at "Insight: Atari," page 77. These subroutines can make life very easy on a programmer.

You should be able to interpret how the assembly language program works by looking at the comments in the source code. The only part that is likely to be unfamiliar to you is the first part. The first number in the USR command is the starting memory location. The other numbers are all placed on the stack as shown in the table. Lines 260 to 390 pull the values off the stack and put them into the memory locations in which they belong.

There is one other memory location that you may find useful: $303 (decimal 771) shows the status after the most recent operation. A 1 means everything is all right. Any other number is an error code. Errors are usually the result of trying to read a bad, or nonexistent, sector.

Top Of Stack
Number of variables passed xx We ignore this
First number passed hi byte xx RAM pointer
First number passed lo byte yy RAM pointer
Second number passed hi byte xx Sector pointer
Second number passed lo byte yy Sector pointer
Third number passed hi byte xx Number of sectors—we ignore the hi byte because the program is set up to do a maximum of 255 sectors
Third number passed lo byte yy
Fourth number passed hi byte xx Disk command — since this value should only be $52 or $57 we can ignore the hi byte
Fourth number passed lo byte yy
Bottom Of Stack

Program 1.

0100 ;**********************************
0110 ;**A routine for storing RAM on **
0120 ;**a disk or for reading it back **
0130 ;**by ANDREW LIEBERMAN 7/10/82 **
0140 ;**********************************
0150 NUMSEC = $600 ;Number of sectors still to be done
0160 DUNIT = $301 ;Which drive?(1-4)
0170 DCOMD = $302 ;$52 = Read, $57 = Write
0180 DBUFL0 = $304 ;Pointer for Lo byte of RAM
0190 DBUFHI = $305 ;Pointer for Hi byte of RAM
0200 DAUXLO = $30A ;Pointer for Lo byte of sector
0210 DAUXHI = $30B ;Pointer for Hi byte of sector
0220 * = $601
0230 ;The USR command places data on the stack
0240 ;This part of the program pulls the data off and puts it in the
0250 ;proper memory locations
0260  PLA ;We don't care about this
0270  PLA
0280  STA DBUFHI
0290  PLA
0300  STA DBUFLO
0310  PLA
0320  STA DAUXHI
0330  PLA
0340  STA DAUXLO
0350  PLA ;This is assumed to be 0
0360  PLA0370 STA NUMSEC
0380 PLA ; This is assumed to be 0
0390 PLA
0400 STA DCOMD
0410 LDA #$01 ;Assume drive 1
0420 STA DUNIT
0430 LOOP DEC NUMSEC ;One less sector to be done
0440 BMI END ; If minus result, last sector was 0, so branch to END
0450 JSR $E453 ; This is the O.S. subroutine that does all the work
0460 CLC
0470 INC DAUXLO ; Increment sector pointer
0480 BCC SKIP1 ; Check for carry
0490 INC DAUXHI ; There was a carry so hi byte is incremented
0500 SKIP1 LDA DBUFLO ; Since each sector is $80 bytes long, the
0510 CLC ; RAM pointer, DBUF, must be incremented by $80
0520 ADC #$80 ; Add $80 to lo byte
0530 BVC SKIP2 ; If it didn't overflow everything's O.K.
0540 INC DBUFHI ; Lo byte overflowed, so increment hi byte
0550 SKIP2 STA DBUFLO ; Don't forget to store the lo byte
0560 CLC ; A Jump done this way makes the program relocatable in RAM
0570 BCC LOOP
0580 END RTS ; A11 done

Program 2.

1 GOSUB 31000
30999 END
31000 RESTORE 31010 : FOR I = 1537 TO 1603 : READ J : POKE I, J : NEXT I : RETURN
31010 DATA 104, 104, 141, 5, 3, 104, 141, 4, 3, 104, 141, 11, 3, 104, 141, 10, 3, 104, 104, 141, 0,
        6, 104, 104, 141, 2, 3, 169, 1, 141, 1, 3, 206
31020 DATA 0, 6, 48, 29, 32, 83, 228, 24, 238, 10, 3, 144, 3, 238, 11, 3, 173, 4, 3, 24, 105, 128, 80, 3,
        238, 5, 3, 141, 4, 3, 24, 144, 222, 96

Program 3.

1 REM A program to examine disk sectors
5 GOSUB 31000
10 DIM A$(128) : A$(128) = " "
20 GRAPHICS 0 : ? "Type sector number, or use right arrow for next sector, left arrow for last sector."
30 POSITION 2, 5 : ? "{11 M{CLEAR}"
40 POSITION 2, 12 : ? "{4 DEL - LINE {CLEAR} WHAT SECTOR?";
50 POKE 764, 255
60 I = PEEK(764) : IF I = 7 THEN SEC = SEC + 1 : GOTO 100
70 IF I = 6 THEN SEC = SEC - 1 : GOTO 100
80 IF I = 255 THEN 60
90 TRAP 40 : INPUT SEC
100 IF SEC < 1 THEN SEC = 1
110 IF SEC > 720 THEN SEC = 720
120 POSITION 2, 4 : ? "SECTOR #" ; SEC ;""
130 I = USR (1537, ADR (A$), SEC, 1, 82) : POSITION 2, 6 : FOR I = 1 TO 128 : J = ASC (A$(I, I))
140 IF J = 155 THEN ? "(RET)" ; : GOTO 160
150 ? CHR$(27) ; CHR$(J) ;
160 NEXT I : ? "{28 SPACES}" : GOTO 40 : REM about 30 spaces
30999 END
31000 RESTORE 31010 : FOR I = 1537 TO 160 3 : READ J : POKE I, J : NEXT I : RETURN
31010 DATA 104, 104, 141, 5, 3, 104, 141, 4, 3, 104, 141, 11, 3, 104, 141, 10, 3, 104, 104, 141, 0,
        6, 104, 104, 141, 2, 3, 16, 9, 1, 141, 1, 3, 206
31020 DATA 0, 6, 48, 29, 32, 83, 228, 24, 238, 10, 3, 144, 3, 238, 11, 3, 173, 4, 3, 24, 105, 128, 80,
        3, 238, 5, 3, 141, 4, 3, 2, 4, 144, 222, 96