Memory problem...?

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Memory problem...?

Post by amateus »

Hi,

I always wanted to develop a game for zx, but never been lucky with assembler, so I decided to learn z88dk and sp1.

I have been doing a breakout game (which will be freely available in the end), and it has been quite an interesting exercise, but I hit a problem that I do not really know how to solve. It seems related to memory, but I am not sure.

Now, the game is not complete and it's not really complex and does not have any huge amount of stuff, so I'm guessing I'm doing something really wrong, or by the way I have structured my code or by not configuring pragma stuff correctly (or both, or none).

The behavior I'm seeing is weird: if I add, for example, another function (you can remove the comments in sprite.c and sprite.h to test it - func collision_ball_die) which is not even called from the loop, I have garbled text on score or text messages. Commenting the code, the problem disappears.
The garbled text is usually one or two characters. I used a asm file to configure a font in the udg, pretty much like Blackstar or mspacman excellent examples.

The current code is available at my github, feel free to browse it: https://github.com/antoniocmateus/z88dk_sp1_yab

Please be aware that I have never developed for the zx spectrum and do not have experience in C (but I developed professionally, and still do occasionally, in other languages for many years), so you might see some code that makes you scream.
I also have to confess that, while I do know more or less the spectrum memory map, analyzing a TAP file to see what is wrong is something I never did nor do I know how. I have checked the debugger a few times in the emulator but... :rolleyes:

So, my question is, if you're in the mood to help a noob in zx dev (and c): is this a memory related problem and if so, what am I doing wrong? Or this is something else?
Also, now that you've seen the code :) what can I improve in the code/structure in order to save memory? Is this philosophy generally correct or it's completely wrong?

Thank you :)
Timmy
Well known member
Posts: 392
Joined: Sat Mar 10, 2012 4:18 pm

Re: Memory problem...?

Post by Timmy »

It's 4 am right now, and I can't get your code compiled, so perhaps you could try this:

set your start address to 29000, and see if the program could run now?
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Re: Memory problem...?

Post by amateus »

Hi,

So I have compiled the program with the following command:

Code: Select all

zcc +zx -v -startup=31 -DWFRAMES=3  -clib=sdcc_iy -SO3 --max-allocs-per-node200000 --fsigned-char "@zproject.lst" -pragma-include:zpragma.inc -o deploy/yab -m -create-app
I compiled a few taps (uploaded). Did not upload the code has the only changes were on CRT_ORG_CODE and comment/uncomment:

yab_good_30000.tap - this one is the same as the previous tap, meaning function in sprites.c and sprites.h is commented. You can see the score increasing correctly and the text in game paused (H key) is correct
yab_bad_30000.tap - uncommented function in sprites.c and sprites.h. It's not called from anywhere. You can see the score increasing incorrectly (2 and 8 are garbled)
yab_bad_29000.tap - no change to code (function is commented). score and paused text garbled.
yab_bad_32768.tap - code uncommented and called from loop. score is ok, but paused text is garbled.

So not sure what's going on here :)

Thanks
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Re: Memory problem...?

Post by amateus »

Hi all,

Been trying to figure it out the problem with no luck. I even deleted some level info but i continue to have problems, so definitely, somewhere, I'm doing something I shouldn't, but what it is, no clue.

Upping or lowering the CRT_ORG_CODE produces different corrupted text, as moving the asm file with the font up and down on the zproject lst. The game itself runs fine on all options I've tried.

Any suggestions? :)
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Memory problem...?

Post by dom »

Normally the best way to do this is to calculate the address of the affected memory and then set a write breakpoint to catch the corruption.

I've just had a look at the raw font data after the corruption appears and it's correct. So maybe something is changing the tile data in someway, so a write breakpoint on that would be a good place to start.
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Re: Memory problem...?

Post by amateus »

dom wrote: Wed Dec 30, 2020 8:43 pm Normally the best way to do this is to calculate the address of the affected memory and then set a write breakpoint to catch the corruption.

I've just had a look at the raw font data after the corruption appears and it's correct. So maybe something is changing the tile data in someway, so a write breakpoint on that would be a good place to start.
Thank you for the insight. I admit that it makes perfectly sense,stopping the execution in the addr corresponding to the pixel in the garbled text and tracing back the problem. Unfortunately I'm spoiled by years of 1) lack of need to manage memory and 2) modern debuggers and so I don't really know how to do that :(
I know it's a limitation on my side and should probably learn it, but like I said, modern debug tools spoiled me to death, so I don't have a clue.

And even if I did, I'm not sure I could follow the trail, as assembler is not my cup of tea. If I was able to debug the c code, that would be interesting, but I gather it's not.

Thanks @dom :)
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Memory problem...?

Post by dom »

Ironically I'm working on some (C) debugging stuff at the moment.

Anyway, it looks like the tile map address is held at $f000 -> $f1fff, so the address of the tile for '2' is at $f032 and $f132. Using Fuse we can use "break write 0xf032" and "break write 0xf132".

Running, we can see we'll break when the tile is registered (good) and then another from sp1_Invalidate().

This one seems to happen because the sp1 update list contains an address of somewhere in the tilemaps.

The question is why, I've never used sp1, but you're invalidating the whole screen: is enough memory allocated to keep the state for each character that should be invalidated?
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Memory problem...?

Post by dom »

dom wrote: Wed Dec 30, 2020 11:15 pm The question is why, I've never used sp1, but you're invalidating the whole screen: is enough memory allocated to keep the state for each character that should be invalidated?
And the answer to that is no. Each tile needs 10 bytes to hold the update state, so we need 7680 bytes. The update array (SP1V_UPDATEARRAY) is located at $d200. To cover the whole screen it will extend to $ffff, thus "overwriting" the tile maps.
Timmy
Well known member
Posts: 392
Joined: Sat Mar 10, 2012 4:18 pm

Re: Memory problem...?

Post by Timmy »

sp1 internally needs every byte from the start of the interrupt table to 65535. You cannot put anything else there.

the memory map of sp1 shows that too. (i cant find it in the new docs, but it's also in https://www.z88dk.org/wiki/doku.php?id= ... es:sp1_ex1 ... the table starts with "horizontal rotation tables", search in that page).

i still haven't had the time to test any of it right now. i am using an old version right now and it doesn't recognise 'intrinsic_ei()' and i have too many new year things to do, and i need to find a place to install a nightly but without changing my current one (and installing it)... just don't have the time for it right now.
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Memory problem...?

Post by dom »

The memory map explains it quite well:

Code: Select all

; f000 - f1ff     SP1.LIB  tile array
; d200 - efff     SP1.LIB  update array for full size screen 32x24
SP1 is setting up tile array, and then updating the display from "update array". The odd thing seems to be that the memory assumes 9 bytes per cell (which is true for the classic hires Timex version), but the size in code is actually 10 bytes.

So in this case the display is 24x32= 768 cells which of course overlaps and the pointers to certain tiles are modified.

I feel like I'm missing something, surely this problem must've been seen before?
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Re: Memory problem...?

Post by amateus »

Ok, so based on the information I indeed do sp1_Invalidate(&game_area), which is not the whole screen ({1, 1, 22, 24}), twice: once when I initialize sp1, and second in the beginning of each level, to clear the whole game area and draw a new level (game.c::draw_level function in the code).

This means that for the first level I invalidate, load gfx, show menu (not yet done), invalidate again and draw tiles.

Removing sp1_Invalidate(&game_area) from the draw_level function solves the problem, eg the tiles are drawed correctly and the text prints correctly as well.

But this leads me to a problem which is the reason why I have used it in first place and not sp1_ClearRectInv when I want to clear the game area: if I use sp1_ClearRectInv(&game_area, INK_WHITE | PAPER_BLACK, ' ', SP1_RFLAG_TILE | SP1_RFLAG_COLOUR); the game area is covered by $ char instead of spaces char, which is something I don't understand why.
I use sp1_ClearRectInv with smaller rects on other places inside and outside the game area (to clear text, score, etc) and I do not have any issues.

So to sum up:
- sp1_Invalidate(&game_area) (the second call) from draw_level clears the screen correctly but produces corruption in tiles.
- removing sp1_Invalidate(&game_area) (the second call) from draw_level , solves the issue, but then the screen is not cleared when changing level
- Adding sp1_ClearRectInv(&game_area, INK_WHITE | PAPER_BLACK, ' ', SP1_RFLAG_TILE | SP1_RFLAG_COLOUR); makes the whole game area with $ instead of spaces.

Here's a simple snippet that produces the ClearRect problem, compiled with zcc +zx -vn -startup=31 -clib=sdcc_iy test.c -o test -create-app

Code: Select all

#pragma output REGISTER_SP            = 0xd000

#include <arch/zx.h>
#include <arch/zx/sp1.h>

struct sp1_Rect game_area = {1, 1, 22, 24};

int main()
{

    zx_border(INK_BLACK);

    // Initialize SP1
    sp1_Initialize(SP1_IFLAG_MAKE_ROTTBL | SP1_IFLAG_OVERWRITE_TILES | SP1_IFLAG_OVERWRITE_DFILE,
                   INK_WHITE | PAPER_BLACK, ' ' );
    
    //Invalidate the game area to force sp1 to redraw next update
    sp1_Invalidate(&game_area); 

    sp1_ClearRect(&game_area, INK_WHITE | PAPER_BLACK, ' ', SP1_RFLAG_TILE | SP1_RFLAG_COLOUR);
    sp1_UpdateNow();

    // Lets go to the main loop
    while (1) {

    }

}
So not sure what are the next steps. Has anyone seen this behavior before?

Thank you for the help, hopefully this will get solved and will be a reference for future noobs like me :)

Happy new year by the way, to all :)
Timmy
Well known member
Posts: 392
Joined: Sat Mar 10, 2012 4:18 pm

Re: Memory problem...?

Post by Timmy »

I indeed do sp1_Invalidate(&game_area), which is not the whole screen ({1, 1, 22, 24})
This is because {1,1,22,24} is not the whole screen, but larger than the screen.

You can read the other thread again for some examples: viewtopic.php?p=18843#p18843

Hint: Some of the 4 parameters are NOT coordinates.
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Re: Memory problem...?

Post by amateus »

S**t, I new it was something simple!

That, my friend, appears to be the root of the whole problem.

Height=24 from y=1 is indeed bigger than the spectrum screen height, and that caused the artifacts in the memory. Changing to 23 solved it. It also solved the sp1_ClearRect issue I was having.

I need to have more attention to detail.

@dom regarding the C debugging stuff, anything related to be able to debug z88dk projects? (I'm also going to use Fuse as it seems to have a more powerful debugger).

Thanks for the help @Timmy and @dom. Appreciate it. I'll finish the project and will share everything for future reference.

Cheers
Post Reply