A Journey into the Spectrum ROM 29/01/90 Antony Purvis The Spectrum ROM holds a myriad of useful routines andfunctions. Some of them are useful in BASIC programs - thescreen scroll routine at address 3280 for instance - whileothers can save time and effort when writing machine code. In this article, I will explain what a few of the more usefulroutines do, and give details of how to use them. There aretimes when the m/c programmer needs to duplicate Basicfunctions, so I have included some of these too. Well, letsstart at the beginning, as someone once said! 00000 (0000h) USR 0 RST 0 This is where the Spectrum arrives when you turn it on- itclears the entire memory, sets up the screen colours, andinitialises all the system variables. It finally displays thecopyright message. Not terribly useful really! 00008 (0008h) USR 8 RST 8 The Error restart. This routine takes the value of the byteimmediately following the RST 8 command, generates theappropriate error message and returns control to BASIC. For instance, following RST 08 with 6 will produce error report7, Return without Gosub, and similarly a value of 23 willgenerate error report O Invalid Stream. This byte is also storedin the system variable ERRNR at 23610. 00016 (0010h) USR 16 RST 16 The PRINT routine is one of the most useful in the Spectrum.Its versatility can only be realised when it is used frommachine code. The routine will take the character whose numberis held in the A register and print it to the currently selectedstream. It can send data to a printer via stream 3, or to the screenvia stream 2, in which case the output is at the current printposition, using the current INK, PAPER, FLASH, BRIGHT and OVERvalues. This routine corrupts all registers though, so make sureyou PUSH them onto the stack first! 00040 (0028h) USR 40 RST 40 This is the "Calculator" restart - it is extremely complex, andit would need the whole of this article to even explain thebasics! 00056 (0038h) USR 56 RST 56 This routine is called 50 times a second in the Speccy - itscans the keyboard, changing the appropriate system variables,then increments the real time clock held at locations 23672/3/4. It POPs an address from the stack, which it jumps to oncompletion. 00654 (028Eh) USR 654 This is the master key scan routine. It returns two values inthe D and E registers. The D register is returned with a valuewhich indicates which shift key is being pressed. The E value isbetween 0 and 39, corresponding with the 40 keys on thekeyboard. If both shift keys are being pressed, the D register holds thecode for CAPS SHIFT, and the E register holds the value ofSYMBOL SHIFT. If no keys are being pressed, then the DE registerpair is returned with a value of FFFF (65535) . If more than 2 keys are being pressed, or neither key or pairof keys is a shift key, the zero flag is reset. The resultsreturned from this routine are rather complex, so this nextroutine is designed to make the scan easier to use 00703 (02BFh) USR 703 This will call the keyscan at 654 and decode the key value. TheCODE of the key, or combination of keys that were pressed isstored in the system variable LASTK (23560). Bit 5 of FLAGS(23611) is set to show that a new key has been pressed. In fact the routine checks the value held in the systemvariable MODE, which keeps track of whether the machine is in K,L, C, E, or G modes. This affects the final value returned toLASTK. 00949 (03B5h) USR 949 This is the routine responsible for the wonderful BEEP command.From machine code, the DE register pair should be loaded with avalue equal to the time that the note should last (in seconds)multiplied by the frequency of the note. The HL register pairshould hold INT ((437500/ frequency) -30.125). That sounds very complicated, because it IS complicated. Forthe middle C note to be produced for one second, DE should holdINT (261.63 * 1) and HL INT ((437500/261.63)-30.125). The 30.125is a constant to compensate for processor timing. 01218 (04C2h) USR 1218 This is the SAVE routine. This should be entered with DEholding the length of the block to save, IX holding the startaddress, and the A register holding 0 for a "header " block, or255 for a "program/data" block. The carry flag should also beSET upon entry. This routine is called twice by the BASIC SAVE command, oncefor the 17-byte header, and once more for the main block ofdata. Incidentally, you can copy the ROM code into RAM, and alter thetimings to produce other SAVE speeds. The colours that are usedfor the border during a SAVE ca n also be changed. 01366 (0556h) USR 1366 Though this routine requires all the same registers to be setin exactly the same manner as for SAVE, there are quite largedifferences between them. LOAD, can to a certain extent, follow quite largeirregularities in the speed of the data coming in. It does thisby detecting the edge, or the point, when the signal levelchanges, on each pulse On return from the routine, the carry flag is set if all wentwell and reset if a loading error occured. 03282 (0CD2) THE SCROLL ROUTINE Unlike the ZX81, the Spectrum has no built-in SCROLL command toscroll the display with. This can be achieved from BASIC withUSR 3282 which is the routine Mr Spectrum uses after it asks you"scroll?". This is the main entry point; see later for someother, more interesting, ways to SCROLL. 03435 (0D68) THE CLS ROUTINE Maybe not much use from BASIC, because typing CLS is easier,but this routine can be useful from machine code. The display iscleared to the current attributes (as held in the systemvariables) and various housekeeping functions are performed withchannel 'K' In effect, the Spectrum CLS routine is un-necessarilycomplicated and slow. A faster and easier way to do this isshown below: LD HL,16384 <Start of display file LD DE,16385 <Start+1 LD BC,6144 <Length of attributes LD (HL),L <Value to copy LDIR <Clear it LD BC,792 This clears LD A, <8 * paper + ink> > the attribtes LD (HL) ,A > Omit to leave LDIR > colour intact You can improve on this too, but that's not likely to benecessary in most applications. 03582 (0DFE) ANOTHER DISPLAY SCROLLER Entering the routine at 3582 will scroll all 23 lines of thedisplay UP by one line. Attributes are handled also. Thisroutine is called by USR 3282 itself. Entering the routine two bytes on, you can select a bottomwindow to scroll. If you enter with the B register holding say,10, then the subsequent CALLing of 3584 will scroll the bottomten lines up only, leaving the rest of the display on topintact. This technique has been used in some adventures to scroll theinput lines, leaving the graphics intact. 03652 (0E44) CLEAR LINES ROUTINE This routine will clear the bottom 'x' lines of the screen, thevalue of 'x' being held in the B register. The area is clearedand filled with the current attribute values. 03756 (0EAC) ZX PRINTER COPY ROUTINE Equivalent to the COPY command. One failing of COPY is that itonly prints the top 22 lines of the screen and completelyignores the bottom two lines. However, the routine itself isvery flexible, if used properly. Just calling 0EAC directly will perform a straight screen dumpbut, by calling a routine at 03762 (0EB2), it becomes much moreinteresting. This is the routine called by USR 3756 (0EAC), which sets upsome variables to perform a "standard" dump. You can create thevariables yourself to produce some useful effects. DI <Vitally Important ! LD B,192 <The number of screen pixel lines to be copied. The ROM sets this to 176, 22 * 8 pixel lines. We can set 192lines for a full screen copy LD HL,16384 < The Base address of the screen display. CALL 0EB2 < Call the main routine. It would be possible to change the address loaded into HL, topoint to a screen that was stored elsewhere in the memory. Youcould thus COPY an invisible screen! This routine exits via ROM routine 0EDF which clears theprinter buffer. This is unnecessary, since the COPY routine doesnot use this area. If this bug had been removed, the ZX COPYcould have stiil worked on 128K machines. It is possible to runa ZX or Alphacom printer on 128K or grey +2 by copying theroutine, and removing the call to the routine that clears thebuffer. Fireview 2's ZX routine does this. Here are the routines used to print via the buffer area.Remember that these routines are only applicable to 48K mode. 03789 (0ECD) COPY PRINTER BUFFER This routine will "copy" the contents of the Printer buffer(held at 23296) to the printer, logically. The routine exits via0EDF, which clears the buffer that runs from 23296 to 23551. Theroutine at 0EDF also resets the system variable PR-CC (PrinterColumn) to zero and resets bit one of FLAGZ to tell the systemthat the buffer is empty. Perhaps you have wondered what it is that enables that error"burp" sound? 04223 (10F7) ED ERROR This piece of code isn't very useful but it is quiteinteresting. It makes the buzz that a ccompanies errors whileyou are editing. Filling up the screen with one line or tryingto edit lines with strange codes in cause it. 10F7 BIT 4,(FLAGS2) No Buzz if not JR Z,1026 using Channel K LD (ERR-NR),FF Cancel Error LD D,0 DE has length of LD E,(RASP) buzz from sysvars. LD HL,1A90 Note constant CALL 03B5 Call the BEEPer 04264 (10A8) KEYBOARD INPUT A reasonably useful routine which returns the value of thecurrent key being pressed in the A register. The more complexfeatures like CAPSLOCK PAPER and INK are also handled. The carryflag is SET when a key is found. 04535 (11B7) THE 'NEW' ROUTINE This can be used from Basic or machine code. Typing NEW andenter is easier, however. System variables P-RAMT, RASP PIP andUDG are left alone, as of is the value in RAMTOP. All RAM iscleared if below RAMTOP. This routine is also called when the computer is turned on orreset with RANDOMISE USR 0, it enters the NEW routine some wayin, making it think that RAMTOP is at 65535 and that all RAM isto be cleared and also that UDGs and system variables must beset up, but we shall leave that until another day. 05808 (16B0) SETMIN It sets the edit area and all areas after it (workspace andcalculator stack) to their minimum values. The apparent effectis that these areas are "cleared". 05861 (16E5) CLOSE# Entered with the A register holding the number of the stream tobe closed. This piece of code crashes the Speccy if you close astream with a value of four or over, which has not been OPENed. This is because no end marker is on the look-up table at1716-171A. It had to be patched by a hardware addition ininterface 1. This would have been easy to fix in laterSpectrums, but it wasn't. It is for this reason that users ofEDITOR who do not use drives are told to remove the CLOSE#statements. 06035 (1793) INTERFACE ONE ERROR Use of the commands CAT, ERASE, FORMAT and MOVE takes theSpeccy here, where the error report O Invalid Stream isgenerated. However, if an interface one is present, this erroris detected and used to "wake up" the IF1 so that it gets theidea that it has to perform a command. In the end, you never seethe error, since IF1 nullifies it as soon as it happens, andthen executes the required command. 06229 (1855) LIST A BASIC LINE This routine is entered with HL holding the address in memoryof where the line actually starts. Basic always starts at theaddress found by PEEK 23635+256* PEEK 23636. This is the PROGsystem variable. There is a similar one which gives the start ofthe next line. 06683 (1A1B) LINE NUMBER PRINTING This prints a line numb er. It's entered with BC holding thenumber to be printed. Be warned that numbers over 9999 will notbe printed correctly. 06747 (1A5B) PRINT a NUMBER TO A STREAM It prints no leading spaces. If you REALLY want these, so thatall numbers are padded out with spaces, then you may enter theroutine at 1A28. HL must point to the address where the numberyou require to print is stored. This example prints 2500 to thecurrent stream. LD BC,2500 CALL 1A5Bh The alternative routine looks like this. LD HL,Any memory Location LD BC,2500 LD (HL),BC CALL 1A28h This prints the leading spaces as I described. 08855 (2297h) BORDER COLOUR CHANGE This routine should be entered with the border colour, (0-7) inthe A register. It will change the border colour and set theBORDCR system variable to the appropriate value. This is done sothe border colour does not change if the speaker is used. Acontrasting INK is also set for the two input lines. 4 ( 22AAh) PIXEL ADDRESS ROUTINE Used by both POINT and PLOT, it is entered with theco-ordinates of a screen pixel in BC. B holds the value for 'y',and C the value for 'x'. On exit, the HL register pair contains the address of the bytecontaining the pixel, and the A register holds the pixel'sposition within the byte. 08911 (22CF) POINT ROUTINE This routine must be entered with the pixel position placed in the BC register pair, exactly as detailed on the previous page. The value which would normally be given from the POINT command- in the form 0= paper, and 1= ink - is pushed onto thecalculator stack. To retrieve it, you would need to call theroutine STK-TO-A at address 2314H. It would then be placed inthe A register. 08927 (22DFh) PLOT ROUTINE Once again, the entry is made with the BC register pair holdingthe position of the pixel to be PLOTted. The rest happensautomatically. The status of both INVERSE and OVER are takeninto account, as stored in the system variable P-FLAG at 23697. 08967 (2307h) STACK TO BC This routine simply pulls a 16 bit value from the floatingpoint stack, and places it in the BC register pair. 08980 (2314h) STACK TO A As mentioned earlier, this can be used at any time to take an8-bit value from the floating point stack, and place it into theA register. 11400 (2C88h) ALPHANUM Now this is actually useful! It is entered with a value in theA register, and if it is a valid ASCII code for a letter or anumber, the carry flag is set. If it is not a valid code, thenthe carry flag is reset. There are two other routines with verysinilar uses, these are: 11547 (2D1Bh) N UMBER Only detects valid digits. 11405 (2C8Dh) ALPHA This only checks for valid letters 12457 (30A9h) MULTIPLY This has its uses too. It multiplies HL and DE. The resultappears in the HL register pair. However, if there was anoverflow, the carry flag is set. That concludes this brief journey into the Spectrum ROM. Inthese articles, I've only scratched the surface of the mostuseful routines. The floating point calculator alone could havea book written about it! If this has aroused your interest in the workings of theSpectrum Rom, the only book that I can reccomend is thelegendary SPECTRUM ROM DISASSEMBLY by DR IAN LOGAN & DR FRANKO'HARA. It is, like many Spectrum titles, out of print now though. ItsISBN number is 0-86161-116-0. You may find that Prestel Booklink(*BOOKLINK_) may be of use in locating a copy.