mame/src/devices/machine/mos8722.cpp

368 lines
7.2 KiB
C++

// license:BSD-3-Clause
// copyright-holders:Curt Coder
/**********************************************************************
MOS Technology 8722 Memory Management Unit emulation
**********************************************************************/
#include "emu.h"
#include "mos8722.h"
//#define VERBOSE 1
#include "logmacro.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(MOS8722, mos8722_device, "mos8722", "MOS 8722 MMU")
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
#define CR_IO BIT(m_reg[CR], 0)
#define CR_ROM_LO BIT(m_reg[CR], 1)
#define CR_ROM_MID ((m_reg[CR] >> 2) & 0x03)
#define CR_ROM_HI ((m_reg[CR] >> 4) & 0x03)
#define CR_A16 BIT(m_reg[CR], 6)
// mode configuration register
#define MCR_8500 BIT(m_reg[MCR], 0)
#define MCR_FSDIR BIT(m_reg[MCR], 3)
#define MCR_GAME BIT(m_reg[MCR], 4)
#define MCR_EXROM BIT(m_reg[MCR], 5)
#define MCR_C64 BIT(m_reg[MCR], 6)
#define MCR_40_80 BIT(m_reg[MCR], 7)
// RAM configuration register
static const offs_t RCR_BOTTOM_ADDRESS[4] = { 0x0400, 0x1000, 0x0400, 0x1000 };
static const offs_t RCR_TOP_ADDRESS[4] = { 0xf000, 0xf000, 0xe000, 0xc000 };
#define RCR_SHARE (m_reg[RCR] & 0x03)
#define RCR_BOTTOM BIT(m_reg[RCR], 2)
#define RCR_TOP BIT(m_reg[RCR], 3)
#define RCR_VA16 BIT(m_reg[RCR], 6)
// page 0 pointer register
#define P0H_A16 BIT(m_reg[P0H], 0)
// page 1 pointer register
#define P1H_A16 BIT(m_reg[P1H], 0)
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// mos8722_device - constructor
//-------------------------------------------------
mos8722_device::mos8722_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, MOS8722, tag, owner, clock),
m_write_z80en(*this),
m_write_fsdir(*this),
m_read_game(*this),
m_read_exrom(*this),
m_read_sense40(*this)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void mos8722_device::device_start()
{
// resolve callbacks
m_write_z80en.resolve_safe();
m_write_fsdir.resolve_safe();
m_read_game.resolve_safe(1);
m_read_exrom.resolve_safe(1);
m_read_sense40.resolve_safe(1);
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void mos8722_device::device_reset()
{
for (auto & elem : m_reg)
{
elem = 0;
}
m_reg[P1L] = 0x01;
m_p0h_latch = 0;
m_p1h_latch = 0;
m_write_z80en(MCR_8500);
m_write_fsdir(MCR_FSDIR);
}
//-------------------------------------------------
// read - register read
//-------------------------------------------------
uint8_t mos8722_device::read(offs_t offset, uint8_t data)
{
if (MCR_C64) return data;
if (!CR_IO && offset >= 0xd500 && offset < 0xd50c)
{
switch (offset & 0x0f)
{
case CR:
data = m_reg[CR] | 0x80;
break;
case MCR:
data = m_reg[MCR] | 0x06;
data &= ((m_read_game() << 4) | ~0x10);
data &= ((m_read_exrom() << 5) | ~0x20);
data &= ((m_read_sense40() << 7) | ~0x80);
break;
case VR:
data = 0x20;
break;
default:
data = m_reg[offset & 0x0f];
break;
}
}
else if (offset >= 0xff00 && offset < 0xff05)
{
switch (offset & 0x0f)
{
case CR:
data = m_reg[CR] | 0x80;
break;
default:
data = m_reg[offset & 0x0f];
break;
}
}
return data;
}
//-------------------------------------------------
// write - register write
//-------------------------------------------------
void mos8722_device::write(offs_t offset, uint8_t data)
{
if (MCR_C64) return;
if (!CR_IO && offset >= 0xd500 && offset < 0xd50c)
{
LOG("MOS8722 Write %01x : %02x\n", offset & 0x0f, data);
switch (offset & 0x0f)
{
case CR:
m_reg[CR] = data & 0x7f;
break;
case PCRA:
case PCRB:
case PCRC:
case PCRD:
m_reg[offset & 0x0f] = data & 0x7f;
break;
case MCR:
{
int _8500 = MCR_8500;
int fsdir = MCR_FSDIR;
m_reg[MCR] = data;
if (_8500 != MCR_8500) m_write_z80en(MCR_8500);
if (fsdir != MCR_FSDIR) m_write_fsdir(MCR_FSDIR);
break;
}
case RCR:
m_reg[RCR] = data & 0x4f;
break;
case P0L:
m_reg[P0L] = data;
m_reg[P0H] = m_p0h_latch;
break;
case P0H:
m_p0h_latch = data & 0x01;
break;
case P1L:
m_reg[P1L] = data;
m_reg[P1H] = m_p1h_latch;
break;
case P1H:
m_p1h_latch = data & 0x01;
break;
default:
m_reg[offset & 0x0f] = data;
}
}
else if (offset >= 0xff00 && offset < 0xff05)
{
LOG("MOS8722 Write %01x : %02x\n", offset & 0x0f, data);
switch (offset & 0x0f)
{
case CR:
m_reg[CR] = data & 0x7f;
break;
default:
m_reg[CR] = m_reg[offset & 0x0f];
break;
}
}
}
//-------------------------------------------------
// fsdir_r - fast serial direction read
//-------------------------------------------------
READ_LINE_MEMBER( mos8722_device::fsdir_r )
{
return MCR_FSDIR;
}
//-------------------------------------------------
// ta_r - translated address read
//-------------------------------------------------
offs_t mos8722_device::ta_r(offs_t offset, int aec, int *ms0, int *ms1, int *ms2, int *ms3, int *cas0, int *cas1)
{
offs_t ta;
*ms0 = 1;
*ms1 = 1;
*ms2 = CR_IO;
*ms3 = !MCR_C64;
if (aec)
{
// CPU access
ta = offset & 0xff00;
*cas0 = CR_A16;
*cas1 = !*cas0;
if (!MCR_C64)
{
if (offset >= 0xff00 && offset < 0xff05)
{
// MMU registers
*cas0 = 1;
*cas1 = 1;
}
else if (!MCR_8500 && !CR_A16 && offset < 0x1000)
{
// Z80 ROM
ta = 0xd000 | (offset & 0xf00);
*ms0 = 0;
*ms1 = 0;
}
else
{
if (offset < 0x0100)
{
// page 0 pointer
ta = m_reg[P0L] << 8;
*cas0 = P0H_A16;
*cas1 = !*cas0;
}
else if (offset < 0x0200)
{
// page 1 pointer
ta = m_reg[P1L] << 8;
*cas0 = P1H_A16;
*cas1 = !*cas0;
}
else if (offset >= 0x4000 && offset < 0x8000)
{
// low ROM
*ms0 = CR_ROM_LO;
*ms1 = CR_ROM_LO;
}
else if (offset >= 0x8000 && offset < 0xc000)
{
// middle ROM
*ms0 = BIT(CR_ROM_MID, 1);
*ms1 = BIT(CR_ROM_MID, 0);
}
else if (offset >= 0xc000)
{
// high ROM
*ms0 = BIT(CR_ROM_HI, 1);
*ms1 = BIT(CR_ROM_HI, 0);
}
if (*ms0 && *ms1)
{
if ((offset >> 8) == m_reg[P0L])
{
ta = 0x0000;
}
else if ((offset >> 8) == m_reg[P1L])
{
ta = 0x0100;
}
}
if ((RCR_BOTTOM && offset < RCR_BOTTOM_ADDRESS[RCR_SHARE]) ||
(RCR_TOP && offset >= RCR_TOP_ADDRESS[RCR_SHARE]))
{
// RAM sharing
*cas0 = 0;
*cas1 = !*cas0;
}
}
}
}
else
{
// VIC access
ta = 0xf000 | (offset & 0xf00);
*cas0 = RCR_VA16;
*cas1 = !*cas0;
}
return ta;
}