From 9bb192141c55ace5a1b3fce8e618f8805bf38327 Mon Sep 17 00:00:00 2001 From: hap Date: Thu, 22 Apr 2021 22:51:45 +0200 Subject: [PATCH] risc2500/tasc: fixed high pitched sound problem --- src/devices/cpu/arm/arm.cpp | 9 +- src/devices/machine/smartboard.cpp | 10 +- src/mame/drivers/mephisto_berlin.cpp | 6 +- src/mame/drivers/saitek_risc2500.cpp | 109 +++++++++++++++----- src/mame/drivers/tasc.cpp | 143 ++++++++++++++++++++------- 5 files changed, 208 insertions(+), 69 deletions(-) diff --git a/src/devices/cpu/arm/arm.cpp b/src/devices/cpu/arm/arm.cpp index ac80af28531..d5f577a390f 100644 --- a/src/devices/cpu/arm/arm.cpp +++ b/src/devices/cpu/arm/arm.cpp @@ -497,10 +497,13 @@ void arm_cpu_device::device_start() { m_program = &space(AS_PROGRAM); - if(m_program->endianness() == ENDIANNESS_LITTLE) { + if(m_program->endianness() == ENDIANNESS_LITTLE) + { m_program->cache(m_cachele); m_pr32 = [this](offs_t address) -> u32 { return m_cachele.read_dword(address); }; - } else { + } + else + { m_program->cache(m_cachebe); m_pr32 = [this](offs_t address) -> u32 { return m_cachebe.read_dword(address); }; } @@ -824,7 +827,7 @@ void arm_cpu_device::HandleALU( uint32_t insn ) { op2 = decodeShift(insn, (insn & INSN_S) ? &sc : nullptr); - if (!(insn & INSN_S)) + if (!(insn & INSN_S)) sc=0; } diff --git a/src/devices/machine/smartboard.cpp b/src/devices/machine/smartboard.cpp index fe1dc0b5d08..c91dbd0ca46 100644 --- a/src/devices/machine/smartboard.cpp +++ b/src/devices/machine/smartboard.cpp @@ -10,11 +10,13 @@ The SmartBoard can detect which piece is present on a specific square, more info on the technology used in the piece recognition system can be found in the US patent 5,129,654 -SB30 (81 LEDs) is "SmartBoard I" -SB20 (64 LEDs) is "SmartBoard II" +SmartBoard I is SB30 (81 LEDs, analog chesspieces) +SmartBoard II is SB20 (64 LEDs, digital chesspieces) +SmartBoard III is SB30 again, but digital -SB20 is not emulated. It's on different hardware, with embedded CPU to reduce -I/O overhead. Note, SB20 is not compatible with old versions of Tasc R30. +SB20 and the newer SB30 are not emulated. They're on different hardware, with +embedded CPU to reduce I/O overhead. Note, These are not compatible with old +versions of Tasc R30. ******************************************************************************/ diff --git a/src/mame/drivers/mephisto_berlin.cpp b/src/mame/drivers/mephisto_berlin.cpp index fcf8f29a648..0d4102d9405 100644 --- a/src/mame/drivers/mephisto_berlin.cpp +++ b/src/mame/drivers/mephisto_berlin.cpp @@ -5,13 +5,13 @@ Mephisto Berlin 68000 / Berlin Professional 68020 Berlin Professional has the same engine as Mephisto Genius. -TODO: -- does it have ROM waitstates like mephisto_modular? - Undocumented buttons: - holding ENTER and LEFT cursor on boot runs diagnostics - holding CLEAR on boot clears battery backed RAM +TODO: +- does it have ROM waitstates like mephisto_modular? + ******************************************************************************/ #include "emu.h" diff --git a/src/mame/drivers/saitek_risc2500.cpp b/src/mame/drivers/saitek_risc2500.cpp index 4cf3eb42561..cf665e89e10 100644 --- a/src/mame/drivers/saitek_risc2500.cpp +++ b/src/mame/drivers/saitek_risc2500.cpp @@ -5,34 +5,47 @@ Saitek RISC 2500, Mephisto Montreux 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. +The hardware+software appears to have been subcontracted to Tasc. It has +similarities with Tasc R30. 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. +Hardware notes: +- PCB label: TASC23C +- ARM2 CPU(VY86C010) @ 14.16MHz +- 128KB ROM, 128KB RAM* +- SED1520, custom LCD screen +- 8*8 chessboard buttons, 16 leds, piezo + +*: Sold with 128KB RAM by default. This can be easily increased up to 2MB +by the user(chesscomputer owner, but also the MAME user in this case). +The manual also says that RAM is expandable. + +According to Saitek's repair manual, there is a GAL and a clock frequency +divider chip, ROM access goes through it. This allows reading from slow EPROM +while the chess engine resides in faster RAM. The piezo output routine is +also in ROM, it would be way too high-pitched at full speed. + 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 -- Sound is too short and high pitched, better when you underclock the cpu. - Is cpu cycle timing wrong? I suspect conditional branch timing due to cache miss - (pipeline has to refill). The delay loop between writing to the speaker is simply: - SUBS R2, R2, #$1, BNE $2000cd8 +- more accurate dynamic cpu clock divider (without the cost of emulation speed) ******************************************************************************/ #include "emu.h" #include "cpu/arm/arm.h" -#include "machine/ram.h" #include "machine/nvram.h" +#include "machine/ram.h" #include "machine/sensorboard.h" #include "machine/timer.h" #include "video/sed1520.h" -#include "sound/dac.h" +#include "sound/spkrdev.h" #include "emupal.h" #include "screen.h" @@ -54,7 +67,7 @@ public: , m_ram(*this, "ram") , m_nvram(*this, "nvram") , m_disable_bootrom(*this, "disable_bootrom") - , m_dac(*this, "dac") + , m_speaker(*this, "speaker") , m_lcdc(*this, "lcdc") , m_board(*this, "board") , m_inputs(*this, "P%u", 0) @@ -79,7 +92,7 @@ private: required_device m_ram; required_device m_nvram; required_device m_disable_bootrom; - required_device m_dac; + required_device m_speaker; required_device m_lcdc; required_device m_board; required_ioport_array<8> m_inputs; @@ -93,6 +106,7 @@ private: SED1520_UPDATE_CB(screen_update_cb); u32 input_r(); void control_w(u32 data); + u32 rom_r(offs_t offset); void power_off(); u32 disable_boot_rom_r(); @@ -100,8 +114,10 @@ private: TIMER_DEVICE_CALLBACK_MEMBER(disable_bootrom) { install_bootrom(false); } bool m_bootrom_enabled = false; - u32 m_control = 0; bool m_power = false; + u32 m_control = 0; + u32 m_prev_pc = 0; + u64 m_prev_cycle = 0; }; void risc2500_state::machine_start() @@ -116,6 +132,8 @@ void risc2500_state::machine_start() save_item(NAME(m_power)); save_item(NAME(m_bootrom_enabled)); save_item(NAME(m_control)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_prev_cycle)); } void risc2500_state::machine_reset() @@ -124,6 +142,8 @@ void risc2500_state::machine_reset() m_power = true; m_control = 0; + m_prev_pc = m_maincpu->pc(); + m_prev_cycle = m_maincpu->total_cycles(); } @@ -190,10 +210,10 @@ SED1520_UPDATE_CB(risc2500_state::screen_update_cb) void risc2500_state::install_bootrom(bool enable) { address_space &program = m_maincpu->space(AS_PROGRAM); - program.unmap_readwrite(0, std::max(m_rom.bytes(), size_t(m_ram->size()) - 1)); + program.unmap_readwrite(0, std::max(m_rom.bytes(), size_t(m_ram->size())) - 1); if (enable) - program.install_rom(0, m_rom.bytes() - 1, m_rom); + program.install_read_handler(0, m_rom.bytes() - 1, read32sm_delegate(*this, FUNC(risc2500_state::rom_r))); else program.install_ram(0, m_ram->size() - 1, m_ram->pointer()); @@ -238,7 +258,7 @@ void risc2500_state::power_off() u32 risc2500_state::input_r() { - u32 data = 0; + u32 data = (u32)m_lcdc->status_read() << 16; for (int i = 0; i < 8; i++) { @@ -249,7 +269,10 @@ u32 risc2500_state::input_r() } } - return data | ((u32)m_lcdc->status_read() << 16); + if (!machine().side_effects_disabled()) + m_maincpu->set_input_line(ARM_FIRQ_LINE, CLEAR_LINE); + + return data; } void risc2500_state::control_w(u32 data) @@ -278,7 +301,7 @@ void risc2500_state::control_w(u32 data) } // speaker - m_dac->write(data >> 28 & 3); + m_speaker->level_w(data >> 28 & 3); // power-off if (BIT(m_control & ~data, 24)) @@ -287,6 +310,38 @@ void risc2500_state::control_w(u32 data) m_control = data; } +u32 risc2500_state::rom_r(offs_t offset) +{ + if (!machine().side_effects_disabled()) + { + // handle dynamic cpu clock divider when accessing rom + u64 cur_cycle = m_maincpu->total_cycles(); + u64 prev_cycle = m_prev_cycle; + s64 diff = cur_cycle - prev_cycle; + + u32 pc = m_maincpu->pc(); + u32 prev_pc = m_prev_pc; + m_prev_pc = pc; + + if (diff >= 0) + { + static constexpr int arm_branch_cycles = 3; + static constexpr int arm_max_cycles = 17; // block data transfer + static constexpr int divider = -8 + 1; + + // this takes care of almost all cases, otherwise, total cycles taken can't be determined + if (diff <= arm_branch_cycles || (diff <= arm_max_cycles && (pc - prev_pc) == 4 && (pc & ~0x02000000) == (offset * 4))) + m_maincpu->adjust_icount(divider * (int)diff); + else + m_maincpu->adjust_icount(divider); + } + + m_prev_cycle = m_maincpu->total_cycles(); + } + + return m_rom[offset]; +} + /****************************************************************************** @@ -297,7 +352,7 @@ void risc2500_state::risc2500_mem(address_map &map) { 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); + map(0x02000000, 0x0203ffff).r(FUNC(risc2500_state::rom_r)); } @@ -353,15 +408,17 @@ INPUT_PORTS_END void risc2500_state::risc2500(machine_config &config) { /* basic machine hardware */ - ARM(config, m_maincpu, 28.322_MHz_XTAL / 2); // VY86C010 + ARM(config, m_maincpu, 28.322_MHz_XTAL / 2); 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 + + const attotime irq_period = attotime::from_hz(32.768_kHz_XTAL / 128); // 256Hz + m_maincpu->set_periodic_int(FUNC(risc2500_state::irq1_line_assert), irq_period); 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_size("128K"); m_ram->set_default_value(0); NVRAM(config, "nvram", nvram_device::DEFAULT_NONE); @@ -389,8 +446,10 @@ void risc2500_state::risc2500(machine_config &config) m_lcdc->set_screen_update_cb(FUNC(risc2500_state::screen_update_cb)); /* sound hardware */ - SPEAKER(config, "speaker").front_center(); - DAC_2BIT_BINARY_WEIGHTED_ONES_COMPLEMENT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); + SPEAKER(config, "mono").front_center(); + static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0.0 }; + SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25); + m_speaker->set_levels(4, speaker_levels); } @@ -423,7 +482,7 @@ ROM_END ******************************************************************************/ // 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 ) +CONS( 1992, risc2500, 0, 0, risc2500, risc2500, risc2500_state, empty_init, "Saitek / Tasc", "Kasparov RISC 2500 (v1.04)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +CONS( 1992, risc2500a, risc2500, 0, risc2500, risc2500, risc2500_state, empty_init, "Saitek / Tasc", "Kasparov RISC 2500 (v1.03)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) -CONS( 1995, montreux, 0, 0, risc2500, risc2500, risc2500_state, empty_init, "Saitek / Tasc", "Mephisto Montreux", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND ) // after Saitek bought Hegener + Glaser +CONS( 1995, montreux, 0, 0, risc2500, risc2500, risc2500_state, empty_init, "Saitek / Tasc", "Mephisto Montreux", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) // after Saitek bought Hegener + Glaser diff --git a/src/mame/drivers/tasc.cpp b/src/mame/drivers/tasc.cpp index 348fea94dfb..60c0049ceea 100644 --- a/src/mame/drivers/tasc.cpp +++ b/src/mame/drivers/tasc.cpp @@ -8,6 +8,9 @@ Commonly known as Tasc R30, it's basically a dedicated ChessMachine. The King chess engines are also compatible with Tasc's The ChessMachine software on PC, however the prototype Gideon 2.1(internally: Rebel 2.01) is not. +WARNING: Don't configure more than 512KB RAM for R30 The King 2.50, it will still +be playable but will actually use less than 512KB RAM and become weaker. + The King 2.23 version was not released to the public. It has an opening book meant for chesscomputer competitions. For more information, see: http://chesseval.com/ChessEvalJournal/R30v223.htm @@ -24,6 +27,14 @@ R40 hardware notes: - +512KB extra RAM piggybacked - rest same as R30 +EPROMs are interchangable between R30 and R40, with some limitations with +The King 2.50 (see below). + +Regarding RAM: The King 2.2x will work fine with RAM expanded up to 8MB. +The King 2.50 appears to be protected against RAM upgrades though, and will +limit itself to 128KB if it detects a non-default amount of RAM. Gideon doesn't +use RAM above 128KB either, perhaps the R30 prototype only had 128KB RAM. + Documentation for the Toshiba chips is hard to find, but similar chips exist: T7778 is equivalent to T6A39, T7900 is equivalent to T6A40. @@ -39,7 +50,8 @@ notes: TODO: - bootrom disable timer shouldn't be needed, real ARM has already fetched the next opcode -- sound is too high pitched, same problem as in risc2500 +- more accurate dynamic cpu clock divider (same problem as in saitek_risc2500.cpp), + sound pitch is correct now though ******************************************************************************/ @@ -48,10 +60,11 @@ TODO: #include "cpu/arm/arm.h" #include "machine/bankdev.h" #include "machine/nvram.h" +#include "machine/ram.h" #include "machine/smartboard.h" #include "machine/timer.h" #include "video/t6963c.h" -#include "sound/dac.h" +#include "sound/spkrdev.h" #include "speaker.h" @@ -68,10 +81,10 @@ public: driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_rom(*this, "maincpu"), - m_mainram(*this, "mainram"), + m_ram(*this, "ram"), m_lcd(*this, "lcd"), m_smartboard(*this, "smartboard"), - m_dac(*this, "dac"), + m_speaker(*this, "speaker"), m_disable_bootrom(*this, "disable_bootrom"), m_inputs(*this, "IN.%u", 0U), m_out_leds(*this, "pled%u", 0U) @@ -79,19 +92,21 @@ public: void tasc(machine_config &config); + DECLARE_INPUT_CHANGED_MEMBER(switch_cpu_freq) { set_cpu_freq(); } + protected: virtual void machine_start() override; - virtual void machine_reset() override { install_bootrom(true); } + virtual void machine_reset() override; virtual void device_post_load() override { install_bootrom(m_bootrom_enabled); } private: // devices/pointers required_device m_maincpu; required_region_ptr m_rom; - required_shared_ptr m_mainram; + required_device m_ram; required_device m_lcd; required_device m_smartboard; - required_device m_dac; + required_device m_speaker; required_device m_disable_bootrom; required_ioport_array<4> m_inputs; output_finder<2> m_out_leds; @@ -101,14 +116,17 @@ private: // I/O handlers u32 input_r(); + u32 rom_r(offs_t offset); void control_w(offs_t offset, u32 data, u32 mem_mask = ~0); + void set_cpu_freq(); void install_bootrom(bool enable); - void disable_bootrom_next(); TIMER_DEVICE_CALLBACK_MEMBER(disable_bootrom) { install_bootrom(false); } bool m_bootrom_enabled = false; u32 m_control = 0; + u32 m_prev_pc = 0; + u64 m_prev_cycle = 0; }; void tasc_state::machine_start() @@ -117,6 +135,23 @@ void tasc_state::machine_start() save_item(NAME(m_bootrom_enabled)); save_item(NAME(m_control)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_prev_cycle)); +} + +void tasc_state::machine_reset() +{ + install_bootrom(true); + set_cpu_freq(); + + m_prev_pc = m_maincpu->pc(); + m_prev_cycle = m_maincpu->total_cycles(); +} + +void tasc_state::set_cpu_freq() +{ + // R30 is 30MHz, R40 is 40MHz + m_maincpu->set_unscaled_clock((ioport("FAKE")->read() & 1) ? 40_MHz_XTAL : 30_MHz_XTAL); } @@ -125,34 +160,30 @@ void tasc_state::machine_start() I/O ******************************************************************************/ -// bootrom bankswitch - void tasc_state::install_bootrom(bool enable) { address_space &program = m_maincpu->space(AS_PROGRAM); - program.unmap_readwrite(0, std::max(m_rom.bytes(), m_mainram.bytes()) - 1); + program.unmap_readwrite(0, std::max(m_rom.bytes(), size_t(m_ram->size())) - 1); + // bootrom bankswitch if (enable) - program.install_rom(0, m_rom.bytes() - 1, m_rom); + program.install_read_handler(0, m_rom.bytes() - 1, read32sm_delegate(*this, FUNC(tasc_state::rom_r))); else - program.install_ram(0, m_mainram.bytes() - 1, m_mainram); + program.install_ram(0, m_ram->size() - 1, m_ram->pointer()); m_bootrom_enabled = enable; } -void tasc_state::disable_bootrom_next() -{ - // 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)); -} - - -// main I/O - u32 tasc_state::input_r() { - disable_bootrom_next(); + if (!machine().side_effects_disabled()) + { + // disconnect bootrom from the bus after next opcode + if (m_bootrom_enabled && !m_disable_bootrom->enabled()) + m_disable_bootrom->adjust(m_maincpu->cycles_to_attotime(5)); + + m_maincpu->set_input_line(ARM_FIRQ_LINE, CLEAR_LINE); + } // read chessboard u32 data = m_smartboard->data_r(); @@ -181,12 +212,44 @@ void tasc_state::control_w(offs_t offset, u32 data, u32 mem_mask) { m_out_leds[0] = BIT(data, 0); m_out_leds[1] = BIT(data, 1); - m_dac->write((data >> 2) & 3); + m_speaker->level_w((data >> 2) & 3); } COMBINE_DATA(&m_control); } +u32 tasc_state::rom_r(offs_t offset) +{ + if (!machine().side_effects_disabled()) + { + // handle dynamic cpu clock divider when accessing rom + u64 cur_cycle = m_maincpu->total_cycles(); + u64 prev_cycle = m_prev_cycle; + s64 diff = cur_cycle - prev_cycle; + + u32 pc = m_maincpu->pc(); + u32 prev_pc = m_prev_pc; + m_prev_pc = pc; + + if (diff >= 0) + { + static constexpr int arm_branch_cycles = 3; + static constexpr int arm_max_cycles = 17; // block data transfer + static constexpr int divider = -7 + 1; + + // this takes care of almost all cases, otherwise, total cycles taken can't be determined + if (diff <= arm_branch_cycles || (diff <= arm_max_cycles && (pc - prev_pc) == 4 && (pc & ~0x02000000) == (offset * 4))) + m_maincpu->adjust_icount(divider * (int)diff); + else + m_maincpu->adjust_icount(divider); + } + + m_prev_cycle = m_maincpu->total_cycles(); + } + + return m_rom[offset]; +} + /****************************************************************************** @@ -195,9 +258,8 @@ void tasc_state::control_w(offs_t offset, u32 data, u32 mem_mask) void tasc_state::main_map(address_map &map) { - map(0x00000000, 0x0007ffff).ram().share("mainram"); map(0x01000000, 0x01000003).rw(FUNC(tasc_state::input_r), FUNC(tasc_state::control_w)); - map(0x02000000, 0x0203ffff).rom().region("maincpu", 0); + map(0x02000000, 0x0203ffff).r(FUNC(tasc_state::rom_r)); map(0x03000000, 0x0307ffff).m("nvram_map", FUNC(address_map_bank_device::amap8)).umask32(0x000000ff); } @@ -233,6 +295,11 @@ static INPUT_PORTS_START( tasc ) PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_ENTER) PORT_NAME("ENTER") PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_DOWN) PORT_NAME("DOWN") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_NAME("Right Clock") + + PORT_START("FAKE") + PORT_CONFNAME( 0x01, 0x00, "CPU Frequency" ) PORT_CHANGED_MEMBER(DEVICE_SELF, tasc_state, switch_cpu_freq, 0) + PORT_CONFSETTING( 0x00, "30MHz (R30)" ) + PORT_CONFSETTING( 0x01, "40MHz (R40)" ) INPUT_PORTS_END @@ -247,10 +314,16 @@ void tasc_state::tasc(machine_config &config) ARM(config, m_maincpu, 30_MHz_XTAL); m_maincpu->set_addrmap(AS_PROGRAM, &tasc_state::main_map); m_maincpu->set_copro_type(arm_cpu_device::copro_type::VL86C020); - m_maincpu->set_periodic_int(FUNC(tasc_state::irq1_line_hold), attotime::from_hz(32.768_kHz_XTAL/128)); // 256Hz + + const attotime irq_period = attotime::from_hz(32.768_kHz_XTAL / 128); // 256Hz + m_maincpu->set_periodic_int(FUNC(tasc_state::irq1_line_assert), irq_period); TIMER(config, "disable_bootrom").configure_generic(FUNC(tasc_state::disable_bootrom)); + RAM(config, m_ram).set_extra_options("512K, 1M, 2M, 4M, 8M"); // see driver notes + m_ram->set_default_size("512K"); + m_ram->set_default_value(0); + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); ADDRESS_MAP_BANK(config, "nvram_map").set_map(&tasc_state::nvram_map).set_options(ENDIANNESS_LITTLE, 8, 17); @@ -264,8 +337,10 @@ void tasc_state::tasc(machine_config &config) config.set_default_layout(layout_tascr30); /* sound hardware */ - SPEAKER(config, "speaker").front_center(); - DAC_2BIT_BINARY_WEIGHTED_ONES_COMPLEMENT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); + SPEAKER(config, "mono").front_center(); + static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0.0 }; + SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25); + m_speaker->set_levels(4, speaker_levels); } @@ -307,7 +382,7 @@ ROM_END ******************************************************************************/ // YEAR NAME PARENT CMP MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS -CONS( 1995, tascr30, 0, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.50)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND ) -CONS( 1993, tascr30a, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.20)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND ) -CONS( 1993, tascr30b, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.23, TM version)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND ) // competed in several chesscomputer tournaments -CONS( 1993, tascr30g, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (Gideon 2.1, prototype)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_IMPERFECT_SOUND ) // made in 1993, later released in 2012 +CONS( 1995, tascr30, 0, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.50)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +CONS( 1993, tascr30a, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.20)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +CONS( 1993, tascr30b, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.23, TM version)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) // competed in several chesscomputer tournaments +CONS( 1993, tascr30g, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (Gideon 2.1, prototype)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) // made in 1993, later released in 2012