Z88DK C+Z80 Development Tools

Discuss ZX Spectrum Next Games, Tools and more.
Stefan123
Posts: 119
Joined: Mon Jun 05, 2017 9:38 pm

Re: Z88DK C+Z80 Development Tools

Postby Stefan123 » Mon Jul 03, 2017 8:24 am

I just want to say that this thread (and the whole forum) is great! A real source of information and a friendly atmosphere.

I'm happy to read that the Next target in z88dk will have both Timex and layer 2 support in the sp1 software sprite library. I guess that this could be used for animating parts of a layer 2 background?

IMHO, the two most important features to have in the Next target would be some kind of support for memory banking and SD card file I/O. It feels reassuring that the z88dk gurus are already thinking and working on this :D

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

Re: Z88DK C+Z80 Development Tools

Postby Alcoholics Anonymous » Tue Jul 04, 2017 4:22 am

Stefan123 wrote:
Mon Jul 03, 2017 8:24 am
I guess that this could be used for animating parts of a layer 2 background?
Yes but it may be sp1 would be changed fundamentally due to the way layer 2 works. Each pixel is its own byte so there is no more software rotation to place sprites with pixel precision. Instead the fastest way to draw sprites may be a bunch of pop/pushes like is done now in spectrum scrolling games. Then the organization of data will change from character oriented to line oriented and that's different from sp1. At 14MHz (max speed with layer 2) I don't think the DMA figures at all.
There's a commonly used method that (most of the time) lets you avoid using LD A,0 / ADC A,0 and the like in these types of operations:

Code: Select all

	add a,mask_table & 0xff
	ld l,a
	adc a,mask_table / 256
	sub a,l
	ld h,a
Cheers Hikaru, fixed up now. There are probably some other places in the code base that do this. They'll be found eventually :)

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

Re: Z88DK C+Z80 Development Tools

Postby Alcoholics Anonymous » Mon Jul 17, 2017 12:29 am

Alcoholics Anonymous wrote:
Sat Jun 17, 2017 3:48 pm
KyotoG wrote:
Sat Jun 17, 2017 10:13 am
2. Can we specify an output folder for the generated .asm files, so I can ignore the folder, rather than each individual file?
I think you mean foo.asm.m4 -> foo.asm and you'd like the foo.asm placed in a junk folder?

Right now that can't be done. z88dk is placing the foo.asm file in the same directory so that include paths are correctly resolved. I'll add it to the list and maybe we can get rid of that requirement and at the same time produce the .asm file in the temp dir rather than the source dir.
I don't think we can do this actually. It's not technically hard to do but many people are organizing their asm projects as a bunch of independent asm files included into a central asm file that is assembled. This is because a lot of common z80 assemblers have no concept of an object file so you have to assemble everything from one file.

If we don't output the foo.asm file generated from the macro foo.asm.m4 then this would defeat this other source code organization style.

User avatar
KyotoG
Posts: 30
Joined: Tue May 30, 2017 5:02 am

Re: Z88DK C+Z80 Development Tools

Postby KyotoG » Mon Jul 17, 2017 12:45 am

Ok, no problem. I've whittled my code down to a single .asm.m4 which is used for data. This works better for me, as debugging errors with generated asm files is awkward as the error line numbers are for the generated files, so it's a little time consuming to translate that to the m4 line, etc....

User avatar
bob_fossil
Posts: 30
Joined: Tue May 30, 2017 5:26 pm

Re: Z88DK C+Z80 Development Tools

Postby bob_fossil » Sat Aug 19, 2017 3:44 pm

I managed to get sdcc built on my Linux box the other day and decided to rebuild Walkabout (my C game) with it. After making some small changes to get it to compile with sdcc (sdcc is more strict about types than sccz80 and there are some subtle differences in how the z88dk works with sdcc - you have to manually #define JOYFUNC to something different with sdcc which should probably be done in the input.h and not have to be done by the user) I had a tap file. After running this in SpecEmu, I noticed graphics corruption and various oddities but the game proceeded to run until I pressed the keyboard to move my character and the game crashed back to basic.

I fixed some of the obvious problems (sdcc needs the IX register preserved which I wasn't doing in my sound effect function which calls the ROM beeper function which in turn modifies IX) and rebuilt it - but it's still not working.

With the command line options:

Code: Select all

-startup=31 -SO3 -clib=sdcc_iy --max-allocs-per-node200000 --fsigned-char
Menu border graphics corrupted
Scrolling message corrupted
Game crashes back to basic with C:Nonsense in basic after you press a key to move the character.

Code: Select all

-startup=31 -SO3 -clib=sdcc_iy --fsigned-char
-startup=31 -clib=sdcc_iy --fsigned-char
Menu border graphics corrupted.
Menu scrolling message corrupted.
Game crashes back to basic after you press a key to move the character.

Code: Select all

-startup=31 -clib=sdcc_ix --fsigned-char
Menu border graphics corrupted.
Menu scrolling message now works.
Game crashes back to basic after you press a key to move the character.

The menu scroller is an asm function which doesn't touch the ix or iy registers. sdcc doesn't seem to be happy with this either:

Code: Select all

unsigned char *backgrounds[MAX_BACKGROUND]=
	{
	TILE_BACKGROUND_BLANK,
	TILE_BACKGROUND_SQUARES,
	TILE_BACKGROUND_STAR,
	TILE_BACKGROUND_MESH,
	TILE_BACKGROUND_TOYBLOCK,
	TILE_BACKGROUND_STRIPES,
	TILE_BACKGROUND_DOTS,
	TILE_BACKGROUND_DIAMOND,
	TILE_BACKGROUND_GRID,
	TILE_BACKGROUND_NET
	};
	
...
	
draw_tile(0, i, backgrounds[2]);
This works on sccz80 but draws garbage to the screen with sdcc. If I do this with sdcc:

Code: Select all

draw_tile(0, i, TILE_BACKGROUND_STAR);
the correct tile is drawn.

I suspect I'm missing some command line or some nugget of Alvin's wisdom but I'm about to throw in the towel with using sdcc and go back to sccz80 as I can spend my limited time doing development with that, rather than trying to divine obscure compiler bugs / operations with sdcc. sdcc is generating smaller code but it's not working.

The sdcc I built returns the following version information:

Code: Select all

SDCC : mcs51/z80/z180/r2k/r3ka/gbz80/tlcs90/ds390/TININative/ds400/hc08/s08/stm8 3.6.9 #9993 (Linux)
Any ideas or suggestions greatly appreciated. Thanks.

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

Re: Z88DK C+Z80 Development Tools

Postby Alcoholics Anonymous » Sat Aug 19, 2017 4:28 pm

bob_fossil wrote:
Sat Aug 19, 2017 3:44 pm
After making some small changes to get it to compile with sdcc (sdcc is more strict about types than sccz80 and there are some subtle differences in how the z88dk works with sdcc - you have to manually #define JOYFUNC to something different with sdcc which should probably be done in the input.h and not have to be done by the user) I had a tap file.
Yes you're probably right. I will look to add JOYFUNC to the headers tonight.

sdcc is more standards conformant and will demand more standard code, as well as accept a larger c subset. Its complaints do help to find subtle bugs.
I fixed some of the obvious problems (sdcc needs the IX register preserved which I wasn't doing in my sound effect function which calls the ROM beeper function which in turn modifies IX) and rebuilt it - but it's still not working.

With the command line options:

Code: Select all

-startup=31 -SO3 -clib=sdcc_iy --max-allocs-per-node200000 --fsigned-char
Menu border graphics corrupted
Scrolling message corrupted
Game crashes back to basic with C:Nonsense in basic after you press a key to move the character.
To rule out the optimizer, it's good to try without SO3 as you've done.

With clib=sdcc_iy, there is something subtle :- the library is built with IX and IY swapped. This means if you call into an asm library function that is documented as using IX as parameter, it is actually using IY. Your regular code is unaffected, it's just the already compiled library code that has had this swap done.

If you are calling any asm library functions, be aware of that swap.

Code: Select all

-startup=31 -clib=sdcc_ix --fsigned-char
Menu border graphics corrupted.
Menu scrolling message now works.
Game crashes back to basic after you press a key to move the character.
And clib=sdcc_ix does not do the swap. So this is probably not the problem.

I'm guessing there's some simple thing going on. I'll have a look at your repo when I have some time tonight.
Bob are you writing functions in asm that are called from C? sdcc pushes params in right to left order whereas sccz80 does it in left to right order. Also, sdcc pushes chars as one byte. I bet this is what is causing the crashes.. Again when I look at your repo I'll suggest some changes to accommodate that.
The sdcc I built returns the following version information:

Code: Select all

SDCC : mcs51/z80/z180/r2k/r3ka/gbz80/tlcs90/ds390/TININative/ds400/hc08/s08/stm8 3.6.9 #9993 (Linux)
Any ideas or suggestions greatly appreciated. Thanks.
There's been some activity at sdcc concerning the z80 target. I'm still using 9958 so I'll check if things work before updating.

User avatar
bob_fossil
Posts: 30
Joined: Tue May 30, 2017 5:26 pm

Re: Z88DK C+Z80 Development Tools

Postby bob_fossil » Sat Aug 19, 2017 4:48 pm

Alcoholics Anonymous wrote:
Sat Aug 19, 2017 4:28 pm
I'm guessing there's some simple thing going on. I'll have a look at your repo when I have some time tonight.
Bob are you writing functions in asm that are called from C? sdcc pushes params in right to left order whereas sccz80 does it in left to right order. Also, sdcc pushes chars as one byte. I bet this is what is causing the crashes.. Again when I look at your repo I'll suggest some changes to accommodate that.
Thanks for the suggestions, Alvin. I am calling some asm functions from C. I had changed the order for sdcc but hadn't realised sdcc was pushing a char as a single byte. The repo doesn't currently have my latest set of changes to get it compiling with sdcc. If I don't get any joy looking again at the asm functions, I'll push my latest set of changes and you can take a look.

UPDATE:

Okay, so the source of all my crashes was my sound effect function in sound.asm:

Code: Select all


_sound_effect:

	; void sound_effect(int pitch, char bend)

IFDEF __SCCZ80

	pop hl			; return address
	pop bc			; bc = bend
	ex (sp),hl		; hl = pitch, return address back on stack

ENDIF

IFDEF __SDCC

	pop af       		; return address
	pop hl       		; hl = pitch
	pop bc       		; bc = bend
	push af      		; return address back on stack

	push ix			; store ix as call to ROM beeper overwrites
ENDIF

	ld b,c			; popped bend into c, so put it into b for the djnz
loop:
	push bc
	push hl			; store pitch.
	ld de, 1		; very short duration.
	call 949		; ROM beeper routine.
	pop hl			; restore pitch.
	inc hl			; pitch going up.
	pop bc
	djnz loop		; repeat.

IFDEF __SDCC

	pop ix			; restore ix for SDCC

ENDIF

	ret
In the header file, sound.h I had:

Code: Select all

extern void sound_effect(int pitch, char bend) __z88dk_callee;
I changed this to:

Code: Select all

extern void sound_effect(int pitch, int bend) __z88dk_callee;
and it all starts working. I still have corrupted menu graphics and in-game background tiles but the code actually runs and you can play the game now.

User avatar
bob_fossil
Posts: 30
Joined: Tue May 30, 2017 5:26 pm

Re: Z88DK C+Z80 Development Tools

Postby bob_fossil » Sat Aug 19, 2017 8:59 pm

Managed to workaround my corrupted tiles problem in sdcc with the following:

Code: Select all

#ifdef __SDCC
unsigned short backgrounds[MAX_BACKGROUND]= 
#else
unsigned char *backgrounds[MAX_BACKGROUND]=
#endif
	{
	TILE_BACKGROUND_BLANK,
	TILE_BACKGROUND_SQUARES,
...
	};
The only remaining problem is in my menu scroller but that looks like it's C related rather than asm as I use some C to populate a character buffer which the asm scroller code uses. For whatever reason, the code sdcc creates only seems to copy the first line of the character into the buffer.

User avatar
bob_fossil
Posts: 30
Joined: Tue May 30, 2017 5:26 pm

Re: Z88DK C+Z80 Development Tools

Postby bob_fossil » Sat Aug 19, 2017 10:02 pm

Got to the bottom of why my scroller wasn't working properly.

In menu.c, in do_menu()

Code: Select all

			// Load character into buffer.
			i = (*scroll_char) - 0x20;
			p = (unsigned char *)SCROLL_CHAR;	
			character = (unsigned char *)(FONT + (i * 8));
			i = 0;
						
			for(; i < 8; i++)
				{
				*p = *character;
				p++;
				character++;
				}
For the command line:

Code: Select all

zcc +zx -vn -startup=31 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 --fsigned-char --c-code-in-asm --list 
sdcc generates the following assembly (menu.c.lis):

Code: Select all

1179  046D              l_do_menu_00124:
1180  046D              ;menu.c:253: for(; i < 8; i++)
1181  046D  FE 08       	cp	a,0x08
1182  046F  30 0F       	jr	NC,l_do_menu_00103
1183  0471              ;menu.c:255: *p = *character;
1184  0471  F5          	push	af
1185  0472  0A          	ld	a, (bc)
1186  0473  DD 77 FF    	ld	(ix-1),a
1187  0476  F1          	pop	af
1188  0477  DD 7E FF    	ld	a,(ix-1)
1189  047A  12          	ld	(de), a
1190  047B              ;menu.c:256: p++;
1191  047B  13          	inc	de
1192  047C              ;menu.c:257: character++;
1193  047C  03          	inc	bc
1194  047D              ;menu.c:253: for(; i < 8; i++)
1195  047D  3C          	inc	a
1196  047E  18 ED       	jr	l_do_menu_00124
1197  0480              l_do_menu_00103:
The register pair af is being popped too early (1187). The loop counter value it's holding gets overwritten by the subsequent load from (ix-1). If I do the following:

Code: Select all

			for(; i < 8; i++)
				{
				scroll_rem = i;
				*p = *character;
				p++;
				character++;
				i = scroll_rem;
				}
the character gets copied to the buffer correctly and the scroller works properly.

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

Re: Z88DK C+Z80 Development Tools

Postby Alcoholics Anonymous » Sun Aug 20, 2017 7:22 am

bob_fossil wrote:
Sat Aug 19, 2017 8:59 pm
Managed to workaround my corrupted tiles problem in sdcc with the following:

Code: Select all

#ifdef __SDCC
unsigned short backgrounds[MAX_BACKGROUND]= 
#else
unsigned char *backgrounds[MAX_BACKGROUND]=
#endif
	{
	TILE_BACKGROUND_BLANK,
	TILE_BACKGROUND_SQUARES,
...
	};
Yes this is a bug. When it's declared as unsigned char *, the pre-processor is delivering this to the compiler:

Code: Select all

unsigned char *backgrounds[10]=
 {
 25768 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32,
 25768 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32 + 32
 };
 
And the compiler is turning that into:

Code: Select all

1808  0028              _backgrounds:
1809  0028  68 00       	DEFW +0x0068
1810  002A  88 00       	DEFW +0x0088
1811  002C  A8 FF       	DEFW +0xffa8
1812  002E  C8 FF       	DEFW +0xffc8
1813  0030  E8 FF       	DEFW +0xffe8
1814  0032  08 00       	DEFW +0x0008
1815  0034  28 00       	DEFW +0x0028
1816  0036  48 00       	DEFW +0x0048
1817  0038  68 00       	DEFW +0x0068
1818  003A  88 00       	DEFW +0x0088
What it looks like to me is that it's computing those values and truncating to char, then sign extending.

Code: Select all

		for(; i < 8; i++)
				{
				*p = *character;
				p++;
				character++;
				}
sdcc generates the following assembly (menu.c.lis):

Code: Select all

1179  046D              l_do_menu_00124:
1180  046D              ;menu.c:253: for(; i < 8; i++)
1181  046D  FE 08       	cp	a,0x08
1182  046F  30 0F       	jr	NC,l_do_menu_00103
1183  0471              ;menu.c:255: *p = *character;
1184  0471  F5          	push	af
1185  0472  0A          	ld	a, (bc)
1186  0473  DD 77 FF    	ld	(ix-1),a
1187  0476  F1          	pop	af
1188  0477  DD 7E FF    	ld	a,(ix-1)
1189  047A  12          	ld	(de), a
1190  047B              ;menu.c:256: p++;
1191  047B  13          	inc	de
1192  047C              ;menu.c:257: character++;
1193  047C  03          	inc	bc
1194  047D              ;menu.c:253: for(; i < 8; i++)
1195  047D  3C          	inc	a
1196  047E  18 ED       	jr	l_do_menu_00124
1197  0480              l_do_menu_00103:
The register pair af is being popped too early (1187). The loop counter value it's holding gets overwritten by the subsequent load from (ix-1). If I do the following:
This part I am not reproducing. Correct code is being generated and the program runs properly.

So I think it's likely sdcc has introduced some new bugs in the recent work on the z80.
The version of sdcc I am using is 9958 if you want to back up to this version. I'll update in the coming days and try to locate new bugs.

Some other changes I made:

The new library has changed the name of "zx_cyx2saddr" to "zx_cxy2saddr" - I thought this change was early enough that no one saw it. The reason for it is to keep a consistent x,y order for everything. So you have an older install that still has the functions defined this way. I changed the function name and param order (now x,y per name) in three places in main.c

The definition of JOYFUNC is now in input.h as of tonight, but it's missed the nightly build so the nightly won't have it until after the next build. This means the definition of JOYFUNC in main.c will have to be removed.

And then the problems you found:

sdcc pushes in right to left order and only one byte for char so the params are read differently in asm functions called from C.

sdcc needs ix preserved in asm and sdcc_ix needs both ix and iy preserved.

Calls to rom functions can be a little tricky. The beep call uses ix so that needs preserving but the other tricky part is it enables interrupts. You have your own im2 routine installed so this is what you want but for compiles that don't set up their own isr, the crt disables interrupts at startup. This is to avoid having basic's isr at 0x38 running because sdcc will use the iy register. Basic's isr uses iy to poke into memory so this combination means random pokes in memory leading to crashes.


Who is online

Users browsing this forum: No registered users and 7 guests