From a422d1dcda810b2f129a9a5213f3f4b440be4bbc Mon Sep 17 00:00:00 2001
From: pixel <pixel>
Date: Sat, 3 Jan 2004 15:04:46 +0000
Subject: Highly started work on mips disassembler + various little fixes.

---
 lib/Makefile       |    2 +-
 lib/isobuilder.cpp |   11 +-
 lib/luacd.cpp      |   21 +-
 lib/mips.cpp       | 1163 +++++++++++++++++++++++++++++++++++++++-------------
 lib/mipsdis.cpp    |  177 ++++++++
 lib/mipsdump.cpp   |  207 ++++++++++
 lib/mipsmem.cpp    |  349 ++++++++++++++++
 7 files changed, 1634 insertions(+), 296 deletions(-)
 create mode 100644 lib/mipsdis.cpp
 create mode 100644 lib/mipsdump.cpp
 create mode 100644 lib/mipsmem.cpp

(limited to 'lib')

diff --git a/lib/Makefile b/lib/Makefile
index 750b4c1..b3d7399 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -3,7 +3,7 @@
 CPPFLAGS=-Wall -g -O3 -mcpu=i686 -I../includes -DHAVE_ZLIB -DUSE_CDREADER -DDEBUG `baltisot-config --cflags` `lua-config --include`
 CXX=g++
 
-OBJECTS = cdutils.o lzss.o yazedc.o cdreader.o cdabstract.o isobuilder.o luacd.o
+OBJECTS = cdutils.o lzss.o yazedc.o cdreader.o cdabstract.o isobuilder.o luacd.o mips.o mipsmem.o mipsdis.o mipsdump.o
 TARGET = lib.a
 
 all: ${TARGET}
diff --git a/lib/isobuilder.cpp b/lib/isobuilder.cpp
index 7928737..586e6f4 100644
--- a/lib/isobuilder.cpp
+++ b/lib/isobuilder.cpp
@@ -17,7 +17,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-/* $Id: isobuilder.cpp,v 1.10 2003-12-26 19:58:13 pixel Exp $ */
+/* $Id: isobuilder.cpp,v 1.11 2004-01-03 15:04:47 pixel Exp $ */
 
 #include "isobuilder.h"
 
@@ -780,11 +780,14 @@ isobuilder::PVD isobuilder::createpvd(Byte * buffer) {
     return r;
 }
 
-void isobuilder::close(Handle * cue, int mode) throw (GeneralException) {
+void isobuilder::close(Handle * cue, int mode, int nsects) throw (GeneralException) {
     Byte datas[2048];
     Byte * pdatas;
     char * cdatas = (char *) datas;
     int psize;
+    
+    if (nsects < 0)
+	nsects = nsectors;
 
     memset(datas, 0, 2048);
 
@@ -808,8 +811,8 @@ void isobuilder::close(Handle * cue, int mode) throw (GeneralException) {
 
     sprintf(cdatas +   8, "%-32s", pvd.sysid.to_charp());
     sprintf(cdatas +  40, "%-32s", pvd.volid.to_charp());
-    *((Uint32 *) (datas + 80)) = nsectors;
-    *((Uint32 *) (datas + 84)) = cdutils::swap_dword(nsectors);
+    *((Uint32 *) (datas + 80)) = nsects;
+    *((Uint32 *) (datas + 84)) = cdutils::swap_dword(nsects);
 
     datas[120] = 1;
     datas[121] = 0;
diff --git a/lib/luacd.cpp b/lib/luacd.cpp
index 0d8b865..b1d43a0 100644
--- a/lib/luacd.cpp
+++ b/lib/luacd.cpp
@@ -17,7 +17,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-/* $Id: luacd.cpp,v 1.8 2003-12-14 22:04:34 pixel Exp $ */
+/* $Id: luacd.cpp,v 1.9 2004-01-03 15:04:47 pixel Exp $ */
 
 #include "luacd.h"
 
@@ -1038,7 +1038,7 @@ int sLua_PVD::PVD_proceed_statics(Lua * L, int n, int caller) {
     case PVD_NEWPVD:
         r = 1;
         {
-            LuaPVD pvd(new PVD);
+            LuaPVD pvd((PVD *) malloc(sizeof(PVD)));
             pvd.pushdestruct(L);
         }
         break;
@@ -1356,7 +1356,7 @@ struct lua_functypes_t isobuilder_methods[] = {
     { ISOBUILDER_CREATEDIR,         "createdir",         2, 5, {LUA_OBJECT, LUA_STRING, LUA_NUMBER, LUA_OBJECT, LUA_NUMBER} },
     { ISOBUILDER_CREATEFILE,        "createfile",        3, 5, {LUA_OBJECT, LUA_STRING, LUA_OBJECT, LUA_OBJECT, LUA_NUMBER} },
     { ISOBUILDER_COPYDIR,           "copydir",           3, 4, {LUA_OBJECT, LUA_OBJECT, LUA_OBJECT, LUA_NUMBER} },
-    { ISOBUILDER_CLOSE,             "close",             0, 2, {LUA_OBJECT, LUA_NUMBER} },
+    { ISOBUILDER_CLOSE,             "close",             0, 3, {LUA_OBJECT, LUA_NUMBER, LUA_NUMBER} },
     { -1, 0, 0, 0, 0 }
 };
 
@@ -1427,7 +1427,7 @@ void Luaisobuilder::pushstatics(Lua * L) throw (GeneralException) {
 int sLua_isobuilder::isobuilder_proceed(Lua * L, int n, isobuilder * iso, int caller) {
     int r = 0, i;
     Handle * h = 0;
-    int mode = -1, sector = -1, rootsize = 1, ptsize = 1, nvd = 1, rootsect = -1;
+    int mode = -1, sector = -1, rootsize = 1, ptsize = 1, nvd = 1, rootsect = -1, nsects = -1;
     size_t size;
     Byte datas[2352 * 16], * p;
     PVD * pvd;
@@ -1573,7 +1573,9 @@ int sLua_isobuilder::isobuilder_proceed(Lua * L, int n, isobuilder * iso, int ca
             h = (Handle *) LuaObject::getme(L, 2);
         if (n >= 2)
             mode = L->tonumber(3);
-        iso->close(h, mode);
+	if (n >= 3)
+	    nsects = L->tonumber(4);
+        iso->close(h, mode, nsects);
         break;
     }
 
@@ -1601,7 +1603,8 @@ int sLua_isobuilder::isobuilder_proceed_statics(Lua * L, int n, int caller) {
         break;
     case ISOBUILDER_CREATEPVD_HANDLE:
         h = (Handle *) LuaObject::getme(L, 1);
-        pvd = new PVD(isobuilder::createpvd(h));
+	pvd = (PVD *) malloc(sizeof(PVD));
+	*pvd = isobuilder::createpvd(h);
         {
             LuaPVD t(pvd);
             t.pushdestruct(L);
@@ -1610,7 +1613,8 @@ int sLua_isobuilder::isobuilder_proceed_statics(Lua * L, int n, int caller) {
         break;
     case ISOBUILDER_CREATEPVD:
         cd = (cdutils *) LuaObject::getme(L, 1);
-        pvd = new PVD(isobuilder::createpvd(cd));
+	pvd = (PVD *) malloc(sizeof(PVD));
+        *pvd = isobuilder::createpvd(cd);
         {
             LuaPVD t(pvd);
             t.pushdestruct(L);
@@ -1624,7 +1628,8 @@ int sLua_isobuilder::isobuilder_proceed_statics(Lua * L, int n, int caller) {
             datas[i] = L->tonumber();
             L->pop();
         }
-        pvd = new PVD(isobuilder::createpvd(datas));
+	pvd = (PVD *) malloc(sizeof(PVD));
+	*pvd = isobuilder::createpvd(datas);
         {
             LuaPVD t(pvd);
             t.pushdestruct(L);
diff --git a/lib/mips.cpp b/lib/mips.cpp
index da8d863..1378227 100644
--- a/lib/mips.cpp
+++ b/lib/mips.cpp
@@ -1,10 +1,43 @@
+/*
+ *  PSX-Tools Bundle Pack
+ *  Copyright (C) 2002-2003 Nicolas "Pixel" Noble
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id: mips.cpp,v 1.3 2004-01-03 15:04:47 pixel Exp $ */
+
 #include "mips.h"
 
+/* Code HIGHLY ripped off^W^W inspired from PCSX. */
+
+#if 1
+char * registers[] = {
+     "0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+    "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra",
+};
+#else
 char * registers[] = {
-"zr", "at", "v0", "v1", "a0", "a1", "a2", "a3",
-"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
-"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
-"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"};
+    "00", "01", "02", "03", "04", "05", "06", "07",
+    "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
+    "10", "11", "12", "13", "14", "15", "16", "17",
+    "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
+};
+#endif
 
 char * CP0registers[] = {
 	"Index"     , "Random"    , "EntryLo0", "EntryLo1", "Context" , "PageMask"  , "Wired"     , "*Check me*",
@@ -12,397 +45,961 @@ char * CP0registers[] = {
 	"Config"    , "LLAddr"    , "WatchLo" , "WatchHi" , "XContext", "*RES*"     , "*RES*"     , "*RES*"     ,
 	"*RES*"     , "*RES* "    , "PErr"    , "CacheErr", "TagLo"   , "TagHi"     , "ErrorEPC"  , "*RES*"     };
 
-Uint8 mips::Read8(Uint32 mem) {
-    if ((mem < 0x80000000) || (mem >= 0x80200000)) {
-	printm(M_WARNING, "Reading at out of bound of memory: 0x%08x\n", mem);
-	return 0;
-    }
-    
-    mem -= 0x80000000;
+typedef void (*TdisR3000AF)(TDis *, Uint32 code, Uint32 pc);
 
-    if (IsPatched(mem)) {
-	return patches[mem];
-    } else {
-	return plainmemory[mem];
-    }
-}
+// These macros are used to assemble the disassembler functions
+#define MakeDisF(fn, b) \
+	static void fn(TDis * d, Uint32 code, Uint32 pc) { \
+	        d->pc = pc; \
+		b; \
+	}
 
-Uint16 mips::Read16(Uint32 mem) {
-    Uint8 a, b;
-    
-    if (mem & 1) {
-	printm(M_WARNING, "Read16 at a non 16-bits boundary: 0x%08x\n", mem);
-    }
+#define _Funct_  ((code      ) & 0x3F) // The funct part of the instruction register 
+#define _Rd_     ((code >> 11) & 0x1F) // The rd part of the instruction register 
+#define _Rt_     ((code >> 16) & 0x1F) // The rt part of the instruction register 
+#define _Rs_     ((code >> 21) & 0x1F) // The rs part of the instruction register 
+#define _Sa_     ((code >>  6) & 0x1F) // The sa part of the instruction register
+#define _Im_     ( code & 0xFFFF)      // The immediate part of the instruction register
+				       // The signed immediate part of the instruction register
+#define _sIm_    (code & 0x8000 ? - (((~code) & 0x7FFF) + 1) : ( code & 0x7FFF))
 
-    a = Read8(mem);
-    b = Read8(mem + 1);
-    
-    return a | (b << 8);
-}
+#define _Target_  (0x80000000 + ((code & 0x03ffffff) * 4))
+#define _Branch_  (pc + 4 + ((short)_Im_ * 4))
+#define _OfB_     _Im_, _nRs_
 
-Uint32 mips::Read32(Uint32 mem) {
-    Uint8 a, b, c, d;
-    
-    if (mem & 3) {
-	printm(M_WARNING, "Read32 at a non 32-bits boundary: 0x%08x\n", mem);
-    }
-    
-    a = Read8(mem);
-    b = Read8(mem + 1);
-    c = Read8(mem + 2);
-    d = Read8(mem + 3);
-    
-    return a | (b << 8) | (c << 16) | (d << 24);
+#define dName(n)	{ d->Name(n); }
+#define dGPR(i)		{ d->PushGPReg(i); }
+#define dCP0(i)		{ d->PushCPReg(i); }
+#define dImm()		{ d->PushImm(_Im_); }
+#define dTarget()	{ d->PushTarget(_Target_); }
+#define dSa()		{ d->PushSa(_Sa_); }
+#if 0
+#define dOfB()		{ \
+    Uint32 pcode = d->getmem()->Read32(pc - 4); \
+    if ((((pcode >> 16) & 0x1F) == _Rs_) && ((pcode >> 26) == 0xf)) { \
+        Uint32 full; \
+        Uint16 lower; \
+        int16 slower; \
+        lower = _Im_; \
+        slower = *((int16 *) &lower); \
+	\
+        full = ((pcode & 0xffff) << 16) + slower; \
+	\
+	d->PushOfB(_Rs_, full, width); \
+	\
+	dMemRefer(full, width); \
+    } else { \
+	d->PushOfB(_Rs_, _Im_, width); \
+    } \
 }
-
-void mips::Write8(Uint32 mem, Uint8 value) {
-    if ((mem < 0x80000000) || (mem > (0x80200000 - 1))) {
-	printm(M_WARNING, "Reading at out of bound of memory: 0x%08x\n", mem);
-	return;
-    }
-    
-    mem -= 0x80000000;
-    
-    patch(mem, 1);
-    patches[mem] = value;
+#else
+#define dOfB()		{ \
+    d->PushOfB(_Rs_, _Im_, width); \
+}
+#endif
+#define dOffset()	{ \
+    d->PushOffset(_Branch_); \
+}
+//    printf("  ; Maybe RefTo %8.8lX", offset);
+#define dFull(full)	{ \
+    d->PushFull(full); \
+    d->Comment("MaybeRefTo..."); \
 }
 
-void mips::Write16(Uint32 mem, Uint16 value) {
-    if ((mem < 0x80000000) || (mem > (0x80200000 - 2))) {
-	printm(M_WARNING, "Reading at out of bound of memory: 0x%08x\n", mem);
-	return;
-    }
+#define sep
 
-    mem -= 0x80000000;
-    
-    patch(mem, 2);
-    patches[mem] = value & 0xff;
-    patches[mem + 1] = (value >> 8) & 0xff;
+#define dInvalid()	{ \
+    d->SetTag(pc, CODE, false); \
+    d->SetTag(pc, STOP, true); \
+    d->Invalid(); \
 }
 
-void mips::Write32(Uint32 mem, Uint32 value) {
-    if ((mem < 0x80000000) || (mem > (0x80200000 - 4))) {
-	printm(M_WARNING, "Reading at out of bound of memory: 0x%08x\n", mem);
-	return;
-    }
-
-    mem -= 0x80000000;
-    
-    patch(mem, 4);
-    patches[mem] = value & 0xff;
-    patches[mem + 1] = (value >> 8) & 0xff;
-    patches[mem + 2] = (value >> 16) & 0xff;
-    patches[mem + 3] = (value >> 24) & 0xff;
+#define dSuspect()      { \
+    d->Suspect(); \
+    d->Comment("Suspect!"); \
 }
+#if 0 // with OfB...
+//    printf("  ; RefTo %8.8lX - %i bits", offset, width);
+#define dMemRefer(offset, width) { \
+    d->PushMemref(offset, width); \
+    d->Comment("RefTo..."); \
+}
+#endif
 
-void mips::unpatch8(Uint32 mem) {
-    unpatch(mem, 1);
+#define Invalidate(reg) { \
+    if (!reg) \
+	dSuspect(); \
 }
 
-void mips::unpatch16(Uint32 mem) {
-    unpatch(mem, 2);
+#define SetReg(reg, val) { \
+    if (!reg) \
+	dSuspect(); \
 }
 
-void mips::unpatch32(Uint32 mem) {
-    unpatch(mem, 4);
+#define MarkFunction(target) { \
+    d->add_function(target); \
 }
 
-bool mips::IsPatched(Uint32 mem) {
-    int mask, pos;
-    
-    pos = mem / 8;
-    mask = 1 << (mem % 8);
-    
-    return patchesmap[pos] &= mask;
+#define Branch(branch) { \
+    d->add_branch(branch); \
 }
 
-void mips::LoadPSYQ(Handle * h) {
-    h->read(psyqhead, 0x800);
-    memset(plainmemory, 0, 0x200000);
-    paddr = ((psyq*)psyqhead)->t_addr;
-    psize = ((psyq*)psyqhead)->t_size;
+#define Jump(target) { \
+    d->add_jump(target); \
+}
 
-    printm(M_INFO, "Loading %i (%08x) bytes of data at %i (%08x).\n", psize, psize, paddr - 0x80000000, paddr);
-    
-    h->read(plainmemory + paddr - 0x80000000, psize);
+#define Stop(target) { \
+    d->SetTag(target, STOP, true); \
 }
 
-void mips::SavePSYQ(Handle * h) {\
-    Uint32 i;
-    
-    if (!*((Uint32 *)psyqhead))
-	return;
-    h->write(psyqhead, 0x800);
-    paddr = ((psyq*)psyqhead)->t_addr;
-    psize = ((psyq*)psyqhead)->t_size;
+/*********************************************************
+* Arithmetic with immediate operand                      *
+* Format:  OP rt, rs, immediate                          *
+*********************************************************/
 
-    printm(M_INFO, "Writing %i (%08x) bytes of data from %i (%08x).\n", psize, psize, paddr - 0x80000000, paddr);
+MakeDisF(disADDI,
+    dName("addi");
     
-    for (i = paddr - 0x80000000; i < psize; i++) {
-	h->writeU8(Read8(i));
+    dGPR(_Rt_); sep;
+    if (_Rt_ != _Rs_) {
+	dGPR(_Rs_); sep;
     }
-}
+    dImm();
+    
+    Invalidate(_Rt_);
+    
+    d->Comment("Add immediate");
+)
 
-Uint32 mips::GetPC() {
-    return startpc;
-}
+MakeDisF(disADDIU,
+    if (!_Rs_) {
+	dName("li");
+	
+	dGPR(_Rt_); sep;
+	dImm();
+
+	Uint32 full;
+	int32 sfull;
+        Uint16 lower;
+        int16 slower;
+        lower = _Im_;
+        slower = *((int16 *) &lower);
+	
+	sfull = slower;
+	full = *((Uint32 *) &sfull);
+	
+	SetReg(_Rt_, full);
+	
+	d->Comment("Load immediate");
+    } else {
+	Uint32 pcode = d->getmem()->Read32(pc - 4);
+	if ((((pcode >> 16) & 0x1F) == _Rt_) && (_Rt_ == _Rs_) && ((pcode >> 26) == 0xf)) {
+	    Uint32 full;
+	    Uint16 lower;
+	    int16 slower;
+	    lower = _Im_;
+	    slower = *((int16 *) &lower);
+	    
+	    full = ((pcode & 0xffff) << 16) + slower;
+
+	    dName("li");
+	    dGPR(_Rt_); sep;
+	    dFull(full);
+	    SetReg(_Rt_, full);
+	    d->Comment("Load immediate (aggregate)");
+	} else {
+	    dName("addiu");
+    
+	    dGPR(_Rt_); sep;
+	    if (_Rt_ != _Rs_) {
+		dGPR(_Rs_); sep;
+	    }
+	    dImm();
+	    
+	    Invalidate(_Rt_);
+	    
+	    d->Comment("Add immediate");
+	}
+    }
+)
 
-void mips::patch(Uint32 mem, int size) {
-    int mask, pos;
+MakeDisF(disANDI,
+    dName("andi");
+    
+    dGPR(_Rt_); sep;
+    if (_Rt_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dImm();
     
-    pos = mem / 8;
-    mask = 1 << (mem % 8);
+    Invalidate(_Rt_);
     
-    patchesmap[pos] |= mask;
+    d->Comment("And immediate");
+)
+
+MakeDisF(disORI,
+    if (!_Rs_) {
+	dName("liu");
+	
+	dGPR(_Rt_); sep;
+	dImm();
+	SetReg(_Rt_, _Im_);
+	
+	d->Comment("Load immediate without sign extension");
+    } else {
+	dName("ori");
     
-    if (size != 1) {
-	patch(mem + 1, size - 1);
+        dGPR(_Rt_); sep;
+	if (_Rt_ != _Rs_) {
+	    dGPR(_Rs_); sep;
+	}
+	dImm();
+	Invalidate(_Rt_);
+	d->Comment("Or immediate");
     }
-}
+)
 
-void mips::unpatch(Uint32 mem, int size) {
-    int mask, pos;
+MakeDisF(disSLTI,
+    dName("slti");
     
-    pos = mem / 8;
-    mask = ~(1 << (mem % 8));
+    dGPR(_Rt_); sep;
+    if (_Rt_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dImm();
     
-    patchesmap[pos] &= mask;
+    Invalidate(_Rt_);
     
-    if (size != 1) {
-	unpatch(mem + 1, size - 1);
+    d->Comment(registers[_Rt_] + String(" = ") + registers[_Rs_] + " < immediate ? 1 : 0 (signed)");
+)
+
+MakeDisF(disSLTIU,
+    dName("sltiu");
+    
+    dGPR(_Rt_); sep;
+    if (_Rt_ != _Rs_) {
+	dGPR(_Rs_); sep;
     }
-}
+    dImm();
 
-/*  Pcsx - Pc Psx Emulator
- *  Copyright (C) 1999-2003  Pcsx Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
+    Invalidate(_Rt_);
+    
+    d->Comment(registers[_Rt_] + String(" = ") + registers[_Rs_] + " < immediate ? 1 : 0 (unsigned)");
+)
 
+MakeDisF(disXORI,
+    dName("xori");
+    
+    dGPR(_Rt_); sep;
+    if (_Rt_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dImm();
 
+    Invalidate(_Rt_);
+    
+    d->Comment("XOr immediate");
+)
 
-// Type deffinition of our functions
+/*********************************************************
+* Register arithmetic                                    *
+* Format:  OP rd, rs, rt                                 *
+*********************************************************/
+MakeDisF(disADD,
+    dName("add");
 
-typedef void (*TdisR3000AF)(TDis *, Uint32 code, Uint32 pc);
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    
+    Invalidate(_Rt_);
+    
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " + " + registers[_Rt_]);
+)
 
-// These macros are used to assemble the disassembler functions
-#define MakeDisF(fn, b) \
-	static void fn(TDis * d, Uint32 code, Uint32 pc) { \
-		printf ("%8.8lx %8.8lx:", pc, code); \
-		b; \
+MakeDisF(disADDU,
+    if (!_Rt_) {
+	dName("move");
+	
+	dGPR(_Rd_); sep;
+	dGPR(_Rs_);
+	if (_Rs_) {
+	    Invalidate(_Rd_);
+	} else {
+	    SetReg(_Rd_, 0);
 	}
+	d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_]);
+    } else {
+	dName("addu");
+    
+	dGPR(_Rd_); sep;
+	if (_Rd_ != _Rs_) {
+	    dGPR(_Rs_); sep;
+	}
+	dGPR(_Rt_);
+	Invalidate(_Rd_);
+	d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " + " + registers[_Rt_]);
+    }
+)
 
+MakeDisF(disAND,
+    dName("and");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " & " + registers[_Rt_]);
+)
 
-#define _Funct_  ((code      ) & 0x3F) // The funct part of the instruction register 
-#define _Rd_     ((code >> 11) & 0x1F) // The rd part of the instruction register 
-#define _Rt_     ((code >> 16) & 0x1F) // The rt part of the instruction register 
-#define _Rs_     ((code >> 21) & 0x1F) // The rs part of the instruction register 
-#define _Sa_     ((code >>  6) & 0x1F) // The sa part of the instruction register
-#define _Im_     ( code & 0xFFFF)      // The immediate part of the instruction register
+MakeDisF(disNOR,
+    dName("nor");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = ~(" + registers[_Rs_] + " & " + registers[_Rt_] + ")");
+)
 
-#define _Target_  (0x80000000 + ((code & 0x03ffffff) * 4))
-#define _Branch_  (pc + 4 + ((short)_Im_ * 4))
-#define _OfB_     _Im_, _nRs_
+MakeDisF(disOR,
+    dName("or");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " | " + registers[_Rt_]);
+)
 
-#define dName(i)	printf(" %-7s,", i)
-#define dGPR(i)		printf(" (%s),", registers[i])
-#define dCP0(i)		printf(" (%s),", CP0registers[i])
-#define dHI()		printf(" (%s),", "hi")
-#define dLO()		printf(" (%s),", "lo")
-#define dImm()		printf(" %4.4lx (%ld),", _Im_, _Im_)
-#define dTarget()	printf(" %8.8lx,", _Target_)
-#define dSa()		printf(" %2.2lx (%ld),", _Sa_, _Sa_)
-#define dOfB()		printf(" %4.4lx (%s),", _Im_, registers[_Rs_])
-#define dOffset()	printf(" %8.8lx,", _Branch_)
-#define dCode()		printf(" %8.8lx,", (code >> 6) & 0xffffff)
+MakeDisF(disSLT,
+    dName("slt");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    Invalidate(_Rd_);
+    d->Comment(registers[_Rd_] + String(" = ") + registers[_Rs_] + " < " + registers[_Rt_] + " ? 1 : 0 (signed)");
+)
 
-/*********************************************************
-* Arithmetic with immediate operand                      *
-* Format:  OP rt, rs, immediate                          *
-*********************************************************/
-MakeDisF(disADDI,		dName("ADDI");  dGPR(_Rt_); dGPR(_Rs_); dImm();)
-MakeDisF(disADDIU,		dName("ADDIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();)
-MakeDisF(disANDI,		dName("ANDI");  dGPR(_Rt_); dGPR(_Rs_); dImm();)
-MakeDisF(disORI,		dName("ORI");   dGPR(_Rt_); dGPR(_Rs_); dImm();)
-MakeDisF(disSLTI,		dName("SLTI");  dGPR(_Rt_); dGPR(_Rs_); dImm();)
-MakeDisF(disSLTIU,		dName("SLTIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();)
-MakeDisF(disXORI,		dName("XORI");  dGPR(_Rt_); dGPR(_Rs_); dImm();)
+MakeDisF(disSLTU,
+    dName("sltu");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    Invalidate(_Rd_);
+    d->Comment(registers[_Rd_] + String(" = ") + registers[_Rs_] + " < " + registers[_Rt_] + " ? 1 : 0 (unsigned)");
+)
 
-/*********************************************************
-* Register arithmetic                                    *
-* Format:  OP rd, rs, rt                                 *
-*********************************************************/
-MakeDisF(disADD,		dName("ADD");  dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disADDU,		dName("ADDU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disAND,		dName("AND");  dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disNOR,		dName("NOR");  dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disOR,			dName("OR");   dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disSLT,		dName("SLT");  dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disSLTU,		dName("SLTU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disSUB,		dName("SUB");  dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disSUBU,		dName("SUBU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disXOR,		dName("XOR");  dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);)
+MakeDisF(disSUB,
+    dName("sub");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " - " + registers[_Rt_]);
+)
+
+MakeDisF(disSUBU,
+    dName("subu");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " - " + registers[_Rt_]);
+)
+
+MakeDisF(disXOR,
+    dName("xor");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rs_) {
+	dGPR(_Rs_); sep;
+    }
+    dGPR(_Rt_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " ^ " + registers[_Rt_]);
+)
 
 /*********************************************************
 * Register arithmetic & Register trap logic              *
 * Format:  OP rs, rt                                     *
 *********************************************************/
-MakeDisF(disDIV,		dName("DIV");   dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disDIVU,		dName("DIVU");  dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disMULT,		dName("MULT");  dGPR(_Rs_); dGPR(_Rt_);)
-MakeDisF(disMULTU,		dName("MULTU"); dGPR(_Rs_); dGPR(_Rt_);)
+MakeDisF(disDIV,
+    dName("div");
+
+    dGPR(_Rs_); sep;
+    dGPR(_Rt_);
+    
+    String c1 = String(registers[_Rs_]) + " / " + registers[_Rt_];
+    String c2 = String(registers[_Rs_]) + " %% " + registers[_Rt_];
+    
+    d->Comment("lo = " + c1 + "; hi = " + c2);
+)
+
+MakeDisF(disDIVU,
+    dName("divu");
+
+    dGPR(_Rs_); sep;
+    dGPR(_Rt_);
+
+    d->Comment(String("lo = " ) + registers[_Rs_] + " / " + registers[_Rt_] + "; hi = " + registers[_Rs_] + " % " + registers[_Rt_]);
+)
+
+MakeDisF(disMULT,
+    dName("mult");
+    
+    dGPR(_Rs_); sep;
+    dGPR(_Rt_);
+    
+    d->Comment(String("hilo = ") + registers[_Rs_] + " * " + registers[_Rt_]);
+)
+
+MakeDisF(disMULTU,
+    dName("multu");
+    
+    dGPR(_Rs_); sep;
+    dGPR(_Rt_);
+
+    d->Comment(String("hilo = ") + registers[_Rs_] + " * " + registers[_Rt_]);
+)
 
 /*********************************************************
 * Register branch logic                                  *
 * Format:  OP rs, offset                                 *
 *********************************************************/
-MakeDisF(disBGEZ,		dName("BGEZ");   dGPR(_Rs_); dOffset();)
-MakeDisF(disBGEZAL,		dName("BGEZAL"); dGPR(_Rs_); dOffset();)
-MakeDisF(disBGTZ,		dName("BGTZ");   dGPR(_Rs_); dOffset();)
-MakeDisF(disBLEZ,		dName("BLEZ");   dGPR(_Rs_); dOffset();)
-MakeDisF(disBLTZ,		dName("BLTZ");   dGPR(_Rs_); dOffset();)
-MakeDisF(disBLTZAL,		dName("BLTZAL"); dGPR(_Rs_); dOffset();)
+MakeDisF(disBGEZ,
+    dName("bgez");
+    
+    dGPR(_Rs_); sep;
+    dOffset();
+    Branch(_Branch_);
+    d->Comment("Branch if " + String(registers[_Rs_]) + " >= 0");
+)
+
+MakeDisF(disBGEZAL,
+    dName("bgezal");
+    
+    dGPR(_Rs_); sep;
+    dOffset();
+    Branch(_Branch_);
+    d->Comment("Branch and link if " + String(registers[_Rs_]) + " >= 0");
+)
+
+MakeDisF(disBGTZ,
+    dName("bgtz");
+    
+    dGPR(_Rs_); sep;
+    dOffset();
+    Branch(_Branch_);
+    d->Comment("Branch if " + String(registers[_Rs_]) + " > 0");
+)
+
+MakeDisF(disBLEZ,
+    dName("blez");
+    
+    dGPR(_Rs_); sep;
+    dOffset();
+    Branch(_Branch_);
+    d->Comment("Branch if " + String(registers[_Rs_]) + " <= 0");
+)
+
+MakeDisF(disBLTZ,
+    dName("bltz");
+    
+    dGPR(_Rs_); sep;
+    dOffset();
+    Branch(_Branch_);
+    d->Comment("Branch if " + String(registers[_Rs_]) + " < 0");
+)
+
+MakeDisF(disBLTZAL,
+    dName("bltzal");
+    
+    dGPR(_Rs_); sep;
+    dOffset();
+    Branch(_Branch_);
+    d->Comment("Branch and link if " + String(registers[_Rs_]) + " <= 0");
+)
 
 /*********************************************************
 * Shift arithmetic with constant shift                   *
 * Format:  OP rd, rt, sa                                 *
 *********************************************************/
-MakeDisF(disSLL,		if (code) { dName("SLL"); dGPR(_Rd_); dGPR(_Rt_); dSa(); } else { dName("NOP"); })
-MakeDisF(disSRA,		dName("SRA"); dGPR(_Rd_); dGPR(_Rt_); dSa();)
-MakeDisF(disSRL,		dName("SRL"); dGPR(_Rd_); dGPR(_Rt_); dSa();)
+MakeDisF(disSLL,
+    if ((!_Rd_) && (!_Rt_)) {
+	dName("nop");
+	if (code) {
+	    dSuspect();
+	}
+    } else {
+	dName("sll");
+	
+	dGPR(_Rd_); sep;
+	if (_Rd_ != _Rt_) {
+	    dGPR(_Rt_); sep;
+	}
+	dSa();
+	Invalidate(_Rd_);
+	d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " << immediate");
+    }
+)
+
+MakeDisF(disSRA,
+    dName("sra");
+
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rt_) {
+        dGPR(_Rt_); sep;
+    }
+    dSa();
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " >> immediate (arithmetic)");
+)
+
+MakeDisF(disSRL,
+    dName("srl");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rt_) {
+        dGPR(_Rt_); sep;
+    }
+    dSa();
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " >> immediate (logical)");
+)
 
 /*********************************************************
 * Shift arithmetic with variant register shift           *
 * Format:  OP rd, rt, rs                                 *
 *********************************************************/
-MakeDisF(disSLLV,		dName("SLLV");  dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);)
-MakeDisF(disSRAV,		dName("SRAV");  dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);)
-MakeDisF(disSRLV,		dName("SRLV");  dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);)
+MakeDisF(disSLLV,
+    dName("sllv");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rt_) {
+        dGPR(_Rt_); sep;
+    }
+    dGPR(_Rs_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " << " + registers[_Rs_]);
+)
+
+MakeDisF(disSRAV,
+    dName("srav");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rt_) {
+        dGPR(_Rt_); sep;
+    }
+    dGPR(_Rs_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " >> " + registers[_Rs_] + " (arithmetic)");
+)
+
+MakeDisF(disSRLV,
+    dName("srlv");
+    
+    dGPR(_Rd_); sep;
+    if (_Rd_ != _Rt_) {
+        dGPR(_Rt_); sep;
+    }
+    dGPR(_Rs_);
+    Invalidate(_Rd_);
+    d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " >> " + registers[_Rs_] + " (logical)");
+)
 
 /*********************************************************
 * Load higher 16 bits of the first word in GPR with imm  *
 * Format:  OP rt, immediate                              *
 *********************************************************/
-MakeDisF(disLUI,		dName("LUI"); dGPR(_Rt_); dImm();)
+MakeDisF(disLUI,
+    dName("lui");
+    
+    dGPR(_Rt_); sep;
+    dImm();
+    
+    Invalidate(_Rt_);
+    
+    d->Comment("Load upper immediate");
+)
 
 /*********************************************************
 * Move from HI/LO to GPR                                 *
 * Format:  OP rd                                         *
 *********************************************************/
-MakeDisF(disMFHI,		dName("MFHI"); dGPR(_Rd_); dHI();)
-MakeDisF(disMFLO,		dName("MFLO"); dGPR(_Rd_); dLO();)
+MakeDisF(disMFHI,
+    dName("mfhi");
+
+    dGPR(_Rd_);
+    Invalidate(_Rd_);
+    
+    d->Comment(String(registers[_Rd_]) + " = hi");
+)
+
+MakeDisF(disMFLO,
+    dName("mflo");
+
+    dGPR(_Rd_);
+    Invalidate(_Rd_);
+
+    d->Comment(String(registers[_Rd_]) + " = lo");
+)
 
 /*********************************************************
 * Move from GPR to HI/LO                                 *
 * Format:  OP rd                                         *
 *********************************************************/
-MakeDisF(disMTHI,		dName("MTHI"); dHI(); dGPR(_Rs_);)
-MakeDisF(disMTLO,		dName("MTLO"); dLO(); dGPR(_Rs_);)
+MakeDisF(disMTHI,
+    dName("mthi");
+    
+    dGPR(_Rd_);
+
+    d->Comment("hi = " + String(registers[_Rd_]));
+)
+
+MakeDisF(disMTLO,
+    dName("mtlo");
+    
+    dGPR(_Rd_);
+
+    d->Comment("lo = " + String(registers[_Rd_]));
+)
 
 /*********************************************************
 * Special purpose instructions                           *
 * Format:  OP                                            *
 *********************************************************/
-MakeDisF(disBREAK,		dName("BREAK"))
-MakeDisF(disRFE,		dName("RFE"))
-MakeDisF(disSYSCALL,		dName("SYSCALL"))
-MakeDisF(disHLE,		dName("HLE"))
-
-
-MakeDisF(disRTPS,		dName("RTPS"))
-MakeDisF(disOP  ,		dName("OP"))
-MakeDisF(disNCLIP,		dName("NCLIP"))
-MakeDisF(disDPCS,		dName("DPCS"))
-MakeDisF(disINTPL,		dName("INTPL"))
-MakeDisF(disMVMVA,		dName("MVMVA"))
-MakeDisF(disNCDS ,		dName("NCDS"))
-MakeDisF(disCDP ,		dName("CDP"))
-MakeDisF(disNCDT ,		dName("NCDT"))
-MakeDisF(disNCCS ,		dName("NCCS"))
-MakeDisF(disCC  ,		dName("CC"))
-MakeDisF(disNCS ,		dName("NCS"))
-MakeDisF(disNCT  ,		dName("NCT"))
-MakeDisF(disSQR  ,		dName("SQR"))
-MakeDisF(disDCPL ,		dName("DCPL"))
-MakeDisF(disDPCT ,		dName("DPCT"))
-MakeDisF(disAVSZ3,		dName("AVSZ3"))
-MakeDisF(disAVSZ4,		dName("AVSZ4"))
-MakeDisF(disRTPT ,		dName("RTPT"))
-MakeDisF(disGPF  ,		dName("GPF"))
-MakeDisF(disGPL  ,		dName("GPL"))
-MakeDisF(disNCCT ,		dName("NCCT"))
-
-MakeDisF(disMFC2,		dName("MFC2"); dGPR(_Rt_);)
-MakeDisF(disCFC2,		dName("CFC2"); dGPR(_Rt_);)
-MakeDisF(disMTC2,		dName("MTC2"); dGPR(_Rt_);)
-MakeDisF(disCTC2,		dName("CTC2"); dGPR(_Rt_);)
+MakeDisF(disBREAK,
+    dName("break");
+    
+    Stop(pc + 4);
+    
+    d->Comment("Stops the machine");
+)
+MakeDisF(disRFE,		dName("rfe"))
+
+MakeDisF(disSYSCALL,
+    int syscall;
+    dName("syscall");
+    syscall = code & 0xfffff;
+    
+    d->Comment(String("Syscall number ") + syscall);
+)
+
+MakeDisF(disHLE,		dName("hle"))
+
+MakeDisF(disRTPS,		dName("rtps"))
+MakeDisF(disOP  ,		dName("op"))
+MakeDisF(disNCLIP,		dName("nclip"))
+MakeDisF(disDPCS,		dName("dpcs"))
+MakeDisF(disINTPL,		dName("intpl"))
+MakeDisF(disMVMVA,		dName("mvmva"))
+MakeDisF(disNCDS ,		dName("ncds"))
+MakeDisF(disCDP ,		dName("cdp"))
+MakeDisF(disNCDT ,		dName("ncdt"))
+MakeDisF(disNCCS ,		dName("nccs"))
+MakeDisF(disCC  ,		dName("cc"))
+MakeDisF(disNCS ,		dName("ncs"))
+MakeDisF(disNCT  ,		dName("nct"))
+MakeDisF(disSQR  ,		dName("sqr"))
+MakeDisF(disDCPL ,		dName("dcpl"))
+MakeDisF(disDPCT ,		dName("dpct"))
+MakeDisF(disAVSZ3,		dName("avsz3"))
+MakeDisF(disAVSZ4,		dName("avsz4"))
+MakeDisF(disRTPT ,		dName("rtpt"))
+MakeDisF(disGPF  ,		dName("gpf"))
+MakeDisF(disGPL  ,		dName("gpl"))
+MakeDisF(disNCCT ,		dName("ncct"))
+
+MakeDisF(disMFC2,		dName("mfc2"); dGPR(_Rt_); Invalidate(_Rt_); )
+MakeDisF(disCFC2,		dName("cfc2"); dGPR(_Rt_); Invalidate(_Rt_); )
+MakeDisF(disMTC2,		dName("mtc2"); dGPR(_Rt_);)
+MakeDisF(disCTC2,		dName("ctc2"); dGPR(_Rt_);)
 
 /*********************************************************
 * Register branch logic                                  *
 * Format:  OP rs, rt, offset                             *
 *********************************************************/
-MakeDisF(disBEQ,		dName("BEQ"); dGPR(_Rs_); dGPR(_Rt_); dOffset();)
-MakeDisF(disBNE,		dName("BNE"); dGPR(_Rs_); dGPR(_Rt_); dOffset();)
+MakeDisF(disBEQ,
+    if ((!_Rt_) && (!_Rs_)) {
+	dName("b");
+	
+	dOffset();
+	Branch(_Branch_);
+	Stop(pc + 8);
+	
+	d->Comment("Branch always");
+    }
+    if (!_Rt_) {
+	dName("bez");
+    
+	dGPR(_Rs_); sep;
+	dOffset();
+	Branch(_Branch_);
+	
+	d->Comment(String("Branch if ") + registers[_Rs_] + " == 0");
+    } else {
+	dName("beq");
+    
+	dGPR(_Rs_); sep;
+	dGPR(_Rt_); sep;
+	dOffset();
+	Branch(_Branch_);
+
+	d->Comment(String("Branch if ") + registers[_Rs_] + " == " + registers[_Rt_]);
+    }
+)
+
+MakeDisF(disBNE,
+    if (!_Rt_) {
+	dName("bnz");
+    
+	dGPR(_Rs_); sep;
+	dOffset();
+	Branch(_Branch_);
+
+	d->Comment(String("Branch if ") + registers[_Rs_] + " != 0");
+    } else {
+        dName("bne");
+    
+        dGPR(_Rs_); sep;
+        dGPR(_Rt_); sep;
+        dOffset();
+	Branch(_Branch_);
+
+	d->Comment(String("Branch if ") + registers[_Rs_] + " != " + registers[_Rt_]);
+    }
+)
 
 /*********************************************************
 * Jump to target                                         *
 * Format:  OP target                                     *
 *********************************************************/
-MakeDisF(disJ,			dName("J");   dTarget();)
-MakeDisF(disJAL,		dName("JAL"); dTarget();)
+MakeDisF(disJ,
+    dName("j");
+    
+    dTarget();
+    Jump(_Target_);
+    Stop(pc + 8);
+
+    d->Comment("Jump always");
+)
+
+MakeDisF(disJAL,
+    dName("jal");
+
+    dTarget();
+    Invalidate(Rra);
+    MarkFunction(_Target_);
+
+    d->Comment("Jump and link (function call)");
+)
 
 /*********************************************************
 * Register jump                                          *
 * Format:  OP rs, rd                                     *
 *********************************************************/
-MakeDisF(disJR,			dName("JR");   dGPR(_Rs_);)
-MakeDisF(disJALR,		dName("JALR"); dGPR(_Rs_); dGPR(_Rd_))
+MakeDisF(disJR,
+    dName("jr");
+    dGPR(_Rs_);
+    Stop(pc + 8);
+
+    d->Comment("Jump register");
+)
+
+MakeDisF(disJALR,
+    dName("jalr");
+    
+    dGPR(_Rs_);
+    
+    if ((_Rd_) != Rra) {
+	sep; dGPR(_Rd_);
+    }
+    
+    Invalidate(_Rd_);
+
+    d->Comment("Jump and link register (function call)");
+)
 
 /*********************************************************
 * Load and store for GPR                                 *
 * Format:  OP rt, offset(base)                           *
 *********************************************************/
-MakeDisF(disLB,			dName("LB");    dGPR(_Rt_);  dOfB();)
-MakeDisF(disLBU,		dName("LBU");   dGPR(_Rt_);  dOfB();)
-MakeDisF(disLH,			dName("LH");    dGPR(_Rt_);  dOfB();)
-MakeDisF(disLHU,		dName("LHU");   dGPR(_Rt_);  dOfB();)
-MakeDisF(disLW,			dName("LW");    dGPR(_Rt_);  dOfB();)
-MakeDisF(disLWL,		dName("LWL");   dGPR(_Rt_);  dOfB();)
-MakeDisF(disLWR,		dName("LWR");   dGPR(_Rt_);  dOfB();)
-MakeDisF(disLWC2,		dName("LWC2");  dGPR(_Rt_);  dOfB();)
-MakeDisF(disSB,			dName("SB");    dGPR(_Rt_);  dOfB();)
-MakeDisF(disSH,			dName("SH");    dGPR(_Rt_);  dOfB();)
-MakeDisF(disSW,			dName("SW");    dGPR(_Rt_);  dOfB();)
-MakeDisF(disSWL,		dName("SWL");   dGPR(_Rt_);  dOfB();)
-MakeDisF(disSWR,		dName("SWR");   dGPR(_Rt_);  dOfB();)
-MakeDisF(disSWC2,		dName("SWC2");  dGPR(_Rt_);  dOfB();)
+MakeDisF(disLB,
+    int width = 8;
+    dName("lb");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    
+    Invalidate(_Rt_);
+    d->Comment("Load signed byte");
+)
+
+MakeDisF(disLBU,
+    int width = 8;
+    dName("lbu");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+
+    Invalidate(_Rt_);
+    d->Comment("Load unsigned byte");
+)
+
+MakeDisF(disLH,
+    int width = 16;
+    dName("lh");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+
+    Invalidate(_Rt_);
+    d->Comment("Load signed half");
+)
+
+MakeDisF(disLHU,
+    int width = 16;
+    dName("lhu");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    
+    Invalidate(_Rt_);
+    d->Comment("Load unsigned half");
+)
+
+MakeDisF(disLW,
+    int width = 32;
+    dName("lw");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    
+    Invalidate(_Rt_);
+    d->Comment("Load word");
+)
+
+MakeDisF(disLWL,
+    int width = 32;
+    dName("lwl");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    
+    Invalidate(_Rt_);
+    d->Comment("Load word left");
+)
+
+MakeDisF(disLWR,
+    int width = 32;
+    dName("lwr");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    
+    Invalidate(_Rt_);
+    d->Comment("Load word right");
+)
+
+MakeDisF(disLWC2,
+    int width = 32;
+    dName("lwc2");
+    
+    dCP0(_Rt_); sep;
+    dOfB();
+)
+
+MakeDisF(disSB,
+    int width = 8;
+    dName("sb");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    d->Comment("Store byte");
+)
+
+MakeDisF(disSH,
+    int width = 16;
+    dName("sh");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    d->Comment("Store half");
+)
+
+MakeDisF(disSW,
+    int width = 32;
+    dName("sw");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    d->Comment("Store word");
+)
+
+MakeDisF(disSWL,
+    int width = 32;
+    dName("swl");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    d->Comment("Store word left");
+)
+
+MakeDisF(disSWR,
+    int width = 32;
+    dName("swr");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+    d->Comment("Store word right");
+)
+
+MakeDisF(disSWC2,
+    int width = 32;
+    dName("swc2");
+    
+    dGPR(_Rt_); sep;
+    dOfB();
+)
 
 /*********************************************************
 * Moves between GPR and COPx                             *
 * Format:  OP rt, fs                                     *
 *********************************************************/
-MakeDisF(disMFC0,		dName("MFC0"); dGPR(_Rt_); dCP0(_Rd_);)
-MakeDisF(disMTC0,		dName("MTC0"); dCP0(_Rd_); dGPR(_Rt_);)
-MakeDisF(disCFC0,		dName("CFC0"); dGPR(_Rt_); dCP0(_Rd_);)
-MakeDisF(disCTC0,		dName("CTC0"); dCP0(_Rd_); dGPR(_Rt_);)
+MakeDisF(disMFC0,		dName("mfc0"); dGPR(_Rt_); sep; dCP0(_Rd_); Invalidate(_Rt_);)
+MakeDisF(disMTC0,		dName("mtc0"); dCP0(_Rd_); sep; dGPR(_Rt_);)
+MakeDisF(disCFC0,		dName("cfc0"); dGPR(_Rt_); sep; dCP0(_Rd_); Invalidate(_Rt_);)
+MakeDisF(disCTC0,		dName("ctc0"); dCP0(_Rd_); sep; dGPR(_Rt_);)
 
 /*********************************************************
 * Unknow instruction (would generate an exception)       *
 * Format:  ?                                             *
 *********************************************************/
-MakeDisF(disNULL,		dName("*** Bad OP ***");)
+MakeDisF(disNULL,
+    dName("*** Bad OP ***");
+    dInvalid();
+)
 
 
 TdisR3000AF disR3000A_SPECIAL[] = { // Subset of disSPECIAL
@@ -415,7 +1012,7 @@ TdisR3000AF disR3000A_SPECIAL[] = { // Subset of disSPECIAL
 	disNULL, disNULL , disNULL, disNULL, disNULL   , disNULL  , disNULL   , disNULL ,
 	disNULL, disNULL , disNULL, disNULL, disNULL   , disNULL  , disNULL  , disNULL};
 
-MakeDisF(disSPECIAL,	disR3000A_SPECIAL[_Funct_](code, pc))
+MakeDisF(disSPECIAL,	disR3000A_SPECIAL[_Funct_](d, code, pc))
 
 TdisR3000AF disR3000A_BCOND[] = { // Subset of disBCOND
 	disBLTZ  , disBGEZ  , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL,
@@ -423,7 +1020,7 @@ TdisR3000AF disR3000A_BCOND[] = { // Subset of disBCOND
 	disBLTZAL, disBGEZAL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL,
 	disNULL  , disNULL  , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL};
 
-MakeDisF(disBCOND,	disR3000A_BCOND[_Rt_](code, pc))
+MakeDisF(disBCOND,	disR3000A_BCOND[_Rt_](d, code, pc))
 
 TdisR3000AF disR3000A_COP0[] = { // Subset of disCOP0
 	disMFC0, disNULL, disCFC0, disNULL, disMTC0, disNULL, disCTC0, disNULL,
@@ -431,7 +1028,7 @@ TdisR3000AF disR3000A_COP0[] = { // Subset of disCOP0
 	disRFE , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL,
 	disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL};
 
-MakeDisF(disCOP0,		disR3000A_COP0[_Rs_](code, pc))
+MakeDisF(disCOP0,		disR3000A_COP0[_Rs_](d, code, pc))
 
 TdisR3000AF disR3000A_BASIC[] = { // Subset of disBASIC (based on rs)
 	disMFC2, disNULL, disCFC2, disNULL, disMTC2, disNULL, disCTC2, disNULL,
@@ -439,7 +1036,7 @@ TdisR3000AF disR3000A_BASIC[] = { // Subset of disBASIC (based on rs)
 	disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL,
 	disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL};
 
-MakeDisF(disBASIC,		disR3000A_BASIC[_Rs_](code, pc))
+MakeDisF(disBASIC,		disR3000A_BASIC[_Rs_](d, code, pc))
 
 TdisR3000AF disR3000A_COP2[] = { // Subset of disR3000F_COP2 (based on funct)
 	disBASIC, disRTPS , disNULL , disNULL , disNULL, disNULL , disNCLIP, disNULL,
@@ -451,7 +1048,7 @@ TdisR3000AF disR3000A_COP2[] = { // Subset of disR3000F_COP2 (based on funct)
 	disRTPT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL,
 	disNULL , disNULL , disNULL , disNULL , disNULL, disGPF  , disGPL  , disNCCT   };
 
-MakeDisF(disCOP2,		disR3000A_COP2[_Funct_](code, pc))
+MakeDisF(disCOP2,		disR3000A_COP2[_Funct_](d, code, pc))
 
 TdisR3000AF disR3000A[] = {
 	disSPECIAL    , disBCOND     , disJ       , disJAL  , disBEQ , disBNE , disBLEZ , disBGTZ ,
@@ -465,7 +1062,7 @@ TdisR3000AF disR3000A[] = {
 
 //MakeDisFg(disR3000AF,	disR3000A[code >> 26](code, pc))
 
-	
-void mips::disassemble(Uint32 mem) {
-    disR3000A[code >> 26](Read32(mem), mem);
+void decode(TDis * d, Uint32 pc) {
+    Uint32 code = d->getmem()->Read32(pc);
+    disR3000A[code >> 26](d, code, pc);
 }
diff --git a/lib/mipsdis.cpp b/lib/mipsdis.cpp
new file mode 100644
index 0000000..a1b2a68
--- /dev/null
+++ b/lib/mipsdis.cpp
@@ -0,0 +1,177 @@
+/*
+ *  PSX-Tools Bundle Pack
+ *  Copyright (C) 2002-2003 Nicolas "Pixel" Noble
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id: mipsdis.cpp,v 1.1 2004-01-03 15:04:47 pixel Exp $ */
+
+#include "mipsdis.h"
+#include "mips.h"
+
+TDis::TDis(mipsmem * _m) : mm(_m) {
+    reset();
+}
+
+void TDis::reset() {
+    invalid = false;
+}
+
+mipsmem * TDis::getmem() {
+    return mm;
+}
+
+void TDis::add_branch(Uint32 target) {
+    bheap.push(target);
+}
+
+void TDis::add_jump(Uint32 target) {
+    jheap.push(target);
+}
+
+void TDis::add_function(Uint32 target) {
+    fheap.push(target);
+}
+
+void TDis::SetTag(Uint32 target, int tag, bool v) {
+    mm->SetTag(target, tag, v);
+}
+
+void TDis::Name(const String & name) {
+}
+
+void TDis::PushGPReg(int reg) {
+}
+
+void TDis::PushCPReg(int reg) {
+}
+
+void TDis::PushImm(Uint32 imm) {
+}
+
+void TDis::PushTarget(Uint32 target) {
+    new refto_t(target, memdata::getmem(pc, getmem()));
+}
+
+void TDis::PushSa(Uint32 sa) {
+}
+
+void TDis::PushOfB(int reg, Uint32 offset, int width) {
+}
+
+void TDis::PushOffset(Uint32 offset) {
+    new refto_t(offset, memdata::getmem(pc, getmem()));
+}
+
+void TDis::PushFull(Uint32 full) {
+    if ((full >= 0x80000000) && (full < (0x80000000 + PSXMEM)))
+	new refto_t(full, memdata::getmem(pc, getmem()));
+}
+
+void TDis::Invalid() {
+    invalid = true;
+}
+
+void TDis::Suspect() {
+}
+
+void TDis::Comment(const String & c) {
+}
+
+Disassembler::Disassembler(mipsmem * _mm) : mm(_mm), dis(new TDis(mm)), started(false), infunction(false) {
+}
+
+Disassembler::~Disassembler() {
+    delete dis;
+}
+
+void Disassembler::crawl_code(Uint32 pc) {
+    Uint32 branched, ipc;
+    
+    if (pc == 0xffffffff) {
+	pc = mm->GetPC();
+    }
+    
+    dis->bheap.push(pc);
+    
+    while (dis->bheap.size()) {
+	branched = pc = dis->bheap.top();
+	dis->bheap.pop();
+	do {
+	    if (pc >= (0x80000000 + PSXMEM)) {
+		dis->invalid = true;
+		break;
+	    }
+	    if (mm->GetTag(pc, CODE) || mm->GetTag(pc, INVALID)) {
+		pc += 4;
+		continue;
+	    }
+	    mm->SetTag(pc, CODE, true);
+	    
+	    printm(M_STATUS, "%8.8lX\r", pc);
+	    decode(dis, pc);
+	    
+	    pc += 4;
+	    dis->reset();
+	} while (!mm->GetTag(pc, STOP) && !dis->invalid);
+	
+	if (dis->invalid) {
+	    for (ipc = branched; ipc <= pc; ipc += 4) {
+		mm->SetTag(ipc, CODE, false);
+		mm->SetTag(ipc, INVALID, true);
+	    }
+	}
+	
+	if (dis->invalid && infunction) {
+	}
+    }
+}
+
+void Disassembler::mainloop(void) {
+    Uint32 pc;
+    
+    infunction = false;
+
+    // Crawl the start part.
+    if (!started)
+	crawl_code();
+    
+    started = true;
+    
+    // Work out all the functions.
+    printm(M_STATUS, "Crawling all detected functions\n");
+    infunction = true;
+    while (dis->fheap.size()) {
+	pc = dis->fheap.top();
+	dis->fheap.pop();
+	if (mm->GetTag(pc, CODE))
+	    continue;
+	crawl_code(pc);
+    }
+
+    // Complete functions and all the detected jumps.
+    printm(M_STATUS, "Fixing all the remaining jumps\n");
+#if 0
+    infunction = false;
+    while (dis->jheap.size()) {
+	pc = dis->jheap.top();
+	dis->jheap.pop();
+	if (mm->GetTag(pc, CODE))
+	    continue;
+	crawl_code(pc);
+    }
+#endif
+}
diff --git a/lib/mipsdump.cpp b/lib/mipsdump.cpp
new file mode 100644
index 0000000..ac77b33
--- /dev/null
+++ b/lib/mipsdump.cpp
@@ -0,0 +1,207 @@
+/*
+ *  PSX-Tools Bundle Pack
+ *  Copyright (C) 2002-2003 Nicolas "Pixel" Noble
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id: mipsdump.cpp,v 1.1 2004-01-03 15:04:47 pixel Exp $ */
+
+#include "mipsdump.h"
+#include "mips.h"
+
+TDump::TDump(mipsmem * mm) : TDis(mm) {
+    reset();
+}
+
+void TDump::reset() {
+    invalid = false;
+    hasbr = false;
+    hastg = false;
+    hasfc = false;
+    name = "";
+    comments = "";
+    args.clear();
+}
+
+void TDump::add_branch(Uint32 _tg) {
+    tg = _tg;
+    hasbr = true;
+}
+
+void TDump::add_jump(Uint32 _tg) {
+    tg = _tg;
+    hastg = true;
+}
+
+void TDump::add_function(Uint32 _tg) {
+    tg = _tg;
+    hasfc = true;
+}
+
+void TDump::SetTag(Uint32 a, int t, bool v) {
+}
+
+void TDump::Name(const String & _name) {
+    name = _name;
+}
+
+void TDump::PushGPReg(int r) {
+    pairarg p;
+    
+    p.left = T_GPREGISTER;
+    p.right.v = r;
+    
+    args.push_back(p);
+}
+
+void TDump::PushCPReg(int r) {
+    pairarg p;
+    
+    p.left = T_CPREGISTER;
+    p.right.v = r;
+    
+    args.push_back(p);
+}
+
+void TDump::PushImm(Uint32 imm) {
+    pairarg p;
+    
+    p.left = T_IMM16;
+    p.right.v = imm;
+    
+    args.push_back(p);
+}
+
+void TDump::PushTarget(Uint32 target) {
+    pairarg p;
+    
+    p.left = T_IMM32;
+    p.right.v = target;
+    
+    args.push_back(p);
+}
+
+void TDump::PushSa(Uint32 sa) {
+    pairarg p;
+    
+    p.left = T_IMM8;
+    p.right.v = sa;
+    
+    args.push_back(p);
+}
+
+void TDump::PushOfB(int reg, Uint32 offset, int width) {
+    pairarg p;
+    
+    p.left = T_OFB;
+    p.right.OfB.o = offset;
+    p.right.OfB.r = reg;
+    p.right.OfB.w = width;
+    
+    args.push_back(p);
+}
+
+void TDump::PushOffset(Uint32 offset) {
+    pairarg p;
+    
+    p.left = T_IMM32;
+    p.right.v = offset;
+    
+    args.push_back(p);
+}
+
+void TDump::PushFull(Uint32 full) {
+    pairarg p;
+    
+    p.left = T_IMM32;
+    p.right.v = full;
+    
+    args.push_back(p);
+}
+
+void TDump::Invalid() {
+    invalid = true;
+}
+
+void TDump::Suspect() {
+}
+
+void TDump::Comment(const String & c) {
+    comments = c;
+}
+
+Dumper::Dumper(mipsmem * _mm) : dump(new TDump(_mm)), mm(_mm) {
+}
+
+void Dumper::process() {
+    Uint32 pc, code;
+    memdata * mem;
+    
+    for (pc = 0x80000000; pc < (0x80000000 + PSXMEM); pc++) {
+	if (mm->GetTag(pc, CODE)) {
+	    decode(dump, pc);
+	    code = mm->Read32(pc);
+	    printm(M_STATUS, "%8.8lX %8.8lX: " + dump->name + "\t", pc, code);
+	    for (std::vector<pairarg>::iterator i = dump->args.begin(); i != dump->args.end(); i++) {
+		switch(i->left) {
+		case T_GPREGISTER:
+		    printm(M_BARE, "$%s", registers[i->right.v]);
+		    break;
+		case T_CPREGISTER:
+		    printm(M_BARE, "$%s", CP0registers[i->right.v]);
+		    break;
+		case T_IMM8:
+		    printm(M_BARE, "0x%2.2lX", i->right.v);
+		    break;
+		case T_IMM16:
+		    printm(M_BARE, "0x%4.4lX", i->right.v);
+		    break;
+		case T_IMM32:
+		    printm(M_BARE, "0x%8.8lX", i->right.v);
+		    break;
+		case T_OFB:
+		    printm(M_BARE, "0x%4.4lX($%s)", i->right.OfB.o, registers[i->right.OfB.r]);
+		    break;
+		}
+		if ((i + 1) != dump->args.end()) {
+		    printm(M_BARE, ", ");
+		}
+	    }
+	    if (dump->comments != "") {
+		printm(M_BARE, "\t; " + dump->comments);
+	    }
+	    printm(M_BARE, "\n");
+	    mem = mm->GetDatas(pc);
+	    if (mem) {
+		reffrom_t * from;
+		refto_t * to;
+		
+		from = mem->getreffrom();
+		to = mem->getrefto();
+		
+		for (from = mem->getreffrom(); from; from = from->getnext()) {
+		    printm(M_STATUS, "     Reference from 0x%8.8lX\n", from->getref()->getaddress());
+		}
+		
+		if (to) {
+		    printm(M_STATUS, "     Reference to 0x%8.8lX\n", to->getref()->getaddress());
+		}
+	    }
+	    pc += 3;
+	    dump->reset();
+	}
+    }
+}
diff --git a/lib/mipsmem.cpp b/lib/mipsmem.cpp
new file mode 100644
index 0000000..761df13
--- /dev/null
+++ b/lib/mipsmem.cpp
@@ -0,0 +1,349 @@
+/*
+ *  PSX-Tools Bundle Pack
+ *  Copyright (C) 2002-2003 Nicolas "Pixel" Noble
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id: mipsmem.cpp,v 1.1 2004-01-03 15:04:47 pixel Exp $ */
+
+#include "mipsmem.h"
+
+refto_t::refto_t(Uint32 to, memdata * _m) : reffrom(new reffrom_t(this, _m->getmem(to))), mem(_m) {
+    refto_t * t = mem->getrefto();
+    if (t)
+	delete t;
+    mem->setrefto(this);
+}
+
+refto_t::~refto_t() {
+    mem->setrefto(0);
+    delete reffrom;
+}
+
+memdata * refto_t::getmem() {
+    return mem;
+}
+
+memdata * refto_t::getref() {
+    return reffrom->getmem();
+}
+
+reffrom_t::reffrom_t(refto_t * _refto, memdata * _m) : refto(_refto), header(_m) {
+    next = header->getreffrom();
+    prev = 0;
+    header->setreffrom(this);
+    if (next)
+	next->prev = this;
+}
+
+reffrom_t::~reffrom_t() {
+    if (next)
+	next->prev = prev;
+    if (prev)
+	prev->next = next;
+    else
+	header->setreffrom(next);
+}
+
+memdata * reffrom_t::getmem() {
+    return header;
+}
+
+memdata * reffrom_t::getref() {
+    return refto->getmem();
+}
+
+reffrom_t * reffrom_t::getnext() {
+    return next;
+}
+
+memdata::memdata(Uint32 _address, mipsmem * _mm) : address(_address), mm(_mm), func(0), refto(0), reffrom(0) {
+    mm->SetDatas(address, this);
+}
+
+memdata::~memdata() {
+    mm->SetDatas(address, 0);
+}
+
+Uint32 memdata::getaddress() {
+    return address;
+}
+
+memdata * memdata::getmem(Uint32 addr) {
+    return getmem(addr, mm);
+}
+
+memdata * memdata::getmem(Uint32 addr, mipsmem * mm) {
+    memdata * t = mm->GetDatas(addr);
+    
+    if (!t) {
+	t = new memdata(addr, mm);
+    }
+    return t;
+}
+
+func_t * memdata::getfunc() {
+    return func;
+}
+
+refto_t * memdata::getrefto() {
+    return refto;
+}
+
+reffrom_t * memdata::getreffrom() {
+    return reffrom;
+}
+
+void memdata::setfunc(func_t * f) {
+    func = f;
+    checkdestroy();
+}
+
+void memdata::setrefto(refto_t * r) {
+    refto = r;
+    checkdestroy();
+}
+
+void memdata::setreffrom(reffrom_t * r) {
+    reffrom = r;
+    checkdestroy();
+}
+
+void memdata::checkdestroy() {
+    if (!func && !refto && !reffrom) {
+	delete this;
+    }
+}
+
+
+mipsmem::mipsmem() {
+    memset(psyqhead, 0, 0x800);
+    memset(plainmemory, 0, PSXMEM);
+    memset(patches, 0, PSXMEM);
+    memset(patchesmap, 0, PSXMEM / 8);
+    memset(tags, 0, PSXMEM);
+    memset(datas, 0, PSXMEM * sizeof(memdata *));
+}
+
+Uint8 mipsmem::Read8(Uint32 mem) {
+    if ((mem < 0x80000000) || (mem >= (0x80000000 + PSXMEM))) {
+	printm(M_WARNING, "Reading at out of bound of memory: 0x%08x\n", mem);
+	return 0xff;
+    }
+    
+    mem -= 0x80000000;
+
+    if (IsPatched(mem)) {
+	return patches[mem];
+    } else {
+	return plainmemory[mem];
+    }
+}
+
+Uint16 mipsmem::Read16(Uint32 mem) {
+    Uint8 a, b;
+    
+    if (mem & 1) {
+	printm(M_WARNING, "Read16 at a non 16-bits boundary: 0x%08x\n", mem);
+    }
+
+    a = Read8(mem);
+    b = Read8(mem + 1);
+    
+    return a | (b << 8);
+}
+
+Uint32 mipsmem::Read32(Uint32 mem) {
+    Uint8 a, b, c, d;
+    
+    if (mem & 3) {
+	printm(M_WARNING, "Read32 at a non 32-bits boundary: 0x%08x\n", mem);
+    }
+    
+    a = Read8(mem);
+    b = Read8(mem + 1);
+    c = Read8(mem + 2);
+    d = Read8(mem + 3);
+    
+    return a | (b << 8) | (c << 16) | (d << 24);
+}
+
+void mipsmem::Write8(Uint32 mem, Uint8 value) {
+    if ((mem < 0x80000000) || (mem > (0x80000000 + PSXMEM - 1))) {
+	printm(M_WARNING, "Writing at out of bound of memory: 0x%08x\n", mem);
+	return;
+    }
+    
+    mem -= 0x80000000;
+    
+    patch(mem, 1);
+    patches[mem] = value;
+}
+
+void mipsmem::Write16(Uint32 mem, Uint16 value) {
+    if ((mem < 0x80000000) || (mem > (0x80000000 + PSXMEM - 2))) {
+	printm(M_WARNING, "Writing at out of bound of memory: 0x%08x\n", mem);
+	return;
+    }
+
+    mem -= 0x80000000;
+    
+    patch(mem, 2);
+    patches[mem] = value & 0xff;
+    patches[mem + 1] = (value >> 8) & 0xff;
+}
+
+void mipsmem::Write32(Uint32 mem, Uint32 value) {
+    if ((mem < 0x80000000) || (mem > (0x80000000 + PSXMEM - 4))) {
+	printm(M_WARNING, "Writing at out of bound of memory: 0x%08x\n", mem);
+	return;
+    }
+
+    mem -= 0x80000000;
+    
+    patch(mem, 4);
+    patches[mem] = value & 0xff;
+    patches[mem + 1] = (value >> 8) & 0xff;
+    patches[mem + 2] = (value >> 16) & 0xff;
+    patches[mem + 3] = (value >> 24) & 0xff;
+}
+
+void mipsmem::unpatch8(Uint32 mem) {
+    unpatch(mem, 1);
+}
+
+void mipsmem::unpatch16(Uint32 mem) {
+    unpatch(mem, 2);
+}
+
+void mipsmem::unpatch32(Uint32 mem) {
+    unpatch(mem, 4);
+}
+
+bool mipsmem::IsPatched(Uint32 mem) {
+    int mask, pos;
+    
+    pos = mem / 8;
+    mask = 1 << (mem % 8);
+    
+    return patchesmap[pos] & mask;
+}
+
+void mipsmem::LoadPSYQ(Handle * h) {
+    h->read(psyqhead, 0x800);
+    memset(plainmemory, 0, PSXMEM);
+    paddr = ((psyq*)psyqhead)->t_addr;
+    psize = ((psyq*)psyqhead)->t_size;
+    startpc = ((psyq*)psyqhead)->pc0;
+
+    printm(M_INFO, "Loading %i (%08x) bytes of data at %i (%08x).\n", psize, psize, paddr - 0x80000000, paddr);
+    
+    h->read(plainmemory + paddr - 0x80000000, psize);
+}
+
+void mipsmem::SavePSYQ(Handle * h) {\
+    Uint32 i;
+    
+    if (!*((Uint32 *)psyqhead))
+	return;
+    h->write(psyqhead, 0x800);
+    paddr = ((psyq*)psyqhead)->t_addr;
+    psize = ((psyq*)psyqhead)->t_size;
+
+    printm(M_INFO, "Writing %i (%08x) bytes of data from %i (%08x).\n", psize, psize, paddr - 0x80000000, paddr);
+    
+    for (i = paddr - 0x80000000; i < psize; i++) {
+	h->writeU8(Read8(i));
+    }
+}
+
+bool mipsmem::GetTag(Uint32 addr, char tag) {
+    int mask;
+    
+    if ((addr < 0x80000000) || (addr >= (0x80000000 + PSXMEM))) {
+	printm(M_WARNING, "Reading tag at out of bound of memory: 0x%08x\n", addr);
+	return false;
+    }
+    
+    mask = 1 << tag;
+    addr -= 0x80000000;
+    
+    return tags[addr] & mask;
+}
+
+void mipsmem::SetTag(Uint32 addr, char tag, bool t) {
+    int mask;
+    
+    if ((addr < 0x80000000) || (addr >= (0x80000000 + PSXMEM))) {
+	printm(M_WARNING, "Setting tag at out of bound of memory: 0x%08x\n", addr);
+	return;
+    }
+    
+    mask = 1 << tag;
+    addr -= 0x80000000;
+    
+    if (t) {
+	tags[addr] |= mask;
+    } else {
+	tags[addr] &= ~mask;
+    }
+}
+
+memdata * mipsmem::GetDatas(Uint32 addr) {
+    return datas[addr];
+}
+
+void mipsmem::SetDatas(Uint32 addr, memdata * p) {
+    datas[addr] = p;
+}
+
+Uint32 mipsmem::GetPC() {
+    return startpc;
+}
+
+Uint32 mipsmem::GetLower() {
+    return paddr;
+}
+
+Uint32 mipsmem::GetUpper() {
+    return paddr + psize;
+}
+
+void mipsmem::patch(Uint32 mem, int size) {
+    int mask, pos;
+    
+    pos = mem / 8;
+    mask = 1 << (mem % 8);
+    
+    patchesmap[pos] |= mask;
+    
+    if (size != 1) {
+	patch(mem + 1, size - 1);
+    }
+}
+
+void mipsmem::unpatch(Uint32 mem, int size) {
+    int mask, pos;
+    
+    pos = mem / 8;
+    mask = ~(1 << (mem % 8));
+    
+    patchesmap[pos] &= mask;
+    
+    if (size != 1) {
+	unpatch(mem + 1, size - 1);
+    }
+}
-- 
cgit v1.2.3