                   A Present from Uncle



          Our thanks to Psion for letting us use

            their routine and to regular Exeter

           contributor Clyde Bish for explaining

                how to use it to the full.



[ As is clear from the first paragraph, this article, and

  the set of programs that go with it, deals with a machine

  code routine found on the Horizons tape. I have chosen

  not to replicate that routine on the TZX that goes with

  this text file. The Horizons tape itself can be found on

  the internet - if nowhere else, certainly on World of

  Spectrum and presumably on the TZX Vault.

  Note that all but the first of these programs do require

  the machine code routine to be present in memory to work,

  and none of them except the second auto-load it. This is

  as it was in the magazine listings. They're short enough

  that it is possible to read through this whole article in

  one sitting, so it should be no problem to load the

  routine once and then load the Basic programs one after

  another.

                                  Richard Bos, March 2011 ]



Aren't we lucky having a kind Uncle - or should it be Sir

Uncle? - who gives us a present with our Spectrums! No, not

the "Horizons" tape per se, but a particularly useful

routine hidden within its bytes. If you'd like to have

titles and messages in large letters, Horizons style, then

read on. All will be revealed.

   It's all done by a machine code routine LOADed to add-

ress 32256 (these are the bytes which autoLOAD before a

program RUNs). Like most presents you have to know just

what it will do before you can use it to best advantage.

Here are some ideas.

   First things first. How does the routine work? I'm not

going to bore you with details about the mechanics of the

code. If you want to "dissect" it, a disassembly is given

in Table A. [This table has been omitted from this file.

These days you can get a better one from your emulator.]

Suffice it to say that information on width and height

multipliers (variables xs and yx respectively), codes of

characters to be PRINTed, vertical start position, and

horizontal start position (calculated by the program) are

fed into the printer buffer. This is simply used as a

convenient dump from where the routine will pick up the

information it needs. (If you've wondered why anything

LPRINTed after the print routine has been used is preceded

by a black band, this is the information still left in the

buffer.) The machine code routine searches the ROM charac-

ter table for the character to be printed, then produces a

pattern of pixels on screen which is xs times wider and ys

times taller than the original. If you want to see how this

works type in and RUN Program 1. This is a Basic simulation

of the routine. It's slow, but it will demonstrate the

principles. (Incidentally it does produce quite nice titles

in its own write (sic).) Try it and you'll see.

   But more of the mechanics later. Let's see the routine

in action. First you need the routine in the machine.

Simply type



        CLEAR 32255: LOAD "c"CODE 32256



   Press ENTER and play Side B of your Horizons tape.

You'll get some programs and bytes listed first but after

about 2 minutes the code you need will LOAD in. When the OK

message appears, stop the tape, type in program 2, RUN it

and experiment. For example, try 2 for width and 3 for

height. You'll find that the letter H which appears will be

twice as wide and three times as tall as normal. Try 5 and

2. This time the H will be 5 times as wide and twice as

tall as usual. The width limit is 32. (Try answering the

INPUT prompts with 32 and 1!) Anything wider will "wrap".

Try a width of 40 to see what I mean. The height limit is

22. Anything larger will prove problematic!

   When you've experimented for long enough, break out of

the INPUT with STOP, then LIST. The listing before you is

the most important you'll come across with regard to the

Print routine. It's the driver which supplies the routine

with the information it needs to operate. So, let's have a

close look. As you already know, xs is the width multiplier

and ys the height multiplier. Variable yy is the distance

down the screen (in pixels) - 0 is the top row, and p$ the

character(s) to be PRINTed. The subroutine to load this

information into the printer buffer starts at line 9998.

Variable xx - the start position across the screen - is

calculated first to ensure that the printing is central on

screen. We'll put this line to more effect (or over-ride

it!) later. The POKEs in line 9999 put the variables into

the buffer (along with an 8 and 255 as markers) before the

machine code routine is called by the USR command. After

printing, a return is made to the main program.

   Before we leave the driver subroutine try the effect of

altering yy (edit line 30). Similarly p$ can be changed -

try more than once character. TO see the effect of line

