// license:BSD-3-Clause
// copyright-holders:hap
// thanks-to:Sean Riddle
/***************************************************************************
AMI S2000 series handhelds or other simple devices.
TODO:
- were any other handhelds with this MCU released?
- wildfire sound can be improved, volume decay should be more steep at the start,
and the pitch sounds wrong too (latter is an MCU emulation problem)
***************************************************************************/
#include "emu.h"
#include "cpu/amis2000/amis2000.h"
#include "video/pwm.h"
#include "machine/timer.h"
#include "sound/spkrdev.h"
#include "speaker.h"
// internal artwork
#include "wildfire.lh"
//#include "hh_amis2k_test.lh" // common test-layout - use external artwork
class hh_amis2k_state : public driver_device
{
public:
hh_amis2k_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_display(*this, "display"),
m_speaker(*this, "speaker"),
m_inputs(*this, "IN.%u", 0)
{ }
// devices
required_device<amis2000_base_device> m_maincpu;
optional_device<pwm_display_device> m_display;
optional_device<speaker_sound_device> m_speaker;
optional_ioport_array<4> m_inputs; // max 4
// misc common
u16 m_a; // MCU address bus
u8 m_d; // MCU data bus
int m_f; // MCU F_out pin
u16 m_inp_mux; // multiplexed inputs mask
u8 read_inputs(int columns);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
};
// machine start/reset
void hh_amis2k_state::machine_start()
{
// zerofill
m_a = 0;
m_d = 0;
m_f = 0;
m_inp_mux = 0;
// register for savestates
save_item(NAME(m_a));
save_item(NAME(m_d));
save_item(NAME(m_f));
save_item(NAME(m_inp_mux));
}
void hh_amis2k_state::machine_reset()
{
}
/***************************************************************************
Helper Functions
***************************************************************************/
// generic input handlers
u8 hh_amis2k_state::read_inputs(int columns)
{
u8 ret = 0;
// read selected input rows
for (int i = 0; i < columns; i++)
if (m_inp_mux >> i & 1)
ret |= m_inputs[i]->read();
return ret;
}
/***************************************************************************
Minidrivers (subclass, I/O, Inputs, Machine Config, ROM Defs)
***************************************************************************/
namespace {
/***************************************************************************
Parker Brothers Wildfire, by Bob and Holly Doyle (prototype), and Garry Kitchen
* AMI S2150, labeled C10641
* RC circuit for speaker volume decay (see patent US4334679 FIG.5,
the 2 resistors at A12 are 10K and the cap is 4.7uF)
This is an electronic handheld pinball game. It has dozens of small leds
to create the illusion of a moving ball, and even the flippers are leds.
A drawing of a pinball table is added as overlay.
led translation table: led Lzz from patent US4334679 FIG.4* = MAME y.x:
*note: 2 mistakes in it: L19 between L12 and L14 should be L13, and L84 should of course be L48
0 = - 10 = 6.6 20 = 4.5 30 = 5.3 40 = 5.7 50 = 11.6
1 = 10.7 11 = 5.6 21 = 4.4 31 = 4.3 41 = 6.0 51 = 11.5
2 = 10.0 12 = 6.5 22 = 5.4 32 = 5.2 42 = 7.0 52 = 11.4
3 = 10.1 13 = 7.5 23 = 6.3 33 = 5.1 43 = 8.0 53 = 11.3
4 = 10.2 14 = 8.5 24 = 7.3 34 = 11.7 44 = 9.0 60 = 3.6
5 = 10.3 15 = 9.4 25 = 11.1 35 = 7.1 45 = 6.7 61 = 3.6(!)
6 = 10.4 16 = 8.4 26 = 9.3 36 = 9.1 46 = 7.7 62 = 3.5
7 = 10.5 17 = 7.4 27 = 9.2 37 = 5.0 47 = 8.7 63 = 3.5(!)
8 = 8.6 18 = 11.2 28 = 8.2 38 = 6.1 48 = 9.7 70 = 3.3
9 = 7.6 19 = 5.5 29 = 11.0 39 = 8.1 49 = -
NOTE!: MAME external artwork is required
***************************************************************************/
class wildfire_state : public hh_amis2k_state
{
public:
wildfire_state(const machine_config &mconfig, device_type type, const char *tag) :
hh_amis2k_state(mconfig, type, tag)
{ }
void update_display();
DECLARE_WRITE8_MEMBER(write_d);
DECLARE_WRITE16_MEMBER(write_a);
DECLARE_WRITE_LINE_MEMBER(write_f);
void speaker_update();
TIMER_DEVICE_CALLBACK_MEMBER(speaker_decay_sim);
double m_speaker_volume;
void wildfire(machine_config &config);
protected:
virtual void machine_start() override;
};
void wildfire_state::machine_start()
{
hh_amis2k_state::machine_start();
// zerofill/init
m_speaker_volume = 0;
save_item(NAME(m_speaker_volume));
}
// handlers
void wildfire_state::speaker_update()
{
if (~m_a & 0x1000)
m_speaker_volume = 1.0;
m_speaker->level_w(m_f * 0x7fff * m_speaker_volume);
}
TIMER_DEVICE_CALLBACK_MEMBER(wildfire_state::speaker_decay_sim)
{
// volume decays when speaker is off (divisor and timer period determine duration)
speaker_update();
m_speaker_volume /= 1.0025;
}
void wildfire_state::update_display()
{
m_display->matrix(~m_a, m_d);
}
WRITE8_MEMBER(wildfire_state::write_d)
{
// D0-D7: led/7seg data
m_d = bitswap<8>(data,7,0,1,2,3,4,5,6);
update_display();
}
WRITE16_MEMBER(wildfire_state::write_a)
{
// A0-A2: digit select
// A3-A11: led select
m_a = data;
update_display();
// A12: speaker on
speaker_update();
}
WRITE_LINE_MEMBER(wildfire_state::write_f)
{
// F: speaker out
m_f = state;
speaker_update();
}
// config
static INPUT_PORTS_START( wildfire )
PORT_START("IN.0") // I
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Shooter Button")
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Left Flipper")
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Right Flipper")
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
INPUT_PORTS_END
// 7seg decoder table differs from default, this one is made by hand
static const u8 wildfire_7seg_table[0x10] =
{
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, // 0, 1, 2, 3, 4, 5, 6, 7
0x7f, 0x6f, 0x77, 0x73, 0x39, 0x38, 0x79, 0x40 // 8, 9, ?, P, ?, L, ?, -
};
void wildfire_state::wildfire(machine_config &config)
{
/* basic machine hardware */
AMI_S2152(config, m_maincpu, 850000); // approximation - RC osc. R=?, C=?
m_maincpu->set_7seg_table(wildfire_7seg_table);
m_maincpu->read_i().set_ioport("IN.0");
m_maincpu->write_d().set(FUNC(wildfire_state::write_d));
m_maincpu->write_a().set(FUNC(wildfire_state::write_a));
m_maincpu->write_f().set(FUNC(wildfire_state::write_f));
/* video hardware */
PWM_DISPLAY(config, m_display).set_size(12, 8);
m_display->set_segmask(7, 0x7f);
m_display->set_bri_levels(0.01, 0.1); // bumpers are dimmed
config.set_default_layout(layout_wildfire);
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25);
TIMER(config, "speaker_decay").configure_periodic(FUNC(wildfire_state::speaker_decay_sim), attotime::from_usec(100));
// set volume levels (set_output_gain is too slow for sub-frame intervals)
static s16 speaker_levels[0x8000];
for (int i = 0; i < 0x8000; i++)
speaker_levels[i] = i;
m_speaker->set_levels(0x8000, speaker_levels);
}
// roms
ROM_START( wildfire )
ROM_REGION( 0x0800, "maincpu", ROMREGION_ERASE00 )
// Typed in from patent US4334679, data should be correct(it included checksums). 1st half was also dumped/verfied with release version.
ROM_LOAD( "us4341385", 0x0000, 0x0400, CRC(84ac0f1f) SHA1(1e00ddd402acfc2cc267c34eed4b89d863e2144f) )
ROM_CONTINUE( 0x0600, 0x0200 )
ROM_END
} // anonymous namespace
/***************************************************************************
Game driver(s)
***************************************************************************/
// YEAR NAME PARENT CMP MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS
CONS( 1979, wildfire, 0, 0, wildfire, wildfire, wildfire_state, empty_init, "Parker Brothers", "Wildfire (patent)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) // note: pretty sure that it matches the commercial release