summaryrefslogblamecommitdiffstatshomepage
path: root/src/mess/drivers/camplynx.c
blob: cd5e9f3260312de70eef8b585f3e1b8adfa41c3c (plain) (tree)
1
2

                             






















































































                                                                                        







                                                   

           



                                               
                                       
                                        

                                               








                                                        
















                                                                        
                                                                                                  




                                                
                                                   



























                                                           
                                                                                                  



























                                                            
                                                                                                  














                                                                          
                                                                                        









                                                     
                                                                                                                   












                                                                                                                
                                                                                        









                                                     

                                                                                                                                                     




















































































                                                                                                                                                         
                                             
 


















                                                          



                                             
                                           




                                         







                                                  

  
                                             





                                                                                             
                                                                     


         
                                                       
 

                                                                          



















                                                                                  
                                                        
 

                                                                          



















                                                                                  
                                  


 













                                                                             

                                                         





                                                  




                                                                                                           








                                                       
                                                            







                                                                             

                                                         





                                                  





                                                                                                           









































                                                                                                                                       
// license:MAME
// copyright-holders:Robbbert
/***************************************************************************

      Camputers Lynx

      05/2009 Skeleton driver.

      The Lynx was an 8-bit British home computer that was first released
      in early 1983 as a 48 kB model.
      The designer of the Lynx was John Shireff and several models were
      available with 48 kB, 96 kB (from Sep 1983) or 128 kB RAM (from Dec
      1983). It was possible reach 192 kB with RAM expansions on-board.

      The machine was based around a Z80A CPU clocked at 4 MHz, and featured
      a Motorola 6845 as video controller. It was possible to run CP/M with
      the optional 5.25" floppy disk-drive on the 96 kB and 128 kB models.
      Approximately 30,000 Lynx units were sold world-wide.

      Camputers ceased trading in June 1984. Anston Technology took over in
      November the same year and a re-launch was planned but never happened.

      In June 1986, Anston sold everything - hardware, design rights and
      thousands of cassettes - to the National Lynx User Group. The group
      planned to produce a Super-Lynx but was too busy supplying spares and
      technical information to owners of existing models, and the project never
      came into being.

      Hardware info:
       - CPU: Zilog Z80A 4 MHz
       - CO-PROCESSOR: Motorola 6845 (CRT controller)
       - RAM: 48 kb, 96 kb or 128 kb depending on models (max. 192 kb)
       - ROM: 16 kb (48K version), 24 KB (96K and 128K versions)
       - TEXT MODES: 40 x 24, 80 x 24
       - GRAPHIC MODES: 256 x 248, 512 x 480
       - SOUND: one voice beeper

      Lynx 128 Memory Map

              | 0000    2000    4000    6000    8000    a000    c000     e000
              | 1fff    3fff    5fff    7fff    9fff    bfff    dfff     ffff
     -------------------------------------------------------------------------
              |                      |                        |       |
      Bank 0  |      BASIC ROM       |    Not Available       |  Ext  |  Ext
              |                      |                        |  ROM1 |  ROM2
     -------------------------------------------------------------------------
              |                      |
      Bank 1  |        STORE         |           Workspace RAM
              |                      |
     -------------------------------------------------------------------------
              |               |               |               |
      Bank 2  |       RED     |     BLUE      |     GREEN     |     Alt
              |               |               |               |    Green
     -------------------------------------------------------------------------
              |
      Bank 3  |              Available for Video Expansion
              |
     -------------------------------------------------------------------------
              |
      Bank 4  |              Available for User RAM Expansion
              |



    48k and 96k are basically the same machine. 128k is different.

    The work so far is without the benefit of manuals, schematic etc [Robbbert]

    48k, 96k:
    Cassette operation is strange indeed. Save takes the dac output and directs
    it to the tape. Load takes over line 0 of the keyboard and uses bits 0 and 5.

    To Do:
    - find Break key
    - banking (it is incomplete atm)
    - devices (cassette, disk, printer, joysticks)
    - find out the mc6845 clock frequency

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

#include "emu.h"
#include "cpu/z80/z80.h"
#include "video/mc6845.h"
#include "sound/dac.h"

class camplynx_state : public driver_device
{
public:
	camplynx_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag)
		, m_palette(*this, "palette")
		, m_maincpu(*this, "maincpu")
		//, m_cass(*this, "cassette")
		//, m_wave(*this, WAVE_TAG)
		//, m_printer(*this, "centronics")
		, m_crtc(*this, "crtc")
		//, m_fdc(*this, "fdc")
	{ }

	DECLARE_WRITE8_MEMBER(lynx48k_bank_w);
	DECLARE_WRITE8_MEMBER(lynx128k_bank_w);
	DECLARE_WRITE8_MEMBER(lynx128k_irq);
	DECLARE_DRIVER_INIT(lynx48k);
	DECLARE_PALETTE_INIT(camplynx);
	DECLARE_MACHINE_RESET(lynx128k);
	MC6845_UPDATE_ROW(lynx48k_update_row);
	MC6845_UPDATE_ROW(lynx128k_update_row);
	required_device<palette_device> m_palette;
private:
	virtual void video_start();
	required_device<cpu_device> m_maincpu;
	//required_device<cassette_image_device> m_cass;
	//required_device<> m_wave;
	//required_device<> m_printer;
	required_device<mc6845_device> m_crtc;
	//optional_device<> m_fdc;
};

/* These bankswitch handlers are very incomplete, just enough to get the
    computer working. Also, as it happens 6 times for every scanline
    of every character, it causes a huge slowdown. */

WRITE8_MEMBER( camplynx_state::lynx48k_bank_w )
{
	if (!data)
		membank("bank1")->set_entry(0);
	else
	if (data & 2)
		membank("bank1")->set_entry(1);
	else
	if (data & 4)
		membank("bank1")->set_entry(2);
	else
		logerror("%04X: Cannot understand bankswitch command %X\n",m_maincpu->pc(), data);
}

WRITE8_MEMBER( camplynx_state::lynx128k_bank_w )
{
	/* get address space */
	UINT8 *base = memregion("maincpu")->base();

	/* Set read banks */
	UINT8 bank = data & 0x0f;

	if (!bank)
	{
		membank("bank1")->set_base(base + 0x00000);
		membank("bank2")->set_base(base + 0x02000);
		membank("bank3")->set_base(base + 0x04000);
		membank("bank4")->set_base(base + 0x16000);
		membank("bank5")->set_base(base + 0x18000);
		membank("bank6")->set_base(base + 0x1a000);
		membank("bank7")->set_base(base + 0x0c000);
		membank("bank8")->set_base(base + 0x0e000);
	}
	else
	if (bank == 0x0e)
	{
		membank("bank1")->set_base(base + 0x20000);
		membank("bank2")->set_base(base + 0x22000);
		membank("bank3")->set_base(base + 0x24000);
		membank("bank4")->set_base(base + 0x26000);
		membank("bank5")->set_base(base + 0x28000);
		membank("bank6")->set_base(base + 0x2a000);
		membank("bank7")->set_base(base + 0x2c000);
		membank("bank8")->set_base(base + 0x2e000);
	}
	else
		logerror("%04X: Cannot understand bankswitch command %X\n",m_maincpu->pc(), data);

	/* Set write banks */
	bank = data & 0xd0;

	if (!bank)
	{
		membank("bank11")->set_base(base + 0x10000);
		membank("bank12")->set_base(base + 0x12000);
		membank("bank13")->set_base(base + 0x14000);
		membank("bank14")->set_base(base + 0x16000);
		membank("bank15")->set_base(base + 0x18000);
		membank("bank16")->set_base(base + 0x1a000);
		membank("bank17")->set_base(base + 0x1c000);
		membank("bank18")->set_base(base + 0x1e000);
	}
	else
	if (bank == 0xc0)
	{
		membank("bank11")->set_base(base + 0x20000);
		membank("bank12")->set_base(base + 0x22000);
		membank("bank13")->set_base(base + 0x24000);
		membank("bank14")->set_base(base + 0x26000);
		membank("bank15")->set_base(base + 0x28000);
		membank("bank16")->set_base(base + 0x2a000);
		membank("bank17")->set_base(base + 0x2c000);
		membank("bank18")->set_base(base + 0x2e000);
	}
	else
		logerror("%04X: Cannot understand bankswitch command %X\n",m_maincpu->pc(), data);
}

static ADDRESS_MAP_START( lynx48k_mem, AS_PROGRAM, 8, camplynx_state )
	ADDRESS_MAP_UNMAP_HIGH
	AM_RANGE(0x0000,0x5fff) AM_ROM
	AM_RANGE(0x6000,0x7fff) AM_RAM
	AM_RANGE(0x8000,0xffff) AM_RAMBANK("bank1")
ADDRESS_MAP_END

static ADDRESS_MAP_START( lynx128k_mem, AS_PROGRAM, 8, camplynx_state )
ADDRESS_MAP_END

static ADDRESS_MAP_START( lynx48k_io , AS_IO, 8, camplynx_state )
	ADDRESS_MAP_UNMAP_HIGH
	AM_RANGE(0x007f,0x007f) AM_MIRROR(0xff00) AM_WRITE(lynx48k_bank_w)
	AM_RANGE(0x0080,0x0080) AM_MIRROR(0xff00) AM_WRITENOP       /* to be emulated */
	AM_RANGE(0x0080,0x0080) AM_READ_PORT("LINE0")
	AM_RANGE(0x0180,0x0180) AM_READ_PORT("LINE1")
	AM_RANGE(0x0280,0x0280) AM_READ_PORT("LINE2")
	AM_RANGE(0x0380,0x0380) AM_READ_PORT("LINE3")
	AM_RANGE(0x0480,0x0480) AM_READ_PORT("LINE4")
	AM_RANGE(0x0580,0x0580) AM_READ_PORT("LINE5")
	AM_RANGE(0x0680,0x0680) AM_READ_PORT("LINE6")
	AM_RANGE(0x0780,0x0780) AM_READ_PORT("LINE7")
	AM_RANGE(0x0880,0x0880) AM_READ_PORT("LINE8")
	AM_RANGE(0x0980,0x0980) AM_READ_PORT("LINE9")
	AM_RANGE(0x0084,0x0084) AM_MIRROR(0xff00) AM_DEVWRITE("dac", dac_device, write_unsigned8)   /* 6-bit dac */
	AM_RANGE(0x0086,0x0086) AM_MIRROR(0xff00) AM_DEVWRITE("crtc", mc6845_device, address_w)
	AM_RANGE(0x0087,0x0087) AM_MIRROR(0xff00) AM_DEVREADWRITE("crtc", mc6845_device, register_r, register_w)
ADDRESS_MAP_END

static ADDRESS_MAP_START( lynx128k_io , AS_IO, 8, camplynx_state )
	ADDRESS_MAP_UNMAP_HIGH
//  AM_RANGE(0x0050,0x0053) AM_MIRROR(0xff80) AM_READ(wd179x_r) // uses a 1793
//  AM_RANGE(0x0054,0x0057) AM_MIRROR(0xff80) AM_WRITE(wd179x_w)
//  AM_RANGE(0x0058,0x0058) AM_MIRROR(0xff80) AM_WRITE(lynx128k_disk_w)
//  AM_RANGE(0x007a,0x007b) AM_MIRROR(0xff80) AM_READ(lynx128k_joysticks_r)
//  AM_RANGE(0x007c,0x007c) AM_MIRROR(0xff80) AM_READ(lynx128k_printer_r)
//  AM_RANGE(0x007d,0x007d) AM_MIRROR(0xff80) AM_WRITE(lynx128k_printer_init_w) // this is rw
//  AM_RANGE(0x007e,0x007e) AM_MIRROR(0xff80) AM_WRITE(lynx128k_printer_w)
	AM_RANGE(0x0080,0x0080) AM_MIRROR(0xff00) AM_WRITENOP       /* to be emulated */
	AM_RANGE(0x0080,0x0080) AM_READ_PORT("LINE0")
	AM_RANGE(0x0180,0x0180) AM_READ_PORT("LINE1")
	AM_RANGE(0x0280,0x0280) AM_READ_PORT("LINE2")
	AM_RANGE(0x0380,0x0380) AM_READ_PORT("LINE3")
	AM_RANGE(0x0480,0x0480) AM_READ_PORT("LINE4")
	AM_RANGE(0x0580,0x0580) AM_READ_PORT("LINE5")
	AM_RANGE(0x0680,0x0680) AM_READ_PORT("LINE6")
	AM_RANGE(0x0780,0x0780) AM_READ_PORT("LINE7")
	AM_RANGE(0x0880,0x0880) AM_READ_PORT("LINE8")
	AM_RANGE(0x0980,0x0980) AM_READ_PORT("LINE9")
	AM_RANGE(0x0082,0x0082) AM_MIRROR(0xff00) AM_WRITE(lynx128k_bank_w) // read=serial buffer
	AM_RANGE(0x0084,0x0084) AM_MIRROR(0xff00) AM_DEVWRITE("dac", dac_device, write_unsigned8)   /* 6-bit dac. Read="single-step", causes a NMI */
	AM_RANGE(0x0086,0x0086) AM_MIRROR(0xff00) AM_DEVREADWRITE("crtc", mc6845_device, status_r, address_w)
	AM_RANGE(0x0087,0x0087) AM_MIRROR(0xff00) AM_DEVREADWRITE("crtc", mc6845_device, register_r, register_w)
ADDRESS_MAP_END

/* Input ports */
static INPUT_PORTS_START( lynx48k )
	PORT_START("LINE0")
	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
	PORT_BIT(0x0e, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
	PORT_START("LINE1")
	PORT_BIT(0xc0, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C CONT") PORT_CODE(KEYCODE_C) PORT_CHAR('C')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D DEL") PORT_CODE(KEYCODE_D) PORT_CHAR('D')
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X WEND") PORT_CODE(KEYCODE_X) PORT_CHAR('X')
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E DATA") PORT_CODE(KEYCODE_E) PORT_CHAR('E')
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
	PORT_START("LINE2")
	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A AUTO") PORT_CODE(KEYCODE_A) PORT_CHAR('A')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("S STOP") PORT_CODE(KEYCODE_S) PORT_CHAR('S')
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z RESTORE") PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W WHILE") PORT_CODE(KEYCODE_W) PORT_CHAR('W')
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q REM") PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR(34)
	PORT_START("LINE3")
	PORT_BIT(0xc0, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F DEFPROC") PORT_CODE(KEYCODE_F) PORT_CHAR('F')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G GOTO") PORT_CODE(KEYCODE_G) PORT_CHAR('G')
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("V VERIFY") PORT_CODE(KEYCODE_V) PORT_CHAR('V')
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("T TRACE") PORT_CODE(KEYCODE_T) PORT_CHAR('T')
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("R REPEAT") PORT_CODE(KEYCODE_R) PORT_CHAR('R')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
	PORT_START("LINE4")
	PORT_BIT(0xc0, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B BEEP") PORT_CODE(KEYCODE_B) PORT_CHAR('B')
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("N NEXT") PORT_CODE(KEYCODE_N) PORT_CHAR('N')
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(32)
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("H GOSUB") PORT_CODE(KEYCODE_H) PORT_CHAR('H')
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y RUN") PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
	PORT_START("LINE5")
	PORT_BIT(0xd0, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("J LABEL") PORT_CODE(KEYCODE_J) PORT_CHAR('J')
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("M RETURN") PORT_CODE(KEYCODE_M) PORT_CHAR('M')
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U UNTIL") PORT_CODE(KEYCODE_U) PORT_CHAR('U')
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7 \'") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR(39)
	PORT_START("LINE6")
	PORT_BIT(0xd0, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("K MON") PORT_CODE(KEYCODE_K) PORT_CHAR('K')
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O ENDPROC") PORT_CODE(KEYCODE_O) PORT_CHAR('O')
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I INPUT") PORT_CODE(KEYCODE_I) PORT_CHAR('I')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
	PORT_START("LINE7")
	PORT_BIT(0xd0, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("; +") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L LIST") PORT_CODE(KEYCODE_L) PORT_CHAR('L')
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P PROC") PORT_CODE(KEYCODE_P) PORT_CHAR('P')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0 _") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
	PORT_START("LINE8")
	PORT_BIT(0xd0, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(": *") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*')
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("[") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[')
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("@ \\") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('@') PORT_CHAR('\\')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("- =") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=')
	PORT_START("LINE9")
	PORT_BIT(0xc0, IP_ACTIVE_LOW, IPT_UNUSED)
	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("End") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END))
	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("]") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']')
	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Delete") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
INPUT_PORTS_END


MACHINE_RESET_MEMBER(camplynx_state,lynx128k)
{
	address_space &mem = m_maincpu->space(AS_PROGRAM);
	mem.install_read_bank (0x0000, 0x1fff, "bank1");
	mem.install_read_bank (0x2000, 0x3fff, "bank2");
	mem.install_read_bank (0x4000, 0x5fff, "bank3");
	mem.install_read_bank (0x6000, 0x7fff, "bank4");
	mem.install_read_bank (0x8000, 0x9fff, "bank5");
	mem.install_read_bank (0xa000, 0xbfff, "bank6");
	mem.install_read_bank (0xc000, 0xdfff, "bank7");
	mem.install_read_bank (0xe000, 0xffff, "bank8");
	mem.install_write_bank (0x0000, 0x1fff, "bank11");
	mem.install_write_bank (0x2000, 0x3fff, "bank12");
	mem.install_write_bank (0x4000, 0x5fff, "bank13");
	mem.install_write_bank (0x6000, 0x7fff, "bank14");
	mem.install_write_bank (0x8000, 0x9fff, "bank15");
	mem.install_write_bank (0xa000, 0xbfff, "bank16");
	mem.install_write_bank (0xc000, 0xdfff, "bank17");
	mem.install_write_bank (0xe000, 0xffff, "bank18");

	lynx128k_bank_w(mem, 0, 0);
}

WRITE8_MEMBER( camplynx_state::lynx128k_irq )
{
	m_maincpu->set_input_line(0, data);
}


static const UINT8 lynx48k_palette[8*3] =
{
	0x00, 0x00, 0x00,   /*  0 Black     */
	0x00, 0x00, 0xff,   /*  1 Blue      */
	0xff, 0x00, 0x00,   /*  2 Red       */
	0xff, 0x00, 0xff,   /*  3 Magenta       */
	0x00, 0xff, 0x00,   /*  4 Green     */
	0x00, 0xff, 0xff,   /*  5 Cyan      */
	0xff, 0xff, 0x00,   /*  6 Yellow        */
	0xff, 0xff, 0xff,   /*  7 White     */
};

PALETTE_INIT_MEMBER(camplynx_state, camplynx)
{
	UINT8 r, b, g, i=0, color_count = 8;

	while (color_count--)
	{
		r = lynx48k_palette[i++]; g = lynx48k_palette[i++]; b = lynx48k_palette[i++];
		palette.set_pen_color(7-color_count, rgb_t(r, g, b));
	}
}

MC6845_UPDATE_ROW( camplynx_state::lynx48k_update_row )
{
	UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
	const rgb_t *palette = m_palette->palette()->entry_list_raw();
	UINT8 r,g,b;
	UINT32 x, *p = &bitmap.pix32(y);

	for (x = (y << 5); x < x_count + (y << 5); x++)
	{
		r = RAM[0x14000+x];
		g = RAM[0x1c000+x];
		b = RAM[0x10000+x];

		*p++ = palette[(BIT(r, 7) << 1) | (BIT(g, 7) << 2) | (BIT(b, 7))];
		*p++ = palette[(BIT(r, 6) << 1) | (BIT(g, 6) << 2) | (BIT(b, 6))];
		*p++ = palette[(BIT(r, 5) << 1) | (BIT(g, 5) << 2) | (BIT(b, 5))];
		*p++ = palette[(BIT(r, 4) << 1) | (BIT(g, 4) << 2) | (BIT(b, 4))];
		*p++ = palette[(BIT(r, 3) << 1) | (BIT(g, 3) << 2) | (BIT(b, 3))];
		*p++ = palette[(BIT(r, 2) << 1) | (BIT(g, 2) << 2) | (BIT(b, 2))];
		*p++ = palette[(BIT(r, 1) << 1) | (BIT(g, 1) << 2) | (BIT(b, 1))];
		*p++ = palette[(BIT(r, 0) << 1) | (BIT(g, 0) << 2) | (BIT(b, 0))];
	}
}

MC6845_UPDATE_ROW( camplynx_state::lynx128k_update_row )
{
	UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
	const rgb_t *palette = m_palette->palette()->entry_list_raw();
	UINT8 r,g,b;
	UINT32 x, *p = &bitmap.pix32(y);

	for (x = (y << 6); x < x_count + (y << 6); x++)
	{
		r = RAM[0x20100+x];
		g = RAM[0x28100+x];
		b = RAM[0x24100+x];

		*p++ = palette[(BIT(r, 7) << 1) | (BIT(g, 7) << 2) | (BIT(b, 7))];
		*p++ = palette[(BIT(r, 6) << 1) | (BIT(g, 6) << 2) | (BIT(b, 6))];
		*p++ = palette[(BIT(r, 5) << 1) | (BIT(g, 5) << 2) | (BIT(b, 5))];
		*p++ = palette[(BIT(r, 4) << 1) | (BIT(g, 4) << 2) | (BIT(b, 4))];
		*p++ = palette[(BIT(r, 3) << 1) | (BIT(g, 3) << 2) | (BIT(b, 3))];
		*p++ = palette[(BIT(r, 2) << 1) | (BIT(g, 2) << 2) | (BIT(b, 2))];
		*p++ = palette[(BIT(r, 1) << 1) | (BIT(g, 1) << 2) | (BIT(b, 1))];
		*p++ = palette[(BIT(r, 0) << 1) | (BIT(g, 0) << 2) | (BIT(b, 0))];
	}
}

void camplynx_state::video_start()
{
}

static MACHINE_CONFIG_START( lynx48k, camplynx_state )

	/* basic machine hardware */
	MCFG_CPU_ADD("maincpu", Z80, XTAL_4MHz)
	MCFG_CPU_PROGRAM_MAP(lynx48k_mem)
	MCFG_CPU_IO_MAP(lynx48k_io)

	/* video hardware */
	MCFG_SCREEN_ADD("screen", RASTER)
	MCFG_SCREEN_REFRESH_RATE(50)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
	MCFG_SCREEN_SIZE(512, 480)
	MCFG_SCREEN_VISIBLE_AREA(0, 511, 0, 479)
	MCFG_SCREEN_UPDATE_DEVICE("crtc", mc6845_device, screen_update)
	MCFG_PALETTE_ADD("palette", 8)
	MCFG_PALETTE_INIT_OWNER(camplynx_state, camplynx)

	/* sound hardware */
	MCFG_SPEAKER_STANDARD_MONO("mono")
	MCFG_SOUND_ADD("dac", DAC, 0)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.8)

	/* devices */
	MCFG_MC6845_ADD("crtc", MC6845, "screen", XTAL_12MHz / 8 /*? dot clock divided by dots per char */)
	MCFG_MC6845_SHOW_BORDER_AREA(false)
	MCFG_MC6845_CHAR_WIDTH(8)
	MCFG_MC6845_UPDATE_ROW_CB(camplynx_state, lynx48k_update_row)
MACHINE_CONFIG_END

static MACHINE_CONFIG_START( lynx128k, camplynx_state )

	/* basic machine hardware */
	MCFG_CPU_ADD("maincpu", Z80, XTAL_6MHz)
	MCFG_CPU_PROGRAM_MAP(lynx128k_mem)
	MCFG_CPU_IO_MAP(lynx128k_io)

	MCFG_MACHINE_RESET_OVERRIDE(camplynx_state,lynx128k)

	/* video hardware */
	MCFG_SCREEN_ADD("screen", RASTER)
	MCFG_SCREEN_REFRESH_RATE(50)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
	MCFG_SCREEN_SIZE(512, 480)
	MCFG_SCREEN_VISIBLE_AREA(0, 511, 0, 479)
	MCFG_SCREEN_UPDATE_DEVICE("crtc", mc6845_device, screen_update)
	MCFG_PALETTE_ADD("palette", 8)
	MCFG_PALETTE_INIT_OWNER(camplynx_state, camplynx)

	/* sound hardware */
	MCFG_SPEAKER_STANDARD_MONO("mono")
	MCFG_SOUND_ADD("dac", DAC, 0)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.8)

	/* devices */
	MCFG_MC6845_ADD("crtc", MC6845, "screen", XTAL_12MHz / 8 /*? dot clock divided by dots per char */)
	MCFG_MC6845_SHOW_BORDER_AREA(false)
	MCFG_MC6845_CHAR_WIDTH(8)
	MCFG_MC6845_UPDATE_ROW_CB(camplynx_state, lynx128k_update_row)
	MCFG_MC6845_OUT_HSYNC_CB(WRITE8(camplynx_state, lynx128k_irq))
