COP400 overhaul

- Rewrite the execution control logic to fetch each byte of an instruction separately in one pass of the main loop. This provides EEPROM-compatible timing for the SIO shift register, allowing the 93C46 on quizpun2 to be read and written properly (though its default contents are a bad dump).
- Add M pseudo-register (internal RAM referenced by B) to debugger state.
- Add T register to debugger state on devices where it only affects SKT.
- The SIO state is now displayed in binary when it is defined as a shift register.
- Skipped instructions and the SKIP flag can be debugged by compile-time switch (disabled by default).
This commit is contained in:
AJR 2017-09-11 08:38:25 -04:00
parent 154d80715e
commit 64c117bb50
4 changed files with 333 additions and 244 deletions

View File

@ -50,7 +50,6 @@
- COP410L/COP410C - COP410L/COP410C
- save internal RAM when CKO is RAM power supply pin - save internal RAM when CKO is RAM power supply pin
- COP404L opcode map switching, dual timer, microbus enable - COP404L opcode map switching, dual timer, microbus enable
- improve SIO output timing for interface with 93CXX serial EEPROMs
*/ */
@ -85,6 +84,9 @@ DEFINE_DEVICE_TYPE(COP446C, cop446c_cpu_device, "cop446c", "COP446C")
#define LOG_MICROBUS 0 #define LOG_MICROBUS 0
// step through skipped instructions in debugger
#define COP_DEBUG_SKIP 0
/*************************************************************************** /***************************************************************************
MACROS MACROS
@ -181,9 +183,8 @@ cop400_cpu_device::cop400_cpu_device(const machine_config &mconfig, device_type
, m_d_mask(d_mask) , m_d_mask(d_mask)
, m_in_mask(in_mask) , m_in_mask(in_mask)
{ {
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++)
m_InstLen[i] = 1; m_InstLen[i] = 1;
}
m_InstLen[0x33] = m_InstLen[0x23] = 2; m_InstLen[0x33] = m_InstLen[0x23] = 2;
@ -192,7 +193,8 @@ cop400_cpu_device::cop400_cpu_device(const machine_config &mconfig, device_type
case COP410_FEATURE: case COP410_FEATURE:
m_opcode_map = COP410_OPCODE_MAP; m_opcode_map = COP410_OPCODE_MAP;
for (int r = 0; r < 2; r++) { for (int r = 0; r < 2; r++)
{
m_InstLen[0x60 + r] = 2; // JMP m_InstLen[0x60 + r] = 2; // JMP
m_InstLen[0x68 + r] = 2; // JSR m_InstLen[0x68 + r] = 2; // JSR
} }
@ -201,7 +203,8 @@ cop400_cpu_device::cop400_cpu_device(const machine_config &mconfig, device_type
case COP420_FEATURE: case COP420_FEATURE:
m_opcode_map = COP420_OPCODE_MAP; m_opcode_map = COP420_OPCODE_MAP;
for (int r = 0; r < 4; r++) { for (int r = 0; r < 4; r++)
{
m_InstLen[0x60 + r] = 2; // JMP m_InstLen[0x60 + r] = 2; // JMP
m_InstLen[0x68 + r] = 2; // JSR m_InstLen[0x68 + r] = 2; // JSR
} }
@ -210,7 +213,8 @@ cop400_cpu_device::cop400_cpu_device(const machine_config &mconfig, device_type
case COP444L_FEATURE: case COP444L_FEATURE:
m_opcode_map = COP444L_OPCODE_MAP; m_opcode_map = COP444L_OPCODE_MAP;
for (int r = 0; r < 8; r++) { for (int r = 0; r < 8; r++)
{
m_InstLen[0x60 + r] = 2; // JMP m_InstLen[0x60 + r] = 2; // JMP
m_InstLen[0x68 + r] = 2; // JSR m_InstLen[0x68 + r] = 2; // JSR
} }
@ -219,7 +223,8 @@ cop400_cpu_device::cop400_cpu_device(const machine_config &mconfig, device_type
case COP424C_FEATURE: case COP424C_FEATURE:
m_opcode_map = COP424C_OPCODE_MAP; m_opcode_map = COP424C_OPCODE_MAP;
for (int r = 0; r < 8; r++) { for (int r = 0; r < 8; r++)
{
m_InstLen[0x60 + r] = 2; // JMP m_InstLen[0x60 + r] = 2; // JMP
m_InstLen[0x68 + r] = 2; // JSR m_InstLen[0x68 + r] = 2; // JSR
} }
@ -369,16 +374,39 @@ void cop400_cpu_device::WRITE_G(uint8_t data)
OUT_G(G); OUT_G(G);
} }
void cop400_cpu_device::WRITE_EN(uint8_t data)
{
if (EN != data)
{
EN = data;
if (BIT(EN, 2))
{
OUT_L(Q);
}
else
{
// tri-state(floating) pins
OUT_L(m_read_l_tristate(0, 0xff));
}
sk_update();
}
}
/*************************************************************************** /***************************************************************************
OPCODE HANDLERS OPCODE HANDLERS
***************************************************************************/ ***************************************************************************/
#define INSTRUCTION(mnemonic) void (cop400_cpu_device::mnemonic)(uint8_t opcode) #define INSTRUCTION(mnemonic) void (cop400_cpu_device::mnemonic)(uint8_t operand)
#define OP(mnemonic) &cop400_cpu_device::mnemonic #define OP(mnemonic) &cop400_cpu_device::mnemonic
INSTRUCTION(illegal) INSTRUCTION(illegal)
{ {
logerror("COP400: PC = %03x, Illegal opcode = %02x\n", PC-1, ROM(PC-1)); if (m_second_byte)
logerror("COP400: PC = %03x, Illegal opcode = %02x %02x\n", m_prevpc, m_opcode, operand);
else
logerror("COP400: PC = %03x, Illegal opcode = %02x\n", m_prevpc, m_opcode);
} }
#include "cop400op.hxx" #include "cop400op.hxx"
@ -426,9 +454,9 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP410_OPCODE_23_
OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal)
}; };
void cop400_cpu_device::cop410_op23(uint8_t opcode) void cop400_cpu_device::cop410_op23(uint8_t operand)
{ {
uint8_t opcode23 = fetch(); uint8_t opcode23 = operand;
(this->*COP410_OPCODE_23_MAP[opcode23])(opcode23); (this->*COP410_OPCODE_23_MAP[opcode23])(opcode23);
} }
@ -472,9 +500,9 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP410_OPCODE_33_
OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal)
}; };
void cop400_cpu_device::cop410_op33(uint8_t opcode) void cop400_cpu_device::cop410_op33(uint8_t operand)
{ {
uint8_t opcode33 = fetch(); uint8_t opcode33 = operand;
(this->*COP410_OPCODE_33_MAP[opcode33])(opcode33); (this->*COP410_OPCODE_33_MAP[opcode33])(opcode33);
} }
@ -557,9 +585,9 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP420_OPCODE_23_
OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal)
}; };
void cop400_cpu_device::cop420_op23(uint8_t opcode) void cop400_cpu_device::cop420_op23(uint8_t operand)
{ {
uint8_t opcode23 = fetch(); uint8_t opcode23 = operand;
(this->*COP420_OPCODE_23_MAP[opcode23])(opcode23); (this->*COP420_OPCODE_23_MAP[opcode23])(opcode23);
} }
@ -603,9 +631,9 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP420_OPCODE_33_
OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal) , OP(illegal)
}; };
void cop400_cpu_device::cop420_op33(uint8_t opcode) void cop400_cpu_device::cop420_op33(uint8_t operand)
{ {
uint8_t opcode33 = fetch(); uint8_t opcode33 = operand;
(this->*COP420_OPCODE_33_MAP[opcode33])(opcode33); (this->*COP420_OPCODE_33_MAP[opcode33])(opcode33);
} }
@ -688,9 +716,9 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP444L_OPCODE_23
OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad)
}; };
void cop400_cpu_device::cop444l_op23(uint8_t opcode) void cop400_cpu_device::cop444l_op23(uint8_t operand)
{ {
uint8_t opcode23 = fetch(); uint8_t opcode23 = operand;
(this->*COP444L_OPCODE_23_MAP[opcode23])(opcode23); (this->*COP444L_OPCODE_23_MAP[opcode23])(opcode23);
} }
@ -734,9 +762,9 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP444L_OPCODE_33
OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi)
}; };
void cop400_cpu_device::cop444l_op33(uint8_t opcode) void cop400_cpu_device::cop444l_op33(uint8_t operand)
{ {
uint8_t opcode33 = fetch(); uint8_t opcode33 = operand;
(this->*COP444L_OPCODE_33_MAP[opcode33])(opcode33); (this->*COP444L_OPCODE_33_MAP[opcode33])(opcode33);
} }
@ -819,9 +847,9 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP424C_OPCODE_23
OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad) , OP(xad)
}; };
void cop400_cpu_device::cop424c_op23(uint8_t opcode) void cop400_cpu_device::cop424c_op23(uint8_t operand)
{ {
uint8_t opcode23 = fetch(); uint8_t opcode23 = operand;
(this->*COP424C_OPCODE_23_MAP[opcode23])(opcode23); (this->*COP424C_OPCODE_23_MAP[opcode23])(opcode23);
} }
@ -865,9 +893,9 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP424C_OPCODE_33
OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi) , OP(lbi)
}; };
void cop400_cpu_device::cop424c_op33(uint8_t opcode) void cop400_cpu_device::cop424c_op33(uint8_t operand)
{ {
uint8_t opcode33 = fetch(); uint8_t opcode33 = operand;
(this->*COP424C_OPCODE_33_MAP[opcode33])(opcode33); (this->*COP424C_OPCODE_33_MAP[opcode33])(opcode33);
} }
@ -911,6 +939,24 @@ const cop400_cpu_device::cop400_opcode_func cop400_cpu_device::COP424C_OPCODE_MA
OP(jp) , OP(jp) , OP(jp) , OP(jp) , OP(jp) , OP(jp) , OP(jp) , OP(jid) OP(jp) , OP(jp) , OP(jp) , OP(jp) , OP(jp) , OP(jp) , OP(jp) , OP(jid)
}; };
inline bool cop400_cpu_device::is_control_transfer(uint8_t opcode)
{
// JP, JSRP, JID or LQID
// (TODO: verify that LQID inhibits interrupts since it transfers control temporarily)
if ((opcode & 0x80) == 0x80)
return true;
// JMP or JSR
if ((opcode & 0xf0) == 0x60)
return true;
// RET or RETSK
if ((opcode & 0xfe) == 0x48)
return true;
return false;
}
/*************************************************************************** /***************************************************************************
TIMER CALLBACKS TIMER CALLBACKS
***************************************************************************/ ***************************************************************************/
@ -931,10 +977,6 @@ void cop400_cpu_device::serial_tick()
OUT_SO(BIT(EN, 3)); OUT_SO(BIT(EN, 3));
// serial clock
OUT_SK(SKL);
// serial input // serial input
m_si <<= 1; m_si <<= 1;
@ -971,17 +1013,6 @@ void cop400_cpu_device::serial_tick()
OUT_SO(0); OUT_SO(0);
} }
// serial clock
if (SKL)
{
OUT_SK(1); // SYNC
}
else
{
OUT_SK(0);
}
// serial input // serial input
SIO = ((SIO << 1) | IN_SI()) & 0x0f; SIO = ((SIO << 1) | IN_SI()) & 0x0f;
@ -992,7 +1023,8 @@ void cop400_cpu_device::counter_tick()
{ {
T++; T++;
if (!T) { if (!T)
{
m_skt_latch = 1; m_skt_latch = 1;
m_idle = false; m_idle = false;
} }
@ -1000,12 +1032,9 @@ void cop400_cpu_device::counter_tick()
void cop400_cpu_device::inil_tick() void cop400_cpu_device::inil_tick()
{ {
uint8_t in; uint8_t in = IN_IN();
int i;
in = IN_IN(); for (int i = 0; i < 4; i++)
for (i = 0; i < 4; i++)
{ {
m_in[i] = (m_in[i] << 1) | BIT(in, i); m_in[i] = (m_in[i] << 1) | BIT(in, i);
@ -1024,17 +1053,9 @@ void cop400_cpu_device::device_timer(emu_timer &timer, device_timer_id id, int p
{ {
switch (id) switch (id)
{ {
case TIMER_SERIAL:
serial_tick();
break;
case TIMER_COUNTER: case TIMER_COUNTER:
counter_tick(); counter_tick();
break; break;
case TIMER_INIL:
inil_tick();
break;
} }
} }
@ -1059,10 +1080,6 @@ void cop400_cpu_device::device_start()
m_write_sk.resolve_safe(); m_write_sk.resolve_safe();
m_read_cko.resolve_safe(0); m_read_cko.resolve_safe(0);
/* allocate serial timer */
m_serial_timer = timer_alloc(TIMER_SERIAL);
m_serial_timer->adjust(attotime::zero, 0, attotime::from_ticks(m_cki, clock()));
/* allocate counter timer */ /* allocate counter timer */
m_counter_timer = nullptr; m_counter_timer = nullptr;
if (m_has_counter) if (m_has_counter)
@ -1071,14 +1088,6 @@ void cop400_cpu_device::device_start()
m_counter_timer->adjust(attotime::zero, 0, attotime::from_ticks(m_cki * 4, clock())); m_counter_timer->adjust(attotime::zero, 0, attotime::from_ticks(m_cki * 4, clock()));
} }
/* allocate IN latch timer */
m_inil_timer = nullptr;
if (m_has_inil)
{
m_inil_timer = timer_alloc(TIMER_INIL);
m_inil_timer->adjust(attotime::zero, 0, attotime::from_ticks(m_cki, clock()));
}
/* register for state saving */ /* register for state saving */
save_item(NAME(m_pc)); save_item(NAME(m_pc));
save_item(NAME(m_prevpc)); save_item(NAME(m_prevpc));
@ -1102,6 +1111,8 @@ void cop400_cpu_device::device_start()
save_item(NAME(m_in)); save_item(NAME(m_in));
save_item(NAME(m_halt)); save_item(NAME(m_halt));
save_item(NAME(m_idle)); save_item(NAME(m_idle));
save_item(NAME(m_opcode));
save_item(NAME(m_second_byte));
// setup debugger state display // setup debugger state display
offs_t pc_mask = m_program->addrmask(); offs_t pc_mask = m_program->addrmask();
@ -1112,18 +1123,20 @@ void cop400_cpu_device::device_start()
state_add(COP400_PC, "PC", m_pc).mask(pc_mask); state_add(COP400_PC, "PC", m_pc).mask(pc_mask);
state_add(COP400_SA, "SA", m_sa).mask(pc_mask); state_add(COP400_SA, "SA", m_sa).mask(pc_mask);
state_add(COP400_SB, "SB", m_sb).mask(pc_mask); state_add(COP400_SB, "SB", m_sb).mask(pc_mask);
if (!(m_featuremask & COP410_FEATURE)) { if (!(m_featuremask & COP410_FEATURE))
state_add(COP400_SC, "SC", m_sc).mask(pc_mask); state_add(COP400_SC, "SC", m_sc).mask(pc_mask);
}
state_add(COP400_B, "B", m_b); state_add(COP400_B, "B", m_b);
state_add(COP400_A, "A", m_a).mask(0xf); state_add(COP400_A, "A", m_a).mask(0xf);
state_add(COP400_M, "M", m_temp_m).mask(0xf).callimport().callexport();
state_add(COP400_G, "G", m_g).mask(0xf); state_add(COP400_G, "G", m_g).mask(0xf);
state_add(COP400_Q, "Q", m_q); state_add(COP400_Q, "Q", m_q);
state_add(COP400_SIO, "SIO", m_sio).mask(0xf); state_add(COP400_SIO, "SIO", m_sio).mask(0xf).formatstr("%4s");
state_add(COP400_EN, "EN", m_en).mask(0xf); state_add(COP400_EN, "EN", m_en).mask(0xf);
if (m_featuremask & COP424C_FEATURE) { if (m_has_counter)
state_add(COP400_T, "T", m_t); state_add(COP400_T, "T", m_t);
} #if COP_DEBUG_SKIP
state_add(COP400_SKIP, "SKIP", m_skip).mask(1);
#endif
m_icountptr = &m_icount; m_icountptr = &m_icount;
@ -1133,12 +1146,14 @@ void cop400_cpu_device::device_start()
m_sc = 0; m_sc = 0;
m_sio = 0; m_sio = 0;
m_flags = 0; m_flags = 0;
m_temp_m = 0;
m_il = 0; m_il = 0;
m_in[0] = m_in[1] = m_in[2] = m_in[3] = 0; m_in[0] = m_in[1] = m_in[2] = m_in[3] = 0;
m_si = 0; m_si = 0;
m_skip_lbi = 0; m_skip_lbi = 0;
m_last_skip = false; m_last_skip = false;
m_skip = false; m_skip = false;
m_opcode = 0x44;
} }
@ -1154,55 +1169,80 @@ void cop400_cpu_device::device_reset()
C = 0; C = 0;
OUT_D(0); OUT_D(0);
EN = 0; EN = 0;
OUT_L(m_read_l_tristate(0, 0xff));
WRITE_G(0); WRITE_G(0);
SKL = 1; SKL = 1;
OUT_SK(0);
T = 0; T = 0;
m_skt_latch = 1; m_skt_latch = 1;
m_halt = false; m_halt = false;
m_idle = false; m_idle = false;
m_second_byte = false;
} }
/*************************************************************************** /***************************************************************************
EXECUTION EXECUTION
***************************************************************************/ ***************************************************************************/
uint8_t cop400_cpu_device::fetch() void cop400_cpu_device::skip()
{ {
m_icount--; // skip the next instruction (TODO: this flag can become an output)
m_skip = true;
}
return ROM(PC++); void cop400_cpu_device::sk_update()
{
// update SK output after XAS or LEI
if (BIT(EN, 0))
{
// SK = SKL when EN0 = 1 (binary counter mode)
OUT_SK(SKL);
}
else
{
// SK = clock or 0 when EN0 = 0 (shift register mode)
OUT_SK(0);
}
} }
void cop400_cpu_device::execute_run() void cop400_cpu_device::execute_run()
{ {
do do
{ {
if (!m_skip) { if (!m_second_byte && (!m_skip || COP_DEBUG_SKIP))
{
// debugger hook // debugger hook
m_prevpc = PC; m_prevpc = PC;
debugger_instruction_hook(this, PC); debugger_instruction_hook(this, PC);
} }
// halt logic // halt logic
if (m_cko == COP400_CKO_HALT_IO_PORT) { if (m_cko == COP400_CKO_HALT_IO_PORT)
m_halt = IN_CKO(); m_halt = IN_CKO();
}
if (m_halt || m_idle) { if (!m_halt && !m_idle)
m_icount--; {
continue; if (!BIT(EN, 0) && SKL)
} {
// Sync pulse actually has a 50% duty cycle, coinciding with address latch for external program
// This implementation, however, is good enough to interface with 93CXX serial EEPROMs
OUT_SK(0);
OUT_SK(1);
}
// fetch opcode // fetch opcode/operand
uint8_t opcode = fetch(); uint8_t operand = ROM(PC++);
cop400_opcode_func function = m_opcode_map[opcode]; if (!m_second_byte)
m_opcode = operand;
// check for interrupt when all successive transfer of control instructions and successive LBIs have been completed
if (!m_second_byte && BIT(EN, 1) && BIT(IL, 1) && !is_control_transfer(m_opcode) && !m_skip_lbi)
{
// acknowledge interrupt
IL &= ~2;
// check for interrupt
if (BIT(EN, 1) && BIT(IL, 1)) {
// all successive transfer of control instructions and successive LBIs have been completed
if ((function != OP(jp)) && (function != OP(jmp)) && (function != OP(jsr)) && !m_skip_lbi) {
// store skip logic // store skip logic
m_last_skip = m_skip; m_last_skip = m_skip;
m_skip = false; m_skip = false;
@ -1213,31 +1253,53 @@ void cop400_cpu_device::execute_run()
// jump to interrupt service routine // jump to interrupt service routine
PC = 0x0ff; PC = 0x0ff;
// disable interrupt // disable interrupts
EN &= ~0x02; EN &= ~2;
}
else if (!m_second_byte && m_InstLen[m_opcode] > 1)
{
m_second_byte = true;
}
else if (m_skip)
{
// finish skipping and execute next instruction
m_skip = false;
m_second_byte = false;
}
else
{
cop400_opcode_func function = m_opcode_map[m_opcode];
if (!m_second_byte && (function == OP(jid) || function == OP(lqid)))
{
// JID and LQID must first transfer control and then fetch the operand
// LQID saves the old program counter on the stack; JID doesn't and just jumps again
if (function == OP(lqid))
PUSH(PC);
// jump within page to operand at A/M
PC = (PC & 0x700) | (A << 4) | RAM_R(B);
m_second_byte = true;
}
else
{
// execute instruction
(this->*(function))(operand);
// LBI skip logic
if (m_skip_lbi > 0)
m_skip_lbi--;
// ready for the next instruction
m_second_byte = false;
}
} }
IL &= ~2; serial_tick();
} if (m_has_inil)
inil_tick();
if (m_skip) {
// skip instruction
if (m_InstLen[opcode] == 2) {
// fetch second byte
opcode = fetch();
}
m_skip = false;
continue;
}
// execute instruction
(this->*(function))(opcode);
// LBI skip logic
if (m_skip_lbi > 0) {
m_skip_lbi--;
} }
m_icount--;
} while (m_icount > 0); } while (m_icount > 0);
} }
@ -1256,6 +1318,11 @@ void cop400_cpu_device::state_import(const device_state_entry &entry)
m_c = BIT(m_flags, 1); m_c = BIT(m_flags, 1);
m_skl = BIT(m_flags, 0); m_skl = BIT(m_flags, 0);
break; break;
case COP400_M:
auto dis = machine().disable_side_effect();
RAM_W(B, m_temp_m);
break;
} }
} }
@ -1266,6 +1333,11 @@ void cop400_cpu_device::state_export(const device_state_entry &entry)
case STATE_GENFLAGS: case STATE_GENFLAGS:
m_flags = (m_skt_latch ? 0x04 : 0x00) | (m_c ? 0x02 : 0x00) | (m_skl ? 0x01 : 0x00); m_flags = (m_skt_latch ? 0x04 : 0x00) | (m_c ? 0x02 : 0x00) | (m_skl ? 0x01 : 0x00);
break; break;
case COP400_M:
auto dis = machine().disable_side_effect();
m_temp_m = RAM_R(B);
break;
} }
} }
@ -1279,6 +1351,22 @@ void cop400_cpu_device::state_string_export(const device_state_entry &entry, std
m_skl ? 'S' : '.', m_skl ? 'S' : '.',
m_skt_latch ? 'T' : '.'); m_skt_latch ? 'T' : '.');
break; break;
case COP400_SIO:
if (BIT(EN, 0))
{
// display counter in hex
str = string_format("%X ", m_sio);
}
else
{
// display shift register in binary
str = string_format("%d%d%d%d",
BIT(m_sio, 3),
BIT(m_sio, 2),
BIT(m_sio, 1),
BIT(m_sio, 0));
}
break;
} }
} }

View File

@ -68,11 +68,13 @@ enum
COP400_B, COP400_B,
COP400_C, COP400_C,
COP400_G, COP400_G,
COP400_M,
COP400_Q, COP400_Q,
COP400_EN, COP400_EN,
COP400_SIO, COP400_SIO,
COP400_SKL, COP400_SKL,
COP400_T COP400_T,
COP400_SKIP
}; };
/* input lines */ /* input lines */
@ -224,7 +226,8 @@ protected:
uint16_t m_sa, m_sb, m_sc; /* subroutine save registers */ uint16_t m_sa, m_sb, m_sc; /* subroutine save registers */
uint8_t m_sio; /* 4-bit shift register and counter */ uint8_t m_sio; /* 4-bit shift register and counter */
int m_skl; /* 1-bit latch for SK output */ int m_skl; /* 1-bit latch for SK output */
uint8_t m_flags; // used for I/O only uint8_t m_flags; // used for debugger state only
uint8_t m_temp_m; // 4-bit RAM at B (for debugger state only)
/* counter */ /* counter */
uint8_t m_t; /* 8-bit timer */ uint8_t m_t; /* 8-bit timer */
@ -248,13 +251,13 @@ protected:
/* execution logic */ /* execution logic */
int m_InstLen[256]; /* instruction length in bytes */ int m_InstLen[256]; /* instruction length in bytes */
int m_icount; /* instruction counter */ int m_icount; /* instruction counter */
uint8_t m_opcode; /* opcode being executed */
bool m_second_byte; /* second byte of opcode */
/* timers */ /* timers */
emu_timer *m_serial_timer;
emu_timer *m_counter_timer; emu_timer *m_counter_timer;
emu_timer *m_inil_timer;
typedef void ( cop400_cpu_device::*cop400_opcode_func ) (uint8_t opcode); typedef void (cop400_cpu_device::*cop400_opcode_func)(uint8_t operand);
const cop400_opcode_func *m_opcode_map; const cop400_opcode_func *m_opcode_map;
@ -271,6 +274,8 @@ protected:
static const cop400_opcode_func COP424C_OPCODE_33_MAP[256]; static const cop400_opcode_func COP424C_OPCODE_33_MAP[256];
static const cop400_opcode_func COP424C_OPCODE_MAP[256]; static const cop400_opcode_func COP424C_OPCODE_MAP[256];
inline static bool is_control_transfer(uint8_t opcode);
void serial_tick(); void serial_tick();
void counter_tick(); void counter_tick();
void inil_tick(); void inil_tick();
@ -279,85 +284,87 @@ protected:
void POP(); void POP();
void WRITE_Q(uint8_t data); void WRITE_Q(uint8_t data);
void WRITE_G(uint8_t data); void WRITE_G(uint8_t data);
void WRITE_EN(uint8_t data);
uint8_t fetch(); void skip();
void sk_update();
void illegal(uint8_t opcode); void illegal(uint8_t operand);
void asc(uint8_t opcode); void asc(uint8_t operand);
void add(uint8_t opcode); void add(uint8_t operand);
void aisc(uint8_t opcode); void aisc(uint8_t operand);
void clra(uint8_t opcode); void clra(uint8_t operand);
void comp(uint8_t opcode); void comp(uint8_t operand);
void nop(uint8_t opcode); void nop(uint8_t operand);
void rc(uint8_t opcode); void rc(uint8_t operand);
void sc(uint8_t opcode); void sc(uint8_t operand);
void xor_(uint8_t opcode); void xor_(uint8_t operand);
void adt(uint8_t opcode); void adt(uint8_t operand);
void casc(uint8_t opcode); void casc(uint8_t operand);
void jid(uint8_t opcode); void jid(uint8_t operand);
void jmp(uint8_t opcode); void jmp(uint8_t operand);
void jp(uint8_t opcode); void jp(uint8_t operand);
void jsr(uint8_t opcode); void jsr(uint8_t operand);
void ret(uint8_t opcode); void ret(uint8_t operand);
void cop420_ret(uint8_t opcode); void cop420_ret(uint8_t operand);
void retsk(uint8_t opcode); void retsk(uint8_t operand);
void halt(uint8_t opcode); void halt(uint8_t operand);
void it(uint8_t opcode); void it(uint8_t operand);
void camq(uint8_t opcode); void camq(uint8_t operand);
void ld(uint8_t opcode); void ld(uint8_t operand);
void lqid(uint8_t opcode); void lqid(uint8_t operand);
void rmb0(uint8_t opcode); void rmb0(uint8_t operand);
void rmb1(uint8_t opcode); void rmb1(uint8_t operand);
void rmb2(uint8_t opcode); void rmb2(uint8_t operand);
void rmb3(uint8_t opcode); void rmb3(uint8_t operand);
void smb0(uint8_t opcode); void smb0(uint8_t operand);
void smb1(uint8_t opcode); void smb1(uint8_t operand);
void smb2(uint8_t opcode); void smb2(uint8_t operand);
void smb3(uint8_t opcode); void smb3(uint8_t operand);
void stii(uint8_t opcode); void stii(uint8_t operand);
void x(uint8_t opcode); void x(uint8_t operand);
void xad(uint8_t opcode); void xad(uint8_t operand);
void xds(uint8_t opcode); void xds(uint8_t operand);
void xis(uint8_t opcode); void xis(uint8_t operand);
void cqma(uint8_t opcode); void cqma(uint8_t operand);
void ldd(uint8_t opcode); void ldd(uint8_t operand);
void camt(uint8_t opcode); void camt(uint8_t operand);
void ctma(uint8_t opcode); void ctma(uint8_t operand);
void cab(uint8_t opcode); void cab(uint8_t operand);
void cba(uint8_t opcode); void cba(uint8_t operand);
void lbi(uint8_t opcode); void lbi(uint8_t operand);
void lei(uint8_t opcode); void lei(uint8_t operand);
void xabr(uint8_t opcode); void xabr(uint8_t operand);
void cop444l_xabr(uint8_t opcode); void cop444l_xabr(uint8_t operand);
void skc(uint8_t opcode); void skc(uint8_t operand);
void ske(uint8_t opcode); void ske(uint8_t operand);
void skgz(uint8_t opcode); void skgz(uint8_t operand);
void skgbz0(uint8_t opcode); void skgbz0(uint8_t operand);
void skgbz1(uint8_t opcode); void skgbz1(uint8_t operand);
void skgbz2(uint8_t opcode); void skgbz2(uint8_t operand);
void skgbz3(uint8_t opcode); void skgbz3(uint8_t operand);
void skmbz0(uint8_t opcode); void skmbz0(uint8_t operand);
void skmbz1(uint8_t opcode); void skmbz1(uint8_t operand);
void skmbz2(uint8_t opcode); void skmbz2(uint8_t operand);
void skmbz3(uint8_t opcode); void skmbz3(uint8_t operand);
void skt(uint8_t opcode); void skt(uint8_t operand);
void ing(uint8_t opcode); void ing(uint8_t operand);
void inl(uint8_t opcode); void inl(uint8_t operand);
void obd(uint8_t opcode); void obd(uint8_t operand);
void omg(uint8_t opcode); void omg(uint8_t operand);
void xas(uint8_t opcode); void xas(uint8_t operand);
void inin(uint8_t opcode); void inin(uint8_t operand);
void cop402m_inin(uint8_t opcode); void cop402m_inin(uint8_t operand);
void inil(uint8_t opcode); void inil(uint8_t operand);
void ogi(uint8_t opcode); void ogi(uint8_t operand);
void cop410_op23(uint8_t opcode); void cop410_op23(uint8_t operand);
void cop410_op33(uint8_t opcode); void cop410_op33(uint8_t operand);
void cop420_op23(uint8_t opcode); void cop420_op23(uint8_t operand);
void cop420_op33(uint8_t opcode); void cop420_op33(uint8_t operand);
void cop444l_op23(uint8_t opcode); void cop444l_op23(uint8_t operand);
void cop444l_op33(uint8_t opcode); void cop444l_op33(uint8_t operand);
void cop424c_op23(uint8_t opcode); void cop424c_op23(uint8_t operand);
void cop424c_op33(uint8_t opcode); void cop424c_op33(uint8_t operand);
void skgbz(int bit); void skgbz(int bit);
void skmbz(int bit); void skmbz(int bit);
}; };

