cpu/hcd62121,casio/pickytlk.cpp: Add support for more Picky Talk models (#13015)

This commit is contained in:
qufb 2024-11-30 01:51:08 +00:00 committed by GitHub
parent 325fa58f6b
commit baeadecbaf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 609 additions and 370 deletions

View File

@ -66,9 +66,14 @@ hcd62121_cpu_device::hcd62121_cpu_device(const machine_config &mconfig, const ch
, m_f(0)
, m_time(0)
, m_time_op(0)
, m_unk_f5(0)
, m_cycles_until_timeout(0)
, m_is_timer_started(false)
, m_is_timer_irq_enabled(false)
, m_is_timer_irq_asserted(false)
, m_is_timer_wait_elapsed(true)
, m_is_infinite_timeout(false)
, m_timer_cycles(0)
, m_lar(0)
, m_opt(0)
, m_port(0)
@ -145,12 +150,12 @@ void hcd62121_cpu_device::write_reg(int size, u8 op1)
if (op1 & 0x80)
{
for (int i = 0; i < size; i++)
m_reg[(op1 - i) & 0x7f] = m_temp1[i];
set_reg((op1 - i) & 0x7f, m_temp1[i]);
}
else
{
for (int i = 0; i < size; i++)
m_reg[(op1 + i) & 0x7f] = m_temp1[i];
set_reg((op1 + i) & 0x7f, m_temp1[i]);
}
}
@ -219,13 +224,13 @@ void hcd62121_cpu_device::write_regreg(int size, u8 arg1, u8 arg2)
{
/* store in arg1 */
for (int i = 0; i < size; i++)
m_reg[(arg1 + i) & 0x7f] = m_temp1[i];
set_reg((arg1 + i) & 0x7f, m_temp1[i]);
}
else
{
/* store in arg2 */
for (int i = 0; i < size; i++)
m_reg[(arg2 + i) & 0x7f] = m_temp1[i];
set_reg((arg2 + i) & 0x7f, m_temp1[i]);
}
}
@ -286,7 +291,7 @@ void hcd62121_cpu_device::write_iregreg(int size, u8 op1, u8 op2)
{
/* store in reg2 */
for (int i = 0; i < size; i++)
m_reg[(op2 + i) & 0x7f] = m_temp1[i];
set_reg((op2 + i) & 0x7f, m_temp1[i]);
}
}
@ -297,7 +302,7 @@ void hcd62121_cpu_device::write_iregreg2(int size, u8 op1, u8 op2)
{
/* store in reg2 */
for (int i = 0; i < size; i++)
m_reg[(op2 + i) & 0x7f] = m_temp2[i];
set_reg((op2 + i) & 0x7f, m_temp2[i]);
}
else
{
@ -574,17 +579,22 @@ void hcd62121_cpu_device::device_reset()
{
m_sp = 0x0000;
m_ip = 0x0000;
m_dsize = 0;
m_cseg = 0;
m_dseg = 0;
m_sseg = 0;
m_lar = 0;
m_f = 0;
m_time = 0;
m_time_op = 0;
m_unk_f5 = 0;
m_cycles_until_timeout = 0;
m_is_timer_started = false;
m_is_timer_irq_enabled = false;
m_is_timer_irq_asserted = false;
m_is_timer_wait_elapsed = true;
m_is_infinite_timeout = false;
m_dsize = 0;
m_timer_cycles = 0;
m_lar = 0;
m_opt = 0;
m_port = 0;
@ -869,15 +879,29 @@ inline void hcd62121_cpu_device::op_sub(int size)
}
inline void hcd62121_cpu_device::op_pushb(u8 source)
{
m_program->write_byte((m_sseg << 16) | m_sp, source);
m_sp--;
}
inline void hcd62121_cpu_device::op_pushw(u16 source)
{
m_program->write_byte(( m_sseg << 16) | m_sp, source & 0xff);
m_program->write_byte((m_sseg << 16) | m_sp, source & 0xff);
m_sp--;
m_program->write_byte(( m_sseg << 16) | m_sp, source >> 8);
m_program->write_byte((m_sseg << 16) | m_sp, source >> 8);
m_sp--;
}
inline u8 hcd62121_cpu_device::op_popb()
{
m_sp++;
return m_program->read_byte((m_sseg << 16) | m_sp);
}
inline u16 hcd62121_cpu_device::op_popw()
{
m_sp++;
@ -888,14 +912,29 @@ inline u16 hcd62121_cpu_device::op_popw()
return res;
}
void hcd62121_cpu_device::timer_elapsed()
{
m_is_timer_wait_elapsed = true;
if (m_is_timer_irq_enabled)
{
m_is_timer_irq_asserted = true;
// Call timer interrupt vector.
op_pushb(m_cseg);
op_pushw(m_ip);
m_cseg = 0x00;
m_ip = 0x0008;
}
}
void hcd62121_cpu_device::execute_run()
{
do
{
if (m_ki_cb() != 0)
if (m_ki_cb() != 0 && m_input_flag_cb() == 0)
{
m_cycles_until_timeout = 0;
m_is_timer_wait_elapsed = true;
m_is_infinite_timeout = false;
}
@ -904,15 +943,26 @@ void hcd62121_cpu_device::execute_run()
set_input_flag(false);
}
if (m_is_infinite_timeout)
if (m_is_infinite_timeout && !m_is_timer_wait_elapsed)
{
m_icount = 0;
}
else if (m_cycles_until_timeout > 0)
else if (m_cycles_until_timeout > 0 && !m_is_timer_irq_asserted)
{
int cycles_to_consume = std::min(m_cycles_until_timeout, m_icount);
m_cycles_until_timeout -= cycles_to_consume;
m_icount -= cycles_to_consume;
if (!m_is_timer_wait_elapsed)
{
// It's a blocking wait, consume as much as possible in this quantum.
m_icount -= cycles_to_consume;
}
if (m_cycles_until_timeout <= 0)
{
m_cycles_until_timeout += m_timer_cycles;
timer_elapsed();
}
}
if (m_icount <= 0)
{
@ -1656,7 +1706,22 @@ void hcd62121_cpu_device::execute_run()
break;
case 0x8E: /* unk_8E */
logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op);
{
logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op);
if (m_unk_f5 == 0xd0)
{
/*
FIXME: Needs to be validated with hardware tests.
Instruction 0x8E is called before reading and testing inputs in some cases.
While the timer is also configured, there's no blocking wait for it to expire.
Instead, there's a busy wait on 2 bytes at register R76 that aren't updated directly by
program code. So far only seen when instruction 0xF5 is executed with operand 0xD0, but
maybe irrelevant, see JD-364 @ 21:b65f.
*/
m_is_timer_irq_enabled = true;
}
}
break;
case 0x90: /* retzh */
@ -1685,6 +1750,12 @@ void hcd62121_cpu_device::execute_run()
}
break;
case 0x9E: /* reti */
m_ip = op_popw();
m_cseg = op_popb();
m_is_timer_irq_asserted = false;
break;
case 0x9F: /* ret */
m_ip = op_popw();
break;
@ -1738,7 +1809,72 @@ void hcd62121_cpu_device::execute_run()
{
u8 arg = read_op();
/*
When timer control is set with operand 0xC0, the CPU periodically reads
from external RAM (address range 0x7c00..0x7fff) at an interval of
832 clock cycles, with the reads themselves taking another 64 clock cycles.
This needs to be explicitly setup, involving writes to unknown segments
0x11 and 0xE1 (see cfx9850.bin @ 00:00fe), otherwise there's only activity
on address lines without any reads.
The total sum of these state reads can be approximated to the closest
power of two to define timeout values. Multiple samples were averaged,
as the state read interval can start at a distinct point in time from
the timer wait execution.
*/
const u64 TIMER_STATE_READ_CYCLES = 832 + 64;
m_is_infinite_timeout = false;
m_is_timer_wait_elapsed = true;
m_cycles_until_timeout = m_timer_cycles = 0;
m_time_op = arg;
switch (m_time_op)
{
case 0x01: case 0x03:
// Likely only timeouts on KO enabled input.
m_is_infinite_timeout = true;
break;
case 0x11: case 0x13: case 0x15: case 0x17: case 0x19: case 0x1b: case 0x1d: case 0x1f:
case 0x31: case 0x33: case 0x35: case 0x37: case 0x39: case 0x3b: case 0x3d: case 0x3f:
case 0x51: case 0x53: case 0x55: case 0x57: case 0x59: case 0x5b: case 0x5d: case 0x5f:
case 0x71: case 0x73: case 0x75: case 0x77: case 0x79: case 0x7b: case 0x7d: case 0x7f:
case 0x91: case 0x93: case 0x95: case 0x97: case 0x99: case 0x9b: case 0x9d: case 0x9f:
case 0xb1: case 0xb3: case 0xb5: case 0xb7: case 0xb9: case 0xbb: case 0xbd: case 0xbf:
case 0xd1: case 0xd3: case 0xd5: case 0xd7: case 0xd9: case 0xdb: case 0xdd: case 0xdf:
// Approximately 814.32us
m_timer_cycles = 0x4 * TIMER_STATE_READ_CYCLES;
break;
case 0x21: case 0x23: case 0x25: case 0x27: case 0x29: case 0x2b: case 0x2d: case 0x2f:
case 0x61: case 0x63: case 0x65: case 0x67: case 0x69: case 0x6b: case 0x6d: case 0x6f:
case 0xa1: case 0xa3: case 0xa5: case 0xa7: case 0xa9: case 0xab: case 0xad: case 0xaf:
// Approximately 1.63ms
m_timer_cycles = 0x8 * TIMER_STATE_READ_CYCLES;
break;
case 0x05: case 0x07: case 0x0d: case 0x0f:
case 0x45: case 0x47: case 0x4d: case 0x4f:
case 0xc5: case 0xc7: case 0xcd: case 0xcf:
// Approximately 209.34ms
m_timer_cycles = 0x400 * TIMER_STATE_READ_CYCLES;
break;
case 0x09: case 0x0b:
case 0x49: case 0x4b:
case 0xc9: case 0xcb:
// Approximately 837.61ms
m_timer_cycles = 0x1000 * TIMER_STATE_READ_CYCLES;
break;
case 0x41: case 0x43:
case 0xc1: case 0xc3:
// Approximately 1.68s
m_timer_cycles = 0x2000 * TIMER_STATE_READ_CYCLES;
break;
case 0x81: case 0x83:
// Approximately 100.58s
m_timer_cycles = 0x7a800 * TIMER_STATE_READ_CYCLES;
break;
default:
logerror("%02x:%04x: unimplemented timer value %02x encountered\n", m_cseg, m_ip-1, m_time_op);
break;
}
m_cycles_until_timeout = m_timer_cycles;
m_is_timer_started = true;
}
break;
@ -1804,7 +1940,7 @@ void hcd62121_cpu_device::execute_run()
for (int i = 0; i < size; i++)
{
m_reg[(reg + i) & 0x7f] = read_op();
set_reg((reg + i) & 0x7f, read_op());
}
}
break;
@ -1848,7 +1984,18 @@ void hcd62121_cpu_device::execute_run()
m_lar += pre_inc;
if (arg1 & 0x80)
{
/*
FIXME: Needs to be validated with hardware tests.
JD-368 @ 20:047a must write value 0x7f @ 40:1819, despite 0x7f7f being
expected @ 20:3492. This routine is used to clear RAM, and will overflow
if 40:1818 = 0xff7f7f, since it will loop beyond the expected 0x8000 size
to clear.
Does this instruction zero-extend immediate values?
*/
m_program->write_byte((m_dseg << 16) | m_lar, arg2);
arg2 = 0;
}
else
{
@ -1863,7 +2010,7 @@ void hcd62121_cpu_device::execute_run()
for (int i = 0; i < size; i++)
{
m_lar += pre_inc;
m_reg[(arg2 + i) & 0x7f] = m_program->read_byte((m_dseg << 16) | m_lar);
set_reg((arg2 + i) & 0x7f, m_program->read_byte((m_dseg << 16) | m_lar));
m_lar += post_inc;
}
}
@ -1970,16 +2117,16 @@ void hcd62121_cpu_device::execute_run()
logerror("%06x: in0 read\n", (m_cseg << 16) | m_ip);
u8 reg1 = read_op();
m_reg[reg1 & 0x7f] = m_in0_cb();
set_reg(reg1 & 0x7f, m_in0_cb());
}
break;
case 0xE1: /* movb reg,OPT */
m_reg[read_op() & 0x7f] = m_opt;
set_reg(read_op() & 0x7f, m_opt);
break;
case 0xE2: /* in kb, reg */
m_reg[read_op() & 0x7f] = m_ki_cb();
set_reg(read_op() & 0x7f, m_ki_cb());
break;
case 0xE3: /* movb reg,dsize */
@ -1987,7 +2134,7 @@ void hcd62121_cpu_device::execute_run()
u8 reg = read_op();
if (reg & 0x80)
fatalerror("%02x:%04x: unimplemented instruction %02x encountered with (arg & 0x80) != 0\n", m_cseg, m_ip-1, op);
m_reg[reg & 0x7f] = m_dsize;
set_reg(reg & 0x7f, m_dsize);
}
break;
@ -1996,24 +2143,24 @@ void hcd62121_cpu_device::execute_run()
u8 reg = read_op();
if (reg & 0x80)
fatalerror("%02x:%04x: unimplemented instruction %02x encountered with (arg & 0x80) != 0\n", m_cseg, m_ip-1, op);
m_reg[reg & 0x7f] = m_f;
set_reg(reg & 0x7f, m_f);
}
break;
case 0xE5: /* movb reg,TIME */
m_reg[read_op() & 0x7f] = m_time;
set_reg(read_op() & 0x7f, m_time);
break;
case 0xE6: /* movb reg,PORT */
m_reg[read_op() & 0x7f] = m_port;
set_reg(read_op() & 0x7f, m_port);
break;
case 0xE8: /* movw r1,lar */
{
u8 reg1 = read_op();
m_reg[reg1 & 0x7f] = m_lar & 0xff;
m_reg[(reg1 + 1) & 0x7f] = m_lar >> 8;
set_reg(reg1 & 0x7f, m_lar & 0xff);
set_reg((reg1 + 1) & 0x7f, m_lar >> 8);
}
break;
@ -2021,8 +2168,8 @@ void hcd62121_cpu_device::execute_run()
{
u8 reg1 = read_op();
m_reg[reg1 & 0x7f] = m_ip & 0xff;
m_reg[(reg1 + 1) & 0x7f] = m_ip >> 8;
set_reg(reg1 & 0x7f, m_ip & 0xff);
set_reg((reg1 + 1) & 0x7f, m_ip >> 8);
}
break;
@ -2030,21 +2177,21 @@ void hcd62121_cpu_device::execute_run()
{
u8 reg1 = read_op();
m_reg[reg1 & 0x7f] = m_sp & 0xff;
m_reg[(reg1 + 1) & 0x7f] = m_sp >> 8;
set_reg(reg1 & 0x7f, m_sp & 0xff);
set_reg((reg1 + 1) & 0x7f, m_sp >> 8);
}
break;
case 0xED: /* movb reg,ds */
m_reg[read_op() & 0x7f] = m_dseg;
set_reg(read_op() & 0x7f, m_dseg);
break;
case 0xEE: /* movb reg,cs */
m_reg[read_op() & 0x7f] = m_cseg;
set_reg(read_op() & 0x7f, m_cseg);
break;
case 0xEF: /* movb reg,ss */
m_reg[read_op() & 0x7f] = m_sseg;
set_reg(read_op() & 0x7f, m_sseg);
break;
case 0xF0: /* movb OPT,reg */
@ -2057,170 +2204,33 @@ void hcd62121_cpu_device::execute_run()
m_port_cb(m_port);
break;
case 0xF5: /* unk_F5 reg/i8 (out?) */
logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op);
m_unk_f5 = read_op();
break;
case 0xF1: /* unk_F1 reg/i8 (out?) */
case 0xF3: /* unk_F3 reg/i8 (out?) */
case 0xF5: /* unk_F5 reg/i8 (out?) */
case 0xF6: /* unk_F6 reg/i8 (out?) */
case 0xF7: /* timer_ctrl i8 */
case 0xF8: /* unk_F8 reg/i8 (out?) */
logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op);
read_op();
break;
case 0xFC: /* unk_FC - disable interrupts/stop timer?? */
logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op);
case 0xFC: /* timer_clear */
// FIXME: Needs to be validated with hardware tests.
m_cycles_until_timeout = m_timer_cycles = 0;
m_is_timer_irq_enabled = false;
m_is_timer_irq_asserted = false;
m_is_timer_wait_elapsed = true;
break;
case 0xFD: /* timer_wait_low (no X1 clock, address or data bus activity) */
case 0xFE: /* timer_wait */
if (m_time_op & 0x01)
if (BIT(m_time_op, 0))
{
/*
When timer control is set with operand 0xC0, the CPU periodically reads
from external RAM (address range 0x7c00..0x7fff) at an interval of
832 clock cycles, with the reads themselves taking another 64 clock cycles.
This needs to be explicitly setup, involving writes to unknown segments
0x11 and 0xE1 (see cfx9850.bin @ 00:00fe), otherwise there's only activity
on address lines without any reads.
The total sum of these state reads can be approximated to the closest
power of two to define timeout values. Multiple samples were averaged,
as the state read interval can start at a distinct point in time from
the timer wait execution.
*/
const u64 TIMER_STATE_READ_CYCLES = 832 + 64;
switch (m_time_op)
{
case 0x01:
case 0x03:
// Likely only timeouts on KO enabled input.
m_is_infinite_timeout = true;
break;
case 0x11:
case 0x13:
case 0x15:
case 0x17:
case 0x19:
case 0x1b:
case 0x1d:
case 0x1f:
case 0x31:
case 0x33:
case 0x35:
case 0x37:
case 0x39:
case 0x3b:
case 0x3d:
case 0x3f:
case 0x51:
case 0x53:
case 0x55:
case 0x57:
case 0x59:
case 0x5b:
case 0x5d:
case 0x5f:
case 0x71:
case 0x73:
case 0x75:
case 0x77:
case 0x79:
case 0x7b:
case 0x7d:
case 0x7f:
case 0x91:
case 0x93:
case 0x95:
case 0x97:
case 0x99:
case 0x9b:
case 0x9d:
case 0x9f:
case 0xb1:
case 0xb3:
case 0xb5:
case 0xb7:
case 0xb9:
case 0xbb:
case 0xbd:
case 0xbf:
case 0xd1:
case 0xd3:
case 0xd5:
case 0xd7:
case 0xd9:
case 0xdb:
case 0xdd:
case 0xdf:
// Approximately 814.32us
m_cycles_until_timeout = 0x4 * TIMER_STATE_READ_CYCLES;
break;
case 0x21:
case 0x23:
case 0x25:
case 0x27:
case 0x29:
case 0x2b:
case 0x2d:
case 0x2f:
case 0x61:
case 0x63:
case 0x65:
case 0x67:
case 0x69:
case 0x6b:
case 0x6d:
case 0x6f:
case 0xa1:
case 0xa3:
case 0xa5:
case 0xa7:
case 0xa9:
case 0xab:
case 0xad:
case 0xaf:
// Approximately 1.63ms
m_cycles_until_timeout = 0x8 * TIMER_STATE_READ_CYCLES;
break;
case 0x05:
case 0x07:
case 0x0d:
case 0x0f:
case 0x45:
case 0x47:
case 0x4d:
case 0x4f:
case 0xc5:
case 0xc7:
case 0xcd:
case 0xcf:
// Approximately 209.34ms
m_cycles_until_timeout = 0x400 * TIMER_STATE_READ_CYCLES;
break;
case 0x09:
case 0x0b:
case 0x49:
case 0x4b:
case 0xc9:
case 0xcb:
// Approximately 837.61ms
m_cycles_until_timeout = 0x1000 * TIMER_STATE_READ_CYCLES;
break;
case 0x41:
case 0x43:
case 0xc1:
case 0xc3:
// Approximately 1.68s
m_cycles_until_timeout = 0x2000 * TIMER_STATE_READ_CYCLES;
break;
case 0x81:
case 0x83:
// Approximately 100.58s
m_cycles_until_timeout = 0x7a800 * TIMER_STATE_READ_CYCLES;
break;
default:
logerror("%02x:%04x: unimplemented timer value %02x encountered\n", m_cseg, m_ip-1, m_time_op);
break;
}
m_is_timer_wait_elapsed = false;
}
else
{

View File

@ -83,8 +83,12 @@ private:
void op_addb(int size);
void op_subb(int size);
void op_sub(int size);
void op_pushb(u8 source);
void op_pushw(u16 source);
u8 op_popb();
u16 op_popw();
void set_reg(u8 i, u8 val) { m_reg[i] = val; /*logerror("R%02X = %02x @ %06X\n", i, val, (m_cseg << 16) | m_ip);*/ }
void timer_elapsed();
address_space_config m_program_config;
@ -98,9 +102,14 @@ private:
u8 m_f;
u8 m_time;
u8 m_time_op;
u8 m_unk_f5;
s32 m_cycles_until_timeout;
bool m_is_timer_started;
bool m_is_timer_irq_enabled;
bool m_is_timer_irq_asserted;
bool m_is_timer_wait_elapsed;
bool m_is_infinite_timeout;
s32 m_timer_cycles;
emu_timer *m_timer;
u16 m_lar;
u8 m_reg[0x80];

View File

@ -157,14 +157,14 @@ const hcd62121_disassembler::dasm hcd62121_disassembler::ops[256] =
{ "movb", ARG_REG, ARG_CS }, { "movb", ARG_REG, ARG_SS },
/* 0xf0 */
{ "movb", ARG_OPT, ARG_REG }, { "unF1?", ARG_I8, ARG_NONE },
{ "movb", ARG_PORT, ARG_REG }, { "unF3?", ARG_I8, ARG_NONE },
{ "unF4?", ARG_I8, ARG_NONE }, { "unF5?", ARG_I8, ARG_NONE },
{ "unF6?", ARG_I8, ARG_NONE }, { "timer_ctrl", ARG_I8, ARG_NONE },
{ "unF8?", ARG_NONE, ARG_NONE }, { "unF9?", ARG_NONE, ARG_NONE },
{ "unFA?", ARG_NONE, ARG_NONE }, { "unFb?", ARG_NONE, ARG_NONE },
{ "unFC?", ARG_NONE, ARG_NONE }, { "timer_wait_low", ARG_NONE, ARG_NONE },
{ "timer_wait", ARG_NONE, ARG_NONE }, { "nop", ARG_NONE, ARG_NONE }
{ "movb", ARG_OPT, ARG_REG }, { "unF1?", ARG_I8, ARG_NONE },
{ "movb", ARG_PORT, ARG_REG }, { "unF3?", ARG_I8, ARG_NONE },
{ "unF4?", ARG_I8, ARG_NONE }, { "unF5?", ARG_I8, ARG_NONE },
{ "unF6?", ARG_I8, ARG_NONE }, { "timer_ctrl", ARG_I8, ARG_NONE },
{ "unF8?", ARG_I8, ARG_NONE }, { "unF9?", ARG_NONE, ARG_NONE },
{ "unFA?", ARG_NONE, ARG_NONE }, { "unFb?", ARG_NONE, ARG_NONE },
{ "timer_clear", ARG_NONE, ARG_NONE }, { "timer_wait_low", ARG_NONE, ARG_NONE },
{ "timer_wait", ARG_NONE, ARG_NONE }, { "nop", ARG_NONE, ARG_NONE }
};
u32 hcd62121_disassembler::opcode_alignment() const

