diff options
author | Angelo Salese <angelosa@users.noreply.github.com> | 2021-08-24 10:22:03 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-24 10:22:03 +0200 |
commit | 0e4ba6d49ad68d13966dc2cd14adbe68a7b3b684 (patch) | |
tree | f44d329f0185cb67a7ff5babafa1b264ac6273ce /src/devices/bus | |
parent | c471fad8e019703bb3323682f662249e251414f4 (diff) |
Major state refactoring of pc98 based HW (#8475)
First major step in splitting up machine classes in NEC PC98 family tree:
* Splits up derivative HWs into own state machine and files (pc98ha.cpp, pc9821.cpp and pc9801_epson.cpp);
* Adds a preliminary uPD4991a parallel RTC, used by pc98ha;
* Fix -26, -86, -118 C-bus sound board dips or jumper settings;
* Fix default sound card for pc9821 (-86) and pc9821ce2 / pc9821cx3 (-118);
* Adds preliminary MAD Factory Otomichan-kai C-bus sound board;
* Adds boilerplate code for C-bus installing board I/Os, avoiding the possible inconvenience of board(s) getting silently unmapped by other installed boards;
* Major refactoring of HW dip switches readouts, using required_ioports instead of scattering things around in PPI hooks;
* Extensive QA rundown, including research on missing features and undumped machines.
pc9801.cpp: Don't passthrough mouse irq frequency when cycle setting is setup too, fixes jastrike mouse input on options menu.
pc9801.cpp: Fix kanji RAM window LR readback, makes telenetm to properly display 8x16 chars on RS and derivative machines.
pc8801.cpp: fixed OPNA RAM readback, allowing SWs to playback ADPCMs properly.
New machines marked as NOT_WORKING
----------------------------------
PC-98LT [anonymous]
PC-98HA "Handy98" [anonymous]
PC-9821Nr15 (98NOTE Lavie) [flyingharuka]
PC-9821Nr166 (98NOTE Lavie) [flyingharuka]
PC-9821Nw150 (98NOTE Lavie) [flyingharuka]
PC-9821Ra266 (98MATE R) [flyingharuka]
PC-9821Cx3 (98MULTi CanBe) [flyingharuka]
PC-9801VX [qazmko1029]
PC-9801US [CoolMod]
Diffstat (limited to 'src/devices/bus')
-rw-r--r-- | src/devices/bus/cbus/mpu_pc98.cpp | 2 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_118.cpp | 120 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_118.h | 3 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_26.cpp | 90 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_26.h | 4 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_55.cpp | 253 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_55.h | 80 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_86.cpp | 259 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_86.h | 59 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_amd98.cpp | 18 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_amd98.h | 12 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_cbus.cpp | 44 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_cbus.h | 2 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_snd.cpp | 8 | ||||
-rw-r--r-- | src/devices/bus/cbus/pc9801_snd.h | 8 |
15 files changed, 814 insertions, 148 deletions
diff --git a/src/devices/bus/cbus/mpu_pc98.cpp b/src/devices/bus/cbus/mpu_pc98.cpp index 2230e966fda..2ba192d4b0d 100644 --- a/src/devices/bus/cbus/mpu_pc98.cpp +++ b/src/devices/bus/cbus/mpu_pc98.cpp @@ -38,7 +38,7 @@ WRITE_LINE_MEMBER( mpu_pc98_device::mpu_irq_out ) // GLOBAL VARIABLES //************************************************************************** -DEFINE_DEVICE_TYPE(MPU_PC98, mpu_pc98_device, "mpu_pc98", "Roland MPU-401 MIDI Interface (CBUS)") +DEFINE_DEVICE_TYPE(MPU_PC98, mpu_pc98_device, "mpu_pc98", "Roland MPU-401 MIDI Interface (C-bus)") //------------------------------------------------- // device_add_mconfig - add device configuration diff --git a/src/devices/bus/cbus/pc9801_118.cpp b/src/devices/bus/cbus/pc9801_118.cpp index 7f45cdf5d5e..403a23b4658 100644 --- a/src/devices/bus/cbus/pc9801_118.cpp +++ b/src/devices/bus/cbus/pc9801_118.cpp @@ -1,16 +1,24 @@ // license:BSD-3-Clause // copyright-holders:Angelo Salese -/*************************************************************************** +/************************************************************************************************** - NEC PC-9801-118 sound card + NEC PC-9801-118 sound card "CanBe Sound 2" - YMF297 + some extra ports + YMF297 + some extra ports, apparently derived from -86. + Introduced around the same time as Windows 95 release, it has various compatibility issues + under DOS (especially when PnP is enabled). + Doesn't have a sound ROM, it also cannot be installed with an environment also sporting a -86. TODO: - - preliminary, presumably needs CS-4232 too, it's an extended clone of the already emulated AD1848 used on the Windows Sound System + - Fix sound chip type (YMF297-F); + - Add CS-4232 support, it's an extended clone of the already emulated AD1848 used on the + Windows Sound System; + - Understand what the obfuscated NEC "ANCHOR" and "MAZE" chips really are; + - PnP interface (missing BIOS); - verify sound irq; + - test if driver can be installed under Windows 95; -***************************************************************************/ +**************************************************************************************************/ #include "emu.h" #include "bus/cbus/pc9801_118.h" @@ -27,11 +35,11 @@ //************************************************************************** // device type definition -DEFINE_DEVICE_TYPE(PC9801_118, pc9801_118_device, "pc9801_118", "pc9801_118") +DEFINE_DEVICE_TYPE(PC9801_118, pc9801_118_device, "pc9801_118", "NEC PC-9801-118") WRITE_LINE_MEMBER(pc9801_118_device::sound_irq) { - /* TODO: seems to die very often */ + // TODO: sometimes misfired irq causes sound or even host hang m_bus->int_w<5>(state); } @@ -41,9 +49,15 @@ WRITE_LINE_MEMBER(pc9801_118_device::sound_irq) void pc9801_118_device::device_add_mconfig(machine_config &config) { + // TODO: "ANCHOR" & "MAZE" custom NEC chips + // sourced by 5D clock + SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); - YM2608(config, m_opn3, XTAL_5B * 2 / 5); // actually YMF297-F, unknown clock / divider, more likely uses 5D clock + + // actually YMF297-F (YMF288 + OPL3 compatible FM sources), unknown clock / divider + // 5B is near both CS-4232 and this + YM2608(config, m_opn3, XTAL_5B * 2 / 5); m_opn3->irq_handler().set(FUNC(pc9801_118_device::sound_irq)); m_opn3->port_a_read_callback().set(FUNC(pc9801_118_device::opn_porta_r)); //m_opn3->port_b_read_callback().set(FUNC(pc8801_state::opn_portb_r)); @@ -61,10 +75,48 @@ void pc9801_118_device::device_add_mconfig(machine_config &config) static INPUT_PORTS_START( pc9801_118 ) PORT_INCLUDE( pc9801_joy_port ) - PORT_START("OPN3_DSW") - PORT_CONFNAME( 0x01, 0x00, "PC-9801-118: Port Base" ) - PORT_CONFSETTING( 0x00, "0x088" ) - PORT_CONFSETTING( 0x01, "0x188" ) + // 12 line Jumper settings @ 8F + // documented at https://sammargh.github.io/pc98/ext_card_doc/9801-118.txt + // TODO: understand how SW can read these + PORT_START("OPN3_JP_8F") + PORT_CONFNAME( 0x001, 0x000, "PC-9801-118: Enable Plug and Play" ) // [1] + PORT_CONFSETTING( 0x000, DEF_STR( No ) ) + PORT_CONFSETTING( 0x001, DEF_STR( Yes ) ) + // "group" is basically a obnoxious machine ID + // details are in the aforementioned link, in a nutshell should be: + // Group 1: later CanBe (Cb onward) + // Group 2: early CanBe (Ce, Ce2, Cs2), 9821 MATE A + // Group 4: several ValueStar models + // Group 5: 9821 MATE B, Notebooks, 9801 BX, some H98 models + // Group 3: anything not covered above (link also mentions BX4 here?) + // In practice this should really be tested on field ... + PORT_CONFNAME( 0x406, 0x000, "PC-9801-118: PCM Group select") // [2, 3, 11] + PORT_CONFSETTING( 0x000, "Groups 2, 3, 4, 5" ) // uses -118 PCM + PORT_CONFSETTING( 0x404, "Group 3" ) // uses PCM host + PORT_CONFSETTING( 0x002, "Group 1" ) // ? + // all other settings "prohibited" + PORT_CONFNAME( 0x008, 0x008, "PC-9801-118: unknown [4]" ) // [4] "prohibited", always ON + PORT_CONFSETTING( 0x000, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x008, DEF_STR( On ) ) + PORT_CONFNAME( 0x030, 0x000, "PC-9801-118: FM Interrupt setting" ) // [5,6] + PORT_CONFSETTING( 0x000, "INT5 (IRQ12)" ) + PORT_CONFSETTING( 0x010, "INT6 (IRQ13)" ) + PORT_CONFSETTING( 0x020, "INT41 (IRQ10)" ) + PORT_CONFSETTING( 0x030, "INT0 (IRQ3)") + PORT_CONFNAME( 0x040, 0x000, "PC-9801-118: DMA channel" ) // [7] + PORT_CONFSETTING( 0x000, "1" ) + PORT_CONFSETTING( 0x040, "2" ) + PORT_CONFNAME( 0x180, 0x000, "PC-9801-118: PCM Interrupt setting" ) // [8,9] + PORT_CONFSETTING( 0x000, "INT5 (IRQ12)" ) + PORT_CONFSETTING( 0x080, "INT1 (IRQ5)" ) + PORT_CONFSETTING( 0x100, "INT41 (IRQ10)" ) + PORT_CONFSETTING( 0x180, "INT0 (IRQ3)" ) + PORT_CONFNAME( 0x200, 0x000, "PC-9801-118: enable MIDI Interrupt" ) // [10] + PORT_CONFSETTING( 0x000, DEF_STR( No ) ) + PORT_CONFSETTING( 0x200, DEF_STR( Yes ) ) // auto for PnP, INT41 for non-PnP + PORT_CONFNAME( 0x800, 0x000, "PC-9801-118: unknown [12]" ) // [12] "prohibited", always OFF + PORT_CONFSETTING( 0x000, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x800, DEF_STR( On ) ) INPUT_PORTS_END ioport_constructor pc9801_118_device::device_input_ports() const @@ -72,8 +124,14 @@ ioport_constructor pc9801_118_device::device_input_ports() const return INPUT_PORTS_NAME( pc9801_118 ); } -// RAM ROM_START( pc9801_118 ) + ROM_REGION( 0x20000, "pnp_bios", ROMREGION_ERASE00 ) + // NB: either socket is exclusively populated, earlier models populates 1E while later populates 2E. + // Most likely contains same data or slight revision bump. + // μPD27c1024 socket + ROM_LOAD( "118 e316.1e", 0x00000, 0x20000, NO_DUMP ) + // LH531024N socket at .2e (unreadable label) + ROM_REGION( 0x100000, "opn3", ROMREGION_ERASE00 ) ROM_END @@ -111,11 +169,24 @@ void pc9801_118_device::device_validity_check(validity_checker &valid) const // device_start - device-specific startup //------------------------------------------------- +u16 pc9801_118_device::read_io_base() +{ + // hardwired on this board + return 0x0188; +} void pc9801_118_device::device_start() { + m_io_base = read_io_base(); m_bus->install_io(0xa460, 0xa463, read8sm_delegate(*this, FUNC(pc9801_118_device::id_r)), write8sm_delegate(*this, FUNC(pc9801_118_device::ext_w))); + m_bus->install_io( + m_io_base, + m_io_base + 7, + read8sm_delegate(*this, FUNC(pc9801_118_device::opn3_r)), + write8sm_delegate(*this, FUNC(pc9801_118_device::opn3_w)) + ); + save_item(NAME(m_ext_reg)); } @@ -126,10 +197,8 @@ void pc9801_118_device::device_start() void pc9801_118_device::device_reset() { - uint16_t port_base = (ioport("OPN3_DSW")->read() & 1) << 8; - m_bus->io_space().unmap_readwrite(0x0088, 0x008b, 0x100); - m_bus->install_io(port_base + 0x0088, port_base + 0x008f, read8sm_delegate(*this, FUNC(pc9801_118_device::opn3_r)), write8sm_delegate(*this, FUNC(pc9801_118_device::opn3_w))); - m_ext_reg = 1; // TODO: enabled or disabled? + // TODO: is this enabled or disabled at boot? + m_ext_reg = 1; } @@ -140,7 +209,7 @@ void pc9801_118_device::device_reset() uint8_t pc9801_118_device::opn3_r(offs_t offset) { - if(((offset & 5) == 0) || m_ext_reg) + if(((offset & 5) == 0) || m_ext_reg ) return m_opn3->read(offset >> 1); else // odd { @@ -152,7 +221,7 @@ uint8_t pc9801_118_device::opn3_r(offs_t offset) void pc9801_118_device::opn3_w(offs_t offset, uint8_t data) { - if(((offset & 5) == 0) || m_ext_reg) + if( ((offset & 5) == 0) || m_ext_reg ) m_opn3->write(offset >> 1,data); //else // odd // printf("PC9801-118: Write to undefined port [%02x] %02x\n",offset+0x188,data); @@ -162,11 +231,13 @@ uint8_t pc9801_118_device::id_r(offs_t offset) { if(offset == 0) { - printf("OPN3 EXT read ID [%02x]\n",offset); + logerror("OPN3 EXT read ID [%02x]\n",offset); + // TODO: confirm ID + // by assumption we make this same as later CanBe releases, may or may not be right return 0x80 | (m_ext_reg & 1); } - printf("OPN3 EXT read unk [%02x]\n",offset); + logerror("OPN3 EXT read unk [%02x]\n", offset); return 0xff; } @@ -175,11 +246,10 @@ void pc9801_118_device::ext_w(offs_t offset, uint8_t data) if(offset == 0) { m_ext_reg = data & 1; - /* TODO: apparently writing a 1 doubles the available channels (and presumably enables CS-4231 too) */ - if(data) - printf("PC-9801-118: extended register %02x write\n",data); + if(data & 2) + logerror("%s: extended register %02x write\n", machine().describe_context(), data); return; } - printf("OPN3 EXT write unk %02x -> [%02x]\n",data,offset); + logerror("%s: EXT write unk %02x -> [%02x]\n", machine().describe_context(), data, offset); } diff --git a/src/devices/bus/cbus/pc9801_118.h b/src/devices/bus/cbus/pc9801_118.h index 0984a9c880c..94ac3bfe24c 100644 --- a/src/devices/bus/cbus/pc9801_118.h +++ b/src/devices/bus/cbus/pc9801_118.h @@ -28,6 +28,8 @@ public: // construction/destruction pc9801_118_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + static constexpr feature_type imperfect_features() { return feature::SOUND; } + uint8_t opn3_r(offs_t offset); void opn3_w(offs_t offset, uint8_t data); uint8_t id_r(offs_t offset); @@ -42,6 +44,7 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual ioport_constructor device_input_ports() const override; virtual const tiny_rom_entry *device_rom_region() const override; + virtual u16 read_io_base() override; private: required_device<pc9801_slot_device> m_bus; diff --git a/src/devices/bus/cbus/pc9801_26.cpp b/src/devices/bus/cbus/pc9801_26.cpp index e9b9498c6ac..8f8b15740bd 100644 --- a/src/devices/bus/cbus/pc9801_26.cpp +++ b/src/devices/bus/cbus/pc9801_26.cpp @@ -1,6 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Angelo Salese -/*************************************************************************** +/************************************************************************************************** NEC PC-9801-26 sound card @@ -8,8 +8,10 @@ TODO: - verify sound irq; + - understand if dips can be read by SW; + - configurable irq level needs a binding flush in C-bus handling; -***************************************************************************/ +**************************************************************************************************/ #include "emu.h" #include "bus/cbus/pc9801_26.h" @@ -23,11 +25,11 @@ //************************************************************************** // device type definition -DEFINE_DEVICE_TYPE(PC9801_26, pc9801_26_device, "pc9801_26", "pc9801_26") +DEFINE_DEVICE_TYPE(PC9801_26, pc9801_26_device, "pc9801_26", "NEC PC-9801-26") WRITE_LINE_MEMBER(pc9801_26_device::sound_irq) { - /* TODO: seems to die very often */ + // TODO: sometimes misfired irq causes sound or even host hang m_bus->int_w<5>(state); } @@ -77,10 +79,27 @@ const tiny_rom_entry *pc9801_26_device::device_rom_region() const static INPUT_PORTS_START( pc9801_26 ) PORT_INCLUDE( pc9801_joy_port ) - PORT_START("OPN_DSW") + // On-board jumpers + // TODO: any way to actually read these from HW? + PORT_START("OPN_JP6A1_JP6A3") + PORT_CONFNAME( 0x03, 0x02, "PC-9801-26: Interrupt level") + PORT_CONFSETTING( 0x00, "IRQ 0" ) // 2-3, 2-3 + PORT_CONFSETTING( 0x01, "IRQ 4" ) // 2-3, 1-2 + PORT_CONFSETTING( 0x02, "IRQ 5" ) // 1-2, 1-2 + PORT_CONFSETTING( 0x03, "IRQ 6" ) // 1-2, 2-3 + + PORT_START("OPN_JP6A2") + PORT_CONFNAME( 0x07, 0x01, "PC-9801-26: Sound ROM address") + PORT_CONFSETTING( 0x00, "0xc8000" ) // 1-10 + PORT_CONFSETTING( 0x01, "0xcc000" ) // 2-9 + PORT_CONFSETTING( 0x02, "0xd0000" ) // 3-8 + PORT_CONFSETTING( 0x03, "0xd4000" ) // 4-7 + PORT_CONFSETTING( 0x04, "Disable ROM") // 5-6 + + PORT_START("OPN_JP6A4") PORT_CONFNAME( 0x01, 0x01, "PC-9801-26: Port Base" ) - PORT_CONFSETTING( 0x00, "0x088" ) - PORT_CONFSETTING( 0x01, "0x188" ) + PORT_CONFSETTING( 0x00, "0x088" ) // 1-4 + PORT_CONFSETTING( 0x01, "0x188" ) // 2-3 INPUT_PORTS_END ioport_constructor pc9801_26_device::device_input_ports() const @@ -97,9 +116,9 @@ ioport_constructor pc9801_26_device::device_input_ports() const //------------------------------------------------- pc9801_26_device::pc9801_26_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : pc9801_snd_device(mconfig, PC9801_26, tag, owner, clock), - m_bus(*this, DEVICE_SELF_OWNER), - m_opn(*this, "opn") + : pc9801_snd_device(mconfig, PC9801_26, tag, owner, clock) + , m_bus(*this, DEVICE_SELF_OWNER) + , m_opn(*this, "opn") { } @@ -117,10 +136,15 @@ void pc9801_26_device::device_validity_check(validity_checker &valid) const // device_start - device-specific startup //------------------------------------------------- +u16 pc9801_26_device::read_io_base() +{ + return ((ioport("OPN_JP6A4")->read() & 1) << 8) + 0x0088; +} void pc9801_26_device::device_start() { - m_bus->program_space().install_rom(0xcc000,0xcffff,memregion(this->subtag("sound_bios").c_str())->base()); + m_rom_base = 0; + m_io_base = 0; } @@ -130,10 +154,48 @@ void pc9801_26_device::device_start() void pc9801_26_device::device_reset() { - uint16_t port_base = (ioport("OPN_DSW")->read() & 1) << 8; + // install the ROM to the physical program space + u8 rom_setting = ioport("OPN_JP6A2")->read() & 7; + static const u32 rom_addresses[8] = { 0xc8000, 0xcc000, 0xd0000, 0xd4000, 0, 0, 0, 0 }; + u32 current_rom = rom_addresses[rom_setting & 7]; + memory_region *rom_region = memregion(this->subtag("sound_bios").c_str()); + const u32 rom_size = rom_region->bytes() - 1; - m_bus->io_space().unmap_readwrite(0x0088, 0x008b, 0x100); - m_bus->install_io(port_base + 0x0088, port_base + 0x008b, read8sm_delegate(*this, FUNC(pc9801_26_device::opn_r)), write8sm_delegate(*this, FUNC(pc9801_26_device::opn_w))); + if (m_rom_base == 0) + m_rom_base = current_rom; + + if (m_rom_base != 0) + { + logerror("%s: uninstall ROM at %08x-%08x\n", machine().describe_context(), m_rom_base, m_rom_base + rom_size); + m_bus->program_space().unmap_readwrite(m_rom_base, m_rom_base + rom_size); + } + if (current_rom != 0) + { + logerror("%s: install ROM at %08x-%08x\n", machine().describe_context(), current_rom, current_rom + rom_size); + m_bus->program_space().unmap_readwrite(current_rom, current_rom + rom_size); + m_bus->program_space().install_rom( + current_rom, + current_rom + rom_size, + rom_region->base() + ); + } + m_rom_base = current_rom; + + // install I/O ports + u16 current_io = read_io_base(); + m_bus->flush_install_io( + this->tag(), + m_io_base, + current_io, + 3, + read8sm_delegate(*this, FUNC(pc9801_26_device::opn_r)), + write8sm_delegate(*this, FUNC(pc9801_26_device::opn_w)) + ); + m_io_base = current_io; + + // install IRQ line +// static const u8 irq_levels[4] = {0, 4, 5, 6}; +// m_irq_level = irq_levels[ioport("OPN_JP6A1_JP6A3")->read() & 3]; } diff --git a/src/devices/bus/cbus/pc9801_26.h b/src/devices/bus/cbus/pc9801_26.h index 84eeaab31d4..80cd57a20cd 100644 --- a/src/devices/bus/cbus/pc9801_26.h +++ b/src/devices/bus/cbus/pc9801_26.h @@ -2,7 +2,7 @@ // copyright-holders:Angelo Salese /*************************************************************************** -Template for skeleton device + NEC PC-9801-26 sound card ***************************************************************************/ @@ -39,12 +39,14 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual ioport_constructor device_input_ports() const override; virtual const tiny_rom_entry *device_rom_region() const override; + virtual u16 read_io_base() override; private: required_device<pc9801_slot_device> m_bus; required_device<ym2203_device> m_opn; DECLARE_WRITE_LINE_MEMBER(sound_irq); + u32 m_rom_base; }; diff --git a/src/devices/bus/cbus/pc9801_55.cpp b/src/devices/bus/cbus/pc9801_55.cpp new file mode 100644 index 00000000000..879ad2f1a66 --- /dev/null +++ b/src/devices/bus/cbus/pc9801_55.cpp @@ -0,0 +1,253 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/************************************************************************************************** + + NEC PC-9801-55/-55U/-55L + + SCSI interface, running on WD33C93A + + TODO: + - Is PC-9801-55 also running on this except with WD33C93 instead? + Will see once we obtain a dump of that; + - DIP is never taken (definitely lies at vector 0x2c -> PC=0xdc01e); + - DRQ + - All roms seems to be misdumped (too generous sizes), is it intentional? + +**************************************************************************************************/ + +#include "emu.h" +#include "bus/cbus/pc9801_55.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +DEFINE_DEVICE_TYPE(PC9801_55U, pc9801_55u_device, "pc9801_55u", "NEC PC-9801-55U") +DEFINE_DEVICE_TYPE(PC9801_55L, pc9801_55l_device, "pc9801_55l", "NEC PC-9801-55L") + +ROM_START( pc9801_55u ) + ROM_REGION16_LE( 0x10000, "scsi_bios", ROMREGION_ERASEFF ) + // JNC2B_00.BIN BADADDR ---xxxxxxxxxxxx + // JNC3B_00.BIN BADADDR ---xxxxxxxxxxxx + ROM_LOAD16_BYTE( "jnc2b_00.bin", 0x000000, 0x008000, CRC(ddace1b7) SHA1(614569be28a90bd385cf8abc193e629e568125b7) ) + ROM_LOAD16_BYTE( "jnc3b_00.bin", 0x000001, 0x008000, CRC(b8a8a49e) SHA1(7781dab492df889148e070a7da7ead207e18ed04) ) +ROM_END + +const tiny_rom_entry *pc9801_55u_device::device_rom_region() const +{ + return ROM_NAME( pc9801_55u ); +} + +ROM_START( pc9801_55l ) + ROM_REGION16_LE( 0x10000, "scsi_bios", ROMREGION_ERASEFF ) + // ETA1B_00.BIN BADADDR ---xxxxxxxxxxxx + // ETA3B_00.BIN BADADDR ---xxxxxxxxxxxx + ROM_LOAD16_BYTE( "eta1b_00.bin", 0x000000, 0x008000, CRC(300ff6c1) SHA1(6cdee535b77535fe6c4dda4427aeb803fcdea0b8) ) + ROM_LOAD16_BYTE( "eta3b_00.bin", 0x000001, 0x008000, CRC(44477512) SHA1(182bb45ba0da7a4f9113e268e04ffca8403cf164) ) +ROM_END + +const tiny_rom_entry *pc9801_55l_device::device_rom_region() const +{ + return ROM_NAME( pc9801_55l ); +} + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +WRITE_LINE_MEMBER(pc9801_55_device::scsi_irq_w) +{ + // TODO: should be INT3, but BIOS configures as INT0 somewhere (unhandled dip reading?) + m_bus->int_w<0>(state); +} + +void pc9801_55_device::device_add_mconfig(machine_config &config) +{ + NSCSI_BUS(config, m_scsi_bus); + // TODO: currently returning default_scsi_devices, checkout if true for PC-98 + NSCSI_CONNECTOR(config, "scsi:0", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:1", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:2", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:3", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:4", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:5", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:6", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:7").option_set("wdc", WD33C93A).machine_config( + [this](device_t *device) + { + wd33c9x_base_device &adapter = downcast<wd33c9x_base_device &>(*device); + + // TODO: unknown clock + adapter.set_clock(10'000'000); + adapter.irq_cb().set(*this, FUNC(pc9801_55_device::scsi_irq_w)); + // TODO: DRQ on C-bus + //adapter.drq_cb().set(*this, FUNC(pc9801_55_device::scsi_drq)); + } + ); +} + +static INPUT_PORTS_START( pc9801_55 ) + PORT_START("SCSI_DSW1") + PORT_DIPNAME( 0x07, 0x07, "PC-9801-55: SCSI board ID") PORT_DIPLOCATION("SCSI_SW1:!1,!2,!3") + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x01, "1" ) + PORT_DIPSETTING( 0x02, "2" ) + PORT_DIPSETTING( 0x03, "3" ) + PORT_DIPSETTING( 0x04, "4" ) + PORT_DIPSETTING( 0x05, "5" ) + PORT_DIPSETTING( 0x06, "6" ) + PORT_DIPSETTING( 0x07, "7" ) + PORT_DIPNAME( 0x38, 0x18, "PC-9801-55: Interrupt level") PORT_DIPLOCATION("SCSI_SW1:!4,!5,!6") + PORT_DIPSETTING( 0x00, "INT0" ) + PORT_DIPSETTING( 0x08, "INT1" ) + PORT_DIPSETTING( 0x10, "INT2" ) + PORT_DIPSETTING( 0x18, "INT3" ) + PORT_DIPSETTING( 0x20, "INT5" ) + PORT_DIPSETTING( 0x28, "INT6" ) + PORT_DIPSETTING( 0x30, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x38, DEF_STR( Unknown ) ) + PORT_DIPNAME( 0xc0, 0x00, "PC-9801-55: DMA channel") PORT_DIPLOCATION("SCSI_SW1:!7,!8") + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x40, "1 (prohibited)" ) + PORT_DIPSETTING( 0x80, "2" ) + PORT_DIPSETTING( 0xc0, "3" ) + + PORT_START("SCSI_DSW2") + // TODO: understand all valid possible settings of this + PORT_DIPNAME( 0x7f, 0x66, "PC-9801-55: machine ID and ROM base address") PORT_DIPLOCATION("SCSI_SW2:!1,!2,!3,!4,!5,!6,!7") + PORT_DIPSETTING( 0x66, "i386, 0xdc000-0xddfff") + // ... + PORT_DIPNAME( 0x80, 0x80, "PC-9801-55: ROM accessibility at Power-On") PORT_DIPLOCATION("SCSI_SW2:!8") + PORT_DIPSETTING( 0x80, DEF_STR( Yes )) + PORT_DIPSETTING( 0x00, DEF_STR( No )) + + PORT_START("SCSI_JP") + // SW3 and SW4 Jumper settings + PORT_CONFNAME( 0x03, 0x00, "PC-9801-55: I/O base address") + PORT_CONFSETTING( 0x00, "0xcc0") // 01-02 01 02 + PORT_CONFSETTING( 0x01, "0xcd0") + PORT_CONFSETTING( 0x02, "0xce0") + PORT_CONFSETTING( 0x03, "0xcf0") +INPUT_PORTS_END + +ioport_constructor pc9801_55_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( pc9801_55 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pc9801_55u_device - constructor +//------------------------------------------------- + +pc9801_55_device::pc9801_55_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , m_bus(*this, DEVICE_SELF_OWNER) + , m_scsi_bus(*this, "scsi") + , m_wdc(*this, "scsi:7:wdc") +{ +} + +pc9801_55u_device::pc9801_55u_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pc9801_55_device(mconfig, PC9801_55U, tag, owner, clock) +{ + +} + +pc9801_55l_device::pc9801_55l_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pc9801_55_device(mconfig, PC9801_55L, tag, owner, clock) +{ + +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void pc9801_55_device::device_validity_check(validity_checker &valid) const +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pc9801_55_device::device_start() +{ + m_bus->program_space().install_rom( + 0xdc000, + 0xddfff, + memregion(this->subtag("scsi_bios").c_str())->base() + ); + + // TODO: docs hints that this has mirrors at 0xcd*, 0xce*, 0xcf* + m_bus->install_io( + 0xcc0, + 0xcc5, + read8sm_delegate(*this, FUNC(pc9801_55_device::comms_r)), + write8sm_delegate(*this, FUNC(pc9801_55_device::comms_w)) + ); + +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pc9801_55_device::device_reset() +{ + +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +u8 pc9801_55_device::comms_r(offs_t offset) +{ + if((offset & 1) == 0) + { + offs_t addr = offset >> 1; + if (addr & 2) + { + logerror("%s: Read to status port [%02x]\n", machine().describe_context(), offset + 0xcc0); + + return 0; + } + + return m_wdc->indir_r(addr); + } + // odd + + logerror("%s: Read to undefined port [%02x]\n", machine().describe_context(), offset + 0xcc0); + + return 0xff; +} + +void pc9801_55_device::comms_w(offs_t offset, u8 data) +{ + if((offset & 1) == 0) + { + offs_t addr = offset >> 1; + if (addr & 2) + { + logerror("%s: Write to command port [%02x] %02x\n", machine().describe_context(), offset + 0xcc0, data); + + return; + } + + m_wdc->indir_w(addr, data); + return; + } + + // odd + logerror("%s: Write to undefined port [%02x] %02x\n", machine().describe_context(), offset + 0xcc0, data); +} diff --git a/src/devices/bus/cbus/pc9801_55.h b/src/devices/bus/cbus/pc9801_55.h new file mode 100644 index 00000000000..b74c754c2b8 --- /dev/null +++ b/src/devices/bus/cbus/pc9801_55.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + + NEC PC-9801-55/-55U/-55L + +***************************************************************************/ + +#ifndef MAME_BUS_CBUS_PC9801_55_H +#define MAME_BUS_CBUS_PC9801_55_H + +#pragma once + +#include "bus/cbus/pc9801_cbus.h" +#include "bus/nscsi/devices.h" +#include "machine/nscsi_bus.h" +#include "machine/wd33c9x.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pc9801_118_device + +class pc9801_55_device : public device_t +{ +public: + // construction/destruction + //pc9801_55_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + pc9801_55_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + static constexpr feature_type unemulated_features() { return feature::DISK; } + + DECLARE_WRITE_LINE_MEMBER(scsi_irq_w); + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const override; + virtual void device_start() override; + virtual void device_reset() override; + // optional information overrides +// virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual ioport_constructor device_input_ports() const override; + +private: + required_device<pc9801_slot_device> m_bus; + required_device<nscsi_bus_device> m_scsi_bus; + required_device<wd33c9x_base_device> m_wdc; + + u8 comms_r(offs_t offset); + void comms_w(offs_t offset, u8 data); +}; + +class pc9801_55u_device : public pc9801_55_device +{ +public: + pc9801_55u_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +private: + virtual const tiny_rom_entry *device_rom_region() const override; + +}; + +class pc9801_55l_device : public pc9801_55_device +{ +public: + pc9801_55l_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +private: + virtual const tiny_rom_entry *device_rom_region() const override; + +}; + +// device type definition +//DECLARE_DEVICE_TYPE(PC9801_55, pc9801_55_device) +DECLARE_DEVICE_TYPE(PC9801_55U, pc9801_55u_device) +DECLARE_DEVICE_TYPE(PC9801_55L, pc9801_55l_device) + +#endif // MAME_BUS_CBUS_PC9801_55_H diff --git a/src/devices/bus/cbus/pc9801_86.cpp b/src/devices/bus/cbus/pc9801_86.cpp index 2b8b9c8d1af..6fcc789e27e 100644 --- a/src/devices/bus/cbus/pc9801_86.cpp +++ b/src/devices/bus/cbus/pc9801_86.cpp @@ -1,25 +1,35 @@ // license:BSD-3-Clause // copyright-holders:Angelo Salese -/*************************************************************************** +/************************************************************************************************** NEC PC-9801-86 sound card NEC PC-9801-SpeakBoard sound card + Mad Factory Otomi-chan Kai sound card Similar to PC-9801-26, this one has YM2608 instead of YM2203 and an additional DAC port + SpeakBoard sound card seems to be derived design from -86, with an additional OPNA mapped at 0x58* + Otomi-chan Kai is a doujinshi sound card based off SpeakBoard design. + It uses YM3438 OPL2C mapped at 0x78*, and anything that uses the nax.exe sound driver + expects this to be installed as default (cfr. datsumj). + To fallback to a regular -26/-86 board user needs to add parameter switches "-2" or "-3" + respectively, cfr. "nax -?" for additional details. + TODO: - - Test all pcm modes - - Make volume work - - Recording + - Test all pcm modes; + - Make volume work; + - Recording; - SpeakBoard: no idea about software that uses this, also board shows a single YM2608B? - "-86 only supports ADPCM instead of PCM, while SpeakBoard has OPNA + 256 Kbit RAM" - Sounds like a sound core flaw since OPNA requires a rom region in any case; + "-86 only supports ADPCM instead of PCM, while SpeakBoard has OPNA + 256 Kbit RAM"; + - Otomi-chan Kai: find a manual (マニュアル), it's mentioned with nax usage. + Very low-res scan of the PCB sports a 4-bit dip-sw bank at very least; + - Otomi-chan Kai: unknown ID port readback; - verify sound irq; -***************************************************************************/ +**************************************************************************************************/ #include "emu.h" #include "bus/cbus/pc9801_86.h" @@ -32,15 +42,22 @@ //************************************************************************** // device type definition -DEFINE_DEVICE_TYPE(PC9801_86, pc9801_86_device, "pc9801_86", "pc9801_86") +DEFINE_DEVICE_TYPE(PC9801_86, pc9801_86_device, "pc9801_86", "NEC PC-9801-86") WRITE_LINE_MEMBER(pc9801_86_device::sound_irq) { m_fmirq = state ? true : false; - /* TODO: seems to die very often */ + // TODO: sometimes misfired irq causes sound or even host hang m_bus->int_w<5>(state || (m_pcmirq ? ASSERT_LINE : CLEAR_LINE)); } +// only for derived designs? +void pc9801_86_device::opna_map(address_map &map) +{ + // TODO: confirm it really is ROMless + // TODO: confirm size + map(0x000000, 0x1fffff).ram(); +} //------------------------------------------------- // device_add_mconfig - add device configuration @@ -60,6 +77,8 @@ void pc9801_86_device::pc9801_86_config(machine_config &config) SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); YM2608(config, m_opna, 7.987_MHz_XTAL); // actually YM2608B + // shouldn't have one +// m_opna->set_addrmap(0, &pc9801_86_device::opna_map); m_opna->irq_handler().set(FUNC(pc9801_86_device::sound_irq)); m_opna->port_a_read_callback().set(FUNC(pc9801_86_device::opn_porta_r)); //m_opna->port_b_read_callback().set(FUNC(pc8801_state::opn_portb_r)); @@ -79,6 +98,16 @@ void pc9801_86_device::device_add_mconfig(machine_config &config) pc9801_86_config(config); } +// helper for derived devices to account for the different master OPNA sound mixing +void pc9801_86_device::opna_reset_routes_config(machine_config &config) +{ + m_opna->reset_routes(); + m_opna->add_route(0, "lspeaker", 0.50); + m_opna->add_route(0, "rspeaker", 0.50); + m_opna->add_route(1, "lspeaker", 0.50); + m_opna->add_route(2, "rspeaker", 0.50); +} + // to load a different bios for slots: // -cbusX pc9801_86,bios=N ROM_START( pc9801_86 ) @@ -87,13 +116,12 @@ ROM_START( pc9801_86 ) // we currently mark bios names based off where they originally belonged to, lacking of a better info // supposedly these are -86 roms according to eikanwa2 sound card detection, // loading a -26 rom in a -86 environment causes an hang there. + // TODO: several later machines (i.e. CanBe) really has an internal -86 with sound BIOS data coming directly from the machine ROM + // it also sports different ID mapping at $a460 ROM_SYSTEM_BIOS( 0, "86rx", "nec86rx" ) ROMX_LOAD( "sound_rx.rom", 0x0000, 0x4000, BAD_DUMP CRC(fe9f57f2) SHA1(d5dbc4fea3b8367024d363f5351baecd6adcd8ef), ROM_BIOS(0) ) - ROM_SYSTEM_BIOS( 1, "86mu", "nec86mu" ) + ROM_SYSTEM_BIOS( 1, "86mu", "epson86mu" ) ROMX_LOAD( "sound_486mu.rom", 0x0000, 0x4000, BAD_DUMP CRC(6cdfa793) SHA1(4b8250f9b9db66548b79f961d61010558d6d6e1c), ROM_BIOS(1) ) - - // RAM - ROM_REGION( 0x100000, "opna", ROMREGION_ERASE00 ) ROM_END const tiny_rom_entry *pc9801_86_device::device_rom_region() const @@ -109,10 +137,32 @@ const tiny_rom_entry *pc9801_86_device::device_rom_region() const static INPUT_PORTS_START( pc9801_86 ) PORT_INCLUDE( pc9801_joy_port ) + // Single 8-bit DSW bank + // TODO: how HW really reads these? PORT_START("OPNA_DSW") - PORT_CONFNAME( 0x01, 0x01, "PC-9801-86: Port Base" ) - PORT_CONFSETTING( 0x00, "0x088" ) - PORT_CONFSETTING( 0x01, "0x188" ) + PORT_DIPNAME( 0x01, 0x00, "PC-9801-86: Port Base" ) PORT_DIPLOCATION("OPNA_SW:!1") + PORT_DIPSETTING( 0x00, "0x188" ) + PORT_DIPSETTING( 0x01, "0x288" ) + PORT_DIPNAME( 0x02, 0x00, "PC-9801-86: Enable sound ROM") PORT_DIPLOCATION("OPNA_SW:!2") + PORT_DIPSETTING( 0x00, DEF_STR( Yes ) ) // hardwired at 0xcc000 + PORT_DIPSETTING( 0x02, DEF_STR( No ) ) + PORT_DIPNAME( 0x0c, 0x00, "PC-9801-86: Interrupt level") PORT_DIPLOCATION("OPNA_SW:!3,!4") + PORT_DIPSETTING( 0x0c, "IRQ 0" ) + PORT_DIPSETTING( 0x08, "IRQ 4" ) + PORT_DIPSETTING( 0x00, "IRQ 5" ) + PORT_DIPSETTING( 0x04, "IRQ 6" ) + PORT_DIPNAME( 0x10, 0x00, "PC-9801-86: Interrupt enable") PORT_DIPLOCATION("OPNA_SW:!5") + PORT_DIPSETTING( 0x00, DEF_STR( Yes ) ) + PORT_DIPSETTING( 0x10, DEF_STR( No ) ) + PORT_DIPNAME( 0xe0, 0x80, "PC-9801-86: ID number") PORT_DIPLOCATION("OPNA_SW:!6,!7,!8") + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x20, "1" ) + PORT_DIPSETTING( 0x40, "2" ) + PORT_DIPSETTING( 0x60, "3" ) + PORT_DIPSETTING( 0x80, "4" ) + PORT_DIPSETTING( 0xa0, "5" ) + PORT_DIPSETTING( 0xc0, "6" ) + PORT_DIPSETTING( 0xe0, "7" ) INPUT_PORTS_END ioport_constructor pc9801_86_device::device_input_ports() const @@ -129,12 +179,12 @@ ioport_constructor pc9801_86_device::device_input_ports() const //------------------------------------------------- pc9801_86_device::pc9801_86_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : pc9801_snd_device(mconfig, type, tag, owner, clock), - m_bus(*this, DEVICE_SELF_OWNER), - m_opna(*this, "opna"), - m_ldac(*this, "ldac"), - m_rdac(*this, "rdac"), - m_queue(QUEUE_SIZE) + : pc9801_snd_device(mconfig, type, tag, owner, clock) + , m_bus(*this, DEVICE_SELF_OWNER) + , m_opna(*this, "opna") + , m_ldac(*this, "ldac") + , m_rdac(*this, "rdac") + , m_queue(QUEUE_SIZE) { } @@ -154,6 +204,11 @@ void pc9801_86_device::device_validity_check(validity_checker &valid) const { } +u16 pc9801_86_device::read_io_base() +{ + return ((ioport("OPNA_DSW")->read() & 1) << 8) + 0x188; +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -161,12 +216,19 @@ void pc9801_86_device::device_validity_check(validity_checker &valid) const void pc9801_86_device::device_start() { - m_bus->program_space().install_rom(0xcc000,0xcffff,memregion(this->subtag("sound_bios").c_str())->base()); + // TODO: uninstall option from dip + m_bus->program_space().install_rom( + 0xcc000, + 0xcffff, + memregion(this->subtag("sound_bios").c_str())->base() + ); m_bus->install_io(0xa460, 0xa463, read8smo_delegate(*this, FUNC(pc9801_86_device::id_r)), write8smo_delegate(*this, FUNC(pc9801_86_device::mask_w))); m_bus->install_io(0xa464, 0xa46f, read8sm_delegate(*this, FUNC(pc9801_86_device::pcm_r)), write8sm_delegate(*this, FUNC(pc9801_86_device::pcm_w))); m_bus->install_io(0xa66c, 0xa66f, read8sm_delegate(*this, [this](offs_t o){ return o == 2 ? m_pcm_mute : 0xff; }, "pc9801_86_mute_r"), write8sm_delegate(*this, [this](offs_t o, u8 d){ if(o == 2) m_pcm_mute = d; }, "pc9801_86_mute_w")); + m_io_base = 0; + m_dac_timer = timer_alloc(); save_item(NAME(m_count)); save_item(NAME(m_queue)); @@ -180,9 +242,16 @@ void pc9801_86_device::device_start() void pc9801_86_device::device_reset() { - uint16_t port_base = (ioport("OPNA_DSW")->read() & 1) << 8; - m_bus->io_space().unmap_readwrite(0x0088, 0x008f, 0x100); - m_bus->install_io(port_base + 0x0088, port_base + 0x008f, read8sm_delegate(*this, FUNC(pc9801_86_device::opna_r)), write8sm_delegate(*this, FUNC(pc9801_86_device::opna_w))); + u16 current_io = read_io_base(); + m_bus->flush_install_io( + this->tag(), + m_io_base, + current_io, + 7, + read8sm_delegate(*this, FUNC(pc9801_86_device::opna_r)), + write8sm_delegate(*this, FUNC(pc9801_86_device::opna_w)) + ); + m_io_base = current_io; m_mask = 0; m_head = m_tail = m_count = 0; @@ -200,36 +269,40 @@ void pc9801_86_device::device_reset() //************************************************************************** -uint8_t pc9801_86_device::opna_r(offs_t offset) +u8 pc9801_86_device::opna_r(offs_t offset) { if((offset & 1) == 0) return m_opna->read(offset >> 1); else // odd { - logerror("PC9801-86: Read to undefined port [%02x]\n",offset+0x188); + logerror("%s: Read to undefined port [%02x]\n", machine().describe_context(), offset + m_io_base); return 0xff; } } -void pc9801_86_device::opna_w(offs_t offset, uint8_t data) +void pc9801_86_device::opna_w(offs_t offset, u8 data) { if((offset & 1) == 0) m_opna->write(offset >> 1,data); else // odd - logerror("PC9801-86: Write to undefined port [%02x] %02x\n",offset+0x188,data); + logerror("%s: Write to undefined port [%02x] %02x\n", machine().describe_context(), offset + m_io_base, data); } -uint8_t pc9801_86_device::id_r() +u8 pc9801_86_device::id_r() { - return 0x40 | m_mask; + // either a -86 or 9821 MATE A uses this id (built-in) + const u8 id_port = ((ioport("OPNA_DSW")->read() & 1) << 4) | 0x40; + return id_port | m_mask; } -void pc9801_86_device::mask_w(uint8_t data) +void pc9801_86_device::mask_w(u8 data) { m_mask = data & 1; + // TODO: bit 1 totally cuts off OPNA output + logerror("%s: OPNA mask setting %02x\n", machine().describe_context(), data); } -uint8_t pc9801_86_device::pcm_r(offs_t offset) +u8 pc9801_86_device::pcm_r(offs_t offset) { if((offset & 1) == 0) { @@ -251,7 +324,7 @@ uint8_t pc9801_86_device::pcm_r(offs_t offset) return 0xff; } -void pc9801_86_device::pcm_w(offs_t offset, uint8_t data) +void pc9801_86_device::pcm_w(offs_t offset, u8 data) { const u32 rate = (25.4_MHz_XTAL).value() / 16; const int divs[8] = {36, 48, 72, 96, 144, 192, 288, 384}; @@ -301,9 +374,9 @@ int pc9801_86_device::queue_count() return m_count; } -uint8_t pc9801_86_device::queue_pop() +u8 pc9801_86_device::queue_pop() { - uint8_t ret = m_queue[m_tail++]; + u8 ret = m_queue[m_tail++]; m_tail %= QUEUE_SIZE; m_count = (m_count - 1) % QUEUE_SIZE; // dangel resets the fifo after filling it completely so maybe it expects an underflow return ret; @@ -356,7 +429,9 @@ void pc9801_86_device::device_timer(emu_timer& timer, device_timer_id id, int pa } //************************************************************************** +// // SpeakBoard device section +// //************************************************************************** DEFINE_DEVICE_TYPE(PC9801_SPEAKBOARD, pc9801_speakboard_device, "pc9801_spb", "NEC PC9801 SpeakBoard") @@ -365,11 +440,6 @@ ROM_START( pc9801_spb ) ROM_REGION( 0x4000, "sound_bios", ROMREGION_ERASEFF ) ROM_LOAD16_BYTE( "spb lh5764 ic21_pink.bin", 0x0001, 0x2000, CRC(5bcefa1f) SHA1(ae88e45d411bf5de1cb42689b12b6fca0146c586) ) ROM_LOAD16_BYTE( "spb lh5764 ic22_green.bin", 0x0000, 0x2000, CRC(a7925ced) SHA1(3def9ee386ab6c31436888261bded042cd64a0eb) ) - - // RAM - ROM_REGION( 0x100000, "opna", ROMREGION_ERASE00 ) - - ROM_REGION( 0x100000, "opna_slave", ROMREGION_ERASE00 ) ROM_END const tiny_rom_entry *pc9801_speakboard_device::device_rom_region() const @@ -377,32 +447,21 @@ const tiny_rom_entry *pc9801_speakboard_device::device_rom_region() const return ROM_NAME( pc9801_spb ); } - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// pc9801_speakboard_device - constructor -//------------------------------------------------- - pc9801_speakboard_device::pc9801_speakboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : pc9801_86_device(mconfig, PC9801_SPEAKBOARD, tag, owner, clock), - m_opna_slave(*this, "opna_slave") + : pc9801_86_device(mconfig, PC9801_SPEAKBOARD, tag, owner, clock) + , m_opna_slave(*this, "opna_slave") { } void pc9801_speakboard_device::device_add_mconfig(machine_config &config) { pc9801_86_config(config); - - m_opna->reset_routes(); - m_opna->add_route(0, "lspeaker", 0.50); - m_opna->add_route(0, "rspeaker", 0.50); - m_opna->add_route(1, "lspeaker", 0.50); - m_opna->add_route(2, "rspeaker", 0.50); + opna_reset_routes_config(config); + // TODO: confirm RAM mapping configuration (shared? not present on either chip? misc?) + m_opna->set_addrmap(0, &pc9801_speakboard_device::opna_map); YM2608(config, m_opna_slave, 7.987_MHz_XTAL); + m_opna_slave->set_addrmap(0, &pc9801_speakboard_device::opna_map); m_opna_slave->add_route(0, "lspeaker", 0.50); m_opna_slave->add_route(0, "rspeaker", 0.50); m_opna_slave->add_route(1, "lspeaker", 0.50); @@ -421,22 +480,96 @@ void pc9801_speakboard_device::device_reset() pc9801_86_device::device_reset(); } -uint8_t pc9801_speakboard_device::opna_slave_r(offs_t offset) +u8 pc9801_speakboard_device::opna_slave_r(offs_t offset) { if((offset & 1) == 0) return m_opna_slave->read(offset >> 1); else // odd { - logerror("PC9801-SPB: Read to undefined port [%02x]\n",offset+0x588); + logerror("%s: Read to undefined port [%02x]\n", machine().describe_context(), offset + 0x588); return 0xff; } } -void pc9801_speakboard_device::opna_slave_w(offs_t offset, uint8_t data) +void pc9801_speakboard_device::opna_slave_w(offs_t offset, u8 data) { if((offset & 1) == 0) m_opna_slave->write(offset >> 1,data); else // odd - logerror("PC9801-SPB: Write to undefined port [%02x] %02x\n",offset+0x588,data); + logerror("%s: Write to undefined port [%02x] %02x\n", machine().describe_context(), offset + 0x588, data); } +//************************************************************************** +// +// Otomi-chan Kai device section +// +//************************************************************************** + +DEFINE_DEVICE_TYPE(OTOMICHAN_KAI, otomichan_kai_device, "pc98_otomichan_kai", "MAD Factory Otomi-chan Kai") // 音美(おとみ)ちゃん改 + +otomichan_kai_device::otomichan_kai_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pc9801_86_device(mconfig, OTOMICHAN_KAI, tag, owner, clock) + , m_opn2c(*this, "opn2c") +{ +} + +ROM_START( pc98_otomichan_kai ) + ROM_REGION( 0x4000, "sound_bios", ROMREGION_ERASEFF ) + // TODO: "compatible" with SpeakBoard, does it even uses a ROM altogether? low-res PCB pic doesn't help at all. + ROM_LOAD16_BYTE( "spb lh5764 ic21_pink.bin", 0x0001, 0x2000, BAD_DUMP CRC(5bcefa1f) SHA1(ae88e45d411bf5de1cb42689b12b6fca0146c586) ) + ROM_LOAD16_BYTE( "spb lh5764 ic22_green.bin", 0x0000, 0x2000, BAD_DUMP CRC(a7925ced) SHA1(3def9ee386ab6c31436888261bded042cd64a0eb) ) +ROM_END + +const tiny_rom_entry *otomichan_kai_device::device_rom_region() const +{ + return ROM_NAME( pc98_otomichan_kai ); +} + +void otomichan_kai_device::device_add_mconfig(machine_config &config) +{ + pc9801_86_config(config); + opna_reset_routes_config(config); + // TODO: confirm if this has OPNA RAM + m_opna->set_addrmap(0, &otomichan_kai_device::opna_map); + + YM3438(config, m_opn2c, 7.987_MHz_XTAL); + m_opn2c->add_route(0, "lspeaker", 0.50); + m_opn2c->add_route(1, "rspeaker", 0.50); +} + +u8 otomichan_kai_device::id_r() +{ + // no ID, unconfirmed if it has mask + return 0xf0 | m_mask; +} + +void otomichan_kai_device::device_start() +{ + pc9801_86_device::device_start(); + + m_bus->install_io(0x0788, 0x078f, read8sm_delegate(*this, FUNC(otomichan_kai_device::opn2c_r)), write8sm_delegate(*this, FUNC(otomichan_kai_device::opn2c_w))); +} + +void otomichan_kai_device::device_reset() +{ + pc9801_86_device::device_reset(); +} + +u8 otomichan_kai_device::opn2c_r(offs_t offset) +{ + if((offset & 1) == 0) + return m_opn2c->read(offset >> 1); + else // odd + { + logerror("%s: Read to undefined port [%02x]\n", machine().describe_context(), offset + 0x788); + return 0xff; + } +} + +void otomichan_kai_device::opn2c_w(offs_t offset, u8 data) +{ + if((offset & 1) == 0) + m_opn2c->write(offset >> 1, data); + else // odd + logerror("%s: Write to undefined port [%02x] %02x\n", machine().describe_context(), offset + 0x788, data); +} diff --git a/src/devices/bus/cbus/pc9801_86.h b/src/devices/bus/cbus/pc9801_86.h index 21de4102f01..5dda6681f6b 100644 --- a/src/devices/bus/cbus/pc9801_86.h +++ b/src/devices/bus/cbus/pc9801_86.h @@ -29,13 +29,6 @@ public: pc9801_86_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); pc9801_86_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); - uint8_t opna_r(offs_t offset); - void opna_w(offs_t offset, uint8_t data); - uint8_t id_r(); - void mask_w(uint8_t data); - uint8_t pcm_r(offs_t offset); - void pcm_w(offs_t offset, uint8_t data); - DECLARE_WRITE_LINE_MEMBER(sound_irq); protected: @@ -45,25 +38,37 @@ protected: virtual void device_reset() override; // optional information overrides virtual void device_add_mconfig(machine_config &config) override; + void opna_reset_routes_config(machine_config &config); virtual ioport_constructor device_input_ports() const override; virtual const tiny_rom_entry *device_rom_region() const override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; void pc9801_86_config(machine_config &config); + virtual u16 read_io_base() override; required_device<pc9801_slot_device> m_bus; required_device<ym2608_device> m_opna; + void opna_map(address_map &map); + + u8 opna_r(offs_t offset); + void opna_w(offs_t offset, u8 data); + virtual u8 id_r(); + void mask_w(u8 data); + u8 pcm_r(offs_t offset); + void pcm_w(offs_t offset, u8 data); + + u8 m_mask; + private: int queue_count(); - uint8_t queue_pop(); - + u8 queue_pop(); - uint8_t m_mask, m_pcm_mode, m_vol[7], m_pcm_ctrl, m_pcm_mute; + u8 m_pcm_mode, m_vol[7], m_pcm_ctrl, m_pcm_mute; uint16_t m_head, m_tail, m_count, m_irq_rate; bool m_pcmirq, m_fmirq, m_pcm_clk, m_init; required_device<dac_word_interface> m_ldac; required_device<dac_word_interface> m_rdac; - std::vector<uint8_t> m_queue; + std::vector<u8> m_queue; emu_timer *m_dac_timer; }; @@ -73,8 +78,10 @@ public: // construction/destruction pc9801_speakboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - uint8_t opna_slave_r(offs_t offset); - void opna_slave_w(offs_t offset, uint8_t data); + static constexpr feature_type imperfect_features() { return feature::SOUND; } + + u8 opna_slave_r(offs_t offset); + void opna_slave_w(offs_t offset, u8 data); protected: virtual void device_add_mconfig(machine_config &config) override; @@ -86,13 +93,33 @@ private: required_device<ym2608_device> m_opna_slave; }; +class otomichan_kai_device : public pc9801_86_device +{ +public: + // construction/destruction + otomichan_kai_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); -// device type definition -DECLARE_DEVICE_TYPE(PC9801_86, pc9801_86_device) -DECLARE_DEVICE_TYPE(PC9801_SPEAKBOARD, pc9801_speakboard_device) + static constexpr feature_type imperfect_features() { return feature::SOUND; } + u8 opn2c_r(offs_t offset); + void opn2c_w(offs_t offset, u8 data); +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + virtual const tiny_rom_entry *device_rom_region() const override; + +private: + required_device<ym3438_device> m_opn2c; + + virtual u8 id_r() override; +}; +// device type definition +DECLARE_DEVICE_TYPE(PC9801_86, pc9801_86_device) +DECLARE_DEVICE_TYPE(PC9801_SPEAKBOARD, pc9801_speakboard_device) +DECLARE_DEVICE_TYPE(OTOMICHAN_KAI, otomichan_kai_device) #endif // MAME_BUS_CBUS_PC9801_86_H diff --git a/src/devices/bus/cbus/pc9801_amd98.cpp b/src/devices/bus/cbus/pc9801_amd98.cpp index a6eeb015c4c..5b4d66bbdff 100644 --- a/src/devices/bus/cbus/pc9801_amd98.cpp +++ b/src/devices/bus/cbus/pc9801_amd98.cpp @@ -1,6 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Angelo Salese -/*************************************************************************** +/************************************************************************************************** System Sacom AMD-98 (AmuseMent boarD) @@ -13,7 +13,7 @@ - PIT control; - PCM section; -============================================================================= +=================================================================================================== - Known games with AMD-98 support Brown's Run (System Sacom) @@ -25,7 +25,7 @@ Relics (Bothtec) Thexder (Game Arts) -***************************************************************************/ +**************************************************************************************************/ #include "emu.h" #include "bus/cbus/pc9801_amd98.h" @@ -37,7 +37,7 @@ //************************************************************************** // device type definition -DEFINE_DEVICE_TYPE(PC9801_AMD98, pc9801_amd98_device, "pc9801_amd98", "pc9801_amd98") +DEFINE_DEVICE_TYPE(PC9801_AMD98, pc9801_amd98_device, "pc9801_amd98", "System Sacom AMD-98") //------------------------------------------------- // device_add_mconfig - add device configuration @@ -101,11 +101,11 @@ ioport_constructor pc9801_amd98_device::device_input_ports() const //------------------------------------------------- pc9801_amd98_device::pc9801_amd98_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, PC9801_AMD98, tag, owner, clock), - m_bus(*this, DEVICE_SELF_OWNER), - m_ay1(*this, "ay1"), - m_ay2(*this, "ay2"), - m_ay3(*this, "ay3") + : device_t(mconfig, PC9801_AMD98, tag, owner, clock) + , m_bus(*this, DEVICE_SELF_OWNER) + , m_ay1(*this, "ay1") + , m_ay2(*this, "ay2") + , m_ay3(*this, "ay3") { } diff --git a/src/devices/bus/cbus/pc9801_amd98.h b/src/devices/bus/cbus/pc9801_amd98.h index fa031edbe1b..f26246c768b 100644 --- a/src/devices/bus/cbus/pc9801_amd98.h +++ b/src/devices/bus/cbus/pc9801_amd98.h @@ -2,7 +2,7 @@ // copyright-holders:Angelo Salese /*************************************************************************** - NEC PC-9801-118 + System Sacom AMD-98 (AmuseMent boarD) ***************************************************************************/ @@ -14,12 +14,11 @@ #include "bus/cbus/pc9801_cbus.h" #include "sound/ay8910.h" - //************************************************************************** // TYPE DEFINITIONS //************************************************************************** -// ======================> pc9801_118_device +// ======================> pc9801_amd98_device class pc9801_amd98_device : public device_t { @@ -54,12 +53,7 @@ private: }; - // device type definition DECLARE_DEVICE_TYPE(PC9801_AMD98, pc9801_amd98_device) - - - - -#endif // MAME_BUS_CBUS_PC9801_118_H +#endif // MAME_BUS_CBUS_PC9801_AMD98_H diff --git a/src/devices/bus/cbus/pc9801_cbus.cpp b/src/devices/bus/cbus/pc9801_cbus.cpp index 649676d31f1..9077d8cc4ea 100644 --- a/src/devices/bus/cbus/pc9801_cbus.cpp +++ b/src/devices/bus/cbus/pc9801_cbus.cpp @@ -1,15 +1,23 @@ // license:BSD-3-Clause // copyright-holders:Angelo Salese -/********************************************************************** +/************************************************************************************************** C-bus slot interface for PC-98xx family a.k.a. NEC version of the ISA bus. + C-bus -> Card Bus TODO: - stub interface, checkout what actually belongs here. + Speculation is that C-bus has ROM / RAM slots always in the 0xc0000-0xdffff region, + and some opacity can be added if true. + - move pc9801_cbus_devices declaration from pc9801 driver in here; + - 8-bit I/O smearing should be handled here; + - INT# should be handled here too; + - Best way to inform user when it tries to install incompatible boards? + - Support for PCI bridging on later machines (cfr. pc9801cx3); -**********************************************************************/ +**************************************************************************************************/ #include "emu.h" #include "pc9801_cbus.h" @@ -123,3 +131,35 @@ template void pc9801_slot_device::install_io<read8_delegate, write8_delegate template void pc9801_slot_device::install_io<read8s_delegate, write8s_delegate >(offs_t start, offs_t end, read8s_delegate rhandler, write8s_delegate whandler); template void pc9801_slot_device::install_io<read8sm_delegate, write8sm_delegate >(offs_t start, offs_t end, read8sm_delegate rhandler, write8sm_delegate whandler); template void pc9801_slot_device::install_io<read8smo_delegate, write8smo_delegate>(offs_t start, offs_t end, read8smo_delegate rhandler, write8smo_delegate whandler); + +// boilerplate code for boards that has configurable I/O with either Jumpers or Dip-Switches +// NB: client must have a mechanism to remember what port has been used before and after calling this, +// in order to avoid "last instantiated wins" issues with overlapping board full configs. +void pc9801_slot_device::flush_install_io(const char *client_tag, u16 old_io, u16 new_io, u16 size, read8sm_delegate rhandler, write8sm_delegate whandler) +{ + // initialize if client have this unmapped (such as first boot) + // device_start fns cannot read input ports ... + if (old_io == 0) + old_io = new_io; + + logerror("%s: %s uninstall I/O at %04x-%04x\n", + this->tag(), + client_tag, + old_io, + old_io + size + ); + this->io_space().unmap_readwrite(old_io, old_io + size); + + logerror("%s: %s install I/O at %04x-%04x\n", + this->tag(), + client_tag, + new_io, + new_io + size + ); + this->install_io( + new_io, + new_io + size, + rhandler, + whandler + ); +} diff --git a/src/devices/bus/cbus/pc9801_cbus.h b/src/devices/bus/cbus/pc9801_cbus.h index 728aca3e692..ab7085dfa86 100644 --- a/src/devices/bus/cbus/pc9801_cbus.h +++ b/src/devices/bus/cbus/pc9801_cbus.h @@ -113,6 +113,8 @@ public: template<int I> void int_w(bool state) { m_int_callback[I](state); } template<typename R, typename W> void install_io(offs_t start, offs_t end, R rhandler, W whandler); + void flush_install_io(const char *client_tag, u16 old_io, u16 new_io, u16 size, read8sm_delegate rhandler, write8sm_delegate whandler); + protected: // device-level overrides virtual void device_start() override; diff --git a/src/devices/bus/cbus/pc9801_snd.cpp b/src/devices/bus/cbus/pc9801_snd.cpp index 6a611d77e78..3a33cfe6757 100644 --- a/src/devices/bus/cbus/pc9801_snd.cpp +++ b/src/devices/bus/cbus/pc9801_snd.cpp @@ -3,21 +3,19 @@ /*************************************************************************** NEC PC-9801 - common functions for CBUS sound boards -26, -86, -118 + common functions for C-bus sound boards -26, -86, -118 ***************************************************************************/ #include "emu.h" #include "pc9801_snd.h" -//DEFINE_DEVICE_TYPE(PC9801_SND, pc9801_snd_device, "pc9801_snd", "PC9801 CBUS Sound") - pc9801_snd_device::pc9801_snd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, type, tag, owner, clock) { } -uint8_t pc9801_snd_device::opn_porta_r() +u8 pc9801_snd_device::opn_porta_r() { if(m_joy_sel & 0x80) return ioport(m_joy_sel & 0x40 ? "PA2" : "PA1")->read(); @@ -25,7 +23,7 @@ uint8_t pc9801_snd_device::opn_porta_r() return 0xff; } -void pc9801_snd_device::opn_portb_w(uint8_t data) { m_joy_sel = data; } +void pc9801_snd_device::opn_portb_w(u8 data) { m_joy_sel = data; } INPUT_PORTS_START(pc9801_joy_port) PORT_START("PA1") diff --git a/src/devices/bus/cbus/pc9801_snd.h b/src/devices/bus/cbus/pc9801_snd.h index c7408c09383..0c9c694a4e3 100644 --- a/src/devices/bus/cbus/pc9801_snd.h +++ b/src/devices/bus/cbus/pc9801_snd.h @@ -18,11 +18,13 @@ public: pc9801_snd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); protected: - uint8_t opn_porta_r(); - void opn_portb_w(uint8_t data); + u8 opn_porta_r(); + void opn_portb_w(u8 data); + u16 m_io_base; + virtual u16 read_io_base() = 0; private: - uint8_t m_joy_sel; + u8 m_joy_sel; }; //DECLARE_DEVICE_TYPE(PC9801_SND, pc9801_snd_device) |