INTO THE 128 by Toni Baker from ZX Computing May 1987 Toni Baker begins a series exploring the secrets of the 128, and starts by proving that you can switch between 48 and 128K modes at will. [The RANDOMIZE USR 32814 function to switch to 128 mode doesn't work. ] [I've tried entering 48k mode from the menu, from the SPECTRUM command,] [and from RANDOMIZE USR 32781 (which works); but whichever way I get to] [48k mode, trying to enter 128k mode with RANDOMIZE USR 32814 always ] [crashes. The call address 32814(802Eh) is correct and the code matches] [the listing, so there must be an error in the listing. JimG] Welcome to the first of a new five part series [only two parts were printed, as ZX Computing ceased publication after the June 1987 issue] on the 128K versions of the Spectrum (ie. both the Spectrum 128 and the 128+2) from a machine code perspective. In this series I intend to cover all aspects of the new machines where they differ from the old 16K and 48K machines. I'll be going through all the special features and explaining how you can access them from machine code. First of all, the most obvious feature of the 128 is its large memory. In fact it now has 32K of ROM and 128K of RAM, making 160K in all - quite a phenomenal amount really. This memory is organised in what are called pages, a page being simply a chunk of continuous memory. On the 128 there are two pages of ROM and eight pages of RAM, and each page contains exactly 16K of memory. Hence we have 2*16 = 32K of ROM, and 8*16 = 128K of RAM altogether. Traditional machine codists will be aware that on the 48K Spectrum the memory was continuous and occupied all addresses from 0000 to FFFF inclusive (with 0000 to 3FFF being ROM and the rest RAM). It is clear, however, that if we want to address more memory than was allowed on the 48K then four hexadecimal digits is simply not enough. To address the vast banks of memory on the 128 we need not four but FIVE hexadecimal digits, so we can have addresses like 12345h or 7CDEF. To see how all this works let's first look at the ROM. A ROM with a view There are two pages of ROM, and each page contains 16K. The first page is numbered (not surprisingly) from 00000 to 03FFF inclusive. This is known as ROM zero, and may be colloquially referred to as "The NEW ROM". When the machine is first switched on or the RESET button pressed then control begins at the very start, at address 00000. This "New ROM" is in fact totally new and is not present on 16K and 48K machines. The second page of ROM is numbered from 10000h to 13FFF. This is called ROM one, and is sometimes referred to as "The OLD ROM". Although a few changes have been made this is, essentially, the original ROM which was present on 16K and 48K machines. Notice that the numbering of the ROMs is not continuous (ie. there is a gap between the end of ROM 0 (03FFF) and the start of ROM 1 (10000h)). The next task is to see how all this ties in with machine code. You are probably aware that all machine code instructions are designed for an address range using only four hex digits, not five. For instance CALL xxxx is allowed but CALL xxxxx is not. Instructions like LD A,(HL) or JP (HL) may at first glance seem like a way round the problem, but then you have to remember that HL itself (as with all register pairs) can only hold values between 0000 and FFFF, which leaves us back at square one. The solution is actually very simple. An instruction like CALL 1234h can mean either CALL 01234h or CALL 11234h depending on which of the ROMs is paged in. You can visualise this by imagining that only one of the two ROMs is allowed in at a time. Either of the ROMs (but never both) may be present in memory at any one time. If ROM 0 is present then we say that ROM 0 is paged in. If ROM 1 is present then we say that ROM 1 is paged in. Whichever of the ROMs is paged in (since one of them must be at all times) is referred to as the current ROM, or the current ROM page. Thus the current ROM will invariably be either 0 or 1 - this supplies the first digit [of] all ROM addresses. The remaining four digits may be handled in machine code as normal. Since there are only two ROMs and no more, addresses such as A1234 cannot exist. I have, however, heard of the Shadow ROM of the ZX Interface One being referred to as ROM two, in which case maybe addresses 20000h to 21FFF could refer to the Shadow ROM, but this is non-standard so I won't go into it in any detail. On the RAM PAGE Having dealt with ROM addresses it is now time to deal with RAM. Addresses in RAM are all between 0000 and FFFF, and as with the ROMs, only one page of RAM may be paged in at any one time. The pages of RAM are numbered from zero to seven, so this means that RAM addresses all lie in one of the ranges 0C000 to 0FFFF, 1C000 to 1FFFF, 2C000 to 2FFFF, 3C000 to 3FFFF, 4C000 to 4FFFF, 5C000 to 5FFFF, 6C000 to 6FFFF, or 7C000 to 7FFFF. Whichever of the RAM pages is paged in is referred to as the current RAM, or the current RAM page. The current RAM page wIll be a digit between 0 and 7 - this supplies the first digit of all RAM addresses, The remaining four digits may be handled in machine code as normal. Having established that all addresses between x0000 and x3FFF are in ROM, and that all addresses xC000 to xFFFF are in RAM, (where x refers to the relevant page number) this leaves us with a gap. What about addresses 4000 to BFFF? The answer is a kind of shorthand. The address range between 4000h and BFFF is split up into two 16K chunks, ie. 4000h to 7FFF and 8000h to BFFF. The first chunk is shorthand for RAM page five, and the second chunk is shorthand for RAM page two. In other words, 4000h means precisely the same thing as 5C000. (Also, 5000h means 5D000, 6000h means 5E000 and 7000h means 5F000, etc). This means that, in effect, page five is permanently paged in, though with a modified addresses range. In similar fashion, 8000h means the same thing as 2F000, etc. So page two is also effectively permanently paged in, again with a modified address range. As well as being a shorthand method of accessing two of the eight RAM pages, we also now have an illusion of continuity - and this is the marvellous trick which makes the 128 compatible with the 48K machine. You see, we now have the situation whereby every single (four digit) address from 0000 all the way up to FFFF now actually means something. At every such address there is memory available, with 0000 to 3FFF being ROM and the rest being RAM. We now have the appearance of a continuous stretch of RAM from 4000h all the way up to FFFF. This is a 48K illusion, but it makes the thing compatible with other Spectrums, and is jolly useful for machine codes. Page to Page The next thing you'll need to know is how to change pages; that is, how to specify which ROM page and which RAM page is to be paged in. The answer comes in the form of an OUT instruction. Output port number 7FFD is the key to the thing. You can think of it almost like an extra register or memory location, in that it can store a value between 00 and FF. Like a memory location you can assign it with a new value, but, unlike a memory location it is impossible ever to read its value. There is essentially only one way of writing to this port in machine code. The sequence of instructions: LD BC,7FFD LD A,?? OUT (C),A (You can of course swap the order of the first two instructions). It is this port which PAGES IN the various ROM and RAM pages. Take a look at figure One. This shows the meanings of the individual bits of port 7FFD. As you can see, bits two to zero specify the RAM page while bit four specifies the ROM page. I'll come to the meanings of the other bits later on. There is, of course, one major problem with port 7FFD. Because you cannot read from this port it is impossible to actually determine which ROM or RAM page is currently paged in at any moment in time. For this reason the Spectrum 128 keeps a back-up copy of the value of port 7FFD in one of its new system variables. The system variable is called BANK-M. Its address is 5B5C. Because of this back-up copy reading (BANK-M) will tell you what is paged in and what isn't. It also means, however, that whenever you change page by writing to port 7FFD then you must also store the value in BANK-M, or else the ROM may cause a crash. In fact, the Spectrum 128's interrupt routines (which lie at addresses 00038 and 10038) actually require that bit four (at least) of BANK-M be accurate. This means that interrupts must be disabled whilst changing ROMs. Furthermore, on leaving the interrupt routine the value in (BANK-M) is output to port 7FFD, so if they didn't match before, they certainly will afterwards. The upshot of all this is that if you want to change RAM page (or screen - but more of that later) then either interrupts must be disabled throughout the change, or (BANK-M) must be loaded first and port 7FFD loaded second. If you get this the wrong way round then you'll get a crash the first time an interrupt occurs between the two instructions. Screen display As with the 48K Spectrum the screen is stored at address 4000h. As I've already stated this is the same thing as 5C000 (ie. address C000 on RAM page five). The Spectrum 128, however, has not one but two screens, though this isn't obviously mentioned in the instruction manual. Both of the 128's screens are memory mapped, but obviously only one of them can ever be visible on the TV at any one time. The normal screen which appears all of the time under normal circumstances is called SCREEN ZERO, but there is also an alternative screen, called SCREEN ONE, which is stored at address 7C000 (ie. address C000 on RAM page seven). If one of these screens is visible on the TV then it is said to be ACTIVE. Normally screen zero is active at all times and screen one is never active; however, you can change this from machine code by setting bit three of (BANK-M) and output port 7FFD (see Figure 1 [IN1_1.GIF]). What's more, it makes no difference if a different RAM page is paged in. For instance, screen one is stored on RAM page seven. Suppose we made screen one active by setting bit three of (BANK-M) and subsequently outputting the value to port 7FFD. This would mean that the contents of screen one would be visible on the TV. The pixels of screen one are stored at addresses 7C000 to 7D7FF; whilst the attributes are stored at addresses 7D800 to 7DAFF. It is clear that page seven must be paged in, in order to change the contents of screen one. However, it is not necessary for page seven to be paged in, in order for screen one to be active. Any RAM page may be paged in, and screen one would still be visible as long as it remained active. Only by activating screen zero can screen one be made to vanish from the TV. Surprisingly, it turns out that you can change the current screen in BASIC without having to use machine code at all. The BASIC instruction POKE 23388,24 will activate screen one, whereas POKE 23388,16 will activate screen zero (and so deactivate screen one). If you try this then all you'll get is a black TV picture since all the attribute bytes contain zero. Unfortunately, it is not possible to print anything onto screen one from BASIC - machine code is a must here. Still - the technique can be useful. If your BASIC program contains the three instructions: POKE 23388,24: LOAD SCREEN$: POKE 23388,16 Then the TV will appear to go blank whilst a file is loaded from tape. When the loading is complete the finished picture will appear on the TV instantaneously! Another useful point to note is that any error report message generated by a BASIC program (including 0:OK) will automatically re-activate screen zero, so if you forget to switch screen one off then the Speccy will do it for you. Port There is one more bit from port 7FFD which is used. This is bit five, which in 128K mode must always be RESET. If this bit is set then the machine "locks" in 48K configuration (ie. with ROM 1 permanently paged in, RAM page zero permanently paged in, and screen zero permanently active). Setting bit five of (BANK-M), however, is not in itself sufficient to enter 48K mode, because the machine stack will contain a few "return addresses" which were intended to refer to ROM 0, and once the machine is locked ROM 0 cannot be paged in. The 128 contains two new BASIC commands - PLAY and SPECTRUM. The more complicated PLAY I shall leave until part five of this series, but SPECTRUM I can deal with now. The effect of typing the command SPECTRUM is twofold: firstly, the machine goes into 48K mode; and secondly the error report 0:OK is produced, stopping any program in its tracks. Page thirty of the Spectrum 128+2 manual tells us, and I quote, "Once in 48K BASIC mode, there is no way back to 128 BASIC mode apart from resetting the +2 (or switching off, then on again)." The same is also true of the ordinary Spectrum 128. The program which accompanies this article, however, will do just that! It is now possible to switch between 48K mode and 128K mode at will! Here's how it's done. Mode switching First, switch the machine on (or reset it) and select "128 BASIC" from the main menu. You may then type SPECTRUM if you wish, but the program will not work if you select "48 BASIC" from the main menu. CLEAR 32767 will ensure that the program remains safely above RAMTOP. LOAD the program which I have listed. You now have two additional commands at your disposal: RANDOMIZE USR 32781 is similar to the command SPECTRUM, in that it will cause the machine to enter 48K mode. However, it will do so without generating the report 0:OK, so that program execution may continue from the next statement. To complement this the command RANDOMIZE USR 32814 will re-enter 128K mode, and will again continue from the next BASIC statement. Whilst all this sounds nice and cozy, please bear in mind that there are rules to follow: NEVER use the command COPY whilst in 48k mode; NEVER use LPRINT or otherwise print to channel "P" (normally stream three) whilst in 48K mode; and NEVER place any code into the printer buffer. The reason for these restrictions is that the printer buffer is used by the Spectrum 128 to store new system variables and subroutines. Corrupting the printer buffer would truly make a return to 128K mode impossible. This new arrangement, however, has tremendous advantages for people who own a Spectrum 128 with a real printer plugged into the RS232 socket - especially if they don't own an Interface One - for it now becomes possible to use the printer in 48K mode after all. Firstly you must set the BAUD rate. This can only be done in 128K mode using the command FORMAT "P",N. Then you can type either SPECTRUM or RANDOMIZE USR 32781 to enter 48K mode, Now to print anything onto your printer all you have to do is include the following statements in your program: RANDOMIZE USR 32814: LPRINT (anything): RANDOMIZE USR 32781 As it happens, the program is relocatable too, except that there is one absolute reference to the label SWAP-2, and another to label P-128. Both of these must be changed if you wish to relocate the program. There is just one other aspect I want to discuss in this article. The Plus 2 comes complete with two little joystick sockets, and it is useful to know how to read the joysticks from machine code. To read from JOYSTICK 1 you must input a byte from port EEFE. Figure 2 [IN1_2.GIF] will show you how to interpret that byte. Each bit will normally be set, but will be reset if the joystick is in use and corresponds to the correct direction. To read the JOYSTICK 2 you must input a byte from port F7FE. Figure 2 will again show you how to interpret that byte. The machine code sequence LD BC,F7FE / IN A,(C) will input the byte into the A register. In the next article in this series I shall tell you all about page codes, and the Spectrum's "Silicon disc" file storage system. See you then.