9998 add lines



        45 LET xx=(any value, try 0)

        47 GO SUB 9999: GO TO 60



At this point, it would be a good idea to SAVE the BASIC

subroutine and code, ready to merge it with your programs

in the future, rather than having to keep finding it on the

Horizons tape. To do this, delete lines 1 to 70, leaving

just the subroutine, add line



        9997 CLEAR 32255: LOAD ""CODE: STOP



then SAVE both program and code using



        SAVE "print"LINE 9997: SAVE "c"CODE 32256,300



and VERIFY both program and code. [This is not on the TZX.

The problem of locating a bit of code on Horizons B.tzx is

not as time-consuming as doing so on the tape.]

   O.K., you've seen the good news; now the bad. The prob-

lems. If you 48K owners have tried LOADing the code into a

high address, you will have discovered that calling it

causes a "crash". You'll find the reason staring you in the

face in the disassembly (Table A). Look at lines (addres-

ses) 32341, 32361 and 32409 and you'll see the letters (op

code) JP followed by a number. This is called an absolute

jump. It means that when the routine reaches this point it

will jump to the address given. This is correct if you've

loaded the code in at 32256 but start anywhere else, and

all the jumps will be wrong. Hence the crash. The answer -

alter the addresses. Program 3 (supplied by our illustrious

Editor [Ray Elder]) will do just that. In essence what it

does is to POKE new (corrected) values into those JP com-

mands, the values being calculated from where you start.

SAVE it with



        SAVE "print"CODE (start address),300



and remember to CLEAR (start address - 1) before you LOAD

it back in as part of a program. One word of warning. Don't

answer the "Start address" prompt with a value greater than

65067 or you'll lose the end of the routine! [There are two

versions of this program on the TZX. "Program 3a" is as it

appeared in ZX Computing, but it contains an interesting

and ironic bug which I couldn't resist including for, ahem,

educational reasons. "Program 3b" includes the natural

bugfix.]



 UDGs



That's relocation solved, now for problem two. Run Program

2, but first replace the "H" with a user-defined graphic

(UDG for short). Any letter will do. What appears on

screen? Nothing. The reason for this is again found in

Table A. Look at the line of op code at address 32272. The

number in brackets is the address of a system variable

called CHARS. This holds a two byte (number) value - nor-

mally 0 and 60 - which tells the computer where to look (in

the ROM) for the character set - the 8 x 8 pattern of pix-

els which make up each of the characters. The Print machine

code looks through this set to find a match for the charac-

ter you want printer. As /you/ design the UDGs no match is

found - hence the blank screen.

   The solution to the problem is quite simple (although it

took me some time to fathom). What you have to do is con-

vince the machine that the character set it wants to look

at is not in the ROM but up in the UDG area. Look at Pro-

gram 4. Line 5 is there simply to make the UDGs different

from normal capitals (by underlining top and bottom). In

line 10 "ABCDE" must be entered in Graphics mode, although

they won't appear underlined until after the program is

RUN. The POKEs following it are the key. They tell the

machine that the set it wants begins at address 64216

(216 + (250 x 256)). USR "a", the first byte of the UDGs is

at 65368. The difference, 1152, divided by 8 (the number of

bytes/character) is 144, and 144 is the code of the first

UDG! If the logic of this has lost you, don't worry, just

POKE 216 and 250 (216 and 122 if you have a 16K machine).

   The POKEs at the end of line 20 reset CHARS to its ori-

ginal position. Otherwise the error messages and listing

would be unreadable.



 Rolling titles



So, now we can use UDGs what do we do with them! (Apart

from their straightforward use in titles). Here's a couple

of ideas. I call them rolling titles. They are interesting

in that they make use of the ROM character set to redesign

the UDGs.

   Program 5 displays the word "SCROLL", then gradually

rolls it away leaving a blank space. This can be especially

effective if it appears in a window surrounded by a diffe-

rent colour background. The DATA line supplies the first

POKE within the loop in line 5, with the UDG to be altered,

then the start address in ROM where the pixel pattern for

