-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]
This commit is contained in:
Vas Crabb 2023-03-22 08:10:42 +11:00
parent 5159d1a271
commit 47c281d0fc
15 changed files with 1578 additions and 920 deletions

View File

@ -716,6 +716,13 @@ private:
return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner(), devcb_read::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name);
}
template <typename T>
std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_t &devbase, char const *tag, T &&func, char const *name)
{
set_used();
return delegate_builder<delegate_type_t<T> >(m_target, m_append, devbase, tag, std::forward<T>(func), name);
}
template <typename T, typename U, bool R>
std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> &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<delegate_type_t<T> >(m_target, m_append, m_target.owner(), devcb_write::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name);
}
template <typename T>
std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_t &devbase, char const *tag, T &&func, char const *name)
{
set_used();
return delegate_builder<delegate_type_t<T> >(m_target, m_append, devbase, tag, std::forward<T>(func), name);
}
template <typename T, typename U, bool R>
std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> &finder, T &&func, char const *name)
{

View File

@ -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<fdc37c93x_device &>(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<jaleco_vj_isa16_sound_device &>(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")

View File

@ -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<pentium_device> m_maincpu;
required_device<jaleco_vj_isa16_sound_device> m_sound;
bool m_is_steppingstage;
};
DECLARE_DEVICE_TYPE(JALECO_VJ_PC, jaleco_vj_pc_device)
#endif // MAME_JALECO_JALECO_VJ_PC_H

View File

@ -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")

View File

@ -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<ymz280b_device, 2> m_ymz;
required_shared_ptr<uint8_t> m_ymzram;
required_shared_ptr<uint8_t> 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

View File

@ -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")

View File

@ -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

View File

@ -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 )

View File

@ -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<u16> m_vj_paletteram_m;
optional_shared_ptr<u16> m_vj_paletteram_r;
required_device<generic_latch_16_device> m_soundlatch;
required_device<jaleco_vj_pc_device> m_jaleco_vj_pc;
optional_ioport_array<2> m_soundvr;
required_device<screen_device> m_rscreen;

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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<cpu_device> m_maincpu;
required_device<x1_001_device> m_spritegen;
required_device<palette_device> m_palette;
required_device<screen_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<cpu_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<upi41_cpu_device> m_mcu;
optional_device<upd4701_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<samples_device> m_samples;
required_ioport m_dswa;
required_ioport m_dswb;
// sound-related
std::unique_ptr<int16_t[]> 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<upd4701_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<cpu_device> m_audiocpu;
required_device<generic_latch_8_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

View File

@ -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);
}

View File

@ -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"
/***************************************************************************

View File

@ -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<cpu_device> m_maincpu;
required_device<x1_001_device> m_spritegen;
required_device<palette_device> m_palette;
required_device<screen_device> m_screen;
};
#endif // MAME_TAITO_TNZS_VIDEO_H