Files

483 lines
11 KiB
C
Executable File

/*****************************************************************************
** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/Memory/SlotManager.c,v $
**
** $Revision: 1.8 $
**
** $Date: 2008-03-30 18:38:42 $
**
** More info: http://www.bluemsx.com
**
** Copyright (C) 2003-2006 Daniel Vik
**
** 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., 675 Mass Ave, Cambridge, MA 02139, USA.
**
******************************************************************************
*/
#include "SlotManager.h"
#include "SaveState.h"
#include "Led.h"
#include "IoPort.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct {
UInt8* pageData;
int readEnable;
int writeEnable;
} RamSlotState;
typedef struct {
int subslotted;
UInt8 state;
UInt8 substate;
UInt8 sslReg;
} PrimarySlotState;
typedef struct {
UInt16 startpage;
UInt16 pages;
UInt8* pageData;
int writeEnable;
int readEnable;
SlotRead read;
SlotRead peek;
SlotWrite write;
SlotEject eject;
void* ref;
} Slot;
static RamSlotState ramslot[8];
static PrimarySlotState pslot[4];
static Slot slotTable[4][4][8];
static Slot slotAddr0;
static UInt8 emptyRAM[0x2000];
static Int32 initialized;
void slotMapRamPage(int slot, int sslot, int page)
{
ramslot[page].readEnable = slotTable[slot][sslot][page].readEnable;
ramslot[page].writeEnable = slotTable[slot][sslot][page].writeEnable;
ramslot[page].pageData = slotTable[slot][sslot][page].pageData;
}
void slotSetRamSlot(int slot, int psl)
{
int ssl;
pslot[slot].state = psl;
pslot[slot].substate = (pslot[psl].sslReg >> (slot * 2)) & 3;
ssl = pslot[psl].subslotted ? pslot[slot].substate : 0;
slotMapRamPage(psl, ssl, 2 * slot);
slotMapRamPage(psl, ssl, 2 * slot + 1);
}
int slotGetRamSlot(int page)
{
int i;
for (i = 0; i < 4; i++) {
if (pslot[i].state == page) {
return i;
}
}
return 0;
}
void slotMapPage(int slot, int sslot, int page, UInt8* pageData,
int readEnable, int writeEnable)
{
if (!initialized) {
return;
}
slotTable[slot][sslot][page].readEnable = readEnable;
slotTable[slot][sslot][page].writeEnable = writeEnable;
if (pageData != NULL) {
slotTable[slot][sslot][page].pageData = pageData;
}
#if 0
if (pslot[page >> 1].state == slot && (!pslot[slot].subslotted || sslot == 2 || pslot[page >> 1].substate == sslot)) {
slotMapRamPage(slot, sslot, page);
}
#else
if (pslot[page >> 1].state == slot &&
(!pslot[slot].subslotted || pslot[page >> 1].substate == sslot))
{
slotMapRamPage(slot, sslot, page);
}
#endif
}
void slotUpdatePage(int slot, int sslot, int page, UInt8* pageData,
int readEnable, int writeEnable)
{
if (!initialized) {
return;
}
slotMapPage(slot, sslot, page, pageData, readEnable, writeEnable);
return;
slotTable[slot][sslot][page].readEnable = readEnable;
slotTable[slot][sslot][page].writeEnable = writeEnable;
if (pageData != NULL) {
slotTable[slot][sslot][page].pageData = pageData;
}
}
void slotUnmapPage(int slot, int sslot, int page)
{
if (!initialized) {
return;
}
slotTable[slot][sslot][page].readEnable = 0;
slotTable[slot][sslot][page].writeEnable = 1;
slotTable[slot][sslot][page].pageData = emptyRAM;
if (pslot[page >> 1].state == slot &&
(!pslot[slot].subslotted || pslot[page >> 1].substate == sslot))
{
slotMapRamPage(slot, sslot, page);
}
}
void slotRegisterWrite0(SlotWrite writeCb, void* ref)
{
if (!initialized) {
return;
}
slotAddr0.read = NULL;
slotAddr0.write = writeCb;
slotAddr0.eject = NULL;
slotAddr0.ref = ref;
}
void slotUnregisterWrite0() {
if (!initialized) {
return;
}
memset(&slotAddr0, 0, sizeof(Slot));
}
void slotRegister(int slot, int sslot, int startpage, int pages,
SlotRead readCb, SlotRead peekCb, SlotWrite writeCb, SlotEject ejectCb, void* ref)
{
Slot* slotInfo;
if (!initialized) {
return;
}
slotInfo = &slotTable[slot][sslot][startpage];
slotInfo->pages = pages;
while (pages--) {
slotInfo->startpage = startpage;
slotInfo->read = readCb;
slotInfo->peek = peekCb;
slotInfo->write = writeCb;
slotInfo->eject = ejectCb;
slotInfo->ref = ref;
slotInfo++;
}
}
void slotUnregister(int slot, int sslot, int startpage)
{
Slot* slotInfo;
int pages;
if (!initialized) {
return;
}
slotInfo = &slotTable[slot][sslot][startpage];
pages = slotInfo->pages;
while (pages--) {
memset(slotInfo, 0, sizeof(Slot));
slotUnmapPage(slot, sslot, startpage + pages);
slotInfo++;
}
}
void slotRemove(int slot, int sslot)
{
int page;
if (!initialized) {
return;
}
for (page = 0; page < 8; page++) {
Slot* slotInfo = &slotTable[slot][sslot][page];
if (slotInfo->eject != NULL) {
slotInfo->eject(slotInfo->ref);
}
}
}
void slotSetSubslotted(int slot, int subslotted)
{
if (!initialized) {
return;
}
pslot[slot].subslotted = subslotted;
}
void slotManagerReset()
{
int page;
if (!initialized) {
return;
}
for (page = 0; page < 4; page++) {
pslot[page].state = 0;
pslot[page].substate = 0;
slotMapRamPage(0, 0, 2 * page);
slotMapRamPage(0, 0, 2 * page + 1);
}
}
void slotManagerCreate()
{
int slot;
int sslot;
int page;
memset(emptyRAM, 0xff, 0x2000);
memset(ramslot, 0, sizeof(ramslot));
memset(pslot, 0, sizeof(pslot));
memset(slotTable, 0, sizeof(slotTable));
memset(&slotAddr0, 0, sizeof(slotAddr0));
for (slot = 0; slot < 4; slot++) {
for (sslot = 0; sslot < 4; sslot++) {
for (page = 0; page < 8; page++) {
slotUnmapPage(slot, sslot, page);
}
}
}
initialized = 1;
}
void slotManagerDestroy()
{
initialized = 0;
}
UInt8 slotPeek(void* ref, UInt16 address)
{
Slot* slotInfo;
int psl;
int ssl;
if (!initialized) {
return 0xff;
}
if (address == 0xffff) {
UInt8 sslReg = pslot[3].state;
if (pslot[sslReg].subslotted) {
return ~pslot[sslReg].sslReg;
}
}
if (ramslot[address >> 13].readEnable) {
return ramslot[address >> 13].pageData[address & 0x1fff];
}
psl = pslot[address >> 14].state;
ssl = pslot[psl].subslotted ? pslot[address >> 14].substate : 0;
slotInfo = &slotTable[psl][ssl][address >> 13];
if (slotInfo->peek != NULL) {
address -= slotInfo->startpage << 13;
return slotInfo->peek(slotInfo->ref, address);
}
return 0xff;
}
UInt8 slotRead(void* ref, UInt16 address)
{
Slot* slotInfo;
int psl;
int ssl;
if (!initialized) {
return 0xff;
}
if (address == 0xffff) {
UInt8 sslReg = pslot[3].state;
if (pslot[sslReg].subslotted) {
return ~pslot[sslReg].sslReg;
}
}
if (ramslot[address >> 13].readEnable) {
return ramslot[address >> 13].pageData[address & 0x1fff];
}
psl = pslot[address >> 14].state;
ssl = pslot[psl].subslotted ? pslot[address >> 14].substate : 0;
slotInfo = &slotTable[psl][ssl][address >> 13];
if (slotInfo->read != NULL) {
address -= slotInfo->startpage << 13;
return slotInfo->read(slotInfo->ref, address);
}
return 0xff;
}
void slotWrite(void* ref, UInt16 address, UInt8 value)
{
Slot* slotInfo;
int psl;
int ssl;
int page;
if (!initialized) {
return;
}
if (address == 0xffff) {
UInt8 pslReg = pslot[3].state;
if (pslot[pslReg].subslotted) {
// printf("SW: %d %d %d %d\n", (value>>0)&3, (value>>2)&3, (value>>4)&3, (value>>6)&3);
pslot[pslReg].sslReg = value;
for (page = 0; page < 4; page++) {
if(pslot[page].state == pslReg) {
pslot[page].substate = value & 3;
slotMapRamPage(pslReg, value & 3, 2 * page);
slotMapRamPage(pslReg, value & 3, 2 * page + 1);
}
value >>= 2;
}
return;
}
}
if (address == 0) {
if (slotAddr0.write != NULL) {
slotAddr0.write(slotAddr0.ref, address, value);
return;
}
}
if (ramslot[address >> 13].writeEnable) {
ramslot[address >> 13].pageData[address & 0x1FFF] = value;
return;
}
psl = pslot[address >> 14].state;
ssl = pslot[psl].subslotted ? pslot[address >> 14].substate : 0;
slotInfo = &slotTable[psl][ssl][address >> 13];
if (slotInfo->write != NULL) {
address -= slotInfo->startpage << 13;
slotInfo->write(slotInfo->ref, address, value);
}
}
void slotSaveState()
{
SaveState* state;
char tag[32];
int i;
if (!initialized) {
return;
}
state = saveStateOpenForWrite("slotManager");
for (i = 0; i < 4; i++) {
sprintf(tag, "subslotted%d", i);
saveStateSet(state, tag, pslot[i].subslotted);
sprintf(tag, "state%d", i);
saveStateSet(state, tag, pslot[i].state);
sprintf(tag, "substate%d", i);
saveStateSet(state, tag, pslot[i].substate);
sprintf(tag, "sslReg%d", i);
saveStateSet(state, tag, pslot[i].sslReg);
}
saveStateClose(state);
}
void slotLoadState()
{
SaveState* state;
char tag[32];
int page;
int i;
if (!initialized) {
return;
}
state = saveStateOpenForRead("slotManager");
for (i = 0; i < 4; i++) {
sprintf(tag, "subslotted%d", i);
pslot[i].subslotted = saveStateGet(state, tag, 0);
sprintf(tag, "state%d", i);
pslot[i].state = (UInt8)saveStateGet(state, tag, 0);
sprintf(tag, "substate%d", i);
pslot[i].substate = (UInt8)saveStateGet(state, tag, 0);
sprintf(tag, "sslReg%d", i);
pslot[i].sslReg = (UInt8)saveStateGet(state, tag, 0);
}
saveStateClose(state);
for (page = 0; page < 4; page++) {
int psl = pslot[page].state;
int ssl = pslot[psl].subslotted ? pslot[page].substate : 0;
slotMapRamPage(psl, ssl, 2 * page);
slotMapRamPage(psl, ssl, 2 * page + 1);
}
}