f2mc16: More opcodes and more robust IRQ handling [R. Belmont]

mb9061x: Implemented timers 0 and 1, including external event counter mode [R. Belmont]
This commit is contained in:
arbee 2019-08-27 15:11:42 -04:00
parent 8b78bdff01
commit 61c288efdb
6 changed files with 641 additions and 48 deletions

View File

@ -225,6 +225,8 @@ void f2mc16_device::execute_run()
}
}
//m_icount--;
u8 opcode = read_8((m_pcb<<16) | m_pc);
debugger_instruction_hook((m_pcb<<16) | m_pc);
@ -319,8 +321,14 @@ void f2mc16_device::execute_run()
m_icount -= 2;
break;
// NEGW A
case 0x0b:
// stream << "NEGW A";
m_tmp32 = doSUB_32(0, m_acc&0xffff);
m_acc &= 0xffff0000;
m_acc |= m_tmp32 & 0xffff;
setNZ_16(m_acc & 0xffff);
m_pc++;
m_icount -= 2;
break;
// LSLW A
@ -516,8 +524,11 @@ void f2mc16_device::execute_run()
// stream << "ADDC A";
break;
// CMP A
case 0x23:
// stream << "CMP A";
doCMP_16(m_acc>>16, m_acc&0xffff);
m_pc++;
m_icount--;
break;
// AND CCR, #imm8
@ -633,12 +644,24 @@ void f2mc16_device::execute_run()
m_pc++;
break;
// ADD A, #imm8
case 0x30:
// util::stream_format(stream, "ADD A, #$%02x", operand);
m_tmp8 = read_8((m_pcb<<16) | (m_pc+1));
m_tmp8 = doADD_8(m_acc & 0xff, m_tmp8);
m_acc &= ~0xff;
m_acc |= m_tmp8;
m_pc += 2;
m_icount -= 2;
break;
// SUB A, #imm8
case 0x31:
// util::stream_format(stream, "SUB A, #$%02x", operand);
m_tmp8 = read_8((m_pcb<<16) | (m_pc+1));
m_tmp8 = doSUB_8(m_acc & 0xff, m_tmp8);
m_acc &= ~0xff;
m_acc |= m_tmp8;
m_pc += 2;
m_icount -= 2;
break;
case 0x32:
@ -700,8 +723,14 @@ void f2mc16_device::execute_run()
m_icount -= 2;
break;
// SUBW A, #imm16
case 0x39:
// util::stream_format(stream, "SUBW A, #$%04x", opcodes.r16(pc+1));
m_tmp16 = read_16((m_pcb<<16) | (m_pc+1));
m_tmp16 = doSUB_16(m_acc & 0xffff, m_tmp16);
m_acc &= 0xffff0000;
m_acc |= m_tmp16;
m_pc += 3;
m_icount -= 2;
break;
// CWBNE A, #imm16, disp8
@ -750,6 +779,16 @@ void f2mc16_device::execute_run()
m_icount -= 2;
break;
// XORW A, #imm16
case 0x3e:
m_tmp16 = read_16((m_pcb<<16) | (m_pc+1));
m_acc ^= m_tmp16;
setNZ_16(m_acc & 0xffff);
m_ps &= ~F_V;
m_pc += 3;
m_icount -= 2;
break;
// NOTW A
case 0x3f:
m_acc ^= 0xffff;
@ -1002,7 +1041,7 @@ void f2mc16_device::execute_run()
// POPW register list
case 0x5f:
m_tmp8 = read_8((m_pcb<<16) | (m_pc+1));
for (int i = 7; i <= 0; i--)
for (int i = 7; i >= 0; i--)
{
if (m_tmp8 & (1<<i))
{
@ -1064,41 +1103,48 @@ void f2mc16_device::execute_run()
// RETI
case 0x6b:
// there's an IRQ chaining facility, let's do it
if (m_outstanding_irqs)
{
int cpulevel = m_ps >> 13;
bool bFoundVec = false;
for (int irq = 0; irq < 256; irq++)
// there's an IRQ chaining facility, let's do it
if (m_outstanding_irqs)
{
if (m_vector_level[irq] < cpulevel)
int cpulevel = peek_stack_16() >> 13;
for (int irq = 0; irq < 256; irq++)
{
m_ps = read_16((m_ssb << 16) | m_ssp);
m_ps |= F_S;
m_ps &= ~0x7000;
m_ps |= (m_vector_level[irq] & 7) << 13;
if (m_vector_level[irq] < cpulevel)
{
m_ps = read_16((m_ssb << 16) | m_ssp);
m_ps |= F_S;
m_ps &= ~0x7000;
m_ps |= (m_vector_level[irq] & 7) << 13;
u32 uVecAddr = 0xfffffc - (irq * 4);
m_pc = read_16(uVecAddr);
m_pcb = read_8(uVecAddr + 2);
break;
u32 uVecAddr = 0xfffffc - (irq * 4);
m_pc = read_16(uVecAddr);
m_pcb = read_8(uVecAddr + 2);
bFoundVec = true;
printf("RETI vector chain to %02x%04x\n", m_pcb, m_pc);
break;
}
}
}
}
else
{
m_ps = pull_16_ssp();
m_pc = pull_16_ssp();
m_tmp16 = pull_16_ssp();
m_pcb = m_tmp16 & 0xff;
m_dtb = m_tmp16 >> 8;
m_tmp16 = pull_16_ssp();
m_adb = m_tmp16 & 0xff;
m_dpr = m_tmp16 >> 8;
m_acc = 0;
m_acc = pull_16_ssp();
m_acc |= (pull_16_ssp() << 16);
m_icount -= 17;
// if no new IRQ was found or could be dispatched by the level
if (!bFoundVec)
{
m_ps = pull_16_ssp();
m_pc = pull_16_ssp();
m_tmp16 = pull_16_ssp();
m_pcb = m_tmp16 & 0xff;
m_dtb = m_tmp16 >> 8;
m_tmp16 = pull_16_ssp();
m_adb = m_tmp16 & 0xff;
m_dpr = m_tmp16 >> 8;
m_acc = 0;
m_acc = pull_16_ssp();
m_acc |= (pull_16_ssp() << 16);
m_icount -= 17;
}
}
break;
@ -1566,6 +1612,23 @@ void f2mc16_device::opcodes_bo6c(u8 operand)
m_icount -= 7;
break;
// BBC dir8, bit, disp8
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
m_tmp32 = read_8((m_pcb<<16) | (m_pc+2));
m_tmp32 |= (m_dpr<<8) | (m_dtb<<8);
m_tmp8 = read_8(m_tmp32);
m_tmp8 = read_8((m_pcb << 16) | (m_pc + 4));
m_ps &= ~F_Z;
m_pc += 4;
if (!(read_8(m_tmp32) & (1 << (operand & 7))))
{
m_ps |= F_Z;
m_pc += (s8)m_tmp8;
m_icount--;
}
m_icount -= 7;
break;
// BBC adr16, bit, disp8
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
m_tmp16 = read_16((m_pcb << 16) | (m_pc + 2));
@ -1823,6 +1886,29 @@ void f2mc16_device::opcodes_2b6f(u8 operand)
m_icount -= 1;
break;
// LSLL A, R0
case 0x1c:
m_tmp8 = read_rX(0);
m_icount -= 6; // 6 cycles base
if (m_tmp8 == 0)
{
m_ps &= ~F_C;
}
else
{
m_icount -= 6;
for (u8 count = 0; count < m_tmp8; count++)
{
m_ps &= ~F_C;
m_ps |= (m_acc & 0x80000000) ? F_C : 0;
m_acc <<= 1;
m_icount --; // 1 additional cycle per iteration
}
setNZ_32(m_acc);
}
m_pc += 2;
break;
// MOV @RLx + #disp8, A
case 0x30: case 0x32: case 0x34: case 0x36:
m_tmp8 = read_8((m_pcb<<16) | (m_pc+2));
@ -1932,7 +2018,7 @@ void f2mc16_device::opcodes_ea70(u8 operand)
m_acc &= m_tmp32;
setNZ_32(m_acc);
m_ps &= ~F_V;
m_pc += 3;
m_pc += 2;
m_icount -= 7;
break;
@ -1970,6 +2056,21 @@ void f2mc16_device::opcodes_ea71(u8 operand)
m_icount -= 11;
break;
// INCL RLx
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
m_tmp64 = read_rlX((operand>>1) & 3);
m_tmp64++;
write_rlX((operand>>1) & 3, m_tmp64&0xffffffff);
setNZ_32(m_tmp64 & 0xffffffff);
m_ps &= ~F_V;
if (m_tmp64 & 0x100000000)
{
m_ps |= F_V;
}
m_pc += 2;
m_icount -= 7;
break;
// INCL @RWx + disp8
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
m_tmp8 = read_8((m_pcb<<16) | (m_pc+2));
@ -2070,6 +2171,17 @@ void f2mc16_device::opcodes_ea71(u8 operand)
m_icount -= 2;
break;
// MOVEA A, @RWx + disp8
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
m_acc <<= 16;
m_tmp8 = read_8((m_pcb<<16) | (m_pc+2));
m_tmp16 = read_rwX(operand & 7);
m_tmp16 += (s8)m_tmp8;
m_acc |= m_tmp16;
m_pc += 3;
m_icount -= 1;
break;
default:
fatalerror("Unknown F2MC EA71 opcode %02x (PC=%x)\n", operand, (m_pcb<<16) | m_pc);
break;
@ -2145,6 +2257,31 @@ void f2mc16_device::opcodes_ea73(u8 operand)
m_icount -= 5;
break;
// INCW addr16
case 0x5f:
m_tmp32 = read_16((m_pcb<<16) | (m_pc+2));
if (m_prefix_valid)
{
m_prefix_valid = false;
m_tmp32 |= (m_prefix << 16);
}
else
{
m_tmp32 |= (m_dtb << 16);
}
m_tmp32aux = read_16(m_tmp32);
m_tmp32aux++;
write_16(m_tmp32, m_tmp32aux & 0xffff);
setNZ_16(m_tmp32aux & 0xffff);
m_ps &= ~F_V;
if (m_tmp32aux & 0x10000)
{
m_ps |= F_V;
}
m_pc += 4;
m_icount -= 5;
break;
// DECW addr16
case 0x7f:
m_tmp32 = read_16((m_pcb<<16) | (m_pc+2));
@ -2171,6 +2308,16 @@ void f2mc16_device::opcodes_ea73(u8 operand)
m_icount -= 5;
break;
// MOVW @RWx + disp8, #imm16
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
m_tmp8 = read_16((m_pcb<<16) | (m_pc+2));
m_tmp16 = read_16((m_pcb<<16) | (m_pc+3));
m_tmpea = read_rwX(operand & 7) + (s8)m_tmp8;
write_16(getRWbank(operand & 7, m_tmpea), m_tmp16);
m_pc += 5;
m_icount -= 4;
break;
// MOVW @RWx + disp16, #imm16
case 0xd8: case 0xd9: case 0xda: case 0xdb:
m_tmp16 = read_16((m_pcb<<16) | (m_pc+2));
@ -2218,6 +2365,31 @@ void f2mc16_device::opcodes_ea74(u8 operand)
m_icount -= 10;
break;
// DBNZ Rx, disp8
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
m_tmp16 = read_rX(operand & 7);
m_tmp16aux = m_tmp16;
m_tmp16--;
write_rX(operand & 7, m_tmp16 & 0xff);
setNZ_8(m_tmp16 & 0xff);
m_ps &= ~F_V;
if ((m_tmp16aux ^ 0x01) & (m_tmp16aux ^ m_tmp16) & 0x80)
{
m_ps |= F_V;
}
if (m_tmp16 & 0xff)
{
m_tmp8 = read_8((m_pcb<<16) | (m_pc+2));
m_pc = (m_pc + 3) + (s8)m_tmp8;
m_icount -= 7;
}
else
{
m_pc += 3;
m_icount -= 6;
}
break;
default:
fatalerror("Unknown F2MC EA74 opcode %02x (PC=%x)\n", operand, (m_pcb<<16) | m_pc);
break;
@ -2247,6 +2419,18 @@ void f2mc16_device::opcodes_ea76(u8 operand)
m_icount -= 3;
break;
// ADDW A, @RWx + disp8
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
m_tmp8 = read_8((m_pcb<<16) | (m_pc+2));
m_tmp16 = read_rwX(operand & 7) + (s8)m_tmp8;
m_tmp16 = read_16(getRWbank(operand & 7, m_tmp16));
m_tmp16aux = doADD_16(m_acc & 0xffff, m_tmp16);
m_acc &= 0xffff0000;
m_acc |= m_tmp16aux;
m_pc += 3;
m_icount -= 3;
break;
// SUBW A, RWx
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
m_tmp16 = doSUB_16(m_acc & 0xffff, read_rwX(operand & 7));
@ -2256,6 +2440,18 @@ void f2mc16_device::opcodes_ea76(u8 operand)
m_icount -= 3;
break;
// SUBW A, @RWx + disp8
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
m_tmp8 = read_8((m_pcb<<16) | (m_pc+2));
m_tmp16 = read_rwX(operand & 7) + (s8)m_tmp8;
m_tmp16 = read_16(getRWbank(operand & 7, m_tmp16));
m_tmp16aux = doSUB_16(m_acc & 0xffff, m_tmp16);
m_acc &= 0xffff0000;
m_acc |= m_tmp16aux;
m_pc += 3;
m_icount -= 3;
break;
// CMPW A, RWx
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
doCMP_16(m_acc & 0xffff, read_rwX(operand & 7));
@ -2283,6 +2479,18 @@ void f2mc16_device::opcodes_ea76(u8 operand)
m_icount -= 4;
break;
// ORW A, @RWx + disp8
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
m_tmp8 = read_8((m_pcb<<16) | (m_pc+2));
m_tmp16 = read_rwX(operand & 7) + (s8)m_tmp8;
m_tmp16 = read_16(getRWbank(operand & 7, m_tmp16));
m_acc |= m_tmp16;
setNZ_16(m_acc & 0xffff);
m_ps &= ~F_V;
m_pc += 3;
m_icount -= 3;
break;
default:
fatalerror("Unknown F2MC EA76 opcode %02x (PC=%x)\n", operand, (m_pcb<<16) | m_pc);
break;
@ -2303,6 +2511,22 @@ void f2mc16_device::opcodes_ea78(u8 operand)
{
switch (operand)
{
// MULUW A, RWx
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
m_tmp16 = read_rwX(operand & 7);
if (m_tmp16 == 0)
{
m_icount -= 4;
m_acc = 0;
}
else
{
m_icount -= 12;
m_acc = m_tmp16 * (m_acc & 0xffff);
}
m_pc += 2;
break;
// MULUW A, @RWx + disp8
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
m_tmp8 = read_8((m_pcb<<16) | (m_pc+2));
@ -2311,7 +2535,7 @@ void f2mc16_device::opcodes_ea78(u8 operand)
if (m_tmp16 == 0)
{
m_icount -= 4;
m_acc <<= 16;
m_acc = 0;
}
else
{
@ -2333,22 +2557,28 @@ void f2mc16_device::execute_set_input(int inputnum, int state)
void f2mc16_device::set_irq(int vector, int level)
{
m_outstanding_irqs++;
m_vector_level[vector] = level;
//printf("set_irq: vec %d level %d\n", vector, level);
if (m_vector_level[vector] != level)
{
m_outstanding_irqs++;
m_vector_level[vector] = level;
// printf("set_irq: vec %d, level %d, %d outstanding\n", vector, level, m_outstanding_irqs);
}
}
void f2mc16_device::clear_irq(int vector)
{
m_outstanding_irqs--;
m_vector_level[vector] = 7;
//printf("clear_irq: vec %d\n", vector);
if (m_vector_level[vector] < 7)
{
m_outstanding_irqs--;
m_vector_level[vector] = 7;
//printf("clear_irq: vec %d, %d outstanding\n", vector, m_outstanding_irqs);
}
}
// note: this function must not use m_tmp16 unless you change RETI
void f2mc16_device::take_irq(int vector, int level)
{
//printf("take_irq: vector %d, level %d, old PC = %02x%04x\n", vector, level, m_pcb, m_pc);
// printf("take_irq: vector %d, level %d, old PC = %02x%04x\n", vector, level, m_pcb, m_pc);
push_16_ssp(m_acc>>16);
push_16_ssp(m_acc & 0xffff);
push_16_ssp((m_dpr<<8) | m_adb);
@ -2357,11 +2587,11 @@ void f2mc16_device::take_irq(int vector, int level)
push_16_ssp(m_ps);
m_ps |= F_S;
m_ps &= ~0x7000;
m_ps &= ~0xe000;
m_ps |= (level & 7) << 13;
u32 uVecAddr = 0xfffffc - (vector * 4);
m_pc = read_16(uVecAddr);
m_pcb = read_8(uVecAddr + 2);
//printf("New PC = %02x%04x\n", m_pcb, m_pc);
//printf("New PC = %02x%04x, new level=%d\n", m_pcb, m_pc, m_ps>>13);
}

View File

@ -67,7 +67,7 @@ private:
u16 m_pc, m_usp, m_ssp, m_ps, m_tmp16, m_tmpea, m_tmp16aux;
u8 m_pcb, m_dtb, m_usb, m_ssb, m_adb, m_dpr, m_tmp8, m_prefix;
u32 m_acc, m_temp, m_tmp32;
u32 m_acc, m_temp, m_tmp32, m_tmp32aux;
s32 m_icount;
u64 m_tmp64;
bool m_prefix_valid;
@ -279,6 +279,21 @@ private:
return rv;
}
inline u16 peek_stack_16()
{
u16 rv = 0;
if (m_ps & F_S)
{
rv = read_16((m_ssb << 16) | m_ssp);
}
else
{
rv = read_16((m_usb << 16) | m_usp);
}
return rv;
}
inline u16 pull_16_ssp()
{
u16 rv = read_16((m_ssb << 16) | m_ssp);
@ -395,6 +410,22 @@ private:
return m_tmp64 & 0xffffffff;
}
inline u8 doADD_8(u8 lhs, u8 rhs)
{
m_tmp16 = lhs + rhs;
m_ps &= ~(F_C|F_V);
if ((m_tmp16 ^ lhs) & (m_tmp16 ^ rhs) & 0x80)
{
m_ps |= F_V;
}
if (m_tmp16 > 0xff)
{
m_ps |= F_C;
}
setNZ_8(m_tmp16 & 0xff);
return m_tmp16 & 0xff;
}
inline u16 doADD_16(u16 lhs, u16 rhs)
{
m_tmp32 = lhs + rhs;

View File

@ -396,6 +396,11 @@ offs_t f2mc16_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
bytes = 3;
break;
case 0x3e:
util::stream_format(stream, "XORW A, #$%04x", opcodes.r16(pc+1));
bytes = 3;
break;
case 0x3f:
stream << "NOTW A";
break;
@ -778,6 +783,20 @@ offs_t f2mc16_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
}
break;
case 0x8:
switch (operand & 0xf)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
util::stream_format(stream, "ANDL A, RL%d", (operand & 0x6)>>1);
bytes = 2;
break;
default:
stream << "UNK ea-type 70 8x";
break;
}
break;
default:
stream << "UNK ea-type 70";
break;
@ -792,6 +811,11 @@ offs_t f2mc16_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
bytes = ea_form1_helper_noA(stream, "CALLP @", pc, operand, opcodes.r16(pc+2));
break;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
util::stream_format(stream, "INCL RL%d", ((operand>>1) & 0x3));
bytes = 2;
break;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
util::stream_format(stream, "INCL @RW%d + #$%02x", (operand & 0x7), opcodes.r8(pc+2));
bytes = 3;
@ -887,6 +911,11 @@ offs_t f2mc16_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
bytes = 3;
break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
util::stream_format(stream, "MOVEA A, @RW%d + #$%02x", (operand & 0x7), opcodes.r8(pc+2));
bytes = 3;
break;
default:
stream << "UNK ea-type 71";
break;
@ -1069,6 +1098,11 @@ offs_t f2mc16_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
bytes = 4;
break;
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
util::stream_format(stream, "DBNZ R%d, $%04x", (operand & 0x7), (s8)opcodes.r8(pc+2) + (pc & 0xffff) + 3);
bytes = 3;
break;
default:
stream << "UNK ea-type 74";
break;
@ -1197,6 +1231,11 @@ offs_t f2mc16_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
bytes = 2;
break;
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
util::stream_format(stream, "ORW A, @RW%d + #$%02x", (operand & 0x7), opcodes.r8(pc+2));
bytes = 3;
break;
default:
stream << "UNK ea-type 76";
break;

View File

@ -42,6 +42,10 @@ void mb9061x_device::device_start()
m_tbtc_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb9061x_device::tbtc_tick), this));
m_tbtc_timer->adjust(attotime::never);
m_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb9061x_device::timer0_tick), this));
m_timer[0]->adjust(attotime::never);
m_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb9061x_device::timer1_tick), this));
m_timer[1]->adjust(attotime::never);
}
@ -59,6 +63,10 @@ device_memory_interface::space_config_vector mb9061x_device::memory_space_config
void mb9061x_device::device_reset()
{
f2mc16_device::device_reset();
m_tbtc = 0;
memset(m_timer_regs, 0, sizeof(m_timer_regs));
memset(m_event_count, 0, sizeof(m_event_count));
m_event_state[0] = m_event_state[1] = CLEAR_LINE;
}
void mb9061x_device::execute_set_input(int inputnum, int state)
@ -83,6 +91,220 @@ mb90610_device::mb90610_device(const machine_config &mconfig, device_type type,
{
}
/* 16-bit preload timers with event count function */
enum
{
TCTH_CSL1 = 0x08, // clock source select bit 1
TCTH_CSL0 = 0x04, // clock source select bit 0
TCTH_MOD2 = 0x02, // mode bit 2
TCTH_MOD1 = 0x01, // mode bit 1
TCTL_MOD0 = 0x80, // mode bit 0
TCTL_OUTE = 0x40, // output enable
TCTL_OUTL = 0x20, // output level
TCTL_RELD = 0x10, // reload
TCTL_INTE = 0x08, // IRQ enable
TCTL_UF = 0x04, // expire flag
TCTL_CNTE = 0x02, // enable counting
TCTL_TRG = 0x01 // force a reload and start counting
};
TIMER_CALLBACK_MEMBER(mb9061x_device::timer0_tick)
{
u8 ctl = m_timer_regs[0];
m_timer_regs[0] |= TCTL_UF;
if (ctl & TCTL_INTE)
{
// printf("timer 0 IRQ\n");
intc_trigger_irq(9, 0x1d);
}
if (ctl & TCTL_RELD)
{
recalc_timer(0);
m_timer[0]->adjust(attotime::from_hz(m_timer_hz[0]));
}
}
TIMER_CALLBACK_MEMBER(mb9061x_device::timer1_tick)
{
u8 ctl = m_timer_regs[4];
m_timer_regs[4] |= TCTL_UF;
if (ctl & TCTL_INTE)
{
// printf("timer 1 IRQ\n");
intc_trigger_irq(9, 0x1e);
}
if (ctl & TCTL_RELD)
{
recalc_timer(0);
m_timer[1]->adjust(attotime::from_hz(m_timer_hz[1]));
}
}
READ8_MEMBER(mb9061x_device::timer_r)
{
//printf("timer_r: offset %d = %02x\n", offset, m_timer_regs[offset]);
return m_timer_regs[offset];
}
WRITE8_MEMBER(mb9061x_device::timer_w)
{
int timer = offset / 4;
int reg = offset % 4;
//printf("timer_w: %x to %d\n", data, offset);
#if 0
switch (reg)
{
case 0: // control/status, lower
printf("%02x to timer %d lower control\n", data, timer);
break;
case 1: // control/status, upper
printf("%02x to timer %d upper control\n", data, timer);
break;
case 2: // timer/reload, lower
printf("%02x to timer %d lower reload\n", data, timer);
break;
case 3: // timer/reload, upper
printf("%02x to timer %d upper reload\n", data, timer);
break;
}
#endif
if (reg == 0)
{
m_timer_regs[offset] &= (TCTL_TRG|TCTL_UF);
m_timer_regs[offset] |= data;
}
else
{
m_timer_regs[offset] = data;
}
int rbase = timer << 2;
u8 csl = (m_timer_regs[rbase+1] >> 2) & 3;
if (reg == 0)
{
if (data & TCTL_TRG)
{
//printf("Got TRG\n");
recalc_timer(timer);
if ((m_timer_regs[rbase] & TCTL_CNTE) && (csl != 3))
{
m_timer[timer]->adjust(attotime::from_hz(m_timer_hz[timer]));
}
}
if ((data & TCTL_CNTE) && (csl != 3))
{
//printf("CNTE set, starting timer at %d Hz\n", m_timer_hz[timer]);
m_timer[timer]->adjust(attotime::from_hz(m_timer_hz[timer]));
}
if ((data & TCTL_CNTE) && (csl == 3))
{
m_event_count[timer] = m_timer_regs[2] | (m_timer_regs[3]<<8);
//printf("CNTE set in event counter mode, reseeding count to %04x\n", m_event_count[timer]);
}
if (!(data & TCTL_UF))
{
intc_clear_irq(9, 0x1d + timer);
}
}
}
WRITE_LINE_MEMBER(mb9061x_device::tin0_w)
{
tin_common(0, 0, state);
}
WRITE_LINE_MEMBER(mb9061x_device::tin1_w)
{
tin_common(1, 4, state);
}
void mb9061x_device::tin_common(int timer, int base, int state)
{
// emsure event counter mode
if ((m_timer_regs[base + 1] & (TCTH_CSL0|TCTH_CSL1)) == (TCTH_CSL0|TCTH_CSL1) &&
(m_timer_regs[base] & TCTL_CNTE))
{
bool bTickIt = false;
// rising edge
if ((state && !m_event_state[base/4]) && (m_timer_regs[base] & TCTL_MOD0) && !(m_timer_regs[base+1] & TCTH_MOD1))
{
bTickIt = true;
}
// falling edge
if ((!state && m_event_state[base/4]) && !(m_timer_regs[base] & TCTL_MOD0) && (m_timer_regs[base+1] & TCTH_MOD1))
{
bTickIt = true;
}
// any edge
if ((state != m_event_state[base/4]) && !(m_timer_regs[base] & TCTL_MOD0) && (m_timer_regs[base+1] & TCTH_MOD1))
{
bTickIt = true;
}
if (bTickIt)
{
m_event_count[timer]--;
//printf("Tick timer %d, new value %04x\n", timer, m_event_count[timer]);
if (m_event_count[timer] == 0xffff)
{
u8 ctl = m_timer_regs[base];
m_timer_regs[base] |= TCTL_UF;
if (ctl & TCTL_INTE)
{
//printf("timer %d IRQ\n", timer);
intc_trigger_irq(9, 0x1d + timer);
}
if (m_timer_regs[timer * 4] & TCTL_RELD)
{
m_event_count[timer] = m_timer_regs[2] | (m_timer_regs[3]<<8);
//printf("timer %d reload to %04x\n", timer, m_event_count[timer]);
}
}
}
m_event_state[timer] = state;
}
}
void mb9061x_device::recalc_timer(int tnum)
{
int rbase = tnum << 2;
u32 divider = 1;
u8 csl = (m_timer_regs[rbase+1] >> 2) & 3;
// check clock select
switch (csl)
{
case 0: divider = 2; break;
case 1: divider = 16; break;
case 2: divider = 64; break;
case 3: // event counter mode
return;
}
u32 tclk = clock() / divider;
u32 tval = m_timer_regs[rbase+2] | (m_timer_regs[rbase+3]<<8);
//printf("CSL %d, tclk %d, tval %d\n", csl, tclk, tval);
//printf("Timer is %d Hz\n", tclk / tval);
m_timer_hz[tnum] = tclk / tval;
}
/* TBTC: timebase counter */
enum
{
@ -182,6 +404,7 @@ void mb9061x_device::intc_clear_irq(int icr, int vector)
/* MB90611 - Production version of this series */
void mb90611_device::mb90611_map(address_map &map)
{
map(0x0038, 0x003f).rw(FUNC(mb9061x_device::timer_r), FUNC(mb9061x_device::timer_w));
map(0x00a9, 0x00a9).rw(FUNC(mb9061x_device::tbtc_r), FUNC(mb9061x_device::tbtc_w));
map(0x00b0, 0x00bf).rw(FUNC(mb9061x_device::intc_r), FUNC(mb9061x_device::intc_w));
map(0x0100, 0x04ff).ram(); // 1K of internal RAM from 0x100 to 0x500

View File

@ -31,6 +31,10 @@ public:
ICR0 = 0, ICR1, ICR2, ICR3, ICR4, ICR5, ICR6, ICR7, ICR8, ICR9, ICR10, ICR11, ICR12, ICR13, ICR14, ICR15
};
// timer external counter tick functions
DECLARE_WRITE_LINE_MEMBER(tin0_w);
DECLARE_WRITE_LINE_MEMBER(tin1_w);
protected:
// construction/destruction
mb9061x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal_map);
@ -53,6 +57,20 @@ private:
void intc_trigger_irq(int icr, int vector);
void intc_clear_irq(int icr, int vector);
// TIMERS
TIMER_CALLBACK_MEMBER(timer0_tick);
TIMER_CALLBACK_MEMBER(timer1_tick);
READ8_MEMBER(timer_r);
WRITE8_MEMBER(timer_w);
void recalc_timer(int tnum);
void tin_common(int timer, int base, int state);
u8 m_timer_regs[8];
u32 m_timer_hz[2];
emu_timer *m_timer[2];
int m_event_state[2];
u16 m_event_count[2];
u8 m_tbtc;
emu_timer *m_tbtc_timer;

View File

@ -5,11 +5,51 @@
Prin-C use a Fujitsu MB90611A MCU (F2MC-16L)
[:maincpu] ':maincpu' (FFC431): unmapped program memory write to 0000A1 = 00 & FF CKSCR
[:maincpu] ':maincpu' (FFC437): unmapped program memory write to 000048 = 04 & FF CS control 0 (Enable out, region is 1 MByte @ F00000)
[:maincpu] ':maincpu' (FFC43D): unmapped program memory write to 000049 = 04 & FF CS control 1 (Enable out, region is 1 MByte @ E00000)
[:maincpu] ':maincpu' (FFC443): unmapped program memory write to 00004A = 07 & FF CS control 2 (Enable out, region is 128 byte @ 68FF80)
[:maincpu] ':maincpu' (FFC449): unmapped program memory write to 00004B = 00 & FF CS control 3 (No out, region is reserved)
[:maincpu] ':maincpu' (FFC44F): unmapped program memory write to 0000A5 = D3 & FF ARSR (3 cycle wait state from addrs 002000 to 7FFFFF, 3 waits from C0 to FF, 1 cycle wait on addresses > 800000)
[:maincpu] ':maincpu' (FFC455): unmapped program memory write to 0000A6 = 00 & FF HACR ()
[:maincpu] ':maincpu' (FFC45B): unmapped program memory write to 0000A7 = 7F & FF ECSR
[:maincpu] ':maincpu' (FFC461): unmapped program memory write to 000011 = 00 & FF Port 1 DDR
[:maincpu] ':maincpu' (FFC467): unmapped program memory write to 000012 = FF & FF 2
[:maincpu] ':maincpu' (FFC46D): unmapped program memory write to 000013 = FF & FF 3
[:maincpu] ':maincpu' (FFC473): unmapped program memory write to 000014 = FF & FF 4
[:maincpu] ':maincpu' (FFC479): unmapped program memory write to 000015 = 01 & FF 5
[:maincpu] ':maincpu' (FFC47F): unmapped program memory write to 000016 = 1F & FF Analog input enable
[:maincpu] ':maincpu' (FFC485): unmapped program memory write to 000016 = E0 & FF 7
[:maincpu] ':maincpu' (FFC48B): unmapped program memory write to 000017 = 30 & FF 8
[:maincpu] ':maincpu' (FFC491): unmapped program memory write to 000018 = 0C & FF 9
[:maincpu] ':maincpu' (FFC497): unmapped program memory write to 00001A = FF & FF A
[:maincpu] ':maincpu' (FFC189): unmapped program memory write to 00000A = 00 & FF port A
[:maincpu] ':maincpu' (FFC257): unmapped program memory write to 00000A = 80 & FF port A
[:maincpu] ':maincpu' (FE2C08): unmapped program memory write to 0000A9 = 96 & FF TBTC - IRQ enabled, 16.384 ms timebase
[:maincpu] ':maincpu' (FE2C11): unmapped program memory write to 0000BB = 06 & FF ICR11 - level 6 interrupt, no intelligent I/O
[:maincpu] ':maincpu' (FE2959): unmapped program memory write to 000017 = 30 & FF port 7 DDR
[:maincpu] ':maincpu' (FE2963): unmapped program memory write to 0000A9 = 96 & FF TBTC
[:maincpu] ':maincpu' (FE296C): unmapped program memory write to 0000BB = 06 & FF ICR11
[:maincpu] ':maincpu' (FE29CC): unmapped program memory write to 000007 = 00 & FF port 7 out
[:maincpu] ':maincpu' (FE2A69): unmapped program memory write to 0000A9 = 96 & FF TBTC
[:maincpu] ':maincpu' (FE2A72): unmapped program memory write to 0000BB = 06 & FF ICR11
[:maincpu] ':maincpu' (FC2AD5): unmapped program memory write to 000018 = 0C & FF port 8 DDR
[:maincpu] ':maincpu' (FC2ADE): unmapped program memory write to 000039 = 0C & FF TMCSR0 (clock = phase 16 MHz / 2^1, trigger input, rising edge)
[:maincpu] ':maincpu' (FC2AE8): unmapped program memory write to 000038 = F0 & FF TMCSR0 (toggle output, H Level at start, no count or interrupt enable)
[:maincpu] ':maincpu' (FC2AF1): unmapped program memory write to 00003D = 0C & FF TMCSR1
[:maincpu] ':maincpu' (FC2AFB): unmapped program memory write to 00003C = F0 & FF TMCSR1
[:maincpu] ':maincpu' (FE2B89): unmapped program memory write to 000007 = 00 & FF port 7 out
[:maincpu] ':maincpu' (FCE68D): unmapped program memory write to 000007 = 10 & FF port 7 out
[:maincpu] ':maincpu' (FCE6BA): unmapped program memory write to 000034 = 73 & FF PRL0 (PPG0 reload)
[:maincpu] ':maincpu' (FCE6D3): unmapped program memory write to 000036 = 0D & FF PRL1 (PPG1 reload)
[:maincpu] ':maincpu' (FCE6DE): unmapped program memory write to 000030 = 85 & FF PPG0C0 (PPG0 control) (PPG Enabled, 16 MHz / 16, no interrupts)
************************************************************************/
#include "emu.h"
#include "screen.h"
#include "speaker.h"
#include "machine/timer.h"
#include "cpu/f2mc16/mb9061x.h"
#include "bus/generic/slot.h"
#include "bus/generic/carts.h"
@ -22,6 +62,7 @@ public:
, m_cart(*this, "cartslot")
, m_screen(*this, "screen")
, m_maincpu(*this, "maincpu")
, m_scantimer(*this, "scantimer")
{ }
void tomy_princ(machine_config &config);
@ -31,13 +72,21 @@ protected:
private:
required_device<generic_slot_device> m_cart;
required_device<screen_device> m_screen;
required_device<f2mc16_device> m_maincpu;
required_device<mb90611_device> m_maincpu;
required_device<timer_device> m_scantimer;
TIMER_DEVICE_CALLBACK_MEMBER(scan_interrupt);
void princ_map(address_map &map);
uint32_t screen_update_tomy_princ(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
};
TIMER_DEVICE_CALLBACK_MEMBER(tomy_princ_state::scan_interrupt)
{
m_maincpu->tin0_w(ASSERT_LINE);
m_maincpu->tin0_w(CLEAR_LINE);
}
uint32_t tomy_princ_state::screen_update_tomy_princ(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
@ -46,7 +95,7 @@ uint32_t tomy_princ_state::screen_update_tomy_princ(screen_device &screen, bitma
void tomy_princ_state::princ_map(address_map &map)
{
map(0x68ff44, 0x68ff44).lr8("free0", [this]() -> u8 { return m_screen->vblank() ? 1 : 0; });
map(0x68ff44, 0x68ff44).lr8("free0", [this]() -> u8 { return m_screen->vblank() ? 0x11 : 0x10; });
map(0xe00000, 0xe07fff).ram(); // stacks are placed here
map(0xf00000, 0xffffff).rom().region("maincpu", 0x00000);
}
@ -67,6 +116,9 @@ void tomy_princ_state::tomy_princ(machine_config &config)
m_screen->set_size(256, 256);
m_screen->set_visarea(0, 256-1, 0, 256-1);
TIMER(config, m_scantimer, 0);
m_scantimer->configure_scanline(FUNC(tomy_princ_state::scan_interrupt), "screen", 0, 1);
GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "princ_cart");
SOFTWARE_LIST(config, "cart_list").set_original("princ");
}