Files

276 lines
8.2 KiB
C
Executable File

/*****************************************************************************
** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/Memory/AmdFlash.c,v $
**
** $Revision: 1.15 $
**
** $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 "AmdFlash.h"
#include "SaveState.h"
#include "sramLoader.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// Minimal AMD flash emulation to support the obsonet flash
typedef struct {
UInt32 address;
UInt8 value;
} AmdCmd;
#define ST_IDLE 0
#define ST_IDENT 1
struct AmdFlash
{
UInt8* romData;
UInt32 cmdAddr1;
UInt32 cmdAddr2;
int state;
int flashSize;
int sectorSize;
AmdCmd cmd[8];
int cmdIdx;
int writeProtectMask;
char sramFilename[512];
};
static int checkCommandEraseSector(AmdFlash* rm)
{
if (rm->cmdIdx > 0 && ((rm->cmd[0].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[0].value != 0xaa)) return 0;
if (rm->cmdIdx > 1 && ((rm->cmd[1].address & 0x7ff) != rm->cmdAddr2 || rm->cmd[1].value != 0x55)) return 0;
if (rm->cmdIdx > 2 && ((rm->cmd[2].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[2].value != 0x80)) return 0;
if (rm->cmdIdx > 3 && ((rm->cmd[3].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[3].value != 0xaa)) return 0;
if (rm->cmdIdx > 4 && ((rm->cmd[4].address & 0x7ff) != rm->cmdAddr2 || rm->cmd[4].value != 0x55)) return 0;
if (rm->cmdIdx > 5 && ( rm->cmd[5].value != 0x30)) return 0;
if (rm->cmdIdx < 6) return 1;
if (((rm->writeProtectMask >> (rm->cmd[5].address / rm->sectorSize)) & 1) == 0) {
memset(rm->romData + (rm->cmd[5].address & ~(rm->sectorSize - 1) & (rm->flashSize - 1)), 0xff, rm->sectorSize);
}
return 0;
}
static int checkCommandEraseChip(AmdFlash* rm)
{
if (rm->cmdIdx > 0 && ((rm->cmd[0].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[0].value != 0xaa)) return 0;
if (rm->cmdIdx > 1 && ((rm->cmd[1].address & 0x7ff) != rm->cmdAddr2 || rm->cmd[1].value != 0x55)) return 0;
if (rm->cmdIdx > 2 && ((rm->cmd[2].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[2].value != 0x80)) return 0;
if (rm->cmdIdx > 3 && ((rm->cmd[3].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[3].value != 0xaa)) return 0;
if (rm->cmdIdx > 4 && ((rm->cmd[4].address & 0x7ff) != rm->cmdAddr2 || rm->cmd[4].value != 0x55)) return 0;
if (rm->cmdIdx > 5 && ( rm->cmd[5].value != 0x10)) return 0;
if (rm->cmdIdx < 6) return 1;
memset(rm->romData, 0xff, rm->flashSize);
return 0;
}
static int checkCommandProgram(AmdFlash* rm)
{
if (rm->cmdIdx > 0 && ((rm->cmd[0].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[0].value != 0xaa)) return 0;
if (rm->cmdIdx > 1 && ((rm->cmd[1].address & 0x7ff) != rm->cmdAddr2 || rm->cmd[1].value != 0x55)) return 0;
if (rm->cmdIdx > 2 && ((rm->cmd[2].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[2].value != 0xa0)) return 0;
if (rm->cmdIdx < 4) return 1;
if (((rm->writeProtectMask >> (rm->cmd[3].address / rm->sectorSize)) & 1) == 0) {
rm->romData[rm->cmd[3].address & (rm->flashSize - 1)] &= rm->cmd[3].value;
}
return 0;
}
static int checkCommandManifacturer(AmdFlash* rm)
{
if (rm->cmdIdx > 0 && ((rm->cmd[0].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[0].value != 0xaa)) return 0;
if (rm->cmdIdx > 1 && ((rm->cmd[1].address & 0x7ff) != rm->cmdAddr2 || rm->cmd[1].value != 0x55)) return 0;
if (rm->cmdIdx > 2 && ((rm->cmd[2].address & 0x7ff) != rm->cmdAddr1 || rm->cmd[2].value != 0x90)) return 0;
if (rm->cmdIdx == 3) {
rm->state = ST_IDENT;
}
if (rm->cmdIdx < 4) return 1;
return 0;
}
UInt8 amdFlashRead(AmdFlash* rm, UInt32 address)
{
if (rm->state == ST_IDENT) {
rm->cmdIdx = 0;
// printf("R %.4x: XX\n", address);
switch (address & 0x03) {
case 0:
return 0x01;
case 1:
return 0xa4;
case 2:
return (rm->writeProtectMask >> (address / rm->sectorSize)) & 1;
case 3:
return 0x01;
}
return 0xff;
}
// printf("R %.4x: %.2x\n", address, rm->romData[address & (rm->flashSize - 1)]);
address &= rm->flashSize - 1;
return rm->romData[address];
}
void amdFlashWrite(AmdFlash* rm, UInt32 address, UInt8 value)
{
if (rm->cmdIdx < sizeof(rm->cmd) / sizeof(rm->cmd[0])) {
int stateValid = 0;
// { static int x = 0; if (++x < 220) printf("W %.4x: %.2x %d\n", address, value, rm->cmdIdx);}
rm->cmd[rm->cmdIdx].address = address;
rm->cmd[rm->cmdIdx].value = value;
rm->cmdIdx++;
stateValid |= checkCommandManifacturer(rm);
stateValid |= checkCommandEraseSector(rm);
stateValid |= checkCommandProgram(rm);
stateValid |= checkCommandEraseChip(rm);
if (stateValid) {
if (value == 0xf0) {
rm->state = ST_IDLE;
rm->cmdIdx = 0;
}
}
if (!stateValid) {
rm->state = ST_IDLE;
rm->cmdIdx = 0;
}
}
}
UInt8* amdFlashGetPage(AmdFlash* rm, UInt32 address)
{
address &= rm->flashSize - 1;
return rm->romData + address;
}
int amdFlashCmdInProgress(AmdFlash* rm)
{
return rm->cmdIdx != 0;
}
void amdFlashReset(AmdFlash* rm)
{
rm->cmdIdx = 0;
rm->state = ST_IDLE;
}
void amdFlashSaveState(AmdFlash* rm)
{
SaveState* state = saveStateOpenForWrite("amdFlash");
int i;
for (i = 0; i < 8; i++) {
char buf[32];
sprintf(buf, "cmd_%d_address", i);
saveStateSet(state, buf, rm->cmd[i].address);
sprintf(buf, "cmd_%d_value", i);
saveStateSet(state, buf, rm->cmd[i].value);
}
saveStateSet(state, "cmdIdx", rm->cmdIdx);
saveStateClose(state);
}
void amdFlashLoadState(AmdFlash* rm)
{
SaveState* state = saveStateOpenForRead("amdFlash");
int i;
for (i = 0; i < 8; i++) {
char buf[32];
sprintf(buf, "cmd_%d_address", i);
rm->cmd[i].address = saveStateGet(state, buf, 0);
sprintf(buf, "cmd_%d_value", i);
rm->cmd[i].value = (UInt8)saveStateGet(state, buf, 0);
}
rm->cmdIdx = saveStateGet(state, "cmdIdx", 0);
saveStateClose(state);
}
AmdFlash* amdFlashCreate(AmdType type, int flashSize, int sectorSize, UInt32 writeProtectMask, void* romData, int size, const char* sramFilename, int loadSram)
{
AmdFlash* rm = (AmdFlash*)calloc(1, sizeof(AmdFlash));
rm->writeProtectMask = writeProtectMask;
if (type == 0) {
rm->cmdAddr1 = 0xaaa;
rm->cmdAddr2 = 0x555;
}
else {
rm->cmdAddr1 = 0x555;
rm->cmdAddr2 = 0x2aa;
}
if (sramFilename != NULL) {
strcpy(rm->sramFilename, sramFilename);
}
rm->flashSize = flashSize;
rm->sectorSize = sectorSize;
rm->romData = malloc(flashSize);
if (size >= flashSize) {
size = flashSize;
}
if (rm->sramFilename[0]) {
memset(rm->romData + size, 0xff, flashSize - size);
sramLoad(rm->sramFilename, rm->romData, rm->flashSize, NULL, 0);
}
if (size > 0) {
memcpy(rm->romData, romData, size);
}
#if 0
if (rm->sramFilename[0] && loadSram) {
sramLoad(rm->sramFilename, rm->romData, rm->flashSize, NULL, 0);
}
#endif
return rm;
}
void amdFlashDestroy(AmdFlash* rm)
{
if (rm->sramFilename[0]) {
sramSave(rm->sramFilename, rm->romData, rm->flashSize, NULL, 0);
}
free(rm);
}