einstein: Improve interrupts, add WIP Speculator support

Also removes a bogus character in the initial centronics output.
This commit is contained in:
Dirk Best 2017-11-20 01:37:08 +01:00
parent 4a211c8443
commit a5a8e0cbdb
6 changed files with 336 additions and 4 deletions

View File

@ -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",
}

View File

@ -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();
@ -69,6 +73,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

View File

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

View File

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

View File

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

View File

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