Part 24 The memory Subjects covered... PEEK POKE CLEAR Memory management Deep inside the +3, everything is stored as bytes, i.e. number between 0 and 255 (FFh). You may think you have stored away the price of Ruddles or the players' names in the Arsenal football team, but in fact, all the information has been converted into collections of bytes, and bytes are what the computer sees. Each place where a byte can be stored has an address, which is a number between 0 (or 0000h) and 65535 (FFFFh). This means that an address can be stored as two bytes. You can think of the memory as a long row of numbered boxes, each of which can contain a byte. Not all the boxes are the same, however - the boxes from 4000h to FFFFh are RAM boxes, which means you can open the lid and alter the contents, but those from 0 to 3FFFh are ROM boxes, which have a glass lid that cannot be opened - you just have to read whatever was put into them when the computer was made. In the +3, we have crammed in more than twice the amount of memory than can comfortably fit. While the processor can address 65536 bytes, there are in fact 131072 bytes of RAM and 65536 bytes of ROM making 196608 bytes (192K) in all! All this is hidden from the processor by the hardware using a process called paging - BASIC (and the processor) always 'sees' the memory as 16K of ROM and 48K of RAM (or 64K of RAM with no ROM - though this latter combination is never used by BASIC). 65535 +---------+ FFFFh | RAM 0-7 | 49152 |---------| C000h | RAM 2 | 32768 |---------| 8000h | RAM 5 | 16384 |---------| 4000h | ROM 0-3 | 0 +---------+ 0000h The +3 memory map To inspect the contents of a box, we use the PEEK function. Its argument is the address of the box, and its result is the contents. For example, this program prints out the first 21 bytes in ROM (and their addresses)... 10 PRINT "Address"; TAB 8; "Byte" 20 FOR a=0 TO 20 30 PRINT a; TAB 8; PEEK a 40 NEXT a All these bytes will probably be quite meaningless to you, but the processor chip understands them to be instructions telling it what to do. To change the contents of a box (if it is RAM), we use the POKE command. Its form is... POKE address,contents ...where address and contents are numeric expressions. For example, if you type... POKE 31000,57 ...then the byte at address 31000 is given the new value 57. Now type... PRINT PEEK 31000 ...to prove this. (Try poking in other values, to show that there is no cheating.) The new value must be between -255 and +255; if it is negative, then 256 is added to it. The ability to poke gives you immense power over the computer if you know how to wield it, and immense destructive possibilities if you don't. It is very easy (by poking the wrong value into the wrong address) to lose vast programs that took you hours to type in. Fortunately though, you won't do the computer any permanent damage. We shall now take a more detailed look at how the RAM is used. Don't bother to read this unless you're really interested. The memory is divided into different areas (shown in the diagram ahead) for storing different kinds of information. The areas are only large enough for the information that they actually contain, and if you insert some more at a given point (for instance by adding a program line or variable), then space is made by shifting up everything above that point. Conversely, if you delete information, then everything is shifted down. The display file stores the contents of the TV screen. It is rather curiously laid out, so you probably won't want to PEEK or POKE in it. Each character position on the screen has an 8 x 8 grid of dots; each dot can be either 0 (paper) or 1 (ink), so by using binary notation we can store the pattern as 8 bytes - one for each row. However, these 8 bytes are not stored together. The corresponding columns in the 32 characters of a single line are stored together as a scan of 32 bytes, because this is what the electron beam in the TV needs as it scans from the left-hand side of the screen to the other. Since the complete picture has 24 lines of 8 scans each, you might expect the total of 192 scans to be stored in order, one after the other - well you'd be wrong! First come the top scans of lines 0 to 7, then the next scans of lines 0 to 7, and so on to the bottom scans of lines 0 to 7; then the same for lines 8 to 15; and again for lines 16 to 23. The upshot of all this is that if you're used to a computer that uses PEEK and POKE on the screen, then you'll have to start using SCREEN$ and 'PRINT AT' instead (or PLOT and POINT). The attributes are the colours and so on for each character position, using the format of ATTR. These are stored line by line in the order you'd expect. The way that the computer organises its affairs changes slightly between 48 BASIC and +3 BASIC mode. The area that was the printer buffer in 48 BASIC mode, is used for extra system variables in +3 BASIC mode in much the same way as it was on the Spectrum +2. The variables have changed, though. 5C00h (23552) | v +-----------------+-----------------+ (48K mode only) | Printer buffer | System vars | +-----------------+-----------------+ : : +--------------+------------+-----------------------------------+-- | Display file | Attributes | System variables | +--------------+------------+-----------------------------------+-- ^ ^ ^ ^ ^ | | | | | 4000h 5800h 5B00h 5C00h 5CB6h (16384) (22528) (23296) (23552) (23734) CHANS --+-------------+-----+-------+------+-----+-------------------+----+-----+-- | Channel | 80h | BASIC | Vars | 80h | Command or prog. | NL | 80h | | information | | prog | | | line being edited | | | --+-------------+-----+-------+------+-----+-------------------+----+-----+-- ^ ^ | | 5CB6h WORKSP (23734) CHANS --+-------+----+------------+------------+-------+---------+-- | INPUT | NL | Temporary | Calculator | Spare | Machine | | data | | work space | stack | | stack | --+-------+----+------------+------------+-------+---------+-- ^ ^ ^ ^ | | | | WORKSP STKBOT STKEND SP (stack pointer) --+--------------+---+-----+-----------------------+ | GO SUB stack | ? | 3Eh | User defined graphics | --+--------------+---+-----+-----------------------+ ^ ^ ^ | | | RAMTOP UDG P RAMT The system variables contain various pieces of information that tell the computer what sort of state it's in. They are listed fully in part 25 of this chapter, but for the moment, note that there are some (called CHANS, PROG, VARS, E LINE, and so on) that contain the addresses of the boundaries between the various areas in memory. These are not BASIC variables, and their names will not be recognised by the +3. The channel information contains information about the input and output devices, namely the keyboard (together with the lower half of the screen), the upper half of the screen, and the printer. Each line of BASIC program has the form... Most significant byte | | Least significant byte | | v v +----+----+---------+-------- - - - - --------+-+-+-+-+-+-+-+-+ | | | | | | | | | | | | | | 2 bytes | 2 bytes | |0 0 0 0 1 1 0 1| | | | | | | | | | | | | | +----+----+---------+-------- - - - - --------+-+-+-+-+-+-+-+-+ \_______/ \_______/ \_______________________/ \_____________/ | | | | Line Length of Text ENTER number text + ENTER Note that, in contrast with all other cases of two-byte numbers in the Z80, the line number here is stored with its most significant byte first, i.e. in the order that you'd write them down. A numerical constant in the program followed by its binary form, using the character 'CHR$ 14' followed by five bytes for the number itself. The variables have different formats according to their different natures. The letters in the names should be imagined as starting off in lower case. Number whose name is one letter only: Sign bit | v +-+-+-+-+-+-+-+-+---------------+-+----- - - - - ------+ | | | | | | | | | | | | |0 1 1 | Exponent byte | 4 Mantissa bytes | | | | | | | | | | | | | +-+-+-+-+-+-+-+-+---------------+-+----- - - - - ------+ \_______/ \____________________________________/ | | Letter-60h Value Number whose name is longer than one letter: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -+-+-+-+-+-+-+-+-+--- - - ---+ | | | | | | | | | | | | | | | | | | | | | | | | | | | |1 0 1 |0 | |1 | 5 bytes | | | | | | | | | | | | | | | | | | | | | | | | | | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - +-+-+-+-+-+-+-+-+--- - - ---+ \_______/ \_____________/ \_____________/ \_________/ | | | | Letter-60h 2nd character Last character Value Array of numbers: +-+-+-+-+-+-+-+-+-------+------+-------+ - - +-------+-------+ | | | | | | | | | 2 | 1 | 2 | | 2 | 5 | |1 0 0 | bytes | byte | bytes | | bytes | bytes | | | | | | | | | | | | | | | each | +-+-+-+-+-+-+-+-+-------+------+-------+ - - +-------+-------+ \_______/ \_____/ \____/ \_____/ \_____/ \_____/ | | | | | | Letter-60h Total No. 1st dim. Last Elements length of dims dim. of elements & dims + 1 for no. of dimensions The order of the elements is: First - the elements for which the first subscript is 1. Next - the elements for which the first subscript is 2. Next - the elements for which the first subscript is 3... ...and so on for all possible values of the first subscript. The elements with a given first subscript are ordered in the same way using the second subscript, and so on down to the last. As an example, the elements of the 3 x 6 array 'c' in part 12 of this chapter are stored in the order c(1,1) c(1,2) c(1,3) c(1,4) c(1,5) c(1,6) and c(2,1) c(2,2) ... c(2,6) and c(3,1) c(3,2) ... c(3,6). Control variable of a FOR...NEXT loop: Least significant byte Most significant byte | | v v +-+-+-+-+-+-+-+-+-------+-------+-------+---+---+------+ | | | | | | | | | 5 | 1 | 2 | | | 1 | |1 1 1 | bytes | byte | bytes |2 bytes| byte | | | | | | | | | | | | | | | | +-+-+-+-+-+-+-+-+-------+-------+-------+---+---+------+ \_______/ \_____/ \_____/ \_____/ \_____/ \____/ | | | | | | Letter-60h Value Limit Step Looping Statement line number within line String: +-+-+-+-+-+-+-+-+---------+--------- - - - ----------+ | | | | | | | | | | | |0 1 0 | 2 bytes | | | | | | | | | | | | | +-+-+-+-+-+-+-+-+---------+--------- - - - ----------+ \_______/ \_______/ \________________________/ | | | Letter-60h Number Text of string of (may be empty) characters Array of characters: +-+-+-+-+-+-+-+-+-------+------+-------+ - - +-------+------+ | | | | | | | | | 2 | 1 | 2 | | 2 | 1 | |1 1 0 | bytes | byte | bytes | | bytes | byte | | | | | | | | | | | | | | | each | +-+-+-+-+-+-+-+-+-------+------+-------+ - - +-------+------+ \_______/ \_____/ \____/ \_____/ \_____/ \____/ | | | | | | Letter-60h Total No. 1st dim. Last Elements length of dims dim. of elements & dims + 1 for no. of dimensions The calculator is the part of the BASIC system that deals with arithmetic, and the numbers on which it is operating are held mostly in the calculator stack. The spare area contains the space so far unused. The machine stack is the stack used by the Z80 processor to hold return addresses and so on. The GO SUB stack was mentioned in part 5 of this chapter. The byte 'pointed to' by RAMTOP has the highest address used by the BASIC system. Even NEW, which clears the RAM, only does so as far as this - so it doesn't change the user-defined graphics. You can change the address RAMTOP by putting a number in a CLEAR statement, i.e.... CLEAR new RAMTOP ...which does the following: 1. Clears out all variables. 2. Clears the display file (like CLS does). 3. Resets the PLOT position to the bottom left-hand corner. 4. RESTOREs the DATA pointer. 5. Clears the GO SUB stack and puts it at the new RAMTOP (assuming that this lies between the calculator and the physical end of RAM; otherwise it leaves RAMTOP where it was). RUN also performs a CLEAR, although it never changes RAMTOP. Using CLEAR in this way, you can either move RAMTOP up to make more room for the BASIC by overwriting the user-defined graphics, or you can move it down to make more RAM that is preserved from NEW. It can also be used to ensure that the machine stack is below BFE0h (49120) when intending to call +3DOS - this means that the stack will not have to be subsequently moved within your own machine code. If you are in an experimental frame of mind you can also use CLEAR to explore the extra memory. 'CLEAR 49151' moves all of BASIC below the addresses that hold the switchable RAM paging. By using 'POKE 23388,16+n' where 'n' is a number between 0 and 7, you can make the computer switch in page 'n' of the RAM. You will then be able to use PEEK and POKE in the normal way to examine and change the page. Beware - the extra pages are normally used by the system for disk and editor operations, so always reset the +3 after exploring in this way, before doing anything else. Type NEW, select '+3 BASIC', then enter the command 'CLEAR 23825' to get some idea of what happens to the machine when it fills up. If you then try to make the +3 compute, (for example, type in 'PRINT 1+1') you will see the report '4 Out of memory' displayed. This means the computer has no more room for information. If you come up against this message while entering a large program, you will have to empty the memory slightly (delete a line or so) in order to control the computer. Memory management We mentioned earlier that there is rather more memory in the computer than the processor can deal with. While the processor can indeed address only 64K of memory at once, the extra memory can be slotted in and out of that 64K at will. Consider a TV set. Although it (and you) can only deal with one channel at a time, there are another three channels always there which can be selected with the right buttons. So, even though there's four times as much information as you can use at any one time, you can pick and choose which part is relevant. It is much the same for the processor. By setting the right bits in an I/O port it can pick and choose which chunks of the 192K of memory it wants to use. For the majority of the time in BASIC it ignores most of the memory, but for games playing, having three times as much RAM is really rather useful. Look again at the +3's memory map (shown at the beginning of this section). RAM pages 2 and 5 are always in the positions shown when BASIC is used, though there's no reason why they shouldn't be in the banked section (C000h to FFFFh) - however, it would be difficult to see any use for this. The RAM banks are of two types: RAM pages 4 to 7 which are contended (meaning that they share time with the video circuitry), and RAM pages 0 to 3 which are uncontended (where the processor has exclusive use). Any machine code which has critical timing loops (such as music or communications programs) should keep all such routines in uncontended banks. For example, executing NOPs in contended RAM will give an effective clock frequency of 2.66Mhz as opposed to the normal 3.55MHz in uncontended RAM. This is a reduction in speed of about 25%. The hardware switch normally used to select RAM is at I/O address 7FFDh (32765). The bit field for this address is as follows: D0...D2 - RAM select D3 - Screen select D4 - ROM select D5 - Disable paging D2...D0 is a three bit number that selects which RAM page goes into the C000h to FFFFh slot. In BASIC, RAM page 0 is normally in situ. When editing or calling +3DOS routines, RAM page 7 is used for various buffers and 'scratchpads'. D3 switches screens: screen 0 is held in RAM 7 (beginning at C000h) and can only be used by machine code programs. It is entirely feasible to set up a screen in RAM 7 and then page it out; this leaves the entire 48K free for data and program. Note that the +3's COPY (file) command may well use buffers in the second screen area (corrupting a second screen which may be 'hidden' there). D4 determines which ROM is paged into 0000h to 3FFFh (in combination with bit 2 of port 1FFDh - see below). D5 is a safety feature - once this bit has been set, no further paging operations will work. This is normally used when the machine assumes a standard 48K Spectrum configuration and all the memory paging circuitry is locked out. It cannot be turned back into a 128K machine other by switching off or pressing RESET button; however, the sound chip can still be driven by OUT. If a 48K Spectrum game loaded from disk will not work, it is possible that by using the SPECTRUM command followed by 'OUT 32765,48' (which locks bit 5 in this port), the game might then work. The +3 also uses I/O port 1FFDh for some ROM and RAM switching. The bit field for this address is as follows: D0...D1 - ROM/RAM switching D2 - Affects whether D0...D1 work on RAM/ROM D3 - Disk motor D4 - Parallel port strobe (active low) When bit 0 is 0, bit 1 has no effect and bit 2 is a 'vertical' ROM switch (i.e. between ROM 0 and ROM 2, or between ROM 1 and ROM 3). Bit 4 in the port at 7FFDh is a 'horizontal' ROM switch (i.e. between ROM 0 and ROM 1, or between ROM 2 and ROM 3). The following diagram serves to show the various ROM switching possibilities... +-------------+ Bit 4 7FFDh (23388) +-------------+ | | (system variable: BANKM) | | | ROM 0 | | ROM 1 | | | <----- horizontal -----> | | | Editor | | Syntax | | | | | +-------------+ +-------------+ ^ ^ | | | Bit 2 1FFDh (23399) | (system variable: BANK678) vertical vertical | | v v +-------------+ +-------------+ | | | | | ROM 2 | | ROM 3 | | | <----- horizontal -----> | | | DOS | | 48 BASIC | | | | | +-------------+ +-------------+ Horizontal and vertical ROM switching It is best to think of bit 4 in port 7FFDh and bit 2 in port 1FFDh combining to form a 2-bit number (0...3) which determines which ROM occupies the memory area 0000h...3FFFh. Bit 4 of port 7FFDh is the least significant bit and bit 2 of 1FFDh is the most significant bit. Bit 2 of 1FFDh Bit 4 of 7FFDh Switched ROM at (sys. var.: BANK678) (sys. var.: BANKM) 0000h...3FFFh 0 0 0 0 1 1 1 0 2 1 1 3 ROM switching (with Bit 0 of 1FFDh set to 0) When bit 0 of port 1FFDh is set to 1, bits 1 and 2 switch in various RAM combinations that occupy the full 64K address space. These are not used by +3 BASIC but are provided for authors of operating systems/games. When the +3DOS 'DOS BOOT' routine is used, the bootstrap is loaded into the 4, 7, 6, 3 RAM page environment. The various +3 extra RAM paging options are as follows: Bit 2 of 1FFDh Bit 1 of 1FFDh RAM pages used (0000h...3FFFh, 4000h...7FFFh, etc.) 0 0 0, 1, 2, 3 0 1 4, 5, 6, 7 1 0 4, 5, 6, 3 1 1 4, 7, 6, 3 Extended memory paging (with Bit 0 of 1FFDh set to 1)