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



                                                                               
                    
 


                                                                             







                                                                               
                      
                           

                    







                                                                                        









                                                   
 




                                                







                                                                                                       
                                
                               
 
                                            
 



                                              
                                                  
                                          


                                   











                                                                                                      




                                                                                                  






                                                                                                              
                                                                                   







                                                                                                                                            
                                                                                                       
 

                                                          

         

                                          












































































































































                                                                                                                                                                     
         


                                                                       
                                                 



                                                                         
                                                     




                                                                    
 
                                                                  
 










                                                                                                                                                 
                          



                                    



                           




                                                           

                                                                                                               









                                    






                                                                                                           

 
                                              

                                                                              
                                
                                                                            

















                                                                             

                            
                                                  
                                                                                                                                         
                                                                                        
                                                                                                                





                     










                                                                                                                                  


       


                                                                                                                                                                                           
// license:BSD-3-Clause
// copyright-holders:Sandro Ronco
/******************************************************************************

    Saitek RISC 2500

    TODO:
     - Sound is too short and high pitch, better when you underclock the cpu.
       Is cpu cycle timing wrong? or waitstate on p1000_w?

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


#include "emu.h"
#include "cpu/arm/arm.h"
#include "machine/ram.h"
#include "machine/nvram.h"
#include "sound/dac.h"
#include "sound/volt_reg.h"
#include "screen.h"
#include "speaker.h"

#include "risc2500.lh"


class risc2500_state : public driver_device
{
public:
	risc2500_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag)
		, m_maincpu(*this, "maincpu")
		, m_ram(*this, "ram")
		, m_nvram(*this, "nvram")
		, m_dac(*this, "dac")
		, m_inputs(*this, "P%u", 0)
		, m_digits(*this, "digit%u", 0U)
		, m_syms(*this, "sym%u", 0U)
		, m_leds(*this, "led%u", 0U)
	{ }

	DECLARE_INPUT_CHANGED_MEMBER(on_button);

	void risc2500(machine_config &config);

protected:
	DECLARE_READ32_MEMBER(p1000_r);
	DECLARE_WRITE32_MEMBER(p1000_w);
	DECLARE_READ32_MEMBER(disable_boot_rom);
	TIMER_CALLBACK_MEMBER(disable_boot_rom);

	virtual void machine_start() override;
	virtual void machine_reset() override;
	uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
	void install_boot_rom();
	void remove_boot_rom();

	void risc2500_mem(address_map &map);

private:
	required_device<cpu_device> m_maincpu;
	required_device<ram_device> m_ram;
	required_device<nvram_device> m_nvram;
	required_device<dac_byte_interface> m_dac;
	required_ioport_array<8> m_inputs;
	output_finder<12> m_digits;
	output_finder<14> m_syms;
	output_finder<16> m_leds;

	uint32_t  m_p1000;
	uint16_t  m_vram_addr;
	uint8_t   m_vram[0x100];
};


void risc2500_state::install_boot_rom()
{
	m_maincpu->space(AS_PROGRAM).install_rom(0x00000000, 0x001ffff, memregion("maincpu")->base());
}

void risc2500_state::remove_boot_rom()
{
	m_maincpu->space(AS_PROGRAM).install_ram(0x00000000, m_ram->size() - 1, m_ram->pointer());
}

uint32_t risc2500_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	for(int c=0; c<12; c++)
	{
		// 12 characters 5 x 7
		for(int x=0; x<5; x++)
		{
			uint8_t gfx = bitswap<8>(m_vram[c*5 + x], 6,5,0,1,2,3,4,7);

			for(int y=0; y<7; y++)
				bitmap.pix16(y, 71 - (c*6 + x)) = (gfx >> (y + 1)) & 1;
		}

		// LCD digits and symbols
		int data_addr = 0x40 + c * 5;
		uint16_t data = ((m_vram[data_addr + 1] & 0x3) << 5) | ((m_vram[data_addr + 2] & 0x7) << 2) | (m_vram[data_addr + 4] & 0x3);
		data = bitswap<8>(data, 7,3,0,1,4,6,5,2) | ((m_vram[data_addr - 1] & 0x04) ? 0x80 : 0);

		m_digits[c] = data;
		m_syms[c] = BIT(m_vram[data_addr + 1], 2);
	}

	m_syms[12] = BIT(m_vram[0x63], 0);
	m_syms[13] = BIT(m_vram[0x4a], 0);

	return 0;
}

INPUT_CHANGED_MEMBER(risc2500_state::on_button)
{
	if (newval)
	{
		install_boot_rom();
		m_maincpu->reset();
	}
}

static INPUT_PORTS_START( risc2500 )
	PORT_START("P0")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // H1
	PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // G1
	PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // F1
	PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // E1
	PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // D1
	PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // C1
	PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // B1
	PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // A1
	PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1_PAD)     PORT_NAME("Pawn")
	PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("BACK")

	PORT_START("P1")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // H2
	PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // G2
	PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // F2
	PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // E2
	PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // D2
	PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // C2
	PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // B2
	PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // A2
	PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2_PAD)     PORT_NAME("Knight")
	PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_ENTER)     PORT_NAME("ENTER")

	PORT_START("P2")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // H3
	PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // G3
	PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // F3
	PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // E3
	PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // D3
	PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // C3
	PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // B3
	PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // A3
	PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3_PAD)     PORT_NAME("Bishop")
	PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_DOWN)      PORT_NAME("DOWN")

	PORT_START("P3")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // H4
	PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // G4
	PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // F4
	PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // E4
	PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // D4
	PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // C4
	PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // B4
	PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // A4
	PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4_PAD)     PORT_NAME("Rook")
	PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_UP)        PORT_NAME("UP")

	PORT_START("P4")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // H5
	PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // G5
	PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // F5
	PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // E5
	PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // D5
	PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // C5
	PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // B5
	PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // A5
	PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5_PAD)     PORT_NAME("Queen")
	PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_M)         PORT_NAME("MENU")

	PORT_START("P5")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // H6
	PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // G6
	PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // F6
	PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // E6
	PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // D6
	PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // C6
	PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // B6
	PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // A6
	PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6_PAD)     PORT_NAME("King")
	PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L)         PORT_NAME("PLAY")

	PORT_START("P6")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // H7
	PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // G7
	PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // F7
	PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // E7
	PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // D7
	PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // C7
	PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // B7
	PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // A7
	PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_RIGHT)     PORT_NAME("RIGHT")
	PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_N)         PORT_NAME("NEW GAME")

	PORT_START("P7")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // H8
	PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // G8
	PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // F8
	PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // E8
	PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // D8
	PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // C8
	PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // B8
	PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_IMPULSE(10)             // A8
	PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_LEFT)      PORT_NAME("LEFT")
	PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_O)         PORT_NAME("OFF")

	PORT_START("RESET")
	PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_I)         PORT_NAME("ON")  PORT_CHANGED_MEMBER(DEVICE_SELF, risc2500_state, on_button, 0)
INPUT_PORTS_END


READ32_MEMBER(risc2500_state::p1000_r)
{
	uint32_t data = 0;

	for(int i=0; i<8; i++)
	{
		if (m_p1000 & (1 << i))
			data |= m_inputs[i]->read();
	}

	return data;
}

WRITE32_MEMBER(risc2500_state::p1000_w)
{
	if ((data & 0xff000000) == 0x01000000)          // VRAM address
	{
		if (data & 0x80)
			m_vram_addr = (m_vram_addr & ~0x40) | (data & 0x01 ? 0x40 : 0);
		else
			m_vram_addr = (m_vram_addr & 0x40) | (data & 0xff);
	}
	else if (data & 0x04000000)                     // VRAM write
	{
		if (!(data & 0x08000000))
			m_vram[m_vram_addr++ & 0x7f] = data & 0xff;
	}
	else if (data & 0x80000000)                     // Vertical LED
	{
		for(int i=0; i<8; i++)
			m_leds[i] = BIT(data, i);
	}
	else if (data & 0x40000000)                     // Horizontal LED
	{
		for(int i=0; i<8; i++)
			m_leds[8 + i] = BIT(data, i);
	}
	else if ((data & 0xff000000) == 0x08000000)     // Power OFF
	{
		memset(m_vram, 0, sizeof(m_vram));
	}

	m_dac->write(data >> 28 & 3);                   // Speaker

	m_p1000 = data;
}

READ32_MEMBER(risc2500_state::disable_boot_rom)
{
	machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(10), timer_expired_delegate(FUNC(risc2500_state::disable_boot_rom), this));
	return 0;
}

TIMER_CALLBACK_MEMBER(risc2500_state::disable_boot_rom)
{
	remove_boot_rom();
}

void risc2500_state::machine_start()
{
	m_digits.resolve();
	m_syms.resolve();
	m_leds.resolve();

	m_nvram->set_base(m_ram->pointer(), m_ram->size());

	save_item(NAME(m_p1000));
	save_item(NAME(m_vram_addr));
	save_item(NAME(m_vram));

	machine().save().register_postload(save_prepost_delegate(FUNC(risc2500_state::remove_boot_rom), this));
}

void risc2500_state::machine_reset()
{
	m_p1000 = 0;
	m_vram_addr = 0;

	install_boot_rom();
}

void risc2500_state::risc2500_mem(address_map &map)
{
	map(0x00000000, 0x0001ffff).ram();
	map(0x01800000, 0x01800003).r(this, FUNC(risc2500_state::disable_boot_rom));
	map(0x01000000, 0x01000003).rw(this, FUNC(risc2500_state::p1000_r), FUNC(risc2500_state::p1000_w));
	map(0x02000000, 0x0203ffff).rom().region("maincpu", 0);
}


MACHINE_CONFIG_START(risc2500_state::risc2500)
	MCFG_DEVICE_ADD("maincpu", ARM, XTAL(28'322'000) / 2)      // VY86C010
	MCFG_DEVICE_PROGRAM_MAP(risc2500_mem)
	MCFG_ARM_COPRO(VL86C020)
	MCFG_DEVICE_PERIODIC_INT_DRIVER(risc2500_state, irq1_line_hold, 250)

	MCFG_SCREEN_ADD("screen", LCD)
	MCFG_SCREEN_REFRESH_RATE(50)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
	MCFG_SCREEN_SIZE(12*6+1, 7)
	MCFG_SCREEN_VISIBLE_AREA(0, 12*6, 0, 7-1)
	MCFG_SCREEN_UPDATE_DRIVER(risc2500_state, screen_update)
	MCFG_SCREEN_PALETTE("palette")

	MCFG_DEFAULT_LAYOUT(layout_risc2500)

	MCFG_PALETTE_ADD_MONOCHROME("palette")

	MCFG_RAM_ADD("ram")
	MCFG_RAM_DEFAULT_SIZE("2M")
	MCFG_RAM_EXTRA_OPTIONS("128K, 256K, 512K, 1M, 2M")

	MCFG_NVRAM_ADD_NO_FILL("nvram")

	/* sound hardware */
	SPEAKER(config, "speaker").front_center();
	MCFG_DEVICE_ADD("dac", DAC_2BIT_BINARY_WEIGHTED_ONES_COMPLEMENT, 0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "speaker", 0.25) // unknown DAC
	MCFG_DEVICE_ADD("vref", VOLTAGE_REGULATOR, 0) MCFG_VOLTAGE_REGULATOR_OUTPUT(5.0)
	MCFG_SOUND_ROUTE(0, "dac", 1.0, DAC_VREF_POS_INPUT) MCFG_SOUND_ROUTE(0, "dac", -1.0, DAC_VREF_NEG_INPUT)
