Explain this behavior

Any discussions related to the creation of new hardware or software for the ZX80 or ZX81
monzamess
Posts: 25
Joined: Sat Jul 08, 2017 8:39 pm

Explain this behavior

Post by monzamess »

Hi, I am getting back into ZX81 (well really TS1000 for me) development. I wrote BASIC programs as a kid, then went on to a career in all sorts of programming, but now I am removed from that life and want a piece of it back. I don't have the time and attention span at the moment to learn Z80 assembly (I started trying) so I am developing in C with z88dk.

Attached is my first attempt at moving a character on the screen. Move the "O" around with 5,6,7,8 keys. I reused the assembly-based character printing routines from Shaun_B's "Shoot" game I found online, hope that's OK. I don't have anything in particular in mind for this "game" yet, thus the name.

The weird behavior (to me) is that the O moves faster the lower you get on the screen. Is this a side effect of how the DFILE is processed? In other words, does it process from bottom up and so when it's only drawing something near the bottom of the screen, it refreshes faster? Regardless, how can I even out the refreshes--add more to the display?
Attachments
wtf.P
(2.91 KiB) Downloaded 195 times
Shaun_B
Posts: 474
Joined: Wed Apr 22, 2009 10:22 am

Re: Explain this behavior

Post by Shaun_B »

That's cool - I have a more sophisticated and faster printAt() type routine for z88dk if you want it? It will allow >1 character and inverse on/off.

I'm going to further modify it so that you may choose at which point in your text string to start your print as well as x/y positioning.

Thanks,

Shaun.
monzamess
Posts: 25
Joined: Sat Jul 08, 2017 8:39 pm

Re: Explain this behavior

Post by monzamess »

Sure, I'd love to see it!
Shaun_B
Posts: 474
Joined: Wed Apr 22, 2009 10:22 am

Re: Explain this behavior

Post by Shaun_B »

To answer your original question, I'm not sure why the bottom of the screen is more responsive that the top? I noticed this myself, and then started an API for z88dk so that I could write to a back buffer and update the screen at regular intervals. I never got around to finishing it though.

Maybe ask over at z88dk.org - they have Sinclair ZX forums there.

Thanks,

Shaun.
monzamess
Posts: 25
Joined: Sat Jul 08, 2017 8:39 pm

Re: Explain this behavior

Post by monzamess »

For what it's worth, I didn't further investigate the odd behavior, but I did finally figure out a way to double-buffer the graphics in C in this "move the O around the screen" program. Code is below. Code is sloppy in general and I need to do something smarter than clear the screen each frame because that's really, really slow, but this is as far as I am for now. It's coming back to me slowly.

Code: Select all

#include <graphics.h>
#include <stdio.h>
#include <input.h>
#include <malloc.h>

#define DFILE 16396
#define VARS 16400


// Global variables:
extern long heap(60000);    // place malloc's heap pointer at address 60000
int drawX = 0;
int drawY = 0;  
int oldDrawX = 0;
int oldDrawY = 0; 


// Return value at location DFILE
int derp()
{
	#asm
	LD HL,(DFILE)	
	RET
	#endasm
}



void clearScreen(char *screen)
{
  int i = 0;
  int x = 0;
  int y = 0;
  
  *(screen) = 118;
  i++;
  for (y = 0; y < 24; y++)
  {
    for (x = 0; x < 32; x++)
    {
      *(screen + i) = 0;
	  i++;
    }
	*(screen + i) = 118;
	i++;
  }
}

 
int drawStuff(char *screen)
{
  int index;
  
  clearScreen(screen);
	
  *(screen + (drawY * 33) + drawX + 1) = 52;
 
  //oldDrawX = drawX;
  //oldDrawY = drawY;

  return 0;
}

int readKeys()
{
  uchar key = in_Inkey();
  if (key == '5')
  {
    drawX--;
	if (drawX < 0) drawX = 0;
  }
  else if (key == '8')
  {
    drawX++;
	if (drawX > 31) drawX = 31;
  }
  else if (key == '6')
  {
    drawY++;
	if (drawY > 21) drawY = 21;
  }
  else if (key == '7')
  {
    drawY--;
	if (drawY < 0) drawY = 0;
  }
  
  return 0;
}


