<!-- PDF page 271 -->

## Chapter 24 – The System Variables

### Overview

Certain locations in memory are set aside for specific uses by the system. There are a few routines (used to keep the paging in order), and some locations called system variables (or SYSVARS). You can use **PEEK** and **DPEEK** to read them, in order to find out various things about the system, and on some of them you can usefully change with **POKE** and **DPOKE**. They are listed here with their uses.

The area occupied by SYSVARS spans the addresses **23296** (**5B00h**) to **23733** (**5CB5h**) (inclusive) and a subset of them are used in 48K BASIC – addresses **23552** (**5C00h**) to **23733** (**5CB5h**).

Note that in 48K mode, there is a buffer area between **23296** (**5B00h**) and **23552** (**5C00h**) which was used for controlling the printer. This was quite a popular location for small machine code programs on the old 48K Spectrum and if any of these routines are tried in *NextBASIC*, the computer will invariably crash. It's advisable that any 48K BASIC program that uses **PEEK**, **POKE** and **USR** to either be run in 48K BASIC mode (although it can be entered in *NextBASIC* mode and transferred using the **SPECTRUM** command) or examined thoroughly and converted so it won't use any of these commands. Alternatively, any machine code routine embedded within it should be moved to a safer area.

### System Variables

The system variables listed below, all have unique names, but do not confuse them with *NextBASIC* variables. The computer will not recognize the names as referring to system variables, and they are given solely as mnemonics to be human-readable.

The abbreviations in column 1 of the table that follows have the following meanings:

**X** The variables should not be poked because the system might crash.\
**N** Poking the variable will have no lasting effect\
**R** Routine entry point. Not a variable.

The number in column 1 is the number of bytes in the variable. For two bytes, the first one is the least significant byte; the reverse of what you might expect. So to **POKE** a value *v* to a two byte variable at address *n*, use **DPOKE** instead, as it does the conversion for you. Otherwise you'll need to enter the following for SYSVAR *n* value *v*:

```
POKE n,v-256*INT (v/256)
POKE n+1,INT (v/256)
```

and to peek its value, either use **DPEEK** or the expression:

```
PEEK n+256*PEEK (n+1)
```

<table>
<thead>
<tr><th rowspan="2">Notes</th><th colspan="2">Address</th><th rowspan="2">Name</th><th rowspan="2">Description</th></tr>
<tr><th>Hex</th><th>Dec</th></tr>
</thead>
<tbody>
<tr><td><b>R16</b></td><td>5B00</td><td>23296</td><td><b>SWAP</b></td><td>Paging subroutine</td></tr>
<tr><td><b>R17</b></td><td>5B10</td><td>23312</td><td><b>STOO</b></td><td>Paging subroutine. Entered with interrupts already disabled and AF, BC on the stack.</td></tr>
<tr><td><b>R9</b></td><td>5B21</td><td>23329</td><td><b>YOUNGER</b></td><td>Paging subroutine</td></tr>
<tr><td><b>R16</b></td><td>5B2A</td><td>23338</td><td><b>REGNUOY</b></td><td>Paging subroutine</td></tr>
<tr><td><b>R24</b></td><td>5B3A</td><td>23354</td><td><b>ONERR</b></td><td>Paging subroutine</td></tr>
<tr><td><b>X2</b></td><td>5B52</td><td>23378</td><td><b>OLDHL</b></td><td>Temporary register store while switching ROMs</td></tr>
<tr><td><b>X2</b></td><td>5B54</td><td>23380</td><td><b>OLDBC</b></td><td>Temporary register store while switching ROMs</td></tr>
<tr><td><b>X2</b></td><td>5B56</td><td>23382</td><td><b>OLDAF</b></td><td>Temporary register store while switching ROMs</td></tr>
<tr><td><b>X1</b></td><td>5B58</td><td>23384</td><td><b>CACHEBNK</b></td><td>8K Bank ID holding cached program data</td></tr>
<tr><td><b>N1</b></td><td>5859</td><td>23385</td><td></td><td>Reserved for system use</td></tr>
</tbody>
</table>

<!-- PDF page 272 -->

