summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/mc68hc11/mc68hc11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/mc68hc11/mc68hc11.cpp')
-rw-r--r--src/devices/cpu/mc68hc11/mc68hc11.cpp393
1 files changed, 280 insertions, 113 deletions
diff --git a/src/devices/cpu/mc68hc11/mc68hc11.cpp b/src/devices/cpu/mc68hc11/mc68hc11.cpp
index c4768d25765..7843b26dd75 100644
--- a/src/devices/cpu/mc68hc11/mc68hc11.cpp
+++ b/src/devices/cpu/mc68hc11/mc68hc11.cpp
@@ -1,23 +1,28 @@
// license:BSD-3-Clause
-// copyright-holders:Ville Linde, Angelo Salese
+// copyright-holders:Ville Linde, Angelo Salese, AJR
/*
Motorola MC68HC11 emulator
Written by Ville Linde & Angelo Salese
TODO:
-- Interrupts handling is really bare-bones, just to make Hit Poker happy;
-- Timers are really sketchy as per now, only TOC1 is emulated so far;
+- Timers are really sketchy as per now;
- Complete opcodes hook-up;
- Emulate the MC68HC12 (same as HC11 with a bunch of new opcodes);
*/
#include "emu.h"
-#include "debugger.h"
#include "mc68hc11.h"
#include "hc11dasm.h"
+#include <tuple>
+
+#define LOG_IRQ (1U << 1)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
enum
{
HC11_PC = 1,
@@ -47,6 +52,7 @@ static const int div_tab[4] = { 1, 4, 8, 16 };
DEFINE_DEVICE_TYPE(MC68HC11A1, mc68hc11a1_device, "mc68hc11a1", "Motorola MC68HC11A1")
DEFINE_DEVICE_TYPE(MC68HC11D0, mc68hc11d0_device, "mc68hc11d0", "Motorola MC68HC11D0")
+DEFINE_DEVICE_TYPE(MC68HC11E1, mc68hc11e1_device, "mc68hc11e1", "Motorola MC68HC11E1")
DEFINE_DEVICE_TYPE(MC68HC811E2, mc68hc811e2_device, "mc68hc811e2", "Motorola MC68HC811E2")
DEFINE_DEVICE_TYPE(MC68HC11F1, mc68hc11f1_device, "mc68hc11f1", "Motorola MC68HC11F1")
DEFINE_DEVICE_TYPE(MC68HC11K1, mc68hc11k1_device, "mc68hc11k1", "Motorola MC68HC11K1")
@@ -55,14 +61,18 @@ DEFINE_DEVICE_TYPE(MC68HC11M0, mc68hc11m0_device, "mc68hc11m0", "Motorola MC68HC
mc68hc11_cpu_device::mc68hc11_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint16_t ram_size, uint16_t reg_block_size, uint16_t rom_size, uint16_t eeprom_size, uint8_t init_value, uint8_t config_mask, uint8_t option_mask)
: cpu_device(mconfig, type, tag, owner, clock)
+ , device_nvram_interface(mconfig, *this, (config_mask & 0xf9) != 0)
, m_program_config("program", ENDIANNESS_BIG, 8, 16, 0, address_map_constructor(FUNC(mc68hc11_cpu_device::internal_map), this))
- , m_port_input_cb(*this)
+ , m_irq_asserted(false)
+ , m_port_input_cb(*this, 0xff)
, m_port_output_cb(*this)
- , m_analog_cb(*this)
- , m_spi2_data_input_cb(*this)
+ , m_analog_cb(*this, 0)
+ , m_spi2_data_input_cb(*this, 0xff)
, m_spi2_data_output_cb(*this)
, m_ram_view(*this, "ram")
, m_reg_view(*this, "regs")
+ , m_eeprom_view(*this, "eeprom")
+ , m_eeprom_data(*this, "eeprom")
, m_internal_ram_size(ram_size)
, m_reg_block_size(reg_block_size)
, m_internal_rom_size(rom_size)
@@ -70,17 +80,13 @@ mc68hc11_cpu_device::mc68hc11_cpu_device(const machine_config &mconfig, device_t
, m_init_value(init_value)
, m_config_mask(config_mask)
, m_option_mask(option_mask)
- , m_config(config_mask)
+ , m_config(config_mask & (m_internal_rom_size == 0 ? 0xfd : 0xff) & (m_internal_eeprom_size == 0 ? 0xfe : 0xff))
{
- if (m_internal_rom_size == 0)
- m_config &= 0xfd;
- if (m_internal_eeprom_size == 0)
- m_config &= 0xfe;
}
void mc68hc11_cpu_device::internal_map(address_map &map)
{
- // TODO: internal ROM & EEPROM
+ // TODO: internal ROM
map(0x0000, 0xffff).view(m_ram_view);
for (int pos = 0; pos < 16; pos++)
@@ -89,6 +95,17 @@ void mc68hc11_cpu_device::internal_map(address_map &map)
for (int pos = 0; pos < 16; pos++)
m_ram_view[pos + 16]((pos << 12) + m_reg_block_size, (pos << 12) + m_reg_block_size + m_internal_ram_size - 1).ram().share("ram");
+ if (m_internal_eeprom_size != 0)
+ {
+ // TODO: allow EEPROM writes in programming mode only, latching address and data
+ map(0x0000, 0xffff).view(m_eeprom_view);
+ if ((m_config_mask & 0xf0) == 0)
+ m_eeprom_view[0](0xb600, 0xb7ff).ram().share(m_eeprom_data);
+ else
+ for (int pos = 0; pos < 16; pos++)
+ m_eeprom_view[pos](((pos + 1) << 12) - m_internal_eeprom_size, ((pos + 1) << 12) - 1).ram().share(m_eeprom_data);
+ }
+
map(0x0000, 0xffff).view(m_reg_view);
for (int pos = 0; pos < 16; pos++)
{
@@ -107,6 +124,11 @@ mc68hc11d0_device::mc68hc11d0_device(const machine_config &mconfig, const char *
{
}
+mc68hc11e1_device::mc68hc11e1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mc68hc11_cpu_device(mconfig, MC68HC11E1, tag, owner, clock, 512, 64, 0, 512, 0x01, 0x0f, 0xfb)
+{
+}
+
mc68hc811e2_device::mc68hc811e2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc68hc11_cpu_device(mconfig, MC68HC811E2, tag, owner, clock, 256, 64, 0, 2048, 0x01, 0xf5, 0xfb)
{
@@ -115,6 +137,7 @@ mc68hc811e2_device::mc68hc811e2_device(const machine_config &mconfig, const char
mc68hc11f1_device::mc68hc11f1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc68hc11_cpu_device(mconfig, MC68HC11F1, tag, owner, clock, 1024, 96, 0, 512, 0x01, 0xf5, 0xff)
{
+ m_config &= 0x0f;
}
mc68hc11k1_device::mc68hc11k1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
@@ -134,18 +157,58 @@ device_memory_interface::space_config_vector mc68hc11_cpu_device::memory_space_c
};
}
-void mc68hc11_cpu_device::device_resolve_objects()
+std::unique_ptr<util::disasm_interface> mc68hc11_cpu_device::create_disassembler()
{
- m_port_input_cb.resolve_all_safe(0xff);
- m_port_output_cb.resolve_all_safe();
- m_analog_cb.resolve_all_safe(0);
- m_spi2_data_input_cb.resolve_safe(0xff);
- m_spi2_data_output_cb.resolve_safe();
+ return std::make_unique<hc11_disassembler>();
}
-std::unique_ptr<util::disasm_interface> mc68hc11_cpu_device::create_disassembler()
+
+bool mc68hc11_cpu_device::nvram_read(util::read_stream &file)
{
- return std::make_unique<hc11_disassembler>();
+ std::error_condition err;
+ size_t actual;
+
+ std::tie(err, actual) = read(file, &m_eeprom_data[0], m_internal_eeprom_size);
+ if (err || (actual != m_internal_eeprom_size))
+ return false;
+
+ std::tie(err, actual) = read(file, &m_config, 1);
+ if (err || (actual != 1))
+ return false;
+
+ return true;
+}
+
+bool mc68hc11_cpu_device::nvram_write(util::write_stream &file)
+{
+ std::error_condition err;
+ size_t actual;
+
+ std::tie(err, actual) = write(file, &m_eeprom_data[0], m_internal_eeprom_size);
+ if (err)
+ return false;
+
+ std::tie(err, actual) = write(file, &m_config, 1);
+ if (err)
+ return false;
+
+ return true;
+}
+
+void mc68hc11_cpu_device::nvram_default()
+{
+ if ((m_config_mask & 0xf9) == 0)
+ return;
+
+ if (m_internal_eeprom_size != 0)
+ {
+ // use region if it exists
+ memory_region *region = memregion("eeprom");
+ if (region != nullptr)
+ std::copy_n(&region->as_u8(), m_internal_eeprom_size, &m_eeprom_data[0]);
+ else
+ std::fill_n(&m_eeprom_data[0], m_internal_eeprom_size, 0xff);
+ }
}
@@ -272,6 +335,9 @@ uint8_t mc68hc11_cpu_device::tmsk1_r()
void mc68hc11_cpu_device::tmsk1_w(uint8_t data)
{
+ for (int i = 0; i < 5; i++)
+ if (BIT(m_tflg1 & (m_tmsk1 ^ data), 7 - i))
+ set_irq_state(0x0b + i, BIT(data, 7 - i));
m_tmsk1 = data;
}
@@ -282,6 +348,9 @@ uint8_t mc68hc11_cpu_device::tflg1_r()
void mc68hc11_cpu_device::tflg1_w(uint8_t data)
{
+ for (int i = 0; i < 5; i++)
+ if (BIT(m_tflg1 & data, 7 - i))
+ set_irq_state(0x0b + i, false);
m_tflg1 &= ~data;
}
@@ -292,6 +361,10 @@ uint8_t mc68hc11_cpu_device::tflg2_r()
void mc68hc11_cpu_device::tflg2_w(uint8_t data)
{
+ if (BIT(m_tflg2 & data, 7))
+ set_irq_state(0x10, false);
+ if (BIT(m_tflg2 & data, 6))
+ set_irq_state(0x07, false);
m_tflg2 &= ~data;
}
@@ -302,6 +375,11 @@ uint8_t mc68hc11_cpu_device::tmsk2_r()
void mc68hc11_cpu_device::tmsk2_w(uint8_t data)
{
+ if (BIT(m_tflg2 & (m_tmsk2 ^ data), 7))
+ set_irq_state(0x10, BIT(data, 7));
+ if (BIT(m_tflg2 & (m_tmsk2 ^ data), 6))
+ set_irq_state(0x07, BIT(data, 6));
+
// TODO: prescaler bits are time-protected
m_tmsk2 = data;
}
@@ -369,7 +447,15 @@ uint8_t mc68hc11_cpu_device::config_1s_r()
void mc68hc11_cpu_device::config_w(uint8_t data)
{
+ // TODO: CONFIG also has EEPROM protection
m_config = data & m_config_mask;
+ if (m_internal_eeprom_size != 0)
+ {
+ if (BIT(m_config, 0))
+ m_eeprom_view.select(((m_config_mask & 0xf0) == 0xb0 ? m_init2 : m_config) >> 4);
+ else
+ m_eeprom_view.disable();
+ }
}
uint8_t mc68hc11_cpu_device::init_r()
@@ -397,6 +483,19 @@ void mc68hc11_cpu_device::init_w(uint8_t data)
}
}
+uint8_t mc68hc11_cpu_device::init2_r()
+{
+ return m_init2;
+}
+
+void mc68hc11_cpu_device::init2_w(uint8_t data)
+{
+ m_init2 = data & 0xf0;
+ assert(m_internal_eeprom_size != 0);
+ if (BIT(m_config, 0))
+ m_eeprom_view.select(data >> 4);
+}
+
uint8_t mc68hc11_cpu_device::option_r()
{
return m_option;
@@ -511,6 +610,40 @@ void mc68hc11d0_device::mc68hc11_reg_map(memory_view::memory_view_entry &block,
block(base + 0x3f, base + 0x3f).rw(FUNC(mc68hc11d0_device::config_r), FUNC(mc68hc11d0_device::config_w)); // CONFIG
}
+void mc68hc11e1_device::mc68hc11_reg_map(memory_view::memory_view_entry &block, offs_t base)
+{
+ block(base + 0x00, base + 0x00).rw(FUNC(mc68hc11e1_device::port_r<0>), FUNC(mc68hc11e1_device::port_w<0>)); // PORTA
+ block(base + 0x02, base + 0x02).r(FUNC(mc68hc11e1_device::pioc_r)); // PIOC
+ block(base + 0x03, base + 0x03).rw(FUNC(mc68hc11e1_device::port_r<2>), FUNC(mc68hc11e1_device::port_w<2>)); // PORTC
+ block(base + 0x04, base + 0x04).rw(FUNC(mc68hc11e1_device::port_r<1>), FUNC(mc68hc11e1_device::port_w<1>)); // PORTB
+ block(base + 0x05, base + 0x05).nopw(); // PORTCL
+ block(base + 0x07, base + 0x07).rw(FUNC(mc68hc11e1_device::ddr_r<2>), FUNC(mc68hc11e1_device::ddr_w<2>)); // DDRC
+ block(base + 0x08, base + 0x08).rw(FUNC(mc68hc11e1_device::port_r<3>), FUNC(mc68hc11e1_device::port_w<3>)); // PORTD
+ block(base + 0x09, base + 0x09).rw(FUNC(mc68hc11e1_device::ddr_r<3>), FUNC(mc68hc11e1_device::ddr_w<3>)); // DDRD
+ block(base + 0x0a, base + 0x0a).r(FUNC(mc68hc11e1_device::port_r<4>)); // PORTE
+ block(base + 0x0e, base + 0x0f).rw(FUNC(mc68hc11e1_device::tcnt_r), FUNC(mc68hc11e1_device::tcnt_w)); // TCNT
+ block(base + 0x16, base + 0x1f).rw(FUNC(mc68hc11e1_device::toc_r), FUNC(mc68hc11e1_device::toc_w)); // TOC1-TOC4, TI4/O5
+ block(base + 0x20, base + 0x20).rw(FUNC(mc68hc11e1_device::tctl1_r), FUNC(mc68hc11e1_device::tctl1_w)); // TCTL1
+ block(base + 0x21, base + 0x21).rw(FUNC(mc68hc11e1_device::tctl2_r), FUNC(mc68hc11e1_device::tctl2_w)); // TCTL2
+ block(base + 0x22, base + 0x22).rw(FUNC(mc68hc11e1_device::tmsk1_r), FUNC(mc68hc11e1_device::tmsk1_w)); // TMSK1
+ block(base + 0x23, base + 0x23).rw(FUNC(mc68hc11e1_device::tflg1_r), FUNC(mc68hc11e1_device::tflg1_w)); // TFLG1
+ block(base + 0x24, base + 0x24).rw(FUNC(mc68hc11e1_device::tmsk2_r), FUNC(mc68hc11e1_device::tmsk2_w)); // TMSK2
+ block(base + 0x25, base + 0x25).rw(FUNC(mc68hc11e1_device::tflg2_r), FUNC(mc68hc11e1_device::tflg2_w)); // TFLG2
+ block(base + 0x26, base + 0x26).rw(FUNC(mc68hc11e1_device::pactl_ddra_r), FUNC(mc68hc11e1_device::pactl_ddra_w)); // PACTL
+ block(base + 0x28, base + 0x28).r(FUNC(mc68hc11e1_device::spcr_r<0>)).nopw(); // SPCR
+ block(base + 0x29, base + 0x29).r(FUNC(mc68hc11e1_device::spsr_r<0>)).nopw(); // SPSR
+ block(base + 0x2a, base + 0x2a).rw(FUNC(mc68hc11e1_device::spdr_r<0>), FUNC(mc68hc11e1_device::spdr_w<0>)); // SPDR
+ block(base + 0x2c, base + 0x2c).r(FUNC(mc68hc11e1_device::sccr1_r)).nopw(); // SCCR1
+ block(base + 0x2d, base + 0x2d).r(FUNC(mc68hc11e1_device::sccr2_r)).nopw(); // SCCR2
+ block(base + 0x30, base + 0x30).rw(FUNC(mc68hc11e1_device::adctl_r), FUNC(mc68hc11e1_device::adctl_w)); // ADCTL
+ block(base + 0x31, base + 0x34).r(FUNC(mc68hc11e1_device::adr_r)); // ADR1-ADR4
+ block(base + 0x39, base + 0x39).rw(FUNC(mc68hc11e1_device::option_r), FUNC(mc68hc11e1_device::option_w)); // OPTION
+ block(base + 0x3a, base + 0x3a).nopw(); // COPRST (watchdog)
+ block(base + 0x3b, base + 0x3b).nopw(); // PPROG (EEPROM programming)
+ block(base + 0x3d, base + 0x3d).rw(FUNC(mc68hc11e1_device::init_r), FUNC(mc68hc11e1_device::init_w)); // INIT
+ block(base + 0x3f, base + 0x3f).rw(FUNC(mc68hc11e1_device::config_r), FUNC(mc68hc11e1_device::config_w)); // CONFIG
+}
+
void mc68hc811e2_device::mc68hc11_reg_map(memory_view::memory_view_entry &block, offs_t base)
{
block(base + 0x00, base + 0x00).rw(FUNC(mc68hc811e2_device::port_r<0>), FUNC(mc68hc811e2_device::port_w<0>)); // PORTA
@@ -626,6 +759,7 @@ void mc68hc11k1_device::mc68hc11_reg_map(memory_view::memory_view_entry &block,
block(base + 0x2a, base + 0x2a).rw(FUNC(mc68hc11k1_device::spdr_r<0>), FUNC(mc68hc11k1_device::spdr_w<0>)); // SPDR
block(base + 0x30, base + 0x30).rw(FUNC(mc68hc11k1_device::adctl_r), FUNC(mc68hc11k1_device::adctl_w)); // ADCTL
block(base + 0x31, base + 0x34).r(FUNC(mc68hc11k1_device::adr_r)); // ADR1-ADR4
+ block(base + 0x37, base + 0x37).rw(FUNC(mc68hc11k1_device::init2_r), FUNC(mc68hc11k1_device::init2_w)); // INIT2
block(base + 0x38, base + 0x38).r(FUNC(mc68hc11k1_device::opt2_r)).nopw(); // OPT2
block(base + 0x39, base + 0x39).rw(FUNC(mc68hc11k1_device::option_r), FUNC(mc68hc11k1_device::option_w)); // OPTION
block(base + 0x3a, base + 0x3a).nopw(); // COPRST (watchdog)
@@ -778,6 +912,7 @@ void mc68hc11_cpu_device::device_start()
save_item(NAME(m_ad_channel));
save_item(NAME(m_init));
save_item(NAME(m_irq_state));
+ save_item(NAME(m_irq_asserted));
save_item(NAME(m_wait_state));
save_item(NAME(m_stop_state));
save_item(NAME(m_tctl1));
@@ -796,6 +931,8 @@ void mc68hc11_cpu_device::device_start()
save_item(NAME(m_port_dir));
save_item(NAME(m_config));
save_item(NAME(m_option));
+ if ((m_config_mask & 0xf0) == 0xb0)
+ save_item(NAME(m_init2));
m_pc = 0;
m_d.d16 = 0;
@@ -805,8 +942,9 @@ void mc68hc11_cpu_device::device_start()
m_ppc = 0;
m_adctl = 0;
m_ad_channel = 0;
- std::fill(std::begin(m_irq_state), std::end(m_irq_state), CLEAR_LINE);
+ m_irq_state = 0;
m_init = 0;
+ m_init2 = 0;
m_option = 0;
m_tflg1 = 0;
m_tmsk1 = 0;
@@ -855,8 +993,26 @@ void mc68hc11_cpu_device::state_string_export(const device_state_entry &entry, s
void mc68hc11_cpu_device::device_reset()
{
- m_pc = READ16(0xfffe); // TODO: vectors differ in bootstrap and special test modes
- m_wait_state = 0;
+ if ((m_config_mask & 0xf9) == 0)
+ {
+ m_config = m_config_mask;
+ if (m_internal_rom_size == 0)
+ m_config &= 0xfd;
+ }
+ else
+ {
+ if ((m_config_mask & 0xf0) == 0xb0)
+ m_init2 = 0;
+ if (m_internal_eeprom_size != 0)
+ {
+ if (BIT(m_config, 0))
+ m_eeprom_view.select(m_config_mask < 0xf0 ? 0 : m_config >> 4);
+ else
+ m_eeprom_view.disable();
+ }
+ }
+
+ m_wait_state = 1;
m_stop_state = 0;
m_ccr = CC_X | CC_I | CC_S;
init_w(m_init_value);
@@ -870,6 +1026,9 @@ void mc68hc11_cpu_device::device_reset()
m_tflg2 = 0;
m_tmsk2 = 3; // timer prescale
m_pactl = 0;
+ m_irq_state = 0x80000000 | (m_irq_state & 0x04000000);
+ if (m_irq_asserted)
+ set_irq_state(0x06, true);
m_frc_base = m_reset_time = total_cycles();
std::fill(std::begin(m_port_dir), std::end(m_port_dir), 0x00);
}
@@ -890,10 +1049,9 @@ void mc68hc11d0_device::device_reset()
m_port_data[0] &= 0x8f;
ddr_w<0>(0x70);
- m_config = 0x00;
}
-void mc68hc811e2_device::device_reset()
+void mc68hc11e1_device::device_reset()
{
mc68hc11_cpu_device::device_reset();
@@ -903,68 +1061,61 @@ void mc68hc811e2_device::device_reset()
ddr_w<1>(0xff);
}
-void mc68hc11f1_device::device_reset()
+void mc68hc811e2_device::device_reset()
{
mc68hc11_cpu_device::device_reset();
- m_option = 0x00;
+ m_port_data[0] &= 0x8f;
+ m_port_data[1] = 0x00;
+ ddr_w<0>(0x70);
+ ddr_w<1>(0xff);
}
-void mc68hc11m0_device::device_reset()
+void mc68hc11f1_device::device_reset()
{
mc68hc11_cpu_device::device_reset();
- m_config = 0x04;
+ m_option = 0x00;
}
-/*
-IRQ table vectors:
-0xffd6: SCI
-0xffd8: SPI
-0xffda: Pulse Accumulator Input Edge
-0xffdc: Pulse Accumulator Overflow
-0xffde: Timer Overflow
-0xffe0: Timer Output Capture 5
-0xffe2: Timer Output Capture 4
-0xffe4: Timer Output Capture 3
-0xffe6: Timer Output Capture 2
-0xffe8: Timer Output Capture 1
-0xffea: Timer Input Capture 3
-0xffec: Timer Input Capture 2
-0xffee: Timer Input Capture 1
-0xfff0: Real Time Int
-0xfff2: IRQ
-0xfff4: XIRQ
-0xfff6: SWI (Trap IRQ)
-0xfff8: Illegal Opcode (NMI)
-0xfffa: CO-Processor Fail
-0xfffc: Clock Monitor
-0xfffe: RESET
-*/
+static const char *const s_irq_names[32] =
+{
+ "RESET", // vectored from $FFFE,FF
+ "Clock Monitor", // vectored from $FFFC,FD
+ "COP Failure", // vectored from $FFFA,FB
+ "Illegal Opcode", // vectored from $FFF8,F9
+ "SWI", // vectored from $FFF6,F7
+ "XIRQ", // vectored from $FFF4,F5
+ "IRQ", // vectored from $FFF2,F3
+ "RTI", // vectored from $FFF0,F1
+ "IC1", // vectored from $FFEE,EF
+ "IC2", // vectored from $FFEC,ED
+ "IC3", // vectored from $FFEA,EB
+ "OC1", // vectored from $FFE8,E9
+ "OC2", // vectored from $FFE6,E7
+ "OC3", // vectored from $FFE4,E5
+ "OC4", // vectored from $FFE2,E3
+ "OC5", // vectored from $FFE0,E1
+ "Timer Overflow", // vectored from $FFDE,DF
+ "PAOV", // vectored from $FFDC,DD
+ "PAI", // vectored from $FFDA,DB
+ "SPI", // vectored from $FFD8,D9
+ "SCI", // vectored from $FFD6,F7
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved"
+};
void mc68hc11_cpu_device::check_irq_lines()
{
- if( m_irq_state[MC68HC11_IRQ_LINE]!=CLEAR_LINE && (!(m_ccr & CC_I)) )
- {
- uint16_t pc_vector;
-
- if(m_wait_state == 0)
- {
- PUSH16(m_pc);
- PUSH16(m_iy);
- PUSH16(m_ix);
- PUSH8(REG_A);
- PUSH8(REG_B);
- PUSH8(m_ccr);
- }
- pc_vector = READ16(0xfff2);
- SET_PC(pc_vector);
- m_ccr |= CC_I; //irq taken, mask the flag
- if(m_wait_state == 1) { m_wait_state = 2; }
- if(m_stop_state == 1) { m_stop_state = 2; }
- standard_irq_callback(MC68HC11_IRQ_LINE);
- }
-
/* check timers here */
{
int divider = div_tab[m_tmsk2 & 3];
@@ -976,49 +1127,39 @@ void mc68hc11_cpu_device::check_irq_lines()
if ((((cur_time - m_reset_time) ^ (m_frc_base - m_reset_time)) >> ((m_pactl & 3) + 13)) > 0)
{
m_tflg2 |= 0x40;
- m_irq_state[MC68HC11_RTI_LINE] = ASSERT_LINE;
+ if (BIT(m_tmsk2, 6))
+ set_irq_state(0x07, true);
}
- for (uint32_t i = 0; i < add; i++)
+ for (int i = 0; i < 5; i++)
{
- m_tcnt++;
- if (m_tcnt == m_toc[0])
+ if (add >= uint16_t(m_toc[i] - m_tcnt))
{
- m_tflg1 |= 0x80;
- m_irq_state[MC68HC11_TOC1_LINE] = ASSERT_LINE;
+ m_tflg1 |= 0x80 >> i;
+ if (BIT(m_tmsk1, 7 - i))
+ set_irq_state(0x0b + i, true);
}
- if (m_tcnt == 0)
- m_tflg2 |= 0x80;
}
- m_frc_base = cur_time;
- }
- }
- if( m_irq_state[MC68HC11_RTI_LINE]!=CLEAR_LINE && (!(m_ccr & CC_I)) && m_tmsk2 & 0x40)
- {
- uint16_t pc_vector;
+ if (add >= 0x10000 - m_tcnt)
+ {
+ m_tflg2 |= 0x80;
+ if (BIT(m_tmsk2, 7))
+ set_irq_state(0x10, true);
+ }
- if(m_wait_state == 0)
- {
- PUSH16(m_pc);
- PUSH16(m_iy);
- PUSH16(m_ix);
- PUSH8(REG_A);
- PUSH8(REG_B);
- PUSH8(m_ccr);
+ m_tcnt += add;
+ m_frc_base = cur_time;
}
- pc_vector = READ16(0xfff0);
- SET_PC(pc_vector);
- m_ccr |= CC_I; //irq taken, mask the flag
- if(m_wait_state == 1) { m_wait_state = 2; }
- if(m_stop_state == 1) { m_stop_state = 2; }
- standard_irq_callback(MC68HC11_RTI_LINE);
- m_irq_state[MC68HC11_RTI_LINE] = CLEAR_LINE; // auto-ack irq
}
- if( m_irq_state[MC68HC11_TOC1_LINE]!=CLEAR_LINE && (!(m_ccr & CC_I)) && m_tmsk1 & 0x80)
+ uint32_t irq_state = m_irq_state;
+ if (m_ccr & CC_X)
+ irq_state &= ~0x04000000; // mask XIRQ out
+ if (irq_state != 0 && (!(m_ccr & CC_I) || (irq_state >= 0x04000000)))
{
- uint16_t pc_vector;
+ int level = count_leading_zeros_32(irq_state); // TODO: respect HPRIO setting
+ standard_irq_callback(level, m_pc);
if(m_wait_state == 0)
{
@@ -1029,22 +1170,48 @@ void mc68hc11_cpu_device::check_irq_lines()
PUSH8(REG_B);
PUSH8(m_ccr);
}
- pc_vector = READ16(0xffe8);
+ // TODO: vectors differ in bootstrap and special test modes
+ uint16_t pc_vector = READ16(0xfffe - level * 2);
SET_PC(pc_vector);
m_ccr |= CC_I; //irq taken, mask the flag
- if(m_wait_state == 1) { m_wait_state = 2; }
+ if (level < 0x06)
+ m_ccr |= CC_X;
+ if(m_wait_state == 1) { m_wait_state = 0; }
if(m_stop_state == 1) { m_stop_state = 2; }
- standard_irq_callback(MC68HC11_TOC1_LINE);
- m_irq_state[MC68HC11_TOC1_LINE] = CLEAR_LINE; // auto-ack irq
+ if (level < 0x05 || (level == 0x06 && BIT(m_option, 5)))
+ set_irq_state(level, false); // auto-ack edge-triggered IRQ
}
+}
+void mc68hc11_cpu_device::set_irq_state(uint8_t irqn, bool state)
+{
+ LOGMASKED(LOG_IRQ, "%s: %s interrupt %s\n", machine().describe_context(), s_irq_names[irqn], state ? "requested" : "cleared");
+ if (state)
+ m_irq_state |= 0x80000000 >> irqn;
+ else
+ m_irq_state &= ~(0x80000000 >> irqn);
}
void mc68hc11_cpu_device::execute_set_input(int inputnum, int state)
{
- m_irq_state[inputnum] = state;
- if (state == CLEAR_LINE) return;
- check_irq_lines();
+ switch (inputnum)
+ {
+ case MC68HC11_IRQ_LINE:
+ if (!m_irq_asserted && state != CLEAR_LINE)
+ set_irq_state(0x06, true);
+ else if (m_irq_asserted && state == CLEAR_LINE && !BIT(m_option, 5))
+ set_irq_state(0x06, false);
+ m_irq_asserted = state != CLEAR_LINE;
+ break;
+
+ case MC68HC11_XIRQ_LINE:
+ set_irq_state(0x05, state != CLEAR_LINE);
+ break;
+
+ default:
+ logerror("Unknown input %d = %d\n", inputnum, state);
+ break;
+ }
}
void mc68hc11_cpu_device::execute_run()