summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/saitek_risc2500.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/saitek_risc2500.cpp')
-rw-r--r--src/mame/drivers/saitek_risc2500.cpp335
1 files changed, 211 insertions, 124 deletions
diff --git a/src/mame/drivers/saitek_risc2500.cpp b/src/mame/drivers/saitek_risc2500.cpp
index 9de8adc73ed..bc56d3a706e 100644
--- a/src/mame/drivers/saitek_risc2500.cpp
+++ b/src/mame/drivers/saitek_risc2500.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Sandro Ronco
+// copyright-holders:Sandro Ronco, hap
/******************************************************************************
Saitek RISC 2500, Mephisto Montreux
@@ -8,9 +8,12 @@ The chess engine is also compatible with Tasc's The ChessMachine software.
The hardware+software appears to have been subcontracted to Tasc. It has similarities
with Tasc R30, PCB label and Montreux repair manual schematics footnotes say TASC23C.
-notes:
-- holding LEFT+RIGHT on boot load the QC TestMode
-- holding UP+DOWN on boot load the TestMode
+To make sure it continues the game at next power-on, press the OFF button before
+exiting MAME. If nvram is broken somehow, boot with the BACK button held down.
+
+Undocumented buttons:
+- hold LEFT+RIGHT on boot to start the QC TestMode
+- hold UP+DOWN on boot to start the TestMode
TODO:
- bootrom disable timer shouldn't be needed, real ARM has already fetched the next opcode
@@ -21,29 +24,36 @@ TODO:
******************************************************************************/
-
#include "emu.h"
+
#include "cpu/arm/arm.h"
#include "machine/ram.h"
#include "machine/nvram.h"
#include "machine/sensorboard.h"
+#include "machine/timer.h"
#include "video/sed1520.h"
#include "sound/dac.h"
+
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
+// internal artwork
#include "saitek_risc2500.lh"
+namespace {
+
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_rom(*this, "maincpu")
, m_ram(*this, "ram")
, m_nvram(*this, "nvram")
+ , m_disable_bootrom(*this, "disable_bootrom")
, m_dac(*this, "dac")
, m_lcdc(*this, "lcdc")
, m_board(*this, "board")
@@ -53,29 +63,22 @@ public:
, m_leds(*this, "led%u", 0U)
{ }
+ DECLARE_INPUT_CHANGED_MEMBER(acl_button) { if (newval) power_off(); }
DECLARE_INPUT_CHANGED_MEMBER(on_button);
void risc2500(machine_config &config);
protected:
- uint32_t p1000_r();
- void p1000_w(uint32_t data);
- uint32_t disable_boot_rom_r();
- TIMER_CALLBACK_MEMBER(disable_boot_rom);
-
virtual void machine_start() override;
virtual void machine_reset() override;
- SED1520_UPDATE_CB(screen_update_cb);
- void install_boot_rom();
- void remove_boot_rom();
- void lcd_palette(palette_device &palette) const;
-
- void risc2500_mem(address_map &map);
+ virtual void device_post_load() override { install_bootrom(m_bootrom_enabled); }
private:
required_device<arm_cpu_device> m_maincpu;
+ required_region_ptr<u32> m_rom;
required_device<ram_device> m_ram;
required_device<nvram_device> m_nvram;
+ required_device<timer_device> m_disable_bootrom;
required_device<dac_byte_interface> m_dac;
required_device<sed1520_device> m_lcdc;
required_device<sensorboard_device> m_board;
@@ -84,21 +87,51 @@ private:
output_finder<14> m_syms;
output_finder<16> m_leds;
- uint32_t m_p1000;
- emu_timer *m_boot_rom_disable_timer;
-};
+ void risc2500_mem(address_map &map);
+
+ void lcd_palette(palette_device &palette) const;
+ SED1520_UPDATE_CB(screen_update_cb);
+ u32 input_r();
+ void control_w(u32 data);
+ void power_off();
+ u32 disable_boot_rom_r();
+ void install_bootrom(bool enable);
+ TIMER_DEVICE_CALLBACK_MEMBER(disable_bootrom) { install_bootrom(false); }
+ bool m_bootrom_enabled = false;
-void risc2500_state::install_boot_rom()
+ u32 m_control = 0;
+ bool m_power = false;
+};
+
+void risc2500_state::machine_start()
{
- m_maincpu->space(AS_PROGRAM).install_rom(0x00000000, 0x001ffff, memregion("maincpu")->base());
+ m_digits.resolve();
+ m_syms.resolve();
+ m_leds.resolve();
+
+ m_nvram->set_base(m_ram->pointer(), m_ram->size());
+
+ // register for savestates
+ save_item(NAME(m_power));
+ save_item(NAME(m_bootrom_enabled));
+ save_item(NAME(m_control));
}
-void risc2500_state::remove_boot_rom()
+void risc2500_state::machine_reset()
{
- m_maincpu->space(AS_PROGRAM).install_ram(0x00000000, m_ram->size() - 1, m_ram->pointer());
+ install_bootrom(true);
+
+ m_power = true;
+ m_control = 0;
}
+
+
+/******************************************************************************
+ Video
+******************************************************************************/
+
void risc2500_state::lcd_palette(palette_device &palette) const
{
palette.set_pen_color(0, rgb_t(131, 136, 139)); // lcd pixel off
@@ -110,16 +143,16 @@ SED1520_UPDATE_CB(risc2500_state::screen_update_cb)
{
bitmap.fill(2, cliprect);
- for (int c=0; c<12; c++)
+ for (int c = 0; c < 12; c++)
{
// 12 characters 5 x 7
- for (int x=0; x<5; x++)
+ for (int x = 0; x < 5; x++)
{
- uint8_t gfx = 0;
+ u8 gfx = 0;
if (lcd_on)
gfx = bitswap<8>(dram[c * 5 + x], 6,5,0,1,2,3,4,7);
- for (int y=1; y<8; y++)
+ for (int y = 1; y < 8; y++)
bitmap.pix(y, 71 - (c * 6 + x)) = BIT(gfx, y);
}
@@ -127,7 +160,7 @@ SED1520_UPDATE_CB(risc2500_state::screen_update_cb)
if (lcd_on)
{
int data_addr = 80 + c * 5;
- uint16_t data = ((dram[data_addr + 1] & 0x3) << 5) | ((dram[data_addr + 2] & 0x7) << 2) | (dram[data_addr + 4] & 0x3);
+ u16 data = ((dram[data_addr + 1] & 0x3) << 5) | ((dram[data_addr + 2] & 0x7) << 2) | (dram[data_addr + 4] & 0x3);
data = bitswap<8>(data, 7,3,0,1,4,6,5,2) | ((dram[data_addr - 1] & 0x04) ? 0x80 : 0);
m_digits[c] = data;
@@ -146,71 +179,82 @@ SED1520_UPDATE_CB(risc2500_state::screen_update_cb)
return 0;
}
-INPUT_CHANGED_MEMBER(risc2500_state::on_button)
+
+
+/******************************************************************************
+ I/O
+******************************************************************************/
+
+// bootrom bankswitch
+
+void risc2500_state::install_bootrom(bool enable)
{
- if (newval)
- {
- install_boot_rom();
- m_maincpu->reset();
- }
+ address_space &program = m_maincpu->space(AS_PROGRAM);
+ program.unmap_readwrite(0, std::max(m_rom.bytes(), m_ram->size()) - 1);
+
+ if (enable)
+ program.install_rom(0, m_rom.bytes() - 1, m_rom);
+ else
+ program.install_ram(0, m_ram->size() - 1, m_ram->pointer());
+
+ m_bootrom_enabled = enable;
}
-static INPUT_PORTS_START( risc2500 )
- PORT_START("P0")
- 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")
+u32 risc2500_state::disable_boot_rom_r()
+{
+ // disconnect bootrom from the bus after next opcode
+ if (m_bootrom_enabled && !m_disable_bootrom->enabled() && !machine().side_effects_disabled())
+ m_disable_bootrom->adjust(m_maincpu->cycles_to_attotime(5));
- PORT_START("P1")
- 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")
+ return 0;
+}
- PORT_START("P2")
- 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(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")
+// soft power on/off
- PORT_START("P4")
- 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")
+INPUT_CHANGED_MEMBER(risc2500_state::on_button)
+{
+ if (newval && !m_power)
+ {
+ m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
+ machine_reset();
+ }
+}
- PORT_START("P5")
- 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")
+void risc2500_state::power_off()
+{
+ m_power = false;
+ m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
- PORT_START("P6")
- 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")
+ // clear display
+ m_lcdc->reset();
- PORT_START("P7")
- 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")
+ for (int i = 0; i < 16; i++)
+ m_leds[i] = 0;
+}
- 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
+// main I/O
-uint32_t risc2500_state::p1000_r()
+u32 risc2500_state::input_r()
{
- uint32_t data = 0;
+ u32 data = 0;
- for (int i=0; i<8; i++)
+ for (int i = 0; i < 8; i++)
{
- if (m_p1000 & (1 << i))
+ if (m_control & (1 << i))
{
- data |= m_inputs[i]->read();
+ data |= m_inputs[i]->read() << 24;
data |= m_board->read_rank(i, true);
}
}
- return data | ((uint32_t)m_lcdc->status_read() << 16);
+ return data | ((u32)m_lcdc->status_read() << 16);
}
-void risc2500_state::p1000_w(uint32_t data)
+void risc2500_state::control_w(u32 data)
{
+ // lcd
if (!BIT(data, 27))
{
if (BIT(data, 26))
@@ -219,73 +263,118 @@ void risc2500_state::p1000_w(uint32_t data)
m_lcdc->control_write(data);
}
- if (BIT(data, 31)) // Vertical LED
+ // vertical leds
+ if (BIT(data, 31))
{
- for (int i=0; i<8; i++)
- m_leds[i] = BIT(data, i);
+ for (int i = 0; i < 8; i++)
+ m_leds[i] = BIT(~data, i);
}
- if (BIT(data, 30)) // Horizontal LED
+ // horizontal leds
+ if (BIT(data, 30))
{
- for (int i=0; i<8; i++)
- m_leds[8 + i] = BIT(data, i);
+ for (int i = 0; i < 8; i++)
+ m_leds[8 + i] = BIT(~data, i);
}
- m_dac->write(data >> 28 & 3); // Speaker
+ // speaker
+ m_dac->write(data >> 28 & 3);
- m_p1000 = data;
-}
+ // power-off
+ if (BIT(m_control & ~data, 24))
+ power_off();
-uint32_t risc2500_state::disable_boot_rom_r()
-{
- m_boot_rom_disable_timer->adjust(m_maincpu->cycles_to_attotime(10));
- return 0;
+ m_control = data;
}
-TIMER_CALLBACK_MEMBER(risc2500_state::disable_boot_rom)
+
+
+/******************************************************************************
+ Address Maps
+******************************************************************************/
+
+void risc2500_state::risc2500_mem(address_map &map)
{
- remove_boot_rom();
+ map(0x01800000, 0x01800003).r(FUNC(risc2500_state::disable_boot_rom_r));
+ map(0x01000000, 0x01000003).rw(FUNC(risc2500_state::input_r), FUNC(risc2500_state::control_w));
+ map(0x02000000, 0x0203ffff).rom().region("maincpu", 0);
}
-void risc2500_state::machine_start()
-{
- m_digits.resolve();
- m_syms.resolve();
- m_leds.resolve();
- m_nvram->set_base(m_ram->pointer(), m_ram->size());
- m_boot_rom_disable_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(risc2500_state::disable_boot_rom), this));
+/******************************************************************************
+ Input Ports
+******************************************************************************/
- save_item(NAME(m_p1000));
+static INPUT_PORTS_START( risc2500 )
+ PORT_START("P0")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Pawn") PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("BACK") PORT_CODE(KEYCODE_BACKSPACE)
- machine().save().register_postload(save_prepost_delegate(FUNC(risc2500_state::remove_boot_rom), this));
-}
+ PORT_START("P1")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Knight") PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD)
-void risc2500_state::machine_reset()
-{
- m_p1000 = 0;
+ PORT_START("P2")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Bishop") PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN)
- install_boot_rom();
-}
+ PORT_START("P3")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Rook") PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("UP") PORT_CODE(KEYCODE_UP)
-void risc2500_state::risc2500_mem(address_map &map)
-{
- map(0x00000000, 0x0001ffff).ram();
- map(0x01800000, 0x01800003).r(FUNC(risc2500_state::disable_boot_rom_r));
- map(0x01000000, 0x01000003).rw(FUNC(risc2500_state::p1000_r), FUNC(risc2500_state::p1000_w));
- map(0x02000000, 0x0203ffff).rom().region("maincpu", 0);
-}
+ PORT_START("P4")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Queen") PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("MENU") PORT_CODE(KEYCODE_M)
+
+ PORT_START("P5")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("King") PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("PLAY") PORT_CODE(KEYCODE_L)
+
+ PORT_START("P6")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("NEW GAME") PORT_CODE(KEYCODE_N)
+
+ PORT_START("P7")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("OFF") PORT_CODE(KEYCODE_O)
+
+ PORT_START("RESET")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("ON") PORT_CODE(KEYCODE_I) PORT_CHANGED_MEMBER(DEVICE_SELF, risc2500_state, on_button, 0)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("ACL") PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, risc2500_state, acl_button, 0)
+INPUT_PORTS_END
+
+
+
+/******************************************************************************
+ Machine Configs
+******************************************************************************/
void risc2500_state::risc2500(machine_config &config)
{
- ARM(config, m_maincpu, XTAL(28'322'000) / 2); // VY86C010
+ /* basic machine hardware */
+ ARM(config, m_maincpu, 28.322_MHz_XTAL / 2); // VY86C010
m_maincpu->set_addrmap(AS_PROGRAM, &risc2500_state::risc2500_mem);
m_maincpu->set_copro_type(arm_cpu_device::copro_type::VL86C020);
m_maincpu->set_periodic_int(FUNC(risc2500_state::irq1_line_hold), attotime::from_hz(32.768_kHz_XTAL/128)); // 256Hz
+ TIMER(config, "disable_bootrom").configure_generic(FUNC(risc2500_state::disable_bootrom));
+
+ RAM(config, m_ram).set_extra_options("128K, 256K, 512K, 1M, 2M");
+ m_ram->set_default_size("2M");
+ m_ram->set_default_value(0);
+
+ NVRAM(config, "nvram", nvram_device::DEFAULT_NONE);
+
+ SENSORBOARD(config, m_board);
+ m_board->set_type(sensorboard_device::BUTTONS);
+ m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess));
+ m_board->set_delay(attotime::from_msec(100));
+ m_board->set_nvram_enable(true);
+
+ /* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
- screen.set_refresh_hz(50);
+ screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
screen.set_size(12*6+1, 7+2);
screen.set_visarea_full();
@@ -299,25 +388,16 @@ void risc2500_state::risc2500(machine_config &config)
SED1520(config, m_lcdc);
m_lcdc->set_screen_update_cb(FUNC(risc2500_state::screen_update_cb));
- SENSORBOARD(config, m_board);
- m_board->set_type(sensorboard_device::BUTTONS);
- m_board->init_cb().set(m_board, FUNC(sensorboard_device::preset_chess));
- m_board->set_delay(attotime::from_msec(100));
- m_board->set_nvram_enable(true);
-
- RAM(config, m_ram).set_extra_options("128K, 256K, 512K, 1M, 2M");
- m_ram->set_default_size("2M");
- m_ram->set_default_value(0);
-
- NVRAM(config, "nvram", nvram_device::DEFAULT_NONE);
-
/* sound hardware */
SPEAKER(config, "speaker").front_center();
- DAC_2BIT_BINARY_WEIGHTED_ONES_COMPLEMENT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); // unknown DAC
+ DAC_2BIT_BINARY_WEIGHTED_ONES_COMPLEMENT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25);
}
-/* ROM definitions */
+
+/******************************************************************************
+ ROM Definitions
+******************************************************************************/
ROM_START( risc2500 )
ROM_REGION( 0x40000, "maincpu", ROMREGION_ERASE00 )
@@ -330,12 +410,19 @@ ROM_START( risc2500a )
ROM_END
ROM_START( montreux ) // v1.00
- ROM_REGION( 0x40000, "maincpu", ROMREGION_ERASE00 )
+ ROM_REGION( 0x40000, "maincpu", 0 )
ROM_LOAD("rt17b_103_u_7.u7", 0x000000, 0x040000, CRC(db374cf3) SHA1(44dd60d56779084326c3dfb41d2137ebf0b4e0ac) ) // 27C020-15
ROM_END
+} // anonymous namespace
+
+
+
+/******************************************************************************
+ Drivers
+******************************************************************************/
-/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS */
+// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS
CONS( 1992, risc2500, 0, 0, risc2500, risc2500, risc2500_state, empty_init, "Saitek / Tasc", "Kasparov RISC 2500 (v1.04)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND )
CONS( 1992, risc2500a, risc2500, 0, risc2500, risc2500, risc2500_state, empty_init, "Saitek / Tasc", "Kasparov RISC 2500 (v1.03)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND )