cmi2x: Modernization and cleanup

- Use interrupt vector read callbacks to handle context switching and special IRQ and RESET vectoring
- Use addressable latch device for CPU function register
This commit is contained in:
AJR 2024-11-01 11:17:31 -04:00
parent 0480765f07
commit ec77693858

View file

@ -91,6 +91,7 @@
#include "machine/6821pia.h"
#include "machine/6850acia.h"
#include "machine/6840ptm.h"
#include "machine/74259.h"
#include "machine/7474.h"
#include "machine/bankdev.h"
#include "machine/clock.h"
@ -257,8 +258,8 @@ public:
void q133_1_portb_w(u8 data);
void cmi_iix_vblank(int state);
IRQ_CALLBACK_MEMBER(cpu1_interrupt_callback);
IRQ_CALLBACK_MEMBER(cpu2_interrupt_callback);
u8 vfetch1_r(offs_t offset);
u8 vfetch2_r(offs_t offset);
// Video-related
u8 video_r(offs_t offset);
@ -290,19 +291,16 @@ public:
// Memory mapping
template<int CpuNum> u8 rom_r(offs_t offset);
void map_ram_w(offs_t offset, u8 data);
template<int CpuNum> u8 vector_r(offs_t offset);
template<int CpuNum> u8 map_r();
template<int CpuNum> void map_w(u8 data);
u8 atomic_r();
void cpufunc_w(u8 data);
template<int CpuNum> void ipi_w(int state);
template<int CpuNum> void nmi_reset_w(int state);
template<int CpuNum> void ms_w(int state);
u8 parity_r(offs_t offset);
void mapsel_w(offs_t offset, u8 data);
template<int CpuNum> u8 irq_ram_r(offs_t offset);
template<int CpuNum> void irq_ram_w(offs_t offset, u8 data);
template<int CpuNum> u8 scratch_ram_r(offs_t offset);
template<int CpuNum> void scratch_ram_w(offs_t offset, u8 data);
template<int CpuNum> u8 scratch_ram_fa_r(offs_t offset);
template<int CpuNum> void scratch_ram_fa_w(offs_t offset, u8 data);
// MIDI/SMPTE
void midi_dma_w(offs_t offset, u16 data, u16 mem_mask = ~0);
@ -432,8 +430,6 @@ private:
int m_cpu_active_space[2]{};
int m_cpu_map_switch[2]{};
u8 m_curr_mapinfo[2]{};
u8 m_irq_address[2][2]{};
int m_m6809_bs_hack_cnt[2]{};
/* Q219 lightpen/graphics card */
std::unique_ptr<u8[]> m_video_ram;
@ -915,11 +911,6 @@ void cmi_state::map_ram_w(offs_t offset, u8 data)
}
}
template<int CpuNum> u8 cmi_state::vector_r(offs_t offset)
{
return m_q133_rom[(CpuNum ? 0xbfe : 0xffe) + offset];
}
template<int CpuNum> u8 cmi_state::map_r()
{
return (m_cpu_active_space[1] << 2) | (m_cpu_active_space[0] << 1) | CpuNum;
@ -930,25 +921,6 @@ template<int CpuNum> void cmi_state::map_w(u8 data)
m_map_switch_timer->adjust(attotime::from_ticks(data & 0xf, M6809_CLOCK), CpuNum);
}
template<int CpuNum> u8 cmi_state::irq_ram_r(offs_t offset)
{
if (machine().side_effects_disabled())
return m_scratch_ram[CpuNum][0xf8 + offset];
if (m_m6809_bs_hack_cnt[CpuNum] > 0)
{
m_m6809_bs_hack_cnt[CpuNum]--;
LOG("CPU%d IRQ vector byte %d (offset %d): %02x\n", CpuNum + 1, 1 - m_m6809_bs_hack_cnt[CpuNum], offset, m_irq_address[CpuNum][offset]);
return m_irq_address[CpuNum][offset];
}
return m_scratch_ram[CpuNum][0xf8 + offset];
}
template<int CpuNum> void cmi_state::irq_ram_w(offs_t offset, u8 data)
{
m_scratch_ram[CpuNum][0xf8 + offset] = data;
}
TIMER_CALLBACK_MEMBER(cmi_state::switch_map)
{
m_cpu_active_space[param] = m_cpu_map_switch[param];
@ -972,26 +944,19 @@ u8 cmi_state::atomic_r()
return 0;
}
void cmi_state::cpufunc_w(u8 data)
template<int CpuNum> void cmi_state::ipi_w(int state)
{
int cpunum = data & 1;
int idx = data & 6;
int bit = (data & 8) >> 3;
set_interrupt(CpuNum, IRQ_IPI2_LEVEL, state ? ASSERT_LINE : CLEAR_LINE);
}
switch (idx)
{
case 0: set_interrupt(cpunum, IRQ_IPI2_LEVEL, bit ? ASSERT_LINE : CLEAR_LINE);
break;
case 2: // TODO: Hardware trace
break;
case 4: m_cpu_map_switch[cpunum] = bit;
break;
case 6: if (cpunum == CPU_1)
m_maincpu1->set_input_line(M6809_FIRQ_LINE, bit ? ASSERT_LINE : CLEAR_LINE);
else
m_maincpu2->set_input_line(M6809_FIRQ_LINE, bit ? ASSERT_LINE : CLEAR_LINE);
break;
}
template<int CpuNum> void cmi_state::nmi_reset_w(int state)
{
// TODO: Hardware trace
}
template<int CpuNum> void cmi_state::ms_w(int state)
{
m_cpu_map_switch[CpuNum] = state;
}
u8 cmi_state::parity_r(offs_t offset)
@ -1140,7 +1105,7 @@ template <int CpuNum> void cmi_state::cpu_periphs_map(address_map &map)
map(0x0800, 0x0bff).rom().region("q133", 0x2800 - CpuNum * 0x1000);
map(0x0c40, 0x0c4f).rw(FUNC(cmi_state::parity_r), FUNC(cmi_state::mapsel_w));
map(0x0c5a, 0x0c5b).noprw(); // Q077 HDD controller - not installed
map(0x0c5e, 0x0c5e).rw(FUNC(cmi_state::atomic_r), FUNC(cmi_state::cpufunc_w));
map(0x0c5e, 0x0c5e).r(FUNC(cmi_state::atomic_r)).w("cpulatch", FUNC(ls259_device::write_nibble_d3));
map(0x0c5f, 0x0c5f).rw(FUNC(cmi_state::map_r<CpuNum>), FUNC(cmi_state::map_w<CpuNum>));
map(0x0c80, 0x0c83).rw(m_q133_acia[0], FUNC(mos6551_device::read), FUNC(mos6551_device::write));
map(0x0c84, 0x0c87).rw(m_q133_acia[1], FUNC(mos6551_device::read), FUNC(mos6551_device::write));
@ -1160,10 +1125,7 @@ template <int CpuNum> void cmi_state::cpu_periphs_map(address_map &map)
map(0x0cfc, 0x0cfc).w(FUNC(cmi_state::i8214_cpu1_w));
map(0x0cfd, 0x0cfd).w(FUNC(cmi_state::i8214_cpu2_w));
map(0x0d00, 0x0eff).rw(FUNC(cmi_state::shared_ram_r), FUNC(cmi_state::shared_ram_w));
map(0x0f00, 0x0ff7).rw(FUNC(cmi_state::scratch_ram_r<CpuNum>), FUNC(cmi_state::scratch_ram_w<CpuNum>));
map(0x0ff8, 0x0ff9).rw(FUNC(cmi_state::irq_ram_r<CpuNum>), FUNC(cmi_state::irq_ram_w<CpuNum>));
map(0x0ffa, 0x0ffd).rw(FUNC(cmi_state::scratch_ram_fa_r<CpuNum>), FUNC(cmi_state::scratch_ram_fa_w<CpuNum>));
map(0x0ffe, 0x0fff).r(FUNC(cmi_state::vector_r<CpuNum>));
map(0x0f00, 0x0fff).rw(FUNC(cmi_state::scratch_ram_r<CpuNum>), FUNC(cmi_state::scratch_ram_w<CpuNum>));
}
/* Input ports */
@ -1188,16 +1150,6 @@ template <int CpuNum> void cmi_state::scratch_ram_w(offs_t offset, u8 data)
m_scratch_ram[CpuNum][offset] = data;
}
template <int CpuNum> u8 cmi_state::scratch_ram_fa_r(offs_t offset)
{
return m_scratch_ram[CpuNum][0xfa + offset];
}
template <int CpuNum> void cmi_state::scratch_ram_fa_w(offs_t offset, u8 data)
{
m_scratch_ram[CpuNum][0xfa + offset] = data;
}
bool cmi_state::map_is_active(int cpunum, int map, u8 *map_info)
{
if (m_cpu_active_space[cpunum] == MAPPING_A)
@ -1720,48 +1672,57 @@ void cmi_state::ptm_q219_irq(int state)
set_interrupt(CPU_2, IRQ_RINT_LEVEL, state);
}
IRQ_CALLBACK_MEMBER( cmi_state::cpu1_interrupt_callback )
u8 cmi_state::vfetch1_r(offs_t offset)
{
/* Switch to mapping A */
// Switch to mapping A
m_cpu_active_space[CPU_1] = MAPPING_A;
update_address_space(CPU_1, m_map_sel[MAPSEL_P1_A]);
if (irqline == INPUT_LINE_IRQ0)
if ((offset & 0x000e) == 0x0008)
{
// IRQ vector
int vector = (m_hp_int ? 0xffe0 : 0xffd0);
int level = (m_hp_int ? m_i8214[2]->a_r() : m_i8214[0]->a_r()) ^ 7;
m_irq_address[CPU_1][0] = m_cpu1space->read_byte(vector + level*2);
m_irq_address[CPU_1][1] = m_cpu1space->read_byte(vector + level*2 + 1);
m_m6809_bs_hack_cnt[CPU_1] = 2;
LOG("%s: CPU1 interrupt, will be pushing address %02x%02x\n", machine().describe_context(), m_irq_address[CPU_1][0], m_irq_address[CPU_1][1]);
u8 irq_address = m_cpu1space->read_byte(vector + level * 2 + BIT(offset, 0));
LOG("%s: CPU1 IRQ vector %s byte: %02x\n", machine().describe_context(), BIT(offset, 0) ? "low" : "high", irq_address);
return irq_address;
}
else if ((offset & 0x000e) == 0x000e)
{
// RESET vector
return m_q133_rom[offset & 0xfff];
}
else
{
LOG("%s: Some other CPU1 interrupt, line %d\n", irqline);
LOG("%s: Some other CPU1 interrupt, fetching vector from $%04x\n", machine().describe_context(), offset);
return m_scratch_ram[CPU_1][offset & 0xff];
}
return 0;
}
IRQ_CALLBACK_MEMBER( cmi_state::cpu2_interrupt_callback )
u8 cmi_state::vfetch2_r(offs_t offset)
{
/* Switch to mapping A */
// Switch to mapping A
m_cpu_active_space[CPU_2] = MAPPING_A;
update_address_space(CPU_2, m_map_sel[MAPSEL_P2_A]);
if (irqline == INPUT_LINE_IRQ0)
if ((offset & 0x000e) == 0x0008)
{
// IRQ vector
int level = m_i8214[1]->a_r() ^ 7;
m_irq_address[CPU_2][0] = m_cpu2space->read_byte(0xffe0 + level*2);
m_irq_address[CPU_2][1] = m_cpu2space->read_byte(0xffe0 + level*2 + 1);
m_m6809_bs_hack_cnt[CPU_2] = 2;
//osd_printf_debug("cpu1 interrupt, will be pushing address %02x%02x\n", m_irq_address[CPU_2][0], m_irq_address[CPU_2][1]);
u8 irq_address = m_cpu2space->read_byte(0xffe0 + level*2 + BIT(offset, 0));
LOG("%s: CPU2 IRQ vector %s byte: %02x (%s)\n", machine().describe_context(), BIT(offset, 0) ? "low" : "high", irq_address);
return irq_address;
}
else if ((offset & 0x000e) == 0x000e)
{
// RESET vector
return m_q133_rom[offset & 0xbff];
}
else
{
LOG("%s: Some other CPU2 interrupt, fetching vector from $%04x\n", machine().describe_context(), offset);
return m_scratch_ram[CPU_2][offset & 0xff];
}
return 0;
}
void cmi_state::set_interrupt(int cpunum, int level, int state)
@ -1931,9 +1892,6 @@ void cmi_state::machine_reset()
/* Select A (system) spaces */
m_cpu_active_space[cpunum] = MAPPING_A;
m_irq_address[cpunum][0] = space->read_byte(0xfff8);
m_irq_address[cpunum][1] = space->read_byte(0xfff9);
}
// TODO - we need to detect empty disk drive!!
@ -1954,8 +1912,6 @@ void cmi_state::machine_reset()
m_cmi02_ptm->set_g1(0);
m_cmi02_ptm->set_g2(0);
m_cmi02_ptm->set_g3(0);
m_m6809_bs_hack_cnt[0] = 0;
m_m6809_bs_hack_cnt[1] = 0;
//m_midi_ptm[0]->set_g1(1); // /G1 has unknown source, "TIMER 1A /GATE" per schematic
m_midi_ptm[0]->set_g2(0); // /G2 and /G3 wired to ground per schematic
@ -2034,11 +1990,11 @@ void cmi_state::cmi2x(machine_config &config)
{
MC6809E(config, m_maincpu1, Q209_CPU_CLOCK);
m_maincpu1->set_addrmap(AS_PROGRAM, &cmi_state::maincpu1_map);
m_maincpu1->set_irq_acknowledge_callback(FUNC(cmi_state::cpu1_interrupt_callback));
m_maincpu1->interrupt_vector_read().set(FUNC(cmi_state::vfetch1_r));
MC6809E(config, m_maincpu2, Q209_CPU_CLOCK);
m_maincpu2->set_addrmap(AS_PROGRAM, &cmi_state::maincpu2_map);
m_maincpu2->set_irq_acknowledge_callback(FUNC(cmi_state::cpu2_interrupt_callback));
m_maincpu2->interrupt_vector_read().set(FUNC(cmi_state::vfetch2_r));
ADDRESS_MAP_BANK(config, m_cpu_periphs[0]).set_options(ENDIANNESS_BIG, 8, 16, 0x1000);
m_cpu_periphs[0]->set_addrmap(AS_PROGRAM, &cmi_state::cpu_periphs_map<0>);
@ -2046,6 +2002,16 @@ void cmi_state::cmi2x(machine_config &config)
ADDRESS_MAP_BANK(config, m_cpu_periphs[1]).set_options(ENDIANNESS_BIG, 8, 16, 0x1000);
m_cpu_periphs[1]->set_addrmap(AS_PROGRAM, &cmi_state::cpu_periphs_map<1>);
ls259_device &cpulatch(LS259(config, "cpulatch")); // 6D (Q209)
cpulatch.q_out_cb<0>().set(FUNC(cmi_state::ipi_w<0>));
cpulatch.q_out_cb<1>().set(FUNC(cmi_state::ipi_w<1>));
cpulatch.q_out_cb<2>().set(FUNC(cmi_state::nmi_reset_w<0>));
cpulatch.q_out_cb<3>().set(FUNC(cmi_state::nmi_reset_w<1>));
cpulatch.q_out_cb<4>().set(FUNC(cmi_state::ms_w<0>));
cpulatch.q_out_cb<5>().set(FUNC(cmi_state::ms_w<1>));
cpulatch.q_out_cb<6>().set_inputline(m_maincpu1, M6809_FIRQ_LINE);
cpulatch.q_out_cb<7>().set_inputline(m_maincpu2, M6809_FIRQ_LINE);
M68000(config, m_midicpu, 20_MHz_XTAL / 2);
m_midicpu->set_addrmap(AS_PROGRAM, &cmi_state::midicpu_map);