m6805 updates:

* Fix disassembly of BIT opcodes
* Don't burn cycles on disabled interrupts
* Add partially implemented MC68HC05C8 and MC68HC705C8A
* Implement 'HC05 digital I/O, timer/capture/compare and COP watchdogs
* Probably still some bugs in 'HC05 peripherals

Also use pure virtual method for Amiga keyboard interface (nw)
This commit is contained in:
Vas Crabb 2017-02-03 11:00:53 +11:00
parent 1469e75875
commit 029b93f95e
6 changed files with 968 additions and 58 deletions

View File

@ -93,7 +93,7 @@ public:
device_amiga_keyboard_interface(const machine_config &mconfig, device_t &device); device_amiga_keyboard_interface(const machine_config &mconfig, device_t &device);
virtual ~device_amiga_keyboard_interface(); virtual ~device_amiga_keyboard_interface();
virtual DECLARE_WRITE_LINE_MEMBER(kdat_w) {}; virtual DECLARE_WRITE_LINE_MEMBER(kdat_w) = 0;
protected: protected:
amiga_keyboard_bus_device *m_host; amiga_keyboard_bus_device *m_host;

View File

@ -36,10 +36,10 @@ enum class lvl {
HC HC
}; };
enum op_names { enum class op_names {
adca, adda, anda, asl, asla, aslx, asr, asra, adca, adda, anda, asl, asla, aslx, asr, asra,
asrx, bcc, bclr, bcs, beq, bhcc, bhcs, bhi, asrx, bcc, bclr, bcs, beq, bhcc, bhcs, bhi,
bih, bil, bita, bls, bmc, bmi, bms, bne, bih, bil, bit, bls, bmc, bmi, bms, bne,
bpl, bra, brclr, brn, brset, bset, bsr, clc, bpl, bra, brclr, brn, brset, bset, bsr, clc,
cli, clr, clra, clrx, cmpa, com, coma, comx, cli, clr, clra, clrx, cmpa, com, coma, comx,
cpx, dec, deca, decx, eora, ill, inc, inca, cpx, dec, deca, decx, eora, ill, inc, inca,
@ -50,10 +50,10 @@ enum op_names {
tst, tsta, tstx, txa, wait tst, tsta, tstx, txa, wait
}; };
#define OP(name, mode) { name, #name, md::mode, lvl::HMOS } #define OP(name, mode) { op_names::name, #name, md::mode, lvl::HMOS }
#define OPC(name, mode) { name, #name, md::mode, lvl::CMOS } #define OPC(name, mode) { op_names::name, #name, md::mode, lvl::CMOS }
#define OPHC(name, mode) { name, #name, md::mode, lvl::HC } #define OPHC(name, mode) { op_names::name, #name, md::mode, lvl::HC }
#define ILLEGAL { ill, nullptr, md::INH, lvl::HMOS } #define ILLEGAL { op_names::ill, nullptr, md::INH, lvl::HMOS }
struct { op_names op; char const *name; md mode; lvl level; } const disasm[0x100] = { struct { op_names op; char const *name; md mode; lvl level; } const disasm[0x100] = {
OP (brset,BTR), OP (brclr,BTR), OP (brset,BTR), OP (brclr,BTR), // 00 OP (brset,BTR), OP (brclr,BTR), OP (brset,BTR), OP (brclr,BTR), // 00
OP (brset,BTR), OP (brclr,BTR), OP (brset,BTR), OP (brclr,BTR), OP (brset,BTR), OP (brclr,BTR), OP (brset,BTR), OP (brclr,BTR),
@ -96,27 +96,27 @@ struct { op_names op; char const *name; md mode; lvl level; } const disasm[0x100
OP (clc, INH), OP (sec, INH), OP (cli, INH), OP (sei, INH), OP (clc, INH), OP (sec, INH), OP (cli, INH), OP (sei, INH),
OP (rsp, INH), OP (nop, INH), ILLEGAL , OP (txa, INH), OP (rsp, INH), OP (nop, INH), ILLEGAL , OP (txa, INH),
OP (suba, IMM), OP (cmpa, IMM), OP (sbca, IMM), OP (cpx, IMM), // a0 OP (suba, IMM), OP (cmpa, IMM), OP (sbca, IMM), OP (cpx, IMM), // a0
OP (anda, IMM), OP (bita, IMM), OP (lda, IMM), ILLEGAL , OP (anda, IMM), OP (bit, IMM), OP (lda, IMM), ILLEGAL ,
OP (eora, IMM), OP (adca, IMM), OP (ora, IMM), OP (adda, IMM), OP (eora, IMM), OP (adca, IMM), OP (ora, IMM), OP (adda, IMM),
ILLEGAL , OP (bsr, REL), OP (ldx, IMM), ILLEGAL , ILLEGAL , OP (bsr, REL), OP (ldx, IMM), ILLEGAL ,
OP (suba, DIR), OP (cmpa, DIR), OP (sbca, DIR), OP (cpx, DIR), // b0 OP (suba, DIR), OP (cmpa, DIR), OP (sbca, DIR), OP (cpx, DIR), // b0
OP (anda, DIR), OP (bita, DIR), OP (lda, DIR), OP (sta, DIR), OP (anda, DIR), OP (bit, DIR), OP (lda, DIR), OP (sta, DIR),
OP (eora, DIR), OP (adca, DIR), OP (ora, DIR), OP (adda, DIR), OP (eora, DIR), OP (adca, DIR), OP (ora, DIR), OP (adda, DIR),
OP (jmp, DIR), OP (jsr, DIR), OP (ldx, DIR), OP (stx, DIR), OP (jmp, DIR), OP (jsr, DIR), OP (ldx, DIR), OP (stx, DIR),
OP (suba, EXT), OP (cmpa, EXT), OP (sbca, EXT), OP (cpx, EXT), // c0 OP (suba, EXT), OP (cmpa, EXT), OP (sbca, EXT), OP (cpx, EXT), // c0
OP (anda, EXT), OP (bita, EXT), OP (lda, EXT), OP (sta, EXT), OP (anda, EXT), OP (bit, EXT), OP (lda, EXT), OP (sta, EXT),
OP (eora, EXT), OP (adca, EXT), OP (ora, EXT), OP (adda, EXT), OP (eora, EXT), OP (adca, EXT), OP (ora, EXT), OP (adda, EXT),
OP (jmp, EXT), OP (jsr, EXT), OP (ldx, EXT), OP (stx, EXT), OP (jmp, EXT), OP (jsr, EXT), OP (ldx, EXT), OP (stx, EXT),
OP (suba, IX2), OP (cmpa, IX2), OP (sbca, IX2), OP (cpx, IX2), // d0 OP (suba, IX2), OP (cmpa, IX2), OP (sbca, IX2), OP (cpx, IX2), // d0
OP (anda, IX2), OP (bita, IX2), OP (lda, IX2), OP (sta, IX2), OP (anda, IX2), OP (bit, IX2), OP (lda, IX2), OP (sta, IX2),
OP (eora, IX2), OP (adca, IX2), OP (ora, IX2), OP (adda, IX2), OP (eora, IX2), OP (adca, IX2), OP (ora, IX2), OP (adda, IX2),
OP (jmp, IX2), OP (jsr, IX2), OP (ldx, IX2), OP (stx, IX2), OP (jmp, IX2), OP (jsr, IX2), OP (ldx, IX2), OP (stx, IX2),
OP (suba, IX1), OP (cmpa, IX1), OP (sbca, IX1), OP (cpx, IX1), // e0 OP (suba, IX1), OP (cmpa, IX1), OP (sbca, IX1), OP (cpx, IX1), // e0
OP (anda, IX1), OP (bita, IX1), OP (lda, IX1), OP (sta, IX1), OP (anda, IX1), OP (bit, IX1), OP (lda, IX1), OP (sta, IX1),
OP (eora, IX1), OP (adca, IX1), OP (ora, IX1), OP (adda, IX1), OP (eora, IX1), OP (adca, IX1), OP (ora, IX1), OP (adda, IX1),
OP (jmp, IX1), OP (jsr, IX1), OP (ldx, IX1), OP (stx, IX1), OP (jmp, IX1), OP (jsr, IX1), OP (ldx, IX1), OP (stx, IX1),
OP (suba, IDX), OP (cmpa, IDX), OP (sbca, IDX), OP (cpx, IDX), // f0 OP (suba, IDX), OP (cmpa, IDX), OP (sbca, IDX), OP (cpx, IDX), // f0
OP (anda, IDX), OP (bita, IDX), OP (lda, IDX), OP (sta, IDX), OP (anda, IDX), OP (bit, IDX), OP (lda, IDX), OP (sta, IDX),
OP (eora, IDX), OP (adca, IDX), OP (ora, IDX), OP (adda, IDX), OP (eora, IDX), OP (adca, IDX), OP (ora, IDX), OP (adda, IDX),
OP (jmp, IDX), OP (jsr, IDX), OP (ldx, IDX), OP (stx, IDX) OP (jmp, IDX), OP (jsr, IDX), OP (ldx, IDX), OP (stx, IDX)
}; };
@ -164,12 +164,12 @@ offs_t disassemble(
u32 flags; u32 flags;
switch (disasm[code].op) switch (disasm[code].op)
{ {
case bsr: case op_names::bsr:
case jsr: case op_names::jsr:
flags = DASMFLAG_STEP_OVER; flags = DASMFLAG_STEP_OVER;
break; break;
case rts: case op_names::rts:
case rti: case op_names::rti:
flags = DASMFLAG_STEP_OUT; flags = DASMFLAG_STEP_OUT;
break; break;
default: default:

View File

@ -386,7 +386,7 @@ void m6805_base_device::interrupt()
m_icount -= 11; m_icount -= 11;
burn_cycles(11); burn_cycles(11);
} }
else if((m_pending_interrupts & ((1 << M6805_IRQ_LINE) | HD63705_INT_MASK)) != 0) else if ((m_pending_interrupts & ((1 << M6805_IRQ_LINE) | HD63705_INT_MASK)) != 0)
{ {
if ((CC & IFLAG) == 0) if ((CC & IFLAG) == 0)
{ {
@ -402,9 +402,10 @@ void m6805_base_device::interrupt()
interrupt_vector(); interrupt_vector();
m_pending_interrupts &= ~(1 << M6805_IRQ_LINE); m_pending_interrupts &= ~(1 << M6805_IRQ_LINE);
m_icount -= 11;
burn_cycles(11);
} }
m_icount -= 11;
burn_cycles(11);
} }
} }

View File

@ -75,7 +75,7 @@ constexpr u16 M68705_VECTOR_BOOTSTRAP = 0xfff6;
constexpr u16 M68705_VECTOR_TIMER = 0xfff8; constexpr u16 M68705_VECTOR_TIMER = 0xfff8;
//constexpr u16 M68705_VECTOR_INT2 = 0xfff8; //constexpr u16 M68705_VECTOR_INT2 = 0xfff8;
constexpr u16 M68705_VECTOR_INT = 0xfffa; constexpr u16 M68705_VECTOR_INT = 0xfffa;
//constexpr u16 M68705_VECTOR_SWI = 0xfffc; constexpr u16 M68705_VECTOR_SWI = 0xfffc;
constexpr u16 M68705_VECTOR_RESET = 0xfffe; constexpr u16 M68705_VECTOR_RESET = 0xfffe;
} // anonymous namespace } // anonymous namespace
@ -201,7 +201,7 @@ m68705_device::m68705_device(
clock, clock,
type, type,
name, name,
{ s_hmos_ops, s_hmos_cycles, addr_width, 0x007f, 0x0060, 0xfffc }, { s_hmos_ops, s_hmos_cycles, addr_width, 0x007f, 0x0060, M68705_VECTOR_SWI },
internal_map, internal_map,
shortname, shortname,
source) source)
@ -249,7 +249,7 @@ template <offs_t B> WRITE8_MEMBER(m68705_device::eprom_w)
else else
{ {
// this causes undefined behaviour, which is bad when EPROM programming is involved // this causes undefined behaviour, which is bad when EPROM programming is involved
logerror("warning: write to EPROM when /PGE = 0 (%x = %x)\n", B + offset, data); logerror("warning: write to EPROM when /PGE = 0 (%04X = %02X)\n", B + offset, data);
} }
} }
} }
@ -273,7 +273,7 @@ template <std::size_t N> READ8_MEMBER(m68705_device::port_r)
u8 const newval(m_port_cb_r[N](space, 0, ~m_port_ddr[N] & ~m_port_mask[N]) & ~m_port_mask[N]); u8 const newval(m_port_cb_r[N](space, 0, ~m_port_ddr[N] & ~m_port_mask[N]) & ~m_port_mask[N]);
if (newval != m_port_input[N]) if (newval != m_port_input[N])
{ {
LOGIOPORT("read PORT%c: new input = %02X & %02X (was %02x)\n", LOGIOPORT("read PORT%c: new input = %02X & %02X (was %02X)\n",
char('A' + N), newval, ~m_port_ddr[N] & ~m_port_mask[N], m_port_input[N]); char('A' + N), newval, ~m_port_ddr[N] & ~m_port_mask[N], m_port_input[N]);
} }
m_port_input[N] = newval; m_port_input[N] = newval;
@ -286,7 +286,7 @@ template <std::size_t N> WRITE8_MEMBER(m68705_device::port_latch_w)
data &= ~m_port_mask[N]; data &= ~m_port_mask[N];
u8 const diff = m_port_latch[N] ^ data; u8 const diff = m_port_latch[N] ^ data;
if (diff) if (diff)
LOGIOPORT("write PORT%c latch: %02X & %02X (was %02x)\n", char('A' + N), data, m_port_ddr[N], m_port_latch[N]); LOGIOPORT("write PORT%c latch: %02X & %02X (was %02X)\n", char('A' + N), data, m_port_ddr[N], m_port_latch[N]);
m_port_latch[N] = data; m_port_latch[N] = data;
if (diff & m_port_ddr[N]) if (diff & m_port_ddr[N])
port_cb_w<N>(); port_cb_w<N>();
@ -297,7 +297,7 @@ template <std::size_t N> WRITE8_MEMBER(m68705_device::port_ddr_w)
data &= ~m_port_mask[N]; data &= ~m_port_mask[N];
if (data != m_port_ddr[N]) if (data != m_port_ddr[N])
{ {
LOGIOPORT("write DDR%c: %02X (was %02x)\n", char('A' + N), data, m_port_ddr[N]); LOGIOPORT("write DDR%c: %02X (was %02X)\n", char('A' + N), data, m_port_ddr[N]);
m_port_ddr[N] = data; m_port_ddr[N] = data;
port_cb_w<N>(); port_cb_w<N>();
} }
@ -594,9 +594,9 @@ void m68705_device::interrupt()
{ {
throw emu_fatalerror("Unknown pending interrupt"); throw emu_fatalerror("Unknown pending interrupt");
} }
m_icount -= 11;
burn_cycles(11);
} }
m_icount -= 11;
burn_cycles(11);
} }
} }

View File

@ -1,37 +1,93 @@
// license:BSD-3-Clause // license:BSD-3-Clause
// copyright-holders:Vas Crabb // copyright-holders:Vas Crabb
/*
High-speed CMOS 6805-compatible microcontrollers
The M68HC05 family uses the M6805 instruction set with a few additions
but runs at two clocks per machine cycle, and has incompatible on-board
peripherals. It comes in mask ROM (M68HC05), EPROM (M68HC705) and
EEPROM (M68HC805) variants. The suffix gives some indication of the
memory sizes and on-board peripherals, but there's not a lot of
consistency across the ROM/EPROM/EEPROM variants.
All devices in this family have a 16-bit free-running counter fed from
the internal clock. The counter value can be captured on an input edge,
and an output can be automatically set when the counter reaches a
certain value.
*/
#include "emu.h" #include "emu.h"
#include "m68hc05.h" #include "m68hc05.h"
#include "m6805defs.h" #include "m6805defs.h"
/**************************************************************************** /****************************************************************************
* Configurable logging * Configurable logging
****************************************************************************/ ****************************************************************************/
//#define VERBOSE (LOG_GENERAL) #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 VERBOSE (LOG_GENERAL | LOG_INT | LOG_IOPORT | LOG_TIMER | LOG_COP)
//#define LOG_OUTPUT_FUNC printf //#define LOG_OUTPUT_FUNC printf
#include "logmacro.h" #include "logmacro.h"
#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__)
#define LOGIOPORT(...) LOGMASKED(LOG_IOPORT, __VA_ARGS__)
#define LOGTIMER(...) LOGMASKED(LOG_TIMER, __VA_ARGS__)
#define LOGCOP(...) LOGMASKED(LOG_COP, __VA_ARGS__)
namespace { namespace {
std::pair<u16, char const *> const m68705c4_syms[] = { std::pair<u16, char const *> const m68hc05c4_syms[] = {
{ 0x0000, "PORTA" }, { 0x0001, "PORTB" }, { 0x0002, "PORTC" }, { 0x0003, "PORTD" }, { 0x0000, "PORTA" }, { 0x0001, "PORTB" }, { 0x0002, "PORTC" }, { 0x0003, "PORTD" },
{ 0x0004, "DDRA" }, { 0x0005, "DDRB" }, { 0x0006, "DDRC" }, { 0x0004, "DDRA" }, { 0x0005, "DDRB" }, { 0x0006, "DDRC" },
{ 0x000a, "SPCR" }, { 0x000b, "SPSR" }, { 0x000c, "SPDR" }, { 0x000a, "SPCR" }, { 0x000b, "SPSR" }, { 0x000c, "SPDR" },
{ 0x000d, "BAUD" }, { 0x000e, "SCCR1" }, { 0x000f, "SCCR2" }, { 0x0010, "SCSR" }, { 0x0011, "SCDR" }, { 0x000d, "BAUD" }, { 0x000e, "SCCR1" }, { 0x000f, "SCCR2" }, { 0x0010, "SCSR" }, { 0x0011, "SCDR" },
{ 0x0012, "TCR" }, { 0x0013, "TSR" }, { 0x0012, "TCR" }, { 0x0013, "TSR" },
{ 0x0014, "ICRH" }, { 0x0015, "ICRL" }, { 0x0016, "OCRH" }, { 0x0017, "OCRL" }, { 0x0014, "ICRH" }, { 0x0015, "ICRL" }, { 0x0016, "OCRH" }, { 0x0017, "OCRL" },
{ 0x0018, "TRH" }, { 0x0019, "TRL" }, { 0x001a, "ATRH" }, { 0x001b, "ATRL" } }; { 0x0018, "TRH" }, { 0x0019, "TRL" }, { 0x001a, "ATRH" }, { 0x001b, "ATRL" } };
std::pair<u16, char const *> const m68hc705c8a_syms[] = {
{ 0x0000, "PORTA" }, { 0x0001, "PORTB" }, { 0x0002, "PORTC" }, { 0x0003, "PORTD" },
{ 0x0004, "DDRA" }, { 0x0005, "DDRB" }, { 0x0006, "DDRC" },
{ 0x000a, "SPCR" }, { 0x000b, "SPSR" }, { 0x000c, "SPDR" },
{ 0x000d, "BAUD" }, { 0x000e, "SCCR1" }, { 0x000f, "SCCR2" }, { 0x0010, "SCSR" }, { 0x0011, "SCDR" },
{ 0x0012, "TCR" }, { 0x0013, "TSR" },
{ 0x0014, "ICRH" }, { 0x0015, "ICRL" }, { 0x0016, "OCRH" }, { 0x0017, "OCRL" },
{ 0x0018, "TRH" }, { 0x0019, "TRL" }, { 0x001a, "ATRH" }, { 0x001b, "ATRL" },
{ 0x001c, "PROG" },
{ 0x001d, "COPRST" }, { 0x001e, "COPCR" } };
ROM_START( m68hc705c8a )
ROM_REGION(0x00f0, "bootstrap", 0)
ROM_LOAD("bootstrap.bin", 0x0000, 0x00f0, NO_DUMP)
ROM_END
//constexpr u16 M68HC05_VECTOR_SPI = 0xfff4;
//constexpr u16 M68HC05_VECTOR_SCI = 0xfff6;
constexpr u16 M68HC05_VECTOR_TIMER = 0xfff8;
//constexpr u16 M68HC05_VECTOR_INT = 0xfffa;
constexpr u16 M68HC05_VECTOR_SWI = 0xfffc;
//constexpr u16 M68HC05_VECTOR_RESET = 0xfffe;
} // anonymous namespace } // anonymous namespace
/**************************************************************************** /****************************************************************************
* Global variables * Global variables
****************************************************************************/ ****************************************************************************/
device_type const M68HC05C4 = &device_creator<m68hc05c4_device>; device_type const M68HC05C4 = &device_creator<m68hc05c4_device>;
device_type const M68HC05C8 = &device_creator<m68hc05c8_device>;
device_type const M68HC705C8A = &device_creator<m68hc705c8a_device>;
/**************************************************************************** /****************************************************************************
@ -55,24 +111,371 @@ m68hc05_device::m68hc05_device(
clock, clock,
type, type,
name, name,
{ s_hc_ops, s_hc_cycles, 13, 0x00ff, 0x00c0, 0xfffc }, { s_hc_ops, s_hc_cycles, 13, 0x00ff, 0x00c0, M68HC05_VECTOR_SWI },
internal_map, internal_map,
shortname, shortname,
source) source)
, m_port_cb_r{ *this, *this, *this, *this }
, m_port_cb_w{ *this, *this, *this, *this }
, m_port_bits{ 0xff, 0xff, 0xff, 0xff }
, m_port_input{ 0xff, 0xff, 0xff, 0xff }
, m_port_latch{ 0xff, 0xff, 0xff, 0xff }
, m_port_ddr{ 0x00, 0x00, 0x00, 0x00 }
, m_tcmp_cb(*this)
, m_tcap_state(false)
, m_tcr(0x00)
, m_tsr(0x00), m_tsr_seen(0x00)
, m_prescaler(0x00)
, m_counter(0xfffc), m_icr(0x0000), m_ocr(0x0000)
, m_inhibit_cap(false), m_inhibit_cmp(false)
, m_trl_buf{ 0xfc, 0xfc }
, m_trl_latched{ false, false }
, m_pcop_cnt(0)
, m_ncop_cnt(0)
, m_coprst(0x00)
, m_copcr(0x00)
, m_ncope(0)
{ {
} }
void m68hc05_device::set_port_bits(u8 a, u8 b, u8 c, u8 d)
{
if (configured() || started())
throw emu_fatalerror("Attempt to set physical port bits after configuration");
m_port_bits[0] = a;
m_port_bits[1] = b;
m_port_bits[2] = c;
m_port_bits[3] = d;
}
READ8_MEMBER(m68hc05_device::port_r)
{
offset &= PORT_COUNT - 1;
if (!m_port_cb_r[offset].isnull())
{
u8 const newval(m_port_cb_r[offset](space, 0, ~m_port_ddr[offset] & m_port_bits[offset]) & m_port_bits[offset]);
if (newval != m_port_input[offset])
{
LOGIOPORT("read PORT%c: new input = %02X & %02X (was %02X)\n",
char('A' + offset), newval, ~m_port_ddr[offset] & m_port_bits[offset], m_port_input[offset]);
}
m_port_input[offset] = newval;
}
return port_value(offset);
}
WRITE8_MEMBER(m68hc05_device::port_latch_w)
{
offset &= PORT_COUNT - 1;
data &= m_port_bits[offset];
u8 const diff = m_port_latch[offset] ^ data;
if (diff)
{
LOGIOPORT("write PORT%c latch: %02X & %02X (was %02X)\n",
char('A' + offset), data, m_port_ddr[offset], m_port_latch[offset]);
}
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]);
}
READ8_MEMBER(m68hc05_device::port_ddr_r)
{
return m_port_ddr[offset & (PORT_COUNT - 1)];
}
WRITE8_MEMBER(m68hc05_device::port_ddr_w)
{
offset &= PORT_COUNT - 1;
data &= m_port_bits[offset];
if (data != m_port_ddr[offset])
{
LOGIOPORT("write DDR%c: %02X (was %02X)\n", char('A' + offset), data, m_port_ddr[offset]);
m_port_ddr[offset] = data;
m_port_cb_w[offset](space, 0, port_value(offset), m_port_ddr[offset]);
}
}
READ8_MEMBER(m68hc05_device::tcr_r)
{
return m_tcr;
}
WRITE8_MEMBER(m68hc05_device::tcr_w)
{
data &= 0xe3;
LOGTIMER("write TCR: ICIE=%u OCIE=%u TOIE=%u IEDG=%u OLVL=%u\n",
BIT(data, 7), BIT(data, 6), BIT(data, 5), BIT(data, 1), BIT(data, 0));
m_tcr = data;
if (m_tcr & m_tsr & 0xe0)
m_pending_interrupts |= u16(1) << M68HC05_TCAP_LINE;
else
m_pending_interrupts &= ~(u16(1) << M68HC05_TCAP_LINE);
}
READ8_MEMBER(m68hc05_device::tsr_r)
{
if (!space.debugger_access())
{
u8 const events(m_tsr & ~m_tsr_seen);
if (events)
{
LOGTIMER("read TSR: seen%s%s%s\n",
BIT(events, 7) ? " ICF" : "", BIT(events, 6) ? " OCF" : "", BIT(events, 5) ? " TOF" : "");
}
m_tsr_seen = m_tsr;
}
return m_tsr;
}
READ8_MEMBER(m68hc05_device::icr_r)
{
// reading IRCH inhibits capture until ICRL is read
// reading ICRL after reading TCR with ICF set clears ICF
u8 const low(BIT(offset, 0));
if (!space.debugger_access())
{
if (low)
{
if (BIT(m_tsr_seen, 7))
{
LOGTIMER("read ICRL, clear ICF\n");
m_tsr &= 0x7f;
m_tsr_seen &= 0x7f;
if (!(m_tcr & m_tsr & 0xe0)) m_pending_interrupts &= ~(u16(1) << M68HC05_TCAP_LINE);
}
if (m_inhibit_cap) LOGTIMER("read ICRL, enable capture\n");
m_inhibit_cap = false;
}
else
{
if (!m_inhibit_cap) LOGTIMER("read ICRH, inhibit capture\n");
m_inhibit_cap = true;
}
}
return u8(m_icr >> (low ? 0 : 8));
}
READ8_MEMBER(m68hc05_device::ocr_r)
{
// reading OCRL after reading TCR with OCF set clears OCF
u8 const low(BIT(offset, 0));
if (!space.debugger_access() && low && BIT(m_tsr_seen, 6))
{
LOGTIMER("read OCRL, clear OCF\n");
m_tsr &= 0xbf;
m_tsr_seen &= 0xbf;
if (!(m_tcr & m_tsr & 0xe0)) m_pending_interrupts &= ~(u16(1) << M68HC05_TCAP_LINE);
}
return u8(m_ocr >> (low ? 0 : 8));
}
WRITE8_MEMBER(m68hc05_device::ocr_w)
{
// writing ORCH inhibits compare until OCRL is written
// writing OCRL after reading TCR with OCF set clears OCF
u8 const low(BIT(offset, 0));
if (!space.debugger_access())
{
if (low)
{
if (BIT(m_tsr_seen, 6))
{
LOGTIMER("write OCRL, clear OCF\n");
m_tsr &= 0xbf;
m_tsr_seen &= 0xbf;
if (!(m_tcr & m_tsr & 0xe0)) m_pending_interrupts &= ~(u16(1) << M68HC05_TCAP_LINE);
}
if (m_inhibit_cmp) LOGTIMER("write OCRL, enable compare\n");
m_inhibit_cmp = false;
}
else
{
if (!m_inhibit_cmp) LOGTIMER("write OCRH, inhibit compare\n");
m_inhibit_cmp = true;
}
}
m_ocr = (m_ocr & (low ? 0xff00 : 0x00ff)) | (u16(data) << (low ? 0 : 8));
}
READ8_MEMBER(m68hc05_device::timer_r)
{
// reading [A]TRH returns current counter MSB and latches [A]TRL buffer
// reading [A]TRL returns current [A]TRL buffer and completes read sequence
// reading TRL after reading TSR with TOF set clears TOF
// reading ATRL doesn't affect TOF
u8 const low(BIT(offset, 0));
u8 const alt(BIT(offset, 1));
if (low)
{
if (!space.debugger_access())
{
if (m_trl_latched[alt]) LOGTIMER("read %sTRL, read sequence complete\n", alt ? "A" : "");
m_trl_latched[alt] = false;
if (!alt && BIT(m_tsr_seen, 5))
{
LOGTIMER("read TRL, clear TOF\n");
m_tsr &= 0xdf;
m_tsr_seen &= 0xdf;
if (!(m_tcr & m_tsr & 0xe0)) m_pending_interrupts &= ~(u16(1) << M68HC05_TCAP_LINE);
}
}
return m_trl_buf[alt];
}
else
{
if (!space.debugger_access() && !m_trl_latched[alt])
{
LOGTIMER("read %sTRH, latch %sTRL\n", alt ? "A" : "", alt ? "A" : "");
m_trl_latched[alt] = true;
m_trl_buf[alt] = u8(m_counter);
}
return u8(m_counter >> 8);
}
}
WRITE8_MEMBER(m68hc05_device::coprst_w)
{
LOGCOP("write COPRST=%02x%s\n", data, ((0xaa == data) && (0x55 == m_coprst)) ? ", reset" : "");
if (0x55 == data)
{
m_coprst = data;
}
else if (0xaa == data)
{
if (0x55 == m_coprst) m_pcop_cnt &= 0x00007fff;
m_coprst = data;
}
}
READ8_MEMBER(m68hc05_device::copcr_r)
{
if (copcr_copf()) LOGCOP("read COPCR, clear COPF\n");
u8 const result(m_copcr);
m_copcr &= 0xef;
return result;
}
WRITE8_MEMBER(m68hc05_device::copcr_w)
{
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)
{
LOGCOP("write COPR: COPC=%u\n", BIT(data, 0));
if (!BIT(data, 0)) m_ncop_cnt = 0;
}
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_input));
save_item(NAME(m_port_latch));
save_item(NAME(m_port_ddr));
// save timer/counter
save_item(NAME(m_tcap_state));
save_item(NAME(m_tcr));
save_item(NAME(m_tsr));
save_item(NAME(m_tsr_seen));
save_item(NAME(m_prescaler));
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_cmp));
save_item(NAME(m_trl_buf));
save_item(NAME(m_trl_latched));
// save COP watchdogs
save_item(NAME(m_pcop_cnt));
save_item(NAME(m_ncop_cnt));
save_item(NAME(m_coprst));
save_item(NAME(m_copcr));
save_item(NAME(m_ncope));
// digital I/O state unaffected by reset
std::fill(std::begin(m_port_input), std::end(m_port_input), 0xff);
std::fill(std::begin(m_port_latch), std::end(m_port_latch), 0xff);
// timer state unaffected by reset
m_tcap_state = false;
m_tcr = 0x00;
m_tsr = 0x00;
m_icr = 0x0000;
m_ocr = 0x0000;
// COP watchdog state unaffected by reset
m_pcop_cnt = 0;
m_coprst = 0x00;
m_copcr = 0x00;
m_ncope = 0;
}
void m68hc05_device::device_reset()
{
m6805_base_device::device_reset();
// digital I/O reset
std::fill(std::begin(m_port_ddr), std::end(m_port_ddr), 0x00);
// timer reset
m_tcr &= 0x02;
m_tsr_seen = 0x00;
m_prescaler = 0;
m_counter = 0xfffc;
m_inhibit_cap = m_inhibit_cmp = false;
m_trl_buf[0] = m_trl_buf[1] = u8(m_counter);
m_trl_latched[0] = m_trl_latched[1] = false;
// COP watchdog reset
m_ncop_cnt = 0;
m_copcr &= 0x10;
}
void m68hc05_device::execute_set_input(int inputnum, int state) void m68hc05_device::execute_set_input(int inputnum, int state)
{ {
switch (inputnum) switch (inputnum)
{ {
case M68HC05_TCAP_LINE:
if ((bool(state) != m_tcap_state) && (bool(state) == tcr_iedg()))
{
LOGTIMER("input capture %04X%s\n", m_counter, m_inhibit_cap ? " [inhibited]" : "");
if (!m_inhibit_cap)
{
m_tsr |= 0x80;
m_icr = m_counter;
if (m_tcr & m_tsr & 0xe0) m_pending_interrupts |= u16(1) << M68HC05_TCAP_LINE;
}
}
m_tcap_state = bool(state);
break;
default: default:
if (m_irq_state[inputnum] != state) if (m_irq_state[inputnum] != state)
{ {
m_irq_state[inputnum] = (state == ASSERT_LINE) ? ASSERT_LINE : CLEAR_LINE; m_irq_state[inputnum] = (state == ASSERT_LINE) ? ASSERT_LINE : CLEAR_LINE;
if (state != CLEAR_LINE) if (state != CLEAR_LINE)
m_pending_interrupts |= 1 << inputnum; m_pending_interrupts |= u16(1) << inputnum;
} }
} }
} }
@ -87,6 +490,7 @@ uint64_t m68hc05_device::execute_cycles_to_clocks(uint64_t cycles) const
return cycles * 2; return cycles * 2;
} }
offs_t m68hc05_device::disasm_disassemble( offs_t m68hc05_device::disasm_disassemble(
std::ostream &stream, std::ostream &stream,
offs_t pc, offs_t pc,
@ -98,6 +502,133 @@ offs_t m68hc05_device::disasm_disassemble(
} }
void m68hc05_device::interrupt()
{
if (m_pending_interrupts & M68HC05_INT_MASK)
{
if (!(CC & IFLAG))
{
pushword(m_pc);
pushbyte(m_x);
pushbyte(m_a);
pushbyte(m_cc);
SEI;
standard_irq_callback(0);
/*if (BIT(m_pending_interrupts, M68705_IRQ_LINE))
{
LOGINT("servicing /INT interrupt\n");
m_pending_interrupts &= ~(1 << M68705_IRQ_LINE);
rm16(M68705_VECTOR_INT, m_pc);
}
else*/ if (BIT(m_pending_interrupts, M68HC05_TCAP_LINE))
{
LOGINT("servicing timer interrupt\n");
rm16(M68HC05_VECTOR_TIMER, m_pc);
}
else
{
throw emu_fatalerror("Unknown pending interrupt");
}
m_icount -= 10;
burn_cycles(10);
}
}
}
void m68hc05_device::burn_cycles(unsigned count)
{
// calculate new timer values (fixed prescaler of four)
unsigned const ps_opt(4);
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 output_compare_match((m_ocr > m_counter) && (m_ocr <= new_counter));
m_prescaler = (count + m_prescaler) & ps_mask;
m_counter = u16(new_counter);
if (timer_rollover)
{
LOGTIMER("timer rollover\n");
m_tsr |= 0x20;
}
if (output_compare_match)
{
LOGTIMER("output compare match %s\n", m_inhibit_cmp ? " [inhibited]" : "");
if (!m_inhibit_cmp)
{
m_tsr |= 0x40;
m_tcmp_cb(tcr_olvl() ? 1 : 0);
}
}
if (m_tcr & m_tsr & 0xe0) m_pending_interrupts |= u16(1) << M68HC05_TCAP_LINE;
// run programmable COP
u32 const pcop_timeout(u32(1) << ((copcr_cm() << 1) + 15));
if (copcr_pcope() && (pcop_timeout <= ((m_pcop_cnt & (pcop_timeout - 1)) + count)))
{
LOGCOP("PCOP reset\n");
m_copcr |= 0x10;
set_input_line(INPUT_LINE_RESET, PULSE_LINE);
}
m_pcop_cnt = (m_pcop_cnt + count) & ((u32(1) << 21) - 1);
// run non-programmable COP
m_ncop_cnt += count;
if ((u32(1) << 17) <= m_ncop_cnt)
{
set_input_line(INPUT_LINE_RESET, PULSE_LINE);
LOGCOP("NCOP reset\n");
}
m_ncop_cnt &= (u32(1) << 17) - 1;
}
void m68hc05_device::add_timer_state()
{
state_add(M68HC05_TCR, "TCR", m_tcr).mask(0x7f);
state_add(M68HC05_TSR, "TSR", m_tsr).mask(0xff);
state_add(M68HC05_ICR, "ICR", m_icr).mask(0xffff);
state_add(M68HC05_OCR, "OCR", m_ocr).mask(0xffff);
state_add(M68HC05_PS, "PS", m_prescaler).mask(0x03);
state_add(M68HC05_TR, "TR", m_counter).mask(0xffff);
}
void m68hc05_device::add_pcop_state()
{
state_add(M68HC05_COPRST, "COPRST", m_coprst).mask(0xff);
state_add(M68HC05_COPCR, "COPCR", m_copcr).mask(0x1f);
state_add(M68HC05_PCOP, "PCOP", m_pcop_cnt).mask(0x001fffff);
}
void m68hc05_device::add_ncop_state()
{
state_add(M68HC05_NCOPE, "NCOPE", m_ncope).mask(0x01);
state_add(M68HC05_NCOP, "NCOP", m_ncop_cnt).mask(0x0001ffff);
}
/****************************************************************************
* M68HC705 base device
****************************************************************************/
m68hc705_device::m68hc705_device(
machine_config const &mconfig,
char const *tag,
device_t *owner,
u32 clock,
device_type type,
char const *name,
address_map_delegate internal_map,
char const *shortname,
char const *source)
: m68hc05_device(mconfig, tag, owner, clock, type, name, internal_map, shortname, source)
{
}
/**************************************************************************** /****************************************************************************
* MC68HC05C4 device * MC68HC05C4 device
****************************************************************************/ ****************************************************************************/
@ -106,13 +637,8 @@ DEVICE_ADDRESS_MAP_START( c4_map, 8, m68hc05c4_device )
ADDRESS_MAP_GLOBAL_MASK(0x1fff) ADDRESS_MAP_GLOBAL_MASK(0x1fff)
ADDRESS_MAP_UNMAP_HIGH ADDRESS_MAP_UNMAP_HIGH
// 0x0000 PORTA AM_RANGE(0x0000, 0x0003) AM_READWRITE(port_r, port_latch_w)
// 0x0001 PORTB AM_RANGE(0x0004, 0x0006) AM_READWRITE(port_ddr_r, port_ddr_w)
// 0x0002 PORTC
// 0x0003 PORTD
// 0x0004 DDRA
// 0x0005 DDRB
// 0x0006 DDRC
// 0x0007-0x0009 unused // 0x0007-0x0009 unused
// 0x000a SPCR // 0x000a SPCR
// 0x000b SPSR // 0x000b SPSR
@ -122,16 +648,11 @@ DEVICE_ADDRESS_MAP_START( c4_map, 8, m68hc05c4_device )
// 0x000f SCCR2 // 0x000f SCCR2
// 0x0010 SCSR // 0x0010 SCSR
// 0x0011 SCDR // 0x0011 SCDR
// 0x0012 TCR AM_RANGE(0x0012, 0x0012) AM_READWRITE(tcr_r, tcr_w)
// 0x0013 TDR AM_RANGE(0x0013, 0x0013) AM_READ(tsr_r)
// 0x0014 ICRH AM_RANGE(0x0014, 0x0015) AM_READ(icr_r)
// 0x0015 ICRL AM_RANGE(0x0016, 0x0017) AM_READWRITE(ocr_r, ocr_w)
// 0x0016 OCRH AM_RANGE(0x0018, 0x001b) AM_READ(timer_r)
// 0x0017 OCRL
// 0x0018 TRH
// 0x0019 TRL
// 0x001a ATRH
// 0x001b ATRL
// 0x001c-0x001f unused // 0x001c-0x001f unused
AM_RANGE(0x0020, 0x004f) AM_ROM // user ROM AM_RANGE(0x0020, 0x004f) AM_ROM // user ROM
AM_RANGE(0x0050, 0x00ff) AM_RAM // RAM/stack AM_RANGE(0x0050, 0x00ff) AM_RAM // RAM/stack
@ -142,6 +663,7 @@ DEVICE_ADDRESS_MAP_START( c4_map, 8, m68hc05c4_device )
AM_RANGE(0x1ff4, 0x1fff) AM_ROM // user vectors AM_RANGE(0x1ff4, 0x1fff) AM_ROM // user vectors
ADDRESS_MAP_END ADDRESS_MAP_END
m68hc05c4_device::m68hc05c4_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock) m68hc05c4_device::m68hc05c4_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
: m68hc05_device( : m68hc05_device(
mconfig, mconfig,
@ -154,8 +676,19 @@ m68hc05c4_device::m68hc05c4_device(machine_config const &mconfig, char const *ta
"m68hc05c4", "m68hc05c4",
__FILE__) __FILE__)
{ {
set_port_bits(0xff, 0xff, 0xff, 0xbf);
} }
void m68hc05c4_device::device_start()
{
m68hc05_device::device_start();
add_timer_state();
}
offs_t m68hc05c4_device::disasm_disassemble( offs_t m68hc05c4_device::disasm_disassemble(
std::ostream &stream, std::ostream &stream,
offs_t pc, offs_t pc,
@ -163,5 +696,167 @@ offs_t m68hc05c4_device::disasm_disassemble(
const uint8_t *opram, const uint8_t *opram,
uint32_t options) uint32_t options)
{ {
return CPU_DISASSEMBLE_NAME(m68hc05)(this, stream, pc, oprom, opram, options, m68705c4_syms); return CPU_DISASSEMBLE_NAME(m68hc05)(this, stream, pc, oprom, opram, options, m68hc05c4_syms);
}
/****************************************************************************
* MC68HC05C8 device
****************************************************************************/
DEVICE_ADDRESS_MAP_START( c8_map, 8, m68hc05c8_device )
ADDRESS_MAP_GLOBAL_MASK(0x1fff)
ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x0000, 0x0003) AM_READWRITE(port_r, port_latch_w)
AM_RANGE(0x0004, 0x0006) AM_READWRITE(port_ddr_r, port_ddr_w)
// 0x0007-0x0009 unused
// 0x000a SPCR
// 0x000b SPSR
// 0x000c SPDR
// 0x000d BAUD
// 0x000e SCCR1
// 0x000f SCCR2
// 0x0010 SCSR
// 0x0011 SCDR
AM_RANGE(0x0012, 0x0012) AM_READWRITE(tcr_r, tcr_w)
AM_RANGE(0x0013, 0x0013) AM_READ(tsr_r)
AM_RANGE(0x0014, 0x0015) AM_READ(icr_r)
AM_RANGE(0x0016, 0x0017) AM_READWRITE(ocr_r, ocr_w)
AM_RANGE(0x0018, 0x001b) AM_READ(timer_r)
// 0x001c-0x001f unused
AM_RANGE(0x0020, 0x004f) AM_ROM // user ROM
AM_RANGE(0x0050, 0x00ff) AM_RAM // RAM/stack
AM_RANGE(0x0100, 0x1eff) AM_ROM // user ROM
AM_RANGE(0x1f00, 0x1fef) AM_ROM // self-check
// 0x1ff0-0x1ff3 unused
AM_RANGE(0x1ff4, 0x1fff) AM_ROM // user vectors
ADDRESS_MAP_END
m68hc05c8_device::m68hc05c8_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
: m68hc05_device(
mconfig,
tag,
owner,
clock,
M68HC05C8,
"MC68HC05C8",
address_map_delegate(FUNC(m68hc05c8_device::c8_map), this),
"m68hc05c8",
__FILE__)
{
set_port_bits(0xff, 0xff, 0xff, 0xbf);
}
void m68hc05c8_device::device_start()
{
m68hc05_device::device_start();
add_timer_state();
}
offs_t m68hc05c8_device::disasm_disassemble(
std::ostream &stream,
offs_t pc,
const uint8_t *oprom,
const uint8_t *opram,
uint32_t options)
{
// same I/O registers as MC68HC05C4
return CPU_DISASSEMBLE_NAME(m68hc05)(this, stream, pc, oprom, opram, options, m68hc05c4_syms);
}
/****************************************************************************
* MC68HC705C8A device
****************************************************************************/
DEVICE_ADDRESS_MAP_START( c8a_map, 8, m68hc705c8a_device )
ADDRESS_MAP_GLOBAL_MASK(0x1fff)
ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x0000, 0x0003) AM_READWRITE(port_r, port_latch_w)
AM_RANGE(0x0004, 0x0006) AM_READWRITE(port_ddr_r, port_ddr_w)
// 0x0007-0x0009 unused
// 0x000a SPCR
// 0x000b SPSR
// 0x000c SPDR
// 0x000d BAUD
// 0x000e SCCR1
// 0x000f SCCR2
// 0x0010 SCSR
// 0x0011 SCDR
AM_RANGE(0x0012, 0x0012) AM_READWRITE(tcr_r, tcr_w)
AM_RANGE(0x0013, 0x0013) AM_READ(tsr_r)
AM_RANGE(0x0014, 0x0015) AM_READ(icr_r)
AM_RANGE(0x0016, 0x0017) AM_READWRITE(ocr_r, ocr_w)
AM_RANGE(0x0018, 0x001b) AM_READ(timer_r)
// 0x001c PROG
AM_RANGE(0x001d, 0x001d) AM_WRITE(coprst_w)
AM_RANGE(0x001e, 0x001e) AM_READWRITE(copcr_r, copcr_w)
// 0x001f unused
AM_RANGE(0x0020, 0x004f) AM_ROM // user PROM FIXME: banked with RAM
AM_RANGE(0x0050, 0x00ff) AM_RAM // RAM/stack
AM_RANGE(0x0100, 0x015f) AM_ROM // user PROM FIXME: banked with RAM
AM_RANGE(0x0160, 0x1eff) AM_ROM // user PROM
AM_RANGE(0x1f00, 0x1fde) AM_ROM AM_REGION("bootstrap", 0x0000) // bootloader
// 0x1fdf option register FIXME: controls banking
AM_RANGE(0x1fe0, 0x1fef) AM_ROM AM_REGION("bootstrap", 0x00e0) // boot ROM vectors
AM_RANGE(0x1ff0, 0x1ff0) AM_WRITE(copr_w)
AM_RANGE(0x1ff0, 0x1fff) AM_ROM // user vectors
ADDRESS_MAP_END
m68hc705c8a_device::m68hc705c8a_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
: m68hc705_device(
mconfig,
tag,
owner,
clock,
M68HC705C8A,
"MC68HC705C8A",
address_map_delegate(FUNC(m68hc705c8a_device::c8a_map), this),
"m68hc705c8a",
__FILE__)
{
set_port_bits(0xff, 0xff, 0xff, 0xbf);
}
tiny_rom_entry const *m68hc705c8a_device::device_rom_region() const
{
return ROM_NAME(m68hc705c8a);
}
void m68hc705c8a_device::device_start()
{
m68hc705_device::device_start();
add_timer_state();
add_pcop_state();
add_ncop_state();
}
void m68hc705c8a_device::device_reset()
{
m68hc705_device::device_reset();
set_ncope(rdmem(0xfff1));
}
offs_t m68hc705c8a_device::disasm_disassemble(
std::ostream &stream,
offs_t pc,
const uint8_t *oprom,
const uint8_t *opram,
uint32_t options)
{
return CPU_DISASSEMBLE_NAME(m68hc05)(this, stream, pc, oprom, opram, options, m68hc705c8a_syms);
} }

