nitendo/n8080.cpp: Encapsulated sound boards.

This commit is contained in:
Vas Crabb 2023-09-10 06:25:34 +10:00
parent c516e72e0c
commit 04aac6dc77
9 changed files with 1107 additions and 1110 deletions

View File

@ -157,7 +157,7 @@ license:CC0-1.0
</software>
<!-- Needs a working light pen interface -->
<software name="lpengrph" supported="partial">
<software name="lpengrph" supported="no">
<description>Light Pen Graphic v1.0 (Japan)</description>
<year>1984</year>
<publisher>Sanyo</publisher>
@ -17678,7 +17678,7 @@ Side B
</software>
<!-- Only part 1 can be loaded -->
<software name="queensfs" supported="partial">
<software name="queensfs" supported="no">
<description>The Queen's Footsteps (English)</description>
<year>2020</year>
<publisher>Davide Bucci</publisher>

View File

@ -978,7 +978,6 @@ template <bool Debugger, bool Caching> inline void dsp16_device_base::execute_so
case 0x1e: // Reserved
throw emu_fatalerror("DSP16: reserved op %u (PC = %04X)\n", op >> 11, m_st_pcbase);
break;
case 0x1f: // F1 ; y = Y ; x = *pt++[i]
m_core->op_dau_ad(op) = m_core->dau_f1(op);

View File

@ -150,10 +150,10 @@ class ttl_mono_state : public driver_device
{
public:
ttl_mono_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_video(*this, "fixfreq"),
m_dac(*this, "dac") /* just to have a sound device */
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_video(*this, "fixfreq")
, m_dac(*this, "dac") /* just to have a sound device */
{
}
@ -172,14 +172,6 @@ public:
m_dac->write(16384 * data);
}
protected:
// driver_device overrides
virtual void machine_start() override { };
virtual void machine_reset() override { };
virtual void video_start() override { };
private:
};
@ -188,9 +180,9 @@ class pong_state : public ttl_mono_state
{
public:
pong_state(const machine_config &mconfig, device_type type, const char *tag)
: ttl_mono_state(mconfig, type, tag),
m_sw1a(*this, "maincpu:sw1a"),
m_sw1b(*this, "maincpu:sw1b")
: ttl_mono_state(mconfig, type, tag)
, m_sw1a(*this, "maincpu:sw1a")
, m_sw1b(*this, "maincpu:sw1b")
{
}
@ -203,13 +195,6 @@ public:
void pongd(machine_config &config);
void pong(machine_config &config);
protected:
// driver_device overrides
virtual void machine_start() override { };
virtual void machine_reset() override { };
virtual void video_start() override { };
private:
};
@ -218,17 +203,17 @@ class breakout_state : public ttl_mono_state
{
public:
breakout_state(const machine_config &mconfig, device_type type, const char *tag)
: ttl_mono_state(mconfig, type, tag),
m_led_serve(*this, "maincpu:led_serve"),
m_lamp_credit1(*this, "maincpu:lamp_credit1"),
m_lamp_credit2(*this, "maincpu:lamp_credit2"),
m_coin_counter(*this, "maincpu:coin_counter"),
m_sw1_1(*this, "maincpu:sw1_1"),
m_sw1_2(*this, "maincpu:sw1_2"),
m_sw1_3(*this, "maincpu:sw1_3"),
m_sw1_4(*this, "maincpu:sw1_4"),
m_serve_led_output(*this, "serve_led"),
m_lamp_credit_output(*this, "lamp_credit%u", 1U)
: ttl_mono_state(mconfig, type, tag)
, m_led_serve(*this, "maincpu:led_serve")
, m_lamp_credit1(*this, "maincpu:lamp_credit1")
, m_lamp_credit2(*this, "maincpu:lamp_credit2")
, m_coin_counter(*this, "maincpu:coin_counter")
, m_sw1_1(*this, "maincpu:sw1_1")
, m_sw1_2(*this, "maincpu:sw1_2")
, m_sw1_3(*this, "maincpu:sw1_3")
, m_sw1_4(*this, "maincpu:sw1_4")
, m_serve_led_output(*this, "serve_led")
, m_lamp_credit_output(*this, "lamp_credit%u", 1U)
{
}
required_device<netlist_mame_analog_output_device> m_led_serve;
@ -268,9 +253,7 @@ public:
protected:
// driver_device overrides
virtual void machine_start() override { m_serve_led_output.resolve(); m_lamp_credit_output.resolve(); };
virtual void machine_reset() override { };
virtual void video_start() override { };
virtual void machine_start() override { m_serve_led_output.resolve(); m_lamp_credit_output.resolve(); }
private:
output_finder<> m_serve_led_output;
@ -309,9 +292,7 @@ public:
protected:
// driver_device overrides
virtual void machine_start() override { m_credit_led.resolve(); };
virtual void machine_reset() override { };
virtual void video_start() override { };
virtual void machine_start() override { m_credit_led.resolve(); }
private:
output_finder<> m_credit_led;

View File

@ -1335,7 +1335,7 @@ MC6845_UPDATE_ROW(heath_gp19_tlb_device::crtc_update_row)
{
for (int x = 0; x < x_count; x++)
{
uint8_t const gfx = m_p_videoram[((ma << 1) + ( ra * x_count ) + x) & 0x3fff] ^ screen_inv;
uint8_t const gfx = m_p_videoram[((ma << 1) + (ra * x_count) + x) & 0x3fff] ^ screen_inv;
for (int b = 0; 8 > b; ++b)
{
@ -1345,7 +1345,7 @@ MC6845_UPDATE_ROW(heath_gp19_tlb_device::crtc_update_row)
}
else
{
uint16_t base = m_char_gen_a11 ? 0x800 : 0x0;
uint16_t const base = m_char_gen_a11 ? 0x800 : 0x0;
for (int x = 0; x < x_count; x++)
{

View File

@ -137,27 +137,541 @@ Notes:
***************************************************************************/
#include "emu.h"
#include "n8080.h"
#include "n8080_a.h"
#include "cpu/i8085/i8085.h"
#include "machine/timer.h"
#include "emupal.h"
#include "screen.h"
namespace {
class n8080_state : public driver_device
{
public:
n8080_state(const machine_config &mconfig, device_type type, const char *tag) ATTR_COLD :
driver_device(mconfig, type, tag),
m_videoram(*this, "videoram"),
m_prom(*this, "proms"),
m_maincpu(*this, "maincpu"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_sound(*this, "soundboard")
{ }
protected:
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
virtual void delayed_sound_1(u8 data);
virtual void delayed_sound_2(u8 data);
void n8080_shift_bits_w(u8 data);
void n8080_shift_data_w(u8 data);
u8 n8080_shift_r();
void n8080_video_control_w(u8 data);
void n8080_sound_1_w(u8 data);
void n8080_sound_2_w(u8 data);
void n8080_inte_callback(int state);
void n8080_status_callback(u8 data);
void n8080_palette(palette_device &palette) const ATTR_COLD;
TIMER_DEVICE_CALLBACK_MEMBER(rst1_tick);
TIMER_DEVICE_CALLBACK_MEMBER(rst2_tick);
TIMER_CALLBACK_MEMBER(stop_mono_flop_callback);
TIMER_CALLBACK_MEMBER(delayed_sound_1_callback);
TIMER_CALLBACK_MEMBER(delayed_sound_2_callback);
void main_cpu_map(address_map &map) ATTR_COLD;
void main_io_map(address_map &map) ATTR_COLD;
/* memory pointers */
required_shared_ptr<u8> m_videoram;
optional_memory_region m_prom;
/* video-related */
u8 m_sheriff_color_mode;
u8 m_sheriff_color_data;
/* other */
unsigned m_shift_data;
u8 m_shift_bits;
bool m_inte;
/* devices */
required_device<i8080a_cpu_device> m_maincpu;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_device<n8080_sound_device_base> m_sound;
};
class spacefev_state : public n8080_state
{
public:
spacefev_state(const machine_config &mconfig, device_type type, const char *tag) ATTR_COLD :
n8080_state(mconfig, type, tag),
m_video_conf(*this, "VIDEO")
{ }
void spacefev(machine_config &config) ATTR_COLD;
protected:
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
virtual void delayed_sound_1(u8 data) override;
virtual void delayed_sound_2(u8 data) override;
private:
TIMER_CALLBACK_MEMBER(stop_red_cannon);
void start_red_cannon();
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
required_ioport m_video_conf;
emu_timer *m_cannon_timer;
u8 m_prev_snd_data = 0;
bool m_red_screen = false;
bool m_red_cannon = false;
};
class sheriff_state : public n8080_state
{
public:
sheriff_state(const machine_config &mconfig, device_type type, const char *tag) ATTR_COLD :
n8080_state(mconfig, type, tag)
{ }
void sheriff(machine_config &config) ATTR_COLD;
void westgun2(machine_config &config) ATTR_COLD;
protected:
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
private:
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
};
class helifire_state : public n8080_state
{
public:
helifire_state(const machine_config &mconfig, device_type type, const char *tag) ATTR_COLD :
n8080_state(mconfig, type, tag),
m_colorram(*this, "colorram"),
m_pot(*this, "POT%u", 0)
{ }
void helifire(machine_config &config) ATTR_COLD;
protected:
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
virtual void delayed_sound_2(u8 data) override;
private:
void helifire_palette(palette_device &palette) const ATTR_COLD;
void next_line();
void screen_vblank(int state);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_cpu_map(address_map &map) ATTR_COLD;
required_shared_ptr<u8> m_colorram;
required_ioport_array<2> m_pot;
bool m_flash = false;
u8 m_LSFR[63];
unsigned m_mv = 0;
unsigned m_sc = 0; // IC56
};
// Shifter circuit done with TTL
void n8080_state::n8080_shift_bits_w(uint8_t data)
void n8080_state::n8080_shift_bits_w(u8 data)
{
m_shift_bits = data & 7;
}
void n8080_state::n8080_shift_data_w(uint8_t data)
void n8080_state::n8080_shift_data_w(u8 data)
{
m_shift_data = (m_shift_data >> 8) | (data << 8);
}
uint8_t n8080_state::n8080_shift_r()
u8 n8080_state::n8080_shift_r()
{
return m_shift_data >> (8 - m_shift_bits);
}
void n8080_state::delayed_sound_1(u8 data)
{
m_sound->sound1_w(data);
}
void spacefev_state::delayed_sound_1(u8 data)
{
if (BIT(data & ~m_prev_snd_data, 4))
start_red_cannon();
m_red_screen = BIT(data, 3);
m_prev_snd_data = data;
n8080_state::delayed_sound_1(data);
}
void n8080_state::delayed_sound_2(u8 data)
{
m_sound->sound2_w(data);
}
void spacefev_state::delayed_sound_2(u8 data)
{
flip_screen_set(BIT(data, 5));
n8080_state::delayed_sound_2(data);
}
void helifire_state::delayed_sound_2(u8 data)
{
m_flash = BIT(data, 5);
n8080_state::delayed_sound_2(data);
}
void n8080_state::n8080_video_control_w(u8 data)
{
m_sheriff_color_mode = (data >> 3) & 3;
m_sheriff_color_data = (data >> 0) & 7;
flip_screen_set(data & 0x20);
}
void n8080_state::n8080_palette(palette_device &palette) const
{
for (int i = 0; i < 8; i++)
palette.set_pen_color(i, pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2));
}
void helifire_state::helifire_palette(palette_device &palette) const
{
n8080_palette(palette);
for (int i = 0; i < 0x100; i++)
{
int const level = 0xff * exp(-3 * i / 255.); // capacitor discharge
palette.set_pen_color(0x000 + 8 + i, rgb_t(0x00, 0x00, level)); // shades of blue
palette.set_pen_color(0x100 + 8 + i, rgb_t(0x00, 0xc0, level)); // shades of blue w/ green star
palette.set_pen_color(0x200 + 8 + i, rgb_t(level, 0x00, 0x00)); // shades of red
palette.set_pen_color(0x300 + 8 + i, rgb_t(level, 0xc0, 0x00)); // shades of red w/ green star
}
}
void spacefev_state::start_red_cannon()
{
m_red_cannon = true;
m_cannon_timer->adjust(attotime::from_usec(550 * 68 * 10));
}
TIMER_CALLBACK_MEMBER(spacefev_state::stop_red_cannon)
{
m_red_cannon = false;
m_cannon_timer->adjust(attotime::never);
}
void helifire_state::next_line()
{
m_mv++;
if (m_sc % 4 == 2)
{
m_mv %= 256;
}
else
{
if (flip_screen())
m_mv %= 255;
else
m_mv %= 257;
}
if (m_mv == 128)
{
m_sc++;
}
}
u32 spacefev_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
const bool mono = bool(m_video_conf->read());
u8 mask = flip_screen() ? 0xff : 0x00;
u8 const *pRAM = m_videoram;
u8 const *const pPROM = m_prom->base();
for (int y = 0; y < 256; y++)
{
u16 *const pLine = &bitmap.pix(y ^ mask);
for (int x = 0; x < 256; x += 8)
{
u8 color = 0;
if (m_red_screen)
color = 1;
else
{
u8 val = pPROM[x >> 3];
if ((x >> 3) == 0x06)
{
color = m_red_cannon ? 1 : 7;
}
if ((x >> 3) == 0x1b)
{
static const u8 ufo_color[] =
{
1, // red
2, // green
7, // white
3, // yellow
5, // magenta
6, // cyan
};
int cycle = screen.frame_number() / 32;
color = ufo_color[cycle % 6];
}
for (int n = color + 1; n < 8; n++)
{
if (~val & (1 << n))
{
color = n;
}
}
}
if (mono)
color = 7; // force B&W here
for (int n = 0; n < 8; n++)
{
pLine[(x + n) ^ mask] = (pRAM[x >> 3] & (1 << n)) ? color : 0;
}
}
pRAM += 32;
}
return 0;
}
u32 sheriff_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
u8 mask = flip_screen() ? 0xff : 0x00;
u8 const *pRAM = m_videoram;
u8 const *const pPROM = m_prom->base();
for (int y = 0; y < 256; y++)
{
u16 *const pLine = &bitmap.pix(y ^ mask);
for (int x = 0; x < 256; x += 8)
{
u8 color = pPROM[32 * (y >> 3) + (x >> 3)];
if (m_sheriff_color_mode == 1 && !(color & 8))
color = m_sheriff_color_data ^ 7;
if (m_sheriff_color_mode == 2)
color = m_sheriff_color_data ^ 7;
if (m_sheriff_color_mode == 3)
color = 7;
for (int n = 0; n < 8; n++)
{
pLine[(x + n) ^ mask] = ((pRAM[x >> 3] >> n) & 1) ? (color & 7) : 0;
}
}
pRAM += 32;
}
return 0;
}
u32 helifire_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
const int SUN_BRIGHTNESS = m_pot[0]->read();
const int SEA_BRIGHTNESS = m_pot[1]->read();
static const int wave[8] = { 0, 1, 2, 2, 2, 1, 0, 0 };
unsigned saved_mv = m_mv;
unsigned saved_sc = m_sc;
for (int y = 0; y < 256; y++)
{
u16 *const pLine = &bitmap.pix(y);
int level = 120 + wave[m_mv & 7];
// draw sky
for (int x = level; x < 256; x++)
{
pLine[x] = 0x200 + 8 + SUN_BRIGHTNESS + x - level;
}
// draw stars
if (m_mv % 8 == 4) // upper half
{
int step = (320 * (m_mv - 0)) % sizeof m_LSFR;
int data =
((m_LSFR[step] & 1) << 6) |
((m_LSFR[step] & 2) << 4) |
((m_LSFR[step] & 4) << 2) |
((m_LSFR[step] & 8) << 0);
pLine[0x80 + data] |= 0x100;
}
if (m_mv % 8 == 5) // lower half
{
int step = (320 * (m_mv - 1)) % sizeof m_LSFR;
int data =
((m_LSFR[step] & 1) << 6) |
((m_LSFR[step] & 2) << 4) |
((m_LSFR[step] & 4) << 2) |
((m_LSFR[step] & 8) << 0);
pLine[0x00 + data] |= 0x100;
}
// draw sea
for (int x = 0; x < level; x++)
{
pLine[x] = 8 + SEA_BRIGHTNESS + x;
}
// draw foreground
for (int x = 0; x < 256; x += 8)
{
int offset = 32 * y + (x >> 3);
for (int n = 0; n < 8; n++)
{
if (flip_screen())
{
if ((m_videoram[offset ^ 0x1fff] << n) & 0x80)
{
pLine[x + n] = m_colorram[offset ^ 0x1fff] & 7;
}
}
else
{
if ((m_videoram[offset] >> n) & 1)
{
pLine[x + n] = m_colorram[offset] & 7;
}
}
}
}
// next line
next_line();
}
m_mv = saved_mv;
m_sc = saved_sc;
return 0;
}
void helifire_state::screen_vblank(int state)
{
// falling edge
if (!state)
{
int n = (m_screen->frame_number() >> 1) % sizeof m_LSFR;
int i;
for (i = 0; i < 8; i++)
{
int R = (i & 1);
int G = (i & 2);
int B = (i & 4);
if (m_flash)
{
if (m_LSFR[n] & 0x20)
{
G |= B;
}
if (m_screen->frame_number() & 0x04)
{
R |= G;
}
}
m_palette->set_pen_color(i,
R ? 255 : 0,
G ? 255 : 0,
B ? 255 : 0);
}
for (i = 0; i < 256; i++)
{
next_line();
}
}
}
void n8080_state::n8080_sound_1_w(u8 data)
{
machine().scheduler().synchronize(timer_expired_delegate(FUNC(n8080_state::delayed_sound_1_callback), this), data); // force CPUs to sync
}
void n8080_state::n8080_sound_2_w(u8 data)
{
machine().scheduler().synchronize(timer_expired_delegate(FUNC(n8080_state::delayed_sound_2_callback), this), data); // force CPUs to sync
}
TIMER_CALLBACK_MEMBER(n8080_state::delayed_sound_1_callback)
{
delayed_sound_1(param);
}
TIMER_CALLBACK_MEMBER(n8080_state::delayed_sound_2_callback)
{
delayed_sound_2(param);
}
// Memory maps
void n8080_state::main_cpu_map(address_map &map)
@ -193,7 +707,7 @@ void n8080_state::main_io_map(address_map &map)
// Input ports
static INPUT_PORTS_START( spacefev )
INPUT_PORTS_START( spacefev )
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_2WAY
@ -249,7 +763,7 @@ static INPUT_PORTS_START( spacefev )
INPUT_PORTS_END
static INPUT_PORTS_START( highsplt )
INPUT_PORTS_START( highsplt )
PORT_INCLUDE( spacefev )
PORT_MODIFY("IN2")
@ -278,7 +792,7 @@ static INPUT_PORTS_START( highsplt )
INPUT_PORTS_END
static INPUT_PORTS_START( spacelnc )
INPUT_PORTS_START( spacelnc )
PORT_INCLUDE( highsplt )
PORT_MODIFY("IN2")
@ -307,7 +821,7 @@ static INPUT_PORTS_START( spacelnc )
INPUT_PORTS_END
static INPUT_PORTS_START( sheriff )
INPUT_PORTS_START( sheriff )
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_RIGHT )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_LEFT )
@ -355,7 +869,7 @@ static INPUT_PORTS_START( sheriff )
INPUT_PORTS_END
static INPUT_PORTS_START( bandido )
INPUT_PORTS_START( bandido )
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_RIGHT )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_LEFT )
@ -406,7 +920,7 @@ static INPUT_PORTS_START( bandido )
INPUT_PORTS_END
static INPUT_PORTS_START( westgun2 )
INPUT_PORTS_START( westgun2 )
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_RIGHT )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_LEFT )
@ -446,7 +960,7 @@ static INPUT_PORTS_START( westgun2 )
INPUT_PORTS_END
static INPUT_PORTS_START( helifire )
INPUT_PORTS_START( helifire )
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT )
@ -540,10 +1054,10 @@ TIMER_DEVICE_CALLBACK_MEMBER(n8080_state::rst2_tick)
void n8080_state::n8080_inte_callback(int state)
{
m_inte = state;
m_inte = state != 0;
}
void n8080_state::n8080_status_callback(uint8_t data)
void n8080_state::n8080_status_callback(u8 data)
{
if (data & i8080a_cpu_device::STATUS_INTA)
{
@ -566,15 +1080,43 @@ void n8080_state::machine_reset()
{
m_shift_data = 0;
m_shift_bits = 0;
m_inte = 0;
m_inte = false;
delayed_sound_1(0);
delayed_sound_2(0);
}
void spacefev_state::machine_start()
{
n8080_state::machine_start();
m_cannon_timer = timer_alloc(FUNC(spacefev_state::stop_red_cannon), this);
flip_screen_set(0);
save_item(NAME(m_prev_snd_data));
save_item(NAME(m_red_screen));
save_item(NAME(m_red_cannon));
}
void spacefev_state::machine_reset()
{
m_prev_snd_data = 0;
n8080_state::machine_reset();
m_red_screen = 0;
m_red_cannon = 0;
m_red_screen = false;
m_red_cannon = false;
}
void sheriff_state::machine_start()
{
n8080_state::machine_start();
flip_screen_set(0);
save_item(NAME(m_sheriff_color_mode));
save_item(NAME(m_sheriff_color_data));
}
void sheriff_state::machine_reset()
@ -585,13 +1127,33 @@ void sheriff_state::machine_reset()
m_sheriff_color_data = 0;
}
void helifire_state::machine_start()
{
n8080_state::machine_start();
u8 data = 0;
for (int i = 0; i < 63; i++)
{
u8 const bit = (data >> 6) ^ (data >> 7) ^ 1;
data = (data << 1) | (bit & 1);
m_LSFR[i] = data;
}
flip_screen_set(0);
save_item(NAME(m_mv));
save_item(NAME(m_sc));
save_item(NAME(m_flash));
save_item(NAME(m_LSFR));
}
void helifire_state::machine_reset()
{
n8080_state::machine_reset();
m_mv = 0;
m_sc = 0;
m_flash = 0;
m_flash = false;
}
@ -618,7 +1180,7 @@ void spacefev_state::spacefev(machine_config &config)
TIMER(config, "rst2").configure_scanline(FUNC(spacefev_state::rst2_tick), "screen", 240, 256);
/* sound hardware */
spacefev_sound(config);
SPACEFEV_SOUND(config, m_sound, u32(0));
}
void sheriff_state::sheriff(machine_config &config)
@ -642,7 +1204,7 @@ void sheriff_state::sheriff(machine_config &config)
TIMER(config, "rst2").configure_scanline(FUNC(sheriff_state::rst2_tick), "screen", 240, 256);
/* sound hardware */
sheriff_sound(config);
SHERIFF_SOUND(config, m_sound, u32(0));
}
void sheriff_state::westgun2(machine_config &config)
@ -676,7 +1238,7 @@ void helifire_state::helifire(machine_config &config)
TIMER(config, "rst2").configure_scanline(FUNC(helifire_state::rst2_tick), "screen", 240, 256);
/* sound hardware */
helifire_sound(config);
HELIFIRE_SOUND(config, m_sound, u32(0));
}
@ -692,7 +1254,7 @@ ROM_START( spacefev )
ROM_LOAD( "h2-ro-.bin", 0x1400, 0x0400, CRC(a163e800) SHA1(e8817f3e17f099a0dc66213d2d3d3fdeb117b10e) ) // "H2??"
ROM_LOAD( "i1-ro-p.bin", 0x1800, 0x0400, CRC(756b5582) SHA1(b7f3d218b7f4267ce6128624306396bcacb9b44e) ) // "I1??P"
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "ss3.ic2", 0x0000, 0x0400, CRC(95c2c1ee) SHA1(42a3a382fc7d2782052372d71f6d0e8a153e74d0) )
ROM_REGION( 0x0020, "proms", 0 ) // for color video hw
@ -709,7 +1271,7 @@ ROM_START( spacefevo )
ROM_LOAD( "h2-ro-.bin", 0x1400, 0x0400, CRC(a163e800) SHA1(e8817f3e17f099a0dc66213d2d3d3fdeb117b10e) ) // "H2??"
ROM_LOAD( "i1-ro-.bin", 0x1800, 0x0400, CRC(00027be2) SHA1(551a779a2e5a6455b7a348d246731c094e0ec709) ) // "I1??"
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "ss3.ic2", 0x0000, 0x0400, CRC(95c2c1ee) SHA1(42a3a382fc7d2782052372d71f6d0e8a153e74d0) )
ROM_REGION( 0x0020, "proms", 0 ) // for color video hw
@ -726,7 +1288,7 @@ ROM_START( spacefevo2 )
ROM_LOAD( "h2-i-.bin", 0x1400, 0x0400, CRC(bddbc94f) SHA1(f90cbc3cd0f695cbb9ae03b608f4bf5a4a000c64) ) // "H2?C"
ROM_LOAD( "i1-i-.bin", 0x1800, 0x0400, CRC(437786c5) SHA1(2ccdb0d48dbbfe47ae82e970ca37970602405cf6) ) // "I1?C"
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "ss3.ic2", 0x0000, 0x0400, CRC(95c2c1ee) SHA1(42a3a382fc7d2782052372d71f6d0e8a153e74d0) )
ROM_REGION( 0x0020, "proms", 0 ) // for color video hw
@ -744,7 +1306,7 @@ ROM_START( highsplt )
ROM_LOAD( "hs.i1", 0x1800, 0x0400, CRC(41e18df9) SHA1(2212c836313775e7c507a875672c0b3635825e02) )
ROM_LOAD( "i2-ha-.bin", 0x1c00, 0x0400, CRC(eff9f82d) SHA1(5004e52dfa652ceefca9ed4210c0fa8f0591dc08) ) // "I2?n"
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "ss4.bin", 0x0000, 0x0400, CRC(939e01d4) SHA1(7c9ccd24e5da03831cd0aa821da17e3b81cd8381) )
ROM_REGION( 0x0020, "proms", 0 )
@ -762,7 +1324,7 @@ ROM_START( highsplta )
ROM_LOAD( "i1-ha-.bin", 0x1800, 0x0400, CRC(aa36b25d) SHA1(28f555aab27b206a8c6f550b6caa938cece6e204) ) // "I1?n"
ROM_LOAD( "i2-ha-.bin", 0x1c00, 0x0400, CRC(eff9f82d) SHA1(5004e52dfa652ceefca9ed4210c0fa8f0591dc08) ) // "I2?n"
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "ss4.bin", 0x0000, 0x0400, CRC(939e01d4) SHA1(7c9ccd24e5da03831cd0aa821da17e3b81cd8381) )
ROM_REGION( 0x0020, "proms", 0 )
@ -780,7 +1342,7 @@ ROM_START( highspltb )
ROM_LOAD( "i1-ha-.bin", 0x1800, 0x0400, CRC(aa36b25d) SHA1(28f555aab27b206a8c6f550b6caa938cece6e204) ) // "I1?n"
ROM_LOAD( "i2-ha-.bin", 0x1c00, 0x0400, CRC(eff9f82d) SHA1(5004e52dfa652ceefca9ed4210c0fa8f0591dc08) ) // "I2?n"
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "ss4.ic2", 0x0000, 0x0400, CRC(ce95dc5f) SHA1(20f7b8c565c408439dcfae240b7d1aa42c29651b) )
ROM_REGION( 0x0020, "proms", 0 )
@ -798,7 +1360,7 @@ ROM_START( spacelnc )
ROM_LOAD( "sl.i1", 0x1800, 0x0400, CRC(d30007a3) SHA1(9e5905df8f7822385daef159a07f0e8257cb862a) )
ROM_LOAD( "sl.i2", 0x1c00, 0x0400, CRC(640ffd2f) SHA1(65c21396c39dc99ec263f66f400a8e4c7712b20a) )
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "sl.snd", 0x0000, 0x0400, CRC(8e1ff929) SHA1(5c7da97b05fb8fff242158978199f5d35b234426) )
ROM_REGION( 0x0020, "proms", 0 )
@ -817,7 +1379,7 @@ ROM_START( sheriff )
ROM_LOAD( "sh.i2", 0x1c00, 0x0400, CRC(5c5f3f86) SHA1(25c64ccb7d0e136f67d6e1da7927ae6d89e0ceb9) )
ROM_LOAD( "sh.j1", 0x2000, 0x0400, CRC(0aa8b79a) SHA1(aed139e8c8ba912823c57fe4cc7231b2d638f479) )
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "sh.snd", 0x0000, 0x0400, CRC(75731745) SHA1(538a63c9c60f1886fca4caf3eb1e0bada2d3f162) )
ROM_REGION( 0x0400, "proms", 0 )
@ -837,7 +1399,7 @@ ROM_START( bandido )
ROM_LOAD( "sh.j1", 0x2000, 0x0400, CRC(0aa8b79a) SHA1(aed139e8c8ba912823c57fe4cc7231b2d638f479) )
ROM_LOAD( "sh-a.j2", 0x2400, 0x0400, CRC(a10b848a) SHA1(c045f1f6a11cbf49a1bae06c701b659d587292a3) )
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "sh.snd", 0x0000, 0x0400, CRC(75731745) SHA1(538a63c9c60f1886fca4caf3eb1e0bada2d3f162) )
ROM_REGION( 0x0400, "proms", 0 )
@ -852,7 +1414,7 @@ ROM_START( westgun2 )
ROM_LOAD( "rf04.ic33", 0x1800, 0x0800, CRC(60b71f0d) SHA1(10650426972afb0ccb964548a52879ed3f0b316a) )
ROM_LOAD( "rf05.ic32", 0x2000, 0x0800, CRC(81e650fb) SHA1(e600567125294d1411fcad3a015edb98cee36ff8) )
ROM_REGION( 0x0800, "audiocpu", 0 )
ROM_REGION( 0x0800, "soundboard:cpu", 0 )
ROM_LOAD( "rf06.ic35", 0x0000, 0x0800, CRC(4eafe957) SHA1(78e03402219c0ad814f63ae507eadc636d95f755) )
ROM_REGION( 0x0400, "proms", 0 )
@ -872,7 +1434,7 @@ ROM_START( helifire )
ROM_LOAD( "tub_j1_b", 0x2000, 0x0400, CRC(98ef24db) SHA1(70ad8dd6e1e8f4bf4ce431737ca1856eecc03d53) )
ROM_LOAD( "tub_j2_b", 0x2400, 0x0400, CRC(5e2b5877) SHA1(f7c747e8a1d9fe2dda71ee6304636cf3cdf727a7) )
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "tub-e_ic5-a", 0x0000, 0x0400, CRC(9d77a31f) SHA1(36db9b5087b6661de88042854874bc247c92d985) )
ROM_END
@ -889,10 +1451,12 @@ ROM_START( helifirea )
ROM_LOAD( "hf.j1", 0x2000, 0x0400, CRC(98ef24db) SHA1(70ad8dd6e1e8f4bf4ce431737ca1856eecc03d53) )
ROM_LOAD( "hf.j2", 0x2400, 0x0400, CRC(5e2b5877) SHA1(f7c747e8a1d9fe2dda71ee6304636cf3cdf727a7) )
ROM_REGION( 0x0400, "audiocpu", 0 )
ROM_REGION( 0x0400, "soundboard:cpu", 0 )
ROM_LOAD( "hf.snd", 0x0000, 0x0400, CRC(9d77a31f) SHA1(36db9b5087b6661de88042854874bc247c92d985) )
ROM_END
} // anonymous namespace
// YEAR, NAME, PARENT, MACHINE, INPUT, CLASS, INIT, MONITOR, COMPANY, FULLNAME, FLAGS
GAME( 1979, spacefev, 0, spacefev, spacefev, spacefev_state, empty_init, ROT270, "Nintendo", "Space Fever (new version)", MACHINE_SUPPORTS_SAVE )

