                ;
                ; tinyFire : some simple fire routine
                ; coded by wiRe / napalm
                ; 21-01-2003
                ;
                ; note: link with -s:NTSCMODE for NTSC version
                ;

                TARGET      BIN, R5900
                INCLUDE     "ps2lib\macros.inc"





NON_INTERLACED  EQU     0
INTERLACED      EQU     1
NTSC            EQU     0
PAL             EQU     1
FRAME           EQU     1
FIELD           EQU     0

GS_PRIM         EQU     0x00
GS_RGBAQ        EQU     0x01
GS_XYZ2         EQU     0x05
GS_XYOFFSET_1   EQU     0x18
GS_PRMODECONT   EQU     0x1A
GS_SCISSOR_1    EQU     0x40
GS_DTHE         EQU     0x45
GS_TEST_1       EQU     0x47
GS_FRAME_1      EQU     0x4C
GS_ZBUF_1       EQU     0x4E

PRIM_TRI_STRIP  EQU     4
PRIM_SPRITE     EQU     6
PRIM_GOURAUD    EQU     (1<<3)
PRIM_ANTIALIAS  EQU     (1<<7)





SCREEN_WIDTH        EQU 640
SCREEN_HEIGHT_PAL   EQU 512
SCREEN_HEIGHT_NTSC  EQU 448
SCREEN_PSM          EQU 0
SCREEN_MAGH         EQU 4

IF (NTSCMODE)
  SCREEN_MODE   EQU NTSC
  SCREEN_HEIGHT EQU SCREEN_HEIGHT_NTSC
ELSE
  SCREEN_MODE   EQU PAL
  SCREEN_HEIGHT EQU SCREEN_HEIGHT_PAL
ENDIF


FIRE_WIDTH      EQU     40
FIRE_HEIGHT     EQU     10
FIRE_DX         EQU     SCREEN_WIDTH/FIRE_WIDTH
FIRE_DY         EQU     SCREEN_HEIGHT/FIRE_HEIGHT



IF !CRUNCHED

                DB  7Fh,"ELF"   ; indentifier
                DB  1           ; File Class: 1=32bit, 2=64bit objects
                DB  1           ; Data Encoding: 1=ELFDATA2LSB, 2=ELFDATA2MSB
                DB  1           ; ELF header version (must be 1)
                DB  0,'w','i','R','e','/','N','P','M'
                DH  2           ; ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE
                DH  8           ; Processor: 8=MIPS
                DW  1           ; Version: 1=current
                DW  code.main   ; Entry point address
                DW  program     ; Start of program headers (offset from file start)
                DW  0           ; Start of section headers (offset from file start)
                DW  20924001h   ; Processor specific flags = 0x20924001 noreorder, mips
                DH  34h         ; ELF header size (0x34 = 52 bytes)
                DH  20h         ; Program headers entry size
                DH  1           ; Number of program headers
                DH  0           ; Section headers entry size
                DH  0           ; Number of section headers
                DH  0           ; Section header stringtable index
  program:      DW  1           ; Segment type: 1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14
                DW  code._fofs  ; Offset from file start to program segment.
                DW  code._ofs   ; Virtual address of the segment
                DW  code._ofs   ; Physical address of the segment
                DW  code._fsize ; Number of bytes in the file image of the segment
                DW  ((code._size+15)>>4)<<4 ; Number of bytes in the memory image of the segment
                DW  0h          ; Flags for segment
               ;DW  0h          ; Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment
code            SEGMENT     0x400000
                DW          0

ELSE

code            SEGMENT     0x400000

