mirror of
https://github.com/holub/mame
synced 2025-05-29 09:03:08 +03:00
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:
parent
1469e75875
commit
029b93f95e
@ -93,7 +93,7 @@ public:
|
||||
device_amiga_keyboard_interface(const machine_config &mconfig, device_t &device);
|
||||
virtual ~device_amiga_keyboard_interface();
|
||||
|
||||
virtual DECLARE_WRITE_LINE_MEMBER(kdat_w) {};
|
||||
virtual DECLARE_WRITE_LINE_MEMBER(kdat_w) = 0;
|
||||
|
||||
protected:
|
||||
amiga_keyboard_bus_device *m_host;
|
||||
|
@ -36,10 +36,10 @@ enum class lvl {
|
||||
HC
|
||||
};
|
||||
|
||||
enum op_names {
|
||||
enum class op_names {
|
||||
adca, adda, anda, asl, asla, aslx, asr, asra,
|
||||
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,
|
||||
cli, clr, clra, clrx, cmpa, com, coma, comx,
|
||||
cpx, dec, deca, decx, eora, ill, inc, inca,
|
||||
@ -50,10 +50,10 @@ enum op_names {
|
||||
tst, tsta, tstx, txa, wait
|
||||
};
|
||||
|
||||
#define OP(name, mode) { name, #name, md::mode, lvl::HMOS }
|
||||
#define OPC(name, mode) { name, #name, md::mode, lvl::CMOS }
|
||||
#define OPHC(name, mode) { name, #name, md::mode, lvl::HC }
|
||||
#define ILLEGAL { ill, nullptr, md::INH, lvl::HMOS }
|
||||
#define OP(name, mode) { op_names::name, #name, md::mode, lvl::HMOS }
|
||||
#define OPC(name, mode) { op_names::name, #name, md::mode, lvl::CMOS }
|
||||
#define OPHC(name, mode) { op_names::name, #name, md::mode, lvl::HC }
|
||||
#define ILLEGAL { op_names::ill, nullptr, md::INH, lvl::HMOS }
|
||||
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),
|
||||
@ -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 (rsp, INH), OP (nop, INH), ILLEGAL , OP (txa, INH),
|
||||
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),
|
||||
ILLEGAL , OP (bsr, REL), OP (ldx, IMM), ILLEGAL ,
|
||||
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 (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 (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 (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 (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 (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 (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 (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 (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 (jmp, IDX), OP (jsr, IDX), OP (ldx, IDX), OP (stx, IDX)
|
||||
};
|
||||
@ -164,12 +164,12 @@ offs_t disassemble(
|
||||
u32 flags;
|
||||
switch (disasm[code].op)
|
||||
{
|
||||
case bsr:
|
||||
case jsr:
|
||||
case op_names::bsr:
|
||||
case op_names::jsr:
|
||||
flags = DASMFLAG_STEP_OVER;
|
||||
break;
|
||||
case rts:
|
||||
case rti:
|
||||
case op_names::rts:
|
||||
case op_names::rti:
|
||||
flags = DASMFLAG_STEP_OUT;
|
||||
break;
|
||||
default:
|
||||
|
@ -386,7 +386,7 @@ void m6805_base_device::interrupt()
|
||||
m_icount -= 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)
|
||||
{
|
||||
@ -402,9 +402,10 @@ void m6805_base_device::interrupt()
|
||||
interrupt_vector();
|
||||
|
||||
m_pending_interrupts &= ~(1 << M6805_IRQ_LINE);
|
||||
|
||||
m_icount -= 11;
|
||||
burn_cycles(11);
|
||||
}
|
||||
m_icount -= 11;
|
||||
burn_cycles(11);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ constexpr u16 M68705_VECTOR_BOOTSTRAP = 0xfff6;
|
||||
constexpr u16 M68705_VECTOR_TIMER = 0xfff8;
|
||||
//constexpr u16 M68705_VECTOR_INT2 = 0xfff8;
|
||||
constexpr u16 M68705_VECTOR_INT = 0xfffa;
|
||||
//constexpr u16 M68705_VECTOR_SWI = 0xfffc;
|
||||
constexpr u16 M68705_VECTOR_SWI = 0xfffc;
|
||||
constexpr u16 M68705_VECTOR_RESET = 0xfffe;
|
||||
|
||||
} // anonymous namespace
|
||||
@ -201,7 +201,7 @@ m68705_device::m68705_device(
|
||||
clock,
|
||||
type,
|
||||
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,
|
||||
shortname,
|
||||
source)
|
||||
@ -249,7 +249,7 @@ template <offs_t B> WRITE8_MEMBER(m68705_device::eprom_w)
|
||||
else
|
||||
{
|
||||
// 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]);
|
||||
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]);
|
||||
}
|
||||
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];
|
||||
u8 const diff = m_port_latch[N] ^ data;
|
||||
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;
|
||||
if (diff & m_port_ddr[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];
|
||||
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;
|
||||
port_cb_w<N>();
|
||||
}
|
||||
@ -594,9 +594,9 @@ void m68705_device::interrupt()
|
||||
{
|
||||
throw emu_fatalerror("Unknown pending interrupt");
|
||||
}
|
||||
m_icount -= 11;
|
||||
burn_cycles(11);
|
||||
}
|
||||
m_icount -= 11;
|
||||
burn_cycles(11);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,37 +1,93 @@
|
||||
// license:BSD-3-Clause
|
||||
// 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 "m68hc05.h"
|
||||
#include "m6805defs.h"
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
#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 {
|
||||
|
||||
std::pair<u16, char const *> const m68705c4_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" } };
|
||||
std::pair<u16, char const *> const m68hc05c4_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" } };
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* 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,
|
||||
type,
|
||||
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,
|
||||
shortname,
|
||||
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)
|
||||
{
|
||||
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:
|
||||
if (m_irq_state[inputnum] != state)
|
||||
{
|
||||
m_irq_state[inputnum] = (state == ASSERT_LINE) ? ASSERT_LINE : 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;
|
||||
}
|
||||
|
||||
|
||||
offs_t m68hc05_device::disasm_disassemble(
|
||||
std::ostream &stream,
|
||||
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
|
||||
****************************************************************************/
|
||||
@ -106,13 +637,8 @@ DEVICE_ADDRESS_MAP_START( c4_map, 8, m68hc05c4_device )
|
||||
ADDRESS_MAP_GLOBAL_MASK(0x1fff)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
|
||||
// 0x0000 PORTA
|
||||
// 0x0001 PORTB
|
||||
// 0x0002 PORTC
|
||||
// 0x0003 PORTD
|
||||
// 0x0004 DDRA
|
||||
// 0x0005 DDRB
|
||||
// 0x0006 DDRC
|
||||
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
|
||||
@ -122,16 +648,11 @@ DEVICE_ADDRESS_MAP_START( c4_map, 8, m68hc05c4_device )
|
||||
// 0x000f SCCR2
|
||||
// 0x0010 SCSR
|
||||
// 0x0011 SCDR
|
||||
// 0x0012 TCR
|
||||
// 0x0013 TDR
|
||||
// 0x0014 ICRH
|
||||
// 0x0015 ICRL
|
||||
// 0x0016 OCRH
|
||||
// 0x0017 OCRL
|
||||
// 0x0018 TRH
|
||||
// 0x0019 TRL
|
||||
// 0x001a ATRH
|
||||
// 0x001b ATRL
|
||||
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
|
||||
@ -142,6 +663,7 @@ DEVICE_ADDRESS_MAP_START( c4_map, 8, m68hc05c4_device )
|
||||
AM_RANGE(0x1ff4, 0x1fff) AM_ROM // user vectors
|
||||
ADDRESS_MAP_END
|
||||
|
||||
|
||||
m68hc05c4_device::m68hc05c4_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
|
||||
: m68hc05_device(
|
||||
mconfig,
|
||||
@ -154,8 +676,19 @@ m68hc05c4_device::m68hc05c4_device(machine_config const &mconfig, char const *ta
|
||||
"m68hc05c4",
|
||||
__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(
|
||||
std::ostream &stream,
|
||||
offs_t pc,
|
||||
@ -163,5 +696,167 @@ offs_t m68hc05c4_device::disasm_disassemble(
|
||||
const uint8_t *opram,
|
||||
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);
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
//**************************************************************************
|
||||
|
||||
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
|
||||
|
||||
#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
|
||||
{
|
||||
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:
|
||||
// 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(
|
||||
machine_config const &mconfig,
|
||||
char const *tag,
|
||||
@ -35,6 +100,29 @@ protected:
|
||||
char const *shortname,
|
||||
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 uint64_t execute_clocks_to_cycles(uint64_t clocks) 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 *opram,
|
||||
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:
|
||||
DECLARE_ADDRESS_MAP(c4_map, 8);
|
||||
|
||||
virtual void device_start() override;
|
||||
|
||||
virtual offs_t disasm_disassemble(
|
||||
std::ostream &stream,
|
||||
offs_t pc,
|
||||
@ -66,4 +226,58 @@ protected:
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user