Page 2 of 4

Re: Plot function in Z88DK

Posted: Thu Feb 01, 2018 8:46 am
by Shaun_B
RobertK wrote: Wed Jan 31, 2018 3:53 pm Thanks Andy, the speed is impressive!
I may seem entirely hopeless, but can anyone please assist me in wrapping this ASM code into a C function? I know that you need to put the ASM code between #asm and #endasm, but everything else regarding ASM in z88dk is currently trial and error for me.
I Robert,

As far as I know, the #asm/#endasm is deprecated - use it like this example:

https://github.com/sbebbers/fruit-machi ... ain.c#L417

Regards,

Shaun.

Re: Plot function in z88dk

Posted: Thu Feb 01, 2018 10:56 am
by RobertK
Here is my sample program using a function I found at the z88dk forums, but for some reason my plotted dots don't appear:

Code: Select all

// found at https://www.z88dk.org/forum/viewtopic.php?id=6271
// Contributors: swensont, siggi, Timmy, alvin

#include <stdio.h>
#include <zx81.h>

// alvin: "It's faster to pop them or use HL to walk the stack.  The best solution is 
// Timmy's which uses CALLEE linkage so that the subroutine can pop the parameters 
// off the stack and not put them back:
static void __CALLEE__ zx_plot( short x, short y)
{
   __asm   
   POP HL   ; HL = return address
   POP DE   ; E  = y,  and  remove y from stack (necessary for CALLEE functions)
   POP BC   ; C  = x,  and  remove x from stack (necessary for CALLEE functions)
   PUSH HL  ; push return address back to stack
   LD B, E  ; BC = yx

   RET   ;; note the compiler automatically adds RET on closing '}' so this is not required
   __endasm;
}

main ( ) {

   short x,y;
   printf("plotting...\n\n");

   /* plot points */	
   zx_plot(10,10);
   zx_plot(20,20);
   
   /* draw a border around the screen */
   for (x = 0; x <= 63; ++x)
   {
	zx_plot(x, 43);
	zx_plot(x, 0);
   }
   for (y = 1; y <= 42; ++y)
   {
	zx_plot(0, y);
	zx_plot(63, y);
   }
   
   printf("done.\n");
   
}
zxplot.c
(1.16 KiB) Downloaded 305 times

I compile it with a batch file containing these commands (the z88root directory needs to be modified):

Code: Select all

setlocal
set z88root=C:\Misc\z88dk\

set path=%PATH%;%z88root%bin\
set zcccfg=%z88root%lib\config\
set z80_ozfiles=%z88root%lib\

zcc +zx81 -startup=2 -o zxplot -create-app zxplot.c
endlocal

pause
Can anyone please check why the plotted dots don't appear?

And/or can anyone try to put Andy's ASM code into a C function?

Re: Plot function in z88dk