View File

@ -35,7 +35,7 @@ INSTRUCTION( asc )
if (A > 0xF) if (A > 0xF)
{ {
C = 1; C = 1;
m_skip = true; skip();
A &= 0xF; A &= 0xF;
} }
else else
@ -80,13 +80,13 @@ INSTRUCTION( add )
INSTRUCTION( aisc ) INSTRUCTION( aisc )
{ {
uint8_t y = opcode & 0x0f; uint8_t y = m_opcode & 0x0f;
A = A + y; A = A + y;
if (A > 0x0f) if (A > 0x0f)
{ {
m_skip = true; skip();
A &= 0xF; A &= 0xF;
} }
} }
@ -238,7 +238,7 @@ INSTRUCTION( casc )
if (A > 0xF) if (A > 0xF)
{ {
C = 1; C = 1;
m_skip = true; skip();
A &= 0xF; A &= 0xF;
} }
else else
@ -266,8 +266,6 @@ INSTRUCTION( casc )
INSTRUCTION( jid ) INSTRUCTION( jid )
{ {
PC = (PC & 0x700) | (A << 4) | RAM_R(B);
uint8_t operand = fetch();
PC = (PC & 0x700) | operand; PC = (PC & 0x700) | operand;
} }
@ -287,8 +285,7 @@ INSTRUCTION( jid )
INSTRUCTION( jmp ) INSTRUCTION( jmp )
{ {
uint8_t operand = fetch(); PC = ((m_opcode & 0x07) << 8) | operand;
PC = ((opcode & 0x07) << 8) | operand;
} }
/* /*
@ -317,18 +314,18 @@ INSTRUCTION( jp )
if (page == 2 || page == 3) if (page == 2 || page == 3)
{ {
uint8_t a = opcode & 0x7f; uint8_t a = m_opcode & 0x7f;
PC = (PC & 0x780) | a; PC = (PC & 0x780) | a;
} }
else if ((opcode & 0xc0) == 0xc0) else if ((m_opcode & 0xc0) == 0xc0)
{ {
uint8_t a = opcode & 0x3f; uint8_t a = m_opcode & 0x3f;
PC = (PC & 0x7c0) | a; PC = (PC & 0x7c0) | a;
} }
else else
{ {
// JSRP // JSRP
uint8_t a = opcode & 0x3f; uint8_t a = m_opcode & 0x3f;
PUSH(PC); PUSH(PC);
PC = 0x80 | a; PC = 0x80 | a;
} }
@ -351,9 +348,8 @@ INSTRUCTION( jp )
INSTRUCTION( jsr ) INSTRUCTION( jsr )
{ {
uint8_t operand = fetch();
PUSH(PC); PUSH(PC);
PC = ((opcode & 0x07) << 8) | operand; PC = ((m_opcode & 0x07) << 8) | operand;
} }
/* /*
@ -413,7 +409,7 @@ INSTRUCTION( cop420_ret )
INSTRUCTION( retsk ) INSTRUCTION( retsk )
{ {
POP(); POP();
m_skip = true; skip();
} }
/* /*
@ -529,7 +525,7 @@ INSTRUCTION( camq )
INSTRUCTION( ld ) INSTRUCTION( ld )
{ {
uint8_t r = opcode & 0x30; uint8_t r = m_opcode & 0x30;
A = RAM_R(B); A = RAM_R(B);
B = B ^ r; B = B ^ r;
@ -551,9 +547,6 @@ INSTRUCTION( ld )
INSTRUCTION( lqid ) INSTRUCTION( lqid )
{ {
PUSH(PC);
PC = (PC & 0x700) | (A << 4) | RAM_R(B);
uint8_t operand = fetch();
WRITE_Q(operand); WRITE_Q(operand);
POP(); POP();
} }
@ -641,7 +634,7 @@ INSTRUCTION( smb3 ) { RAM_W(B, RAM_R(B) | 0x8); }
INSTRUCTION( stii ) INSTRUCTION( stii )
{ {
uint8_t y = opcode & 0x0f; uint8_t y = m_opcode & 0x0f;
uint16_t Bd; uint16_t Bd;
RAM_W(B, y); RAM_W(B, y);
@ -667,7 +660,7 @@ INSTRUCTION( stii )
INSTRUCTION( x ) INSTRUCTION( x )
{ {
uint8_t r = opcode & 0x30; uint8_t r = m_opcode & 0x30;
uint8_t t = RAM_R(B); uint8_t t = RAM_R(B);
RAM_W(B, A); RAM_W(B, A);
@ -692,7 +685,7 @@ INSTRUCTION( x )
INSTRUCTION( xad ) INSTRUCTION( xad )
{ {
uint8_t rd = opcode & 0x7f; uint8_t rd = operand & 0x7f;
uint8_t t = A; uint8_t t = A;
A = RAM_R(rd); A = RAM_R(rd);
@ -721,7 +714,7 @@ INSTRUCTION( xad )
INSTRUCTION( xds ) INSTRUCTION( xds )
{ {
uint8_t t, Bd; uint8_t t, Bd;
uint8_t r = opcode & 0x30; uint8_t r = m_opcode & 0x30;
t = RAM_R(B); t = RAM_R(B);
RAM_W(B, A); RAM_W(B, A);
@ -732,7 +725,8 @@ INSTRUCTION( xds )
B = B ^ r; B = B ^ r;
if (Bd == 0x0f) m_skip = true; if (Bd == 0x0f)
skip();
} }
/* /*
@ -756,7 +750,7 @@ INSTRUCTION( xds )
INSTRUCTION( xis ) INSTRUCTION( xis )
{ {
uint8_t t, Bd; uint8_t t, Bd;
uint8_t r = opcode & 0x30; uint8_t r = m_opcode & 0x30;
t = RAM_R(B); t = RAM_R(B);
RAM_W(B, A); RAM_W(B, A);
@ -767,7 +761,8 @@ INSTRUCTION( xis )
B = B ^ r; B = B ^ r;
if (Bd == 0x00) m_skip = true; if (Bd == 0x00)
skip();
} }
/* /*
@ -806,7 +801,7 @@ INSTRUCTION( cqma )
INSTRUCTION( ldd ) INSTRUCTION( ldd )
{ {
uint8_t rd = opcode & 0x7f; uint8_t rd = operand & 0x7f;
A = RAM_R(rd); A = RAM_R(rd);
} }
@ -914,13 +909,13 @@ INSTRUCTION( lbi )
if (m_skip_lbi > 1) return; if (m_skip_lbi > 1) return;
m_skip_lbi++; m_skip_lbi++;
if (opcode & 0x80) if (operand & 0x80)
{ {
B = opcode & 0x7f; B = operand & 0x7f;
} }
else else
{ {
B = (opcode & 0x30) | (((opcode & 0x0f) + 1) & 0x0f); B = (operand & 0x30) | (((operand & 0x0f) + 1) & 0x0f);
} }
} }
@ -940,19 +935,9 @@ INSTRUCTION( lbi )
INSTRUCTION( lei ) INSTRUCTION( lei )
{ {
uint8_t y = opcode & 0x0f; uint8_t y = operand & 0x0f;
EN = y; WRITE_EN(y);
if (BIT(EN, 2))
{
OUT_L(Q);
}
else
{
// tri-state(floating) pins
OUT_L(m_read_l_tristate(0, 0xff));
}
} }
/* /*
@ -1020,7 +1005,8 @@ INSTRUCTION( cop444l_xabr )
INSTRUCTION( skc ) INSTRUCTION( skc )
{ {
if (C == 1) m_skip = true; if (C == 1)
skip();
} }
/* /*
@ -1038,7 +1024,8 @@ INSTRUCTION( skc )
INSTRUCTION( ske ) INSTRUCTION( ske )
{ {
if (A == RAM_R(B)) m_skip = true; if (A == RAM_R(B))
skip();
} }
/* /*
@ -1056,7 +1043,8 @@ INSTRUCTION( ske )
INSTRUCTION( skgz ) INSTRUCTION( skgz )
{ {
if (IN_G() == 0) m_skip = true; if (IN_G() == 0)
skip();
} }
/* /*
@ -1081,7 +1069,8 @@ INSTRUCTION( skgz )
void cop400_cpu_device::skgbz(int bit) void cop400_cpu_device::skgbz(int bit)
{ {
if (!BIT(IN_G(), bit)) m_skip = true; if (!BIT(IN_G(), bit))
skip();
} }
INSTRUCTION( skgbz0 ) { skgbz(0); } INSTRUCTION( skgbz0 ) { skgbz(0); }
@ -1111,7 +1100,8 @@ INSTRUCTION( skgbz3 ) { skgbz(3); }
void cop400_cpu_device::skmbz(int bit) void cop400_cpu_device::skmbz(int bit)
{ {
if (!BIT(RAM_R(B), bit)) m_skip = true; if (!BIT(RAM_R(B), bit))
skip();
} }
INSTRUCTION( skmbz0 ) { skmbz(0); } INSTRUCTION( skmbz0 ) { skmbz(0); }
@ -1137,7 +1127,7 @@ INSTRUCTION( skt )
if (m_skt_latch) if (m_skt_latch)
{ {
m_skt_latch = 0; m_skt_latch = 0;
m_skip = true; skip();
} }
} }
@ -1241,7 +1231,11 @@ INSTRUCTION( xas )
SIO = A; SIO = A;
A = t; A = t;
SKL = C; if (SKL != C)
{
SKL = C;
sk_update();
}
} }
/* /*
@ -1318,7 +1312,7 @@ INSTRUCTION( inil )
INSTRUCTION( ogi ) INSTRUCTION( ogi )
{ {
uint8_t y = opcode & 0x0f; uint8_t y = operand & 0x0f;
WRITE_G(y); WRITE_G(y);
} }

View File

@ -32,7 +32,7 @@ PCB Layout
| YM3014 MAHJONG28 | | YM3014 MAHJONG28 |
|---------------------------------------------| |---------------------------------------------|
Notes: Notes:
COP - COP402 or COP404 MCU (DIP40, +5V on pin 17, GND on pin 22). COP - DIP40 identified as COP402 MCU (+5V on pin 17, GND on pin 22).
pins 4,3,2 of 93C46 tied to COP pins 23,24,25 pins 4,3,2 of 93C46 tied to COP pins 23,24,25
All clocks unknown, PCB not working All clocks unknown, PCB not working
Possibly Z80's @ 4MHz and YM2203 @ 2MHz Possibly Z80's @ 4MHz and YM2203 @ 2MHz
@ -655,7 +655,7 @@ ROM_START( quizpun2 )
ROM_LOAD( "u1", 0x00000, 0x10000, CRC(58506040) SHA1(9d8bed2585e8f188a20270fccd9cfbdb91e48599) ) ROM_LOAD( "u1", 0x00000, 0x10000, CRC(58506040) SHA1(9d8bed2585e8f188a20270fccd9cfbdb91e48599) )
ROM_LOAD( "u2", 0x10000, 0x10000, CRC(9294a19c) SHA1(cd7109262e5f68b946c84aa390108bcc47ee1300) ) ROM_LOAD( "u2", 0x10000, 0x10000, CRC(9294a19c) SHA1(cd7109262e5f68b946c84aa390108bcc47ee1300) )
ROM_REGION16_BE( 0x80, "eeprom", 0 ) // EEPROM (tied to the unknown DIP40) ROM_REGION16_BE( 0x80, "eeprom", 0 ) // EEPROM
ROM_LOAD( "93c46", 0x00, 0x80, CRC(4d244cc8) SHA1(6593d5b7ac1ebb77fee4648ad1d3d9b59a25fdc8) BAD_DUMP ) // backup ram error ROM_LOAD( "93c46", 0x00, 0x80, CRC(4d244cc8) SHA1(6593d5b7ac1ebb77fee4648ad1d3d9b59a25fdc8) BAD_DUMP ) // backup ram error
ROM_END ROM_END