summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/drivers/einstein.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/drivers/einstein.c')
-rw-r--r--src/mess/drivers/einstein.c909
1 files changed, 909 insertions, 0 deletions
diff --git a/src/mess/drivers/einstein.c b/src/mess/drivers/einstein.c
new file mode 100644
index 00000000000..e3024ec298e
--- /dev/null
+++ b/src/mess/drivers/einstein.c
@@ -0,0 +1,909 @@
+/******************************************************************************
+
+ Tatung Einstein
+ system driver
+
+
+ TMS9129 VDP Graphics
+ 16k ram
+
+ Z80 CPU (4 MHz)
+
+ Z80 CTC (4 MHz)
+ channel 0 is serial transmit clock
+ channel 1 is serial receive clock
+ trigger for channel 0,1 and 2 is a 2 MHz clock
+ trigger for channel 3 is the terminal count of channel 2
+
+ Intel 8251 Serial (2 MHz clock?)
+
+ WD1770 Floppy Disc controller
+ density is fixed, 4 drives and double sided supported
+
+ AY-3-8910 PSG (2 MHz)
+ port A and port B are connected to the keyboard. Port A is keyboard
+ line select, Port B is data.
+
+ printer connected to port A of PIO. /ACK from printer is connected to /ASTB.
+ D7-D0 of PIO port A is printer data lines.
+ ARDY of PIO is connected to /STROBE on printer.
+
+ user port is port B of PIO
+ keyboard connected to port A and port B of PSG
+
+ TODO:
+ - The ADC is not emulated!
+ - printer emulation needs checking!
+
+ Many thanks to Chris Coxall for the schematics of the TC-01, the dump of the
+ system rom and a dump of a Xtal boot disc.
+
+ Many thanks to Andrew Dunipace for his help with the 80-column card
+ and Speculator hardware (Spectrum emulator).
+
+ Kevin Thacker [MESS driver]
+
+
+ 2011-Mar-14, Phill Harvey-Smith.
+ Having traced out the circuit of the TK02 80 coumn card, I have changed the
+ emulation to match what the hardware does, the emulation was mostly correct,
+ just some minor issues with the addressing of the VRAM, and bit 0 of the
+ status register is the latched output of the 6845 DE, and not vblank.
+
+ Also added defines to stop the log being flooded with keyboard messages :)
+
+ ******************************************************************************/
+
+#include "emu.h"
+#include "machine/z80ctc.h"
+#include "machine/z80pio.h"
+#include "machine/z80sio.h"
+#include "video/tms9928a.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+#include "machine/wd1772.h"
+#include "formats/hxcmfm_dsk.h"
+#include "formats/mfi_dsk.h"
+#include "formats/dsk_dsk.h"
+#include "machine/ctronics.h"
+#include "machine/i8251.h"
+#include "imagedev/flopdrv.h"
+#include "sound/ay8910.h"
+#include "video/mc6845.h"
+#include "rendlay.h"
+#include "machine/ram.h"
+#include "includes/einstein.h"
+
+#define VERBOSE_KEYBOARD 0
+#define VERBOSE_DISK 0
+
+const floppy_format_type einstein_state::floppy_formats[] = {
+ FLOPPY_DSK_FORMAT, FLOPPY_MFM_FORMAT, FLOPPY_MFI_FORMAT,
+ NULL
+};
+
+/***************************************************************************
+ 80 COLUMN DEVICE
+***************************************************************************/
+
+/* lower 3 bits of address define a 256-byte "row".
+ * upper 8 bits define the offset in the row,
+ * data bits define data to write
+ */
+WRITE8_MEMBER(einstein_state::einstein_80col_ram_w)
+{
+ m_crtc_ram[((offset & 0x07) << 8) | ((offset >> 8) & 0xff)] = data;
+}
+
+READ8_MEMBER(einstein_state::einstein_80col_ram_r)
+{
+ return m_crtc_ram[((offset & 0x07) << 8) | ((offset >> 8) & 0xff)];
+}
+
+/* TODO: Verify implementation */
+/* From traces of the TK02 board character ROM is addressed by the 6845 as follows
+ bit 0..2 ra0..ra2
+ bit 3..10 data 0..7 from VRAM
+ bit 11 ra3
+ bit 12 jumper M004, this could be used to select two different character
+ sets.
+*/
+static MC6845_UPDATE_ROW( einstein_6845_update_row )
+{
+ einstein_state *einstein = device->machine().driver_data<einstein_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ UINT8 *data = device->machine().root_device().memregion("gfx1")->base();
+ UINT8 char_code, data_byte;
+ int i, x;
+
+ for (i = 0, x = 0; i < x_count; i++, x += 8)
+ {
+ char_code = einstein->m_crtc_ram[(ma + i) & 0x07ff];
+ data_byte = data[(char_code << 3) + (ra & 0x07) + ((ra & 0x08) << 8)];
+
+ bitmap.pix32(y, x + 0) = palette[TMS9928A_PALETTE_SIZE + BIT(data_byte, 7)];
+ bitmap.pix32(y, x + 1) = palette[TMS9928A_PALETTE_SIZE + BIT(data_byte, 6)];
+ bitmap.pix32(y, x + 2) = palette[TMS9928A_PALETTE_SIZE + BIT(data_byte, 5)];
+ bitmap.pix32(y, x + 3) = palette[TMS9928A_PALETTE_SIZE + BIT(data_byte, 4)];
+ bitmap.pix32(y, x + 4) = palette[TMS9928A_PALETTE_SIZE + BIT(data_byte, 3)];
+ bitmap.pix32(y, x + 5) = palette[TMS9928A_PALETTE_SIZE + BIT(data_byte, 2)];
+ bitmap.pix32(y, x + 6) = palette[TMS9928A_PALETTE_SIZE + BIT(data_byte, 1)];
+ bitmap.pix32(y, x + 7) = palette[TMS9928A_PALETTE_SIZE + BIT(data_byte, 0)];
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( einstein_6845_de_changed )
+{
+ einstein_state *einstein = device->machine().driver_data<einstein_state>();
+ einstein->m_de=state;
+}
+
+/* bit 0 - latched display enabled (DE) from 6845
+ * bit 1 - Jumper M003 0 = 40 column mode (color monitor), 1 = 80 column mode (b/w monitor)
+ * bit 2 - Jumper M002 0 = 50Hz, 1 = 60Hz
+ * bit 3 - Jumper M001 0 = ???, 1=??? perminently wired high on both the boards I have seen - PHS.
+ */
+READ8_MEMBER(einstein_state::einstein_80col_state_r)
+{
+ UINT8 result = 0;
+
+ result |= m_de;
+ result |= ioport("80column_dips")->read() & 0x06;
+
+ return result;
+}
+
+/* int priority */
+/* keyboard int->ctc/adc->pio */
+static const z80_daisy_config einstein_daisy_chain[] =
+{
+ { "keyboard_daisy" },
+ { IC_I058 },
+ { "adc_daisy" },
+ { IC_I063 },
+ { "fire_daisy" },
+ { NULL }
+};
+
+
+/***************************************************************************
+ KEYBOARD
+***************************************************************************/
+
+/* refresh keyboard data. It is refreshed when the keyboard line is written */
+static void einstein_scan_keyboard(running_machine &machine)
+{
+ einstein_state *einstein = machine.driver_data<einstein_state>();
+ UINT8 data = 0xff;
+
+ if (!BIT(einstein->m_keyboard_line, 0)) data &= machine.root_device().ioport("LINE0")->read();
+ if (!BIT(einstein->m_keyboard_line, 1)) data &= machine.root_device().ioport("LINE1")->read();
+ if (!BIT(einstein->m_keyboard_line, 2)) data &= machine.root_device().ioport("LINE2")->read();
+ if (!BIT(einstein->m_keyboard_line, 3)) data &= machine.root_device().ioport("LINE3")->read();
+ if (!BIT(einstein->m_keyboard_line, 4)) data &= machine.root_device().ioport("LINE4")->read();
+ if (!BIT(einstein->m_keyboard_line, 5)) data &= machine.root_device().ioport("LINE5")->read();
+ if (!BIT(einstein->m_keyboard_line, 6)) data &= machine.root_device().ioport("LINE6")->read();
+ if (!BIT(einstein->m_keyboard_line, 7)) data &= machine.root_device().ioport("LINE7")->read();
+
+ einstein->m_keyboard_data = data;
+}
+
+static TIMER_DEVICE_CALLBACK( einstein_keyboard_timer_callback )
+{
+ einstein_state *einstein = timer.machine().driver_data<einstein_state>();
+
+ /* re-scan keyboard */
+ einstein_scan_keyboard(timer.machine());
+
+ /* if /fire1 or /fire2 is 0, signal a fire interrupt */
+ if ((timer.machine().root_device().ioport("BUTTONS")->read() & 0x03) != 0)
+ {
+ einstein->m_interrupt |= EINSTEIN_FIRE_INT;
+ }
+
+ /* keyboard data changed? */
+ if (einstein->m_keyboard_data != 0xff)
+ {
+ /* generate interrupt */
+ einstein->m_interrupt |= EINSTEIN_KEY_INT;
+ }
+}
+
+WRITE8_MEMBER(einstein_state::einstein_keyboard_line_write)
+{
+
+ if (VERBOSE_KEYBOARD)
+ logerror("einstein_keyboard_line_write: %02x\n", data);
+
+ m_keyboard_line = data;
+
+ /* re-scan the keyboard */
+ einstein_scan_keyboard(machine());
+}
+
+READ8_MEMBER(einstein_state::einstein_keyboard_data_read)
+{
+
+ /* re-scan the keyboard */
+ einstein_scan_keyboard(machine());
+
+ if (VERBOSE_KEYBOARD)
+ logerror("einstein_keyboard_data_read: %02x\n", m_keyboard_data);
+
+ return m_keyboard_data;
+}
+
+
+/***************************************************************************
+ FLOPPY DRIVES
+***************************************************************************/
+
+static WRITE8_DEVICE_HANDLER( einstein_drsel_w )
+{
+ einstein_state *einstein = device->machine().driver_data<einstein_state>();
+ if(VERBOSE_DISK)
+ logerror("%s: einstein_drsel_w %02x\n", device->machine().describe_context(), data);
+
+ /* bit 0 to 3 select the drive */
+ static const char *names[] = { "fd0", "fd1", "fd2", "fd3" };
+ floppy_image_device *floppy = 0;
+ for(int i=0; i<4; i++) {
+ if(BIT(data, i)) {
+ floppy_connector *con = device->machine().device<floppy_connector>(names[i]);
+ if(con)
+ floppy = con->get_device();
+ }
+ }
+
+ /* double sided drive connected? */
+ if (device->machine().root_device().ioport("config")->read() & data)
+ {
+ /* bit 4 selects the side then */
+ //floppy->ss_w(BIT(data, 4));
+ }
+ if (floppy) floppy->ss_w(0);
+ einstein->m_fdc->set_floppy(floppy);
+}
+
+
+/***************************************************************************
+ CTC
+***************************************************************************/
+
+/* channel 0 and 1 have a 2 MHz input clock for triggering */
+static TIMER_DEVICE_CALLBACK( einstein_ctc_trigger_callback )
+{
+ einstein_state *einstein = timer.machine().driver_data<einstein_state>();
+
+ /* toggle line status */
+ einstein->m_ctc_trigger ^= 1;
+
+ einstein->m_ctc->trg0(einstein->m_ctc_trigger);
+ einstein->m_ctc->trg1(einstein->m_ctc_trigger);
+}
+
+
+/***************************************************************************
+ UART
+***************************************************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( einstein_serial_transmit_clock )
+{
+ i8251_device *uart = device->machine().device<i8251_device>(IC_I060);
+ uart->transmit_clock();
+}
+
+static WRITE_LINE_DEVICE_HANDLER( einstein_serial_receive_clock )
+{
+ i8251_device *uart = device->machine().device<i8251_device>(IC_I060);
+ uart->receive_clock();
+}
+
+
+/***************************************************************************
+ MEMORY BANKING
+***************************************************************************/
+
+static void einstein_page_rom(running_machine &machine)
+{
+ einstein_state *state = machine.driver_data<einstein_state>();
+ state->membank("bank1")->set_base(state->m_rom_enabled ? machine.root_device().memregion("bios")->base() : machine.device<ram_device>(RAM_TAG)->pointer());
+}
+
+/* writing to this port is a simple trigger, and switches between RAM and ROM */
+WRITE8_MEMBER(einstein_state::einstein_rom_w)
+{
+ m_rom_enabled ^= 1;
+ einstein_page_rom(machine());
+}
+
+
+/***************************************************************************
+ INTERRUPTS
+***************************************************************************/
+
+READ8_MEMBER(einstein_state::einstein_kybintmsk_r)
+{
+ centronics_device *centronics = machine().device<centronics_device>("centronics");
+ UINT8 data = 0;
+
+ /* clear key int. a read of this I/O port will do this or a reset */
+ m_interrupt &= ~EINSTEIN_KEY_INT;
+
+ /* bit 0 and 1: fire buttons on the joysticks */
+ data |= ioport("BUTTONS")->read();
+
+ /* bit 2 to 4: printer status */
+ data |= centronics->busy_r() << 2;
+ data |= centronics->pe_r() << 3;
+ data |= centronics->fault_r() << 4;
+
+ /* bit 5 to 7: graph, control and shift key */
+ data |= ioport("EXTRA")->read();
+
+ if(VERBOSE_KEYBOARD)
+ logerror("%s: einstein_kybintmsk_r %02x\n", machine().describe_context(), data);
+
+ return data;
+}
+
+WRITE8_MEMBER(einstein_state::einstein_kybintmsk_w)
+{
+
+ logerror("%s: einstein_kybintmsk_w %02x\n", machine().describe_context(), data);
+
+ /* set mask from bit 0 */
+ if (data & 0x01)
+ {
+ logerror("key int is disabled\n");
+ m_interrupt_mask &= ~EINSTEIN_KEY_INT;
+ }
+ else
+ {
+ logerror("key int is enabled\n");
+ m_interrupt_mask |= EINSTEIN_KEY_INT;
+ }
+}
+
+/* writing to this I/O port sets the state of the mask; D0 is used */
+/* writing 0 enables the /ADC interrupt */
+WRITE8_MEMBER(einstein_state::einstein_adcintmsk_w)
+{
+
+ logerror("%s: einstein_adcintmsk_w %02x\n", machine().describe_context(), data);
+
+ if (data & 0x01)
+ {
+ logerror("adc int is disabled\n");
+ m_interrupt_mask &= ~EINSTEIN_ADC_INT;
+ }
+ else
+ {
+ logerror("adc int is enabled\n");
+ m_interrupt_mask |= EINSTEIN_ADC_INT;
+ }
+}
+
+/* writing to this I/O port sets the state of the mask; D0 is used */
+/* writing 0 enables the /FIRE interrupt */
+WRITE8_MEMBER(einstein_state::einstein_fire_int_w)
+{
+
+ logerror("%s: einstein_fire_int_w %02x\n", machine().describe_context(), data);
+
+ if (data & 0x01)
+ {
+ logerror("fire int is disabled\n");
+ m_interrupt_mask &= ~EINSTEIN_FIRE_INT;
+ }
+ else
+ {
+ logerror("fire int is enabled\n");
+ m_interrupt_mask |= EINSTEIN_FIRE_INT;
+ }
+}
+
+
+/***************************************************************************
+ MACHINE EMULATION
+***************************************************************************/
+
+static TMS9928A_INTERFACE(einstein_tms9929a_interface)
+{
+ "screen",
+ 0x4000, /* 16k RAM, provided by IC i040 and i041 */
+ DEVCB_NULL
+};
+
+static MACHINE_START( einstein )
+{
+}
+
+static MACHINE_RESET( einstein )
+{
+ einstein_state *state = machine.driver_data<einstein_state>();
+ //device_t *floppy;
+ //UINT8 config = machine.root_device().ioport("config")->read();
+
+ /* save pointers to our devices */
+ state->m_color_screen = machine.device("screen");
+ state->m_ctc = machine.device<z80ctc_device>(IC_I058);
+
+ /* initialize memory mapping */
+ state->membank("bank2")->set_base(machine.device<ram_device>(RAM_TAG)->pointer());
+ state->membank("bank3")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x8000);
+ state->m_rom_enabled = 1;
+ einstein_page_rom(machine);
+
+ /* a reset causes the fire int, adc int, keyboard int mask
+ to be set to 1, which causes all these to be DISABLED */
+ state->m_interrupt = 0;
+ state->m_interrupt_mask = 0;
+
+ state->m_ctc_trigger = 0;
+
+ /* configure floppy drives */
+/* floppy_type_t type_80 = FLOPPY_STANDARD_5_25_DSHD;
+ floppy_type_t type_40 = FLOPPY_STANDARD_5_25_SSDD_40;
+ floppy = machine.device("floppy0");
+ floppy_drive_set_geometry(floppy, config & 0x01 ? type_80 : type_40);
+ floppy = machine.device("floppy1");
+ floppy_drive_set_geometry(floppy, config & 0x02 ? type_80 : type_40);
+ floppy = machine.device("floppy2");
+ floppy_drive_set_geometry(floppy, config & 0x04 ? type_80 : type_40);
+ floppy = machine.device("floppy3");
+ floppy_drive_set_geometry(floppy, config & 0x08 ? type_80 : type_40);*/
+}
+
+static MACHINE_RESET( einstein2 )
+{
+ einstein_state *einstein = machine.driver_data<einstein_state>();
+
+ /* call standard initialization first */
+ MACHINE_RESET_CALL(einstein);
+
+ /* get 80 column specific devices */
+ einstein->m_mc6845 = machine.device<mc6845_device>("crtc");
+ einstein->m_crtc_screen = machine.device<screen_device>("80column");
+
+ /* 80 column card palette */
+ palette_set_color(machine, TMS9928A_PALETTE_SIZE, RGB_BLACK);
+ palette_set_color(machine, TMS9928A_PALETTE_SIZE + 1, MAKE_RGB(0, 224, 0));
+}
+
+static MACHINE_START( einstein2 )
+{
+ einstein_state *einstein = machine.driver_data<einstein_state>();
+ einstein->m_crtc_ram = auto_alloc_array(machine, UINT8, 2048);
+ MACHINE_START_CALL(einstein);
+}
+
+
+/***************************************************************************
+ VIDEO EMULATION
+***************************************************************************/
+
+static SCREEN_UPDATE_RGB32( einstein2 )
+{
+ einstein_state *einstein = screen.machine().driver_data<einstein_state>();
+
+ if (&screen == einstein->m_color_screen)
+ {
+ tms9929a_device *tms9929a = screen.machine().device<tms9929a_device>( "tms9929a" );
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ bitmap_ind16 &src = tms9929a->get_bitmap();
+ for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
+ for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
+ bitmap.pix32(y, x) = palette[src.pix16(y, x)];
+ }
+ else if (&screen == einstein->m_crtc_screen)
+ einstein->m_mc6845->screen_update( screen, bitmap, cliprect);
+ else
+ fatalerror("Unknown screen '%s'", screen.tag());
+
+ return 0;
+}
+
+
+/***************************************************************************
+ ADDRESS MAPS
+***************************************************************************/
+
+static ADDRESS_MAP_START( einstein_mem, AS_PROGRAM, 8, einstein_state )
+ AM_RANGE(0x0000, 0x07fff) AM_READ_BANK("bank1") AM_WRITE_BANK("bank2")
+ AM_RANGE(0x8000, 0x0ffff) AM_RAMBANK("bank3")
+ADDRESS_MAP_END
+
+/* The I/O ports are decoded into 8 blocks using address lines A3 to A7 */
+static ADDRESS_MAP_START( einstein_io, AS_IO, 8, einstein_state )
+ /* block 0, ay8910 psg */
+ AM_RANGE(0x02, 0x02) AM_MIRROR(0xff04) AM_DEVREADWRITE_LEGACY(IC_I030, ay8910_r, ay8910_address_w)
+ AM_RANGE(0x03, 0x03) AM_MIRROR(0xff04) AM_DEVWRITE_LEGACY(IC_I030, ay8910_data_w)
+ /* block 1, tms9928a vdp */
+ AM_RANGE(0x08, 0x08) AM_MIRROR(0xff06) AM_DEVREADWRITE("tms9929a", tms9929a_device, vram_read, vram_write)
+ AM_RANGE(0x09, 0x09) AM_MIRROR(0xff06) AM_DEVREADWRITE("tms9929a", tms9929a_device, register_read, register_write)
+ /* block 2, i8251 uart */
+ AM_RANGE(0x10, 0x10) AM_MIRROR(0xff06) AM_DEVREADWRITE(IC_I060, i8251_device, data_r, data_w)
+ AM_RANGE(0x11, 0x11) AM_MIRROR(0xff06) AM_DEVREADWRITE(IC_I060, i8251_device, status_r, control_w)
+ /* block 3, wd1770 floppy controller */
+ AM_RANGE(0x18, 0x1b) AM_MIRROR(0xff04) AM_DEVREADWRITE(IC_I042, wd177x_t, read, write)
+ /* block 4, internal controls */
+ AM_RANGE(0x20, 0x20) AM_MIRROR(0xff00) AM_READWRITE(einstein_kybintmsk_r, einstein_kybintmsk_w)
+ AM_RANGE(0x21, 0x21) AM_MIRROR(0xff00) AM_WRITE(einstein_adcintmsk_w)
+ AM_RANGE(0x23, 0x23) AM_MIRROR(0xff00) AM_DEVWRITE_LEGACY(IC_I042, einstein_drsel_w)
+ AM_RANGE(0x24, 0x24) AM_MIRROR(0xff00) AM_WRITE(einstein_rom_w)
+ AM_RANGE(0x25, 0x25) AM_MIRROR(0xff00) AM_WRITE(einstein_fire_int_w)
+ /* block 5, z80ctc */
+ AM_RANGE(0x28, 0x2b) AM_MIRROR(0xff04) AM_DEVREADWRITE(IC_I058, z80ctc_device, read, write)
+ /* block 6, z80pio */
+ AM_RANGE(0x30, 0x33) AM_MIRROR(0xff04) AM_DEVREADWRITE(IC_I063, z80pio_device, read, write)
+#if 0
+ /* block 7, adc */
+ AM_RANGE(0x38, 0x38) AM_MIRROR(0xff07) AM_DEVREADWRITE_LEGACY(IC_I050, adc0844_r, adc0844_w)
+#endif
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( einstein2_io, AS_IO, 8, einstein_state )
+ AM_IMPORT_FROM(einstein_io)
+ AM_RANGE(0x40, 0x47) AM_MIRROR(0xff00) AM_MASK(0xffff) AM_READWRITE(einstein_80col_ram_r, einstein_80col_ram_w)
+ AM_RANGE(0x48, 0x48) AM_MIRROR(0xff00) AM_DEVWRITE("crtc", mc6845_device, address_w)
+ AM_RANGE(0x49, 0x49) AM_MIRROR(0xff00) AM_DEVWRITE("crtc", mc6845_device, register_w)
+ AM_RANGE(0x4c, 0x4c) AM_MIRROR(0xff00) AM_READ(einstein_80col_state_r)
+ADDRESS_MAP_END
+
+
+/***************************************************************************
+ INPUT PORTS
+***************************************************************************/
+
+static INPUT_PORTS_START( einstein )
+ PORT_START("LINE0")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BREAK") PORT_CODE(KEYCODE_LALT)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("?") PORT_CODE(KEYCODE_1_PAD)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F0") PORT_CODE(KEYCODE_F1)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("?") PORT_CODE(KEYCODE_3_PAD)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+
+ PORT_START("LINE1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('\xA3')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\xBA') PORT_CHAR('\xBD') // is \xBA correct for double vertical bar || ?
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('@')
+
+ PORT_START("LINE2")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F5))
+
+ PORT_START("LINE3")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("DELETE") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('-')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F4))
+
+ PORT_START("LINE4")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ 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_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F3))
+
+ PORT_START("LINE5")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F2))
+
+ PORT_START("LINE6")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
+ 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_D) PORT_CHAR('D')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F1))
+
+ PORT_START("LINE7")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
+ 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_V) PORT_CHAR('V')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F6))
+
+ PORT_START("EXTRA")
+ PORT_BIT(0x1f, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("GRPH") PORT_CODE(KEYCODE_F8)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+
+ /* fire buttons for analogue joysticks */
+ PORT_START("BUTTONS")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Joystick 1 Button 1") PORT_PLAYER(1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Joystick 2 Button 1") PORT_PLAYER(2)
+ PORT_BIT(0xfc, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ /* analog joystick 1 x axis */
+ PORT_START("JOY1_X")
+ PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(1) PORT_REVERSE
+
+ /* analog joystick 1 y axis */
+ PORT_START("JOY1_Y")
+ PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(1) PORT_REVERSE
+
+ /* analog joystick 2 x axis */
+ PORT_START("JOY2_X")
+ PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(2) PORT_REVERSE
+
+ /* analog joystick 2 Y axis */
+ PORT_START("JOY2_Y")
+ PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2) PORT_REVERSE
+
+ PORT_START("config")
+ PORT_CONFNAME(0x01, 0x00, "Floppy drive #1")
+ PORT_CONFSETTING(0x00, "Single sided")
+ PORT_CONFSETTING(0x01, "Double sided")
+ PORT_CONFNAME(0x02, 0x00, "Floppy drive #2")
+ PORT_CONFSETTING(0x00, "Single sided")
+ PORT_CONFSETTING(0x02, "Double sided")
+ PORT_CONFNAME(0x04, 0x00, "Floppy drive #3")
+ PORT_CONFSETTING(0x00, "Single sided")
+ PORT_CONFSETTING(0x04, "Double sided")
+ PORT_CONFNAME(0x08, 0x00, "Floppy drive #4")
+ PORT_CONFSETTING(0x00, "Single sided")
+ PORT_CONFSETTING(0x08, "Double sided")
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( einstein_80col )
+ PORT_INCLUDE(einstein)
+
+ /* dip switches on the 80 column card */
+ PORT_START("80column_dips")
+ PORT_DIPNAME(0x02, 0x00, "Startup mode")
+ PORT_DIPSETTING(0x00, "40 column")
+ PORT_DIPSETTING(0x02, "80 column")
+ PORT_DIPNAME(0x04, 0x00, "50/60Hz")
+ PORT_DIPSETTING(0x00, "50Hz")
+ PORT_DIPSETTING(0x04, "60Hz")
+INPUT_PORTS_END
+
+
+/***************************************************************************
+ MACHINE DRIVERS
+***************************************************************************/
+
+static Z80CTC_INTERFACE( einstein_ctc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_LINE(einstein_serial_transmit_clock),
+ DEVCB_LINE(einstein_serial_receive_clock),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF, z80ctc_device, trg3)
+};
+
+
+static Z80PIO_INTERFACE( einstein_pio_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER("centronics", centronics_device, write),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER("centronics", centronics_device, strobe_w),
+ DEVCB_NULL
+};
+
+static const ay8910_interface einstein_ay_interface =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(einstein_state, einstein_keyboard_data_read),
+ DEVCB_DRIVER_MEMBER(einstein_state, einstein_keyboard_line_write),
+ DEVCB_NULL
+};
+
+static const centronics_interface einstein_centronics_config =
+{
+ DEVCB_DEVICE_LINE_MEMBER(IC_I063, z80pio_device, strobe_a),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static const mc6845_interface einstein_crtc6845_interface =
+{
+ "80column",
+ 8,
+ NULL,
+ einstein_6845_update_row,
+ NULL,
+ DEVCB_LINE(einstein_6845_de_changed),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ NULL
+};
+
+/* F4 Character Displayer */
+static const gfx_layout einstei2_charlayout =
+{
+ 8, 10, /* 8 x 10 characters */
+ 256, /* 256*2 characters */
+ 1, /* 1 bits per pixel */
+ { 0 },
+ /* x offsets */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 0x800*8, 0x801*8 },
+ 8*8
+};
+
+static GFXDECODE_START( einstei2 )
+ GFXDECODE_ENTRY( "gfx1", 0x0000, einstei2_charlayout, 16, 1 )
+ GFXDECODE_ENTRY( "gfx1", 0x1000, einstei2_charlayout, 16, 1 )
+GFXDECODE_END
+
+static SLOT_INTERFACE_START( einstein_floppies )
+ SLOT_INTERFACE( "525dd", FLOPPY_525_DD )
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_START( einstein, einstein_state )
+ /* basic machine hardware */
+ MCFG_CPU_ADD(IC_I001, Z80, XTAL_X002 / 2)
+ MCFG_CPU_PROGRAM_MAP(einstein_mem)
+ MCFG_CPU_IO_MAP(einstein_io)
+ MCFG_CPU_CONFIG(einstein_daisy_chain)
+
+ MCFG_MACHINE_START(einstein)
+ MCFG_MACHINE_RESET(einstein)
+
+ /* this is actually clocked at the system clock 4 MHz, but this would be too fast for our
+ driver. So we update at 50Hz and hope this is good enough. */
+ MCFG_TIMER_ADD_PERIODIC("keyboard", einstein_keyboard_timer_callback, attotime::from_hz(50))
+
+ MCFG_Z80PIO_ADD(IC_I063, XTAL_X002 / 2, einstein_pio_intf)
+
+ MCFG_Z80CTC_ADD(IC_I058, XTAL_X002 / 2, einstein_ctc_intf)
+ /* the input to channel 0 and 1 of the ctc is a 2 MHz clock */
+ MCFG_TIMER_ADD_PERIODIC("ctc", einstein_ctc_trigger_callback, attotime::from_hz(XTAL_X002 /4))
+
+ /* Einstein daisy chain support for non-Z80 devices */
+ MCFG_DEVICE_ADD("keyboard_daisy", EINSTEIN_KEYBOARD_DAISY, 0)
+ MCFG_DEVICE_ADD("adc_daisy", EINSTEIN_ADC_DAISY, 0)
+ MCFG_DEVICE_ADD("fire_daisy", EINSTEIN_FIRE_DAISY, 0)
+
+ /* video hardware */
+ MCFG_TMS9928A_ADD( "tms9929a", TMS9929A, einstein_tms9929a_interface )
+ MCFG_TMS9928A_SCREEN_ADD_PAL( "screen" )
+ MCFG_SCREEN_UPDATE_DEVICE( "tms9929a", tms9929a_device, screen_update )
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(IC_I030, AY8910, XTAL_X002 / 4)
+ MCFG_SOUND_CONFIG(einstein_ay_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20)
+
+ /* printer */
+ MCFG_CENTRONICS_PRINTER_ADD("centronics", einstein_centronics_config)
+
+ /* uart */
+ MCFG_I8251_ADD(IC_I060, default_i8251_interface)
+
+ MCFG_WD1770x_ADD(IC_I042, XTAL_X002)
+
+ MCFG_FLOPPY_DRIVE_ADD("fd0", einstein_floppies, "525dd", 0, einstein_state::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fd1", einstein_floppies, "525dd", 0, einstein_state::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fd2", einstein_floppies, "525dd", 0, einstein_state::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fd3", einstein_floppies, "525dd", 0, einstein_state::floppy_formats)
+
+ /* software lists */
+ MCFG_SOFTWARE_LIST_ADD("disk_list","einstein")
+
+ /* RAM is provided by 8k DRAM ICs i009, i010, i011, i012, i013, i014, i015 and i016 */
+ /* internal ram */
+ MCFG_RAM_ADD(RAM_TAG)
+ MCFG_RAM_DEFAULT_SIZE("64K")
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( einstei2, einstein )
+
+ MCFG_CPU_MODIFY(IC_I001)
+ MCFG_CPU_IO_MAP(einstein2_io)
+
+ MCFG_MACHINE_START(einstein2)
+ MCFG_MACHINE_RESET(einstein2)
+
+ /* video hardware */
+ MCFG_DEFAULT_LAYOUT(layout_dualhsxs)
+
+ MCFG_SCREEN_ADD("80column", RASTER)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
+ MCFG_SCREEN_SIZE(640, 400)
+ MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 400-1)
+ MCFG_SCREEN_REFRESH_RATE(50)
+ MCFG_SCREEN_UPDATE_STATIC(einstein2)
+ MCFG_GFXDECODE(einstei2)
+
+ /* 2 additional colors for the 80 column screen */
+ MCFG_PALETTE_LENGTH(TMS9928A_PALETTE_SIZE + 2)
+
+ MCFG_MC6845_ADD("crtc", MC6845, XTAL_X002 / 4, einstein_crtc6845_interface)
+MACHINE_CONFIG_END
+
+
+/***************************************************************************
+ ROM DEFINITIONS
+***************************************************************************/
+
+/* There are two sockets, i023 and i024, each either a 2764 or 27128
+ * only i023 is used by default and fitted with the 8k bios (called MOS).
+ *
+ * We are missing dumps of version MOS 1.1, possibly of 1.0 if it exists.
+ */
+ROM_START( einstein )
+ ROM_REGION(0x8000, "bios", 0)
+ /* i023 */
+ ROM_SYSTEM_BIOS(0, "mos12", "MOS 1.2")
+ ROMX_LOAD("mos12.i023", 0, 0x2000, CRC(ec134953) SHA1(a02125d8ebcda48aa784adbb42a8b2d7ef3a4b77), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(1, "mos121", "MOS 1.21")
+ ROMX_LOAD("mos121.i023", 0, 0x2000, CRC(a746eeb6) SHA1(f75aaaa777d0fd92225acba291f6bf428b341d3e), ROM_BIOS(2))
+ ROM_RELOAD(0x2000, 0x2000)
+ /* i024 */
+ ROM_FILL(0x4000, 0x4000, 0xff)
+ROM_END
+
+ROM_START( einstei2 )
+ ROM_REGION(0x8000, "bios", 0)
+ /* i023 */
+ ROM_SYSTEM_BIOS(0, "mos12", "MOS 1.2")
+ ROMX_LOAD("mos12.i023", 0, 0x2000, CRC(ec134953) SHA1(a02125d8ebcda48aa784adbb42a8b2d7ef3a4b77), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(1, "mos121", "MOS 1.21")
+ ROMX_LOAD("mos121.i023", 0, 0x2000, CRC(a746eeb6) SHA1(f75aaaa777d0fd92225acba291f6bf428b341d3e), ROM_BIOS(2))
+ ROM_RELOAD(0x2000, 0x2000)
+ /* i024 */
+ ROM_FILL(0x4000, 0x4000, 0xff)
+
+ /* character rom from 80 column card */
+ ROM_REGION(0x2000, "gfx1", 0)
+ ROM_LOAD("tk02-v1.00.rom", 0, 0x2000, CRC(ad3c4346) SHA1(cd57e630371b4d0314e3f15693753fb195c7257d))
+ROM_END
+
+ROM_START( einst256 )
+ ROM_REGION(0x8000, "bios", 0)
+ ROM_LOAD("tc256.rom", 0x0000, 0x4000, CRC(ef8dad88) SHA1(eb2102d3bef572db7161c26a7c68a5fcf457b4d0) )
+ROM_END
+
+/***************************************************************************
+ GAME DRIVERS
+***************************************************************************/
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */
+COMP( 1984, einstein, 0, 0, einstein, einstein, driver_device, 0, "Tatung", "Einstein TC-01", 0 )
+COMP( 1984, einstei2, einstein, 0, einstei2, einstein_80col, driver_device, 0, "Tatung", "Einstein TC-01 + 80 column device", 0 )
+COMP( 1984, einst256, 0, 0, einstein, einstein, driver_device, 0, "Tatung", "Einstein 256", GAME_NOT_WORKING )