summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/cbus/pc9801_118.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/cbus/pc9801_118.cpp')
-rw-r--r--src/devices/bus/cbus/pc9801_118.cpp120
1 files changed, 95 insertions, 25 deletions
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);
}