<table>
<thead>
<tr><th rowspan="2">Notes</th><th colspan="2">Address</th><th rowspan="2">Name</th><th rowspan="2">Description</th></tr>
<tr><th>Hex</th><th>Dec</th></tr>
</thead>
<tbody>
<tr><td><b>X2</b></td><td>5B5A</td><td>23386</td><td><b>RETADDR</b></td><td>Return address in ROM 1</td></tr>
<tr><td><b>X1</b></td><td>5B5C</td><td>23388</td><td><b>BANKM</b></td><td>Copy of last byte output to I/O port <b>7FFDh</b> (<b>32765</b>). See Chapter 23 – The Memory. This byte must be kept up to date with the last value output to the port if interrupts are enabled</td></tr>
<tr><td><b>X1</b></td><td>5B5D</td><td>23389</td><td><b>RAMRST</b></td><td><b>RST 8</b> instruction. Used by ROM 1 to report old errors to ROM 3</td></tr>
<tr><td><b>N1</b></td><td>5B5E</td><td>23390</td><td><b>RAMERR</b></td><td>Error number passed from ROM 1 to ROM 3. Also used by <b>SAVE</b>/<b>LOAD</b> as temporary drive store</td></tr>
<tr><td><b>1</b></td><td>5B5F</td><td>23391</td><td><b>INKL</b></td><td><b>INK</b> colour for LoRes</td></tr>
<tr><td><b>1</b></td><td>5B60</td><td>23392</td><td><b>INK2</b></td><td><b>INK</b> colour for Layer 2</td></tr>
<tr><td><b>1</b></td><td>5B61</td><td>23393</td><td><b>ATTRULA</b></td><td>Attributes for standard mode</td></tr>
<tr><td><b>1</b></td><td>5B62</td><td>23394</td><td><b>ATTRHR</b></td><td>Attributes for HiRes (only paper colour in bits 5:3 is used)</td></tr>
<tr><td><b>1</b></td><td>5B63</td><td>23395</td><td><b>ATTRHC</b></td><td>Attributes for HiColour</td></tr>
<tr><td><b>1</b></td><td>5B64</td><td>23396</td><td><b>INKMASK</b></td><td>Softcopy of EnhancedULA InkMask (or <b>0</b>)</td></tr>
<tr><td><b>N1</b></td><td>5B65</td><td>23397</td><td><b>LSBANK</b></td><td>Temporary bank number in <b>LOAD</b>/<b>SAVE</b> and other operations</td></tr>
<tr><td><b>1</b></td><td>5B66</td><td>23398</td><td><b>FLAGS3</b></td><td>Various flags. Bits 0, 1, 6 and 7 unlikely to be useful. Bit 2 is set when tokens are to be expanded on printing. Bit 3 is set if print output is RS232. The default (at reset) is Centronics. Bit 4 is set if a disk interface is present. Bit 5 is set if drive B: is present</td></tr>
<tr><td><b>X1</b></td><td>5B67</td><td>23399</td><td><b>BANK678</b></td><td>Copy of last byte output to I/O port <b>1FFDh</b> (8189). This port is used to control the +3 extended RAM and ROM switching (bits 0..2 – if bit 0 is 0 then bit 2 controls the 'vertical' ROM switch 02 and 13), the disk motor (bit 3) and Centronics strobe (bit 4). This byte must be kept up to date with the last value output to the port if interrupts are enabled</td></tr>
<tr><td><b>X1</b></td><td>5B68</td><td>23400</td><td><b>FLAGN</b></td><td>Flags for the NextZXOS system</td></tr>
<tr><td><b>1</b></td><td>5B69</td><td>23401</td><td><b>MAXBNK</b></td><td>Maximum available RAM bank</td></tr>
<tr><td><b>X2</b></td><td>5B6A</td><td>23402</td><td><b>OLDSP</b></td><td>Old SP (stack pointer) when TSTACK is in use</td></tr>
<tr><td><b>X2</b></td><td>5B6C</td><td>23404</td><td><b>SYNRET</b></td><td>Return address for <b>ONERR</b></td></tr>
<tr><td><b>5</b></td><td>5B6E</td><td>23406</td><td><b>LASTV</b></td><td>Last value printed by calculator</td></tr>
<tr><td><b>1</b></td><td>5B73</td><td>23411</td><td><b>TILEBNKL</b></td><td>Tiles bank for LoRes</td></tr>
<tr><td><b>1</b></td><td>5B74</td><td>23412</td><td><b>TILEML</b></td><td>Tilemap bank for LoRes</td></tr>
<tr><td><b>1</b></td><td>5B75</td><td>23413</td><td><b>TILEBNK2</b></td><td>Tiles bank for Layer2</td></tr>
<tr><td><b>1</b></td><td>5B76</td><td>23414</td><td><b>TILEM2</b></td><td>Tilemap bank for Layer2</td></tr>
<tr><td><b>X1</b></td><td>5B77</td><td>23415</td><td><b>NXTBNK</b></td><td>Bank containing NXTLIN</td></tr>
<tr><td><b>X1</b></td><td>5B78</td><td>23416</td><td><b>DATABNK</b></td><td>Bank containing DATADD</td></tr>
<tr><td><b>1</b></td><td>5B79</td><td>23417</td><td><b>LODDRV</b></td><td>Holds <b>'T'</b> if <b>LOAD</b>, <b>VERIFY</b>, <b>MERGE</b> are from tape, otherwise holds <b>'A'</b>, <b>'B'</b> or <b>'M'</b></td></tr>
<tr><td><b>1</b></td><td>5B7A</td><td>23418</td><td><b>SAVDRV</b></td><td>Holds <b>'T'</b> if <b>SAVE</b> is to tape, otherwise holds <b>'A'</b>, <b>'B'</b> or <b>'M'</b></td></tr>
<tr><td><b>N1</b></td><td>5B7B</td><td>23419</td><td><b>L2SOFT</b></td><td>Softcopy of Layer 2 port</td></tr>
<tr><td><b>2</b></td><td>5B7C</td><td>23420</td><td><b>TILEWL</b></td><td>Width of LoRes tilemap</td></tr>
<tr><td><b>2</b></td><td>5B7E</td><td>23422</td><td><b>TILEW2</b></td><td>Width of Layer 2 tilemap</td></tr>
<tr><td><b>2</b></td><td>5B80</td><td>23424</td><td><b>TILEOFFL</b></td><td>Offset in bank for LoRes tilemap</td></tr>
<tr><td><b>2</b></td><td>5B82</td><td>23426</td><td><b>TILEOFF2</b></td><td>Offset in bank for Layer 2 tilemap</td></tr>
<tr><td><b>2</b></td><td>5B84</td><td>23428</td><td><b>COORDSX</b></td><td>X Coordinate of last point plotted (Layer 1/2)</td></tr>
<tr><td><b>2</b></td><td>5B86</td><td>23430</td><td><b>COORDSY</b></td><td>Y Coordinate of last point plotted (Layer 1/2)</td></tr>
<tr><td><b>1</b></td><td>5B88</td><td>23432</td><td><b>PAPERL</b></td><td><b>PAPER</b> colour for LoRes mode</td></tr>
<tr><td><b>1</b></td><td>5B89</td><td>23433</td><td><b>PAPER2</b></td><td><b>PAPER</b> colour for Layer 2 mode</td></tr>
<tr><td><b>Nx</b></td><td>5B8A</td><td>23434</td><td><b>TMPVARS</b></td><td>Base of temporary system variables (space shared with bottom of TSTACK)</td></tr>
</tbody>
</table>

<!-- PDF page 273 -->

<table>
<thead>
<tr><th rowspan="2">Notes</th><th colspan="2">Address</th><th rowspan="2">Name</th><th rowspan="2">Description</th></tr>
<tr><th>Hex</th><th>Dec</th></tr>
</thead>
<tbody>
<tr><td><b>X117</b></td><td>5BFF</td><td>23551</td><td><b>TSTACK</b></td><td>Temporary stack grows down from here. Used when RAM bank <b>7</b> is switched in at top of memory while executing the editor or calling NextZXOS. It may safely go down to <b>5B8Ah</b> if necessary. This guarantees at least 117 bytes of stack when NextBASIC calls NextZXOS</td></tr>
<tr><td><b>N8</b></td><td>5C00</td><td>23552</td><td><b>KSTATE</b></td><td>Used in reading the keyboard</td></tr>
<tr><td><b>N1</b></td><td>5C08</td><td>23560</td><td><b>LASTK</b></td><td>Stores newly pressed key</td></tr>
<tr><td><b>1</b></td><td>5C09</td><td>23561</td><td><b>REPDEL</b></td><td>Time (in 50<sup>ths</sup> of a second) that a key must be held down before it repeats. This starts off at 35, but you can <b>POKE</b> in other values</td></tr>
<tr><td><b>1</b></td><td>5C0A</td><td>23562</td><td><b>REPPER</b></td><td>Delay (in 50<sup>ths</sup> of a second) between successive repeats of a key held down – initially 5)</td></tr>
<tr><td><b>X2</b></td><td>5C0B</td><td>23563</td><td><b>RETVARS</b></td><td>Address of local variables on return stack</td></tr>
<tr><td><b>N1</b></td><td>5C0D</td><td>23565</td><td><b>K_DATA</b></td><td>Stores 2<sup>nd</sup> byte of colour controls entered from keyboard</td></tr>
<tr><td><b>N2</b></td><td>5C0E</td><td>23566</td><td><b>TVDATA</b></td><td>Stores bytes of colour, <b>AT</b> and <b>TAB</b> controls going to TV</td></tr>
<tr><td><b>X38</b></td><td>5C10</td><td>23568</td><td><b>STRMS</b></td><td>Addresses of channels attached to streams</td></tr>
<tr><td><b>2</b></td><td>5C36</td><td>23606</td><td><b>CHARS</b></td><td>256 less than address of character set (which starts with space and carries on until ©). Normally in ROM, but you can set up your own in RAM and make CHARS point to it</td></tr>
<tr><td><b>1</b></td><td>5C38</td><td>23608</td><td><b>RASP</b></td><td>Length of warning buzz</td></tr>
<tr><td><b>1</b></td><td>5C39</td><td>23609</td><td><b>PIP</b></td><td>Length of keyboard click</td></tr>
<tr><td><b>1</b></td><td>5C3A</td><td>23610</td><td><b>ERRNR</b></td><td><b>1</b> less than the report code. Starts off at <b>255</b> (for <b>-1</b>) so <b>PEEK 23610</b> gives <b>255</b></td></tr>
<tr><td><b>X1</b></td><td>5C3B</td><td>23611</td><td><b>FLAGS</b></td><td>Various flags to control the NextBASIC system</td></tr>
<tr><td><b>X1</b></td><td>5C3C</td><td>23612</td><td><b>TVFLAG</b></td><td>Flags associated with the TV</td></tr>
<tr><td><b>X2</b></td><td>5C3D</td><td>23613</td><td><b>ERRSP</b></td><td>Address of item on machine stack to be used as error return</td></tr>
<tr><td><b>N2</b></td><td>5C3F</td><td>23615</td><td></td><td>Reserved for system use</td></tr>
<tr><td><b>N1</b></td><td>5C41</td><td>23617</td><td><b>MODE</b></td><td>Specifies <code>K</code>, <code>L</code>, <code>C</code>, <code>E</code> or <code>G</code> cursor.</td></tr>
<tr><td><b>2</b></td><td>5C42</td><td>23618</td><td><b>NEWPPC</b></td><td>Line to be jumped to</td></tr>
<tr><td><b>N1</b></td><td>5C44</td><td>23620</td><td></td><td>Reserved for system use</td></tr>
<tr><td><b>2</b></td><td>5C45</td><td>23621</td><td><b>PPC</b></td><td>Line number of statement currently being executed</td></tr>
<tr><td><b>1</b></td><td>5C47</td><td>23623</td><td><b>SUBPPC</b></td><td>Number within line of statement currently being executed</td></tr>
<tr><td><b>1</b></td><td>5C48</td><td>23624</td><td><b>BORDCR</b></td><td>Border colour multiplied by 8; also contains the attributes normally used for the lower half of the screen</td></tr>
<tr><td><b>2</b></td><td>5C49</td><td>23625</td><td><b>E_PPC</b></td><td>Number of current line (with program cursor)</td></tr>
<tr><td><b>X2</b></td><td>5C4B</td><td>23627</td><td><b>VARS</b></td><td>Address of variables</td></tr>
<tr><td><b>N2</b></td><td>5C4D</td><td>23629</td><td><b>DEST</b></td><td>Address of variable in assignment</td></tr>
<tr><td><b>X2</b></td><td>5C4F</td><td>23631</td><td><b>CHANS</b></td><td>Address of channel data</td></tr>
<tr><td><b>X2</b></td><td>5C51</td><td>23633</td><td><b>CURCHL</b></td><td>Address of information currently being used for input and output</td></tr>
<tr><td><b>X2</b></td><td>5C53</td><td>23635</td><td><b>PROG</b></td><td>Address of NextBASIC program</td></tr>
<tr><td><b>X2</b></td><td>5C55</td><td>23637</td><td><b>NXTLIN</b></td><td>Address of next line in program</td></tr>
<tr><td><b>X2</b></td><td>5C57</td><td>23639</td><td><b>DATADD</b></td><td>Address of terminator of last <b>DATA</b> item</td></tr>
<tr><td><b>X2</b></td><td>5C59</td><td>23641</td><td><b>E_LINE</b></td><td>Address of command being typed in</td></tr>
<tr><td><b>2</b></td><td>5C5B</td><td>23643</td><td><b>K_CUR</b></td><td>Address of cursor</td></tr>
<tr><td><b>X2</b></td><td>5C5D</td><td>23645</td><td><b>CH_ADD</b></td><td>Address of the next character to be interpreted – the character after the argument of <b>PEEK</b>, or the <b>NEWLINE</b> at the end of a <b>POKE</b> statement</td></tr>
<tr><td><b>2</b></td><td>5C5F</td><td>23647</td><td><b>X_PTR</b></td><td>Address of the character after the <code>?</code> marker</td></tr>
<tr><td><b>X2</b></td><td>5C61</td><td>23649</td><td><b>WORKSP</b></td><td>Address of temporary work space</td></tr>
<tr><td><b>X2</b></td><td>5C63</td><td>23651</td><td><b>STKBOT</b></td><td>Address of bottom of calculator stack</td></tr>
<tr><td><b>X2</b></td><td>5C65</td><td>23653</td><td><b>STKEND</b></td><td>Address of start of spare space</td></tr>
<tr><td><b>N1</b></td><td>5C67</td><td>23655</td><td><b>BREG</b></td><td>Calculator's B register</td></tr>
</tbody>
</table>

