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]
This commit is contained in:
Angelo Salese 2021-08-24 10:22:03 +02:00 committed by GitHub
parent c471fad8e0
commit 0e4ba6d49a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 5718 additions and 2178 deletions

View File

@ -10988,7 +10988,9 @@ ExtractDisk [02]"MAPディスク " -> "duel kawanakajima_02.d88"
</part>
</software>
<software name="emeraldd">
<!-- Displays Glodia transition then logo keeps scrolling left -->
<!-- Same as Vain Dream? -->
<software name="emeraldd" supported="no">
<description>Emerald Dragon</description>
<year>1989</year>
<publisher>バショウハウス (Bashou House)</publisher>
@ -23448,7 +23450,10 @@ ExtractDisk [03]"USER_DISK " -> "maha-kala_03.d88"
</part>
</software>
<software name="valis2">
<!-- boot OK -->
<!-- Omake: press F5 during opening for music test, alternatively just boot disk G from drive 1 -->
<!-- TODO: checkout if there are other hidden hotkeys like PC98 version -->
<software name="valis2" supported="yes">
<description>Mugen Senshi Valis II</description>
<year>1989</year>
<publisher>日本テレネット (Nihon Telenet)</publisher>
@ -23686,12 +23691,12 @@ ExtractDisk [03]"USER_DISK " -> "maha-kala_03.d88"
</software>
<software name="navitune">
<description>Navitune</description>
<description>Navitune - Dragon Koukaiki</description>
<year>1989</year>
<publisher>工画堂スタジオ (Kogado Studio)</publisher>
<!-- PC8801mk2SR -->
<info name="release" value="198911xx"/>
<info name="alt_title" value="ナビチューン"/>
<info name="alt_title" value="ナビチューン ドラゴン航海記"/>
<!--combined image-->
<!--rom name="navitune.d88" size="1662512" crc="b9540b35" sha1="8d937c8acfb62a12d24596114e7168db1087eaf0"/-->
@ -36112,7 +36117,9 @@ ExtractDisk [03]"Ulysses_Disk1 " -> "ulysses_v80_03.d88" (same as ulyssesa)
</part>
</software>
<software name="vaindrea">
<!-- Displays Glodia transition then logo keeps scrolling left with wrong colors -->
<!-- Known to be related to write protect flag on System disk that must be ON (PC=0xB0A4) -->
<software name="vaindrea" supported="no">
<description>Vain Dream</description>
<year>1991</year>
<publisher>グローディア (Global Media)</publisher>

File diff suppressed because it is too large Load Diff

View File

@ -4366,6 +4366,8 @@ if (BUSES["CBUS"]~=null) then
files {
MAME_DIR .. "src/devices/bus/cbus/pc9801_26.cpp",
MAME_DIR .. "src/devices/bus/cbus/pc9801_26.h",
MAME_DIR .. "src/devices/bus/cbus/pc9801_55.cpp",
MAME_DIR .. "src/devices/bus/cbus/pc9801_55.h",
MAME_DIR .. "src/devices/bus/cbus/pc9801_86.cpp",
MAME_DIR .. "src/devices/bus/cbus/pc9801_86.h",
MAME_DIR .. "src/devices/bus/cbus/pc9801_118.cpp",

View File

@ -3448,6 +3448,18 @@ if (MACHINES["UPD1990A"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/upd4991a.h,MACHINES["UPD4991A"] = true
---------------------------------------------------
if (MACHINES["UPD4991A"]~=null) then
files {
MAME_DIR .. "src/devices/machine/upd4991a.cpp",
MAME_DIR .. "src/devices/machine/upd4991a.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/upd4992.h,MACHINES["UPD4992"] = true

View File

@ -676,6 +676,7 @@ MACHINES["TSB12LV01A"] = true
--MACHINES["TTL7474"] = true
--MACHINES["UCB1200"] = true
MACHINES["UPD1990A"] = true
--MACHINES["UPD4991A"] = true
MACHINES["UPD4992"] = true
MACHINES["UPD4701"] = true
MACHINES["UPD7001"] = true

View File

@ -729,6 +729,7 @@ MACHINES["TTL7474"] = true
MACHINES["TUBE"] = true
MACHINES["UCB1200"] = true
MACHINES["UPD1990A"] = true
MACHINES["UPD4991A"] = true
--MACHINES["UPD4992"] = true
MACHINES["UPD4701"] = true
MACHINES["UPD7001"] = true
@ -3123,6 +3124,12 @@ files {
MAME_DIR .. "src/mame/machine/pc9801_cd.h",
MAME_DIR .. "src/mame/machine/pc9801_memsw.cpp",
MAME_DIR .. "src/mame/machine/pc9801_memsw.h",
MAME_DIR .. "src/mame/drivers/pc98ha.cpp",
MAME_DIR .. "src/mame/includes/pc98ha.h",
MAME_DIR .. "src/mame/drivers/pc9801_epson.cpp",
MAME_DIR .. "src/mame/includes/pc9801_epson.h",
MAME_DIR .. "src/mame/drivers/pc9821.cpp",
MAME_DIR .. "src/mame/includes/pc9821.h",
MAME_DIR .. "src/mame/drivers/tk80bs.cpp",
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,140 @@
// license:BSD-3-Clause
// copyright-holders: Angelo Salese
/**************************************************************************************************
NEC uPD4991/uPD4991a parallel RTC
uPD4991 should be very similar but with "30% more power consumption" (cit.)
TODO:
- bare minimum to make PC98HA happy;
- set clock regs;
- alarm & timer pulse;
- AM/PM hour mode;
- leap year;
- busy flag;
- adjust/clock stop/clock wait mechanisms;
**************************************************************************************************/
#include "emu.h"
#include "machine/upd4991a.h"
//*************************************************************************************************
// GLOBAL VARIABLES
//*************************************************************************************************
// device type definition
DEFINE_DEVICE_TYPE(UPD4991A, upd4991a_device, "upd4991a", "NEC uPD4991a parallel RTC")
//*************************************************************************************************
// LIVE DEVICE
//*************************************************************************************************
//-------------------------------------------------
// upd4991a_device - constructor
//-------------------------------------------------
upd4991a_device::upd4991a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, UPD4991A, tag, owner, clock)
, device_rtc_interface(mconfig, *this)
, m_timer_clock(nullptr)
{
std::fill(std::begin(m_rtc_regs), std::end(m_rtc_regs), 0);
}
//-------------------------------------------------
// device_validity_check - perform validity checks
// on this device
//-------------------------------------------------
void upd4991a_device::device_validity_check(validity_checker &valid) const
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void upd4991a_device::device_start()
{
m_timer_clock = timer_alloc(TIMER_CLOCK);
m_timer_clock->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
save_item(NAME(m_address));
}
void upd4991a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case TIMER_CLOCK:
advance_seconds();
break;
}
}
//-------------------------------------------------
// rtc_clock_updated -
//-------------------------------------------------
void upd4991a_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
{
/*
[0-1]
xxxx xxxx seconds
[2-3]
xxxx xxxx minutes
[4-5]
xxxx xxxx hour
[6-7]
---- xxxx date digit (weekday?)
xxxx ---- 1 day digit
[8-9]
---- xxxx 10 day digit
xxxx ---- 1 month digit
[a-b]
---- xxxx 10 month digit
xxxx ---- 1 year digit
[c-d]
---- xxxx 10 year digit
xxxx ---- control register 1 (write only)
[e-f]
---- xxxx control register 2 (read/write)
xxxx ---- mode register (write only)
*/
m_rtc_regs[0] = convert_to_bcd(second);
m_rtc_regs[1] = convert_to_bcd(minute);
m_rtc_regs[2] = convert_to_bcd(hour);
const u8 bcd_day = convert_to_bcd(day);
const u8 bcd_month = convert_to_bcd(month);
const u8 bcd_year = convert_to_bcd(year);
m_rtc_regs[3] = (day_of_week-1) | ((bcd_day & 0x0f) << 4);
m_rtc_regs[4] = ((bcd_day & 0xf0) >> 4) | ((bcd_month & 0x0f) << 4);
m_rtc_regs[5] = ((bcd_month & 0xf0) >> 4) | ((bcd_year & 0x0f) << 4);
m_rtc_regs[6] = ((bcd_year & 0xf0) >> 4);
}
//*************************************************************************************************
// READ/WRITE HANDLERS
//*************************************************************************************************
u8 upd4991a_device::data_r(offs_t offset)
{
return m_rtc_regs[m_address >> 1] >> ((m_address & 1) ? 4 : 0);
}
void upd4991a_device::data_w(offs_t offset, u8 data)
{
// ...
}
void upd4991a_device::address_w(offs_t offset, u8 data)
{
m_address = data & 0xf;
}

View File

@ -0,0 +1,59 @@
// license:BSD-3-Clause
// copyright-holders: Angelo Salese
/***************************************************************************
uPD4991a RTC
***************************************************************************/
#ifndef MAME_MACHINE_UPD4991A_H
#define MAME_MACHINE_UPD4991A_H
#pragma once
#include "dirtc.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> upd4991a_device
class upd4991a_device : public device_t, public device_rtc_interface
{
public:
// construction/destruction
upd4991a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
// I/O operations
void address_w(offs_t offset, u8 data);
u8 data_r(offs_t offset);
void data_w(offs_t offset, u8 data);
protected:
// device-level overrides
virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_start() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
private:
enum
{
TIMER_CLOCK
//TIMER_TP,
//TIMER_DATA_OUT,
//TIMER_TEST_MODE
};
emu_timer *m_timer_clock;
u8 m_rtc_regs[8];
u8 m_address;
};
// device type definition
DECLARE_DEVICE_TYPE(UPD4991A, upd4991a_device)
#endif // MAME_MACHINE_UPD4991A_H

View File

@ -1082,7 +1082,7 @@ void neogeo_base_state::memcard_w(offs_t offset, uint16_t data, uint16_t mem_mas
if (ACCESSING_BITS_0_7)
{
if (m_memcard->present())
m_memcard->write(offset, data);
m_memcard->write(offset, data);
}
}

View File

@ -1,24 +1,31 @@
// license:BSD-3-Clause
// copyright-holders:Angelo Salese
/*************************************************************************************************************************************
/**************************************************************************************************
PC-8801 (c) 1981 NEC
driver by Angelo Salese, original MESS PC-88SR driver by ???
TODO:
- implement proper i8214 routing, also add irq latch mechanism;
- Fix up Floppy Terminal Count 0 / 1 writes properly, Castle Excellent (and presumably other games) is very picky about it.
- add differences between various models;
- implement proper upd3301 / i8257 support;
- fix "jumps" in mouse support pointer (noticeable in Balance of Power);
- implement proper i8214 routing, and add irq latch mechanism;
- Fix up Floppy Terminal Count 0 / 1 writes properly, Castle Excellent (and presumably other
games) is very picky about it.
- implement proper upd3301 / i8257 text support (currently hacked around);
- Add limits for extend work RAM;
- What happens to the palette contents when the analog/digital palette mode changes?
- waitstates;
- dipswitches needs to be controlled;
- below notes states that plain PC-8801 doesn't have a disk CPU, but the BIOS clearly checks the floppy ports. Wrong info?
- clean-ups, banking and video in particular (i.e. hook-ups with memory region should go away and device models should be used instead)
- clean-ups:
- better state machine isolation of features between various models (currently pretty cheaty);
- refactor memory banking to use address maps;
- video;
- double check dipswitches;
- move PC80S31K to device, needed by PC-6601SR, PC-88VA, (vanilla & optional) PC-9801.
Also notice that there are common points with SPC-1000 and TF-20 FDDs;
- backport/merge what is portable to PC-8001;
- implement bus slot mechanism for NEC boards ("PC-8800-**"), HAL PCG-8100 & GSX8800,
probably others (does bus have an actual codename or just "PC-8801 bus"?);
- below notes states that plain PC-8801 doesn't have a disk CPU, but the BIOS clearly checks
the floppy ports. Wrong info or check for external board anyway?
- fix "jumps" in mouse support pointer (noticeable in Balance of Power);
per-game specific TODO:
- 100yen Soft 8 Revival Special: tight loop with vblank bit, but vblank irq takes too much time to execute its code;
@ -334,6 +341,8 @@ void pc8801_state::draw_bitmap_3bpp(bitmap_ind16 &bitmap,const rectangle &clipre
if(cliprect.contains(x+xi, y+0))
bitmap.pix(y+0, x+xi) = m_palette->pen(pen & 7);
// TODO: real HW seems to actually just output to either even or odd line when in 3bpp mode
// investigate which is right
if(cliprect.contains(x+xi, y+1))
bitmap.pix(y+1, x+xi) = m_palette->pen(pen & 7);
}
@ -1170,6 +1179,8 @@ void pc8801_state::pc8801_palram_w(offs_t offset, uint8_t data)
m_palram[offset].g = data & 4 ? 7 : 0;
}
// TODO: What happens to the palette contents when the analog/digital palette mode changes?
// Preserve content? Translation? Undefined?
m_palette->set_pen_color(offset, pal3bit(m_palram[offset].r), pal3bit(m_palram[offset].g), pal3bit(m_palram[offset].b));
}
@ -1294,6 +1305,7 @@ void pc8801_state::pc8801_dmac_mode_w(uint8_t data)
m_dmac_mode = data;
m_dmac_ff = 0;
// Valis II sets 0x20
if(data != 0xe4 && data != 0xa0 && data != 0xc4 && data != 0x80 && data != 0x00)
printf("%02x DMAC mode\n",data);
}
@ -1333,10 +1345,13 @@ void pc8801_state::pc8801_alu_ctrl2_w(uint8_t data)
m_alu_ctrl2 = data;
}
// TODO: Implement PCG-8100 as a bus option
// It's an HAL Laboratory custom board with PCG (maps to chars $80-$ff),
// dual AY-3-891x & PIT, I/O $b0-$b2 is the I/O ID for it?
// Find a supported SW (only HAL seems to support it) & investigate
void pc8801_state::pc8801_pcg8100_w(offs_t offset, uint8_t data)
{
if(data)
printf("Write to PCG-8100 %02x %02x\n",offset,data);
logerror("%s: Possible write to PCG-8100 %02x %02x\n", machine().describe_context(), offset, data);
}
void pc8801_state::pc8801_txt_cmt_ctrl_w(uint8_t data)
@ -1615,7 +1630,8 @@ void pc8801_state::pc8801fdc_mem(address_map &map)
TIMER_CALLBACK_MEMBER(pc8801_state::pc8801fd_upd765_tc_to_zero)
{
//printf("0\n");
// TODO: holein1 explictly reads TC port at PC=504e followed by an HALT opcode, failing to boot
// is this gonna unbreak HALT state too?
m_fdc->tc_w(false);
}
@ -1629,10 +1645,13 @@ uint8_t pc8801_state::upd765_tc_r()
{
//printf("%04x 1\n",m_fdccpu->pc());
m_fdc->tc_w(true);
//TODO: I'm not convinced that this works correctly with current hook-up ... 1000 usec is needed by Aploon, a bigger value breaks Alpha.
//OTOH, 50 seems more than enough for the new upd...
machine().scheduler().timer_set(attotime::from_usec(50), timer_expired_delegate(FUNC(pc8801_state::pc8801fd_upd765_tc_to_zero),this));
if (!machine().side_effects_disabled())
{
m_fdc->tc_w(true);
//TODO: I'm not convinced that this works correctly with current hook-up ... 1000 usec is needed by Aploon, a bigger value breaks Alpha.
//OTOH, 50 seems more than enough for the new upd...
machine().scheduler().timer_set(attotime::from_usec(50), timer_expired_delegate(FUNC(pc8801_state::pc8801fd_upd765_tc_to_zero),this));
}
return 0xff; // value is meaningless
}
@ -1662,6 +1681,13 @@ void pc8801_state::pc8801fdc_io(address_map &map)
map(0xfc, 0xff).rw("d8255_slave", FUNC(i8255_device::read), FUNC(i8255_device::write));
}
void pc8801_state::opna_map(address_map &map)
{
// TODO: confirm it really is ROMless
// TODO: confirm size
map(0x000000, 0x1fffff).ram();
}
/* Input Ports */
/* 2008-05 FP:
@ -2378,17 +2404,27 @@ void pc8801_state::pc8801(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
m_cassette->add_route(ALL_OUTPUTS, "mono", 0.05);
// TODO: sound irqs goes different routes when both boards are installed
YM2203(config, m_opn, MASTER_CLOCK);
m_opn->irq_handler().set(FUNC(pc8801_state::pc8801_sound_irq));
m_opn->port_a_read_callback().set(FUNC(pc8801_state::opn_porta_r));
m_opn->port_b_read_callback().set(FUNC(pc8801_state::opn_portb_r));
m_opn->add_route(ALL_OUTPUTS, "mono", 1.00);
// TODO: handtune mixing
m_opn->add_route(0, "mono", 0.25);
m_opn->add_route(1, "mono", 0.25);
m_opn->add_route(2, "mono", 0.25);
m_opn->add_route(3, "mono", 0.25);
YM2608(config, m_opna, MASTER_CLOCK*2);
m_opna->set_addrmap(0, &pc8801_state::opna_map);
m_opna->irq_handler().set(FUNC(pc8801_state::pc8801_sound_irq));
m_opna->port_a_read_callback().set(FUNC(pc8801_state::opn_porta_r));
m_opna->port_b_read_callback().set(FUNC(pc8801_state::opn_portb_r));
m_opna->add_route(ALL_OUTPUTS, "mono", 1.00);
// TODO: handtune mixing
m_opna->add_route(0, "mono", 0.25);
m_opna->add_route(1, "mono", 0.25);
m_opna->add_route(2, "mono", 0.25);
BEEP(config, m_beeper, 2400).add_route(ALL_OUTPUTS, "mono", 0.10);
@ -2413,15 +2449,7 @@ void pc8801_state::pc8801mc(machine_config &config)
MCFG_MACHINE_RESET_OVERRIDE(pc8801_state, pc8801_cdrom )
}
/* TODO: clean this up */
#define PC8801_MEM_LOAD \
ROM_REGION( 0x100000, "opna", ROMREGION_ERASE00 )
ROM_START( pc8801 )
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.2
ROM_LOAD( "n80.rom", 0x0000, 0x8000, CRC(5cb8b584) SHA1(063609dd518c124a4fc9ba35d1bae35771666a34) )
@ -2442,8 +2470,6 @@ ROM_END
/* The dump only included "maincpu". Other roms arbitrariely taken from PC-8801 & PC-8801 MkIISR (there should be
at least 1 Kanji ROM). */
ROM_START( pc8801mk2 )
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.4
ROM_LOAD( "m2_n80.rom", 0x0000, 0x8000, CRC(91d84b1a) SHA1(d8a1abb0df75936b3fc9d226ccdb664a9070ffb1) )
@ -2462,8 +2488,6 @@ ROM_START( pc8801mk2 )
ROM_END
ROM_START( pc8801mk2sr )
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.5
ROM_LOAD( "mk2sr_n80.rom", 0x0000, 0x8000, CRC(27e1857d) SHA1(5b922ed9de07d2a729bdf1da7b57c50ddf08809a) )
@ -2490,8 +2514,6 @@ ROM_START( pc8801mk2sr )
ROM_END
ROM_START( pc8801mk2fr )
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.5
ROM_LOAD( "m2fr_n80.rom", 0x0000, 0x8000, CRC(27e1857d) SHA1(5b922ed9de07d2a729bdf1da7b57c50ddf08809a) )
@ -2517,8 +2539,6 @@ ROM_START( pc8801mk2fr )
ROM_END
ROM_START( pc8801mk2mr )
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.8
ROM_LOAD( "m2mr_n80.rom", 0x0000, 0x8000, CRC(f074b515) SHA1(ebe9cf4cf57f1602c887f609a728267f8d953dce) )
@ -2545,8 +2565,6 @@ ROM_START( pc8801mk2mr )
ROM_END
ROM_START( pc8801mh )
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.8, but different BIOS code?
ROM_LOAD( "mh_n80.rom", 0x0000, 0x8000, CRC(8a2a1e17) SHA1(06dae1db384aa29d81c5b6ed587877e7128fcb35) )
@ -2573,8 +2591,6 @@ ROM_START( pc8801mh )
ROM_END
ROM_START( pc8801fa )
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.8, but different BIOS code?
ROM_LOAD( "fa_n80.rom", 0x0000, 0x8000, CRC(8a2a1e17) SHA1(06dae1db384aa29d81c5b6ed587877e7128fcb35) )
@ -2601,8 +2617,6 @@ ROM_START( pc8801fa )
ROM_END
ROM_START( pc8801ma ) // newer floppy BIOS and Jisyo (dictionary) ROM
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.8, but different BIOS code?
ROM_LOAD( "ma_n80.rom", 0x0000, 0x8000, CRC(8a2a1e17) SHA1(06dae1db384aa29d81c5b6ed587877e7128fcb35) )
@ -2633,8 +2647,6 @@ ROM_START( pc8801ma ) // newer floppy BIOS and Jisyo (dictionary) ROM
ROM_END
ROM_START( pc8801ma2 )
PC8801_MEM_LOAD
ROM_REGION( 0x8000, "n80rom", ROMREGION_ERASEFF ) // 1.8
ROM_LOAD( "ma2_n80.rom", 0x0000, 0x8000, CRC(8a2a1e17) SHA1(06dae1db384aa29d81c5b6ed587877e7128fcb35) )
@ -2664,8 +2676,6 @@ ROM_START( pc8801ma2 )
ROM_END
ROM_START( pc8801mc )
PC8801_MEM_LOAD
ROM_REGION( 0x08000, "n80rom", ROMREGION_ERASEFF ) // 1.8
ROM_LOAD( "mc_n80.rom", 0x0000, 0x8000, CRC(8a2a1e17) SHA1(06dae1db384aa29d81c5b6ed587877e7128fcb35) )

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,490 @@
// license:BSD-3-Clause
// copyright-holders:Angelo Salese,Carl
/**************************************************************************************************
Epson PC98[01] class machine
TODO (PC-386M):
- Incomplete shadow IPL banking, we currently never bankswitch to the other ROM bank
(which barely contains program code);
- "ERR:VR" at POST (GFX VRAM)
Sub-routine that throws this is at PC=0xfd9bc. Notice that you can actually skip this
with eip=0x1bf in debugger and make the system to actually checkout memory installed.
(Shorthand: "bp fd9bc,eip=0x1bf")
- POST throws non-fatal "ERR:PA" (page fault, "Protected Address"?) after checking memory
installed. Non-fatal as in POST will checkout bootable devices afterward.
TODO: (PC-486SE/PC-486MU):
- Verify ROM bankswitch;
On PC-486SE sets up what is normally IPL bankswitch at PC=0xf5115, successive opcode
is a jmp 0xf8000, pretty unlikely it delays bankswitch so assume it reloads
the same bank.
- Remove IDE regression hack at I/O $74e;
- Regressed with a ERR:RA (conventional memory!?) when moving driver to
stand-alone file;
- Eventually errors with a ERR:VR (GFX VRAM);
Notes:
- A detailed list of Epson PC98s can be seen from here:
http://www.pc-9800.net/db_epson/index.htm
- Being these knockoffs means that there isn't 100% compatibility with all SWs.
Additionally NEC introduced the so called "EPSON Protect" / "EPSON check" ()
starting with MS-DOS 3.3 onward, which checks the presence of NEC / Microsoft copyright
string at E800:0DD8 and refuses to boot if not satisfied.
cfr. https://github.com/joncampbell123/dosbox-x/issues/682
Epson offcially provided PC "Software Installation Program" (SIP) floppy disks
(the "epinstal*" in SW list?) that counteracts with the protection check.
There's alternatively a freeware user released "Dispell!" program tool that can be used for
the same purpose, which also works for 32-bit DOS/V machines.
**************************************************************************************************/
#include "emu.h"
#include "includes/pc9801_epson.h"
template <unsigned which> void pc98_epson_state::shadow_ipl_w(offs_t offset, u16 data, u16 mem_mask)
{
// TODO: shadow register 0x6a may actually be write deprotect
COMBINE_DATA(&m_shadow_ipl[which][offset]);
}
/**************************************************************************************************
Control port for Epson shadow IPL
If any of these isn't right system throws "ERR:BR" at boot (BIOS loader error).
Executes some code in text VRAM area (PC=$a006e), trying to setup a writeable RAM bank
to IPL window area.
**************************************************************************************************/
void pc98_epson_state::epson_ipl_bank_w(offs_t offset, u8 data)
{
m_shadow_ipl_bank = data;
switch(m_shadow_ipl_bank)
{
case 0x2a:
m_ipl->set_bank(2);
break;
case 0xe6:
m_ipl->set_bank(0);
break;
default:
// TODO: at least 0xa6 used, what for?
logerror("%s: unknown Epson shadow IPL bank setting set %02x\n", machine().describe_context(), data);
break;
}
}
// overrides original PC98 $43c-$43f ports
void pc98_epson_state::epson_itf_bank_w(offs_t offset, u8 data)
{
// $43f
if (offset == 1)
{
switch(data)
{
case 0x40: m_itf_bank_enable = false; break;
case 0x42: m_itf_bank_enable = true; break;
default:
logerror("%s: unknown ITF enable setting %02x\n", machine().describe_context(), data);
break;
}
}
// $43d
if (offset == 0)
{
switch(data)
{
case 0x00:
case 0x02:
if (m_itf_bank_enable == true)
m_ipl->set_bank((data & 2) >> 1);
break;
default:
// TODO: 0x10 - 0x12 setting, which should be same as NEC PC98
// (i.e. reversed compared to above)
logerror("%s: unknown ITF bank setting %02x\n", machine().describe_context(), data);
break;
}
}
}
void pc98_epson_state::epson_a20_w(offs_t offset, u8 data)
{
// pc386m PC=0xfd9b3
// if this isn't mapped then POST throws "ERR:RA" (conventional memory -> "Real Address"?)
m_gate_a20 = data & 1;
m_maincpu->set_input_line(INPUT_LINE_A20, m_gate_a20 ? ASSERT_LINE : CLEAR_LINE);
logerror("%s: Epson gate a20 %02x\n", machine().describe_context(), data);
}
void pc98_epson_state::epson_vram_bank_w(offs_t offset, u8 data)
{
// m_vram_bank = (data & 1) ^ 1;
// accessed in the same routine that actually throws ERR:VR
logerror("%s: Epson $c06 write %02x\n", machine().describe_context(), data);
}
void pc98_epson_state::pc386m_map(address_map &map)
{
pc9801rs_map(map);
// TODO: is shadow RAM physically mapped here?
// map(0xd0000, 0xd**ff).ram();
}
void pc98_epson_state::pc486se_map(address_map &map)
{
pc386m_map(map);
map(0x000e8000, 0x000fffff).m(m_ipl, FUNC(address_map_bank_device::amap16));
map(0xffee8000, 0xffefffff).m(m_ipl, FUNC(address_map_bank_device::amap16));
map(0xfffe8000, 0xffffffff).m(m_ipl, FUNC(address_map_bank_device::amap16));
}
void pc98_epson_state::pc386m_io(address_map &map)
{
pc9801rs_io(map);
// map(0x0c03, 0x0c03).r Epson CPU mode, 'R' for Real mode, 'P' for Protected mode (lolwut)
map(0x0c05, 0x0c05).w(FUNC(pc98_epson_state::epson_a20_w));
map(0x0c06, 0x0c06).w(FUNC(pc98_epson_state::epson_vram_bank_w));
map(0x0c07, 0x0c07).w(FUNC(pc98_epson_state::epson_ipl_bank_w));
// map(0x0c13, 0x0c13).r Epson <unknown> readback
// map(0x0c14, 0x0c14).r Epson <unknown> readback
}
void pc98_epson_state::pc486se_io(address_map &map)
{
pc386m_io(map);
map(0x0082, 0x0082).lr8(NAME([]() -> u8 { return 0x00; }));
map(0x043c, 0x043f).w(FUNC(pc98_epson_state::epson_itf_bank_w)).umask16(0xff00);
map(0x0c42, 0x0c43).lr16(NAME([]() -> u16 { return 0x0000; }));
// map(0x0640, 0x064f).rw(FUNC(pc9801_state::ide_cs0_r), FUNC(pc9801_state::ide_cs0_w));
// map(0x0740, 0x074f).rw(FUNC(pc9801_state::ide_cs1_r), FUNC(pc9801_state::ide_cs1_w));
// HACK: avoid POST moaning for misconfigured HDDs (!?)
map(0x074e, 0x074e).lr8(NAME([]() -> u8 { return 0xff; }));
// (R) bit 0: expected to go off at PC=0xf8c52 (pc486se)
// (W) commands for?
map(0x0c09, 0x0c09).lr8(NAME([]() -> u8 { return 0x00; }));
map(0x0c0b, 0x0c0b).lr8(NAME([]() -> u8 { return 0x00; }));
}
void pc98_epson_state::pc386m_ipl_bank(address_map &map)
{
map(0x00000, 0x17fff).rom().region("ipl", 0x00000).w(FUNC(pc98_epson_state::shadow_ipl_w<0>));
map(0x18000, 0x2ffff).rom().region("ipl", 0x18000).w(FUNC(pc98_epson_state::shadow_ipl_w<1>));
map(0x30000, 0x47fff).ram().share("shadow_ipl_0");
map(0x48000, 0x5ffff).ram().share("shadow_ipl_1");
}
static INPUT_PORTS_START( pc386m )
// in tracer bullet fashion we intentionally separated all dips/mouse switches
// since there's no real need to actually INPUT_PORTS_EXTERN here:
// - mouse should really be a device interface anyway;
// - dips may really diverge from NEC specs or even be unmapped (needs verification).
// In both cases those needs a major cleanup, haven't yet found actual documentation for these specifically.
// Notice that Epson eventually inherited SDIP chip as well.
PORT_START("DSW1")
PORT_DIPNAME( 0x01, 0x01, "Monitor Type" )
PORT_DIPSETTING( 0x00, "Normal Display (15KHz)" )
PORT_DIPSETTING( 0x01, "Hi-Res Display (24KHz)" )
PORT_DIPNAME( 0x02, 0x00, "DSW1" )
PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x04, 0x04, "Display Type" )
PORT_DIPSETTING( 0x04, "RGB" )
PORT_DIPSETTING( 0x00, "Plasma" )
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x80, 0x00, "Graphic Function" )
PORT_DIPSETTING( 0x80, "Basic (8 Colors)" )
PORT_DIPSETTING( 0x00, "Expanded (16/4096 Colors)" )
PORT_START("DSW2")
PORT_DIPNAME( 0x01, 0x00, "DSW2" )
PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x04, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x80, 0x80, "GDC clock" )
PORT_DIPSETTING( 0x80, "2.5 MHz" )
PORT_DIPSETTING( 0x00, "5 MHz" )
PORT_START("DSW3")
PORT_DIPNAME( 0x01, 0x01, "FDD Fix Mode" )
PORT_DIPSETTING( 0x00, "Auto-Detection" )
PORT_DIPSETTING( 0x01, "Fixed" )
PORT_DIPNAME( 0x02, 0x02, "FDD Density Select" )
PORT_DIPSETTING( 0x00, "2DD" )
PORT_DIPSETTING( 0x02, "2HD" )
PORT_DIPNAME( 0x04, 0x04, "DSW3" )
PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x40, "Conventional RAM size" )
PORT_DIPSETTING( 0x40, "640 KB" )
PORT_DIPSETTING( 0x00, "512 KB" )
PORT_DIPNAME( 0x80, 0x00, "CPU Type" )
PORT_DIPSETTING( 0x80, "V30" )
PORT_DIPSETTING( 0x00, "I386" )
PORT_START("MOUSE_X")
PORT_BIT( 0xff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(30) PORT_KEYDELTA(30)
PORT_START("MOUSE_Y")
PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(30) PORT_KEYDELTA(30)
PORT_START("MOUSE_B")
PORT_BIT(0x0f, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("Mouse Right Button")
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_CODE(MOUSECODE_BUTTON3) PORT_NAME("Mouse Middle Button")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("Mouse Left Button")
PORT_START("ROM_LOAD")
PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_CONFNAME( 0x04, 0x04, "Load IDE BIOS" )
PORT_CONFSETTING( 0x00, DEF_STR( Yes ) )
PORT_CONFSETTING( 0x04, DEF_STR( No ) )
INPUT_PORTS_END
MACHINE_START_MEMBER(pc98_epson_state, pc98_epson)
{
MACHINE_START_CALL_MEMBER(pc9801rs);
}
MACHINE_RESET_MEMBER(pc98_epson_state, pc98_epson)
{
MACHINE_RESET_CALL_MEMBER(pc9801rs);
m_ipl->set_bank(0);
}
void pc98_epson_state::pc386m(machine_config &config)
{
pc9801rs(config);
I386SX(config.replace(), m_maincpu, 16000000); // i386SX 16MHz, switchable to 10/6 MHz
m_maincpu->set_addrmap(AS_PROGRAM, &pc98_epson_state::pc386m_map);
m_maincpu->set_addrmap(AS_IO, &pc98_epson_state::pc386m_io);
m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb));
m_ipl->set_addrmap(AS_PROGRAM, &pc98_epson_state::pc386m_ipl_bank);
// TODO: 19 or 20 address lines?
// 20 may be used in case that mixed up ROM & shadow IPL loads are actually possible
// (which sounds pretty possible)
m_ipl->set_options(ENDIANNESS_LITTLE, 16, 19, 0x18000);
MCFG_MACHINE_START_OVERRIDE(pc98_epson_state, pc98_epson)
MCFG_MACHINE_RESET_OVERRIDE(pc98_epson_state, pc98_epson)
// RAM: 640KB + 14.6MB max
// 2 3.5 floppy drives
// ...
}
void pc98_epson_state::pc486se(machine_config &config)
{
pc386m(config);
const XTAL xtal = XTAL(25'000'000);
I486(config.replace(), m_maincpu, xtal); // i486SX, switchable to 10/5 MHz, supports overdrive
m_maincpu->set_addrmap(AS_PROGRAM, &pc98_epson_state::pc486se_map);
m_maincpu->set_addrmap(AS_IO, &pc98_epson_state::pc486se_io);
m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb));
pit_clock_config(config, xtal/8); // unknown, passes "ERR:TM" test
// RAM: 1.6 MB (!) + 17.6 max
// "dedicated internal memory slot x 1"
// "dedicated video board" slot
}
void pc98_epson_state::pc486mu(machine_config &config)
{
pc386m(config);
const XTAL xtal = XTAL(33'000'000);
I486(config.replace(), m_maincpu, xtal); // i486SX, switchable to I386DX 10MHz/5MHz, Pentium ODP compatible
m_maincpu->set_addrmap(AS_PROGRAM, &pc98_epson_state::pc486se_map);
m_maincpu->set_addrmap(AS_IO, &pc98_epson_state::pc386m_io);
m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb));
pit_clock_config(config, xtal/8); // unknown, passes "ERR:TM" test
// CL-GD5428
// RAM: 5.6 + 61.6MB max
// 2 x 3.5 floppy drives
}
// backported from pc98, of course both aren't 100% identical to the NEC counterpart
#define LOAD_IDE_ROM \
ROM_REGION( 0x4000, "ide", ROMREGION_ERASEVAL(0xcb) ) \
ROM_LOAD( "epson_ide_bios.rom", 0x0000, 0x2000, NO_DUMP ) \
ROM_IGNORE( 0x2000 ) \
ROM_IGNORE( 0x2000 ) \
ROM_IGNORE( 0x2000 )
#define LOAD_KANJI_ROMS \
ROM_REGION( 0x80000, "raw_kanji", ROMREGION_ERASEFF ) \
ROM_LOAD16_BYTE( "24256c-x01.bin", 0x00000, 0x4000, BAD_DUMP CRC(28ec1375) SHA1(9d8e98e703ce0f483df17c79f7e841c5c5cd1692) ) \
ROM_CONTINUE( 0x20000, 0x4000 ) \
ROM_LOAD16_BYTE( "24256c-x02.bin", 0x00001, 0x4000, BAD_DUMP CRC(90985158) SHA1(78fb106131a3f4eb054e87e00fe4f41193416d65) ) \
ROM_CONTINUE( 0x20001, 0x4000 ) \
ROM_LOAD16_BYTE( "24256c-x03.bin", 0x40000, 0x4000, BAD_DUMP CRC(d4893543) SHA1(eb8c1bee0f694e1e0c145a24152222d4e444e86f) ) \
ROM_CONTINUE( 0x60000, 0x4000 ) \
ROM_LOAD16_BYTE( "24256c-x04.bin", 0x40001, 0x4000, BAD_DUMP CRC(5dec0fc2) SHA1(41000da14d0805ed0801b31eb60623552e50e41c) ) \
ROM_CONTINUE( 0x60001, 0x4000 ) \
ROM_REGION( 0x100000, "kanji", ROMREGION_ERASEFF ) \
ROM_REGION( 0x80000, "new_chargen", ROMREGION_ERASEFF )
/*
Epson PC-386M
i386SX-16 @ 16
1MB
3.5"2DD/2HDx2
CBus: 3slots
*/
ROM_START( pc386m )
ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF )
// bank 0: definitely wants this ROM mapping otherwise POST throws "ERR:R0" (BIOS checksum)
ROM_LOAD( "cwma-a02.bin", 0x10000, 0x08000, CRC(d2c357a4) SHA1(819c9a1fc92124a8d6a85339c74651add7efaf92) )
ROM_CONTINUE( 0x00000, 0x10000 )
ROM_CONTINUE( 0x28000, 0x08000 ) // bank 1, unconfirmed
ROM_REGION( 0x80000, "chargen", 0 )
ROM_LOAD( "font_486mu.rom", 0x0000, 0x46800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff))
LOAD_KANJI_ROMS
LOAD_IDE_ROM
ROM_END
/*
Epson PC-486SE
i486SX @ 25 MHz
1.6 MB of conventional memory (???)
17.6 MB
CBus: 2slots
*/
ROM_START( pc486se )
ROM_REGION16_LE( 0x20000, "biosrom", ROMREGION_ERASEFF )
ROM_LOAD( "1699ma_cw99-a03.bin", 0x00000, 0x20000, CRC(f03df711) SHA1(88614746e01c7d3cff9f3b8ce0a598830a77d1dc) )
ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF )
// this is quite convoluted
ROM_COPY( "biosrom", 0x08000, 0x00000, 0x08000 )
ROM_COPY( "biosrom", 0x00000, 0x10000, 0x08000 )
ROM_COPY( "biosrom", 0x10000, 0x08000, 0x08000 )
// ROM_FILL( 0x18000, 0x08000, 0x90) // untested by BIOS
ROM_COPY( "biosrom", 0x10000, 0x20000, 0x08000 )
ROM_COPY( "biosrom", 0x18000, 0x28000, 0x08000 )
ROM_REGION( 0x80000, "chargen", 0 )
ROM_LOAD( "font_486mu.rom", 0x0000, 0x46800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff))
LOAD_KANJI_ROMS
LOAD_IDE_ROM
ROM_END
/*
Epson PC-486MU
i486SX-33 @ 33
8MB RAM
3.5'2DD/2HDx2, 2xCD-ROM
CBus: 3 slots
*/
ROM_START( pc486mu )
ROM_REGION16_LE( 0x20000, "biosrom", ROMREGION_ERASEFF )
ROM_LOAD( "pc-486mu_hn27c1024.bin", 0x00000, 0x20000, CRC(113268e1) SHA1(2a630abc825b2808f9f8fb65c6cb1fb7e7f6c710))
// ROM_LOAD( "bios_486mu.rom", 0x00000, 0x18000, BAD_DUMP CRC(57b5d701) SHA1(15029800842e93e07615b0fd91fb9f2bfe3e3c24))
ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF )
// backported from pc486se
ROM_COPY( "biosrom", 0x08000, 0x00000, 0x08000 )
ROM_COPY( "biosrom", 0x00000, 0x10000, 0x08000 )
ROM_COPY( "biosrom", 0x10000, 0x08000, 0x08000 )
// ROM_FILL( 0x18000, 0x08000, 0x90) // untested by BIOS
ROM_COPY( "biosrom", 0x10000, 0x20000, 0x08000 )
ROM_COPY( "biosrom", 0x18000, 0x28000, 0x08000 )
ROM_REGION( 0x80000, "chargen", 0 )
ROM_LOAD( "font_486mu.rom", 0x0000, 0x46800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff))
LOAD_KANJI_ROMS
LOAD_IDE_ROM
ROM_END
// Epson PC98 desktop line
// PC-286 (i286, first model released in Oct 1987)
// PC-286U (same as above except running on V30)
// PC-286C "PC Club" (same as PC-286?)
// ...
// PC-386 (i386)
COMP( 1990, pc386m, 0, 0, pc386m, pc386m, pc98_epson_state, init_pc9801_kanji, "Epson", "PC-386M", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
// PC-486 (i486SX/DX)
COMP( 1994, pc486mu, 0, 0, pc486se, pc386m, pc98_epson_state, init_pc9801_kanji, "Epson", "PC-486MU", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
COMP( 1993, pc486se, pc486mu, 0, pc486se, pc386m, pc98_epson_state, init_pc9801_kanji, "Epson", "PC-486SE", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
// PRO-486 (first actual version with i486dx? Supports High-reso)
// PC-486P/Win (same as a PC-486P but with Windows 3.0a + MS-DOS 3.3 HDD pre-installed?)
// PC-586 (Pentium/Pentium ODP compatibles)
// ...
// Epson PC98 L[aptop] line
// PC-286B (80C286)
// PC-286L* (V30 or 80C286)
// ...
// PC-386BL* (i386sx)
// PC-386LS* (just bigger version of above?)
// ...
// Epson PC98 NOTE[book] line
// PC-*86N* (runs on correlated CPU as above)
// PC-486PT ("P[or]T[able]" SL enhanced i486, wallet-like dimensions, supports light pen, runs under "PenDOS")
// ...

1418
src/mame/drivers/pc9821.cpp Normal file

File diff suppressed because it is too large Load Diff

526
src/mame/drivers/pc98ha.cpp Normal file
View File

@ -0,0 +1,526 @@
// license:BSD-3-Clause
// copyright-holders:Angelo Salese
/**************************************************************************************************
PC98LT/HA class machine "Handy98" aka 1st Gen LCD PC98
TODO:
- pc98lt: remove timer hack:
- definitely incorrect given the erratic cursor blinking in N88BASIC;
- identify LCDC used here, reg 2 is clearly H display (0x4f+1)*8=640
- merge from base pc98 class (WIP);
- when idle for some time buzzer farts until a key is pressed (?);
- add NVRAM saving:
- pinpoint NVRAM init switch source:
- first port C read (pc98lt: i/o 0x35, PC=0xf841f) tests for bit 7,
which initializes battery backup if on, but port C is in output mode there.
Somehow obf irq is on at boot if battery failed?
- power handling;
- pc98ha specifics:
- RTC is upd4991a (partially done), it's parallel instead of serial and incompatible with
everything else ugh;
- EMS fails at boot, it's never ever really checked;
- MSDOS cannot detect EMS properly, is there a flag somewhere?
- JEIDA memory card interface;
- optional docking station (for floppy device only or can mount other stuff too?);
**************************************************************************************************/
#include "emu.h"
#include "includes/pc98ha.h"
void pc98lt_state::lt_palette(palette_device &palette) const
{
palette.set_pen_color(0, 160, 168, 160);
palette.set_pen_color(1, 48, 56, 16);
}
uint32_t pc98lt_state::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect )
{
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
for (int x = cliprect.min_x; x <= cliprect.max_x; x += 16)
{
u16 pen = bitswap<16>(m_gvram[(y*640+x)/16], 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7);
for (int xi = 0; xi < 16; xi++)
{
u8 dot = (pen >> xi) & 1;
bitmap.pix(y, x+xi) = m_palette->pen(dot);
}
}
return 0;
}
/*
* Power Status Register
*
* x--- ---- docking station connected (HA only?)
* -x-- ---- AC power supply connected
* ---x ---- alarm enabled
* ---- x--- unknown
* ---- -x-- Lithium battery low (HA only?)
* ---- --x- battery low
* ---- ---x power off
*/
u8 pc98lt_state::power_status_r()
{
return 0x80;
}
void pc98lt_state::power_control_w(offs_t offset, u8 data)
{
// TODO: happens pretty often, supposed to halt the system and wake up on arbitrary event?
if (BIT(data, 2))
logerror("%s: power_control_w standby signal ON\n", machine().describe_context());
// pc98lt: go to prompt (type "command" in main menu) and execute "poweroff.com"
if (BIT(data, 0))
logerror("%s: power_control_w power off signal ON\n", machine().describe_context());
// pc98ha bit 1: flips between 0->1 on system boot failure, in tandem with standby mode held
if (data & ~0x07)
logerror("%s: power_control_w unknown signal sent %02x\n", machine().describe_context(), data);
}
// TODO: intentionally repeated from base pc98 until I understand what's going on here.
// (supposedly should be same from base pc98 minus the V50 integrations and whatever the "docking station" really adds up)
u8 pc98lt_state::floppy_mode_r(offs_t offset)
{
// floppy "mode" identifies drive capabilities, if 2dd/2hd exclusive or mixed type.
// and to my understanding it doesn't really read from write reg ...
return (m_floppy_mode & 3) | 0x08;
}
void pc98lt_state::floppy_mode_w(offs_t offset, u8 data)
{
// bit 1: selects between 2hd and 2dd, not unlike base PC98
m_floppy_mode = data & 3;
m_fdc->subdevice<floppy_connector>("0")->get_device()->set_rpm(data & 0x02 ? 360 : 300);
m_fdc->subdevice<floppy_connector>("1")->get_device()->set_rpm(data & 0x02 ? 360 : 300);
m_fdc->set_rate(data & 0x02 ? 500000 : 250000);
}
u8 pc98lt_state::fdc_ctrl_r(offs_t offset)
{
// TODO: doesn't work as intended, bit 4 is supposedly if the drive has a disk in or not according to documentation.
int ret = (m_fdc->subdevice<floppy_connector>("0")->get_device()->ready_r()) ? 0x10 : 0;
ret |= (m_fdc->subdevice<floppy_connector>("1")->get_device()->ready_r()) ? 0x10 : 0;
return ret | 0x64;
}
void pc98lt_state::fdc_ctrl_w(offs_t offset, u8 data)
{
m_fdc->reset_w(BIT(data, 7));
m_fdc_ctrl = data;
if(data & 0x40)
{
m_fdc->set_ready_line_connected(0);
m_fdc->ready_w(0);
}
else
m_fdc->set_ready_line_connected(1);
m_fdc->subdevice<floppy_connector>("0")->get_device()->mon_w(data & 8 ? ASSERT_LINE : CLEAR_LINE);
m_fdc->subdevice<floppy_connector>("1")->get_device()->mon_w(data & 8 ? ASSERT_LINE : CLEAR_LINE);
}
void pc98lt_state::lt_map(address_map &map)
{
map.unmap_value_high();
map(0x00000, 0x5ffff).ram(); // 384 KB
map(0x60000, 0x9ffff).noprw();
// no TVRAM
map(0xa8000, 0xaffff).ram().share("gvram");
// 0xb0000-0xbffff unmapped GVRAM or mirror, check me
map(0xc0000, 0xcffff).unmaprw(); // EMS area, not present here but checked
map(0xd0000, 0xd3fff).bankrw("bram_bank");
map(0xd4000, 0xd7fff).bankr("dict_bank");
map(0xd8000, 0xdbfff).bankr("kanji_bank");
map(0xe0000, 0xeffff).bankr("romdrv_bank");
map(0xf0000, 0xfffff).rom().region("ipl", 0);
}
void pc98lt_state::lt_io(address_map &map)
{
map.unmap_value_high();
// map(0x0000, 0x001f) // PIC (bit 3 ON slave / master), V50 internal / <undefined>
map(0x0020, 0x002f).w(FUNC(pc98lt_state::rtc_w)).umask16(0x00ff);
map(0x0030, 0x0037).rw(m_ppi_sys, FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0xff00); //i8251 RS232c / i8255 system port
map(0x0040, 0x0047).rw(m_ppi_prn, FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0x00ff);
map(0x0040, 0x0047).rw(m_keyb, FUNC(pc9801_kbd_device::rx_r), FUNC(pc9801_kbd_device::tx_w)).umask16(0xff00); //i8255 printer port / i8251 keyboard
// map(0x0070, 0x007f) // PIT, V50 internal
// floppy actually requires a docking station on PC98HA, density should be 2dd given the mapping
map(0x00be, 0x00be).rw(FUNC(pc98lt_state::floppy_mode_r), FUNC(pc98lt_state::floppy_mode_w));
map(0x00c8, 0x00cb).m(m_fdc, FUNC(upd765a_device::map)).umask16(0x00ff);
map(0x00cc, 0x00cc).rw(FUNC(pc98lt_state::fdc_ctrl_r), FUNC(pc98lt_state::fdc_ctrl_w));
// map(0x00e0, 0x00ef) // uPD71071, V50 internal
// map(0x0810, 0x0810) // <unknown device data>, LCDC?
// map(0x0812, 0x0812) // <unknown device address> & 0xf
map(0x0c10, 0x0c10).lrw8(
NAME([this] () { return (m_bram_bank_reg & (m_bram_banks - 1)) | 0x40; }),
NAME([this] (u8 data) { m_bram_bank_reg = data & (m_bram_banks - 1); m_bram_bank->set_entry(m_bram_bank_reg); })
);
// map(0x0f8e, 0x0f8e) // card slot status 1 (undefined on pc98lt?)
// map(0x4810, 0x4810) // ?
map(0x4c10, 0x4c10).lrw8(
NAME([this] () { return (m_dict_bank_reg & 0x3f) | 0x40; }),
NAME([this] (u8 data) { m_dict_bank_reg = data & 0x3f; m_dict_bank->set_entry(m_dict_bank_reg); })
);
// map(0x5e8e, 0x5e8e) // card slot status 2
// map(0x6e8e, 0x6e8e) // modem control 1
// map(0x7e8e, 0x7e8e) // modem control 2
map(0x8810, 0x8810).rw(FUNC(pc98lt_state::power_status_r), FUNC(pc98lt_state::power_control_w));
map(0x8c10, 0x8c10).lw8(NAME([this] (u8 data) { m_kanji_bank->set_entry(data & 0x0f); }));
// map(0xc810, 0xc810) // ?
map(0xcc10, 0xcc10).lrw8(
NAME([this] () { return (m_romdrv_bank_reg & 0xf) | 0x40; }),
NAME([this] (u8 data) { m_romdrv_bank_reg = data & 0xf; m_romdrv_bank->set_entry(m_romdrv_bank_reg); })
);
}
/************************************
*
* 98HA specifics
*
***********************************/
void pc98ha_state::ext_view_bank_w(offs_t offset, u8 data)
{
if (m_ext_view_sel == 0x81)
m_ramdrv_bank->set_entry(data & 0x7f);
else
logerror("External view SEL bank set %02x (view=%02x)\n", data, m_ext_view_sel);
}
void pc98ha_state::ext_view_sel_w(offs_t offset, u8 data)
{
m_ext_view_sel = data;
// either bit 7 ON or writing 0x80 to this port disables the external view.
if (data & 0x80)
m_ext_view.select(data & 0x3);
if (data != 0x81)
logerror("External view SEL line set %02x\n", data);
}
void pc98ha_state::ems_bank_w(offs_t offset, u8 data)
{
m_ems_banks[offset]->set_entry(data & 0x7f);
}
u8 pc98ha_state::memcard_status_1_r(offs_t offset)
{
// TODO: identify exact type
// 0x0e: memory card present
// bit 3 is checked at boot, PC=f82a5
// mask 0xf0 is checked at PC=f8956 then periodically polled at PC=0xfd110
// NeoGeo uses v3
return 0x04;
}
u8 pc98ha_state::memcard_status_2_r(offs_t offset)
{
// 0x46: memory card present
return 0x40;
}
void pc98ha_state::ha_map(address_map &map)
{
lt_map(map);
map(0x00000, 0x9ffff).ram(); // 640 KB
map(0xc0000, 0xc3fff).bankrw("ems_bank1");
map(0xc4000, 0xc7fff).bankrw("ems_bank2");
map(0xc8000, 0xcbfff).bankrw("ems_bank3");
map(0xcc000, 0xcffff).bankrw("ems_bank4");
map(0xdc000, 0xdffff).view(m_ext_view);
m_ext_view[0](0xdc000, 0xdffff).unmaprw(); // unknown, accessed on MSDOS boot
m_ext_view[1](0xdc000, 0xdffff).bankrw("ramdrv_bank");
m_ext_view[2](0xdc000, 0xdffff).unmaprw(); // JEIDA memory card
m_ext_view[3](0xdc000, 0xdffff).unmaprw();
}
void pc98ha_state::ha_io(address_map &map)
{
lt_io(map);
map(0x0020, 0x002f).unmaprw();
map(0x0022, 0x0022).w(m_rtc_pio, FUNC(upd4991a_device::address_w));
map(0x0023, 0x0023).rw(m_rtc_pio, FUNC(upd4991a_device::data_r), FUNC(upd4991a_device::data_w));
map(0x08e0, 0x08e7).w(FUNC(pc98ha_state::ems_bank_w)).umask16(0xff00);
map(0x0e8e, 0x0e8e).w(FUNC(pc98ha_state::ext_view_bank_w));
map(0x0f8e, 0x0f8e).r(FUNC(pc98ha_state::memcard_status_1_r));
map(0x1e8e, 0x1e8e).w(FUNC(pc98ha_state::ext_view_sel_w));
map(0x5f8e, 0x5f8e).r(FUNC(pc98ha_state::memcard_status_2_r));
}
static INPUT_PORTS_START( pc98lt )
PORT_START("SYSB")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER(RTC_TAG, upd1990a_device, data_out_r)
PORT_DIPNAME( 0x02, 0x00, "SYSB" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x02, DEF_STR( On ) )
PORT_DIPNAME( 0x04, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x04, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x08, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x10, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x20, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x40, DEF_STR( On ) )
PORT_DIPNAME( 0x80, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x80, DEF_STR( On ) )
PORT_START("SYSC")
PORT_DIPNAME( 0x01, 0x00, "SYSC" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x01, DEF_STR( On ) )
PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x02, DEF_STR( On ) )
PORT_DIPNAME( 0x04, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x04, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x08, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x10, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x20, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x40, DEF_STR( On ) )
PORT_DIPNAME( 0x80, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x80, DEF_STR( On ) )
PORT_START("PRNB")
PORT_DIPNAME( 0x01, 0x00, "PRNB" ) // checked on boot
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x01, DEF_STR( On ) )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // CPUT LT/HA switch
PORT_DIPNAME( 0x04, 0x00, DEF_STR( Unknown ) ) // checked on boot
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x04, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x08, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x10, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x20, DEF_STR( On ) )
PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(pc98lt_state, system_type_r)
INPUT_PORTS_END
static INPUT_PORTS_START( pc98ha )
PORT_INCLUDE( pc98lt )
PORT_MODIFY("SYSB")
PORT_DIPNAME( 0x01, 0x00, "<rtc empty signal>" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x01, DEF_STR( On ) )
PORT_MODIFY("PRNB")
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNKNOWN )
INPUT_PORTS_END
// debug
static const gfx_layout gfx_16x16x1 =
{
16,16,
RGN_FRAC(1,1),
1,
{ 0 },
{ STEP16(0,1) },
{ STEP16(0,16) },
16*16
};
static GFXDECODE_START( gfx_pc98lt )
GFXDECODE_ENTRY( "kanji", 0x00000, gfx_8x8x1, 0x000, 0x01 )
GFXDECODE_ENTRY( "kanji", 0x00000, gfx_16x16x1, 0x000, 0x01 )
GFXDECODE_END
void pc98lt_state::machine_start()
{
// TODO: make this and NVRAM saving to co-exist
// we have a 16-bit host bus with a banked NVRAM window that also has different sizes depending on the model,
// may consider to encapsulate instead.
const u32 bram_size = memregion("backup")->bytes() / 2;
uint16_t *bram = (uint16_t *)memregion("backup")->base();
m_bram_banks = (bram_size * 2) / 0x4000;
m_bram_ptr = make_unique_clear<uint16_t[]>(bram_size);
for (int i = 0; i < bram_size; i++)
m_bram_ptr[i] = bram[i];
m_kanji_bank->configure_entries( 0, 0x10, memregion("kanji")->base(), 0x4000);
m_bram_bank->configure_entries( 0, m_bram_banks, m_bram_ptr.get(), 0x4000);
m_romdrv_bank->configure_entries( 0, 0x10, memregion("romdrv")->base(), 0x10000);
m_dict_bank->configure_entries( 0, 0x40, memregion("dict")->base(), 0x4000);
if (m_rtc != nullptr)
{
m_rtc->cs_w(1);
m_rtc->oe_w(1);
}
m_sys_type = 0xc0 >> 6;
save_item(NAME(m_bram_bank_reg));
save_item(NAME(m_romdrv_bank_reg));
save_item(NAME(m_dict_bank_reg));
save_pointer(NAME(m_bram_ptr), bram_size);
}
void pc98ha_state::machine_start()
{
pc98lt_state::machine_start();
const u32 ems_banks = 0x80;
const u32 ems_size = (ems_banks * 0x4000) / 2;
m_ramdrv_bank->configure_entries(0, 0x80, memregion("ramdrv")->base(), 0x4000);
m_ems_ram = make_unique_clear<uint16_t[]>(ems_size);
for (int i = 0; i < 4; i++)
m_ems_banks[i]->configure_entries(0, ems_banks, m_ems_ram.get(), 0x4000);
save_item(NAME(m_ext_view_sel));
save_pointer(NAME(m_ems_ram), ems_size);
}
static void pc9801_floppies(device_slot_interface &device)
{
// device.option_add("525dd", FLOPPY_525_DD);
device.option_add("525hd", FLOPPY_525_HD);
// device.option_add("35hd", FLOPPY_35_HD);
}
void pc98lt_state::lt_config(machine_config &config)
{
const XTAL xtal = XTAL(8'000'000);
V50(config, m_maincpu, xtal); // µPD70216
m_maincpu->set_addrmap(AS_PROGRAM, &pc98lt_state::lt_map);
m_maincpu->set_addrmap(AS_IO, &pc98lt_state::lt_io);
// TODO: jumps off the weeds if divided by / 4 after timer check, DMA issue?
// m_maincpu->set_tclk(xtal / 4);
m_maincpu->set_tclk(xtal / 100);
// m_maincpu->tout2_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ2);
// m_pit->out_handler<0>().set(m_pic1, FUNC(pic8259_device::ir0_w));
// m_pit->out_handler<2>().set(m_sio, FUNC(i8251_device::write_txc));
// m_pit->out_handler<2>().append(m_sio, FUNC(i8251_device::write_rxc));
// m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb));
PC9801_KBD(config, m_keyb, 53);
m_keyb->irq_wr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ1);
I8255(config, m_ppi_sys, 0);
// PC98LT/HA has no dips, port A acts as a RAM storage
m_ppi_sys->in_pa_callback().set(m_ppi_sys, FUNC(i8255_device::pa_r));
m_ppi_sys->in_pb_callback().set_ioport("SYSB");
// m_ppi_sys->in_pc_callback().set_constant(0xa0); // 0x80 cpu triple fault reset flag?
m_ppi_sys->out_pc_callback().set(FUNC(pc98lt_state::ppi_sys_beep_portc_w));
I8255(config, m_ppi_prn, 0);
m_ppi_prn->in_pb_callback().set_ioport("PRNB");
UPD1990A(config, m_rtc);
UPD765A(config, m_fdc, 8'000'000, false, true);
m_fdc->intrq_wr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ6);
m_fdc->drq_wr_callback().set(m_maincpu, FUNC(v50_device::dreq_w<2>)).invert();
// m_fdc->drq_wr_callback().set(m_maincpu, FUNC(v50_device::dreq_w<3>)).invert(); // 2dd
FLOPPY_CONNECTOR(config, "upd765:0", pc9801_floppies, "525hd", pc9801_state::floppy_formats);
FLOPPY_CONNECTOR(config, "upd765:1", pc9801_floppies, "525hd", pc9801_state::floppy_formats);
SCREEN(config, m_screen, SCREEN_TYPE_LCD);
// TODO: copied verbatim from base PC98, verify clock et al.
m_screen->set_raw(21.0526_MHz_XTAL, 848, 0, 640, 440, 0, 400);
m_screen->set_screen_update(FUNC(pc98lt_state::screen_update));
// m_screen->screen_vblank().set(FUNC(pc9801_state::vrtc_irq));
PALETTE(config, m_palette, FUNC(pc98lt_state::lt_palette), 2);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_pc98lt);
SPEAKER(config, "mono").front_center();
BEEP(config, m_beeper, 2400).add_route(ALL_OUTPUTS, "mono", 0.05);
}
void pc98ha_state::ha_config(machine_config &config)
{
lt_config(config);
const XTAL xtal = XTAL(10'000'000);
V50(config.replace(), m_maincpu, xtal);
m_maincpu->set_addrmap(AS_PROGRAM, &pc98ha_state::ha_map);
m_maincpu->set_addrmap(AS_IO, &pc98ha_state::ha_io);
m_maincpu->set_tclk(xtal / 4);
// m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb));
config.device_remove("rtc");
UPD4991A(config, m_rtc_pio, 32'768);
}
// all ROMs in both sets needs at least chip renaming, and I haven't seen a single PCB pic from the net.
// dict.rom and ramdrv.bin definitely won't fit an even ROM size regardless,
// also backup.bin may not be factory default.
ROM_START( pc98lt )
ROM_REGION16_LE( 0x10000, "ipl", ROMREGION_ERASEFF )
ROM_LOAD( "ipl.rom", 0x000000, 0x010000, BAD_DUMP CRC(b6a6a382) SHA1(3f1767cccc1ae02b3e48f6ee327d3ef4fad05750) )
ROM_REGION( 0x40000, "kanji", ROMREGION_ERASEFF )
ROM_LOAD( "kanji.rom", 0x000000, 0x040000, BAD_DUMP CRC(26a81aa2) SHA1(bf12e40c608ef6ef1ac38f6b0b3ca79260a50cef) )
ROM_REGION16_LE( 0x10000, "backup", ROMREGION_ERASEFF )
ROM_LOAD( "backup.bin", 0x000000, 0x010000, BAD_DUMP CRC(56d7ca00) SHA1(d17942e166f98af1d484e497e97d31da515973f7) )
ROM_REGION( 0x100000, "dict", ROMREGION_ERASEFF )
ROM_LOAD( "dict.rom", 0x000000, 0x080000, BAD_DUMP CRC(421278ee) SHA1(f6066fc5085de521395ce1a8bb040536c1454c7e) )
ROM_REGION( 0x100000, "romdrv", ROMREGION_ERASEFF )
ROM_LOAD( "romdrv.rom", 0x000000, 0x080000, BAD_DUMP CRC(282ff6eb) SHA1(f4833e49dd9089ec40f5e86a713e08cd8c598578) )
ROM_END
ROM_START( pc98ha )
ROM_REGION16_LE( 0x10000, "ipl", ROMREGION_ERASEFF )
ROM_LOAD( "ipl.rom", 0x000000, 0x010000, BAD_DUMP CRC(2f552bb9) SHA1(7f53bf95181d65b2f9942285da669d92c61247a3) )
ROM_REGION( 0x40000, "kanji", ROMREGION_ERASEFF )
ROM_LOAD( "kanji.rom", 0x000000, 0x040000, BAD_DUMP CRC(4be5ff2f) SHA1(261d28419a2ddebe3177a282952806d7bb036b40) )
ROM_REGION16_LE( 0x40000, "backup", ROMREGION_ERASEFF )
ROM_LOAD( "backup.bin", 0x000000, 0x040000, BAD_DUMP CRC(3c5b2a99) SHA1(f8e2f5a4c7601d4e81d5e9c83621107ed3f5a29a) )
ROM_REGION( 0x100000, "dict", ROMREGION_ERASEFF )
ROM_LOAD( "dict.rom", 0x000000, 0x0c0000, BAD_DUMP CRC(6dc8493c) SHA1(3e04cdc3403a814969b6590cd78e239e72677fe5) )
ROM_REGION( 0x100000, "romdrv", ROMREGION_ERASEFF )
ROM_LOAD( "romdrv.rom", 0x000000, 0x100000, BAD_DUMP CRC(2f59127f) SHA1(932cb970c2b22408f7895dbf9df6dbc47f8e055b) )
// $00 filled with odd size
ROM_REGION( 0x200000, "ramdrv", ROMREGION_ERASEFF )
ROM_LOAD( "ramdrv.bin", 0x000000, 0x160000, BAD_DUMP CRC(f2cec994) SHA1(c986ad6d8f810ac0a9657c1af26b6fec712d56ed) )
ROM_END
COMP( 1989, pc98lt, 0, 0, lt_config, pc98lt, pc98lt_state, empty_init, "NEC", "PC-98LT", MACHINE_NOT_WORKING )
COMP( 1990, pc98ha, 0, 0, ha_config, pc98ha, pc98ha_state, empty_init, "NEC", "PC-98HA (Handy98)", MACHINE_NOT_WORKING )

View File

@ -253,6 +253,7 @@ private:
void fdc_8255_c_w(uint8_t data);
uint8_t opn_porta_r();
uint8_t opn_portb_r();
void opna_map(address_map &map);
IRQ_CALLBACK_MEMBER(pc8801_irq_callback);
DECLARE_WRITE_LINE_MEMBER(pc8801_sound_irq);
};

