summaryrefslogtreecommitdiff
path: root/tools/ps2test
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ps2test')
-rw-r--r--tools/ps2test/CMakeLists.txt26
-rw-r--r--tools/ps2test/gs.h437
-rwxr-xr-xtools/ps2test/main.cpp788
-rw-r--r--tools/ps2test/mem.h95
-rw-r--r--tools/ps2test/ps2.h23
-rw-r--r--tools/ps2test/vu/defaultpipe.dsm93
-rw-r--r--tools/ps2test/vu/light.vu94
-rw-r--r--tools/ps2test/vu/setup_persp.vu39
-rw-r--r--tools/ps2test/vu/skinpipe.dsm94
9 files changed, 1689 insertions, 0 deletions
diff --git a/tools/ps2test/CMakeLists.txt b/tools/ps2test/CMakeLists.txt
new file mode 100644
index 0000000..5195a19
--- /dev/null
+++ b/tools/ps2test/CMakeLists.txt
@@ -0,0 +1,26 @@
+add_executable(ps2test
+ gs.h
+ main.cpp
+ mem.h
+ ps2.h
+
+ vu/defaultpipe.dsm
+ vu/skinpipe.dsm
+
+ vu/light.vu
+ vu/setup_persp.vu
+)
+
+target_link_libraries(ps2test
+ PRIVATE
+ librw::librw
+ kernel
+)
+
+librw_platform_target(ps2test INSTALL)
+
+if(LIBRW_INSTALL)
+ install(TARGETS ps2test
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ )
+endif()
diff --git a/tools/ps2test/gs.h b/tools/ps2test/gs.h
new file mode 100644
index 0000000..361ad8c
--- /dev/null
+++ b/tools/ps2test/gs.h
@@ -0,0 +1,437 @@
+#define GS_NONINTERLACED 0
+#define GS_INTERLACED 1
+
+#define GS_NTSC 2
+#define GS_PAL 3
+#define GS_VESA1A 0x1a
+#define GS_VESA1B 0x1b
+#define GS_VESA1C 0x1c
+#define GS_VESA1D 0x1d
+#define GS_VESA2A 0x2a
+#define GS_VESA2B 0x2b
+#define GS_VESA2C 0x2c
+#define GS_VESA2D 0x2d
+#define GS_VESA2E 0x2e
+#define GS_VESA3B 0x3b
+#define GS_VESA3C 0x3c
+#define GS_VESA3D 0x3d
+#define GS_VESA3E 0x3e
+#define GS_VESA4A 0x4a
+#define GS_VESA4B 0x4b
+#define GS_DTV480P 0x50
+
+#define GS_FIELD 0
+#define GS_FRAME 1
+
+#define GS_PSMCT32 0
+#define GS_PSMCT24 1
+#define GS_PSMCT16 2
+#define GS_PSMCT16S 10
+#define GS_PS_GPU24 18
+
+#define GS_PSMZ32 0
+#define GS_PSMZ24 1
+#define GS_PSMZ16 2
+#define GS_PSMZ16S 10
+
+#define GS_ZTST_NEVER 0
+#define GS_ZTST_ALWAYS 1
+#define GS_ZTST_GREATER 2
+#define GS_ZTST_GEQUAL 3
+
+#define GS_PRIM_POINT 0
+#define GS_PRIM_LINE 1
+#define GS_PRIM_LINE_STRIP 2
+#define GS_PRIM_TRI 3
+#define GS_PRIM_TRI_STRIP 4
+#define GS_PRIM_TRI_FAN 5
+#define GS_PRIM_SPRITE 6
+#define GS_PRIM_NO_SPEC 7
+#define GS_IIP_FLAT 0
+#define GS_IIP_GOURAUD 1
+
+/* GS general purpose registers */
+
+#define GS_PRIM 0x00
+#define GS_RGBAQ 0x01
+#define GS_ST 0x02
+#define GS_UV 0x03
+#define GS_XYZF2 0x04
+#define GS_XYZ2 0x05
+#define GS_TEX0_1 0x06
+#define GS_TEX0_2 0x07
+#define GS_CLAMP_1 0x08
+#define GS_CLAMP_2 0x09
+#define GS_FOG 0x0a
+#define GS_XYZF3 0x0c
+#define GS_XYZ3 0x0d
+#define GS_TEX1_1 0x14
+#define GS_TEX1_2 0x15
+#define GS_TEX2_1 0x16
+#define GS_TEX2_2 0x17
+#define GS_XYOFFSET_1 0x18
+#define GS_XYOFFSET_2 0x19
+#define GS_PRMODECONT 0x1a
+#define GS_PRMODE 0x1b
+#define GS_TEXCLUT 0x1c
+#define GS_SCANMSK 0x22
+#define GS_MIPTBP1_1 0x34
+#define GS_MIPTBP1_2 0x35
+#define GS_MIPTBP2_1 0x36
+#define GS_MIPTBP2_2 0x37
+#define GS_TEXA 0x3b
+#define GS_FOGCOL 0x3d
+#define GS_TEXFLUSH 0x3f
+#define GS_SCISSOR_1 0x40
+#define GS_SCISSOR_2 0x41
+#define GS_ALPHA_1 0x42
+#define GS_ALPHA_2 0x43
+#define GS_DIMX 0x44
+#define GS_DTHE 0x45
+#define GS_COLCLAMP 0x46
+#define GS_TEST_1 0x47
+#define GS_TEST_2 0x48
+#define GS_PABE 0x49
+#define GS_FBA_1 0x4a
+#define GS_FBA_2 0x4b
+#define GS_FRAME_1 0x4c
+#define GS_FRAME_2 0x4d
+#define GS_ZBUF_1 0x4e
+#define GS_ZBUF_2 0x4f
+#define GS_BITBLTBUF 0x50
+#define GS_TRXPOS 0x51
+#define GS_TRXREG 0x52
+#define GS_TRXDIR 0x53
+#define GS_HWREG 0x54
+#define GS_SIGNAL 0x60
+#define GS_FINISH 0x61
+#define GS_LABEL 0x62
+
+typedef union
+{
+ struct {
+ uint64 EN1 : 1;
+ uint64 EN2 : 1;
+ uint64 CRTMD : 3;
+ uint64 MMOD : 1;
+ uint64 AMOD : 1;
+ uint64 SLBG : 1;
+ uint64 ALP : 8;
+ } f;
+ uint64 d;
+} GsPmode;
+
+#define GS_MAKE_PMODE(EN1,EN2,MMOD,AMOD,SLBG,ALP) \
+ (BIT64(EN1,0) | BIT64(EN2,1) | BIT64(1,2) | \
+ BIT64(MMOD,5) | BIT64(AMOD,6) | BIT64(SLBG,7) | BIT64(ALP,8))
+
+typedef union
+{
+ struct {
+ uint64 INT : 1;
+ uint64 FFMD : 1;
+ uint64 DPMS : 2;
+ } f;
+ uint64 d;
+} GsSmode2;
+
+#define GS_MAKE_SMODE2(INT,FFMD,DPMS) \
+ (BIT64(INT,0) | BIT64(FFMD,1) | BIT64(DPMS,2))
+
+typedef union
+{
+ struct {
+ uint64 FBP : 9;
+ uint64 FBW : 6;
+ uint64 PSM : 5;
+ uint64 : 12;
+ uint64 DBX : 11;
+ uint64 DBY : 11;
+ } f;
+ uint64 d;
+} GsDispfb;
+
+#define GS_MAKE_DISPFB(FBP,FBW,PSM,DBX,DBY) \
+ (BIT64(FBP,0) | BIT64(FBW,9) | BIT64(PSM,15) | \
+ BIT64(DBX,32) | BIT64(DBY,43))
+
+typedef union
+{
+ struct {
+ uint64 DX : 12;
+ uint64 DY : 11;
+ uint64 MAGH : 4;
+ uint64 MAGV : 2;
+ uint64 : 3;
+ uint64 DW : 12;
+ uint64 DH : 11;
+ } f;
+ uint64 d;
+} GsDisplay;
+
+#define GS_MAKE_DISPLAY(DX,DY,MAGH,MAGV,DW,DH) \
+ (BIT64(DX,0) | BIT64(DY,12) | BIT64(MAGH,23) | \
+ BIT64(MAGV,27) | BIT64(DW,32) | BIT64(DH,44))
+
+typedef union
+{
+ struct {
+ uint64 EXBP : 14;
+ uint64 EXBW : 6;
+ uint64 FBIN : 2;
+ uint64 WFFMD : 1;
+ uint64 EMODA : 2;
+ uint64 EMODC : 2;
+ uint64 : 5;
+ uint64 WDX : 11;
+ uint64 WDY : 11;
+ } f;
+ uint64 d;
+} GsExtbuf;
+
+#define GS_MAKE_EXTBUF(EXBP,EXBW,FBIN,WFFMD,EMODA,EMODC,WDX,WDY) \
+ (BIT64(EXBP,0) | BIT64(EXBW,14) | BIT64(FBIN,20) | \
+ BIT64(WFFMD,22) | BIT64(EMODA,23) | BIT64(EMODC,25) | \
+ BIT64(WDX,32) | BIT64(WDY,43))
+
+typedef union
+{
+ struct {
+ uint64 SX : 12;
+ uint64 SY : 11;
+ uint64 SMPH : 4;
+ uint64 SMPV : 2;
+ uint64 : 3;
+ uint64 WW : 12;
+ uint64 WH : 11;
+ } f;
+ uint64 d;
+} GsExtdata;
+
+#define GS_MAKE_EXTDATA(SX,SY,SMPH,SMPV,WW,WH) \
+ (BIT64(SX,0) | BIT64(SY,12) | BIT64(SMPH,23) | \
+ BIT64(SMPV,27) | BIT64(WW,32) | BIT64(WH,44))
+
+typedef union
+{
+ struct {
+ uint64 WRITE : 1;
+ } f;
+ uint64 d;
+} GsExtwrite;
+
+typedef union
+{
+ struct {
+ uint64 R : 8;
+ uint64 G : 8;
+ uint64 B : 8;
+ } f;
+ uint64 d;
+} GsBgcolor;
+
+#define GS_MAKE_BGCOLOR(R,G,B) \
+ (BIT64(R,0) | BIT64(G,8) | BIT64(B,16))
+
+typedef union
+{
+ struct {
+ uint64 SIGNAL : 1;
+ uint64 FINISH : 1;
+ uint64 HSINT : 1;
+ uint64 VSINT : 1;
+ uint64 EDWINT : 1;
+ uint64 : 3;
+ uint64 FLUSH : 1;
+ uint64 RESET : 1;
+ uint64 : 2;
+ uint64 NFIELD : 1;
+ uint64 FIELD : 1;
+ uint64 FIFO : 2;
+ uint64 REV : 8;
+ uint64 ID : 8;
+ } f;
+ uint64 d;
+} GsCsr;
+
+#define GS_CSR_SIGNAL_O 0
+#define GS_CSR_FINISH_O 1
+#define GS_CSR_HSINT_O 2
+#define GS_CSR_VSINT_O 3
+#define GS_CSR_EDWINT_O 4
+#define GS_CSR_FLUSH_O 8
+#define GS_CSR_RESET_O 9
+#define GS_CSR_NFIELD_O 12
+#define GS_CSR_FIELD_O 13
+#define GS_CSR_FIFO_O 14
+#define GS_CSR_REV_O 16
+#define GS_CSR_ID_O 24
+
+typedef union
+{
+ struct {
+ uint64 : 8;
+ uint64 SIGMSK : 1;
+ uint64 FINISHMSK : 1;
+ uint64 HSMSKMSK : 1;
+ uint64 VSMSKMSK : 1;
+ uint64 EDWMSKMSK : 1;
+ } f;
+ uint64 d;
+} GsImr;
+
+typedef union
+{
+ struct {
+ uint64 DIR : 1;
+ } f;
+ uint64 d;
+} GsBusdir;
+
+typedef union
+{
+ struct {
+ uint64 SIGID : 32;
+ uint64 LBLID : 32;
+ } f;
+ uint64 d;
+} GsSiglblid;
+
+
+typedef union
+{
+ struct {
+ uint64 FBP : 9;
+ uint64 : 7;
+ uint64 FBW : 6;
+ uint64 : 2;
+ uint64 PSM : 6;
+ uint64 : 2;
+ uint64 FBMSK : 32;
+ } f;
+ uint64 d;
+} GsFrame;
+
+#define GS_MAKE_FRAME(FBP,FBW,PSM,FBMASK) \
+ (BIT64(FBP,0) | BIT64(FBW,16) | BIT64(PSM,24) | BIT64(FBMASK,32))
+
+typedef union
+{
+ struct {
+ uint64 ZBP : 9;
+ uint64 : 15;
+ uint64 PSM : 4;
+ uint64 : 4;
+ uint64 ZMSDK : 1;
+ } f;
+ uint64 d;
+} GsZbuf;
+
+#define GS_MAKE_ZBUF(ZBP,PSM,ZMSK) \
+ (BIT64(ZBP,0) | BIT64(PSM,24) | BIT64(ZMSK,32))
+
+typedef union
+{
+ struct {
+ uint64 OFX : 16;
+ uint64 : 16;
+ uint64 OFY : 16;
+ } f;
+ uint64 d;
+} GsXyOffset;
+
+#define GS_MAKE_XYOFFSET(OFX,OFY) \
+ (BIT64(OFX,0) | BIT64(OFY,32))
+
+typedef union
+{
+ struct {
+ uint64 SCAX0 : 11;
+ uint64 : 5;
+ uint64 SCAX1 : 11;
+ uint64 : 5;
+ uint64 SCAY0 : 11;
+ uint64 : 5;
+ uint64 SCAY1 : 11;
+ } f;
+ uint64 d;
+} GsScissor;
+
+#define GS_MAKE_SCISSOR(SCAX0,SCAX1,SCAY0,SCAY1) \
+ (BIT64(SCAX0,0) | BIT64(SCAX1,16) | BIT64(SCAY0,32) | BIT64(SCAY1,48))
+
+#define GS_MAKE_TEST(ATE,ATST,AREF,AFAIL,DATE,DATM,ZTE,ZTST) \
+ (BIT64(ATE,0) | BIT64(ATST,1) | BIT64(AREF,4) | BIT64(AFAIL,12) | \
+ BIT64(DATE,14) | BIT64(DATM,15) | BIT64(ZTE,16) | BIT64(ZTST,17))
+
+#define GS_MAKE_PRIM(PRIM,IIP,TME,FGE,ABE,AA1,FST,CTXT,FIX) \
+ (BIT64(PRIM,0) | BIT64(IIP,3) | BIT64(TME,4) | BIT64(FGE,5) | \
+ BIT64(ABE,6) | BIT64(AA1,7) | BIT64(FST,8) | BIT64(CTXT,9) | BIT64(FIX,10))
+
+#define GS_MAKE_RGBAQ(R,G,B,A,Q) \
+ (BIT64(R,0) | BIT64(G,8) | BIT64(B,16) | BIT64(A,24) | BIT64(Q,32))
+
+#define GS_MAKE_XYZ(X,Y,Z) \
+ (BIT64(X,0) | BIT64(Y,16) | BIT64(Z,32))
+
+#define GIF_PACKED 0
+#define GIF_REGLIST 1
+#define GIF_IMAGE 2
+
+#define GIF_MAKE_TAG(NLOOP,EOP,PRE,PRIM,FLG,NREG) \
+ (BIT64(NLOOP,0) | BIT64(EOP,15) | BIT64(PRE,46) | \
+ BIT64(PRIM,47) | BIT64(FLG,58) | BIT64(NREG,60))
+
+/* This is global and not tied to a user context because
+ * it is set up by kernel functions and not really changed
+ * afterwards. */
+typedef struct GsCrtState GsCrtState;
+struct GsCrtState
+{
+ short inter, mode, ff;
+};
+extern GsCrtState gsCrtState;
+
+typedef struct GsDispCtx GsDispCtx;
+struct GsDispCtx
+{
+ // two circuits
+ GsPmode pmode;
+ GsDispfb dispfb1;
+ GsDispfb dispfb2;
+ GsDisplay display1;
+ GsDisplay display2;
+ GsBgcolor bgcolor;
+};
+
+typedef struct GsDrawCtx GsDrawCtx;
+struct GsDrawCtx
+{
+ //two contexts
+ uint128 gifTag;
+ GsFrame frame1;
+ uint64 ad_frame1;
+ GsFrame frame2;
+ uint64 ad_frame2;
+ GsZbuf zbuf1;
+ uint64 ad_zbuf1;
+ GsZbuf zbuf2;
+ uint64 ad_zbuf2;
+ GsXyOffset xyoffset1;
+ uint64 ad_xyoffset1;
+ GsXyOffset xyoffset2;
+ uint64 ad_xyoffset2;
+ GsScissor scissor1;
+ uint64 ad_scissor1;
+ GsScissor scissor2;
+ uint64 ad_scissor2;
+};
+
+typedef struct GsCtx GsCtx;
+struct GsCtx
+{
+ // display context; two buffers
+ GsDispCtx disp[2];
+ // draw context; two buffers
+ GsDrawCtx draw[2];
+};
diff --git a/tools/ps2test/main.cpp b/tools/ps2test/main.cpp
new file mode 100755
index 0000000..6eb0f25
--- /dev/null
+++ b/tools/ps2test/main.cpp
@@ -0,0 +1,788 @@
+#include <cstdio>
+#include <cassert>
+#include <cerrno>
+
+#define PAL
+
+#include <rw.h>
+using rw::uint8;
+using rw::uint16;
+using rw::uint32;
+using rw::uint64;
+using rw::int8;
+using rw::int16;
+using rw::int32;
+using rw::int64;
+using rw::bool32;
+using rw::float32;
+typedef uint8 uchar;
+typedef uint16 ushort;
+typedef uint32 uint;
+
+#define WIDTH 640
+#ifdef PAL
+#define HEIGHT 512
+#define VMODE GS_PAL
+#else
+#define HEIGHT 448
+#define VMODE GS_NTSC
+#endif
+
+#include "ps2.h"
+
+// getting undefined references otherwise :/
+int *__errno() { return &errno; }
+
+// NONINTERLACED and FRAME have half of the FIELD vertical resolution!
+// NONINTERLACED has half the vertical units
+
+uint128 packetbuf[128];
+uint128 vuXYZScale;
+uint128 vuXYZOffset;
+extern uint32 geometryCall[];
+extern uint32 skinPipe[];
+
+uint128 *curVifPtr;
+uint128 lightpacket[128];
+int32 numLightQ;
+
+
+
+rw::World *world;
+rw::Camera *camera;
+
+
+int frames;
+
+void
+printquad(uint128 p)
+{
+ uint64 *lp;
+ lp = (uint64*)&p;
+ printf("%016lx %016lx\n", lp[1], lp[0]);
+}
+
+void
+printquad4(uint128 p)
+{
+ uint32 *lp;
+ lp = (uint32*)&p;
+ printf("%08x %08x %08x %08x\n", lp[0], lp[1], lp[2], lp[3]);
+}
+
+void
+dump4(uint128 *p, int n)
+{
+printf("data at %p\n", p);
+ while(n--)
+ printquad4(*p++);
+}
+
+struct DmaChannel {
+ uint32 chcr; uint32 pad0[3];
+ uint32 madr; uint32 pad1[3];
+ uint32 qwc; uint32 pad2[3];
+ uint32 tadr; uint32 pad3[3];
+ uint32 asr0; uint32 pad4[3];
+ uint32 asr1; uint32 pad5[3];
+ uint32 pad6[8];
+ uint32 sadr;
+};
+
+static struct DmaChannel *dmaChannels[] = {
+ (struct DmaChannel *) &D0_CHCR,
+ (struct DmaChannel *) &D1_CHCR,
+ (struct DmaChannel *) &D2_CHCR,
+ (struct DmaChannel *) &D3_CHCR,
+ (struct DmaChannel *) &D4_CHCR,
+ (struct DmaChannel *) &D5_CHCR,
+ (struct DmaChannel *) &D6_CHCR,
+ (struct DmaChannel *) &D7_CHCR,
+ (struct DmaChannel *) &D8_CHCR,
+ (struct DmaChannel *) &D9_CHCR
+};
+
+void
+dmaReset(void)
+{
+ /* don't clear the SIF channels */
+ int doclear[] = { 1, 1, 1, 1, 1, 0, 0, 0, 1, 1 };
+ int i;
+
+ D_CTRL = 0;
+ for(i = 0; i < 10; i++)
+ if(doclear[i]){
+ dmaChannels[i]->chcr = 0;
+ dmaChannels[i]->madr = 0;
+ dmaChannels[i]->qwc = 0;
+ dmaChannels[i]->tadr = 0;
+ dmaChannels[i]->asr0 = 0;
+ dmaChannels[i]->asr1 = 0;
+ dmaChannels[i]->sadr = 0;
+ }
+ D_CTRL = 1;
+}
+
+void
+waitDMA(volatile uint32 *chcr)
+{
+ while(*chcr & (1<<8));
+}
+
+void
+qwcpy(uint128 *dst, uint128 *src, int n)
+{
+ while(n--) *dst++ = *src++;
+}
+
+void
+toGIF(void *src, int n)
+{
+ FlushCache(0);
+ D2_QWC = n;
+ D2_MADR = (uint32)src;
+ D2_CHCR = 1<<8;
+ waitDMA(&D2_CHCR);
+}
+
+void
+toGIFchain(void *src)
+{
+ FlushCache(0);
+ D2_QWC = 0;
+ D2_TADR = (uint32)src & 0x0FFFFFFF;
+ D2_CHCR = 1<<0 | 1<<2 | 1<<6 | 1<<8;
+ waitDMA(&D2_CHCR);
+}
+
+void
+toVIF1chain(void *src)
+{
+ FlushCache(0);
+ D1_QWC = 0;
+ D1_TADR = (uint32)src & 0x0FFFFFFF;
+ D1_CHCR = 1<<0 | 1<<2 | 1<<6 | 1<<8;
+ waitDMA(&D1_CHCR);
+}
+
+
+GsCrtState gsCrtState;
+
+int psmsizemap[64] = {
+ 4, // GS_PSMCT32
+ 4, // GS_PSMCT24
+ 2, // GS_PSMCT16
+ 0, 0, 0, 0, 0, 0, 0,
+ 2, // GS_PSMCT16S
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, // GS_PSMZ32
+ 4, // GS_PSMZ24
+ 2, // GS_PSMZ16
+ 2, // GS_PSMZ16S
+ 0, 0, 0, 0, 0
+};
+
+void
+GsResetCrt(uchar inter, uchar mode, uchar ff)
+{
+ gsCrtState.inter = inter;
+ gsCrtState.mode = mode;
+ gsCrtState.ff = ff;
+ GS_CSR = 1 << GS_CSR_RESET_O;
+ __asm__("sync.p; nop");
+ GsPutIMR(0xff00);
+ SetGsCrt(gsCrtState.inter, gsCrtState.mode, gsCrtState.ff);
+}
+
+uint gsAllocPtr = 0;
+
+void
+GsInitDispCtx(GsDispCtx *disp, int width, int height, int psm)
+{
+ int magh, magv;
+ int dx, dy;
+ int dw, dh;
+
+ dx = gsCrtState.mode == GS_NTSC ? 636 : 656;
+ dy = gsCrtState.mode == GS_NTSC ? 25 : 36;
+ magh = 2560/width - 1;
+ magv = 0;
+ dw = 2560-1;
+ dh = height-1;
+
+ if(gsCrtState.inter == GS_INTERLACED){
+ dy *= 2;
+ if(gsCrtState.ff == GS_FRAME)
+ dh = (dh+1)*2-1;
+ }
+
+ disp->pmode.d = GS_MAKE_PMODE(0, 1, 1, 1, 0, 0x00);
+// disp->bgcolor.d = 0x404040;
+ disp->bgcolor.d = 0x000000;
+ disp->dispfb1.d = 0;
+ disp->dispfb2.d = GS_MAKE_DISPFB(0, width/64, psm, 0, 0);
+ disp->display1.d = 0;
+ disp->display2.d = GS_MAKE_DISPLAY(dx, dy, magh, magv, dw, dh);
+}
+
+void
+GsPutDispCtx(GsDispCtx *disp)
+{
+ GS_PMODE = disp->pmode.d;
+ GS_DISPFB1 = disp->dispfb1.d;
+ GS_DISPLAY1 = disp->display1.d;
+ GS_DISPFB2 = disp->dispfb2.d;
+ GS_DISPLAY2 = disp->display2.d;
+ GS_BGCOLOR = disp->bgcolor.d;
+}
+
+void
+GsInitDrawCtx(GsDrawCtx *draw, int width, int height, int psm, int zpsm)
+{
+ MAKE128(draw->gifTag, 0xe,
+ GIF_MAKE_TAG(8, 1, 0, 0, GIF_PACKED, 1));
+ draw->frame1.d = GS_MAKE_FRAME(0, width/64, psm, 0);
+ draw->ad_frame1 = GS_FRAME_1;
+ draw->frame2.d = draw->frame1.d;
+ draw->ad_frame2 = GS_FRAME_2;
+ draw->zbuf1.d = GS_MAKE_ZBUF(0, zpsm, 0);
+ draw->ad_zbuf1 = GS_ZBUF_1;
+ draw->zbuf2.d = draw->zbuf1.d;
+ draw->ad_zbuf2 = GS_ZBUF_2;
+ draw->xyoffset1.d = GS_MAKE_XYOFFSET(2048<<4, 2048<<4);
+ draw->ad_xyoffset1 = GS_XYOFFSET_1;
+ draw->xyoffset2.d = draw->xyoffset1.d;
+ draw->ad_xyoffset2 = GS_XYOFFSET_2;
+ draw->scissor1.d = GS_MAKE_SCISSOR(0, width-1, 0, height-1);
+ draw->ad_scissor1 = GS_SCISSOR_1;
+ draw->scissor2.d = draw->scissor1.d;
+ draw->ad_scissor2 = GS_SCISSOR_2;
+}
+
+void
+GsPutDrawCtx(GsDrawCtx *draw)
+{
+// printquad(*(uint128*)&draw->frame1);
+ toGIF(draw, 9);
+}
+
+void
+GsInitCtx(GsCtx *ctx, int width, int height, int psm, int zpsm)
+{
+ uint fbsz, zbsz;
+ uint fbp, zbp;
+ fbsz = (width*height*psmsizemap[psm] + 2047)/2048;
+ zbsz = (width*height*psmsizemap[0x30|zpsm] + 2047)/2048;
+ gsAllocPtr = 2*fbsz + zbsz;
+ fbp = fbsz;
+ zbp = fbsz*2;
+
+ GsInitDispCtx(&ctx->disp[0], width, height, psm);
+ GsInitDispCtx(&ctx->disp[1], width, height, psm);
+ GsInitDrawCtx(&ctx->draw[0], width, height, psm, zpsm);
+ GsInitDrawCtx(&ctx->draw[1], width, height, psm, zpsm);
+ ctx->disp[1].dispfb2.f.FBP = fbp/4;
+ ctx->draw[0].frame1.f.FBP = fbp/4;
+ ctx->draw[0].frame2.f.FBP = fbp/4;
+ ctx->draw[0].zbuf1.f.ZBP = zbp/4;
+ ctx->draw[0].zbuf2.f.ZBP = zbp/4;
+ ctx->draw[1].zbuf1.f.ZBP = zbp/4;
+ ctx->draw[1].zbuf2.f.ZBP = zbp/4;
+}
+
+void
+initrender(void)
+{
+ uint128 *p, tmp;
+ p = packetbuf;
+ MAKE128(tmp, 0xe, GIF_MAKE_TAG(2, 1, 0, 0, GIF_PACKED, 1));
+ *p++ = tmp;
+ MAKE128(tmp, GS_PRMODECONT, 1);
+ *p++ = tmp;
+ MAKE128(tmp, GS_COLCLAMP, 1);
+ *p++ = tmp;
+ toGIF(packetbuf, 3);
+}
+
+void
+clearscreen(int r, int g, int b)
+{
+ int x, y;
+ uint128 *p, tmp;
+ p = packetbuf;
+
+ x = (2048 + WIDTH)<<4;
+ y = (2048 + HEIGHT)<<4;
+
+ MAKE128(tmp, 0xe, GIF_MAKE_TAG(5, 1, 0, 0, GIF_PACKED, 1));
+ *p++ = tmp;
+ MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 1));
+ *p++ = tmp;
+ MAKE128(tmp, GS_PRIM, GS_MAKE_PRIM(GS_PRIM_SPRITE,0,0,0,0,0,0,0,0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(r, g, b, 0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(2048<<4, 2048<<4, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x, y, 0));
+ *p++ = tmp;
+ toGIF(packetbuf, 6);
+}
+
+void
+drawtest(void)
+{
+ int x0, x1, x2, x3;
+ int y0, y1, y2;
+ uint128 *p, tmp;
+ int n;
+
+ x0 = 2048<<4;
+ x1 = (2048 + 210)<<4;
+ x2 = (2048 + 430)<<4;
+ x3 = (2048 + 640)<<4;
+ y0 = 2048<<4;
+ y1 = (2048 + 224)<<4;
+ y2 = (2048 + 448)<<4;
+
+ n = 2 + 3*7;
+ p = packetbuf;
+ MAKEQ(tmp, 0x70000000 | n+1, 0, 0, 0);
+ *p++ = tmp;
+ MAKE128(tmp, 0xe, GIF_MAKE_TAG(n, 1, 0, 0, GIF_PACKED, 1));
+ *p++ = tmp;
+ MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 1));
+ *p++ = tmp;
+ MAKE128(tmp, GS_PRIM, GS_MAKE_PRIM(GS_PRIM_SPRITE,0,0,0,0,0,0,0,0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 0, 0, 0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x0, y0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y1, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 255, 0, 0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y1, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 0, 255, 0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, y1, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 255, 255, 0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x0, y1, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y2, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 0, 255, 0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y1, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y2, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 255, 0, 0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y1, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, y2, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 255, 255, 0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ((2048+20)<<4, y0, 0));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, (2048+20)<<4, 0));
+ *p++ = tmp;
+ toGIFchain(packetbuf);
+}
+
+void
+drawtri(void)
+{
+ uint128 *p, tmp;
+ uint32 *ip;
+ int nverts, n;
+
+ nverts = 3;
+ n = 2*nverts;
+ p = packetbuf;
+ MAKEQ(tmp, 0x70000000 | n+1, 0, 0, 0);
+ *p++ = tmp;
+ MAKE128(tmp, (0x5<<4) | 0x1,
+ GIF_MAKE_TAG(nverts, 1, 1, GS_MAKE_PRIM(GS_PRIM_TRI, 1, 0, 0, 0, 0, 0, 0, 0), GIF_PACKED, 2));
+ *p++ = tmp;
+ MAKEQ(tmp, 255, 0, 0, 0);
+ *p++ = tmp;
+ MAKEQ(tmp, (2048+85)<<4, (2048+70)<<4, 0, 0);
+ *p++ = tmp;
+ MAKEQ(tmp, 0, 255, 0, 0);
+ *p++ = tmp;
+ MAKEQ(tmp, (2048+260)<<4, (2048+200)<<4, 0, 0);
+ *p++ = tmp;
+ MAKEQ(tmp, 0, 0, 255, 0);
+ *p++ = tmp;
+ MAKEQ(tmp, (2048+180)<<4, (2048+350)<<4, 0, 0);
+ *p++ = tmp;
+ toGIFchain(packetbuf);
+}
+
+void
+printMatrix(rw::Matrix *m)
+{
+ rw::V3d *x = &m->right;
+ rw::V3d *y = &m->up;
+ rw::V3d *z = &m->at;
+ rw::V3d *w = &m->pos;
+ printf(
+ "[ [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
+ " [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
+ " [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
+ " [ %8.4f, %8.4f, %8.4f, %8.4f ] ]\n"
+ " %08x == flags\n",
+ x->x, y->x, z->x, w->x,
+ x->y, y->y, z->y, w->y,
+ x->z, y->z, z->z, w->z,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ m->flags);
+}
+
+// This is not proper data, just for testing
+void
+setupLight(rw::Atomic *atomic)
+{
+ using namespace rw;
+ Matrix *lightmat;
+ float32 *lp;
+
+ numLightQ = 0;
+ lp = (float32*)lightpacket;
+
+ // TODO: this is the wrong matrix. we actually want to
+ // transform the light, not all normals.
+ lightmat = atomic->getFrame()->getLTM();
+ *lp++ = lightmat->right.x;
+ *lp++ = lightmat->right.y;
+ *lp++ = lightmat->right.z;
+ *lp++ = 0.0f;
+ *lp++ = lightmat->up.x;
+ *lp++ = lightmat->up.y;
+ *lp++ = lightmat->up.z;
+ *lp++ = 0.0f;
+ *lp++ = lightmat->at.x;
+ *lp++ = lightmat->at.y;
+ *lp++ = lightmat->at.z;
+ *lp++ = 0.0f;
+ *lp++ = lightmat->pos.x;
+ *lp++ = lightmat->pos.y;
+ *lp++ = lightmat->pos.z;
+ *lp++ = 1.0f;
+ // TODO: make a proper light block
+ // ambient
+ *lp++ = 80.0f;
+ *lp++ = 80.0f;
+ *lp++ = 80.0f;
+ *lp++ = 0.0f;
+ // directional
+ *lp++ = 0.5f;
+ *lp++ = -0.5f;
+ *lp++ = -0.7071f;
+ *lp++ = 0.0f;
+ numLightQ = 6;
+}
+
+void
+setupTransform(rw::Atomic *atomic, rw::Matrix *trans)
+{
+ rw::Matrix::mult(trans, atomic->getFrame()->getLTM(), &camera->viewMatrix);
+}
+
+enum {
+ DMAcnt = 0x10000000,
+ DMAref = 0x30000000,
+ DMAcall = 0x50000000,
+ DMAret = 0x60000000,
+ DMAend = 0x70000000,
+
+ V4_32 = 0x6C
+};
+
+#define UNPACK(type, nq, offset) ((type)<<24 | (nq)<<16 | (offset))
+#define STCYCL(WL,CL) (0x01000000 | (WL)<<8 | (CL))
+
+void
+drawAtomic(rw::Atomic *atomic)
+{
+ using namespace rw;
+
+ Matrix trans;
+ Geometry *geo;
+ ps2::ObjPipeline *pipe;
+ ps2::MatPipeline *matpipe;
+ Material *material;
+ uint128 tmp, *lp;
+ uint32 *vec;
+ RGBAf color;
+ int i;
+
+ geo = atomic->geometry;
+ pipe = (ps2::ObjPipeline*)atomic->getPipeline();
+ if(pipe->platform != PLATFORM_PS2)
+ return;
+
+ setupLight(atomic);
+ setupTransform(atomic, &trans);
+
+ curVifPtr = packetbuf;
+ // upload lights
+ MAKEQ(tmp, DMAcnt | numLightQ+8, 0, STCYCL(4,4), UNPACK(V4_32, numLightQ, 0x3d0));
+ *curVifPtr++ = tmp;
+ for(lp = lightpacket; numLightQ--;)
+ *curVifPtr++ = *lp++;
+
+ // upload transformation matrix
+ MAKEQ(tmp, 0, 0, STCYCL(4,4), UNPACK(V4_32, 4, 0x3f0));
+ *curVifPtr++ = tmp;
+ vec = (uint32*)&trans.right;
+ MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]);
+ *curVifPtr++ = tmp;
+ vec = (uint32*)&trans.up;
+ MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]);
+ *curVifPtr++ = tmp;
+ vec = (uint32*)&trans.at;
+ MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]);
+ *curVifPtr++ = tmp;
+ vec = (uint32*)&trans.pos;
+ MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]);
+ *curVifPtr++ = tmp;
+
+ // upload camera/screen info
+ MAKEQ(tmp, 0, 0, STCYCL(4,4), UNPACK(V4_32, 2, 0x3f7));
+ *curVifPtr++ = tmp;
+ *curVifPtr++ = vuXYZScale;
+ *curVifPtr++ = vuXYZOffset;
+
+ assert(geo->instData != NULL);
+ rw::ps2::InstanceDataHeader *instData =
+ (rw::ps2::InstanceDataHeader*)geo->instData;
+ rw::MeshHeader *meshHeader = geo->meshHeader;
+ rw::Mesh *mesh;
+ for(i = 0; i < instData->numMeshes; i++){
+ material = instData->instanceMeshes[i].material;
+ matpipe = pipe->groupPipeline;
+ if(matpipe == nil)
+ matpipe = (ps2::MatPipeline*)material->pipeline;
+ if(matpipe == nil)
+ matpipe = ps2::defaultMatPipe;
+
+ // call vu code
+ MAKEQ(tmp, DMAcall, (uint32)skinPipe, 0, 0);
+ *curVifPtr++ = tmp;
+ // unpack GIF tag, material color, surface properties
+ MAKEQ(tmp, DMAcnt | 3, 0, STCYCL(4,4), UNPACK(V4_32, 3, 0x3fa));
+ *curVifPtr++ = tmp;
+ MAKE128(tmp, 0x412,
+ GIF_MAKE_TAG(0, 1, 1, GS_MAKE_PRIM(GS_PRIM_TRI_STRIP,1,0,0,0,0,0,0,0), GIF_PACKED, 3));
+ *curVifPtr++ = tmp;
+ convColor(&color, &material->color);
+ color.alpha *= 128.0f/255.0f;
+ MAKEQ(tmp, *(uint32*)&color.red, *(uint32*)&color.green,
+ *(uint32*)&color.blue, *(uint32*)&color.alpha);
+ *curVifPtr++ = tmp;
+ MAKEQ(tmp, *(uint32*)&material->surfaceProps.ambient,
+ *(uint32*)&material->surfaceProps.specular,
+ *(uint32*)&material->surfaceProps.diffuse,
+ 0.0f); // extra
+ *curVifPtr++ = tmp;
+ // call geometry
+ MAKEQ(tmp, DMAcall, (uint32)instData->instanceMeshes[i].data, 0x03000000, 0x02000000 | matpipe->vifOffset);
+ *curVifPtr++ = tmp;
+ }
+ MAKEQ(tmp, DMAend, 0, 0, 0);
+ *curVifPtr++ = tmp;
+// for(lp = packetbuf; lp < curVifPtr; lp++)
+// printquad4(*lp);
+ toVIF1chain(packetbuf);
+}
+
+void
+beginCamera(void)
+{
+ uint128 *p, tmp;
+ float32 *f;
+
+ p = packetbuf;
+ MAKE128(tmp, 0xe, GIF_MAKE_TAG(2, 1, 0, 0, GIF_PACKED, 1));
+ *p++ = tmp;
+ MAKE128(tmp, GS_XYOFFSET_1, GS_MAKE_XYOFFSET(2048-WIDTH/2 <<4, 2048-HEIGHT/2 <<4));
+ *p++ = tmp;
+ MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 2));
+ *p++ = tmp;
+ toGIF(packetbuf, 3);
+ f = (float32*)&vuXYZScale;
+ f[0] = WIDTH;
+ f[1] = HEIGHT;
+ f[2] = camera->zScale;
+ f[3] = 0.0f;
+ f = (float32*)&vuXYZOffset;
+ f[0] = 2048.0f;
+ f[1] = 2048.0f;
+ f[2] = camera->zShift;
+ f[3] = 0.0f;
+}
+
+rw::EngineOpenParams engineOpenParams;
+
+void
+pluginattach(void)
+{
+ rw::ps2::registerPDSPlugin(40);
+ rw::ps2::registerPluginPDSPipes();
+
+ rw::registerMeshPlugin();
+ rw::registerNativeDataPlugin();
+ rw::registerAtomicRightsPlugin();
+ rw::registerMaterialRightsPlugin();
+ rw::xbox::registerVertexFormatPlugin();
+ rw::registerSkinPlugin();
+ rw::registerHAnimPlugin();
+ rw::registerMatFXPlugin();
+ rw::registerUVAnimPlugin();
+ rw::ps2::registerADCPlugin();
+}
+
+bool32
+initrw(void)
+{
+ rw::version = 0x34000;
+ rw::platform = rw::PLATFORM_PS2;
+ if(!rw::Engine::init())
+ return 0;
+ pluginattach();
+ if(!rw::Engine::open(&engineOpenParams))
+ return 0;
+ if(!rw::Engine::start())
+ return 0;
+ rw::Texture::setLoadTextures(0);
+
+ rw::TexDictionary::setCurrent(rw::TexDictionary::create());
+ rw::Image::setSearchPath(".");
+
+ world = rw::World::create();
+ camera = rw::Camera::create();
+ camera->frameBuffer = rw::Raster::create(WIDTH, HEIGHT, 0, rw::Raster::CAMERA);
+ camera->zBuffer = rw::Raster::create(WIDTH, HEIGHT, 0, rw::Raster::ZBUFFER);
+ camera->setFrame(rw::Frame::create());
+ rw::V3d t = { 0.0f, 0.0f, -4.0f };
+// rw::V3d t = { 0.0f, 0.0f, -40.0f };
+ camera->getFrame()->translate(&t, rw::COMBINEPOSTCONCAT);
+ rw::V3d axis = { 0.0f, 1.0f, 0.0f };
+ camera->getFrame()->rotate(&axis, 40.0f, rw::COMBINEPOSTCONCAT);
+ camera->setNearPlane(0.1f);
+ camera->setFarPlane(450.0f);
+ camera->setFOV(60.0f, 4.0f/3.0f);
+ world->addCamera(camera);
+ return 1;
+}
+
+int vsynchInt = 0;
+
+int
+vsynch(int id)
+{
+ vsynchInt = 1;
+ frames++;
+ ExitHandler();
+ return 0;
+}
+
+int
+main()
+{
+ FlushCache(0);
+ if(!initrw()){
+ printf("init failed!\n");
+ for(;;);
+ }
+
+ rw::uint32 len;
+ rw::uint8 *data = rw::getFileContents("host:player.DFF", &len);
+// rw::uint8 *data = rw::getFileContents("host:od_newscafe_dy.dff", &len);
+ rw::StreamMemory in;
+ in.open(data, len);
+ rw::findChunk(&in, rw::ID_CLUMP, NULL, NULL);
+ rw::Clump *clump = rw::Clump::streamRead(&in);
+ in.close();
+ rwFree(data);
+
+ GsCtx gsCtx;
+
+ dmaReset();
+
+// GsResetCrt(GS_NONINTERLACED, GS_NTSC, 0);
+// GsInitCtx(&gsCtx, 640, 224, GS_PSMCT32, GS_PSMZ32);
+
+// GsResetCrt(GS_INTERLACED, GS_NTSC, GS_FRAME);
+// GsInitCtx(&gsCtx, 640, 224, GS_PSMCT32, GS_PSMZ32);
+
+ GsResetCrt(GS_INTERLACED, VMODE, GS_FIELD);
+ GsInitCtx(&gsCtx, WIDTH, HEIGHT, GS_PSMCT32, GS_PSMZ32);
+
+ initrender();
+
+ AddIntcHandler(2, vsynch, 0);
+ EnableIntc(2);
+
+ GsPutDrawCtx(&gsCtx.draw[0]);
+ GsPutDispCtx(&gsCtx.disp[1]);
+ // PCSX2 needs a delay for some reason
+ { int i; for(i = 0; i < 1000000; i++); }
+ clearscreen(0x80, 0x80, 0x80);
+// drawtest();
+// drawtri();
+
+ float angle = 40.0f;
+ int drawbuf = 0;
+ int dispbuf = 1;
+ for(;;){
+ clearscreen(0x80, 0x80, 0x80);
+
+ rw::V3d t = { 0.0f, 0.0f, -4.0f };
+ camera->getFrame()->translate(&t, rw::COMBINEREPLACE);
+ rw::V3d axis = { 0.0f, 1.0f, 0.0f };
+ camera->getFrame()->rotate(&axis, angle, rw::COMBINEPOSTCONCAT);
+ angle += 1.0f;
+
+ camera->beginUpdate();
+ beginCamera();
+ FORLIST(lnk, clump->atomics)
+ drawAtomic(rw::Atomic::fromClump(lnk));
+ camera->endUpdate();
+ printf("");
+
+ while(vsynchInt == 0);
+ GsPutDrawCtx(&gsCtx.draw[drawbuf]);
+ GsPutDispCtx(&gsCtx.disp[dispbuf]);
+ drawbuf = !drawbuf;
+ dispbuf = !dispbuf;
+ vsynchInt = 0;
+ }
+/*
+ camera->beginUpdate();
+ beginCamera();
+ FORLIST(lnk, clump->atomics)
+ drawAtomic(rw::Atomic::fromClump(lnk));
+ camera->endUpdate();
+
+ printf("hello %p\n", clump);
+ for(;;)
+ printf("");
+*/
+
+ return 0;
+}
diff --git a/tools/ps2test/mem.h b/tools/ps2test/mem.h
new file mode 100644
index 0000000..088c1d4
--- /dev/null
+++ b/tools/ps2test/mem.h
@@ -0,0 +1,95 @@
+/* FIFOs */
+#define VIF0_FIFO (*(volatile uint128*)0x10004000)
+#define VIF1_FIFO (*(volatile uint128*)0x10005000)
+#define GIF_FIFO (*(volatile uint128*)0x10006000)
+#define IPU_out_FIFO (*(volatile uint128*)0x10007000)
+#define IPU_in_FIFO (*(volatile uint128*)0x10007010)
+
+/* DMA channels */
+// to VIF0
+#define D0_CHCR (*(volatile uint32*)0x10008000)
+#define D0_MADR (*(volatile uint32*)0x10008010)
+#define D0_QWC (*(volatile uint32*)0x10008020)
+#define D0_TADR (*(volatile uint32*)0x10008030)
+#define D0_ASR0 (*(volatile uint32*)0x10008040)
+#define D0_ASR1 (*(volatile uint32*)0x10008050)
+// VIF1
+#define D1_CHCR (*(volatile uint32*)0x10009000)
+#define D1_MADR (*(volatile uint32*)0x10009010)
+#define D1_QWC (*(volatile uint32*)0x10009020)
+#define D1_TADR (*(volatile uint32*)0x10009030)
+#define D1_ASR0 (*(volatile uint32*)0x10009040)
+#define D1_ASR1 (*(volatile uint32*)0x10009050)
+// to GIF
+#define D2_CHCR (*(volatile uint32*)0x1000a000)
+#define D2_MADR (*(volatile uint32*)0x1000a010)
+#define D2_QWC (*(volatile uint32*)0x1000a020)
+#define D2_TADR (*(volatile uint32*)0x1000a030)
+#define D2_ASR0 (*(volatile uint32*)0x1000a040)
+#define D2_ASR1 (*(volatile uint32*)0x1000a050)
+// fromIPU
+#define D3_CHCR (*(volatile uint32*)0x1000b000)
+#define D3_MADR (*(volatile uint32*)0x1000b010)
+#define D3_QWC (*(volatile uint32*)0x1000b020)
+// toIPU
+#define D4_CHCR (*(volatile uint32*)0x1000b400)
+#define D4_MADR (*(volatile uint32*)0x1000b410)
+#define D4_QWC (*(volatile uint32*)0x1000b420)
+#define D4_TADR (*(volatile uint32*)0x1000b430)
+// from SIF0
+#define D5_CHCR (*(volatile uint32*)0x1000c000)
+#define D5_MADR (*(volatile uint32*)0x1000c010)
+#define D5_QWC (*(volatile uint32*)0x1000c020)
+// to SIF1
+#define D6_CHCR (*(volatile uint32*)0x1000c400)
+#define D6_MADR (*(volatile uint32*)0x1000c410)
+#define D6_QWC (*(volatile uint32*)0x1000c420)
+#define D6_TADR (*(volatile uint32*)0x1000c430)
+// SIF2
+#define D7_CHCR (*(volatile uint32*)0x1000c800)
+#define D7_MADR (*(volatile uint32*)0x1000c810)
+#define D7_QWC (*(volatile uint32*)0x1000c820)
+// fromSPR
+#define D8_CHCR (*(volatile uint32*)0x1000d000)
+#define D8_MADR (*(volatile uint32*)0x1000d010)
+#define D8_QWC (*(volatile uint32*)0x1000d020)
+#define D8_SADR (*(volatile uint32*)0x1000d080)
+// toSPR
+#define D9_CHCR (*(volatile uint32*)0x1000d400)
+#define D9_MADR (*(volatile uint32*)0x1000d410)
+#define D9_QWC (*(volatile uint32*)0x1000d420)
+#define D9_TADR (*(volatile uint32*)0x1000d430)
+#define D9_SADR (*(volatile uint32*)0x1000d480)
+
+/* DMA controller */
+#define D_CTRL (*(volatile uint32*)0x1000e000)
+#define D_STAT (*(volatile uint32*)0x1000e010)
+#define D_PCR (*(volatile uint32*)0x1000e020)
+#define D_SQWC (*(volatile uint32*)0x1000e030)
+#define D_RBSR (*(volatile uint32*)0x1000e040)
+#define D_RBOR (*(volatile uint32*)0x1000e050)
+#define D_STADR (*(volatile uint32*)0x1000e060)
+#define D_ENABLER (*(volatile uint32*)0x1000f520)
+#define D_ENABLEW (*(volatile uint32*)0x1000f590)
+
+
+/* GS privileged registers */
+#define GS_PMODE (*(volatile uint64*)0x12000000)
+#define GS_SMODE1 (*(volatile uint64*)0x12000010)
+#define GS_SMODE2 (*(volatile uint64*)0x12000020)
+#define GS_SRFSH (*(volatile uint64*)0x12000030)
+#define GS_SYNCH1 (*(volatile uint64*)0x12000040)
+#define GS_SYNCH2 (*(volatile uint64*)0x12000050)
+#define GS_SYNCV (*(volatile uint64*)0x12000060)
+#define GS_DISPFB1 (*(volatile uint64*)0x12000070)
+#define GS_DISPLAY1 (*(volatile uint64*)0x12000080)
+#define GS_DISPFB2 (*(volatile uint64*)0x12000090)
+#define GS_DISPLAY2 (*(volatile uint64*)0x120000a0)
+#define GS_EXTBUF (*(volatile uint64*)0x120000b0)
+#define GS_EXTDATA (*(volatile uint64*)0x120000c0)
+#define GS_EXTWRITE (*(volatile uint64*)0x120000d0)
+#define GS_BGCOLOR (*(volatile uint64*)0x120000e0)
+#define GS_CSR (*(volatile uint64*)0x12001000)
+#define GS_IMR (*(volatile uint64*)0x12001010)
+#define GS_BUSDIR (*(volatile uint64*)0x12001040)
+#define GS_SIGLBLID (*(volatile uint64*)0x12001080)
diff --git a/tools/ps2test/ps2.h b/tools/ps2test/ps2.h
new file mode 100644
index 0000000..ced015a
--- /dev/null
+++ b/tools/ps2test/ps2.h
@@ -0,0 +1,23 @@
+#include <kernel.h>
+
+typedef int quad __attribute__((mode(TI)));
+typedef int int128 __attribute__((mode(TI)));
+typedef unsigned int uquad __attribute__((mode(TI)));
+typedef unsigned int uint128 __attribute__((mode(TI)));
+
+#define MAKE128(RES,MSB,LSB) \
+ __asm__ ( "pcpyld %0, %1, %2" : "=r" (RES) : "r" ((uint64)MSB), "r" ((uint64)LSB))
+#define UINT64(LOW,HIGH) (((uint64)HIGH)<<32 | ((uint64)LOW))
+#define MAKEQ(RES,W0,W1,W2,W3) MAKE128(RES,UINT64(W2,W3),UINT64(W0,W1))
+
+#define BIT64(v,s) (((uint64)(v)) << (s))
+
+#include "mem.h"
+#include "gs.h"
+
+extern uint128 packetbuf[128];
+
+void waitDMA(volatile uint32 *chcr);
+void toGIF(void *src, int n);
+
+void drawcube(void);
diff --git a/tools/ps2test/vu/defaultpipe.dsm b/tools/ps2test/vu/defaultpipe.dsm
new file mode 100644
index 0000000..ae3fa39
--- /dev/null
+++ b/tools/ps2test/vu/defaultpipe.dsm
@@ -0,0 +1,93 @@
+.global defaultPipe
+
+.equ vertexTop, 0x3d0
+.equ numInAttribs, 4
+.equ numOutAttribs, 3
+.equ numOutBuf, 2
+.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf))
+.equ offset, (vertCount*numInAttribs)
+.equ outBuf1, (2*offset)
+.equ outSize, ((vertexTop-outBuf1-2)/2)
+.equ outBuf2, (outBuf1+outSize)
+
+.equ lightMat, 0x3d0
+.equ ambientLight, 0x3d4
+.equ lightDir, 0x3d5
+
+.equ matrix, 0x3f0
+.equ XYZScale, 0x3f7
+.equ XYZOffset, 0x3f8
+.equ gifTag, 0x3fa
+.equ matColor, 0x3fb
+.equ surfProps, 0x3fc
+
+
+.balign 16,0
+defaultPipe:
+DMAret *
+MPG 0, *
+.vu
+Start:
+#include "setup_persp.vu"
+Cnt:
+ NOP XTOP VI02 ; input pointer
+ NOP LQ VF01, gifTag(VI00)
+ NOP XITOP VI01 ; vertex count
+ NOP IADDIU VI05, VI00, 0x4000
+ NOP IADD VI05, VI05, VI05
+ NOP IOR VI05, VI05, VI01
+ NOP SQ VF01, 0(VI12)
+ NOP ISW.x VI05, 0(VI12)
+ NOP IADDIU VI03, VI12, 1 ; output pointer
+ NOP LQ VF18, lightMat(VI00)
+ NOP LQ VF19, lightMat+1(VI00)
+ NOP LQ VF20, lightMat+2(VI00)
+
+Loop:
+ NOP LQI VF01, (VI02++) ; vertex
+ NOP LQI VF02, (VI02++) ; UV
+ NOP LQI VF03, (VI02++) ; color
+ NOP LQI VF04, (VI02++) ; normal
+
+ MULAw.xyzw ACC, VF31, VF00w NOP ; transform vertex
+ MADDAx.xyw ACC, VF28, VF01x NOP
+ MADDAy.xyw ACC, VF29, VF01y NOP
+ MADDz.xyzw VF01, VF30, VF01z NOP
+ ITOF0 VF03, VF03 NOP
+ ITOF0[I] VF04, VF04 LOI 0.0078125 ; - normal scale
+ NOP NOP
+ NOP DIV Q, VF00w, VF01w
+ NOP WAITQ
+ MULq VF01, VF01, Q NOP ; perspective division
+ MULi VF04, VF04, I NOP ; scale normal
+ NOP MR32.z VF02, VF00
+ NOP NOP
+ SUB.w VF01, VF01, VF01 NOP
+ MULAx.xyz ACC, VF18, VF04x NOP ; transform normal
+ MADDAy.xyz ACC, VF19, VF04y NOP
+ MADDz.xyz VF04, VF20, VF04z NOP
+ ADD.xyz VF01, VF01, VF25 NOP
+ MULq VF02, VF02, Q NOP
+ NOP NOP
+ FTOI0 VF03, VF03 NOP
+ FTOI4 VF01, VF01 NOP
+ NOP SQ VF04, -2(VI02) ; store normal
+ NOP IADDI VI01, VI01, -1
+ NOP SQI VF02, (VI03++) ; STQ
+ NOP SQI VF03, (VI03++) ; color
+ NOP SQI VF01, (VI03++) ; vertex
+ NOP IBNE VI01, VI00, Loop
+ NOP NOP
+
+#include "light.vu"
+
+ NOP XGKICK VI12
+ NOP IADD VI15,VI00,VI12
+ NOP IADD VI12,VI00,VI13
+ NOP[E] IADD VI13,VI00,VI15
+ NOP NOP
+ NOP B Cnt
+ NOP NOP
+
+.EndMPG
+.EndDmaData
diff --git a/tools/ps2test/vu/light.vu b/tools/ps2test/vu/light.vu
new file mode 100644
index 0000000..8f7a31c
--- /dev/null
+++ b/tools/ps2test/vu/light.vu
@@ -0,0 +1,94 @@
+; Ambient light:
+ NOP LQ VF26, ambientLight(VI00)
+ NOP XITOP VI01
+ NOP IADDIU VI03, VI12, 2
+Ambloop:
+ NOP LQ VF03, 0(VI03) ; output color
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ ITOF0 VF03, VF03 NOP
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ ADD.xyz VF03, VF03, VF26 NOP
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ FTOI0 VF03, VF03 NOP
+ NOP IADDI VI01, VI01, -1
+ NOP IADDIU VI03, VI03, numOutAttribs
+ NOP IBNE VI01, VI00, Ambloop
+ NOP SQ VF03, -numOutAttribs(VI03)
+; end amblight
+
+; Direct Light
+ NOP LQ VF26, lightDir(VI00)
+ NOP XITOP VI01
+ NOP XTOP VI02
+ NOP IADDIU VI03, VI12, 2
+ SUB.xyz VF26, VF00, VF26 NOP
+Dirloop:
+ NOP LQ VF01, 3(VI02); ; normal
+ NOP LQ VF02, 0(VI03); ; output color
+ NOP NOP
+ NOP NOP
+ MUL VF03, VF01, VF26 NOP
+ ITOF0 VF02, VF02 NOP
+ NOP NOP
+ NOP NOP
+ ADDy.x VF03, VF03, VF03y NOP
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ ADDz.x VF03, VF03, VF03z NOP
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ MAX.x VF03, VF00, VF03 NOP ; clamp to 0
+ NOP[I] LOI 255
+ NOP NOP
+ NOP NOP
+ MULi.x VF03, VF03, I NOP
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ ADDx.xyz VF02, VF02, VF03x NOP
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ FTOI0 VF02, VF02 NOP
+ NOP IADDI VI01, VI01, -1
+ NOP IADDIU VI02, VI02, numInAttribs
+ NOP IADDIU VI03, VI03, numOutAttribs
+ NOP IBNE VI01, VI00, Dirloop
+ NOP SQ VF02, -numOutAttribs(VI03)
+; end dirlight
+
+; Material color and clamp
+ NOP LQ VF27, matColor(VI00)
+ NOP XITOP VI01
+ NOP IADDIU VI03, VI12, 2
+Colorloop:
+ NOP LQ VF03, 0(VI03)
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ ITOF0 VF03, VF03 NOP
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ MUL VF03, VF03, VF27 NOP
+ NOP[I] LOI 255
+ NOP NOP
+ NOP NOP
+ MINIi VF03, VF03, I NOP
+ NOP NOP
+ NOP NOP
+ NOP NOP
+ FTOI0 VF03, VF03 NOP
+ NOP IADDI VI01, VI01, -1
+ NOP IADDIU VI03, VI03, numOutAttribs
+ NOP IBNE VI01, VI00, Colorloop
+ NOP SQ VF03, -numOutAttribs(VI03)
+; end material color
diff --git a/tools/ps2test/vu/setup_persp.vu b/tools/ps2test/vu/setup_persp.vu
new file mode 100644
index 0000000..b9ea42f
--- /dev/null
+++ b/tools/ps2test/vu/setup_persp.vu
@@ -0,0 +1,39 @@
+/* This is the the projection matrix we start with:
+ * 1/2w 0 ox/2w + 1/2 -ox/2w
+ * 0 -1/2h -oy/2h + 1/2 oy/2h
+ * 0 0 1 0
+ * 0 0 1 0
+ * To get rid of the +1/2 in the combined matrix we
+ * subtract the z-row/2 from the x- and y-rows.
+ *
+ * The z-row is then set to [0 0 0 1] such that multiplication
+ * by XYZscale gives [0 0 0 zScale]. After perspective division
+ * and addition of XYZoffset we then get zScale/w + zShift for z.
+ *
+ * XYZScale scales xy to the resolution and z by zScale.
+ * XYZOffset translates xy to the GS coordinate system (where
+ * [2048, 2048] is the center of the frame buffer) and add zShift to z.
+ */
+
+; constant:
+; VF28-VF31 transformation matrix
+; VF25 XYZ offset
+
+
+ SUB.z VF28, VF28, VF28 LOI 0.5 ; right.z = 0
+ SUB.z VF29, VF29, VF29 LQ VF28, matrix(VI00) ; up.z = 0 - load matrix
+ SUB.z VF30, VF30, VF30 LQ VF29, matrix+1(VI00) ; at.z = 0 - load matrix
+ ADDw.z VF31, VF00, VF00 LQ VF30, matrix+2(VI00) ; at.z = 1 - load matrix
+ NOP LQ VF31, matrix+3(VI00) ; - load matrix
+ MULi.w VF20, VF28, I LQ.xyz VF01, XYZScale(VI00) ; fix matrix - load scale
+ MULi.w VF21, VF29, I NOP ; fix matrix
+ MULi.w VF22, VF30, I NOP ; fix matrix
+ MULi.w VF23, VF31, I NOP ; fix matrix
+ SUBw.xy VF28, VF28, VF20 NOP ; fix matrix
+ SUBw.xy VF29, VF29, VF21 NOP ; fix matrix
+ SUBw.xy VF30, VF30, VF22 NOP ; fix matrix
+ SUBw.xy VF31, VF31, VF23 NOP ; fix matrix
+ MUL.xy VF28, VF28, VF01 LQ.xyz VF25, XYZOffset(VI00) ; scale matrix
+ MUL.xy VF29, VF29, VF01 IADDIU VI12, VI00, outBuf1 ; scale matrix
+ MUL.xy VF30, VF30, VF01 IADDIU VI13, VI00, outBuf2 ; scale matrix
+ MUL.xyz VF31, VF31, VF01 NOP ; scale matrix
diff --git a/tools/ps2test/vu/skinpipe.dsm b/tools/ps2test/vu/skinpipe.dsm
new file mode 100644
index 0000000..18536cd
--- /dev/null
+++ b/tools/ps2test/vu/skinpipe.dsm
@@ -0,0 +1,94 @@
+.global skinPipe
+
+.equ vertexTop, 0x2d0
+.equ numInAttribs, 5
+.equ numOutAttribs, 3
+.equ numOutBuf, 2
+.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf))
+.equ offset, (vertCount*numInAttribs)
+.equ outBuf1, (2*offset)
+.equ outSize, ((vertexTop-outBuf1-2)/2)
+.equ outBuf2, (outBuf1+outSize)
+
+.equ lightMat, 0x3d0
+.equ ambientLight, 0x3d4
+.equ lightDir, 0x3d5
+
+.equ matrix, 0x3f0
+.equ XYZScale, 0x3f7
+.equ XYZOffset, 0x3f8
+.equ gifTag, 0x3fa
+.equ matColor, 0x3fb
+.equ surfProps, 0x3fc
+
+
+.balign 16,0
+skinPipe:
+DMAret *
+MPG 0, *
+.vu
+Start:
+#include "setup_persp.vu"
+Cnt:
+ NOP XTOP VI02 ; input pointer
+ NOP LQ VF01, gifTag(VI00)
+ NOP XITOP VI01 ; vertex count
+ NOP IADDIU VI05, VI00, 0x4000
+ NOP IADD VI05, VI05, VI05
+ NOP IOR VI05, VI05, VI01
+ NOP SQ VF01, 0(VI12)
+ NOP ISW.x VI05, 0(VI12)
+ NOP IADDIU VI03, VI12, 1 ; output pointer
+ NOP LQ VF18, lightMat(VI00)
+ NOP LQ VF19, lightMat+1(VI00)
+ NOP LQ VF20, lightMat+2(VI00)
+
+Loop:
+ NOP LQI VF01, (VI02++) ; vertex
+ NOP LQI VF02, (VI02++) ; UV
+ NOP LQI VF03, (VI02++) ; color
+ NOP LQI VF04, (VI02++) ; normal
+ NOP IADDIU VI02, VI02, 1 ; skip weights
+
+ MULAw.xyzw ACC, VF31, VF00w NOP ; transform vertex
+ MADDAx.xyw ACC, VF28, VF01x NOP
+ MADDAy.xyw ACC, VF29, VF01y NOP
+ MADDz.xyzw VF01, VF30, VF01z NOP
+ ITOF0 VF03, VF03 NOP
+ ITOF0[I] VF04, VF04 LOI 0.0078125 ; - normal scale
+ NOP NOP
+ NOP DIV Q, VF00w, VF01w
+ NOP WAITQ
+ MULq VF01, VF01, Q NOP ; perspective division
+ MULi VF04, VF04, I NOP ; scale normal
+ NOP MR32.z VF02, VF00
+ NOP NOP
+ SUB.w VF01, VF01, VF01 NOP
+ MULAx.xyz ACC, VF18, VF04x NOP ; transform normal
+ MADDAy.xyz ACC, VF19, VF04y NOP
+ MADDz.xyz VF04, VF20, VF04z NOP
+ ADD.xyz VF01, VF01, VF25 NOP
+ MULq VF02, VF02, Q NOP
+ NOP NOP
+ FTOI0 VF03, VF03 NOP
+ FTOI4 VF01, VF01 NOP
+ NOP SQ VF04, -2(VI02) ; store normal
+ NOP IADDI VI01, VI01, -1
+ NOP SQI VF02, (VI03++) ; STQ
+ NOP SQI VF03, (VI03++) ; color
+ NOP SQI VF01, (VI03++) ; vertex
+ NOP IBNE VI01, VI00, Loop
+ NOP NOP
+
+#include "light.vu"
+
+ NOP XGKICK VI12
+ NOP IADD VI15,VI00,VI12
+ NOP IADD VI12,VI00,VI13
+ NOP[E] IADD VI13,VI00,VI15
+ NOP NOP
+ NOP B Cnt
+ NOP NOP
+
+.EndMPG
+.EndDmaData