Section one: the 6845 CRTC


The television section of the BBC micro is based around a special chip, the 6845, running in conjunction with the ULA. There are other bits and bobs, but we are not concerned with them for the moment. Both of these chips rival the 6502 as far as complexity is concerned, but the 6845 is considerably easier to use. This chapter describes the hardware used, and how to program the 6845 yourself.

Before discussing the Beeb way of doing things, it is important that you understand how the video section of a typical, old fashioned, micro works. The following account is based on the old PET's video section.

An area of 1000 bytes of memory is used by both the computer and the video circuitry. To the computer this area appears as a normal block of memory, starting at address 32768 and continuing to 33767, assuming the screen format is 25 lines of 40 characters. The video circuitry translates data stored in the memory to the pictures you see on the screen. It does so by accessing each character position of the block in turn, and then displaying the correct character at the correct point on the screen. A description follows the circuit diagram.

This circuit is simplified -- some of the important points and features have been left out. Each character on the PET screen is made up out of an 8 by 8 matrix, the same as the BBC micro in modes 0 to 6. Thus, there are 64 bits needed to make up each character. These bits are stored in the 'character generator' like this:

ADDRESSBINARY DATA
000000000000
000100111100
000200100100
000300100100
000400100100
000500100100
000600111100
000700000000

And so on with the rest of the characters. The character shown above is a 'box' shape. As you can see, eight bytes of storage are required for each character. The type of ROM used for a character generator can hold 2048 bytes, which means that its address bus is 11 bits wide. If you divide 2048 by eight you get 256, which is the total number of displayable characters on the PET screen. 256 characters need eight bits to be represented uniquely. So, the 11 address lines of the character generator are used as follows:

Low order 3 bits -- character row (0 to 7)
High order 8 bits -- character select (0 to 255)

So to access the data stored in the 5th row of the 45th character, we need to put the following data on the character generator's address lines:

A0 to A2 -- 5
A3 to A10 -- 45.

You can see the 11 lines going in to the character generator in the diagram. The data bus of the character generator is connected to a serializer, which is a simple chip which accepts eight bits, and then clocks the bits out at a pre-determined rate, one at a time. This chip is typically a 74165.

Thus, to display the fifth row of the 45th character, the above procedure should be carried out, and the required byte will be clocked to the TV by the serializer.

You can also see from the diagram where the eight 'character select' inputs to the character generator come from -- they are simply the contents of the memory location currently being accessed in the VDU RAM. The 'row select' signal comes from the TTL bits and pieces. These pieces access the VDU RAM at the right time, with the right row output to the character generator, eight times, once for each row of each character.

The point of that explanation was to show you how the character generator works. This arrangement is similar to that used in the teletext mode of the BBC computer, except a special character generator is used, the SA5050, and the matrix for each character is much larger, 16 by 16.

The other modes are dot resolution modes. Before discussing these modes, we have to make another comparison, this time with the Atom. The Atom's highest resolution screen is mapped like this, with reference to the start of VDU RAM, which is again 32768:

Contrast this to the BBC's arrangement:

It looks a little odd compared to the Atom arrangement, but we shall see that it is logical.

To put off the moment when we have to start on the rest of the hardware, here are the details of how the individual bits map on to the display.

In all modes with two possible colours, the arrangement is as follows:

Pixels:p0p1p2p3p4p5p6p7
Bits:b7b6b5b4b3b2b1b0

In this table, p0 is the leftmost pixel of a group of eight, and b0 is the low order bit. Therefore, a byte with 128 in it will appear as 'XOOOOOOO', where an 'X' represents a white spot, and 'O' represents a black spot.

In modes with 4 colours, each byte only accounts for four pixels. The arrangement is like this:

Pixelp0p1p2p3
Bits:b0/b4b1/b5b2/b6b3/b7

This arrangement is a bit odd, but will only really concern the machine code programmer.

Mode 2 is mapped like this:

Pixels:p0p1
Bits:b0/b2/b4/b6b1/b3/b5/b7

The best way of experimenting to see these arrangements is to move to the required mode, press 'return' a few times and then type CLG. The top left of the screen will now be blank. You can put any byte you like into the top left position using '?H.=X', ('H.' is the abbreviation for HIMEM). When doing this, do not scroll the screen.