View File

@ -2,19 +2,16 @@
// copyright-holders:QUFB
/***************************************************************************
Driver for Casio Picky Talk
Driver for Casio Picky Talk and Casio Plet's
TODO:
- Communication port;
- Panel active buttons display;
- Review PORT/OPT callbacks copied from CFX9850G;
Some points of interest can be accessed under the debugger:
1. bpset 0x200328
2. ip=3fe (clock screen)
3. ip=410 (main screen)
- Fix unk_F8 loop when viewing calendar in JD-363/JD-364 models;
- Fix busy loop @ 20:2981 in Plet's models;
- Keyboard input for Plet's models;
Hardware
--------
@ -26,6 +23,25 @@
- LSI3 (Static RAM): NEC D441000LGZ (1M-bit, 128K-word by 8-bit)
- LSI5 (Mask ROM): NEC D23C8000XGX-C64 (8M-bit, 1M-word by 8-bit, pin compatible with AMD AM29F800B)
Plet's (MK-300):
- PCB revision: A141252-1 Z836-1
- LSI1 (CPU): Unknown (instruction set compatible with Hitachi HCD62121)
- LSI3 (Static RAM): Toshiba TC551001BFL-10V (1M-bit, 128K-word by 8-bit)
- LSI5 (Mask ROM): NEC D23C8000XGX-C77 (8M-bit, 1M-word by 8-bit, pin compatible with AMD AM29F800B)
Plet's (MK-350):
- PCB revision: A141252-1 Z836-1
- LSI1 (CPU): Unknown (instruction set compatible with Hitachi HCD62121)
- LSI3 (Static RAM): NEC D441000LGW-B85X
- LSI5 (Mask ROM): Oki M538032E-48
Hidden Features
---------------
[JD-370] On the debugger, run "bpset 20adb2,,{ ip=20ad27; g; }" to access an unused test program.
***************************************************************************/
#include "emu.h"
@ -46,10 +62,10 @@
namespace {
class pickytlk_state : public driver_device
class pickytlk_base_state : public driver_device
{
public:
pickytlk_state(const machine_config &mconfig, device_type type, const char *tag)
pickytlk_base_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_display_ram(*this, "display_ram")
, m_maincpu(*this, "maincpu")
@ -68,7 +84,7 @@ public:
ioport_value pen_y_rescale_r();
ioport_value pen_target_r();
private:
protected:
enum pen_target : u8
{
PEN_TARGET_LCD = 0,
@ -96,11 +112,11 @@ private:
TIMER_CALLBACK_MEMBER(io_timer_tick);
u8 io_pen_x_read();
u8 io_pen_y_read();
u8 tablet_read(offs_t offset);
virtual u8 tablet_read(offs_t offset);
void tablet_write(offs_t offset, u8 data);
virtual void pickytlk_layout(machine_config &config);
void update_crosshair(screen_device &screen);
void pickytlk_palette(palette_device &palette) const;
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void pickytlk_mem(address_map &map) ATTR_COLD;
@ -128,19 +144,19 @@ private:
u8 m_pen_target;
};
void pickytlk_state::machine_start()
void pickytlk_base_state::machine_start()
{
save_item(NAME(m_ko));
save_item(NAME(m_port));
save_item(NAME(m_opt));
m_io_tablet_regs = make_unique_clear<u8[]>(0x100);
save_pointer(NAME(m_io_tablet_regs), 0x100);
m_io_timer = timer_alloc(FUNC(pickytlk_state::io_timer_tick), this);
m_io_timer = timer_alloc(FUNC(pickytlk_base_state::io_timer_tick), this);
save_item(NAME(m_pen_state));
save_item(NAME(m_pen_target));
}
void pickytlk_state::machine_reset()
void pickytlk_base_state::machine_reset()
{
memset(m_io_tablet_regs.get(), 0, 0x100);
m_io_timer->reset(attotime::never);
@ -148,14 +164,14 @@ void pickytlk_state::machine_reset()
m_pen_target = PEN_TARGET_LCD;
}
CROSSHAIR_MAPPER_MEMBER(pickytlk_state::pen_y_mapper)
CROSSHAIR_MAPPER_MEMBER(pickytlk_base_state::pen_y_mapper)
{
// Parameter `linear_value` is ignored, since we will read the input port directly
// for adjustments, just need to return that value in the expected range [0.0f..1.0f].
return (float) pen_y_rescale_r() / 0xff;
}
ioport_value pickytlk_state::pen_y_rescale_r()
ioport_value pickytlk_base_state::pen_y_rescale_r()
{
/*
There are two distinct areas that can be interacted with the pen:
@ -182,25 +198,12 @@ ioport_value pickytlk_state::pen_y_rescale_r()
return adjusted_value;
}
ioport_value pickytlk_state::pen_target_r()
ioport_value pickytlk_base_state::pen_target_r()
{
return m_pen_target;
}
void pickytlk_state::pickytlk_mem(address_map &map)
{
map(0x000000, 0x007fff).mirror(0x008000).rom();
map(0x080000, 0x0807ff).ram();
map(0x080300, 0x08030f).rw(FUNC(pickytlk_state::tablet_read), FUNC(pickytlk_state::tablet_write));
// map(0x100000, 0x10ffff) // some memory mapped i/o???
// map(0x110000, 0x11ffff) // some memory mapped i/o???
map(0x200000, 0x2fffff).rom().region("mask_rom", 0);
map(0x400000, 0x4007ff).ram().share("display_ram");
map(0x400800, 0x41ffff).ram();
// map(0xe10000, 0xe1ffff) // some memory mapped i/o???
}
TIMER_CALLBACK_MEMBER(pickytlk_state::io_timer_tick)
TIMER_CALLBACK_MEMBER(pickytlk_base_state::io_timer_tick)
{
if (m_pen_state == PEN_PRESS)
{
@ -208,7 +211,7 @@ TIMER_CALLBACK_MEMBER(pickytlk_state::io_timer_tick)
}
}
u8 pickytlk_state::io_pen_x_read()
u8 pickytlk_base_state::io_pen_x_read()
{
// Pen callibration tests seem to check coordinates relative to the center of the LCD screen,
// and those offsets also align with the LCD position relative to the full tablet surface.
@ -218,7 +221,7 @@ u8 pickytlk_state::io_pen_x_read()
return rescale(io_pen_x_pos, io_pen_x_min, io_pen_x_max, 0x20, 0xdf);
}
u8 pickytlk_state::io_pen_y_read()
u8 pickytlk_base_state::io_pen_y_read()
{
s16 io_pen_y_min = m_io_pen_y->field(0xff)->minval();
s16 io_pen_y_max = m_io_pen_y->field(0xff)->maxval();
@ -228,7 +231,260 @@ u8 pickytlk_state::io_pen_y_read()
: rescale(io_pen_y_pos, io_pen_y_min, io_pen_y_max, 0xa0, 0xf0);
}
u8 pickytlk_state::tablet_read(offs_t offset)
u8 pickytlk_base_state::tablet_read(offs_t offset)
{
// Default (overriden by each system)
return 0;
}
void pickytlk_base_state::tablet_write(offs_t offset, u8 data)
{
LOGMASKED(LOG_TABLET, "%s: tablet_write [%02x] = %02x\n", machine().describe_context(), offset, data);
m_io_tablet_regs[offset] = data;
}
void pickytlk_base_state::kol_w(u8 data)
{
m_ko = (m_ko & 0xff00) | data;
LOGMASKED(LOG_IO, "%s: KO = %04x\n", machine().describe_context(), m_ko);
}
void pickytlk_base_state::koh_w(u8 data)
{
m_ko = (m_ko & 0x00ff) | (u16(data) << 8);
LOGMASKED(LOG_IO, "%s: KO = %04x\n", machine().describe_context(), m_ko);
}
void pickytlk_base_state::port_w(u8 data)
{
m_port = data;
LOGMASKED(LOG_IO, "%s: PORT = %02x\n", machine().describe_context(), m_port);
}
void pickytlk_base_state::opt_w(u8 data)
{
m_opt = data;
LOGMASKED(LOG_IO, "%s: OPT = %02x\n", machine().describe_context(), m_opt);
}
u8 pickytlk_base_state::ki_r()
{
if (BIT(m_io_buttons->read(), 6))
{
if (m_pen_state == PEN_RELEASE)
{
m_pen_state = PEN_PRESS;
// FIXME: Adjust delay when more accurate instruction timings are implemented.
// Program code waits for input flag to be stable by executing `mov DSIZE,0xff`
// then `movq R00,R00` 15 times (see pickytlk ROM @ 2015f6).
m_io_timer->adjust(attotime::from_msec(20), 0, attotime::never);
}
}
else
{
m_pen_state = PEN_RELEASE;
m_io_timer->reset(attotime::never);
}
return m_pen_state == PEN_PRESS ? 0x80 : 0;
}
u8 pickytlk_base_state::in0_r()
{
// battery level?
// bit4 -> if reset CPU keeps restarting (several unknown instructions before jumping to 0)
// perhaps a battery present check?
// bit 5 -> 0 = low battery
// --XX ---- VDET
// ---- -X-- data-in
return 0x30 & ~0x00;
}
u8 pickytlk_base_state::input_flag_read()
{
return m_pen_state == PEN_PRESS || m_pen_state == PEN_HOLD ? 0 : 1;
}
void pickytlk_base_state::pickytlk_layout(machine_config &config)
{
// Nothing (overriden by each system)
}
void pickytlk_base_state::update_crosshair(screen_device &screen)
{
// Either screen crosshair or layout view's cursor should be visible at a time.
machine().crosshair().get_crosshair(0).set_screen(m_pen_target ? CROSSHAIR_SCREEN_NONE : &screen);
}
u32 pickytlk_base_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
update_crosshair(screen);
u16 offset = 0;
for (int i = 0; i < 16; i++)
{
int const x = i * 8;
for (int j = 0; j < 64; j++)
{
u16 *const row = &bitmap.pix(63 - j);
u8 const data1 = m_display_ram[offset];
u8 const data2 = m_display_ram[offset + 0x400];
for (int b = 0; b < 8; b++)
{
if (x + b < 127)
{
row[x + b] = (BIT(data1, b) << 1) | BIT(data2, b);
}
}
offset++;
}
}
return 0;
}
static INPUT_PORTS_START(pickytlk)
// TODO: On/Off/Reset
PORT_START("BUTTONS")
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("Pen Down")
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(FUNC(pickytlk_base_state::pen_target_r))
PORT_START("PEN_X")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(30) PORT_KEYDELTA(10) PORT_MINMAX(0, 255) PORT_PLAYER(1) PORT_NAME("Pen X")
PORT_START("PEN_Y")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(30) PORT_KEYDELTA(10) PORT_MINMAX(0, 255) PORT_PLAYER(1) PORT_NAME("Pen Y") PORT_CROSSHAIR_MAPPER_MEMBER(FUNC(pickytlk_base_state::pen_y_mapper))
PORT_START("PEN_Y_RESCALE")
PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(FUNC(pickytlk_base_state::pen_y_rescale_r))
INPUT_PORTS_END
void pickytlk_base_state::pickytlk(machine_config &config)
{
HCD62121(config, m_maincpu, 4300000); /* X1 - 4.3 MHz */
m_maincpu->kol_cb().set(FUNC(pickytlk_base_state::kol_w));
m_maincpu->koh_cb().set(FUNC(pickytlk_base_state::koh_w));
m_maincpu->port_cb().set(FUNC(pickytlk_base_state::port_w));
m_maincpu->opt_cb().set(FUNC(pickytlk_base_state::opt_w));
m_maincpu->ki_cb().set(FUNC(pickytlk_base_state::ki_r));
m_maincpu->in0_cb().set(FUNC(pickytlk_base_state::in0_r));
m_maincpu->input_flag_cb().set(FUNC(pickytlk_base_state::input_flag_read));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
screen.set_refresh_hz(60);
screen.set_size(127, 64);
screen.set_visarea(0, 126, 0, 63);
screen.set_screen_update(FUNC(pickytlk_base_state::screen_update));
screen.set_palette("palette");
pickytlk_layout(config);
}
class pickytlk_monocolor_state : public pickytlk_base_state
{
public:
pickytlk_monocolor_state(const machine_config &mconfig, device_type type, const char *tag)
: pickytlk_base_state(mconfig, type, tag)
{ }
void pickytlk_monocolor(machine_config &config);
private:
virtual u8 tablet_read(offs_t offset) override;
virtual void pickytlk_layout(machine_config &config) override;
void pickytlk_mem(address_map &map);
void pickytlk_palette(palette_device &palette) const;
};
void pickytlk_monocolor_state::pickytlk_layout(machine_config &config)
{
config.set_default_layout(layout_pickytlk);
}
u8 pickytlk_monocolor_state::tablet_read(offs_t offset)
{
LOGMASKED(LOG_TABLET, "%s: tablet_read [%02x] = %02x\n", machine().describe_context(), offset, m_io_tablet_regs[offset]);
if (BIT(offset, 0))
{
u8 y = BIT(m_ko, 3) ? io_pen_y_read() : 0;
LOGMASKED(LOG_TABLET, "%s: pen y = %02x\n", machine().describe_context(), y);
return BIT(m_ko, 0) ? y : (0xff - y);
}
else
{
u8 x = BIT(m_ko, 2) ? io_pen_x_read() : 0;
LOGMASKED(LOG_TABLET, "%s: pen x = %02x\n", machine().describe_context(), x);
return BIT(m_ko, 0) ? x : (0xff - x);
}
}
void pickytlk_monocolor_state::pickytlk_mem(address_map &map)
{
map(0x000000, 0x00bfff).rom();
// map(0x040000, 0x04ffff) // Unknown
map(0x080000, 0x0807ff).ram();
// map(0x100000, 0x10ffff) // Unknown
map(0x200000, 0x2fffff).rom().region("mask_rom", 0);
map(0x400000, 0x4007ff).ram().share("display_ram");
map(0x400800, 0x41ffff).ram();
// Read after pen callibration
map(0x800030, 0x80003f).rw(FUNC(pickytlk_monocolor_state::tablet_read), FUNC(pickytlk_monocolor_state::tablet_write));
// Read before pen callibration
map(0x800040, 0x80004f).rw(FUNC(pickytlk_monocolor_state::tablet_read), FUNC(pickytlk_monocolor_state::tablet_write));
// map(0xe00000, 0xe0ffff) // LCD I/O
}
void pickytlk_monocolor_state::pickytlk_palette(palette_device &palette) const
{
palette.set_pen_color(0, 0xee, 0xee, 0xcc);
palette.set_pen_color(1, 0x11, 0x11, 0x11);
palette.set_pen_color(2, 0x11, 0x11, 0x11);
palette.set_pen_color(3, 0x11, 0x11, 0x11);
}
void pickytlk_monocolor_state::pickytlk_monocolor(machine_config &config)
{
pickytlk_base_state::pickytlk(config);
m_maincpu->set_addrmap(AS_PROGRAM, &pickytlk_monocolor_state::pickytlk_mem);
// TODO: Verify palette. Colors can be changed by changing the contrast.
PALETTE(config, "palette", FUNC(pickytlk_monocolor_state::pickytlk_palette), 4);
}
class pickytlk_multicolor_state : public pickytlk_base_state
{
public:
pickytlk_multicolor_state(const machine_config &mconfig, device_type type, const char *tag)
: pickytlk_base_state(mconfig, type, tag)
{ }
void pickytlk_multicolor(machine_config &config);
private:
virtual u8 tablet_read(offs_t offset) override;
virtual void pickytlk_layout(machine_config &config) override;
void pickytlk_mem(address_map &map);
void pickytlk_palette(palette_device &palette) const;
};
void pickytlk_multicolor_state::pickytlk_layout(machine_config &config)
{
config.set_default_layout(layout_pickytlk);
}
u8 pickytlk_multicolor_state::tablet_read(offs_t offset)
{
/*
Pen coordinates can return a mirrored value when bit 4 is not set.
@ -268,82 +524,20 @@ u8 pickytlk_state::tablet_read(offs_t offset)
}
}
void pickytlk_state::tablet_write(offs_t offset, u8 data)
void pickytlk_multicolor_state::pickytlk_mem(address_map &map)
{
LOGMASKED(LOG_TABLET, "%s: tablet_write [%02x] = %02x\n", machine().describe_context(), offset, data);
m_io_tablet_regs[offset] = data;
map(0x000000, 0x007fff).rom();
map(0x080000, 0x0807ff).ram();
map(0x080300, 0x08030f).rw(FUNC(pickytlk_multicolor_state::tablet_read), FUNC(pickytlk_multicolor_state::tablet_write));
// map(0x100000, 0x10ffff) // Unknown
// map(0x110000, 0x11ffff) // LCD I/O
map(0x200000, 0x2fffff).rom().region("mask_rom", 0);
map(0x400000, 0x4007ff).ram().share("display_ram");
map(0x400800, 0x41ffff).ram();
// map(0xe10000, 0xe1ffff) // LCD I/O
}
void pickytlk_state::kol_w(u8 data)
{
m_ko = (m_ko & 0xff00) | data;
LOGMASKED(LOG_IO, "%s: KO = %04x\n", machine().describe_context(), m_ko);
}
void pickytlk_state::koh_w(u8 data)
{
m_ko = (m_ko & 0x00ff) | (u16(data) << 8);
LOGMASKED(LOG_IO, "%s: KO = %04x\n", machine().describe_context(), m_ko);
}
void pickytlk_state::port_w(u8 data)
{
m_port = data;
LOGMASKED(LOG_IO, "%s: PORT = %02x\n", machine().describe_context(), m_port);
}
void pickytlk_state::opt_w(u8 data)
{
m_opt = data;
LOGMASKED(LOG_IO, "%s: OPT = %02x\n", machine().describe_context(), m_opt);
}
u8 pickytlk_state::ki_r()
{
if (BIT(m_io_buttons->read(), 6))
{
if (m_pen_state == PEN_RELEASE)
{
m_pen_state = PEN_PRESS;
// FIXME: Adjust delay when more accurate instruction timings are implemented.
// Program code waits for input flag to be stable by executing `mov DSIZE,0xff`
// then `movq R00,R00` 15 times (see pickytlk ROM @ 2015f6).
m_io_timer->adjust(attotime::from_msec(1), 0, attotime::never);
}
}
else
{
m_pen_state = PEN_RELEASE;
m_io_timer->reset(attotime::never);
}
return m_pen_state == PEN_PRESS ? 0x80 : 0;
}
u8 pickytlk_state::in0_r()
{
// battery level?
// bit4 -> if reset CPU keeps restarting (several unknown instructions before jumping to 0)
// perhaps a battery present check?
// bit 5 -> 0 = low battery
// --XX ---- VDET
// ---- -X-- data-in
return 0x30 & ~0x00;
}
u8 pickytlk_state::input_flag_read()
{
return m_pen_state == PEN_HOLD ? 0 : 1;
}
void pickytlk_state::update_crosshair(screen_device &screen)
{
// Either screen crosshair or layout view's cursor should be visible at a time.
machine().crosshair().get_crosshair(0).set_screen(m_pen_target ? CROSSHAIR_SCREEN_NONE : &screen);
}
void pickytlk_state::pickytlk_palette(palette_device &palette) const
void pickytlk_multicolor_state::pickytlk_palette(palette_device &palette) const
{
palette.set_pen_color(0, 0xee, 0xee, 0xcc);
palette.set_pen_color(1, 0x11, 0x33, 0x99);
@ -351,92 +545,112 @@ void pickytlk_state::pickytlk_palette(palette_device &palette) const
palette.set_pen_color(3, 0xee, 0x77, 0x33);
}
u32 pickytlk_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
void pickytlk_multicolor_state::pickytlk_multicolor(machine_config &config)
{
update_crosshair(screen);
pickytlk_base_state::pickytlk(config);
u16 offset = 0;
m_maincpu->set_addrmap(AS_PROGRAM, &pickytlk_multicolor_state::pickytlk_mem);
for (int i = 0; i < 16; i++)
{
int const x = i * 8;
for (int j = 0; j < 64; j++)
{
u16 *const row = &bitmap.pix(63 - j);
u8 const data1 = m_display_ram[offset];
u8 const data2 = m_display_ram[offset + 0x400];
for (int b = 0; b < 8; b++)
{
if (x + b < 127)
{
row[x + b] = (BIT(data1, b) << 1) | BIT(data2, b);
}
}
offset++;
}
}
return 0;
// TODO: Verify palette. Colors can be changed by changing the contrast.
PALETTE(config, "palette", FUNC(pickytlk_multicolor_state::pickytlk_palette), 4);
}
static INPUT_PORTS_START(pickytlk)
// TODO: On/Off/Reset
PORT_START("BUTTONS")
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("Pen Down")
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(FUNC(pickytlk_state::pen_target_r))
PORT_START("PEN_X")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(30) PORT_KEYDELTA(10) PORT_MINMAX(0, 255) PORT_PLAYER(1) PORT_NAME("Pen X")
PORT_START("PEN_Y")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(30) PORT_KEYDELTA(10) PORT_MINMAX(0, 255) PORT_PLAYER(1) PORT_NAME("Pen Y") PORT_CROSSHAIR_MAPPER_MEMBER(FUNC(pickytlk_state::pen_y_mapper))
PORT_START("PEN_Y_RESCALE")
PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(FUNC(pickytlk_state::pen_y_rescale_r))
INPUT_PORTS_END
void pickytlk_state::pickytlk(machine_config &config)
class plets_state : public pickytlk_multicolor_state
{
HCD62121(config, m_maincpu, 4300000); /* X1 - 4.3 MHz */
m_maincpu->set_addrmap(AS_PROGRAM, &pickytlk_state::pickytlk_mem);
m_maincpu->kol_cb().set(FUNC(pickytlk_state::kol_w));
m_maincpu->koh_cb().set(FUNC(pickytlk_state::koh_w));
m_maincpu->port_cb().set(FUNC(pickytlk_state::port_w));
m_maincpu->opt_cb().set(FUNC(pickytlk_state::opt_w));
m_maincpu->ki_cb().set(FUNC(pickytlk_state::ki_r));
m_maincpu->in0_cb().set(FUNC(pickytlk_state::in0_r));
m_maincpu->input_flag_cb().set(FUNC(pickytlk_state::input_flag_read));
public:
plets_state(const machine_config &mconfig, device_type type, const char *tag)
: pickytlk_multicolor_state(mconfig, type, tag)
{ }
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
screen.set_refresh_hz(60);
screen.set_size(127, 64);
screen.set_visarea(0, 126, 0, 63);
screen.set_screen_update(FUNC(pickytlk_state::screen_update));
screen.set_palette("palette");
private:
virtual void pickytlk_layout(machine_config &config) override;
};
// TODO: Verify amount of colors and palette. Colors can be changed by changing the contrast.
PALETTE(config, "palette", FUNC(pickytlk_state::pickytlk_palette), 4);
config.set_default_layout(layout_pickytlk);
void plets_state::pickytlk_layout(machine_config &config)
{
// Nothing
}
#define CPU_ROM_MONOCOLOR \
ROM_REGION(0xc000, "maincpu", 0) \
ROM_LOAD("cpu.lsi1", 0x0000, 0xc000, CRC(67c76253) SHA1(2f7d368e584608d0ed3135159c36f35f02cdd8c4))
#define CPU_ROM_MULTICOLOR \
ROM_REGION(0x8000, "maincpu", 0) \
ROM_LOAD("cpu.lsi1", 0x0000, 0x8000, CRC(d58efff9) SHA1(a8d2c2a331d79c5299274e2f2d180deda60a5aed))
ROM_START(jd363)
CPU_ROM_MONOCOLOR
ROM_REGION(0x100000, "mask_rom", 0)
ROM_LOAD("d23c8000lwgx-c11.lsi5", 0x00000, 0x100000, CRC(d4c6e7d2) SHA1(ef199725f04da977cd47293dba8086011f156baf))
ROM_END
ROM_START(pickydis)
CPU_ROM_MONOCOLOR
ROM_REGION(0x100000, "mask_rom", 0)
ROM_LOAD("d23c8000lwgx-c14.lsi5", 0x00000, 0x100000, CRC(1a6273c7) SHA1(f0601873503272d9a620789b5c9798f6e1baf4e7))
ROM_END
ROM_START(jd364)
CPU_ROM_MULTICOLOR
ROM_REGION(0x100000, "mask_rom", 0)
ROM_LOAD("d23c8000lwgx-c12.lsi5", 0x00000, 0x100000, CRC(c023b709) SHA1(0c081a62f00d0fbee496a5c9067fb145cb79c8cd))
ROM_END
ROM_START(jd368)
CPU_ROM_MULTICOLOR
ROM_REGION(0x100000, "mask_rom", 0)
ROM_LOAD("d23c8000xgx-c42.lsi5", 0x00000, 0x100000, CRC(c396bafb) SHA1(0d5610d288ab2474017c05ed54fc816d2e82525f))
ROM_END
ROM_START(pickytlk)
ROM_REGION(0x8000, "maincpu", 0)
ROM_LOAD("cpu.lsi1", 0x0000, 0x8000, CRC(d58efff9) SHA1(a8d2c2a331d79c5299274e2f2d180deda60a5aed))
CPU_ROM_MULTICOLOR
ROM_REGION(0x100000, "mask_rom", 0)
ROM_LOAD("d23c8000xgx-c64.lsi5", 0x00000, 0x100000, CRC(6ed6feae) SHA1(f9a63db3d048da0954cab052690deb01ec384b22))
ROM_END
ROM_START(mk300)
CPU_ROM_MULTICOLOR
ROM_REGION(0x100000, "mask_rom", 0)
ROM_LOAD("d23c8000xgx-c77.lsi5", 0x00000, 0x100000, CRC(50ecb853) SHA1(5f2564ccb6ff7e0e5a21064ca32626f35dc81506))
ROM_END
ROM_START(mk350)
CPU_ROM_MULTICOLOR
ROM_REGION(0x100000, "mask_rom", 0)
ROM_LOAD("m538032e-48.lsi5", 0x00000, 0x100000, CRC(42068a99) SHA1(24f8dc15a51a391d4c35cce7332d55f1fa4d8160))
ROM_END
} // anonymous namespace
// "CASIO スーパーピッキートーク「グルタンの森」はやわかりビデオ" has copyright dates 1997,1998,1999
COMP(1997, pickytlk, 0, 0, pickytlk, pickytlk, pickytlk_state, empty_init, "Casio", "Super Picky Talk - Forest of Gurutan", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)
// Release date 1995-09 from "Casio Game Perfect Catalogue"
COMP(1995, jd363, 0, 0, pickytlk_monocolor, pickytlk, pickytlk_monocolor_state, empty_init, "Casio", "Picky Talk - Super Denshi Techou", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)
// ROM date 9539K7001
COMP(1995?, pickydis, 0, 0, pickytlk_monocolor, pickytlk, pickytlk_monocolor_state, empty_init, "Tsukuda Original", "Disney Characters - Tegaki Electronic Note", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)
// Release date 1995-10 from "Casio Game Perfect Catalogue"
COMP(1995, jd364, 0, 0, pickytlk_multicolor, pickytlk, pickytlk_multicolor_state, empty_init, "Casio", "Color Picky Talk - Super Denshi Techou", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)
// ROM date 9737K7041
COMP(1997?, jd368, 0, 0, pickytlk_multicolor, pickytlk, pickytlk_multicolor_state, empty_init, "Casio", "Super Picky Talk - Access Pet", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)
// Release date 1998-07 from "Casio Game Perfect Catalogue"
COMP(1998, pickytlk, 0, 0, pickytlk_multicolor, pickytlk, pickytlk_multicolor_state, empty_init, "Casio", "Super Picky Talk - Forest of Gurutan", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)
// Release date 1999-09 from "Casio Game Perfect Catalogue"
COMP(1999, mk300, 0, 0, pickytlk_multicolor, pickytlk, plets_state, empty_init, "Casio", "Plet's (MK-300)", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)
// ROM date 0019K7001
COMP(2000?, mk350, 0, 0, pickytlk_multicolor, pickytlk, plets_state, empty_init, "Casio", "Plet's (MK-350)", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)

View File

@ -16138,7 +16138,13 @@ pb1000 // Casio PB-1000
pb2000c // Casio PB-2000C
@source:casio/pickytlk.cpp
pickytlk // Casio Picky Talk
jd363 // Casio Picky Talk - Super Denshi Techou
jd364 // Casio Color Picky Talk - Super Denshi Techou
jd368 // Casio Super Picky Talk - Access Pet
mk300 // Casio Plet's (MK-300)
mk350 // Casio Plet's (MK-350)
pickydis // Tsukuda Original Disney Characters - Tegaki Electronic Note
pickytlk // Casio Super Picky Talk - Forest of Gurutan
@source:casio/pv1000.cpp
pv1000 // Casio PV-1000