// license:BSD-3-Clause
// copyright-holders:Curt Coder
/***************************************************************************
Netronics Elf II
****************************************************************************/
/*
TODO:
- proper layout
*/
#include "emu.h"
#include "includes/elf.h"
#include "elf2.lh"
#define RUN \
BIT(m_special->read(), 0)
#define LOAD \
BIT(m_special->read(), 1)
#define MEMORY_PROTECT \
BIT(m_special->read(), 2)
#define INPUT \
BIT(m_special->read(), 3)
/* Read/Write Handlers */
READ8_MEMBER( elf2_state::dispon_r )
{
m_vdc->disp_on_w(1);
m_vdc->disp_on_w(0);
return 0xff;
}
READ8_MEMBER( elf2_state::data_r )
{
return m_data;
}
WRITE8_MEMBER( elf2_state::data_w )
{
m_led_l->a_w(data & 0x0f);
m_led_h->a_w(data >> 4);
}
WRITE8_MEMBER( elf2_state::memory_w )
{
if (LOAD)
{
if (MEMORY_PROTECT)
{
/* latch data from memory */
data = m_ram->pointer()[offset];
}
else
{
/* write latched data to memory */
m_ram->pointer()[offset] = data;
}
/* write data to 7 segment displays */
m_led_l->a_w(data & 0x0f);
m_led_h->a_w(data >> 4);
}
}
/* Memory Maps */
void elf2_state::elf2_mem(address_map &map)
{
map.unmap_value_high();
map.global_mask(0xff);
map(0x0000, 0x00ff).bankrw("bank1");
}
void elf2_state::elf2_io(address_map &map)
{
map.unmap_value_high();
map(0x01, 0x01).r(this, FUNC(elf2_state::dispon_r));
map(0x04, 0x04).rw(this, FUNC(elf2_state::data_r), FUNC(elf2_state::data_w));
}
/* Input Ports */
INPUT_CHANGED_MEMBER( elf2_state::input_w )
{
if (newval)
{
/* assert DMAIN */
m_maincpu->set_input_line(COSMAC_INPUT_LINE_DMAIN, ASSERT_LINE);
}
}
static INPUT_PORTS_START( elf2 )
PORT_START("X1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8')
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("X2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9')
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("X3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("X4")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("SPECIAL")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("RUN") PORT_CODE(KEYCODE_R) PORT_TOGGLE
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LOAD") PORT_CODE(KEYCODE_L) PORT_TOGGLE
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M/P") PORT_CODE(KEYCODE_M) PORT_TOGGLE
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("INPUT") PORT_CODE(KEYCODE_ENTER) PORT_CHANGED_MEMBER(DEVICE_SELF, elf2_state, input_w, 0)
INPUT_PORTS_END
/* CDP1802 Configuration */
READ_LINE_MEMBER( elf2_state::wait_r )
{
return LOAD;
}
READ_LINE_MEMBER( elf2_state::clear_r )
{
return RUN;
}
READ_LINE_MEMBER( elf2_state::ef4_r )
{
return INPUT;
}
WRITE_LINE_MEMBER( elf2_state::q_w )
{
m_led = state ? 1 : 0;
}
READ8_MEMBER( elf2_state::dma_r )
{
return m_data;
}
WRITE8_MEMBER( elf2_state::sc_w )
{
switch (data)
{
case COSMAC_STATE_CODE_S2_DMA:
case COSMAC_STATE_CODE_S3_INTERRUPT:
/* clear DMAIN */
m_maincpu->set_input_line(COSMAC_INPUT_LINE_DMAIN, CLEAR_LINE);
break;
default:
break;
}
}
/* MM74C923 Interface */
WRITE_LINE_MEMBER( elf2_state::da_w )
{
if (state)
{
/* shift keyboard data to latch */
m_data <<= 4;
m_data |= m_kb->read() & 0x0f;
if (LOAD)
{
/* write data to 7 segment displays */
m_led_l->a_w(m_data & 0x0f);
m_led_h->a_w(m_data >> 4);
}
}
}
/* Machine Initialization */
void elf2_state::machine_start()
{
address_space &program = m_maincpu->space(AS_PROGRAM);
m_led.resolve();
/* initialize LED displays */
m_7segs.resolve();
m_led_l->rbi_w(1);
m_led_h->rbi_w(1);
/* setup memory banking */
program.install_read_bank(0x0000, 0x00ff, "bank1");
program.install_write_handler(0x0000, 0x00ff, write8_delegate(FUNC(elf2_state::memory_w), this));
membank("bank1")->configure_entry(0, m_ram->pointer());
membank("bank1")->set_entry(0);
/* register for state saving */
save_item(NAME(m_data));
}
/* Machine Driver */
QUICKLOAD_LOAD_MEMBER( elf2_state, elf )
{
int size = image.length();
if (size > m_ram->size())
{
return image_init_result::FAIL;
}
image.fread(m_ram->pointer(), size);
return image_init_result::PASS;
}
MACHINE_CONFIG_START(elf2_state::elf2)
/* basic machine hardware */
MCFG_DEVICE_ADD(CDP1802_TAG, CDP1802, XTAL(3'579'545)/2)
MCFG_DEVICE_PROGRAM_MAP(elf2_mem)
MCFG_DEVICE_IO_MAP(elf2_io)
MCFG_COSMAC_WAIT_CALLBACK(READLINE(*this, elf2_state, wait_r))
MCFG_COSMAC_CLEAR_CALLBACK(READLINE(*this, elf2_state, clear_r))
MCFG_COSMAC_EF4_CALLBACK(READLINE(*this, elf2_state, ef4_r))
MCFG_COSMAC_Q_CALLBACK(WRITELINE(*this, elf2_state, q_w))
MCFG_COSMAC_DMAR_CALLBACK(READ8(*this, elf2_state, dma_r))
MCFG_COSMAC_DMAW_CALLBACK(WRITE8(CDP1861_TAG, cdp1861_device, dma_w))
MCFG_COSMAC_SC_CALLBACK(WRITE8(*this, elf2_state, sc_w))
/* video hardware */
MCFG_DEFAULT_LAYOUT(layout_elf2)
MCFG_DEVICE_ADD(CDP1861_TAG, CDP1861, XTAL(3'579'545)/2)
MCFG_CDP1861_IRQ_CALLBACK(INPUTLINE(CDP1802_TAG, COSMAC_INPUT_LINE_INT))
MCFG_CDP1861_DMA_OUT_CALLBACK(INPUTLINE(CDP1802_TAG, COSMAC_INPUT_LINE_DMAOUT))
MCFG_CDP1861_EFX_CALLBACK(INPUTLINE(CDP1802_TAG, COSMAC_INPUT_LINE_EF1))
MCFG_CDP1861_SCREEN_ADD(CDP1861_TAG, SCREEN_TAG, XTAL(3'579'545)/2)
/* devices */
MCFG_DEVICE_ADD(MM74C923_TAG, MM74C923, 0)
MCFG_MM74C922_OSC(CAP_U(0.15))
MCFG_MM74C922_DEBOUNCE(CAP_U(1))
MCFG_MM74C922_DA_CALLBACK(WRITELINE(*this, elf2_state, da_w))
MCFG_MM74C922_X1_CALLBACK(IOPORT("X1"))
MCFG_MM74C922_X2_CALLBACK(IOPORT("X2"))
MCFG_MM74C922_X3_CALLBACK(IOPORT("X3"))
MCFG_MM74C922_X4_CALLBACK(IOPORT("X4"))
MCFG_DEVICE_ADD(DM9368_H_TAG, DM9368, 0)
MCFG_DM9368_UPDATE_CALLBACK(WRITE8(*this, elf2_state, digit_w<0>))
MCFG_DEVICE_ADD(DM9368_L_TAG, DM9368, 0)
MCFG_DM9368_UPDATE_CALLBACK(WRITE8(*this, elf2_state, digit_w<1>))
MCFG_CASSETTE_ADD("cassette")
MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_MUTED)
MCFG_QUICKLOAD_ADD("quickload", elf2_state, elf, "bin", 0)
/* internal ram */
MCFG_RAM_ADD(RAM_TAG)
MCFG_RAM_DEFAULT_SIZE("256")
MACHINE_CONFIG_END
/* ROMs */
ROM_START( elf2 )
ROM_REGION( 0x10000, CDP1802_TAG, ROMREGION_ERASE00 )
ROM_END
/* System Drivers */
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 1978, elf2, 0, 0, elf2, elf2, elf2_state, empty_init, "Netronics", "Elf II", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND)