Personal Computer News


Amstrad Scrollwork

 
Author: Clare Gurton
Published in Personal Computer News #077

Scroll the Amstrad screen display with Clare Gurton's simple machine code routines.

Amstrad Scrollwork

Scroll the Amstrad screen display with Clare Gurton's simple machine code routines

It's often useful to scroll a computer's screen display up or down, particularly in games. On most machines you can scroll the screen up a line by printing in the last screen cell, but there's no way you can reverse the process to scroll the screen downwards.

Of course, it's possible to write machine code routines to shift the screen display about according to your needs, but this means getting to grips with assembly language programming, and most of us would rather steer clear of that.

Fortunately, the Amstrad ROM is so well-documented that it's possible to write very simple machine code routines which call up ROM routines to do such complex tasks.

For example, there's a ROM routine called SCR HW ROLL at &BD4C (50395 decimal) which uses the Amstrad's hardware to scroll the screen up or down, depending on the contents of the B register. The ROM routine moves the screen by eight pixel lines (one character row) at a time, and fills the new top or bottom row with the colour given by the ink code of the contents of the A register. If the contents of the B register is zero, the screen scrolls downwards, and any non-zero value forces an upwards scroll.

There are two simple ways of using the ROM routine. Either you can set up a single routine which you have to change by one byte (via a POKE) before calling it, or you can set up two routines, one for up, the other for down, and that's the first method shown here.

Each routine will first load the B register with the relevant value - 255 for up, 0 for down - then call the ROM routine and finally return to Basic. Loading the B register uses the mnemonic LD B,n (where n is a number between 0 and 255). The opcode for LD B is 06, so this will be the first byte of each of the assembled routines. For the down-scroll routine the next number will be zero, while the up-scroll routine will need any non-zero value - FF (255 decimal) will do.

Calling the ROM routine requries the mnemonic CALL nn, op-code C9, 205 decimal. The ROM routine begins at &BC4D (50395 decimal) and, because the Z80 works on the low byte, high byte principle for referring to 16-bit addresses, we'll need to follow the CALL with 4D (77 decimal) then BC (188 decimal). Finally, the routines must return to Basic via the mnemonic RET, op-code CD, 201 decimal.

The Basic loader for the two routines is given in Figure 1 below.

You can RUN this, then delete it before entering a program which uses scrolling. You'll have to set memory to 43879 to preserve the routines from corruption by Basic programs and their data.

Address Mnemonic Opcode/Data Decimal
43880 LD B,FF 06 6
43881   FF 255
43882 CALL BC4D C9 205
43883   4D 77
43884   BC 188
43885 RET CD 201
43886 LD B,00 06 6
43887   00 0
43888 CALL &BC4D C9 205
43889   4D 77
43990   BC 188
43991 RET CD 201
Figure 2. Addresses, mnemonics, opcodes/data and decimal values

 10 MEMORY 43879
 20 up.scroll=43880:down.scroll=43886
 30 WHILE A$ = ""
 40 FOR up = 1 TO 10
 50 CALL up.scroll
 60 NEXT
 70 FOR down = 1 TO 10
 80 CALL down.scroll
 90 NEXT
100 A$ = INKEY$
110 WEND

Figure 3. Demonstration of routines

The routines are assembled from 43880CALL 43880 will scroll the screen up, while CALL 43886 will perform a downwards scroll. You may find it easier to set up two variables such as: down.scroll = 43880; then use CALL up.scroll and CALL down.scroll. Figure 3 demonstrates how to use the routines like this.

Address Mnemonic Opcode/Data Decimal
43870 LD B,A 06 6
43871   A 10
43872 LD A,0 3E 62
43873   0 0
43874 PUSH BC C5 197
43875 PUSH AF F5 245
43876 LD B,FF 06 6
43877   FF 255
43878 CALL &BC4D CD 205
43879   4D 77
43880   BC 188
43881 POP AF F1 241
43882 POP BC C1 193
43883 DJNZ 10 16
43884   F5 245
43885 RET C9 201
Figure 4. Multiple Scrolls

Figure 4 gives the details of a rather more complex, single machine code routine which will repeatedly call SCR HW ROLL according to the contents of address 43871. As given, the routine uses an ink value of zero and scrolls the screen up by ten lines.

You can alter any of these by POKEs to the relevant addresses. You can POKE 43877 with 0 for a down scroll, 255 for up, while the ink colour for the newly created top or bottom line is held in 43873. So, if you wanted the screen to scroll up ten times you'd POKE 43877,255:POKE 43871,10:CALL 43870. The last listing (Figure 5) is the Basic loader for the routine.

This routine uses the B register as a sort of loop counter. The routine begins by loading the B register with the contents of address 43871, which is why you have to poke this address with an eight bit number (<=255) for the number of lines to scroll.

Next, the colour for the blank line which will be created by a scroll in either direction is loaded into the A register. Both A and B have to be PUSHed onto the stack before calling the ROM routine because it corrupts all the register pairs. The last action before calling SCR HW ROLL is to load the B register with the direction in which to scroll the screen.

When the ROM routine returns, the AF and BC register pairs have to be restored (POPed) for the next operation. This is the Z80 instruction DJNZ - decrement and jump on non-zero. This subtracts one from the B register and jumps according to the displacement (two's complement) in the next byte if the new content of the B register is not zero. When the DJNZ operation results in zero, the zero flag is set, the test fails and the routine ends in RET, passing control back to Basic.

Ideally, you'd use an assembler to work out the displacement for you, but until one is available for the Amstrad you'll just have to hand-assemble awkward details like this.

In this example the program flow needs to be directed back to address 43874, which is nine bytes back from the address of the DJNZ instruction. However, you have to add 2 to this value, because the program counter (PC) will be pointing to two bytes on from the DJNZ instruction by the time the decrement etc has been done. This means you want a negative jump of 11 bytes.

To translate a negative decimal number like -11 into its two's complement, write down the binary pattern (00001011), rewrite it with all noughts replaced with ones and vice versa (11110100). Then add one to the binary pattern (11110101) and finally convert to decimal (245) which is the value you put at address 43884 as the negative displacement for the DJNZ instruction.

 10 MEMORY 43869
 20 address = 43869
 30 scroll = 43870
 40 DATA 6,10,62,0,197,245,6,255,205,77
 50 DATA 188,241,193,16,245,201
 60 FOR count = 1 TO 16
 70 READ value
 80 POKE address + count,value
 90 NEXT
100 '
110 ' 43873 is colour of new line
120 ' 43871 is number of scroll lines
130 ' 43877 is up/down
140 '
150 REM Demonstrations
160 GOSUB 210
170 POKE 43871,10
180 GOSUB 300
190 END
200 ' Demo One
210 FOR no.lines = 1 TO 20
220 POKE 43871,no.lines
230 POKE 43877,0
240 CALL scroll
250 POKE 43877,255
260 CALL scroll
270 NEXT
280 RETURN
290 ' Demo Two
300 FOR colour = 1 TO 255
310 POKE 43877,0
320 CALL scroll
330 POKE 43877,255
340 CALL scroll
350 POKE 43873,colour
360 NEXT
370 RETURN

Figure 5 also gives demonstrations of the routines. You'll find that altering the value contained in the A register results in some interesting coloured textures.

Clare Gurton

This article was converted to a web page from the following pages of Personal Computer News #077.

Personal Computer News #077 scan of page 22

Page 22

Personal Computer News #077 scan of page 23

Page 23