Skip to content

Commit

Permalink
laserbat.cpp: Quantise area effect 2/shell effect for catnmous.
Browse files Browse the repository at this point in the history
  • Loading branch information
cuavas committed Apr 18, 2021
1 parent eebc080 commit 349f5cb
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 98 deletions.
6 changes: 3 additions & 3 deletions src/mame/audio/laserbat.cpp
Expand Up @@ -130,7 +130,7 @@ void laserbat_state_base::csound2_w(uint8_t data)
void laserbat_state::csound2_w(uint8_t data)
{
// there are a bunch of edge-triggered things, so grab changes
unsigned const diff = data ^ m_csound2;
uint8_t const diff = data ^ m_csound2;

// SN76477 and distortion control
if (data & diff & 0x01)
Expand Down Expand Up @@ -317,10 +317,10 @@ void catnmous_state::csound1_w(uint8_t data)
void catnmous_state::csound2_w(uint8_t data)
{
// the bottom bit is used for sprite banking, of all things
m_gfx2 = memregion("gfx2")->base() + ((data & 0x01) ? 0x0800 : 0x0000);
m_gfx2_base = uint16_t(BIT(data, 0)) << 11;

// the top bit is called RESET on the wiring diagram
m_audiopcb->reset_w((data & 0x80) ? 1 : 0);
m_audiopcb->reset_w(BIT(data, 7));

m_csound2 = data;
}
24 changes: 17 additions & 7 deletions src/mame/drivers/laserbat.cpp
Expand Up @@ -65,6 +65,11 @@
* The sprite ROM is twice the size as Laser Battle with the bank
selected using bit 9 of the 16-bit sound interface (there's a wire
making this connection visible on the component side of the PCB)
* At least some boards have IC13I pins 8, 9, 10 and 11 bent out of
the socket, tied together, and pulled high via a 4k7 resistor,
which quantises the shell/area effect 2 to four-pixel boundaries
(implemented as m_eff2_mask) - would be good to see whether this
mod is present on all boards
* If demo sounds are enabled (using DIP switches), background music
is played every sixth time through the attract loop
* Sound board emulation is based on tracing the program and guessing
Expand Down Expand Up @@ -412,9 +417,14 @@ INTERRUPT_GEN_MEMBER(laserbat_state_base::laserbat_interrupt)
m_maincpu->set_input_line(0, ASSERT_LINE);
}

void laserbat_state_base::init_laserbat()
void laserbat_state_base::machine_start()
{
// start rendering scanlines
m_screen->register_screen_bitmap(m_bitmap);
m_scanline_timer = timer_alloc(TIMER_SCANLINE);
m_scanline_timer->adjust(m_screen->time_until_pos(1, 0));

save_item(NAME(m_gfx2_base));

save_item(NAME(m_input_mux));
save_item(NAME(m_mpx_p_1_2));
Expand All @@ -436,10 +446,10 @@ void laserbat_state_base::init_laserbat()
save_item(NAME(m_neg1));
save_item(NAME(m_neg2));

save_item(NAME(m_csound1));
save_item(NAME(m_csound2));
save_item(NAME(m_rhsc));
save_item(NAME(m_whsc));
save_item(NAME(m_csound1));
save_item(NAME(m_csound2));
}

void laserbat_state::machine_start()
Expand Down Expand Up @@ -732,7 +742,7 @@ ROM_START( catnmousa )
ROM_END


GAME( 1981, laserbat, 0, laserbat, laserbat, laserbat_state, init_laserbat, ROT0, "Zaccaria", "Laser Battle", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1981, lazarian, laserbat, laserbat, lazarian, laserbat_state, init_laserbat, ROT0, "Zaccaria (Bally Midway license)", "Lazarian", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmous, 0, catnmous, catnmous, catnmous_state, init_laserbat, ROT90, "Zaccaria", "Cat and Mouse (type 02 program)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmousa, catnmous, catnmous, catnmous, catnmous_state, init_laserbat, ROT90, "Zaccaria", "Cat and Mouse (type 01 program)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1981, laserbat, 0, laserbat, laserbat, laserbat_state, empty_init, ROT0, "Zaccaria", "Laser Battle", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1981, lazarian, laserbat, laserbat, lazarian, laserbat_state, empty_init, ROT0, "Zaccaria (Bally Midway license)", "Lazarian", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmous, 0, catnmous, catnmous, catnmous_state, empty_init, ROT90, "Zaccaria", "Cat and Mouse (type 02 program)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmousa, catnmous, catnmous, catnmous, catnmous_state, empty_init, ROT90, "Zaccaria", "Cat and Mouse (type 01 program)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
117 changes: 49 additions & 68 deletions src/mame/includes/laserbat.h
Expand Up @@ -29,7 +29,14 @@
class laserbat_state_base : public driver_device
{
public:
laserbat_state_base(const machine_config &mconfig, device_type type, const char *tag)
void laserbat_base(machine_config &config);
void laserbat_io_map(address_map &map);
void laserbat_map(address_map &map);

protected:
enum { TIMER_SCANLINE };

laserbat_state_base(const machine_config &mconfig, device_type type, const char *tag, uint8_t eff2_mask)
: driver_device(mconfig, type, tag)
, m_mux_ports(*this, {"ROW0", "ROW1", "SW1", "SW2"})
, m_row1(*this, "ROW1")
Expand All @@ -40,39 +47,12 @@ class laserbat_state_base : public driver_device
, m_gfxmix(*this, "gfxmix")
, m_pvi(*this, "pvi%u", 1U)
, m_gfxdecode(*this, "gfxdecode")
, m_scanline_timer(nullptr)
, m_gfx1(nullptr)
, m_gfx2(nullptr)
, m_input_mux(0)
, m_mpx_p_1_2(false)
, m_mpx_bkeff(false)
, m_nave(false)
, m_clr_lum(0)
, m_shp(0)
, m_wcoh(0)
, m_wcov(0)
, m_abeff1(false)
, m_abeff2(false)
, m_mpx_eff2_sh(false)
, m_coleff(0)
, m_neg1(false)
, m_neg2(false)
, m_rhsc(0)
, m_whsc(0)
, m_csound1(0)
, m_csound2(0)
, m_gfx1(*this, "gfx1")
, m_gfx2(*this, "gfx2")
, m_eff2_mask(eff2_mask)
{
}

void init_laserbat();

void laserbat_base(machine_config &config);
void laserbat_io_map(address_map &map);
void laserbat_map(address_map &map);

protected:
enum { TIMER_SCANLINE };

// control ports
void ct_io_w(uint8_t data);
uint8_t rrowx_r();
Expand All @@ -93,7 +73,7 @@ class laserbat_state_base : public driver_device
virtual void csound2_w(uint8_t data);

// running the video
virtual void video_start() override;
virtual void machine_start() override;
uint32_t screen_update_laserbat(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);

virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
Expand All @@ -102,67 +82,68 @@ class laserbat_state_base : public driver_device
TIMER_CALLBACK_MEMBER(video_line);

// input lines
required_ioport_array<4> m_mux_ports;
required_ioport m_row1;
required_ioport m_row2;
required_ioport_array<4> m_mux_ports;
required_ioport m_row1;
required_ioport m_row2;

// main CPU device
required_device<s2650_device> m_maincpu;
required_device<s2650_device> m_maincpu;

// video devices
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_device<pla_device> m_gfxmix;
required_device_array<s2636_device, 3> m_pvi;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_device<pla_device> m_gfxmix;
required_device_array<s2636_device, 3> m_pvi;
required_device<gfxdecode_device> m_gfxdecode;

// stuff for rendering video
emu_timer *m_scanline_timer;
bitmap_ind16 m_bitmap;
uint8_t const *m_gfx1;
uint8_t const *m_gfx2;
required_region_ptr<uint8_t> m_gfx1;
required_region_ptr<uint8_t> m_gfx2;
emu_timer *m_scanline_timer = nullptr;
bitmap_ind16 m_bitmap;
uint16_t m_gfx2_base = 0;
uint8_t const m_eff2_mask;

// control lines
unsigned m_input_mux;
uint8_t m_input_mux;
bool m_mpx_p_1_2;

// RAM used by TTL video hardware, writable by CPU
uint8_t m_bg_ram[0x400]; // background tilemap
uint8_t m_eff_ram[0x400]; // per-scanline effects (A8 not wired meaning only half is usable)
bool m_mpx_bkeff; // select between writing background and effects memory
uint8_t m_bg_ram[0x400]; // background tilemap
uint8_t m_eff_ram[0x400]; // per-scanline effects (A8 not wired meaning only half is usable)
bool m_mpx_bkeff = false; // select between writing background and effects memory

// signals affecting the TTL-generated 32x32 sprite
bool m_nave; // 1-bit enable
unsigned m_clr_lum; // 3-bit colour/luminance
unsigned m_shp; // 3-bit shape
unsigned m_wcoh; // 8-bit offset horizontal
unsigned m_wcov; // 8-bit offset vertical
bool m_nave = false; // 1-bit enable
uint8_t m_clr_lum = 0; // 3-bit colour/luminance
uint8_t m_shp = 0; // 3-bit shape
uint8_t m_wcoh = 0; // 8-bit offset horizontal
uint8_t m_wcov = 0; // 8-bit offset vertical

// video effects signals
bool m_abeff1; // 1-bit effect enable
bool m_abeff2; // 1-bit effect enable
bool m_mpx_eff2_sh; // 1-bit effect selection
unsigned m_coleff; // 2-bit colour effect
bool m_neg1; // 1-bit area selection
bool m_neg2; // 1-bit area selection
bool m_abeff1 = false; // 1-bit effect enable
bool m_abeff2 = false; // 1-bit effect enable
bool m_mpx_eff2_sh = false; // 1-bit effect selection
uint8_t m_coleff = 0; // 2-bit colour effect
bool m_neg1 = false; // 1-bit area selection
bool m_neg2 = false; // 1-bit area selection

// sound board I/O signals
unsigned m_rhsc; // 8-bit input from J7
unsigned m_whsc; // 8-bit output to J7
unsigned m_csound1; // bits 1-8 on J3
unsigned m_csound2; // bits 9-16 on J3
uint8_t m_rhsc = 0; // 8-bit input from J7
uint8_t m_whsc = 0; // 8-bit output to J7
uint8_t m_csound1 = 0; // bits 1-8 on J3
uint8_t m_csound2 = 0; // bits 9-16 on J3
};


class laserbat_state : public laserbat_state_base
{
public:
laserbat_state(const machine_config &mconfig, device_type type, const char *tag)
: laserbat_state_base(mconfig, type, tag)
: laserbat_state_base(mconfig, type, tag, 0x00)
, m_csg(*this, "csg")
, m_synth_low(*this, "synth_low")
, m_synth_high(*this, "synth_high")
, m_keys(0)
{
}

Expand All @@ -184,15 +165,15 @@ class laserbat_state : public laserbat_state_base
required_device<tms3615_device> m_synth_high;

// register state
unsigned m_keys; // low octave keys 1-13 and high octave keys 2-12 (24 bits)
uint32_t m_keys = 0; // low octave keys 1-13 and high octave keys 2-12 (24 bits)
};


class catnmous_state : public laserbat_state_base
{
public:
catnmous_state(const machine_config &mconfig, device_type type, const char *tag)
: laserbat_state_base(mconfig, type, tag)
: laserbat_state_base(mconfig, type, tag, 0x03)
, m_audiopcb(*this, "audiopcb")
{
}
Expand Down
26 changes: 6 additions & 20 deletions src/mame/video/laserbat.cpp
Expand Up @@ -157,18 +157,6 @@ void laserbat_state_base::cnt_nav_w(uint8_t data)
}


void laserbat_state_base::video_start()
{
// we render straight from ROM
m_gfx1 = memregion("gfx1")->base();
m_gfx2 = memregion("gfx2")->base();

// start rendering scanlines
m_screen->register_screen_bitmap(m_bitmap);
m_scanline_timer->adjust(m_screen->time_until_pos(1, 0));
}


uint32_t laserbat_state_base::screen_update_laserbat(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bool const flip_y = flip_screen_y(), flip_x = flip_screen_x();
Expand Down Expand Up @@ -281,16 +269,14 @@ TIMER_CALLBACK_MEMBER(laserbat_state_base::video_line)
for (int x = 0, px = x_offset; max_x >= px; x++)
{
// calculate area effects
// I have no idea where the magical x offset comes from but it's necessary
bool const right_half = bool((x + 0) & 0x80);
bool const eff1_cmp = right_half ? (uint8_t((x + 0) & 0x7f) < (eff1_val & 0x7f)) : (uint8_t((x + 0) & 0x7f) > (~eff1_val & 0x7f));
bool const eff2_cmp = right_half ? (uint8_t((x + 0) & 0x7f) < (eff2_val & 0x7f)) : (uint8_t((x + 0) & 0x7f) > (~eff2_val & 0x7f));
bool const right_half = bool(x & 0x80);
bool const eff1_cmp = right_half ? (uint8_t(x & 0x7f) < (eff1_val & 0x7f)) : (uint8_t(x & 0x7f) > (~eff1_val & 0x7f));
bool const eff2_cmp = right_half ? ((uint8_t(x & 0x7f) | m_eff2_mask) < ((eff2_val & 0x7f) | m_eff2_mask)) : ((uint8_t(x & 0x7f) | m_eff2_mask) > ((~eff2_val & 0x7f) | m_eff2_mask));
bool const eff1 = m_abeff1 && (m_neg1 ? !eff1_cmp : eff1_cmp);
bool const eff2 = m_abeff2 && (m_neg2 ? !eff2_cmp : eff2_cmp) && m_mpx_eff2_sh;

// calculate shell point effect
// using the same magical offset as the area effects
bool const shell = m_abeff2 && (uint8_t((x + 0) & 0xff) == (eff2_val & 0xff)) && !m_mpx_eff2_sh;
bool const shell = m_abeff2 && ((uint8_t(x & 0xff) | m_eff2_mask) == ((eff2_val & 0xff) | m_eff2_mask)) && !m_mpx_eff2_sh;

// set effect bits, and mix in PVI graphics while we're here
uint16_t const effect_bits = (shell ? 0x0800 : 0x0000) | (eff1 ? 0x1000 : 0x0000) | (eff2 ? 0x2000 : 0x0000);
Expand All @@ -305,15 +291,15 @@ TIMER_CALLBACK_MEMBER(laserbat_state_base::video_line)
}

// render the TTL-generated sprite
// more magic offsets here I don't understand the source of
// magic offsets here I don't understand the source of
if (m_nave)
{
int const sprite_row = y + y_offset - ((256 - m_wcov) & 0x0ff);
if ((0 <= sprite_row) && (32 > sprite_row))
{
for (unsigned byte = 0, x = x_offset + (3 * ((256 - m_wcoh + 5) & 0x0ff)); 8 > byte; byte++)
{
uint8_t bits = m_gfx2[((m_shp << 8) & 0x700) | ((sprite_row << 3) & 0x0f8) | (byte & 0x07)];
uint8_t bits = m_gfx2[m_gfx2_base | ((m_shp << 8) & 0x700) | ((sprite_row << 3) & 0x0f8) | (byte & 0x07)];
for (unsigned pixel = 0; 4 > pixel; pixel++, bits <<= 2)
{
if (max_x >= x) row[x++] |= (bits >> 6) & 0x03;
Expand Down

0 comments on commit 349f5cb

Please sign in to comment.