msx/msx_s1990.cpp, msx/msxtr.cpp: Added preliminary MSX-Engine S1990 device and started implementing MSX turbo R. (#12753)

Moved fsa1st and fsa1gt (Panasonic FSA-1 systems) to the new msx/msxtr.cpp source file.
This commit is contained in:
wilbertpol 2024-09-15 17:36:42 +01:00 committed by GitHub
parent f26d792959
commit 233a5e8279
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 919 additions and 98 deletions

View File

@ -0,0 +1,91 @@
<?xml version="1.0"?>
<!--
license:CC0-1.0
-->
<mamelayout version="2">
<element name="green_led">
<rect state="0">
<color red="0.2" green="0.2" blue="0.2" />
</rect>
<rect state="1">
<color red="0.0" green="1.0" blue="0.0" />
</rect>
</element>
<element name="orange_led">
<rect state="0">
<color red="0.2" green="0.2" blue="0.2" />
</rect>
<rect state="1">
<color red="1.0" green="0.6" blue="0.0" />
</rect>
</element>
<element name="caps_name">
<text string="Caps" align="1">
<color red="1.0" green="1.0" blue="1.0" />
</text>
</element>
<element name="code_name">
<text string="かな" align="1">
<color red="1.0" green="1.0" blue="1.0" />
</text>
</element>
<element name="pause_name">
<text string="Pause" align="1">
<color red="1.0" green="1.0" blue="1.0" />
</text>
</element>
<element name="r800_name">
<text string="高速モード" align="1">
<color red="1.0" green="1.0" blue="1.0" />
</text>
</element>
<element name="drv0">
<text string="Drive A" align="1">
<color red="1.0" green="1.0" blue="1.0" />
</text>
</element>
<element name="not_present" />
<view name="System LEDs">
<screen index="0">
<bounds x="75" y="0" width="1024" height="768" />
</screen>
<element name="caps_led_name" ref="caps_name">
<bounds left="0" right="74" top="0" bottom="30" />
</element>
<element name="caps_led" ref="green_led">
<bounds left="0" right="20" top="31" bottom="39" />
</element>
<element name="code_led_name" ref="code_name">
<bounds left="0" right="74" top="40" bottom="70" />
</element>
<element name="code_led" ref="green_led">
<bounds left="0" right="20" top="71" bottom="79" />
</element>
<element name="pause_led_name" ref="pause_name">
<bounds left="0" right="74" top="80" bottom="110" />
</element>
<element name="pause_led" ref="green_led">
<bounds left="0" right="20" top="111" bottom="119" />
</element>
<element name="r800_led_name" ref="r800_name">
<bounds left="0" right="74" top="120" bottom="150" />
</element>
<element name="r800_led" ref="green_led">
<bounds left="0" right="20" top="151" bottom="159" />
</element>
<element name="internal_drive0_name" ref="drv0">
<bounds left="0" right="74" top="160" bottom="190" />
</element>
<element name="internal_drive0_led" ref="orange_led">
<bounds left="0" right="20" top="191" bottom="199" />
</element>
<element name="internal_drive1_name" ref="not_present">
<bounds left="0" right="74" top="200" bottom="230" />
</element>
<element name="internal_drive1_led" ref="not_present">
<bounds left="0" right="20" top="231" bottom="239" />
</element>
</view>
</mamelayout>

View File

@ -32760,8 +32760,6 @@ expert3t //
expertac //
expertdx //
fsa1fx // 1988 MSX2+ Japan
fsa1gt //
fsa1st //
fsa1wsx // 1989 MSX2+ Japan
fsa1wx // 1988 MSX2+ Japan
fsa1wxa // 1988 MSX2+ Japan
@ -32771,6 +32769,10 @@ phc35j // 1989 MSX2+ Japan
phc70fd // 1988 MSX2+ Japan
phc70fd2 // 1988 MSX2+ Japan
@source:msx/msxtr.cpp
fsa1gt //
fsa1st //
@source:msx/pengadvb.cpp
pengadvb // (c) 1988 Screen
pengadvb2 // (c) 1988 Comet

View File

@ -53,9 +53,6 @@ public:
void phc35j(machine_config &config);
void hbf1xdj(machine_config &config);
void hbf1xv(machine_config &config);
void fsa1gt(machine_config &config);
void fsa1st(machine_config &config);
};
/******************************** MSX 2+ **********************************/
@ -638,94 +635,6 @@ void msx2p_state::hbf1xv(machine_config &config)
msx2plus(SND_YM2149, config, layout_msx_jp_1fdd);
}
/* MSX Turbo-R - Panasonic FS-A1GT */
ROM_START(fsa1gt)
ROM_REGION(0x46c000, "maincpu", 0)
ROM_LOAD("a1gtbios.rom", 0x0000, 0x8000, CRC(937c8dbb) SHA1(242e73d8284a012b275c0a266844ebbc4269d787))
ROM_LOAD("a1gtext.rom", 0x8000, 0x4000, CRC(70aea0fe) SHA1(018d7a5222f28514908fb1b1513286a6558a6d05))
ROM_LOAD("a1gtdos.rom", 0xc000, 0x10000, CRC(bb2a0eae) SHA1(4880bf34f1c86fff5456ec2b4cf70d02339e2caa))
ROM_LOAD("a1gtkdr.rom", 0x1c000, 0x8000, CRC(eaf0d125) SHA1(5b39c1ccd3a213b78e02927f56a9abc72cd8c28d))
ROM_LOAD("a1gtmus.rom", 0x24000, 0x4000, CRC(f5f93437) SHA1(6aea1aef5ec31c1826c22edf580525f93baad425))
ROM_LOAD("a1gtopt.rom", 0x28000, 0x4000, CRC(50d11f60) SHA1(b4433a3975c57dd440d6bf12dbd28b2ac1b90ef4))
ROM_LOAD("a1gtkfn.rom", 0x2c000, 0x40000, CRC(1f6406fb) SHA1(5aff2d9b6efc723bc395b0f96f0adfa83cc54a49))
ROM_LOAD("a1gtfirm.rom", 0x6c000, 0x400000, CRC(feefeadc) SHA1(e779c338eb91a7dea3ff75f3fde76b8af22c4a3a))
ROM_END
void msx2p_state::fsa1gt(machine_config &config)
{
// AY8910 (in T9769)
// FDC: tc8566af, 1 3.5" DSDD drive
// 2 Cartridge slots
// T9769C + S1990
// FM built-in
// Microphone
// MIDI-in
// MIDI-out
// firmware switch
// pause button
// ren-sha turbo slider
add_internal_slot(config, MSX_SLOT_ROM, "bios", 0, 0, 0, 2, "maincpu");
add_internal_slot(config, MSX_SLOT_MUSIC, "mus", 0, 2, 1, 1, "maincpu", 0x24000).set_ym2413_tag(m_ym2413);
add_internal_slot(config, MSX_SLOT_ROM, "opt", 0, 3, 1, 1, "maincpu", 0x28000);
add_cartridge_slot<1>(config, 1);
add_cartridge_slot<2>(config, 2);
add_internal_slot(config, MSX_SLOT_RAM_MM, "ram_mm", 3, 0, 0, 4).set_total_size(0x20000); // 128KB?? Mapper RAM
add_internal_slot(config, MSX_SLOT_ROM, "ext", 3, 1, 0, 1, "maincpu", 0x8000);
add_internal_slot(config, MSX_SLOT_ROM, "kdr", 3, 1, 1, 2, "maincpu", 0x1c000);
add_internal_disk(config, MSX_SLOT_DISK4_TC8566, "dos", 3, 2, 1, 3, "maincpu", 0xc000);
add_internal_slot(config, MSX_SLOT_ROM, "firm", 3, 3, 0, 4, "maincpu", 0x6c000);
MSX_SYSTEMFLAGS(config, "sysflags", m_maincpu, 0x00);
msx_ym2413(config);
turbor(SND_AY8910, config, layout_msx_jp_1fdd);
}
/* MSX Turbo-R - Panasonic FS-A1ST */
ROM_START(fsa1st)
ROM_REGION(0x46c000, "maincpu", 0)
ROM_LOAD("a1stbios.rom", 0x0000, 0x8000, CRC(77b94ae0) SHA1(f078b5ec56884bfb81481d45c7151418770bff5a))
ROM_LOAD("a1stext.rom", 0x8000, 0x4000, CRC(2c2c77a4) SHA1(373412f9c32762de1c3a7e27fc3d80614e0a0c8e))
ROM_LOAD("a1stdos.rom", 0xc000, 0x10000, CRC(1fc71407) SHA1(5d2186658adcf4ce0c2d3232384b5712341108e5))
ROM_LOAD("a1stkdr.rom", 0x1c000, 0x8000, CRC(eaf0d125) SHA1(5b39c1ccd3a213b78e02927f56a9abc72cd8c28d))
ROM_LOAD("a1stmus.rom", 0x24000, 0x4000, CRC(fd7dec41) SHA1(e002a9b426732e6c2d31e548c40cf7c122348ce3))
ROM_LOAD("a1stopt.rom", 0x28000, 0x4000, CRC(c6a4a2a1) SHA1(cb06dea7b025745f9d2b87dcf03ded615287ead3))
ROM_LOAD("a1stkfn.rom", 0x2c000, 0x40000, CRC(1f6406fb) SHA1(5aff2d9b6efc723bc395b0f96f0adfa83cc54a49))
ROM_LOAD("a1stfirm.rom", 0x6c000, 0x400000, CRC(139ac99c) SHA1(c212b11fda13f83dafed688c54d098e7e47ab225))
ROM_END
void msx2p_state::fsa1st(machine_config &config)
{
// AY8910 (in T9769)
// FDC: tc8566af, 1 3.5" DSDD drive
// T9769C + S1990
// 2 Cartridge slots
// FM built-in
// microphone
// firmware switch
// pause button
// ren-sha turbo slider
add_internal_slot(config, MSX_SLOT_ROM, "bios", 0, 0, 0, 2, "maincpu");
add_internal_slot(config, MSX_SLOT_MUSIC, "mus", 0, 2, 1, 1, "maincpu", 0x24000).set_ym2413_tag(m_ym2413);
add_internal_slot(config, MSX_SLOT_ROM, "opt", 0, 3, 1, 1, "maincpu", 0x28000);
add_cartridge_slot<1>(config, 1);
add_cartridge_slot<2>(config, 2);
add_internal_slot(config, MSX_SLOT_RAM_MM, "ram_mm", 3, 0, 0, 4).set_total_size(0x20000); // 128KB?? Mapper RAM
add_internal_slot(config, MSX_SLOT_ROM, "ext", 3, 1, 0, 1, "maincpu", 0x8000);
add_internal_slot(config, MSX_SLOT_ROM, "kdr", 3, 1, 1, 2, "maincpu", 0x1c000);
add_internal_disk(config, MSX_SLOT_DISK4_TC8566, "dos", 3, 2, 1, 3, "maincpu", 0xc000);
add_internal_slot(config, MSX_SLOT_ROM, "firm", 3, 3, 0, 4, "maincpu", 0x6c000);
MSX_SYSTEMFLAGS(config, "sysflags", m_maincpu, 0x00);
msx_ym2413(config);
turbor(SND_AY8910, config, layout_msx_jp_1fdd);
}
} // anonymous namespace
COMP(19??, expert3i, 0, 0, expert3i, msx2, msx2p_state, empty_init, "Ciel", "Expert 3 IDE (MSX2+, Brazil)", MACHINE_NOT_WORKING) // Some hardware not emulated
@ -741,8 +650,3 @@ COMP(1989, phc70fd2, 0, 0, phc70fd2, msx2jp, msx2p_state, empty
COMP(1989, phc35j, 0, 0, phc35j, msx2jp, msx2p_state, empty_init, "Sanyo", "PHC-35J / Wavy35 (MSX2+, Japan)", 0)
COMP(1988, hbf1xdj, 0, 0, hbf1xdj, msx2jp, msx2p_state, empty_init, "Sony", "HB-F1XDJ (MSX2+, Japan)", 0)
COMP(1989, hbf1xv, 0, 0, hbf1xv, msx2jp, msx2p_state, empty_init, "Sony", "HB-F1XV (MSX2+, Japan)", 0)
/* MSX Turbo-R */
/* Temporary placeholders, Turbo-R hardware is not supported yet */
COMP(1991, fsa1gt, 0, 0, fsa1gt, msx2jp, msx2p_state, empty_init, "Panasonic", "FS-A1GT (MSX Turbo-R, Japan)", MACHINE_NOT_WORKING)
COMP(1991, fsa1st, 0, 0, fsa1st, msx2jp, msx2p_state, empty_init, "Panasonic", "FS-A1ST (MSX Turbo-R, Japan)", MACHINE_NOT_WORKING)

268
src/mame/msx/msx_s1990.cpp Normal file
View File

@ -0,0 +1,268 @@
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
#include "emu.h"
#include "msx_s1990.h"
#define LOG_CPU (1U << 1)
#define LOG_PCM (1U << 2)
//#define VERBOSE (LOG_CPU | LOG_PCM)
#include "logmacro.h"
/***************************************************************************
ASCII S1990 MSX-Engine
TODO:
- Injection of wait states when accessing VDP when Z80 is active.
- Injection of wait states when accessing VDP when R800 is active.
- Injection of wait state to align 7MHz R800 bus with 3.5MHz MSX bus.
- Unknown what the other internal registers do
Internal registers:
- 0x00
- 0x01
- 0x02
- 0x03
- 0x04
- 0x05 - Read only?
Read
7------- Unknown
-6------ 1 - Firmware enabled
--543210 Unknown
- 0x06 - R/W - CPU Control
Write
76------ Unknown
--5----- 0 - R800 active, 1 - Z80 active
---43210 Unknown
- 0x07
- 0x08
- 0x09
- 0x0a
- 0x0b
- 0x0c
- 0x0d
- 0x0e - Byte before last byte written - read only?
- 0x0f - Last byte written - read only?
***************************************************************************/
DEFINE_DEVICE_TYPE(MSX_S1990, msx_s1990_device, "msx_s1990", "MSX-Engine S1990")
msx_s1990_device::msx_s1990_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, MSX_S1990, tag, owner, clock)
, device_memory_interface(mconfig, *this)
, m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0)
, m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0)
, m_firmware_switch_cb(*this, 0)
, m_pause_led_cb(*this)
, m_r800_led_cb(*this)
, m_dac_write_cb(*this)
, m_sample_hold_cb(*this)
, m_select_cb(*this)
, m_filter_cb(*this)
, m_muting_cb(*this)
, m_comp_cb(*this, 0)
, m_z80(*this, finder_base::DUMMY_TAG)
, m_r800(*this, finder_base::DUMMY_TAG)
, m_reg_index(0)
, m_last_counter_reset(attotime::zero)
, m_last_pcm_write_ticks(0)
, m_pcm_control(0)
, m_pcm_data(0x80)
, m_dac_timer(nullptr)
, m_z80_halt_enabled(false)
{
}
device_memory_interface::space_config_vector msx_s1990_device::memory_space_config() const
{
return space_config_vector {
std::make_pair(AS_PROGRAM, &m_program_config),
std::make_pair(AS_IO, &m_io_config)
};
}
void msx_s1990_device::device_start()
{
space(AS_PROGRAM).specific(m_data);
space(AS_IO).specific(m_io);
save_item(NAME(m_regs));
save_item(NAME(m_reg_index));
save_item(NAME(m_last_counter_reset));
save_item(NAME(m_last_pcm_write_ticks));
save_item(NAME(m_pcm_control));
save_item(NAME(m_pcm_data));
m_dac_timer = timer_alloc(FUNC(msx_s1990_device::dac_write), this);
}
void msx_s1990_device::device_reset()
{
m_regs[6] = 0x20; // Z80 active
m_last_counter_reset = attotime::zero;
m_last_pcm_write_ticks = 0;
m_z80->resume(SUSPEND_REASON_HALT);
m_r800->suspend(SUSPEND_REASON_HALT, true);
}
INPUT_CHANGED_MEMBER(msx_s1990_device::pause_callback)
{
if (m_z80_halt_enabled && BIT(m_regs[0x06], 5))
m_z80->set_input_line(Z80_INPUT_LINE_WAIT, BIT(newval, 0) ? ASSERT_LINE : CLEAR_LINE);
}
void msx_s1990_device::pause_w(u8 data)
{
m_pause_led_cb(BIT(data, 0));
m_z80_halt_enabled = BIT(data, 1);
m_r800_led_cb(BIT(data, 7));
}
void msx_s1990_device::reg_index_write(u8 data)
{
m_reg_index = data;
}
u8 msx_s1990_device::regs_read()
{
if ((m_reg_index & 0x0f) == 0x05)
return (m_firmware_switch_cb()) ? 0x40 : 0x00;
return m_regs[m_reg_index & 0x0f];
}
void msx_s1990_device::regs_write(u8 data)
{
if ((m_reg_index & 0x0f) == 0x06)
{
if (BIT(data, 5))
{
LOGMASKED(LOG_CPU, "Enable Z80, disable R800\n");
m_z80->resume(SUSPEND_REASON_HALT);
m_r800->suspend(SUSPEND_REASON_HALT, true);
}
else
{
LOGMASKED(LOG_CPU, "Disable Z80, enable R800\n");
m_z80->suspend(SUSPEND_REASON_HALT, true);
m_r800->resume(SUSPEND_REASON_HALT);
}
}
m_regs[m_reg_index & 0x0f] = data;
}
void msx_s1990_device::mem_write(offs_t offset, u8 data)
{
// TODO Clock syncing when in R800 mode
m_regs[0x0e] = m_regs[0x0f];
m_regs[0x0f] = data;
m_data.write_byte(offset, data);
}
u8 msx_s1990_device::mem_read(offs_t offset)
{
// TODO Clock syncing when in R800 mode
return m_data.read_byte(offset);
}
void msx_s1990_device::io_write(offs_t offset, u8 data)
{
// TODO Clock syncing/extra wait cycles
// TODO Injection of wait states when accessing VDP
m_io.write_byte(offset, data);
}
u8 msx_s1990_device::io_read(offs_t offset)
{
// TODO Clock syncing/extra wait cycles
return m_io.read_byte(offset);
}
void msx_s1990_device::counter_write(u8 data)
{
// TODO: Round to last counter tick?
m_last_counter_reset = machine().time();
}
u8 msx_s1990_device::counter_read(offs_t offset)
{
u64 counter = attotime_to_clocks(machine().time() - m_last_counter_reset) / 28;
return (counter >> (8 * BIT(offset, 0))) & 0xff;
}
TIMER_CALLBACK_MEMBER(msx_s1990_device::dac_write)
{
m_dac_write_cb(m_pcm_data);
}
void msx_s1990_device::pmdac(u8 data)
{
m_pcm_data = data;
if (!BIT(m_pcm_control, 1))
{
// Round to last counter tick and schedule next dac write?
m_last_pcm_write_ticks = machine().time().as_ticks(PCM_FREQUENCY);
m_dac_timer->adjust(attotime::from_ticks(m_last_pcm_write_ticks + 1, PCM_FREQUENCY));
}
}
u8 msx_s1990_device::pmcnt()
{
return (machine().time().as_ticks(PCM_FREQUENCY) - m_last_pcm_write_ticks) & 0x03;
}
void msx_s1990_device::pmcntl(u8 data)
{
// 7------- 0
// -6------ 0
// --5----- 0
// ---4---- SMPL
// ----3--- SEL
// -----2-- FILT
// ------1- MUTE
// -------0 ADDA ??
LOGMASKED(LOG_PCM, "pmcntl: %02x\n", data);
m_pcm_control = data & 0x1f;
m_sample_hold_cb(BIT(m_pcm_control, 4));
m_select_cb(BIT(m_pcm_control, 3));
m_filter_cb(BIT(m_pcm_control, 2));
m_muting_cb(BIT(m_pcm_control, 1));
}
u8 msx_s1990_device::pmstat()
{
// 7------- COMP
// -6------ 0
// --5----- 0
// ---4---- SMPL
// ----3--- SEL
// -----2-- FILT
// ------1- MUTE
// -------0 BUFF ??
return (m_pcm_control & 0x1f) | (m_comp_cb() ? 0x80 : 0x00);
}

