Learn to Implement Vertical Scrolling in BASIC on Atari 8-Bit Computers (30-60 mins)

Task: Learn to Implement Vertical Scrolling in BASIC on Atari 8-Bit Computers

Needed: Turbo BASIC XL

Time: 30-60 mins


I never learned how to program scrolling playfields in BASIC back in the day, but have decided to take the plunge. Over the last few weeks I have read a number of sources and have gained a pretty good understanding of how this is done. This post will cover vertical scrolling. The next one will cover horizontal scrolling which is a bit more difficult to understand and to implement. For a more in depth tutorial in assembly language, I recommend this post from the Player/Missile website.

There are three keys to understanding scrolling on the Atari 8-bit computer. The first is how screen memory is organized and accessed. The second is the display list which specifies where screen memory is when ANTIC draws the screen. The third is the fine scroll registers. I will briefly review each of these in turn.

Screen Memory

When a graphics mode is invoked (e.g. GRAPHICS 1+16) the Atari sets aside the required memory just below the top of the memory map (i.e. RAMTOP) whose address can be found with a PEEK of memory location 106. There is a nice figure and description of this in Chapter 1 of the book Atari Graphics and Arcade Game Design. Note that the display list (discussed next) is stored just below screen memory. For graphics mode 1+16 there are 24 rows of 20 characters or 480 bytes of screen data. The first byte of screen memory is the character in the top left corner of the screen. The first 20 bytes of screen memory hold the first row of characters (or graphics for graphics modes). The next 20 bytes hold the next row or mode line down and so on. So, you can think of the 480 characters making up the screen as a one-dimensional string with 480 characters held in 480 bytes of memory. Vertical scrolling in graphics mode 1+16 is nothing more than moving the start of screen memory forward 20 bytes (i.e. +1 row for scrolling up) or backward 20 bytes (i.e. -1 row for scrolling down). This is done with the display list. In the demo below, I have two screens of data which I read into a memory location I allocate using DIM STRING$(480*2). The DIM tells BASIC to reserve and keep track of that memory location. I use the ADR command to get the address and use this as my own special screen memory location for the display list described below. The two screens allow me to scroll on one screen while the other is being scrolled off. When the first screen is scrolled off (now seeing screen two) I cycle back to the beginning and start over. The screens are the same so it appears as though the bytes are cycling off the top of the screen and immediately back to the bottom in a loop. Here is the BASIC code to refer to for the line descriptions below.

Lines 10-70 perform some initializations. Lines 20 and 30 setup a Graphics 1 screen with a blue background and white characters. Line 40 finds the address of the display list which is automatically created when we invoke the graphics statement. Line 50 initializes a string where we will store the two screens of data. Line 60 finds the memory address of the screen data. Line 70 sets up the variable SCROLL which is initialized to the screen address and then later incremented as part of the vertical scroll.

20 GRAPHICS 1+16
30 SETCOLOR 0,0,14:SETCOLOR 4,7,0
40 DL=PEEK(560)+PEEK(561)*256
50 DIM DAT$(960)

Lines 100 to 160 read in the screen data stored in DATA statements from line 1000 to 1480. Shown below are the first two lines of screen data. Refer to the BASIC code file for all of them. The numbers in the DATA statements refer to the Atari internal character set. See the Table 1 from Chapter 3 of Compute’s First Book of Atari Graphics for the number to character mapping.

110 REM *** EACH SCREEN IS 20*24=480 BYTES ***
130 FOR I=0 to 959
140 READ A
160 NEXT I

1010 DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
1020 DATA 0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

The Display List

The display list is the program that tells the ANTIC chip how to draw the screen. The display list (abbreviate DL in the program below) starts with instructions to draw three blank lines followed by a special first mode line drawn on the visible part of the screen (i.e. first row of characters or graphics). This fourth line of the display list specifies a value of 6 for graphics mode 1 (graphics mode 1 = ANTIC mode 6). We add a value of 64 to the ANTIC mode number (e.g. 6) telling ANTIC that this is the load memory scan (LMS) line. The LMS instruction tells ANTIC that the next two lines of the display list carry the low byte (line 5) and high byte (line 6) of the start of the screen memory. The next 23 lines specify the rest of the 24 mode lines of graphics 1+16. We will modify lines 5 and 6 following the LMS instruction to implement coarse vertical scrolling. Here, we simply add (for scrolling up) or subtract (for scrolling down) 20 lines to the low byte of screen memory and POKE it into line 5 (DL+4) of the display list. Looping will create the vertical scrolling. When we reach the end of a page of memory (one page = 256 bytes) we need to increment or decrement the high byte of screen memory and POKE it into line 6 of the display list. Of course, you need to have another screen of data ready to scroll onto the screen. The demo below has two screens prepared and stored in our own special memory location.

Recall from above the initializations above that line 20 calls GRAPHICS 1+16. This automatically creates a graphics 1 display list for us to modify for the scroll. Line 40 uses some PEEKs to get the address of the display list so we know where to find it.

Lines 200 to 280 modify the display list. Lines 210 and 220 get the low and high bytes of the screen memory location. Line 230 specifies the LMS line mentioned above with a 6 for graphics mode 1, a 64 for the LMS instruction, and a 32 to enable fine scrolling. Lines 240 and 250 provide the low and high bytes of screen memory. Lines 260 to 280 write the rest of the graphics 1 mode lines each with fine scrolling enabled.

230 POKE DL+3,6+64+32
260 FOR I = 6 TO 28
270 POKE DL+I,6+32
280 NEXT I

Lines 310 and 420 specify an outer FOR loop to scroll 24 lines or one screen.

Lines 360 to 400 specify the coarse scrolling by advancing the screen memory (tracked with SCROLL) 20 characters or one mode line at a time. New low and high memory bytes (lines 370 and 380) are then written into the display list (lines 390 and 400). Shifting the location of screen memory in the display list creates the vertical scrolling.

Line 430 resets the screen memory location after one entire screen has been scrolled (and replaced by the second screen). The whole process starts over with a GOTO in line 440.

310 FOR I=1 to 24
320 FOR J=0 to 7
330 PAUSE 0:POKE 54277,J
350 NEXT J
410 POKE 54277,0
420 NEXT I
440 GOTO 300

Fine Scroll Registers

The procedure described above with the display list shifts the screen one full mode line at a time to create coarse vertical scrolling. Fine scrolling is controlled by the vertical scroll register (VSCROL) and moves one pixel at a time (characters have eight rows of pixels to fine scroll). VSCROL is a write-only register at address 54277. A character can be scrolled up by POKEing values 0 to 7 in a FOR loop for each of the eight pixel lines making up the characters. Scrolling down can be accomplished by POKEing values 7 to 0 in a FOR loop with STEP -1. When the character is in its new spot after the fine scroll has completed its coarse position is moved to match as described above. You will see from the demo below that this creates a very nice scrolling effect like you would see in Defender or Caverns of Mars. One thing to keep in mind is that the POKE 54277 doesn’t happen fast enough in Atari BASIC to keep up resulting in some jitters and hiccups on the screen. This timing issue can be addressed in two ways. First, you can write an assembly language routine for the coarse and fine scrolling and execute it during the vertical blank. This is a good way to do it if you are writing a game and performance is essential. I am not covering this method here although there are some good sources such as Chapter 6 of the Atari Assembly Language Programmer’s Guide. For this demo, I took advantage of the PAUSE command available in Turbo BASIC XL. This command pauses the screen after it is drawn thus providing better timing for executing the fine scrolling POKE (see line 330). Works like a charm but you need a flavor of BASIC with the PAUSE command.

Lines 320 to 350 above execute the fine scrolling. Line 330 includes the PAUSE to sync the POKE 54277.


Here is the Fine Vertical Scrolling Video of what you should see when you run the program. Here is the BASIC code in a text file. Here is an ATR file with the BASIC program.

Step 1

Open Altirra and load Turbo BASIC XL. Atari BASIC and Altirra BASIC will not work for this demo because they lack the PUASE command used here.

Step 2

Open the BASIC code in your PC text editor or web browser and copy the text to your clipboard. Click on the View tab of Altirra and choose the paste text option from the bottom of the list. Altirra will slowly paste the text into the BASIC command line. It is important to keep focus on the Altirra window or the paste will stop and it will lose some characters. You can significantly speed this up by selecting Warp Speed from the Altirra System menu. Type RUN.

Step 3

Also try booting the ATR file in Altirra or on your Atari from your PC using SIO2PC. You must have Turbo BASIC XL loaded. See the VSCROLL.TBX file. An SD card-based device such as FujiNet would work well too.


Vertical scrolling is relatively easy to implement but has a lot of moving parts to get your head around as covered in the introduction. Putting all the scrolling code in an assembly routine is needed for a fast game. I cover that later for horizontal scrolling. For now, this provides the basic concepts in BASIC!

Be sure and read this post from the Player/Missile website once you get the basics down.

Caverns of Mars is a great example of vertical scrolling!