Posted: Thu Feb 01, 2018 12:16 pm
by siggi
The code snippet above is only an example, how parameters (plot coordinates) could be passed efficiently from C to ASM. This snippet does NOTHING, because the plot-code is not included (Andy's could be added after " LD B, E ; BC = yx" and "RET"/end of function).

HTH Siggi

Re: Plot function in z88dk

Posted: Thu Feb 01, 2018 9:16 pm
by Andy Rea
here you go straight out of the notepad..... zx_plot and zx_unplot and another question or problem for someone more familiar with z88DK for zx81

i tried to expand the number of parameters passed to the function to allow a plotmode param however it just kept crashing the zx81, as you'll see much of the code for plot and unplot is the same so it is a little stupid to have 2 functions ...

any way... its pretty fast... NO BOUNDS CHECK and only works in standard text display mode with a FULL d-file.

chuck the following code in your z88dk assembler and smoke it !

Code: Select all

// found at https://www.z88dk.org/forum/viewtopic.php?id=6271
// Contributors: swensont, siggi, Timmy, alvin

#include <stdio.h>
#include <zx81.h>

// alvin: "It's faster to pop them or use HL to walk the stack.  The best solution is 
// Timmy's which uses CALLEE linkage so that the subroutine can pop the parameters 
// off the stack and not put them back:
static void __CALLEE__ zx_plot( short x, short y)
{
   __asm   
   POP HL   ; HL = return address
   POP BC   ; C  = y,  and  remove y from stack (necessary for CALLEE functions)
   EX (SP),HL
   LD  B,L  ; BC = XY
     
  

CALC_DFILE_BYTE:
	;WORK OUT SCREEN BYTE FROM CO-ORDS
	LD	A,C			;GET CURRENT Y POSITION 0 TO 47
	SRL	A			;A = 0 TO 23
					
	LD	E,A			;E = 1 * A
	
	LD	D,0			;DE = 1 *  A
	ADD	A,A			;A = 2* ,	MAX = 46
	ADD	A,A			;A = 4 *  , MAX = 92
	ADD	A,A			;A = 8 * , MAX =184
	ADD	A,A			;A = 16 Y , MAX = 112 AND CARRY SET
	LD 	H,0			;NO EFFECT ON CARRY
	RL	H			;PICK UP ANY CARRY	
	LD	L,A
	ADD	HL,HL		;HL = 32 * Y
	ADD	HL,DE		;HL = 33 * Y
	
	
	
	LD	A,B			;GET X POSITION 
	SRL	A			;DIVIDE BY 2
	LD	E,A
	LD	D,0			
	ADD	HL,DE		;HL NOW = SCREEN OFFSET
	LD	DE,($400C)
	ADD	HL,DE		;HL NOW = CURRENT DFILE + OFFSET
	
	INC	HL			;COMPENSATE FOR 1ST HALT IN DFILE

	;screen address now in HL

	
        LD      A,$01        
        SRA     C              
        JR      NC,EVEN_Y

        LD      A,$04


EVEN_Y: SRA     B          
        JR      NC,EVEN_X  

        RLCA			; 1 OR 4 BECOMES 2 OR 8                

EVEN_X:
	LD	C,A		;SAVE A FOR NOW

	LD 	A,(HL)		;GET BYTE FROM SCREEN
	RLCA
	CP	16
	JR	NC,A_ZERO
	RRCA
	JR	NC,GOOD_CHAR
	XOR	$8F		;ELSE INVERTED CHAR
	JR	GOOD_CHAR
A_ZERO:
	XOR	A
GOOD_CHAR:
	
	OR	C
	CP	8
	JR	C,LAST_BIT
	XOR	$8F

LAST_BIT:
	LD	(HL),A



   RET   ;; note the compiler automatically adds RET on closing '}' so this is not required
   __endasm;
}

static void __CALLEE__ zx_unplot( short x, short y)
{
   __asm   
   POP HL   ; HL = return address
   POP BC   ; C  = y,  and  remove y from stack (necessary for CALLEE functions)
   EX (SP),HL
   LD  B,L  ; BC = XY
     
  

UN_CALC_DFILE_BYTE:
	;WORK OUT SCREEN BYTE FROM CO-ORDS
	LD	A,C			;GET CURRENT Y POSITION 0 TO 47
	SRL	A			;A = 0 TO 23
					
	LD	E,A			;E = 1 * A
	
	LD	D,0			;DE = 1 *  A
	ADD	A,A			;A = 2* ,	MAX = 46
	ADD	A,A			;A = 4 *  , MAX = 92
	ADD	A,A			;A = 8 * , MAX =184
	ADD	A,A			;A = 16 Y , MAX = 112 AND CARRY SET
	LD 	H,0			;NO EFFECT ON CARRY
	RL	H			;PICK UP ANY CARRY	
	LD	L,A
	ADD	HL,HL		;HL = 32 * Y
	ADD	HL,DE		;HL = 33 * Y
	
	
	
	LD	A,B			;GET X POSITION 
	SRL	A			;DIVIDE BY 2
	LD	E,A
	LD	D,0			
	ADD	HL,DE		;HL NOW = SCREEN OFFSET
	LD	DE,($400C)
	ADD	HL,DE		;HL NOW = CURRENT DFILE + OFFSET
	
	INC	HL			;COMPENSATE FOR 1ST HALT IN DFILE

	;screen address now in HL

	
        LD      A,$01        
        SRA     C              
        JR      NC,UN_EVEN_Y

        LD      A,$04


UN_EVEN_Y: SRA     B          
        JR      NC,UN_EVEN_X  

        RLCA			; 1 OR 4 BECOMES 2 OR 8                

UN_EVEN_X:
	LD	C,A		;SAVE A FOR NOW

	LD 	A,(HL)		;GET BYTE FROM SCREEN
	RLCA
	CP	16
	JR	NC,UN_A_ZERO
	RRCA
	JR	NC,UN_GOOD_CHAR
	XOR	$8F		;ELSE INVERTED CHAR
	JR	UN_GOOD_CHAR
UN_A_ZERO:
	XOR	A
UN_GOOD_CHAR:
	LD B,A
	LD A,C
	CPL
	AND	B
	CP	8
	JR	C,UN_LAST_BIT
	XOR	$8F

UN_LAST_BIT:
	LD	(HL),A



   RET   ;; note the compiler automatically adds RET on closing '}' so this is not required
   __endasm;
}

main ( )
{

  short x,y;
  printf("plotting...\n\n");

   /* plot points */	
   zx_plot(5,10);
   zx_plot(15,20);
   
   /* draw a border around the screen */
	
   for (x = 0; x <= 63; ++x)
   {
	zx_plot(x, 47);
	zx_plot(x, 0);
   }
   for (y = 1; y <= 47; ++y)
   {
	zx_plot(0, y);
	zx_plot(63, y);
   }

 for (x = 0; x <= 63; ++x)
   {
	zx_unplot(x, 47);
	zx_unplot(x, 0);
   }
   for (y = 1; y <= 47; ++y)
   {
	zx_unplot(0, y);
	zx_unplot(63, y);
   }
   printf("done.\n");

 for (y=1; y <= 47; ++y)
  {
    for (x=0; x<=63; x += y)
      {
         zx_plot (x,y);
         zx_plot ((63-x), (47-y));
      }
   }

   
}


Re: Plot function in z88dk

Posted: Thu Feb 01, 2018 11:31 pm
by RobertK
Thanks Andy, that works just GREAT!

I hope that I will soon be able to post a little program that uses these functions.

And I hope some z88dk expert can try to merge the two functions, I assume that two functions need more memory than just one...

Re: Plot function in z88dk

Posted: Sat Feb 03, 2018 10:19 pm
by Andy Rea
once again straight from the notepad, further investigation into my previous attempt at combining plot and unplot into one function ended up with some illegal bytes been put into D-file, its all fixed up now and its 3 function to boot... PLOT , UNPLOT and XOR-PLOT

zx_plot( short x, short y, short pmode)
x is 0 to 63
y is 0 to 47
pmode is 0 = unplot, 1 = plot, 2 =xor plot

again NO BOUNDS check and only works with FULL d-file

regards Andy

Code: Select all

// found at https://www.z88dk.org/forum/viewtopic.php?id=6271
// Contributors: swensont, siggi, Timmy, alvin

#include <stdio.h>
#include <zx81.h>

// alvin: "It's faster to pop them or use HL to walk the stack.  The best solution is 
// Timmy's which uses CALLEE linkage so that the subroutine can pop the parameters 
// off the stack and not put them back:
static void __CALLEE__ zx_plot( short x, short y, short pmode)
{
   __asm   
   POP HL   ; HL = return address
   POP DE   ; E  = plot mode
   POP BC   ; C  = y,  and  remove y from stack (necessary for CALLEE functions)
   EX (SP),HL
   LD  B,L  ; BC = XY
   PUSH DE  ; SAVE PMODE FOR LATER
     
  

CALC_DFILE_BYTE:
	;WORK OUT SCREEN BYTE FROM CO-ORDS
	LD	A,C			;GET CURRENT Y POSITION 0 TO 47
	SRL	A			;A = 0 TO 23
					
	LD	E,A			;E = 1 * A
	
	LD	D,0			;DE = 1 *  A
	ADD	A,A			;A = 2* ,	MAX = 46
	ADD	A,A			;A = 4 *  , MAX = 92
	ADD	A,A			;A = 8 * , MAX =184
	ADD	A,A			;A = 16 Y , MAX = 112 AND CARRY SET
	LD 	H,0			;NO EFFECT ON CARRY
	RL	H			;PICK UP ANY CARRY	
	LD	L,A
	ADD	HL,HL		;HL = 32 * Y
	ADD	HL,DE		;HL = 33 * Y
	
	
	
	LD	A,B			;GET X POSITION 
	SRL	A			;DIVIDE BY 2
	LD	E,A
	LD	D,0			
	ADD	HL,DE		;HL NOW = SCREEN OFFSET
	LD	DE,($400C)
	ADD	HL,DE		;HL NOW = CURRENT DFILE + OFFSET
	
	INC	HL			;COMPENSATE FOR 1ST HALT IN DFILE

	;screen address now in HL

	
        LD      A,$01        
        SRA     C              
        JR      NC,EVEN_Y

        LD      A,$04


EVEN_Y: SRA     B          
        JR      NC,EVEN_X  

        RLCA			; 1 OR 4 BECOMES 2 OR 8                

EVEN_X:
	LD	B,A		;SAVE the new pixwl block in b

	LD 	A,(HL)		;GET BYTE FROM SCREEN
	RLCA
	CP	16
	JR	NC,A_ZERO
	RRCA
	JR	NC,GOOD_CHAR
	XOR	$8F		;ELSE INVERTED CHAR
	JR	GOOD_CHAR
A_ZERO:
	XOR	A
GOOD_CHAR:

        ; so at this point we have the screen char ( or zero if not a valif block graphic ) in A
        ; and the quarter block graphic in B, for plotting we OR B with A result in A
        ; for unplotting we complment ( invert )  B and then AND with A
	; for XOR plot we XOR B with A
	
	ld	C,a	;put a in safe place

	pop	de
	xor	a
	or	e
	jr	z,do_unplot
	dec	e
	jr	z,do_plot
        
	;else xor-plot

	ld	a,c	
	xOR	B
	CP	8
	JR	C,plot_done
	XOR	$8F
	jr	plot_done

do_unplot:
	LD A,B
	CPL
	AND	C
	CP	8
	JR	C,plot_done
	XOR	$8F
	jr	plot_done

do_plot:
	ld	a,c	
	OR	b
	CP	8
	JR	C,plot_done
	XOR	$8F



plot_done:
	LD	(HL),A



	



   RET   ;; note the compiler automatically adds RET on closing '}' so this is not required
   __endasm;
}



main ( )
{

  short x,y;
  printf("plotting...\n\n");

   /* plot points */	
   zx_plot(5,10,1);
   zx_plot(15,20,1);
   
   /* draw a border around the screen */
	
   for (x = 0; x <= 63; ++x)
   {
	zx_plot(x, 47,1);
	zx_plot(x, 0,1);
   }
   for (y = 1; y <= 47; ++y)
   {
	zx_plot(0, y,1);
	zx_plot(63, y,1);
   }

 for (x = 0; x <= 63; ++x)
   {
	zx_plot(x, 47,0);
	zx_plot(x, 0,0);
   }
   for (y = 1; y <= 47; ++y)
   {
	zx_plot(0, y,0);
	zx_plot(63, y,0);
   }
   printf("done.\n");

 for (y=1; y <= 47; ++y)
  {
    for (x=0; x<=63; x += y)
      {
         zx_plot (x,y,2);
         zx_plot (63-x, 47-y,2);
      }
   }

   
}



Re: Plot function in z88dk

Posted: Sun Feb 04, 2018 6:35 pm
by Andy Rea
Just a little rejig of the assembler to make it a few bytes shorter, functionally the same as last post.

Code: Select all

// found at https://www.z88dk.org/forum/viewtopic.php?id=6271
// Contributors: swensont, siggi, Timmy, alvin

#include <stdio.h>
#include <zx81.h>

// alvin: "It's faster to pop them or use HL to walk the stack.  The best solution is 
// Timmy's which uses CALLEE linkage so that the subroutine can pop the parameters 
// off the stack and not put them back:
static void __CALLEE__ zx_plot( short x, short y, short pmode)
{
  __asm   
   POP HL   ; HL = return address
   POP DE   ; E  = plot mode
   POP BC   ; C  = y,  and  remove y from stack (necessary for CALLEE functions)
   EX (SP),HL
   LD  B,L  ; BC = XY
   PUSH DE  ; SAVE PMODE FOR LATER
     
  

CALC_DFILE_BYTE:
	;WORK OUT SCREEN BYTE FROM CO-ORDS
	LD	A,C			;GET CURRENT Y POSITION 0 TO 47
	SRL	A			;A = 0 TO 23
					
	LD	E,A			;E = 1 * A
	
	LD	D,0			;DE = 1 *  A
	ADD	A,A			;A = 2* ,	MAX = 46
	ADD	A,A			;A = 4 *  , MAX = 92
	ADD	A,A			;A = 8 * , MAX =184
	ADD	A,A			;A = 16 Y , MAX = 112 AND CARRY SET
	LD 	H,0			;NO EFFECT ON CARRY
	RL	H			;PICK UP ANY CARRY	
	LD	L,A
	ADD	HL,HL		;HL = 32 * Y
	ADD	HL,DE		;HL = 33 * Y
	
	
	
	LD	A,B			;GET X POSITION 
	SRL	A			;DIVIDE BY 2
	LD	E,A
	LD	D,0			
	ADD	HL,DE		;HL NOW = SCREEN OFFSET
	LD	DE,($400C)
	ADD	HL,DE		;HL NOW = CURRENT DFILE + OFFSET
	
	INC	HL			;COMPENSATE FOR 1ST HALT IN DFILE

	;screen address now in HL

	
        LD      A,$01        
        SRA     C              
        JR      NC,EVEN_Y

        LD      A,$04


EVEN_Y: SRA     B          
        JR      NC,EVEN_X  

        RLCA			; 1 OR 4 BECOMES 2 OR 8                

EVEN_X:
	LD	B,A		;SAVE the new pixwl block in b

	LD 	A,(HL)		;GET BYTE FROM SCREEN
	RLCA
	CP	16
	JR	NC,A_ZERO
	RRCA
	JR	NC,GOOD_CHAR
	XOR	$8F		;ELSE INVERTED CHAR
	JR	GOOD_CHAR
A_ZERO:
	XOR	A
GOOD_CHAR:

        ; so at this point we have the screen char ( or zero if not a valif block graphic ) in A
        ; and the quarter block graphic in B, for plotting we OR B with A result in A
        ; for unplotting we complment ( invert )  B and then AND with A
	; for XOR plot we XOR B with A
	
	ld	C,a	;save for unplot.... 

	pop	de
	dec	e
	jr	z,do_plot
	dec	e
	jr	z,xor_plot
        
	;else unplot

do_unplot:
	LD A,B
	CPL
	AND	C
	jr	plot_done

xor_plot:
	xOR	B
	jr	plot_done


do_plot:
	OR	b

plot_done:
	CP	8
	JR	C,put_char
	XOR	$8F



put_char:
	LD	(HL),A



	



   RET   ;; note the compiler automatically adds RET on closing '}' so this is not required
   __endasm;
}



main ( )
{

  short x,y;
  printf("plotting...\n\n");

   /* plot points */	
   zx_plot(5,10,1);
   zx_plot(15,20,1);
   
   /* draw a border around the screen */
	
   for (x = 0; x <= 63; ++x)
   {
	zx_plot(x, 47,1);
	zx_plot(x, 0,1);
   }
   for (y = 1; y <= 47; ++y)
   {
	zx_plot(0, y,1);
	zx_plot(63, y,1);
   }

 for (x = 0; x <= 63; ++x)
   {
	zx_plot(x, 47,0);
	zx_plot(x, 0,0);
   }
   for (y = 1; y <= 47; ++y)
   {
	zx_plot(0, y,0);
	zx_plot(63, y,0);
   }
   printf("done.\n");

 for (y=1; y <= 47; ++y)
  {
    for (x=0; x<=63; x += y)
      {
         zx_plot (x,y,2);
         zx_plot (63-x, 47-y,2);
      }
   }

   
}


Re: Plot function in z88dk

Posted: Mon Feb 05, 2018 10:41 pm
by Andy Rea
just thinking about this... probably already functions out there but a Bresenham line and circle function would go nice with this.

Andy

Re: Plot function in z88dk

Posted: Tue Feb 06, 2018 8:37 am
by RobertK
Thanks once more, the parameterised function works great as well.
Andy Rea wrote: Mon Feb 05, 2018 10:41 pmjust thinking about this... probably already functions out there but a Bresenham line and circle function would go nice with this.
And maybe more important: a function that checks whether there is a plotted pixel at (x,y), we could call that checkplot(x,y) for example. Is this technically possible?

I would need this for collision detection for a little game that I would like to port to the ZX81. I could of course use a 64x48 bit array to remember where the obstacles are, but such a function would help to save memory.

Re: Plot function in z88dk

Posted: Tue Feb 06, 2018 1:30 pm
by Andy Rea
RobertK wrote: Tue Feb 06, 2018 8:37 am Thanks once more, the parameterised function works great as well.
Andy Rea wrote: Mon Feb 05, 2018 10:41 pmjust thinking about this... probably already functions out there but a Bresenham line and circle function would go nice with this.
And maybe more important: a function that checks whether there is a plotted pixel at (x,y), we could call the checkplot(x,y) for example. Is this technically possible?

I would need this for collision detection for a little game that I would like to port to the ZX81. I could of course use a 64x48 bit array to remember where the obstacles are, but such a function would help to save memory.
yes a checkpoint function should be easy to implement. when i get a moment i'll see what i can rustle up.