diff options
Diffstat (limited to 'lib/mipsmem.cpp')
-rw-r--r-- | lib/mipsmem.cpp | 349 |
1 files changed, 349 insertions, 0 deletions
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); + } +} |