Spectrum Tool Kit Bobby Rao offers some handy hints to would-be machine-code users. Here are some useful off-the-peg routines. Here are about 20 machine-code graphics routines, any com- bination of which may be used in your programs to enhance the screen displays, or to give them that extra touch of elegance that comes only from the use of machine code. Also included are renumber and memory-left routines which may be used to aid your programming. No understanding of machine code is necessary to use the routines - just a good working knowledge of the Spectrum and its manual. Machine code is the computer's first lan- guage - it only speaks Basic out of courtesy to humans - and its use results in greater speed, flexibility and more economical use of memory than does the use of Basic. To get the machine code into the computer a hex loader must be used - see program 1. Type this in and save it. Machine code can either be stored above RAMTOP or in a REM statement at the beginning of a program. I prefer the latter method, for each different routine may be stored in a REM statement with a different line number and then merged into a program as required. However, if you wish to use the first method then change line 5 as shown under- neath the program listing. [I.e., "change line 5 to read 5 CLEAR x: LET a=x where x is the address they need to move RAMTOP to". Note that this is wrong, though: it should read "CLEAR x-1", unless you like confusing the GO SUB stack.] Here is an examnple of how you go about loading in the memory-left routine, see figure 1. [Or rather, listing 1; it's on the TZX as "memoryleft".] First load in the hex loader and type in a REM statement as line 1. This REM statement should consist of 14 full stops because the memory-left routine is 14 bytes - characters - long. If you are using the RAMTOP method then you will not need to do this - just CLEAR yourself enough memory space above RAMTOP. Now carefully type in the DATA line in figure 1 and after checking this line run the program. Listing it will show that line 1 is now a meaningless jumble - if you have a line 1, that is - but do not worry, for this is supposed to happen. Also it is likely that listing the program when the REM line is in this state will cause the computer to stop with an error report. To avoid this and view the rest of the program you must always used LIST -line number of first line after the REM line- so that the Spectrum does not try to list the unlistable REM line. Now the routine is ready to be saved. Erase all of the hex loader except the REM line - do not use NEW whatever you do - and save this with a filename like "Mem Left". Now NEW the computer and reload the hex loader. Repeat the above process for the rest of the routines, but make sure you never use the same REM line number for two different routines because this will cause trouble when you come to merging routines together. [Which would a good trick, seeing that REM must be the first line of the program and the first line of the loader is line 5...] RAMTOP-method users may save their routines by using the SAVE filename CODE method detailed in the manual on pages 143 and 180. [ And now the method for TZX-users, which is even simpler. Load the program called "Hexloader", then merge the required routine (e.g., "memoryleft"). Note that a. the mergeable routines have their required REM statements already added; b. each of these has a different line number; c. to accomodate this, the hexloader starts at line 1000 instead of at 5. Note also that you will get the error "E Out of DATA, 1010:2"; this is normal and would also have occurred, albeit at line 10 instead, had you typed in the listings yourself. And if you want it even easier: at the end of the TZX, you will find pre-REMmed versions of all routines, with all the other lines removed. Just merge them into your program and you're ready to go. They're the ones with the capitals in the names (e.g., "ScrInvert", where the version for the loader would be "scrinvert".] Once the tedious task of typing in and saving the rou- tines has been accomplished [you're welcome] you are ready to use these routines. If you wish to use some of the rou- tines in one of your programs then start that program at, for example, line 100, leaving the earlier line numbers free for the machine-code REM lines. After typing in the program, merge in the routines you require. To run machine code rather than Basic the USR function must be used. The argument of this function is the address of the first byte of the machine-code routine you want to run, and this may be found, if you are using the REM method, by using program 2 [on the TZX as "linefinder"]. On running this program - whilst the machine-code routines are in the computer - line numbers and the start addresses of the routines in those lines are printed until the computer finds a non-REM line, when it will stop. Note these start addresses down, or better still, define variables equal to these values by placing a lot of LET statements somewhere in your program, for example: LET inv=23760 Now just typing PRINT inv will tell you the address of the first byte of the invert-screen routine. RAMTOP method users will not need to use program 2 because they will already know the addresses of their rou- tines or they would not have been able to get them above RAMTOP in the first place. To use the routines use the command RANDOMIZE 0*USR X, where X is the address of the routine you are using. The result of the USR function is multiplied by 0 to keep RND truly random, that is, it acts like a RANDOMIZE 0 command. Below there is a description of all the routines and how to use them. In these descriptions the variable X stands for the address of the first byte of the routine in ques- tion. All numbers are in decimal and unless otherwise stated all the screen routines operate on all 24 lines of the screen. When you are told to poke something somewhere the pokes must be done before you use the routines and they may be entered as a series of direct commands before you run the program or they may be built into the program. Memory Left: running this, listing 1 ["memoryleft"], using PRINT USR X will tell you the exact number of free bytes of memory you have left. Hi-Res Up Scroll: this, listing 2 ["hiscrup"], routine scrolls the screen up by one hi-res pixel, replacing the bottom line of pixels with blanks. Hi-Res Down Scroll: as in listing 2, but this - listing 3 ["hiscrdown"] - scrolls down, blanking the top line of pixels. Hi-Res Left Scroll: this scrolls the screen left one pixel, replacing the rightmost column of pixels with blanks. See listing 4 ["hiscrleft"]. Hi-Res Right Scroll: as in listing 4, but listing 5 ["hiscrright"] scrolls right, blanking the leftmost column of pixels. One Character Left Scroll: the listing 6 ["chscrleft"] routine scrolls the screen left one character, replacing the rightmost column with either blanks - for this effect POKE X+16,54 - or the previous leftmost column, a wrap- around effect - for this POKE X+16,119. One Character Right Scroll: the listing 7 ["chscrright"] routine scrolls right. POKE X+16,54 causes the leftmost column to be blanked and POKE X+16,119 replaces this column with the previous rightmost column. These last two routines are adjustable in which part of the screen they scroll, but you only have five options. The table below tells you how to adjust the routines. The first column tells you which part of the screen is to be scrolled. The next two columns tell you what to poke in X+1 and in X+4 respectively for the left scroll routine. The last two columns tell you what to poke in X+1 and X+4 respectively for the right scroll routine. Top one-third 64 64 64 71 Middle one-third 64 72 64 69 Bottom one-third 64 80 64 87 Top two-thirds 128 64 128 79 Bottom two-thirds 128 72 128 87 [ Whole screen 192 64 192 87 - these were not given in the article, being the default setting when you poke nothing at all, but they're useful to know if you want to restore them after using the others.] Invert Screen: the listing 8 ["scrinvert"] inverts the actual pixels on the screen, that is, all pixels on are turned off and all pixels off are turned on, and so it is different from the INVERSE function on the Spectrum which only inverts the INK and PAPER colours - which this routine does not alter. Screen Fill: this routine, listing 9 ["scrfill"], fills in a box of height a, width b, and a top left-hand corner at point c,d - where c and d are co-ordinates used by the PRINT AT system - with any character of your choice. POKE X+1,character code POKE X+3,a POKE X+4,c POKE X+6,b POKE x+7,d So if a=22, b=32, c=0 and d=0 then the normal 22-line screen is filled. You must have printed something somewhere before using this routine or it will not work properly. Also note that you cannot print on line 24 with this routine. Ink Change: this - see listing 10 ["chngink"] - changes the ink colour of the screen without altering anything else. Poke X+1, the number of the colour you want to change the ink to. Paper Change: as listing 10 but changes the paper colour. Poke X+1, the number of the colour you want to change the paper to. See listing 11 ["chngpaper"]. Flash On/Off: this routine, listing 12 ["chngflash"], sets the whole screen flashing - for this POKE X+9,254 - or returns the screen to normal non-flashing mode - for this POKE X+9,190. Bright On/Off: the routine shown in listing 13 ["chngbright"] makes the whole screen bright - POKE X+9,246 - or returns it to normal brightness - POKE X+9,182. Attr Fill: the fourteenth listing ["attrfill"] changes the attributes for a box height a, width b and of top left- hand corner at point c,d wheew c and d are co-ordinates used by the PRINT AT system to denote a point on the screen. POKE X+3,d POKE X+4,c POKE X+6,b POKE X+7,a POKE X+1, the value you want to change the attributes to. This value may be calculated thus: first assume that the new ATTR value is Y and initially Y=0. If flash is on add 128 to Y, if off add 0. If bright is on add 64 to Y, if off add 0. Add eight times the number of the paper colour to Y. Add the number of the ink colour to Y. This means that an attribute of flashing, bright yelllow ink on blue paper would be 128+64+(1x8)+6=206. With this routine you can change the attributes of the whole 24-line screen. Attr Up Scroll: this routine, listing 15 ["atscrup"], allows you to scroll up the attributes for a box height a, width b, and top left-hand corner at point c,d. The bottom line of the box is replaced with an attribute of value Y - see Attr Fill for how to calculate Y. POKE X+1,y POKE X+3,d POKE X+4,c POKE X+6,b POKE X+7,a Attr Down Scroll: listing 16 ["atscrdown"] scrolls down replacing the top line of the box with the new attribute. The pokes are the same as for the previous routine. Attr Left Scroll: as listing 16 but scrolls left re- placing the rightmost column of the box with either a new attribute - for this POKE X+36,0 - with what was previously in the leftmost column of the box - for this POKE X+36,26. This last effect, wrap-around, allows this routine to be used fully with the one character left scroll routine given above. See listing 17 ["atscrleft"]. Attr Right Scroll: the routine shown in listing 18 ["atscrright"] scrolls right, replacint the leftmost column of the box with either a new attribute - for this POKE X+43,0 - or with what was previously in the rightmost column of the box - for this POKE X+43,26. This last effect allows this routine to be used fully with the one charac- ter right scroll given previously. The next three routines allow you to store screens cur- rently being displayed in spare memory and then recall them on to the display, either making them swap memory position with the screen currently being displayed, or overprinting them on to the current display. To store screens you must firstly CLEAR some memory space so you can store the screens there. Each screen - with attributes - is 6,912 bytes long, so this much space is required for each screen. The memory location of RAMTOP - the last byte of the computer's memory - can be found by using PRINT PEEK 23730+ 256*PEEK 23731. If this number is W then W-Q*6912 - where Q is the number of screens to be stored - will tell you the address to CLEAR RAMTOP to - see manual page 168. You must have cleared this space or the routines will not function correctly. If you only have 16K of memory then space exists for storing only one screen so CLEAR 25685 is all you need to use. In order that the routines know where in the memory a screen is to be fetched from or sent to you must do the following for all the routines: POKE X+1,W-256*INT(W/256) POKE X+2,INT(W/256) If you have 48K and you wish to store more than one screen then it might be advisable to leave a gap of a few bytes in between screens so as to lower the risk of one screen running over on to another by accident. If you are using the RAMTOP method for storing the machine-code routines then be extra careful, or you will end up ruining the routines and crashing the computer. Make sure you take into account the length of the routines when deciding where you CLEAR RAMTOP to. Store Screen: This replaces the current display with one already in the memory. See listing 19 ["scrstore"]. Swap Screens: This routine swaps the current display with one higher up in the memory so that the screen that was being displayed is stored in the memory and the screen that was in the memory is now displayed. See listing 20. ["scrswap". The listings for this and the next routine were printed the other way 'round in the magazine. The order on the TZX is the one in this text.] Overprint Screens: This overprints a screen from higher up in the memory onto the current display. The old display is lost in its original form - it is not stored anywhere by this routine before it is altered - but the screen used to PRINT OVER the old display still remains intact higher up in the memory. [Note that this, and the reversible nature of OVER, means that you can get the original screen back by calling the routine a second time.] The attributes are not changed by this routine so after the routine has been used the attributes being displayed are those of the old display. See listing 21 ["scrover"]. Renumber: this routine, listing 22 ["renumber"...], instantly renumbers all the line numbers of your program starting the first line at a specified value and increasing this value by a specified amount as it renumbers the rest of the lines. Note that this does not change the GO TOs and GO SUBs so you will have to alter these manually. If the first line is renumbered L and the value by which L is in- creased is M then POKE X+5,M-256*INT(M/256) POKE X+6,INT(M/256) POKE X+8,L-256*INT(L/256) POKE X+9,INT(L/256) For fun you might try renumbering all lines 0 or try using a starting value greater than 9999. The uses of these routines are many and varied, limited only by the imagination of the user. For example, the left and right scrolls with wrap-around may be used to create a constantly moving background for a space game. Any of the scrolling routines may be used to clear all or part of the screen in a novel way. The ink and paper changing routines may be used to create a surprise effect by first drawing a picture on the screen using the same ink and paper colour and then altering either so that the picture appears instantly. Animated cartoon effects are possible using the screen swapping routines and stunning explosion effects may be simulated by using the Invert Screen routine repeatedly - in a loop. The list is endless and these are just a few broad guidelines that you can experiment with and doubtless improve on. Just as a bit of fun try the following POKE next time you have a program in your Spectrum: POKE 23606,8. This makes the computer speak Russian - nearly. POKE 23606,0 restores normality. [No, I have no idea what this has to do with the rest of the article, either.]