summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/cosmac/cosmac.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/cosmac/cosmac.cpp')
-rw-r--r--src/devices/cpu/cosmac/cosmac.cpp230
1 files changed, 153 insertions, 77 deletions
diff --git a/src/devices/cpu/cosmac/cosmac.cpp b/src/devices/cpu/cosmac/cosmac.cpp
index cc773ebd8a3..6b9c866c92e 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,27 @@ 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),
- 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_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,20 +450,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();
- m_read_ef.resolve_all();
- 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();
@@ -513,7 +525,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);
@@ -526,13 +544,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
}
@@ -644,7 +656,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);
}
@@ -654,7 +666,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);
}
@@ -665,7 +677,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);
}
@@ -675,7 +687,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);
}
@@ -686,7 +698,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);
}
@@ -863,7 +875,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;
@@ -875,7 +887,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();
@@ -918,11 +930,11 @@ 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);
}
@@ -933,7 +945,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]();
}
@@ -1058,7 +1070,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;
@@ -1072,6 +1084,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
@@ -1079,6 +1101,7 @@ inline void cosmac_device::reset_state()
inline void cosmac_device::initialize()
{
+ T = (X << 4) | P;
X = 0;
P = 0;
R[0] = 0;
@@ -1128,7 +1151,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;
}
@@ -1160,7 +1183,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;
}
@@ -1172,8 +1195,6 @@ inline void cosmac_device::dma_input()
{
m_state = cosmac_state::STATE_0_FETCH;
}
-
- standard_irq_callback(COSMAC_INPUT_LINE_DMAIN);
}
@@ -1198,7 +1219,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;
}
@@ -1206,8 +1227,6 @@ inline void cosmac_device::dma_output()
{
m_state = cosmac_state::STATE_0_FETCH;
}
-
- standard_irq_callback(COSMAC_INPUT_LINE_DMAOUT);
}
@@ -1217,6 +1236,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;
@@ -1239,8 +1260,6 @@ inline void cosmac_device::interrupt()
{
m_state = cosmac_state::STATE_0_FETCH;
}
-
- standard_irq_callback(COSMAC_INPUT_LINE_INT);
}
@@ -1402,7 +1421,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); }
@@ -1459,11 +1478,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(m_irq); }
+
+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::ldc() { /* logerror("LDC counter set: %X\n", D); */ }
-void cosmac_device::gec() { D = machine().rand() & 0xf; } // wrong!
+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;
+ }
+}
+
+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