This page contains software for the ZX Spectrum Next, written and shared by former Crash magazine Tech Tipster Simon N Goodwin. Latest update: noon on 14th April 2020, Nextramon bugfixes and support for automatically labelling 182 system variables. All the programs have been updated and tested on NextZXOS 2.06A and Core 3.01.03 which are expected to be in the next official release.
The files on this page may be freely distributed on a non-commercial basis so long as the author's name Simon N Goodwin is acknowledged and a link to this page is included with any redistribution.Quick index
Please contact Simon if you have any comments or changes to these programs which you would like to share.
NextPort.bas is a short example NextBASIC program which reads the custom Next hardware registers to find and display aspects of the hardware setup such as the Machine ID and version, Machine type and configuration of the memory banks. The program listing is here. The program has been updated since the Day Zero NextZXOS release to use new features like REG and to show 16K page as well as bank numbers, and the amount of free memory for variables in NextBASIC.
Streams.bas is a small NextBASIC program which can list the ZX input output channels - like K, F, P and S, find a free stream number for you, list open streams and their channel bindings. It also detects and illustrates the new M and V channels in use. The program listing is here.
PROC CHANS lists currently active channels while PROC STREAMS will list open streams and the channels they connect to. PROC TEST uses the V channel to capture output of dot commands in a string. The timers example uses an earlier version of this procedure to read the Real Time Clock. PROC FREESTREAM returns the lowest openable stream number 4..15 or 999 if all streams are already open. PROC PEEKSTRING and PROC POKESTRING use that to work with whatever streams are free, rather than limit the choices to programs that call them.
The fly in the ointment is that unlike original Spectrums which ran a steady PAL TV rate of 50 frames per second (Hertz) Next has to accommodate the weird collection of TVs and monitors we've semi-globalised since, including HDMI (which has to run a bit slow), authentic and US/Japan-friendly 60 Hertz frames, and seven flavo(u)rs of IBM-legacy VGA timings (cheap and sometimes works). The PROCs in Timers.bas include one which tells you how many real frames your '50' or '60' Hertz setting is really kicking out, which could make a crucial difference when timing and designing games and tools for all the thousands of Nexts in the wild. Next '50 Hertz' settings may vary in practice from 48 to 59 Hertz - clock speeds and frame rates vary accordingly. A nominal '100 second' pause might take 103s for 60 Hertz VGA 0 (PAUSE 6000) or 86 seconds in VGA 6 on the same system.
Similar but different things happen in 50 Hertz mode, or on HDMI. You'll need the real-time clock add-on to compare real times with frame counts. The real time clock counts whole seconds and rounds down; for consistency it waits for a tick before starting to time an interval. Here is the program listing, with explanatory comments before the key PROCs.The general principle is that you call a PROC like dT (for times up to 255 frames, about four seconds) or dF (for times up to 20 minutes or so, requiring NextZXOS 2.06 and later) a minimum of THREE times. Once to get things started, then AGAIN immediately before the operation you want to perform. As soon as that's done, call the third time. The interval between the second and third calls will be in t%. Integer variables %a, %b and %t will be used during the timing - alternate versions that use %c, %d and %f are included. If the code you are testing alters %a, or %c, these frame timers won't work.
PROC SECONDS requires real-time clock hardware. It returns the number of seconds the RTC has counted today. PROC REALTIME(30) times a '30 second' PAUSE and shows how many real seconds passed in that time. Run it on your Next, you may be surprised at the result!
Nextramon.bas This development and investigation tool reads ROM or RAM and decodes the Z80 assembly-language (mnemonic machine code), ZX 40-bit floating point language - used for much of the BASIC runtime code, and by native ZX compilers - ASCII text or numbers wherever you point it, to your screen or printer. It's a NextBASIC disassembler and memory monitor, capable of disassembling all the Z80N instructions including Nextras, Floating point calculator (FPC) language codes, System Variable mnemonics, Sinclair report and Interface 1, GDOS and Unidos hook codes. Memory areas can also be displayed as text, hex or decimal.
This is a major update and bugfix for Spectramon, a Z80 disassembler written in ZX BASIC first published in ZX Computing magazine. Simon wrote the original on his new Spectrum in 1982, in a three-day marathon attempt to get to grips with keyword entry and adapt from TRS-80 BASIC.
The original program was documented and listed in the April/May and June/July 1983 issues of ZX Computing, and later sold on cassette by Argus Press Software. Just for good measure, Argus also ran it, over nine pages, in the Spring 1984 issue of Personal Software magazine. An extended version for Sam Coupe appeared in issue 33 of the Sam Supplement disc magazine.
The 2020 Next versions are faster, though still not as fast as a disassembler written well in machine code - they select 28 MHz with RUN AT 3 from the start, to take full advantage of the Next. You still get nonsensical results, as from any dissembler, if you disassemble memory that does not contain valid Z80 code. You can avoid this by checking with the A or N options. if you're looking for ROM patches, these are a quicker way to find them than by paging through the disassembly.
The April 2020 update knows about 182 of the System Variables stored in memory between 23552 TO 23733, and can use their symbolic names instead of numbers in the disassembly, making it easier to see what compiled code and ROM routines are doing. Since you may be dissassembling code that overwrites the system data or pages other memory to those addresses, there is a new option in the main menu - type S to toggle whether or not System variable names are shown in disassembly when corresponding addresses or offsets are encountered.
The above example, taken from the NextZXOS 2.06A implementation of the CLEAR and GO SUB commands, shows how System Variables are identified by Nextramon in two contexts. The Spectrum ROM expects the IY register to point into the system variables specifically at address 23610 (5C3AH) which holds ERRNR, the error report code. The interrupt routine which polls the keyboard at the start of each display field relies on this, which is why the Next manual says machine code called from BASIC must preserve that value. The same assumption is made in many places in the Spectrum ROM and system-friendly programs, so Nextramon checks the offsets associated with code references to the IY register and substitutes symbolic names if the offsets fall within the range of System Variables documented in all the Spectrum Manuals. Extras added in the ZX printer buffer (before the original system variables) are not detected as they fall out of the 8-bit signed range accessible via IY.
Often the ROM uses IY to access system variables, but sometimes it uses the 16-bit addresses directly, e.g. when transferring values between memory and the HL register. To cater for this, Nextramon checks 16-bit addresses used in load and store instructions and if they fall into the relevant range it substitutes names for numbers then as well, as long as the 'S' option is enabled in the menu. Since the symbolic values are offsets relative to address 23610, for compatibility with indexing IY, an extra symbolic constant SV is added to the absolute value; to reassemble code that uses either indexed or direct addressing, equate SV to 23610 in your assembler.
The mnemonic names are essentially those used in Spectrum manuals and Ian Logan's ROM disassembly, except that underscores are omitted as not all assemblers support them, and the names are unambiguous without them; when names differ between ZXOS versions the Next label is generally used. Next's STIMEOUT is an outlier (Sinclair labels were 6 bytes max) but it just fits the array. Many of the system variables occupy multiple bytes, so in the case of word pointers the label is used for the first (low order) byte and the same label with +1 appended appears if the second byte is accessed. KSTATE is similar so what Logan calls KSTATE4 is KSTATE+4 in the disassembly.
The large tables of stream pointers and calculator workspace are specially handled to show the internal structure; for instance the 30 byte workspace is shown as six five-byte memory areas, labelled MEM0 to MEM5 matching references to those in the Floating point calculator language. Those labels point to the exponent of each value. Suffixes +1 to +4 refer to the mantissa bytes, e.g. MEM5+4 is the label of the last byte of workspace. Streams use 38 bytes, with a pair for each channel number from #-3 to #15. For the negative streams I had to use M instead of the minus sign '-' as that’s an operator in most assemblers. Streams accessible to BASIC use corresponding positive numbers in the internal labels, e.g. STRM15+1 for the last byte of the last stream pointer.
Nextramon automatically switches between Z80N and FPC machine language byte encodings after a RST 56 instruction which switches the Spectrum to expect FPC code, but sometimes FPC code is entered directly via a branch from other FPC code. The F option allows you to start disassembly in FPC mode, whereas D defaults to Z80N instructions. FPC code is extensively used in the original Spectrum ROM and generated code from ZX compilers that support Sinclair's five-byte floating point format. The rendering of embedded floating-point constants in FPC code has been improved, and the speed of hex-dumps increased, in the March 2020 update. Input addresses may now be prefixed with $ as an alternative to suffixing them with H, when it's not obvious from the characters that a value is hexadecimal rather than decimal.
Nextramon uses Timex 2068 hires mode for a 64-column display. It supports the Alphacom and ZX printers, and possibly other printers which are compatible with NextBASIC.
This program was written from scratch for Next, though informed by structured programs written for QL SuperBASIC, so it exercises many of the features that set NextBASIC apart from ZX BASIC. There are quite a few potentially useful and re-usable PROCs in the program, so here's the NextBASIC source text of the MGT reader in case you'd like to see inside and pick up ideas, even if you've not got any MGT disc images to recover.
The April 2020 update of this utility uses recent NextBASIC extensions like PEEK$ to speed things up, and restores a couple of nested REPEAT loops which upset NextZXOS releases before March.
The program starts by using the Next file browser to help you locate a disc image for unpacking. The filename should have the extension .DSK unless you modify line 1116 to let through a different file extension, such as .MGT if you have your disc images named that way. MGT disk images are usually 800K long and always a multiple of 200K, but .browse doesn't yet allow filtering of files by size though in this case it's a much stronger hint of the contents than however the filename ends. There are some test command to load disc images directly by name in the previous commented-out lines starting REM PROC ReadDir.
The first couple of PROCs are at the start of the program for speed, though they don't use any GO TO or GO SUB instructions. PROC CopyBlock calls the subsequent GetSector repeatedly to read each sector of a file inside the disc image into the 510 byte string G$ so it can be displayed (if it's ASCII - expect errors if it contains undisplayable characters interpreted by PRINT as ZX BASIC control codes) and copied to the output file (in any case). MGT sectors are the standard 512 bytes long but the last two characters are not file data but the track and sector number of the following chunk of file data. Track numbers over 127 refer to the second side of the disc (for disks of over 400K) and a pair of zeros mark the end of the file.
PROC UPPER$ has standard ZX BASIC internals and just converts its argument into a string with UPPER-CASE characters in place of any lower-case ones. To make a similar PROC LOWER$, substitute "Z" and "A" for "z" and "a" in line 2665 and add rather than subtract 32 in the next line.
Sinclair allocated space for details of a file, such as array names, code addresses or BASIC variable offsets, in the tape header or microdrive directory but Amstrad's CP/M adaptation for the Plus Three scrapped that approach and introduced a 128 byte data block at the start of every ZX-standard file - DATA arrays, programs and variables, CODE or SCREEN$. It's mostly empty but 128 is the original CP/M sector size so the minimum amount of data it's easy to skip over in a CP/M file. But this does mean there's an extra byte, at offset 13 in the data prefix, for files more than 64K long, which Sinclair didn't consider. The PROC SetHead creates an Amstrad-style header, also required for ZX files in ZXNextOS, and copies in the filetype and up to three words of ZX file details, as documented in the Sinclair manuals.
This PROC will be useful to anyone else bringing ZX files onto Next and expecting to load them later with the LOAD or MERGE commands. But it is not fully structured despite the parameters and LOCALs, as it has some external dependencies like the variables plus3header and headLen which tell it where to compile the header, and the flag file which is non-zero if the header is to be written to file stream #5 after compilation. It also clobbers two of Next's fast integer variables, c% and s%, which can't yet be safely declared LOCAL. Sundry cryptic messages appear if the expected setup is not found. One neat trick in this PROC is the way it uses BANK 2 ERASE to clear 120 bytes to zero in one statement, though this will need adjustment if plus3header is not in memory bank 2, 32768 to 49151 - hence the sanity checks.
For speed, PROC ReadDir uses the dot command .extract to read entire 5K tracks of disc data into memory in one statement. It ten calls PROC UnPack to decode each 256 byte disc directory entry, most of which is a bitmap identifying the sectors allocated to the file, though not their order. UnPack extracts vital parts of the directory data into seven BASIC arrays, with one entry per file in each array. PROC SortDir then sorts the names in f$ and corresponding elements in the arrays a(), b(), s(), t(), x() and z() into ascending alphabetical order, using a Shell sort, which is much faster than a slightly simpler bubblesort but doesn't require recursion, which is still problematic in Next BASIC. This nicely structured PROC (apart from the hard-wired array names it uses) fell foul of a new BASIC bug in the day 0 update so one of the REPEAT loops has had to be commented out and replaced with an olde-worlde IF test and pair of GO TOs; various workarounds are commented out. The same bug and workaround appears in PROC SelectFile.
PROC UnPack can identify and label 20 file types, including the four standard ZX ones and extensions added by SAM, UniDOS and BetaDOS. It strips off the 'hidden' and 'protected' flags in the MGT directory and sets limit to the number of files found, to speed up the sorting. Various diagnostic and test routines appear from line 3000 in the listing. These include StrTest for the string peeks and pokes, WordTest for the 16-bit ones, MDevTest for the memory channel and - probably the most useful - PROC GetHead which opens any file and looks for a Plus3DOS header at the start and extracts and displays key information from it, if found.