int main (void) 
{
  int dfileAddress = DFILE;
  int varsAddress = VARS;
  
  int currScreen = 0;
  
  int i = 0;
  
  char *screen0;
  char *screen1;
  
  mallinit();              // heap cleared to empty
  sbrk(30000,1000);        // add 2000 bytes from addresses 30000-31999 inclusive to the heap
 
  screen0 = (char *)(*dfileAddress);
  screen1 = (char *)(malloc(800 * sizeof(char)));  // screen size actually 793...?

  printf("dfile is at %x\n", derp());
  
  printf("dfile is still at %x\n", *dfileAddress);
  printf("vars is at %x\n", *varsAddress);
  printf("so dfile size is %d\n", *varsAddress - *dfileAddress);

  printf("screen0 is at %x\n", screen0);
  printf("screen1 is at %x\n", screen1);
  
  while (0)
  {
    *dfileAddress = screen1;
    clg();
    printf("\n\n\n\n\n\n\n\n\n\nthis is screen2");

    *dfileAddress = screen0;
    clg();
    printf("\n\n\n\n\nthis is screen1");

    while (0)
    {	  
      *dfileAddress = screen0;
      *dfileAddress = screen1;
    }
  } 
 
  clearScreen(screen0);
  clearScreen(screen1);  

  drawX = 15;
  drawY = 10;
  
  while (1)
  {
	readKeys();
	if (currScreen == 0)
	{
	  currScreen = 1;
      drawStuff(screen1);
	  *dfileAddress = screen1;	  
	}
	else
	{
	  currScreen = 0;
	  drawStuff(screen0);
	  *dfileAddress = screen0;	  
	}
  }
  
  
  return 0;
}

daybyter
Posts: 17
Joined: Wed Nov 23, 2016 11:03 pm

Re: Explain this behavior

Post by daybyter »

Very cool! I like C and the zx81in general, so I appreciate your efforts.

First optimization, that caught my eye was this *(screen+i)= ...

Why not *screen++ = ... ?
monzamess
Posts: 25
Joined: Sat Jul 08, 2017 8:39 pm

Re: Explain this behavior

Post by monzamess »

That would work in that case--normally I would not want to modify the screen pointer, but within this function there would be no harm. However I suspect the bulk of the time cost is in loop iterating through 793 character locations rather than the addition. I wrote the very basic beginnings of a "dirty list" last night so that I only clear parts of the screen buffer that need to be cleared--that works much faster but will require a lot more accounting in the code... I'll post an update later when I can.
monzamess
Posts: 25
Joined: Sat Jul 08, 2017 8:39 pm

Re: Explain this behavior

Post by monzamess »

Here's the double-buffered version of the "push the O around the screen" program. I'm not at all sure where I'm going with this. This version doesn't *seem* to exhibit the speed differential between top and bottom of screen like the single-buffered version posted above exhibits. Maybe it's doing enough between frames that it dwarfs whatever caused the discrepancy. ???

When I put the heap at 60000 and the second screen buffer at 30000 within the heap (I think!), I was just copying an example on how to use malloc in z88dk. What would be more proper memory locations for the heap and allocated screen buffer on a 16K ZX81?
Attachments
flip.P
(4.26 KiB) Downloaded 158 times
flip.c
(3.63 KiB) Downloaded 159 times
sirmorris
Posts: 2811
Joined: Thu May 08, 2008 5:45 pm

Re: Explain this behavior

Post by sirmorris »

The memory map of a 16k ZX81 doesn't include RAM at address 60000. I'd suggest aiming a little lower. Unless I'm misunderstanding how the heap placement in z88 works?

http://forum.tlienhard.com/TS1000/www.t ... orymap.htm
monzamess
Posts: 25
Joined: Sat Jul 08, 2017 8:39 pm

Re: Explain this behavior

Post by monzamess »

I was using the same memory map, and I also don't understand the 60000 magic number.

Using the new and very cool live memory viewer in EightyOne, I confirmed the actual memory allocation happens at 30000 as requested in the code, which is just under ramtop for a 16k machine.

(Also, I forgot that I've been testing on an emulated 16k machine and it works...)

So time for me to re-educate myself on the heap! It bugs me when things work only by happenstance. :)
Post Reply