Back to the BBC computer's circuits:

I have chosen mode 4 as an example, but all modes work roughly the same, except mode 7.

The 6845 is a clever piece of equipment, which basically acts as the TTL bits and pieces in the PET. There are some more sophisticated things it can do. It generates the cursor, scrolls the screen and deals with the light pen.

Take a look at the circuit diagram:

The first important point to note is the absence of a character generator. The second difference between this diagram and the first is that the PET VDU takes 1000 bytes of RAM, but the BBC computer takes a vast 10K to generate a picture.

The same process is carried out to generate a picture as on the PET, except that the character generator row address makes up the lowest three bits of the VDU RAM address. Thus, rather than the code for a particular character being held in VDU RAM, the dot pattern for the entire character is held, byte by byte in VDU RAM.

Each VDU RAM location is only accessed once, but if you forget about the low order three bits for the moment, each group of eight VDU RAM locations is accessed eight times, once for each row of each character.

In the case of graphics, because each screen location is in effect its own character generator, VDU RAM can be written bit (as in byte) by bit.

The role of the ULA is to deal with the scrolling mechanism, the colours, and the addressing mechanism, because the character generator is only used in mode 7.

All communications between you and the 6845 are carried out via 18 'ports'. These ports are like variables, except that some may only be written to, and some others may only be read and two can be both written to and read from. These ports are referred to as 'register'.

There are ways to get a number into a register. You can either use the command 'VDU 23, 0, reg, val, 0;0;0;' to copy the number 'val' into register number 'reg' (the registers are numbered 0 to 17), or you can execute the statements '?&FE00=reg: ?&FE01=val'. The second way is usually best to use in machine language, and the first is the neater way in BASIC.

There is only one way to read the number held in a register. Execute '?&FE00=reg: val=?&FE01' to copy the value in register 'reg' to variable 'val'.

If you have your machine turned on, you will find it helpful to enter the following procedure and function, used to read and write to the registers, so you can experiment with the registers discussed in the next few pages.

 900 REM ****************************
 910 REM This procedure loads register
 920 REM 'reg' with 'val'.
 930 REM ****************************
1000 DEF PROCLOAD(reg,val)
1010 VDU 23,0,reg,val,0,0,0,0,0,0
1020 ENDPROC
1030 REM ****************************
1910 REM This function returns the
1920 REM value in register 'reg'.
1930 REM ****************************
2000 DEF FNREAD(reg)
2010 ?&FE00=reg
2020=?&FE01
2030 REM ****************************


There follows a description of each of the 18 registers.

The first few registers are not very interesting, in that altering them serves no useful purpose, except sometimes collapsing your display, so I'll skate over them quickly.


Register 0 -- 'Horizontal total'. (Write only).


The contents of this register determine the total time allocated to each scan line in terms of character clocks. In other words it contains the total number of displayed and undisplayed characters on the screen, minus one, per horizontal line. Thus it determines the horizontal SYNC frequency. Its contents in the various modes are as follows:

Mode --01234567
Contents --12712712712763636363

The numbers are larger than the number of characters per line, to allow for a border. This leads on to an important point, namely that from the above table, it looks as though modes 0 to 3 have the same number of characters, as do modes 4 to 7. This is in fact so.

It transpires that modes 0 to 3 have 80 characters to a line, and the others have 40. The reason why modes 1,2, and 5 do not appear to have the right number of characters per line is that they allow more than two colours. The range of values for register 0 is 0 to 255.


Register 1 -- 'Characters per line'. (Write only).


This register determines the number of characters to be displayed on each horizontal line. This register is loaded with the number of characters actually displayed per line. Thus, the difference between this register and register 0 are the borders on the sides of the display.

The contents of this register in each of the modes are as follows:

Mode --01234567
Contents8080808040404040

This table reinforces the comments I made about the number of characters per line in the discussion of register 0.

You can put anything you like in this register and see the effect, but if you make the contents of this register larger than the contents of register 0, the display collapses. This is because the border will be a negative number of characters, which confuses the 6845.

