mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2025-04-02 10:31:51 -04:00
378 lines
7.8 KiB
C++
378 lines
7.8 KiB
C++
////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Nestopia - NES/Famicom emulator written in C++
|
|
//
|
|
// Copyright (C) 2003-2008 Martin Freij
|
|
//
|
|
// This file is part of Nestopia.
|
|
//
|
|
// Nestopia 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.
|
|
//
|
|
// Nestopia 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 Nestopia; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "NstBoard.hpp"
|
|
#include "NstBoardBandai24c0x.hpp"
|
|
|
|
namespace Nes
|
|
{
|
|
namespace Core
|
|
{
|
|
namespace Boards
|
|
{
|
|
namespace Bandai
|
|
{
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("s", on)
|
|
#endif
|
|
|
|
void X24C0X<0>::Reset()
|
|
{
|
|
line.scl = 0;
|
|
line.sda = 0;
|
|
mode = MODE_IDLE;
|
|
next = MODE_IDLE;
|
|
latch.bit = 0;
|
|
latch.address = 0;
|
|
latch.data = 0;
|
|
rw = false;
|
|
output = 0x10;
|
|
}
|
|
|
|
void X24C0X<0>::SaveState
|
|
(
|
|
State::Saver& state,
|
|
const dword baseChunk,
|
|
const byte* const mem,
|
|
const uint size
|
|
) const
|
|
{
|
|
state.Begin( baseChunk );
|
|
|
|
const byte data[6] =
|
|
{
|
|
line.scl | line.sda,
|
|
uint(mode << 0) | uint(next << 4),
|
|
latch.address,
|
|
latch.data,
|
|
latch.bit,
|
|
output | (rw ? 0x80 : 0x00)
|
|
};
|
|
|
|
state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
|
|
state.Begin( AsciiId<'R','A','M'>::V ).Compress( mem, size ).End();
|
|
|
|
state.End();
|
|
}
|
|
|
|
void X24C0X<0>::LoadState(State::Loader& state,byte* const mem,const uint size)
|
|
{
|
|
while (const dword chunk = state.Begin())
|
|
{
|
|
switch (chunk)
|
|
{
|
|
case AsciiId<'R','E','G'>::V:
|
|
{
|
|
State::Loader::Data<6> data( state );
|
|
|
|
line.scl = data[0] & 0x20;
|
|
line.sda = data[0] & 0x40;
|
|
|
|
if ((data[1] & 0xF) < MODE_MAX)
|
|
mode = static_cast<Mode>(data[1] & 0xF);
|
|
|
|
if ((data[1] >> 4) < MODE_MAX)
|
|
next = static_cast<Mode>(data[1] >> 4);
|
|
|
|
latch.address = data[2] & (size-1);
|
|
latch.data = data[3];
|
|
latch.bit = NST_MAX(data[4],8);
|
|
|
|
rw = data[5] & 0x80;
|
|
output = data[5] & 0x10;
|
|
break;
|
|
}
|
|
|
|
case AsciiId<'R','A','M'>::V:
|
|
|
|
state.Uncompress( mem, size );
|
|
break;
|
|
}
|
|
|
|
state.End();
|
|
}
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("s", on)
|
|
#endif
|
|
|
|
void X24C0X<0>::Stop()
|
|
{
|
|
mode = MODE_IDLE;
|
|
output = 0x10;
|
|
}
|
|
|
|
template<>
|
|
void X24C0X<128>::Start()
|
|
{
|
|
mode = MODE_ADDRESS;
|
|
latch.bit = 0;
|
|
latch.address = 0;
|
|
output = 0x10;
|
|
}
|
|
|
|
template<>
|
|
void X24C0X<256>::Start()
|
|
{
|
|
mode = MODE_DATA;
|
|
latch.bit = 0;
|
|
output = 0x10;
|
|
}
|
|
|
|
template<>
|
|
void X24C0X<128>::Rise(const uint bit)
|
|
{
|
|
NST_ASSERT( bit <= 1 );
|
|
|
|
if (mode == MODE_ADDRESS)
|
|
{
|
|
if (latch.bit < 7)
|
|
{
|
|
latch.address &= ~(1U << latch.bit);
|
|
latch.address |= bit << latch.bit++;
|
|
}
|
|
else if (latch.bit < 8)
|
|
{
|
|
latch.bit = 8;
|
|
|
|
if (bit)
|
|
{
|
|
next = MODE_READ;
|
|
latch.data = mem[latch.address];
|
|
}
|
|
else
|
|
{
|
|
next = MODE_WRITE;
|
|
}
|
|
}
|
|
}
|
|
else if (mode == MODE_ACK)
|
|
{
|
|
output = 0x00;
|
|
}
|
|
else if (mode == MODE_READ && (latch.bit < 8))
|
|
{
|
|
output = (latch.data & 1U << latch.bit++) ? 0x10 : 0x00;
|
|
}
|
|
else if (mode == MODE_WRITE && (latch.bit < 8))
|
|
{
|
|
latch.data &= ~(1U << latch.bit);
|
|
latch.data |= bit << latch.bit++;
|
|
}
|
|
else if (mode == MODE_ACK_WAIT && (bit == 0))
|
|
{
|
|
next = MODE_IDLE;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void X24C0X<128>::Fall()
|
|
{
|
|
if (mode == MODE_ADDRESS && (latch.bit == 8))
|
|
{
|
|
mode = MODE_ACK;
|
|
output = 0x10;
|
|
}
|
|
else if (mode == MODE_ACK)
|
|
{
|
|
mode = next;
|
|
latch.bit = 0;
|
|
output = 0x10;
|
|
}
|
|
else if (mode == MODE_READ && (latch.bit == 8))
|
|
{
|
|
mode = MODE_ACK_WAIT;
|
|
latch.address = (latch.address+1) & 0x7F;
|
|
}
|
|
else if (mode == MODE_WRITE && (latch.bit == 8))
|
|
{
|
|
mode = MODE_ACK;
|
|
next = MODE_IDLE;
|
|
mem[latch.address] = latch.data;
|
|
latch.address = (latch.address+1) & 0x7F;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void X24C0X<256>::Rise(const uint bit)
|
|
{
|
|
NST_ASSERT( bit <= 1 );
|
|
|
|
switch (mode)
|
|
{
|
|
case MODE_DATA:
|
|
|
|
if (latch.bit < 8)
|
|
{
|
|
latch.data &= ~(1U << (7-latch.bit));
|
|
latch.data |= bit << (7-latch.bit++);
|
|
}
|
|
break;
|
|
|
|
case MODE_ADDRESS:
|
|
|
|
if (latch.bit < 8)
|
|
{
|
|
latch.address &= ~(1U << (7-latch.bit));
|
|
latch.address |= bit << (7-latch.bit++);
|
|
}
|
|
break;
|
|
|
|
case MODE_READ:
|
|
|
|
if (latch.bit < 8)
|
|
output = (latch.data & 1U << (7-latch.bit++)) ? 0x10 : 0x00;
|
|
|
|
break;
|
|
|
|
case MODE_WRITE:
|
|
|
|
if (latch.bit < 8)
|
|
{
|
|
latch.data &= ~(1U << (7-latch.bit));
|
|
latch.data |= bit << (7-latch.bit++);
|
|
}
|
|
break;
|
|
|
|
case MODE_NOT_ACK:
|
|
|
|
output = 0x10;
|
|
break;
|
|
|
|
case MODE_ACK:
|
|
|
|
output = 0x00;
|
|
break;
|
|
|
|
case MODE_ACK_WAIT:
|
|
|
|
if (bit == 0)
|
|
{
|
|
next = MODE_READ;
|
|
latch.data = mem[latch.address];
|
|
}
|
|
break;
|
|
|
|
case MODE_IDLE:
|
|
case MODE_MAX:
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void X24C0X<256>::Fall()
|
|
{
|
|
switch (mode)
|
|
{
|
|
case MODE_DATA:
|
|
|
|
if (latch.bit == 8)
|
|
{
|
|
if ((latch.data & 0xA0) == 0xA0)
|
|
{
|
|
latch.bit = 0;
|
|
mode = MODE_ACK;
|
|
rw = latch.data & 0x01;
|
|
output = 0x10;
|
|
|
|
if (rw)
|
|
{
|
|
next = MODE_READ;
|
|
latch.data = mem[latch.address];
|
|
}
|
|
else
|
|
{
|
|
next = MODE_ADDRESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mode = MODE_NOT_ACK;
|
|
next = MODE_IDLE;
|
|
output = 0x10;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MODE_ADDRESS:
|
|
|
|
if (latch.bit == 8)
|
|
{
|
|
latch.bit = 0;
|
|
mode = MODE_ACK;
|
|
next = (rw ? MODE_IDLE : MODE_WRITE);
|
|
output = 0x10;
|
|
}
|
|
break;
|
|
|
|
case MODE_READ:
|
|
|
|
if (latch.bit == 8)
|
|
{
|
|
mode = MODE_ACK_WAIT;
|
|
latch.address = (latch.address+1) & 0xFF;
|
|
}
|
|
break;
|
|
|
|
case MODE_WRITE:
|
|
|
|
if (latch.bit == 8)
|
|
{
|
|
latch.bit = 0;
|
|
mode = MODE_ACK;
|
|
next = MODE_WRITE;
|
|
mem[latch.address] = latch.data;
|
|
latch.address = (latch.address+1) & 0xFF;
|
|
}
|
|
break;
|
|
|
|
case MODE_NOT_ACK:
|
|
|
|
mode = MODE_IDLE;
|
|
latch.bit = 0;
|
|
output = 0x10;
|
|
break;
|
|
|
|
case MODE_ACK:
|
|
case MODE_ACK_WAIT:
|
|
|
|
mode = next;
|
|
latch.bit = 0;
|
|
output = 0x10;
|
|
break;
|
|
|
|
case MODE_IDLE:
|
|
case MODE_MAX:
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|