MACHINE_CONFIG_END


/* ROM definitions */

ROM_START( risc )
	ROM_REGION( 0x40000, "maincpu", ROMREGION_ERASE )
	ROM_SYSTEM_BIOS( 0, "v104", "v1.04" )
	ROMX_LOAD("s2500_v104.bin", 0x000000, 0x020000, CRC(84a06178) SHA1(66f4d9f53de6da865a3ebb4af1d6a3e245c59a3c), ROM_BIOS(1))
	ROM_SYSTEM_BIOS( 1, "v103", "v1.03" )
	ROMX_LOAD("s2500_v103.bin", 0x000000, 0x020000, CRC(7a707e82) SHA1(87187fa58117a442f3abd30092cfcc2a4d7c7efc), ROM_BIOS(2))
ROM_END

ROM_START( montreux )
	ROM_REGION( 0x40000, "maincpu", ROMREGION_ERASE )
	ROM_SYSTEM_BIOS( 0, "v100", "v1.00" )
	ROMX_LOAD("montreux.bin", 0x000000, 0x040000, CRC(db374cf3) SHA1(44dd60d56779084326c3dfb41d2137ebf0b4e0ac), ROM_BIOS(1))
ROM_END


/*    YEAR  NAME      PARENT  COMPAT  MACHINE   INPUT     CLASS           INIT        COMPANY                      FULLNAME             FLAGS */
CONS( 1992, risc,     0,      0,      risc2500, risc2500, risc2500_state, empty_init, "Saitek",                    "RISC 2500",         MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK )
CONS( 1995, montreux, 0,      0,      risc2500, risc2500, risc2500_state, empty_init, "Saitek / Hegener & Glaser", "Mephisto Montreux", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK )