diff options
Diffstat (limited to 'src/devices/cpu/cosmac')
-rw-r--r-- | src/devices/cpu/cosmac/cosdasm.cpp | 54 | ||||
-rw-r--r-- | src/devices/cpu/cosmac/cosmac.cpp | 287 | ||||
-rw-r--r-- | src/devices/cpu/cosmac/cosmac.h | 96 |
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]; |