View File

@ -1,5 +1,11 @@
// license:BSD-3-Clause
// copyright-holders:Angelo Salese,Carl
/******************************************
*
* NEC PC-9801
*
******************************************/
#ifndef MAME_INCLUDES_PC9801_H
#define MAME_INCLUDES_PC9801_H
@ -9,6 +15,7 @@
#include "cpu/i86/i286.h"
#include "cpu/i86/i86.h"
#include "cpu/nec/nec.h"
#include "cpu/nec/v5x.h"
#include "imagedev/floppy.h"
#include "machine/am9517a.h"
@ -17,12 +24,13 @@
#include "machine/i8251.h"
#include "machine/i8255.h"
#include "machine/output_latch.h"
#include "machine/pc9801_memsw.h"
#include "machine/pic8259.h"
#include "machine/pit8253.h"
#include "machine/ram.h"
#include "machine/timer.h"
#include "machine/upd1990a.h"
#include "machine/pc9801_memsw.h"
#include "machine/upd4991a.h"
#include "machine/upd765.h"
#include "bus/scsi/pc9801_sasi.h"
@ -37,6 +45,7 @@
#include "video/upd7220.h"
#include "bus/cbus/pc9801_26.h"
#include "bus/cbus/pc9801_55.h"
#include "bus/cbus/pc9801_86.h"
#include "bus/cbus/pc9801_118.h"
#include "bus/cbus/pc9801_amd98.h"
@ -61,8 +70,7 @@
#include "formats/dip_dsk.h"
#include "formats/nfd_dsk.h"
#define UPD1990A_TAG "upd1990a"
#define RTC_TAG "rtc"
#define UPD8251_TAG "upd8251"
#define SASIBUS_TAG "sasi"
@ -77,156 +85,136 @@
#define ANALOG_256_MODE (0x20 >> 1)
#define GDC_IS_5MHz (0x84 >> 1)
class pc9801_state : public driver_device
class pc98_base_state : public driver_device
{
public:
pc9801_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_dmac(*this, "i8237"),
m_pit8253(*this, "pit8253"),
m_pic1(*this, "pic8259_master"),
m_pic2(*this, "pic8259_slave"),
m_ppi_sys(*this, "ppi8255_sys"),
m_ppi_prn(*this, "ppi8255_prn"),
m_fdc_2hd(*this, "upd765_2hd"),
m_fdc_2dd(*this, "upd765_2dd"),
m_rtc(*this, UPD1990A_TAG),
m_memsw(*this, "memsw"),
m_keyb(*this, "keyb"),
m_sio(*this, UPD8251_TAG),
m_hgdc1(*this, "upd7220_chr"),
m_hgdc2(*this, "upd7220_btm"),
m_sasibus(*this, SASIBUS_TAG),
m_sasi_data_out(*this, "sasi_data_out"),
m_sasi_data_in(*this, "sasi_data_in"),
m_sasi_ctrl_in(*this, "sasi_ctrl_in"),
m_ide(*this, "ide%u", 1U),
m_video_ram_1(*this, "video_ram_1"),
m_video_ram_2(*this, "video_ram_2"),
m_ext_gvram(*this, "ext_gvram"),
m_beeper(*this, "beeper"),
m_dac(*this, "dac"),
m_ram(*this, RAM_TAG),
m_ipl(*this, "ipl_bank"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_screen(*this, "screen")
pc98_base_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_gfxdecode(*this, "gfxdecode")
, m_palette(*this, "palette")
, m_screen(*this, "screen")
, m_keyb(*this, "keyb")
, m_rtc(*this, RTC_TAG)
, m_ppi_sys(*this, "ppi_sys")
, m_ppi_prn(*this, "ppi_prn")
, m_beeper(*this, "beeper")
{
}
DECLARE_CUSTOM_INPUT_MEMBER(system_type_r);
protected:
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_device<screen_device> m_screen;
required_device<pc9801_kbd_device> m_keyb;
optional_device<upd1990a_device> m_rtc;
required_device<i8255_device> m_ppi_sys;
required_device<i8255_device> m_ppi_prn;
optional_device<beep_device> m_beeper;
void rtc_w(uint8_t data);
void ppi_sys_beep_portc_w(uint8_t data);
static void floppy_formats(format_registration &fr);
u8 m_sys_type;
};
class pc9801_state : public pc98_base_state
{
public:
pc9801_state(const machine_config &mconfig, device_type type, const char *tag)
: pc98_base_state(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_ipl(*this, "ipl_bank")
, m_dmac(*this, "i8237")
, m_pit(*this, "pit")
, m_dsw1(*this, "DSW1")
, m_dsw2(*this, "DSW2")
, m_ppi_mouse(*this, "ppi_mouse")
, m_fdc_2hd(*this, "upd765_2hd")
, m_fdc_2dd(*this, "upd765_2dd")
, m_ram(*this, RAM_TAG)
, m_hgdc(*this, "hgdc%d", 1)
, m_video_ram(*this, "video_ram_%d", 1)
, m_cbus(*this, "cbus%d", 0)
, m_pic1(*this, "pic8259_master")
, m_pic2(*this, "pic8259_slave")
, m_memsw(*this, "memsw")
, m_sio(*this, UPD8251_TAG)
, m_sasibus(*this, SASIBUS_TAG)
, m_sasi_data_out(*this, "sasi_data_out")
, m_sasi_data_in(*this, "sasi_data_in")
, m_sasi_ctrl_in(*this, "sasi_ctrl_in")
{
}
void pc9801(machine_config &config);
void pc9801vm(machine_config &config);
void pc9801ux(machine_config &config);
void pc9801rs(machine_config &config);
void pc9801bx2(machine_config &config);
void pc9821(machine_config &config);
void pc9821as(machine_config &config);
void pc9821ap2(machine_config &config);
void pc9821xa16(machine_config &config);
void pc9821ra20(machine_config &config);
void pc9821ra333(machine_config &config);
void pc9821v20(machine_config &config);
void pc386m(machine_config &config);
void pc486mu(machine_config &config);
void pc486se(machine_config &config);
DECLARE_CUSTOM_INPUT_MEMBER(system_type_r);
void init_pc9801_kanji();
void init_pc9801vm_kanji();
// Device declarations
protected:
virtual void video_start() override;
required_device<cpu_device> m_maincpu;
optional_device<address_map_bank_device> m_ipl;
required_device<am9517a_device> m_dmac;
required_device<pit8253_device> m_pit;
required_ioport m_dsw1;
required_ioport m_dsw2;
required_device<i8255_device> m_ppi_mouse;
// TODO: should really be one FDC
// (I/O $90-$93 is a "simplified" version)
required_device<upd765a_device> m_fdc_2hd;
optional_device<upd765a_device> m_fdc_2dd;
optional_device<ram_device> m_ram;
required_device_array<upd7220_device, 2> m_hgdc;
required_shared_ptr_array<uint16_t, 2> m_video_ram;
required_device_array<pc9801_slot_device, 2> m_cbus;
required_device<pic8259_device> m_pic1;
required_device<pic8259_device> m_pic2;
private:
required_device<pc9801_memsw_device> m_memsw;
required_device<i8251_device> m_sio;
optional_device<scsi_port_device> m_sasibus;
optional_device<output_latch_device> m_sasi_data_out;
optional_device<input_buffer_device> m_sasi_data_in;
optional_device<input_buffer_device> m_sasi_ctrl_in;
// Infrastructure declaration
protected:
DECLARE_MACHINE_START(pc9801_common);
DECLARE_MACHINE_RESET(pc9801_common);
void pc9801_keyboard(machine_config &config);
void pc9801_mouse(machine_config &config);
void pc9801_cbus(machine_config &config);
void pc9801_sasi(machine_config &config);
void pc9801_ide(machine_config &config);
void pc9801_common(machine_config &config);
void pc9801_pit_clock(machine_config &config, const XTAL clock);
void config_floppy_525hd(machine_config &config);
void config_floppy_35hd(machine_config &config);
private:
static void cdrom_headphones(device_t *device);
void pit_clock_config(machine_config &config, const XTAL clock);
required_device<cpu_device> m_maincpu;
required_device<am9517a_device> m_dmac;
required_device<pit8253_device> m_pit8253;
required_device<pic8259_device> m_pic1;
required_device<pic8259_device> m_pic2;
required_device<i8255_device> m_ppi_sys;
required_device<i8255_device> m_ppi_prn;
required_device<upd765a_device> m_fdc_2hd;
optional_device<upd765a_device> m_fdc_2dd;
required_device<upd1990a_device> m_rtc;
required_device<pc9801_memsw_device> m_memsw;
required_device<pc9801_kbd_device> m_keyb;
required_device<i8251_device> m_sio;
required_device<upd7220_device> m_hgdc1;
required_device<upd7220_device> m_hgdc2;
optional_device<scsi_port_device> m_sasibus;
optional_device<output_latch_device> m_sasi_data_out;
optional_device<input_buffer_device> m_sasi_data_in;
optional_device<input_buffer_device> m_sasi_ctrl_in;
optional_device_array<ata_interface_device, 2> m_ide;
required_shared_ptr<uint16_t> m_video_ram_1;
required_shared_ptr<uint16_t> m_video_ram_2;
optional_shared_ptr<uint32_t> m_ext_gvram;
optional_device<beep_device> m_beeper;
// optional_device<dac_1bit_device> m_dac;
optional_device<speaker_sound_device> m_dac;
optional_device<ram_device> m_ram;
optional_device<address_map_bank_device> m_ipl;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_device<screen_device> m_screen;
void pc9801_common_io(address_map &map);
void ipl_bank(address_map &map);
void rtc_w(uint8_t data);
void dmapg4_w(offs_t offset, uint8_t data);
void dmapg8_w(offs_t offset, uint8_t data);
void nmi_ctrl_w(offs_t offset, uint8_t data);
void vrtc_clear_w(uint8_t data);
void pc9801_video_ff_w(uint8_t data);
uint8_t txt_scrl_r(offs_t offset);
void txt_scrl_w(offs_t offset, uint8_t data);
uint8_t grcg_r(offs_t offset);
void grcg_w(offs_t offset, uint8_t data);
void egc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint8_t pc9801_a0_r(offs_t offset);
void pc9801_a0_w(offs_t offset, uint8_t data);
uint8_t fdc_2hd_ctrl_r();
void fdc_2hd_ctrl_w(uint8_t data);
uint8_t fdc_2dd_ctrl_r();
void fdc_2dd_ctrl_w(uint8_t data);
uint16_t tvram_r(offs_t offset, uint16_t mem_mask = ~0);
void tvram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint8_t gvram_r(offs_t offset);
void gvram_w(offs_t offset, uint8_t data);
void pc9801rs_mouse_freq_w(offs_t offset, uint8_t data);
uint16_t grcg_gvram_r(offs_t offset, uint16_t mem_mask = ~0);
void grcg_gvram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t grcg_gvram0_r(offs_t offset, uint16_t mem_mask = ~0);
void grcg_gvram0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
u8 unk_r(offs_t offset);
uint8_t f0_r(offs_t offset);
uint16_t pc9821_grcg_gvram_r(offs_t offset, uint16_t mem_mask = ~0);
void pc9821_grcg_gvram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t pc9821_grcg_gvram0_r(offs_t offset, uint16_t mem_mask = ~0);
void pc9821_grcg_gvram0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint8_t m_nmi_ff;
uint16_t upd7220_grcg_r(offs_t offset, uint16_t mem_mask = ~0);
void upd7220_grcg_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
virtual u8 ppi_prn_portb_r();
uint8_t ide_ctrl_r();
void ide_ctrl_w(uint8_t data);
uint16_t ide_cs0_r(offs_t offset, uint16_t mem_mask = ~0);
void ide_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t ide_cs1_r(offs_t offset, uint16_t mem_mask = ~0);
void ide_cs1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
private:
void pc9801_io(address_map &map);
void pc9801_map(address_map &map);
void nmi_ctrl_w(offs_t offset, uint8_t data);
u8 ppi_sys_portb_r();
void sasi_data_w(uint8_t data);
uint8_t sasi_data_r();
@ -235,84 +223,46 @@ private:
uint8_t sasi_status_r();
void sasi_ctrl_w(uint8_t data);
uint8_t pc9801rs_knjram_r(offs_t offset);
void pc9801rs_knjram_w(offs_t offset, uint8_t data);
void pc9801rs_bank_w(offs_t offset, uint8_t data);
uint8_t f0_r(offs_t offset);
uint8_t a20_ctrl_r(offs_t offset);
void a20_ctrl_w(offs_t offset, uint8_t data);
uint8_t fdc_mode_ctrl_r();
void fdc_mode_ctrl_w(uint8_t data);
// uint8_t pc9801rs_2dd_r();
// void pc9801rs_2dd_w(uint8_t data);
void pc9801rs_video_ff_w(offs_t offset, uint8_t data);
void pc9801rs_a0_w(offs_t offset, uint8_t data);
void pc9821_video_ff_w(offs_t offset, uint8_t data);
uint8_t pc9821_a0_r(offs_t offset);
void pc9821_a0_w(offs_t offset, uint8_t data);
uint8_t access_ctrl_r(offs_t offset);
void access_ctrl_w(offs_t offset, uint8_t data);
uint8_t midi_r();
// uint8_t winram_r();
// void winram_w(uint8_t data);
DECLARE_MACHINE_START(pc9801f);
DECLARE_MACHINE_RESET(pc9801f);
// PIC
protected:
uint8_t pic_r(offs_t offset);
void pic_w(offs_t offset, uint8_t data);
uint8_t sdip_0_r(offs_t offset);
uint8_t sdip_1_r(offs_t offset);
uint8_t sdip_2_r(offs_t offset);
uint8_t sdip_3_r(offs_t offset);
uint8_t sdip_4_r(offs_t offset);
uint8_t sdip_5_r(offs_t offset);
uint8_t sdip_6_r(offs_t offset);
uint8_t sdip_7_r(offs_t offset);
uint8_t sdip_8_r(offs_t offset);
uint8_t sdip_9_r(offs_t offset);
uint8_t sdip_a_r(offs_t offset);
uint8_t sdip_b_r(offs_t offset);
void sdip_0_w(offs_t offset, uint8_t data) ;
void sdip_1_w(offs_t offset, uint8_t data) ;
void sdip_2_w(offs_t offset, uint8_t data) ;
void sdip_3_w(offs_t offset, uint8_t data) ;
void sdip_4_w(offs_t offset, uint8_t data) ;
void sdip_5_w(offs_t offset, uint8_t data) ;
void sdip_6_w(offs_t offset, uint8_t data) ;
void sdip_7_w(offs_t offset, uint8_t data) ;
void sdip_8_w(offs_t offset, uint8_t data) ;
void sdip_9_w(offs_t offset, uint8_t data) ;
void sdip_a_w(offs_t offset, uint8_t data) ;
void sdip_b_w(offs_t offset, uint8_t data) ;
uint8_t as_unkdev_data_r(offs_t offset);
void as_unkdev_data_w(offs_t offset, uint8_t data);
void as_unkdev_addr_w(offs_t offset, uint8_t data);
uint8_t window_bank_r(offs_t offset);
void window_bank_w(offs_t offset, uint8_t data);
uint16_t timestamp_r(offs_t offset);
uint8_t ext2_video_ff_r();
void ext2_video_ff_w(uint8_t data);
static void floppy_formats(format_registration &fr);
UPD7220_DISPLAY_PIXELS_MEMBER( hgdc_display_pixels );
UPD7220_DRAW_TEXT_LINE_MEMBER( hgdc_draw_text );
DECLARE_MACHINE_START(pc9801_common);
DECLARE_MACHINE_START(pc9801f);
DECLARE_MACHINE_START(pc9801rs);
DECLARE_MACHINE_START(pc9801bx2);
DECLARE_MACHINE_START(pc9821);
DECLARE_MACHINE_START(pc9821ap2);
DECLARE_MACHINE_RESET(pc9801_common);
DECLARE_MACHINE_RESET(pc9801f);
DECLARE_MACHINE_RESET(pc9801rs);
DECLARE_MACHINE_RESET(pc9821);
void pc9801_palette(palette_device &palette) const;
DECLARE_WRITE_LINE_MEMBER(vrtc_irq);
private:
uint8_t get_slave_ack(offs_t offset);
// FDC
protected:
uint8_t fdc_2hd_ctrl_r();
void fdc_2hd_ctrl_w(uint8_t data);
u8 m_fdc_2hd_ctrl;
bool fdc_drive_ready_r(upd765a_device *fdc);
private:
DECLARE_WRITE_LINE_MEMBER(fdc_2dd_irq);
uint8_t fdc_2dd_ctrl_r();
void fdc_2dd_ctrl_w(uint8_t data);
u8 m_fdc_2dd_ctrl;
// DMA
protected:
uint8_t m_dma_offset[4];
uint8_t m_dma_autoinc[4];
int m_dack;
private:
void dmapg4_w(offs_t offset, uint8_t data);
inline void set_dma_channel(int channel, int state);
DECLARE_WRITE_LINE_MEMBER(dma_hrq_changed);
DECLARE_WRITE_LINE_MEMBER(tc_w);
uint8_t dma_read_byte(offs_t offset);
@ -321,71 +271,73 @@ private:
DECLARE_WRITE_LINE_MEMBER(dack1_w);
DECLARE_WRITE_LINE_MEMBER(dack2_w);
DECLARE_WRITE_LINE_MEMBER(dack3_w);
void ppi_sys_beep_portc_w(uint8_t data);
void ppi_sys_dac_portc_w(uint8_t data);
DECLARE_WRITE_LINE_MEMBER(fdc_2dd_irq);
DECLARE_WRITE_LINE_MEMBER(pc9801rs_fdc_irq);
DECLARE_WRITE_LINE_MEMBER(pc9801rs_fdc_drq);
uint8_t ppi_mouse_porta_r();
void ppi_mouse_porta_w(uint8_t data);
void ppi_mouse_portb_w(uint8_t data);
void ppi_mouse_portc_w(uint8_t data);
TIMER_DEVICE_CALLBACK_MEMBER( mouse_irq_cb );
uint8_t unk_r();
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
uint32_t a20_286(bool state);
void ipl_bank(address_map &map);
void pc9801_common_io(address_map &map);
void pc9801_io(address_map &map);
void pc9801_map(address_map &map);
void pc9801rs_io(address_map &map);
void pc9801rs_map(address_map &map);
void pc9801ux_io(address_map &map);
void pc9801ux_map(address_map &map);
void pc9821_io(address_map &map);
void pc9821_map(address_map &map);
void pc9821as_io(address_map &map);
// Video
protected:
void upd7220_1_map(address_map &map);
void upd7220_2_map(address_map &map);
void upd7220_grcg_2_map(address_map &map);
enum
{
TIMER_VBIRQ
};
UPD7220_DISPLAY_PIXELS_MEMBER( hgdc_display_pixels );
virtual void video_start() override;
void pc9801_palette(palette_device &palette) const;
inline void set_dma_channel(int channel, int state);
uint8_t *m_char_rom;
uint8_t *m_kanji_rom;
uint8_t m_dma_offset[4];
uint8_t m_dma_autoinc[4];
int m_dack;
struct {
uint8_t mode;
uint8_t tile[4], tile_index;
}m_grcg;
uint8_t m_video_ff[8],m_gfx_ff;
enum
{
TIMER_VBIRQ,
TIMER_FDC_TRIGGER
};
uint16_t tvram_r(offs_t offset, uint16_t mem_mask = ~0);
void tvram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint8_t gvram_r(offs_t offset);
void gvram_w(offs_t offset, uint8_t data);
uint8_t grcg_r(offs_t offset);
void grcg_w(offs_t offset, uint8_t data);
void pc9801_video_ff_w(uint8_t data);
uint16_t m_font_addr;
uint16_t m_font_lr;
uint8_t m_video_ff[8];
// TODO: move to derived state
uint8_t m_ex_video_ff[128];
u8 m_vram_bank;
u8 m_vram_disp;
private:
UPD7220_DRAW_TEXT_LINE_MEMBER( hgdc_draw_text );
DECLARE_WRITE_LINE_MEMBER(vrtc_irq);
void vrtc_clear_w(uint8_t data);
uint8_t txt_scrl_r(offs_t offset);
void txt_scrl_w(offs_t offset, uint8_t data);
// TODO: make this virtual
// (necessary for H98 high-reso mode, PC9821-E02, SVGA binds)
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
uint8_t m_font_line;
std::unique_ptr<uint16_t[]> m_tvram;
uint8_t m_gfx_ff;
uint8_t m_txt_scroll_reg[8];
uint8_t m_pal_clut[4];
std::unique_ptr<uint16_t[]> m_tvram;
uint16_t m_font_addr;
uint8_t m_font_line;
uint16_t m_font_lr;
uint8_t m_fdc_2dd_ctrl,m_fdc_2hd_ctrl;
uint8_t m_nmi_ff;
uint8_t m_vram_bank;
uint8_t m_vram_disp;
// SASI
uint8_t m_sasi_data;
int m_sasi_data_enable;
uint8_t m_sasi_ctrl;
// Mouse
protected:
struct{
uint8_t control;
uint8_t lx, ly;
@ -395,41 +347,130 @@ private:
uint8_t freq_index;
}m_mouse;
uint8_t m_ide_sel;
private:
u8 ppi_mouse_porta_r();
void ppi_mouse_porta_w(uint8_t data);
void ppi_mouse_portb_w(uint8_t data);
void ppi_mouse_portc_w(uint8_t data);
TIMER_DEVICE_CALLBACK_MEMBER( mouse_irq_cb );
};
/**********************************************************
*
* VM class
*
**********************************************************/
class pc9801vm_state : public pc9801_state
{
public:
pc9801vm_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9801_state(mconfig, type, tag)
, m_dsw3(*this, "DSW3")
, m_ide(*this, "ide%u", 1U)
, m_dac1bit(*this, "dac1bit")
{
}
void pc9801vm(machine_config &config);
void pc9801ux(machine_config &config);
void pc9801vx(machine_config &config);
void pc9801rs(machine_config &config);
void init_pc9801vm_kanji();
protected:
void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
void pc9801rs_io(address_map &map);
void pc9801rs_map(address_map &map);
uint16_t grcg_gvram_r(offs_t offset, uint16_t mem_mask = ~0);
void grcg_gvram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t grcg_gvram0_r(offs_t offset, uint16_t mem_mask = ~0);
void grcg_gvram0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t upd7220_grcg_r(offs_t offset, uint16_t mem_mask = ~0);
void upd7220_grcg_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void upd7220_grcg_2_map(address_map &map);
void pc9801_ide(machine_config &config);
static void cdrom_headphones(device_t *device);
void pc9801rs_video_ff_w(offs_t offset, uint8_t data);
void pc9801rs_a0_w(offs_t offset, uint8_t data);
uint8_t ide_ctrl_r();
void ide_ctrl_w(uint8_t data);
uint16_t ide_cs0_r(offs_t offset, uint16_t mem_mask = ~0);
void ide_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t ide_cs1_r(offs_t offset, uint16_t mem_mask = ~0);
void ide_cs1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void dmapg8_w(offs_t offset, uint8_t data);
uint16_t timestamp_r(offs_t offset);
void ppi_sys_dac_portc_w(uint8_t data);
virtual u8 ppi_prn_portb_r() override;
DECLARE_MACHINE_START(pc9801rs);
DECLARE_MACHINE_RESET(pc9801rs);
u8 m_gate_a20;
u8 m_dma_access_ctrl;
u8 m_ide_sel;
// starting from PC9801VF/U buzzer is substituted with a DAC1BIT
bool m_dac_disable;
bool m_dac1bit_disable;
/* PC9801RS specific, move to specific state */
uint8_t m_gate_a20; //A20 line
uint8_t m_access_ctrl; // DMA related
uint8_t m_fdc_ctrl;
uint8_t m_ex_video_ff[128];
required_ioport m_dsw3;
private:
optional_device_array<ata_interface_device, 2> m_ide;
// optional_device<dac_1bit_device> m_dac1bit;
required_device<speaker_sound_device> m_dac1bit;
void pc9801ux_io(address_map &map);
void pc9801ux_map(address_map &map);
uint32_t a20_286(bool state);
uint8_t pc9801rs_knjram_r(offs_t offset);
void pc9801rs_knjram_w(offs_t offset, uint8_t data);
void pc9801rs_bank_w(offs_t offset, uint8_t data);
uint8_t midi_r();
// 286-based machines except for PC98XA
u8 dma_access_ctrl_r(offs_t offset);
void dma_access_ctrl_w(offs_t offset, u8 data);
uint8_t a20_ctrl_r(offs_t offset);
void a20_ctrl_w(offs_t offset, uint8_t data);
template <unsigned port> u8 fdc_2hd_2dd_ctrl_r();
template <unsigned port> void fdc_2hd_2dd_ctrl_w(u8 data);
DECLARE_WRITE_LINE_MEMBER(fdc_irq_w);
DECLARE_WRITE_LINE_MEMBER(fdc_drq_w);
emu_timer *m_fdc_timer;
u8 m_fdc_mode;
u8 fdc_mode_r();
void fdc_mode_w(u8 data);
void fdc_set_density_mode(bool is_2hd);
protected:
struct {
uint8_t pal_entry;
uint8_t r[16],g[16],b[16];
}m_analog16;
struct {
uint8_t pal_entry;
uint8_t r[0x100],g[0x100],b[0x100];
uint16_t bank[2];
}m_analog256;
struct {
uint8_t mode;
uint8_t tile[4], tile_index;
}m_grcg;
void egc_blit_w(uint32_t offset, uint16_t data, uint16_t mem_mask);
uint16_t egc_blit_r(uint32_t offset, uint16_t mem_mask);
/* PC9821 specific */
uint8_t m_sdip[24], m_sdip_bank;
uint8_t m_unkdev0468[0x100], m_unkdev0468_addr;
uint8_t m_pc9821_window_bank;
uint8_t m_ext2_ff;
uint8_t m_sys_type;
private:
// EGC, PC9801VX onward
struct {
uint16_t regs[8];
uint16_t pat[4];
@ -440,13 +481,76 @@ private:
bool init;
} m_egc;
uint16_t m_pc9821_256vram_bank;
protected:
void egc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
private:
void egc_blit_w(uint32_t offset, uint16_t data, uint16_t mem_mask);
uint16_t egc_blit_r(uint32_t offset, uint16_t mem_mask);
uint8_t m_sdip_read(uint16_t port, uint8_t sdip_offset);
void m_sdip_write(uint16_t port, uint8_t sdip_offset,uint8_t data);
uint16_t egc_do_partial_op(int plane, uint16_t src, uint16_t pat, uint16_t dst) const;
uint16_t egc_shift(int plane, uint16_t val);
uint16_t egc_color_pat(int plane) const;
protected:
u8 mouse_freq_r(offs_t offset);
void mouse_freq_w(offs_t offset, u8 data);
u8 ppi_mouse_portb_r();
u8 ppi_mouse_portc_r();
};
class pc9801us_state : public pc9801vm_state
{
public:
pc9801us_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9801vm_state(mconfig, type, tag)
{
}
void pc9801us(machine_config &config);
protected:
void pc9801us_io(address_map &map);
DECLARE_MACHINE_START(pc9801us);
// SDIP, PC9801DA onward
protected:
u8 m_sdip[24];
private:
u8 m_sdip_bank;
template<unsigned port> u8 sdip_r(offs_t offset);
template<unsigned port> void sdip_w(offs_t offset, u8 data);
void sdip_bank_w(offs_t offset, u8 data);
};
/**********************************************************
*
* BX class ("98Fellow")
*
**********************************************************/
class pc9801bx_state : public pc9801us_state
{
public:
pc9801bx_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9801us_state(mconfig, type, tag)
{
}
void pc9801bx2(machine_config &config);
protected:
void pc9801bx2_io(address_map &map);
void pc9801bx2_map(address_map &map);
DECLARE_MACHINE_START(pc9801bx2);
DECLARE_MACHINE_RESET(pc9801bx2);
private:
u8 i486_cpu_mode_r(offs_t offset);
u8 gdc_31kHz_r(offs_t offset);
void gdc_31kHz_w(offs_t offset, u8 data);
};
#endif // MAME_INCLUDES_PC9801_H

View File

@ -0,0 +1,58 @@
// license:BSD-3-Clause
// copyright-holders:Angelo Salese,Carl
/******************************************
*
* Epson PC98 clones
*
******************************************/
#ifndef MAME_INCLUDES_PC9801_EPSON_H
#define MAME_INCLUDES_PC9801_EPSON_H
#pragma once
#include "includes/pc9801.h"
class pc98_epson_state : public pc9801vm_state
{
public:
pc98_epson_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9801vm_state(mconfig, type, tag)
, m_shadow_ipl(*this, "shadow_ipl_%u", 0)
{
}
void pc386m(machine_config &config);
void pc486mu(machine_config &config);
void pc486se(machine_config &config);
protected:
void pc386m_ipl_bank(address_map &map);
void pc386m_io(address_map &map);
void pc386m_map(address_map &map);
void pc486se_io(address_map &map);
void pc486se_map(address_map &map);
// virtual void machine_start() override;
// virtual void machine_reset() override;
DECLARE_MACHINE_START(pc98_epson);
DECLARE_MACHINE_RESET(pc98_epson);
private:
void epson_ipl_bank_w(offs_t offset, u8 data);
void epson_itf_bank_w(offs_t offset, u8 data);
void epson_a20_w(offs_t offset, u8 data);
void epson_vram_bank_w(offs_t offset, u8 data);
required_shared_ptr_array<uint16_t, 2> m_shadow_ipl;
template <unsigned which> void shadow_ipl_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
u8 m_shadow_ipl_bank;
bool m_itf_bank_enable;
// u8 m_itf_bank;
};
#endif // MAME_INCLUDES_PC9801_EPSON_H

193
src/mame/includes/pc9821.h Normal file
View File

@ -0,0 +1,193 @@
// license:BSD-3-Clause
// copyright-holders:Angelo Salese,Carl
/******************************************
*
* NEC PC-9821
*
******************************************/
#ifndef MAME_INCLUDES_PC9821_H
#define MAME_INCLUDES_PC9821_H
#pragma once
#include "includes/pc9801.h"
class pc9821_state : public pc9801bx_state
{
public:
pc9821_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9801bx_state(mconfig, type, tag)
, m_ext_gvram(*this, "ext_gvram")
{
}
void pc9821(machine_config &config);
protected:
void pc9821_io(address_map &map);
void pc9821_map(address_map &map);
DECLARE_MACHINE_START(pc9821);
DECLARE_MACHINE_RESET(pc9821);
private:
required_shared_ptr<uint32_t> m_ext_gvram;
uint16_t pc9821_grcg_gvram_r(offs_t offset, uint16_t mem_mask = ~0);
void pc9821_grcg_gvram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t pc9821_grcg_gvram0_r(offs_t offset, uint16_t mem_mask = ~0);
void pc9821_grcg_gvram0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void pc9821_video_ff_w(offs_t offset, uint8_t data);
uint8_t pc9821_a0_r(offs_t offset);
void pc9821_a0_w(offs_t offset, uint8_t data);
uint8_t window_bank_r(offs_t offset);
void window_bank_w(offs_t offset, uint8_t data);
uint8_t ext2_video_ff_r();
void ext2_video_ff_w(uint8_t data);
uint8_t m_pc9821_window_bank;
uint8_t m_ext2_ff;
struct {
uint8_t pal_entry;
uint8_t r[0x100],g[0x100],b[0x100];
uint16_t bank[2];
}m_analog256;
void pc9821_egc_w(offs_t offset, u16 data, u16 mem_mask = ~0);
UPD7220_DISPLAY_PIXELS_MEMBER( pegc_display_pixels );
};
// MATE A
class pc9821_mate_a_state : public pc9821_state
{
public:
pc9821_mate_a_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9821_state(mconfig, type, tag)
{
}
void pc9821as(machine_config &config);
void pc9821ap2(machine_config &config);
protected:
void pc9821as_io(address_map &map);
private:
DECLARE_MACHINE_START(pc9821ap2);
// Ap, As, Ae only
u8 ext_sdip_data_r(offs_t offset);
void ext_sdip_data_w(offs_t offset, u8 data);
void ext_sdip_address_w(offs_t offset, u8 data);
void ext_sdip_access_w(offs_t offset, u8 data);
uint8_t m_ext_sdip[0x100], m_ext_sdip_addr;
};
// CanBe
class pc9821_canbe_state : public pc9821_state
{
public:
pc9821_canbe_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9821_state(mconfig, type, tag)
{
}
void pc9821ce2(machine_config &config);
void pc9821cx3(machine_config &config);
protected:
void pc9821cx3_map(address_map &map);
void pc9821cx3_io(address_map &map);
private:
void remote_addr_w(offs_t offset, u8 data);
u8 remote_data_r(offs_t offset);
void remote_data_w(offs_t offset, u8 data);
DECLARE_MACHINE_START(pc9821_canbe);
struct {
u8 index;
}m_remote;
};
// class pc9821_cereb_state : public pc9821_canbe_state
// Mate B
// class pc9821_mate_b_state : public pc9821_state
// Mate X (NB: should be subclass of Mate B)
class pc9821_mate_x_state : public pc9821_state
{
public:
pc9821_mate_x_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9821_state(mconfig, type, tag)
{
}
void pc9821xa16(machine_config &config);
void pc9821xs(machine_config &config);
};
// Mate R
class pc9821_mate_r_state : public pc9821_mate_x_state
{
public:
pc9821_mate_r_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9821_mate_x_state(mconfig, type, tag)
{
}
void pc9821ra20(machine_config &config);
void pc9821ra266(machine_config &config);
void pc9821ra333(machine_config &config);
};
class pc9821_valuestar_state : public pc9821_mate_x_state
{
public:
pc9821_valuestar_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9821_mate_x_state(mconfig, type, tag)
{
}
void pc9821v13(machine_config &config);
void pc9821v20(machine_config &config);
};
// 9821NOTE
class pc9821_note_state : public pc9821_state
{
public:
pc9821_note_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9821_state(mconfig, type, tag)
{
}
void pc9821ne(machine_config &config);
};
class pc9821_note_lavie_state : public pc9821_note_state
{
public:
pc9821_note_lavie_state(const machine_config &mconfig, device_type type, const char *tag)
: pc9821_note_state(mconfig, type, tag)
{
}
void pc9821nr15(machine_config &config);
void pc9821nr166(machine_config &config);
void pc9821nw150(machine_config &config);
};
#endif // MAME_INCLUDES_PC9821_H

104
src/mame/includes/pc98ha.h Normal file
View File

@ -0,0 +1,104 @@
// license:BSD-3-Clause
// copyright-holders:Angelo Salese
/******************************************
*
* NEC "Handy98" 1st gen portables
*
******************************************/
#ifndef MAME_INCLUDES_PC98HA_H
#define MAME_INCLUDES_PC98HA_H
#pragma once
#include "includes/pc9801.h"
class pc98lt_state : public pc98_base_state
{
public:
pc98lt_state(const machine_config &mconfig, device_type type, const char *tag)
: pc98_base_state(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_fdc(*this, "upd765")
, m_gvram(*this, "gvram")
, m_bram_bank(*this, "bram_bank")
, m_dict_bank(*this, "dict_bank")
, m_kanji_bank(*this, "kanji_bank")
, m_romdrv_bank(*this, "romdrv_bank")
{
}
void lt_config(machine_config &config);
protected:
void lt_map(address_map &map);
void lt_io(address_map &map);
required_device<v50_device> m_maincpu;
virtual void machine_start() override;
// virtual void machine_reset() override;
private:
required_device<upd765a_device> m_fdc;
required_shared_ptr<uint16_t> m_gvram;
std::unique_ptr<uint16_t[]> m_bram_ptr;
required_memory_bank m_bram_bank;
required_memory_bank m_dict_bank;
required_memory_bank m_kanji_bank;
required_memory_bank m_romdrv_bank;
void lt_palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
u8 power_status_r();
void power_control_w(offs_t offset, u8 data);
u8 floppy_mode_r(offs_t offset);
void floppy_mode_w(offs_t offset, u8 data);
u8 fdc_ctrl_r(offs_t offset);
void fdc_ctrl_w(offs_t offset, u8 data);
u8 m_romdrv_bank_reg;
u8 m_bram_banks;
u8 m_bram_bank_reg;
u8 m_dict_bank_reg;
u8 m_floppy_mode;
u8 m_fdc_ctrl;
};
class pc98ha_state : public pc98lt_state
{
public:
pc98ha_state(const machine_config &mconfig, device_type type, const char *tag)
: pc98lt_state(mconfig, type, tag)
, m_ems_banks(*this, "ems_bank%u", 1U)
, m_ext_view(*this, "ext_io")
, m_ramdrv_bank(*this, "ramdrv_bank")
, m_rtc_pio(*this, "prtc")
{
}
void ha_config(machine_config &config);
protected:
void ha_map(address_map &map);
void ha_io(address_map &map);
virtual void machine_start() override;
private:
required_memory_bank_array<4> m_ems_banks;
memory_view m_ext_view;
required_memory_bank m_ramdrv_bank;
required_device<upd4991a_device> m_rtc_pio;
std::unique_ptr<uint16_t[]> m_ems_ram;
void ext_view_bank_w(offs_t offset, u8 data);
void ext_view_sel_w(offs_t offset, u8 data);
void ems_bank_w(offs_t offset, u8 data);
u8 memcard_status_1_r(offs_t offset);
u8 memcard_status_2_r(offs_t offset);
u8 m_ext_view_sel;
};
#endif // MAME_INCLUDES_PC9801_EPSON_H

View File

@ -33849,28 +33849,43 @@ pc8801mk2sr //
pc88va //
pc88va2 //
@source:pc98ha.cpp
pc98lt // 1989
pc98ha // 1990
@source:pc9801.cpp
pc386m //
pc486mu //
pc486se // 1993
pc9801bx2 // 1993
pc9801f // 1983
pc9801rs // 1989
pc9801rx // 1988
pc9801us // 1992
pc9801ux // 1987
pc9801vm // 1985
pc9801vm11 //
pc9821 //
pc9821ap2 //
pc9821as //
pc9821ce2 //
pc9821ne //
pc9821ra20 //
pc9821ra333 //
pc9821v13 //
pc9821v20 //
pc9821xa16 //
pc9821xs //
pc9801vm11 // 1985
pc9801vx // 1986
@source:pc9801_epson.cpp
pc386m // 1990
pc486se // 1993
pc486mu // 1994
@source:pc9821.cpp
pc9821 // 1992
pc9821ap2 // 1993
pc9821as // 1993
pc9821ce2 // 1994
pc9821cx3 // 1995
pc9821ne // 1994
pc9821nr15 // 1996
pc9821nr166 // 1997
pc9821nw150 // 1997
pc9821ra20 // 1996
pc9821ra266 // 1997
pc9821ra333 // 1998
pc9821v13 // 1998
pc9821v20 // 1998
pc9821xa16 // 1996
pc9821xs // 1994
@source:pcat_dyn.cpp
toursol // (c) 1995 Dynamo

View File

@ -30,8 +30,10 @@ uint32_t pc9801_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap
bitmap.fill(m_palette->black_pen(), cliprect);
/* graphics */
m_hgdc2->screen_update(screen, bitmap, cliprect);
m_hgdc1->screen_update(screen, bitmap, cliprect);
if(m_video_ff[DISPLAY_REG] != 0)
m_hgdc[1]->screen_update(screen, bitmap, cliprect);
m_hgdc[0]->screen_update(screen, bitmap, cliprect);
return 0;
}
@ -46,39 +48,21 @@ UPD7220_DISPLAY_PIXELS_MEMBER( pc9801_state::hgdc_display_pixels )
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
if(m_video_ff[DISPLAY_REG] == 0) //screen is off
return;
uint8_t colors16_mode = (m_ex_video_ff[ANALOG_16_MODE]) ? 16 : 8;
if(m_ex_video_ff[ANALOG_256_MODE])
for(int xi=0;xi<16;xi++)
{
uint8_t *ext_gvram = (uint8_t *)m_ext_gvram.target();
for(int xi=0;xi<16;xi++)
{
int res_x = x + xi;
int res_y = y;
int res_x = x + xi;
int res_y = y;
uint8_t pen = ext_gvram[(address)*16+xi+(m_vram_disp*0x40000)];
uint8_t pen;
bitmap.pix(res_y, res_x) = palette[pen + 0x20];
}
}
else
{
for(int xi=0;xi<16;xi++)
{
int res_x = x + xi;
int res_y = y;
uint8_t pen;
pen = ((m_video_ram_2[((address & 0x3fff) + (0x4000) + ((m_vram_disp*0x20000)>>1))] >> xi) & 1) ? 1 : 0;
pen|= ((m_video_ram_2[((address & 0x3fff) + (0x8000) + ((m_vram_disp*0x20000)>>1))] >> xi) & 1) ? 2 : 0;
pen|= ((m_video_ram_2[((address & 0x3fff) + (0xc000) + ((m_vram_disp*0x20000)>>1))] >> xi) & 1) ? 4 : 0;
if(m_ex_video_ff[ANALOG_16_MODE])
pen|= ((m_video_ram_2[((address & 0x3fff) + (0) + ((m_vram_disp*0x20000)>>1))] >> xi) & 1) ? 8 : 0;
bitmap.pix(res_y, res_x) = palette[pen + colors16_mode];
}
pen = ((m_video_ram[1][((address & 0x3fff) + (0x4000) + ((m_vram_disp*0x20000)>>1))] >> xi) & 1) ? 1 : 0;
pen|= ((m_video_ram[1][((address & 0x3fff) + (0x8000) + ((m_vram_disp*0x20000)>>1))] >> xi) & 1) ? 2 : 0;
pen|= ((m_video_ram[1][((address & 0x3fff) + (0xc000) + ((m_vram_disp*0x20000)>>1))] >> xi) & 1) ? 4 : 0;
if(m_ex_video_ff[ANALOG_16_MODE])
pen|= ((m_video_ram[1][((address & 0x3fff) + (0) + ((m_vram_disp*0x20000)>>1))] >> xi) & 1) ? 8 : 0;
bitmap.pix(res_y, res_x) = palette[pen + colors16_mode];
}
}
@ -107,8 +91,8 @@ UPD7220_DRAW_TEXT_LINE_MEMBER( pc9801_state::hgdc_draw_text )
uint8_t kanji_sel = 0;
uint8_t kanji_lr = 0;
uint16_t tile = m_video_ram_1[tile_addr & 0xfff] & 0xff;
uint8_t knj_tile = m_video_ram_1[tile_addr & 0xfff] >> 8;
uint16_t tile = m_video_ram[0][tile_addr & 0xfff] & 0xff;
uint8_t knj_tile = m_video_ram[0][tile_addr & 0xfff] >> 8;
if(knj_tile)
{
/* Note: bit 7 doesn't really count, if a kanji is enabled then the successive tile is always the second part of it.
@ -135,7 +119,7 @@ UPD7220_DRAW_TEXT_LINE_MEMBER( pc9801_state::hgdc_draw_text )
{
/* Rori Rori Rolling definitely uses different colors for brake stop PCG elements,
assume that all attributes are recalculated on different strips */
uint8_t attr = (m_video_ram_1[((tile_addr+kanji_lr) & 0xfff) | 0x1000] & 0xff);
uint8_t attr = (m_video_ram[0][((tile_addr+kanji_lr) & 0xfff) | 0x1000] & 0xff);
uint8_t secret = (attr & 1) ^ 1;
uint8_t blink = attr & 2;
@ -310,7 +294,7 @@ uint8_t pc9801_state::pc9801_a0_r(offs_t offset)
{
case 0x00:
case 0x02:
return m_hgdc2->read((offset & 2) >> 1);
return m_hgdc[1]->read((offset & 2) >> 1);
/* TODO: double check these two */
case 0x04:
return m_vram_disp & 1;
@ -355,7 +339,7 @@ void pc9801_state::pc9801_a0_w(offs_t offset, uint8_t data)
{
case 0x00:
case 0x02:
m_hgdc2->write((offset & 2) >> 1,data);
m_hgdc[1]->write((offset & 2) >> 1,data);
return;
case 0x04:
m_vram_disp = data & 1;
@ -452,7 +436,7 @@ void pc9801_state::tvram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
else if(m_video_ff[MEMSW_REG] && ACCESSING_BITS_0_7)
m_memsw->write(offset & 0x0f, data & 0xff);
COMBINE_DATA(&m_video_ram_1[offset]); //TODO: check me
COMBINE_DATA(&m_video_ram[0][offset]); //TODO: check me
}
/*************************************************
@ -464,15 +448,15 @@ void pc9801_state::tvram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
/* +0x8000 is trusted (bank 0 is actually used by 16 colors mode) */
uint8_t pc9801_state::gvram_r(offs_t offset)
{
return bitswap<8>(m_video_ram_2[(offset>>1)+0x04000+m_vram_bank*0x10000] >> ((offset & 1) << 3),0,1,2,3,4,5,6,7);
return bitswap<8>(m_video_ram[1][(offset>>1)+0x04000+m_vram_bank*0x10000] >> ((offset & 1) << 3),0,1,2,3,4,5,6,7);
}
void pc9801_state::gvram_w(offs_t offset, uint8_t data)
{
uint16_t ram = m_video_ram_2[(offset>>1)+0x04000+m_vram_bank*0x10000];
uint16_t ram = m_video_ram[1][(offset>>1)+0x04000+m_vram_bank*0x10000];
int mask = (offset & 1) << 3;
data = bitswap<8>(data,0,1,2,3,4,5,6,7);
m_video_ram_2[(offset>>1)+0x04000+m_vram_bank*0x10000] = (ram & (0xff00 >> mask)) | (data << mask);
m_video_ram[1][(offset>>1)+0x04000+m_vram_bank*0x10000] = (ram & (0xff00 >> mask)) | (data << mask);
}
/*************************************************
@ -481,12 +465,12 @@ void pc9801_state::gvram_w(offs_t offset, uint8_t data)
*
************************************************/
uint16_t pc9801_state::upd7220_grcg_r(offs_t offset, uint16_t mem_mask)
uint16_t pc9801vm_state::upd7220_grcg_r(offs_t offset, uint16_t mem_mask)
{
uint16_t res = 0;
if(!(m_grcg.mode & 0x80) || machine().side_effects_disabled())
res = m_video_ram_2[offset];
res = m_video_ram[1][offset];
else if(m_ex_video_ff[2])
res = egc_blit_r(offset, mem_mask);
else if(!(m_grcg.mode & 0x40))
@ -499,7 +483,7 @@ uint16_t pc9801_state::upd7220_grcg_r(offs_t offset, uint16_t mem_mask)
{
if((m_grcg.mode & (1 << i)) == 0)
{
res |= m_video_ram_2[offset | (((i + 1) & 3) * 0x4000)] ^ (m_grcg.tile[i] | m_grcg.tile[i] << 8);
res |= m_video_ram[1][offset | (((i + 1) & 3) * 0x4000)] ^ (m_grcg.tile[i] | m_grcg.tile[i] << 8);
}
}
@ -509,16 +493,16 @@ uint16_t pc9801_state::upd7220_grcg_r(offs_t offset, uint16_t mem_mask)
return res;
}
void pc9801_state::upd7220_grcg_w(offs_t offset, uint16_t data, uint16_t mem_mask)
void pc9801vm_state::upd7220_grcg_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if(!(m_grcg.mode & 0x80))
COMBINE_DATA(&m_video_ram_2[offset]);
COMBINE_DATA(&m_video_ram[1][offset]);
else if(m_ex_video_ff[2])
egc_blit_w(offset, data, mem_mask);
else
{
int i;
uint8_t *vram = (uint8_t *)m_video_ram_2.target();
uint8_t *vram = (uint8_t *)m_video_ram[1].target();
offset = (offset << 1) & 0x27fff;
if(m_grcg.mode & 0x40) // RMW
@ -563,7 +547,7 @@ void pc9801_state::upd7220_grcg_w(offs_t offset, uint16_t data, uint16_t mem_mas
*
************************************************/
uint16_t pc9801_state::egc_color_pat(int plane) const
uint16_t pc9801vm_state::egc_color_pat(int plane) const
{
uint8_t color = 0;
switch((m_egc.regs[1] >> 13) & 3)
@ -582,7 +566,7 @@ uint16_t pc9801_state::egc_color_pat(int plane) const
return BIT(color, plane) ? 0xffff : 0;
}
uint16_t pc9801_state::egc_shift(int plane, uint16_t val)
uint16_t pc9801vm_state::egc_shift(int plane, uint16_t val)
{
int src_off = m_egc.regs[6] & 0xf, dst_off = (m_egc.regs[6] >> 4) & 0xf;
int left = src_off - dst_off, right = dst_off - src_off;
@ -616,7 +600,7 @@ uint16_t pc9801_state::egc_shift(int plane, uint16_t val)
return out;
}
uint16_t pc9801_state::egc_do_partial_op(int plane, uint16_t src, uint16_t pat, uint16_t dst) const
uint16_t pc9801vm_state::egc_do_partial_op(int plane, uint16_t src, uint16_t pat, uint16_t dst) const
{
uint16_t out = 0;
@ -631,7 +615,7 @@ uint16_t pc9801_state::egc_do_partial_op(int plane, uint16_t src, uint16_t pat,
return out;
}
void pc9801_state::egc_blit_w(uint32_t offset, uint16_t data, uint16_t mem_mask)
void pc9801vm_state::egc_blit_w(uint32_t offset, uint16_t data, uint16_t mem_mask)
{
uint16_t mask = m_egc.regs[4] & mem_mask, out = 0;
bool dir = !(m_egc.regs[6] & 0x1000);
@ -684,7 +668,7 @@ void pc9801_state::egc_blit_w(uint32_t offset, uint16_t data, uint16_t mem_mask)
src = egc_shift(i, data);
if((m_egc.regs[2] & 0x300) == 0x200)
pat = m_video_ram_2[offset + (((i + 1) & 3) * 0x4000)];
pat = m_video_ram[1][offset + (((i + 1) & 3) * 0x4000)];
switch((m_egc.regs[2] >> 11) & 3)
{
@ -692,7 +676,7 @@ void pc9801_state::egc_blit_w(uint32_t offset, uint16_t data, uint16_t mem_mask)
out = data;
break;
case 1:
out = egc_do_partial_op(i, src, pat, m_video_ram_2[offset + (((i + 1) & 3) * 0x4000)]);
out = egc_do_partial_op(i, src, pat, m_video_ram[1][offset + (((i + 1) & 3) * 0x4000)]);
break;
case 2:
out = pat;
@ -702,8 +686,8 @@ void pc9801_state::egc_blit_w(uint32_t offset, uint16_t data, uint16_t mem_mask)
return;
}
m_video_ram_2[offset + (((i + 1) & 3) * 0x4000)] &= ~mask;
m_video_ram_2[offset + (((i + 1) & 3) * 0x4000)] |= out & mask;
m_video_ram[1][offset + (((i + 1) & 3) * 0x4000)] &= ~mask;
m_video_ram[1][offset + (((i + 1) & 3) * 0x4000)] |= out & mask;
}
}
if(mem_mask != 0xffff)
@ -731,15 +715,15 @@ void pc9801_state::egc_blit_w(uint32_t offset, uint16_t data, uint16_t mem_mask)
}
}
uint16_t pc9801_state::egc_blit_r(uint32_t offset, uint16_t mem_mask)
uint16_t pc9801vm_state::egc_blit_r(uint32_t offset, uint16_t mem_mask)
{
uint32_t plane_off = offset & 0x13fff;
if((m_egc.regs[2] & 0x300) == 0x100)
{
m_egc.pat[0] = m_video_ram_2[plane_off + 0x4000];
m_egc.pat[1] = m_video_ram_2[plane_off + (0x4000 * 2)];
m_egc.pat[2] = m_video_ram_2[plane_off + (0x4000 * 3)];
m_egc.pat[3] = m_video_ram_2[plane_off];
m_egc.pat[0] = m_video_ram[1][plane_off + 0x4000];
m_egc.pat[1] = m_video_ram[1][plane_off + (0x4000 * 2)];
m_egc.pat[2] = m_video_ram[1][plane_off + (0x4000 * 3)];
m_egc.pat[3] = m_video_ram[1][plane_off];
}
//TODO: this needs another look
/*if(m_egc.first && !m_egc.init)
@ -750,17 +734,17 @@ uint16_t pc9801_state::egc_blit_r(uint32_t offset, uint16_t mem_mask)
}*/
m_egc.init = true;
for(int i = 0; i < 4; i++)
m_egc.src[i] = egc_shift(i, m_video_ram_2[plane_off + (((i + 1) & 3) * 0x4000)]);
m_egc.src[i] = egc_shift(i, m_video_ram[1][plane_off + (((i + 1) & 3) * 0x4000)]);
if(BIT(m_egc.regs[2], 13))
{
uint16_t ret;
// docs say vram is compared to the foreground color register but 4a2 13-14 must be 2
// guess that the other values probably work too
ret = ~(egc_color_pat(0) ^ m_video_ram_2[plane_off + 0x4000]);
ret &= ~(egc_color_pat(1) ^ m_video_ram_2[plane_off + (0x4000 * 2)]);
ret &= ~(egc_color_pat(2) ^ m_video_ram_2[plane_off + (0x4000 * 3)]);
ret &= ~(egc_color_pat(3) ^ m_video_ram_2[plane_off]);
ret = ~(egc_color_pat(0) ^ m_video_ram[1][plane_off + 0x4000]);
ret &= ~(egc_color_pat(1) ^ m_video_ram[1][plane_off + (0x4000 * 2)]);
ret &= ~(egc_color_pat(2) ^ m_video_ram[1][plane_off + (0x4000 * 3)]);
ret &= ~(egc_color_pat(3) ^ m_video_ram[1][plane_off]);
return ret;
}
else