diff options
Diffstat (limited to 'src/devices/cpu/m6805/m68hc05.cpp')
-rw-r--r-- | src/devices/cpu/m6805/m68hc05.cpp | 269 |
1 files changed, 212 insertions, 57 deletions
diff --git a/src/devices/cpu/m6805/m68hc05.cpp b/src/devices/cpu/m6805/m68hc05.cpp index 5cdbe2d619b..f2033bb55b4 100644 --- a/src/devices/cpu/m6805/m68hc05.cpp +++ b/src/devices/cpu/m6805/m68hc05.cpp @@ -28,11 +28,10 @@ determines both the COP watchdog timeout and the real-time interrupt rate * Configurable logging ****************************************************************************/ -#define LOG_GENERAL (1U << 0) -#define LOG_INT (1U << 1) -#define LOG_IOPORT (1U << 2) -#define LOG_TIMER (1U << 3) -#define LOG_COP (1U << 4) +#define LOG_INT (1U << 1) +#define LOG_IOPORT (1U << 2) +#define LOG_TIMER (1U << 3) +#define LOG_COP (1U << 4) //#define VERBOSE (LOG_GENERAL | LOG_INT | LOG_IOPORT | LOG_TIMER | LOG_COP) //#define LOG_OUTPUT_FUNC printf @@ -64,7 +63,8 @@ std::pair<u16, char const *> const m68hc705c8a_syms[] = { { 0x0014, "ICRH" }, { 0x0015, "ICRL" }, { 0x0016, "OCRH" }, { 0x0017, "OCRL" }, { 0x0018, "TRH" }, { 0x0019, "TRL" }, { 0x001a, "ATRH" }, { 0x001b, "ATRL" }, { 0x001c, "PROG" }, - { 0x001d, "COPRST" }, { 0x001e, "COPCR" } }; + { 0x001d, "COPRST" }, { 0x001e, "COPCR" }, + { 0x1fdf, "OPTION" } }; std::pair<u16, char const *> const m68hc705j1a_syms[] = { { 0x0000, "PORTA" }, { 0x0001, "PORTB" }, @@ -88,6 +88,11 @@ std::pair<u16, char const *> const m68hc05l9_syms[] = { { 0x001d, "HOUR" }, { 0x001e, "MIN" }, { 0x001f, "SEC" } }; +ROM_START( m68hc705c4a ) + ROM_REGION(0x00f0, "bootstrap", 0) + ROM_LOAD("bootstrap.bin", 0x0000, 0x00f0, NO_DUMP) +ROM_END + ROM_START( m68hc705c8a ) ROM_REGION(0x00f0, "bootstrap", 0) ROM_LOAD("bootstrap.bin", 0x0000, 0x00f0, NO_DUMP) @@ -116,6 +121,7 @@ constexpr u16 M68HC05_INT_MASK = M68HC05_INT_IRQ | M68HC05_INT_TIMER; DEFINE_DEVICE_TYPE(M68HC05C4, m68hc05c4_device, "m68hc05c4", "Motorola MC68HC05C4") DEFINE_DEVICE_TYPE(M68HC05C8, m68hc05c8_device, "m68hc05c8", "Motorola MC68HC05C8") +DEFINE_DEVICE_TYPE(M68HC705C4A, m68hc705c4a_device, "m68hc705c4a", "Motorola MC68HC705C4A") DEFINE_DEVICE_TYPE(M68HC705C8A, m68hc705c8a_device, "m68hc705c8a", "Motorola MC68HC705C8A") DEFINE_DEVICE_TYPE(M68HC705J1A, m68hc705j1a_device, "m68hc705j1a", "Motorola MC68HC705J1A") DEFINE_DEVICE_TYPE(M68HC05L9, m68hc05l9_device, "m68hc05l9", "Motorola MC68HC05L9") @@ -142,10 +148,10 @@ m68hc05_device::m68hc05_device( owner, clock, type, - { s_hc_ops, s_hc_cycles, addr_width, 0x00ff, 0x00c0, vector_mask, M68HC05_VECTOR_SWI }, + { addr_width > 13 ? s_hc_b_ops : s_hc_s_ops, s_hc_cycles, addr_width, 0x00ff, 0x00c0, vector_mask, M68HC05_VECTOR_SWI }, internal_map) - , m_port_cb_r{ *this, *this, *this, *this } - , m_port_cb_w{ *this, *this, *this, *this } + , m_port_cb_r(*this, 0xff) + , m_port_cb_w(*this) , m_port_bits{ 0xff, 0xff, 0xff, 0xff } , m_port_interrupt{ 0x00, 0x00, 0x00, 0x00 } , m_port_input{ 0xff, 0xff, 0xff, 0xff } @@ -188,18 +194,18 @@ void m68hc05_device::set_port_interrupt(std::array<u8, PORT_COUNT> const &interr { diff |= (m_port_interrupt[i] ^ interrupt[i]) & ~m_port_ddr[i]; m_port_interrupt[i] = interrupt[i]; - if (interrupt[i] && !m_port_cb_r[i].isnull()) + if (interrupt[i] && !m_port_cb_r[i].isunset()) logerror("PORT%c has interrupts enabled with pulled inputs, behaviour may be incorrect\n", 'A' + i); } if (diff) update_port_irq(); } -READ8_MEMBER(m68hc05_device::port_read) +u8 m68hc05_device::port_read(offs_t offset) { offset &= PORT_COUNT - 1; - if (!machine().side_effects_disabled() && !m_port_cb_r[offset].isnull()) + if (!machine().side_effects_disabled() && !m_port_cb_r[offset].isunset()) { - u8 const newval(m_port_cb_r[offset](space, 0, ~m_port_ddr[offset] & m_port_bits[offset]) & m_port_bits[offset]); + u8 const newval(m_port_cb_r[offset](0, ~m_port_ddr[offset] & m_port_bits[offset]) & m_port_bits[offset]); u8 const diff(newval ^ m_port_input[offset]); if (diff) { @@ -213,7 +219,7 @@ READ8_MEMBER(m68hc05_device::port_read) return port_value(offset); } -WRITE8_MEMBER(m68hc05_device::port_latch_w) +void m68hc05_device::port_latch_w(offs_t offset, u8 data) { offset &= PORT_COUNT - 1; data &= m_port_bits[offset]; @@ -225,15 +231,15 @@ WRITE8_MEMBER(m68hc05_device::port_latch_w) } m_port_latch[offset] = data; if (diff & m_port_ddr[offset]) - m_port_cb_w[offset](space, 0, port_value(offset), m_port_ddr[offset]); + m_port_cb_w[offset](0, port_value(offset), m_port_ddr[offset]); } -READ8_MEMBER(m68hc05_device::port_ddr_r) +u8 m68hc05_device::port_ddr_r(offs_t offset) { return m_port_ddr[offset & (PORT_COUNT - 1)]; } -WRITE8_MEMBER(m68hc05_device::port_ddr_w) +void m68hc05_device::port_ddr_w(offs_t offset, u8 data) { offset &= PORT_COUNT - 1; data &= m_port_bits[offset]; @@ -244,9 +250,9 @@ WRITE8_MEMBER(m68hc05_device::port_ddr_w) m_port_ddr[offset] = data; if (diff & m_port_interrupt[offset]) { - if (!m_port_cb_r[offset].isnull()) + if (!m_port_cb_r[offset].isunset()) { - u8 const newval(m_port_cb_r[offset](space, 0, ~m_port_ddr[offset] & m_port_bits[offset]) & m_port_bits[offset]); + u8 const newval(m_port_cb_r[offset](0, ~m_port_ddr[offset] & m_port_bits[offset]) & m_port_bits[offset]); u8 const diff(newval ^ m_port_input[offset]); if (diff) { @@ -257,17 +263,17 @@ WRITE8_MEMBER(m68hc05_device::port_ddr_w) } update_port_irq(); } - m_port_cb_w[offset](space, 0, port_value(offset), m_port_ddr[offset]); + m_port_cb_w[offset](0, port_value(offset), m_port_ddr[offset]); } } -READ8_MEMBER(m68hc05_device::tcr_r) +u8 m68hc05_device::tcr_r() { return m_tcr; } -WRITE8_MEMBER(m68hc05_device::tcr_w) +void m68hc05_device::tcr_w(u8 data) { data &= 0xe3; LOGTIMER("write TCR: ICIE=%u OCIE=%u TOIE=%u IEDG=%u OLVL=%u\n", @@ -279,7 +285,7 @@ WRITE8_MEMBER(m68hc05_device::tcr_w) m_pending_interrupts &= ~M68HC05_INT_TIMER; } -READ8_MEMBER(m68hc05_device::tsr_r) +u8 m68hc05_device::tsr_r() { if (!machine().side_effects_disabled()) { @@ -294,7 +300,7 @@ READ8_MEMBER(m68hc05_device::tsr_r) return m_tsr; } -READ8_MEMBER(m68hc05_device::icr_r) +u8 m68hc05_device::icr_r(offs_t offset) { // reading IRCH inhibits capture until ICRL is read // reading ICRL after reading TCR with ICF set clears ICF @@ -323,7 +329,7 @@ READ8_MEMBER(m68hc05_device::icr_r) return u8(m_icr >> (low ? 0 : 8)); } -READ8_MEMBER(m68hc05_device::ocr_r) +u8 m68hc05_device::ocr_r(offs_t offset) { // reading OCRL after reading TCR with OCF set clears OCF @@ -338,9 +344,9 @@ READ8_MEMBER(m68hc05_device::ocr_r) return u8(m_ocr >> (low ? 0 : 8)); } -WRITE8_MEMBER(m68hc05_device::ocr_w) +void m68hc05_device::ocr_w(offs_t offset, u8 data) { - // writing ORCH inhibits compare until OCRL is written + // writing OCRH inhibits compare until OCRL is written // writing OCRL after reading TCR with OCF set clears OCF u8 const low(BIT(offset, 0)); @@ -367,7 +373,7 @@ WRITE8_MEMBER(m68hc05_device::ocr_w) m_ocr = (m_ocr & (low ? 0xff00 : 0x00ff)) | (u16(data) << (low ? 0 : 8)); } -READ8_MEMBER(m68hc05_device::timer_r) +u8 m68hc05_device::timer_r(offs_t offset) { // reading [A]TRH returns current counter MSB and latches [A]TRL buffer // reading [A]TRL returns current [A]TRL buffer and completes read sequence @@ -405,7 +411,7 @@ READ8_MEMBER(m68hc05_device::timer_r) } -WRITE8_MEMBER(m68hc05_device::coprst_w) +void m68hc05_device::coprst_w(u8 data) { LOGCOP("write COPRST=%02x%s\n", data, ((0xaa == data) && (0x55 == m_coprst)) ? ", reset" : ""); if (0x55 == data) @@ -419,22 +425,25 @@ WRITE8_MEMBER(m68hc05_device::coprst_w) } } -READ8_MEMBER(m68hc05_device::copcr_r) +u8 m68hc05_device::copcr_r() { - if (copcr_copf()) LOGCOP("read COPCR, clear COPF\n"); u8 const result(m_copcr); - m_copcr &= 0xef; + if (!machine().side_effects_disabled()) + { + if (copcr_copf()) LOGCOP("read COPCR, clear COPF\n"); + m_copcr &= 0xef; + } return result; } -WRITE8_MEMBER(m68hc05_device::copcr_w) +void m68hc05_device::copcr_w(u8 data) { LOGCOP("write COPCR: CME=%u PCOPE=%u [%s] CM=%u\n", BIT(data, 3), BIT(data, 2), (!copcr_pcope() && BIT(data, 2)) ? "set" : "ignored", data & 0x03); m_copcr = (m_copcr & 0xf4) | (data & 0x0f); // PCOPE is set-only, hence the mask overlap } -WRITE8_MEMBER(m68hc05_device::copr_w) +void m68hc05_device::copr_w(u8 data) { LOGCOP("write COPR: COPC=%u\n", BIT(data, 0)); if (!BIT(data, 0)) m_ncop_cnt = 0; @@ -445,11 +454,6 @@ void m68hc05_device::device_start() { m6805_base_device::device_start(); - // resolve callbacks - for (devcb_read8 &cb : m_port_cb_r) cb.resolve(); - for (devcb_write8 &cb : m_port_cb_w) cb.resolve_safe(); - m_tcmp_cb.resolve_safe(); - // save digital I/O save_item(NAME(m_port_interrupt)); save_item(NAME(m_port_input)); @@ -468,7 +472,7 @@ void m68hc05_device::device_start() save_item(NAME(m_counter)); save_item(NAME(m_icr)); save_item(NAME(m_ocr)); - save_item(NAME(m_inhibit_cap));; + save_item(NAME(m_inhibit_cap)); save_item(NAME(m_inhibit_cmp)); save_item(NAME(m_trl_buf)); save_item(NAME(m_trl_latched)); @@ -561,12 +565,12 @@ void m68hc05_device::execute_set_input(int inputnum, int state) } } -u64 m68hc05_device::execute_clocks_to_cycles(u64 clocks) const +u64 m68hc05_device::execute_clocks_to_cycles(u64 clocks) const noexcept { return (clocks + 1) / 2; } -u64 m68hc05_device::execute_cycles_to_clocks(u64 cycles) const +u64 m68hc05_device::execute_cycles_to_clocks(u64 cycles) const noexcept { return cycles * 2; } @@ -581,24 +585,40 @@ void m68hc05_device::interrupt() { if ((m_pending_interrupts & M68HC05_INT_MASK) && !(CC & IFLAG)) { - pushword(m_pc); - pushbyte(m_x); - pushbyte(m_a); - pushbyte(m_cc); + if (m_params.m_addr_width > 13) { + pushword<true>(m_pc); + pushbyte<true>(m_x); + pushbyte<true>(m_a); + pushbyte<true>(m_cc); + } + else + { + pushword<false>(m_pc); + pushbyte<false>(m_x); + pushbyte<false>(m_a); + pushbyte<false>(m_cc); + } SEI; - standard_irq_callback(0); if (m_pending_interrupts & M68HC05_INT_IRQ) { LOGINT("servicing external interrupt\n"); + standard_irq_callback(0, m_pc.w.l); m_irq_latch = 0; m_pending_interrupts &= ~M68HC05_INT_IRQ; - rm16(M68HC05_VECTOR_IRQ & m_params.m_vector_mask, m_pc); + if (m_params.m_addr_width > 13) + rm16<true>(M68HC05_VECTOR_IRQ & m_params.m_vector_mask, m_pc); + else + rm16<false>(M68HC05_VECTOR_IRQ & m_params.m_vector_mask, m_pc); } else if (m_pending_interrupts & M68HC05_INT_TIMER) { LOGINT("servicing timer interrupt\n"); - rm16(M68HC05_VECTOR_TIMER & m_params.m_vector_mask, m_pc); + standard_irq_callback(1, m_pc.w.l); + if (m_params.m_addr_width > 13) + rm16<true>(M68HC05_VECTOR_TIMER & m_params.m_vector_mask, m_pc); + else + rm16<false>(M68HC05_VECTOR_TIMER & m_params.m_vector_mask, m_pc); } else { @@ -621,7 +641,7 @@ void m68hc05_device::burn_cycles(unsigned count) unsigned const ps_mask((1 << ps_opt) - 1); unsigned const increments((count + (m_prescaler & ps_mask)) >> ps_opt); u32 const new_counter(u32(m_counter) + increments); - bool const timer_rollover((0x010000 > m_counter) && (0x010000 <= new_counter)); + bool const timer_rollover(0x010000 <= new_counter); bool const output_compare_match((m_ocr > m_counter) && (m_ocr <= new_counter)); m_prescaler = (count + m_prescaler) & ps_mask; m_counter = u16(new_counter); @@ -653,7 +673,7 @@ void m68hc05_device::burn_cycles(unsigned count) // run non-programmable COP m_ncop_cnt += count; - if ((u32(1) << 17) <= m_ncop_cnt) + if (m_ncope && ((u32(1) << 17) <= m_ncop_cnt)) { pulse_input_line(INPUT_LINE_RESET, attotime::zero); LOGCOP("NCOP reset\n"); @@ -880,6 +900,100 @@ std::unique_ptr<util::disasm_interface> m68hc05c8_device::create_disassembler() /**************************************************************************** + * MC68HC705C4A device + ****************************************************************************/ + +void m68hc705c4a_device::c4a_map(address_map &map) +{ + map.global_mask(0x1fff); + map.unmap_value_high(); + + map(0x0000, 0x0003).rw(FUNC(m68hc705c4a_device::port_read), FUNC(m68hc705c4a_device::port_latch_w)); + map(0x0004, 0x0006).rw(FUNC(m68hc705c4a_device::port_ddr_r), FUNC(m68hc705c4a_device::port_ddr_w)); + // 0x0007-0x0009 unused + // 0x000a SPCR + // 0x000b SPSR + // 0x000c SPDR + // 0x000d BAUD + // 0x000e SCCR1 + // 0x000f SCCR2 + // 0x0010 SCSR + // 0x0011 SCDR + map(0x0012, 0x0012).rw(FUNC(m68hc705c4a_device::tcr_r), FUNC(m68hc705c4a_device::tcr_w)); + map(0x0013, 0x0013).r(FUNC(m68hc705c4a_device::tsr_r)); + map(0x0014, 0x0015).r(FUNC(m68hc705c4a_device::icr_r)); + map(0x0016, 0x0017).rw(FUNC(m68hc705c4a_device::ocr_r), FUNC(m68hc705c4a_device::ocr_w)); + map(0x0018, 0x001b).r(FUNC(m68hc705c4a_device::timer_r)); + // 0x001c PROG + // 0x001d-0x001f unused + map(0x0020, 0x004f).rom(); // user PROM + map(0x0050, 0x00ff).ram(); // RAM/stack + map(0x0100, 0x10ff).rom(); // user PROM + // 0x1100-0x1eff unused + map(0x1f00, 0x1fde).rom().region("bootstrap", 0x0000); // bootloader + map(0x1fdf, 0x1fdf).lw8(NAME([this] (u8 data) { m_option = data; })); + map(0x1fe0, 0x1fef).rom().region("bootstrap", 0x00e0); // boot ROM vectors + map(0x1ff0, 0x1ff0).w(FUNC(m68hc705c4a_device::copr_w)); + map(0x1ff0, 0x1fff).rom(); // user vectors +} + + +m68hc705c4a_device::m68hc705c4a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : m68hc705_device( + mconfig, + tag, + owner, + clock, + M68HC705C4A, + 13, + address_map_constructor(FUNC(m68hc705c4a_device::c4a_map), this)) + , m_rom(*this, DEVICE_SELF) +{ + set_port_bits(std::array<u8, PORT_COUNT>{{ 0xff, 0xff, 0xff, 0xbf }}); +} + + +tiny_rom_entry const *m68hc705c4a_device::device_rom_region() const +{ + return ROM_NAME(m68hc705c4a); +} + + +void m68hc705c4a_device::device_start() +{ + m68hc705_device::device_start(); + + add_port_state(std::array<bool, PORT_COUNT>{{ true, true, true, false }}); + add_timer_state(); + add_ncop_state(); + + state_add(M68HC705C8A_OPTION, "OPTION", m_option).mask(0xff); + + save_item(NAME(m_option)); +} + +void m68hc705c4a_device::device_reset() +{ + m68hc705_device::device_reset(); + + // latch MOR registers on reset + set_port_interrupt(std::array<u8, PORT_COUNT>{{ 0x00, u8(rdmem<false>(0xfff0)), 0x00, 0x00 }}); + set_ncope(BIT(rdmem<false>(0xfff1), 0)); + + // IRQ negative edge and level sensitive + m_option = 0x02; +} + + +std::unique_ptr<util::disasm_interface> m68hc705c4a_device::create_disassembler() +{ + return std::make_unique<m68hc05_disassembler>(m68hc705c8a_syms); +} + + + + +/**************************************************************************** * MC68HC705C8A device ****************************************************************************/ @@ -908,12 +1022,12 @@ void m68hc705c8a_device::c8a_map(address_map &map) map(0x001d, 0x001d).w(FUNC(m68hc705c8a_device::coprst_w)); map(0x001e, 0x001e).rw(FUNC(m68hc705c8a_device::copcr_r), FUNC(m68hc705c8a_device::copcr_w)); // 0x001f unused - map(0x0020, 0x004f).rom(); // user PROM FIXME: banked with RAM + map(0x0020, 0x004f).rw(FUNC(m68hc705c8a_device::ram0_r), FUNC(m68hc705c8a_device::ram0_w)); // PROM/RAM map(0x0050, 0x00ff).ram(); // RAM/stack - map(0x0100, 0x015f).rom(); // user PROM FIXME: banked with RAM + map(0x0100, 0x015f).rw(FUNC(m68hc705c8a_device::ram1_r), FUNC(m68hc705c8a_device::ram1_w)); // PROM/RAM map(0x0160, 0x1eff).rom(); // user PROM map(0x1f00, 0x1fde).rom().region("bootstrap", 0x0000); // bootloader - // 0x1fdf option register FIXME: controls banking + map(0x1fdf, 0x1fdf).lw8(NAME([this] (u8 data) { m_option = data; })); map(0x1fe0, 0x1fef).rom().region("bootstrap", 0x00e0); // boot ROM vectors map(0x1ff0, 0x1ff0).w(FUNC(m68hc705c8a_device::copr_w)); map(0x1ff0, 0x1fff).rom(); // user vectors @@ -929,6 +1043,7 @@ m68hc705c8a_device::m68hc705c8a_device(machine_config const &mconfig, char const M68HC705C8A, 13, address_map_constructor(FUNC(m68hc705c8a_device::c8a_map), this)) + , m_rom(*this, DEVICE_SELF) { set_port_bits(std::array<u8, PORT_COUNT>{{ 0xff, 0xff, 0xff, 0xbf }}); } @@ -948,6 +1063,14 @@ void m68hc705c8a_device::device_start() add_timer_state(); add_pcop_state(); add_ncop_state(); + + state_add(M68HC705C8A_OPTION, "OPTION", m_option).mask(0xff); + + save_item(NAME(m_ram)); + save_item(NAME(m_option)); + + // clear RAM + std::fill(std::begin(m_ram), std::end(m_ram), 0x00); } void m68hc705c8a_device::device_reset() @@ -955,8 +1078,11 @@ void m68hc705c8a_device::device_reset() m68hc705_device::device_reset(); // latch MOR registers on reset - set_port_interrupt(std::array<u8, PORT_COUNT>{{ 0x00, u8(rdmem(0xfff0)), 0x00, 0x00 }}); - set_ncope(BIT(rdmem(0xfff1), 0)); + set_port_interrupt(std::array<u8, PORT_COUNT>{{ 0x00, u8(rdmem<false>(0xfff0)), 0x00, 0x00 }}); + set_ncope(BIT(rdmem<false>(0xfff1), 0)); + + // RAM disabled, IRQ negative edge and level sensitive + m_option = 0x02; } @@ -966,6 +1092,35 @@ std::unique_ptr<util::disasm_interface> m68hc705c8a_device::create_disassembler( } +u8 m68hc705c8a_device::ram0_r(offs_t offset) +{ + if (BIT(m_option, 7)) + return offset >= 0x10 ? m_ram[offset - 0x10] : 0x00; // 20-2f reserved + else + return m_rom[0x20 + offset]; +} + +void m68hc705c8a_device::ram0_w(offs_t offset, u8 data) +{ + if (BIT(m_option, 7) && offset >= 0x10) + m_ram[offset - 0x10] = data; +} + +u8 m68hc705c8a_device::ram1_r(offs_t offset) +{ + if (BIT(m_option, 6)) + return m_ram[0x20 + offset]; + else + return m_rom[0x100 + offset]; +} + +void m68hc705c8a_device::ram1_w(offs_t offset, u8 data) +{ + if (BIT(m_option, 6)) + m_ram[0x20 + offset] = data; +} + + /**************************************************************************** * MC68HC05J1A device @@ -1022,7 +1177,7 @@ void m68hc705j1a_device::device_reset() m68hc705_device::device_reset(); // latch MOR register on reset - set_ncope(BIT(rdmem(0x07f1), 0)); // FIXME: this is more like C8A's PCOP + set_ncope(BIT(rdmem<false>(0x07f1), 0)); // FIXME: this is more like C8A's PCOP } |