From krunch@intac.com Fri Jun 13 02:41:20 1997
To: ugd-jag@rhein-main.de
Subject: Re: Nothing much particular
From: krunch@intac.com (Steve Scavone)
Date: Thu, 12 Jun 1997 20:41:20 -0400 (EDT)

>> 
>>         I have just last night , using the GPU, sucseefully drew a line,
>> circle, pixel and box using the mac cc1.exe that was floating around.
>
>Hmm, I always loved to be pointed to the better way.
>So some howto's would be useful. 
>
>again:
> stop $2000
> tst.w gpu_gcc_works
> beq again
> bsr gpu-gcc
>
>42Bastian
>
>
        Ok, I'll give a little info for now but will post more when
something more exicting happens. :)

First, download DGJPP off the internet and install it( a good compiler that
make dos almost worth something). Put the CC1.EXE in the BIN subdir of djgpp
renaming it to JC1.EXE or somthing to preserve the PC cc1.exe. Use cpp.exe
in conjunction with jc1.exe in a batch file (or you wont be able to "#"
directives. ...like so

"j.bat" (or whatever)
c:\djgpp\bin\cpp %1.c %1.i
c:\djgpp\bin\jc1 %1.i -O -O1 -O2 -O3 -O4 -fomit-frame-pointer -o %1.s %2 %3
%4 %5 %6 %7 %8 %9
pause
; do this so you can pause to see any errors. Gcc out puts asm, good or bad.
edit c:\djgpp\%1.s c:\djgpp\%1.c /*to show what you have created afterwards*/

invoke like so

j filename -[up to nine other options(overkill I know)]

Always use the -fomit-frame-pointer and -O -O1 -O2 -O3 -O4(yes using them
all does make a difference as I have looked at the generated asm code trying
many combos and all of them do the best.) 

Don't define a "main" function as the gcc generates code that looks for a
"___main" start up routine(not genetated by gcc.) Call it "start" or
something else.  

The first function in the c code is the first function the GPU will execute
so "start" is a good name. 

When invoking gcc, don't point to a file like this....

        gcc c:\djgpp\jagcode.c 
        
        because your code's start and end labels will look like this....

_c:\djgpp\jagcode_start::
>
>
>       dode
>
>
_c:\djgpp\jagcode_end::

        mad mac does not like the"\" or the ":" (well it expects the ":"
after the name, not in the middle like here.)

        You can say

        c:\djgpp\gcc jagcode.c 

        and your labels will look like this. the .c should be in the djgpp dir
and your path should have all of the djgpp directories defined in it so it
can find everything.

_jagcode_start::
>
>
>       code
>
>
_jagcode_end::

MAC.TTP wants to see labels like this.

link the code with ALN.TTP with the options as suggested in the sever manual

        I beleive the "::" signifies an externally reachable label. 

        the code will also generate a...

        jr      t,*
        nop     ;forever    

        at the end of the first funtion( "start::" )
        change this to 
loop:
        jr      t,loop
        nop     ;forever        

        for now. 

        Your program should never reach this point anyway. One or more other
things to change on the output asm.......

_jag_size      .EQU    *- _jag_start
      .GLOBL  _jag_size
      .IF     _jag_size>$1000
      .PRINT  "Code size (",/l/x _jag_size,") is over $1000"
	.FAIL
	.ENDIF

        Change the...

_jag_size      .EQU    *- _jag_start

        to this...

_jag_size      .EQU    _jag_end - _jag_start


        One last thing...


add this line at the top of the output under the other .ccdef's

LE      .CCDEF  $1C   ; bin rep = 11100

;this gives a less than or equal to condition(i think).The compiler generates

jr      LE,somewhere 

code but for some reason does not define the "LE .CCDEF  $1C".

        I defined "LE"  myself and it seems to work fine. If I am off base
here with this define, those who know better, let me know.

        Below is the corrected code. It works in a vid buffer at $1a0000 at 
320x240x256. I will make this pointable to wherever you want it in the future.
For now this is all I got. I also remaned some of the jr lables for my
better understanding. This code draws a breshenham line, breshenham circle,
box and a 
pixel. I also commented alot of what's going on (at least to the best of
what little I yet understand about the GPU.) You should set up a main loop
using 68000 to set up the screen object and to init the GPU, load the code
in and then
jsr gpurun somewher in that loop.

	MACRO	_RTS
	load	(ST),TMP
	jump	T,(TMP)
	addqt	#4,ST	;rts
	ENDM

_jag_start::
	.GPU
	.ORG	$F03000
ST	.REGEQU	r31
TMP	.REGEQU	r16
GT	.CCDEF	$15
LE      .CCDEF  $1C

gcc2_compiled_for_madmac:
	;(.DATA)
	.LONG

_byte_line::
	.DC.L	320
	;(.TEXT)
	.EVEN

_start::
        movei   #$F04000,ST             ; stack pointer = $F04000
        moveq   #0,r0                   ; r0 = x1
        moveq   #0,r1                   ; r1 = y1
        movei   #_video_buffer,r3       ; r3 = pointer to video_buffer
        movei   #319,r2                 ; r2 = x2
        movei   #1703936,r6             ; r6 = start of video_buffer

        movei   #_Draw_Line,r5          ; r5 = the address of DrawLine fnc.
        store   r6,(r3)                 ; video_buffer points to video start
        moveq   #4,r4                   ; r4 = color
        movei   #239,r3                 ; r3 = y2
        move    PC,TMP                  ; this 
        subqt   #4,ST                   ; is 
        addqt   #10,TMP                 ; for
        jump    T,(r5)                  ; calling the routine
        store   TMP,(ST)                ; call   r5

        moveq   #6,r2                   ; r2 = pixel color
        movei   #100,r0                 ; r0 = x
        movei   #_Plot_Pixel_Fast,r3    ; r3 = get address of routine
        move    r0,r1                   ; r1 = y
	move	PC,TMP
	subqt	#4,ST
	addqt	#10,TMP
	jump	T,(r3)
	store	TMP,(ST)	;call	r3

loop:
        jr      T,loop
	nop	;FOREVER
	.EVEN

_Draw_Line::
        moveq   #0,r6                   ; clear r6 ?(error variable maybe)
        move    r2,r7                   ; r7 = x2
        movei   #_video_buffer,r5       ; r5 = address of video start
        sub     r0,r7                   ; r7 = dx (x2 - x1)
        move    r1,r2                   ; r2 = y1
        load    (r5),r5                 ; r5 = video pointer
        sub     r1,r3                   ; r3 = dy (y2 - y1)
        shlq    #6,r2                   ; (y1<<6) 
        add     r5,r2                   ; + vid_start (r2 = vidpos pointer)
        shlq    #8,r1                   ; (y1<<8)
        add     r1,r2                   ; + vid_start (r2 = vidpos pointer)  
        move    r2,r5                   ; put vidpos pointer back in r5
        cmpq    #0,r7                   ; is dx negitive?
        jr      MI,dxp_xim              ; set dx = pos | x_inc = neg
        add     r0,r5                   ; add x1 to vidpos
        jr      T,dxm_xip               ; set dx = neg | x_inc = pos
        moveq   #1,r2                   ; this line sets x_inc = 1 (RISC)
	.EVEN

dxp_xim:
        moveq   #0,r2                   ; r2 = 0
        neg     r7                      ; dx = pos(was neg)
        subqt   #1,r2                   ; x_inc = -1

dxm_xip:
        cmpq    #0,r3                   ; is dy negitive?
        jr      MI,dyp_yim              ; set dy = pos | y_inc = neg
        nop                             ; pad instruction cache
        movei   #_byte_line,r0          ; r0 = points to y_inc 
        jr      T,dyn_yip               ; set dy = neg | y_inc = pos
        load    (r0),r0                 ; this line sets r0 = y_inc (RISC) 
	.EVEN

dyp_yim:
        movei   #_byte_line,r0          ; r0 point to y_inc
        load    (r0),r0                 ; r0 = y_inc
        neg     r3                      ; dy = pos (was neg)
        neg     r0                      ; y_inc = -320

dyn_yip:
        cmp     r7,r3                   ; is dy(r3) greater dx(r7) 
        movei   #do_line_y,TMP          ; set up jump pointer
        jump    GT,(TMP)                ; if so do a y incremented line
        moveq   #0,r1                   ; cache padded instruction
        cmp     r7,r1                   ; is dy(r3) greater than index
        movei   #leave_draw,TMP         ; then we are done and
        jump    GT,(TMP)                ; and we can now
        nop                             ; leave
L31:
        add     r3,r6                   ; error += dy
        cmp     r6,r7                   ; if error>dx
        jr      GT,L32                  ; jump to 
        storeb  r4,(r5)                 ; plot line point in video_buffer
        sub     r7,r6                   ; error -= dx
        add     r0,r5                   ; video_pointer += y_inc
L32:
        addqt   #1,r1                   ; index++
        cmp     r1,r7                   ; index(r1) < dx?
        jr      GT,L31                  ; no, then do next pixel
        add     r2,r5                   ; video_pointer += x_inc
        movei   #leave_draw,TMP         ; index is greater so
        jump    T,(TMP)                 ; lets get out
        nop                             ; here
        .EVEN                           

do_line_y:                               
        cmp     r3,r1                   ; index > dy? 
        jr      GT,leave_draw           ; if so, later
	nop
L38:                                    
        add     r7,r6                   ; error += dy 
        jr      LE,L39                  ; if error goes 0 or neg?
        storeb  r4,(r5)                 ; plot line point to video_buffer
        sub     r3,r6                   ; error -= dy
        add     r2,r5                   ; video_pointer += x_inc
L39:
        addqt   #1,r1                   ; index += 1
        cmp     r1,r3                   ; dx > index?
        jr      GT,L38                  ; if so, continue
        add     r0,r5                   ; video_pointer += y_inc
leave_draw:
	_RTS
	.EVEN

_Plot_Pixel_Fast::
        move    r1,r4                   ; r4 = y
        movei   #_video_buffer,r3       ; r3 = video buffer start address
        shlq    #8,r4                   ; r4 = (y<<8) 
        shlq    #6,r1                   ; r1 = (y<<6) 
        load    (r3),r3                 ; r3 points to video_start
        add     r1,r4                   ; (y<<8) + (y<<6) +
        add     r0,r3                   ; x +
        add     r4,r3                   ; video_start 
        storeb  r2,(r3)                 ; plot the pixel with color in r2
        _RTS                            ; done

_video_buffer::	.DCB.B	8,0
	.LONG
	.68000

_jag_end::
_jag_size      .EQU    _jag_end - _jag_start
      .GLOBL  _jag_size
      .IF     _jag_size>$1000
      .PRINT  "Code size (",/l/x _jag_size,") is over $1000"
	.FAIL
	.ENDIF



This is the "c" code I started with( i only changed the x,y coords in some of
the function calls to experiment so if they don't jive with th out put asm
don't worry too much as this is why.



void Box(int x, int y, int w, int h, int c);
void Draw_Circle( int xc, int yc, int r, int c);
void Draw_Line(int xo, int yo, int x1,int y1, char color);
void Plot_Pixel_Fast(int x, int y, int c);
void Plot_8(int xc, int yc, int xcrd, int ycrd, int c);
void start(void);

unsigned char *video_buffer;
int  byte_line = 320;

void start(void)
{
video_buffer = (char *)0x1A0000;
Box(64, 67, 65, 66, 69);
Draw_Circle(128, 119, 50, 77);
Draw_Line(64,64,319,239,132);
Plot_Pixel_Fast(120,130,104);
}

void  Box(int x, int y, int w, int h, int c)
{
int i;
for ( i = x ; i < x+(w+1); i++ )
        {
        Plot_Pixel_Fast(i,y,c);
        Plot_Pixel_Fast(i,y+h,c);
        }
for (i = y ; i < y+(h+1); i++ )
        {
        Plot_Pixel_Fast(x,i,c);
        Plot_Pixel_Fast(x+w,i,c);
        }
}

void  Draw_Circle( int xc, int yc, int r, int c)
{
int     xcrd,ycrd,a,b,f,rn;
	xcrd = r;
	ycrd = 0;
	a = -2 * (xcrd + 1);
	b = 1;
	f = 0;
	while( b <= (-a))
	{
	Plot_8( xc, yc, xcrd, ycrd, c);
	ycrd = ycrd + 1;
	f = f + b;
		if(f > r)
		{
		f = f + a;
		a = a + 2;
		xcrd = xcrd - 1;
		}
	b = b + 2;
	}
}

void Draw_Line(int xo, int yo, int x1,int y1, char color)
{
int dx, dy, x_inc, y_inc, error = 0, index;
char  *vb_start = video_buffer;
vb_start = vb_start + ((int)yo<<6) +((int)yo<<8) +(int)xo;
dx = x1-xo;
dy = y1-yo;
if (dx>=0){x_inc = 1;}
else{x_inc = -1;
   dx    = -dx;}
if (dy>=0){y_inc = byte_line;}
else{y_inc = -byte_line;
   dy    = -dy;}
if (dx>dy)
   {
   for (index=0; index<=dx; index++)
       {*vb_start = color;
       error+=dy;
       if (error>dx){error-=dx;
	  vb_start+=y_inc;}
       vb_start+=x_inc;}
   }
else
   {
   for (index=0; index<=dy; index++)
       {*vb_start = color;
       error+=dx;
       if (error>0)
	  {error-=dy;
	  vb_start+=x_inc;}
       vb_start+=y_inc;}
   }
}

void Plot_Pixel_Fast(int x, int y, int c)
{
y = (y<<8) + (y<<6) + x;
if(y > 76799 || y < 0){return;}
video_buffer[y] = c;
}

void  Plot_8(int xc, int yc, int xcrd, int ycrd, int c)
{
  Plot_Pixel_Fast (ycrd + xc, xcrd + yc, c);        /* b quart c-clockwise */
  Plot_Pixel_Fast (-ycrd + xc, xcrd + yc, c+1);       /* b quart clockwise */
  Plot_Pixel_Fast (-ycrd + xc, -xcrd + yc, c+2);      /* d quart c-clockwise */
  Plot_Pixel_Fast (ycrd + xc, -xcrd + yc, c+3);       /* d quart clockwise */
  Plot_Pixel_Fast (xcrd + xc, -ycrd + yc, c);       /* a quart c-clockwise */
  Plot_Pixel_Fast (xcrd + xc, ycrd + yc, c);        /* a quart clockwise */
  Plot_Pixel_Fast (-xcrd + xc, ycrd + yc, c);       /* c quart c-clockwise */
  Plot_Pixel_Fast (-xcrd + xc, -ycrd + yc, c);      /* c quart clockwise */
}


       Join the Telegames list. As a result of the list, 6 new games will be
released for the JAguar. Show your support!!!! Contact Telegames at
http://www.telegames.com
1) Breakout2000 2) TowersII 3) Worms 4) Zero 5 5) Iron Soldier II 6) 6)World
Tour Racing
    Also, don't forget to support 4 Play and BattleShpere( buy a few copies
cuz you'll need 'em;])



         


