mirror of
https://github.com/holub/mame
synced 2025-04-22 00:11:58 +03:00
[COCO1/2] Rewrote the 6883 SAM memory management; should not be as slow when
switching between 64k RAM and ROM/RAM mode anymore.
This commit is contained in:
parent
13f2c9b37d
commit
d3570cf176
@ -49,15 +49,36 @@
|
||||
|
||||
#include "machine/6883sam.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CONSTANTS
|
||||
//**************************************************************************
|
||||
|
||||
#define LOG_SAM 0
|
||||
|
||||
const device_type SAM6883 = &device_creator<sam6883_device>;
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE SETUP
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// ctor
|
||||
//-------------------------------------------------
|
||||
|
||||
sam6883_device::sam6883_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, SAM6883, "SAM6883", tag, owner, clock)
|
||||
: device_t(mconfig, SAM6883, "SAM6883", tag, owner, clock),
|
||||
m_space_0000(*this),
|
||||
m_space_8000(*this),
|
||||
m_space_A000(*this),
|
||||
m_space_C000(*this),
|
||||
m_space_FF00(*this),
|
||||
m_space_FF20(*this),
|
||||
m_space_FF40(*this),
|
||||
m_space_FF60(*this),
|
||||
m_space_FFE0(*this)
|
||||
{
|
||||
memset(m_banks, '\0', sizeof(m_banks));
|
||||
}
|
||||
@ -72,18 +93,18 @@ void sam6883_device::device_start()
|
||||
{
|
||||
const sam6883_interface *config = (const sam6883_interface *) static_config();
|
||||
|
||||
/* find the CPU */
|
||||
// find the CPU
|
||||
m_cpu = machine().device<cpu_device>(config->m_cpu_tag);
|
||||
m_cpu_space = &m_cpu->space(config->m_cpu_space);
|
||||
|
||||
/* resolve callbacks */
|
||||
// resolve callbacks
|
||||
m_res_input_func.resolve(config->m_input_func, *this);
|
||||
|
||||
/* install SAM handlers */
|
||||
// install SAM handlers
|
||||
m_cpu_space->install_read_handler(0xFFC0, 0xFFDF, 0, 0, read8_delegate(FUNC(sam6883_device::read), this));
|
||||
m_cpu_space->install_write_handler(0xFFC0, 0xFFDF, 0, 0, write8_delegate(FUNC(sam6883_device::write), this));
|
||||
|
||||
/* save state support */
|
||||
// save state support
|
||||
save_item(NAME(m_sam_state));
|
||||
save_item(NAME(m_counter));
|
||||
save_item(NAME(m_counter_xdiv));
|
||||
@ -131,19 +152,19 @@ void sam6883_device::configure_bank(int bank, UINT8 *memory, UINT32 memory_size,
|
||||
switch(bank)
|
||||
{
|
||||
case 4:
|
||||
update_bank(4, 0xFF00, 0xFF1F, 0x0000);
|
||||
m_space_FF00.point(&m_banks[4], 0x0000);
|
||||
break;
|
||||
case 5:
|
||||
update_bank(5, 0xFF20, 0xFF3F, 0x0000);
|
||||
m_space_FF20.point(&m_banks[5], 0x0000);
|
||||
break;
|
||||
case 6:
|
||||
update_bank(6, 0xFF40, 0xFF5F, 0x0000);
|
||||
m_space_FF40.point(&m_banks[6], 0x0000);
|
||||
break;
|
||||
case 7:
|
||||
update_bank(7, 0xFF60, 0xFFBF, 0x0000);
|
||||
m_space_FF60.point(&m_banks[7], 0x0000);
|
||||
break;
|
||||
case 2:
|
||||
update_bank(2, 0xFFE0, 0xFFFF, 0x1FE0);
|
||||
m_space_FFE0.point(&m_banks[2], 0x1FE0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -195,89 +216,85 @@ void sam6883_device::update_state(void)
|
||||
|
||||
void sam6883_device::update_memory(void)
|
||||
{
|
||||
/* Memory size - allowed restricting memory accesses to something less than
|
||||
* 32k
|
||||
*
|
||||
* This was a SAM switch that occupied 4 addresses:
|
||||
*
|
||||
* $FFDD (set) R1
|
||||
* $FFDC (clear) R1
|
||||
* $FFDB (set) R0
|
||||
* $FFDA (clear) R0
|
||||
*
|
||||
* R1:R0 formed the following states:
|
||||
* 00 - 4k
|
||||
* 01 - 16k
|
||||
* 10 - 64k
|
||||
* 11 - static RAM (??)
|
||||
*
|
||||
* If something less than 64k was set, the low RAM would be smaller and
|
||||
* mirror the other parts of the RAM
|
||||
*
|
||||
* TODO: Find out what "static RAM" is
|
||||
* TODO: This should affect _all_ memory accesses, not just video ram
|
||||
* TODO: Verify that the CoCo 3 ignored this
|
||||
*/
|
||||
// Memory size - allowed restricting memory accesses to something less than
|
||||
// 32k
|
||||
//
|
||||
// This was a SAM switch that occupied 4 addresses:
|
||||
//
|
||||
// $FFDD (set) R1
|
||||
// $FFDC (clear) R1
|
||||
// $FFDB (set) R0
|
||||
// $FFDA (clear) R0
|
||||
//
|
||||
// R1:R0 formed the following states:
|
||||
// 00 - 4k
|
||||
// 01 - 16k
|
||||
// 10 - 64k
|
||||
// 11 - static RAM (??)
|
||||
//
|
||||
// If something less than 64k was set, the low RAM would be smaller and
|
||||
// mirror the other parts of the RAM
|
||||
//
|
||||
// TODO: Find out what "static RAM" is
|
||||
// TODO: This should affect _all_ memory accesses, not just video ram
|
||||
// TODO: Verify that the CoCo 3 ignored this
|
||||
|
||||
/* update $0000-$7FFF */
|
||||
update_bank(0, 0x0000, 0x7FFF, m_sam_state & SAM_STATE_P1 ? 0x8000 : 0x0000);
|
||||
// for now, lets assume that the caller is nice and made m_memory_size
|
||||
// a power of two
|
||||
UINT16 ram_mask = (UINT16) m_banks[0].m_memory_size - 1;
|
||||
|
||||
if (m_sam_state & SAM_STATE_TY)
|
||||
// switch depending on the M1/M0 variables
|
||||
bool setup_rom = true;
|
||||
switch(m_sam_state & (SAM_STATE_M1|SAM_STATE_M0))
|
||||
{
|
||||
update_bank(0, 0x8000, 0xFEFF, 0x8000);
|
||||
case 0:
|
||||
// 4K mode
|
||||
m_space_0000.point(&m_banks[0], 0x0000, ram_mask);
|
||||
m_counter_mask = 0x0FFF;
|
||||
m_counter_or = 0x0000;
|
||||
break;
|
||||
|
||||
case SAM_STATE_M0:
|
||||
// 16K mode
|
||||
m_space_0000.point(&m_banks[0], 0x0000, ram_mask);
|
||||
m_counter_mask = 0x3FFF;
|
||||
m_counter_or = 0x0000;
|
||||
break;
|
||||
|
||||
case SAM_STATE_M1:
|
||||
case SAM_STATE_M1|SAM_STATE_M0:
|
||||
// 64k mode
|
||||
if (m_sam_state & SAM_STATE_TY)
|
||||
{
|
||||
// full 64k RAM
|
||||
m_space_0000.point(&m_banks[0], 0x0000, ram_mask);
|
||||
m_space_8000.point(&m_banks[0], 0x8000);
|
||||
m_space_A000.point(&m_banks[0], 0xA000);
|
||||
m_space_C000.point(&m_banks[0], 0xC000);
|
||||
m_counter_mask = 0xFFFF;
|
||||
m_counter_or = 0x0000;
|
||||
setup_rom = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ROM/RAM
|
||||
UINT16 ram_base = (m_sam_state & SAM_STATE_P1) ? 0x8000 : 0x0000;
|
||||
m_space_0000.point(&m_banks[0], ram_base, ram_mask);
|
||||
m_counter_mask = 0x7FFF;
|
||||
m_counter_or = ram_base;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
if (setup_rom)
|
||||
{
|
||||
update_bank(1, 0x8000, 0x9FFF, 0x0000);
|
||||
update_bank(2, 0xA000, 0xBFFF, 0x0000);
|
||||
update_bank(3, 0xC000, 0xFEFF, 0x0000);
|
||||
m_space_8000.point(&m_banks[1], 0x0000);
|
||||
m_space_A000.point(&m_banks[2], 0x0000);
|
||||
m_space_C000.point(&m_banks[3], 0x0000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// install_memory
|
||||
//-------------------------------------------------
|
||||
|
||||
void sam6883_device::install_memory(offs_t addrstart, offs_t addrend, void *memory, bool is_read_only)
|
||||
{
|
||||
if (addrend >= addrstart)
|
||||
{
|
||||
if (memory == NULL)
|
||||
m_cpu_space->unmap_readwrite(addrstart, addrend);
|
||||
else if (is_read_only)
|
||||
m_cpu_space->install_rom(addrstart, addrend, memory);
|
||||
else
|
||||
m_cpu_space->install_ram(addrstart, addrend, memory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_bank
|
||||
//-------------------------------------------------
|
||||
|
||||
void sam6883_device::update_bank(int bank, offs_t addrstart, offs_t addrend, offs_t offset)
|
||||
{
|
||||
assert((bank >= 0) && (bank < sizeof(m_banks) / sizeof(m_banks[0])));
|
||||
|
||||
if (m_banks[bank].m_memory != NULL)
|
||||
{
|
||||
/* this bank is a memory bank */
|
||||
install_memory(addrstart, MIN(addrend, addrstart + m_banks[bank].m_memory_size - 1), m_banks[bank].m_memory + m_banks[bank].m_memory_offset + offset, m_banks[bank].m_memory_read_only);
|
||||
install_memory(addrstart + m_banks[bank].m_memory_size, addrend, NULL, m_banks[bank].m_memory_read_only);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this bank uses handlers */
|
||||
assert(offset == 0); /* changes to the offset are not supported */
|
||||
if (!m_banks[bank].m_rhandler.isnull())
|
||||
m_cpu_space->install_read_handler(addrstart, addrend, 0, 0, m_banks[bank].m_rhandler);
|
||||
if (!m_banks[bank].m_whandler.isnull())
|
||||
m_cpu_space->install_write_handler(addrstart, addrend, 0, 0, m_banks[bank].m_whandler);
|
||||
}
|
||||
// update $FFE0-$FFFF
|
||||
m_space_FFE0.point(&m_banks[2], 0x1FE0);
|
||||
}
|
||||
|
||||
|
||||
@ -289,31 +306,31 @@ void sam6883_device::update_bank(int bank, offs_t addrstart, offs_t addrend, off
|
||||
|
||||
void sam6883_friend_device::update_cpu_clock(void)
|
||||
{
|
||||
/* The infamous speed up poke.
|
||||
*
|
||||
* This was a SAM switch that occupied 4 addresses:
|
||||
*
|
||||
* $FFD9 (set) R1
|
||||
* $FFD8 (clear) R1
|
||||
* $FFD7 (set) R0
|
||||
* $FFD6 (clear) R0
|
||||
*
|
||||
* R1:R0 formed the following states:
|
||||
* 00 - slow 0.89 MHz
|
||||
* 01 - dual speed ???
|
||||
* 1x - fast 1.78 MHz
|
||||
*
|
||||
* R1 controlled whether the video addressing was speeded up and R0
|
||||
* did the same for the CPU. On pre-CoCo 3 machines, setting R1 caused
|
||||
* the screen to display garbage because the M6847 could not display
|
||||
* fast enough.
|
||||
*
|
||||
* TODO: Make the overclock more accurate. In dual speed, ROM was a fast
|
||||
* access but RAM was not. I don't know how to simulate this.
|
||||
*/
|
||||
// The infamous speed up poke.
|
||||
//
|
||||
// This was a SAM switch that occupied 4 addresses:
|
||||
//
|
||||
// $FFD9 (set) R1
|
||||
// $FFD8 (clear) R1
|
||||
// $FFD7 (set) R0
|
||||
// $FFD6 (clear) R0
|
||||
//
|
||||
// R1:R0 formed the following states:
|
||||
// 00 - slow 0.89 MHz
|
||||
// 01 - dual speed ???
|
||||
// 1x - fast 1.78 MHz
|
||||
//
|
||||
// R1 controlled whether the video addressing was speeded up and R0
|
||||
// did the same for the CPU. On pre-CoCo 3 machines, setting R1 caused
|
||||
// the screen to display garbage because the M6847 could not display
|
||||
// fast enough.
|
||||
//
|
||||
// TODO: Make the overclock more accurate. In dual speed, ROM was a fast
|
||||
// access but RAM was not. I don't know how to simulate this.
|
||||
|
||||
int speed = (m_sam_state & (SAM_STATE_R1|SAM_STATE_R0)) / SAM_STATE_R0;
|
||||
|
||||
/* the line below is weird because we are not strictly emulating the M6809E with emphasis on the 'E' */
|
||||
// the line below is weird because we are not strictly emulating the M6809E with emphasis on the 'E'
|
||||
m_cpu->set_clock_scale(speed ? 2 : 1);
|
||||
}
|
||||
|
||||
@ -329,7 +346,6 @@ void sam6883_device::set_bank_offset(int bank, offs_t offset)
|
||||
{
|
||||
m_banks[bank].m_memory_offset = offset;
|
||||
update_memory();
|
||||
update_bank(2, 0xFFE0, 0xFFFF, 0x1FE0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,3 +441,115 @@ WRITE_LINE_MEMBER( sam6883_device::hs_w )
|
||||
horizontal_sync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// sam_space::ctor
|
||||
//-------------------------------------------------
|
||||
|
||||
template<UINT16 _addrstart, UINT16 _addrend>
|
||||
sam6883_device::sam_space<_addrstart, _addrend>::sam_space(sam6883_device &owner)
|
||||
: m_owner(owner)
|
||||
{
|
||||
m_read_bank = NULL;
|
||||
m_write_bank = NULL;
|
||||
m_mask = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// sam_space::cpu_space
|
||||
//-------------------------------------------------
|
||||
|
||||
template<UINT16 _addrstart, UINT16 _addrend>
|
||||
address_space &sam6883_device::sam_space<_addrstart, _addrend>::cpu_space() const
|
||||
{
|
||||
assert(m_owner.m_cpu_space != NULL);
|
||||
return *m_owner.m_cpu_space;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// sam_space::point
|
||||
//-------------------------------------------------
|
||||
|
||||
template<UINT16 _addrstart, UINT16 _addrend>
|
||||
void sam6883_device::sam_space<_addrstart, _addrend>::point(const sam_bank *bank, UINT16 offset, UINT16 mask)
|
||||
{
|
||||
if (LOG_SAM)
|
||||
{
|
||||
logerror("sam6883_device::sam_space::point(): addrstart=0x%04X addrend=0x%04X offset=0x%04X mask=0x%04X bank->m_memory=0x%p bank->m_memory_read_only=%s\n",
|
||||
(unsigned) _addrstart,
|
||||
(unsigned) _addrend,
|
||||
(unsigned) offset,
|
||||
(unsigned) mask,
|
||||
bank->m_memory,
|
||||
bank->m_memory_read_only ? "true" : "false");
|
||||
}
|
||||
|
||||
point_specific_bank(bank, offset, mask, m_read_bank, _addrstart, _addrend, false);
|
||||
point_specific_bank(bank, offset, mask, m_write_bank, _addrstart, _addrend, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// sam_space::point_specific_bank
|
||||
//-------------------------------------------------
|
||||
template<UINT16 _addrstart, UINT16 _addrend>
|
||||
void sam6883_device::sam_space<_addrstart, _addrend>::point_specific_bank(const sam_bank *bank, UINT16 offset, UINT16 mask, memory_bank *&memory_bank, INT32 addrstart, INT32 addrend, bool is_write)
|
||||
{
|
||||
char buffer[16];
|
||||
|
||||
if (bank->m_memory != NULL)
|
||||
{
|
||||
// normalize offset
|
||||
if (mask != 0)
|
||||
offset &= mask;
|
||||
|
||||
// this bank is a memory bank - first ensure that we have a bank
|
||||
if (!memory_bank || !memory_bank->matches_exactly(addrstart, addrend) || (mask != m_mask))
|
||||
{
|
||||
// name the bank
|
||||
snprintf(buffer, ARRAY_LENGTH(buffer), "bank%04X_%c", addrstart, is_write ? 'w' : 'r');
|
||||
|
||||
// install it
|
||||
if (is_write)
|
||||
cpu_space().install_write_bank(addrstart, addrend, mask, 0, buffer);
|
||||
else
|
||||
cpu_space().install_read_bank(addrstart, addrend, mask, 0, buffer);
|
||||
m_mask = mask;
|
||||
|
||||
// and get it
|
||||
memory_bank = cpu_space().device().owner()->membank(buffer);
|
||||
}
|
||||
|
||||
// point the bank
|
||||
if (memory_bank != NULL)
|
||||
{
|
||||
if (is_write && bank->m_memory_read_only)
|
||||
memory_bank->set_base(m_owner.m_dummy);
|
||||
else
|
||||
memory_bank->set_base(bank->m_memory + offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this bank uses handlers
|
||||
assert((offset == 0) && (mask == 0)); // changes to the offset are not supported
|
||||
|
||||
if (is_write)
|
||||
{
|
||||
if (!bank->m_whandler.isnull())
|
||||
cpu_space().install_write_handler(addrstart, addrend, 0, 0, bank->m_whandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bank->m_rhandler.isnull())
|
||||
cpu_space().install_read_handler(addrstart, addrend, 0, 0, bank->m_rhandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ public:
|
||||
if (bit3_carry)
|
||||
counter_carry_bit3();
|
||||
}
|
||||
return m_res_input_func(m_counter);
|
||||
return m_res_input_func((m_counter & m_counter_mask) | m_counter_or);
|
||||
}
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( hs_w );
|
||||
@ -136,25 +136,60 @@ protected:
|
||||
virtual void device_post_load();
|
||||
|
||||
private:
|
||||
// represents an external memory bank - memory or IO that the SAM
|
||||
// points to with the S2/S1/S0 output
|
||||
struct sam_bank
|
||||
{
|
||||
UINT8 * m_memory;
|
||||
UINT32 m_memory_size;
|
||||
offs_t m_memory_offset;
|
||||
bool m_memory_read_only;
|
||||
read8_delegate m_rhandler;
|
||||
write8_delegate m_whandler;
|
||||
UINT8 * m_memory;
|
||||
UINT32 m_memory_size;
|
||||
offs_t m_memory_offset;
|
||||
bool m_memory_read_only;
|
||||
read8_delegate m_rhandler;
|
||||
write8_delegate m_whandler;
|
||||
};
|
||||
|
||||
// represents one of the memory "spaces" (e.g. - $8000-$9FFF) that
|
||||
// can ultimately point to a bank
|
||||
template<UINT16 _addrstart, UINT16 _addrend>
|
||||
class sam_space
|
||||
{
|
||||
public:
|
||||
sam_space(sam6883_device &owner);
|
||||
void point(const sam_bank *bank, UINT16 offset, UINT16 mask = 0);
|
||||
|
||||
private:
|
||||
sam6883_device & m_owner;
|
||||
memory_bank * m_read_bank;
|
||||
memory_bank * m_write_bank;
|
||||
UINT16 m_mask;
|
||||
|
||||
address_space &cpu_space() const;
|
||||
void point_specific_bank(const sam_bank *bank, UINT16 offset, UINT16 mask, memory_bank *&memory_bank, INT32 addrstart, INT32 addrend, bool is_write);
|
||||
};
|
||||
|
||||
// incidentals
|
||||
address_space * m_cpu_space;
|
||||
devcb_resolved_read8 m_res_input_func;
|
||||
sam_bank m_banks[8];
|
||||
address_space * m_cpu_space;
|
||||
devcb_resolved_read8 m_res_input_func;
|
||||
sam_bank m_banks[8];
|
||||
sam_space<0x0000, 0x7FFF> m_space_0000;
|
||||
sam_space<0x8000, 0x9FFF> m_space_8000;
|
||||
sam_space<0xA000, 0xBFFF> m_space_A000;
|
||||
sam_space<0xC000, 0xFEFF> m_space_C000;
|
||||
sam_space<0xFF00, 0xFF1F> m_space_FF00;
|
||||
sam_space<0xFF20, 0xFF3F> m_space_FF20;
|
||||
sam_space<0xFF40, 0xFF5F> m_space_FF40;
|
||||
sam_space<0xFF60, 0xFFBF> m_space_FF60;
|
||||
sam_space<0xFFE0, 0xFFFF> m_space_FFE0;
|
||||
UINT16 m_counter_mask;
|
||||
UINT16 m_counter_or;
|
||||
|
||||
// SAM state
|
||||
UINT16 m_counter;
|
||||
UINT8 m_counter_xdiv;
|
||||
UINT8 m_counter_ydiv;
|
||||
UINT16 m_counter;
|
||||
UINT8 m_counter_xdiv;
|
||||
UINT8 m_counter_ydiv;
|
||||
|
||||
// dummy scratch memory
|
||||
UINT8 m_dummy[0x8000];
|
||||
|
||||
// typically called by CPU
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
@ -219,8 +254,6 @@ private:
|
||||
void horizontal_sync(void);
|
||||
void update_state(void);
|
||||
void update_memory(void);
|
||||
void update_bank(int bank, offs_t addrstart, offs_t addrend, offs_t offset);
|
||||
void install_memory(offs_t addrstart, offs_t addrend, void *memory, bool is_read_only);
|
||||
};
|
||||
|
||||
extern const device_type SAM6883;
|
||||
|
Loading…
Reference in New Issue
Block a user