/* * 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); } }