APPENDIX THREE

This appendix assumes that you have already read the description of SDLSTL at locations 560 and 561 and SAVMSC at locations 88 and 89.

Since designing a custom graphics mode is so simple, let's jump right into it. The first step is to decide what you want the new mode to look like. In other words, figure out how you want to mix the existing graphics modes. For our example, let's mix graphics modes zero, one, two, and seven.

So far so good. Next comes the tricky part; we have to decide how many rows of each mode we want. Why is this tricky? Because we have to have 192 scan lines altogether (remember that a scan line is the height of a graphics mode eight line, or row). If we have less than 192, then the display will be too short on the screen. Similarly, too many will make it too long. You can try it later and see for yourself. Anyway, we need to know how many scan lines high each graphics mode row is. Figure 57 tells us just that.

 MODE 0 1 2 3 4 5 6 7 8-11 LINES 8 8 16 8 4 4 2 2 1

FIGURE 57. Designing PM graphics modes

For our example, suppose that we definitely want one row of mode two, two of mode one, and three of mode zero. That gives us a total of 16+2*8+3*8 = 56 scan lines, leaving 192-56 = 136 scan lines left over for mode seven. Since mode seven rows are two scan lines high, we can have 68 of them. Oh, I forgot to mention that we're going to want the mode two row on top, followed by half the mode seven rows, the mode one rows, the rest of the mode seven rows, and then the mode zero rows on the bottom.

Now we're ready to make our display list. Since BASIC has a built-in ability to set up a normal display list (and screen memory), let's not waste it. We'll have BASIC set up the mode that uses the most memory out of the ones we want to mix (that way, we know there will be enough screen memory for us). In our case that's graphics mode seven, so we'll start with the following line:

100 GRAPHICS 7+16

We use 7+16 because we don't want a text window. Now we want to change the first row into graphics mode two. First we need to know where the display list is:

110 DLIST=PEEK(560)+PEEK(561)*256

We'll also turn off the screen so that funny things don't happen while we're changing things, and put an endless loop at the end so we won't go back to graphics mode zero when we're through:

120 POKE 559,0
999 GOTO 999

You'll recall from SDLSTL that the first three bytes of a display list are used to keep the first 24 scan lines blank. That means that the fourth byte in the display list is the instruction for the first row. You may also recall that this instruction has an LMS modification to it, since ANTIC has to know where the screen memory is before it can start drawing the screen. So we look at the chart in Appendix Twelve and find that a mode two LMS instruction has a value of 71. So...

130 POKE DLIST+3,71

In case the DLIST+3 is confusing you, keep in mind that DLIST is the first byte, not DLIST+1.

Now we've got our mode two row. Next we want 34 mode seven rows. But wait a minute, we started with a graphics mode seven dispay list so that means that the mode seven rows are already set up for us. Great, let's go on to mode one.

Our two mode one rows will be the thirty-sixth and thirty-seventh rows on the screen, right? That corresponds to the forty-first and forty-second bytes in the display list. Why? Don't forget that the first three bytes are the BLK instructions and then we have two more bytes for the LMS address. Looking at Appendix Twelve again, we see that a graphics mode one instruction has a value of six, so we add the following lines to our program:

140 POKE DLIST+40,6
150 POKE DLIST+41,6

Now we want the rest of our mode seven rows, which again are already set up for us, in DLIST+42 through DLIST+75, so we skip over to mode zero. The seventy-second and seventy-third rows will be mode zero, so we'll change the seventy-seventh and seventy-eighth bytes:

160 POKE DLIST+76,2
170 POKE DLIST+77,2:POKE DLIST+78,2

And now we're done, right? Not quite, we still have to put in the JVB instruction (see SDLSTL):

180 POKE DLIST+79,65
190 POKE DLIST+80,PEEK(560)
200 POKE DLIST+81,PEEK(561)

Now we're done, so let's turn the screen back on:

210 POKE 559,34

Uh-oh, we can see the graphics mode zero rows down at the bottom. That's easy enough to change:

220 SETCOLOR 2,0,0

Much better. Now comes the fun part-trying to put stuff on the screen. There are a lot of problems associated with this, so let's look at them one by one.

We'll start at the top, with our mode two row. What's the problem here? The OS thinks that it's in graphics mode seven, since we told it it was. That's easy to change, however, since DINDEX (87) can be changed to indicate the mode we want:

230 POKE 87,2

Now we can go ahead and PRINT to the row:

240 POSITION 0,0
250 PRINT #6;" graphics mode two"

So far so good; let's go on to the first group of mode seven rows. Unfortunately, we can't just change DINDEX back and go ahead and PLOT and DRAWTO. Why not? Graphics mode seven uses 40 bytes per row while graphics mode two only uses 20 (see SAVMSC). This will cause things to be PLOTted in the wrong place. Try the following to see for yourself:

260 POKE 87,7
270 COLOR 1
280 PLOT 0,1

This causes a pixel to be plotted halfway across the screen instead of in the first column. Not to worry, however, there's an easy solution. We can change SAVMSC to point to the beginning of the mode seven area. By doing that, the upper left corner of the mode seven area will be treated as the beginning of the screen. The only hard thing about doing this is that we have to figure out the memory location of the beginning of the first mode seven row. How do we do that? Well, we know that DLIST+4 and DLIST+5 hold the LMS address, which is the address of the beginning of screen memory. We also know that there is a mode two row between the beginning of screen memory and the beginning of our mode seven rows. From the table at location SAVMSC, we know that a mode two row takes up 20 bytes, so that means the beginning of the mode seven rows is 20 bytes after the beginning of screen memory. All of this together gives us:

260 SCRMEM=PEEK(DLIST+4)+PEEK(DLIST+5)*256
270 MEM7A=SCRMEM+20
280 POKE 89,INT(MEM7A/256)
290 POKE 88,MEM7A-PEEK(89)*256

Now we can go ahead and PLOT and DRAWTO, remembering that there are only 34 mode seven rows before we hit the mode one rows. Oh, we also have to remember to change DINDEX:

300 POKE 87,7
310 COLOR 1
320 PLOT 0,0
330 DRAWTO 159,0:DRAWTO 0,33
340 DRAWTO 159,33:DRAWTO 0,0

For our mode one lines we'll follow the same procedure. There are 1 mode two rows and 34 mode seven rows between the beginning of screen memory and the beginning of the mode one rows. That's a grand total of 20+34*40 = 1380 bytes:

350 MEM1=SCRMEM+1380
360 POKE 89,INT(MEMl/256)
370 POKE 88,MEM1-PEEK(89)*256

And now to PRINT:

380 POKE 87,1
390 POSITION 7,0
400 PRINT #6;"here's"
410 PRINT #6;" graphics mode one"

And so it goes for the rest of the screen:

420 MEM7B=SCRMEM+1420
430 POKE 89,INT(MEM7B/256)
440 POKE 88,MEM7B-PEEK(89)*256
450 POKE 87,7
460 PLOT 0,0
470 DRAWTO 159,0:DRAWTO 0,33
480 DRAWTO 159,33:DRAWTO 0,0
490 MEM0=SCRMEM+2780
500 POKE 89,INT(MEM0/256)
510 POKE 88,MEM0-PEEK(89)*256
520 POKE 87,0
530 POKE 752,1
540 POSITION 10,0
550 PRINT #6;"And now, finally..."
560 POSITION 9,1
570 PRINT #6;"...GRAPHICS MODE ZERO"

Everything here may seem a little overwhelming at first, but it really isn't. Type in the example and make sure you understand it. Make little changes and see what the effect is. In no time at all you'll be whipping up your own graphics modes at the drop of a hat.

Now that you're confident that you know what's going on, I'll mention the catch. Fortunately, the only time you'll run across it is if you're mixing graphics mode eight into your custom mode. You'll recall that back at SDLSTL I mentioned that the graphics mode eight display list has to have an extra LMS instruction so it can cross a 4K boundary. Well, this means that you have to be careful when you start your custom mode with a mode eight display list. First of all, find out where the LMS is. Usually it's the hundredth byte (DLIST+99), but your program should check first to make sure. Once you know where it is, make sure you don't change the two bytes after it, since they are the LMS address. Next, don't forget about those two bytes when you change instructions that come after the LMS. For example, let's suppose that the LMS is at DLIST+99 and you want to change the hundred-twenty-fifth row. Normally this would be DLIST+129, but because of the LMS address it's now DLIST+131. The final thing to watch out for is changing SAVMSC for rows that come after the LMS. What you'll have to do is use the LMS address instead of SCRMEM, and figure out how many bytes past that your mode rows begin. As you can see, this can get to be a real pain in the you-know-what. Unfortunately, there seems to be no way around it.