summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/cosmac
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/cosmac')
-rw-r--r--src/devices/cpu/cosmac/cosdasm.cpp54
-rw-r--r--src/devices/cpu/cosmac/cosmac.cpp287
-rw-r--r--src/devices/cpu/cosmac/cosmac.h96
3 files changed, 286 insertions, 151 deletions
diff --git a/src/devices/cpu/cosmac/cosdasm.cpp b/src/devices/cpu/cosmac/cosdasm.cpp
index b54bd167386..d655a2e0a2b 100644
--- a/src/devices/cpu/cosmac/cosdasm.cpp
+++ b/src/devices/cpu/cosmac/cosdasm.cpp
@@ -150,19 +150,19 @@ offs_t cosmac_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
CDP1801_OPCODE("DEC R%d", implied(opcode)); break;
case 0x30: CDP1801_OPCODE("BR %04X", short_branch(base_pc, pc, params)); break;
- case 0x32: CDP1801_OPCODE("BZ %04X", short_branch(base_pc, pc, params)); break;
- case 0x33: CDP1801_OPCODE("BDF %04X", short_branch(base_pc, pc, params)); break;
- case 0x34: CDP1801_OPCODE("B1 %04X", short_branch(base_pc, pc, params)); break;
- case 0x35: CDP1801_OPCODE("B2 %04X", short_branch(base_pc, pc, params)); break;
- case 0x36: CDP1801_OPCODE("B3 %04X", short_branch(base_pc, pc, params)); break;
- case 0x37: CDP1801_OPCODE("B4 %04X", short_branch(base_pc, pc, params)); break;
+ case 0x32: CDP1801_OPCODE("BZ %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x33: CDP1801_OPCODE("BDF %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x34: CDP1801_OPCODE("B1 %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x35: CDP1801_OPCODE("B2 %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x36: CDP1801_OPCODE("B3 %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x37: CDP1801_OPCODE("B4 %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
case 0x38: CDP1801_OPCODE("SKP %04X", short_skip(pc)); break;
- case 0x3a: CDP1801_OPCODE("BNZ %04X", short_branch(base_pc, pc, params)); break;
- case 0x3b: CDP1801_OPCODE("BNF %04X", short_branch(base_pc, pc, params)); break;
- case 0x3c: CDP1801_OPCODE("BN1 %04X", short_branch(base_pc, pc, params)); break;
- case 0x3d: CDP1801_OPCODE("BN2 %04X", short_branch(base_pc, pc, params)); break;
- case 0x3e: CDP1801_OPCODE("BN3 %04X", short_branch(base_pc, pc, params)); break;
- case 0x3f: CDP1801_OPCODE("BN4 %04X", short_branch(base_pc, pc, params)); break;
+ case 0x3a: CDP1801_OPCODE("BNZ %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x3b: CDP1801_OPCODE("BNF %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x3c: CDP1801_OPCODE("BN1 %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x3d: CDP1801_OPCODE("BN2 %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x3e: CDP1801_OPCODE("BN3 %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x3f: CDP1801_OPCODE("BN4 %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
CDP1801_OPCODE("LDA R%d", implied(opcode)); break;
@@ -213,8 +213,8 @@ offs_t cosmac_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
case 0xfd: CDP1801_OPCODE("SDI #%02X", immediate(pc, params)); break;
case 0xff: CDP1801_OPCODE("SMI #%02X", immediate(pc, params)); break;
// CDP1802
- case 0x31: CDP1802_OPCODE("BQ %04X", short_branch(base_pc, pc, params)); break;
- case 0x39: CDP1802_OPCODE("BNQ %04X", short_branch(base_pc, pc, params)); break;
+ case 0x31: CDP1802_OPCODE("BQ %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
+ case 0x39: CDP1802_OPCODE("BNQ %04X", short_branch(base_pc, pc, params)); flags = STEP_COND; break;
case 0x60:
util::stream_format(stream, m_variant < TYPE_1802 ? "OUT 0" : "IRX");
if (m_config && m_config->get_p() == m_config->get_x())
@@ -235,21 +235,21 @@ offs_t cosmac_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
case 0x7e: CDP1802_OPCODE("SHLC"); break;
case 0x7f: CDP1802_OPCODE("SMBI #%02X", immediate(pc, params)); break;
case 0xc0: CDP1802_OPCODE("LBR %04X", long_branch(pc, params)); break;
- case 0xc1: CDP1802_OPCODE("LBQ %04X", long_branch(pc, params)); break;
- case 0xc2: CDP1802_OPCODE("LBZ %04X", long_branch(pc, params)); break;
- case 0xc3: CDP1802_OPCODE("LBDF %04X", long_branch(pc, params)); break;
+ case 0xc1: CDP1802_OPCODE("LBQ %04X", long_branch(pc, params)); flags = STEP_COND; break;
+ case 0xc2: CDP1802_OPCODE("LBZ %04X", long_branch(pc, params)); flags = STEP_COND; break;
+ case 0xc3: CDP1802_OPCODE("LBDF %04X", long_branch(pc, params)); flags = STEP_COND; break;
case 0xc4: CDP1802_OPCODE("NOP"); break;
- case 0xc5: CDP1802_OPCODE("LSNQ %04X", long_skip(pc)); break;
- case 0xc6: CDP1802_OPCODE("LSNZ %04X", long_skip(pc)); break;
- case 0xc7: CDP1802_OPCODE("LSNF %04X", long_skip(pc)); break;
+ case 0xc5: CDP1802_OPCODE("LSNQ %04X", long_skip(pc)); flags = STEP_COND; break;
+ case 0xc6: CDP1802_OPCODE("LSNZ %04X", long_skip(pc)); flags = STEP_COND; break;
+ case 0xc7: CDP1802_OPCODE("LSNF %04X", long_skip(pc)); flags = STEP_COND; break;
case 0xc8: CDP1802_OPCODE("LSKP %04X", long_skip(pc)); break;
- case 0xc9: CDP1802_OPCODE("LBNQ %04X", long_skip(pc)); break;
- case 0xca: CDP1802_OPCODE("LBNZ %04X", long_skip(pc)); break;
- case 0xcb: CDP1802_OPCODE("LBNF %04X", long_skip(pc)); break;
- case 0xcc: CDP1802_OPCODE("LSIE %04X", long_skip(pc)); break;
- case 0xcd: CDP1802_OPCODE("LSQ %04X", long_skip(pc)); break;
- case 0xce: CDP1802_OPCODE("LSZ %04X", long_skip(pc)); break;
- case 0xcf: CDP1802_OPCODE("LSDF %04X", long_skip(pc)); break;
+ case 0xc9: CDP1802_OPCODE("LBNQ %04X", long_branch(pc, params)); flags = STEP_COND; break;
+ case 0xca: CDP1802_OPCODE("LBNZ %04X", long_branch(pc, params)); flags = STEP_COND; break;
+ case 0xcb: CDP1802_OPCODE("LBNF %04X", long_branch(pc, params)); flags = STEP_COND; break;
+ case 0xcc: CDP1802_OPCODE("LSIE %04X", long_skip(pc)); flags = STEP_COND; break;
+ case 0xcd: CDP1802_OPCODE("LSQ %04X", long_skip(pc)); flags = STEP_COND; break;
+ case 0xce: CDP1802_OPCODE("LSZ %04X", long_skip(pc)); flags = STEP_COND; break;
+ case 0xcf: CDP1802_OPCODE("LSDF %04X", long_skip(pc)); flags = STEP_COND; break;
case 0xfe: CDP1802_OPCODE("SHL"); break;
//
default: CDP1801_OPCODE("illegal"); break;
diff --git a/src/devices/cpu/cosmac/cosmac.cpp b/src/devices/cpu/cosmac/cosmac.cpp
index 7038a26a470..eb1b73397ac 100644
--- a/src/devices/cpu/cosmac/cosmac.cpp
+++ b/src/devices/cpu/cosmac/cosmac.cpp
@@ -10,15 +10,13 @@ TODO:
- is it useful to emulate I and N registers or can they just be defined as (m_op >> x & 0xf)?
- 1804/5/6: extended opcode timing is wrong, multiple execute states
- 1804/5/6: add more extended opcodes (05/06 supports more than 04)
-- 1804/5/6: add counter/timer
+- 1804/5/6: other counter modes
- 1804/5: add internal address map (ram/rom)
**********************************************************************/
#include "emu.h"
-#include "debugger.h"
#include "cosmac.h"
-#include "coreutil.h"
// permit our enums to be saved
ALLOW_SAVE_TYPE(cosmac_device::cosmac_mode);
@@ -253,10 +251,10 @@ cosmac_device::ophandler cdp1802_device::get_ophandler(uint16_t opcode) const
const cosmac_device::ophandler cdp1804_device::s_opcodetable_ex[256] =
{
- &cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und,
- &cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::ldc, &cdp1804_device::und,
- &cdp1804_device::gec, &cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und,
- &cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und,
+ &cdp1804_device::stpc, &cdp1804_device::und, &cdp1804_device::spm2, &cdp1804_device::scm2,
+ &cdp1804_device::spm1, &cdp1804_device::scm1, &cdp1804_device::ldc, &cdp1804_device::stm,
+ &cdp1804_device::gec, &cdp1804_device::und, &cdp1804_device::xie, &cdp1804_device::xid,
+ &cdp1804_device::cie, &cdp1804_device::cid, &cdp1804_device::und, &cdp1804_device::und,
&cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und,
&cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und, &cdp1804_device::und,
@@ -360,31 +358,30 @@ DEFINE_DEVICE_TYPE(CDP1806, cdp1806_device, "cdp1806", "RCA CDP1806")
// cosmac_device - constructor
//-------------------------------------------------
-cosmac_device::cosmac_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : cpu_device(mconfig, type, tag, owner, clock),
- cosmac_disassembler::config(),
- m_program_config("program", ENDIANNESS_LITTLE, 8, 16),
- m_io_config("io", ENDIANNESS_LITTLE, 8, 3),
- m_read_wait(*this),
- m_read_clear(*this),
- m_read_ef{{*this}, {*this}, {*this}, {*this}},
- m_write_q(*this),
- m_read_dma(*this),
- m_write_dma(*this),
- m_write_sc(*this),
- m_write_tpb(*this),
- m_op(0),
- m_state(cosmac_state::STATE_1_INIT),
- m_mode(cosmac_mode::RESET),
- m_pmode(cosmac_mode::RUN),
- m_wait(true),
- m_clear(true),
- m_irq(CLEAR_LINE),
- m_dmain(CLEAR_LINE),
- m_dmaout(CLEAR_LINE),
- m_program(nullptr),
- m_io(nullptr),
- m_cache(nullptr)
+cosmac_device::cosmac_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ cpu_device(mconfig, type, tag, owner, clock),
+ cosmac_disassembler::config(),
+ m_program_config("program", ENDIANNESS_LITTLE, 8, 16),
+ m_io_config("io", ENDIANNESS_LITTLE, 8, 3),
+ m_read_wait(*this, 0),
+ m_read_clear(*this, 0),
+ m_read_int(*this, 0),
+ m_read_dma_in(*this, 0),
+ m_read_dma_out(*this, 0),
+ m_read_ef(*this, 0),
+ m_write_q(*this),
+ m_read_dma(*this, 0),
+ m_write_dma(*this),
+ m_write_sc(*this),
+ m_write_tpb(*this),
+ m_state(cosmac_state::STATE_1_INIT),
+ m_mode(cosmac_mode::RESET),
+ m_pmode(cosmac_mode::RUN),
+ m_wait(true),
+ m_clear(true),
+ m_irq(CLEAR_LINE),
+ m_dmain(CLEAR_LINE),
+ m_dmaout(CLEAR_LINE)
{
for (auto & elem : m_ef)
elem = CLEAR_LINE;
@@ -456,21 +453,38 @@ cdp1806_device::cdp1806_device(const machine_config &mconfig, const char *tag, d
void cosmac_device::device_start()
{
- // resolve callbacks
- m_read_wait.resolve();
- m_read_clear.resolve();
- for (auto &cb : m_read_ef)
- cb.resolve();
- m_write_q.resolve_safe();
- m_read_dma.resolve_safe(0);
- m_write_dma.resolve_safe();
- m_write_sc.resolve_safe();
- m_write_tpb.resolve_safe();
+ // init uninitialized
+ m_pc = 0;
+ m_op = 0;
+ m_flagsio = 0;
+
+ m_d = 0;
+ m_b = 0;
+ m_p = 0;
+ m_x = 0;
+ m_n = 0;
+ m_i = 0;
+ m_t = 0;
+
+ m_df = 0;
+ m_ie = 0;
+ m_cie = 0;
+ m_xie = 0;
+ m_cil = 0;
+ m_q = 0;
+
+ for (uint16_t &r : m_r)
+ r = 0;
+
+ m_cnt_mode = 0;
+ m_cnt_load = 0;
+ m_cnt_count = 0;
+ m_cnt_timer = timer_alloc(FUNC(cosmac_device::cnt_timerout), this);
// get our address spaces
- m_program = &space(AS_PROGRAM);
- m_cache = m_program->cache<0, 0, ENDIANNESS_LITTLE>();
- m_io = &space(AS_IO);
+ space(AS_PROGRAM).cache(m_cache);
+ space(AS_PROGRAM).specific(m_program);
+ space(AS_IO).specific(m_io);
// register our state for the debugger
state_add(STATE_GENPC, "GENPC", m_pc).callimport().callexport().noshow();
@@ -514,7 +528,13 @@ void cosmac_device::device_start()
save_item(NAME(m_t));
save_item(NAME(m_df));
save_item(NAME(m_ie));
+ save_item(NAME(m_cie));
+ save_item(NAME(m_xie));
+ save_item(NAME(m_cil));
save_item(NAME(m_q));
+ save_item(NAME(m_cnt_mode));
+ save_item(NAME(m_cnt_load));
+ save_item(NAME(m_cnt_count));
// set our instruction counter
set_icountptr(m_icount);
@@ -527,13 +547,7 @@ void cosmac_device::device_start()
void cosmac_device::device_reset()
{
- m_ie = 0;
- set_q_flag(0);
- m_df = 0;
- m_p = 0;
-
- for (int i = 0; i < ARRAY_LENGTH(m_r); i++)
- m_r[i] = machine().rand() & 0xffff;
+ // not here, it's done with WAIT and CLEAR lines
}
@@ -645,7 +659,7 @@ std::unique_ptr<util::disasm_interface> cdp1805_device::create_disassembler()
inline uint8_t cosmac_device::read_opcode(offs_t pc)
{
- return m_cache->read_byte(pc);
+ return m_cache.read_byte(pc);
}
@@ -655,7 +669,7 @@ inline uint8_t cosmac_device::read_opcode(offs_t pc)
inline uint8_t cosmac_device::read_byte(offs_t address)
{
- return m_program->read_byte(address);
+ return m_program.read_byte(address);
}
@@ -666,7 +680,7 @@ inline uint8_t cosmac_device::read_byte(offs_t address)
inline uint8_t cosmac_device::read_io_byte(offs_t address)
{
- return m_io->read_byte(address);
+ return m_io.read_byte(address);
}
@@ -676,7 +690,7 @@ inline uint8_t cosmac_device::read_io_byte(offs_t address)
inline void cosmac_device::write_byte(offs_t address, uint8_t data)
{
- m_program->write_byte(address, data);
+ m_program.write_byte(address, data);
}
@@ -687,7 +701,7 @@ inline void cosmac_device::write_byte(offs_t address, uint8_t data)
inline void cosmac_device::write_io_byte(offs_t address, uint8_t data)
{
- m_io->write_byte(address, data);
+ m_io.write_byte(address, data);
}
@@ -711,7 +725,7 @@ offs_t cosmac_device::get_memory_address()
// cycles it takes for one instruction to execute
//-------------------------------------------------
-uint32_t cosmac_device::execute_min_cycles() const
+uint32_t cosmac_device::execute_min_cycles() const noexcept
{
return 8 * 2;
}
@@ -722,24 +736,13 @@ uint32_t cosmac_device::execute_min_cycles() const
// cycles it takes for one instruction to execute
//-------------------------------------------------
-uint32_t cosmac_device::execute_max_cycles() const
+uint32_t cosmac_device::execute_max_cycles() const noexcept
{
return 8 * 3;
}
//-------------------------------------------------
-// execute_input_lines - return the number of
-// input/interrupt lines
-//-------------------------------------------------
-
-uint32_t cosmac_device::execute_input_lines() const
-{
- return 7;
-}
-
-
-//-------------------------------------------------
// execute_set_input -
//-------------------------------------------------
@@ -796,7 +799,7 @@ void cosmac_device::execute_run()
// execute initialization cycle
m_state = cosmac_state::STATE_1_INIT;
- run();
+ run_state();
// next state is IDLE
m_state = cosmac_state::STATE_1_EXECUTE;
@@ -812,11 +815,13 @@ void cosmac_device::execute_run()
break;
case cosmac_mode::RESET:
+ debugger_wait_hook();
reset_state();
m_icount--;
break;
case cosmac_mode::PAUSE:
+ debugger_wait_hook();
m_icount--;
break;
@@ -864,7 +869,7 @@ inline void cosmac_device::run_state()
{
case cosmac_state::STATE_0_FETCH:
m_op = 0;
-
+ [[fallthrough]];
case cosmac_state::STATE_0_FETCH_2ND:
fetch_instruction();
break;
@@ -876,7 +881,7 @@ inline void cosmac_device::run_state()
case cosmac_state::STATE_1_EXECUTE:
sample_ef_lines();
-
+ [[fallthrough]];
case cosmac_state::STATE_1_EXECUTE_2ND:
execute_instruction();
debug();
@@ -906,7 +911,7 @@ inline void cosmac_device::run_state()
inline void cosmac_device::debug()
{
- if ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) && m_state == cosmac_state::STATE_0_FETCH)
+ if (debugger_enabled() && m_state == cosmac_state::STATE_0_FETCH)
{
debugger_instruction_hook(R[P]);
}
@@ -919,11 +924,33 @@ inline void cosmac_device::debug()
inline void cosmac_device::sample_wait_clear()
{
- if (!m_read_wait.isnull()) m_wait = m_read_wait();
- if (!m_read_clear.isnull()) m_clear = m_read_clear();
+ if (!m_read_wait.isunset()) m_wait = m_read_wait();
+ if (!m_read_clear.isunset()) m_clear = m_read_clear();
m_pmode = m_mode;
- m_mode = (cosmac_mode) ((m_clear << 1) | m_wait);
+ m_mode = cosmac_mode((m_clear << 1) | m_wait);
+}
+
+
+//-------------------------------------------------
+// sample_interrupt - sample interrupt line
+//-------------------------------------------------
+
+bool cosmac_device::sample_interrupt()
+{
+ if (!m_read_int.isunset()) m_irq = m_read_int();
+ return bool(m_irq);
+}
+
+
+//-------------------------------------------------
+// sample_dma_io - sample dma in/out lines
+//-------------------------------------------------
+
+inline void cosmac_device::sample_dma_io()
+{
+ if (!m_read_dma_in.isunset()) m_dmain = m_read_dma_in();
+ if (!m_read_dma_out.isunset()) m_dmaout = m_read_dma_out();
}
@@ -934,7 +961,7 @@ inline void cosmac_device::sample_wait_clear()
inline void cosmac_device::sample_ef_lines()
{
for (int i = 0; i < 4; i++)
- EF[i] = m_read_ef[i].isnull() ? m_ef_line[i] : m_read_ef[i]();
+ EF[i] = m_read_ef[i].isunset() ? m_ef_line[i] : m_read_ef[i]();
}
@@ -1059,7 +1086,7 @@ inline void cosmac_device::fetch_instruction()
// reset_state - handle reset state
//-------------------------------------------------
-inline void cosmac_device::reset_state()
+void cosmac_device::reset_state()
{
m_state = cosmac_state::STATE_1_INIT;
@@ -1073,6 +1100,16 @@ inline void cosmac_device::reset_state()
output_state_code();
}
+void cdp1804_device::reset_state()
+{
+ m_xie = 1;
+ m_cie = 1;
+ m_cil = 0;
+ stop_count();
+
+ cosmac_device::reset_state();
+}
+
//-------------------------------------------------
// initialize - handle initialization state
@@ -1080,6 +1117,7 @@ inline void cosmac_device::reset_state()
inline void cosmac_device::initialize()
{
+ T = (X << 4) | P;
X = 0;
P = 0;
R[0] = 0;
@@ -1089,6 +1127,8 @@ inline void cosmac_device::initialize()
m_icount -= CLOCKS_INIT;
+ sample_dma_io();
+
if (m_dmain)
{
m_state = cosmac_state::STATE_2_DMA_IN;
@@ -1117,6 +1157,8 @@ inline void cosmac_device::execute_instruction()
m_icount -= CLOCKS_EXECUTE;
+ sample_dma_io();
+
if (m_state == cosmac_state::STATE_1_EXECUTE && (m_op >> 4) == 0xc) // "long" opcodes
{
m_state = cosmac_state::STATE_1_EXECUTE_2ND;
@@ -1129,7 +1171,7 @@ inline void cosmac_device::execute_instruction()
{
m_state = cosmac_state::STATE_2_DMA_OUT;
}
- else if (IE && m_irq)
+ else if (check_irq())
{
m_state = cosmac_state::STATE_3_INT;
}
@@ -1153,6 +1195,8 @@ inline void cosmac_device::dma_input()
m_icount -= CLOCKS_DMA;
+ sample_dma_io();
+
if (m_dmain)
{
m_state = cosmac_state::STATE_2_DMA_IN;
@@ -1161,7 +1205,7 @@ inline void cosmac_device::dma_input()
{
m_state = cosmac_state::STATE_2_DMA_OUT;
}
- else if (IE && m_irq)
+ else if (check_irq())
{
m_state = cosmac_state::STATE_3_INT;
}
@@ -1173,8 +1217,6 @@ inline void cosmac_device::dma_input()
{
m_state = cosmac_state::STATE_0_FETCH;
}
-
- standard_irq_callback(COSMAC_INPUT_LINE_DMAIN);
}
@@ -1191,6 +1233,8 @@ inline void cosmac_device::dma_output()
m_icount -= CLOCKS_DMA;
+ sample_dma_io();
+
if (m_dmain)
{
m_state = cosmac_state::STATE_2_DMA_IN;
@@ -1199,7 +1243,7 @@ inline void cosmac_device::dma_output()
{
m_state = cosmac_state::STATE_2_DMA_OUT;
}
- else if (IE && m_irq)
+ else if (check_irq())
{
m_state = cosmac_state::STATE_3_INT;
}
@@ -1207,8 +1251,6 @@ inline void cosmac_device::dma_output()
{
m_state = cosmac_state::STATE_0_FETCH;
}
-
- standard_irq_callback(COSMAC_INPUT_LINE_DMAOUT);
}
@@ -1218,6 +1260,8 @@ inline void cosmac_device::dma_output()
inline void cosmac_device::interrupt()
{
+ standard_irq_callback(COSMAC_INPUT_LINE_INT, R[P]);
+
T = (X << 4) | P;
X = 2;
P = 1;
@@ -1228,6 +1272,8 @@ inline void cosmac_device::interrupt()
m_icount -= CLOCKS_INTERRUPT;
+ sample_dma_io();
+
if (m_dmain)
{
m_state = cosmac_state::STATE_2_DMA_IN;
@@ -1240,8 +1286,6 @@ inline void cosmac_device::interrupt()
{
m_state = cosmac_state::STATE_0_FETCH;
}
-
- standard_irq_callback(COSMAC_INPUT_LINE_INT);
}
@@ -1403,7 +1447,7 @@ void cosmac_device::lsie() { long_skip(IE); }
// control instructions opcode handlers
void cosmac_device::idl() { /* idle */ }
void cosmac_device::nop() { }
-void cosmac_device::und() { /* undefined opcode in CDP1801 */ }
+void cosmac_device::und() { /* undefined opcode */ }
void cosmac_device::sep() { P = N; }
void cosmac_device::sex() { X = N; }
void cosmac_device::seq() { set_q_flag(1); }
@@ -1460,11 +1504,68 @@ void cosmac_device::rsxd() { RAM_W(R[X], R[N] & 0xff); R[X]--; RAM_W(R[X], R[N]
void cosmac_device::rnx() { R[X] = R[N]; }
-void cosmac_device::bci() { short_branch(1); } // wrong! tests CI flag
-void cosmac_device::bxi() { short_branch(0); } // wrong! tests XI flag
+void cosmac_device::bci() { short_branch(m_cil); m_cil = 0; }
+void cosmac_device::bxi() { short_branch(sample_interrupt()); }
+
+void cosmac_device::xie() { m_xie = 1; }
+void cosmac_device::xid() { m_xie = 0; }
+void cosmac_device::cie() { m_cie = 1; }
+void cosmac_device::cid() { m_cie = 0; }
+
+void cosmac_device::scm1() { stop_count(); m_cnt_mode = 2; }
+void cosmac_device::scm2() { stop_count(); m_cnt_mode = 3; }
+void cosmac_device::spm1() { stop_count(); m_cnt_mode = 4; }
+void cosmac_device::spm2() { stop_count(); m_cnt_mode = 5; }
+
+void cosmac_device::gec() { D = get_count(); }
+void cosmac_device::stpc() { stop_count(); }
+
+void cosmac_device::stm()
+{
+ if (m_cnt_mode != 1)
+ {
+ // start clocking counter in timer mode
+ m_cnt_mode = 1;
+ int count = (m_cnt_count == 0) ? 0x100 : m_cnt_count;
+ m_cnt_timer->adjust(attotime::from_ticks(0x100 * count, clock()));
+ }
+}
+
+void cosmac_device::ldc()
+{
+ m_cnt_load = D;
+ if (m_cnt_mode == 0)
+ {
+ m_cnt_count = m_cnt_load;
+ m_cil = 0;
+ }
+}
-void cosmac_device::ldc() { /* logerror("LDC counter set: %X\n", D); */ }
-void cosmac_device::gec() { D = machine().rand() & 0xf; } // wrong!
+uint8_t cosmac_device::get_count()
+{
+ if (m_cnt_mode == 1)
+ {
+ // get current count of active timer (rounded up)
+ uint64_t ticks = m_cnt_timer->remaining().as_ticks(clock());
+ return (ticks >> 8) + ((ticks & 0xff) ? 1 : 0);
+ }
+ else
+ return m_cnt_count;
+}
+
+void cosmac_device::stop_count()
+{
+ m_cnt_count = get_count();
+ m_cnt_mode = 0;
+ m_cnt_timer->adjust(attotime::never);
+}
+
+TIMER_CALLBACK_MEMBER(cosmac_device::cnt_timerout)
+{
+ m_cil = 1;
+ int count = (m_cnt_load == 0) ? 0x100 : m_cnt_load;
+ m_cnt_timer->adjust(attotime::from_ticks(0x100 * count, clock()));
+}
// CDP1805/06 additional extended opcodes
// TODO
diff --git a/src/devices/cpu/cosmac/cosmac.h b/src/devices/cpu/cosmac/cosmac.h
index 3607ce37d59..01b35785911 100644
--- a/src/devices/cpu/cosmac/cosmac.h
+++ b/src/devices/cpu/cosmac/cosmac.h
@@ -158,6 +158,9 @@ public:
auto wait_cb() { return m_read_wait.bind(); }
auto clear_cb() { return m_read_clear.bind(); }
+ auto int_cb() { return m_read_int.bind(); }
+ auto dma_in_cb() { return m_read_dma_in.bind(); }
+ auto dma_out_cb() { return m_read_dma_out.bind(); }
auto ef1_cb() { return m_read_ef[0].bind(); }
auto ef2_cb() { return m_read_ef[1].bind(); }
auto ef3_cb() { return m_read_ef[2].bind(); }
@@ -171,28 +174,27 @@ public:
// public interfaces
offs_t get_memory_address();
- DECLARE_WRITE_LINE_MEMBER( wait_w ) { set_input_line(COSMAC_INPUT_LINE_WAIT, state); }
- DECLARE_WRITE_LINE_MEMBER( clear_w ) { set_input_line(COSMAC_INPUT_LINE_CLEAR, state); }
- DECLARE_WRITE_LINE_MEMBER( int_w ) { set_input_line(COSMAC_INPUT_LINE_INT, state); }
- DECLARE_WRITE_LINE_MEMBER( dma_in_w ) { set_input_line(COSMAC_INPUT_LINE_DMAIN, state); }
- DECLARE_WRITE_LINE_MEMBER( dma_out_w ) { set_input_line(COSMAC_INPUT_LINE_DMAOUT, state); }
- DECLARE_WRITE_LINE_MEMBER( ef1_w ) { set_input_line(COSMAC_INPUT_LINE_EF1, state); }
- DECLARE_WRITE_LINE_MEMBER( ef2_w ) { set_input_line(COSMAC_INPUT_LINE_EF2, state); }
- DECLARE_WRITE_LINE_MEMBER( ef3_w ) { set_input_line(COSMAC_INPUT_LINE_EF3, state); }
- DECLARE_WRITE_LINE_MEMBER( ef4_w ) { set_input_line(COSMAC_INPUT_LINE_EF4, state); }
+ void wait_w(int state) { set_input_line(COSMAC_INPUT_LINE_WAIT, state); }
+ void clear_w(int state) { set_input_line(COSMAC_INPUT_LINE_CLEAR, state); }
+ void int_w(int state) { set_input_line(COSMAC_INPUT_LINE_INT, state); }
+ void dma_in_w(int state) { set_input_line(COSMAC_INPUT_LINE_DMAIN, state); }
+ void dma_out_w(int state) { set_input_line(COSMAC_INPUT_LINE_DMAOUT, state); }
+ void ef1_w(int state) { set_input_line(COSMAC_INPUT_LINE_EF1, state); }
+ void ef2_w(int state) { set_input_line(COSMAC_INPUT_LINE_EF2, state); }
+ void ef3_w(int state) { set_input_line(COSMAC_INPUT_LINE_EF3, state); }
+ void ef4_w(int state) { set_input_line(COSMAC_INPUT_LINE_EF4, state); }
protected:
// construction/destruction
cosmac_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
// device_execute_interface overrides
- virtual uint32_t execute_min_cycles() const override;
- virtual uint32_t execute_max_cycles() const override;
- virtual uint32_t execute_input_lines() const override;
+ virtual uint32_t execute_min_cycles() const noexcept override;
+ virtual uint32_t execute_max_cycles() const noexcept override;
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
@@ -218,14 +220,17 @@ protected:
// execution logic
inline void run_state();
inline void debug();
- inline void reset_state();
+ virtual void reset_state();
inline void initialize();
inline void fetch_instruction();
inline void execute_instruction();
inline void dma_input();
inline void dma_output();
inline void interrupt();
+ virtual bool check_irq() { return m_ie && sample_interrupt(); }
inline void sample_wait_clear();
+ bool sample_interrupt();
+ inline void sample_dma_io();
inline void sample_ef_lines();
virtual void output_state_code();
inline void set_q_flag(int state);
@@ -348,13 +353,28 @@ protected:
void ldc();
void gec();
+ void stpc();
+ void stm();
+ void scm1();
+ void scm2();
+ void spm1();
+ void spm2();
+
+ void xie();
+ void xid();
+ void cie();
+ void cid();
+
const address_space_config m_program_config;
const address_space_config m_io_config;
// device callbacks
devcb_read_line m_read_wait;
devcb_read_line m_read_clear;
- devcb_read_line m_read_ef[4];
+ devcb_read_line m_read_int;
+ devcb_read_line m_read_dma_in;
+ devcb_read_line m_read_dma_out;
+ devcb_read_line::array<4> m_read_ef;
devcb_write_line m_write_q;
devcb_read8 m_read_dma;
devcb_write8 m_write_dma;
@@ -384,9 +404,9 @@ protected:
};
// internal state
- uint16_t m_pc; // fake program counter
- uint16_t m_op; // current opcode
- uint8_t m_flagsio; // flags storage for state saving
+ uint16_t m_pc; // fake program counter
+ uint16_t m_op; // current opcode
+ uint8_t m_flagsio; // flags storage for state saving
cosmac_state m_state; // state
cosmac_mode m_mode; // control mode
cosmac_mode m_pmode; // previous control mode
@@ -399,25 +419,37 @@ protected:
int m_ef_line[4]; // external flags
// registers
- uint8_t m_d; // data register (accumulator)
- uint8_t m_b; // auxiliary holding register
- uint16_t m_r[16]; // scratchpad registers
- uint8_t m_p; // designates which register is Program Counter
- uint8_t m_x; // designates which register is Data Pointer
- uint8_t m_n; // low-order instruction digit
- uint8_t m_i; // high-order instruction digit
- uint8_t m_t; // temporary register
+ uint8_t m_d; // data register (accumulator)
+ uint8_t m_b; // auxiliary holding register
+ uint16_t m_r[16]; // scratchpad registers
+ uint8_t m_p; // designates which register is Program Counter
+ uint8_t m_x; // designates which register is Data Pointer
+ uint8_t m_n; // low-order instruction digit
+ uint8_t m_i; // high-order instruction digit
+ uint8_t m_t; // temporary register
// flags
int m_df; // data flag (ALU carry)
- int m_ie; // interrupt enable
+ int m_ie; // master interrupt enable
+ int m_cie; // counter interrupt enable
+ int m_xie; // external interrupt enable
+ int m_cil; // counter interrupt latch
int m_q; // output flip-flop
+ uint8_t m_cnt_mode; // counter mode
+ uint8_t m_cnt_load; // counter reload value
+ uint8_t m_cnt_count; // active counter value
+ emu_timer *m_cnt_timer; // counter mode 1 timer handler
+
+ TIMER_CALLBACK_MEMBER(cnt_timerout);
+ uint8_t get_count();
+ void stop_count();
+
// internal stuff
int m_icount;
- address_space * m_program;
- address_space * m_io;
- memory_access_cache<0, 0, ENDIANNESS_LITTLE> *m_cache;
+ memory_access<16, 0, 0, ENDIANNESS_LITTLE>::cache m_cache;
+ memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_program;
+ memory_access< 3, 0, 0, ENDIANNESS_LITTLE>::specific m_io;
// opcode/condition tables
typedef void (cosmac_device::*ophandler)();
@@ -481,6 +513,8 @@ protected:
virtual cosmac_device::ophandler get_ophandler(uint16_t opcode) const override;
virtual bool has_extended_opcodes() override { return true; }
+ virtual bool check_irq() override { return m_ie && ((sample_interrupt() && m_xie) || (m_cil && m_cie)); }
+ virtual void reset_state() override;
private:
static const ophandler s_opcodetable_ex[256];