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








                                                                                                          
                                                                                                        

                           
                                                                                                              

                                                                                                           























                                                                                  
                   


























































                                                                                                                                                    
                                                                                                                                                

































                                                                                                                                               
                                                  















                                                   




                                        



                                          




















                                                                                                       
                                        
 









                                   
























































































































































                                                                                                                                                   
                                                                                                 









































































                                                                                                          




                                                    
                                                                                                

                                                         














































































































                                                                                                                                                                                  
                                      

                                                          

                     
                                         















                                                                                 








                                                                    

                                                                                                               

                                                                        

                                 
                                                                    













                                                                                                                 
                                                                           

                                                            
                                                               











                                                                                                                                                         





                                                                           



                                                                                                                           

                                                                                                                                

                                       
                                                                                                                

       

                                                                                                                                                  
// license:BSD-3-Clause
// copyright-holders:Joakim Larsson Edstrom
/*
 *
 * History of Didact
 *------------------
 * See didact.cpp
 *
 * The Esselte 100 was an original design with a CRT and a full Keyboard that also had a BASIC interpreter
 * extended with commands suitable for educational experiments using the exapansion bus and its built in
 * io control capabilities.
 *
 * The Esselte 1000 was an educational package based on Apple II plus software and literature but the relation
 * to Didact is at this point unknown so it is probably a pure Esselte software production. If this branded
 * distribution is recovered it will be added as a clone of the Apple II driver or just as softlist item.
 *
 * Misc links about the boards supported by this driver.
 *-----------------------------------------------------
 * http://elektronikforumet.com/forum/download/file.php?id=63988&mode=view
 * http://elektronikforumet.com/forum/viewtopic.php?f=2&t=79576&start=150#p1203915
 *
 *  TODO:
 * -------------------------------
 *  - Dump more ROM:s
 *  - Keyboard for early rev PCB
 *  - Expansion bus
 *  - Expansion overlay
 *  - Serial
 ****************************************************************************/

#include "emu.h"
#include "cpu/m6800/m6800.h"
#include "machine/6821pia.h"
#include "machine/74145.h"
#include "machine/timer.h"

// Features
#include "imagedev/cassette.h"
#include "bus/rs232/rs232.h"
#include "emupal.h"
#include "screen.h"

//**************************************************************************
//  MACROS / CONSTANTS
//**************************************************************************

//#define LOG_GENERAL (1U <<  0)
#define LOG_SETUP   (1U <<  1)
#define LOG_SCAN    (1U <<  2)
#define LOG_BANK    (1U <<  3)
#define LOG_SCREEN  (1U <<  4)
#define LOG_READ    (1U <<  5)
#define LOG_CS      (1U <<  6)

//#define VERBOSE (LOG_READ | LOG_GENERAL | LOG_SETUP | LOG_BANK)
//#define LOG_OUTPUT_FUNC printf
#include "logmacro.h"

#define LOGSETUP(...)   LOGMASKED(LOG_SETUP,   __VA_ARGS__)
#define LOGSCAN(...)    LOGMASKED(LOG_SCAN,    __VA_ARGS__)
#define LOGBANK(...)    LOGMASKED(LOG_BANK,    __VA_ARGS__)
#define LOGSCREEN(...)  LOGMASKED(LOG_SCREEN,  __VA_ARGS__)
#define LOGR(...)       LOGMASKED(LOG_READ,    __VA_ARGS__)
#define LOGCS(...)      LOGMASKED(LOG_CS,      __VA_ARGS__)

#ifdef _MSC_VER
#define FUNCNAME __func__
#else
#define FUNCNAME __PRETTY_FUNCTION__
#endif

#define PIA1_TAG "pia1"
#define PIA2_TAG "pia2"

