| This article and utility is just one of the many included on Chris Dewhurst's LUTIUS PROJECT, reviewed in EUG #66, 'The Bible' for any discerning programmer | ![]() |
| Table 1 - how bytes are used to make up the display in various Modes | |||||
| MODE | Bytes per char | Chars per row | Bytes per char row | Columns per char | Columns per char row |
| 0 | 8 | 80 | 8*80 = 640 | 1 | 1*80 = 80 |
| 1 | 16 | 40 | 16*40 = 640 | 2 | 2*40 = 80 |
| 2 | 32 | 20 | 32*20 = 640 | 4 | 4*20 = 80 |
| 4 | 8 | 40 | 40* 8 = 320 | 1 | 1*40 = 40 |
| 5 | 16 | 20 | 16*20 = 320 | 2 | 2*20 = 40 |
| Table 2 - Screen Registers and values to put in them | ||
| Register | Function | Value to put in |
| R1 | Screen width | b%*w% DIV 8 |
| R2 | Horizontal screen position | (b%*c%-b%*w%) DIV 16 |
| R6 | Screen length | l% |
| R7 | Vertical screen position | (36+l%) DIV 2 |
| R12 | High byte of start of screen | s% DIV 8 MOD 256 |
| R13 | Low byte of start of screen | s% MOD 8 MOD 256 |
| b% | = | bytes per character |
| c% | = | default characters per row |
| d% | = | default R2* |
| l% | = | new screen length in characters |
| s% | = | start of screen in RAM, calculated by &8000-w%*b%*l% |
| w% | = | new screen width in characters |
| Table 3 - Default screen register values | ||||||
| Mode | R1 | R2 | R6 | R7 | R12 | R13 |
| 0 | 80 | 97 | 32 | 34 | 6 | 0 |
| 1 | 80 | 97 | 32 | 34 | 6 | 0 |
| 2 | 80 | 97 | 32 | 34 | 6 | 0 |
| 4 | 40 | 49 | 32 | 34 | &B | 0 |
| 5 | 40 | 49 | 32 | 34 | &B | 0 |
VDU 23,0,register_number,value,0,0,0,0,0,0
which can, in Basic, be abbreviated to:
VDU 23;register_number,value;0;0;0;
Type in this short program:
10 MODE 2 20 VDU 19,0,1;0; 30 VDU 23,1,40;0;0;0;
Line 30 is our new VDU 23 statement, and line 20 simply puts on a red background so that you can see how we are progressing. The left half of the screen should be red and the right half black.
The next thing to do is tell the BBC the length of our screen. This goes into R6, and, thankfully, it's not as complicated, because it's simply the number of characters (or columns, if you like) down the screen. (You can't have a length of several characters-and-a-bit, like you can the width; it's either one extra or none extra.) Add:
40 VDU 23,6,16;0;0;0;
to the program and run it again. You'll notice from the table that R6 is always 32 because there are always 32 rows of characters down the screen in every graphic Mode.
The red box doesn't look very good sitting at the top left corner of the screen, does it? We'll centralize it with registers 2 and 7. R6 controls the horizontal screen position, and R7 the vertical position on your monitor. Increasing R2 moves the screen to the left and decreasing it moves it to the right. Increasing R7 moves the display up and decreasing it moves it down.
You'll have to experiment to see which values suit your particular TV or monitor, though the formulas I've worked out in Table 2 should work with most. Using certain values will cause the screen to go crazy: to get rid of it, simply change Mode.
Our values, then:
| R2 | R7 | |
| = 97-(32*20-32*10)/16 = 97-20 = 77 |
= (36+16)/2 = 26 |
50 VDU 23;2,77;0;0;0; 60 VDU 23;7,26;0;0;0;
We now have our screen centralized, but we're not even half way! We need to tell the BBC the size of our screen and where it is located in RAM. The necessary pokes are shown in Table 4:
| Table 4 - Locations in RAM whose contents are changed for new screens | ||
| Location | Name | Basic commands |
| &E0/&E1 | Pointer to screen lookup table | ?&E0=table MOD 256: ?&E0=table DIV 256 |
| &34E | High byte of the top of the screen address | ?&34E=s% DIV 256 |
| &352/&353 | Bytes per character row | ?&352=(b%*w%) MOD 256 ?&353=(b%*w%) DIV 256 |
| &354 | High byte of screen size | ?&354=(w%*b%*l%) DIV 256 |
90 ?&354=&14
From this we can work out where the screen should start in RAM by subtracting &1400 from &8000 (the end of RAM) to give &6C00. You could, of course, locate the screen anywhere in RAM, but unless you know what you're doing, stick to this method. The high byte of &6C00 is &6C, and this must be poked in at &34E:
100 ?&34E=&6C
We have to tell the operating system about the start-of-screen address as well, and we do this with registers 12 and 13. Strangely, we have to feed in the screen size divided by 8. In our example it is &6C00/8 = &D80. The high byte of &D80 is &D and the low byte is &80. The high byte is put into R12 and the low byte into R13 (contrary to the usual low byte-high byte fashion).
70 VDU 23;12,&D;0;0;0; 80 VDU 23;12,&80;0;0;0;
The last value that must be adjusted in page 3 is at locations &352/&353. These simply contain the number od bytes per row. Multiply the number of bytes per character by the number of characters across the screen. In our case it's 10*32 = &140
110 ?&352=&40 120 ?&353=1
Finished? No! There's still something wrong, because when you press Return, the prompt is always on the next line but one, and when you reach the bottom of the screen you can't see what you're typing.
As you might have guessed, the BBC doesn't know you want the next line of characters to begin 10 characters (or rather 320 bytes) after the previous line, and that the display is to be scrolled after the 16th line.
Unfortunately, there's no way around this on the BBC Master. But on the BBC B, we can create a table of 'look-up addresses', offsets from the top of the screen (&&C00) pointing to the address of each of the 16 lines. Usually the BBC refers to a 640-times table, located at &C375 in the OS ROM. This address is stored in zero page at &E0/&E1. We simply substitute the address for the address of our own table:
130 table=&900 140 FOR L%=0 TO 15 150 B%=L%*&140 160 ?(table+L%*2)=B% DIV 256 170 ?(table+1+L%*2)=B% MOD 256 180 NEXT 190 ?&E0=0:?&E1=9
Our table begins at &900 (line 110). Line 120 sets up a loop for the 16 lines down our Mode 2 screen. Line 130 assigns the actual offset of line L% to B%. For some reason, if you're in Mode 4 or 5, this number must be multiplied by 2, that is:
150 B%=L%*&280
Line 190 pokes the values of the low and high bytes of the table into &E0/&E1. The table consists of 32 bytes of 16 addresses, each two bytes long. Yours will be different depending on the screen size. If, say, your screen was 10 by 32 characters, there would be 64 bytes of 32 addresses in the table.
My table begins at &900, but you could use other areas of memory, provided it isn't the disc RAM, &D00-&10FF, and steer clear of the area above PAGE where your Basic program may sit. A good alternative is to store it in the extra memory created from shrinking the screen.
If you are programming in Basic, we can raise HIMEM to make use of the extra memory:
200 HIMEM=&6C00
Finally, we must set up a text window:
210 CLS 220 VDU 28,0,15,9,0
And if you're going to be drawing in the new Mode, set the graphics origin:
230 VDU 29,0;512;
Phew! We've done quite a bit of programming to set up our new screen, haven't we? After all that, I've made life easier by writing an utility, DIYSCR. After being given the screen dimensions and the Mode it is derived from, it will do all the necessary calculations, and assemble a machine code program to do all the initialization I've just talked through. It wll be saved as a small file, and all you do is *RUN it in the relevant Mode.
All that you have to to is input the source Mode and width and length of the screen in characters. Screen sizes larger than the standard size for the Mode you typed in won't be accepted. You can have larger screens if you really want, but you'll have to program them by hand.
![]() That'll Take You One Step Closer To Writing Something Like RANSACK! |
Christopher Dewhurst, EUG #67