If you just increment or decrement this register from its normal value, you get a slanted display, which can be quite dramatic. This program uses register 1 in a number of ways.

   10 MODE 5
   20 VDU 19,3,4,0,0,0,19,0,7,0,0,0,19,
      2,0,0,0,0
   30 FOR T=0 TO 14
   40 COLOUR RND(3)
   50 PRINT "Interface..."'
   60 NEXT T
   61 TIME=0
   62 REPEAT UNTIL TIME>100
   70 TIME=0
   80 REPEAT
   90 FOR T=1 TO 40
  100 PROCLOAD(1,T)
  110 G=TIME
  120 REPEAT UNTIL (TIME-G)>20
  130 NEXT T
  135 G=TIME
  136 REPEAT UNTIL (TIME-G)>50
  140 FOR T=39 TO 2 STEP --1
  150 PROCLOAD(1,T)
  160 G=TIME
  170 REPEAT UNTIL (TIME-G)>20
  180 NEXT T
  190 UNTIL TIME>1000
  200 TIME=0
  210 REPEAT UNTIL TIME>100
  220 MODE 2
  230 PROCLOAD(1,79)
  240 TIME=0
  250 REPEAT
  260 COLOUR RND(7)
  270 VDU 8,8,42
  280 UNTIL TIME>1000
  290 REPEAT UNTIL FALSE
  999 REM ****************************
 1000 DEF PROCLOAD(reg,val)
 1010 VDU 23,0,reg,val,0,0,0,0,0,0
 1020 ENDPROC 
 2000 DEF FNREAD(reg)
 2010 ?&FE00=reg
 2020=?&FE01


The range of values for register 1 is 0 to 255 -- but more realistically the upper limit is the contents of register 0.


Register 2 -- 'Horizontal SYNC position'. (Write only).


This register establishes the point where the horizontal SYNC signal switches. It is specified in terms of characters. The reference point is the left most character position displayed on the screen.

What this means is that this register determines the displacement from the left-hand side of the screen of the left most character in the display. The contents of this register in each of the 8 modes are as follows:

Mode --01234567
Contents --9898989849494951

If you increase the number given in the above table the whole display will move to the left, if you decrease it, the display moves to the right. Some characters may be lost at the edges of the screen. Altering the value more than a few characters collapses the display.

The range for this register is 0 to 255.


Register 3 -- 'Horizontal SYNC width'. (Write only).


This register establishes the duration of the horizontal SYNC pulse. DO NOT ADJUST IT!!!


Register 4 -- 'Vertical total'. (Write only).


This register gives the total number of displayed and undisplayed character rows, or lines. The contents of this register in the 8 modes are as follows:

Mode --01234567
Contents --3838383038383030

As a consequence of its function, this register helps determine the frame refresh rate, 50 Hz. Thus, if you alter its value too radically, you're likely to lose synchronisation.

There is a little point in altering this register, except that if you reduce its value by about 1 or 2, it is possible to move the display up the screen a bit.

The range of this register is 0 to 127.


Register 5 -- 'Vertical SYNC adjust'. (Write only).


It was stated above that register 4 helps determine the frame refresh rate. Register 4 is a coarse adjustment, while register 5 enables more accurate, fine, adjustments to be made. Zero is usually stored in this register, except in mode 7, where 2 is stored.

If you alter this, you can move the vertical position of the display a little, but numbers should be kept fairly low -- some televisions are not very tolerant of differences in the SYNC pulse, and so many cause the picture to collapse.

The range of register 5 is 0 to 31.


Register 6 -- 'Character rows per frame'. (Write only).


This register allows you to alter the number of lines displayed on the screen. There are, however, some severe limitations. In mode 7, altering the number of lines causes characters to be sliced up, and in other modes, increasing the number of lines beyond the normal will lead to repetitions, ie some lines appear twice! Also, the height of the lines is not affected, so if you ask the computer to display 40 lines in mode 0, it will, but six of them will probably be off the display. Reducing the number of lines is quite possible.

The range of this register is 0 to 127.


Register 7 -- 'Vertical SYNC position'. (Write only).


This register normally contains the number of lines on the screen, plus three.

Altering this register gives you another way of moving the picture up and down the screen. Increasing it from its normal value moves the display up, and decreasing it moves the display down. A similar function is performed by the *TV MOS command.

The range of this register is 0 to 127.


Register 8 -- 'Interlace mode'. (Write only).


This register holds a number between 0 and 3 inclusive. The effects of the numbers are as follows:

0 -- Non-interlaced picture
1 -- Interlaced SYNC picture
2 -- Non-interlaced picture
3 -- Interlaced SYNC and VIDEO picture

Mode 7 is interlaced with SYNC and VIDEO. All other modes are just interlaced SYNC.

Interlaced pictures are more complete than non-interlaced pictures -- if you turn off interlace (which you can't do in mode 7) the lines that made up characters become visible.

There is little point in altering this register. If you do want to, you are better off using *TV with a second argument, as described in the User Guide.


Register 9 -- 'Scan lines per row'. (Write only).


The contents of this register determine the total number of vertical dots that go to make up each character. Its contents in each mode are as follows:

Mode --01234567
Contents --777977918

In fact, the number loaded is one less than the total, so the numbers above tell us that there are eight vertical dots to characters in modes 0,1,2,4 and 5, which we knew already from our knowledge of the VDU 23 command for redefining characters 224 to 255. It also tells us that in modes 3 and 6, two extra lines are inserted, to give the spacing between lines.

You can see the size of the mode 7 matrix from the last value in the table.


Register 10 -- 'Cursor start line'. (Write only).


Each character on the display stretches over a number of 'scan lines'. The exact number for each mode is given in the section on register 9. The cursor can extend between any two of these scan lines. In mode 7, for example, the cursor starts and stops on the last scan line of the character, giving the impression of a single bar, but in modes 3 and 6 it starts on scan line 7, and finishes on scan line 9, which is why the cursor appears thicker in these modes.

The contents of this register determined the first scan line on which the cursor will appear. Thus, its contents in each of the 8 modes are as follows:

Mode --01234567
Contents --777777718

In fact, the register does not contain these numbers on their own. However, register 10 does contain numbers combined with information about the flash rate of the cursor, and whether it is visible or not. Add these numbers for the following attributes for the cursor:

Number to be addedAttribute
0Cursor doesn't blink
32Cursor invisible
64Cursor flashes quickly
96Cursor flashes slowly

The cursor normally flashes slowly, so the actual values stored for each mode are as follows:

Mode --01234567
Contents --103103103103103103103114
(96+7)(96+7)(96+7)(96+7)(96+7)(96+7)(96+7)(96+18)

If you execute 'VDU 23,0,10,64,0;0;0;', to make the cursor blink quickly and start at the first scan line, in mode 7, you will be amazed to see that if you type control-K a few times (so that the cursor is over some character already on the screen) reverse field characters can be displayed. Altering the above 64 to zero would give a solid, unblinking, cursor, which would show the effect better. It is normally impossible to display reverse video in this way in mode 7.

One application of this register is to alter the cursor's appearance in a program to show which mode you're in (I don't mean screen mode). I will give some examples of cursors after the discussion of the next register. The range of the first part of this register is 0 to 31.

Register 11 -- 'Cursor stop line'. (Write only).


This register gives the last scan line on which the cursor will appear. Its contents in all the modes are as follows:

Mode --01234567
Contents --777977919

(This table gives the impression that the mode 7 cursor is two scan lines deep -- it is, but because of the way the SA5050 character generator operates, only one scan line appears to be used).

All of the following examples are to be tried in any mode but mode 7.

Start scan lineStop scan lineEffect
00Underlines the
character above the
cursor
44Gives a narrow,
centralized, dash
cursor
36Gives a thick dash as
a cursor
47Gives a cursor
occupying half the
space allocated to it.

You can probably quite easily make up your own cursors -- but remember, contrary to popular belief, you cannot make the cursor any ASCII character you want.


Registers 12 &13 -- 'Top of page'. (Write only).

MSB LSB


These two registers behave differently in modes 0 to 6 from mode 7. I'll discuss them first in modes 0 to 6, then go on to talk about mode 7.

MODES 0 TO 6:

In these modes, registers 12 and 13 indicate the lowest memory address that is being used by the current screen mode. For this purpose the least significant byte of the address is stored in register 13, and the most significant is stored in register 12. However, you don't store the actual address in these registers -- you have to use the address divided by 8. So this procedure will, in combination with the one you've already got in memory, make the current screen mode start at any address you choose:

  30 REM This procedure makes
  40 REM VDU RAM set any address
  50 REM (modes 0 to 6 only)
 800 DEF PROCSTART(address)
 805 address=address DIV 8
 810 PROCLOAD(12,address DIV 256)
 820 PROCLOAD(13,address MOD 256)
 830 ENDPROC
 999 REM ****************************
1000 DEF PROCLOAD(reg,val)
1010 VDU 23,0,reg,val,0,0,0,0,0,0
1020 ENDPROC
2000 DEF FNREAD(reg)
2010 ?&FE00=reg
2020=?&FE01


One interesting thing you can do with this procedure is to set the display to start at address 0. If you do, you can see all the lower memory locations being changed very rapidly. Run through the following examples:

Execute MODE 0/VDU 28,0,10,79,0/PROCSTART(0) to put you in mode 0, with screen memory starting at 0. The VDU 28 command defines a text window which keeps the cursor in the visible part of the screen. (MODE 0 takes up 20K, if you make it start at address 0 the screen will overlap the old mode 0 -- ie you can see what you type, which you can't do if you do all this in mode 4.) The screen should look something like this:
I have annotated the diagram to show where various things are stored. Try the following, and watch the relevant areas of the screen as you do so. Insert some extra lines (REM statements, perhaps) in your program. You will see the area labelled 'PROGRAM' expand. If you then delete some lines , you can see the same area contracting, as less memory is used up.

Execute 'FOR T%=TOP TO HIMEM:?T%=0:NEXT'. This will clear the unused area of memory.

Define a user defined key. The area labelled 'KEYS' will expand slightly.

Type a SOUND statement and you will see the 'SOUND QUEUE' area become active. Similarly, type an ENVELOPE and you will see the ENVELOPE storage area, labelled 'ENVELOPES', pop into life.

Try redefining the letter 'A', using VDU 23,65,1,2,3,4,5,6,7,8. The area labelled 'CHARS 64 TO 95' will get filled with the dot patterns of the aforementioned characters.

Similarly defining any character will bring that labelled area of memory into life. If you've got a long program in memory, though, you are likely to overwrite it -- so be careful!

Watch the area labelled 'KEYBOARD BUFFER' as you type text in at the keyboard.

Then execute a loop such as 'TIME=0:REPEAT UNTIL TIME=10@100'. While the loop is executing, watch the area labelled 'RUN TIME BUFFER' as you type text in. When the loop is finished, the 'KEYBOARD BUFFER' will get filled up.

Watch the area called 'COPY' when you use the copy key to copy characters. If you are a little confused at this stage, no need to worry as all the things you are watching will be explained in subsequent chapters.

Back now to more serious matters:

If you make screen memory start at an address before its normal address (ie lower than HIMEM), you will see that only a part of the normal screen will be shown, if any, but if you make the start address larger than normal, the screen 'wraps around'. This means that instead of starting to display characters above the place where memory should stop, it goes back to the start of official screen RAM, and displays that instead. This is how the scrolling of memory is done so fast on the computer -- it doesn't have to alter anything to scroll the screen, except these registers.

This program uses the scrolling principle outlined above to print in mode 4, and then allows you to 'roll' the screen in any direction, using the cursor control keys.

Just type RUN, then manipulate the cursor keys. Various games using this principle spring to mind. (INKEY is used with a negative argument, so you can press combinations of keys for diagonal movement).

   10 REM Movement
   20 REM For modes 4 and 5.
   30 REM Modes 0,1 & 2 - see below.
   40 REM (C) Jeremy Ruston.
   50 REM *******************
   60 MODE 4
   70 PRINT TAB(7,16);"The BBC Micro Rev
ealed..."
   80 PROCASSEMBLE
   90 START=HIMEM/8
  100 X=0
  110 Y=0
  120 REM *******************
  130 REPEAT
  140 IF INKEY(-42) THEN Y=(Y+31) MOD 32
  150 IF INKEY(-58) THEN Y=(Y+1) MOD 32
  160 IF INKEY(-26) THEN X=(X+1) MOD 40
  170 IF INKEY(-122) THEN X=(X+39) MOD 40
  180 S=START+X+Y*40
  190 ?&D00=S DIV 256
  200 ?&D01=S MOD 256
  210 CALL &D10
  220 UNTIL FALSE
  230 REM *******************
  240 REM Machine code routine to load
  250 REM register 12 with the contents
  260 REM of &D00 and 13 with that of
  270 REM &D01.  Has to be in MC for
  280 REM high speed.
  290 DEF PROCASSEMBLE
  300 P%=&D10
  310 [OPT 0
  320 LDA #12:STA &FE00
  330 LDA &D00:STA &FE01
  340 LDA #13:STA &FE00
  350 LDA &D01:STA &FE01
  360 RTS:]
  370 ENDPROC
  380 REM *******************
  390 For modes 0,1 and 2, make these
  400 changes:
  410  
  420 Line 180 becomes :
  430 IF INKEY(-26) THEN X=(X+1) MOD 80
  440 Line 190 becomes :
  450 IF INKEY(-122) THEN X=(X+79) MOD 8
  460 Line 200 becomes :
  470 S=START+X+Y*80


Before scrolling takes place in any of these modes, the value in register 13 is always zero. So you can do a certain amount of work just using register 13 for scrolling from side to side. For example:


   10 MODE 2
   20 VDU 29,640;512;
   30 VDU 24,-639;-511;639;511;
   40 GCOL 0,132
   50 CLG
   60 VDU 24,-499;-399;499;399;
   70 GCOL 0,128
   80 CLG
   90 FOR T=1 TO 100
  100 X=RND(640)-1
  110 Y=RND(512)-1
  120 GCOL 0,RND(7)
  130 FOR ones=-1 TO 1 STEP 2
  140 FOR twos=-1 TO 1 STEP 2
  150 MOVE 0,0
  160 PLOT 1,ones*X,twos*Y
  170 NEXT twos
  180 NEXT ones
  190 NEXT T
  200 DELAY=0
  210 FOR T=1 TO 79 STEP 2
  220 FOR A=1 TO T
  230 PROCLOAD(13,A)
  240 PROCDELAY(DELAY)
  250 NEXT A
  260 FOR A=T-1 TO 2 STEP -1
  270 PROCLOAD(13,A)
  280 PROCDELAY(DELAY)
  290 NEXT A
  300 NEXT T
  310 PROCLOAD(13,0)
  320 END
  330 DEF PROCLOAD(reg,val)
  340 VDU 23,0,reg,val,0,0,0,0,0,0
  350 ENDPROC
  360 DEF PROCDELAY(TIM)
  370 TIME=0
  380 REPEAT UNTIL TIME>TIM
  390 ENDPROC


Notice that the scrolling from side to side used here is not the same as the rolling you can achieve with register 2, since with register 2 you often lose characters off the edge of the screen. With register 13 you get full wrap around, to stop you losing any characters.

You should now be able to see why these two registers are called 'TOP of page', and not 'Screen memory start'.

MODE 7:

Things work similarly in mode 7 -- except that the address loaded does not have to be divided by 8. The complication is that the start of mode 7 is not quite where you would expect it to be -- try it and see. Also, if you decrease the top of page value, to below the normal value, you will not move back by a few bytes -- you will move forward by 6700 bytes. This is complex and only amounts to making these registers rather trickier to use. Messing about with register 13 is easy in mode 7, however.


Register 14 & 15 -- 'Cursor address'. (Read and write).

MSB LSB


These two registers hold the address of the cursor. The address is held as it should be in mode 7, but in all other modes, the address stored is the actual address divided by 8.

Thus, at a CLS or mode change (under program control, to stop the prompt appearing), the address in these two registers is the same as the address in registers 12 & 13.


Registers 16 & 17 -- 'Light pen position'. (Read only).

MSB LSB


This register gives the position of the light pen, as an absolute address. In modes 0 to 6 this address is 8 times too small, but in mode 7 you get the actual address. Not having a light pen, I can't give a very helpful description of these two registers. However, it would appear to make more sense to use *FX136, as described in the manual.

That completes the description of the 6845's internal registers.

For completeness, here is a table showing the contents of the various registers in each of the modes:
Mode --01234567
0 Register12712712712763636363
18080808040404040
29898989849494951
43838383038383030
500000000
63232322532322525
73535352835352828
811111113
9777977918
10103103103103103103103114
11777977919

Notice that, to the 6845, there is no difference between modes 0,1 and 2, nor is there between modes 4 and 5.


Designing your own modes.


To test our understanding of the registers, let's see if we can use them to make up a screen mode to our own specifications. The only way we can do this is by altering the number of lines and number of characters displayed in an existing mode.

I'll work slowly through the way I managed to get a mode of 16 lines of 32 characters, then it would be instructive for you to see if you can go on to make other modes, of different numbers of characters.

Before we start, make sure you've got PROCLOAD defined at the top of memory, say at line 1000, and then type an END statement at about line 500. This will ensure that as we add extra lines to our program, when we execute it, we won't go charging through the procedure definition, which could cause problems.

Our first choice is to choose an existing mode with which to start work. I chose mode 4, since it is slightly bigger than the format we are aiming at. So, the first line of our program is:

10 MODE 4

We're aiming for a mode with 16 lines. At the moment there are 32, so we've got to get rid of 16 of them. Looking back at our tour of 6845 registers, we can see that the relevant one to change is register 6. So by setting the contents of register 6 to 16 we will instruct the 6845 to display 16 lines of characters. To do this, add the following to your program.

20 PROCLOAD(6,16)

Now run the program. The screen will probably give a little kick, and then settle down to look like a normal mode 4 screen. If you execute 'VDU 19,1,0,0,0,0,19,0,7,0,0,0' you will see that this is not the case. Now that you've got a white background, you can see that only the top half of the screen is being used. That's all very well, but it would be nicer if the 16 lines could be spaced out a little, to fill up all the available screen area. We'll do it in the same way as the extra spaces are inserted into modes 3 and 6. To achieve this spacing, we allow for 16 scan lines per line of text, instead of the normal 8. If you look back a few pages, you will see why this line is the one to be added:

40 PROCLOAD(9,15)

This display should now appear to be spaced out correctly, but there will probably be a good deal of flicker on the screen, and the first line of text will not start at its accustomed place at the top of the screen.

The reason for the display being half way down the screen is that the vertical total register, register 18, has not been informed of the reduction in the number of screen lines, and so is pumping out a vast border at the top of the screen, which shifts everything else on the screen down a few lines. So we update the vertical total register with:

50 PROCLOAD(4,18)

The display should now start at the right place, but you may find that the picture rolls rather a lot. After much experimentation, it transpires that all we have to do to remove the rolling is to adjust the position of the vertical SYNC pulse. Actually the experimentation consisted of looking at the table of register contents under various modes, seeing which registers held some connection with the number of lines displayed and ensuring that all those had been adjusted. Register 7 was the only one which hadn't. From the table, I expected this register to hold two more than the number of screen lines, but I get steadier picture with 17 in this register. So the line we can finally add is:

60 PROCLOAD(7,17)

We should now have a perfect display of 16 lines by 40 characters. So now all we have to do is remove 8 characters from the end of each line. Before we do so, you may like to add:

70 PROCLOAD(11,15)

which gives an odd cursor.

To adjust the number of characters in the line, we use:

80 PROCLOAD(1,32)

We now have a screen of 16 lines of 32 characters -- but the computer is still treating it as a screen of 32 lines of 40 characters, and so printing will not work as you want.

Finally in this section, here is a table of the 6845 registers:

6845 REGISTERS:

RegisterName/function
0Horizontal total
1Characters/row
2HSYNC position
3HSYNC width
4Vertical total
5VSYNC adjust
6Character rows/frame
7VSYNC position
8Interlace mode
9Scan lines/row
10Cursor start scan line
11Cursor stop scan line
12MSB Start address (top of page)
13LSB Start address (top of page)
14MSB Cursor position
15LSB Cursor position
16MSB Light pen position
17LSB Light pen position