93
src/mame/msx/msx_s1990.h Normal file
View File

@ -0,0 +1,93 @@
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
#ifndef MAME_MSX_MSX_S1990_H
#define MAME_MSX_MSX_S1990_H
#pragma once
#include "cpu/z80/r800.h"
#include "cpu/z80/z80.h"
DECLARE_DEVICE_TYPE(MSX_S1990, msx_s1990_device)
class msx_s1990_device : public device_t,
public device_memory_interface
{
public:
msx_s1990_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
static constexpr feature_type imperfect_features() { return feature::TIMING; }
// configuration
template <typename T> void set_z80_tag(T &&tag) { m_z80.set_tag(std::forward<T>(tag)); }
template <typename T> void set_r800_tag(T &&tag) { m_r800.set_tag(std::forward<T>(tag)); }
auto firmware_switch_callback() { return m_firmware_switch_cb.bind(); }
auto pause_led_callback() { return m_pause_led_cb.bind(); }
auto r800_led_callback() { return m_r800_led_cb.bind(); }
auto dac_write_callback() { return m_dac_write_cb.bind(); }
auto sample_hold_callback() { return m_sample_hold_cb.bind(); }
auto select_callback() { return m_select_cb.bind(); }
auto filter_callback() { return m_filter_cb.bind(); }
auto muting_callback() { return m_muting_cb.bind(); }
auto comp_callback() { return m_comp_cb.bind(); }
void pause_w(u8 data);
void reg_index_write(u8 data);
u8 regs_read();
void regs_write(u8 data);
void mem_write(offs_t offset, u8 data);
u8 mem_read(offs_t offset);
void io_write(offs_t offset, u8 data);
u8 io_read(offs_t offset);
void counter_write(u8 data);
u8 counter_read(offs_t offset);
void pmdac(u8 data);
u8 pmcnt();
void pmcntl(u8 data);
u8 pmstat();
DECLARE_INPUT_CHANGED_MEMBER(pause_callback);
protected:
virtual void device_start() override;
virtual void device_reset() override;
// device_memory_interface implementation
virtual space_config_vector memory_space_config() const override;
virtual u32 translate_memory_address(u16 address) { return address; }
private:
TIMER_CALLBACK_MEMBER(dac_write);
static constexpr u32 PCM_FREQUENCY = 15750;
const address_space_config m_program_config;
const address_space_config m_io_config;
memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_data;
memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_io;
devcb_read_line m_firmware_switch_cb;
devcb_write_line m_pause_led_cb;
devcb_write_line m_r800_led_cb;
devcb_write8 m_dac_write_cb;
devcb_write_line m_sample_hold_cb;
devcb_write_line m_select_cb;
devcb_write_line m_filter_cb;
devcb_write_line m_muting_cb;
devcb_read_line m_comp_cb;
required_device<z80_device> m_z80;
required_device<r800_device> m_r800;
u8 m_regs[16];
u8 m_reg_index;
attotime m_last_counter_reset;
u64 m_last_pcm_write_ticks;
u8 m_pcm_control;
u8 m_pcm_data;
emu_timer *m_dac_timer;
bool m_z80_halt_enabled;
};
#endif // MAME_MSX_MSX_S1990_H