the replacement letter begins. Refer to Table B [a simple

table of some characters and their charset addresses in

ROM - 15616 for space, 15880 for A, 15888 for B and so on.

I haven't replicated it, since it's easy to create your own

should anyone want it] and you will see that 16024 is the

start of S, 15896 of "C" and so on for the word SCROLL. The

reason for alternate UDGs being redefined becomes apparent

in the second POKE. This POKEs the unaltered UDGs between,

with 0 - a blank space. The letters for p$ in line 10 must

be entered as UDGs (as yet not redefined). When the program

RUNs, it displays the POKEd patterns, but moving up one

byte each time it loops in line 10 so that the top line is

lost and the blank lines of the redefined spaces move in to

take the place. The best way to understand how this program

(or any other) works is to put in a word of your own. (If

you want other than 6 letters then you will have to alter

the limit number in the f loop of line 5.) Use Table B to

get the DATA numbers you need, and remember, the UDGs must

be used alternately. Good luck.

   Program 6 is an extension of this roller idea where,

instead of blanks, a second word (TITLES) is redefined. So,

as SCROLL rolls off, TITLES rolls on. Incidentally, if you

want to use a character set other than that in the ROM, you

can define your own in the RAM and point the machine code

routine to it by setting CHARS to 256 less than the start-

ing address. I'll leave designing the new set to you (or

you can crib it from an earlier mag).

   Now for something easier. Obviously you can use the

routine for titles, Horizons style, but how about some ani-

mations? Programs 7, 8, 9 and 10 use the routine to produce

such effects.

   Program 7 puts each successive word in the same place on

screen as the previous one, but makes it larger (and a dif-

ferent colour) so that the title "zooms in".

   Program 8 reverses this procedure, so parts of previous

words remain giving a blocked effect.

   Programs 9 and 10 are similar to Program 8 but also move

the print position so that the title shifts up or down the

screen giving a perspective effect.



 Clearing the screen



And now for something completely different. Spaces. The

routine will quite happily print these and give interesting

CLS effect. Actually, it's more of a "wipe". Programs 11

and 12 will demonstrate. The former clears the screen in a

series of 8 left to right wipes starting at the top, where-

as the latter clears in a series of vertical lines starting

from the left. In each case line 10 just fills the screen

for wiping. Try experimenting with other values for xs and

ys. (xs must divide exactly into 32.) If you add a state-

ment such as PAPER 4 then you will clear and change the

screen colour at the same time.

   You can also use the printing spaces technique to clear

just part of the screen (a window). Try Program 13. This

will produce a central cleared area 48 pixels down from the

top, with the window 16 characters wide and 8 deep. If you

want to clear a window to right or left of screen centre

then you will have to set variable xx as well and call the

routine at line 9999, not 9998 - see Program 14.

   Computers normally print characters to screen by justi-

fying to the left - like a typewriter. That is they produce

a straight left-hand and a ragged right-hand margin. A book

(or this magazine) is printed with right and left justifi-

cation. Both margins are straight. [Note that, unlike the

original article, this plain-text file has a ragged right

margin.] A word processor does the same. Program 15 justi-

fies to centre, meaning that each line of print is balanced

about the mid line and so the left and right margins are

even [or rather, identically uneven]. This gives a pleasing

look to on-screen instructions. In outline, the program

takes the contents of the string held in a$, chops it

up into lines of maximum length 32 characters, without

chopping words, and then uses the machine code routine to

balance each of those lines centrally on screen. As print-

ed, the listing gives normal size characters, but you

could, for example, change to double size by altering ys

and xs to 2, and changing all 32s to 16 and 33s to 17.

   To end, here is a Really Useful Program (as Pooh would

say). Program 16 will produce cassette lables if you have

a printer. The titles are printed twice normal print size,

and appear both on the spine and on the side of the lable.

The straight lines printed show you where to fold to fit

the box. If you want to make a complete cover for the side

(and can afford the paper) add some LPRINTs before COPY to

make it long enough.

   Well, there are the ideas. From now on it's up to you.

Have fun with Uncle's present!