/*  __________________________________________________________________________________________________________________________________________
 * | The Didact Esselte 100 CPU board rev1, 14/8 1980                                                                          in-PCB coil     +----
 * |   +--+     +--+     +--+     +--+        +--+     +--+                                                                 +--------+    |VHF
 * |   74       74       74       74          74       74                   7805CT              7805CT        trim 3,5-13pF |+-----+ |    |  TV
 * |    157      393       04       10          00       03                                                        2N2369 | || o-+ | |    +----
 * |   +--+     +--+     +--+     +--+        +--+     +--+                                                               | |+---+ | |       |
 * |1Kohm                                                                                                                 | +------+ |    +----
 * |trim                                                                                                                  +----------+    |CVS
 * | 8 +--+              +--+          +--+                                                              7805CP                           | MON
 * | 0 74                74            74                                                                                                 +----
 * | 0  132               157            93                                                                                                  |
 * | 8 +--+              +--+          +--+                                                                          J401                    |
 * | 1 +--+                                                                          +--+  +--+                                     LM339    |
 * | 4 74                +--+          +--+                                          74    74     +--+ +--+                   J402           |
 * |    165              74            74                                             122    00   74   74    4Mhz                            |
 * | J +--+               157           393                                          +--+  +--+    138  138  XTAL                         +----
 * | G                   +--+          +--+                                                       +--+ +--+    +----+  +----+  +----+     |TAPE
 * | +----+      +----+                                                                                               optional            |
 * |  CHAR       VIDEO                 +--+    +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+ +====++  CPU     PIA2    PIA1      +----
 * |   ROM        RAM                  74      6116   6116   6116   6116                                    ||                               |
 * |  2716       MK4118                 245      alt    alt    alt    alt                                2x ||  6802    6821    6821      +----
 * | +----+      +----+                +--+    MK4118 MK4118 MK4118 MK4118  2716   2716   2716   2716   2716||                            |PRNT
 * |DIDACT ESS 100 CPU                         +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----++                            |
 * |___________________________________________________________________________________________________________+----+__+----+__+----+_____+----
 *
 * rev2 board had 4Kb more ROM memory, 2 x 2764 instead of the 6 x 2716 (note the rev1 piggyback on rightmost 2716) with funny address decoding.
 * Once we get a rom dump for rev 1 the driver need to accomodate another keymap too so probably needs to be splitted somehow.
 *  __________________________________________________________________________________________________________________________________________
 * | The Didact Esselte 100 CPU board rev2, 15/4 1983                                                                     in-PCB coil     +----
 * |           +--+     +--+     +--+     +--+     +--+     +--+                                                            +--------+    |VHF
 * |           74       74       74       74       74       74              7805CT              7805CT        trim 3,5-13pF |+-----+ |    |  TV
 * |             93      393       10      393       00       03                                                   2N2369 | || o-+ | |    +----
 * |           +--+     +--+     +--+     +--+     +--+     +--+                                                          | |+---+ | |       |
 * |1Kohm                                                                                                                 | +------+ |    +----
 * |trim                                                                                                                  +----------+    |CVS
 * |   +--+    +--+     +--+    +--+   +--+   J                                                          7805CP                           | MON
 * |   74      74       74      74     74     2                                                                                           +----
 * |    165     132      157     157     04   0                                                                                              |
 * |   +--+    +--+     +--+    +--+   +--+   1       J 2 0 2                     +----+ +----+                      J401                    |
 * |                                                                                                                                         |
 * | +----+            +----+          +--+             +--+   +--+   +--+  +--+   U202   U201                                J402           |
 * |  CHAR             VIDEO           74               74     74     74    74                               4Mhz                            |
 * |   ROM              RAM             157              138    08     00    138   2764   2764               XTAL                         +----
 * |  2716             HM6116          +--+             +--+   +--+   +--+  +--+                               +----+  +----+  +----+     |TAPE
 * | +----+            +----+                J                                    +----+ +----+                       optional            |
 * |                                   +--+  2        +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+   CPU     PIA2    PIA1      +----
 * |                                   74    0        6116   6116   6116   6116   6116   6116   6116   6116                          +--+    |
 * |   8169 830415                      245  3                                     opt    opt    opt    opt     6802    6821    6821 LM   +----
 * |  ESSELTE 100                      +--+                                                                                           339 |PRNT
 * |  CPU 100                                         +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+                        +--+ |
 * |___________________________________________________________________________________________________________+----+__+----+__+----+_____+----
 *
 *   Both rev1 and rev2 has a matrix keyboard PCB with a 74LS145 connected to J402 (PIA2)
 */

/* Esselte 100 driver class */
class e100_state : public driver_device // public didact_state
{
public:
	e100_state(const machine_config &mconfig, device_type type, const char * tag)
	//      : didact_state(mconfig, type, tag)
		: driver_device(mconfig, type, tag)
		,m_maincpu(*this, "maincpu")
		,m_kbd_74145(*this, "kbd_74145")
		,m_videoram(*this, "videoram")
		,m_cassette(*this, "cassette")
		,m_rs232(*this, "rs232")
		,m_io_line0(*this, "LINE0")
		,m_io_line1(*this, "LINE1")
		,m_io_line2(*this, "LINE2")
		,m_io_line3(*this, "LINE3")
		,m_io_line4(*this, "LINE4")
		,m_io_line5(*this, "LINE5")
		,m_io_line6(*this, "LINE6")
		,m_io_line7(*this, "LINE7")
		,m_io_line8(*this, "LINE8")
		,m_io_line9(*this, "LINE9")
		,m_pia1(*this, PIA1_TAG)
		,m_pia2(*this, PIA2_TAG)
		,m_pia1_B(0)
		,m_50hz(0)
		{ }

	void e100(machine_config &config);

private:
	required_device<m6802_cpu_device> m_maincpu;
	required_device<ttl74145_device> m_kbd_74145;
	required_shared_ptr<uint8_t> m_videoram;
	required_device<cassette_image_device> m_cassette;
	optional_device<rs232_port_device> m_rs232;
	uint8_t *m_char_ptr;
	uint8_t *m_vram;
	uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
	virtual void machine_reset() override { m_maincpu->reset(); LOG("--->%s()\n", FUNCNAME); };
	virtual void machine_start() override;
	DECLARE_READ8_MEMBER( pia_r );
	DECLARE_WRITE8_MEMBER( pia_w );
	DECLARE_READ8_MEMBER( pia1_kbA_r );
	DECLARE_WRITE8_MEMBER( pia1_kbA_w );
	DECLARE_READ8_MEMBER( pia1_kbB_r );
	DECLARE_WRITE8_MEMBER( pia1_kbB_w );
	DECLARE_READ_LINE_MEMBER( pia1_ca1_r );
	DECLARE_READ_LINE_MEMBER( pia1_cb1_r );
	DECLARE_WRITE_LINE_MEMBER( pia1_ca2_w);
	DECLARE_WRITE_LINE_MEMBER( pia1_cb2_w);
	TIMER_DEVICE_CALLBACK_MEMBER(rtc_w);
	void e100_map(address_map &map);

	required_ioport m_io_line0;
	required_ioport m_io_line1;
	required_ioport m_io_line2;
	required_ioport m_io_line3;
	required_ioport m_io_line4;
	required_ioport m_io_line5;
	required_ioport m_io_line6;
	required_ioport m_io_line7;
	required_ioport m_io_line8;
	required_ioport m_io_line9;
	required_device<pia6821_device> m_pia1;
	required_device<pia6821_device> m_pia2;
	uint8_t m_pia1_B;
	uint8_t m_50hz;
};

TIMER_DEVICE_CALLBACK_MEMBER(e100_state::rtc_w)
{
	m_pia2->ca1_w((m_50hz++ & 1));
}

void e100_state::machine_start()
{
	LOG("%s()\n", FUNCNAME);
	m_char_ptr  = memregion("chargen")->base();
	m_vram      = (uint8_t *)m_videoram.target();

	/* register for state saving */
	save_pointer (NAME (m_char_ptr), sizeof(m_char_ptr));
	save_pointer (NAME (m_vram), sizeof(m_vram));
	save_item(NAME(m_50hz));
	save_item(NAME(m_pia1_B));
}

uint32_t e100_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	int x, y;
	int vramad;
	uint8_t *chardata;
	uint8_t charcode;

	LOGSCREEN("%s()\n", FUNCNAME);
	vramad = 0;
	for (int row = 0; row < 32 * 8; row += 8)
	{
		for (int col = 0; col < 32 * 8; col += 8)
		{
			/* look up the character data */
			charcode = m_vram[vramad];
			if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN("\n %c at X=%d Y=%d: ", charcode, col, row);
			chardata = &m_char_ptr[(charcode * 8)];
			/* plot the character */
			for (y = 0; y < 8; y++)
			{
				if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN("\n  %02x: ", *chardata);
				for (x = 0; x < 8; x++)
				{
					if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN(" %02x: ", *chardata);
					bitmap.pix16(row + y, col + x) = (*chardata & (1 << x)) ? 1 : 0;
				}
				chardata++;
			}
			vramad++;
		}
		if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN("\n");
	}

	return 0;
}

