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!