463
src/mame/msx/msxtr.cpp Normal file
View File

@ -0,0 +1,463 @@
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
#include "emu.h"
#include "msx.h"
#include "msx_keyboard.h"
#include "msx_s1990.h"
#include "msx_systemflags.h"
#include "bus/midi/midi.h"
#include "bus/msx/slot/disk.h"
#include "bus/msx/slot/music.h"
#include "bus/msx/slot/panasonic08r.h"
#include "bus/msx/slot/ram_mm.h"
#include "bus/msx/slot/rom.h"
#include "machine/i8251.h"
#include "machine/pit8253.h"
#include "softlist_dev.h"
#include "msx_turbor.lh"
using namespace msx_keyboard;
/***************************************************************************
MSX Turbo-R machine drivers
The R800 and Z80 see exactly the same memory layouts, only one of the two CPUs
is active at any one time. The S1990 controls which CPU is active and can inject
wait states depending on which cpu is active.
TODO:
- sfg extensions may not work due to irq callbacks being registered with the Z80 only.
- v9958 commands seem to execute too fast. Several software items hang because of this.
- verify midi interface operation on fsa1gt.
- Implement DAC/PCM related hardware/filter and hook it up to the S1990.
- Microphone input.
***************************************************************************/
namespace {
class msxtr_state : public msx2p_base_state
{
public:
msxtr_state(const machine_config &mconfig, device_type type, const char *tag)
: msx2p_base_state(mconfig, type, tag, 21.477272_MHz_XTAL, 6)
, m_r800(*this, "r800")
, m_s1990(*this, "s1990")
, m_pause_switch(*this, "PAUSE")
, m_firmware_switch(*this, "FIRMWARE")
, m_pause_led(*this, "pause_led")
, m_r800_led(*this, "r800_led")
, m_pcmdac(*this, "pcmdac")
{
}
void fsa1st(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
void turbor(ay8910_type ay8910_type, machine_config &config, const internal_layout &layout);
void turbor_add_softlists(machine_config &config);
void s1990_mem_map(address_map &map);
void s1990_io_map(address_map &map);
void cpu_mem_map(address_map &map);
void cpu_io_map(address_map &map);
virtual void setup_slot_spaces(msx_internal_slot_interface &device) override;
virtual address_space& get_io_space() override;
void pause_led_w(int state);
void r800_led_w(int state);
void pcm_dac_w(u8 data);
void pcm_sample_hold_w(int state);
void pcm_select_w(int state);
void pcm_filter_w(int state);
void muting_w(int state);
int pcm_comp_r();
required_device<r800_device> m_r800;
required_device<msx_s1990_device> m_s1990;
required_ioport m_pause_switch;
required_ioport m_firmware_switch;
output_finder<> m_pause_led;
output_finder<> m_r800_led;
required_device<dac_8bit_r2r_device> m_pcmdac;
u8 m_pcm_last_sample;
u8 m_pcm_held_sample;
u8 m_pcm_sample_hold;
};
class fsa1gt_state : public msxtr_state
{
public:
fsa1gt_state(const machine_config &mconfig, device_type type, const char *tag)
: msxtr_state(mconfig, type, tag)
, m_i8251(*this, "i8251")
, m_i8254(*this, "i8254")
, m_midiin(*this, "midiin_port")
, m_midiout(*this, "midiout_port")
, m_dtr(false)
, m_rts(false)
, m_rxrdy(false)
, m_timer2_ff(false)
{
}
void fsa1gt(machine_config &config);
private:
required_device<i8251_device> m_i8251;
required_device<pit8254_device> m_i8254;
required_device<midi_port_device> m_midiin;
required_device<midi_port_device> m_midiout;
bool m_dtr;
bool m_rts;
bool m_rxrdy;
bool m_timer2_ff;
void s1990_io_map(address_map &map);
void dtr_w(int state);
void rts_w(int state);
void rxrdy_w(int state);
void timer0_w(int state);
void timer2_w(int state);
void update_midi_int_state();
void clear_timer2_ff(u8 data);
};
address_space& msxtr_state::get_io_space()
{
return m_s1990->space(AS_IO);
}
void msxtr_state::setup_slot_spaces(msx_internal_slot_interface &device)
{
device.set_memory_space(m_s1990, AS_PROGRAM);
device.set_io_space(m_s1990, AS_IO);
// TODO: This is used for signalling irq vectors. But that should go to the currently active cpu not just the z80.
device.set_maincpu(m_maincpu);
}
void msxtr_state::machine_start()
{
msx2p_base_state::machine_start();
m_pause_led.resolve();
m_r800_led.resolve();
save_item(NAME(m_pcm_last_sample));
save_item(NAME(m_pcm_held_sample));
save_item(NAME(m_pcm_sample_hold));
}
void msxtr_state::machine_reset()
{
msx2p_base_state::machine_reset();
m_pause_led = 0;
m_r800_led = 0;
}
void msxtr_state::s1990_mem_map(address_map &map)
{
memory_map(map);
}
void msxtr_state::s1990_io_map(address_map &map)
{
msx2plus_io_map(map);
map(0xa4, 0xa4).rw(m_s1990, FUNC(msx_s1990_device::pmcnt), FUNC(msx_s1990_device::pmdac));
map(0xa5, 0xa5).rw(m_s1990, FUNC(msx_s1990_device::pmstat), FUNC(msx_s1990_device::pmcntl));
map(0xa7, 0xa7).portr(m_pause_switch.finder_tag());
map(0xa7, 0xa7).w(m_s1990, FUNC(msx_s1990_device::pause_w));
map(0xe4, 0xe4).w(m_s1990, FUNC(msx_s1990_device::reg_index_write));
map(0xe5, 0xe5).rw(m_s1990, FUNC(msx_s1990_device::regs_read), FUNC(msx_s1990_device::regs_write));
map(0xe6, 0xe6).w(m_s1990, FUNC(msx_s1990_device::counter_write));
map(0xe6, 0xe7).r(m_s1990, FUNC(msx_s1990_device::counter_read));
}
void msxtr_state::cpu_mem_map(address_map &map)
{
map(0x0000, 0xffff).rw(m_s1990, FUNC(msx_s1990_device::mem_read), FUNC(msx_s1990_device::mem_write));
}
void msxtr_state::cpu_io_map(address_map &map)
{
map.global_mask(0xff);
map(0x00, 0xff).rw(m_s1990, FUNC(msx_s1990_device::io_read), FUNC(msx_s1990_device::io_write));
}
void msxtr_state::pause_led_w(int state)
{
m_pause_led = state;
}
void msxtr_state::r800_led_w(int state)
{
m_r800_led = state;
}
void msxtr_state::turbor(ay8910_type ay8910_type, machine_config &config, const internal_layout &layout)
{
msx2plus_base(ay8910_type, config, layout);
m_maincpu->set_addrmap(AS_PROGRAM, &msxtr_state::cpu_mem_map);
m_maincpu->set_addrmap(AS_IO, &msxtr_state::cpu_io_map);
R800(config, m_r800, 28.636363_MHz_XTAL);
m_r800->set_addrmap(AS_PROGRAM, &msxtr_state::cpu_mem_map);
m_r800->set_addrmap(AS_IO, &msxtr_state::cpu_io_map);
MSX_S1990(config, m_s1990, 28.636363_MHz_XTAL / 4);
m_s1990->set_addrmap(AS_PROGRAM, &msxtr_state::s1990_mem_map);
m_s1990->set_addrmap(AS_IO, &msxtr_state::s1990_io_map);
m_s1990->set_z80_tag(m_maincpu);
m_s1990->set_r800_tag(m_r800);
m_s1990->pause_led_callback().set(FUNC(msxtr_state::pause_led_w));
m_s1990->r800_led_callback().set(FUNC(msxtr_state::r800_led_w));
m_s1990->firmware_switch_callback().set_ioport(m_firmware_switch);
m_s1990->dac_write_callback().set(FUNC(msxtr_state::pcm_dac_w));
m_s1990->sample_hold_callback().set(FUNC(msxtr_state::pcm_sample_hold_w));
m_s1990->select_callback().set(FUNC(msxtr_state::pcm_select_w));
m_s1990->filter_callback().set(FUNC(msxtr_state::pcm_filter_w));
m_s1990->muting_callback().set(FUNC(msxtr_state::muting_w));
m_s1990->comp_callback().set(FUNC(msxtr_state::pcm_comp_r));
// TODO: Do IRQ requests go to both cpus (only to be ignored by the inactive cpu) or only to the currently active cpu?
m_mainirq->output_handler().append_inputline(m_r800, INPUT_LINE_IRQ0);
DAC_8BIT_R2R(config, m_pcmdac).add_route(ALL_OUTPUTS, m_speaker, 1.0); // Unknown DAC type
// Software lists
turbor_add_softlists(config);
}
void msxtr_state::pcm_dac_w(u8 data)
{
m_pcmdac->write(data);
m_pcm_last_sample = data;
}
void msxtr_state::pcm_sample_hold_w(int state)
{
if (!m_pcm_sample_hold && state)
m_pcm_held_sample = m_pcm_last_sample;
m_pcm_sample_hold = state;
}
void msxtr_state::pcm_select_w(int state)
{
// TODO pcm select
}
void msxtr_state::pcm_filter_w(int state)
{
// TODO enable pcm filter
}
int msxtr_state::pcm_comp_r()
{
// TODO pcm output compare
return 0;
}
void msxtr_state::muting_w(int state)
{
// TODO mute all sound
}
void msxtr_state::turbor_add_softlists(machine_config &config)
{
if (m_hw_def.has_cartslot())
{
SOFTWARE_LIST(config, "cart_list").set_original("msxr_cart");
SOFTWARE_LIST(config, "msx2p_cart_list").set_compatible("msx2p_cart");
SOFTWARE_LIST(config, "msx2_cart_list").set_compatible("msx2_cart");
SOFTWARE_LIST(config, "msx1_cart_list").set_compatible("msx1_cart");
}
if (m_hw_def.has_fdc())
{
SOFTWARE_LIST(config, "flop_list").set_original("msxr_flop");
SOFTWARE_LIST(config, "msx2p_flop_list").set_compatible("msx2p_flop");
SOFTWARE_LIST(config, "msx2_flop_list").set_compatible("msx2_flop");
SOFTWARE_LIST(config, "msx1_flop_list").set_compatible("msx1_flop");
}
}
/* MSX Turbo-R - Panasonic FS-A1GT */
ROM_START(fsa1gt)
ROM_REGION(0x400000, "firmware", 0)
// This should be 2 1MB roms at locations IC20 and IC23.
ROM_LOAD("a1gtfirm.rom", 0, 0x400000, CRC(feefeadc) SHA1(e779c338eb91a7dea3ff75f3fde76b8af22c4a3a) BAD_DUMP)
ROM_REGION(0x40000, "kanji", 0)
ROM_LOAD("a1gtkfn.rom", 0, 0x40000, CRC(1f6406fb) SHA1(5aff2d9b6efc723bc395b0f96f0adfa83cc54a49))
ROM_END
void fsa1gt_state::s1990_io_map(address_map &map)
{
msxtr_state::s1990_io_map(map);
map(0xe8, 0xe9).rw(m_i8251, FUNC(i8251_device::read), FUNC(i8251_device::write));
map(0xea, 0xea).w(FUNC(fsa1gt_state::clear_timer2_ff));
map(0xec, 0xef).rw(m_i8254, FUNC(pit8254_device::read), FUNC(pit8254_device::write));
}
void fsa1gt_state::fsa1gt(machine_config &config)
{
// AY8910 (in T9769)
// FDC: tc8566af, 1 3.5" DSDD drive
// 2 Cartridge slots
// T9769C + S1990
// FM built-in
// Microphone
// MIDI-in
// MIDI-out
// firmware switch
// pause button
// ren-sha turbo slider
add_internal_slot(config, MSX_SLOT_ROM, "bios", 0, 0, 0, 2, "firmware", 0x050000);
add_internal_slot(config, MSX_SLOT_MUSIC, "msxmusic", 0, 2, 1, 1, "firmware", 0x07c000).set_ym2413_tag(m_ym2413);
add_internal_slot(config, MSX_SLOT_ROM, "opt", 0, 3, 1, 1, "firmware", 0x048000);
add_cartridge_slot<1>(config, 1);
add_cartridge_slot<2>(config, 2);
add_internal_slot(config, MSX_SLOT_RAM_MM, "ram_mm", 3, 0, 0, 4).set_total_size(0x80000); // 512KB Mapper RAM
add_internal_slot(config, MSX_SLOT_ROM, "ext", 3, 1, 0, 1, "firmware", 0x070000);
add_internal_slot(config, MSX_SLOT_ROM, "kdr", 3, 1, 1, 2, "firmware", 0x074000);
add_internal_disk(config, MSX_SLOT_DISK4_TC8566, "dos", 3, 2, 1, 3, "firmware", 0x060000);
add_internal_slot(config, MSX_SLOT_PANASONIC08R, "firmware", 3, 3, 0, 4, "firmware").set_sram_size(0x8000).set_mm_tag("ram_mm");
MSX_SYSTEMFLAGS(config, "sysflags", m_maincpu, 0x00);
msx_ym2413(config);
m_hw_def.has_cassette(false);
turbor(SND_AY8910, config, layout_msx_turbor);
m_s1990->set_addrmap(AS_IO, &fsa1gt_state::s1990_io_map);
I8251(config, m_i8251, 16_MHz_XTAL / 4); // Not sure about this
m_i8251->txd_handler().set(m_midiout, FUNC(midi_port_device::write_txd));
m_i8251->dtr_handler().set(*this, FUNC(fsa1gt_state::dtr_w));
m_i8251->rts_handler().set(*this, FUNC(fsa1gt_state::rts_w));
m_i8251->rxrdy_handler().set(*this, FUNC(fsa1gt_state::rxrdy_w));
PIT8254(config, m_i8254);
m_i8254->set_clk<0>(16_MHz_XTAL / 4);
m_i8254->set_clk<2>(16_MHz_XTAL/ 4);
m_i8254->out_handler<0>().set(*this, FUNC(fsa1gt_state::timer0_w));
m_i8254->out_handler<2>().set(*this, FUNC(fsa1gt_state::timer2_w));
MIDI_PORT(config, m_midiin, midiin_slot, "midiin").rxd_handler().set(m_i8251, FUNC(i8251_device::rx_w));
MIDI_PORT(config, m_midiout, midiout_slot, "midiout");
}
void fsa1gt_state::rts_w(int state)
{
m_rts = state;
update_midi_int_state();
}
void fsa1gt_state::rxrdy_w(int state)
{
m_rxrdy = state;
update_midi_int_state();
}
void fsa1gt_state::dtr_w(int state)
{
m_dtr = state;
update_midi_int_state();
}
void fsa1gt_state::timer0_w(int state)
{
m_i8251->tx_clock_w(state);
m_i8251->rx_clock_w(state);
}
void fsa1gt_state::timer2_w(int state)
{
m_timer2_ff = m_timer2_ff | state;
m_i8254->write_clk1(state);
update_midi_int_state();
}
void fsa1gt_state::clear_timer2_ff(u8 data)
{
m_timer2_ff = false;
update_midi_int_state();
}
void fsa1gt_state::update_midi_int_state()
{
m_i8251->write_dsr(m_timer2_ff && m_dtr);
m_mainirq->in_w<3>(!((m_timer2_ff && m_dtr) || (m_rts && m_rxrdy)));
}
/* MSX Turbo-R - Panasonic FS-A1ST */
ROM_START(fsa1st)
ROM_REGION(0x400000, "firmware", 0)
// This should be either 3 512KB roms or 1 1MB and 1 512KB rom (at IC12 and IC18?). Both variants are known to exist.
ROM_LOAD("a1stfirm.rom", 0, 0x400000, CRC(139ac99c) SHA1(c212b11fda13f83dafed688c54d098e7e47ab225) BAD_DUMP)
ROM_REGION(0x40000, "kanji", 0)
ROM_LOAD("a1stkfn.rom", 0, 0x40000, CRC(1f6406fb) SHA1(5aff2d9b6efc723bc395b0f96f0adfa83cc54a49))
ROM_END
void msxtr_state::fsa1st(machine_config &config)
{
// AY8910 (in T9769)
// FDC: tc8566af, 1 3.5" DSDD drive
// T9769C + S1990
// 2 Cartridge slots
// FM built-in
// microphone
// firmware switch
// pause button
// ren-sha turbo slider
add_internal_slot(config, MSX_SLOT_ROM, "bios", 0, 0, 0, 2, "firmware", 0x050000);
add_internal_slot(config, MSX_SLOT_MUSIC, "msxmusic", 0, 2, 1, 1, "firmware", 0x07c000).set_ym2413_tag(m_ym2413);
add_internal_slot(config, MSX_SLOT_ROM, "opt", 0, 3, 1, 1, "firmware", 0x048000);
add_cartridge_slot<1>(config, 1);
add_cartridge_slot<2>(config, 2);
add_internal_slot(config, MSX_SLOT_RAM_MM, "ram_mm", 3, 0, 0, 4).set_total_size(0x40000); // 256KB Mapper RAM
add_internal_slot(config, MSX_SLOT_ROM, "ext", 3, 1, 0, 1, "firmware", 0x070000);
add_internal_slot(config, MSX_SLOT_ROM, "kdr", 3, 1, 1, 2, "firmware", 0x074000);
add_internal_disk(config, MSX_SLOT_DISK4_TC8566, "dos", 3, 2, 1, 3, "firmware", 0x060000);
add_internal_slot(config, MSX_SLOT_PANASONIC08R, "firmware", 3, 3, 0, 4, "firmware").set_sram_size(0x4000).set_mm_tag("ram_mm");
MSX_SYSTEMFLAGS(config, "sysflags", m_maincpu, 0x00);
msx_ym2413(config);
m_hw_def.has_cassette(false);
turbor(SND_AY8910, config, layout_msx_turbor);
}
INPUT_PORTS_START(msxtr)
PORT_INCLUDE(msx2jp)
PORT_START("PAUSE")
PORT_CONFNAME(0x01, 0x00, "Pause") PORT_CHANGED_MEMBER("s1990", msx_s1990_device, pause_callback, 0)
PORT_CONFSETTING(0x00, "off")
PORT_CONFSETTING(0x01, "on")
PORT_START("FIRMWARE")
PORT_CONFNAME(0x01, 0x01, "Firmware")
PORT_CONFSETTING(0x01, "enabled")
PORT_CONFSETTING(0x00, "disabled")
INPUT_PORTS_END
} // anonymous namespace
/* MSX Turbo-R */
COMP(1991, fsa1gt, 0, 0, fsa1gt, msxtr, fsa1gt_state, empty_init, "Panasonic", "FS-A1GT (MSX Turbo-R, Japan)", MACHINE_NOT_WORKING)
COMP(1991, fsa1st, 0, 0, fsa1st, msxtr, msxtr_state, empty_init, "Panasonic", "FS-A1ST (MSX Turbo-R, Japan)", MACHINE_NOT_WORKING)