348 lines
9.4 KiB
C++
348 lines
9.4 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:David Haywood
|
|
/* 68307 */
|
|
|
|
#include "emu.h"
|
|
#include "68307.h"
|
|
#include "68307bus.h"
|
|
#include "68307sim.h"
|
|
#include "68307tmu.h"
|
|
|
|
DEFINE_DEVICE_TYPE(M68307, m68307_cpu_device, "mc68307", "MC68307")
|
|
|
|
|
|
/* 68307 SERIAL Module */
|
|
/* all ports on this are 8-bit? */
|
|
|
|
/* this is a 68681 'compatible' chip but with only a single channel implemented
|
|
(writes to the other channel have no effects)
|
|
|
|
for now at least we piggyback on the existing 68307 emulation rather than having
|
|
a custom verson here, that may change later if subtle differences exist.
|
|
|
|
*/
|
|
READ8_MEMBER( m68307_cpu_device::m68307_internal_serial_r )
|
|
{
|
|
if (offset&1) return m_duart->read(*m_program, offset>>1);
|
|
return 0x0000;
|
|
}
|
|
|
|
WRITE8_MEMBER(m68307_cpu_device::m68307_internal_serial_w)
|
|
{
|
|
if (offset & 1) m_duart->write(*m_program, offset >> 1, data);
|
|
}
|
|
|
|
|
|
|
|
static ADDRESS_MAP_START( m68307_internal_map, AS_PROGRAM, 16, m68307_cpu_device )
|
|
AM_RANGE(0x000000f0, 0x000000ff) AM_READWRITE(m68307_internal_base_r, m68307_internal_base_w)
|
|
ADDRESS_MAP_END
|
|
|
|
|
|
MACHINE_CONFIG_MEMBER( m68307_cpu_device::device_add_mconfig )
|
|
MCFG_DEVICE_ADD("internal68681", MC68681, 16000000/4) // ?? Mhz - should be specified in inline config
|
|
MCFG_MC68681_IRQ_CALLBACK(WRITELINE(m68307_cpu_device, m68307_duart_irq_handler))
|
|
MCFG_MC68681_A_TX_CALLBACK(WRITELINE(m68307_cpu_device, m68307_duart_txa))
|
|
MCFG_MC68681_B_TX_CALLBACK(WRITELINE(m68307_cpu_device, m68307_duart_txb))
|
|
MCFG_MC68681_INPORT_CALLBACK(READ8(m68307_cpu_device, m68307_duart_input_r))
|
|
MCFG_MC68681_OUTPORT_CALLBACK(WRITE8(m68307_cpu_device, m68307_duart_output_w))
|
|
MACHINE_CONFIG_END
|
|
|
|
|
|
m68307_cpu_device::m68307_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: m68000_device(mconfig, tag, owner, clock, M68307, 16, 24, ADDRESS_MAP_NAME(m68307_internal_map)),
|
|
m_write_irq(*this),
|
|
m_write_a_tx(*this),
|
|
m_write_b_tx(*this),
|
|
m_read_inport(*this),
|
|
m_write_outport(*this),
|
|
m_duart(*this, "internal68681")
|
|
{
|
|
m_m68307SIM = nullptr;
|
|
m_m68307MBUS = nullptr;
|
|
m_m68307TIMER = nullptr;
|
|
m_m68307_base = 0;
|
|
m_m68307_scrhigh = 0;
|
|
m_m68307_scrlow = 0;
|
|
m_m68307_currentcs = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void m68307_cpu_device::device_reset()
|
|
{
|
|
m68000_device::device_reset();
|
|
|
|
if (m_m68307SIM) m_m68307SIM->reset();
|
|
if (m_m68307MBUS) m_m68307MBUS->reset();
|
|
if (m_m68307TIMER) m_m68307TIMER->reset();
|
|
|
|
m_m68307_base = 0xbfff;
|
|
m_m68307_scrhigh = 0x0007;
|
|
m_m68307_scrlow = 0xf010;
|
|
|
|
}
|
|
|
|
|
|
/* todo: is it possible to calculate the address map based on CS when they change
|
|
and install handlers? Going through this logic for every memory access is
|
|
very slow */
|
|
|
|
inline int m68307_cpu_device::calc_cs(offs_t address) const
|
|
{
|
|
m68307_sim const &sim = *m_m68307SIM;
|
|
for (int i=0; i < 4; i++)
|
|
{
|
|
int const br = sim.m_br[i] & 1;
|
|
int const amask = (sim.m_or[i] & 0x1ffc) << 11;
|
|
int const bra = (sim.m_br[i] & 0x1ffc) << 11;
|
|
if (br && ((address & amask) == bra)) return i + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
uint16_t m68307_cpu_device::simple_read_immediate_16_m68307(offs_t address)
|
|
{
|
|
// m_m68307_currentcs = calc_cs(address);
|
|
return m_direct->read_word(address);
|
|
}
|
|
|
|
uint8_t m68307_cpu_device::read_byte_m68307(offs_t address)
|
|
{
|
|
// m_m68307_currentcs = calc_cs(address);
|
|
return m_space->read_byte(address);
|
|
}
|
|
|
|
uint16_t m68307_cpu_device::read_word_m68307(offs_t address)
|
|
{
|
|
// m_m68307_currentcs = calc_cs(address);
|
|
return m_space->read_word(address);
|
|
}
|
|
|
|
uint32_t m68307_cpu_device::read_dword_m68307(offs_t address)
|
|
{
|
|
// m_m68307_currentcs = calc_cs(address);
|
|
return m_space->read_dword(address);
|
|
}
|
|
|
|
void m68307_cpu_device::write_byte_m68307(offs_t address, uint8_t data)
|
|
{
|
|
// m_m68307_currentcs = calc_cs(address);
|
|
m_space->write_byte(address, data);
|
|
}
|
|
|
|
void m68307_cpu_device::write_word_m68307(offs_t address, uint16_t data)
|
|
{
|
|
// m_m68307_currentcs = calc_cs(address);
|
|
m_space->write_word(address, data);
|
|
}
|
|
|
|
void m68307_cpu_device::write_dword_m68307(offs_t address, uint32_t data)
|
|
{
|
|
// m_m68307_currentcs = calc_cs(address);
|
|
m_space->write_dword(address, data);
|
|
}
|
|
|
|
|
|
|
|
|
|
void m68307_cpu_device::init16_m68307(address_space &space)
|
|
{
|
|
m_space = &space;
|
|
m_direct = space.direct<0>();
|
|
m_opcode_xor = 0;
|
|
|
|
m_readimm16 = m68k_readimm16_delegate(&m68307_cpu_device::simple_read_immediate_16_m68307, this);
|
|
m_read8 = m68k_read8_delegate(&m68307_cpu_device::read_byte_m68307, this);
|
|
m_read16 = m68k_read16_delegate(&m68307_cpu_device::read_word_m68307, this);
|
|
m_read32 = m68k_read32_delegate(&m68307_cpu_device::read_dword_m68307, this);
|
|
m_write8 = m68k_write8_delegate(&m68307_cpu_device::write_byte_m68307, this);
|
|
m_write16 = m68k_write16_delegate(&m68307_cpu_device::write_word_m68307, this);
|
|
m_write32 = m68k_write32_delegate(&m68307_cpu_device::write_dword_m68307, this);
|
|
}
|
|
|
|
|
|
|
|
void m68307_cpu_device::set_port_callbacks(
|
|
porta_read_delegate &&porta_r,
|
|
porta_write_delegate &&porta_w,
|
|
portb_read_delegate &&portb_r,
|
|
portb_write_delegate &&portb_w)
|
|
{
|
|
m_porta_r = std::move(porta_r);
|
|
m_porta_w = std::move(porta_w);
|
|
m_portb_r = std::move(portb_r);
|
|
m_portb_w = std::move(portb_w);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t m68307_cpu_device::get_cs(offs_t address)
|
|
{
|
|
m_m68307_currentcs = calc_cs(address);
|
|
|
|
return m_m68307_currentcs;
|
|
}
|
|
|
|
|
|
/* 68307 specifics - MOVE */
|
|
|
|
void m68307_cpu_device::set_interrupt(int level, int vector)
|
|
{
|
|
set_input_line_and_vector(level, HOLD_LINE, vector);
|
|
}
|
|
|
|
void m68307_cpu_device::timer0_interrupt()
|
|
{
|
|
int prioritylevel = (m_m68307SIM->m_picr & 0x7000)>>12;
|
|
int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0xa;
|
|
set_interrupt(prioritylevel, vector);
|
|
}
|
|
|
|
void m68307_cpu_device::timer1_interrupt()
|
|
{
|
|
int prioritylevel = (m_m68307SIM->m_picr & 0x0700)>>8;
|
|
int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0xb;
|
|
set_interrupt(prioritylevel, vector);
|
|
}
|
|
|
|
|
|
void m68307_cpu_device::serial_interrupt(int vector)
|
|
{
|
|
int prioritylevel = (m_m68307SIM->m_picr & 0x0070)>>4;
|
|
set_interrupt(prioritylevel, vector);
|
|
}
|
|
|
|
WRITE_LINE_MEMBER(m68307_cpu_device::m68307_duart_irq_handler)
|
|
{
|
|
if (state == ASSERT_LINE)
|
|
{
|
|
serial_interrupt(m_duart->get_irq_vector());
|
|
}
|
|
}
|
|
|
|
void m68307_cpu_device::mbus_interrupt()
|
|
{
|
|
int prioritylevel = (m_m68307SIM->m_picr & 0x0007)>>0;
|
|
int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0xd;
|
|
set_interrupt(prioritylevel, vector);
|
|
}
|
|
|
|
void m68307_cpu_device::licr2_interrupt()
|
|
{
|
|
int prioritylevel = (m_m68307SIM->m_licr2 & 0x0007)>>0;
|
|
int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0x9;
|
|
m_m68307SIM->m_licr2 |= 0x8;
|
|
|
|
|
|
set_interrupt(prioritylevel, vector);
|
|
}
|
|
|
|
void m68307_cpu_device::device_start()
|
|
{
|
|
init_cpu_m68000();
|
|
|
|
/* basic CS logic, timers, mbus, serial logic
|
|
set via remappable register
|
|
*/
|
|
|
|
init16_m68307(*m_program);
|
|
|
|
m_m68307SIM = new m68307_sim();
|
|
m_m68307MBUS = new m68307_mbus();
|
|
m_m68307TIMER = new m68307_timer();
|
|
|
|
m_m68307TIMER->init(this);
|
|
|
|
m_m68307SIM->reset();
|
|
m_m68307MBUS->reset();
|
|
m_m68307TIMER->reset();
|
|
|
|
m_internal = &space(AS_PROGRAM);
|
|
m_m68307_base = 0xbfff;
|
|
m_m68307_scrhigh = 0x0007;
|
|
m_m68307_scrlow = 0xf010;
|
|
|
|
m_write_irq.resolve_safe();
|
|
m_write_a_tx.resolve_safe();
|
|
m_write_b_tx.resolve_safe();
|
|
m_read_inport.resolve();
|
|
m_write_outport.resolve_safe();
|
|
|
|
set_port_callbacks(porta_read_delegate(), porta_write_delegate(), portb_read_delegate(), portb_write_delegate());
|
|
}
|
|
|
|
|
|
|
|
READ16_MEMBER( m68307_cpu_device::m68307_internal_base_r )
|
|
{
|
|
int pc = space.device().safe_pc();
|
|
logerror("%08x m68307_internal_base_r %08x, (%04x)\n", pc, offset*2,mem_mask);
|
|
|
|
switch (offset<<1)
|
|
{
|
|
case 0x2: return m_m68307_base;
|
|
case 0x4: return m_m68307_scrhigh;
|
|
case 0x6: return m_m68307_scrlow;
|
|
}
|
|
|
|
logerror("(read was illegal?)\n");
|
|
|
|
return 0x0000;
|
|
}
|
|
|
|
WRITE16_MEMBER( m68307_cpu_device::m68307_internal_base_w )
|
|
{
|
|
int pc = space.device().safe_pc();
|
|
logerror("%08x m68307_internal_base_w %08x, %04x (%04x)\n", pc, offset*2,data,mem_mask);
|
|
int base;
|
|
//int mask = 0;
|
|
|
|
switch (offset<<1)
|
|
{
|
|
case 0x2:
|
|
/* remove old internal handler */
|
|
base = (m_m68307_base & 0x0fff) << 12;
|
|
//mask = (m_m68307_base & 0xe000) >> 13;
|
|
//if ( m_m68307_base & 0x1000 ) mask |= 7;
|
|
m_internal->unmap_readwrite(base+0x000, base+0x04f);
|
|
m_internal->unmap_readwrite(base+0x100, base+0x11f);
|
|
m_internal->unmap_readwrite(base+0x120, base+0x13f);
|
|
m_internal->unmap_readwrite(base+0x140, base+0x149);
|
|
|
|
/* store new base address */
|
|
COMBINE_DATA(&m_m68307_base);
|
|
|
|
/* install new internal handler */
|
|
base = (m_m68307_base & 0x0fff) << 12;
|
|
//mask = (m_m68307_base & 0xe000) >> 13;
|
|
//if ( m_m68307_base & 0x1000 ) mask |= 7;
|
|
m_internal->install_readwrite_handler(base + 0x000, base + 0x04f, read16_delegate(FUNC(m68307_cpu_device::m68307_internal_sim_r),this), write16_delegate(FUNC(m68307_cpu_device::m68307_internal_sim_w),this));
|
|
m_internal->install_readwrite_handler(base + 0x100, base + 0x11f, read8_delegate(FUNC(m68307_cpu_device::m68307_internal_serial_r),this), write8_delegate(FUNC(m68307_cpu_device::m68307_internal_serial_w),this), 0xffff);
|
|
m_internal->install_readwrite_handler(base + 0x120, base + 0x13f, read16_delegate(FUNC(m68307_cpu_device::m68307_internal_timer_r),this), write16_delegate(FUNC(m68307_cpu_device::m68307_internal_timer_w),this));
|
|
m_internal->install_readwrite_handler(base + 0x140, base + 0x149, read8_delegate(FUNC(m68307_cpu_device::m68307_internal_mbus_r),this), write8_delegate(FUNC(m68307_cpu_device::m68307_internal_mbus_w),this), 0xffff);
|
|
|
|
|
|
break;
|
|
|
|
case 0x4:
|
|
COMBINE_DATA(&m_m68307_scrhigh);
|
|
break;
|
|
|
|
case 0x6:
|
|
COMBINE_DATA(&m_m68307_scrlow);
|
|
break;
|
|
|
|
default:
|
|
logerror("(write was illegal?)\n");
|
|
break;
|
|
}
|
|
}
|