cosmac.cpp: Interface overhaul (nw)

- Split execution of long branch/long skip instructions into two separate states
- Eliminate reset state
- Sample pushed EF lines at the right time
- Implement a few CDP1801 differences
- Correct disassembly of destinations for skip instructions
- SC callback also includes state of N lines for I/O instructions
- TPB callback added (not used yet)
- Callbacks can be configured through devcb3 bindings
This commit is contained in:
AJR 2018-07-19 00:55:47 -04:00
parent ee92a79a9c
commit 13c663f17a
4 changed files with 167 additions and 106 deletions

View File

@ -42,12 +42,12 @@ offs_t cosmac_disassembler::long_branch(offs_t &pc, const data_buffer &params)
offs_t cosmac_disassembler::short_skip(offs_t pc)
{
return pc + 2;
return pc + 1;
}
offs_t cosmac_disassembler::long_skip(offs_t pc)
{
return pc + 3;
return pc + 2;
}
@ -152,7 +152,8 @@ offs_t cosmac_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
// 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 0x60: CDP1802_OPCODE("IRX"); break;
case 0x60: util::stream_format(stream, m_variant < TYPE_1802 ? "OUT 0" : "IRX"); break;
case 0x68: util::stream_format(stream, m_variant < TYPE_1802 ? "INP 0" : "illegal"); break;
case 0x72: CDP1802_OPCODE("LDXA"); break;
case 0x73: CDP1802_OPCODE("STXD"); break;
case 0x74: CDP1802_OPCODE("ADC"); break;

View File

@ -21,24 +21,12 @@ ALLOW_SAVE_TYPE(cosmac_device::cosmac_state);
// CONSTANTS
//**************************************************************************
#define CLOCKS_RESET 8
#define CLOCKS_INIT 8 // really 9, but needs to be 8 to synchronize cdp1861 video timings
#define CLOCKS_FETCH 8
#define CLOCKS_EXECUTE 8
#define CLOCKS_DMA 8
#define CLOCKS_INTERRUPT 8
const cosmac_state_code COSMAC_STATE_CODE[] =
{
COSMAC_STATE_CODE_S0_FETCH, // COSMAC_STATE_0_FETCH
COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_RESET
COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_INIT
COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_EXECUTE
COSMAC_STATE_CODE_S2_DMA, // COSMAC_STATE_2_DMA_IN
COSMAC_STATE_CODE_S2_DMA, // COSMAC_STATE_2_DMA_OUT
COSMAC_STATE_CODE_S3_INTERRUPT // COSMAC_STATE_3_INT
};
//**************************************************************************
@ -110,9 +98,10 @@ const cosmac_device::ophandler cdp1801_device::s_opcodetable[256] =
&cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str,
&cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str,
&cdp1801_device::und, &cdp1801_device::out, &cdp1801_device::out, &cdp1801_device::out,
// OUT 0 and INP 0 are valid on the CDP1801
&cdp1801_device::out, &cdp1801_device::out, &cdp1801_device::out, &cdp1801_device::out,
&cdp1801_device::und, &cdp1801_device::inp, &cdp1801_device::inp, &cdp1801_device::inp,
&cdp1801_device::out, &cdp1801_device::out, &cdp1801_device::out, &cdp1801_device::out,
&cdp1801_device::inp, &cdp1801_device::inp, &cdp1801_device::inp, &cdp1801_device::inp,
&cdp1801_device::inp, &cdp1801_device::inp, &cdp1801_device::inp, &cdp1801_device::inp,
&cdp1801_device::ret, &cdp1801_device::dis, &cdp1801_device::und, &cdp1801_device::und,
@ -275,16 +264,14 @@ cosmac_device::cosmac_device(const machine_config &mconfig, device_type type, co
m_io_config("io", ENDIANNESS_LITTLE, 8, 3),
m_read_wait(*this),
m_read_clear(*this),
m_read_ef1(*this),
m_read_ef2(*this),
m_read_ef3(*this),
m_read_ef4(*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_RESET),
m_state(cosmac_state::STATE_1_INIT),
m_mode(cosmac_mode::RESET),
m_irq(CLEAR_LINE),
m_dmain(CLEAR_LINE),
@ -295,6 +282,8 @@ cosmac_device::cosmac_device(const machine_config &mconfig, device_type type, co
{
for (auto & elem : m_ef)
elem = CLEAR_LINE;
for (auto & elem : m_ef_line)
elem = CLEAR_LINE;
}
@ -327,14 +316,13 @@ void cosmac_device::device_start()
// resolve callbacks
m_read_wait.resolve();
m_read_clear.resolve();
m_read_ef1.resolve();
m_read_ef2.resolve();
m_read_ef3.resolve();
m_read_ef4.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();
// get our address spaces
m_program = &space(AS_PROGRAM);
@ -372,6 +360,7 @@ void cosmac_device::device_start()
save_item(NAME(m_dmain));
save_item(NAME(m_dmaout));
save_item(NAME(m_ef));
save_item(NAME(m_ef_line));
save_item(NAME(m_d));
save_item(NAME(m_b));
save_item(NAME(m_r));
@ -396,7 +385,7 @@ void cosmac_device::device_start()
void cosmac_device::device_reset()
{
m_ie = 0;
m_q = 0;
set_q_flag(0);
m_df = 0;
m_p = 0;
rand_memory(m_r, sizeof(m_r));
@ -623,7 +612,7 @@ void cosmac_device::execute_set_input(int inputnum, int state)
case COSMAC_INPUT_LINE_EF2:
case COSMAC_INPUT_LINE_EF3:
case COSMAC_INPUT_LINE_EF4:
EF[inputnum - COSMAC_INPUT_LINE_EF1] = state;
m_ef_line[inputnum - COSMAC_INPUT_LINE_EF1] = state;
break;
case COSMAC_INPUT_LINE_CLEAR:
@ -667,13 +656,13 @@ void cosmac_device::execute_run()
m_op = 0;
I = 0;
N = 0;
run();
run_state();
}
break;
case cosmac_mode::RESET:
m_state = cosmac_state::STATE_1_RESET;
run();
reset_state();
m_icount--;
break;
case cosmac_mode::PAUSE:
@ -692,17 +681,17 @@ void cosmac_device::execute_run()
case cosmac_mode::RESET:
m_pmode = cosmac_mode::RUN;
m_state = cosmac_state::STATE_1_INIT;
run();
run_state();
break;
case cosmac_mode::PAUSE:
m_pmode = cosmac_mode::RUN;
m_state = cosmac_state::STATE_0_FETCH;
run();
run_state();
break;
case cosmac_mode::RUN:
run();
run_state();
break;
}
break;
@ -713,10 +702,10 @@ void cosmac_device::execute_run()
//-------------------------------------------------
// run - run the CPU state machine
// run_state - run the CPU state machine
//-------------------------------------------------
inline void cosmac_device::run()
inline void cosmac_device::run_state()
{
output_state_code();
@ -726,11 +715,6 @@ inline void cosmac_device::run()
fetch_instruction();
break;
case cosmac_state::STATE_1_RESET:
reset();
debug();
break;
case cosmac_state::STATE_1_INIT:
initialize();
debug();
@ -738,6 +722,8 @@ inline void cosmac_device::run()
case cosmac_state::STATE_1_EXECUTE:
sample_ef_lines();
case cosmac_state::STATE_1_EXECUTE_2ND:
execute_instruction();
debug();
break;
@ -764,7 +750,7 @@ inline void cosmac_device::run()
inline void cosmac_device::debug()
{
if (device_t::machine().debug_flags & DEBUG_FLAG_ENABLED)
if ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) && m_state == cosmac_state::STATE_0_FETCH)
{
debugger_instruction_hook(R[P]);
}
@ -791,10 +777,8 @@ inline void cosmac_device::sample_wait_clear()
inline void cosmac_device::sample_ef_lines()
{
if (!m_read_ef1.isnull()) EF[0] = m_read_ef1();
if (!m_read_ef2.isnull()) EF[1] = m_read_ef2();
if (!m_read_ef3.isnull()) EF[2] = m_read_ef3();
if (!m_read_ef4.isnull()) EF[3] = m_read_ef4();
for (int i = 0; i < 4; i++)
EF[i] = m_read_ef[i].isnull() ? m_ef_line[i] : m_read_ef[i]();
}
@ -804,7 +788,55 @@ inline void cosmac_device::sample_ef_lines()
inline void cosmac_device::output_state_code()
{
m_write_sc(offs_t(0), COSMAC_STATE_CODE[std::underlying_type_t<cosmac_state>(m_state)]);
if (m_state == cosmac_state::STATE_0_FETCH)
{
// S0 fetch
m_write_sc(0, COSMAC_STATE_CODE_S0_FETCH);
}
else if (m_state == cosmac_state::STATE_2_DMA_IN || m_state == cosmac_state::STATE_2_DMA_OUT)
{
// S2 DMA
m_write_sc(0, COSMAC_STATE_CODE_S2_DMA);
}
else if (m_state == cosmac_state::STATE_3_INT)
{
// S3 interrupt
m_write_sc(0, COSMAC_STATE_CODE_S3_INTERRUPT);
}
else
{
// S1 execute
m_write_sc(I == 0x6 ? (N & 7) : 0, COSMAC_STATE_CODE_S1_EXECUTE);
}
}
void cdp1801_device::output_state_code()
{
if (m_state == cosmac_state::STATE_0_FETCH)
{
// S0 fetch
m_write_sc(0, 4);
}
else if (m_state == cosmac_state::STATE_2_DMA_IN || m_state == cosmac_state::STATE_2_DMA_OUT)
{
// S2 DMA
m_write_sc(0, 2);
}
else if (m_state == cosmac_state::STATE_3_INT)
{
// S3 interrupt
m_write_sc(0, 3);
}
else if (I == 0x6)
{
// S1 execute (I/O)
m_write_sc(N, 1);
}
else
{
// S1 execute (non-I/O)
m_write_sc(0, 0);
}
}
@ -849,7 +881,9 @@ inline void cosmac_device::fetch_instruction()
{
// instruction fetch
offs_t addr = R[P]++;
m_write_tpb(1);
m_op = read_opcode(addr);
m_write_tpb(0);
I = m_op >> 4;
N = m_op & 0x0f;
@ -861,18 +895,19 @@ inline void cosmac_device::fetch_instruction()
//-------------------------------------------------
// reset - handle reset state
// reset_state - handle reset state
//-------------------------------------------------
inline void cosmac_device::reset()
inline void cosmac_device::reset_state()
{
m_state = cosmac_state::STATE_1_INIT;
output_state_code();
m_op = 0;
I = 0;
N = 0;
Q = 0;
set_q_flag(0);
IE = 1;
m_icount -= CLOCKS_RESET;
}
@ -886,6 +921,9 @@ inline void cosmac_device::initialize()
P = 0;
R[0] = 0;
m_write_tpb(1);
m_write_tpb(0);
m_icount -= CLOCKS_INIT;
if (m_dmain)
@ -910,11 +948,17 @@ inline void cosmac_device::initialize()
inline void cosmac_device::execute_instruction()
{
// parse the instruction
m_write_tpb(1);
(this->*this->get_ophandler(m_op))();
m_write_tpb(0);
m_icount -= CLOCKS_EXECUTE;
if (m_dmain)
if (I == 0xc && m_state == cosmac_state::STATE_1_EXECUTE)
{
m_state = cosmac_state::STATE_1_EXECUTE_2ND;
}
else if (m_dmain)
{
m_state = cosmac_state::STATE_2_DMA_IN;
}
@ -940,7 +984,9 @@ inline void cosmac_device::execute_instruction()
inline void cosmac_device::dma_input()
{
offs_t addr = R[0]++;
m_write_tpb(1);
RAM_W(addr, m_read_dma(addr));
m_write_tpb(0);
m_icount -= CLOCKS_DMA;
@ -976,7 +1022,9 @@ inline void cosmac_device::dma_input()
inline void cosmac_device::dma_output()
{
offs_t addr = R[0]++;
m_write_tpb(1);
m_write_dma(addr, RAM_R(addr));
m_write_tpb(0);
m_icount -= CLOCKS_DMA;
@ -1012,6 +1060,9 @@ inline void cosmac_device::interrupt()
P = 1;
IE = 0;
m_write_tpb(1);
m_write_tpb(0);
m_icount -= CLOCKS_INTERRUPT;
if (m_dmain)
@ -1141,18 +1192,20 @@ void cosmac_device::long_branch(int taken)
{
if (taken)
{
// S1#1
B = OPCODE_R(R[P]++);
// S1#2
R[P] = (B << 8) | OPCODE_R(R[P]);
if (m_state == cosmac_state::STATE_1_EXECUTE)
{
// S1#1
B = OPCODE_R(R[P]++);
}
else
{
// S1#2
R[P] = (B << 8) | OPCODE_R(R[P]);
}
}
else
{
// S1#1
R[P]++;
// S1#2
// S1#1, S1#2
R[P]++;
}
@ -1173,14 +1226,9 @@ void cosmac_device::long_skip(int taken)
{
if (taken)
{
// S1#1
R[P]++;
// S1#2
// S1#1, S1#2
R[P]++;
}
m_icount -= CLOCKS_EXECUTE;
}
void cosmac_device::lsz() { long_skip(D == 0); }
@ -1193,8 +1241,8 @@ void cosmac_device::lsie() { long_skip(IE); }
// control instructions opcode handlers
void cosmac_device::idl() { /* idle */ }
void cosmac_device::nop() { m_icount -= CLOCKS_EXECUTE; }
void cosmac_device::und() { /* undefined opcode in CDP1801 */ m_icount -= CLOCKS_EXECUTE; }
void cosmac_device::nop() { }
void cosmac_device::und() { /* undefined opcode in CDP1801 */ }
void cosmac_device::sep() { P = N; }
void cosmac_device::sex() { X = N; }
void cosmac_device::seq() { set_q_flag(1); }

View File

@ -192,13 +192,24 @@ public:
COSMAC_SC
};
auto wait_cb() { return m_read_wait.bind(); }
auto clear_cb() { return m_read_clear.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(); }
auto ef4_cb() { return m_read_ef[3].bind(); }
auto q_cb() { return m_write_q.bind(); }
auto dma_rd_cb() { return m_read_dma.bind(); }
auto dma_wr_cb() { return m_write_dma.bind(); }
auto sc_cb() { return m_write_sc.bind(); }
auto tpb_cb() { return m_write_tpb.bind(); }
template <class Object> devcb_base &set_wait_rd_callback(Object &&cb) { return m_read_wait.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_clear_rd_callback(Object &&cb) { return m_read_clear.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ef1_rd_callback(Object &&cb) { return m_read_ef1.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ef2_rd_callback(Object &&cb) { return m_read_ef2.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ef3_rd_callback(Object &&cb) { return m_read_ef3.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ef4_rd_callback(Object &&cb) { return m_read_ef4.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ef1_rd_callback(Object &&cb) { return m_read_ef[0].set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ef2_rd_callback(Object &&cb) { return m_read_ef[1].set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ef3_rd_callback(Object &&cb) { return m_read_ef[2].set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ef4_rd_callback(Object &&cb) { return m_read_ef[3].set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_q_wr_callback(Object &&cb) { return m_write_q.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_dma_rd_callback(Object &&cb) { return m_read_dma.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_dma_wr_callback(Object &&cb) { return m_write_dma.set_callback(std::forward<Object>(cb)); }
@ -248,9 +259,9 @@ protected:
inline void write_io_byte(offs_t address, uint8_t data);
// execution logic
inline void run();
inline void run_state();
inline void debug();
inline void reset();
inline void reset_state();
inline void initialize();
inline void fetch_instruction();
inline void execute_instruction();
@ -259,7 +270,7 @@ protected:
inline void interrupt();
inline void sample_wait_clear();
inline void sample_ef_lines();
inline void output_state_code();
virtual void output_state_code();
inline void set_q_flag(int state);
inline void put_low_reg(int reg, uint8_t data);
inline void put_high_reg(int reg, uint8_t data);
@ -376,14 +387,12 @@ protected:
// device callbacks
devcb_read_line m_read_wait;
devcb_read_line m_read_clear;
devcb_read_line m_read_ef1;
devcb_read_line m_read_ef2;
devcb_read_line m_read_ef3;
devcb_read_line m_read_ef4;
devcb_read_line m_read_ef[4];
devcb_write_line m_write_q;
devcb_read8 m_read_dma;
devcb_write8 m_write_dma;
devcb_write8 m_write_sc;
devcb_write_line m_write_tpb;
// control modes
enum class cosmac_mode : u8
@ -398,9 +407,9 @@ protected:
enum class cosmac_state : u8
{
STATE_0_FETCH = 0,
STATE_1_RESET,
STATE_1_INIT,
STATE_1_EXECUTE,
STATE_1_EXECUTE_2ND,
STATE_2_DMA_IN,
STATE_2_DMA_OUT,
STATE_3_INT
@ -419,6 +428,7 @@ protected:
int m_dmain; // DMA input request
int m_dmaout; // DMA output request
int m_ef[4]; // external flags
int m_ef_line[4]; // external flags
// registers
uint8_t m_d; // data register (accumulator)
@ -461,6 +471,8 @@ protected:
virtual cosmac_device::ophandler get_ophandler(uint8_t opcode) const override;
virtual void output_state_code() override;
static const ophandler s_opcodetable[256];
};

View File

@ -402,12 +402,12 @@ void cidelsa_state::machine_reset()
MACHINE_CONFIG_START(cidelsa_state::destryer)
/* basic system hardware */
MCFG_DEVICE_ADD(CDP1802_TAG, CDP1802, DESTRYER_CHR1)
MCFG_DEVICE_PROGRAM_MAP(destryer_map)
MCFG_DEVICE_IO_MAP(destryer_io_map)
MCFG_COSMAC_WAIT_CALLBACK(CONSTANT(1))
MCFG_COSMAC_CLEAR_CALLBACK(READLINE(*this, cidelsa_state, clear_r))
MCFG_COSMAC_Q_CALLBACK(WRITELINE(*this, cidelsa_state, q_w))
cdp1802_device &cpu(CDP1802(config, CDP1802_TAG, DESTRYER_CHR1));
cpu.set_addrmap(AS_PROGRAM, &cidelsa_state::destryer_map);
cpu.set_addrmap(AS_IO, &cidelsa_state::destryer_io_map);
cpu.wait_cb().set_constant(1);
cpu.clear_cb().set(FUNC(cidelsa_state::clear_r));
cpu.q_cb().set(FUNC(cidelsa_state::q_w));
MCFG_NVRAM_ADD_0FILL("nvram")
@ -417,12 +417,12 @@ MACHINE_CONFIG_END
MACHINE_CONFIG_START(cidelsa_state::destryera)
/* basic system hardware */
MCFG_DEVICE_ADD(CDP1802_TAG, CDP1802, DESTRYER_CHR1)
MCFG_DEVICE_PROGRAM_MAP(destryera_map)
MCFG_DEVICE_IO_MAP(destryer_io_map)
MCFG_COSMAC_WAIT_CALLBACK(CONSTANT(1))
MCFG_COSMAC_CLEAR_CALLBACK(READLINE(*this, cidelsa_state, clear_r))
MCFG_COSMAC_Q_CALLBACK(WRITELINE(*this, cidelsa_state, q_w))
cdp1802_device &cpu(CDP1802(config, CDP1802_TAG, DESTRYER_CHR1));
cpu.set_addrmap(AS_PROGRAM, &cidelsa_state::destryera_map);
cpu.set_addrmap(AS_IO, &cidelsa_state::destryer_io_map);
cpu.wait_cb().set_constant(1);
cpu.clear_cb().set(FUNC(cidelsa_state::clear_r));
cpu.q_cb().set(FUNC(cidelsa_state::q_w));
MCFG_NVRAM_ADD_0FILL("nvram")
@ -432,12 +432,12 @@ MACHINE_CONFIG_END
MACHINE_CONFIG_START(cidelsa_state::altair)
/* basic system hardware */
MCFG_DEVICE_ADD(CDP1802_TAG, CDP1802, ALTAIR_CHR1)
MCFG_DEVICE_PROGRAM_MAP(altair_map)
MCFG_DEVICE_IO_MAP(altair_io_map)
MCFG_COSMAC_WAIT_CALLBACK(CONSTANT(1))
MCFG_COSMAC_CLEAR_CALLBACK(READLINE(*this, cidelsa_state, clear_r))
MCFG_COSMAC_Q_CALLBACK(WRITELINE(*this, cidelsa_state, q_w))
cdp1802_device &cpu(CDP1802(config, CDP1802_TAG, ALTAIR_CHR1));
cpu.set_addrmap(AS_PROGRAM, &cidelsa_state::altair_map);
cpu.set_addrmap(AS_IO, &cidelsa_state::altair_io_map);
cpu.wait_cb().set_constant(1);
cpu.clear_cb().set(FUNC(cidelsa_state::clear_r));
cpu.q_cb().set(FUNC(cidelsa_state::q_w));
MCFG_NVRAM_ADD_0FILL("nvram")
@ -461,12 +461,12 @@ MACHINE_CONFIG_END
MACHINE_CONFIG_START(draco_state::draco)
/* basic system hardware */
MCFG_DEVICE_ADD(CDP1802_TAG, CDP1802, DRACO_CHR1)
MCFG_DEVICE_PROGRAM_MAP(draco_map)
MCFG_DEVICE_IO_MAP(draco_io_map)
MCFG_COSMAC_WAIT_CALLBACK(CONSTANT(1))
MCFG_COSMAC_CLEAR_CALLBACK(READLINE(*this, cidelsa_state, clear_r))
MCFG_COSMAC_Q_CALLBACK(WRITELINE(*this, cidelsa_state, q_w))
cdp1802_device &cpu(CDP1802(config, CDP1802_TAG, ALTAIR_CHR1));
cpu.set_addrmap(AS_PROGRAM, &draco_state::draco_map);
cpu.set_addrmap(AS_IO, &draco_state::draco_io_map);
cpu.wait_cb().set_constant(1);
cpu.clear_cb().set(FUNC(draco_state::clear_r));
cpu.q_cb().set(FUNC(draco_state::q_w));
MCFG_NVRAM_ADD_0FILL("nvram")