/* PIA write - the Esselte 100 allows the PIA:s to be accessed simultaneously */
WRITE8_MEMBER( e100_state::pia_w )
{
	LOG("%s(%02x)\n", FUNCNAME, data);
	if ((offset & 0x08) == 0x08)
	{
		LOG("- PIA1\n");
		m_pia1->write(space, offset, data);
	}
	if ((offset & 0x10) == 0x10)
	{
		LOG("- PIA2\n");
		m_pia2->write(space, offset, data);
	}
	if (VERBOSE && (offset & 0x18) == 0x18)
	{
		LOGCS("- Dual device write access!\n");
	}
	if (VERBOSE && (offset & 0x18) == 0x00)
	{
		logerror("- Funny write at offset %02x!\n", offset);
	}
}

/* PIA read  - the Esselte 100 allows the PIA:s to be accessed simultaneously */
READ8_MEMBER( e100_state::pia_r )
{
	uint8_t data = 0;

	switch (offset & 0x18)
	{
	case 0x18: // read PIA1 and PIA2 at the same time, should really only happen for writes...
		{
			uint8_t data1 =  m_pia1->read(space, offset);
			uint8_t data2 =  m_pia2->read(space, offset);
			logerror("%s: Dual device read may have caused unpredictable results on real hardware\n", FUNCNAME);
			data = data1 & data2; // We assume that the stable behaviour is that data lines with a low level by either device succeeds
			LOGCS("%s %s[%02x] %02x & %02x -> %02x Dual device read!!\n", PIA1_TAG "/" PIA2_TAG, FUNCNAME, offset, data1, data2, data);
		}
		break;
	case 0x08: // PIA1
		data = m_pia1->read(space, offset);
		LOGCS("%s %s(%02x)\n", PIA1_TAG, FUNCNAME, data);
		break;
	case 0x10: // PIA2
		data = m_pia2->read(space, offset);
		LOGCS("%s %s(%02x)\n", PIA2_TAG, FUNCNAME, data);
		break;
	default: // None of the devices are selected
		logerror("%s: Funny read at offset %02x\n", FUNCNAME, offset);
	}
	return data;
}

WRITE8_MEMBER( e100_state::pia1_kbA_w )
{
	LOG("%s(%02x)\n", FUNCNAME, data);
}

READ8_MEMBER( e100_state::pia1_kbA_r )
{
	int ls145;
	uint8_t pa = 0x00;

	// Read out the selected column
	ls145 = m_kbd_74145->read() & 0x3ff;

	// read out the artwork
	switch (ls145)
	{
	case 0: pa = 0x00; break;
	case 1 << 0: pa = (~m_io_line0->read()) & 0xff; break;
	case 1 << 1: pa = (~m_io_line1->read()) & 0xff; break;
	case 1 << 2: pa = (~m_io_line2->read()) & 0xff; break;
	case 1 << 3: pa = (~m_io_line3->read()) & 0xff; break;
	case 1 << 4: pa = (~m_io_line4->read()) & 0xff; break;
	case 1 << 5: pa = (~m_io_line5->read()) & 0xff; break;
	case 1 << 6: pa = (~m_io_line6->read()) & 0xff; break;
	case 1 << 7: pa = (~m_io_line7->read()) & 0xff; break;
	case 1 << 8: pa = (~m_io_line8->read()) & 0xff; break;
	case 1 << 9: pa = (~m_io_line9->read()) & 0xff; break;
	default: logerror("Keyboard is misconfigured, please report!: %04x", ls145); break;
	}
	if (VERBOSE && ls145 && pa) LOGSCAN("%s  [%03x]%04x\n", FUNCNAME, ls145, pa);

	return ~pa;
}