View File

@ -13,6 +13,8 @@
//************************************************************************** //**************************************************************************
extern device_type const M68HC05C4; extern device_type const M68HC05C4;
extern device_type const M68HC05C8;
extern device_type const M68HC705C8A;
//************************************************************************** //**************************************************************************
@ -21,9 +23,72 @@ extern device_type const M68HC05C4;
// ======================> m68hc05_device // ======================> m68hc05_device
#define MCFG_M68HC05_PORTA_R_CB(obj) \
devcb = &m68hc05_device::set_port_cb_r<0>(*device, DEVCB_##obj);
#define MCFG_M68HC05_PORTB_R_CB(obj) \
devcb = &m68hc05_device::set_port_cb_r<1>(*device, DEVCB_##obj);
#define MCFG_M68HC05_PORTC_R_CB(obj) \
devcb = &m68hc05_device::set_port_cb_r<2>(*device, DEVCB_##obj);
#define MCFG_M68HC05_PORTD_R_CB(obj) \
devcb = &m68hc05_device::set_port_cb_r<3>(*device, DEVCB_##obj);
#define MCFG_M68HC05_PORTA_W_CB(obj) \
devcb = &m68hc05_device::set_port_cb_w<0>(*device, DEVCB_##obj);
#define MCFG_M68HC05_PORTB_W_CB(obj) \
devcb = &m68hc05_device::set_port_cb_w<1>(*device, DEVCB_##obj);
#define MCFG_M68HC05_PORTC_W_CB(obj) \
devcb = &m68hc05_device::set_port_cb_w<2>(*device, DEVCB_##obj);
#define MCFG_M68HC05_PORTD_W_CB(obj) \
devcb = &m68hc05_device::set_port_cb_w<3>(*device, DEVCB_##obj);
#define MCFG_M68HC05_TCMP_CB(obj) \
devcb = &m68hc05_device::set_tcmp_cb(*device, DEVCB_##obj);
class m68hc05_device : public m6805_base_device class m68hc05_device : public m6805_base_device
{ {
public:
// static configuration helpers
template<std::size_t N, typename Object> static devcb_base &set_port_cb_r(device_t &device, Object &&obj)
{ return downcast<m68hc05_device &>(device).m_port_cb_r[N].set_callback(std::forward<Object>(obj)); }
template<std::size_t N, typename Object> static devcb_base &set_port_cb_w(device_t &device, Object &&obj)
{ return downcast<m68hc05_device &>(device).m_port_cb_w[N].set_callback(std::forward<Object>(obj)); }
template<typename Object> static devcb_base &set_tcmp_cb(device_t &device, Object &&obj)
{ return downcast<m68hc05_device &>(device).m_tcmp_cb.set_callback(std::forward<Object>(obj)); }
protected: protected:
// state index constants
enum
{
M68HC05_A = M6805_A,
M68HC05_PC = M6805_PC,
M68HC05_S = M6805_S,
M68HC05_X = M6805_X,
M68HC05_CC = M6805_CC,
M68HC05_IRQ_STATE = M6805_IRQ_STATE,
M68HC05_TCR = 0x10,
M68HC05_TSR,
M68HC05_ICR,
M68HC05_OCR,
M68HC05_PS,
M68HC05_TR,
M68HC05_COPRST,
M68HC05_COPCR,
M68HC05_PCOP,
M68HC05_NCOPE,
M68HC05_NCOP
};
enum { PORT_COUNT = 4 };
m68hc05_device( m68hc05_device(
machine_config const &mconfig, machine_config const &mconfig,
char const *tag, char const *tag,
@ -35,6 +100,29 @@ protected:
char const *shortname, char const *shortname,
char const *source); char const *source);
void set_port_bits(u8 a, u8 b, u8 c, u8 d);
DECLARE_READ8_MEMBER(port_r);
DECLARE_WRITE8_MEMBER(port_latch_w);
DECLARE_READ8_MEMBER(port_ddr_r);
DECLARE_WRITE8_MEMBER(port_ddr_w);
DECLARE_READ8_MEMBER(tcr_r);
DECLARE_WRITE8_MEMBER(tcr_w);
DECLARE_READ8_MEMBER(tsr_r);
DECLARE_READ8_MEMBER(icr_r);
DECLARE_READ8_MEMBER(ocr_r);
DECLARE_WRITE8_MEMBER(ocr_w);
DECLARE_READ8_MEMBER(timer_r);
void set_ncope(bool state) { m_ncope = state ? 1 : 0; }
DECLARE_WRITE8_MEMBER(coprst_w);
DECLARE_READ8_MEMBER(copcr_r);
DECLARE_WRITE8_MEMBER(copcr_w);
DECLARE_WRITE8_MEMBER(copr_w);
virtual void device_start() override;
virtual void device_reset() override;
virtual void execute_set_input(int inputnum, int state) override; virtual void execute_set_input(int inputnum, int state) override;
virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const override; virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const override;
virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const override; virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const override;
@ -45,6 +133,76 @@ protected:
const uint8_t *oprom, const uint8_t *oprom,
const uint8_t *opram, const uint8_t *opram,
uint32_t options) override; uint32_t options) override;
virtual void interrupt() override;
virtual void burn_cycles(unsigned count) override;
void add_timer_state();
void add_pcop_state();
void add_ncop_state();
private:
u8 port_value(unsigned offset) const
{
return (m_port_latch[offset] & m_port_ddr[offset]) | (m_port_input[offset] & ~m_port_ddr[offset]);
}
bool tcr_icie() const { return BIT(m_tcr, 7); }
bool tcr_ocie() const { return BIT(m_tcr, 6); }
bool tcr_toie() const { return BIT(m_tcr, 5); }
bool tcr_iedg() const { return BIT(m_tcr, 1); }
bool tcr_olvl() const { return BIT(m_tcr, 0); }
bool tsr_icf() const { return BIT(m_tsr, 7); }
bool tsr_ocf() const { return BIT(m_tsr, 6); }
bool tsr_tof() const { return BIT(m_tsr, 5); }
bool copcr_copf() const { return BIT(m_copcr, 4); }
bool copcr_cme() const { return BIT(m_copcr, 3); }
bool copcr_pcope() const { return BIT(m_copcr, 2); }
u8 copcr_cm() const { return m_copcr & 0x03; }
// digital I/O
devcb_read8 m_port_cb_r[PORT_COUNT];
devcb_write8 m_port_cb_w[PORT_COUNT];
u8 m_port_bits[PORT_COUNT];
u8 m_port_input[PORT_COUNT];
u8 m_port_latch[PORT_COUNT];
u8 m_port_ddr[PORT_COUNT];
// timer/counter
devcb_write_line m_tcmp_cb;
bool m_tcap_state;
u8 m_tcr;
u8 m_tsr, m_tsr_seen;
u8 m_prescaler;
u16 m_counter, m_icr, m_ocr;
bool m_inhibit_cap, m_inhibit_cmp;
u8 m_trl_buf[2];
bool m_trl_latched[2];
// COP watchdogs
u32 m_pcop_cnt, m_ncop_cnt;
u8 m_coprst, m_copcr;
u8 m_ncope;
};
// ======================> m68hc705_device
class m68hc705_device : public m68hc05_device
{
protected:
m68hc705_device(
machine_config const &mconfig,
char const *tag,
device_t *owner,
u32 clock,
device_type type,
char const *name,
address_map_delegate internal_map,
char const *shortname,
char const *source);
}; };
@ -58,6 +216,8 @@ public:
protected: protected:
DECLARE_ADDRESS_MAP(c4_map, 8); DECLARE_ADDRESS_MAP(c4_map, 8);
virtual void device_start() override;
virtual offs_t disasm_disassemble( virtual offs_t disasm_disassemble(
std::ostream &stream, std::ostream &stream,
offs_t pc, offs_t pc,
@ -66,4 +226,58 @@ protected:
uint32_t options) override; uint32_t options) override;
}; };
// ======================> m68hc05c8_device
class m68hc05c8_device : public m68hc05_device
{
public:
m68hc05c8_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
protected:
DECLARE_ADDRESS_MAP(c8_map, 8);
virtual void device_start() override;
virtual offs_t disasm_disassemble(
std::ostream &stream,
offs_t pc,
const uint8_t *oprom,
const uint8_t *opram,
uint32_t options) override;
};
// ======================> m68hc705c8a_device
class m68hc705c8a_device : public m68hc705_device
{
public:
m68hc705c8a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
protected:
DECLARE_ADDRESS_MAP(c8a_map, 8);
virtual tiny_rom_entry const *device_rom_region() const override;
virtual void device_start() override;
virtual void device_reset() override;
virtual offs_t disasm_disassemble(
std::ostream &stream,
offs_t pc,
const uint8_t *oprom,
const uint8_t *opram,
uint32_t options) override;
};
/****************************************************************************
* 68HC05 section
****************************************************************************/
#define M68HC05_INT_MASK 0x03
#define M68HC05_IRQ_LINE (M6805_IRQ_LINE + 0)
#define M68HC05_TCAP_LINE (M6805_IRQ_LINE + 1)
#endif // MAME_CPU_M6805_M68HC05_H #endif // MAME_CPU_M6805_M68HC05_H