cothello: add coin handling and sound

This commit is contained in:
hap 2023-02-01 23:31:48 +01:00
parent acc7d534af
commit dbaf7b376d
3 changed files with 117 additions and 21 deletions

View File

@ -65,7 +65,7 @@ void beep_device::sound_stream_update(sound_stream &stream, std::vector<read_str
clock = m_frequency; clock = m_frequency;
/* if we're not enabled, just fill with 0 */ /* if we're not enabled, just fill with 0 */
if ( !m_enable || clock == 0 ) if (!m_enable || clock == 0)
{ {
buffer.fill(0); buffer.fill(0);
return; return;

View File

@ -57,10 +57,11 @@
emulates an unmodified PCB, you can enable the hacks in the DRIVER emulates an unmodified PCB, you can enable the hacks in the DRIVER
CONFIGURATION menu. CONFIGURATION menu.
B&W cabinet versions also exist.
Versions of Tomahawk using the Astro Fighter PROM have been seen, Versions of Tomahawk using the Astro Fighter PROM have been seen,
see notes in ROM loading. see notes in ROM loading.
****************************************************************************/ ****************************************************************************/

View File

@ -12,27 +12,32 @@ and is presumed to be on the same base hardware as the arcade version.
Hardware notes: Hardware notes:
- PCB label: COG CPU - PCB label: COG CPU
- M58710S (8080A), ?MHz XTAL - M58710S (8080A), 3.579545MHz XTAL
- 3*1KB M58732S 2708 ROM, 4th socket is empty - 3*1KB M58732S 2708 ROM, 4th socket is empty
- 256 bytes RAM (2*M58722P 2111A), 0.5KB DRAM (M58755S) - 256 bytes RAM (2*M58722P 2111A), 0.5KB DRAM (M58755S)
- M58741P Color TV Interface, 64*64 1bpp video - M58741P Color TV Interface, 64*64 1bpp video
- 7seg time counter (not software controlled)
- beeper - beeper
TODO: TODO:
- verify XTAL
- verify video timing - verify video timing
- coin - beeper duration and base frequency is approximated (divisor is correct)
- sound - CPU speed is wrong, it's likely running at 1.79MHz. But that's way too fast
- is there a button select, or is current input emulation correct where for compared to videos of the game. 0.9MHz(XTAL/4) is also too fast. It's probably
example P1 can move P2 cursor? (the only unique P2 button is the Set button) due to the M58741P HOLD pin halting the 8080, which is not emulated.
- unknown if the screen is color or B&W + overlay, but since the video chip is - Is there a button select somewhere? I really can't find any. Or is current
meant for a color tv, let's assume the green tint is from the screen itself input emulation correct where for example P1 can move P2 cursor? (the only
unique P2 button is the Set button)
- It's not known if the screen is color or B&W + overlay, but since the video
chip is meant for a color tv, let's assume the green tint is from the screen
itself. Photos of the home version also show a green tint.
*******************************************************************************/ *******************************************************************************/
#include "emu.h" #include "emu.h"
#include "cpu/i8085/i8085.h" #include "cpu/i8085/i8085.h"
#include "sound/beep.h"
#include "screen.h" #include "screen.h"
#include "speaker.h" #include "speaker.h"
@ -50,26 +55,52 @@ public:
m_maincpu(*this, "maincpu"), m_maincpu(*this, "maincpu"),
m_screen(*this, "screen"), m_screen(*this, "screen"),
m_vram(*this, "vram"), m_vram(*this, "vram"),
m_inputs(*this, "IN.%u", 0) m_beeper(*this, "beeper"),
m_inputs(*this, "IN.%u", 0),
m_digits(*this, "digit%u", 0U)
{ } { }
void cothello(machine_config &config); void cothello(machine_config &config);
DECLARE_INPUT_CHANGED_MEMBER(insert_coin);
protected:
virtual void machine_start() override;
private: private:
required_device<cpu_device> m_maincpu; required_device<cpu_device> m_maincpu;
required_device<screen_device> m_screen; required_device<screen_device> m_screen;
required_shared_ptr<u8> m_vram; required_shared_ptr<u8> m_vram;
required_ioport_array<3> m_inputs; required_device<beep_device> m_beeper;
required_ioport_array<4> m_inputs;
output_finder<4> m_digits;
void main_map(address_map &map); void main_map(address_map &map);
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
u8 input_r();
u8 coin_r(); u8 coin_r();
u8 input_r();
void sound_w(u8 data); void sound_w(u8 data);
TIMER_CALLBACK_MEMBER(counter_tick);
TIMER_CALLBACK_MEMBER(beeper_off) { m_beeper->set_state(0); }
u16 m_counter = 0;
emu_timer *m_counter_timer;
emu_timer *m_beeper_off;
}; };
void cothello_state::machine_start()
{
m_digits.resolve();
m_counter_timer = timer_alloc(FUNC(cothello_state::counter_tick), this);
m_beeper_off = timer_alloc(FUNC(cothello_state::beeper_off), this);
save_item(NAME(m_counter));
}
/******************************************************************************* /*******************************************************************************
@ -96,6 +127,46 @@ u32 cothello_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, c
I/O I/O
*******************************************************************************/ *******************************************************************************/
INPUT_CHANGED_MEMBER(cothello_state::insert_coin)
{
if (!newval || m_counter_timer->enabled())
return;
// reset counter
m_counter = ~0;
m_counter_timer->adjust(attotime::zero);
}
TIMER_CALLBACK_MEMBER(cothello_state::counter_tick)
{
m_counter++;
// highest digit is compared to a digit wheel setting
u8 max = std::clamp(int(m_inputs[3]->read()), 1, 9);
u8 high = (m_counter / 100) % 10;
if (high == 0 || high == max)
m_maincpu->set_input_line(0, HOLD_LINE);
if (high != max)
m_counter_timer->adjust(attotime::from_seconds(1));
// output counter to 7segs
static const u8 led_map[] = { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f };
m_digits[0] = led_map[m_counter % 10];
m_digits[1] = led_map[(m_counter / 10) % 10];
m_digits[2] = led_map[high];
}
u8 cothello_state::coin_r()
{
// d0-d2: coin status
// d3: ?
// d4-d7: unused
return m_counter_timer->enabled() ? 0xfb : 0xff;
}
u8 cothello_state::input_r() u8 cothello_state::input_r()
{ {
u8 data = 0xff; u8 data = 0xff;
@ -106,14 +177,22 @@ u8 cothello_state::input_r()
return data; return data;
} }
u8 cothello_state::coin_r()
{
return 0xfb;
}
void cothello_state::sound_w(u8 data) void cothello_state::sound_w(u8 data)
{ {
//printf("%X ",data); if (data & 0x80)
{
// d3: beeper start
if (data & 8)
{
m_beeper->set_state(1);
m_beeper_off->adjust(attotime::from_msec(80));
}
// d0-d2: beeper frequency
u8 freq = (data & 0x7) + 1;
const u32 base = 3500;
m_beeper->set_clock(base / freq);
}
} }
@ -164,6 +243,21 @@ static INPUT_PORTS_START( cothello )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_COCKTAIL PORT_NAME("P2 Pass") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_COCKTAIL PORT_NAME("P2 Pass")
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_COCKTAIL PORT_NAME("P2 Set") PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_COCKTAIL PORT_NAME("P2 Set")
PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN.3")
PORT_CONFNAME( 0x0f, 0x05, "Time" )
PORT_DIPSETTING( 0x01, "100 seconds" )
PORT_DIPSETTING( 0x02, "200 seconds" )
PORT_DIPSETTING( 0x03, "300 seconds" )
PORT_DIPSETTING( 0x04, "400 seconds" )
PORT_DIPSETTING( 0x05, "500 seconds" )
PORT_DIPSETTING( 0x06, "600 seconds" )
PORT_DIPSETTING( 0x07, "700 seconds" )
PORT_DIPSETTING( 0x08, "800 seconds" )
PORT_DIPSETTING( 0x09, "900 seconds" )
PORT_START("COIN")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, cothello_state, insert_coin, 0)
INPUT_PORTS_END INPUT_PORTS_END
@ -176,7 +270,6 @@ void cothello_state::cothello(machine_config &config)
{ {
// basic machine hardware // basic machine hardware
I8080A(config, m_maincpu, 750000); I8080A(config, m_maincpu, 750000);
m_maincpu->set_vblank_int("screen", FUNC(cothello_state::irq0_line_hold));
m_maincpu->set_addrmap(AS_PROGRAM, &cothello_state::main_map); m_maincpu->set_addrmap(AS_PROGRAM, &cothello_state::main_map);
// video hardware // video hardware
@ -188,6 +281,8 @@ void cothello_state::cothello(machine_config &config)
m_screen->set_screen_update(FUNC(cothello_state::screen_update)); m_screen->set_screen_update(FUNC(cothello_state::screen_update));
// sound hardware // sound hardware
SPEAKER(config, "mono").front_center();
BEEP(config, m_beeper, 0).add_route(ALL_OUTPUTS, "mono", 0.25);
} }
@ -212,4 +307,4 @@ ROM_END
******************************************************************************/ ******************************************************************************/
// YEAR NAME PARENT MACHINE INPUT CLASS INIT SCREEN COMPANY, FULLNAME, FLAGS // YEAR NAME PARENT MACHINE INPUT CLASS INIT SCREEN COMPANY, FULLNAME, FLAGS
GAMEL(1978, cothello, 0, cothello, cothello, cothello_state, empty_init, ROT0, "Nintendo", "Computer Othello", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING | MACHINE_NO_SOUND, layout_cothello ) GAMEL(1978, cothello, 0, cothello, cothello, cothello_state, empty_init, ROT0, "Nintendo", "Computer Othello", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND, layout_cothello )