MACHINE_CONFIG_END

DRIVER_INIT_MEMBER(camplynx_state,lynx48k)
{
	UINT8 *RAM = memregion("maincpu")->base();
	membank("bank1")->configure_entries(0, 3, &RAM[0x8000],  0x8000);
}


/* ROM definition */
ROM_START( lynx48k )
	ROM_REGION( 0x20000, "maincpu", ROMREGION_ERASEFF )
	ROM_SYSTEM_BIOS(0, "1", "Set1")
	ROMX_LOAD( "lynx48-1.rom", 0x0000, 0x2000, CRC(56feec44) SHA1(7ded5184561168e159a30fa8e9d3fde5e52aa91a), ROM_BIOS(1) )
	ROMX_LOAD( "lynx48-2.rom", 0x2000, 0x2000, CRC(d894562e) SHA1(c08a78ecb4eb05baa4c52488fce3648cd2688744), ROM_BIOS(1) )
	ROM_SYSTEM_BIOS(1, "2", "Set2")
	ROMX_LOAD( "lynx4811.rom", 0x0000, 0x2000, CRC(a933e577) SHA1(c7b30a28d99b38dbe63a1314c78e3e614287143b), ROM_BIOS(2) )
	ROMX_LOAD( "lynx4812.rom", 0x2000, 0x2000, CRC(3d3fdd0e) SHA1(259d124f05367a96f891790f9418cc9c7798e2f8), ROM_BIOS(2) )
ROM_END

ROM_START( lynx96k )
	ROM_REGION( 0x20000, "maincpu", ROMREGION_ERASEFF )
	ROM_LOAD( "lynx9646.rom",  0x0000, 0x2000, CRC(f86c5514) SHA1(77a4af7557382003d697d08f364839e2dc28f063) )
	ROM_LOAD( "lynx9645.rom",  0x2000, 0x2000, CRC(f596b9a3) SHA1(3fca46bd68422d34c6cd801dd904507e52bd8846) )
	ROM_LOAD( "lynx9644.rom",  0x4000, 0x1000, CRC(4b96b0de) SHA1(c372a8d26399b9b45e615b674d61ccda76491b8b) )
	ROM_LOAD( "dosrom.rom",    0xe000, 0x2000, CRC(011e106a) SHA1(e77f0ca99790551a7122945f3194516b2390fb69) )
ROM_END

ROM_START( lynx128k )
	ROM_REGION( 0x50000, "maincpu", ROMREGION_ERASEFF )
	ROM_LOAD( "lynx128-1.rom", 0x0000, 0x2000, CRC(65d292ce) SHA1(36567c2fbd9cf72f758e8cb80c21cb4d82040752) )
	ROM_LOAD( "lynx128-2.rom", 0x2000, 0x2000, CRC(23288773) SHA1(e12a7ebea3fae5eb375c03e848dbb81070d9d189) )
	ROM_LOAD( "lynx128-3.rom", 0x4000, 0x2000, CRC(9827b9e9) SHA1(1092367b2af51c72ce9be367179240d692aeb131) )
	ROM_LOAD( "dosrom.rom",    0xe000, 0x2000, CRC(011e106a) SHA1(e77f0ca99790551a7122945f3194516b2390fb69) )
ROM_END


/* Driver */
/*    YEAR  NAME       PARENT     COMPAT   MACHINE    INPUT     INIT         COMPANY     FULLNAME     FLAGS */
COMP( 1983, lynx48k,   0,         0,       lynx48k,   lynx48k, camplynx_state,  lynx48k,  "Camputers",  "Lynx 48k",   GAME_NOT_WORKING)
COMP( 1983, lynx96k,   lynx48k,   0,       lynx48k,   lynx48k, camplynx_state,  lynx48k,  "Camputers",  "Lynx 96k",   GAME_NOT_WORKING)
COMP( 1983, lynx128k,  lynx48k,   0,       lynx128k,  lynx48k, driver_device,  0,        "Camputers",  "Lynx 128k",  GAME_NOT_WORKING)