Zeus-ish Z80 cross assembler

(I suggest you copy this text out and paste it into a text editor/window where you
can search it easily. This text and the example files and games on my website form
the documentation for Zeus.)

It's all the fault of She Who Must Be Obeyed...

"I've been converting some of my old games files"
  "Uh-huh"
"Recovered them for some old floppies"
  "Uh-huh"
"Bloody hard work, I might add..."
  "Yep"
"Not helped by the rotten tools I had to use"
  "Uh huh"
"Frankly I could have written a better assembler in the time I wasted"
  "I should hope so"
"From scratch, I'm talking about the whole bloody thing!"
  "Surprised you didn't. Anything on the TV?"
"The useless one I had to use doesn't even know all the instructions!"
  "Strictly come dancing is on, do you want to watch that?"
"Neurgh! Right! I'll do it... I'll show 'em!"
  "That's nice dear... What's an assembler?"

So, as you can see I had no alternative whatsoever to writing this... Gah.

Long time (fifteen years) since I've written a Z80 assembler, back then it took
two days to do in 80x86 assembler, so I'm assuming it'll be a doddle in Delphi...

Session 1 started 22:22 4/Oct/2008
 - Start with symbol table and evaluator from the FPGA risc assembler
   They'll need modifying but that can wait. The symbol table is naive but works

 - Implemented ds
 - Implemented align
 - Implemented db,dw,dl
 - Implemented fixed opcodes
 - Implemented INC/DEC
 - Implemented JP/CALL/RET
 - Implemented just about everything except the ROT/BIT/LD set
Session 1 ends 05:11 5/Oct/2008

Session 2 started 13:19 5/Oct/2008
 - Start with ROT, they're easy.
 - Note! Z80 documentation on web is wrong, "RR" missing. Called "RL" again
 - Implemented ROT 13:38
 - Implemented STRICT and EXTENDED 13:44
 - Cleaned up editor exit behaviour with clean files
 - Implemented BIT 14:00 (Oh gawd, only the LD set left)
 - Note! Z80 documentation on web is wrong, "LD A,R LD R,A" missing.
 - Implemented LD A,[full set] 14:51
 - Implemented LD [8-bit reg],[full set] 15:09
 - Implemented LD [16-bit reg],[full set] 15:41
 - Note! Correctly handles indirect addressing issue ld a,(4*5)+1 is not ld a,(n)
 - Note! Zeus has extra 16-bit loads, eg, ld hl,de... This doesn't yet
 - All Z80 instructions full implemented. 16:21

 - Now we need to bring the evaluator up to scratch.
 - Added support for $hex, #hex, and either . $ or * for PC 16:34
 - Added &,| and ^ as aliases for and, or and xor 16:40
 - Added single character string literals to evaluator 16:45

 - Assembles Forbidden Planet 16:51
   Sluggish though, FP (14,400 lines) takes almost a second <grin>
   I'd guess from previous assemblers that a hashed symbol-table would
   speed this up by a factor of ten or so... Not really bothered.
   [Turns out it's much faster except for the long time Delphi's memo takes
    just to provide the text in the first place...]

Session 2 ends 16:58 5/Oct/2008

Session 3 started 21:20 5/Oct/2008
  - Ported my binary -> szx file convert routines and added them.

  FP didn't run. A binary comparison of the output with it assembled by my dev
  tools showed JR displacements weren't calculated correctly. Forgot you had
  to store the PC at the start of the instruction so it didn't change
  as bytes were planted. Doh! Still, it has been 15 years since I last wrote
  a Z80 assembler... I've said that already, haven't I? Evidence of senility...

  Now generates same bytes as my development assembler. Project finished?
  So, it took about 11 hours to write a complete and useable Z80 assembler.
  Life in the olde dog yet...

  - Added a QAD find function to editor 22:07

Session 3 ended 22:52 5/Oct/2008


- Added some backward compatibility stuff for Spectrum Zeus.
  '!' for OR (Note - v1.1 revises this and makes ! and NOT behave as logical nots)
  'ENT' is ignored.

Well, that's as much as I can be bothered to write for now.  All that needs
adding to the assembler is conditional assembly and some looping structures.
That's about an hour's work. I might add a real editor at some point, but not now.

7 Oct 2008
  - Felt frisky after a successful day at work, so I've added some of Zeus's
    extensions for compatibility.
  - DEFM aliases DEFB
  - // comments
  - Added support for variables as well as labels
  - Added predefined true/false/version labels
  - Filtered out Camel Case from internal tokens so they can be used as labels
  - Added displacement support, both as "DISP" and as "ORG ADDR,DISP"
  - Added struct/send for declaring structures
  - Added import_bin for importing raw data
  - Added more documentation files
  - Added jump to error line if error message clicked on in report window
  - Added loop/lend
  - Added repeat/until
  - Added while/wend
  - Added if/elseif/else/endif

Released as V1.1 (zeusver = 1)

I wanted to call it SPASM, but that's been taken. I've called it Zeus, which is
a little unfair to the real Zeus (part of my in-house development tools) but he'll
just have to live with it.


Dedicated to all those Z80 instructions lost in action. You will not be
forgotten...


[later]

From starting out as an amusing diversion this has developed into an interesting
tool... I'm now trying out ideas (mostly implementation details) I'll use in my
next generation of development tool assemblers.

7 Oct 2008
  - Added a hashed symbol-table (virtually the same as Zeus-2 had in 1984) and
    revised token handling to use it... Much faster passes.
  - Added support for Zeus's 16-bit load set.

Released as V1.2 (zeusver = 2)

10 Oct 2008
  - Added the Diana disassembler.
  - Added support for multiple files (syntax -> include "c:\fred.asm")
  - Added support for exporting symbol tables (syntax -> export_sym "c:\fred.txt" [, numeric options]

See examples for more details.

Released as V1.3 (zeusver = 3)

13 Oct 2008
  - Added proc/endp to provide local labels. (see zeus_ex-macros.asm)
  - Added parameterless macros. (see zeus_ex-macros.asm)

Released as V1.4 (zeusver = 4)

13 Oct 2008 (later)
  - Added flow control checking (noflow - see zeus_ex_macros.asm)
  - Changed local label format and added global access to local labels
  - Added segments (see zeus_ex_segments.asm)

Released as V1.5 (zeusver = 5)

16 Oct 2008
  - New expression evaluator supports strings and floats
  - Added various string and numeric functions
  - Changed symbol table reporting options

Released as V1.6 (zeusver = 6)

16 Oct 2008 (later)
  - Fixed a bug (had to have one sooner or later) in multiple source handling.

Released as V1.61 (zeusver = 7)

18 Oct 2008
  - Added full support for macro parameters
  - Removed curly-braces comment style.
    I'm sorry if anyone has used these extensively, but I intend to use these as code block delimiters

Released as V1.7 (zeusver = 8)

19 Oct 2008
  - Added support for '==' and ':='
  - Removed a couple of debugging calls and changes I'd forgotten to disable

Released as V1.71 (zeusver = 8)

20 Oct 2008
  - Improved macro handling when macros are passed as parameters to macros
  - Added '\' as a string to token conversion operator. Allows calculated instructions, etc.

Released as V1.8 (zeusver = 9)

20 Oct 2008 (later)
  - Looking at producing a command line version. More of a PITA than it should be...
  - Added support for multi-line expressions inside brackets. See zeus_ex_macro.

Released as V1.81 (zeusver = 9)

23 Oct 2008
  - Created a command-line only version for use with other editors. (zcl.exe)
  - Extended output options to support hex files and multiple file writes

Released as V1.9 (zeusver = 10)

24 Oct 2008
  - Tidied up command line version.
  - Added support for roman numerals. Use zero-R as a prefix (i.e. 0rMMVIII) and zeusprintroman
    At last the wait is over - a Z80 assembler that understands roman notation!
    "Vos quod regam orbis terrarum!!!!!" - Nero.
    "Haud incultus hex!" - crem.

Released as v1.91 (zeusver = 10)

25 Oct 2008
  - Saves screen position

Released as v1.92 (zeusver = 10)

26 Oct 2008
  - Added syntax highlighting editor. Very experimental.
    The editor is a sub-set of the one used in the real Zeus.
    This implementation has always been a pain in the arse, so I expect trouble...
    Use the config tab to enable it.

Released as v2.00 (zeusver = 10)

29 Oct 2008
  - Added horizontal scroll bar to Diana definition window

Released as v2.01 (zeusver = 10)

 6 Nov 2008
  - Added various option variables.
  - Added DG pseudo-op for graphical character definition
  - Added a couple of options to Diana. See the help text.

Released as v2.10 (zeusver = 11)

7 Dec 2008
  - Added DF and DEFF which plant IEEE 32-bit floating-point values.
    Note that these are not compatible with ZX Spectrum floating point values.
    (I would support ZX format as well but I can't find a definition of it on t'web).

  - Added TIMESTR
    plants the time of assembly - eg "db TIMESTR"

  - Added LOW
    returns the low 8-bits of a value - eg "db low $1278 ; plants $78"
  - Added HIGH
    returns the high 8-bits of a value (shifted right) - eg "db high  $1278 ; plants $12"
  - Added WORD
    returns the low 16-bits of a value - eg "dw word $12345678 ; plants $5678"
    (For historical reasons these functions do not require brackets).
  - Added ZEUSRAND
    returns a 32-bit random number

  - Added SUM_MEM
    calculates the byte sum of an area of memory - eg SUM_MEM(Start,Length)
  - Added XOR_MEM
    calculates the byte xor sum of an area of memory - eg XOR_MEM(Start,Length)
    (Both used to calculate the correct values of simple CRC's for blocks of memory)

  - Added DBX and DBXO
    These allow simple encryption (obfuscation, really) of data.
    DBX takes a byte xor value followed by the same parameters as a DB statement.
    It then plants the bytes xor'd with that first value.

    By default DBX xor's each byte with the same value. If you want zeus can change
    that xor value dynamically by adding a value to it after every byte.
    Use DBXO to set this increment.

  - Added :: Scope selector
    used inside procedures/macros as a prefix to force a symbol to use the global symbol table
    eg "::Fred = ::Fred+1"

  - Increased code memory size to 256K
    To support paged memory designs. The sxz output routines don't support this directly yet.

  - Changed hex code display to eliminate redundant lines (lines that are all zeros)
    With 256K of memory it was taking too long to display the code ;)

    Note that you will need to delete the z80.tok file in order for Zeus to update it
    if you want Zeus to include these new tokens in the syntax highlighting.

Released as v2.20 (zeusver = 12)

8 Dec 2008
  - Changed file routines so that they will create paths if they don't already exist.

Released as v2.21 (zeusver = 12)

9 Dec 2008
  - Changed zeusrand to use Mersenne Twister algorythmn - Delphi's was a joke.
    Zeus now reseeds the MT algorythmn before each pass.
    use "zeusrand [value]" to reseed with a constant value.

Released as v2.22 (zeusver = 13)

9 Dec 2008
  - Revised pass control scheme. Don't know what I was thinking of when I wrote it...
  - Revised text extraction from syntax highlighting editor.

Released as v2.30 (zeusver = 14)

12 Dec 2008
  - Bug the third :( When I increased memory size I screwed up "import_bin"... Now fixed

Released as v2.31 (zeusver = 15)

6 Feb 2009
  - Extended "import_bin" to support loading parts of binary files.
    (e.g. import_bin "filepath", memory address, length to read, offset into file)
    It also now supports loading to default PC address
    (e.g. import_bin "filepath")

Released as v2.32 (zeusver = 16)

16 Sept 2009
  - Added "TextTidy" option to the edit menu. Just does some simple text reformatting.
    It usually improves the look of badly formatted source code, but it's easily fooled so
    I suggest comparing the code generated before and after use to be sure it hasn't
    altered the source's meaning.

Released as v2.33 (zeusver = 16)

30 Sept 2009
  - Added backup file options. (See editor options in config tab)
  - Bug-fix. Unary operators applied to string constants were ignored.

Released as v2.34 (zeusver = 17)

26 Aug 2010
  - Added SETRADIX pseudo-op to define the radix of numbers with leading zeros
   This is to aid compatibility with Grahams M80 sources

Released as v2.40 (zeusver = 18)

30 Aug 2010
  - Added code display option to editor (right-click on an editor)

Released as v2.41 (zeusver = 18)

30 Aug 2010
  - Added binary comparison option to zeus
   This is complicated and needs an example source written

Released as v2.50 (zeusver = 19)

17 May 2011
  - Changed pass end detection logic
  - Added output_db and output_unit filetypes

Released as v2.51 (zeusver = 20)

17 May 2011
  - Cured a bug with undefined label reporting
  - Cured a bug with saving the flow warning option

Released as v2.52

20 May 2011
  - Added a version of the Delphi Spec spectrum emulator, written by Chris Cowley.
    This does not handle memory contention but is very useful for debugging code,
    detecting logical errors, memory access errors and so forth.

Released as v2.60 (zeusver = 21)

27 May 2011
  - Improved the emulator
  - Added "emulate_spectrum" pseudo-op

Released as v2.61 (zeusver = 22)

29 May 2011
  - Added breakpoints to my editor windows

Released as v2.62 (zeusver = 22)

30 May 2011
  - Improved a few bits and pieces

Released as v2.63 (zeusver = 22)

2 June 2011
  - Fixed a bug where Zeus didn't fault ld ixl,l and similar illegal loads.
  - Adding the option to single-step the emulator in the editor
    F7 = step, F8 = run, F9 = stop
    Some register inspection works (F7 + hover the cursor over a register)

Released as v2.64 (zeusver = 23)

9 June 2011
  - Fixed the memory display (was using alt-BC and alt_DE register values, doh!)
  - Rather more register/memory inspection works (F7 + hover the cursor over a register
    or memory address, ie, (ix+dWhatever) or the fred bit of ld a,(fred)

Released as v2.65 (zeusver = 23)

29 Feb 2012
  - Adding some half-assed support for different models of Spectrum

Released as v2.70 (zeusver = 24)

26 Mar 2012
  - Removed a bug in the Z80 emulator's parity handling (there wasn't any) - my fault.
  - Changed Spectrum emulation, joystick behaviour mainly.

Released as v2.71 (zeusver = 25)

27 Mar 2012
  - Added simple compression option for tape-loaders.
    See next entry for details.

Released as v2.72 (zeusver = 26)

27 Mar 2012
  - Updated compression option

    The idea is for Zeus to take a single, contiguous block of memory specified by the user and
    compress it, then add the code to expand it again to the start so it will be expanded again
    when run. The compression algorythmn is currently simple and just encodes runs of identical bytes.

    The pseudo-op is zeuscompress and it requires at least three parameters:
    START_ADDR  - the start memory address of the block to be compressed.
    END_ADDR    - the end address of the block to be compressed. (The byte after the last one you need).
    EXEC_ADDR   - the address (presumably inside this block!) of the code to execute after it is expanded.

    These can be followed by up to two more optional parameters:

    RESULT_ADDR - where the compressed block is located in memory (defaults to $5B00)
    FLAGS       - Option flags.
                  At the moment only bit 0 is used. If set, the expander flashes the border during expansion.

    So, "zeuscompress $8000,$9000,$8080" would compress the block of memory from $8000..$8FFF inclusive
    and put the resulting compressed data at $5B00. Call it at $5B00 to expand it, and after expansion
    it would call the start of the code at $8080.

    So, "zeuscompress $8000,$9000,$8080,$F000,1" would compress the block of memory from $8000..$8FFF inclusive
    and put the resulting compressed data at $F000. Call it at $5B00 to expand it, and the border would flicker
    during expansion. After expansion it would call the start of the code at $8080.

    One issue - a big one - at this point was that Zeus did not know how large the compressed block was until
    after it had finished passing, generating the code and compressing it. So you had to inspect the code zeus
    generated to find how large the block is.

    This behaviour was revised in v3.51 - see below.


Released as v2.73 (zeusver = 27)

10 Jul 2014
  - Added roman, morse, bitmap and invbitmap functions

Released as v2.74 (zeusver = 28)

30 Sept 2014
  - Changed import_bin file handling to make it more civilised
    Filenames with no path will now be assumed to come from the same directory as the main sourcefile

Released as v2.75 (zeusver = 29)

1 Oct 2014
  - Removed a bug which prevented the use of labels in nested macros

12 Dec 2014
  - Added FOR/TO/STEP/NEXT, TOSTR, TOHEX, LABEL

    (See v3.57 for amendments to LABEL)
    LABEL has three uses:
    LABEL(name) defines a label from a string and gives it the current address as a value
    LABEL(name,val) defines a label from a string and gives it the value Val
    LABEL(name) in expressions returns the value of a label given as a string
    these are mainly intended for automatic code generation in macros/loops.

  - Added HX,LX,HY,LY as aliases for IXH etc, DUP/EDUP for LOOP/LEND
    these can save some editing when working with sources for other assemblers.

  - I have changed the string slicing so that the index can optionally start from 0
    set this with "zoStringIndexFromZero"

  - Enabled some of the the profile timing in the free version.
    You can mark code to be profiled like this:
    PROFILE = true
    nop                 ; This will be counted (NOP takes 4 cycles)
    PROFILE = false

    Or you can mark blocks of memory like this:
    PROFILE Start,Length
    Usually you'd do that at the end of the source-file or it will be overwritten as code is dumped

    If you want to see the profile data on a line by line basis you need to use the syntax highlighting
    editor and right-click to toggle profiling. It will update live if you want (F7/F8)

    You can elect to profile the number of TStates or the number of times an instruction is executed.

Released as v2.80 (zeusver = 31)

  - Enabled the SWITCH,CASE,ENDCASE,ENDSWITCH,DEFAULT in the free version.
  - Enabled OPTIONSIZE and OPTIONLIST in the free version.

Released as v2.81 (zeusver = 32)

1 Jan 2015
  - Various bits of tidying up in the emulator.
    Added stack display. Removed unnecessary analog joystick panel (just use the screen window)
    Register values can now be edited (stop the emulation, change value and hit return)
    PC cursor keys now emulated.

  - Removed support for non-syntax highlighting editor, too many options need it.

Released as v2.82 (zeusver = 32)

3 Jan 2015
  - Added the rescale menu option and the notes tab.

Released as v2.83 (zeusver = 32)

25 Feb 2015
  - Increased the number of include files allowed from 32 to 255.

Released as v2.84 (zeusver = 33)

26 Feb 2015
  - Local paths on include files are now supported. (Mutters darkly about bugs in other people's code)

Released as v2.85 (zeusver = 34)

25 Mar 2015
  - Added support for saving 128K szx files.
    If you set [emulate_spectrum "128K"] and then use output_szx it will save 128K .szx files.
    If you set [emulate_spectrum "3"] and then use output_szx it will save Model 3 .szx files.

    How Zeus's memory maps into the blocks isn't straightforward. See the notes below
    for v3.42 of Zeus.

Released as v2.86 (zeusver = 35)

12 Oct 2015
  - Relaxed requirement to have "A," on 8-bit add,adc,sbc instructions. (Unless STRICT)
    So as well as "ADD A,B" Zeus will accept "ADD B", for example.

  - Some changes to give Zeus compatibility with Pasmo sources, as far as seems reasonable.
    The biggest issue was their differing operator precedence rules. There's now a flag in
    Zeus to support low priority logical operators if it really must. [mutter]

Released as v3.00 (zeusver = 36)

23 Nov 2015
  - Replaced the Spectrum emulator with one that correctly emulates the Z80 flags, understands
    memory contention and has cycle-accurate timing... Delphi Spec was extremely useful but
    I've always wanted an emulator that could handle border timing graphics; having invented
    them with Tony (the space-invader figure that lurks in the border during High Score display
    in Dark Star) it always nagged at me that the emulator in Zeus couldn't display them... so
    I finally bit the bullet and wrote one... urgh... I'd say I'm grateful to all the people who've
    put information out on the web, much of which is entirely accurate, about the Spectrum hardware,
    except that without them I probably wouldn't have bothered doing this at all and saved myself
    several hours of farting about.

    The new emulator should also handle "bi-colour" mode software that dynamically changes the
    pixel/attribute data in real-time.

    LIMITATIONS - tested with a 48K Spectrum. Should support 128K accurately. Doesn't attempt to
    accurately support anything else.


  - Added output_tzx so that Zeus can directly generate TZX tape files.

    This was updated, see the documentation for v4.04 and/or v3.52 below.

  - The profile times are now shown as ccccc , ttttt, where ccccc is the T-State count in the
    current video frame when this line was last executed, and ttttt is the total time spent in
    it. The time in the frame is useful when writing code that dynamically alters the border
    or attributes.
    In CP/M emulation there's no concept of video frames so this doesn't apply.

  - Removed support for (* comment *) comments... Too much source code has (* or *) in it.

    I dithered about this, since it breaks compatibility, but too many old files have stuff like
    "org (* or blah de bloody blah)" in them, and it gets annoying having Zeus treat it as comments.

  - Changed the way Zeus supports local labels in nested structures.

    Shouldn't be a concern to anyone unless they're doing something narsty with macros. Zeus is
    now more forgiving about some things than it used to be.

  - Added MULTIPASS support...

    Do not confuse MULTIPASS with the normal run of the mill multiple passes that Zeus performs
    anyway... consider a source that has options, so that the user can choose to generate different
    versions of it. Before MULTIPASS the user would have to edit the source to set the options
    required, assemble the source, change the options, assemble the source, etc, etc, for each
    set of options. What MULTIPASS allows is the assembler to automatically run several times with
    different options. I will provide example source code at some point.

  - Added support for emulating a simple Z80 machine, with 64K RAM + CF card interface and serial port.
    This is capable of running the software for a number of simple Z80 machines, notably that of
    Grant Searle's CP/M project (with the UART code modified)...

    I will provide example files for running/debugging CP/M on this hardware.
    See www.desdes.com/products/oldfiles...

  - Added "import_hex" for importing hex files.

    import_hex "fred.hex",StartAddr,Length

    Unlike binary files, hex files contain addresses for the data they contain. StartAddr will only
    work correctly if the first address mentioned in the file is the lowest address in the file, ie,
    has the smallest value. This may not always be the case... import_hex will deduce the format of the
    hex file if it can and copes with most standard 8-bit hex files (Intel, S-Record, etc).

    Unlike binary files Zeus provides no support for offsetting into hex files, sorry.

  - Lots of other changes I have forgotten or don't feel like sharing ;)

Released as v3.10 (zeusver = 37)

12 Dec 2015
  - Added NASCOM 2 emulation. See the usual place for support files...
    The NASCOM keyboard is mapped onto the PC keys as well as reasonably possible.
    The "Nascom.zip" file contains several games including The Keys of Kraal, they all run well.
    The "Upload File" buttons will upload "*.CAS" files to the NASCOM during emulation.

  - Added MEM_ROM to allow areas of memory to be set as ROM, they cannot then be changed by executing code.

  - Added an option (See config tab) to allow some of the memory flags to be displayed on the Zeus Code tab.
    This now updates the code tab whenever it's opened, bit slower but more useful.

Released as v3.11 (zeusver = 37)

12 Dec 2015
  - Widened the borders in the Spectrum emulator.
  - Stopped the assembler resetting the editor back to the start of the first source.

Released as v3.12 (zeusver = 38)

15 Dec 2015
  - Added homebrew emulation.
    A right bugger, actually, trying to get the LED brightnesses more or less right.

Released as v3.20 (zeusver = 39)

17 Dec 2015
  - Added ULA+ support and changed ':' handling for increased compatibility with neolithic source syntax

Released as v3.30 (zeusver = 40)

23 Dec 2015
  - Added support for emulating the Membership Card Z80 project
    The OS can be found in membership.zip, assemble and emulate membership.asm to see it operating.

    There are instructions in their PDF file in the zip.

Released as v3.31 (zeusver = 40)

23 Dec 2015
  - Added support for the membership card serial port. Click on the terminal window in the emulator2 tab
    while it's running.

Released as v3.32 (zeusver = 41)

23 Dec 2015
  - Added support for formatted strings. So you can optionally use stuff like "Hello\r\n"
    The syntax highlighting fails for some obscure cases, an example is "\" "
    I need to rip that rancid code out and rewrite it.

  - Changed 48K Spectrum emulation to start code as if loaded from tape, with
    the interrupt running and so on.

  - Added "xl", "xh", "yl", "yh" as aliases for the extended register set "ixl" etc...
    So that's IXL, LX and XL now... how many variants of names for these are there?
    [historical note - Zeus-2 was the first Z80 assembler to support the extended
     registers and we defined them as IXL, IXH and so on. That used to be the standard,
     but lots of things about Z80 history seem to have been forgotten...]

18 May 2016
  - Added template file for 48K Spectrum coding. (file menu New)
    Changed Zeus code tab behaviour to show the rom.
    I'm going to alter the whole way this displays when I get a moment or two.

  - Enabled GIF file generation in ZX Spectrum mode. See emulator tab.

Released as v3.33 (zeusver = 42)

20 May 2016
  - Enabled GIF generation in ULA+ mode (oops) and NASCOM-2 mode.

Released as v3.34 (zeusver = 42)

31 May 2016
  - Changed profiling instruction counting so ix/iy instructions count as 1 per execution.
  - Changed TextTidy option (improved tidying for *really* vile sources)
  - Added "TextUglify" for those who prefer tabs after mnemonics.
  - Added some notes.
  - Changed ZeusEmulate_PC to Zeus_PC, Zeus_SP to Zeus_SP,EmulateStartInCycle to Zeus_Cycle
  - Changed editor focusing code and profile update timing.
  - Increased Spectrum FAST mode to 30MHz...

Released as v3.35 (zeusver = 43)
  - Oops! One of my dafter ideas in the last update was stopping the terminal window from becoming
    the active control... this broke the CP/M emulator. Now fixed.

Released as v3.36 (zeusver = 43)

  - Started adding the Battle mode...
  - Added the "gamble" menu option for people who like garish colours in their syntax highlighting.
    There is no ungamble option, but rest assured that Zeus will be its normal restrained and
    relaxing self again after you restart it...
  - Improved the syntax highlighting option for formatted strings (uses the config option)
  - More work on the Battle mode...

Released as v3.37 (zeusver = 44)

  - Cured a small bug in the syntax extension that allowed "CP A,0", "OR A,B" and so on.
    It was allowing registers other than A to be used.
  - Changed single-step to skip LDIR and the other repeat instructions with one key press.
    (If you want to stop after every iteration uncheck the "Step skips LDIR(etc)" checkbox
     which is on the register display panel)
  - More work on the Battle mode. Not yet functional.

  - To improve compatibility with the old GENS assembler Zeus now allows:
    - spaces in hex numbers. So "# FF" now is valid and means "#FF"... "# 1 2 3 4" means "#1234"
    - The symbol "@" to be used for OR. Note that GENS uses "!" for XOR, whereas Zeus uses "!" for NOT
      So GENS sources that use "!" will need the "!" to be changed to "xor" or "^"

    Historical note: I believe Zeus was the first assembler to allow spaces in numbers, back in 1983.
    I decided to permit them in binary numbers so bit-fields could be shown clearly. But I drew the
    line at allowing them in hex/decimal numbers as they were less useful there and people found them
    confusing...
    Recently I have seen some Russian sources that have spaces in hex numbers, which may just be a printing
    mistake, but for compatibility I've changed Zeus to support them. It shouldn't break anything.

  - Enabled support for memory panel views in the free versions of Zeus.
    (A right bugger too, since it meant re-writing the bloody hex viewer from scratch, as the dynamic
    updating relied on other things I don't intend to give away in my free assemblers... gah...)

    The hex panels show as separate windows. These can be dragged and resized as required. Zeus attempts to
    remember your preference for hex window placement across sessions. This is stored on the computer not
    in the source file, as placements generally relate to a specific computer's display hardware.

    The syntax is "zeusmem Address, Name, Width, ShowAddress, ShowText, HideOnEdit" where:
      Address is the Z80 memory address to start showing
      Name (optional) is the name to show in the caption bar
      Width (optional) is the number of bytes to show per line
      ShowAddress (optional) is set TRUE to show the start address of each line
      ShowText (optional) is set TRUE to show the data as text characters
      HideOnEdit (optional) is set TRUE to hide the memory panel when editing (added 16/1/2018)

      Examples:

      zeusmem $4000,"Screen",32,true,false      ; Show the Spectrum screen memory
      zeusmem $5800,"Attrs",32,true,false       ; Show the Spectrum attributes
      zeusmem $C000,"Maze",128,true,false       ; If playing Halls, show the maze data.

      zeusmem $C000,"Maze",128,true,false,true  ; If playing Halls, show the maze data, but not while editing

    Note 1 - there is an option on the config tab to force the memory panels to use the same font as the
    editor. This is optional, as the Dina font I prefer for editing does not scale down to very small sizes.
    Changes to this option will probably require an assembler restart, or at least the memory panels being
    undisplayed/restored.

    Note 2 - should the memory panels not appear as expected, perhaps after a change in the computers display
    configuration, the edit menu rescale option will restore them to their initial default positions.


  - Added zeussyntaxhighlight pseudo-op to allow the users to play with the editor syntax highlighting.

    The syntax is "zeussyntaxhighlight Index, Red, Green, Blue, Bold" where:
      Index is a number which specifies the type of syntax item
       0 = Tokens
       1 = Identifiers
       2 = Comments
       3 = Constants
       4 = LineNumbers
       5 = Markers
       6 = Errors
       7 = Margin data bytes
       ..
       16 = Memory Panel Addr Background
       17 = Memory Panel Addr Foreground
       18 = Memory Panel Data Background
       19 = Memory Panel Data Foreground
       20 = Memory Panel Changed Data Background
       21 = Memory Panel Changed Data Foreground
       ..
       100 = Diana background
       101 = Diana foreground
       102 = Diana defn background
       103 = Diana defn foreground
       ..
       249 = editor "marked line" colour. [not used in this version]
       250 = margin separator line colour
       251 = margin separator line2 colour
       252 = current executing line background colour
       253 = current editing line background colour
       254 = margin background colour
       255 = editor background colour

       300 = CP/M terminal Normal background colour
       301 = CP/M terminal Normal foreground colour
       302 = CP/M terminal Highlight background colour
       303 = CP/M terminal Highlight background colour

      Red,Green,Blue specify an RGB colour (0,0,0 = black, 255,0,0 = bright red, 255,255,255 = white, etc)

      Bold is optionally true or false to select bold or normal font. It defaults to false.

      So, Zeus's normal syntax highlighting uses the following:

      zeussyntaxhighlight   0, $00,$00,$00, true  ; Set the token colour
      zeussyntaxhighlight   1, $00,$00,$00, false ; Set the identifier colour
      zeussyntaxhighlight   2, $00,$00,$FF, false ; Set the comment colour
      zeussyntaxhighlight   3, $00,$00,$00, false ; Set the constant colour
      zeussyntaxhighlight   4, $00,$00,$00, true  ; Set the line number colour
      zeussyntaxhighlight   5, $00,$00,$00, true  ; Set the marker colour
      zeussyntaxhighlight   6, $FF,$00,$00, true  ; Set the error colour
      zeussyntaxhighlight   7, $00,$00,$00, false ; Set the margin data colour

      zeussyntaxhighlight  16, $00,$00,$30        ; Set the memory panel addr background
      zeussyntaxhighlight  17, $00,$FF,$FF        ; Set the memory panel addr foreground
      zeussyntaxhighlight  18, $00,$00,$30        ; Set the memory panel data background
      zeussyntaxhighlight  19, $C0,$C0,$FF        ; Set the memory panel data foreground
      zeussyntaxhighlight  20, $00,$00,$30        ; Set the memory panel new data background
      zeussyntaxhighlight  21, $FF,$FF,$FF        ; Set the memory panel new data foreground

      zeussyntaxhighlight 250, $D8,$D8,$D8        ; Set the margin separator line colour
      zeussyntaxhighlight 251, $F8,$F8,$F8        ; Set the margin separator line2 colour
      zeussyntaxhighlight 252, $00,$FF,$FF        ; Set the current executing line background colour
      zeussyntaxhighlight 253, $F8,$F8,$F8        ; Set the current editing line background colour
      zeussyntaxhighlight 254, $F0,$F0,$F0        ; Set the margin background colour
      zeussyntaxhighlight 255, $FF,$FF,$FF        ; Set the editor background colour

      Or you could use something like these for an alternate light on dark editor:

      zeussyntaxhighlight   0, $FF,$FF,$FF, true  ; Set the token colour
      zeussyntaxhighlight   1, $FF,$FF,$FF, false ; Set the identifier colour
      zeussyntaxhighlight   2, $00,$C0,$FF, false ; Set the comment colour
      zeussyntaxhighlight   3, $FF,$FF,$FF, false ; Set the constant colour
      zeussyntaxhighlight   4, $FF,$FF,$FF, true  ; Set the line number colour
      zeussyntaxhighlight   5, $FF,$FF,$FF, true  ; Set the marker colour
      zeussyntaxhighlight   6, $FF,$FF,$FF        ; Set the error colour
      zeussyntaxhighlight   7, $80,$FF,$FF        ; Set the margin data colour

      zeussyntaxhighlight 100, $FF,$FF,$FF        ; Diana background
      zeussyntaxhighlight 101, $00,$00,$A0        ; Diana foreground
      zeussyntaxhighlight 102, $FF,$FF,$FF        ; Diana defn background
      zeussyntaxhighlight 103, $00,$00,$A0        ; Diana defn foreground

      zeussyntaxhighlight 249, $00,$00,$A0        ; Set the "marked line" colour. [not used in this version]
      zeussyntaxhighlight 250, $00,$00,$A0        ; Set the margin separator line colour
      zeussyntaxhighlight 251, $00,$00,$C8        ; Set the margin separator line2 colour
      zeussyntaxhighlight 252, $00,$C0,$C0        ; Set the current executing line background colour
      zeussyntaxhighlight 253, $10,$40,$80        ; Set the current editing line background colour
      zeussyntaxhighlight 254, $20,$20,$90        ; Set the margin background colour
      zeussyntaxhighlight 255, $00,$00,$80        ; Set the editor background colour

      Memory panels can also be recoloured, note that it may take a couple of assemble cycles for the
      changes to propagate depending on how you have placed the colour changes/panel definitions

      zeussyntaxhighlight  16, $FF,$FF,$FF        ; Set the memory panel addr background
      zeussyntaxhighlight  17, $FF,$00,$FF        ; Set the memory panel addr foreground
      zeussyntaxhighlight  18, $FF,$FF,$FF        ; Set the memory panel data background
      zeussyntaxhighlight  19, $00,$00,$00        ; Set the memory panel data foreground
      zeussyntaxhighlight  20, $FF,$00,$00        ; Set the memory panel new data background
      zeussyntaxhighlight  21, $00,$00,$FF        ; Set the memory panel new data foreground

      Note that the dynamic change highlighting will automatically adapt to use whatever fore/back colours
      you provide.

      The CP/M terminal window can also be customised.

      zeussyntaxhighlight 300,$00,$20,$00         ; Normal background = light green
      zeussyntaxhighlight 301,$00,$FF,$00         ; Normal foreground = bright green
      zeussyntaxhighlight 302,$00,$80,$00         ; Highlight background = Medium green
      zeussyntaxhighlight 303,$00,$00,$00         ; Highlight foreground = Black

  - Changed the Zeus Code page behaviour depending on the "Show Memory Flags" option in the config tab.
      If you have the option to show the memory flags set then the Zeus Code tab behaviour is unchanged.
      If you don't have it set then the Code Tab shows two independent hex panels.
      The two hex panels update in real time, etc, etc.

Released as v3.38 (zeusver = 45)

  - Various changes to the editor and emulator interactions to give them a nicer "feel"

  - Added NOROM as a machine option.
    This tells the emulator to use RAM instead of ROM for the first 16K in ZX Spectrum emulation.
    This allows you to write/emulate Spectrum ROMS, and/or if you include the Spectrum ROM as a
    source file in your projects you can single step through ROM calls if you use them...

    example:

----------
                zeusemulate "48K","ULA+","NOROM"    ; Emulate a 48K Spectrum with no ROM

                ; Your code here as usual

                ; Follow it with this to add the ROM code

SpectrumRom     proc                                ; Enclose this in proc/pend so the labels are local
                include "sp_rom.asm"                ; Include the Spectrum rom source code
                mem_rom 0,$4000                     ; Prevent writes from changing it.
                pend                                ; Done

----------

Released as v3.39 (zeusver = 46)

  - Changes to function keys.
    F1  - toggle zoom
    F2  - Zoom out
    F3  - Zoom in
    F4  - Toggle "Follow Execution" mode - tells the editor to follow the executing line or not

    F7  - Single Step
    F8  - Run
    F9  - Assemble
    F10 - Assemble and Run

  - Added an update rate option for the debugging displays. See the CONFIG tab.
    On very slow computers you might prefer to reduce the overhead caused by debugging updates.
    On fast ones you might prefer smoother debugging displays than the old default.
    Move the scroll-bar in the "Emulator Options" panel to set this to taste.

  - Added a phosphor decay rate option for the hex debugging displays. See the CONFIG tab.
    Move the scroll-bar in the "Emulator Options" panel to set the time it takes for changed byte
    highlights to fade away.
    This setting does not alter the computing overhead much, so just set this to taste.

Released as v3.40 (zeusver = 46)

  - Added default ROMS/memory contents to all computer emulations so you can just hit reset to use them.
  - Fixed bug in Nascom emulation introduced in v3.37 (oops)
  - Added more template files

Released as v3.41 (zeusver = 46)

  - Fixed bug in cpm boot.asm code. Download the cpm_sources.zip file...

Released as v3.42 (zeusver = 46)

  - A few detail changes to improve assembler support for extended memory model machines.

  - Extended the "output_szx" so that it writes a 128K file for 128K Spectrum models.
    See below for an explanation of how Zeus handles 128K memory.
    It also outputs compressed rather than uncomressed files now.

  - Added "output_z80" to output *.z80 files. These will also be 128K for 128K Spectrum models.
    (see below)

    The syntax for "output_z80" is as follows:

    output_z80 "filename",StackPointer,StartAddress

    e.g.
    output_z80 "demo.z80",$0000,$8000 ; Puts the stack at $0000 and starts executing code at $8000

    You can also just give Zeus the filename and let Zeus determine the SP and PC values from the
    emulator settings.

    Zeus_PC = $8000             ; Start at $8000
    output_z80 "filename"       ; Save a Z80 file

  A note on memory addressing in Zeus, this applied to the Spectrum machine models.
  (See also "zeuspage" in the documentation for v3.52, below).

  Most Z80 assemblers (every other one as far as I know) do not understand and cannot address
  more than 64K of memory. This is understandable as the Z80 only has 16-bit addressing.

  Zeus, however, does understand large memory addressing, up to at least 256K of memory.
  What this means is that for, say, 128K Spectrum hardware you can use Zeus to build the entire
  memory contents, and have Zeus save the whole 128K out to file formats that understand 128K
  of data - this includes "*.szx", "*.z80" and also MODE 3 of "*.tap" and "*.tzx" files at the moment.

  The mapping might be confusing, this is because the naming of Spectrum memory pages isn't
  obvious, and Zeus has to follow the existing names and mapping so that it can emulate code
  correctly.

  If you are writing code for the 48K Spectrum, things do what you expect and you can ignore
  the memory paging, because the 48K Spectrum hasn't got the ability to page memory.

  For the 128K Spectrum models you should consider them as having eight 16K memory pages, which
  have numbers 0 to 7.

  For compatibility with the Spectrum hardware, when assembling code they are mapped to Zeus
  addresses like this:

    Zeus addresses -> Memory Page number
    00000 - 03FFF  -> Map into ROM and are not normally writable.
    04000 - 07FFF  -> Page 5
    08000 - 0BFFF  -> Page 2
    0C000 - 0FFFF  -> Page 0

    And the pages can also be addressed using these (greater than 64K) addresses.

    10000 - 13FFF -> Page 0
    14000 - 17FFF -> Page 1
    18000 - 1BFFF -> Page 2
    1C000 - 1FFFF -> Page 3
    20000 - 23FFF -> Page 4
    24000 - 27FFF -> Page 5
    28000 - 2BFFF -> Page 6
    2C000 - 2FFFF -> Page 7

  (The code tab can show these higher addresses)

Released as v3.43 (zeusver = 46)

  - Changes to the editor, to clean up searching and code execution swapping.

  - Improved support for debugging Spectrum ROMS. You can now access the ROMS using these
    (greater than 64K) addresses.

    30000 - 33FFF -> ROM 0 (Normal 48K ROM, lower 128K ROM, Model 3 ROM 0)
    34000 - 37FFF -> ROM 1 (              , upper 128K ROM, Model 3 ROM 1)
    38000 - 3BFFF -> ROM 2 (                                Model 3 ROM 2)
    3C000 - 3FFFF -> ROM 3 (                                Model 3 ROM 3)

    So, to write code to the Spectrum 48K ROM you could do this:
    ---------
          zeusemulate "48K","norom","raw"
          org $0000
          disp $30000
    Start   DI                  ; First byte of the ROM
    ---------

    To write code to the Spectrum 128K Lower ROM you could do this:

    ---------
            zeusemulate "128K","norom","raw"
            org $0000
            disp $30000

    Start   DI                  ; First byte of the ROM
    ---------

    To write code to the Spectrum 128K Higher ROM you could do this:

    ---------
            zeusemulate "128K","norom","raw"
            org $0000
            disp $34000

    Start   DI                  ; First byte of the ROM
    ---------

    And so on.

    Note that by using "org $0000" and "disp $30000" this code is correctly assembled
    to run at address $0000, but DISPLACED to be stored at $30000, as opposed to simply
    doing "org $30000" where Zeus would assign $30000 to label Start, etc.

    Also note that surrounding the ROM code with a proc/endp to make the labels local
    is probably a good idea, so that routines in the ROM don't accidentally use the
    addresses of code in a different ROM (the Z80 can only see one at a time).

    I'd put the first ROM inside a procedure called ROM0, and the second one inside a
    procedure called ROM1, then to access the ROM routines use Zeus's scoped local names
    so ROM0.Start or ROM1.Start, etc, etc.

    For example:

    ---------
            zeusemulate "128K","norom","raw"    ; Tell Zeus we don't want the default ROMS

    ; Code for ROM0
    ROM0    proc                ; Code for the first ROM in a procedure called ROM0

            org $0000           ;
            disp $30000         ;

    Start   DI                  ; First byte of the ROM
            JP Start            ;

            pend                ;

    ; Code for ROM1
    ROM1    proc                ; Code for the second ROM in a procedure called ROM1

            org $0000           ;
            disp $30000         ;

            nop                 ; Just so the code in this ROM is different

    Start   DI                  ; Start is NOT the first byte of ROM 1
            JP Start            ;

            pend                ;

    ; Using procedure blocks means the local labels "Start" and "Start" can refer to
    ; different addresses.
    ; Then code outside the ROM can refer to the local labels like this "ROMn.Label":

            org $8000           ; Somewhere in RAM

            ; Do something to page ROM 0 into memory
            ; Then use this to call a label inside ROM0
            call ROM0.Start     ; This calls address 0000

            ; Do something to page ROM 1 into memory
            ; Then use this to call a label inside ROM1
            call ROM1.Start     ; This calls address 0001

            ; And so on.

            output_bin "rom0",$30000,$4000      ; To write them to disk.
            output_bin "rom1",$34000,$4000      ; Or use output_srec

    ---------

  - Added zeuskeyaddr and zeuskeymask pseudo-ops. These are intended for the ZX Spectrum.

    Given a string containing key definitions, "A" .. "Z", "0" .. "9" and "[sym]", "[space]"
    "[shift]" and/or "[enter}" these return the I/O address or the input bit mask.

    So to scan a key you can do something like this:

    ---------

    PlayerLeftKey = "Q"

        ld bc,zeuskeyaddr(PlayerLeftKey)        ; Get the IO address to input
        in a,(c)                                ; Read those 5 keys
        and zeuskeymask(PlayerLeftKey)          ; And with the bit for PlayerLeftKey
        jr z PlayerLeftPressed                  ; If it's zero the key is pressed

    ---------

    The string can contain more than one key and the output will be the combination of
    all the keys in that string. This is only useful for some combinations.

        ld bc,zeuskeyaddr("1234567890")         ; Get the IO address of the top two rows
        in a,(c)                                ; Read those 10 keys
        ld e,zeuskeymask("1234567890")          ; All the bits from any of those keys
        and e                                   ; See if any are low
        cp e                                    ; Were any of them cleared?
        jr nz AnyKeyPressed                     ; It's different. Something on the top row is pressed

    The advantage of these pseudo-ops is that changing playing keys becomes a matter of
    changing a single equate.

Released as v3.44 (zeusver = 46)

  - Added "CPC64" and "CPC128" as targets for the assembler. Not (yet?) for the emulator.
    Use zeusemulate "CPC64", for example, when writing code for the CPC-64.

  - Added an option to output Amstrad SNA snapshot files. These are type 1, and either
    64 or 128K long to match the CPC64/CPC128 option selected as above.

    Use output_sna "filename",SP,PC

    Or you can just use output_sna "filename" and let Zeus pick up the SP and PC values from the usual
    Zeus_SP and Zeus_PC emulator setting variables.

    (From version 3.98 onwards Zeus can also output Spectrum 48K/128K SNA files.)

Released as v3.50 (zeusver = 47)

  - Cured a minor timing error in the emulator.

  - Added an optional address to END statements for backwards compatibility, this sets up the emulator's
    PC value.

    eg:

    END $8000

    Is equivalent to having a "Zeus_PC = $8000" statement.

  - Added zeusinvoke to call external dos commands after successful assembly.
    This is intended to allow external applications to process the files generated by Zeus.

    Use "zeusinvoke filename" or "zeusinvoke filename,working_directory"

    eg:
    zeusinvoke "test.bat"       ; Run "test.bat" every time the assembly process succeeds
    zeusinvoke "test.bat","D:\" ; Run "test.bat" with "D:\" as the working directory.

    By default it blocks and waits for the external application to finish before continuing, but you can
    add a "false" option to stop zeus waiting.

    eg:
    zeusinvoke "emulator.exe","",false ; Run "emulator.exe" every time the assembly process succeeds, and don't wait.


    If the assembly process doesn't succeed nothing happens.


  - Changed the way Zeus handles data compression.
    If you use "zeuscompress" Zeus will perform as many passes as required to generate the code,
    as normal, then run the compression algorythmn to compress the code as specified.
    That was all it did before this release.
    Now Zeus changes the assembly pointer (after the zeuscompress pseudo-op)to refer to the first
    free byte *after* the compressed data block, and then does one more pass - this means that
    output statements can know the size of the compressed data and the tape file generators can
    write exactly the right number of bytes to tape.

Released as v3.51 (zeusver = 48)

  - Added an extra mode to "output_tzx", this can now output tzx files with a loader that can
    automatically load multiple blocks of code/data, as defined by the user, including loading
    to different pages. So this can be used to load 128K applications/data.

    (See v4.04 for the simpler alternative "output_tzx_auto")

    "output_tzx" Usage:

    There are four separate modes... (see my games source code for examples of these):


    MODE 0 (Code block for 16K,48K, or first 48K of a 128K models supported)

    To generate a "CODE" block for storing binary data:
    output_tzx "pc filename","tape filename","comment",Start,Length

    From Zeus v3.53 onward you can specify a different load address like this:

    output_tzx "pc filename","tape filename","comment",Start,Length,0,LoadAddr

    Note the "0" before the load address, to specify it's mode 0.

    Where "pc filename" is the name to be used for the file, "tape filename" is the name to be
    put in the tzx file for the code block, "comment" is any comment required in the file, Start
    is the address in memory ($4000 ..  $FFFF) of the first byte and Length is the number of bytes.
    On 128K machines this cannot load to the pages that do not map into main memory normally.

    eg:

    output_tzx "darkstar.tzx","","",$8000,$4000
    output_tzx "darkstar.tzx","beefburger","not the original",$8000,$4000

    Use LOAD "" CODE to load this.



    MODE 1 (Uses a custom loader. 48K, or first 48K of a 128K model)

    Zeus can also automatically generate a "PROGRAM" block containing a tape loader, and add the
    code as a data block after it... this uses a loader like the ones I used to use in the 80's
    that load the screen at the same time as they load the data.

    This mode cannot be used on the 16K Spectrum, and on the 128K models it cannot load to the pages
    that do not map into main memory normally. (For 128K loading see mode 3, below).

    output_tzx "pc filename","tape filename","comment",Start,Length, 1 ,ExecuteAddr
    or it supports some options, mainly you can change the border colours
    output_tzx "pc filename","tape filename","comment",Start,Length, 1 ,ExecuteAddr,Options

    To use this loader sensibly you should have a loading screen loaded in memory at $4000 .. $5AFF
    for it to use... how Zeus chooses to load the screen depends on how much of it contains visible
    pixels; if entire lines of pixels are $00 Zeus will not load them.

    For example, if you have an assembler source for a game that starts at $8000, is $2000 bytes
    long and you have a loading screen for it in a file called "screen.scr" then Zeus can generate
    a tzx file with a nice loading screen using the commands:

    import_bin "screen.scr",$4000 ; This gets the loading screen and puts it in memory in place
    output_tzx "game.tzx","mygame","(c) Etc",$8000,$2000,1,$8000 ; Generate the tzx file
    where the 1 indicates this is the required TZX format.

    To load a program generated using Zeus use LOAD "" on your Spectrum or emulator.

    The "Options" optional parameter allows you to set the colours used while the loader is operating.
    Options is a 32-bit value containing six 4-bit fields. These are as follows:

    Bits    | 31 .. 24  | 23 .. 20 | 19 .. 16 | 15 .. 12 | 11 ..  8 |  7 ..  4 |  3 ..  0 |
    Effect  | Not Used  | Line INC | Line XOR | Loader A | Loader B | Leader A | Leader B |

    Where Leader A and B are the colours used while reading the tape leader, Loader A and B are the
    colours used while reading the data, and the loader colours are modified at the end of each
    video line by the Line XOR and Line INC values... the XOR and INC values interact with each
    other... if you don't want the border flashing on each bit-cycle make the A and B values the
    same. For example these colours are particularly repulsive.

    output_tzx "tony","tony","Hideous!",$7F00,$4000,1,$7F00,$00123456

    The most significant byte is reserved for other loader options to be added in future. Set it
    to zero for the moment.

    Use LOAD "" to load this. Or will load automatically on most emulators.


    MODE 2 (Program. 48K, or first 48K of a 128K models supported)

    Zeus can also put the code it generates inside a REM statement and save this as a BASIC
    programme that automatically runs the code.

    This mode can be used on any model of Spectrum, but on the 128K models it cannot load to the
    pages that do not map into main memory normally.

    During tape loading the REM statement code is placed in memory at address $5BC0, so if you
    assemble and save code starting at that address it is run there. Otherwise Zeus prepends a
    chunk of code at the start of the REM to move your code into the required position.

    output_tzx "pc filename","tape filename","comment",Start,Length, 2 ,ExecuteAddr
    where the 2 indicates this is the required TZX format.

    Use LOAD "" to load this. Or will load automatically on most emulators.


    MODE 3 (Uses a custom loader. 48K,128K models fully supported)

    Zeus can also automatically generate a "PROGRAM" block containing a tape loader, and add the
    code as a data block after it... this uses a loader like the ones I used to use in the 80's
    that load the screen at the same time as they load the data.

    This mode cannot be used on the 16K Spectrum. On the 128K models it can load to any page or pages.

    This mode can load multiple blocks of memory, which can be on any 16K page, or even overlap pages.

    The command is the same as for mode 1, including the start and length of the first block as normal:

    output_tzx "pc filename","tape filename","comment",Start,Length, 3 ,ExecuteAddr
    or it supports some options, mainly you can change the border colours
    output_tzx "pc filename","tape filename","comment",Start,Length, 3 ,ExecuteAddr,Options

    But you can add extra blocks either as Start,Length pairs after the full command like this:

    output_tzx "pc filename","tape filename","comment",Start,Length, 3 ,ExecuteAddr,Options ,Start2,Length2
    and so on, or using "output_tzx_block" commands:

    output_tzx_block "pc filename",Start,Length
    output_tzx_block "pc filename",Start,Length,Start2,Length2,Start3,Length3 and so on...

    Note that the "pc filename" must be the same in the block commands as in the original, that is
    how zeus knows which file you are adding blocks to.

    The "start" address can be a normal 16-bit $4000..$FFFF address, or anywhere in Zeus's page memory as
    described above using greater than 16-bit addressing. So, for example, for a 128K Spectrum page 0 can
    be addressed at $10000, where that number has four zero's.
    You could use "zeuspage(0)" as well.

    The "length" can also be larger than 64K... for example, saving from $10000 for $10000 would save
    pages 0,1,2, and 3.

    To use this loader sensibly you should have a loading screen loaded in memory at $4000 .. $5AFF
    for it to use... how Zeus chooses to load the screen depends on how much of it contains visible
    pixels; if entire lines of pixels are $00 Zeus will not load them. Also this mode optimises zeros
    at the beginning and ending of lines... Zeus will load non-zero attribute lines when they are
    required, just before any pixels using them are loaded.

    For example, if you have an assembler source for a game that starts at $8000, is $2000 bytes
    long and you have a loading screen for it in a file called "screen.scr" then Zeus can generate
    a tzx file with a nice loading screen using the commands:

    import_bin "screen.scr",$4000 ; This gets the loading screen and puts it in memory in place
    output_tzx "game.tzx","mygame","(c) Etc",$8000,$2000,3,$8000 ; Generate the tzx file
    where the 3 indicates this is the required TZX format.

    To load a program generated using Zeus use LOAD "" on your Spectrum or emulator.

    The "Options" optional parameter allows you to set the colours used while the loader is operating.
    (Same as MODE 1)

    output_tzx "tony","tony","Hideous!",$7F00,$4000,3,$7F00,$00123456

    The most significant byte is reserved for other loader options to be added in future. Set it
    to zero for the moment.

    LIMITATIONS:

    48K Spectrum.

    You can load blocks of code to any address from $4000 to $FFFF, but you cannot load all 48K.
    The loader itself needs to be placed in memory on a page boundary between $8000..$FE00.
    Zeus will handle deciding where to put the loader, but you must leave at least one whole page
    of memory free somewhere for it to do so.

    When your code starts running (at ExecuteAddr) interrupts will be disabled and the stack
    pointer will be left at some address between $8000..$BF00, so I STRONGLY suggest the first
    thing your code does is to load the SP register with a safe value.

    128K Spectrum.

    You can load blocks of code to any address from $4000 to $FFFF, including all 48K. You can
    also load as much as you like to any other block, or blocks, but you cannot load all $128K.

    The loader itself needs to be placed in memory on a page boundary between $8000..$BF00 while
    running, but if none of this memory is available (because you are loading all over it) Zeus
    will put the loader somewhere in there and add code so that when the load is finished the loader
    will automatically be overwritten with your code, so you need not be concerned about it.

    However, this means that you must leave about 270 bytes free somewhere in the 128K... if you
    do, Zeus will find it and use it automatically.

    The execute address should be between $4000..$BFFF... if it is above $C000 the code may not
    be paged in correctly if Zeus needed to find a different page to put the overlay copy of the
    user's code in.

    When your code starts running (at ExecuteAddr) interrupts will be disabled and the stack
    pointer will be left at some address between $8000..$BF00, so I STRONGLY suggest the first
    thing your code does is to load the SP register with a safe value... also, the page register
    (IO address $7FFD) may have been written with a random page, so you should also set this with
    whatever page you need.

    NOTE - the loader will also change the ROM page in I/O port $7FFE, so you will need to reset
    this at the start of your code if you intend to call ROM routines. If you haven't loaded over
    the ROM variable area then having this code at the start of your code should put it back:

                        ld a,($5B5C)      ; Previous value of port is stored here
                        ld bc,$7ffd       ; Page register address
                        out (c),a         ; Put it back as the BASIC, etc, expects.

    And as an added bonus for reading this far, bits 26..24 of the "option" word are actually used
    in mode 3... have fun finding out what they do ;)

    Use LOAD "" to load this. Or will load automatically on most emulators.


  - Added ZEUSPAGE function. For use when writing 128K code.

    Given a page number, 0 .. 7, this returns the 32 bit address in memory which Zeus uses to denote that
    page.

    So, to place data in specific pages, for example, one could do this:

                org zeuspage(0)

                db "These bytes are placed at the start of page 0"

                org zeuspage(7)

                db "These bytes are placed at the start of page 7"

    How the Spectrum maps the eight 16K blocks is a right bloody mess. Zeus maps them as discussed
    above in the documentation for v3.43... it isn't nice, but there is no ideal way to do it.


  - Added a "GotoDefinition" option to the right-click menu. Sometimes.

    If you right-click while the overlay text is showing the value of a symbol, then Zeus should
    show "GotoDefinition" in the menu options. Selecting this will jump to the editor line where
    that symbol was defined.

Released as v3.52 (zeusver = 49)

  - Added support for *.TAP files using "ouput_tap" and "output_tap_block".

    (See version 4.04 for easier alternatives)

    These commands take exactly the same parameters as the "ouput_tzx" and "output_tzx_block" commands.

    Be aware that there is a limitation in the TAP format that blocks cannot be longer than 64K,
    which imposes a limit on the amount of data that can be encoded by the loader. This will not be
    a problem with normal 48K files, but it does limit 128K scatterloaded files to loading a total amount
    of formatted data that will fit in a 64K block... this varies according to the screen data but the
    formatting overhead is of the order of 2%.

    Zeus will issue a warning if the data cannot be fitted into a TAP file, but as this is detected after
    Zeus has finished making passes through the source and generating code, it may not be regarded by Zeus
    as an error and may not prevent Zeus from executing external applications using zeusinvoke.

    - Added a load address option to MODE 0 of *.TAP or *.TZX output. See above:

    - Changed zcl.exe to return an exit code of "0" for success, "1" for failure.

    - Added "output_hex" to allow the output of text hex files.

      eg:
      output_hex "test.hex",Start,Length
      output_hex "test.hex",Start,Length,AddrWidth
      output_hex "test.hex",Start,Length,AddrWidth,DataWidth

      AddrWidth determines if the address is added to the start of the line, and how many digits it uses.
      DataWidth determines how many bytes of data are shown on each line.
      By default AddrWidth = 4, DataWidth = 16

      Eg:

                org $8000
                db "Hello!"
                output_hex "test.hex",$8000,6

      Would output this in test.hex:

                8000 48 65 6C 6C 6F 21

      Eg:
                org $8000
                db "Hello!"
                output_hex "test.hex",$8000,6,8,1

      Would output this in test.hex:

                00008000 48
                00008001 65
                00008002 6C
                00008003 6C
                00008004 6F
                00008005 21

      Eg:
                org $8000
                db "Hello!"
                output_hex "test.hex",$8000,6,0,1

      Would output this in test.hex:

                48
                65
                6C
                6C
                6F
                21

      And so on.


  - Added support for code timers. These can be used to time how long sections of code take to execute.

    There are two timers, they are identical. They can be started with "zeustimerstart ID" and stopped
    with "zeustimerstop ID", where ID = 1 or 2.

    The results of the timers are shown on the "Timers" Tab page.

    For example:

                        org $8000

                        di

                zeustimerstart 1
TestLoop                ld a,12
                zeustimerstop 1

                zeustimerstart 2
                        ld hl,1234
                zeustimerstop 2

                        jp TestLoop

    After executing that if you look on the timer tab you should see timer 1 with a period of 7 and
    timer 2 with a period of 10.

    If you move the code down to $6000, which is contended memory you should see the times change as
    the video accesses stop the processor clock during video accesses.

    If you remove the "di" you should see the times change as the interrupt routine disturbs the time
    taken.

    When on the timer tab, if you double click on any of the "min" or "max" displays, it will clear that
    min/max value so that the process of establishing the min/max starts again.

    The time difference between the start of timer 2 and the start of timer 1 is also displayed.

    If you start a timer again without stopping it, the timer start acts as a timer stop first.
    So to time the period of a loop you need only have a single "zeustimerstart" in it.

Released as v3.53 (zeusver = 50)

  - Added "zeusgetfilelength".
    This will look for a file on disc and return its length in bytes (up to 2GB).
    It returns -1 if the file doesn't exist or can't be opened.

    Handy for stuff like this:

    ; Load up a suitable loading screen if we have one
    if zeusgetfilelength("Test.scr") = $1B00    ; Does this file exist and is it the right length
      import_bin "Test.scr",$4000               ; Yes, load it
    endif                                       ; Done


  - Changed history text slightly

  - Changed 128K emulation timing slightly, cleared a glitch with NIRVANA+...

  - Changed the way emulation error traps work to prevent multiple reports.

Released as v3.54 (zeusver = 51)

  - Added options to resize the hex panels on the code tab.

  - Oops! Looks like the zeuspage(x) function's mapping wasn't right.
    I've changed it to be as follows:

    0 -> $0C000
    1 -> $14000
    2 -> $08000
    3 -> $1C000
    4 -> $20000
    5 -> $04000
    6 -> $28000
    7 -> $2C000

    (Thanks to Robin Verhagen-Guest for pointing this bug out, the utter bastard)

Released as v3.55 (zeusver = 52)

  - Added stimulation/replay.

  When you emulate a ZX Spectrum app/game Zeus now stores the keystrokes you type and will replay
  them the next time you start emulating. This is to allow you to replay games and reproduce bugs.

  If you start pressing keys during a replay then you resume control of the game from that point
  and the new keystrokes become the replay in the next run, and so on.

  If you do not want this check the "Replay Locked" option on the emulator tab. This will still let
  you take control, but the new keystrokes will not be stored and the replay will revert back to the
  original on subsequent runs.

  For the moment the replay keystrokes can be seen and edited on the "Stimulation" tab as text.
  This file can also be saved and restored in the file menu (use open/save when in the stimulation tab).

  You can change the CPU speed during replay without altering the gameplay.

  It is possible to edit the replay text file to embed some commands to dynamically alter options, this
  will change so I'm not documenting it here yet, but for now S <cycle time>,<speed> sets the emulation speed,
  where <cycle time> has to be a reasonable value and <speed> is a bizarrely awful number to do with
  speed scroll-bar position. It will get better, or rather it will change completely to something nicer.

Released (to beta-testers only) as v3.56 (zeusver = 52)

  - Added "output_c" to generate C header files.

    E.g. output_c "c:\\temp\\fred.h","SCREEN","unsigned char Screen","#include \"main.h\"",$4000,$1B00

  - Added stimulation file control from source code.

    It is possible to clear any existing stimulation data using "Zeus_StimFileErase":

    Zeus_StimDataErase = true               ; Clear any existing simulation data

    It is possible to tell Zeus to load an existing stimulation file using "Zeus_StimFileLoad":

    Zeus_StimDataLoad = "HallsSim.txt"      ; Load the file "HallsSim.txt"

    Note that "Zeus_StimDataLoad" will NOT load a stimulation file if there is already stimulation
    data present. So if you want to force Zeus to load the same simulation data for each run you
    would precede "Zeus_StimDataLoad" with "Zeus_StimDataErase"

  - Amended LABEL behaviour

    LABEL used to only generate, or look for, global symbols. Now it behaves exactly as other labels as far
    as scoping rules go. So a LABEL statement used inside a procedure will generate labels local to that
    procedure. If you want it to generate GLOBAL labels from inside a procedure block, simply prepend the
    "::" scoping operator to the LABEL operator.

    LABEL creates fixed numeric address labels. These cannot have their value changed.

    EG:

        LABEL("Fred",42) ; Exactly the same as "Fred EQU 42"

        Bert PROC

          LABEL("Fred",43) ; Generates a local label, exactly the same as "Fred EQU 42" would here
                           ; This can be seen globally as "Bert.Fred"

          zeusprint Fred,::Fred
          zeusprint LABEL("Fred"),::LABEL("Fred")

          PEND

    LABEL has three uses:
    LABEL(name) defines a label from a string and gives it the current address as a value
    LABEL(name,val) defines a label from a string and gives it the value Val
    LABEL(name) in expressions returns the value of a label given as a string
    these are mainly intended for automatic code generation in procs/macros/loops.

  - Added VARIABLE

    VARIABLE is an alternative to LABEL, except it creates variables.

    VARIABLE has three uses:
    VARIABLE(name) defines a label from a string and gives it the current address as a value
    VARIABLE(name,val) defines a label from a string and gives it the value Val
    VARIABLE(name) in expressions returns the value of a label given as a string
    VARIABLE(name) and LABEL(name) in expressions are identical.
    these are mainly intended for automatic code generation in procs/macros/loops.

    EG:

        VARIABLE("Fred",42) ; Exactly the same as "Fred = 42"

        Bert PROC

          VARIABLE("Fred",43) ; Generates a local label, exactly the same as "Fred = 42" would here
                           ; This can be seen globally as "Bert.Fred"

          zeusprint Fred,::Fred
          zeusprint VARIABLE("Fred"),::VARIABLE("Fred")

          ::VARIABLE("Fred",43) ; Alters the global label, exactly the same as "::Fred = 42" would here
                           ; This can be seen globally as "Fred"

          zeusprint Fred,::Fred
          zeusprint VARIABLE("Fred"),::VARIABLE("Fred")

          PEND

  - Changed emulator screen layout to use a tabbed box to select which controls are visible, The screen
    was getting too cluttered before, this helps.

  - Changed Spectrum mouse pointer driven screen address display in emulator.

    Now shows x/y position, graphic address and pixel number and attribute address, and Nirvana+ line
    and attribute addresses. You can set the base address of the Nirvana+ data.

    Double-click on the emulator screen to lock the mouse position, double-click again to unlock it.

    You can now define a sub-set of the screen for GIF file generation - either enter values directly or
    hold shift down and press and drag the left mouse button to define the GIF screen area. There's no
    visible feedback (yet).

    GIF files can be scaled. Note that choosing any scale other than 1 or 2 makes the emulator slow down
    dramatically, which is a pain. Your best bet to capture gameplay is probably to play your game before
    generating the GIF and then reassemble it using the replay option to have Zeus automatically replay it
    and generate the GIF during the replay. GIF files will replay at normal speed even if generated slowly.

    Note that keys entered while typing values into the GIF options will be seen as keypresses and cancel
    the replay, so set the scale etc first, and/or use the "replay locked" option to prevent your presses
    from destroying the replay data.

  - Added tape loading support. Very preliminary and incomplete suppport.

    I wouldn't normally release anything as rough edged as this, but people have asked for a version of Zeus
    with the replay option and I won't have time to finish the tape support for a while.

    There's a "Tape" tab. You can give Zeus a *.tzx file and load it using the normal Spectrum ROM tape
    loading routines. This option is mainly intended for testing tape loaders and so it supports emulating
    tape speed variations and wow and flutter. See the options on the emulator tab.

    The tape support is unfinished, actually it's barely started - there's less than an hour's work gone into
    it... You will need to reset the Spectrum after selecting a new tape file from the menu.

    You can select the tzx file to load from assembler source code using:

    Zeus_TapeFileLoad = "tapefilename.tzx" // With the right filename, of course.

    Remember string escape characters if you enter a path, "\\" for "\" and so on, if they're enabled.

    To actually load a tape you need to use the emulator - reset and run the Spectrum, then start a tape
    loading as normal. The keys for 48K Spectrum mode are: J for LOAD, ctrl-P for ", and to get
    CODE press ctrl and shift together to select E editing mode then release them and press I. For 128K
    just use the menu and ENTER.

  - Added "zxpixeladdr" and "zxattraddr" functions.

    These take an X,Y value and return the memory address of the appropriate byte in screen memory.

    eg:

    ld hl,zxpixeladdr(0,0)      ; hl = $4000
    ld de,zxattraddr(0,0)       ; de = $5800

    ld hl,zxpixeladdr(255,191)  ; hl = $57FF
    ld de,zxattraddr(255,191)   ; de = $5AFF

Released as v3.57 (zeusver = 53)

  - Improved the TZX tape loading. Now ignores "group/group end" blocks.

  - Added tape export as "*.wav" file.

    There are two options in the menu. You can export a "clean" file without any speed variation or
    noise added, or a "dirty" file that has wow and flutter, speed variation and the kind of noise that
    gets added by nasty playground tape coping with recorders that have AGC added... useful for testing
    protection methods that rely on noise counting, like the one in my "Dark Star" loader.

    Both wav files are filtered to emulate a realistic tape player bandwidth, though, so if you just
    want WAV files for general use there are utilities out there that will generate them in a more
    compressible though less accurate form... I couldn't actually find one that even got the basic
    frequencies exactly right, mind you, which I thought was rather unimpressive. I presume they chose to
    use integer maths and just generate an approximation to the right sample rate; [shrug] Not a terrible
    decision by any means, the Spectrum is tolerant and they're certainly close enough to load.

    Speaking of exact timing note that the timings Zeus uses for tape generation change slightly according
    to the machine model selected at the time of tape generation:

    The wav file timings are generated assuming a 3.500MHz clock if the model is a 48K machine, otherwise
    a 3.54690MHz clock is used. The difference is minor, you can ignore it for most purposes, but it is done
    intentionally...

    The specification for "*.tzx" files specifies that the timings are for a 3.5MHz clock, and as the wav
    files are generated from tzx files I initially used this fixed rate. But the purpose of Zeus generating
    wav files is testing, and for accurate testing purposes I want the timing in the wav file to reflect the
    timing of the actual hardware that generated it, because I doubt that anyone generating tape files on a
    128K machine changed their timing settings from those of 48K machines in order to reflect the different
    clocks... so Zeus generates wav files for 128K machines with that error baked in to make them realistic.

    If you want wav files that are accurate to tzx file specifications regarding the clock timing remember
    to generate them with a 48K model selected, otherwise there's about a 1% difference in frequencies.


Released as v3.58 (zeusver = 53)

  - Added zeussleep function. This allows you to pause while external utilities get on with stuff.

    Usage:

    zeussleep Period

    where period is (1 .. 10000) in mS. If period is outside this range no sleeping occurs.

  - Added support for an extra tap/tzx tape format, this allows the writing of full custom loaders.

    MODE 4 (Supports a user supplied custom loader. Any 48K/128K models may be supported)

    Zeus will use its internal custom loader to load the loading screen and a user supplied
    loader into memory. Zeus then outputs the required code/data as a stream of bytes with
    formatting information embedded and calls the user supplied loader to load this stream.

    This is far too complicated to fully cover here, a zeus source example is provided, and the
    Halls sources at least will soon be updated to support the new loader.

  - Added various tools for creating and editing loading screens. See the tabbed control on the
    emulator tab. Clicking on the Spectrum screen can capture a "character" into data structures
    suitable for the demo loader (which can be cut and pasted into the demo source), and loading
    screens can be drawn crudely.
    Holding shift down while clicking on the Spectrum screen... does things... maybe even useful
    things.
    To draw a screen using "Edit" you need to assemble a source that generates a character set.
    Then you can click on the characters to select them and click on the Spectrum screen to place
    them. The assembler source needs to include these labels:

    zeuseditfontbase equ where the data lives in memory
    zeuseditfontcount equ how many characters

    So, for example:

    zeuseditfontbase  dg ........
                      dg ........
                      dg XXXXXXXX
                      dg XXXXXXXX
                      dg XXXXXXXX
                      dg XXXXXXXX
                      dg ........
                      dg ........
                      db $04

    zeuseditfontcount equ (* - zeuseditfontbase) / 9; // How many there were

    From this data Zeus builds the character set used in the Edit tab.

    Yes, it's an awful hack - you can ask for your money back at any point, I'll understand.

Released as v3.59 (zeusver = 54)

  - Added support for a single data breakpoint. Changed later, see below.

Revised and released as v3.60 (zeusver = 55)

  - Added support for multiple data breakpoints. (See also v3.62 and v3.64 for extensions)

    These can break only when certain conditions are met, say when the contents of register have
    specific values. The conditions are set with text strings in the tabs 1 to 9 on the
    "Breakpoint Code" tab in the emulation window, and the breakpoint is placed in the source
    window by holding shift down and clicking on the blue dot in the gutter.

    Data breakpoints are shown in magenta.

    You can place an unlimited number of data breakpoints, with up to 9 different test code blocks.
    (If you need more than nine different test cases remember you can include the pc in a test case
    so one code block could handle an essentially unlimited number of separate condition tests, and
    what the hell are you writing?)

    How to place breakpoints using the editor:
    Hold the shift key down and press and hold the mouse button in the editor gutter column used
    for breakpoints (there will be blue dots there on executable lines after an assemble). This
    should insert a data breakpoint number "1" and show this with a "1" in purple.
    While holding the mouse key down (you can release shift) you can move the mouse to change this
    number from 1 to 9. I suggest you use 1 if you only have one case.

    How to enter a test condition:
    On the first emulator screen there is a control tab called "Breakpoint Code", select it.
    Under this there are 9 tabs, tab 1 contains the code for breakpoint 1, and so on. Enter
    the condition code required for breakpoint 1 into the editor under tab 1.

    Example conditions:

    A simple example condition might be wanting the code to stop if the value in the accumulator A
    is higher than some limit. Let's say ten. To have a data breakpoint stop execution when A has
    a value greater than ten you'd simply pick a data breakpoint number, let's say 1, and find the
    corresponding tab on the emulator screen under "Breakpoint Code", click on it, then click on the
    memo panel beneath it and enter the text "a>10"... without the "" quotes, of course.
    That tells data breakpoint 1 what condition you want it to stop execution on.
    Now you need to tell Zeus where you want it to do this check, and to do that go to your source
    code, hold shift down and click in the breakpoint column on the line of source code you want
    to test. If you want to do the test on more than one line, repeat this as many times as you
    like, making sure they all say 1... if you get a different number shift-click on it and, while
    holding the mouse button pressed, move the mouse until you get the number 1, or whatever
    number tab (1..9) that you are using for this test.
    When that line or lines is executed, if the value in A is greater than 10 emulation will stop.

    The test conditions can be as simple as that, or as complicated as you need them to be. Here
    are some examples:

    hl=$8000 && a=$42 <- this would break only when hl was $8000 and a was $42

    (pc=$8000 && a=$42) || (pc=$8010 && a=$41) <- this would break only when the pc was $8000 and
    A was $42, or when the pc was $8010 and A was $41 - assuming there were breakpoints placed in
    the margin at addresses $8000 and $8010, of course.

    Alternate registers can be selected using a' or bc' and so on.

    hl<>hl' <- this would break if the value in hl and alternate hl were different.

    Labels can be used just by using their name.

    hl < DataStart || hl > DataEnd <- Assuming these labels exist, this would break if hl was not
    inside a region.

    The flags can be tested with a bit mask, (F and $01) = 0 <- This is true on NC
    But as a shorthand Z,NZ,NC,M,P exist. C cannot be used for Carry, as it's a register, but
    "!" means not, so you can use !NC as shorthand for CF

    So (hl=$8000) && Z <- Would break when HL=$8000 AND the Zero flag is set.

    Bytes in memory can be tested using [], so [$8000] = $42 would stop when the byte at $8000 was
    $42, similarly [hl]=$42 would stop when the byte pointed at by HL was $42.

    Words in memory can be tested using []W, so [$8000]W = $1278 would stop when the word at $8000
    was $1278, and [ix+5]W < $8000 when the 16-bit value at [ix+5] is less than $8000, etc, etc.

    Longwords in memory (32-bit) can be tested using []L, so [$8000]L = $127800 would stop when the
    32-bit value at $8000 was $127800, and [ix+5]L < $8000 when the 32-bit value at [ix+5] is less
    than $8000, etc, etc.

    Expressions may use the tertiary ? operator.  a=1?b:c for example would return the value of B
    if A=1 and the value of C if not.

    Conditions can be as complicated as required. They are evaluated for every line containing a
    breakpoint marker in the margin. Zeus is fast enough that even complicated breakpoints on
    every line do not pose an unreasonable emulation speed penalty.

    [hl*3+42] >= [de]*[bc'] is a valid test condition, for example.

    Data breakpoint also supports assignment, or writing values to memory. This is done as follows:

    [$8000] := $42 <- Would write the byte $42 to memory at address $8000
    [$8000]W := $1278 <- Would write the word $1278 to memory at addresses $8000..$8001
    [$8000]L := $12345678 <- Would write the 32-bit value $12345678 to memory at addresses $8000..$8003

 -  There is support for data logging/capture using "zeusprint" and "zeusprinthex" in data breakpoint
    definitions.

    The usage is considerably different to their use in source code. Briefly you use them like this:

    zeusprint(condition,data{,Data...})     <- if condition is true, the data is reported in decimal
    zeusprinthex(condition,data{,Data...})  <- if condition is true, the data is reported in hex

    Sometimes it is useful to be able print data and also test for a breakpoint, you can separate
    expressions with a ',' and only the last one will determine if Zeus should break.

    zeusprint(hl=$8000,a,b,c),hl=$9000

    This will report the values in a,b and c only if hl=$8000, and stop only if hl=$9000

    The data reports are shown in the emulator report window and also in the main report window if
    you are stepping through the source code.

    Be aware that generating lots of reports will cause the computer to become unresponsive.

    For example, to log the value in A when a routine is entered, put a data breakpoint on the entry
    and use this as the breakpoint code:

    zeusprint(true,a)

    For example, to log the value in A when a routine is entered, but only when HL is $8000, put a data
    breakpoint on the entry and use this as the breakpoint code:

    zeusprint(hl=$8000,a)

    Byte values are treated as unsigned 8-bit data.
    Word values are treated as unsigned 16-bit data.
    Label values are treated as 32-bit signed values, floating point and string values are not supported.
    All calculations are performed using 32-bit signed arithmetic.

    (The window underneath the data breakpoint shows some debugging information. Ignore it.)

    The operator precedence for data breakpoint test code is as follows:

    Highest priority:
    (),[],[]W
    !,NOT,-,+          these are unary -/+
    &,AND,|,OR,^,XOR   these are the binary logical operators
    *,/,%              mul, div, mod
    -,+                these are add, sub
    =,<>,!=,>,<,>=,<=  comparisons (all signed comparisons)
    &&,||,^^           these are the logical logical operators
    ?                  the ternary operator
    Lowest priority

  - There is also a command "zeusdatabreakpoint" that can be used in the source to generate data
    breakpoints. The usages are:

    zeusdatabreakpoint breakpoint number, address of breakpoint
    zeusdatabreakpoint breakpoint number, address of breakpoint, length of breakpoint area

    zeusdatabreakpoint breakpoint number, "text of breakpoint condition"
    zeusdatabreakpoint breakpoint number, "text of breakpoint condition",address
    zeusdatabreakpoint breakpoint number, "text of breakpoint condition",address,length

    This can easily put multiple breakpoints on large numbers of source lines.

    "breakpoint number" can be zero, in which case an unconditional code breakpoint is used.
    If "breakpoint number" is in the range 1 to zeusmaxdatabreakpoint, then that selects a data breakpoint
    with the corresponding number.

    Examples:

    zeusdatabreakpoint 1,"pc=$8000",0,$FFFF ; This would put breakpoint 1 on every line and
                                            ; stop when executing an instruction at $8000

    Note: Zeus only checks for breakpoints on the first byte of a multi-byte instruction.

  - While adding support for data breakpoints the user interface machine selection was changed from
    using radio buttons to a drop-down menu, I made a right mess of this and it introduced some
    problems when selecting the ula+ versions of the hardware. These have been dealt with.

Released as v3.61 (zeusver = 56)

  - Removed an absurd bug in "find" introduced in v3.61, as in it didn't work at all.
    (The motto of this version is do NOT write software while ill, it might distract you,
    but you'll screw things up badly...)

  - Added some extra functionality to data breakpoints.

    pagereg1 reports the value last written to I/O location $7FFD (zx128k)
    pagereg2 reports the value last written to I/O location $1FFD (zx3 only)

    zeusdisplayaddr(cond,0,address) <- If condition is true, set the left hand code display base
    zeusdisplayaddr(cond,1,address) <- If condition is true, set the right hand code display base

  - Added some functionality to the Zeus code hex display page.

    When looking at memory, to find out which line of source code is responsible for generating
    any of the bytes shown, double-click on a byte. This will take you to the line of source, if
    that byte was generated by a line of source.

    When looking at memory, to find out which line of source code is responsible for last reading
    that byte, hold shift down and double-click on a byte. This will take you to the line of source
    containing the Z80 instruction that last read it, if possible.

    When looking at memory, to find out which line of source code is responsible for last writing to
    that byte, hold ctrl down and double-click on a byte. This will take you to the line of source
    containing the Z80 instruction that last wrote to it, if possible.

  - Changed various aspects of Diana, spacing, made her less "shouty", cured a couple of potential
    range-error/overflow bugs.

Released as v3.62 (zeusver = 57)

  - Various changes, tidyings up and improvements, mainly of Diana.

  - Repaired another emulation problem introduced in v3.57... what a disaster writing that change
    while ill was... urgh...

Released as v3.63 (zeusver = 58)

  - Some improvements to Diana, mainly performance-related.

  - Extended breakpoint code support to include assignment. Use this with care, it writes to the
    normal Z80 emulated code space. I've amended the comments above for v3.61 that describe data
    breakpoints.

  - Added three extra data-breapoint panels - reads, writes and pages. These can be found with the
    other data breakpoint editors on the editor tab.

    "reads" is checked whenever the Z80 reads data from memory.
    "writes" is checked whenever the Z80 writes data to memory.
    "pages" is checked whenever the Z80 writes to the memory paging register.

    Take "writes" as an example. Suppose you have a bug that manifests itself by writing the wrong
    value to a variable in memory. You can have a data breakpoint that checks every write to see if
    it is the one doing this using the "writes" tab - for example put the following breakpoint code
    in the "Writes" tab to check to see if you are writing a value of 0 to a variable called "Index"

    addr=Index && data=0

    All Z80 writes take place 8-bits at a time (the bus is only 8-bits wide) so this code is called
    once for each 8-bit right of 16-bit operations like "push" or "ld (xxxx),hl", which can be
    awkward for testing the value of 16-bit variables.

    However, to help you Zeus sets a flag called "bIs16Bit" for 16-bit write operations which is true
    for both of the 8-bit writes, and also passes the 16-bit value being written in "dataword", so
    you can test for 16-bit values like this:

    bIs16Bit && addr=Index && dataword=$1234

    Note that the addr will change depending on which half of the value is being written, so if you
    compare for the LSB address or the MSB address, it will match only once.

    "Reads" is similar except that it is checked on read operations.

    "pages" is checked whenever a memory paging register is written. For this "data" is the value
    being written, "addr" is the I/O address (either $7FFD or $1FFD), and the current value before
    the write takes place can be found using "mempage1" or "mempage2".

    Something to note is that as these traps occur during the execution of an instruction the cyan
    "run line" will have moved onto the next instruction when Zeus stops and reports a breakpoint.
    This could be some distance away if the break occurred on a call, jump or ret instruction.

    To help Zeus marks the line that caused the actual breakpoint by adding a slightly orange
    background.

    These breakpoints can be set using the command "zeusdatabreakpoint" in the source as described
    above (v3.61)

    If "breakpoint number" is 10, then that selects the "Reads" data breakpoint
    If "breakpoint number" is 11, then that selects the "Writes" data breakpoint
    If "breakpoint number" is 12, then that selects the "Pages" data breakpoint

    After you have finished using these three extra global data-breakpoint panels - reads, writes
    and pages - remember to delete all the breakpoint text in them, or it might well hang around and
    cause breakpoints to fire in subsequent code. Be especially careful to clear breakpoint code if
    it assigns values as these may well overwrite memory in subsequent runs.

  - Added "output_text" for writing text files from Zeus.

    usage: output_text "fn",string or integer[,string or integer]

    eg.

    output_text "fred.txt","; Creates a text file fred.txt with this comment in it"

    If you provide more than one string they are concatenated. If you provide an integer parameter
    it is added as a character.

    output_text "fred.txt","; Creates", " a text file",32,"fred.txt",$20,"with this comment in it"

    Multiple output_text commands using the same filename append their text to the file. Zeus inserts
    a line-separator of CR, LF in the file between the commands.

    output_text "bert.txt","; Creates a text file bert.txt with this comment in it"
    output_text "bert.txt",""
    output_text "bert.txt","; Then a blank line, then this comment"

    Etc, etc

  - Added a boolean parameter to the "include" command. If "true" Zeus will reload the text of
    the source-file from the OS before assembly.

    eg.

    include "dynamic.inc",true  ; <- The true means reload this file on assembly

    Normally Zeus loads include files the first time you assemble a file containing any includes
    and then uses the copy it has loaded for every subsequent assembly operation.

    There are (rarely) special cases where a user might want to do something unusual with Zeus,
    for example having Zeus create dynamic assembler source files which are to be loaded up during
    subsequent assembly processes. This is often called "metaprogramming", and this parameter has
    been added to include to facilitate that.

    Note that if you have the "save source files on assemble" option checked then Zeus will save any
    changes you have made to these files after loading them, *before* it reloads them during assembly.
    (Which makes the ",true" option fairly safe to use).

    This option works well with multipass, so metaprogramming code might well also use multipass to
    generate dynamic source files on the first multipass (multipass=0) then use them on on subsequent
    multipasses.

  - Changes to tape file generation to help with incomplete example sources.

    TAP and TZX generation in modes 1,2 and 3 now check to see if the block of memory you are loading
    is likely to interfere with the BASIC variables, if it is not then Zeus's loader will preserve the
    IY register and re-enable interrupts after loading, hopefully allowing simple code that calls the
    BASIC or OS to run as if just typed in... this may well not work, but it might help beginners who
    try to save incomplete code examples that were not expecting to have been loaded from tape.

    Zeus considers that using mode-4, any saving/loading below $5CDE or above $FD00 or using Data Blocks
    is likely to interfere with BASIC, and in those cases does not preserve the registers or reenable
    interrupts after loading. The assumption is that by the time people are trying this kind of thing
    they've moved on and are either writing complete applications that do not rely on that bloody awful
    ROM or are saving the variables with the loader.

  - Added "Facebook Copy" to the Edit menu... this is experimental. To use it select a block of source
    and click on "Facebook Copy" in the edit menu, this copies that source code, reformats it and leaves
    the reformatted code on the clipboard ready to be pasted (ctrl-V) into Facebook comments and statuses.
    What it does is change the spacing and replace space characters with a combination of unicode characters
    that Facebook will not remove, making source code pasted into facebook *slightly* more readable.
    It can be an improvement, especially if the pasted code is then manually edited.
    Zeus cannot make this perfect and even if it did Facebook changes often enough to break it, so don't
    expect miracles or report problems.

Released 18/May/2017 as v3.64 (zeusver = 59)

  - Added command-line "first file" parameter to allow file association with "*.asm" files if required.

  - Zeus no longer adds include files to the file history list.

  - Added "Replay Enable" checkbox. If not checked, key(etc) replay is disabled.

  - Changed Spectrum emulation so that the PC's right shift key can be used as "SYM SHIFT", as well as
    the Ctrl keys.

  - Added support for nested procedures (named and anonymous), and a new scoping operator that ascends the
    stack one level (^^). These are handy when using nested loops.

    Consider code made of repeated blocks, maybe something like this:

              call Fred
              jr nz Next_1
              call Fred
              jr nz Next_1
              call Fred
              jr nz Next_1
              call Fred

      Next_1  call Fred
              jr nz Next_2
              call Fred
              jr nz Next_2
              call Fred
              jr nz Next_2
              call Fred

      Next_2  call Fred
              etc,etc

      Fred:   some code

    Ideally you'd want to be able to write something like this:

              loop 4
                loop 3
                  call Fred
                  jr nz Next
                  do something
                  lend
      Next      lend

      But that won't work, because Next is being declared each time through the loop at different places.

      So, Zeus provided "anonymous procedures" which would allow you to declare a procedure inside the loop
      to give you local labels, then you can have 4 different Next labels as they're each local.

              loop 4
                proc
                loop 3
                  call Fred
                  jr nz Next
                  do something
                  lend
      Next      pend
                lend

      And this is fine. But suppose as well as local labels inside the outer loop we wanted local labels inside
      the loop nested inside it? Zeus did not used to allow nested anonymous procedures.

      If it did you might try writing something like this, using nested anonymous procedures:

              loop 4
                proc
                loop 3
                  proc
      Lp          call Fred
                  djnz Lp
                  jr nz Bert ; This will not work.
                  pend
                  lend
      Bert      pend
                lend

      And indeed this will still fail - but only slightly now. Zeus will allow you to declare the nested
      procedures, but there's an issue in that the label "Bert" referred to in the inner loop is not
      declared in that inner loop, it's declared in the one above.

      If Bert was global you could force a reference to it using the scope resolution operator "::", but
      that's no good here as it's still a local label, just not local to the level of locals we're in
      when it's referenced. So Zeus now adds another scope resolution operator "^^" which basically means
      move up the local definition level one layer.

      So we could write this as:

              loop 4
                proc
                loop 3
                  proc
      Lp          call Fred
                  djnz Lp
                  jr nz ^^Bert ; This will work
                  pend
                  lend
      Bert      pend
                lend

      You may use multiple ^^ operators to ascend more than one level. "^^^^Fred" is a label Fred in the
      level above the level above the reference. Note that this is NOT ^^^, you need to repeat the pairs
      of pointer chars.

  - Changed the options on the symbol table export.
    The syntax is still:
       export_sym filename [, numeric option]

    if an empty filename is given, then no file is written, but the options are used to generate the symbol
    table displayed in zeus.

    The numeric option has changed to make it more convenient to use.

    The bottom 2 bits of option still select the type of value display (But see $10000, below)
       $0 = Show as "equ $xxxx" (hex)
       $1 = Show as "$xxxx"     (hex)
       $2 = Show as "equ xxxx"  (decimal)
       $3 = Show as "xxxx"      (decimal)

    Then the next bits are individual enable bits to enable the display of each symbol type. Combine these:

       $0004 = Show integers
       $0008 = Show floating point vars
       $0010 = Show strings
       $0020 = Show locals
       $0040 = Show segments
       $0080 = Show addresses
       $0100 = Show variables
       $0200 = Show macros
       $0400 = Show anonymous proc labels
       $1000 = Show Zeus's internal symbols

    Then there are a couple of unusual options select bits that override all others:

       $2000 = Output only local variables in some bizarre format
       $4000 = Generate a Diana symbol table suitable for importing into Diana definitions

    Then an option to alpha-sort the symbol table (But not if it's in Diana format).

       $8000 = Sort the table into alphabetical order

    Then an option to swap the symbol/value order (But not in Diana format).

       $10000 = Swap the symbol/value order.

   With this bit set, the bottom two bits work as follows:

       $0 = Show as "xxxxxxxx fred"      (hex)
       $1 = Show as "$xxxxxxxx fred"     (hex)
       $2 = Show as "0xHHHHHHHH fred"    (hex)
       $3 = Show as "xxxx fred"          (decimal)

    Then an option to force 32-bit fixed-format hex numbers (But not in Diana format).

       $20000 = Force hex numbers to be 32-bit, with leading zeros

   With this bit set, all hex numbers are shown as eight digits.

    To show pretty well all the defined symbols, use this:

       export_sym "",$1FFC

  - Added support for the Spectrum Next sprites.

    These are emulated with behaviour as described on the Next website (as of 3/6/2017) and some
    deductions made from the behaviour of the TBBlue Spectrum.

    If you intend to multiplex sprites or change the pixel colours in real time be aware that I
    don't have a Next and would not rely on the timing being any more accurate than within a
    video line or so...

    I will provide a Zeus example source or two for driving these. See "zeus_ex_sprites.asm", etc.

Released 3/June/2017 as v3.65 (zeusver = 60)

  - I've amended the Next sprite support to set the "Max Sprites" flag on 12 sprites rather than
    13... I assumed it would be an overflow flag, but apparently it's not.

Released 3/June/2017 as v3.65 (zeusver = 60) (Can't be arsed changing it for this)

  - Amended the tape generation to cure a problem when saving very large mode 1 files, and also made
    mode 3 support leaving the interrupts enabled for scatter-loaded files that do not seem to destroy
    BASIC variables.

  - Added an "optimise" option to help improve loading screens. Click the button on the emulator tab
    when there's a screen in memory and Zeus will swap the foreground/background attributes where the
    background is brighter than the foreground, and invert the corresponding pixels so no change is visible.
    If you save these optimised screens as loading screens they'll probably look better when loading.

Released for testing 7/June/2017 still as v3.65 (zeusver = 60)

  - Altered Next sprite port addressing to be xx53, xx55 and xx57 in accord with the new documentation.
    (sigh) And either it was wrong or they changed it again. v3.96 changes these ports to
    Sprite port addressing to be xx53, xx57 and xx5B in accord with the new documentation.
    And also port 303B.

Released 14/June/2017 as v3.66 (zeusver = 61)

  - Added some support for Polyp as running on the ZX-Uno hardware.
    Supports single layer display mode only at this point, with pretty accurate display timing (CPU timing is
    guesswork at the moment) but it should be good enough for me to write a demo ;)

  - Made various changes to the GIF support, faster and the scaling factor now makes more sense. (aka: "works")

  - Removed a debugging statement from breakpoint setting, oops.

Released for testing 18/June/2017 as v3.67 (zeusver = 62)

  - Fixed an obscure bug with .Z80 format tape files.
    (Mutter, mutter, Robin Verhagen-Guest, mutter, found two bugs now, greedy bastard, mutter...)

  - Extended data formats to allow dynamic resizing... "What the hell does that mean?" I hear you ask.

    It means you can now do this:
              db 1,2,3,dw 1000,2000,dl $12345678, df 3.1415
    Instead of having to do this:
              db 1,2,3
              dw 1000,2000
              dl $12345678
              df 3.1415

    You can include "spaces" in data definitions using the ds operator *but* the format is subtly different to
    using a stand-alone "ds" statement, in that you *must* specify the value of the bytes to be placed.
    The format is ds length:value.

       eg.    db $FF,ds 3:$AA, db $FF ; note the colon in there. This would plant $FF,$AA,$AA,$AA,$FF

    (Why the colon? Because otherwise it would be ambiguous. What would the ds in "db 1, ds 2,3, db 4" mean?
     Two bytes of value 3, or a space 2 bytes long followed by a space 3 bytes long?)

  - Extended data formats to include big endian words and longs.
    These are specified using the horrible mnemonics "defwbe" and "deflbe", which are "defw" and "defl" with
    "be" tacked on the end.

       eg:    defwbe $1234      ; This would plant $12,$34
              deflbe $12345678  ; This would plant $12,$34,$56,$78

    (Normal Z80 16 bit values are little endian. So defw $1234 would plant $34,$12).

Released for testing 1/Aug/2017 as v3.68 (zeusver = 63)

  - Added support for the following "Next opcodes" to the assembler and disassembler and emulator

    EDIT 26 Jan 2018 - there's now some documentation. I have updated the emulator and timings for these.
    Most of the timings I'd guessed correctly.

    EDIT 25 June 2018 - and they've changed again.
    EDIT  6 July 2018 - and again.
    EDIT  3  Dec 2018 - and again..
    EDIT  7  Feb 2019 - and again...

    swapnib           ED 23           8 T-states
    mirror a          ED 24           8 T-states
    test XX           ED 27 XX        11 T-states
    bsla de,b         ED 28           8 T-states
    bsra de,b         ED 29           8 T-states
    bsrl de,b         ED 2A           8 T-states
    bsrf de,b         ED 2B           8 T-states
    brlc de,b         ED 2C           8 T-states
    mul d,e           ED 30           8 T-states
    add hl,a          ED 31           8 T-states (A is unsigned)
    add de,a          ED 32           8 T-states (A is unsigned)
    add bc,a          ED 33           8 T-states (A is unsigned)
    add hl,WWWW       ED 34 LL HH     16 T-states (I'd assumed 14, tsk...)
    add de,WWWW       ED 35 LL HH     16 T-states (I'd assumed 14, tsk...)
    add bc,WWWW       ED 36 LL HH     16 T-states (I'd assumed 14, tsk...)
    push WWWW         ED 8A LL HH     23 T-states
    outinb            ED 90           Zeus uses 11+Contention T-states, the docs say 14 T-States.
    nextreg reg,val   ED 91 reg,val   16 T-states (I'm not sure I've got this right - needs testing) (I'd guessed 12)
    nextreg reg,a     ED 92 reg       12 T-states (I'm not sure I've got this right - needs testing) (I'd guessed 11)
    pixeldn           ED 93           8 T-states (I'm doing a typical Spectrum move down algorithmn)
    pixelad           ED 94           8 T-states (I'm assuming addresses map into $4000..$57FF else 0)
    setae             ED 95           8 T-states (I'm assuming E[7:3] are ignored
    jp (c)            ED 98           13 T-states apparently.
    ldix              ED A4           Timing as LDI except if not copied -3T, flags set as LDI
    ldws              ED A5           14 T-states
    lddx              ED AC           Timing as LDD except if not copied -3T, flags set as LDD
    ldirx             ED B4           Timing as LDIR except if not copied -3T, flags set as LDIR
    ldpirx            ED B7           21/16
    lddrx             ED BC           Timing as LDDR except if not copied -3T, flags set as LDDR
    ldirscale         ED B6           ??

  - Added I/O In and Out breakpoint pages, to make trapping I/O activity easier.
    These can be found with the other data breakpoint editors on the editor tab.
    (If you are not familiar with Zeus's breakpoint capability see the documentation above for v3.60)

    "I/O In" is checked whenever the Z80 reads data from an input port.
    "I/O Out" is checked whenever the Z80 write data to an output port.

    addr is set to the port address, data is set to the data being read/written.

    Suppose you want to find out when code reads a Spectrum keyboard - this means checking I/O In
    instructions but only when bit 0 of the address is 0.

    The simplest way to do this is to use the following breakpoint code:

    !(addr&1)

    Which means "break if the I/O address we're reading has a bottom bit of zero", which is the incompletely
    decoded keyboard input port on a Spectrum.

    If you wanted to break only when the keyboard was read and a key was pressed, you could do something like
    this horror:

    !(addr&1) & (data&$1F <> $1F)

    Which breaks when the keyboard port is read and the result has at least one of the bits driven low.

    NOTE - there is a potential emulation issue here - when Zeus leaves the emulator page the keyboard state
    is frozen so the state of the keyboard as far as the Spectrum is concerned is fixed as it was when you
    were emulating it - the reason for Zeus doing this is so that keys that were pressed or released remain
    pressed or released while you step through the source code... otherwise you'd have to hold them down all
    the time while debugging.

    This is helpful in most respects, but it can cause confusion with key-pressed breakpoints like this example
    as Zeus may continue to break on key pressed unless you manually click on the emulator tab - from v3.69
    onwards whenever you return to the emulation page Zeus releases all the pressed keys.

    These breakpoints can be set using the command "zeusdatabreakpoint" in the source as described
    above (v3.61)

    If "breakpoint number" is 13, then that selects the "I/O In" data breakpoint
    If "breakpoint number" is 14, then that selects the "I/O Out" data breakpoint

    After you have finished using any global data-breakpoint panel remember to delete all the breakpoint text
    in them, or it might well hang around and cause breakpoints to fire in subsequent code. Be especially
    careful to clear breakpoint code if it assigns values as these may well overwrite memory in subsequent runs.

Released 6/Sep/2017 as v3.69 (zeusver = 64)

  - Changed the tape menu to make it more obvious you can load *.TAP files too.

  - Added the option to preset all the Z80 registers before execution from source code. Zeus used to just allow
    "Zeus_PC" and "Zeus_SP", but I've extended the support for this.

    Eg, to start execution with BC containing $1234, do this:

    Zeus_BC = $1234 ; Set BC a variable that may be redefined later in the source
    or
    Zeus_BC equ $1234 ; Set BC as a fixed value that may not be redefined.

    The 16-bit registers available are:

    Zeus_AF, Zeus_BC, Zeus_DE, Zeus_HL, Zeus_IX, Zeus_IY, Zeus_PC, Zeus_SP
    Zeus_AltAF, Zeus_AltBC, Zeus_AltDE, Zeus_AltHL

    The 8-bit registers available are:

    Zeus_A, Zeus_B, Zeus_C, Zeus_D, Zeus_E, Zeus_H, Zeus_L, Zeus_F, Zeus_I, Zeus_R
    Zeus_AltA, Zeus_AltB, Zeus_AltC, Zeus_AltD, Zeus_AltE, Zeus_AltH, Zeus_AltL, Zeus_AltF

    In addition you can control interrupts with:

    Zeus_IM, Zeus_IE

    where Zeus_IM sets the interrupt mode to 0,1,2 and Zeus_IE sets the interrupt enable to true/false.

    In addition the following registers exist for some versions of the Z80 and some obscure cases:

    Zeus_A32, Zeus_MEMPTR

    In the case where the same register is set from both 8 and 16-bit definitions, the 8-bit setting takes
    precedence. So, in BOTH the following code examples BC starts with the value $FF42

    Zeus_B = $FF        ; Set B to $FF
    Zeus_BC = $4242     ; Try to set BC to $4242, but B will still be overridden to $FF

    or

    Zeus_BC = $4242     ; Set BC to $4242, but B will be overridden
    Zeus_B = $FF        ; Set B to $FF

    It should be noted that Zeus is fairly tolerant about these labels. "ZEUSPC", "ZeusPC", "Zeus_PC",
    "ZeusEmulatePC", and "ZeusEmulate_PC" will all work... basically because I can never remember the format...
    (5/Nov/2017 - added "zeus_pc" and "zeuspc", etc, etc)

Released 12/Sep/2017 as v3.70 (zeusver = 65)

  - Added options for setting the spacing of the Text-Tidy source formatting. See the config tab.

  - Typing or clicking in the editor now stops emulation. You can start it again with F8 as usual.

  - There's now a checkbox near the I register value display. It shows the state of interrupt enable.
    Clicking on it will toggle the state of interrupt enable.

Released 16/Oct/2017 as v3.71 (zeusver = 65)

  - Added an option to allow the use of non-fixed pitch fonts... don't get excited, the editor will
    still look horrible if you do use a variable pitch font, how could it do otherwise? But this at
    least allows the selection of those fonts that are fixed pitch but don't have the right flags set
    to say that they are... it's a check-box on the config tab near the "Set Editor Font" button.

    Note that the syntax highlighting uses regular/bold fonts, and assumes that a bold character is
    no wider than a regular one. This is not true for some otherwise fixed fonts, unfortunately, and
    they will fail to render properly. Fonts I like which work nicely include "Dina", "LektonCode"
    "Source Code Pro" and "Fantastique Sans Mono" - they're all free.

  - Added a padding option to add/subtract space between characters, this can help with some fonts.
    See the config tab.

    (Also see v3.38 above for syntax highlighting options)

  - Added ! as an operator for neatly combining bytes to form words. This takes two values, multiplies
    the first by 256 and adds the second. This can save you having to type highbyte*256 + lowbyte.

    Example:

    HighByte = $12              ; Two arbitrary 8-bit values
    LowByte = $34               ;

    Address = HighByte!LowByte  ; Combined into a word - address becomes $1234

  - Added the option to have multiple load operations in a single LD instruction.
    This includes optimising some combinations to 16-bit loads.

    Example:

    ld a,1,b,2,ix,$1234,a,(hl)  ; Equivalent to LD A,1:LD B,2:LD IX,$1234:LD A,(HL)

    This normally just saves typing the LD characters - not particularly useful and possibly confusing.
    However, Zeus will optimise some multiple 8-bit loads into 16-bit ones:

    ld b,5,c,6                  ; This would be converted to a single LD BC,$0506 instruction
    ld c,6,b,6                  ; As would this.
    ld a,1,ixl,2,ixh,3,l,4,h,5  ; Optimised to LD A,1:LD IX,$0302:LD HL,$0504

    There are limitations at the moment, for Zeus to optimise two 8-bit loads to one 16-bit one the two
    8-bit registers must be consecutive... it doesn't matter what order they're in, but they must not
    be separated by any other load.

    (Change suggested by George Phillips)

Released 24/Oct/2017 as v3.72 (zeusver = 66)

  - Added support for floating bus emulation, as some people actually wish to use it. (Urgh)
    It's accurately modelled on the 48K, and reasonably accurate on the 128K (might be a few t-states out)

  - Added some support for "snow"... this isn't perfectly accurate but it's representative and useful
    as a warning.

  - Added a few functions: lowercase()/uppercase()/titlecase()/ord()

  - Added [[ ]] as zero-indexed string slicing operators. These operate the same way as [ ] except unlike
    [ ] which can optionally start with the first character being 0 or 1, the n in [[n]] always starts at
    zero.

    e.g.

        zeusprint "ABCDEF"[1 .. 3]      ; Prints either ABC or BCD depending on zoStringIndexFromZero
        zeusprint "ABCDEF"[[1 .. 3]]    ; Always prints BCD

  - Added "Zeus_IM" (etc) and "Zeus_IE" (etc) to allow presetting of the IM (0..2) and the IFF flags for
    emulation

    e.g.

        Zeus_IM = 2             ; Set interrupt mode 2
        Zeus_IE = true          ; Interrupts are enabled

  - Added literal string support. To use this put an @ symbol in front of the string.
    Literal strings will not process escape characters, so they leave the contents of a string completely
    alone... with one exception, in strings delimited by double-quotes like this one "blah blah", you can
    place double-quote characters in the string by using pairs of them.

    e.g.

        zeusprint @"Hello\n\r"  ; This prints Hello\n\r

Released for testing 3/Nov/2017 as v3.80 (zeusver = 66)

  - Played with CP/M emulation a bit, added some escape codes to the terminal window and remapping of the
    cursor keys, etc, so that WordStar works reasonably well... You'll probably want to reload the CPM zip
    file that contains the CPM utilities as I've (slightly) modified the binary of WordStar to work with
    a larger than normal terminal.

Released for testing 20/Dec/2017 as v3.81 (zeusver = 66)

  - Added support for outputing data directly to CP/M files on an existing virtual disk drive.

    The command is "output_cpm filename, start address, length"

    The filename must be in the form "x:name.ext", where x is a single-character drive name from a onwards,
    "name" is a CP/M format 1 to 8 character filename and ".ext" is an optional three character extension.

    If the file already exists it will be overwritten.

    (If a file is output with the length set to zero this will erase the file).

    Zeus disregards all the CP/M flags, including the read-only flag, and so will overwrite read-only files.

    Zeus allows various options for the CP/M disk format to be set, but by default uses settings compatible
    with the version of CP/M 2.2 that the emulator supports. These are set as follows, see example file(s).

    All these labels ARE case-sensitive, be careful.

    Zeus_cpm_sec_per_track  = 128                           ; 128 sectors per track
    Zeus_cpm_sec_per_block  = 32                            ; 32 sectors per allocation block (16K)
    Zeus_cpm_blocks_per_disk = 2048                         ; 2048 blocks per virtual disk (8M)
    Zeus_cpm_dir_cnt        = 512                           ; 512 directory entries (uses 4 blocks)
    Zeus_cpm_res_tracks_0   = 1                             ; 1 reserved track for CP/M boot files on drive A:
    Zeus_cpm_res_tracks_x   = 0                             ; No reserved tracks on the other disks
    Zeus_cpm_disk_cnt       = 16                            ; There are 16 virtual disks
    Zeus_cpm_user           = 0                             ; Which user we are

    Note that CP/M 2.2 does not understand file lengths particularly well, and if you write text-files from
    Zeus you need to add at least one $1A EOF character.

  - Added support for importing data directly from CP/M files on an existing virtual disk drive.

    The command is "import_cpm filename" to import bytes to the current assembly position, or
    "import_cpm filename, start address, length" to import bytes to an address in memory

    The filename must be in the form "x:name.ext", where x is a single-character drive name from a onwards,
    "name" is a CP/M format 1 to 8 character filename and ".ext" is an optional three character extension.

    Note that CP/M does not understand file lengths particularly well, and often reports them rounded up to
    the nearest 128 bytes.

  - Added "Zeus_cpm_drives" as a variable which reports the filename of the emulated CP/M disk drives, and
    which can be used to tell the emulator where to find this file.

  - Added "zeus_src_dir" as a predefined label which is set by Zeus to the directory (folder) in which the
    first source file is located.

  - Added "-" as a new string operator.

    This subtracts substrings from the tail of a string but only if the substring matches the tail.

    This will probably be most useful for removing subdirectories from paths, for example, the expression
    "c:\projects\halls\src" - "src" would yield the string "c:\projects\halls\".

    If the substring doesn't match then the original string is left unchanged.

    The substring may contain single character wildcards encoded as "?", which will match any character.

Released for testing 9/Jan/2018 as v3.90 (zeusver = 67)

  - Slight change to the way Zeus handles initialising the SP in the emulator... it now looks at the machine
    model and for the Spectrums it sets SP according to the model to the right value to have the emulator
    return to BASIC after emulating a simple programme.

  - Generating a tap or tzx file used to clear the emulator's SP register, it no longer does.

Released for testing 11/Jan/2018 as v3.91 (zeusver = 67)

  - Added an option to the emulator/"Nascom and CP/M options" tab which allows you to easily select multiple
    files on the PC and copy them to a CP/M drive... it's important to set the required CP/M drive first as
    the files copy immediately the diolog box closes.

Released for testing 12/Jan/2018 as v3.92 (zeusver = 67)

  - Added support for changing the CP/M terminal colour scheme to the "zeussyntaxhighlight" option.

    The syntax is "zeussyntaxhighlight Index, Red, Green, Blue" where:

      Index is a number which specifies the type of syntax item
        300 = CP/M terminal Normal background colour
        301 = CP/M terminal Normal foreground colour
        302 = CP/M terminal Highlight background colour
        303 = CP/M terminal Highlight background colour

      Red,Green,Blue specify an RGB colour (0,0,0 = black, 255,0,0 = bright red, 255,255,255 = white, etc)

      So, for example:

        zeussyntaxhighlight 300,$00,$20,$00             ; Normal background = light green
        zeussyntaxhighlight 301,$00,$FF,$00             ; Normal foreground = bright green
        zeussyntaxhighlight 302,$00,$80,$00             ; Highlight background = Medium green
        zeussyntaxhighlight 303,$00,$00,$00             ; Highlight foreground = Black

  - Changed CP/M terminal to use the editor font and resize as required.

  - Added an option to hide the memory panes when in the editor. (See memory panes above)

Released for testing 16/Jan/2018 as v3.93 (zeusver = 68)

  - Fixed a bug in the emulator's +3 memory paging logic. (Spotted by Robin wassisface again... bloody users)

Released for testing 22/Jan/2018 as v3.94 (zeusver = 68)

  - Added support for Zeus controling some more options from the source.

    Zeus_data_breakpoints = true/false    ; Enable/disable data breakpoints
    Zeus_follow_execution = true/false    ; Follow execution, or not

  - Added "zeusmaxdatabreakpoint" as a constant for use with zeusdatabreakpoint, so you can do things like:

    for index=1 to zeusmaxdatabreakpoint; Iterate through the data breakpoints
      zeusdatabreakpoint index,""       ; Clear this one
      next                              ; Loop

  - Changed some of the Spectrum Next extra instruction's timing, and changed the "add rr,a" set to use
    unsigned addition rather than signed...

  - Added "ldirscale" and "ldpirx" to both the assembler and the emulator. I think the emulation is correct
    (Uses HL_A', not HL_E') aside from the timing which may well not be.

  - Slight change to how the "raw" option works - it now disables Nascom, CPM, Homebrew and Memebership card
    roms as well as the Spectrum ROMS.

Released for testing 26/Jan/2018 as v3.95 (zeusver = 69)

  - Added "zeusdatafollows" to allow you to give zeus a list of subroutines and RST addresses which have data
    following the call in memory - if you include the addresses of such RSTs or subroutines in this list then
    Zeus will not issue a flow warning when they're used.

    e.g.

        ; This code that prints data in memory after the call would normally generate a flow warning

        call PrintFollowingStrZ ; Print "Hello!"
        db "Hello!",0           ; A string in memory after the call

        ; But if this statement is present anywhere in the source-code Zeus knows that is allowed.

        zeusdatafollows PrintFollowingStrZ      ; Tell Zeus that "PrintFollowingStrZ" has data after it in mem.

  - Changed the sprite index port in Zeus's emulation from $xx55 to $xx5B, since the Next hardware has changed
    at some point.

Released for testing 31/Jan/2018 as v3.96 (zeusver = 70)

  - Following on from a suggestion by Chris Kirby I've added support for the post-fixes 'b','w' and 'l' on
    binary numbers. These specify that the number should have 8, 16 or 32 bits respectively, and Zeus will
    emit a warning if one doesn't.

    So %111 is a perfectly valid three-digit binary number, but %111b would issue a warning because it is not
    %00000111b, and so on. This is to help avoid simple typing mistakes like missing a digit.

    Note that this is compatible with all Zeus's existing binary formatting options, so all these are valid:

    %0000 0000, %0000_0000, %11xxxx00, %1x1x xx_00 (urgh)
    %0000 0000b, %0000_0000b, %11xxxx00b, %1x1x xx_00b (urgh)

    Zeus lets you use x or z in binary numbers to indicate bits that don't matter, they both mean 0.

    (Zeus also supports binary numbers post-fixed with 'b' or 'B', like this one: 1010b)

Released for testing 31/Jan/2018 as v3.97 (zeusver = 70)

  - Improved support for "output_sna" so that it can output Spectrum SNA files as well as Amstrad ones.

    The format for "output_sna" has been extended so that you can just supply a filename and have Zeus get the
    SNA file type (Amstrad CPC, Spectrum 48K or 128K) from the machine setting and the register values from the
    emulator settings:

      So, for example, you could save an SNA file that should start executing at $8000 like this:

      Zeus_PC = $8000
      output_sna "fred.sna"

      or set some other registers like this... etc, etc.

      Zeus_PC = $8000
      Zeus_SP = $9000
      Zeus_A = $42
      output_sna "fred.sna"

    Note that you can alter the register settings as often as you like in a source, but only the last ones
    count when generating files because files are generated AFTER Zeus has finished going through the source.
    If you are saving multiple SNA files and need different register settings for each of them (gawd knows why
    anyone would do this) then you'll need to use MULTIPASS (as discussed up there ^^^ somewhere).

    As documented above the possible register setting variables in Zeus are:

      32-bit:
      Zeus_A32

      16-bit:
      Zeus_AF, Zeus_BC, Zeus_DE, Zeus_HL, Zeus_IX, Zeus_IY, Zeus_PC, Zeus_SP, Zeus_AltAF, Zeus_AltBC, Zeus_AltDE,
      Zeus_AltHL

      8-bit:
      Zeus_A, Zeus_B, Zeus_C, Zeus_D, Zeus_E, Zeus_H, Zeus_L, Zeus_F, Zeus_I, Zeus_R
      Zeus_AltA, Zeus_AltB, Zeus_AltC, Zeus_AltD, Zeus_AltE, Zeus_AltH, Zeus_AltL, Zeus_AltF

      Control:
      Zeus_MEMPTR, Zeus_IM, Zeus_IE

  - Added a new data definition pseudo-op "dh", which takes strings and extracts hex bytes from them and plants
    these into memory. e.g. :

       dh "12"          ; Plants a $12, same as "db $12"
       dh "1234"        ; Plants $12,$34 same as "db $12,$34"
       dh "1234","5678" ; Plants $12,$34,$56,$78 same as "db $12,$34,$56,$78"

       and so on. Useful for defining large blocks of raw bytes.

Released for testing 5/Feb/2018 as v3.98 (zeusver = 71)

  - The formats for "output_z80" and "output_szx" have been extended so that you can just supply a filename and
    have Zeus get the register values from the emulator settings, as follows:

      Zeus_PC = $8000           ; Zeus needs to know the start address at least
      output_z80 "fred.z80"     ; Just a filename will do now
      output_szx "fred.szx"     ; Just a filename will do now

  - Added support for the Spectrum Next's UART in Zeus's emulator so emulated Next software can talk to ParaSys.
    The emulation assumes an infinite baud-rate so don't expect timing accuracy. The serial receive buffer is
    accurately modelled, though.

Released for testing 7/Feb/2018 as v3.99 (zeusver = 72)

  - Added a lot of support for serial ParaSys on the Next to Zeus. See example files, when available.

  - Changed Zeus to select "Courier New" as a font when first used.

Released 2/Mar/2018 as v3.991 (zeusver = 73)


  - Changed internal memory paging to use 8K blocks instead of 16K blocks to start Next memory emulation.
    Big changes afoot.


  - Added "Next" as a machine option. No more support added yet, though...


  - Functions, SMC labels, defv (void, not readable or writable))


  - Slight change to emulator in Spectrum mode to correct the "undocumented" flag behaviour of the CCF and SCF
    instructions (thanks to investigations of this done by Patrik Rak)


  - All sorts of goodies related to [censored] which I have no intention of mentioning for the moment.
      (Okay, this was the introduction of data labels, which I really must document. They're beautiful)

  - All sorts of goodies related to [censored] which I have no intention of mentioning for the moment.
    This is a different [censored] to the last [censored] and you'd really like it, but...
       (And this was the introduction of functions, which I really must document)

  - Next instructions changed yet again. The current set are documented at "1/Aug/2017 as v3.68" above.


  - Added malign and maligned for ensuring memory alignment of blocks.
    malign/maligned is a block pseudo-op used to ensure objects are placed in the same region of memory.

    Typically the use is to ensure things are placed in the same 256-byte "page", so here is an example:

        malign 256
          fred ds somesize
          bert ds someothersize
        maligned

    malign here moves to an address that is a multiple of 256 and maligned then checks that everything between
    the malign and maligned fits in that same 256 byte page... if it doesn't Zeus will issue an error.

    malign can also be used with the parameter ",false" which does not do the initial move unless it is required
    in order for the items to fit in the same "page". Here is an example:

        org $8001

        ; These two will fit on the same page even though they start at $8001
        malign 256,false
          fred ds 128   ; This would be placed at $8001
          bert ds 127   ; This would be placed at $8081
        maligned
        ; The next byte will be at $8100

        Here is another example:

        org $8002

        ; These two will NOT fit on the same page starting at $8002
        ; So Zeus will move the start to $8100
        malign 256,false
          fred ds 128   ; This would be placed at $8100
          bert ds 127   ; This would be placed at $8180
        maligned
        ; The next byte will be at $81FF


    You can use "malignend" as well as "maligned" for consistency with the other directives.


   - szx file generation now uses emulation variables (thanks to Graham Mason for pointing out that it didn't)

Released for testing only 29/June/2018 as v4.00 (zeusver = 74)


  - Added "LM" Load Multiple pseudo-op.

Val     equ $11223344                   ; Just a value that's easy to see in the hex

; Showing the LM - Load Multiple pseudo-op.
; Most useful for loading 24 and 32-bit values into registers

        lm a,b,c,d,$11223344            ; This is the same as "LD A,$11:LD B,$22:LD C,$33:LD D,$44"
                                        ; Except Zeus optimises the LD B,$22 and LD C,$33 into LD BC,$2233

        lm a,sp,Val                     ; If SP is included it is always loaded last. (slightly safer IRQ's)
        lm sp,a,Val                     ;        "                   "

        lm a,b,Val                      ; 16-bit loads to 8-bit registers
        lm b,c,Val                      ; Which get optimised to 16-bit loads if possible
        lm c,b,Val                      ;

        lm a,c,e,Val                    ; 24-bit loads to registers
        lm d,a,b,Val                    ;

        lm a,hl,Val                     ; Which can include 16-bit registers
        lm hl,a,Val                     ;
        lm b,c,a,Val                    ; Zeus spots them when split
        lm c,a,b,Val                    ; disordered and/or mixed get optimised

        lm de,hl,Val                    ; 32-bit loads to 16-bit register pairs
        lm hl,de,Val                    ;
        lm d,l,h,e,Val                  ; Disordered and mixed pairs get optimised

        lm c,ix,b,Val                   ; 32-bit loads to various registers including ixl/h/iyl/h
        lm a,b,ixl,Val                  ;
        lm ixh,iyl,Val                  ;
        lm ixh,iyl,ixl,iyh,Val          ; Optimised if possible, of course


  - The outinb instruction is back...


  - Added support for generating model 3 *.szx files. Use Emulate "3"... be aware the emulation's timing is far
    from clock-cycle accurate for the Spectrum "2" and "3" models, it's just included to allow generation of files
    with the right machine type.


  - Added an option to zeusinvoke to stop Zeus waiting the invoked application to finish. (See doc for v3.50)

    zeusinvoke "naffemu.exe","",false ; this runs external app naffemu after a successful assemble and does not wait


  - Added hex address entry and some control keys to "zeusmem" hex display panels. You can now type addresses at hex
    panels to show specific addresses., and page up/down and cursor moves.


  - Added "DBL","DBLW" and "DBLL" DefineByteLength

    These are DB statements that plant the number of bytes defined in the statement as either a byte, word or long
    at the start.

      dbl "fred" ; is equivalent to db 4,"fred"
      dbl 0,0,"a string of bytes" ; is equivalent to db 19,0,0,"a string of bytes"

      dblw "fred" ; is equivalent to dw 4,db "fred"
      dblw 0,0,"a string of bytes" ; is equivalent to dw 19,db 0,0,"a string of bytes"

      dbll "fred" ; is equivalent to dl 4,db "fred"
      dbll 0,0,"a string of bytes" ; is equivalent to dl 19,db 0,0,"a string of bytes"

    They're intended to be used for jobs like printing strings of text/control bytes.


  - Changed how the ParaSys UART is used. See the Parasys Tab.

    "Emulated ParaSys"          - Zeus emulates a UART and ParaSys connects to the emulated UART, no hardware required.
    "External ParaSys"          - ParaSys connects to external hardware using the PC's UART for comms.
    "(No PS) Drives Hardware"   - Zeus emulates a UART and connects the emulator to a real PC UART.
                                  Zeus does not emulate baud-rate changes (yet?) so you need to set the appropriate rate
                                  in the "ParaSys Options" box on the config tab. Also check "ParaSys uses Next protocol"


  - I've added a way to limit the length of exported symbol names in case Zeus's unlimited symbol lengths break
    poorly-written tools.

    Just put a line like this in the source:

      ZeusMaxSymbolExportLength = 16 ; Symbol names will be clipped to 16 characters

    And labels like "ProgrammersLoveLongTediousLables" will become "ProgrammersLoveL" in exported symbol-tables.
    (I've decided not to append ".." to the clipped symbols)


  - Added support for "@label" half-arsed local labels. Zeus has procedures to support proper local labels, with nested
    namespaces, but to help support legacy source-code it will also treat symbols declared with "@" as "local" to the
    last declared symbol... please use proc/pend instead of this ghastly neolithic bodge in new sources.

      Here is an example of this, but please don't use it in new code.

      Print     push hl
      @Lp       nop             ; Declares the symbol "Print.Lp"
                call @Lp        ; Calls "Print.Lp"
                pop hl
                ret

      PrintStr  push hl
      @Lp       nop             ; Declares the symbol "PrintStr.Lp"
                call @Lp        ; Calls "PrintStr.Lp"
                pop hl
                ret

     Instead do this:

     Print      proc
     Lp         nop             ; Declares "Print.LP"
                pend            ; or use retp to plant the "RET"

     PrintStr   proc
     Lp         nop               ; Declares "PrintStr.LP"
                call PrintStr.Lp  ; Calls the Lp in the procedure Print
                call Print.Lp     ; Calls our local "Lp"
                pend

     Tidier, but more importantly it nests correctly and saves/restores context. Zeus will sneer at you if you put any
     of this "@" nonsense in anything other than the root namespace.


  - Added "dbgexit" and "dbgbreak", which plant DD 00 and DD 01 respectively. For use with other emulators.

    (DD 00 makes sense, a Z80 will ignore it. But DD 01? Idiotic... If this code gets left in a Z80 will treat that as
    LC BC,NNNN and fail. There are several single-byte safe opcodes this could and should have used.)

    To use these you must first set zoDebug=true in the source. You can bracket them as follows:

      zoDebug = true
                dbgbreak        ; This will plant DD 01
      zoDebug = false
                dbgbreak        ; This will not plant anything.

    (If you want to toggle that inside a macro or proc use ::zoDebug, because it's a global symbol)

    At the moment Zeus's emulator doesn't know what this amateur-hour crap is, it uses meta-data direct from Zeus for
    control.


  - Changed several bits of Diana. Added "Tnn" to run to a terminator and various hex hex/decimal options.
    See the Diana help text in the help menu.


  - Added emulation support for Basil
    If you don't know what Basil was don't worry about it.


  - Added an extra option to the "output_bin" command, you can now insert bytes generated by Zeus into an existing file

      output_bin "filename",start,length  <- creates a binary file as before

      output_bin "filename",start,length,offset <- inserts this block of data into an existing file at offset


  - Added another set of Next instructions to Zeus, Diana and the emulator ("Spectrum Next" mode only)

    BSLA
    BSRA
    BSRL
    BSRF
    BRLC
    JP (C)


  - Changed the way speculative parsing reports out of range errors. [mutter, grump]


  - Added an option flag to allow reporting of unreferenced symbols.

      export_sym "",$100000

      These are shown prefixed by the source/line in which they are defined.
      Double-click on this info to jump to the definition line.


  - Changed Next support to assume it's a 2M Next.


  - Added "output_list" to provide debugging support for some external emulators.

    Usage:

      output_list "fred.list"

      This vomits forth a listing file in a format that some emulator or other might like. (user request).


  - Added zeusassert.

    Usage:

      zeusassert conditional,string

      or

      zeusassert conditional

      eg.

      zeusassert PC>=$8000,"This code can't run in contended memory!"
      zeusassert ScreenBase=$4000

    If the conditional is false, zeus reports an error using the error message as the string.
    If no string is supplied Zeus will invent a suitable error message.


  - Added a mechanism for passing commands from assembler source to the emulator.

    This really needs an example source or two writing... it's provided to support odd requests
    from users who want the emulator to support some unusual hardware or other.

    For example, "zeusemucmd $FF" is a command to the emulator to get the current date and time in MSDOS standard
    32-bit format and put them into the Z80 registers BC and DE... this was added to support someone developing RTC code.

    Usage:

      zeusemucmd cmd,[data]     ; Data is passed in the same format as a "db" command.

      eg

      zeusemucmd $FF                            ; The emulator would write the MSDOS time into BC,DE
      zeusemucmd $FE,dw ClockStringBuffer       ; The emulator would write the time and date into memory as raw bytes.
      zeusemucmd $FD,dw ClockStringBuffer       ; The emulator would write the time and date into memory as an ASCII string.

    These emulation commands may be disabled using "zoDebug = false"


  - Adding support for outputting *.nex files, an executable file format for the Spectrum_Next

    See example files. Hopefully there'll be one.

    This was requested by Robin Verhagen-Guest, who helped by documenting the spec and suggesting ways to suppport it.

      OUTPUT_NEX directive

      optionally:
      OUTPUT_NEX_SCREEN directive
      OUTPUT_NEX_PALETTE directive
      OUTPUT_NEX_DATA directive

    The process of generating a nex file requires an "OUTPUT_NEX" directive appear first, then other NEX directives if
    required. They often won't be... Zeus will deduce what blocks to include in the file, basically if you have written
    a byte in any block, Zeus will include that block.

    You can add one "OUTPUT_NEX_SCREEN" directive to specify a loading screen (if required), and one "OUTPUT_NEX_PALETTE"
    directive to specify a palette for that loading screen, if it doesn't include one or if you wish to override the one
    it does include... be aware that some of the NEXT emulators currently fail if the NEX file includes a loading screen.

    The NEX format is subject to change. Zeus presently supports nex V1.1 and V1.2 (and decides automatically which to
    use).

    There are some file options that are set using variables, they are "pu8NEXFileHandle", "pu8NEXCmdLineBase" and
    "u16NEXCmdLineLength"

    You would use these as follows, for example:

    pu8NEXFileHandle = some value, see below:

    if pu8NEXFileHandle is $0000 the file is closed and nothing is passed
    if pu8NEXFileHandle is $0001..3FFF file is left open and passed in C register
    if pu8NEXFileHandle is $4000..FFFF file is left open and the file-handle is poked into memory at (pu8NEXFileHandle)

    u16NEXCmdLineLength = maximum length of command line passed to your code.
    pu8NEXCmdLineBase   = pointer to the start of a buffer for the command line.

    The loader will put the text on the end of the command line that loaded your application into this buffer and zero
    terminate it. The "u16NEXCmdLineLength" parameter limits the maximum length of the line.

    You should ensure these variables have the values you want them to have before the OUTPUT_NEX directive.
    If you don't define them, or set them to -1, they'll default to not being supported and Zeus will generate
    a V1.1 NEX file.

    You can generate several NEX files during an assembly - these can have different values for these variables, just
    set them to what you want before each OUTPUT_NEX statement and they'll affect that NEX file and subsequent ones
    until you set them differently. Or you can make them constants using "equ" instead of "=" when defining them, and
    they will not be changeable for different files.


    OUTPUT_NEX:

    The output_nex directive has this format:

      output_nex "pc filename", SP, PC[, CoreRequired[, EntryBank[, loadedDelay[, dontResetRegs[, BorderColour]]]]]

    CoreRequired (string) defaults to "0.0.0", in which case loader never fails core version check
    EntryBank (byte) defaults to 0, in which case PC would be expected to appear in 16k banks 5/2/0.
    If EntryBank present, PC would be executed to be $C000..FFFF when EntryBank was paged in at $C000
    loadedDelay (bool) defaults to false
    dontResetRegs (bool) defaults to false
    BorderColour defaults to 0 (Black)


    OUTPUT_NEX_SCREEN: (optional)

    The output_nex_screen directive has this format:

      output_nex_screen "pc filename","screen filename",loading_bar,loading_colour[,HiResColours]

    "pc filename" must be the same as the filename in the "output_nex" block. This is how Zeus knows which blocks belong
    to which file.
    "screen filename" refers to a file containing the loading screen. This file must exist, and Zeus determines the screen
    type from the size of the file, so it should be a standard Next screen type.
    loading_bar is true/false, if true and using a layer-2 loading screen the loader will draw a loading bar
    loading_colour is an integer, when using a layer-2 loading screen this is the colour used for the loading bar.

    Optionally you may provide a parameter called HiResColours, which does something for timex hires screens.

    NOTE: Instead of "screen filename" Zeus will accept a null-string "" followed by a memory address and length, and read
    the screen data from there instead of from a file.


    OUTPUT_NEX_PALETTE: (optional)

    The output_nex_palette directive has this format:

      output_nex_palette "pc filename","palette filename"

    "pc filename" must be the same as the filename in the "output_nex" block. This is how Zeus knows which blocks belong
    to which file.
    "palette filename" refers to a file containing a standard Next palette. This file must exist, and should probably be
    512 bytes long. Zeus will try to cope if it isn't.

    NOTE: Instead of "palette filename" Zeus will accept a null-string "" followed by a memory address and length, and read
    the palette data from there instead of from a file.


    OUTPUT_NEX_DATA: (optional)

    The output_nex_data directive has this format:

      output_nex_data "pc filename",[data definition]

    This directive adds data to the end of the NEX file, after the parts that get loaded as code.

    "pc filename" must be the same as the filename in the "output_nex" block. This is how Zeus knows which blocks belong
    to which file.

    The [data definition] is basically the same as you can put in a "db" or "dbl" statement, with a single exception for
    adding files - "df" doesn't plant floating point values, but files.

    Some examples might make this clear:

      output_nex_data "foo.nex",1,2,3,4      ; Would add the bytes 1,2,3,4 to the end of the file
      output_nex_data "foo.nex",dw 1,2,3,4   ; Would add the words 1,2,3,4 to the end of the file
      output_nex_data "foo.nex","Hello!"     ; Would add the bytes for the string "Hello!" to the end of the file

      output_nex_data "foo.nex",dbl "Hello!" ; Would add a length byte (6) then the string "Hello!" to the end of the file

    You can add raw binary file data like this:

      output_nex_data "foo.nex",df "data.bin"   ; Would add the bytes in the file "data.bin" to the end of the file

      Note that "df" here doesn't mean "define floating point", but "define file"

      output_nex_data "foo.nex",df "data.bin",0 ; Would add the bytes in the file "data.bin" to the end of the file
                                                ; And put a byte of 0 after them

      and so on.

    If you use the "dbl" variants, be aware that the length planted is the length of the total number of bytes after that.
    So using it for multiple strings, say, may not do what you want... consider this:

      output_nex_data "foo.nex",dbl "Hello!",dbl "There"

    This would add these data bytes:

       $0C,$48,$65,$6C,$6C,$6F,$21,$05,$54,$68,$65,$72,$65

    Where the first length is the length of the remaining bytes, not just the length of the first string.

    To use "dbl" to plant the lengths for separate strings you need to use multiple OUTPUT_NEX_DATA statements, with one
    dbl directive in each.

    There's a limit of 2MB on the maximum extra data Zeus will add to a file. If you want more than that you'll have
    to do it with external tools, which can always be "invoked" by Zeus, of course.

    (If anyone has a serious use case for a larger limit, contact me.)


  - Added ZEUSMARKUSED and ZEUSMARKUNUSED

    Lets you define areas of memory as used or unused by Zeus.

    This is so Zeus knows which bytes need to be included in files, see NEX files above.

    Basically Zeus marks any bytes it plants in memory as "USED", and (say) NEX files will then include them.
    These directives let you override this automatic control. You should not need to do this.
    If you use these, put them near the end of your source code so that bytes planted later don't override them.


  - Added ALIAS

    Much the same as a #define directive to a pre-processor, this lets you give names to lines of code and re-use them.

    "Then why not support #define, then, you awkward bastard?"
    "I don't really know, I just think symbol - keyword - parameter is more in keeping with assembler philosophy"
    "You could support both, you know, if you cared about your users at all"
    "[mutters]"

    Example:

      zp alias zeusprint

      zp "Hello!"       ; This would print "Hello" as zp is replaced by zeusprint

    aliases can recurse and can be redefined.

    Example:

      Mary alias 42             ;
      Jane alias Mary*Mary      ;

      zp alias zeusprint        ; Define "zp" as an alias for "zeusprint"

      zp Jane                   ; Prints 1764

      Mary alias 10             ; Change Mary

      zp Jane                   ; Prints 100 (Jane changes because she uses Mary who has changed)

      zp alias zeusprinthex     ; Redefine "zp" to now be an alias for "zeusprinthex"

      zp Jane                   ; Prints 00000064

    ALIAS is convenient for options, etc, etc.

    Okay, okay... you can also use #define. I am supposed to be the nice one, after all.

      #define Mary 42           ; Etc...


  - Added zeuskeybit. This is intended for the ZX Spectrum.

    Given a string containing key definitions, "A" .. "Z", "0" .. "9" and "[sym]", "[space]"
    "[shift]" and/or "[enter}" this returns the I/O bit number.

    So to scan a key you can do something like this:

    ---------

    PlayerLeftKey = "Q"

        ld bc,zeuskeyaddr(PlayerLeftKey)        ; Get the IO address to input
        in a,(c)                                ; Read those 5 keys
        bit zeuskeybit(PlayerLeftKey)           ; Test the bit for PlayerLeftKey
        jr z PlayerLeftPressed                  ; If it's zero the key is pressed

    ---------

    See v3.44 above for zeuskeyaddr and zeuskeymask


  - Added ZEUSCOPYFILE, ZEUSMOVEFILE and ZEUSDELETEFILE.

    These are intended to allow file operations after a successful assembly.

    zeuscopyfile sourcefilename,targetfilename
    zeusmovefile sourcefilename,targetfilename
    zeusdeletefile targetfilename

    Note: If the assembly process doesn't succeed nothing happens.


  - Added "DBTB" DefineByteTopBit

    These are DB statements that set the top bit of the last character of any strings.

      dbtb "fred" ; Outputs $46,$52,$65,$E4

    They're intended to be used where software uses bit 7 as a string terminator.

    dbtb can be used as a marker inside db/dw/dl and dbl, etc, statements.

    dbl dbtb "Urgh" ; This is preceded by a length and terminated with the top-bit set.


  - Changed Spectrum Next memory mapping to match the documented "Real Addresses"

    When using the Next memory model Zeus now starts the banked memory at $40000, which
    corresponds more closely with the Next hardware documented addresses.

    $000000 â€ô $00FFFF (64K) => Memory as seen by the Z80 (depends on bank registers,etc)

    These addresses are reserved for Zeus to emulate later.
    $010000 â€ô $013FFF (16K) => ESXDOS ROM
    $014000 â€ô $017FFF (16K) => Multiface ROM
    $018000 â€ô $01BFFF (16K) => Multiface extra ROM
    $01C000 â€ô $01FFFF (16K) => Multiface RAM
    $020000 â€ô $03FFFF (128K) => divMMC RAM

    The banked SRAM starts here:
    $040000 â€ô $05FFFF (128K) => ZX Spectrum RAM
    $060000 â€ô $07FFFF (128K) => Extra RAM
    $080000 â€ô $0FFFFF (512K) => 1st Extra IC RAM
    $100000 â€ô $17FFFF (512K) => 2nd Extra IC RAM
    $180000 â€ô $1FFFFF (512K) => 3rd Extra IC RAM

    So, zeusmmu(0) returns $00040000
        zeusmmu(1) returns $00042000
        and so on...
        zeusmmu(223) returns $001FE000

    In "Next" mode, zeuspage(0) returns $40000, zeuspage(1) returns $44000, etc.


  - Changed address display in editor margin

    For machines that have memory pages or banks, the margin display now shows bank
    numbers when appropriate.

    For the moment the Spectrum Next always shows bank numbers.


  - Changed DF so that if a Spectrum model is selected it outputs the Sinclair floating
    point format. This format can also encode integers in the range -65535 to +65535 and
    DF supports that, so "DF 1" will output 00 00 01 00 00


  - Stripped Next hardware support and the Z80N extended instructions out of the other Spectrum models.


  - Added "zoStrictSyntax" as a separate option.

    "zoStrictSyntax=true" enables strict syntax enforcement.
    "zoStrictSyntax=false" disables strict syntax enforcement.

    When enabled strict syntax enforcement disallows some of Zeus's relaxed syntax checking and makes Zeus take a much
    prissier approach to syntax checking... one example is Zeus's indifference to commas after conditional codes in
    the conditional jump/call instructions. With strict enforcement Zeus will complain if they're not there. Do it too
    much and it will secretly harbour a silent resentment and feel vaguely contemptuous of you. But hell, it's written
    in Pascal and probably does anyway.

    STRICT (and the config option checkbox) sets both "zoStrict" and "zoStrictSyntax"
    EXTENDED clears them both.


  - Added "zoSpinnish" to allow some rough emulation of a certain naff assembler's insane attitude to error reporting.

    "zoSpinnish=true" will add a random offset to the lines reported in error messages, and other jolly japes.
    Never set it to true. Never.


  - Added "Zeus_parasys_baud" as a variable that's set to the IDE's currently set parasys baudrate.

    See the latest ParaSys boot stub source for usage... well, when I release it. If I release it.


  - Added "zxnextmap" as a way to setup a particular memory map during assembly for the ZX Next memory blocks.

    Only supported in the "Next" model, at the moment. Can help avoid complicated ORG and DISP or DISPTO in simple
    apps that don't change the memory model. Dot commands and suchlike.

    Usage:

      zxnextmap x0,x1,x2,x3,x4,x5,x6,x7 ; Provide a list of the 8 memory blocks to assume are paged in (see zeusmmu)

    x0 is the number of the block paged in at $0000
    x1 is the number of the block paged in at $2000
    and so on.

    If x is negative, the settings for that block are left unchanged.
    So:

      zxnextmap -1,42,-1,-1,-1,-1,-1,-1 ; Sets block 42 at address $2000

    You may have as many zxnextmap's as you like in the source, they affect the lines after them.

    (This had a bug when used with simple filetypes, see the docs below for zeusver=81. Didn't affect *.NEX files,
    so it escaped notice...)

Released for testing only 6/Feb/2020 as v4.01 (zeusver = 75)

  - added "mexit" and "pexit" as default labels for the exit points of macros and procedures.

    The idea is that you often want to jump to the end of a macro or procedure, and now don't have to put an explicit
    label on it... no more of this, basically:

    mDecAIfNotZero macro()
      or a
      jr z exit
      dec a
    exit mend

    Now you can just do:

    mDecAIfNotZero macro()
      or a
      jr z mexit
      dec a
      mend

Released for testing only 11/Feb/2020 as v4.02 (zeusver = 76)

  - Changed "Notes" text.

  - Added a "comment toggle" function to the editor.

    To use this you must select a block of lines in the editor, then press CTRL-K, and it will comment them or
    uncomment them (it will uncomment if they were all already commented).

    It comments by adding a ';' to the start of every line, including those that have one already. It does this so
    when it removes them again it restores any existing comments.

    If it doesn't appear to do anything it's because the editor configuration file doesn't contain an entry for
    CTRL-K, which it doesn't by default - if you haven't changed it to suit yourself then just click on
    "Delete EditorDef Files" in the "Editor" tab of the "Config" tab and leave then restart Zeus.

    Otherwise you just need to add this line to your customised "keymap.def" file, in the Zeus execution folder.

      x       0       1       K       CommentToggle

    Didn't know about "keymap.def"? Well, you do now. Customise away. If you delete it, Zeus will restore the defaults.

Released for testing only 6/Apr/2020 as v4.03 (zeusver = 76)

  - Added some extra range checking to parameters in output commands, etc.

  - Added automatic options for TAP and TZX file generation.

    The basic idea is that Zeus knows which bytes your source has generated so it can automatically work out which
    bytes need to be saved to tape... this is smart enough to use Zeus's custom loader and tape format to load bytes
    in the high pages of the 128K machines.

    There are four separate modes... the same as the normal "output_tap" and "output_tzx" commands up there ^^^.

    But all you will normally need to do is give Zeus the filenames, and leave it to do the rest. If will pick up
    the execute address from "Zeus_PC" or however you've chosen to set it for the emulator.

      output_tzx_auto "pc filename","tape filename","comment"

    Or

      output_tap_auto "pc filename","tape filename","comment"

    Those will generate Mode 3 files, with a loader.

    You can specify a different mode like this

      output_tzx_auto "pc filename","tape filename","comment",Mode ; Where mode is 0,1,2,3

    You can specify the execution address like this, but you'll then need to specify a mode as well.

      output_tzx_auto "pc filename","tape filename","comment",Mode,ExecAddr ; Where mode is 0,1,2,3

    You can specify the colours used by the loader like this, but you'll then need to specify a mode and execution
    address as well.

      output_tzx_auto "pc filename","tape filename","comment",3,ExecAddr,Options ; Where mode must be 3

Released for testing only 21/Apr/2020 as v4.04 (zeusver = 77)

  - Added AY-3-8910 noise generator register display for 128K Spectrum models. Useful for debugging, but still
    mercifully silent...

  - Added a configuration option to select the type of displacement calculation performed. See the Notes.

    Briefly: It transpires there is an ambiguity in the way assemblers handle negative displacements in the indexed
    addressing mode. The problem arises when the offset is calculated by an expression starting with a negative number.

    Consider this offset: (ix-1+2), some assemblers will generate the code for (ix+1) and others (ix-3), it's about a
    70:30 split between the two cases, in that order...

    Zeus used to do the first, but having considered which I feel is most correct, it now does the second (by default)
    with an option to change this. If you want (ix-1+2) to generate (ix+1) set the simple expression configuration option,
    if you want it to generate (ix-3) clear it... this can be done in the configuration tab or by using
    "zoSimpleDisplacementCalc=true/false"

    If you want to write portable code it's best to bracket expressions in these addressing modes. Nearly all assemblers
    would agree on (ix-(1+2)) being (ix-3), for example.

  - Mentioned data labels and functions in the history text, which have been supported for several years, but I wasn't
    really interested in having yet another couple of ideas stolen so information has been restricted to developers I
    mostly trust... I'm sick and tired of everyone under the sun stealing ideas from Zeus, and thinking they can write
    a simple assembler and pretend it's as competent... [sigh]

    Data labels are a way to help support self modifying code. Zeus can plant labels on the data parts of instructions.

    Consider this traditional self-modifying code:

      ld (SelfModifyingLoad+1),sp  ; Modify the data bytes of the LD SP instruction
      .
      .
      SelfModifyingLoad ld sp,0    ;

    Nasty, isn't it. You have to know that the data bytes of the the load instruction start one byte into it, and
    remember to allow for that.

    Zeus now supports what I call "data labels", which are labels placed on the data parts of instructions. That code
    could now be:

      ld (SelfModifyingLoad),sp    ; Modify the data bytes of the LD SP instruction
      .
      .
      ld sp,[SelfModifyingLoad] 0  ; The square brackets mean label this data.

    Which may not be that much clearer, but what about cases like this?

      ld (ix+[SMC_Disp] 0),[SMC_Val] 0

    There the label SMC_Disp is pointing at the displacement byte, and the label SMC_Val is pointing at the data byte.
    Rather better than having to remember the offset is +2 for the displacement and +3 for the data, hmm?
    Some data fields are buried in with others in the same opcode byte, for safety these cannot be labeled.
    (Bit numbers, for example).

    Note that data labels can also be placed on items in "defb" (etc) pseudo-ops.

      ld a,'2'
      ld (pDigit),a

      db "Hello, you collected ", [pDigit] "0 rings you lucky bugger",0

    Used sensibly these can make your source cleaner.

    Another point worth mentioning is that Zeus is smart enough to tell its emulator about data labels - the bytes
    you label with them are automatically marked as self-modifying code, which means the emulator will let them be
    written during emulation without generating a warning even though they form part of an instruction (and so would
    normally be marked as read/execute only, and cause a warning if written).

  - Functions are functions. You can now declare functions to be evaluated at assembly time and use them in expressions.
    Functions are written in a pseudo-code like language that's going to need a lot of documentation...

Released for testing only 23/Apr/2020 as v4.05 (zeusver = 78)

  - Added error detection to the case where someone data-labels the displacement in a 16-bit pseudo-load instruction.

      e.g.      ld (ix+[smcDisp] 42),de   ; Error! Which displacement? There's one for D and one for E...

    There's no problem labeling the displacement byte of an 8-bit load, of course, but for 16-bit loads Zeus generates
    two 8-bit instructions, and the data label can't apply to both of the displacements.

  - Changed the editor to hide error message text for the line containing the cursor if it would hide part of the text.

Released for testing only 8/May/2020 as v4.06 (zeusver = 79)

  - Added output_map to provide support for the undocumented "*.MAP" symbol export format. Subject to change.

    usage:

      output_map "filename"[,SymbolLength]

    SymbolLength is the maximum length of symbol names. Must be greater than 4. Names longer than this will be truncated.
    If SymbolLength is not supplied, it defaults to 16.

Released for testing only 14/May/2020 as v4.07 (zeusver = 80)

  - Fixed a bug(!) introduced in zeusver 75, when using "zxnextmap" to set up a memory map during assembly the default
    memory mapping was still used instead of the modified one from "zxnextmap" when generating simple binary/hex or
    Sinclair-specific audio-tape files. (Didn't affect *.NEX files, so it escaped notice...)

Released for testing only 21/May/2020 as v4.08 (zeusver = 81)

  - Changed Text Tidy to leave lines starting with recognised tokens mostly alone.
  - Internal changes to the way the assembly process updates margin flags and data on editor lines
  - Removed a spurious ')' from the "output_c" array text generation
  - Removed unused "Enable ParaSys" checkbox.

Released for testing only 30/Aug/2020 as v4.09 (zeusver = 82)

  - Removed an obscure bug in tapeloader mode 3, which caused screen disruption on tape load failures
  - Changed tapeloader code to use data labels

Released for testing only 5/Apr/2022 as v4.10 (zeusver = 83)