Which z88dk version is good?

If you like transforming your statements into code, this is the place for you

Moderator: Programming Moderators

Henk de Groot
Posts: 28
Joined: Tue May 30, 2017 8:23 pm

Which z88dk version is good?

Post by Henk de Groot » Thu Jun 22, 2017 7:41 pm

Which z88dk package should I get?

On may 20 I got z88dk-latest.tgz and it compiled fine (Linux Mint 18.1). I noticed that some of the spectrum examples did not work, for example mandel.c. I didn't look into it until this evening. I found the problem, take a look at this sample program:

what.c:

Code: Select all

#include <stdio.h>

void main()
{
	float a;
	a = -2.0;
	printf("a = %f\n",a);
}
(please note, I took some shortcuts with the definition of main() and its return value to keep it small and to the point).

Compile with: zcc +zx -vn what.c -lndos -lm -create-app -owhat.bin
Then run: fuse what.tap

Now look at the output, it says a = 2 instead of -2! What??

After changing the initialization in mandel.c from a=-2.0; to a=0 - 2.0; it did what is was supposed to do. So this is a glitch I most certainly did not expect. I haven't seen compiler bugs like this for years (most "compiler bugs" are ID-10T errors).

So it looks I got my source at the worse possible time. But what version would be a trusted copy?

Alcoholics Anonymous
Posts: 511
Joined: Mon May 29, 2017 7:00 pm

Re: Which z88dk version is good?

Post by Alcoholics Anonymous » Thu Jun 22, 2017 8:20 pm

Henk de Groot wrote:
Thu Jun 22, 2017 7:41 pm
So it looks I got my source at the worse possible time. But what version would be a trusted copy?
Always grab the current build. That's where the bugfixes happen as they are found.

You definitely found a bug in sccz80 - the program is behaving correctly as the actual constant stored is +2.0 rather than -2.0. A month ago, sccz80's float parsing was completely rewritten and I guess this simple case was missed. I'll file a bug report now.

If you've compiled zsdcc (for linux you need to compile it separately), it does not have that issue:

(classic library, zsdcc as compiler)
zcc +zx -vn -compiler=sdcc -SO3 --max-allocs-per-node200000 --reserve-regs-iy what.c -o what.bin -lndos -lmath48 -create-app

The high optimization settings "-SO3 --max-allocs-per-node200000" can be omitted. "--reserve-regs-iy" is required unless your program disables interrupts to avoid conflict with basic's interrupt service routine. "-lmath48" chooses a different floating point package that is compatible with zsdcc (-lm chooses genmath which is not compatible).

If you add a pragma to enable the %f converter:

Code: Select all

#pragma printf="%f"

#include <stdio.h>

void main()
{
	float a;
	a = -2.0;
	printf("a = %f\n",a);
}
You can also compile with the new library:

(newlib, zsdcc as compiler)
zcc +zx -vn -clib=sdcc_iy -SO3 --max-allocs-per-node200000 what.c -o what -lm -create-app

There is no issue with basic's isr as interrupts are disabled by the new library's crt (however --reserve-regs-iy is automatically selected by clib=sdcc_iy because it leads to better code with SO3 there). The default math library for the newlib is math48 so "-lm" is fine.

Unlike the classic library, the newlib does not have zpragma scan the program to locate printf converters to enable. The default printf does not enable %f to avoid attaching the float library in casual use so you must explicitly ask for it ( https://www.z88dk.org/wiki/doku.php?id= ... figuration ) via a pragma in your program or in a separate pragmas file.

The same program can be compiled using sccz80:

(newlib, sccz80 as compiler)
zcc +zx -vn -clib=new what.c -o what -lm -create-app

However it will still suffer the same bug because the bug is in sccz80 not elsewhere.


Someone has started writing an introductory series using zsdcc/newlib you may want to check out.
And then have a look at some examples for newlib here.

The classic library I think you already have some familiarity with :)
Last edited by Alcoholics Anonymous on Thu Jun 22, 2017 8:59 pm, edited 4 times in total.

Henk de Groot
Posts: 28
Joined: Tue May 30, 2017 8:23 pm

Re: Which z88dk version is good?

Post by Henk de Groot » Thu Jun 22, 2017 8:40 pm

Thanks for confirming it. I just compiled it with "make" and then used "make" in examples/spectrum so no just the out of the box examples, nothing fancy. I know the standard C libraries but it has been more than 20 years that I used something like ncurses, I forgot most of that I'm afraid (is that supported, would be cool...). But of course the additions like 'plot' as used in mandel.c is new to me. Best way to learn about the libraries is using them.

I already grabbed the latest copy and compiled it. It still has the problem but you already found out. Since the examples are there I guess it used to work in the past.

Oh, another tip maybe. I see people in another thread using "zcc --version" etc. to look and compare their versions. But that version just happens to be the compile date and does not really tell which date the source was. Maybe the step that generates the .tgz file can be extended to slip in a constant to show the actual source date which can be shown with the version.

Alcoholics Anonymous
Posts: 511
Joined: Mon May 29, 2017 7:00 pm

Re: Which z88dk version is good?

Post by Alcoholics Anonymous » Thu Jun 22, 2017 9:24 pm

Henk de Groot wrote:
Thu Jun 22, 2017 8:40 pm
I know the standard C libraries but it has been more than 20 years that I used something like ncurses, I forgot most of that I'm afraid (is that supported, would be cool...). But of course the additions like 'plot' as used in mandel.c is new to me. Best way to learn about the libraries is using them.
The classic library has an ansi driver that understands some subset of vt100. And there is a "curses.h" header file that may implement a few functions. The other stdio drivers for zx tend to understand a superset of the control codes from sinclair basic.

The newlib has drivers with control codes and ioctl() to affect some driver parameters. Perhaps one of the most interesting features in the newlib is that you can set up any number of window terminals on screen, in any mode (32-column, 64-column, proportional fonts). Curses and vt100/vt52 terminal emulation are something for "later" as the disk io (not written yet) in newlib will somewhat change how all drivers, including terminal, will work.

For graphics, classic has a b&w library that includes things like plot, draw, circle, etc, stencils and a driver for a subset of svg. The newlib doesn't have this because we see this as an opportunity to improve things in a rewrite. The idea will be to have a graphics pipeline that does clipping, at minimum, so that draw functions do not have to check boundaries and targets will be able to specify a context so that the draw primitives can also do colour in a target independent manner. Nothing of that is done though so the newlib must be satisfied with the low level display file manipulators and a fast patterned flood fill for now.

The low level display file manipulators are available in both libraries and are good way for fast & easy drawing directly to the display. (The introductory series I pointed you to in the last post uses them to plot and draw lines and it's fairly easy to do).
Oh, another tip maybe. I see people in another thread using "zcc --version" etc. to look and compare their versions. But that version just happens to be the compile date and does not really tell which date the source was. Maybe the step that generates the .tgz file can be extended to slip in a constant to show the actual source date which can be shown with the version.
That's probably a good idea, I'll bring up this issue too.

Henk de Groot
Posts: 28
Joined: Tue May 30, 2017 8:23 pm

Re: Which z88dk version is good?

Post by Henk de Groot » Fri Jun 23, 2017 9:59 pm

I saw yesterday there was already work on the FP constant issue. That was amazingly fast, thank you!

I was eager to look at the results so I cloned the master branch to my laptop and compiled it to check it out. However the commit "Issue #257: Store the correct sign for fp constants." broke something, now the spectrum examples can not be compiled any more while the version before that could (with the fp bug of course). I now get:

Code: Select all

zcc +zx -vn ccoswave.c -lndos -lm -create-app -occoswave.bin
Error at file '/tmp/tmpXX0SvHQc.asm' line 278: symbol 'i_6' not defined
Error at file '/tmp/tmpXX0SvHQc.asm' line 309: symbol 'i_6' not defined
2 errors occurred during assembly
Errors in source file ccoswave.c:
Error at file '/tmp/tmpXX0SvHQc.asm' line 278: symbol 'i_6' not defined
                   ^ ---- 	ld	hl,i_6+0
Error at file '/tmp/tmpXX0SvHQc.asm' line 309: symbol 'i_6' not defined
                   ^ ---- 	ld	hl,i_6+0
Makefile:64: recept voor doel 'ccoswave' is mislukt
make: *** [ccoswave] Fout 1
(make errors are in Dutch localization but I guess that's not a problem)

So to be clear, the spectrum examples compile fine with commit 63beb371bfa4c960d73655aed87eaf13f6a7f665 and commit e97dbbe87586c224dbb352ccd536d9a93cb6dfa0 broke it.

In the mean time I also tried an other version and indeed that worked fine. I took the snapshot from january 1st and only later saw it was released on the 12th but I guess that one will work fine too. But of course using the latest would be better.

EDIT: Never mind, it is fixed already with commit 2afac3f9a8b194bbb57cab55f19869e39762f320 GREAT JOB!

Alcoholics Anonymous
Posts: 511
Joined: Mon May 29, 2017 7:00 pm

Re: Which z88dk version is good?

Post by Alcoholics Anonymous » Fri Jun 23, 2017 10:15 pm

Yes the current build is broken as sccz80 is failing the float tests.
There is a 'build failing' indication in the text area on the front page.

If you click on the commits tab there is a list of recent commits and red X / green check / yellow circle to indicate if builds fail or pass on each commit. If you click on those images this will pop up the Travis page and you can see exactly where the build is failing.

It's still being worked on - I can see another commit in the last few minutes.
EDIT: Never mind, it is fixed already with commit 2afac3f9a8b194bbb57cab55f19869e39762f320 GREAT JOB!
It was fixed while I was typing lol. But not quite -- the build is failing on clang but gcc will be ok

Henk de Groot
Posts: 28
Joined: Tue May 30, 2017 8:23 pm

Re: Which z88dk version is good?

Post by Henk de Groot » Fri Jun 23, 2017 10:46 pm

Thanks for pointing me to the the build indication, looks useful. I saw also the snapshot for 23-6 was missing so I guess it is only published after a successful build.

In the mean time I compiled the mandelbrod and cosine wave examples and they at least look okay, but I guess the tests are much more thorough. Great to have these tests incorporated in the build tough, really professional.

I read in another thread somebody started to make procedures to handle sprites, I think this set of tools will become invaluable once the ZX Spectrum Next arrived.

Henk de Groot
Posts: 28
Joined: Tue May 30, 2017 8:23 pm

Re: Which z88dk version is good?

Post by Henk de Groot » Sat Jun 24, 2017 6:05 pm

Okay, looking at more spectrum examples I noticed that "julia" shows a gap in the middle after finishing. After some digging I found this was due to rounding errors. The final x coordinate is as float 127.00000 but when cast to int it becomes 126.00000. I checked and the version of January does the same.

No harm here, floating point is infamous for those kinds of problems, to try a fix I just give the value a slight increase so it will fall the right way, so I added 0.001 before casting. But now I run into a bug, I created a simple example:

Code: Select all

#include <stdio.h>

void main()
{
        float x0, r, ux;

        x0 = 127.5;
        r = -1.587451;
        ux = 79.6875;

        printf("cast = %d (expected: 1)\n", (int)(0.001+x0+r*ux));
}
Compiled it with:
zcc +zx -vn what.c -lndos -lm -create-app -owhat.bin

So using the old compiler. The printed result is -29540 instead of 1. I also compiled the source natively with gcc to check if I did not make a mistake, but it shows 1 as expected.

I tried to compile the new zsdcc compiler but that needs a bit work work. Sdcc is configured and patched but it fails on a make step (this was predicted) but in my case it did this before the binaries in 'bin' were created. So I can't report if that makes a difference.

EDIT:
I managed to compile 'zsdcc' now (I was only missing the texinfo package) and this compiler works correctly, the example prints 1 as it should. I did get a compiler warning about double not being supported however. Compile command:
zcc +zx -vn -compiler=sdcc -SO3 --max-allocs-per-node200000 --reserve-regs-iy what.c -o what.bin -lndos -lmath48 -create-app

Alcoholics Anonymous
Posts: 511
Joined: Mon May 29, 2017 7:00 pm

Re: Which z88dk version is good?

Post by Alcoholics Anonymous » Sat Jun 24, 2017 8:40 pm

Henk de Groot wrote:
Fri Jun 23, 2017 10:46 pm
but I guess the tests are much more thorough. Great to have these tests incorporated in the build tough, really professional.
Eventually it will be a great asset but it's still in infancy otherwise we would have caught that float error long ago.
So using the old compiler. The printed result is -29540 instead of 1. I also compiled the source natively with gcc to check if I did not make a mistake, but it shows 1 as expected.
Another bug report - the compiler is not inserting a cast to integer after the float computation. It probably broke with the recent fix.
I managed to compile 'zsdcc' now (I was only missing the texinfo package) and this compiler works correctly
It's actually cheating by just printing out the answer:

Code: Select all

394   0000              _main:
395   0000  21 01 00    	ld	hl,0x0001
396   0003  E5          	push	hl
397   0004  21 00 00    	ld	hl,___str_0
398   0007  E5          	push	hl
399   0008  CD 00 00    	call	_printf
400   000B  F1          	pop	af
401   000C  F1          	pop	af
402   000D  C9          	ret
403   000E              	SECTION rodata_compiler
404   0000              ___str_0:
405   0000  63 61 73 74 20 3D 20 25 64 20 28 65 78 70 65 63 74 65 64 3A 20 31 29 
                        	DEFM "cast = %d (expected: 1)"
406   0017  0A          	DEFB 0x0a
407   0018  00          	DEFB 0x00
The "ld hl,0x0001" at the beginning is the precomputed value.

You have to make those float values volatile to force zsdcc to generate real code but it still comes up with the right answer. zsdcc can do some nifty things like this but it does stumble when initializing variables to values inside functions as you can see from the generated code with those floats made volatile. (Add "--list --c-code-in-asm" to see the translation to asm).
I read in another thread somebody started to make procedures to handle sprites, I think this set of tools will become invaluable once the ZX Spectrum Next arrived.
There are some good things coming, including an api for the hw sprites. It's always better to add some value to the basic hw otherwise there's no reason for people to use another api so we'll be looking at doing things like grouping sprites together to make big bad guys and whatnot.

Henk de Groot
Posts: 28
Joined: Tue May 30, 2017 8:23 pm

Re: Which z88dk version is good?

Post by Henk de Groot » Sun Jun 25, 2017 11:26 am

Alcoholics Anonymous wrote:
Sat Jun 24, 2017 8:40 pm
It's actually cheating by just printing out the answer:
I should have known that, after all I even supplied parameter O3 to optimize but even without it the compiler knows it are actually constants. Of course it is still calculated, however compile time instead of runtime. So actually calculations can take place in the compiler which is Linux native code or take place at runtime on the target which will be completely different code. So for zsdcc this bare version does something completely different than the calculations in "julia.c".

I will add the flags you suggested to look at the assembly output, it will be interesting to look at. I know from experience in the past that a good C compiler produces very efficient assembly code, in a lot of cases (way) better than assembling by hand. I made the float volatile and the result is indeed vastly different. However volatile forces the compiler to read the variable from memory every time so this will most likely be different from what happens in "julia.c" because for a normal variable the compiler can read once and keep intermediate results or keep things in cache or in registers. By the looks of is zsdcc does a very good job and is superior to the old compiler. Sccz80 will be phased out in the future?
There are some good things coming, including an api for the hw sprites. It's always better to add some value to the basic hw otherwise there's no reason for people to use another api so we'll be looking at doing things like grouping sprites together to make big bad guys and whatnot.
Yes, I was thinking about a very simple demo "Pong" program where the ball is one sprite (extremely simple as it is a black square) and the bats are 4 stacked sprites acting as one group (same black squares, so a lot easier than making a bad guy). This would be about the most basic example still showing the movement, bouncing and collision detection (with the walls, the bat groups and the border). With these sprites it should be easy.

Post Reply