483 lines
11 KiB
C
Executable File
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);
|
|
}
|
|
}
|