From 47c281d0fc86ccfb00cf5f050afa85ed30790715 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Wed, 22 Mar 2023 08:10:42 +1100 Subject: [PATCH] -jaleco/tetrisp2.cpp: Added partial emulation of PC for music games. [Windy Fairy] -emu/devcb.h: Allow base device to be specified directly in delegate setters. [Vas Crabb] -taito/tnzs.cpp: Untangled inheritance a bit. [Vas Crabb] --- src/emu/devcb.h | 15 + src/mame/jaleco/jaleco_vj_pc.cpp | 163 ++++ src/mame/jaleco/jaleco_vj_pc.h | 45 + src/mame/jaleco/jaleco_vj_sound.cpp | 328 +++++++ src/mame/jaleco/jaleco_vj_sound.h | 76 ++ src/mame/jaleco/jaleco_vj_ups.cpp | 44 + src/mame/jaleco/jaleco_vj_ups.h | 13 + src/mame/jaleco/tetrisp2.cpp | 69 +- src/mame/jaleco/tetrisp2.h | 7 +- src/mame/taito/cchance.cpp | 10 +- src/mame/taito/tnzs.cpp | 877 +++++++++++++++++- src/mame/taito/tnzs.h | 305 ------ src/mame/taito/tnzs_m.cpp | 495 ---------- src/mame/taito/{tnzs_v.cpp => tnzs_video.cpp} | 15 +- src/mame/taito/tnzs_video.h | 36 + 15 files changed, 1578 insertions(+), 920 deletions(-) create mode 100644 src/mame/jaleco/jaleco_vj_pc.cpp create mode 100644 src/mame/jaleco/jaleco_vj_pc.h create mode 100644 src/mame/jaleco/jaleco_vj_sound.cpp create mode 100644 src/mame/jaleco/jaleco_vj_sound.h create mode 100644 src/mame/jaleco/jaleco_vj_ups.cpp create mode 100644 src/mame/jaleco/jaleco_vj_ups.h delete mode 100644 src/mame/taito/tnzs.h delete mode 100644 src/mame/taito/tnzs_m.cpp rename src/mame/taito/{tnzs_v.cpp => tnzs_video.cpp} (72%) create mode 100644 src/mame/taito/tnzs_video.h diff --git a/src/emu/devcb.h b/src/emu/devcb.h index 7638f901296..9a50df90a00 100644 --- a/src/emu/devcb.h +++ b/src/emu/devcb.h @@ -716,6 +716,13 @@ private: return delegate_builder >(m_target, m_append, m_target.owner(), devcb_read::cast_reference >(obj), std::forward(func), name); } + template + std::enable_if_t::value, delegate_builder > > set(device_t &devbase, char const *tag, T &&func, char const *name) + { + set_used(); + return delegate_builder >(m_target, m_append, devbase, tag, std::forward(func), name); + } + template std::enable_if_t::value, delegate_builder > > set(device_finder &finder, T &&func, char const *name) { @@ -2055,6 +2062,7 @@ private: { if ((data ^ exor) & mask) devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message); }; } }; + class binder { public: @@ -2092,6 +2100,13 @@ private: return delegate_builder >(m_target, m_append, m_target.owner(), devcb_write::cast_reference >(obj), std::forward(func), name); } + template + std::enable_if_t::value, delegate_builder > > set(device_t &devbase, char const *tag, T &&func, char const *name) + { + set_used(); + return delegate_builder >(m_target, m_append, devbase, tag, std::forward(func), name); + } + template std::enable_if_t::value, delegate_builder > > set(device_finder &finder, T &&func, char const *name) { diff --git a/src/mame/jaleco/jaleco_vj_pc.cpp b/src/mame/jaleco/jaleco_vj_pc.cpp new file mode 100644 index 00000000000..38905000471 --- /dev/null +++ b/src/mame/jaleco/jaleco_vj_pc.cpp @@ -0,0 +1,163 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +/* +Hardware to run VJ Windows PC side software + +Motherboard is similar to EP-5BVPXB but says REV 1.3 which matches NMC-5VXC +but the board used does not have the NMC markings like the NMC-5VXC. + +VIA 82C586B PCI ISA/IDE bridge +VIA 82C585VPX +Winbond W83877F IO Core Logic + +S3 Virge/DX Q5C2BB (not connected to a monitor) + +UPS is connected to COM1 port + +CD-ROM: Mitsumi CRMC-FX3210S(?) +Floppy: Unidentified but machine has floppy drive + + +TODO: None of the VIA chips are emulated in the new PCI code +Windows 95 will ask you to install the new hardware every boot. There's an autoexec.bat that'll +restore the registry and other configs back to the factory setup every boot so +the hardware will never stay "installed" between boots. + +Keyboard and mouse should not enabled by default but it'd be impossible to install drivers currently. +It's recommended to disable the keyboard (Input Settings > Keyboard Selection > AT Keyboard > Disabled) +when actually playing the games because otherwise you'll be sending inputs to the Windows PC in the background. +*/ + +#include "emu.h" +#include "jaleco_vj_pc.h" + +#include "jaleco_vj_ups.h" + +#include "bus/isa/isa_cards.h" +#include "bus/rs232/rs232.h" +#include "machine/fdc37c93x.h" +#include "machine/i82371sb.h" +#include "machine/i82439hx.h" +#include "machine/i82439tx.h" +#include "machine/pci-ide.h" +#include "machine/pci.h" +#include "video/virge_pci.h" + + +jaleco_vj_pc_device::jaleco_vj_pc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, JALECO_VJ_PC, tag, owner, clock), + device_mixer_interface(mconfig, *this, 2), + m_maincpu(*this, "maincpu"), + m_sound(*this, "isa1:vj_sound"), + m_is_steppingstage(false) +{ +} + +void jaleco_vj_pc_device::device_start() +{ +} + +static void isa_internal_devices(device_slot_interface &device) +{ + device.option_add("fdc37c93x", FDC37C93X); +} + +static void isa_com(device_slot_interface &device) +{ + // TODO: Stepping Stage uses a different UPS but will still boot unlike VJ without a valid UPS attached + device.option_add("vj_ups", JALECO_VJ_UPS); +} + +static void isa_cards(device_slot_interface &device) +{ + device.option_add("vj_sound", JALECO_VJ_ISA16_SOUND); +} + +void jaleco_vj_pc_device::superio_config(device_t &device) +{ + // TODO: This should be a Winbond W83877F Super I/O + fdc37c93x_device &fdc = downcast(device); + fdc.set_sysopt_pin(1); + fdc.gp20_reset().set_inputline(m_maincpu, INPUT_LINE_RESET); + fdc.gp25_gatea20().set_inputline(m_maincpu, INPUT_LINE_A20); + fdc.irq1().set(*this, "pci:07.0", FUNC(i82371sb_isa_device::pc_irq1_w)); + fdc.irq8().set(*this, "pci:07.0", FUNC(i82371sb_isa_device::pc_irq8n_w)); + fdc.txd1().set(*this, "serport0", FUNC(rs232_port_device::write_txd)); + fdc.ndtr1().set(*this, "serport0", FUNC(rs232_port_device::write_dtr)); + fdc.nrts1().set(*this, "serport0", FUNC(rs232_port_device::write_rts)); + fdc.txd2().set(*this, "serport1", FUNC(rs232_port_device::write_txd)); + fdc.ndtr2().set(*this, "serport1", FUNC(rs232_port_device::write_dtr)); + fdc.nrts2().set(*this, "serport1", FUNC(rs232_port_device::write_rts)); +} + +void jaleco_vj_pc_device::sound_config(device_t &device) +{ + jaleco_vj_isa16_sound_device &sound = downcast(device); + sound.set_steppingstage_mode(m_is_steppingstage); + sound.add_route(0, *this, 1.0, AUTO_ALLOC_INPUT, 0); + sound.add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1); +} + +void jaleco_vj_pc_device::boot_state_w(uint8_t data) +{ + logerror("Boot state %02x\n", data); +} + +void jaleco_vj_pc_device::device_add_mconfig(machine_config &config) +{ + // PCI config IDs pulled from Windows registry + PENTIUM(config, m_maincpu, 20'000'000); // TODO: Pentium 60/90mhz? Underclocked for performance reasons + m_maincpu->set_irq_acknowledge_callback("pci:07.0:pic8259_master", FUNC(pic8259_device::inta_cb)); + m_maincpu->smiact().set("pci:00.0", FUNC(i82439hx_host_device::smi_act_w)); + + PCI_ROOT(config, "pci", 0); + I82439HX(config, "pci:00.0", 0, m_maincpu, 256*1024*1024); // TODO: Should be 0x05851106 VIA VT82C585 Apollo VP,VPX,VPX-97 System Controller + + i82371sb_isa_device &isa(I82371SB_ISA(config, "pci:07.0", 0, m_maincpu)); + // isa.set_ids(0x05861106, 0x23, 0x060100, 0x00000000); // TODO: Should be VIA VT82C586B, PCI-to-ISA Bridge + isa.boot_state_hook().set(FUNC(jaleco_vj_pc_device::boot_state_w)); + isa.smi().set_inputline(m_maincpu, INPUT_LINE_SMI); + + i82371sb_ide_device &ide(I82371SB_IDE(config, "pci:07.1", 0, m_maincpu)); + // ide.set_ids(0x05711106, 0x06, 0x01018a, 0x00000000); // TODO: Should be VIA VT82C586B, IDE Controller + ide.irq_pri().set("pci:07.0", FUNC(i82371sb_isa_device::pc_irq14_w)); + ide.irq_sec().set("pci:07.0", FUNC(i82371sb_isa_device::pc_mirq0_w)); + + // TODO: pci:07.3 0x30401106 VIA VT83C572, VT86C586/A/B Power Management Controller + + VIRGEDX_PCI(config, "pci:10.0", 0); // TODO: Should actually be pci:0a.0 but it only shows a black screen + + ISA16_SLOT(config, "board4", 0, "pci:07.0:isabus", isa_internal_devices, "fdc37c93x", true).set_option_machine_config("fdc37c93x", [this] (device_t *device) { superio_config(*device); }); + ISA16_SLOT(config, "isa1", 0, "pci:07.0:isabus", isa_cards, "vj_sound", true).set_option_machine_config("vj_sound", [this] (device_t *device) { sound_config(*device); }); + ISA16_SLOT(config, "isa2", 0, "pci:07.0:isabus", isa_cards, nullptr, true); + ISA16_SLOT(config, "isa3", 0, "pci:07.0:isabus", isa_cards, nullptr, true); + + rs232_port_device& serport0(RS232_PORT(config, "serport0", isa_com, "vj_ups")); + serport0.rxd_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::rxd1_w)); + serport0.dcd_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::ndcd1_w)); + serport0.dsr_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::ndsr1_w)); + serport0.ri_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::nri1_w)); + serport0.cts_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::ncts1_w)); + + rs232_port_device &serport1(RS232_PORT(config, "serport1", isa_com, nullptr)); + serport1.rxd_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::rxd2_w)); + serport1.dcd_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::ndcd2_w)); + serport1.dsr_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::ndsr2_w)); + serport1.ri_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::nri2_w)); + serport1.cts_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::ncts2_w)); +} + +ROM_START(jaleco_vj_pc) + // TODO: BIOS undumped. Seems like it should be an Award BIOS which won't boot currently. + // Placeholder BIOS taken from pcipc + ROM_REGION32_LE(0x40000, "pci:07.0", 0) // PC bios + ROM_SYSTEM_BIOS(0, "m55ns04", "m55ns04") // Micronics M55HI-Plus with no sound + ROMX_LOAD("m55-04ns.rom", 0x20000, 0x20000, CRC(0116b2b0) SHA1(19b0203decfd4396695334517488d488aec3ccde) BAD_DUMP, ROM_BIOS(0)) +ROM_END + +const tiny_rom_entry *jaleco_vj_pc_device::device_rom_region() const +{ + return ROM_NAME(jaleco_vj_pc); +} + +DEFINE_DEVICE_TYPE(JALECO_VJ_PC, jaleco_vj_pc_device, "jaleco_vj_pc", "Jaleco VJ PC") diff --git a/src/mame/jaleco/jaleco_vj_pc.h b/src/mame/jaleco/jaleco_vj_pc.h new file mode 100644 index 00000000000..bf21d326aed --- /dev/null +++ b/src/mame/jaleco/jaleco_vj_pc.h @@ -0,0 +1,45 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +#ifndef MAME_JALECO_JALECO_VJ_PC_H +#define MAME_JALECO_JALECO_VJ_PC_H + +#pragma once + +#include "jaleco_vj_sound.h" + +#include "cpu/i386/i386.h" + + +class jaleco_vj_pc_device : + public device_t, + public device_mixer_interface +{ +public: + jaleco_vj_pc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void set_steppingstage_mode(bool mode) { m_is_steppingstage = mode; } + + uint16_t response_r(offs_t offset, uint16_t mem_mask = ~0) { return m_sound->response_r(offset, mem_mask); } + void comm_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_sound->comm_w(offset, data, mem_mask); } + void ymz_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_sound->ymz_w(offset, data, mem_mask); } + +protected: + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + + void superio_config(device_t &device) ATTR_COLD; + void sound_config(device_t &device) ATTR_COLD; + +private: + void boot_state_w(uint8_t data); + + required_device m_maincpu; + required_device m_sound; + bool m_is_steppingstage; +}; + + +DECLARE_DEVICE_TYPE(JALECO_VJ_PC, jaleco_vj_pc_device) + +#endif // MAME_JALECO_JALECO_VJ_PC_H diff --git a/src/mame/jaleco/jaleco_vj_sound.cpp b/src/mame/jaleco/jaleco_vj_sound.cpp new file mode 100644 index 00000000000..da22c550fb8 --- /dev/null +++ b/src/mame/jaleco/jaleco_vj_sound.cpp @@ -0,0 +1,328 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +/* +ISA card used by VJ +Handles sound playback and communication between PC and arcade PCB + +------------------------------------------------------------------ +| IC26? CN6 | +| IC23 IC24 IC25 | +| IC27 IC28 IC2x1 | +| IC15 IC16 IC17 IC29 IC2x2 | +| CN5 IC18 CN4 | +| IC9 IC10 IC11 IC19 IC20 IC14 | +| X1 IC13 IC6 | +| IC1 IC2 IC3 IC4 IC12 IC5 IC7 IC8 | +---------------------| |-| |------------- + |-----------| |----------------| + + +CN4 - 34-pin connector for IDC cable (chains to both CN6 on main board and CN1 on subboard) +CN5 - 80-pin connector +CN6 - 8-pin header, carries 4 channel stereo audio + +IC1, IC2, IC3, IC9, IC10, IC11, IC15, IC16, IC17, IC23, IC24, IC25 - Toshiba TC554001 FL-70 4MBit 512Kx8 SRAM +IC4 - ? +IC5 - XILINX XC9572 +IC7 - Texas Instruments HC24(5?) +IC6 - Texas Instruments HC244 +IC12 - XILINX XCS30 PQ240CKN9817 A2014617A 3C +IC13 - Motorola 74HCU04A 845UE +IC14 - Texas Instruments HC245 +IC18 - XILINX 17S30PC One-Time Programmable Configuration PROM +IC19 - Yamaha YMZ280B-F sound chip +IC20 - Yamaha YAC516-M DAC +IC2x1 - Unidentified 8-pin chip +IC2x2 - Unidentified TO-92 package 3-pin IC +IC26 - XILINX 17S30PC One-Time Programmable Configuration PROM +IC27 - XILINX XCS30 PQ240CKN9817 A2014617A 3C +IC28 - Yamaha YMZ280B-F sound chip +IC29 - Yamaha YAC516-M DAC +X1 - 16.9344MHz clock + +Audio gets sent to the VJ-98346 4ch amp via 8 pin header (CN6) on ISA card + + +TODO: Check Stepping Stage +VJ and Stepping Stage most likely have different FPGA programs in IC18 and IC26 based on the differences in where +each game expects to be able to play certain audio files when loaded into the assigned channels. + +TODO: Main PCB's YMZ should be used for the sound effects +Main board PCB's YMZ is used for sound effect channels (0x01, 0x02) but there's no way to differentiate +what YMZ chip a write to the YMZ register should go to so just using the two YMZ chips in this driver simplifies +the code a lot and also fixes some popping issues that would result from trying to play empty buffers. +*/ + +#include "emu.h" +#include "jaleco_vj_sound.h" + +#include "speaker.h" + + +#define LOG_COMM (1U << 1) +#define LOG_SOUND (1U << 2) +// #define VERBOSE (LOG_SOUND | LOG_COMM) +// #define LOG_OUTPUT_STREAM std::cout + +#include "logmacro.h" + + +uint8_t jaleco_vj_isa16_sound_device::comm_r(offs_t offset) +{ + uint8_t r = 0; + + if (offset == 0) { + r = m_comm & 0xff; + } else if (offset == 1) { + r = m_comm >> 8; + } + + LOGMASKED(LOG_COMM, "comm_r: %04x\n", r); + + return r; +} + +uint8_t jaleco_vj_isa16_sound_device::unk2_r(offs_t offset) +{ + // Usage unknown but it's known that it's a single byte sized register thanks to the + // debug GUI output in the vj.exe program used by Stepping 3 Superior. + if (!machine().side_effects_disabled()) + LOGMASKED(LOG_COMM, "unk2_r called!\n"); + return 0; +} + +uint16_t jaleco_vj_isa16_sound_device::buffer_status_r(offs_t offset, uint16_t mem_mask) +{ + // This will only be checked if there is additional BGM data that can be transferred + uint16_t r = m_request_extra_data && !m_receiving_extra_data ? 3 : 0; + if (!machine().side_effects_disabled()) { + m_is_checking_additional_bgm = true; + LOGMASKED(LOG_COMM, "buffer_status_r: %04x\n", r); + } + return r; +} + +uint16_t jaleco_vj_isa16_sound_device::response_r(offs_t offset, uint16_t mem_mask) +{ + uint16_t r = m_response; + if (!machine().side_effects_disabled()) { + m_response = 0; + LOGMASKED(LOG_COMM, "response_r: %04x\n", r); + } + return r; +} + +void jaleco_vj_isa16_sound_device::response_w(offs_t offset, uint8_t data) +{ + if (offset == 0) + m_response = (m_response & ~0xff) | (data & 0xff); + else if (offset == 1) + m_response = (m_response & ~0xff00) | ((data & 0xff) << 8); + + LOGMASKED(LOG_COMM, "response_w: %04x\n", m_response); +} + +uint16_t jaleco_vj_isa16_sound_device::target_buffer_r(offs_t offset, uint16_t mem_mask) +{ + if (!machine().side_effects_disabled()) + LOGMASKED(LOG_COMM, "target_buffer_r called!\n"); + return 0; +} + +void jaleco_vj_isa16_sound_device::target_buffer_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + // 0x01 Game SE + // 0x02 Song SE + // 0x09 Song BGM Normal + // 0x0a Song BGM Woofer + // 0x0b Song BGM Normal + // 0x0c Song BGM Woofer + if (data == 0x0101) { + m_target_addr = 0x000000; + } else if (data == 0x0202) { + m_target_addr = 0x080000; + } else if (data == 0x0909) { + if (m_is_steppingstage) + m_target_addr = 0x900000; + else + m_target_addr = m_receiving_extra_data ? 0x500000 : 0x400000; + } else if (data == 0x0b0b) { + if (m_is_steppingstage) + m_target_addr = 0x980000; + else + m_target_addr = m_receiving_extra_data ? 0x500000 : 0x480000; + } else if (data == 0x0a0a) { + if (m_is_steppingstage) + m_target_addr = 0xa00000; + else + m_target_addr = m_receiving_extra_data ? 0xb00000 : 0xa00000; + } else if (data == 0x0c0c) { + if (m_is_steppingstage) + m_target_addr = 0xa80000; + else + m_target_addr = m_receiving_extra_data ? 0xb00000 : 0xa80000; + } + + if (data == 0 && (m_target_buffer == 0x0101 || m_target_buffer == 0x0202) && m_is_checking_additional_bgm) { + // The code used to load additional BGM is run in a separate thread, and it does not check if another file + // is being transferred already, so if the code is called too soon then it'll clash with the code to load + // the song keysound effects by overwriting the target address. + m_request_extra_data = true; + } + + m_target_buffer = data; + + LOGMASKED(LOG_COMM, "target_buffer_w: %04x (%08x)\n", data, m_target_addr); +} + +void jaleco_vj_isa16_sound_device::sound_data_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + LOGMASKED(LOG_SOUND, "sound_data_w: %08x %04x\n", m_target_addr, data); + + m_ymzram[m_target_addr] = BIT(data, 0, 8); + m_ymzram2[m_target_addr] = BIT(data, 8, 8); + m_target_addr++; +} + +uint16_t jaleco_vj_isa16_sound_device::unkc_r(offs_t offset, uint16_t mem_mask) +{ + // unkc_r and unke_r combined seem to do something together but it's unclear. + // The values read back are never used, but the number of times unke_r is called before unkc_r is unique for different situations. + // no calls to unke_r = writing additional BGM data + // 1 call to unke_r = a BGM/sound request that will overwrite the address using the value written to target_buffer_w + // 3 calls to unkc_r = preparing the thread that will write additional BGM data + // It may be a hack but it's the only unique action performed that can differentiate between the different types of requests. + if (!machine().side_effects_disabled()) { + LOGMASKED(LOG_COMM, "unkc_r: %d\n", m_unke_read_cnt); + + if (m_unke_read_cnt == 0) { + m_request_extra_data = false; + m_receiving_extra_data = true; + } else { + m_receiving_extra_data = false; + } + + m_unke_read_cnt = 0; + } + + return 0; +} + +uint16_t jaleco_vj_isa16_sound_device::unke_r(offs_t offset, uint16_t mem_mask) +{ + if (!machine().side_effects_disabled()) { + m_unke_read_cnt++; + LOGMASKED(LOG_COMM, "unke_r: %d\n", m_unke_read_cnt); + } + return 0; +} + +void jaleco_vj_isa16_sound_device::comm_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + // 0x00XX - "Rewrite" (Skipped) + // 0x0100 - NOP? + // 0x0101 - Check video ready + // 0x0102 - COM_MSTART Start music + // 0x0103 - COM_STOP Stop video + // 0x0104 - Check music ready + // 0x0106 - COM_RESTART (restarts video, Stepping Stage only) + // 0x0107 - JSP dongle check (Stepping Stage only) + // 0x0165 - COM_INIT + // 0x029a - COM_START + // 0x03XX - Video load command + // 0x07XX - Music load command + LOGMASKED(LOG_COMM, "comm_w: %04x\n", data); + + m_comm = data; +} + +jaleco_vj_isa16_sound_device::jaleco_vj_isa16_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, JALECO_VJ_ISA16_SOUND, tag, owner, clock), + device_isa16_card_interface(mconfig, *this), + device_mixer_interface(mconfig, *this, 2), + m_ymz(*this, "ymz%u", 1), + m_ymzram(*this, "ymz_ram"), + m_ymzram2(*this, "ymz_ram2"), + m_response(0), + m_comm(0), + m_target_buffer(0), + m_target_addr(0), + m_unke_read_cnt(0), + m_request_extra_data(false), + m_receiving_extra_data(false), + m_is_checking_additional_bgm(false), + m_is_steppingstage(false) +{ +} + +void jaleco_vj_isa16_sound_device::device_add_mconfig(machine_config &config) +{ + // BGM normal + YMZ280B(config, m_ymz[0], 16.9344_MHz_XTAL); + m_ymz[0]->set_addrmap(0, &jaleco_vj_isa16_sound_device::ymz280b_map); + m_ymz[0]->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 0); + + // BGM subwoofer + YMZ280B(config, m_ymz[1], 16.9344_MHz_XTAL); + m_ymz[1]->set_addrmap(0, &jaleco_vj_isa16_sound_device::ymz280b_map2); + m_ymz[1]->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1); +} + +void jaleco_vj_isa16_sound_device::device_start() +{ + set_isa_device(); + + save_item(NAME(m_response)); + save_item(NAME(m_comm)); + save_item(NAME(m_target_buffer)); + save_item(NAME(m_target_addr)); + save_item(NAME(m_unke_read_cnt)); + save_item(NAME(m_request_extra_data)); + save_item(NAME(m_receiving_extra_data)); + save_item(NAME(m_is_checking_additional_bgm)); + save_item(NAME(m_is_steppingstage)); +} + +void jaleco_vj_isa16_sound_device::device_reset() +{ + m_response = 0; + m_comm = 0; + m_target_buffer = 0; + m_target_addr = 0; + m_unke_read_cnt = 0; + m_request_extra_data = false; + m_receiving_extra_data = false; + m_is_checking_additional_bgm = false; +} + +void jaleco_vj_isa16_sound_device::ymz280b_map(address_map &map) +{ + map(0x000000, 0xffffff).ram().share(m_ymzram); +} + +void jaleco_vj_isa16_sound_device::ymz280b_map2(address_map &map) +{ + map(0x000000, 0xffffff).ram().share(m_ymzram2); +} + +void jaleco_vj_isa16_sound_device::io_map(address_map &map) +{ + map(0x00, 0x01).r(FUNC(jaleco_vj_isa16_sound_device::comm_r)); + map(0x02, 0x02).r(FUNC(jaleco_vj_isa16_sound_device::unk2_r)); + map(0x04, 0x05).r(FUNC(jaleco_vj_isa16_sound_device::buffer_status_r)); + map(0x05, 0x06).w(FUNC(jaleco_vj_isa16_sound_device::response_w)); + map(0x08, 0x09).rw(FUNC(jaleco_vj_isa16_sound_device::target_buffer_r), FUNC(jaleco_vj_isa16_sound_device::target_buffer_w)); + map(0x0a, 0x0b).w(FUNC(jaleco_vj_isa16_sound_device::sound_data_w)); + map(0x0c, 0x0d).r(FUNC(jaleco_vj_isa16_sound_device::unkc_r)); + map(0x0e, 0x0f).r(FUNC(jaleco_vj_isa16_sound_device::unke_r)); +} + +void jaleco_vj_isa16_sound_device::remap(int space_id, offs_t start, offs_t end) +{ + if (space_id == AS_IO) { + m_isa->install_device(0x300, 0x30f, *this, &jaleco_vj_isa16_sound_device::io_map); + } +} + + +DEFINE_DEVICE_TYPE(JALECO_VJ_ISA16_SOUND, jaleco_vj_isa16_sound_device, "jaleco_vj_sound", "VJSlap ISA Sound Card") diff --git a/src/mame/jaleco/jaleco_vj_sound.h b/src/mame/jaleco/jaleco_vj_sound.h new file mode 100644 index 00000000000..a39d382fe89 --- /dev/null +++ b/src/mame/jaleco/jaleco_vj_sound.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +#ifndef MAME_JALECO_JALECO_VJ_SOUND_H +#define MAME_JALECO_JALECO_VJ_SOUND_H + +#pragma once + +#include "bus/isa/isa.h" +#include "sound/ymz280b.h" + + +class jaleco_vj_isa16_sound_device : + public device_t, + public device_isa16_card_interface, + public device_mixer_interface +{ +public: + // construction/destruction + jaleco_vj_isa16_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void set_steppingstage_mode(bool mode) { m_is_steppingstage = mode; } // TODO: Split this out into a device specific to Stepping Stage + + uint16_t response_r(offs_t offset, uint16_t mem_mask = ~0); + void comm_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + + void ymz_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) + { + if (ACCESSING_BITS_0_7) + m_ymz[0]->write(offset, BIT(data, 0, 8)); + if (ACCESSING_BITS_8_15) + m_ymz[1]->write(offset, BIT(data, 8, 8)); + } + + virtual void remap(int space_id, offs_t start, offs_t end) override; + +protected: + // device_t implementation + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +private: + uint8_t comm_r(offs_t offset); + uint8_t unk2_r(offs_t offset); + uint16_t buffer_status_r(offs_t offset, uint16_t mem_mask = ~0); + void response_w(offs_t offset, uint8_t data); + uint16_t target_buffer_r(offs_t offset, uint16_t mem_mask = ~0); + void target_buffer_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + void sound_data_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t unkc_r(offs_t offset, uint16_t mem_mask = ~0); + uint16_t unke_r(offs_t offset, uint16_t mem_mask = ~0); + + void io_map(address_map &map) ATTR_COLD; + void ymz280b_map(address_map &map) ATTR_COLD; + void ymz280b_map2(address_map &map) ATTR_COLD; + + required_device_array m_ymz; + required_shared_ptr m_ymzram; + required_shared_ptr m_ymzram2; + + uint16_t m_response; + uint16_t m_comm; + uint16_t m_target_buffer; + uint32_t m_target_addr; + uint32_t m_unke_read_cnt; + bool m_request_extra_data; + bool m_receiving_extra_data; + bool m_is_checking_additional_bgm; + + bool m_is_steppingstage; +}; + + +DECLARE_DEVICE_TYPE(JALECO_VJ_ISA16_SOUND, jaleco_vj_isa16_sound_device) + +#endif // MAME_JALECO_JALECO_VJ_SOUND_H diff --git a/src/mame/jaleco/jaleco_vj_ups.cpp b/src/mame/jaleco/jaleco_vj_ups.cpp new file mode 100644 index 00000000000..8bc98e629b9 --- /dev/null +++ b/src/mame/jaleco/jaleco_vj_ups.cpp @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +/* + * Densei UPS for VJ + */ + +#include "emu.h" +#include "jaleco_vj_ups.h" + + +namespace { + +class jaleco_vj_ups_device : public device_t, public device_rs232_port_interface +{ +public: + jaleco_vj_ups_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; +}; + + +jaleco_vj_ups_device::jaleco_vj_ups_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, JALECO_VJ_UPS, tag, owner, clock) + , device_rs232_port_interface(mconfig, *this) +{ +} + +void jaleco_vj_ups_device::device_start() +{ +} + +void jaleco_vj_ups_device::device_reset() +{ + // TODO: provide a way for the user to change the status? + output_cts(1); // line power down + output_dsr(1); // line shutdown + output_dcd(0); // line low battery +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(JALECO_VJ_UPS, device_rs232_port_interface, jaleco_vj_ups_device, "rs232_densei_ups", "RS232 Densei UPS") diff --git a/src/mame/jaleco/jaleco_vj_ups.h b/src/mame/jaleco/jaleco_vj_ups.h new file mode 100644 index 00000000000..d071b0d6afb --- /dev/null +++ b/src/mame/jaleco/jaleco_vj_ups.h @@ -0,0 +1,13 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +#ifndef MAME_JALECO_JALECO_VJ_UPS_H +#define MAME_JALECO_JALECO_VJ_UPS_H + +#pragma once + +#include "bus/rs232/rs232.h" + + +DECLARE_DEVICE_TYPE(JALECO_VJ_UPS, device_rs232_port_interface) + +#endif // MAME_JALECO_JALECO_VJ_UPS_H diff --git a/src/mame/jaleco/tetrisp2.cpp b/src/mame/jaleco/tetrisp2.cpp index 25033b12e04..a355466e504 100644 --- a/src/mame/jaleco/tetrisp2.cpp +++ b/src/mame/jaleco/tetrisp2.cpp @@ -523,11 +523,6 @@ void stepstag_state::stepstag_b00000_w(u16 data) vj_upload_fini = false; } -void stepstag_state::stepstag_main2pc_w(u16 data) -{ - popmessage("cmd @ pc: 0x%x\n", data); -} - u16 stepstag_state::stepstag_sprite_status_status_r() { // Guessed based on usage, but this is checked to make sure @@ -540,11 +535,6 @@ u16 stepstag_state::unknown_read_0xffff00() return machine().rand(); } -u16 stepstag_state::stepstag_pc2main_r() -{ - return 0xffff; -} - void stepstag_state::stepstag_soundlatch_word_w(u16 data) { m_soundlatch->write(data); @@ -726,7 +716,7 @@ void stepstag_state::adv7176a_w(u16 data) logerror("Mode register 0\n"); logerror("\tencode mode control %02x ", encode_mode_control); - switch(encode_mode_control) + switch (encode_mode_control) { case 0b00: logerror("NTSC\n"); break; case 0b01: logerror("PAL (B, D, G, H, I)\n"); break; @@ -737,7 +727,7 @@ void stepstag_state::adv7176a_w(u16 data) logerror("\tpedestal control %02x %s\n", pedestal_control, pedestal_control ? "on" : "off"); logerror("\tluminance filter control %02x ", luminance_filter_control); - switch(luminance_filter_control) + switch (luminance_filter_control) { case 0b00: logerror("Low pass filter (A)\n"); break; case 0b01: logerror("Notch filter\n"); break; @@ -762,7 +752,7 @@ void stepstag_state::adv7176a_w(u16 data) logerror("Mode register 1\n"); logerror("\tinterlaced mode control %02x %s\n", interlaced_mode_control, interlaced_mode_control ? "non-interlaced" : "interlaced"); logerror("\tclosed captioning field control %02x ", closed_captioning_field_control); - switch(closed_captioning_field_control) + switch (closed_captioning_field_control) { case 0b00: logerror("No data out\n"); break; case 0b01: logerror("Odd field only\n"); break; @@ -798,7 +788,7 @@ void stepstag_state::adv7176a_w(u16 data) logerror("\tblank control %02x %s\n", blank_control, blank_control ? "disable" : "enable"); logerror("\tluma delay %02x ", luma_delay_control); - switch(luma_delay_control) + switch (luma_delay_control) { case 0b00: logerror("0ns delay\n"); break; case 0b01: logerror("74ns delay\n"); break; @@ -819,7 +809,7 @@ void stepstag_state::adv7176a_w(u16 data) logerror("Timing register 1\n"); auto d = 1; - switch(hsync_width) + switch (hsync_width) { case 0b00: d = 1; break; case 0b01: d = 4; break; @@ -827,7 +817,7 @@ void stepstag_state::adv7176a_w(u16 data) case 0b11: d = 128; break; } logerror("\thsync width %02x %d\n", hsync_width, d); - switch(hsync_to_vsync_delay) + switch (hsync_to_vsync_delay) { case 0b00: d = 0; break; case 0b01: d = 4; break; @@ -852,7 +842,7 @@ void stepstag_state::adv7176a_w(u16 data) logerror("Mode register 2\n"); logerror("\tsquare pixel control %02x %s\n", square_pixel_mode_control, square_pixel_mode_control ? "enable" : "disable"); logerror("\tgenlock control %02x ", genlock_control); - switch(genlock_control) + switch (genlock_control) { case 0b00: case 0b10: logerror("Disable genlock\n"); break; @@ -918,12 +908,12 @@ void stepstag_state::stepstag_map(address_map &map) map(0xa10000, 0xa10001).portr("RHYTHM").w(FUNC(stepstag_state::stepstag_step_leds_w)); // I/O map(0xa20000, 0xa20001).nopr().w(FUNC(stepstag_state::stepstag_button_leds_w)); // I/O map(0xa30000, 0xa30001).r(FUNC(stepstag_state::stepstag_soundvolume_r)).nopw(); // Sound Volume - map(0xa42000, 0xa42001).r(FUNC(stepstag_state::stepstag_pc2main_r)); + map(0xa42000, 0xa42001).r(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::response_r)); map(0xa44000, 0xa44001).nopr(); // watchdog - map(0xa48000, 0xa48001).w(FUNC(stepstag_state::stepstag_main2pc_w)); // PC Comm + map(0xa48000, 0xa48001).w(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::comm_w)); // map(0xa4c000, 0xa4c001).noprw(); // Related to 0xa60000 map(0xa50000, 0xa50001).r(m_soundlatch, FUNC(generic_latch_16_device::read)).w(FUNC(stepstag_state::stepstag_soundlatch_word_w)); - map(0xa60000, 0xa60003).w("ymz", FUNC(ymz280b_device::write)).umask16(0x00ff); // Sound + map(0xa60000, 0xa60003).w(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::ymz_w)); map(0xb00000, 0xb00001).w(FUNC(stepstag_state::stepstag_b00000_w)); // init xilinx uploading?? map(0xb20000, 0xb20001).w(FUNC(stepstag_state::stepstag_b20000_w)); // 98343 interface board xilinx uploading? @@ -974,9 +964,9 @@ void stepstag_state::stepstag_sub_map(address_map &map) // map(0xac0000, 0xac0001).nopw(); // cleared at boot // The code for PC comms fully exists in VJ but it doesn't appear to ever be called - // map(0xa42000, 0xa42001).r(":jaleco_vj_pc:isa1:jaleco_vj_sound", FUNC(jaleco_vj_isa16_sound_device::response_r)); - // map(0xa44000, 0xa44001).nopr(); // watchdog - // map(0xa48000, 0xa48001).w(":jaleco_vj_pc:isa1:jaleco_vj_sound", FUNC(jaleco_vj_isa16_sound_device::comm_w)); + //map(0xa42000, 0xa42001).r(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::response_r)); + //map(0xa44000, 0xa44001).nopr(); // watchdog + //map(0xa48000, 0xa48001).w(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::comm_w)); map(0xb00000, 0xb00001).rw(m_soundlatch, FUNC(generic_latch_16_device::read), FUNC(generic_latch_16_device::write)); @@ -1762,12 +1752,6 @@ void tetrisp2_state::init_rockn3() m_rockn_protectdata = 4; } -void stepstag_state::init_stepstag() -{ - init_rockn_timer(); // used - m_rockn_protectdata = 1; // unused? -} - WRITE_LINE_MEMBER(tetrisp2_state::field_irq_w) { // irq1 is valid on all games but tetrisp2, but always masked by SR? @@ -2137,9 +2121,10 @@ void stepstag_state::stepstag(machine_config &config) GENERIC_LATCH_16(config, m_soundlatch); - ymz280b_device &ymz(YMZ280B(config, "ymz", subxtal/3)); // unknown - ymz.add_route(0, "lspeaker", 1.0); - ymz.add_route(1, "rspeaker", 1.0); + JALECO_VJ_PC(config, m_jaleco_vj_pc, 0); + m_jaleco_vj_pc->set_steppingstage_mode(true); + m_jaleco_vj_pc->add_route(0, "lspeaker", 1.0); + m_jaleco_vj_pc->add_route(1, "rspeaker", 1.0); } void stepstag_state::vjdash(machine_config &config) // 4 Screens @@ -2224,9 +2209,10 @@ void stepstag_state::vjdash(machine_config &config) // 4 Screens GENERIC_LATCH_16(config, m_soundlatch); - ymz280b_device &ymz(YMZ280B(config, "ymz", subxtal/3)); // unknown - ymz.add_route(0, "lspeaker", 1.0); - ymz.add_route(1, "rspeaker", 1.0); + JALECO_VJ_PC(config, m_jaleco_vj_pc, 0); + m_jaleco_vj_pc->set_steppingstage_mode(false); + m_jaleco_vj_pc->add_route(0, "lspeaker", 1.0); + m_jaleco_vj_pc->add_route(1, "rspeaker", 1.0); } void stepstag_state::machine_start() @@ -3251,9 +3237,6 @@ ROM_START( vjdasha ) ROM_REGION( 0x010000, "xilinx", 0 ) // XILINX CPLD ROM_LOAD( "15c.ic49", 0x000000, 38807, CRC(60d50907) SHA1(c5a837b3105ba15fcec103154c8c4d00924974e1) ) - ROM_REGION( 0x400000, "ymz", ROMREGION_ERASE ) // Samples - ROM_LOAD( "vjdash-sound", 0x000000, 0x400000, NO_DUMP ) - DISK_REGION( "jaleco_vj_pc:pci:07.1:ide1:0:hdd:image" ) DISK_IMAGE( "vj_ver1", 0, SHA1(bf5c70fba13186854ff0b7eafab07dd527aac663) BAD_DUMP ) ROM_END @@ -3304,9 +3287,6 @@ ROM_START( stepstag ) ROM_REGION( 0x400000, "gfx3", ROMREGION_ERASE ) /* 16x16x8 (Rotation) */ ROM_LOAD( "stepstag_rott", 0x000000, 0x400000, NO_DUMP ) - ROM_REGION( 0x400000, "ymz", ROMREGION_ERASE ) // Samples - ROM_LOAD( "stepstag-sound", 0x000000, 0x400000, NO_DUMP ) - DISK_REGION( "jaleco_vj_pc:pci:07.1:ide1:0:hdd:image" ) DISK_IMAGE( "stepstag", 0, NO_DUMP ) ROM_END @@ -3357,9 +3337,6 @@ ROM_START( step3 ) ROM_REGION( 0x400000, "gfx3", ROMREGION_ERASE ) /* 16x16x8 (Rotation) */ - ROM_REGION( 0x400000, "ymz", ROMREGION_ERASE ) /* Samples */ - ROM_LOAD( "step3-sound", 0x000000, 0x400000, NO_DUMP ) - DISK_REGION( "jaleco_vj_pc:pci:07.1:ide1:0:hdd:image" ) DISK_IMAGE( "step3", 0, SHA1(926a32998c837f7ba45d07db243c43c1f9d46d6a) ) ROM_END @@ -3399,5 +3376,5 @@ GAME( 1999, vjdasha, vjslap, vjdash, vjdash, stepstag_state, empty_init // - Stepping Stage <- the original Game // - Stepping Stage 2 Supreme // Dumped (partially): -GAME( 1999, stepstag, 0, stepstag, stepstag, stepstag_state, init_stepstag, ROT0, "Jaleco", "Stepping Stage Special", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) -GAME( 1999, step3, 0, stepstag, stepstag, stepstag_state, init_stepstag, ROT0, "Jaleco", "Stepping 3 Superior", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) +GAME( 1999, stepstag, 0, stepstag, stepstag, stepstag_state, empty_init, ROT0, "Jaleco", "Stepping Stage Special", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) +GAME( 1999, step3, 0, stepstag, stepstag, stepstag_state, empty_init, ROT0, "Jaleco", "Stepping 3 Superior", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) diff --git a/src/mame/jaleco/tetrisp2.h b/src/mame/jaleco/tetrisp2.h index cd2f516aa42..4c0807d909d 100644 --- a/src/mame/jaleco/tetrisp2.h +++ b/src/mame/jaleco/tetrisp2.h @@ -6,6 +6,7 @@ #pragma once #include "jaleco_ms32_sysctrl.h" +#include "jaleco_vj_pc.h" #include "ms32_sprite.h" #include "machine/gen_latch.h" @@ -222,6 +223,7 @@ public: , m_vj_paletteram_m(*this, "paletteram2") , m_vj_paletteram_r(*this, "paletteram3") , m_soundlatch(*this, "soundlatch") + , m_jaleco_vj_pc(*this, "jaleco_vj_pc") , m_soundvr(*this, "SOUND_VR%u", 1) , m_rscreen(*this, "rscreen") { } @@ -229,8 +231,6 @@ public: void stepstag(machine_config &config); void vjdash(machine_config &config); - void init_stepstag(); - DECLARE_VIDEO_START(stepstag); protected: @@ -243,10 +243,8 @@ private: bool vj_upload_fini = false; void stepstag_b00000_w(u16 data); void stepstag_b20000_w(offs_t offset, u16 data, u16 mem_mask = ~0); - void stepstag_main2pc_w(u16 data); u16 stepstag_sprite_status_status_r(); u16 unknown_read_0xffff00(); - u16 stepstag_pc2main_r(); void stepstag_soundlatch_word_w(u16 data); void stepstag_neon_w(offs_t offset, u16 data, u16 mem_mask = ~0); void stepstag_step_leds_w(offs_t offset, u16 data, u16 mem_mask = ~0); @@ -295,6 +293,7 @@ private: optional_shared_ptr m_vj_paletteram_m; optional_shared_ptr m_vj_paletteram_r; required_device m_soundlatch; + required_device m_jaleco_vj_pc; optional_ioport_array<2> m_soundvr; required_device m_rscreen; diff --git a/src/mame/taito/cchance.cpp b/src/mame/taito/cchance.cpp index 6dc2f7f078b..9df0431a591 100644 --- a/src/mame/taito/cchance.cpp +++ b/src/mame/taito/cchance.cpp @@ -29,14 +29,14 @@ cha1 $dc81 cha2 $cca8 cha3 $10d8 -2 color proms for the output. will get those dumped as well. +2 color PROMs for the output. will get those dumped as well. *****************************************************************************************************************************/ #include "emu.h" -#include "tnzs.h" +#include "tnzs_video.h" #include "cpu/z80/z80.h" #include "sound/ay8910.h" @@ -228,8 +228,8 @@ void cchance_state::cchance(machine_config &config) m_maincpu->set_vblank_int("screen", FUNC(cchance_state::irq0_line_hold)); X1_001(config, m_spritegen, 12_MHz_XTAL, m_palette, gfx_cchance); - m_spritegen->set_fg_yoffsets( -0x12, 0x0e ); - m_spritegen->set_bg_yoffsets( 0x1, -0x1 ); + m_spritegen->set_fg_yoffsets(-0x12, 0x0e); + m_spritegen->set_bg_yoffsets(0x1, -0x1); // video hardware SCREEN(config, m_screen, SCREEN_TYPE_RASTER); @@ -261,7 +261,7 @@ ROM_START( cchance ) ROM_LOAD("chance-cccha2.bin", 0x10000, 0x10000, CRC(fa5ccf5b) SHA1(21957a6a7b88c315d1fbb82e98a924a637a28397) ) ROM_LOAD("chance-cccha3.bin", 0x00000, 0x10000, CRC(2a2979c9) SHA1(5036313e219ec561fa6753f0db6bb28c6fc97963) ) - ROM_REGION( 0x0400, "proms", 0 ) /* color proms */ + ROM_REGION( 0x0400, "proms", 0 ) // color PROMs ROM_LOAD( "prom1", 0x0000, 0x0200, NO_DUMP ) ROM_LOAD( "prom2", 0x0200, 0x0200, NO_DUMP ) ROM_END diff --git a/src/mame/taito/tnzs.cpp b/src/mame/taito/tnzs.cpp index 9fbeae7d782..c1debfd699e 100644 --- a/src/mame/taito/tnzs.cpp +++ b/src/mame/taito/tnzs.cpp @@ -664,19 +664,764 @@ d23f=input port 1 value ***************************************************************************/ #include "emu.h" -#include "tnzs.h" -#include "taitoipt.h" +#include "taitoipt.h" +#include "tnzs_video.h" + +#include "cpu/mcs48/mcs48.h" #include "cpu/z80/z80.h" +#include "machine/gen_latch.h" +#include "machine/upd4701.h" +#include "sound/dac.h" +#include "sound/samples.h" #include "sound/ymopm.h" #include "sound/ymopn.h" -#include "screen.h" + #include "speaker.h" //#define VERBOSE 1 #include "logmacro.h" +namespace { + +class insectx_state : public tnzs_video_state_base +{ +public: + insectx_state(const machine_config &mconfig, device_type type, const char *tag) + : tnzs_video_state_base(mconfig, type, tag) + , m_subcpu(*this, "sub") + , m_subbank(*this, "subbank") + , m_ramromview(*this, "ramrom") + { } + + void insectx(machine_config &config) ATTR_COLD; + +protected: + void tnzs_base(machine_config &config) ATTR_COLD; + + virtual void machine_start() override ATTR_COLD; + + void ramrom_bankswitch_w(uint8_t data); + + void prompal_main_map(address_map &map) ATTR_COLD; + void rampal_main_map(address_map &map) ATTR_COLD; + + void base_sub_map(address_map &map) ATTR_COLD; + + // devices + required_device m_subcpu; + required_memory_bank m_subbank; + +private: + void insectx_bankswitch1_w(uint8_t data); + + void insectx_sub_map(address_map &map) ATTR_COLD; + + memory_view m_ramromview; +}; + + +class tnzs_mcu_state : public insectx_state +{ +public: + tnzs_mcu_state(const machine_config &mconfig, device_type type, const char *tag) + : insectx_state(mconfig, type, tag) + , m_mcu(*this, "mcu") + , m_in0(*this, "IN0") + , m_in1(*this, "IN1") + , m_in2(*this, "IN2") + , m_input_select(0) + { } + + void tnzs(machine_config &config) ATTR_COLD; + void extrmatn(machine_config &config) ATTR_COLD; + +protected: + void tnzs_bankswitch1_w(uint8_t data); + uint8_t mcu_port1_r(); + template void mcu_port2_w(uint8_t data); + uint8_t mcu_r(offs_t offset); + void mcu_w(offs_t offset, uint8_t data); + + template void tnzs_mcu(machine_config &config) ATTR_COLD; + + void tnzs_sub_map(address_map &map) ATTR_COLD; + + required_device m_mcu; + + required_ioport m_in0; + required_ioport m_in1; + required_ioport m_in2; + + uint8_t m_input_select; +}; + + +class plumppop_state : public tnzs_mcu_state +{ +public: + plumppop_state(const machine_config &mconfig, device_type type, const char *tag) + : tnzs_mcu_state(mconfig, type, tag) + , m_upd4701(*this, "upd4701") + { + } + + void plumppop(machine_config &config) ATTR_COLD; + +protected: + void plumppop_bankswitch1_w(uint8_t data); + + void plumppop_sub_map(address_map &map) ATTR_COLD; + + required_device m_upd4701; +}; + + +class arknoid2_state : public plumppop_state +{ +public: + arknoid2_state(const machine_config &mconfig, device_type type, const char *tag) + : plumppop_state(mconfig, type, tag) + , m_coin1(*this, "COIN1") + , m_coin2(*this, "COIN2") + { } + + void arknoid2(machine_config &config) ATTR_COLD; + +private: + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD; + + void arknoid2_bankswitch1_w(uint8_t data); + + uint8_t mcu_r(offs_t offset); + void mcu_w(offs_t offset, uint8_t data); + INTERRUPT_GEN_MEMBER(mcu_interrupt); + + void arknoid2_sub_map(address_map &map) ATTR_COLD; + + void mcu_reset(); + void mcu_handle_coins(int coin); + + required_ioport m_coin1; + required_ioport m_coin2; + + int m_mcu_initializing = 0; + int m_mcu_coinage_init = 0; + int m_mcu_command = 0; + int m_mcu_readcredits = 0; + int m_mcu_reportcoin = 0; + int m_insertcoin = 0; + uint8_t m_mcu_coinage[4]{}; + uint8_t m_mcu_coins_a = 0; + uint8_t m_mcu_coins_b = 0; + uint8_t m_mcu_credits = 0; +}; + + +class kageki_state : public insectx_state +{ +public: + kageki_state(const machine_config &mconfig, device_type type, const char *tag) + : insectx_state(mconfig, type, tag) + , m_samples(*this, "samples") + , m_dswa(*this, "DSWA") + , m_dswb(*this, "DSWB") + , m_csport_sel(0) + { } + + void kageki(machine_config &config) ATTR_COLD; + + void init_kageki() ATTR_COLD; + +protected: + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD; + +private: + static constexpr unsigned MAX_SAMPLES = 0x2f; + + void kageki_bankswitch1_w(uint8_t data); + + uint8_t csport_r(); + void csport_w(uint8_t data); + + SAMPLES_START_CB_MEMBER(init_samples); + + void kageki_sub_map(address_map &map) ATTR_COLD; + + required_device m_samples; + + required_ioport m_dswa; + required_ioport m_dswb; + + // sound-related + std::unique_ptr m_sampledata[MAX_SAMPLES]; + int m_samplesize[MAX_SAMPLES]{}; + + int m_csport_sel; +}; + + +class jpopnics_state : public insectx_state +{ +public: + jpopnics_state(const machine_config &mconfig, device_type type, const char *tag) + : insectx_state(mconfig, type, tag) + , m_upd4701(*this, "upd4701") + { } + + void jpopnics(machine_config &config) ATTR_COLD; + +private: + void subbankswitch_w(uint8_t data); + + void jpopnics_main_map(address_map &map) ATTR_COLD; + void jpopnics_sub_map(address_map &map) ATTR_COLD; + + required_device m_upd4701; +}; + + +class tnzsb_state : public insectx_state +{ +public: + tnzsb_state(const machine_config &mconfig, device_type type, const char *tag) + : insectx_state(mconfig, type, tag) + , m_audiocpu(*this, "audiocpu") + , m_soundlatch(*this, "soundlatch") + { } + + void tnzsb(machine_config &config) ATTR_COLD; + +protected: + DECLARE_WRITE_LINE_MEMBER(ym2203_irqhandler); + + void sound_command_w(uint8_t data); + + void tnzsb_bankswitch1_w(uint8_t data); + + void tnzsb_base_sub_map(address_map &map) ATTR_COLD; + void tnzsb_sub_map(address_map &map) ATTR_COLD; + void tnzsb_cpu2_map(address_map &map) ATTR_COLD; + void tnzsb_io_map(address_map &map) ATTR_COLD; + + required_device m_audiocpu; + required_device m_soundlatch; +}; + + +class kabukiz_state : public tnzsb_state +{ +public: + kabukiz_state(const machine_config &mconfig, device_type type, const char *tag) + : tnzsb_state(mconfig, type, tag) + , m_audiobank(*this, "audiobank") + { } + + void kabukiz(machine_config &config) ATTR_COLD; + +protected: + virtual void machine_start() override ATTR_COLD; + +private: + void sound_bank_w(uint8_t data); + + void kabukiz_cpu2_map(address_map &map) ATTR_COLD; + void kabukiz_sub_map(address_map &map) ATTR_COLD; + + required_memory_bank m_audiobank; +}; + + +/*************************************************************************** + + Functions to emulate general aspects of the machine (RAM, ROM, interrupts, + I/O ports) + + The I8742 MCU takes care of handling the coin inputs and the tilt switch. + To simulate this, we read the status in the interrupt handler for the main + CPU and update the counters appropriately. We also must take care of + handling the coin/credit settings ourselves. + +***************************************************************************/ + +uint8_t tnzs_mcu_state::mcu_r(offs_t offset) +{ + uint8_t data = m_mcu->upi41_master_r(offset & 1); + m_subcpu->yield(); + +// logerror("%s: read %02x from mcu $c00%01x\n", m_maincpu->pcbase(), data, offset); + + return data; +} + +void tnzs_mcu_state::mcu_w(offs_t offset, uint8_t data) +{ +// logerror("%s: write %02x to mcu $c00%01x\n", m_maincpu->pcbase(), data, offset); + + m_mcu->upi41_master_w(offset & 1, data); +} + +uint8_t tnzs_mcu_state::mcu_port1_r() +{ + int data = 0; + + switch (m_input_select) + { + case 0x0a: data = m_in2->read(); break; + case 0x0c: data = m_in0->read(); break; + case 0x0d: data = m_in1->read(); break; + default: data = 0xff; break; + } + +// logerror("%s: Read %02x from port 1\n", m_maincpu->pcbase(), data); + + return data; +} + +template +void tnzs_mcu_state::mcu_port2_w(uint8_t data) +{ + machine().bookkeeping().coin_lockout_w(0, (data & 0x40) ? LockoutLevel : !LockoutLevel); + machine().bookkeeping().coin_lockout_w(1, (data & 0x80) ? LockoutLevel : !LockoutLevel); + machine().bookkeeping().coin_counter_w(0, (~data & 0x10)); + machine().bookkeeping().coin_counter_w(1, (~data & 0x20)); + + m_input_select = data & 0xf; +} + +template void tnzs_mcu_state::mcu_port2_w(uint8_t); +template void tnzs_mcu_state::mcu_port2_w(uint8_t); + +void arknoid2_state::mcu_reset() +{ + m_mcu_initializing = 3; + m_mcu_coinage_init = 0; + m_mcu_coinage[0] = 1; + m_mcu_coinage[1] = 1; + m_mcu_coinage[2] = 1; + m_mcu_coinage[3] = 1; + m_mcu_coins_a = 0; + m_mcu_coins_b = 0; + m_mcu_credits = 0; + m_mcu_reportcoin = 0; + m_mcu_command = 0; +} + +void arknoid2_state::mcu_handle_coins(int coin) +{ + /* The coin inputs and coin counters are managed by the i8742 mcu. */ + /* Here we simulate it. */ + /* Credits are limited to 9, so more coins should be rejected */ + /* Coin/Play settings must also be taken into consideration */ + + if (coin & 0x08) /* tilt */ + m_mcu_reportcoin = coin; + else if (coin && coin != m_insertcoin) + { + if (coin & 0x01) /* coin A */ + { +// logerror("Coin dropped into slot A\n"); + machine().bookkeeping().coin_counter_w(0,1); machine().bookkeeping().coin_counter_w(0,0); /* Count slot A */ + m_mcu_coins_a++; + if (m_mcu_coins_a >= m_mcu_coinage[0]) + { + m_mcu_coins_a -= m_mcu_coinage[0]; + m_mcu_credits += m_mcu_coinage[1]; + if (m_mcu_credits >= 9) + { + m_mcu_credits = 9; + machine().bookkeeping().coin_lockout_global_w(1); /* Lock all coin slots */ + } + else + { + machine().bookkeeping().coin_lockout_global_w(0); /* Unlock all coin slots */ + } + } + } + + if (coin & 0x02) /* coin B */ + { +// logerror("Coin dropped into slot B\n"); + machine().bookkeeping().coin_counter_w(1,1); machine().bookkeeping().coin_counter_w(1,0); /* Count slot B */ + m_mcu_coins_b++; + if (m_mcu_coins_b >= m_mcu_coinage[2]) + { + m_mcu_coins_b -= m_mcu_coinage[2]; + m_mcu_credits += m_mcu_coinage[3]; + if (m_mcu_credits >= 9) + { + m_mcu_credits = 9; + machine().bookkeeping().coin_lockout_global_w(1); /* Lock all coin slots */ + } + else + { + machine().bookkeeping().coin_lockout_global_w(0); /* Unlock all coin slots */ + } + } + } + + if (coin & 0x04) /* service */ + { +// logerror("Coin dropped into service slot C\n"); + m_mcu_credits++; + } + + m_mcu_reportcoin = coin; + } + else + { + if (m_mcu_credits < 9) + machine().bookkeeping().coin_lockout_global_w(0); /* Unlock all coin slots */ + + m_mcu_reportcoin = 0; + } + m_insertcoin = coin; +} + +/********************************* + +TNZS sync bug kludge + +In all TNZS versions there is code like this: + +0C5E: ld ($EF10),a +0C61: ld a,($EF10) +0C64: inc a +0C65: ret nz +0C66: jr $0C61 + +which is sometimes executed by the main cpu when it writes to shared RAM a +command for the second CPU. The intended purpose of the code is to wait an +acknowledge from the sub CPU: the sub CPU writes FF to the same location +after reading the command. + +However the above code is wrong. The "ret nz" instruction means that the +loop will be exited only when the contents of $EF10 are *NOT* $FF!! +On the real board, this casues little harm: the main CPU will just write +the command, read it back and, since it's not $FF, return immediately. There +is a chance that the command might go lost, but this will cause no major +harm, the worse that can happen is that the background tune will not change. + +In MAME, however, since CPU interleaving is not perfect, it can happen that +the main CPU ends its timeslice after writing to EF10 but before reading it +back. In the meantime, the sub CPU will run, read the command and write FF +there - therefore causing the main CPU to enter an endless loop. + +Unlike the usual sync problems in MAME, which can be fixed by increasing the +interleave factor, in this case increasing it will actually INCREASE the +chance of entering the endless loop - because it will increase the chances of +the main CPU ending its timeslice at the wrong moment. + +So what we do here is catch writes by the main CPU to the RAM location, and +process them using a timer, in order to +a) force a resync of the two CPUs +b) make sure the main CPU will be the first one to run after the location is + changed + +Since the answer from the sub CPU is ignored, we don't even need to boost +interleave. + +*********************************/ + +/* +TIMER_CALLBACK_MEMBER(insectx_state::kludge_callback) +{ + tnzs_sharedram[0x0f10] = param; +} + +void insectx_state::tnzs_sync_kludge_w(uint8_t data) +{ + machine().scheduler().synchronize(timer_expired_delegate(FUNC(insectx_state::kludge_callback),this), data); +} +*/ + +uint8_t arknoid2_state::mcu_r(offs_t offset) +{ + static const char mcu_startup[] = "\x55\xaa\x5a"; + + //logerror("%s: read mcu %04x\n", m_maincpu->pc(), 0xc000 + offset); + + if (offset == 0) + { + /* if the mcu has just been reset, return startup code */ + if (m_mcu_initializing) + { + m_mcu_initializing--; + return mcu_startup[2 - m_mcu_initializing]; + } + + switch (m_mcu_command) + { + case 0x41: + return m_mcu_credits; + + case 0xc1: + /* Read the credit counter or the inputs */ + if (m_mcu_readcredits == 0) + { + m_mcu_readcredits = 1; + if (m_mcu_reportcoin & 0x08) + { + m_mcu_initializing = 3; + return 0xee; /* tilt */ + } + else return m_mcu_credits; + } + else return m_in0->read(); /* buttons */ + + default: + logerror("error, unknown mcu command\n"); + /* should not happen */ + return 0xff; + } + } + else + { + /* + status bits: + 0 = mcu is ready to send data (read from c000) + 1 = mcu has read data (from c000) + 2 = unused + 3 = unused + 4-7 = coin code + 0 = nothing + 1,2,3 = coin switch pressed + e = tilt + */ + if (m_mcu_reportcoin & 0x08) return 0xe1; /* tilt */ + if (m_mcu_reportcoin & 0x01) return 0x11; /* coin 1 (will trigger "coin inserted" sound) */ + if (m_mcu_reportcoin & 0x02) return 0x21; /* coin 2 (will trigger "coin inserted" sound) */ + if (m_mcu_reportcoin & 0x04) return 0x31; /* coin 3 (will trigger "coin inserted" sound) */ + return 0x01; + } +} + +void arknoid2_state::mcu_w(offs_t offset, uint8_t data) +{ + if (offset == 0) + { + //logerror("%s: write %02x to mcu %04x\n", m_maincpu->pc(), data, 0xc000 + offset); + if (m_mcu_command == 0x41) + { + m_mcu_credits = (m_mcu_credits + data) & 0xff; + } + } + else + { + /* + 0xc1: read number of credits, then buttons + 0x54+0x41: add value to number of credits + 0x15: sub 1 credit (when "Continue Play" only) + 0x84: coin 1 lockout (issued only in test mode) + 0x88: coin 2 lockout (issued only in test mode) + 0x80: release coin lockout (issued only in test mode) + during initialization, a sequence of 4 bytes sets coin/credit settings + */ + //logerror("%s: write %02x to mcu %04x\n", m_maincpu->pc(), data, 0xc000 + offset); + + if (m_mcu_initializing) + { + /* set up coin/credit settings */ + m_mcu_coinage[m_mcu_coinage_init++] = data; + if (m_mcu_coinage_init == 4) + m_mcu_coinage_init = 0; /* must not happen */ + } + + if (data == 0xc1) + m_mcu_readcredits = 0; /* reset input port number */ + + if (data == 0x15) + { + m_mcu_credits = (m_mcu_credits - 1) & 0xff; + if (m_mcu_credits == 0xff) + m_mcu_credits = 0; + } + m_mcu_command = data; + } +} + +INTERRUPT_GEN_MEMBER(arknoid2_state::mcu_interrupt) +{ + int coin = ((m_coin1->read() & 1) << 0); + coin |= ((m_coin2->read() & 1) << 1); + coin |= ((m_in2->read() & 3) << 2); + coin ^= 0x0c; + mcu_handle_coins(coin); + + device.execute().set_input_line(0, HOLD_LINE); +} + +void arknoid2_state::machine_reset() +{ + plumppop_state::machine_reset(); + + // initialize the MCU simulation + mcu_reset(); + + m_mcu_readcredits = 0; + m_insertcoin = 0; +} + +void kageki_state::machine_reset() +{ + insectx_state::machine_reset(); + + m_csport_sel = 0; +} + +void insectx_state::machine_start() +{ + tnzs_video_state_base::machine_start(); + + uint8_t *const sub = memregion("sub")->base(); + m_subbank->configure_entries(0, 4, &sub[0x08000], 0x2000); + m_subbank->set_entry(0); + + m_ramromview.select(2); +} + +void arknoid2_state::machine_start() +{ + plumppop_state::machine_start(); + + save_item(NAME(m_mcu_readcredits)); + save_item(NAME(m_insertcoin)); + save_item(NAME(m_mcu_initializing)); + save_item(NAME(m_mcu_coinage_init)); + save_item(NAME(m_mcu_coinage)); + save_item(NAME(m_mcu_coins_a)); + save_item(NAME(m_mcu_coins_b)); + save_item(NAME(m_mcu_credits)); + save_item(NAME(m_mcu_reportcoin)); + save_item(NAME(m_mcu_command)); + + // kludge to make device work with active-high coin inputs + m_upd4701->left_w(0); + m_upd4701->middle_w(0); +} + +void kageki_state::machine_start() +{ + insectx_state::machine_start(); + + save_item(NAME(m_csport_sel)); +} + +void kabukiz_state::machine_start() +{ + tnzsb_state::machine_start(); + + uint8_t *sound = memregion("audiocpu")->base(); + m_audiobank->configure_entries(0, 8, &sound[0x00000], 0x4000); +} + +void insectx_state::ramrom_bankswitch_w(uint8_t data) +{ +// logerror("%s: writing %02x to bankswitch\n", m_maincpu->pc(),data); + + // bit 4 resets the second CPU + m_subcpu->set_input_line(INPUT_LINE_RESET, BIT(data, 4) ? CLEAR_LINE : ASSERT_LINE); + + // bits 0-2 select RAM/ROM bank + m_ramromview.select(data & 0x07); +} + +void arknoid2_state::arknoid2_bankswitch1_w(uint8_t data) +{ + // bits 0-1 select ROM bank + m_subbank->set_entry(data & 0x03); + + if (BIT(data, 2)) + mcu_reset(); + + // never actually written by arknoid2 (though code exists to do it) + m_upd4701->resetx_w(BIT(data, 5)); + m_upd4701->resety_w(BIT(data, 5)); +} + +void insectx_state::insectx_bankswitch1_w(uint8_t data) +{ + // bits 0-1 select ROM bank + m_subbank->set_entry(data & 0x03); + + machine().bookkeeping().coin_lockout_w(0, BIT(~data, 2)); + machine().bookkeeping().coin_lockout_w(1, BIT(~data, 3)); + machine().bookkeeping().coin_counter_w(0, BIT(data, 4)); + machine().bookkeeping().coin_counter_w(1, BIT(data, 5)); +} + +void tnzsb_state::tnzsb_bankswitch1_w(uint8_t data) +{ + // bits 0-1 select ROM bank + m_subbank->set_entry(data & 0x03); + + machine().bookkeeping().coin_lockout_w(0, BIT(~data, 4)); + machine().bookkeeping().coin_lockout_w(1, BIT(~data, 5)); + machine().bookkeeping().coin_counter_w(0, BIT(data, 2)); + machine().bookkeeping().coin_counter_w(1, BIT(data, 3)); +} + +void kageki_state::kageki_bankswitch1_w(uint8_t data) +{ + // bits 0-1 select ROM bank + m_subbank->set_entry(data & 0x03); + + machine().bookkeeping().coin_lockout_global_w(BIT(~data, 5)); + machine().bookkeeping().coin_counter_w(0, BIT(data, 2)); + machine().bookkeeping().coin_counter_w(1, BIT(data, 3)); +} + +void tnzs_mcu_state::tnzs_bankswitch1_w(uint8_t data) +{ + // bits 0-1 select ROM bank + m_subbank->set_entry(data & 0x03); + + if (BIT(data, 2)) + m_mcu->pulse_input_line(INPUT_LINE_RESET, attotime::zero); +} + +void plumppop_state::plumppop_bankswitch1_w(uint8_t data) +{ + tnzs_bankswitch1_w(data); + + // written only at startup by plumppop? + m_upd4701->resetx_w(BIT(data, 5)); + m_upd4701->resety_w(BIT(data, 5)); +} + +void jpopnics_state::subbankswitch_w(uint8_t data) +{ + // bits 0-1 select ROM bank + m_subbank->set_entry(data & 0x03); + + // written once at startup + m_upd4701->resetx_w(BIT(data, 5)); + m_upd4701->resety_w(BIT(data, 5)); +} + +void tnzsb_state::sound_command_w(uint8_t data) +{ + m_soundlatch->write(data); + m_audiocpu->set_input_line_and_vector(0, HOLD_LINE, 0xff); // Z80 +} + +// handler called by the 2203 emulator when the internal timers cause an IRQ +WRITE_LINE_MEMBER(tnzsb_state::ym2203_irqhandler) +{ + m_audiocpu->set_input_line(INPUT_LINE_NMI, state ? ASSERT_LINE : CLEAR_LINE); +} + +void kabukiz_state::sound_bank_w(uint8_t data) +{ + // to avoid the write when the sound chip is initialized + if (data != 0xff) + m_audiobank->set_entry(data & 0x07); +} + + SAMPLES_START_CB_MEMBER(kageki_state::init_samples) { uint8_t *src = memregion("samples")->base() + 0x0090; @@ -762,7 +1507,7 @@ void kageki_state::csport_w(uint8_t data) } } -void tnzs_base_state::prompal_main_map(address_map &map) +void insectx_state::prompal_main_map(address_map &map) { map(0x0000, 0x7fff).rom(); map(0x8000, 0xbfff).view(m_ramromview); @@ -776,25 +1521,35 @@ void tnzs_base_state::prompal_main_map(address_map &map) map(0xf000, 0xf2ff).rw(m_spritegen, FUNC(x1_001_device::spriteylow_r8), FUNC(x1_001_device::spriteylow_w8)); map(0xf300, 0xf303).mirror(0xfc).w(m_spritegen, FUNC(x1_001_device::spritectrl_w8)); // control registers (0x80 mirror used by Arkanoid 2) map(0xf400, 0xf400).w(m_spritegen, FUNC(x1_001_device::spritebgflag_w8)); // enable / disable background transparency - map(0xf600, 0xf600).nopr().w(FUNC(tnzs_base_state::ramrom_bankswitch_w)); + map(0xf600, 0xf600).nopr().w(FUNC(insectx_state::ramrom_bankswitch_w)); // arknoid2, extrmatn, plumppop and drtoppel have PROMs instead of RAM // drtoppel and kabukiz write here anyway! map(0xf800, 0xfbff).nopw(); } -void tnzs_base_state::rampal_main_map(address_map &map) + +/*************************************************************************** + + The New Zealand Story doesn't have a color PROM. It uses 1024 bytes of RAM + to dynamically create the palette. Each couple of bytes defines one + color (15 bits per pixel; the top bit of the second byte is unused). + Since the graphics use 4 bitplanes, hence 16 colors, this makes for 32 + different color codes. + +***************************************************************************/ + +void insectx_state::rampal_main_map(address_map &map) { prompal_main_map(map); map(0xf800, 0xfbff).ram().w(m_palette, FUNC(palette_device::write8)).share("palette"); } -void tnzs_base_state::base_sub_map(address_map &map) +void insectx_state::base_sub_map(address_map &map) { map(0x0000, 0x7fff).rom(); map(0x8000, 0x9fff).bankr(m_subbank); - map(0xa000, 0xa000).w(FUNC(tnzs_base_state::bankswitch1_w)); map(0xb000, 0xb001).rw("ymsnd", FUNC(ym2203_device::read), FUNC(ym2203_device::write)); map(0xd000, 0xdfff).ram(); map(0xe000, 0xefff).ram().share("share1"); @@ -804,17 +1559,24 @@ void tnzs_mcu_state::tnzs_sub_map(address_map &map) { base_sub_map(map); - map(0xc000, 0xc001).rw(FUNC(tnzs_mcu_state::mcu_r), FUNC(tnzs_mcu_state::mcu_w)); /* not present in insectx */ - map(0xa000, 0xa000).w(FUNC(tnzs_mcu_state::bankswitch1_w)); - map(0xf000, 0xf003).r(FUNC(tnzs_mcu_state::analog_r)); /* paddles in arkanoid2/plumppop. The ports are */ - /* read but not used by the other games, and are not read at */ - /* all by insectx. */ + map(0xa000, 0xa000).w(FUNC(tnzs_mcu_state::tnzs_bankswitch1_w)); + map(0xc000, 0xc001).rw(FUNC(tnzs_mcu_state::mcu_r), FUNC(tnzs_mcu_state::mcu_w)); + map(0xf000, 0xf003).nopr(); // paddles in arkanoid2/plumppop. The ports are read but not used by the other games, and are not read at all by insectx. +} + +void plumppop_state::plumppop_sub_map(address_map &map) +{ + tnzs_sub_map(map); + + map(0xa000, 0xa000).w(FUNC(plumppop_state::plumppop_bankswitch1_w)); + map(0xf000, 0xf003).r(m_upd4701, FUNC(upd4701_device::read_xy)); } void arknoid2_state::arknoid2_sub_map(address_map &map) { - tnzs_sub_map(map); + plumppop_sub_map(map); + map(0xa000, 0xa000).w(FUNC(arknoid2_state::arknoid2_bankswitch1_w)); map(0xc000, 0xc001).rw(FUNC(arknoid2_state::mcu_r), FUNC(arknoid2_state::mcu_w)); } @@ -822,6 +1584,7 @@ void kageki_state::kageki_sub_map(address_map &map) { base_sub_map(map); + map(0xa000, 0xa000).w(FUNC(kageki_state::kageki_bankswitch1_w)); map(0xc000, 0xc000).portr("IN0"); map(0xc001, 0xc001).portr("IN1"); map(0xc002, 0xc002).portr("IN2"); @@ -831,6 +1594,7 @@ void insectx_state::insectx_sub_map(address_map &map) { base_sub_map(map); + map(0xa000, 0xa000).w(FUNC(insectx_state::insectx_bankswitch1_w)); map(0xc000, 0xc000).portr("IN0"); map(0xc001, 0xc001).portr("IN1"); map(0xc002, 0xc002).portr("IN2"); @@ -842,7 +1606,7 @@ void tnzsb_state::tnzsb_base_sub_map(address_map &map) { map(0x0000, 0x7fff).rom(); map(0x8000, 0x9fff).bankr(m_subbank); - map(0xa000, 0xa000).w(FUNC(tnzsb_state::bankswitch1_w)); + map(0xa000, 0xa000).w(FUNC(tnzsb_state::tnzsb_bankswitch1_w)); map(0xb002, 0xb002).portr("DSWA"); map(0xb003, 0xb003).portr("DSWB"); map(0xb004, 0xb004).w(FUNC(tnzsb_state::sound_command_w)); @@ -1528,16 +2292,16 @@ static GFXDECODE_START( gfx_insectx ) GFXDECODE_ENTRY( "gfx1", 0, insectx_charlayout, 0, 32 ) GFXDECODE_END -void tnzs_base_state::tnzs_base(machine_config &config) +void insectx_state::tnzs_base(machine_config &config) { /* basic machine hardware */ Z80(config, m_maincpu, XTAL(12'000'000)/2); /* 6.0 MHz ??? - Main board Crystal is 12MHz, verified on insectx, kageki, tnzsb */ - m_maincpu->set_addrmap(AS_PROGRAM, &tnzs_base_state::rampal_main_map); - m_maincpu->set_vblank_int("screen", FUNC(tnzs_base_state::irq0_line_hold)); + m_maincpu->set_addrmap(AS_PROGRAM, &insectx_state::rampal_main_map); + m_maincpu->set_vblank_int("screen", FUNC(insectx_state::irq0_line_hold)); Z80(config, m_subcpu, XTAL(12'000'000)/2); /* 6.0 MHz ??? - Main board Crystal is 12MHz, verified on insectx, kageki, tnzsb */ - m_subcpu->set_addrmap(AS_PROGRAM, &tnzs_base_state::base_sub_map); - m_subcpu->set_vblank_int("screen", FUNC(tnzs_base_state::irq0_line_hold)); + m_subcpu->set_addrmap(AS_PROGRAM, &insectx_state::base_sub_map); + m_subcpu->set_vblank_int("screen", FUNC(insectx_state::irq0_line_hold)); config.set_perfect_quantum(m_maincpu); @@ -1551,8 +2315,8 @@ void tnzs_base_state::tnzs_base(machine_config &config) m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); m_screen->set_size(32*8, 32*8); m_screen->set_visarea(0*8, 32*8-1, 2*8, 30*8-1); - m_screen->set_screen_update(FUNC(tnzs_base_state::screen_update_tnzs)); - m_screen->screen_vblank().set(FUNC(tnzs_base_state::screen_vblank_tnzs)); + m_screen->set_screen_update(FUNC(insectx_state::screen_update_tnzs)); + m_screen->screen_vblank().set(FUNC(insectx_state::screen_vblank_tnzs)); m_screen->set_palette(m_palette); PALETTE(config, m_palette).set_format(palette_device::xRGB_555, 512); @@ -1561,13 +2325,15 @@ void tnzs_base_state::tnzs_base(machine_config &config) SPEAKER(config, "speaker").front_center(); } -void tnzs_mcu_state::tnzs(machine_config &config) +template +void tnzs_mcu_state::tnzs_mcu(machine_config &config) { tnzs_base(config); + I8742(config, m_mcu, 12000000/2); /* 400KHz ??? - Main board Crystal is 12MHz */ m_mcu->p1_in_cb().set(FUNC(tnzs_mcu_state::mcu_port1_r)); m_mcu->p2_in_cb().set_ioport("IN2"); - m_mcu->p2_out_cb().set(FUNC(tnzs_mcu_state::mcu_port2_w)); + m_mcu->p2_out_cb().set(FUNC(tnzs_mcu_state::mcu_port2_w)); m_mcu->t0_in_cb().set_ioport("COIN1"); m_mcu->t1_in_cb().set_ioport("COIN2"); @@ -1584,24 +2350,31 @@ void tnzs_mcu_state::tnzs(machine_config &config) ymsnd.add_route(ALL_OUTPUTS, "speaker", 0.3); } -void extrmatn_state::extrmatn(machine_config &config) +void tnzs_mcu_state::tnzs(machine_config &config) { - tnzs(config); + tnzs_mcu(config); +} - /* basic machine hardware */ - m_maincpu->set_addrmap(AS_PROGRAM, &extrmatn_state::prompal_main_map); +void tnzs_mcu_state::extrmatn(machine_config &config) +{ + tnzs_mcu(config); - /* video hardware */ + // basic machine hardware + m_maincpu->set_addrmap(AS_PROGRAM, &tnzs_mcu_state::prompal_main_map); + + // video hardware m_screen->set_refresh_hz(60); m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); - m_palette->set_init(FUNC(extrmatn_state::prompalette)); + m_palette->set_init(FUNC(tnzs_mcu_state::prompalette)); } -void extrmatn_state::plumppop(machine_config &config) +void plumppop_state::plumppop(machine_config &config) { extrmatn(config); + m_subcpu->set_addrmap(AS_PROGRAM, &plumppop_state::plumppop_sub_map); + UPD4701A(config, m_upd4701); m_upd4701->set_portx_tag("AN1"); m_upd4701->set_porty_tag("AN2"); @@ -1611,11 +2384,11 @@ void arknoid2_state::arknoid2(machine_config &config) { plumppop(config); - /* basic machine hardware */ m_maincpu->set_vblank_int("screen", FUNC(arknoid2_state::mcu_interrupt)); + m_subcpu->set_addrmap(AS_PROGRAM, &arknoid2_state::arknoid2_sub_map); - subdevice("mcu")->set_disable(); + m_mcu->set_disable(); } void insectx_state::insectx(machine_config &config) @@ -1759,7 +2532,7 @@ ROM_START( plumppop ) ROM_LOAD( "a98-13.15f", 0x0000, 0x200, CRC(7cde2da5) SHA1(0cccfc35fb716ebb4cffa85c75681f33ca80a56e) ) /* hi bytes, AM27S29 or compatible like MB7124 */ ROM_LOAD( "a98-12.17f", 0x0200, 0x200, CRC(90dc9da7) SHA1(f719dead7f4597e5ee6f1103599505b98cb58299) ) /* lo bytes, AM27S29 or compatible like MB7124 */ - ROM_REGION( 0x10000, "pal", 0 ) /* pals on plumppop are the same set as arkanoid2/extrmatn/drtoppel/chukataio/etc with the exception of d9? */ + ROM_REGION( 0x10000, "pal", 0 ) /* PALs on plumppop are the same set as arkanoid2/extrmatn/drtoppel/chukataio/etc with the exception of d9? */ ROM_LOAD( "b06-10-1.pal16l8a.d9.jed", 0x00000, 0x01000, NO_DUMP) ROM_LOAD( "b06-11.pal16l8a.d6.jed", 0x01000, 0x01000, NO_DUMP) ROM_LOAD( "b06-12.pal16l8a.c3.jed", 0x02000, 0x01000, NO_DUMP) @@ -2906,42 +3679,44 @@ ROM_START( insectxbl ) ROM_LOAD16_BYTE( "ic215", 0xc0001, 0x20000, CRC(ff1dee9e) SHA1(3ef91f8188ae400880c03ba8d1fc039c8920d6c0) ) ROM_END +} // anonymous namespace + // YEAR, NAME, PARENT, MACHINE, INPUT, CLASS, INIT, MONITOR,COMPANY, FULLNAME, FLAGS -GAME( 1987, plumppop, 0, plumppop, plumppop, extrmatn_state, empty_init, ROT0, "Taito Corporation", "Plump Pop (Japan)", MACHINE_SUPPORTS_SAVE ) +GAME( 1987, plumppop, 0, plumppop, plumppop, plumppop_state, empty_init, ROT0, "Taito Corporation", "Plump Pop (Japan)", MACHINE_SUPPORTS_SAVE ) GAME( 1992, jpopnics, 0, jpopnics, jpopnics, jpopnics_state, empty_init, ROT0, "Nics", "Jumping Pop (Nics, Korean hack of Plump Pop)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) -GAME( 1987, extrmatn, 0, extrmatn, extrmatn, extrmatn_state, empty_init, ROT270, "Taito Corporation Japan", "Extermination (World)", MACHINE_SUPPORTS_SAVE ) -GAME( 1987, extrmatnu, extrmatn, extrmatn, extrmatn, extrmatn_state, empty_init, ROT270, "Taito (World Games license)", "Extermination (US, World Games)", MACHINE_SUPPORTS_SAVE ) -GAME( 1987, extrmatnur,extrmatn, extrmatn, extrmatn, extrmatn_state, empty_init, ROT270, "Taito America Corporation (Romstar license)", "Extermination (US, Romstar)", MACHINE_SUPPORTS_SAVE ) -GAME( 1987, extrmatnj, extrmatn, extrmatn, extrmatn, extrmatn_state, empty_init, ROT270, "Taito Corporation", "Extermination (Japan)", MACHINE_SUPPORTS_SAVE ) +GAME( 1987, extrmatn, 0, extrmatn, extrmatn, tnzs_mcu_state, empty_init, ROT270, "Taito Corporation Japan", "Extermination (World)", MACHINE_SUPPORTS_SAVE ) +GAME( 1987, extrmatnu, extrmatn, extrmatn, extrmatn, tnzs_mcu_state, empty_init, ROT270, "Taito (World Games license)", "Extermination (US, World Games)", MACHINE_SUPPORTS_SAVE ) +GAME( 1987, extrmatnur,extrmatn, extrmatn, extrmatn, tnzs_mcu_state, empty_init, ROT270, "Taito America Corporation (Romstar license)", "Extermination (US, Romstar)", MACHINE_SUPPORTS_SAVE ) +GAME( 1987, extrmatnj, extrmatn, extrmatn, extrmatn, tnzs_mcu_state, empty_init, ROT270, "Taito Corporation", "Extermination (Japan)", MACHINE_SUPPORTS_SAVE ) GAME( 1987, arknoid2, 0, arknoid2, arknoid2, arknoid2_state, empty_init, ROT270, "Taito Corporation Japan", "Arkanoid - Revenge of DOH (World)", MACHINE_SUPPORTS_SAVE ) GAME( 1987, arknoid2u, arknoid2, arknoid2, arknid2u, arknoid2_state, empty_init, ROT270, "Taito America Corporation (Romstar license)", "Arkanoid - Revenge of DOH (US)", MACHINE_SUPPORTS_SAVE ) GAME( 1987, arknoid2j, arknoid2, arknoid2, arknid2u, arknoid2_state, empty_init, ROT270, "Taito Corporation", "Arkanoid - Revenge of DOH (Japan)", MACHINE_SUPPORTS_SAVE ) GAME( 1987, arknoid2b, arknoid2, arknoid2, arknid2u, arknoid2_state, empty_init, ROT270, "bootleg", "Arkanoid - Revenge of DOH (Japan bootleg)", MACHINE_SUPPORTS_SAVE ) -GAME( 1987, drtoppel, 0, extrmatn, drtoppel, extrmatn_state, empty_init, ROT90, "Kaneko / Taito Corporation Japan", "Dr. Toppel's Adventure (World)", MACHINE_SUPPORTS_SAVE ) /* Possible region hack */ -GAME( 1987, drtoppelu, drtoppel, extrmatn, drtopplu, extrmatn_state, empty_init, ROT90, "Kaneko / Taito America Corporation", "Dr. Toppel's Adventure (US)", MACHINE_SUPPORTS_SAVE ) /* Possible region hack */ -GAME( 1987, drtoppelj, drtoppel, extrmatn, drtopplu, extrmatn_state, empty_init, ROT90, "Kaneko / Taito Corporation", "Dr. Toppel's Tankentai (Japan)", MACHINE_SUPPORTS_SAVE ) +GAME( 1987, drtoppel, 0, extrmatn, drtoppel, tnzs_mcu_state, empty_init, ROT90, "Kaneko / Taito Corporation Japan", "Dr. Toppel's Adventure (World)", MACHINE_SUPPORTS_SAVE ) /* Possible region hack */ +GAME( 1987, drtoppelu, drtoppel, extrmatn, drtopplu, tnzs_mcu_state, empty_init, ROT90, "Kaneko / Taito America Corporation", "Dr. Toppel's Adventure (US)", MACHINE_SUPPORTS_SAVE ) /* Possible region hack */ +GAME( 1987, drtoppelj, drtoppel, extrmatn, drtopplu, tnzs_mcu_state, empty_init, ROT90, "Kaneko / Taito Corporation", "Dr. Toppel's Tankentai (Japan)", MACHINE_SUPPORTS_SAVE ) GAME( 1988, kageki, 0, kageki, kageki, kageki_state, empty_init, ROT90, "Kaneko / Taito Corporation", "Kageki (World)", MACHINE_SUPPORTS_SAVE ) GAME( 1988, kagekiu, kageki, kageki, kagekiu, kageki_state, empty_init, ROT90, "Kaneko / Taito America Corporation (Romstar license)", "Kageki (US)", MACHINE_SUPPORTS_SAVE ) GAME( 1988, kagekij, kageki, kageki, kagekij, kageki_state, empty_init, ROT90, "Kaneko / Taito Corporation", "Kageki (Japan)", MACHINE_SUPPORTS_SAVE ) GAME( 1992, kagekih, kageki, kageki, kageki, kageki_state, empty_init, ROT90, "hack", "Kageki (hack)", MACHINE_SUPPORTS_SAVE ) // date is hacked at least, might also be a Japan set hacked to show english -GAME( 1988, chukatai, 0, tnzs, chukatai, tnzs_state, empty_init, ROT0, "Taito Corporation Japan", "Chuka Taisen (World) (P0-028-A PCB)", MACHINE_SUPPORTS_SAVE ) /* Possible region hack */ -GAME( 1988, chukataiu, chukatai, tnzs, chukatau, tnzs_state, empty_init, ROT0, "Taito America Corporation", "Chuka Taisen (US) (P0-028-A PCB)", MACHINE_SUPPORTS_SAVE ) /* Possible region hack */ -GAME( 1988, chukataij, chukatai, tnzs, chukatau, tnzs_state, empty_init, ROT0, "Taito Corporation", "Chuka Taisen (Japan) (P0-028-A PCB)", MACHINE_SUPPORTS_SAVE ) -GAME( 1988, chukataija,chukatai, extrmatn, chukatau, extrmatn_state, empty_init, ROT0, "Taito Corporation", "Chuka Taisen (Japan) (P0-025-A PCB)", MACHINE_SUPPORTS_SAVE ) /* Higher ROM ID# but older PCB stock */ +GAME( 1988, chukatai, 0, tnzs, chukatai, tnzs_mcu_state, empty_init, ROT0, "Taito Corporation Japan", "Chuka Taisen (World) (P0-028-A PCB)", MACHINE_SUPPORTS_SAVE ) /* Possible region hack */ +GAME( 1988, chukataiu, chukatai, tnzs, chukatau, tnzs_mcu_state, empty_init, ROT0, "Taito America Corporation", "Chuka Taisen (US) (P0-028-A PCB)", MACHINE_SUPPORTS_SAVE ) /* Possible region hack */ +GAME( 1988, chukataij, chukatai, tnzs, chukatau, tnzs_mcu_state, empty_init, ROT0, "Taito Corporation", "Chuka Taisen (Japan) (P0-028-A PCB)", MACHINE_SUPPORTS_SAVE ) +GAME( 1988, chukataija,chukatai, extrmatn, chukatau, tnzs_mcu_state, empty_init, ROT0, "Taito Corporation", "Chuka Taisen (Japan) (P0-025-A PCB)", MACHINE_SUPPORTS_SAVE ) /* Higher ROM ID# but older PCB stock */ GAME( 1988, tnzs, 0, tnzsb, tnzs, tnzsb_state, empty_init, ROT0, "Taito Corporation Japan", "The NewZealand Story (World, new version) (P0-043A PCB)", MACHINE_SUPPORTS_SAVE ) GAME( 1988, tnzsj, tnzs, tnzsb, tnzsj, tnzsb_state, empty_init, ROT0, "Taito Corporation", "The NewZealand Story (Japan, new version) (P0-043A PCB)", MACHINE_SUPPORTS_SAVE ) -GAME( 1988, tnzso, tnzs, tnzs, tnzsop, tnzs_state, empty_init, ROT0, "Taito Corporation Japan", "The NewZealand Story (World, old version) (P0-041A PCB)", MACHINE_SUPPORTS_SAVE ) -GAME( 1988, tnzsjo, tnzs, tnzs, tnzsjo, tnzs_state, empty_init, ROT0, "Taito Corporation", "The NewZealand Story (Japan, old version) (P0-041A PCB)", MACHINE_SUPPORTS_SAVE ) -GAME( 1988, tnzsuo, tnzs, tnzs, tnzsjo, tnzs_state, empty_init, ROT0, "Taito America Corporation", "The NewZealand Story (US, old version) (P0-041A PCB)", MACHINE_SUPPORTS_SAVE ) -GAME( 1988, tnzsoa, tnzs, tnzs, tnzsop, tnzs_state, empty_init, ROT0, "Taito Corporation Japan", "The NewZealand Story (World, unknown version) (P0-041A PCB)", MACHINE_SUPPORTS_SAVE ) -GAME( 1988, tnzsop, tnzs, tnzs, tnzsop, tnzs_state, empty_init, ROT0, "Taito Corporation Japan", "The NewZealand Story (World, prototype) (P0-041-1 PCB)", MACHINE_SUPPORTS_SAVE ) +GAME( 1988, tnzso, tnzs, tnzs, tnzsop, tnzs_mcu_state, empty_init, ROT0, "Taito Corporation Japan", "The NewZealand Story (World, old version) (P0-041A PCB)", MACHINE_SUPPORTS_SAVE ) +GAME( 1988, tnzsjo, tnzs, tnzs, tnzsjo, tnzs_mcu_state, empty_init, ROT0, "Taito Corporation", "The NewZealand Story (Japan, old version) (P0-041A PCB)", MACHINE_SUPPORTS_SAVE ) +GAME( 1988, tnzsuo, tnzs, tnzs, tnzsjo, tnzs_mcu_state, empty_init, ROT0, "Taito America Corporation", "The NewZealand Story (US, old version) (P0-041A PCB)", MACHINE_SUPPORTS_SAVE ) +GAME( 1988, tnzsoa, tnzs, tnzs, tnzsop, tnzs_mcu_state, empty_init, ROT0, "Taito Corporation Japan", "The NewZealand Story (World, unknown version) (P0-041A PCB)", MACHINE_SUPPORTS_SAVE ) +GAME( 1988, tnzsop, tnzs, tnzs, tnzsop, tnzs_mcu_state, empty_init, ROT0, "Taito Corporation Japan", "The NewZealand Story (World, prototype) (P0-041-1 PCB)", MACHINE_SUPPORTS_SAVE ) GAME( 1988, kabukiz, 0, kabukiz, kabukiz, kabukiz_state, empty_init, ROT0, "Kaneko / Taito Corporation Japan", "Kabuki-Z (World)", MACHINE_SUPPORTS_SAVE ) GAME( 1988, kabukizj, kabukiz, kabukiz, kabukizj, kabukiz_state, empty_init, ROT0, "Kaneko / Taito Corporation", "Kabuki-Z (Japan)", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/taito/tnzs.h b/src/mame/taito/tnzs.h deleted file mode 100644 index f180b6d304b..00000000000 --- a/src/mame/taito/tnzs.h +++ /dev/null @@ -1,305 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Luca Elia, Mirko Buffoni, Takahiro Nogi -#ifndef MAME_TAITO_TNZS_H -#define MAME_TAITO_TNZS_H - -#pragma once - -#include "cpu/mcs48/mcs48.h" -#include "machine/gen_latch.h" -#include "machine/upd4701.h" -#include "sound/dac.h" -#include "sound/samples.h" -#include "video/x1_001.h" - -#include "emupal.h" -#include "screen.h" - - -class tnzs_video_state_base : public driver_device -{ -protected: - tnzs_video_state_base(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - , m_spritegen(*this, "spritegen") - , m_palette(*this, "palette") - , m_screen(*this, "screen") - { - } - - void prompalette(palette_device &palette) const; - uint32_t screen_update_tnzs(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - DECLARE_WRITE_LINE_MEMBER(screen_vblank_tnzs); - - required_device m_maincpu; - required_device m_spritegen; - required_device m_palette; - required_device m_screen; -}; - - -class tnzs_base_state : public tnzs_video_state_base -{ -protected: - tnzs_base_state(const machine_config &mconfig, device_type type, const char *tag) - : tnzs_video_state_base(mconfig, type, tag) - , m_subcpu(*this, "sub") - , m_subbank(*this, "subbank") - , m_ramromview(*this, "ramrom") - { } - - void tnzs_base(machine_config &config) ATTR_COLD; - - virtual void machine_start() override ATTR_COLD; - - virtual void bankswitch1_w(uint8_t data); - - void ramrom_bankswitch_w(uint8_t data); - - void prompal_main_map(address_map &map) ATTR_COLD; - void rampal_main_map(address_map &map) ATTR_COLD; - - void base_sub_map(address_map &map) ATTR_COLD; - - // devices - required_device m_subcpu; - required_memory_bank m_subbank; - -private: - memory_view m_ramromview; -}; - - -class tnzs_mcu_state : public tnzs_base_state -{ -public: - tnzs_mcu_state(const machine_config &mconfig, device_type type, const char *tag, bool lockout_level) - : tnzs_base_state(mconfig, type, tag) - , m_mcu(*this, "mcu") - , m_upd4701(*this, "upd4701") - , m_in0(*this, "IN0") - , m_in1(*this, "IN1") - , m_in2(*this, "IN2") - , m_input_select(0) - , m_lockout_level(lockout_level) - { } - - void tnzs(machine_config &config) ATTR_COLD; - -protected: - virtual void bankswitch1_w(uint8_t data) override; - - uint8_t mcu_port1_r(); - void mcu_port2_w(uint8_t data); - uint8_t mcu_r(offs_t offset); - void mcu_w(offs_t offset, uint8_t data); - - uint8_t analog_r(offs_t offset); - - void tnzs_sub_map(address_map &map) ATTR_COLD; - - required_device m_mcu; - optional_device m_upd4701; - - required_ioport m_in0; - required_ioport m_in1; - required_ioport m_in2; - - int m_input_select = 0; - bool m_lockout_level = false; -}; - -class tnzs_state : public tnzs_mcu_state -{ -public: - tnzs_state(const machine_config &mconfig, device_type type, const char *tag) - : tnzs_mcu_state(mconfig, type, tag, true) - { } -}; - -class extrmatn_state : public tnzs_mcu_state -{ -public: - extrmatn_state(const machine_config &mconfig, device_type type, const char *tag) - : tnzs_mcu_state(mconfig, type, tag, false) - { } - - void extrmatn(machine_config &config) ATTR_COLD; - void plumppop(machine_config &config) ATTR_COLD; -}; - -class arknoid2_state : public extrmatn_state -{ -public: - arknoid2_state(const machine_config &mconfig, device_type type, const char *tag) - : extrmatn_state(mconfig, type, tag) - , m_coin1(*this, "COIN1") - , m_coin2(*this, "COIN2") - , m_in0(*this, "IN0") - , m_in1(*this, "IN1") - , m_in2(*this, "IN2") - { } - - void arknoid2(machine_config &config) ATTR_COLD; - -private: - virtual void machine_start() override ATTR_COLD; - virtual void machine_reset() override ATTR_COLD; - - virtual void bankswitch1_w(uint8_t data) override; - - uint8_t mcu_r(offs_t offset); - void mcu_w(offs_t offset, uint8_t data); - INTERRUPT_GEN_MEMBER(mcu_interrupt); - - void arknoid2_sub_map(address_map &map) ATTR_COLD; - - void mcu_reset(); - - required_ioport m_coin1; - required_ioport m_coin2; - required_ioport m_in0; - required_ioport m_in1; - required_ioport m_in2; - - int m_mcu_initializing = 0; - int m_mcu_coinage_init = 0; - int m_mcu_command = 0; - int m_mcu_readcredits = 0; - int m_mcu_reportcoin = 0; - int m_insertcoin = 0; - uint8_t m_mcu_coinage[4]{}; - uint8_t m_mcu_coins_a = 0; - uint8_t m_mcu_coins_b = 0; - uint8_t m_mcu_credits = 0; - - void mcu_handle_coins(int coin); -}; - -class kageki_state : public tnzs_base_state -{ -public: - kageki_state(const machine_config &mconfig, device_type type, const char *tag) - : tnzs_base_state(mconfig, type, tag) - , m_samples(*this, "samples") - , m_dswa(*this, "DSWA") - , m_dswb(*this, "DSWB") - , m_csport_sel(0) - { } - - void kageki(machine_config &config) ATTR_COLD; - - void init_kageki() ATTR_COLD; - -protected: - virtual void machine_start() override ATTR_COLD; - virtual void machine_reset() override ATTR_COLD; - -private: - static constexpr unsigned MAX_SAMPLES = 0x2f; - - virtual void bankswitch1_w(uint8_t data) override; - - uint8_t csport_r(); - void csport_w(uint8_t data); - - SAMPLES_START_CB_MEMBER(init_samples); - - void kageki_sub_map(address_map &map) ATTR_COLD; - - required_device m_samples; - - required_ioport m_dswa; - required_ioport m_dswb; - - // sound-related - std::unique_ptr m_sampledata[MAX_SAMPLES]; - int m_samplesize[MAX_SAMPLES]{}; - - int m_csport_sel = 0; -}; - -class jpopnics_state : public tnzs_base_state -{ -public: - jpopnics_state(const machine_config &mconfig, device_type type, const char *tag) - : tnzs_base_state(mconfig, type, tag) - , m_upd4701(*this, "upd4701") - { } - - void jpopnics(machine_config &config) ATTR_COLD; - -private: - void subbankswitch_w(uint8_t data); - - void jpopnics_main_map(address_map &map) ATTR_COLD; - void jpopnics_sub_map(address_map &map) ATTR_COLD; - - required_device m_upd4701; -}; - -class insectx_state : public tnzs_base_state -{ -public: - insectx_state(const machine_config &mconfig, device_type type, const char *tag) - : tnzs_base_state(mconfig, type, tag) - { } - - void insectx(machine_config &config) ATTR_COLD; - -private: - virtual void bankswitch1_w(uint8_t data) override; - void insectx_sub_map(address_map &map) ATTR_COLD; -}; - -class tnzsb_state : public tnzs_base_state -{ -public: - tnzsb_state(const machine_config &mconfig, device_type type, const char *tag) - : tnzs_base_state(mconfig, type, tag) - , m_audiocpu(*this, "audiocpu") - , m_soundlatch(*this, "soundlatch") - { } - - void tnzsb(machine_config &config) ATTR_COLD; - -protected: - DECLARE_WRITE_LINE_MEMBER(ym2203_irqhandler); - - void sound_command_w(uint8_t data); - - virtual void bankswitch1_w(uint8_t data) override; - - void tnzsb_base_sub_map(address_map &map) ATTR_COLD; - void tnzsb_sub_map(address_map &map) ATTR_COLD; - void tnzsb_cpu2_map(address_map &map) ATTR_COLD; - void tnzsb_io_map(address_map &map) ATTR_COLD; - - required_device m_audiocpu; - required_device m_soundlatch; -}; - -class kabukiz_state : public tnzsb_state -{ -public: - kabukiz_state(const machine_config &mconfig, device_type type, const char *tag) - : tnzsb_state(mconfig, type, tag) - , m_audiobank(*this, "audiobank") - { } - - void kabukiz(machine_config &config) ATTR_COLD; - -protected: - virtual void machine_start() override ATTR_COLD; - -private: - void sound_bank_w(uint8_t data); - - void kabukiz_cpu2_map(address_map &map) ATTR_COLD; - void kabukiz_sub_map(address_map &map) ATTR_COLD; - - required_memory_bank m_audiobank; -}; - -#endif // MAME_TAITO_TNZS_H diff --git a/src/mame/taito/tnzs_m.cpp b/src/mame/taito/tnzs_m.cpp deleted file mode 100644 index d1b6c8b5e53..00000000000 --- a/src/mame/taito/tnzs_m.cpp +++ /dev/null @@ -1,495 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Luca Elia, Mirko Buffoni, Takahiro Nogi,Stephane Humbert -/*************************************************************************** - - machine.c - - Functions to emulate general aspects of the machine (RAM, ROM, interrupts, - I/O ports) - - The I8742 MCU takes care of handling the coin inputs and the tilt switch. - To simulate this, we read the status in the interrupt handler for the main - CPU and update the counters appropriately. We also must take care of - handling the coin/credit settings ourselves. - -***************************************************************************/ - -#include "emu.h" -#include "cpu/mcs48/mcs48.h" -#include "tnzs.h" - -uint8_t tnzs_mcu_state::mcu_r(offs_t offset) -{ - uint8_t data = m_mcu->upi41_master_r(offset & 1); - m_subcpu->yield(); - -// logerror("%s: read %02x from mcu $c00%01x\n", m_maincpu->pcbase(), data, offset); - - return data; -} - -void tnzs_mcu_state::mcu_w(offs_t offset, uint8_t data) -{ -// logerror("%s: write %02x to mcu $c00%01x\n", m_maincpu->pcbase(), data, offset); - - m_mcu->upi41_master_w(offset & 1, data); -} - -uint8_t tnzs_mcu_state::mcu_port1_r() -{ - int data = 0; - - switch (m_input_select) - { - case 0x0a: data = m_in2->read(); break; - case 0x0c: data = m_in0->read(); break; - case 0x0d: data = m_in1->read(); break; - default: data = 0xff; break; - } - -// logerror("%s: Read %02x from port 1\n", m_maincpu->pcbase(), data); - - return data; -} - -void tnzs_mcu_state::mcu_port2_w(uint8_t data) -{ - machine().bookkeeping().coin_lockout_w(0, (data & 0x40) != 0 ? m_lockout_level : !m_lockout_level); - machine().bookkeeping().coin_lockout_w(1, (data & 0x80) != 0 ? m_lockout_level : !m_lockout_level); - machine().bookkeeping().coin_counter_w(0, (~data & 0x10)); - machine().bookkeeping().coin_counter_w(1, (~data & 0x20)); - - m_input_select = data & 0xf; -} - -uint8_t tnzs_mcu_state::analog_r(offs_t offset) -{ - return m_upd4701.found() ? m_upd4701->read_xy(offset) : 0; -} - -void arknoid2_state::mcu_reset() -{ - m_mcu_initializing = 3; - m_mcu_coinage_init = 0; - m_mcu_coinage[0] = 1; - m_mcu_coinage[1] = 1; - m_mcu_coinage[2] = 1; - m_mcu_coinage[3] = 1; - m_mcu_coins_a = 0; - m_mcu_coins_b = 0; - m_mcu_credits = 0; - m_mcu_reportcoin = 0; - m_mcu_command = 0; -} - -void arknoid2_state::mcu_handle_coins( int coin ) -{ - /* The coin inputs and coin counters are managed by the i8742 mcu. */ - /* Here we simulate it. */ - /* Credits are limited to 9, so more coins should be rejected */ - /* Coin/Play settings must also be taken into consideration */ - - if (coin & 0x08) /* tilt */ - m_mcu_reportcoin = coin; - else if (coin && coin != m_insertcoin) - { - if (coin & 0x01) /* coin A */ - { -// logerror("Coin dropped into slot A\n"); - machine().bookkeeping().coin_counter_w(0,1); machine().bookkeeping().coin_counter_w(0,0); /* Count slot A */ - m_mcu_coins_a++; - if (m_mcu_coins_a >= m_mcu_coinage[0]) - { - m_mcu_coins_a -= m_mcu_coinage[0]; - m_mcu_credits += m_mcu_coinage[1]; - if (m_mcu_credits >= 9) - { - m_mcu_credits = 9; - machine().bookkeeping().coin_lockout_global_w(1); /* Lock all coin slots */ - } - else - { - machine().bookkeeping().coin_lockout_global_w(0); /* Unlock all coin slots */ - } - } - } - - if (coin & 0x02) /* coin B */ - { -// logerror("Coin dropped into slot B\n"); - machine().bookkeeping().coin_counter_w(1,1); machine().bookkeeping().coin_counter_w(1,0); /* Count slot B */ - m_mcu_coins_b++; - if (m_mcu_coins_b >= m_mcu_coinage[2]) - { - m_mcu_coins_b -= m_mcu_coinage[2]; - m_mcu_credits += m_mcu_coinage[3]; - if (m_mcu_credits >= 9) - { - m_mcu_credits = 9; - machine().bookkeeping().coin_lockout_global_w(1); /* Lock all coin slots */ - } - else - { - machine().bookkeeping().coin_lockout_global_w(0); /* Unlock all coin slots */ - } - } - } - - if (coin & 0x04) /* service */ - { -// logerror("Coin dropped into service slot C\n"); - m_mcu_credits++; - } - - m_mcu_reportcoin = coin; - } - else - { - if (m_mcu_credits < 9) - machine().bookkeeping().coin_lockout_global_w(0); /* Unlock all coin slots */ - - m_mcu_reportcoin = 0; - } - m_insertcoin = coin; -} - -/********************************* - -TNZS sync bug kludge - -In all TNZS versions there is code like this: - -0C5E: ld ($EF10),a -0C61: ld a,($EF10) -0C64: inc a -0C65: ret nz -0C66: jr $0C61 - -which is sometimes executed by the main cpu when it writes to shared RAM a -command for the second CPU. The intended purpose of the code is to wait an -acknowledge from the sub CPU: the sub CPU writes FF to the same location -after reading the command. - -However the above code is wrong. The "ret nz" instruction means that the -loop will be exited only when the contents of $EF10 are *NOT* $FF!! -On the real board, this casues little harm: the main CPU will just write -the command, read it back and, since it's not $FF, return immediately. There -is a chance that the command might go lost, but this will cause no major -harm, the worse that can happen is that the background tune will not change. - -In MAME, however, since CPU interleaving is not perfect, it can happen that -the main CPU ends its timeslice after writing to EF10 but before reading it -back. In the meantime, the sub CPU will run, read the command and write FF -there - therefore causing the main CPU to enter an endless loop. - -Unlike the usual sync problems in MAME, which can be fixed by increasing the -interleave factor, in this case increasing it will actually INCREASE the -chance of entering the endless loop - because it will increase the chances of -the main CPU ending its timeslice at the wrong moment. - -So what we do here is catch writes by the main CPU to the RAM location, and -process them using a timer, in order to -a) force a resync of the two CPUs -b) make sure the main CPU will be the first one to run after the location is - changed - -Since the answer from the sub CPU is ignored, we don't even need to boost -interleave. - -*********************************/ - -/* -TIMER_CALLBACK_MEMBER(tnzs_base_state::kludge_callback) -{ - tnzs_sharedram[0x0f10] = param; -} - -void tnzs_base_state::tnzs_sync_kludge_w(uint8_t data) -{ - machine().scheduler().synchronize(timer_expired_delegate(FUNC(tnzs_base_state::kludge_callback),this), data); -} -*/ - -uint8_t arknoid2_state::mcu_r(offs_t offset) -{ - static const char mcu_startup[] = "\x55\xaa\x5a"; - - //logerror("%s: read mcu %04x\n", m_maincpu->pc(), 0xc000 + offset); - - if (offset == 0) - { - /* if the mcu has just been reset, return startup code */ - if (m_mcu_initializing) - { - m_mcu_initializing--; - return mcu_startup[2 - m_mcu_initializing]; - } - - switch (m_mcu_command) - { - case 0x41: - return m_mcu_credits; - - case 0xc1: - /* Read the credit counter or the inputs */ - if (m_mcu_readcredits == 0) - { - m_mcu_readcredits = 1; - if (m_mcu_reportcoin & 0x08) - { - m_mcu_initializing = 3; - return 0xee; /* tilt */ - } - else return m_mcu_credits; - } - else return m_in0->read(); /* buttons */ - - default: - logerror("error, unknown mcu command\n"); - /* should not happen */ - return 0xff; - } - } - else - { - /* - status bits: - 0 = mcu is ready to send data (read from c000) - 1 = mcu has read data (from c000) - 2 = unused - 3 = unused - 4-7 = coin code - 0 = nothing - 1,2,3 = coin switch pressed - e = tilt - */ - if (m_mcu_reportcoin & 0x08) return 0xe1; /* tilt */ - if (m_mcu_reportcoin & 0x01) return 0x11; /* coin 1 (will trigger "coin inserted" sound) */ - if (m_mcu_reportcoin & 0x02) return 0x21; /* coin 2 (will trigger "coin inserted" sound) */ - if (m_mcu_reportcoin & 0x04) return 0x31; /* coin 3 (will trigger "coin inserted" sound) */ - return 0x01; - } -} - -void arknoid2_state::mcu_w(offs_t offset, uint8_t data) -{ - if (offset == 0) - { - //logerror("%s: write %02x to mcu %04x\n", m_maincpu->pc(), data, 0xc000 + offset); - if (m_mcu_command == 0x41) - { - m_mcu_credits = (m_mcu_credits + data) & 0xff; - } - } - else - { - /* - 0xc1: read number of credits, then buttons - 0x54+0x41: add value to number of credits - 0x15: sub 1 credit (when "Continue Play" only) - 0x84: coin 1 lockout (issued only in test mode) - 0x88: coin 2 lockout (issued only in test mode) - 0x80: release coin lockout (issued only in test mode) - during initialization, a sequence of 4 bytes sets coin/credit settings - */ - //logerror("%s: write %02x to mcu %04x\n", m_maincpu->pc(), data, 0xc000 + offset); - - if (m_mcu_initializing) - { - /* set up coin/credit settings */ - m_mcu_coinage[m_mcu_coinage_init++] = data; - if (m_mcu_coinage_init == 4) - m_mcu_coinage_init = 0; /* must not happen */ - } - - if (data == 0xc1) - m_mcu_readcredits = 0; /* reset input port number */ - - if (data == 0x15) - { - m_mcu_credits = (m_mcu_credits - 1) & 0xff; - if (m_mcu_credits == 0xff) - m_mcu_credits = 0; - } - m_mcu_command = data; - } -} - -INTERRUPT_GEN_MEMBER(arknoid2_state::mcu_interrupt) -{ - int coin = ((m_coin1->read() & 1) << 0); - coin |= ((m_coin2->read() & 1) << 1); - coin |= ((m_in2->read() & 3) << 2); - coin ^= 0x0c; - mcu_handle_coins(coin); - - device.execute().set_input_line(0, HOLD_LINE); -} - -void arknoid2_state::machine_reset() -{ - extrmatn_state::machine_reset(); - - // initialize the MCU simulation - mcu_reset(); - - m_mcu_readcredits = 0; - m_insertcoin = 0; -} - -void kageki_state::machine_reset() -{ - tnzs_base_state::machine_reset(); - - m_csport_sel = 0; -} - -void tnzs_base_state::machine_start() -{ - tnzs_video_state_base::machine_start(); - - uint8_t *const sub = memregion("sub")->base(); - m_subbank->configure_entries(0, 4, &sub[0x08000], 0x2000); - m_subbank->set_entry(0); - - m_ramromview.select(2); -} - -void arknoid2_state::machine_start() -{ - extrmatn_state::machine_start(); - - save_item(NAME(m_mcu_readcredits)); - save_item(NAME(m_insertcoin)); - save_item(NAME(m_mcu_initializing)); - save_item(NAME(m_mcu_coinage_init)); - save_item(NAME(m_mcu_coinage)); - save_item(NAME(m_mcu_coins_a)); - save_item(NAME(m_mcu_coins_b)); - save_item(NAME(m_mcu_credits)); - save_item(NAME(m_mcu_reportcoin)); - save_item(NAME(m_mcu_command)); - - // kludge to make device work with active-high coin inputs - m_upd4701->left_w(0); - m_upd4701->middle_w(0); -} - -void kageki_state::machine_start() -{ - tnzs_base_state::machine_start(); - - save_item(NAME(m_csport_sel)); -} - -void kabukiz_state::machine_start() -{ - tnzsb_state::machine_start(); - - uint8_t *sound = memregion("audiocpu")->base(); - m_audiobank->configure_entries(0, 8, &sound[0x00000], 0x4000); -} - -void tnzs_base_state::ramrom_bankswitch_w(uint8_t data) -{ -// logerror("%s: writing %02x to bankswitch\n", m_maincpu->pc(),data); - - // bit 4 resets the second CPU - m_subcpu->set_input_line(INPUT_LINE_RESET, BIT(data, 4) ? CLEAR_LINE : ASSERT_LINE); - - // bits 0-2 select RAM/ROM bank - m_ramromview.select(data & 0x07); -} - -void arknoid2_state::bankswitch1_w(uint8_t data) -{ - tnzs_base_state::bankswitch1_w(data); - - if (BIT(data, 2)) - mcu_reset(); - - // never actually written by arknoid2 (though code exists to do it) - m_upd4701->resetx_w(BIT(data, 5)); - m_upd4701->resety_w(BIT(data, 5)); -} - -void insectx_state::bankswitch1_w(uint8_t data) -{ - tnzs_base_state::bankswitch1_w(data); - - machine().bookkeeping().coin_lockout_w(0, BIT(~data, 2)); - machine().bookkeeping().coin_lockout_w(1, BIT(~data, 3)); - machine().bookkeeping().coin_counter_w(0, BIT(data, 4)); - machine().bookkeeping().coin_counter_w(1, BIT(data, 5)); -} - -void tnzsb_state::bankswitch1_w(uint8_t data) // kabukiz_state -{ - tnzs_base_state::bankswitch1_w(data); - - machine().bookkeeping().coin_lockout_w(0, BIT(~data, 4)); - machine().bookkeeping().coin_lockout_w(1, BIT(~data, 5)); - machine().bookkeeping().coin_counter_w(0, BIT(data, 2)); - machine().bookkeeping().coin_counter_w(1, BIT(data, 3)); -} - -void kageki_state::bankswitch1_w(uint8_t data) -{ - tnzs_base_state::bankswitch1_w(data); - - machine().bookkeeping().coin_lockout_global_w(BIT(~data, 5)); - machine().bookkeeping().coin_counter_w(0, BIT(data, 2)); - machine().bookkeeping().coin_counter_w(1, BIT(data, 3)); -} - -void tnzs_mcu_state::bankswitch1_w(uint8_t data) -{ - tnzs_base_state::bankswitch1_w(data); - - if (BIT(data, 2) && m_mcu) - m_mcu->pulse_input_line(INPUT_LINE_RESET, attotime::zero); - - // written only at startup by plumppop? - if (m_upd4701.found()) - { - m_upd4701->resetx_w(BIT(data, 5)); - m_upd4701->resety_w(BIT(data, 5)); - } -} - -void tnzs_base_state::bankswitch1_w(uint8_t data) -{ -// logerror("%s: writing %02x to bankswitch 1\n", m_maincpu->pc(),data); - - // bits 0-1 select ROM bank - m_subbank->set_entry(data & 0x03); -} - -void jpopnics_state::subbankswitch_w(uint8_t data) -{ - // bits 0-1 select ROM bank - m_subbank->set_entry(data & 0x03); - - // written once at startup - m_upd4701->resetx_w(BIT(data, 5)); - m_upd4701->resety_w(BIT(data, 5)); -} - -void tnzsb_state::sound_command_w(uint8_t data) -{ - m_soundlatch->write(data); - m_audiocpu->set_input_line_and_vector(0, HOLD_LINE, 0xff); // Z80 -} - -// handler called by the 2203 emulator when the internal timers cause an IRQ -WRITE_LINE_MEMBER(tnzsb_state::ym2203_irqhandler) -{ - m_audiocpu->set_input_line(INPUT_LINE_NMI, state ? ASSERT_LINE : CLEAR_LINE); -} - -void kabukiz_state::sound_bank_w(uint8_t data) -{ - // to avoid the write when the sound chip is initialized - if (data != 0xff) - m_audiobank->set_entry(data & 0x07); -} diff --git a/src/mame/taito/tnzs_v.cpp b/src/mame/taito/tnzs_video.cpp similarity index 72% rename from src/mame/taito/tnzs_v.cpp rename to src/mame/taito/tnzs_video.cpp index ccaf206dfb8..042abf1ef38 100644 --- a/src/mame/taito/tnzs_v.cpp +++ b/src/mame/taito/tnzs_video.cpp @@ -2,25 +2,12 @@ // copyright-holders:Luca Elia, Mirko Buffoni, Takahiro Nogi /*************************************************************************** - video.c - Functions to emulate the video hardware of the machine. ***************************************************************************/ #include "emu.h" -#include "tnzs.h" - -/*************************************************************************** - - The New Zealand Story doesn't have a color PROM. It uses 1024 bytes of RAM - to dynamically create the palette. Each couple of bytes defines one - color (15 bits per pixel; the top bit of the second byte is unused). - Since the graphics use 4 bitplanes, hence 16 colors, this makes for 32 - different color codes. - -***************************************************************************/ - +#include "tnzs_video.h" /*************************************************************************** diff --git a/src/mame/taito/tnzs_video.h b/src/mame/taito/tnzs_video.h new file mode 100644 index 00000000000..e4a9dd30324 --- /dev/null +++ b/src/mame/taito/tnzs_video.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia, Mirko Buffoni, Takahiro Nogi +#ifndef MAME_TAITO_TNZS_VIDEO_H +#define MAME_TAITO_TNZS_VIDEO_H + +#pragma once + +#include "video/x1_001.h" + +#include "emupal.h" +#include "screen.h" + + +class tnzs_video_state_base : public driver_device +{ +protected: + tnzs_video_state_base(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_spritegen(*this, "spritegen") + , m_palette(*this, "palette") + , m_screen(*this, "screen") + { + } + + void prompalette(palette_device &palette) const; + uint32_t screen_update_tnzs(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + DECLARE_WRITE_LINE_MEMBER(screen_vblank_tnzs); + + required_device m_maincpu; + required_device m_spritegen; + required_device m_palette; + required_device m_screen; +}; + +#endif // MAME_TAITO_TNZS_VIDEO_H