View File

@ -1,209 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Pierpaolo Prazzoli
#ifndef MAME_NINTENDO_N8080_H
#define MAME_NINTENDO_N8080_H
#pragma once
#include "cpu/i8085/i8085.h"
#include "cpu/mcs48/mcs48.h"
#include "machine/timer.h"
#include "sound/dac.h"
#include "sound/sn76477.h"
#include "emupal.h"
#include "screen.h"
class n8080_state : public driver_device
{
public:
n8080_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_videoram(*this, "videoram"),
m_prom(*this, "proms"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_n8080_dac(*this, "n8080_dac"),
m_sn(*this, "snsnd"),
m_screen(*this, "screen"),
m_palette(*this, "palette")
{ }
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void sound_pins_changed();
virtual void update_SN76477_status();
virtual void delayed_sound_1(int data);
virtual void delayed_sound_2(int data);
/* memory pointers */
required_shared_ptr<uint8_t> m_videoram;
optional_memory_region m_prom;
/* video-related */
int m_sheriff_color_mode;
int m_sheriff_color_data;
/* sound-related */
emu_timer* m_sound_timer[3];
uint16_t m_prev_sound_pins;
uint16_t m_curr_sound_pins;
int m_mono_flop[3];
uint8_t m_prev_snd_data;
/* other */
unsigned m_shift_data;
unsigned m_shift_bits;
int m_inte;
/* devices */
required_device<i8080a_cpu_device> m_maincpu;
required_device<i8035_device> m_audiocpu;
optional_device<dac_bit_interface> m_n8080_dac;
optional_device<sn76477_device> m_sn;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
void n8080_shift_bits_w(uint8_t data);
void n8080_shift_data_w(uint8_t data);
uint8_t n8080_shift_r();
void n8080_video_control_w(uint8_t data);
void n8080_sound_1_w(uint8_t data);
void n8080_sound_2_w(uint8_t data);
uint8_t n8080_8035_p1_r();
int n8080_8035_t0_r();
int n8080_8035_t1_r();
void n8080_dac_w(uint8_t data);
void n8080_inte_callback(int state);
void n8080_status_callback(uint8_t data);
void n8080_palette(palette_device &palette) const;
TIMER_DEVICE_CALLBACK_MEMBER(rst1_tick);
TIMER_DEVICE_CALLBACK_MEMBER(rst2_tick);
void start_mono_flop( int n, const attotime &expire );
void stop_mono_flop( int n );
TIMER_CALLBACK_MEMBER( stop_mono_flop_callback );
TIMER_CALLBACK_MEMBER( delayed_sound_1_callback );
TIMER_CALLBACK_MEMBER( delayed_sound_2_callback );
void main_cpu_map(address_map &map);
void main_io_map(address_map &map);
void n8080_sound_cpu_map(address_map &map);
};
class spacefev_state : public n8080_state
{
public:
spacefev_state(const machine_config &mconfig, device_type type, const char *tag) :
n8080_state(mconfig, type, tag),
m_video_conf(*this, "VIDEO")
{ }
void spacefev(machine_config &config);
protected:
virtual void machine_reset() override;
virtual void sound_start() override;
virtual void sound_reset() override;
virtual void video_start() override;
virtual void sound_pins_changed() override;
virtual void update_SN76477_status() override;
virtual void delayed_sound_1(int data) override;
virtual void delayed_sound_2(int data) override;
private:
required_ioport m_video_conf;
void spacefev_sound(machine_config &config);
TIMER_DEVICE_CALLBACK_MEMBER(vco_voltage_timer);
TIMER_CALLBACK_MEMBER(stop_red_cannon);
void start_red_cannon();
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
emu_timer* m_cannon_timer;
int m_red_screen;
int m_red_cannon;
};
class sheriff_state : public n8080_state
{
public:
sheriff_state(const machine_config &mconfig, device_type type, const char *tag) :
n8080_state(mconfig, type, tag)
{ }
void sheriff(machine_config &config);
void westgun2(machine_config &config);
protected:
virtual void machine_reset() override;
virtual void sound_start() override;
virtual void sound_reset() override;
virtual void video_start() override;
virtual void sound_pins_changed() override;
virtual void update_SN76477_status() override;
private:
void sheriff_sound(machine_config &config);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
};
class helifire_state : public n8080_state
{
public:
helifire_state(const machine_config &mconfig, device_type type, const char *tag) :
n8080_state(mconfig, type, tag),
m_dac(*this, "helifire_dac"),
m_colorram(*this, "colorram"),
m_pot(*this, "POT%u", 0)
{ }
void helifire(machine_config &config);
protected:
virtual void machine_reset() override;
virtual void sound_start() override;
virtual void sound_reset() override;
virtual void video_start() override;
virtual void sound_pins_changed() override;
virtual void delayed_sound_2(int data) override;
private:
void helifire_sound(machine_config &config);
TIMER_DEVICE_CALLBACK_MEMBER(dac_volume_timer);
int helifire_8035_t0_r();
int helifire_8035_t1_r();
uint8_t helifire_8035_external_ram_r();
uint8_t helifire_8035_p2_r();
void sound_ctrl_w(uint8_t data);
void sound_io_map(address_map &map);
void helifire_palette(palette_device &palette) const;
void next_line();
void screen_vblank(int state);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_cpu_map(address_map &map);
required_device<dac_8bit_r2r_device> m_dac;
required_shared_ptr<uint8_t> m_colorram;
required_ioport_array<2> m_pot;
int m_dac_phase = 0;
double m_dac_volume = 0;
double m_dac_timing = 0;
int m_flash = 0;
uint8_t m_LSFR[63];
unsigned m_mv = 0;
unsigned m_sc = 0; // IC56
};
#endif // MAME_NINTENDO_N8080_H

View File

@ -7,539 +7,513 @@
***************************************************************************/
#include "emu.h"
#include "n8080.h"
#include "n8080_a.h"
#include "machine/timer.h"
#include "sound/dac.h"
#include "sound/sn76477.h"
#include "speaker.h"
constexpr double ATTACK_RATE = 10e-6 * 500;
constexpr double DECAY_RATE = 10e-6 * 16000;
#include <cmath>
void spacefev_state::update_SN76477_status()
namespace {
template <unsigned Monostables>
class n8080_csg_sound_device_base : public n8080_sound_device_base
{
protected:
n8080_csg_sound_device_base(
machine_config const &mconfig,
device_type type,
char const *tag,
device_t *parent,
u32 clock) :
n8080_sound_device_base(mconfig, type, tag, parent, clock),
m_dac(*this, "dac"),
m_sn(*this, "snsnd")
{
}
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
bool mono_flop(unsigned n) const { return m_mono_flop[n]; }
attotime mono_elapsed(unsigned n) { return m_mono_timer[n]->elapsed(); }
void start_mono_flop(unsigned n, attotime const &expiry);
void stop_mono_flop(unsigned n);
required_device<dac_bit_interface> m_dac;
required_device<sn76477_device> m_sn;
private:
u8 p1_r()
{
return bitswap<8>(current_pins(), 1, 2, 3, 5, 8, 9, 10, 11);
}
int t0_r()
{
return BIT(current_pins(), 7);
}
int t1_r()
{
return BIT(current_pins(), 12);
}
void dac_w(u8 data)
{
m_dac->write(BIT(data, 7));
}
TIMER_CALLBACK_MEMBER(stop_mono_flop_callback)
{
stop_mono_flop(param);
}
virtual void update_sn_status() = 0;
emu_timer *m_mono_timer[Monostables];
bool m_mono_flop[Monostables];
};
template <unsigned Monostables>
void n8080_csg_sound_device_base<Monostables>::device_add_mconfig(machine_config &config)
{
n8080_sound_device_base::device_add_mconfig(config);
m_cpu->t0_in_cb().set(FUNC(n8080_csg_sound_device_base::t0_r));
m_cpu->t1_in_cb().set(FUNC(n8080_csg_sound_device_base::t1_r));
m_cpu->p1_in_cb().set(FUNC(n8080_csg_sound_device_base::p1_r));
m_cpu->p2_out_cb().set(FUNC(n8080_csg_sound_device_base::dac_w));
SPEAKER(config, "speaker").front_center();
DAC_1BIT(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.15);
SN76477(config, m_sn);
m_sn->set_attack_params(CAP_U(1.0), RES_K(20));
m_sn->set_amp_res(RES_K(150));
m_sn->set_feedback_res(RES_K(47));
m_sn->set_vco_params(0, CAP_N(1), RES_M(1.5));
m_sn->set_pitch_voltage(0);
m_sn->set_vco_mode(0);
m_sn->set_mixer_params(0, 0, 0);
m_sn->set_envelope_params(1, 0);
m_sn->set_enable(1);
m_sn->add_route(ALL_OUTPUTS, "speaker", 0.35);
}
template <unsigned Monostables>
void n8080_csg_sound_device_base<Monostables>::device_start()
{
n8080_sound_device_base::device_start();
for (unsigned i = 0; Monostables > i; ++i)
m_mono_timer[i] = timer_alloc(FUNC(n8080_csg_sound_device_base::stop_mono_flop_callback), this);
save_item(NAME(m_mono_flop));
}
template <unsigned Monostables>
void n8080_csg_sound_device_base<Monostables>::device_reset()
{
n8080_sound_device_base::device_reset();
for (unsigned i = 0; Monostables > i; ++i)
m_mono_flop[i] = false;
}
template <unsigned Monostables>
void n8080_csg_sound_device_base<Monostables>::start_mono_flop(unsigned n, attotime const &expiry)
{
m_mono_flop[n] = true;
update_sn_status();
m_mono_timer[n]->adjust(expiry, n);
}
template <unsigned Monostables>
void n8080_csg_sound_device_base<Monostables>::stop_mono_flop(unsigned n)
{
m_mono_flop[n] = false;
update_sn_status();
m_mono_timer[n]->adjust(attotime::never, n);
}
class spacefev_sound_device : public n8080_csg_sound_device_base<3>
{
public:
spacefev_sound_device(
machine_config const &mconfig,
char const *tag,
device_t *parent,
u32 clock) :
n8080_csg_sound_device_base<3>(mconfig, SPACEFEV_SOUND, tag, parent, clock)
{
}
protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
private:
virtual void update_sn_status() override;
virtual void pins_changed(u16 curr, u16 prev) override;
TIMER_DEVICE_CALLBACK_MEMBER(vco_voltage_timer);
};
void spacefev_sound_device::device_add_mconfig(machine_config &config)
{
n8080_csg_sound_device_base<3>::device_add_mconfig(config);
m_sn->set_noise_params(RES_K(36), RES_K(150), CAP_N(1));
m_sn->set_decay_res(RES_M(1));
m_sn->set_slf_params(CAP_N(47), RES_M(1));
m_sn->set_oneshot_params(CAP_N(47), RES_K(820));
TIMER(config, "vco_timer").configure_periodic(FUNC(spacefev_sound_device::vco_voltage_timer), attotime::from_hz(1000));
}
void spacefev_sound_device::update_sn_status()
{
double dblR0 = RES_M(1.0);
double dblR1 = RES_M(1.5);
if (!mono_flop(0))
dblR0 = 1.0 / (1.0 / RES_K(150) + 1.0 / dblR0); // ?
if (!m_mono_flop[0])
{
dblR0 = 1 / (1 / RES_K(150) + 1 / dblR0); /* ? */
}
if (!m_mono_flop[1])
{
dblR1 = 1 / (1 / RES_K(620) + 1 / dblR1); /* ? */
}
double dblR1 = RES_M(1.5);
if (!mono_flop(1))
dblR1 = 1.0 / (1.0 / RES_K(620) + 1.0 / dblR1); // ?
m_sn->decay_res_w(dblR0);
m_sn->vco_res_w(dblR1);
m_sn->enable_w(
!m_mono_flop[0] &&
!m_mono_flop[1] &&
!m_mono_flop[2]);
m_sn->vco_w(m_mono_flop[1]);
m_sn->mixer_b_w(m_mono_flop[0]);
m_sn->enable_w((!mono_flop(0) && !mono_flop(1) && !mono_flop(2)) ? 1 : 0);
m_sn->vco_w(mono_flop(1) ? 1 : 0);
m_sn->mixer_b_w(mono_flop(0) ? 1 : 0);
}
void sheriff_state::update_SN76477_status()
void spacefev_sound_device::pins_changed(u16 curr, u16 prev)
{
if (m_mono_flop[1])
{
m_sn->vco_voltage_w(5);
}
else
{
m_sn->vco_voltage_w(0);
}
u16 const changes = ~curr & prev;
m_sn->enable_w(
!m_mono_flop[0] &&
!m_mono_flop[1]);
m_sn->vco_w(m_mono_flop[0]);
m_sn->mixer_b_w(!m_mono_flop[0]);
}
void n8080_state::update_SN76477_status()
{
}
void n8080_state::start_mono_flop( int n, const attotime &expire )
{
m_mono_flop[n] = 1;
update_SN76477_status();
m_sound_timer[n]->adjust(expire, n);
}
void n8080_state::stop_mono_flop( int n )
{
m_mono_flop[n] = 0;
update_SN76477_status();
m_sound_timer[n]->adjust(attotime::never, n);
}
TIMER_CALLBACK_MEMBER( n8080_state::stop_mono_flop_callback )
{
stop_mono_flop(param);
}
void spacefev_state::sound_pins_changed()
{
uint16_t changes = ~m_curr_sound_pins & m_prev_sound_pins;
if (changes & (1 << 0x3))
{
if (BIT(changes, 3))
stop_mono_flop(1);
}
if (changes & ((1 << 0x3) | (1 << 0x6)))
{
if (BIT(changes, 3) || BIT(changes, 6))
stop_mono_flop(2);
}
if (changes & (1 << 0x3))
{
if (BIT(changes, 3))
start_mono_flop(0, attotime::from_usec(550 * 36 * 100));
}
if (changes & (1 << 0x6))
{
if (BIT(changes, 6))
start_mono_flop(1, attotime::from_usec(550 * 22 * 33));
}
if (changes & (1 << 0x4))
{
if (BIT(changes, 4))
start_mono_flop(2, attotime::from_usec(550 * 22 * 33));
}
bool irq_active = (~m_curr_sound_pins & ((1 << 0x2) | (1 << 0x3) | (1 << 0x5))) != 0;
m_audiocpu->set_input_line(INPUT_LINE_IRQ0, irq_active ? ASSERT_LINE : CLEAR_LINE);
bool const irq_active = BIT(~curr, 2) || BIT(~curr, 3) || BIT(~curr, 5);
m_cpu->set_input_line(INPUT_LINE_IRQ0, irq_active ? ASSERT_LINE : CLEAR_LINE);
}
void sheriff_state::sound_pins_changed()
{
uint16_t changes = ~m_curr_sound_pins & m_prev_sound_pins;
if (changes & (1 << 0x6))
{
stop_mono_flop(1);
}
if (changes & (1 << 0x6))
{
start_mono_flop(0, attotime::from_usec(550 * 33 * 33));
}
if (changes & (1 << 0x4))
{
start_mono_flop(1, attotime::from_usec(550 * 33 * 33));
}
bool irq_active = (~m_curr_sound_pins & ((1 << 0x2) | (1 << 0x3) | (1 << 0x5))) != 0;
m_audiocpu->set_input_line(INPUT_LINE_IRQ0, irq_active ? ASSERT_LINE : CLEAR_LINE);
}
void helifire_state::sound_pins_changed()
{
//uint16_t changes = ~m_curr_sound_pins & m_prev_sound_pins;
/* ((m_curr_sound_pins >> 0xa) & 1) not emulated */
/* ((m_curr_sound_pins >> 0xb) & 1) not emulated */
/* ((m_curr_sound_pins >> 0xc) & 1) not emulated */
bool irq_active = (~m_curr_sound_pins & (1 << 6)) != 0;
m_audiocpu->set_input_line(INPUT_LINE_IRQ0, irq_active ? ASSERT_LINE : CLEAR_LINE);
}
void n8080_state::sound_pins_changed()
{
}
void n8080_state::delayed_sound_1(int data)
{
m_curr_sound_pins &= ~(
(1 << 0x7) |
(1 << 0x5) |
(1 << 0x6) |
(1 << 0x3) |
(1 << 0x4) |
(1 << 0x1));
if (~data & 0x01) m_curr_sound_pins |= 1 << 0x7;
if (~data & 0x02) m_curr_sound_pins |= 1 << 0x5; /* pulse */
if (~data & 0x04) m_curr_sound_pins |= 1 << 0x6; /* pulse */
if (~data & 0x08) m_curr_sound_pins |= 1 << 0x3; /* pulse (except in Helifire) */
if (~data & 0x10) m_curr_sound_pins |= 1 << 0x4; /* pulse (except in Helifire) */
if (~data & 0x20) m_curr_sound_pins |= 1 << 0x1;
sound_pins_changed();
m_prev_sound_pins = m_curr_sound_pins;
m_prev_snd_data = data;
}
void spacefev_state::delayed_sound_1(int data)
{
if (data & ~m_prev_snd_data & 0x10)
start_red_cannon();
m_red_screen = data & 0x08;
n8080_state::delayed_sound_1(data);
}
TIMER_CALLBACK_MEMBER( n8080_state::delayed_sound_1_callback )
{
delayed_sound_1(param);
}
void n8080_state::delayed_sound_2(int data)
{
m_curr_sound_pins &= ~(
(1 << 0x8) |
(1 << 0x9) |
(1 << 0xa) |
(1 << 0xb) |
(1 << 0x2) |
(1 << 0xc));
if (~data & 0x01) m_curr_sound_pins |= 1 << 0x8;
if (~data & 0x02) m_curr_sound_pins |= 1 << 0x9;
if (~data & 0x04) m_curr_sound_pins |= 1 << 0xa;
if (~data & 0x08) m_curr_sound_pins |= 1 << 0xb;
if (~data & 0x10) m_curr_sound_pins |= 1 << 0x2; /* pulse */
if (~data & 0x20) m_curr_sound_pins |= 1 << 0xc;
sound_pins_changed();
m_prev_sound_pins = m_curr_sound_pins;
}
void spacefev_state::delayed_sound_2(int data)
{
flip_screen_set(data & 0x20);
n8080_state::delayed_sound_2(data);
}
void helifire_state::delayed_sound_2(int data)
{
m_flash = data & 0x20;
n8080_state::delayed_sound_2(data);
}
TIMER_CALLBACK_MEMBER( n8080_state::delayed_sound_2_callback )
{
delayed_sound_2(param);
}
void n8080_state::n8080_sound_1_w(uint8_t data)
{
machine().scheduler().synchronize(timer_expired_delegate(FUNC(n8080_state::delayed_sound_1_callback), this), data); /* force CPUs to sync */
}
void n8080_state::n8080_sound_2_w(uint8_t data)
{
machine().scheduler().synchronize(timer_expired_delegate(FUNC(n8080_state::delayed_sound_2_callback), this), data); /* force CPUs to sync */
}
uint8_t n8080_state::n8080_8035_p1_r()
{
uint8_t val = 0;
if ((m_curr_sound_pins >> 0xb) & 1) val |= 0x01;
if ((m_curr_sound_pins >> 0xa) & 1) val |= 0x02;
if ((m_curr_sound_pins >> 0x9) & 1) val |= 0x04;
if ((m_curr_sound_pins >> 0x8) & 1) val |= 0x08;
if ((m_curr_sound_pins >> 0x5) & 1) val |= 0x10;
if ((m_curr_sound_pins >> 0x3) & 1) val |= 0x20;
if ((m_curr_sound_pins >> 0x2) & 1) val |= 0x40;
if ((m_curr_sound_pins >> 0x1) & 1) val |= 0x80;
return val;
}
int n8080_state::n8080_8035_t0_r()
{
return (m_curr_sound_pins >> 0x7) & 1;
}
int n8080_state::n8080_8035_t1_r()
{
return (m_curr_sound_pins >> 0xc) & 1;
}
int helifire_state::helifire_8035_t0_r()
{
return (m_curr_sound_pins >> 0x3) & 1;
}
int helifire_state::helifire_8035_t1_r()
{
return (m_curr_sound_pins >> 0x4) & 1;
}
uint8_t helifire_state::helifire_8035_external_ram_r()
{
uint8_t val = 0;
if ((m_curr_sound_pins >> 0x7) & 1) val |= 0x01;
if ((m_curr_sound_pins >> 0x8) & 1) val |= 0x02;
if ((m_curr_sound_pins >> 0x9) & 1) val |= 0x04;
if ((m_curr_sound_pins >> 0x1) & 1) val |= 0x08;
return val;
}
uint8_t helifire_state::helifire_8035_p2_r()
{
return ((m_curr_sound_pins >> 0xc) & 1) ? 0x10 : 0x00; /* not used */
}
void n8080_state::n8080_dac_w(uint8_t data)
{
m_n8080_dac->write(BIT(data, 7));
}
void helifire_state::sound_ctrl_w(uint8_t data)
{
m_dac_phase = data & 0x80;
/* data & 0x40 not emulated */
/* data & 0x20 not emulated */
if (m_dac_phase)
{
m_dac_timing = ATTACK_RATE * log(1 - m_dac_volume);
}
else
{
m_dac_timing = DECAY_RATE * log(m_dac_volume);
}
m_dac_timing += machine().time().as_double();
}
TIMER_DEVICE_CALLBACK_MEMBER(spacefev_state::vco_voltage_timer)
TIMER_DEVICE_CALLBACK_MEMBER(spacefev_sound_device::vco_voltage_timer)
{
double voltage = 0;
if (m_mono_flop[2])
{
voltage = 5 * (1 - exp(- m_sound_timer[2]->elapsed().as_double() / 0.22));
}
if (mono_flop(2))
voltage = 5.0 * (1.0 - exp(-mono_elapsed(2).as_double() / 0.22));
m_sn->vco_voltage_w(voltage);
}
TIMER_DEVICE_CALLBACK_MEMBER(helifire_state::dac_volume_timer)
{
double t = m_dac_timing - machine().time().as_double();
if (m_dac_phase)
class sheriff_sound_device : public n8080_csg_sound_device_base<2>
{
public:
sheriff_sound_device(
machine_config const &mconfig,
char const *tag,
device_t *parent,
u32 clock) :
n8080_csg_sound_device_base<2>(mconfig, SHERIFF_SOUND, tag, parent, clock)
{
m_dac_volume = 1 - exp(t / ATTACK_RATE);
}
else
{
m_dac_volume = exp(t / DECAY_RATE);
}
m_dac->set_output_gain(ALL_OUTPUTS, m_dac_volume);
protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
private:
virtual void update_sn_status() override;
virtual void pins_changed(u16 curr, u16 prev) override;
};
void sheriff_sound_device::device_add_mconfig(machine_config &config)
{
n8080_csg_sound_device_base<2>::device_add_mconfig(config);
m_sn->set_noise_params(RES_K(36), RES_K(100), CAP_N(1));
m_sn->set_decay_res(RES_K(620));
m_sn->set_slf_params(CAP_N(47), RES_M(1.5));
m_sn->set_oneshot_params(CAP_N(47), RES_K(560));
}
void spacefev_state::sound_start()
void sheriff_sound_device::update_sn_status()
{
m_sound_timer[0] = timer_alloc(FUNC(spacefev_state::stop_mono_flop_callback), this);
m_sound_timer[1] = timer_alloc(FUNC(spacefev_state::stop_mono_flop_callback), this);
m_sound_timer[2] = timer_alloc(FUNC(spacefev_state::stop_mono_flop_callback), this);
save_item(NAME(m_prev_snd_data));
save_item(NAME(m_prev_sound_pins));
save_item(NAME(m_curr_sound_pins));
save_item(NAME(m_mono_flop));
m_sn->vco_voltage_w(mono_flop(1) ? 5 : 0);
m_sn->enable_w((!mono_flop(0) && !mono_flop(1)) ? 1 : 0);
m_sn->vco_w(mono_flop(0) ? 1 : 0);
m_sn->mixer_b_w(mono_flop(0) ? 0 : 1);
}
void spacefev_state::sound_reset()
void sheriff_sound_device::pins_changed(u16 curr, u16 prev)
{
m_mono_flop[0] = 0;
m_mono_flop[1] = 0;
m_mono_flop[2] = 0;
m_prev_snd_data = 0;
m_prev_sound_pins = 0;
m_curr_sound_pins = 0;
u16 const changes = ~curr & prev;
delayed_sound_1(0);
delayed_sound_2(0);
if (BIT(changes, 6))
stop_mono_flop(1);
if (BIT(changes, 6))
start_mono_flop(0, attotime::from_usec(550 * 33 * 33));
if (BIT(changes, 4))
start_mono_flop(1, attotime::from_usec(550 * 33 * 33));
bool const irq_active = BIT(~curr, 2) || BIT(~curr, 3) || BIT(~curr, 5);
m_cpu->set_input_line(INPUT_LINE_IRQ0, irq_active ? ASSERT_LINE : CLEAR_LINE);
}
void sheriff_state::sound_start()
{
m_sound_timer[0] = timer_alloc(FUNC(sheriff_state::stop_mono_flop_callback), this);
m_sound_timer[1] = timer_alloc(FUNC(sheriff_state::stop_mono_flop_callback), this);
save_item(NAME(m_prev_snd_data));
save_item(NAME(m_prev_sound_pins));
save_item(NAME(m_curr_sound_pins));
save_item(NAME(m_mono_flop));
class helifire_sound_device : public n8080_sound_device_base
{
public:
helifire_sound_device(machine_config const &mconfig,
char const *tag,
device_t *parent,
u32 clock) :
n8080_sound_device_base(mconfig, HELIFIRE_SOUND, tag, parent, clock),
m_dac(*this, "dac"),
m_dac_volume(1.0),
m_dac_timing(0.0),
m_dac_phase(false)
{
}
protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
private:
static inline constexpr double ATTACK_RATE = 10e-6 * 500;
static inline constexpr double DECAY_RATE = 10e-6 * 16'000;
u8 ram_r()
{
return bitswap<4>(current_pins(), 1, 9, 8, 7);
}
u8 p2_r()
{
return BIT(current_pins(), 12) ? 0x10 : 0x00; // not used
}
int t0_r()
{
return BIT(current_pins(), 3);
}
int t1_r()
{
return BIT(current_pins(), 4);
}
void ctrl_w(u8 data);
virtual void pins_changed(u16 curr, u16 prev) override;
TIMER_DEVICE_CALLBACK_MEMBER(volume_timer);
void io_map(address_map &map) ATTR_COLD;
required_device<dac_8bit_r2r_device> m_dac;
double m_dac_volume;
double m_dac_timing;
bool m_dac_phase;
};
void helifire_sound_device::device_add_mconfig(machine_config &config)
{
n8080_sound_device_base::device_add_mconfig(config);
m_cpu->set_addrmap(AS_IO, &helifire_sound_device::io_map);
m_cpu->t0_in_cb().set(FUNC(helifire_sound_device::t0_r));
m_cpu->t1_in_cb().set(FUNC(helifire_sound_device::t1_r));
m_cpu->p2_in_cb().set(FUNC(helifire_sound_device::p2_r));
m_cpu->p1_out_cb().set(m_dac, FUNC(dac_byte_interface::data_w));
m_cpu->p2_out_cb().set(FUNC(helifire_sound_device::ctrl_w));
TIMER(config, "volume_timer").configure_periodic(FUNC(helifire_sound_device::volume_timer), attotime::from_hz(1000));
SPEAKER(config, "speaker").front_center();
DAC_8BIT_R2R(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.15); // unknown DAC
}
void sheriff_state::sound_reset()
void helifire_sound_device::device_start()
{
m_mono_flop[0] = 0;
m_mono_flop[1] = 0;
m_prev_snd_data = 0;
m_prev_sound_pins = 0;
m_curr_sound_pins = 0;
n8080_sound_device_base::device_start();
delayed_sound_1(0);
delayed_sound_2(0);
}
void helifire_state::sound_start()
{
save_item(NAME(m_prev_snd_data));
save_item(NAME(m_prev_sound_pins));
save_item(NAME(m_curr_sound_pins));
save_item(NAME(m_dac_volume));
save_item(NAME(m_dac_timing));
save_item(NAME(m_dac_phase));
}
void helifire_state::sound_reset()
void helifire_sound_device::device_reset()
{
m_dac_volume = 1;
m_dac_timing = 0;
m_dac_phase = 0;
m_prev_snd_data = 0;
m_prev_sound_pins = 0;
m_curr_sound_pins = 0;
n8080_sound_device_base::device_reset();
delayed_sound_1(0);
delayed_sound_2(0);
m_dac_volume = 1.0;
m_dac_timing = 0.0;
m_dac_phase = false;
}
void n8080_state::n8080_sound_cpu_map(address_map &map)
void helifire_sound_device::ctrl_w(u8 data)
{
m_dac_phase = BIT(data, 7);
// data bit 6 not emulated
// data bit 5 not emulated
m_dac_timing = machine().time().as_double();
if (m_dac_phase)
m_dac_timing += ATTACK_RATE * log(1 - m_dac_volume);
else
m_dac_timing += DECAY_RATE * log(m_dac_volume);
}
void helifire_sound_device::pins_changed(u16 curr, u16 prev)
{
// bit 10 not emulated
// bit 11 not emulated
// bit 12 not emulated
bool const irq_active = BIT(~curr, 6);
m_cpu->set_input_line(INPUT_LINE_IRQ0, irq_active ? ASSERT_LINE : CLEAR_LINE);
}
TIMER_DEVICE_CALLBACK_MEMBER(helifire_sound_device::volume_timer)
{
double const t = m_dac_timing - machine().time().as_double();
if (m_dac_phase)
m_dac_volume = 1.0 - exp(t / ATTACK_RATE);
else
m_dac_volume = exp(t / DECAY_RATE);
m_dac->set_output_gain(ALL_OUTPUTS, m_dac_volume);
}
void helifire_sound_device::io_map(address_map &map)
{
map(0x00, 0x00).mirror(0x7f).r(FUNC(helifire_sound_device::ram_r));
}
} // anonymous namespace
void n8080_sound_device_base::sound1_w(u8 data)
{
u16 const prev = m_curr_pins;
m_curr_pins &= ~((1 << 7) | (1 << 5) | (1 << 6) | (1 << 3) | (1 << 4) | (1 << 1));
if (BIT(~data, 0)) m_curr_pins |= 1 << 7;
if (BIT(~data, 1)) m_curr_pins |= 1 << 5; // pulse
if (BIT(~data, 2)) m_curr_pins |= 1 << 6; // pulse
if (BIT(~data, 3)) m_curr_pins |= 1 << 3; // pulse (except in HeliFire)
if (BIT(~data, 4)) m_curr_pins |= 1 << 4; // pulse (except in HeliFire)
if (BIT(~data, 5)) m_curr_pins |= 1 << 1;
pins_changed(m_curr_pins, prev);
}
void n8080_sound_device_base::sound2_w(u8 data)
{
u16 const prev = m_curr_pins;
m_curr_pins &= ~((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 2) | (1 << 12));
if (BIT(~data, 0)) m_curr_pins |= 1 << 8;
if (BIT(~data, 1)) m_curr_pins |= 1 << 9;
if (BIT(~data, 2)) m_curr_pins |= 1 << 10;
if (BIT(~data, 3)) m_curr_pins |= 1 << 11;
if (BIT(~data, 4)) m_curr_pins |= 1 << 2; // pulse
if (BIT(~data, 5)) m_curr_pins |= 1 << 12;
pins_changed(m_curr_pins, prev);
}
n8080_sound_device_base::n8080_sound_device_base(
machine_config const &mconfig,
device_type type,
char const *tag,
device_t *parent,
u32 clock) :
device_t(mconfig, type, tag, parent, clock),
m_cpu(*this, "cpu"),
m_curr_pins(0)
{
}
void n8080_sound_device_base::device_add_mconfig(machine_config &config)
{
I8035(config, m_cpu, 6_MHz_XTAL);
m_cpu->set_addrmap(AS_PROGRAM, &n8080_sound_device_base::prg_map);
}
void n8080_sound_device_base::device_start()
{
save_item(NAME(m_curr_pins));
}
void n8080_sound_device_base::prg_map(address_map &map)
{
map.global_mask(0x3ff);
map(0x0000, 0x03ff).rom();
}
void helifire_state::sound_io_map(address_map &map)
{
map(0x00, 0x00).mirror(0x7f).r(FUNC(helifire_state::helifire_8035_external_ram_r));
}
void spacefev_state::spacefev_sound(machine_config &config)
{
/* basic machine hardware */
I8035(config, m_audiocpu, 6_MHz_XTAL);
m_audiocpu->set_addrmap(AS_PROGRAM, &spacefev_state::n8080_sound_cpu_map);
m_audiocpu->t0_in_cb().set(FUNC(spacefev_state::n8080_8035_t0_r));
m_audiocpu->t1_in_cb().set(FUNC(spacefev_state::n8080_8035_t1_r));
m_audiocpu->p1_in_cb().set(FUNC(spacefev_state::n8080_8035_p1_r));
m_audiocpu->p2_out_cb().set(FUNC(spacefev_state::n8080_dac_w));
TIMER(config, "vco_timer").configure_periodic(FUNC(spacefev_state::vco_voltage_timer), attotime::from_hz(1000));
template class device_finder<n8080_sound_device_base, false>;
template class device_finder<n8080_sound_device_base, true>;
/* sound hardware */
SPEAKER(config, "speaker").front_center();
DAC_1BIT(config, m_n8080_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.15);
SN76477(config, m_sn);
m_sn->set_noise_params(RES_K(36), RES_K(150), CAP_N(1));
m_sn->set_decay_res(RES_M(1));
m_sn->set_attack_params(CAP_U(1.0), RES_K(20));
m_sn->set_amp_res(RES_K(150));
m_sn->set_feedback_res(RES_K(47));
m_sn->set_vco_params(0, CAP_N(1), RES_M(1.5));
m_sn->set_pitch_voltage(0);
m_sn->set_slf_params(CAP_N(47), RES_M(1));
m_sn->set_oneshot_params(CAP_N(47), RES_K(820));
m_sn->set_vco_mode(0);
m_sn->set_mixer_params(0, 0, 0);
m_sn->set_envelope_params(1, 0);
m_sn->set_enable(1);
m_sn->add_route(ALL_OUTPUTS, "speaker", 0.35);
}
void sheriff_state::sheriff_sound(machine_config &config)
{
/* basic machine hardware */
I8035(config, m_audiocpu, 6_MHz_XTAL);
m_audiocpu->set_addrmap(AS_PROGRAM, &sheriff_state::n8080_sound_cpu_map);
m_audiocpu->t0_in_cb().set(FUNC(sheriff_state::n8080_8035_t0_r));
m_audiocpu->t1_in_cb().set(FUNC(sheriff_state::n8080_8035_t1_r));
m_audiocpu->p1_in_cb().set(FUNC(sheriff_state::n8080_8035_p1_r));
m_audiocpu->p2_out_cb().set(FUNC(sheriff_state::n8080_dac_w));
/* sound hardware */
SPEAKER(config, "speaker").front_center();
DAC_1BIT(config, m_n8080_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.15);
SN76477(config, m_sn);
m_sn->set_noise_params(RES_K(36), RES_K(100), CAP_N(1));
m_sn->set_decay_res(RES_K(620));
m_sn->set_attack_params(CAP_U(1.0), RES_K(20));
m_sn->set_amp_res(RES_K(150));
m_sn->set_feedback_res(RES_K(47));
m_sn->set_vco_params(0, CAP_N(1), RES_M(1.5));
m_sn->set_pitch_voltage(0);
m_sn->set_slf_params(CAP_N(47), RES_M(1.5));
m_sn->set_oneshot_params(CAP_N(47), RES_K(560));
m_sn->set_vco_mode(0);
m_sn->set_mixer_params(0, 0, 0);
m_sn->set_envelope_params(1, 0);
m_sn->set_enable(1);
m_sn->add_route(ALL_OUTPUTS, "speaker", 0.35);
}
void helifire_state::helifire_sound(machine_config &config)
{
/* basic machine hardware */
I8035(config, m_audiocpu, 6_MHz_XTAL);
m_audiocpu->set_addrmap(AS_PROGRAM, &helifire_state::n8080_sound_cpu_map);
m_audiocpu->set_addrmap(AS_IO, &helifire_state::sound_io_map);
m_audiocpu->t0_in_cb().set(FUNC(helifire_state::helifire_8035_t0_r));
m_audiocpu->t1_in_cb().set(FUNC(helifire_state::helifire_8035_t1_r));
m_audiocpu->p2_in_cb().set(FUNC(helifire_state::helifire_8035_p2_r));
m_audiocpu->p1_out_cb().set("helifire_dac", FUNC(dac_byte_interface::data_w));
m_audiocpu->p2_out_cb().set(FUNC(helifire_state::sound_ctrl_w));
TIMER(config, "helifire_dac_volume_timer").configure_periodic(FUNC(helifire_state::dac_volume_timer), attotime::from_hz(1000));
/* sound hardware */
SPEAKER(config, "speaker").front_center();
DAC_8BIT_R2R(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.15); // unknown DAC
}
DEFINE_DEVICE_TYPE_PRIVATE(SPACEFEV_SOUND, n8080_sound_device_base, spacefev_sound_device, "spacefev_sound", "Nintendo Space Fever Sound Board")
DEFINE_DEVICE_TYPE_PRIVATE(SHERIFF_SOUND, n8080_sound_device_base, sheriff_sound_device, "sheriff_sound", "Nintendo Sheriff Sound Board")
DEFINE_DEVICE_TYPE_PRIVATE(HELIFIRE_SOUND, n8080_sound_device_base, helifire_sound_device, "helifire_sound", "Nintendo HeliFire Sound Board")

View File

@ -0,0 +1,47 @@
// license:BSD-3-Clause
// copyright-holders:Pierpaolo Prazzoli
/***************************************************************************
Nintendo 8080 sound emulation
***************************************************************************/
#ifndef MAME_NINTENDO_N8080_A_H
#define MAME_NINTENDO_N8080_A_H
#pragma once
#include "cpu/mcs48/mcs48.h"
class n8080_sound_device_base : public device_t
{
public:
void sound1_w(u8 data);
void sound2_w(u8 data);
protected:
n8080_sound_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *parent, u32 clock);
required_device<i8035_device> m_cpu;
protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual void device_start() override ATTR_COLD;
u16 current_pins() const { return m_curr_pins; }
private:
virtual void pins_changed(u16 curr, u16 prev) = 0;
void prg_map(address_map &map) ATTR_COLD;
u16 m_curr_pins;
};
DECLARE_DEVICE_TYPE(SPACEFEV_SOUND, n8080_sound_device_base)
DECLARE_DEVICE_TYPE(SHERIFF_SOUND, n8080_sound_device_base)
DECLARE_DEVICE_TYPE(HELIFIRE_SOUND, n8080_sound_device_base)
#endif // MAME_NINTENDO_N8080_A_H

View File

@ -1,359 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Pierpaolo Prazzoli
/***************************************************************************
Nintendo 8080 video emulation
***************************************************************************/
#include "emu.h"
#include "n8080.h"
void n8080_state::n8080_video_control_w(uint8_t data)
{
m_sheriff_color_mode = (data >> 3) & 3;
m_sheriff_color_data = (data >> 0) & 7;
flip_screen_set(data & 0x20);
}
void n8080_state::n8080_palette(palette_device &palette) const
{
for (int i = 0; i < 8; i++)
palette.set_pen_color(i, pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2));
}
void helifire_state::helifire_palette(palette_device &palette) const
{
n8080_palette(palette);
for (int i = 0; i < 0x100; i++)
{
int const level = 0xff * exp(-3 * i / 255.); // capacitor discharge
palette.set_pen_color(0x000 + 8 + i, rgb_t(0x00, 0x00, level)); // shades of blue
palette.set_pen_color(0x100 + 8 + i, rgb_t(0x00, 0xc0, level)); // shades of blue w/ green star
palette.set_pen_color(0x200 + 8 + i, rgb_t(level, 0x00, 0x00)); // shades of red
palette.set_pen_color(0x300 + 8 + i, rgb_t(level, 0xc0, 0x00)); // shades of red w/ green star
}
}
void spacefev_state::start_red_cannon()
{
m_red_cannon = 1;
m_cannon_timer->adjust(attotime::from_usec(550 * 68 * 10));
}
TIMER_CALLBACK_MEMBER(spacefev_state::stop_red_cannon)
{
m_red_cannon = 0;
m_cannon_timer->adjust(attotime::never);
}
void helifire_state::next_line()
{
m_mv++;
if (m_sc % 4 == 2)
{
m_mv %= 256;
}
else
{
if (flip_screen())
m_mv %= 255;
else
m_mv %= 257;
}
if (m_mv == 128)
{
m_sc++;
}
}
void spacefev_state::video_start()
{
m_cannon_timer = timer_alloc(FUNC(spacefev_state::stop_red_cannon), this);
flip_screen_set(0);
save_item(NAME(m_red_screen));
save_item(NAME(m_red_cannon));
}
void sheriff_state::video_start()
{
flip_screen_set(0);
save_item(NAME(m_sheriff_color_mode));
save_item(NAME(m_sheriff_color_data));
}
void helifire_state::video_start()
{
uint8_t data = 0;
int i;
save_item(NAME(m_mv));
save_item(NAME(m_sc));
save_item(NAME(m_flash));
save_item(NAME(m_LSFR));
for (i = 0; i < 63; i++)
{
int bit =
(data >> 6) ^
(data >> 7) ^ 1;
data = (data << 1) | (bit & 1);
m_LSFR[i] = data;
}
flip_screen_set(0);
}
uint32_t spacefev_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
const bool mono = bool(m_video_conf->read());
uint8_t mask = flip_screen() ? 0xff : 0x00;
uint8_t const *pRAM = m_videoram;
uint8_t const *const pPROM = m_prom->base();
for (int y = 0; y < 256; y++)
{
uint16_t *const pLine = &bitmap.pix(y ^ mask);
for (int x = 0; x < 256; x += 8)
{
uint8_t color = 0;
if (m_red_screen)
color = 1;
else
{
uint8_t val = pPROM[x >> 3];
if ((x >> 3) == 0x06)
{
color = m_red_cannon ? 1 : 7;
}
if ((x >> 3) == 0x1b)
{
static const uint8_t ufo_color[] =
{
1, // red
2, // green
7, // white
3, // yellow
5, // magenta
6, // cyan
};
int cycle = screen.frame_number() / 32;
color = ufo_color[cycle % 6];
}
for (int n = color + 1; n < 8; n++)
{
if (~val & (1 << n))
{
color = n;
}
}
}
if (mono)
color = 7; // force B&W here
for (int n = 0; n < 8; n++)
{
pLine[(x + n) ^ mask] = (pRAM[x >> 3] & (1 << n)) ? color : 0;
}
}
pRAM += 32;
}
return 0;
}
uint32_t sheriff_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
uint8_t mask = flip_screen() ? 0xff : 0x00;
uint8_t const *pRAM = m_videoram;
uint8_t const *const pPROM = m_prom->base();
for (int y = 0; y < 256; y++)
{
uint16_t *const pLine = &bitmap.pix(y ^ mask);
for (int x = 0; x < 256; x += 8)
{
uint8_t color = pPROM[32 * (y >> 3) + (x >> 3)];
if (m_sheriff_color_mode == 1 && !(color & 8))
color = m_sheriff_color_data ^ 7;
if (m_sheriff_color_mode == 2)
color = m_sheriff_color_data ^ 7;
if (m_sheriff_color_mode == 3)
color = 7;
for (int n = 0; n < 8; n++)
{
pLine[(x + n) ^ mask] = ((pRAM[x >> 3] >> n) & 1) ? (color & 7) : 0;
}
}
pRAM += 32;
}
return 0;
}
uint32_t helifire_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
const int SUN_BRIGHTNESS = m_pot[0]->read();
const int SEA_BRIGHTNESS = m_pot[1]->read();
static const int wave[8] = { 0, 1, 2, 2, 2, 1, 0, 0 };
unsigned saved_mv = m_mv;
unsigned saved_sc = m_sc;
for (int y = 0; y < 256; y++)
{
uint16_t *const pLine = &bitmap.pix(y);
int level = 120 + wave[m_mv & 7];
// draw sky
for (int x = level; x < 256; x++)
{
pLine[x] = 0x200 + 8 + SUN_BRIGHTNESS + x - level;
}
// draw stars
if (m_mv % 8 == 4) // upper half
{
int step = (320 * (m_mv - 0)) % sizeof m_LSFR;
int data =
((m_LSFR[step] & 1) << 6) |
((m_LSFR[step] & 2) << 4) |
((m_LSFR[step] & 4) << 2) |
((m_LSFR[step] & 8) << 0);
pLine[0x80 + data] |= 0x100;
}
if (m_mv % 8 == 5) // lower half
{
int step = (320 * (m_mv - 1)) % sizeof m_LSFR;
int data =
((m_LSFR[step] & 1) << 6) |
((m_LSFR[step] & 2) << 4) |
((m_LSFR[step] & 4) << 2) |
((m_LSFR[step] & 8) << 0);
pLine[0x00 + data] |= 0x100;
}
// draw sea
for (int x = 0; x < level; x++)
{
pLine[x] = 8 + SEA_BRIGHTNESS + x;
}
// draw foreground
for (int x = 0; x < 256; x += 8)
{
int offset = 32 * y + (x >> 3);
for (int n = 0; n < 8; n++)
{
if (flip_screen())
{
if ((m_videoram[offset ^ 0x1fff] << n) & 0x80)
{
pLine[x + n] = m_colorram[offset ^ 0x1fff] & 7;
}
}
else
{
if ((m_videoram[offset] >> n) & 1)
{
pLine[x + n] = m_colorram[offset] & 7;
}
}
}
}
// next line
next_line();
}
m_mv = saved_mv;
m_sc = saved_sc;
return 0;
}
void helifire_state::screen_vblank(int state)
{
// falling edge
if (!state)
{
int n = (m_screen->frame_number() >> 1) % sizeof m_LSFR;
int i;
for (i = 0; i < 8; i++)
{
int R = (i & 1);
int G = (i & 2);
int B = (i & 4);
if (m_flash)
{
if (m_LSFR[n] & 0x20)
{
G |= B;
}
if (m_screen->frame_number() & 0x04)
{
R |= G;
}
}
m_palette->set_pen_color(i,
R ? 255 : 0,
G ? 255 : 0,
B ? 255 : 0);
}
for (i = 0; i < 256; i++)
{
next_line();
}
}
}