summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Dirk Best <mail@dirk-best.de>2017-11-20 01:37:08 +0100
committer Dirk Best <mail@dirk-best.de>2017-11-20 01:37:42 +0100
commita5a8e0cbdb29b256d08497ea122b40eff241d471 (patch)
tree89b82c8dc02c53cf929b0a58b0d4bf8a975fe47c
parent4a211c8443f71271f163b85d1db9606da5904898 (diff)
einstein: Improve interrupts, add WIP Speculator support
Also removes a bogus character in the initial centronics output.
-rw-r--r--scripts/src/bus.lua2
-rw-r--r--src/devices/bus/einstein/pipe/pipe.cpp15
-rw-r--r--src/devices/bus/einstein/pipe/pipe.h6
-rw-r--r--src/devices/bus/einstein/pipe/speculator.cpp206
-rw-r--r--src/devices/bus/einstein/pipe/speculator.h66
-rw-r--r--src/mame/drivers/einstein.cpp45
6 files changed, 336 insertions, 4 deletions
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index a0cadb5e4cd..4c329ee49a3 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -3300,6 +3300,8 @@ if (BUSES["TATUNG_PIPE"]~=null) then
MAME_DIR .. "src/devices/bus/einstein/pipe/pipe.h",
MAME_DIR .. "src/devices/bus/einstein/pipe/silicon_disc.cpp",
MAME_DIR .. "src/devices/bus/einstein/pipe/silicon_disc.h",
+ MAME_DIR .. "src/devices/bus/einstein/pipe/speculator.cpp",
+ MAME_DIR .. "src/devices/bus/einstein/pipe/speculator.h",
MAME_DIR .. "src/devices/bus/einstein/pipe/tk02.cpp",
MAME_DIR .. "src/devices/bus/einstein/pipe/tk02.h",
}
diff --git a/src/devices/bus/einstein/pipe/pipe.cpp b/src/devices/bus/einstein/pipe/pipe.cpp
index 106dbe0f8ec..51169544ba7 100644
--- a/src/devices/bus/einstein/pipe/pipe.cpp
+++ b/src/devices/bus/einstein/pipe/pipe.cpp
@@ -11,6 +11,7 @@
// supported devices
#include "silicon_disc.h"
+#include "speculator.h"
#include "tk02.h"
@@ -55,6 +56,9 @@ tatung_pipe_device::~tatung_pipe_device()
void tatung_pipe_device::device_start()
{
+ // get inserted module
+ m_card = dynamic_cast<device_tatung_pipe_interface *>(get_card_device());
+
// resolve callbacks
m_int_handler.resolve_safe();
m_nmi_handler.resolve_safe();
@@ -70,6 +74,16 @@ void tatung_pipe_device::device_reset()
}
//-------------------------------------------------
+// host to module interface
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( tatung_pipe_device::host_int_w )
+{
+ if (m_card)
+ m_card->int_w(state);
+}
+
+//-------------------------------------------------
// set_program_space - set address space we are attached to
//-------------------------------------------------
@@ -117,5 +131,6 @@ device_tatung_pipe_interface::~device_tatung_pipe_interface()
SLOT_INTERFACE_START( tatung_pipe_cards )
SLOT_INTERFACE("silicon_disc", EINSTEIN_SILICON_DISC)
+ SLOT_INTERFACE("speculator", EINSTEIN_SPECULATOR)
SLOT_INTERFACE("tk02", TK02_80COL)
SLOT_INTERFACE_END
diff --git a/src/devices/bus/einstein/pipe/pipe.h b/src/devices/bus/einstein/pipe/pipe.h
index 759103595c6..02be494cb2e 100644
--- a/src/devices/bus/einstein/pipe/pipe.h
+++ b/src/devices/bus/einstein/pipe/pipe.h
@@ -90,6 +90,9 @@ public:
template <class Object> static devcb_base &set_reset_handler(device_t &device, Object &&cb)
{ return downcast<tatung_pipe_device &>(device).m_reset_handler.set_callback(std::forward<Object>(cb)); }
+ // called from host
+ DECLARE_WRITE_LINE_MEMBER( host_int_w );
+
// called from card device
DECLARE_WRITE_LINE_MEMBER( int_w ) { m_int_handler(state); }
DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_nmi_handler(state); }
@@ -119,6 +122,9 @@ public:
device_tatung_pipe_interface(const machine_config &mconfig, device_t &device);
virtual ~device_tatung_pipe_interface();
+ // host to card
+ virtual void int_w(int state) { }
+
protected:
address_space &program_space() { return *m_slot->m_program; }
address_space &io_space() { return *m_slot->m_io; }
diff --git a/src/devices/bus/einstein/pipe/speculator.cpp b/src/devices/bus/einstein/pipe/speculator.cpp
new file mode 100644
index 00000000000..51918b018ca
--- /dev/null
+++ b/src/devices/bus/einstein/pipe/speculator.cpp
@@ -0,0 +1,206 @@
+// license: GPL-2.0+
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Speculator
+
+ TODO: Not working, based on the schematics of the Memotech MTX version
+
+***************************************************************************/
+
+#include "emu.h"
+#include "speculator.h"
+#include "machine/rescap.h"
+#include "sound/wave.h"
+#include "formats/tzx_cas.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(EINSTEIN_SPECULATOR, einstein_speculator_device, "einstein_speculator", "Einstein Speculator")
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+MACHINE_CONFIG_MEMBER( einstein_speculator_device::device_add_mconfig )
+ MCFG_DEVICE_ADD("ic5a", TTL74123, 0)
+ MCFG_TTL74123_CONNECTION_TYPE(TTL74123_NOT_GROUNDED_NO_DIODE)
+ MCFG_TTL74123_RESISTOR_VALUE(RES_K(47))
+ MCFG_TTL74123_CAPACITOR_VALUE(CAP_P(560))
+ MCFG_TTL74123_A_PIN_VALUE(1)
+ MCFG_TTL74123_B_PIN_VALUE(1)
+ MCFG_TTL74123_CLEAR_PIN_VALUE(0)
+ MCFG_TTL74123_OUTPUT_CHANGED_CB(WRITELINE(einstein_speculator_device, ic5a_q_w))
+
+ MCFG_DEVICE_ADD("ic5b", TTL74123, 0)
+ MCFG_TTL74123_CONNECTION_TYPE(TTL74123_NOT_GROUNDED_NO_DIODE)
+ MCFG_TTL74123_RESISTOR_VALUE(RES_K(47))
+ MCFG_TTL74123_CAPACITOR_VALUE(CAP_P(560))
+ MCFG_TTL74123_A_PIN_VALUE(1)
+ MCFG_TTL74123_B_PIN_VALUE(1)
+ MCFG_TTL74123_CLEAR_PIN_VALUE(0)
+ MCFG_TTL74123_OUTPUT_CHANGED_CB(WRITELINE(einstein_speculator_device, ic5b_q_w))
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette")
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+ MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+
+ MCFG_CASSETTE_ADD("cassette")
+ MCFG_CASSETTE_FORMATS(tzx_cassette_formats)
+ MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED)
+ MCFG_CASSETTE_INTERFACE("spectrum_cass")
+MACHINE_CONFIG_END
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// einstein_speculator_device - constructor
+//-------------------------------------------------
+
+einstein_speculator_device::einstein_speculator_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, EINSTEIN_SPECULATOR, tag, owner, clock),
+ device_tatung_pipe_interface(mconfig, *this),
+ m_ic5a(*this, "ic5a"), m_ic5b(*this, "ic5b"),
+ m_cassette(*this, "cassette"),
+ m_speaker(*this, "speaker"),
+ m_nmisel(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void einstein_speculator_device::device_start()
+{
+ // setup ram
+ m_ram = std::make_unique<uint8_t[]>(0x800);
+ memset(m_ram.get(), 0xff, 0x800);
+
+ // register for save states
+ save_pointer(NAME(m_ram.get()), 0x800);
+ save_item(NAME(m_nmisel));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void einstein_speculator_device::device_reset()
+{
+ // ram: range 0x1f, 0x3f, 0x5f, 0x7f, 0x9f, 0xbf, 0xdf, 0xff
+ io_space().install_readwrite_handler(0x1f, 0x1f, 0, 0, 0xffe0,
+ read8_delegate(FUNC(einstein_speculator_device::ram_r), this),
+ write8_delegate(FUNC(einstein_speculator_device::ram_w), this));
+
+ // ram: range 0x60 - 0xff
+ io_space().install_readwrite_handler(0x60, 0x60, 0, 0, 0xff9f,
+ read8_delegate(FUNC(einstein_speculator_device::ram_r), this),
+ write8_delegate(FUNC(einstein_speculator_device::ram_w), this));
+
+ // tape read/nmi write register: range 0xff
+ io_space().install_readwrite_handler(0xff, 0xff, 0, 0, 0xff00,
+ read8_delegate(FUNC(einstein_speculator_device::tape_r), this),
+ write8_delegate(FUNC(einstein_speculator_device::nmi_w), this));
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+WRITE_LINE_MEMBER( einstein_speculator_device::ic5a_q_w )
+{
+ m_ic5b->a_w(state);
+
+ if (m_nmisel == 1)
+ {
+ logerror("imm nmi: %d\n", state);
+ m_slot->nmi_w(state);
+ }
+}
+
+WRITE_LINE_MEMBER( einstein_speculator_device::ic5b_q_w )
+{
+ if (m_nmisel == 0)
+ {
+ logerror("del nmi: %d\n", state);
+ m_slot->nmi_w(state);
+ }
+}
+
+void einstein_speculator_device::int_w(int state)
+{
+ logerror("int_w: %d\n", state);
+ m_ic5a->a_w(!state);
+}
+
+// pal ic4
+offs_t einstein_speculator_device::address_translate(offs_t offset)
+{
+ int ra3, ra2, ra1, ra0;
+
+ ra3 = !BIT(offset, 7) && BIT(offset, 0);
+
+ ra2 = BIT(offset, 15) && BIT(offset, 14) && BIT(offset, 13) && BIT(offset, 12) && !BIT(offset, 11);
+ ra2 |= BIT(offset, 15) && BIT(offset, 14) && BIT(offset, 13) && BIT(offset, 12) && !BIT(offset, 10);
+ ra2 |= BIT(offset, 15) && BIT(offset, 14) && BIT(offset, 13) && BIT(offset, 12) && !BIT(offset, 9);
+ ra2 |= BIT(offset, 15) && BIT(offset, 14) && BIT(offset, 13) && BIT(offset, 12) && !BIT(offset, 8);
+
+ ra1 = BIT(offset, 15) && BIT(offset, 14) && !BIT(offset, 13);
+ ra1 |= BIT(offset, 15) && BIT(offset, 14) && !BIT(offset, 12);
+ ra1 |= BIT(offset, 15) && BIT(offset, 14) && BIT(offset, 11) && BIT(offset, 10) && !BIT(offset, 9);
+ ra1 |= BIT(offset, 15) && BIT(offset, 14) && BIT(offset, 11) && BIT(offset, 10) && !BIT(offset, 8);
+
+ ra0 = BIT(offset, 15) && !BIT(offset, 14);
+ ra0 |= BIT(offset, 15) && BIT(offset, 13) && !BIT(offset, 12);
+ ra0 |= BIT(offset, 15) && BIT(offset, 13) && BIT(offset, 11) && !BIT(offset, 10);
+ ra0 |= BIT(offset, 15) && BIT(offset, 13) && BIT(offset, 11) && BIT(offset, 9) && !BIT(offset, 8);
+
+ return (ra3 << 3) | (ra2 << 2) | (ra1 << 1) | (ra0 << 0);
+}
+
+READ8_MEMBER( einstein_speculator_device::ram_r )
+{
+ offs_t addr = ((offset << 4) & 0x7f) | address_translate(offset);
+ return m_ram[addr];
+}
+
+WRITE8_MEMBER( einstein_speculator_device::ram_w )
+{
+ offs_t addr = ((offset << 4) & 0x7f) | address_translate(offset);
+ m_ram[addr] = data;
+}
+
+READ8_MEMBER( einstein_speculator_device::tape_r )
+{
+ // 7654321- unknown
+ // -------0 cassette input
+
+ return m_cassette->input() > 0.0038 ? 1 : 0;
+}
+
+WRITE8_MEMBER( einstein_speculator_device::nmi_w )
+{
+ logerror("nmi_w offset %04x data %02x\n", offset, data);
+
+ // 76543--- unknown
+ // -----2-- nmi enable?
+ // ------1- nmi select?
+ // -------0 speaker?
+
+ m_ic5a->clear_w(BIT(data, 2));
+ m_ic5b->clear_w(BIT(data, 2));
+
+ m_nmisel = BIT(data, 1);
+
+ m_speaker->level_w(BIT(data, 0));
+}
diff --git a/src/devices/bus/einstein/pipe/speculator.h b/src/devices/bus/einstein/pipe/speculator.h
new file mode 100644
index 00000000000..348187012c5
--- /dev/null
+++ b/src/devices/bus/einstein/pipe/speculator.h
@@ -0,0 +1,66 @@
+// license: GPL-2.0+
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Speculator
+
+ A Spectrum emulator
+
+***************************************************************************/
+
+#ifndef MAME_BUS_EINSTEIN_PIPE_SPECULATOR_H
+#define MAME_BUS_EINSTEIN_PIPE_SPECULATOR_H
+
+#pragma once
+
+#include "pipe.h"
+#include "machine/74123.h"
+#include "imagedev/cassette.h"
+#include "sound/spkrdev.h"
+#include "speaker.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> einstein_speculator_device
+
+class einstein_speculator_device : public device_t, public device_tatung_pipe_interface
+{
+public:
+ // construction/destruction
+ einstein_speculator_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void int_w(int state) override;
+
+ DECLARE_READ8_MEMBER(ram_r);
+ DECLARE_WRITE8_MEMBER(ram_w);
+ DECLARE_READ8_MEMBER(tape_r);
+ DECLARE_WRITE8_MEMBER(nmi_w);
+
+ DECLARE_WRITE_LINE_MEMBER(ic5a_q_w);
+ DECLARE_WRITE_LINE_MEMBER(ic5b_q_w);
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ offs_t address_translate(offs_t offset);
+
+ required_device<ttl74123_device> m_ic5a;
+ required_device<ttl74123_device> m_ic5b;
+ required_device<cassette_image_device> m_cassette;
+ required_device<speaker_sound_device> m_speaker;
+
+ std::unique_ptr<uint8_t[]> m_ram;
+
+ int m_nmisel;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(EINSTEIN_SPECULATOR, einstein_speculator_device)
+
+#endif // MAME_BUS_EINSTEIN_PIPE_SPECULATOR_H
diff --git a/src/mame/drivers/einstein.cpp b/src/mame/drivers/einstein.cpp
index f0f9421e9cd..a08d6c95498 100644
--- a/src/mame/drivers/einstein.cpp
+++ b/src/mame/drivers/einstein.cpp
@@ -83,7 +83,8 @@ public:
m_buttons(*this, "BUTTONS"),
m_rom_enabled(0),
m_keyboard_line(0), m_keyboard_data(0xff),
- m_centronics_busy(0), m_centronics_perror(0), m_centronics_fault(0)
+ m_centronics_busy(0), m_centronics_perror(0), m_centronics_fault(0), m_strobe(-1),
+ m_int(0)
{}
DECLARE_INPUT_CHANGED_MEMBER(joystick_button);
@@ -94,6 +95,7 @@ public:
DECLARE_WRITE8_MEMBER(reset_w);
DECLARE_READ8_MEMBER(rom_r);
DECLARE_WRITE8_MEMBER(rom_w);
+ template <int source> DECLARE_WRITE_LINE_MEMBER(int_w);
DECLARE_READ8_MEMBER(kybint_msk_r);
DECLARE_WRITE8_MEMBER(kybint_msk_w);
DECLARE_WRITE8_MEMBER(adcint_msk_w);
@@ -139,6 +141,9 @@ private:
int m_centronics_busy;
int m_centronics_perror;
int m_centronics_fault;
+ int m_strobe;
+
+ int m_int;
};
@@ -245,11 +250,13 @@ WRITE_LINE_MEMBER( einstein_state::write_centronics_fault )
WRITE_LINE_MEMBER( einstein_state::ardy_w )
{
- if (state)
+ if (m_strobe == 0 && state == 1)
{
m_centronics->write_strobe(1);
m_strobe_timer->adjust(attotime::from_double(TIME_OF_74LS123(RES_K(10), CAP_N(1))));
}
+
+ m_strobe = state;
}
TIMER_DEVICE_CALLBACK_MEMBER( einstein_state::strobe_callback )
@@ -272,6 +279,30 @@ static const z80_daisy_config einstein_daisy_chain[] =
{ nullptr }
};
+template <int source> WRITE_LINE_MEMBER( einstein_state::int_w )
+{
+ int old = m_int;
+
+ if (state)
+ {
+ m_int |= (1 << source);
+ if (!old)
+ {
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
+ m_pipe->host_int_w(ASSERT_LINE);
+ }
+ }
+ else
+ {
+ m_int &= ~(1 << source);
+ if (old && !m_int)
+ {
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
+ m_pipe->host_int_w(CLEAR_LINE);
+ }
+ }
+}
+
READ8_MEMBER( einstein_state::kybint_msk_r )
{
uint8_t data = 0;
@@ -370,6 +401,8 @@ void einstein_state::machine_reset()
m_keyboard_daisy->mask_w(1);
m_adc_daisy->mask_w(1);
m_fire_daisy->mask_w(1);
+
+ m_strobe = -1;
}
@@ -548,7 +581,7 @@ static MACHINE_CONFIG_START( einstein )
MCFG_TIMER_DRIVER_ADD_PERIODIC("keyboard", einstein_state, keyboard_timer_callback, attotime::from_hz(50))
MCFG_DEVICE_ADD(IC_I063, Z80PIO, XTAL_X002 / 2)
- MCFG_Z80PIO_OUT_INT_CB(INPUTLINE(IC_I001, INPUT_LINE_IRQ0))
+ MCFG_Z80PIO_OUT_INT_CB(WRITELINE(einstein_state, int_w<0>))
MCFG_Z80PIO_OUT_PA_CB(DEVWRITE8("cent_data_out", output_latch_device, write))
MCFG_Z80PIO_OUT_ARDY_CB(WRITELINE(einstein_state, ardy_w))
MCFG_Z80PIO_IN_PB_CB(DEVREAD8("user", einstein_userport_device, read))
@@ -556,7 +589,7 @@ static MACHINE_CONFIG_START( einstein )
MCFG_Z80PIO_OUT_BRDY_CB(DEVWRITELINE("user", einstein_userport_device, brdy_w))
MCFG_DEVICE_ADD(IC_I058, Z80CTC, XTAL_X002 / 2)
- MCFG_Z80CTC_INTR_CB(INPUTLINE(IC_I001, INPUT_LINE_IRQ0))
+ MCFG_Z80CTC_INTR_CB(WRITELINE(einstein_state, int_w<1>))
MCFG_Z80CTC_ZC0_CB(DEVWRITELINE(IC_I060, i8251_device, write_txc))
MCFG_Z80CTC_ZC1_CB(DEVWRITELINE(IC_I060, i8251_device, write_rxc))
MCFG_Z80CTC_ZC2_CB(DEVWRITELINE(IC_I058, z80ctc_device, trg3))
@@ -568,8 +601,11 @@ static MACHINE_CONFIG_START( einstein )
/* Einstein daisy chain support for non-Z80 devices */
MCFG_Z80DAISY_GENERIC_ADD("keyboard_daisy", 0xf7)
+ MCFG_Z80DAISY_GENERIC_INT_CB(WRITELINE(einstein_state, int_w<2>))
MCFG_Z80DAISY_GENERIC_ADD("adc_daisy", 0xfb)
+ MCFG_Z80DAISY_GENERIC_INT_CB(WRITELINE(einstein_state, int_w<3>))
MCFG_Z80DAISY_GENERIC_ADD("fire_daisy", 0xfd)
+ MCFG_Z80DAISY_GENERIC_INT_CB(WRITELINE(einstein_state, int_w<4>))
/* video hardware */
MCFG_DEVICE_ADD("vdp", TMS9129, XTAL_10_738635MHz / 2)
@@ -633,6 +669,7 @@ static MACHINE_CONFIG_START( einstein )
// tatung pipe connector
MCFG_TATUNG_PIPE_ADD("pipe")
+ MCFG_TATUNG_PIPE_NMI_HANDLER(INPUTLINE(IC_I001, INPUT_LINE_NMI))
// user port
MCFG_EINSTEIN_USERPORT_ADD("user")