/*
  PB0-PB3 is connected to U601 (74LS145) which select a column to scan
  PB4-PB5 together with CA1, CA2, CB1 and CB2 are used for the printer interface
  PB6-PB7 forms the cassette interface

  The serial bitbanging performs unreliably atm, can be poor original code or inexact CPU timing.
  Best results is achieved with 8 bit at 9600 baud as follows:

    mame e100 -window -rs232 null_modem -bitbngr socket.127.0.0.1:4321

  Start the favourite Telnet client towards the 4321 port and exit the startup screen of MAME.
  At the "Esselte 100 #" prompt change to 8 bit communication and start the terminal mode:

   POKE (69,1)
   TERM(9600)

  It is now possible to send characters from the Esselte screen to the Telnet terminal. When a
  carriage return has been sent to the terminal the Esselte 100 goes into receiving mode until
  it receives a carriage return from the terminal at which point it will start sending again.

  TODO:
  - Fix key mapping of the Ctl-PI exit sequence to get out of the TERM mode.
  - Fix timing issues for the PIA bit banging, could be related to that the CPU emulation is not
    cycle exact or the ROM code is buggy
*/

#define SERIAL_OUT 0x10
#define SERIAL_IN  0x20
#define CASS_OUT   0x40
#define CASS_IN    0x80
WRITE8_MEMBER( e100_state::pia1_kbB_w )
{
	uint8_t col;

	// Keyboard
	//  if (VERBOSE && data != m_pia1_B) LOGSCAN("%s(%02x)\n", FUNCNAME, data);
	m_pia1_B = data;
	col = data & 0x0f;
	m_kbd_74145->write( col );

	// Cassette
	m_cassette->output(data & CASS_OUT ? 1.0 : -1.0);

	// Serial
	m_rs232->write_txd(data & SERIAL_OUT ? 0 : 1);
}

READ8_MEMBER( e100_state::pia1_kbB_r )
{
	m_pia1_B &= ~(CASS_IN|SERIAL_IN);

	m_pia1_B |= (m_cassette->input() > 0.03 ? CASS_IN : 0x00);

	m_pia1_B |= (m_rs232->rxd_r() != 0 ? SERIAL_IN : 0x00);

	return m_pia1_B;
}

READ_LINE_MEMBER(e100_state::pia1_ca1_r)
{
	// TODO: Make this a slot device for time meassurements
	return ASSERT_LINE;  // Default is handshake for serial port TODO: Fix RS 232 handshake as default
}

READ_LINE_MEMBER(e100_state::pia1_cb1_r)
{
	return m_rs232->rxd_r();
}

WRITE_LINE_MEMBER(e100_state::pia1_ca2_w)
{
	// TODO: Make this a slot device to trigger time meassurements
}

WRITE_LINE_MEMBER(e100_state::pia1_cb2_w)
{
	m_rs232->write_txd(!state);
}

// This map is derived from info in "TEMAL 100 - teknisk manual Esselte 100"
void e100_state::e100_map(address_map &map)
{
	map(0x0000, 0x1fff).ram();
	map(0x8000, 0x87ff).rom().region("roms", 0);
	map(0xc000, 0xc3ff).ram().share("videoram");
	map(0xc800, 0xc81f).rw(FUNC(e100_state::pia_r), FUNC(e100_state::pia_w)).mirror(0x07e0);
	map(0xd000, 0xffff).rom().region("roms", 0x1000);
}

/* E100 Input ports
 * Four e100 keys are not mapped yet,
 * - The redundant '*' on the keyboard together with the '\'' single quote, both on same e100 key
 * - The 'E' key on the keypad, presumably used for calculator applications to remove the last entered number
 * - The 'Break' key on rev2 will be mapped to NMI at some point, a recomended modification of the rev1 mother board
 * - The 'REPT' key has a so far unknown function
 */
static INPUT_PORTS_START( e100 )
/*  Bits read on PIA1 A when issueing line number on PIA1 B bits 0-3 through a 74145 demultiplexer */
	PORT_START("LINE0")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_UNUSED)
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_UNUSED)
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_SPACE)        PORT_CHAR(' ')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_LSHIFT)       PORT_CODE(KEYCODE_RSHIFT)       PORT_CHAR(UCHAR_SHIFT_1)
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_LCONTROL)     PORT_CHAR(UCHAR_SHIFT_2)
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)   PORT_NAME("REPT") /* Not mapped yet */
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_UNUSED)
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_UNUSED)

	PORT_START("LINE1")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_UNUSED)
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_UNUSED)
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_Z)            PORT_CHAR('z')  PORT_CHAR('Z')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_A)            PORT_CHAR('a')  PORT_CHAR('A')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_Q)            PORT_CHAR('q')  PORT_CHAR('Q')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_1)            PORT_CHAR('1')  PORT_CHAR('!')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_UNUSED)
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_UNUSED)

	PORT_START("LINE2")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_PLUS_PAD)     PORT_CHAR('+')
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_MINUS_PAD)    PORT_CHAR('-')
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_X)            PORT_CHAR('x')  PORT_CHAR('X')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_S)            PORT_CHAR('s')  PORT_CHAR('S')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_W)            PORT_CHAR('w')  PORT_CHAR('W')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_2)            PORT_CHAR('2')  PORT_CHAR('"')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_SLASH_PAD)    PORT_CHAR('/')
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_ASTERISK)     PORT_CHAR('*')

	PORT_START("LINE3")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_COLON)        PORT_CHAR(0xF6) PORT_CHAR(0xD6)
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_UNUSED)
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_STOP)         PORT_CHAR('.')  PORT_CHAR(':')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_L)            PORT_CHAR('l')  PORT_CHAR('L')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_O)            PORT_CHAR('o')  PORT_CHAR('O')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_9)            PORT_CHAR(')')  PORT_CHAR('9')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_P)            PORT_CHAR('p')  PORT_CHAR('P')
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_0)            PORT_CHAR('0')  PORT_CHAR('=')

	PORT_START("LINE4")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_QUOTE)        PORT_CHAR(0xE4) PORT_CHAR(0xC4)
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_SLASH)        PORT_CHAR('-')  PORT_CHAR('_')
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_COMMA)        PORT_CHAR(',')  PORT_CHAR(';')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_K)            PORT_CHAR('k')  PORT_CHAR('K')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_I)            PORT_CHAR('i')  PORT_CHAR('I')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_8)            PORT_CHAR('8')  PORT_CHAR('(')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_OPENBRACE)    PORT_CHAR(0xE5) PORT_CHAR(0xC5)
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_MINUS)        PORT_CHAR('+')  PORT_CHAR('?')

	PORT_START("LINE5")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_KEYBOARD) PORT_NAME("'/*") /* No good mapping */
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_UNUSED)
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_M)            PORT_CHAR('m')  PORT_CHAR('M')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_J)            PORT_CHAR('j')  PORT_CHAR('J')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_U)            PORT_CHAR('u')  PORT_CHAR('U')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_7)            PORT_CHAR('7')  PORT_CHAR('/')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_CLOSEBRACE)   PORT_CHAR('^')
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_KEYBOARD) PORT_NAME("PI")               PORT_CODE(KEYCODE_ESC)          PORT_CHAR(0x27)

	PORT_START("LINE6")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_LEFT)         PORT_CHAR(UCHAR_MAMEKEY(LEFT))  PORT_CHAR(UCHAR_MAMEKEY(UP))
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_RIGHT)        PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_N)            PORT_CHAR('n')  PORT_CHAR('N')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_H)            PORT_CHAR('h')  PORT_CHAR('H')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_Y)            PORT_CHAR('y')  PORT_CHAR('Y')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_6)            PORT_CHAR('&')  PORT_CHAR('6')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_ENTER)        PORT_CHAR('\r')
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_BACKSLASH2)   PORT_CHAR('<')  PORT_CHAR('>')

	PORT_START("LINE7")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_1_PAD)        PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_0_PAD)        PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_B)            PORT_CHAR('b')  PORT_CHAR('B')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_G)            PORT_CHAR('g')  PORT_CHAR('G')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_T)            PORT_CHAR('t')  PORT_CHAR('T')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_5)            PORT_CHAR('5')  PORT_CHAR('%')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_4_PAD)        PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_7_PAD)        PORT_CHAR(UCHAR_MAMEKEY(7_PAD))

	PORT_START("LINE8")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_2_PAD)        PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_DEL_PAD)      PORT_CHAR(UCHAR_MAMEKEY(STOP))
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_V)            PORT_CHAR('v')  PORT_CHAR('V')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_F)            PORT_CHAR('f')  PORT_CHAR('F')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_R)            PORT_CHAR('r')  PORT_CHAR('R')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_4)            PORT_CHAR('4')  PORT_CHAR('$')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_5_PAD)        PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_8_PAD)        PORT_CHAR(UCHAR_MAMEKEY(8_PAD))

	PORT_START("LINE9")
	PORT_BIT(0x01, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
	PORT_BIT(0x02, IP_ACTIVE_LOW,   IPT_KEYBOARD) PORT_NAME("Keypad E") /* No good mapping */
	PORT_BIT(0x04, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_C)            PORT_CHAR('c')  PORT_CHAR('C')
	PORT_BIT(0x08, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_D)            PORT_CHAR('d')  PORT_CHAR('D')
	PORT_BIT(0x10, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_E)            PORT_CHAR('e')  PORT_CHAR('E')
	PORT_BIT(0x20, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_3)            PORT_CHAR('3')  PORT_CHAR('#')
	PORT_BIT(0x40, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_6_PAD)        PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
	PORT_BIT(0x80, IP_ACTIVE_LOW,   IPT_KEYBOARD)                               PORT_CODE(KEYCODE_9_PAD)        PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
INPUT_PORTS_END

MACHINE_CONFIG_START(e100_state::e100)
	MCFG_DEVICE_ADD("maincpu", M6802, XTAL(4'000'000))
	MCFG_DEVICE_PROGRAM_MAP(e100_map)

	/* Devices */
	TTL74145(config, m_kbd_74145, 0);

	/* --PIA inits----------------------- */
	/* 0xF883 0xC818 (PIA1 DDR A)     = 0x00 - Port A all inputs */
	/* 0xF883 0xC818 (PIA2 DDR A)     = 0x00 - Port A all inputs */
	/* 0xF883 0xC818 (PIA1 Control A) = 0x00 - Channel A IRQ disabled */
	/* 0xF883 0xC818 (PIA2 Control A) = 0x00 - Channel A IRQ disabled */
	/* 0xF886 0xC81A (PIA1 DDR B)     = 0x00 - Port B all inputs */
	/* 0xF886 0xC81A (PIA2 DDR B)     = 0x00 - Port B all inputs */
	/* 0xF886 0xC81A (PIA1 Control B) = 0x00 - Channel B IRQ disabled */
	/* 0xF886 0xC81A (PIA2 Control B) = 0x00 - Channel B IRQ disabled */
	/* 0xF88e 0xC80A (PIA1 DDR B)     = 0x4F - Port B 5 outputs set to 0 */
	/* 0xF890 0xC812 (PIA2 DDR B)     = 0xFF - Port B all outputs set to 0 */
	/* 0xF894 0xC818 (PIA1 Control A) = 0x34 - CA2 is low and lock DDRA */
	/* 0xF894 0xC818 (PIA2 Control A) = 0x34 - CA2 is low and lock DDRA */
	/* 0xF896 0xC818 (PIA1 Control B) = 0x34 - CB2 is low and lock DDRB */
	/* 0xF896 0xC818 (PIA2 Control B) = 0x34 - CB2 is low and lock DDRB */
	PIA6821(config, m_pia1, 0);
	m_pia1->writepa_handler().set(FUNC(e100_state::pia1_kbA_w));
	m_pia1->readpa_handler().set(FUNC(e100_state::pia1_kbA_r));
	m_pia1->writepb_handler().set(FUNC(e100_state::pia1_kbB_w));
	m_pia1->readpb_handler().set(FUNC(e100_state::pia1_kbB_r));
	m_pia1->readca1_handler().set(FUNC(e100_state::pia1_ca1_r));
	m_pia1->readcb1_handler().set(FUNC(e100_state::pia1_cb1_r));
	m_pia1->ca2_handler().set(FUNC(e100_state::pia1_ca2_w));
	m_pia1->cb2_handler().set(FUNC(e100_state::pia1_cb2_w));

	/* The optional second PIA enables the expansion port on CA1 and a software RTC with 50Hz resolution */
	PIA6821(config, m_pia2, 0);
	m_pia2->irqa_handler().set_inputline("maincpu", M6800_IRQ_LINE);

	/* Serial port support */
	RS232_PORT(config, m_rs232, default_rs232_devices, nullptr);

	/* Cassette support - E100 uses 300 baud Kansas City Standard with 1200/2400 Hz modulation */
	/* NOTE on usage: mame e100 -window -cass <wav file> -ui_active
	 * Once running enable/disable internal UI by pressing Scroll Lock in case it interferes with target keys
	 * Open the internal UI by pressing TAB and then select 'Tape Control' or use F2/Shift F2 for PLAY/PAUSE
	 * In order to use a wav file it has first to be created using TAB and select the 'File manager'
	 * Once created it may be given on the commandline or mounted via TAB and select
	 * E100 supports cassette through the 'LOAD' and 'SAVE' commands with no arguments
	 */
	MCFG_CASSETTE_ADD( "cassette" )
	MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_SPEAKER_MUTED | CASSETTE_MOTOR_ENABLED)

	/* screen TODO: simplify the screen config, look at zx.cpp */
	MCFG_SCREEN_ADD("screen", RASTER)
	MCFG_SCREEN_RAW_PARAMS(XTAL(4'000'000)/2, 265, 0, 265, 265, 0, 265)
	MCFG_SCREEN_UPDATE_DRIVER(e100_state, screen_update)
	MCFG_SCREEN_PALETTE("palette")
	PALETTE(config, "palette", palette_device::MONOCHROME);

	/* There is a 50Hz signal from the video circuit to CA1 which generates interrupts and drives a software RTC */
	MCFG_TIMER_DRIVER_ADD_PERIODIC("video50hz", e100_state, rtc_w, attotime::from_hz(100)) /* Will be divided by two through toggle in the handler */
MACHINE_CONFIG_END

/* ROM sets from Didact was not versioned in general, so the numbering are just assumptions */
ROM_START( e100 )
	ROM_REGION(0x4000, "roms", 0)
	ROM_DEFAULT_BIOS("rev2-basic")

	/* TODO: Get the original ROMs */
	ROM_SYSTEM_BIOS(0, "rev1-basic", "Esselte 100 rev1 BASIC")
	ROMX_LOAD( "e100r1u201.bin", 0x1000, 0x0800, NO_DUMP, ROM_BIOS(0) )
	ROMX_LOAD( "e100r1u202.bin", 0x1800, 0x0800, NO_DUMP, ROM_BIOS(0) )
	ROMX_LOAD( "e100r1u203.bin", 0x2000, 0x0800, NO_DUMP, ROM_BIOS(0) )
	ROMX_LOAD( "e100r1u204.bin", 0x2800, 0x0800, NO_DUMP, ROM_BIOS(0) )
	ROMX_LOAD( "e100r1u205.bin", 0x3000, 0x0800, NO_DUMP, ROM_BIOS(0) )
	ROMX_LOAD( "e100r1u206.bin", 0x3800, 0x0800, NO_DUMP, ROM_BIOS(0) )

	/* This is a prototype ROM, commercial relase not verified. The prototype also have different keyboard and supports
	   more ram so might need to be split out as a clone later */
	ROM_SYSTEM_BIOS(1, "rev2-basic", "Esselte 100 rev2 BASIC")
	ROMX_LOAD( "e100r2u201.bin", 0x0000, 0x2000, CRC(53513b67) SHA1(a91c5c32aead82dcc87db5d818ff286a7fc6a5c8), ROM_BIOS(1) )
	ROMX_LOAD( "e100r2u202.bin", 0x2000, 0x2000, CRC(eab3adf2) SHA1(ff3f5f5c8ea8732702a39cff76d0706ab6b751ee), ROM_BIOS(1) )

	ROM_REGION(0x0800, "chargen",0)
	ROM_LOAD( "e100u506.bin", 0x0000, 0x0800, CRC(fff9f288) SHA1(2dfb3eb551fe1ef67da328f61ef51ae8d1abdfb8) )
ROM_END

//    YEAR  NAME  PARENT  COMPAT  MACHINE  INPUT  CLASS       INIT        COMPANY      FULLNAME       FLAGS
COMP( 1982, e100, 0,      0,      e100,    e100,  e100_state, empty_init, "Didact AB", "Esselte 100", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE)