Page 1 of 4

DAAD Adventure Writer and ZX Next

Posted: Thu Sep 12, 2019 8:50 pm
by Uto
Hi all,

I'm looking for information about ZX Spectrum Next, cause I want to make an addon for DAAD Aventure Writer so it can display raster graphics in the Next.

For those who doesn't know what DAAD is, maybe this article helps. To make thing easy I would just say it's Tim Gilbert's latest adventure maker, made after PAW and SWAN, and able to create games for Spectrum, CPC, C64, MSX, PCW, ST, Amiga and PC-DOS.

Just as PAWs, DAAD uses vectorial graphics for the 8 bits machines (except PCW), and it also supports using external code (or addons) via EXTERN feature.

To be honest, I have already provided support for raster graphics to DAAD for Spectrum (+3 or DivIDE/MMC), Amstrad CPC (3" disk or M4), MSX (floppy disk, MSX-DOS 1.0 or avobe) and C64 (floppy or SD2IEC), so going for the Spectrum Next is going for another target. You can fin my addons for all those computers here.

So after this large introduction... what do I need to know?

- I've heard or read Spectrum next OS is fully compatible with ESXDOS calls, is that correct? May I get the code I already have for the DivIDE/MMC version and keep all file operations unmodified and that would work?

- As the DAAD interpreter already exist, I cannot change the way the text is displayed, so I should keep the standard Spectrum video mode for that as Tim's code will take care of that, so I believe the best way to make appear is using Layer2, that is I leave the space for the graphics free in "normal layer" and then paint the graphic in Layer 2.

Regarding this I have some questions:

1) Is that possible?
2) Is there any documentation for Layer2. I've read a lot but it looks some things changed and now I'm confused
3) May I assume Spectrum Next will have 128K RAM and the additional pages are empty? Otherwise, how much RAM does the DivMMC implemented in the Next have? (maybe I use that RAM).

I hope you can help :-)

PS: I've also created a new compiler for DAAD, which has some interesting features .

Re: DAAD Adventure Writer and ZX Next

Posted: Thu Sep 12, 2019 9:43 pm
by Uto
I've found this tutorial, and I think I understand it better now. Basically if I have a 256x192 bytes file, including 48K bytes (a whole layer 2 screen) I would have to

1) Activate Layer2 and select first bank
2) Load 16K from file at $0000 using ESXDOS (*)
3) Select 2nd bank
4) Load another 16K at $0000
5) Select 3rd bank
6) Load last 16K at $0000

If my image is smaller (what in text adventure would be often, half the screen for the image), then I can stop at any time reading from file.

I'll also have to have a look at how to set palette, but if understand what it's shown in the wiki, loading layer2 full screen width pictures is easier than standard mode ones.

I haven't found how to ask the layer 2 to be on top of the ULA layer, nor I haven't found a list of Next registers.

(*) Well, actually if you do that probably it won't work as ESXDOS is paged when calling ESXDOS functions, so I belive I'd have to find some other empty page, page it to $C000, load with ESXDOs at C000 and LDIR to 0000. Same on next three blocks.

Re: DAAD Adventure Writer and ZX Next

Posted: Fri Sep 13, 2019 4:21 am
by Alcoholics Anonymous
The standard esxdos api is a subset of the esx-compatible api in nextzxos so you will be able to make the same calls to load data and whatnot from sd card. The most immediately noticeable difference is that nextzxos will accept long filenames.

Nextzxos's esxdos api is documented here: ... s/nextzxos

in file "NextZXOS_and_esxDOS_APIs.pdf". The description of the esxdos api starts on page 25 and documentation for all the esxdos calls starts on page 30. You can compare with the calls you are using already.

ROM3, the standard 48k rom, that is always present when programs are started has a hook at address $08 so that esxdos calls will work from inside your program. The next launches programs with ROM3 in the bottom 16k and banks 5,2,0 in the top 48k of ram.

The esxdos api is effectively separate from the operating system and it does not use any system variables or place any restrictions on what you can or cannot overwrite in memory. It lies entirely in divmmc memory which is separate from normal memory. The next has 128k of divmmc memory and either 768k ram (the unexpanded nexts) or 1792k ram (the 2MB nexts). The roms are also in a separate memory space so that 768k is real ram covering 16k banks 0-47 of which banks 0-7 correspond to the 128k's ram. Nextzxos also takes 16k bank 8 for itself although that is not important if your program only uses esxdos (and not special nextzxos calls) and doesn't use rom routines.

The memory space has two different names, one divided it into 16k blocks as described already - 16k banks 0-47 on the unexpanded next. It can also be divided into 8k pages named 8k page 0-95. 16k bank 5 corresponds to 8k pages 10,11 (*2 and *2+1). The reason there are two names for memory is that 16k banking is what is inherited from the 128k spectrum. You can bank like normal through port 0x7ffd. There are only 3-bits there for bank number so this port alone can only place banks 0-7 in the top 16k. There is another port 0xdffd that adds four more bits to the bank number. So by using port 0xdffd for the top 4 bits of the bank number and port 0x7ffd for the bottom 3 bits of the bank number you can reach 7-bit 16k bank numbers banked into the top 16k like on regular spectrums.

However, the memory is also divided into 8k pages. This is because the next can place an page of memory into any 8k of the z80's 64k address space. The address space 0-8k is known as mmu0, 8k-16k as mmu1, ..., 56k-64k as mmu7. The screen is normally located in 16k bank 5 (8k page 10) and you can make it appear at address 0 by setting mmu0=10. This is done via nextreg 0x50. Some assemblers have a special instruction "mmu0 10" that will do it but more commonly the special z80n instruction is used "nextreg 0x50,10". There is an equivalent OUT that does it with the regular z80 instruction set. "OUT 0x243B,0x50 ; OUT 0x253B,10". The first out selects a nextreg and the second out writes data there. The mmu0-mmu7 are mapped to nextreg registers 0x50-0x57. You can overlay the rom with ram and map whatever memory pages you want in those 8k slots. When you do write to legacy ports 0x7ffd, 0xdffd, 0x1ffd, those port writes will change mmu6 and mmu7 as well as restore the rom in the bottom 16k mmu0 and mmu1.

I went through all that explanation because layer 2 can be placed anywhere in ram and to read/write it you just have to map it into memory. You can do that with ports 0x7ffd, 0xdffd or with mmu. The special mapping by port 0x123B is another method that you have found - it allows the mapping of layer 2 to be write only and/or read only. If write only, eg, you could read bytes underneath layer 2 and write them into layer 2 at the same address.

Anyway, the wiki is always a bit behind so I will give some information here. Layer 2 is 256x192 one byte per pixel. This byte is passed through a palette lookup that returns a 9-bit RRRGGGBBB colour. So layer 2 is 256 simultaneous colours from a palette of 512 colours. The default palette just has colours 0-256 in the palette so that a pixel 0-256 maps to a colour 0-256 RRRGGGBB (the palette can be written as RRRGGGBB or RRRGGGBBB; if the former the third blue bit is the logical OR of the other two blue bits). This means the default has the layer 2 pixels looking like RRRGGGBB pixels.

There is a catch - after the final colour is looked up in the palette, it is compared against a global transparency colour using the top 8-bits only of the 9-bit colour. If there is a match, that colour is transparent and layers underneath layer 2 will be visible. So of the 256 colours a layer 2 picture uses, one is always reserved for transparent.

Layer 2 is 256x192 one byte per pixel arranged so that +1 moves right one pixel and +256 moves down one pixel. This makes it 48k in size. I will mention that it is highly likely that layer 2 will have 320x256 and 640x256 modes in the future but if you are using the ula screen as well, 256x192 is a good fit anyway.

The location of layer 2 in memory is pointed at by nextreg 0x12 (the nextreg, which is machine state, is documented here . The machine state is accessed via io ports 0x243b, 0x253b and special nextreg instructions added to the z80n as mentioned above). The value in nextreg 0x12 indicates the starting 16k bank of the actively displayed layer 2. You have 16k banks 0-47 in an unexpanded next, 0-8 is normally taken by nextzxos (which doesn't matter if you take over the machine and only use esxdos functions). If you place layer 2 at bank 9 by writing a 9 to nextreg 0x12, then layer 2 occupies 16k banks 9,10,11 (16k*3=48k). How do you write to that? Map it into memory and write to it. The mapping can be done the legacy 128k way with ports 0x7ffd,0xdffd into the top 16k or it can be done with mmu into an 8k slot in the 64k space. The third way is the special layer 2 mapping using port 0x123B. This is how the port works now (core 3.00.00, cspect will emulate this very soon):

* Port $123B is changed somewhat: MM00SREW
E = 1 to enable layer 2 display
W = 1 to enable write only mapping of layer 2 memory over the bottom 16k
R = 1 to enable read ony mapping of layer 2 memory over the bottom 16k
S = 1 to map the shadow layer 2 memory instead of the active layer 2 memory
MM = 00 to map the first 16k of layer 2 over the bottom 16k
01 to map the second 16k of layer 2 over the bottom 16k
10 to map the last 16k of layer 2 over the bottom 16k
11 to map all 48k of layer 2 over the bottom 48k of memory

E=1 to turn on layer 2 to make it visible

W=1 to enable write-only mapping of layer 2
R=1 to enable read-only mapping of layer 2

MM = 00,01,10 to map the three 16k segments of layer 2 over the bottom 16k only
MM = 11 to map the entire 48k of layer 2 over 0-48k of memory.

If you use the mapping modes, keep in mind where your interrupts are going and make sure the mapping is off (R,W=0) before using esxdos. esxdos needs r/w access in the bottom 16k to its own memory.

The layer priority on screen is controlled by nextreg 0x15:

(R/W) 0x15 (21) => Sprite and Layers system
bit 7 = LoRes mode, 128 x 96 x 256 colours (1 = enabled)
bit 6 = Sprite priority (1 = sprite 0 on top, 0 = sprite 127 on top)
bit 5 = Enable sprite clipping in over border mode (1 = enabled)
bits 4-2 = set layers priorities:
Reset default is 000, sprites over the Layer 2, over the ULA graphics
000 - S L U
001 - L S U
010 - S U L
011 - L U S
100 - U S L
101 - U L S
110 - S(U+L) ULA and Layer 2 combined, colours clamped to 7
111 - S(U+L-5) ULA and Layer 2 combined, colours clamped to [0,7]
bit 1 = Over border (1 = yes)(Back to 0 after a reset)
bit 0 = Sprites visible (1 = visible)(Back to 0 after a reset)

For example, "SLU" means sprites over layer 2 over ula.

In addition, all layers including layer 2 can hardware scroll and can be clipped. See nextreg 0x16, 0x17, 0x18

The magnetic scrolls games for the next (jinxter linked here) use layer 2 and optiionally timex hi-res in the same way you are considering for daad:

The layer 2 screen is the picture and this can be scrolled up by mouse to reveal more ula text underneath.

Re: DAAD Adventure Writer and ZX Next

Posted: Fri Sep 13, 2019 4:28 am
by Ped7g
# about (NOT) loading into 0000 area:

The write over ROM area is actually NOT possible while loading from disk (you must disable that). I.e. your proposal would not work.

That feature has two extra benefits:
1) the [y:x] coordinates are also address into memory (y masked with 63 of course, and correct bank selected for the particular third) (in new core 3.0 there should be new mode which will map whole bottom 48kiB address range for write, then the [y:x] value is also address)
2) it's write only, so you don't need to lose read access to other area just to be able to write into layer2, it's even possible to map source data into the low 0000..3FFF range and do "memcpy" from there into layer2

None of that matters for simple file load and the disk routines needs 0000..3FFF writes to land into the divMMC memory (which is extra beyond the regular Next pages), so this feature must be off.

# about where the layer2 data can reside in memory, and how to turn display of them

On the current core 2.0.28 the layer2 data has to reside in first 256kiB of RAM (in new core 3.0 this limit is lifted IIRC), which in terms of 16kiB banks means the banks 0..15 has to be used for layer2. The NextZXOS itself by default expects banks 9..11 to be used for layer2 (with 12..14 eventually as second buffer if you need double buffered).

To display the layer 2, you enable it on $123B port, and write the number of first 16kiB bank into nextreg $12. That's all. For example to flip double buffer you keep alternating 9 and 12 into nextreg $12 at beginning of frame.

To switch ordering how layers are drawn there is nextreg $15 (that's the main one, there are few extras for tilemap modes, etc.. but for ULA + Layer2 this is so far enough). To make classic ULA screen visible in certain parts of screen under the layer2, you can achieve that in many ways...
* use Layer2 clip-window nextreg $18 to limit the layer2 to rectangular area
* use global transparency colour $14 and draw pixels of that colour in the layer2 where the layer under it should be visible
* put layer2 under ULA screen, and use "layer2 priority" bit while setting colours in palette (two bytes per colour, RRRGGGBB + p000000B, written to $44) to prepare colours, which when drawn into layer2, will raise over anything else, even if the layer is under ULA/sprites in the order set by $15

I think the clip register is perfect fit for you if the area is static and rectangular, but with transparency you can maybe add also some custom "frame" around the regular text area, so whatever you like... (the third option is just to make you aware of it, I don't think it's a good fit for your goal).

# about how to load the data

You just map the target pages into regular 4000..FFFF address space with normal memory mapping (MMU registers $50..$57) and load the data there. With full 48kiB image, and your code having to reside somewhere too, it's sort of inevitable to load the file at least in two parts, paging between (my `nexload2.asm` does actually page only 8kiB in range E000..FFFF and loads layer2 loading screen from NEX file by 8kiB parts with six fread calls). With smaller data (less that 40kiB) you may eventually arrange the memory in a way where your code+stack+etc is in one 8kiB page and rest of the 40kiB range is mapped continuously, so you can fread it all in one go (IMO more fuss to arrange the code layout for this, than to simply page after each 8kiB fread in a loop).

Attention: the Layer2 start in nextreg $12 is specified in "16kiB bank" values, let's say you will want to use the NextZXOS default "9" (and that means the other thirds of data will occupy banks 10 and 11). But MMU registers are paging the "8kiB pages", so to load those data you will need to MMU map 8kiB pages 18, 19 (= bank 9), 20, 21 (= bank 10), 22, 23 (= bank 11).

After you load the data into target memory, you can map other memory into Z80 address space, the displaying of Layer2 doesn't need the banks to be mapped, the display goes by nextreg $12 and fetches directly into correct area of memory chip for the pixel data.

You will probably want also to check nextregs $40..$44 (palette stuff)

# about nextregs:

The wiki should be quite accurate and complete with regard to core 2.00.28
The new incoming core 3.0 is not documented there yet, but it will be largely backward compatible, mostly just extending the 2.0 definitions, so as long as you properly respect "reserved" bits while setting/reading next-registers, your code will very likely work with core 3.0 without change. If you set some bit extra here and there not respecting the reserved status, unexpected things may happen with core 3.0.

The nexload2.asm source which is using the esxDOS emulation for fopen/fread/...: ... xload2.asm
(you may want to be interested into LoadScreenBlock: part...)
(although reading it now after not seeing it for months, it's maybe a bit cryptic, as it is not only loading the layer2 screen, but also doing some extras around and can actually load also other types of images, and it was written a bit in code-size optimized way ... yep, you should probably not spend too much looking into it... if at all :D )

Re: DAAD Adventure Writer and ZX Next

Posted: Fri Sep 13, 2019 7:43 am
by Uto
Wow! Thank you guys for the detailed information and solution proposals. Your help it's really appreciated!

Re: DAAD Adventure Writer and ZX Next

Posted: Fri Sep 13, 2019 11:07 am
by Uto
Ok, after reading your posts a bit further, I think that best and easier way of loading to layer 2 would be using reg 0x12 to map layer 2 RAM to some bank (i.e. 9) so Layer2 RAM is at banks 9,10,11, and then use standar 128K paging to page up to 3 banks (depending on image size) ay 0xC000 and use ESXDOS to load directly to 0xC000.

Of course I have to take care of palette first,and sort the layers as SLU or LUS.

About transparency, I'll let the user (the writer) choose wether to use it or not. If he doesn't know how to create a file with transparency or he just doesn't want to, I will make sure the transparency register has a value different from last palette entry.

Finally, I have one concern:

Does the 0x12 register, the transparency register, and the standard-but-expanded 128K paging method work with the core version installed in the boards that were already delivered to backers? What about the way of setting the palette?

I know they can update the core, but I wonder how many of them do it, and I would like to keep this compatible with the larger number of boards possible.

Re: DAAD Adventure Writer and ZX Next

Posted: Fri Sep 13, 2019 2:45 pm
by SevenFFF
Welcome Uto!

All of those things should be compatible with old core versions. You can read the core version through nextreg 0x01 and 0x0E, and offer a suitable upgrade message for older cores. If you don't want to test your code with every old core version, I suggest 2.00.00 would be a sensible cutoff point. Most users have already upgraded beyond the 1.10.10(?) that shipped with the boards. If you package your program as a .NEX file, you can specify a minumum core version and the .nexload dot command will enforce that for you.

I'm not 100% sure what you mean by "standard-but-expanded 128K paging method". We have the 128K (port 0x7FFD) and +3 (port 0x1FFD) paging mechanisms which work the same as the original models.

New to the Next is MMU paging (similar to Timex and UNO but different from both - using register 0x50-0x57), which allows any 8K RAM bankto be mapped to any of the eight slots in the 684K memory. Because we have two nextreg opcodes which take less bytes and less Ts than 128K paging, most people use MMU paging for everything on the Next - even when a similar result could be achieved with 128K paging.

Code: Select all

nextreg $56, 9
nextreg $57, 10
will map 8k banks 9 and 10 into the upper 16K for example, faster and smaller than 128K paging would do. These register values can also be read back without needing a shadow sysvar, so you can write very clean code to preseve, bank then restore.

Also we have the extended Velesoft divIDE/divMMC paging mechanism, which works as you would expect. Some of this memory is used by NextZXOS, so there is a mechanism to request and release pages dynamically. Normally you would not touch this memory at all unless you were writing drivers or TSR programs.

BTW Tim Gilberts is on the Next team, and also in this forum. He's a really nice and helpful guy. AA also has a very deep knowledge of the FPGA core, so please ask as many technical questions as you want :)

Can I also say big thanks for maintaining the UNO FAQ. I have found this very helpful many times!

Re: DAAD Adventure Writer and ZX Next

Posted: Fri Sep 13, 2019 4:14 pm
by Uto
Oh! with ""standard-but-expanded 128K paging method" I meant it's like 128K but with more pages.

Tim has helped me a lot, although I tend to bother him only when i'm stuck :-D

It is a pleasure to hear my FAQ was helpful :-)

I'll have a look at core version and just do nothing (won't paint the image) if the version is too low. That is the way Maluva extension work (fail silently) an I believe is better as that way the adventure works anyway (without graphics). I feel like adding my own text to the adventure is taking control of someone else's work.

Re: DAAD Adventure Writer and ZX Next

Posted: Sun Sep 15, 2019 5:11 pm
by Alcoholics Anonymous
Uto wrote:
Fri Sep 13, 2019 11:07 am
About transparency, I'll let the user (the writer) choose wether to use it or not. If he doesn't know how to create a file with transparency or he just doesn't want to, I will make sure the transparency register has a value different from last palette entry.
You will probably want to reserve one 8-bit colour (last blue bit ignored) as the transparent colour. The default is 0xE3 which is a magenta colour.
Does the 0x12 register, the transparency register, and the standard-but-expanded 128K paging method work with the core version installed in the boards that were already delivered to backers? What about the way of setting the palette?

I know they can update the core, but I wonder how many of them do it, and I would like to keep this compatible with the larger number of boards possible.
The original core and software shipped with the boards is ancient :) I believe there was port 0xdffd (but not well tested), the transparent register and 8-bit colours in layer 2 (9-bit came later, the method for writing 8-bit colours should be the same). But honestly nothing is really going to work on the original core + sw as everything has moved forward significantly since then. NextZXOS is not going to work, many of the dot commands will not work, almost none of the new software will work.

What we are doing is using core v3.00.00 as the baseline as this is the version that will ship on the cased nexts.

Re: DAAD Adventure Writer and ZX Next

Posted: Sun Sep 15, 2019 9:33 pm
by Ped7g
AA: You will rewrite the sdcards once more? Wasn't it doing Henrique himself last time at the SMS facility? Can't even recall how long ago that was, I think the cards have now something like 2.00.12 +- ... But I recall "it was the last time, there's no more budget for another rewrite" ...

So if you will manage to get 3.0 on the cased ones, that will be amazing (I already voiced my worries back then, that probably some percentage of users will never upgrade from what is shipped just because of their casual Next usage, so people designing SW "for everyone" should probably aim for that core version as supported minimum ... if the 3.0 will be stable and shipped, that means a very good base for SW development, I think the Next core sort of "matured" in last 1.5y)... So... I hope you will have success with this, in all aspects involved, sounds very good. :)

Uto: I wouldn't stress too much about versions of core shipped with boards-only. Those were either picked by technically savvy users (who will upgrade to core 3.0 sooner or later, very likely *sooner* because of the features), or they are already catching lot of dust. But I have full understanding for your approach in terms of cased-Next core version.