ENDIF



  rand_z        DW          0x2317A033
  rand_b        DW          0xA86C90A3
  rand_a        DW          0x645E7933


  main:
                lui         fp, 0x50                    ; fp points on fire field
                lui         gp, 0x40                    ; gp points on code
                lui         t9, 0x1200                  ; t9 points of gs reg
                lui         t8, 0x1000+1                ; t8 points on dma register


                ; --- dma reset ---
                COMMENT /*                              ; we run this using napLink only, reset is allready done
                sw          zero, 0xA080-0x10000(t8)
                sw          zero, 0xA000-0x10000(t8)
                sw          zero, 0xA030-0x10000(t8)
                sw          zero, 0xA010-0x10000(t8)
                sw          zero, 0xA050-0x10000(t8)
                sw          zero, 0xA040-0x10000(t8)
                ori         v0, zero, 0xFF1F
                sw          v0, 0xE010-0x10000(t8)
                lw          v1, 0xE010-0x10000(t8)
                and         v1, v0
                sw          v1, 0xE010-0x10000(t8)
                sw          zero, 0xE000-0x10000(t8)
                sw          zero, 0xE020-0x10000(t8)
                sw          zero, 0xE030-0x10000(t8)
                sw          zero, 0xE050-0x10000(t8)
                sw          zero, 0xE040-0x10000(t8)
                lw          v0, 0xE000-0x10000(t8)
                ori         v0, 1
                sw          v0, 0xE000-0x10000(t8)*/


                ; --- reset gs ---

                addiu       at, 1<<9
                sd          at, 0x1000(t9)
               ;sync.p
               ;ori         a0, zero, 0x0000FF00        ; set imr
               ;addiu       v1, zero, 0x71
               ;syscall
                addiu       a0, zero, INTERLACED        ; set gs crt
                addiu       a1, zero, SCREEN_MODE
                addiu       a2, zero, FIELD
                addiu       v1, zero, 2
                syscall


                ; --- set video mode ---

                ; PMODE: EN1=0,EN2=1,001=0,MMOD=1,AMOD=1,SLBG=0,ALP=0xFF
                ori         at, zero, 0xFF62
                sd          at, 0x00(t9)
                ; DISPFB2: FBP=0,FBW=SCREEN_WIDTH/64,PSM=SCREEN_PSM,DBX=0,DBY=0
                ori         at, zero, (SCREEN_PSM<<15)|((SCREEN_WIDTH/64)<<9)
                sd          at, 0x90(t9)
                ; DISPLAY2: DX=653,DY=72,MAGH=SCREEN_MAGH-1,MAGV=0,DW=SCREEN_WIDTH*SCREEN_MAGH-1,DH=SCREEN_HEIGHT-1
                lid         at, (653<<0)|(72<<12)|((SCREEN_MAGH-1)<<23)|((SCREEN_WIDTH*SCREEN_MAGH-1)<<32)|((SCREEN_HEIGHT-1)<<44)
                sd          at, 0xA0(t9)


                ; --- init ---

                addiu       at, fp, 0
                addiu       v0, zero, FIRE_WIDTH*(FIRE_HEIGHT+10)
  finit_lp:     sw          zero, (at)
                subi        v0, 1
                bgtz        v0, finit_lp
                addiu       at, 4


  main_lp:      ; ---------------------------------------------------------------------------------
                lw          v0, 0xA000-0x10000(t8)          ; dma wait
                andi        v0, 0x100
                bnez        v0, main_lp



                ; fseeds...
                ;   y = size_y+2
                ;   for x=3 to size_x-2:if ran()>0.26 then
                ;     fire(y-1,x  ) = fire(y-1,x  ) + 63
                ;     fire(y  ,x-1) = fire(y  ,x-1) + 63
                ;     fire(y  ,x  ) = fire(y  ,x  ) + 127
                ;     fire(y  ,x+1) = fire(y  ,x+1) + 63
                ;     fire(y+1,x  ) = fire(y+1,x  ) + 63
                ;   fi:next

                addiu       t0, fp, (FIRE_WIDTH*(FIRE_HEIGHT+1) + 2)*4
                addiu       t1, zero, FIRE_WIDTH-4
  fseed_lp:
                lwu         v1, ~rand_a(gp)
                lwu         at, ~rand_b(gp)
                lwu         v0, ~rand_z(gp)

                lw          s0, (( 0)*FIRE_WIDTH+( 0))*4(t0)
                lw          s1, (( 1)*FIRE_WIDTH+(-1))*4(t0)
                lw          s2, (( 1)*FIRE_WIDTH+( 1))*4(t0)
                lw          s3, (( 2)*FIRE_WIDTH+( 0))*4(t0)
                lw          s4, (( 1)*FIRE_WIDTH+( 0))*4(t0)

                multu       v0, v0, v1
                addu        v0, at
                sw          v0, ~rand_z(gp)
                andi        v0, 0xFFF
                slti        v0, v0, 1065
                bnez        v0, fseed_skip

                addi        s0, 63
                addi        s1, 63
                addi        s2, 63
                addi        s3, 63
                addi        s4, 127

                sw          s0, (( 0)*FIRE_WIDTH+( 0))*4(t0)
                sw          s1, (( 1)*FIRE_WIDTH+(-1))*4(t0)
                sw          s2, (( 1)*FIRE_WIDTH+( 1))*4(t0)
                sw          s3, (( 2)*FIRE_WIDTH+( 0))*4(t0)
                sw          s4, (( 1)*FIRE_WIDTH+( 0))*4(t0)

  fseed_skip:   subi        t1, 1
                bgtz        t1, fseed_lp
                addiu       t0, 4



                ; fipol...
                ;   for y=1 to size_y+3:for x=2 to size_x-1
                ;     fire(y,x) = int( (fire(y+1,x  )+fire(y+3,x  )+
                ;                       fire(y+2,x-1)+fire(y+2,x+1)+
                ;                       fire(y+2,x  )) /5)-29
                ;     if fire(y,x)<0 then fire(y,x)=0 fi
                ;     if fire(y,x)>254 then fire(y,x)=255 fi
                ;   next:next

                addiu       t0, fp, 4
                addiu       t1, zero, FIRE_HEIGHT+4 -1
  fipol_ylp:
                addiu       t2, zero, FIRE_WIDTH-2 -1
  fipol_xlp:
                lw          s0, (( 1)*FIRE_WIDTH+( 0))*4(t0)
                lw          s1, (( 2)*FIRE_WIDTH+(-1))*4(t0)
                lw          s2, (( 2)*FIRE_WIDTH+( 0))*4(t0)
                lw          s3, (( 2)*FIRE_WIDTH+( 1))*4(t0)
                lw          s4, (( 3)*FIRE_WIDTH+( 0))*4(t0)

                dadd        s0, s1
                dadd        s0, s2
                dadd        s0, s3
                dadd        s0, s4

                addiu       at, zero, 5
                div         s0, at
                mflo        s0
                subi        s0, 29

                bltzl       s0, $+8
                move        s0, zero

                slti        s1, s0, 256
                addiu       at, zero, 255
                movz        s0, at, s1
                sw          s0, 0(t0)

                addiu       t0, 4
                bgtz        t2, fipol_xlp
                subi        t2, 1
                addiu       t0, 8
                bgtz        t1, fipol_ylp
                subi        t1, 1



                ; fdraw (generate gif packet)...
                ;   mx = 640/size_x
                ;   my = 512/size_y
                ;
                ;   fy = 0
                ;   for y=1 to size_y-1:fx=0
                ;    for x=1 to size_x-1
                ;      setrgb 1, fire(y,x),0,0
                ;      setrgb 2, fire(y,x+1),0,0
                ;      setrgb 3, fire(y+1,x+1),0,0
                ;      gtriangle fx,fy to fx+mx,fy to fx+mx,fy+my
                ;      setrgb 2, fire(y+1,x),0,0
                ;      gtriangle fx,fy to fx,fy+my to fx+mx,fy+my
                ;      fx=fx+mx
                ;    next:fy=fy+my
                ;   next

                lui         at, 0x2000                  ; uncached mem
                addiu       t7, gp, GIF_PACKET_INSERT
                or          t7, at

                addiu       t0, fp, 0
                addiu       t1, zero, FIRE_HEIGHT+1 -1
                lui         t3, FIRE_DY<<4              ; y_inc value
                move        t4, zero

  fdraw_ylp:
                move        t5, t4
                addiu       t2, zero, FIRE_WIDTH+1 -1

                addiu       at, zero, PRIM_TRI_STRIP|PRIM_GOURAUD|PRIM_ANTIALIAS
                addiu       v1, zero, GS_PRIM
                addiu       t7, 16
                sd          at, 0-16(t7)
                sd          v1, 8-16(t7)
  fdraw_xlp:
                lbu         s0, (( 0)*FIRE_WIDTH+( 0))*4(t0)
                lbu         s1, (( 1)*FIRE_WIDTH+( 0))*4(t0)
                addiu       t0, 4

                addu        t6, t5, t3
                sd          s0, 0*16+0(t7)
                sd          s1, 2*16+0(t7)
                sd          t6, 3*16+0(t7)
                sd          t5, 1*16+0(t7)
                addiu       t5, FIRE_DX<<4

                addiu       at, zero, GS_RGBAQ
                addiu       v0, zero, GS_XYZ2
                sd          at, 0*16+8(t7)
                sd          at, 2*16+8(t7)
                sd          v0, 1*16+8(t7)
                sd          v0, 3*16+8(t7)
                addiu       t7, 4*16

                bgtz        t2, fdraw_xlp
                subi        t2, 1

                subiu       t0, 4
                addu        t4, t3
                bgtz        t1, fdraw_ylp
                subi        t1, 1



                ; --- send whole shit to gs ---

                addiu       v1, zero, 4-1
  vsync_rep:    ori         v0, zero, 8
                sd          v0, 0x1000(t9)
  vsync_lp:     ld          v0, 0x1000(t9)
                andi        v0, 8
                beqz        v0, vsync_lp
                addiu       t1, zero, (1 + (gif_packet._size/16) + (FIRE_HEIGHT+1)*(4*FIRE_WIDTH+5))
                bgtz        v1, vsync_rep
                subi        v1, 1
  wait_lp:     ;lw          v0, 0xA000-0x10000(t8)  ; no dma wait needed here
               ;andi        v0, 0x100
               ;bnez        v0, wait_lp
                addiu       v1, gp, ~gif_packet-16
                sw          v1, 0xA010-0x10000(t8)
                ori         v1, zero, 101h
                sw          t1, 0xA020-0x10000(t8)
                b           main_lp
                sw          v1, 0xA000-0x10000(t8)
                ; ---------------------------------------------------------------------------------



                ALIGN       16
                DD          (1<<60)|(0x50<<24)|(1<<15)|((gif_packet._size/16) + (FIRE_HEIGHT+1)*(4*FIRE_WIDTH+5)), 0x0E

  gif_packet    TABLE ALIGN 16
                DD          1,              GS_PRMODECONT
               ;DD          1<<12,          GS_TEST_1
               ;DD          0,              GS_ZBUF_1
               ;DD          0,              GS_DTHE
               ;DD          0,              GS_XYOFFSET_1
                DD          ((SCREEN_WIDTH/64)<<16)|(SCREEN_PSM<<24),       GS_FRAME_1
                DD          ((SCREEN_WIDTH-1)<<16)|((SCREEN_HEIGHT-1)<<48), GS_SCISSOR_1
               ;DD          PRIM_SPRITE,    GS_PRIM
               ;DD          0x80FF0000,     GS_RGBAQ
               ;DD          0,              GS_XYZ2
               ;DD          (SCREEN_HEIGHT)<<20|(SCREEN_WIDTH)<<4, GS_XYZ2

                GIF_PACKET_INSERT EQU $-code
               ;DD          GS_TRI_STRIP|PRIM_GOURAUD|PRIM_ANTIALIAS, GS_PRIM
               ;DD          red, GS_RGBA
               ;DD          xy, GS_XYZ2
               ;...
  gif_packet    ENDT

code            ENDS
                END
