From 61c288efdb2249bc910de30ebaecc9091436dd1c Mon Sep 17 00:00:00 2001 From: arbee Date: Tue, 27 Aug 2019 15:11:42 -0400 Subject: f2mc16: More opcodes and more robust IRQ handling [R. Belmont] mb9061x: Implemented timers 0 and 1, including external event counter mode [R. Belmont] --- src/devices/cpu/f2mc16/f2mc16.cpp | 322 +++++++++++++++++++++++++++++----- src/devices/cpu/f2mc16/f2mc16.h | 33 +++- src/devices/cpu/f2mc16/f2mc16dasm.cpp | 39 ++++ src/devices/cpu/f2mc16/mb9061x.cpp | 223 +++++++++++++++++++++++ src/devices/cpu/f2mc16/mb9061x.h | 18 ++ src/mame/drivers/tomy_princ.cpp | 56 +++++- 6 files changed, 642 insertions(+), 49 deletions(-) diff --git a/src/devices/cpu/f2mc16/f2mc16.cpp b/src/devices/cpu/f2mc16/f2mc16.cpp index a71c1532fac..cbe44880421 100644 --- a/src/devices/cpu/f2mc16/f2mc16.cpp +++ b/src/devices/cpu/f2mc16/f2mc16.cpp @@ -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<> 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; - - u32 uVecAddr = 0xfffffc - (irq * 4); - m_pc = read_16(uVecAddr); - m_pcb = read_8(uVecAddr + 2); - break; + 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); + 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); } diff --git a/src/devices/cpu/f2mc16/f2mc16.h b/src/devices/cpu/f2mc16/f2mc16.h index 3e5217268e1..abcf35e4d53 100644 --- a/src/devices/cpu/f2mc16/f2mc16.h +++ b/src/devices/cpu/f2mc16/f2mc16.h @@ -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; diff --git a/src/devices/cpu/f2mc16/f2mc16dasm.cpp b/src/devices/cpu/f2mc16/f2mc16dasm.cpp index ede0b35ac65..28d2b9ae464 100644 --- a/src/devices/cpu/f2mc16/f2mc16dasm.cpp +++ b/src/devices/cpu/f2mc16/f2mc16dasm.cpp @@ -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; diff --git a/src/devices/cpu/f2mc16/mb9061x.cpp b/src/devices/cpu/f2mc16/mb9061x.cpp index 47546332280..4794410f4be 100644 --- a/src/devices/cpu/f2mc16/mb9061x.cpp +++ b/src/devices/cpu/f2mc16/mb9061x.cpp @@ -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 diff --git a/src/devices/cpu/f2mc16/mb9061x.h b/src/devices/cpu/f2mc16/mb9061x.h index e79d0202601..97d3e977c49 100644 --- a/src/devices/cpu/f2mc16/mb9061x.h +++ b/src/devices/cpu/f2mc16/mb9061x.h @@ -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; diff --git a/src/mame/drivers/tomy_princ.cpp b/src/mame/drivers/tomy_princ.cpp index cf2e22b4ae2..6754bbff471 100644 --- a/src/mame/drivers/tomy_princ.cpp +++ b/src/mame/drivers/tomy_princ.cpp @@ -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 m_cart; required_device m_screen; - required_device m_maincpu; + required_device m_maincpu; + required_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"); } -- cgit v1.2.3