<!-- PDF page 274 -->

<table>
<thead>
<tr><th rowspan="2">Notes</th><th colspan="2">Address</th><th rowspan="2">Name</th><th rowspan="2">Description</th></tr>
<tr><th>Hex</th><th>Dec</th></tr>
</thead>
<tbody>
<tr><td><b>N2</b></td><td>5C68</td><td>23656</td><td><b>MEM</b></td><td>Address of area used for calculator's memory (usually MEMBOT, but not always)</td></tr>
<tr><td><b>1</b></td><td>5C6A</td><td>23658</td><td><b>FLAGS2</b></td><td>More flags. (Bit 3 set when <b>CAPS SHIFT</b> or <b>CAPS LOCK</b> is on)</td></tr>
<tr><td><b>X1</b></td><td>5C6B</td><td>23659</td><td><b>DF_SZ</b></td><td>The number of lines (including one blank line) in the lower part of the screen</td></tr>
<tr><td><b>N2</b></td><td>5C6C</td><td>23660</td><td></td><td>Reserved for system use</td></tr>
<tr><td><b>2</b></td><td>5C6E</td><td>23662</td><td><b>OLDPPC</b></td><td>Line number to which <b>CONTINUE</b> jumps</td></tr>
<tr><td><b>1</b></td><td>5C70</td><td>23664</td><td><b>OSPPC</b></td><td>Number within line of statement to which <b>CONTINUE</b> jumps</td></tr>
<tr><td><b>N1</b></td><td>5C71</td><td>23665</td><td><b>FLAGX</b></td><td>Various flags</td></tr>
<tr><td><b>N2</b></td><td>5C72</td><td>23666</td><td><b>STRLEN</b></td><td>Length of string type destination in assignment</td></tr>
<tr><td><b>N2</b></td><td>5C74</td><td>23668</td><td><b>T_ADDR</b></td><td>Address of next item in syntax table (very unlikely to be useful)</td></tr>
<tr><td><b>2</b></td><td>5C76</td><td>23670</td><td><b>SEED</b></td><td>The seed for <b>RND</b>. This is the variable that is set by <b>RANDOMIZE</b></td></tr>
<tr><td><b>3</b></td><td>5C78</td><td>23672</td><td><b>FRAMES</b></td><td>3 byte (least significant byte first), frame counter incremented every 20ms</td></tr>
<tr><td><b>2</b></td><td>5C7B</td><td>23675</td><td><b>UDG</b></td><td>Address of first user-defined graphic. You can change this, for instance, to save space by having fewer user-defined characters</td></tr>
<tr><td><b>1</b></td><td>5C7D</td><td>23677</td><td><b>COORDS</b></td><td>X-coordinate of last point plotted</td></tr>
<tr><td><b>1</b></td><td>5C7E</td><td>23678</td><td></td><td>Y-coordinate of last point plotted</td></tr>
<tr><td><b>X1</b></td><td>5C7F</td><td>23679</td><td><b>GMODE</b></td><td>Graphical layer/mode flags</td></tr>
<tr><td><b>X1</b></td><td>5C80</td><td>23680</td><td><b>PRCC</b></td><td>Full address of next position for <b>LPRINT</b> to print at (in ZX Printer buffer). Legal values 5B00 – 5B1F[^p274-1]</td></tr>
<tr><td><b>1</b></td><td>5C81</td><td>23681</td><td><b>STIMEOUT</b></td><td>Screensaver control</td></tr>
<tr><td><b>2</b></td><td>5C82</td><td>23682</td><td><b>ECHO_E</b></td><td>33-column number and 24 line number (in lower half) of end of input buffer</td></tr>
<tr><td><b>2</b></td><td>5C84</td><td>23684</td><td><b>DF_CC</b></td><td>Address in display file of <b>PRINT</b> position</td></tr>
<tr><td><b>2</b></td><td>5C86</td><td>23686</td><td><b>DF_CCL</b></td><td>Like DF_CC for lower part of screen</td></tr>
<tr><td><b>X1</b></td><td>5C88</td><td>23688</td><td><b>S_POSN</b></td><td>33-column number for <b>PRINT</b> position</td></tr>
<tr><td><b>X1</b></td><td>5C89</td><td>23689</td><td></td><td>24-line number for <b>PRINT</b> position</td></tr>
<tr><td><b>X2</b></td><td>5C8A</td><td>23690</td><td><b>SPOSNL</b></td><td>Like S_POSN for lower part</td></tr>
<tr><td><b>1</b></td><td>5C8C</td><td>23692</td><td><b>SCR_CT</b></td><td>Counts scrolls – it is always 1 more than the number of scrolls that will be done before stopping with <b>scroll?</b>. If you keep poking this with a number bigger than 1 (say 255), the screen will scroll on and on without asking you</td></tr>
<tr><td><b>1</b></td><td>5C8D</td><td>23693</td><td><b>ATTR_P</b></td><td>Permanent current colours, etc., (as set up by colour statements)</td></tr>
<tr><td><b>1</b></td><td>5C8E</td><td>23694</td><td><b>MASK_P</b></td><td>Used for transparent colours, etc. Any bit that is 1 shows that the corresponding attribute bit is taken not from ATTR_P, but from what is already on the screen</td></tr>
<tr><td><b>N1</b></td><td>5C8F</td><td>23695</td><td><b>ATTR_T</b></td><td>Temporary current colours, etc., (as set up by colour items)</td></tr>
<tr><td><b>N1</b></td><td>5C90</td><td>23696</td><td><b>MASK_T</b></td><td>Like MASK_P, but temporary</td></tr>
<tr><td><b>1</b></td><td>5C91</td><td>23697</td><td><b>P_FLAG</b></td><td>More flags</td></tr>
<tr><td><b>N30</b></td><td>5C92</td><td>23698</td><td><b>MEMBOT</b></td><td>Calculator's memory area – used to store numbers that cannot conveniently be put on the calculator stack</td></tr>
<tr><td><b>2</b></td><td>5CB0</td><td>23728</td><td></td><td>Not used</td></tr>
<tr><td><b>2</b></td><td>5CB2</td><td>23730</td><td><b>RAMTOP</b></td><td>Address of last byte of NextBASIC system area.</td></tr>
<tr><td><b>2</b></td><td>5CB4</td><td>23732</td><td><b>P_RAMT</b></td><td>Address of last byte of physical RAM.</td></tr>
</tbody>
</table>

[^p274-1]: Not used in 128K mode or when certain peripherals are attached

