summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/emma2.cpp
blob: 2a1fa2ebfdb659eefb0cd7fdd234c44ac2f12965 (plain) (tree)
1
2
3
4
5
6
7
8






                                                                            
                          
































                                                                            
                                               
                                                                   

                





























































































































































































                                                                                                                                
// license:BSD-3-Clause
// copyright-holders:Robbbert
/***************************************************************************

Emma and Emma II by L.J.Technical Systems
These were produced by L.J.Electronics Ltd, Norwich in 1979.

2018-09-20 Working driver.

We don't have roms for the Emma, so only the Emma II is emulated.

Keys:
0-9,A-F: hex input
M      : memory mode (modify address, or modify data)
G      : go
R      : single step (not emulated)
P      : insert a forced break
S      : save to cassette
L      : load from cassette
+      : up (use UP-arrow key)
-      : down (use DOWN-arrow key)

Pasting example:
M0020M01^02^03^04^05^06^07^08^09^M000020
Press up arrow to see your input.

To save, press S, enter beginning address, press S, enter end address+1,
press S, start the recorder, press 0 for 300 baud or 1 for 1200 baud. The
data is saved.

To load, press L, press play, while leader is playing press 0 or 1 as above.
When a row of dots appears, the data has been loaded.


There's an expansion unit with its own rom, a 8255, an eprom programmer,
and 16k of static RAM.



To Do:
- Cassette LED doesn't work.
- Display should blank if PB0 not being pulsed.
- Code up the expansion unit (rom is there but no schematic exists)
- Need software.


****************************************************************************/

#include "emu.h"
#include "cpu/m6502/m6502.h"
#include "machine/6522via.h"
#include "machine/6821pia.h"
#include "imagedev/cassette.h"
#include "sound/wave.h"
#include "speaker.h"
#include "emma2.lh"


class emma2_state : public driver_device
{
public:
	emma2_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag)
		, m_maincpu(*this, "maincpu")
		, m_cassette(*this, "cassette")
		, m_via(*this, "via")
		, m_pia(*this, "pia")
		, m_keyboard(*this, "X%u", 0)
		, m_digits(*this, "digit%u", 0U)
	{ }

	void emma2(machine_config &config);

private:
	DECLARE_WRITE8_MEMBER(segment_w);
	DECLARE_WRITE8_MEMBER(digit_w);
	DECLARE_READ8_MEMBER(keyboard_r);
	virtual void machine_reset() override;
	virtual void machine_start() override;

	void mem_map(address_map &map);

	uint8_t m_digit;
	bool m_dig_change;
	required_device<cpu_device> m_maincpu;
	required_device<cassette_image_device> m_cassette;
	required_device<via6522_device> m_via;
	required_device<pia6821_device> m_pia;
	required_ioport_array<8> m_keyboard;
	output_finder<8> m_digits;
};

void emma2_state::mem_map(address_map &map)
{
	map.unmap_value_high();
	map(0x0000, 0x03ff).ram();
	map(0x0900, 0x090f).mirror(0x02f0).rw(m_via, FUNC(via6522_device::read), FUNC(via6522_device::write));
	map(0x0a00, 0x0a03).mirror(0x00fc).rw(m_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write));
	map(0x0c00, 0x0fff).ram();
	map(0xd800, 0xdfff).mirror(0x2000).rom();
}


/* Input ports */
static INPUT_PORTS_START( emma2 )
/*
M   L   0   4   8   C
G   R   1   5   9   D
P   +   2   6   A   E
S   -   3   7   B   F
*/

	PORT_START("X0")
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0')

	PORT_START("X1")
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1')

	PORT_START("X2")
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2')

	PORT_START("X3")
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3')

	PORT_START("X4")
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4')

	PORT_START("X5")
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5')

	PORT_START("X6")
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR('^')
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6')

	PORT_START("X7")
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR('V')
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7')
INPUT_PORTS_END


WRITE8_MEMBER( emma2_state::digit_w )
{
	m_cassette->output( BIT(data, 6) ? +1.0 : -1.0);

	data &= 7;
	if (data != m_digit)
	{
		m_digit = data;
		m_dig_change = true;
	}
}

WRITE8_MEMBER( emma2_state::segment_w )
{
	if (m_dig_change)
	{
		m_dig_change = false;
		m_digits[m_digit] = data;
	}
}

READ8_MEMBER( emma2_state::keyboard_r )
{
	u8 data = m_keyboard[m_digit]->read();
	data |= ((m_cassette)->input() < 0.0) ? 0x80 : 0;
	return data;
}

void emma2_state::machine_start()
{
	m_digits.resolve();
}

void emma2_state::machine_reset()
{
	m_digit = 0;
	m_dig_change = 0;
}

MACHINE_CONFIG_START(emma2_state::emma2)
	/* basic machine hardware */
	MCFG_DEVICE_ADD("maincpu", M6502, 1'000'000)
	MCFG_DEVICE_PROGRAM_MAP(mem_map)

	/* video hardware */
	config.set_default_layout(layout_emma2);

	/* Devices */
	VIA6522(config, m_via, 1'000'000);  // #2 from cpu
	m_via->irq_handler().set_inputline(m_maincpu, m6502_device::IRQ_LINE);

	PIA6821(config, m_pia, 0);
	m_pia->writepa_handler().set(FUNC(emma2_state::segment_w));
	m_pia->writepb_handler().set(FUNC(emma2_state::digit_w));
	m_pia->readpb_handler().set(FUNC(emma2_state::keyboard_r));
	m_pia->ca2_handler().set([this] (bool state) { output().set_value("led0", state); });
	m_pia->irqa_handler().set_inputline(m_maincpu, m6502_device::IRQ_LINE);
	m_pia->irqb_handler().set_inputline(m_maincpu, m6502_device::IRQ_LINE);

	/* cassette */
	MCFG_CASSETTE_ADD( "cassette" )
	MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED)

	/* sound hardware */
	SPEAKER(config, "mono").front_center();
	WAVE(config, "wave", "cassette").add_route(ALL_OUTPUTS, "mono", 0.05);
MACHINE_CONFIG_END


/* ROM definition */
ROM_START( emma2 )
	ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF )
	ROM_LOAD( "se118a_90-97", 0x9000, 0x0800, CRC(32d36938) SHA1(910fd1c18c7deae83933c7c4f397103a35bf574a) )
	ROM_LOAD( "se116a_d8-dd_fe-ff", 0xd800, 0x0800, CRC(ef0f1513) SHA1(46089ba0402828b4204812a04134b313d9be0f93) )
ROM_END


/* Driver */

//    YEAR  NAME    PARENT  COMPAT  MACHINE  INPUT   CLASS         INIT        COMPANY  FULLNAME           FLAGS
COMP( 1979, emma2,  0,      0,      emma2,   emma2,  emma2_state,  empty_init, "L.J.Technical Systems",   "Emma II trainer", 0 )