From cf7493307104c241da83ecd1ec944089c116426f Mon Sep 17 00:00:00 2001 From: DavidHaywood <28625134+DavidHaywood@users.noreply.github.com> Date: Sat, 4 Aug 2018 02:26:30 +0100 Subject: current hng64 / tlcs870 notes, tweaks etc. I'll probably tear out the simulation at some point soon so that we're trying to hook this up live, IMHO it's not far off being able to do something useful, just need to find the various triggers and make things like the timer timing realistic. Don't think the serial stuff is going to matter for the basic hookup. None of the games are marked as working yet anyway, so hopefully won't be a problem. --- src/devices/cpu/tlcs870/tlcs870.cpp | 97 +++++++++++------ src/devices/cpu/tlcs870/tlcs870.h | 2 + src/mame/drivers/hng64.cpp | 203 +++++++++++++++++++++++++----------- src/mame/includes/hng64.h | 26 ++--- 4 files changed, 224 insertions(+), 104 deletions(-) diff --git a/src/devices/cpu/tlcs870/tlcs870.cpp b/src/devices/cpu/tlcs870/tlcs870.cpp index 39518fd1f50..94644a14eed 100644 --- a/src/devices/cpu/tlcs870/tlcs870.cpp +++ b/src/devices/cpu/tlcs870/tlcs870.cpp @@ -475,6 +475,8 @@ READ8_MEMBER(tlcs870_device::tbtcr_r) /* SIO emulation */ +// TODO: use templates for SIO1/2 ports, as they're the same except for the DBR region they use? + // Serial Port 1 WRITE8_MEMBER(tlcs870_device::sio1cr1_w) { @@ -493,14 +495,40 @@ WRITE8_MEMBER(tlcs870_device::sio1cr1_w) m_transfer_mode[0] = (m_SIOCR1[0] & 0x38) >> 3; switch (m_transfer_mode[0]) { - case 0x0: logerror("(Serial set to 8-bit transmit mode)\n"); break; - case 0x1: logerror("(Serial set to invalid mode)\n"); break; - case 0x2: logerror("(Serial set to 4-bit transmit mode)\n"); break; - case 0x3: logerror("(Serial set to invalid mode)\n"); break; - case 0x4: logerror("(Serial set to 8-bit transmit/receive mode)\n"); break; - case 0x5: logerror("(Serial set to 8-bit receive mode)\n"); break; - case 0x6: logerror("(Serial set to 4-bit receive mode)\n"); break; - case 0x7: logerror("(Serial set to invalid mode)\n"); break; + case 0x0: + logerror("(Serial set to 8-bit transmit mode)\n"); + m_transmit_bits[0] = 8; + m_receive_bits[0] = 0; + break; + + case 0x2: + logerror("(Serial set to 4-bit transmit mode)\n"); + m_transmit_bits[0] = 4; + m_receive_bits[0] = 0; + break; + + case 0x4: + logerror("(Serial set to 8-bit transmit/receive mode)\n"); + m_transmit_bits[0] = 8; + m_receive_bits[0] = 8; + break; + + case 0x5: logerror("(Serial set to 8-bit receive mode)\n"); + m_transmit_bits[0] = 0; + m_receive_bits[0] = 8; + break; + + case 0x6: + logerror("(Serial set to 4-bit receive mode)\n"); + m_transmit_bits[0] = 0; + m_receive_bits[0] = 4; + break; + + default: + logerror("(Serial set to invalid mode)\n"); + m_transmit_bits[0] = 0; + m_receive_bits[0] = 0; + break; } if ((m_SIOCR1[0] & 0xc0) == 0x80) @@ -510,7 +538,7 @@ WRITE8_MEMBER(tlcs870_device::sio1cr1_w) m_transfer_shiftreg[0] = 0; m_transfer_pos[0] = 0; - m_serial_transmit_timer[0]->adjust(attotime::zero); + m_serial_transmit_timer[0]->adjust(attotime::zero); } } @@ -547,39 +575,42 @@ READ8_MEMBER(tlcs870_device::sio1sr_r) TIMER_CALLBACK_MEMBER(tlcs870_device::sio0_transmit_cb) { - int finish = 0; - if (m_transfer_shiftpos[0] == 0) + if (m_transmit_bits[0]) // TODO: handle receive cases { - m_transfer_shiftreg[0] = m_dbr[m_transfer_pos[0]]; - logerror("transmitting byte %02x\n", m_transfer_shiftreg[0]); - } + int finish = 0; + if (m_transfer_shiftpos[0] == 0) + { + m_transfer_shiftreg[0] = m_dbr[m_transfer_pos[0]]; + logerror("transmitting byte %02x\n", m_transfer_shiftreg[0]); + } - int dataout = m_transfer_shiftreg[0] & 0x01; + int dataout = m_transfer_shiftreg[0] & 0x01; - m_serial_out_cb[0](dataout); + m_serial_out_cb[0](dataout); - m_transfer_shiftreg[0] >>= 1; - m_transfer_shiftpos[0]++; + m_transfer_shiftreg[0] >>= 1; + m_transfer_shiftpos[0]++; - if (m_transfer_shiftpos[0] == 8) - { - logerror("transmitted\n"); + if (m_transfer_shiftpos[0] == 8) + { + logerror("transmitted\n"); - m_transfer_shiftpos[0] = 0; - m_transfer_pos[0]++; + m_transfer_shiftpos[0] = 0; + m_transfer_pos[0]++; - if (m_transfer_pos[0] > m_transfer_numbytes[0]) - { - logerror("end of transmission\n"); - m_SIOCR1[0] &= ~0x80; - // set interrupt latch - m_IL |= 1 << (15-TLCS870_IRQ_INTSIO1); - finish = 1; + if (m_transfer_pos[0] > m_transfer_numbytes[0]) + { + logerror("end of transmission\n"); + m_SIOCR1[0] &= ~0x80; + // set interrupt latch + m_IL |= 1 << (15 - TLCS870_IRQ_INTSIO1); + finish = 1; + } } - } - if (!finish) - m_serial_transmit_timer[0]->adjust(cycles_to_attotime(1000)); // TODO: use real speed + if (!finish) + m_serial_transmit_timer[0]->adjust(cycles_to_attotime(1000)); // TODO: use real speed + } } // Serial Port 2 diff --git a/src/devices/cpu/tlcs870/tlcs870.h b/src/devices/cpu/tlcs870/tlcs870.h index aeeac11f0eb..7d23d08c71e 100644 --- a/src/devices/cpu/tlcs870/tlcs870.h +++ b/src/devices/cpu/tlcs870/tlcs870.h @@ -299,6 +299,8 @@ private: uint8_t m_transfer_shiftreg[2]; uint8_t m_transfer_shiftpos[2]; uint8_t m_transfer_mode[2]; + int m_transmit_bits[2]; + int m_receive_bits[2]; emu_timer *m_serial_transmit_timer[2]; diff --git a/src/mame/drivers/hng64.cpp b/src/mame/drivers/hng64.cpp index 35dbad18412..dbf219bf4e0 100644 --- a/src/mame/drivers/hng64.cpp +++ b/src/mame/drivers/hng64.cpp @@ -188,7 +188,7 @@ LVS-JAM SNK 1999.1.20 No. PCB Label IC Markings IC Package ---------------------------------------------------- -01 DPRAM1 DT 71321 LA55PF QFP64 +01 DPRAM1 DT 71321 LA55PF QFP64 * 02 IC1 MC44200FT QFP44 03 IOCTR1 TOSHIBA TMP87CH40N-4828 SDIP64 04 BACKUP EPSON RTC62423 SOP24 @@ -204,6 +204,9 @@ Notes: 2. If the game cart is not plugged in, the hardware shows nothing on screen. 3. The IOCTR I/O MCU runs at 8 MHz. + *"IDT71321 is function-compatible (but not pin-compatible) with MB8421" ( src\devices\machine\mb8421.cpp ) + It appears unlikely the interrupt function of the DPRAM is unused unless address pins are all inverted as + there aren't any accesses to 7ff / 7fe outside of the RAM testing, commands are put at byte 0 by the MIPS Hyper Neo Geo game cartridges ----------------------------- @@ -782,8 +785,24 @@ Beast Busters 2 outputs (all at offset == 0x1c): WRITE32_MEMBER(hng64_state::hng64_dualport_w) { - //printf("dualport WRITE %08x %08x (PC=%08x)\n", offset*4, hng64_dualport[offset], m_maincpu->pc()); - COMBINE_DATA (&m_dualport[offset]); + /* + MIPS clearly writes commands for the TLCS870 MCU at 00 here + first command it writes after the startup checks is 0x0a, it should also trigger an EXTINT0 on the TLCS870 + around that time, as the EXTINT0 reads the command. + + call at CBB0 in the MCU is to read the command from shared RAM + value is used in the jump table at CBC5 + command 0x0a points at ccbd + which starts with a call to copy 0x40 bytes of data from 0x200 in shared RAM to the internal RAM of the MCU + the MIPS (at least in Fatal Fury) uploads this data to shared RAM prior to the call. + + need to work out what triggers the interrupt, as a write to 0 wouldn't as the Dual Port RAM interrupts + are on addresses 0x7fe and 0x7ff + + (currently we use m_dualport due to simulation, but this should actually be the same RAM as m_ioram) + */ + COMBINE_DATA(&m_dualport[offset]); + logerror("%s: dualport WRITE %08x (%08x)\n", machine().describe_context(), offset * 4, data, mem_mask); } @@ -1534,50 +1553,61 @@ void hng64_state::machine_reset() reset_sound(); } -// used (shared ram access at least) -READ8_MEMBER(hng64_state::ioport0_r) -{ - uint16_t addr = (m_ex_ramaddr | (m_ex_ramaddr_upper<<9)) & 0x7ff; - uint8_t ret = m_ioram[addr]; - - logerror("%s: ioport0_r %02x (from address %04x)\n", machine().describe_context(), ret, addr); - return ret; // expects 0x03 after writing it to port 0 earlier -} +/*********************************************** -// used -READ8_MEMBER(hng64_state::ioport1_r) -{ - logerror("%s: ioport1_r\n", machine().describe_context()); - return 0xff; -} + Control / Lamp etc. access from MCU side? -// used (shared ram access at least) -WRITE8_MEMBER(hng64_state::ioport0_w) -{ - uint16_t addr = (m_ex_ramaddr | (m_ex_ramaddr_upper<<9)) & 0x7ff; - m_ioram[addr] = data; + this is probably 8 multiplexed 8-bit input / output ports (probably joysticks, coins etc.) - logerror("%s: ioport0_w %02x (to address %04x)\n", machine().describe_context(), data, addr); -} +***********************************************/ -// used WRITE8_MEMBER(hng64_state::ioport1_w) { logerror("%s: ioport1_w %02x\n", machine().describe_context(), data); + + /* Port bits + + aaac w-?- + + a = external port number / address? + c = toggled during read / write accesses, probably clocking byte from/to latch + + ? = toggled at the start of extint 0 , set during reads? + + w = set during writes? + + */ + + m_port1 = data; } -// used +// it does write 0xff here before each set of reading, but before setting a new output address? WRITE8_MEMBER(hng64_state::ioport3_w) { - logerror("%s: ioport3_w %02x\n", machine().describe_context(), data); + int addr = (m_port1&0xe0)>>5; + + logerror("%s: ioport3_w %02x (to address %02x) (other bits of m_port1 %02x)\n", machine().describe_context(), data, addr, m_port1 & 0x1f); +} + +READ8_MEMBER(hng64_state::ioport3_r) +{ + int addr = (m_port1&0xe0)>>5; + + logerror("%s: ioport3_r (from address %02x) (other bits of m_port1 %02x)\n", machine().describe_context(), addr, m_port1 & 0x1f); + return 0xff; } -// used (shared ram access control for port 0 at least) +/*********************************************** + + Dual Port RAM access from MCU side + +***********************************************/ + WRITE8_MEMBER(hng64_state::ioport7_w) { /* Port bits - -?xR Aacr + i?xR Aacr a = 0x200 of address bit to external RAM (direct?) A = 0x400 of address bit to external RAM (direct?) @@ -1589,12 +1619,19 @@ WRITE8_MEMBER(hng64_state::ioport7_w) x = written with clock bits, might be latch related? ? = written before some operations + i = generate interrupt on MIPS? (written after the MCU has completed writing 'results' of some operations to shared ram, before executing more code to write another result, so needs to be processed quickly by the MIPS?) + */ //logerror("%s: ioport7_w %02x\n", machine().describe_context(), data); m_ex_ramaddr_upper = (data & 0x0c) >> 2; + if ((!(data & 0x80)) && (m_port7 & 0x80)) + { + logerror("%s: MCU request MIPS IRQ?\n"); + } + if ((!(data & 0x01)) && (m_port7 & 0x01)) { m_ex_ramaddr = 0; @@ -1609,18 +1646,43 @@ WRITE8_MEMBER(hng64_state::ioport7_w) m_port7 = data; } -// check if these are used -READ8_MEMBER(hng64_state::ioport2_r) { logerror("%s: ioport2_r\n", machine().describe_context()); return 0xff; } -READ8_MEMBER(hng64_state::ioport3_r) { logerror("%s: ioport3_r\n", machine().describe_context()); return 0xff; } -READ8_MEMBER(hng64_state::ioport4_r) { logerror("%s: ioport4_r\n", machine().describe_context()); return 0xff; } -READ8_MEMBER(hng64_state::ioport5_r) { logerror("%s: ioport5_r\n", machine().describe_context()); return 0xff; } -READ8_MEMBER(hng64_state::ioport6_r) { logerror("%s: ioport6_r\n", machine().describe_context()); return 0xff; } -READ8_MEMBER(hng64_state::ioport7_r) { logerror("%s: ioport7_r\n", machine().describe_context()); return 0xff; } +READ8_MEMBER(hng64_state::ioport0_r) +{ + uint16_t addr = (m_ex_ramaddr | (m_ex_ramaddr_upper<<9)) & 0x7ff; + uint8_t ret = m_ioram[addr]; + + logerror("%s: ioport0_r %02x (from address %04x)\n", machine().describe_context(), ret, addr); + return ret; // expects 0x03 after writing it to port 0 earlier +} + +WRITE8_MEMBER(hng64_state::ioport0_w) +{ + uint16_t addr = (m_ex_ramaddr | (m_ex_ramaddr_upper<<9)) & 0x7ff; + m_ioram[addr] = data; + + logerror("%s: ioport0_w %02x (to address %04x)\n", machine().describe_context(), data, addr); +} + -WRITE8_MEMBER(hng64_state::ioport2_w) { logerror("%s: ioport2_w %02x\n", machine().describe_context(), data); } -WRITE8_MEMBER(hng64_state::ioport4_w) { logerror("%s: ioport4_w %02x\n", machine().describe_context(), data); } -WRITE8_MEMBER(hng64_state::ioport5_w) { logerror("%s: ioport5_w %02x\n", machine().describe_context(), data); } -WRITE8_MEMBER(hng64_state::ioport6_w) { logerror("%s: ioport6_w %02x\n", machine().describe_context(), data); } +/*********************************************** + + Unknown (LED?) access from MCU side + +***********************************************/ + +/* This port is dual purpose, with the upper pins being used as a serial input / output / clock etc. and the output latch (written data) being configured appropriately however the lower 2 bits also seem to be used + maybe these lower 2 bits were intended for serial comms LEDs, although none are documented in the PCB layouts. +*/ +WRITE8_MEMBER(hng64_state::ioport4_w) +{ + logerror("%s: ioport4_w %02x\n", machine().describe_context(), data); +} + +/*********************************************** + + Other port accesses from MCU side + +***********************************************/ READ8_MEMBER(hng64_state::anport0_r) { logerror("%s: anport0_r\n", machine().describe_context()); return 0xff; } READ8_MEMBER(hng64_state::anport1_r) { logerror("%s: anport1_r\n", machine().describe_context()); return 0xff; } @@ -1631,6 +1693,26 @@ READ8_MEMBER(hng64_state::anport5_r) { logerror("%s: anport5_r\n", machine().des READ8_MEMBER(hng64_state::anport6_r) { logerror("%s: anport6_r\n", machine().describe_context()); return 0xff; } READ8_MEMBER(hng64_state::anport7_r) { logerror("%s: anport7_r\n", machine().describe_context()); return 0xff; } +/*********************************************** + + Serial Accesses from MCU side + +***********************************************/ + +/* I think the serial reads / writes actually go to the network hardware, and the IO MCU is acting as an interface between the actual network and the KL5C80A12CFP + because the network connectors are on the IO board. This might also be related to the 'm_no_machine_error_code' value required which differs per IO board + type as the game startup sequences read that from the 0x6xx region of shared RAM, which also seems to be where a lot of the serial stuff is stored. +*/ + +// there are also serial reads, TLCS870 core doesn't support them yet + +WRITE_LINE_MEMBER( hng64_state::sio0_w ) +{ + // tlcs870 core provides better logging than anything we could put here at the moment +} + + + TIMER_CALLBACK_MEMBER(hng64_state::tempio_irqon_callback) { @@ -1651,7 +1733,8 @@ void hng64_state::init_io() m_tempio_irqoff_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hng64_state::tempio_irqoff_callback), this)); m_tempio_irqon_timer->adjust(m_maincpu->cycles_to_attotime(100000000)); // just ensure an IRQ gets turned on to move the program forward, real source currently unknown - m_port7 = 0; + m_port7 = 0x00; + m_port1 = 0x00; m_ex_ramaddr = 0; m_ex_ramaddr_upper = 0; @@ -1686,22 +1769,23 @@ MACHINE_CONFIG_START(hng64_state::hng64) hng64_network(config); tmp87ph40an_device &iomcu(TMP87PH40AN(config, m_iomcu, 8_MHz_XTAL)); - iomcu.p0_in_cb().set(FUNC(hng64_state::ioport0_r)); - iomcu.p1_in_cb().set(FUNC(hng64_state::ioport1_r)); - iomcu.p2_in_cb().set(FUNC(hng64_state::ioport2_r)); - iomcu.p3_in_cb().set(FUNC(hng64_state::ioport3_r)); - iomcu.p4_in_cb().set(FUNC(hng64_state::ioport4_r)); - iomcu.p5_in_cb().set(FUNC(hng64_state::ioport5_r)); - iomcu.p6_in_cb().set(FUNC(hng64_state::ioport6_r)); - iomcu.p7_in_cb().set(FUNC(hng64_state::ioport7_r)); - iomcu.p0_out_cb().set(FUNC(hng64_state::ioport0_w)); - iomcu.p1_out_cb().set(FUNC(hng64_state::ioport1_w)); - iomcu.p2_out_cb().set(FUNC(hng64_state::ioport2_w)); - iomcu.p3_out_cb().set(FUNC(hng64_state::ioport3_w)); - iomcu.p4_out_cb().set(FUNC(hng64_state::ioport4_w)); - iomcu.p5_out_cb().set(FUNC(hng64_state::ioport5_w)); - iomcu.p6_out_cb().set(FUNC(hng64_state::ioport6_w)); - iomcu.p7_out_cb().set(FUNC(hng64_state::ioport7_w)); + iomcu.p0_in_cb().set(FUNC(hng64_state::ioport0_r)); // reads from shared ram + //iomcu.p1_in_cb().set(FUNC(hng64_state::ioport1_r)); // the IO MCU code uses opcodes that only access the output latch, never read from the port + //iomcu.p2_in_cb().set(FUNC(hng64_state::ioport2_r)); // the IO MCU uses EXTINT0 which shares one of the pins on this port, but the port is not used for IO + iomcu.p3_in_cb().set(FUNC(hng64_state::ioport3_r)); // probably reads input ports? + //iomcu.p4_in_cb().set(FUNC(hng64_state::ioport4_r)); // the IO MCU code uses opcodes that only access the output latch, never read from the port + //iomcu.p5_in_cb().set(FUNC(hng64_state::ioport5_r)); // simply seems to be unused, neither used for an IO port, nor any of the other features + //iomcu.p6_in_cb().set(FUNC(hng64_state::ioport6_r)); // the IO MCU code uses the ADC which shares pins with port 6, meaning port 6 isn't used as an IO port + //iomcu.p7_in_cb().set(FUNC(hng64_state::ioport7_r)); // the IO MCU code uses opcodes that only access the output latch, never read from the port + iomcu.p0_out_cb().set(FUNC(hng64_state::ioport0_w)); // writes to shared ram + iomcu.p1_out_cb().set(FUNC(hng64_state::ioport1_w)); // configuration / clocking for input port (port 3) accesses + //iomcu.p2_out_cb().set(FUNC(hng64_state::ioport2_w)); // the IO MCU uses EXTINT0 which shares one of the pins on this port, but the port is not used for IO + iomcu.p3_out_cb().set(FUNC(hng64_state::ioport3_w)); // writes to input ports? maybe lamps, coin counters etc.? + iomcu.p4_out_cb().set(FUNC(hng64_state::ioport4_w)); // unknown, lower 2 IO bits accessed along with serial accesses + //iomcu.p5_out_cb().set(FUNC(hng64_state::ioport5_w)); // simply seems to be unused, neither used for an IO port, nor any of the other features + //iomcu.p6_out_cb().set(FUNC(hng64_state::ioport6_w)); // the IO MCU code uses the ADC which shares pins with port 6, meaning port 6 isn't used as an IO port + iomcu.p7_out_cb().set(FUNC(hng64_state::ioport7_w)); // configuration / clocking for shared ram (port 0) accesses + // most likely the analog inputs, up to a maximum of 8 iomcu.an0_in_cb().set(FUNC(hng64_state::anport0_r)); iomcu.an1_in_cb().set(FUNC(hng64_state::anport1_r)); iomcu.an2_in_cb().set(FUNC(hng64_state::anport2_r)); @@ -1710,6 +1794,9 @@ MACHINE_CONFIG_START(hng64_state::hng64) iomcu.an5_in_cb().set(FUNC(hng64_state::anport5_r)); iomcu.an6_in_cb().set(FUNC(hng64_state::anport6_r)); iomcu.an7_in_cb().set(FUNC(hng64_state::anport7_r)); + // network related? + iomcu.serial0_out_cb().set(FUNC(hng64_state::sio0_w)); + //iomcu.serial1_out_cb().set(FUNC(hng64_state::sio1_w)); // not initialized / used MACHINE_CONFIG_END diff --git a/src/mame/includes/hng64.h b/src/mame/includes/hng64.h index 68b81a9f238..b9c25b1c7fc 100644 --- a/src/mame/includes/hng64.h +++ b/src/mame/includes/hng64.h @@ -305,24 +305,20 @@ private: DECLARE_READ8_MEMBER(hng64_comm_mmu_r); DECLARE_WRITE8_MEMBER(hng64_comm_mmu_w); + // shared ram access DECLARE_READ8_MEMBER(ioport0_r); - DECLARE_READ8_MEMBER(ioport1_r); - DECLARE_READ8_MEMBER(ioport2_r); - DECLARE_READ8_MEMBER(ioport3_r); - DECLARE_READ8_MEMBER(ioport4_r); - DECLARE_READ8_MEMBER(ioport5_r); - DECLARE_READ8_MEMBER(ioport6_r); - DECLARE_READ8_MEMBER(ioport7_r); - DECLARE_WRITE8_MEMBER(ioport0_w); - DECLARE_WRITE8_MEMBER(ioport1_w); - DECLARE_WRITE8_MEMBER(ioport2_w); + DECLARE_WRITE8_MEMBER(ioport7_w); + + // input port access + DECLARE_READ8_MEMBER(ioport3_r); DECLARE_WRITE8_MEMBER(ioport3_w); + DECLARE_WRITE8_MEMBER(ioport1_w); + + // unknown access DECLARE_WRITE8_MEMBER(ioport4_w); - DECLARE_WRITE8_MEMBER(ioport5_w); - DECLARE_WRITE8_MEMBER(ioport6_w); - DECLARE_WRITE8_MEMBER(ioport7_w); + // analog input access DECLARE_READ8_MEMBER(anport0_r); DECLARE_READ8_MEMBER(anport1_r); DECLARE_READ8_MEMBER(anport2_r); @@ -332,7 +328,11 @@ private: DECLARE_READ8_MEMBER(anport6_r); DECLARE_READ8_MEMBER(anport7_r); + DECLARE_WRITE_LINE_MEMBER( sio0_w ); + uint8_t m_port7; + uint8_t m_port1; + int m_ex_ramaddr; int m_ex_ramaddr_upper; std::unique_ptr m_ioram; -- cgit v1.2.3