sega/deniam.cpp, sega/kopunch.cpp, sega/stactics.cpp, sega/suprloco.cpp: consolidated drivers in single files, minor cleanups

This commit is contained in:
Ivan Vangelista 2022-08-25 17:27:32 +02:00
parent 94afa5a44a
commit 278ebb10d5
12 changed files with 1692 additions and 1758 deletions

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria
// copyright-holders: Nicola Salmoria
/***************************************************************************
Deniam games
@ -44,84 +45,566 @@ Notes:
***************************************************************************/
#include "emu.h"
#include "deniam.h"
#include "cpu/m68000/m68000.h"
#include "cpu/z80/z80.h"
#include "machine/gen_latch.h"
#include "sound/okim6295.h"
#include "sound/ymopl.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
void deniam_state::deniam16b_oki_rom_bank_w(u8 data)
namespace {
class deniamc_state : public driver_device
{
public:
deniamc_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_oki(*this, "oki"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_videoram(*this, "videoram"),
m_textram(*this, "textram"),
m_spriteram(*this, "spriteram"),
m_spritegfx(*this, "spritegfx")
{ }
void deniam16c(machine_config &config);
void init_logicpro();
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
// devices
required_device<cpu_device> m_maincpu;
required_device<okim6295_device> m_oki;
// configuration
u16 m_bg_scrollx_offs = 0;
u8 m_bg_scrolly_offs = 0;
u16 m_fg_scrollx_offs = 0;
u8 m_fg_scrolly_offs = 0;
u8 m_bg_scrollx_reg = 0;
u8 m_bg_scrolly_reg = 0;
u8 m_bg_page_reg = 0;
u8 m_fg_scrollx_reg = 0;
u8 m_fg_scrolly_reg = 0;
u8 m_fg_page_reg = 0;
void common_init();
void base_main_map(address_map &map);
private:
// devices
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
// memory pointers
required_shared_ptr<u16> m_videoram;
required_shared_ptr<u16> m_textram;
required_shared_ptr<u16> m_spriteram;
required_memory_region m_spritegfx;
// video-related
tilemap_t *m_fg_tilemap = nullptr;
tilemap_t *m_bg_tilemap = nullptr;
tilemap_t *m_tx_tilemap = nullptr;
u8 m_display_enable = 0;
int m_bg_page[4]{};
int m_fg_page[4]{};
u16 m_coinctrl = 0;
void irq_ack_w(u16 data);
void videoram_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void textram_w(offs_t offset, u16 data, u16 mem_mask = ~0);
u16 coinctrl_r();
void coinctrl_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void oki_rom_bank_w(u8 data);
TILEMAP_MAPPER_MEMBER(scan_pages);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
TILE_GET_INFO_MEMBER(get_fg_tile_info);
TILE_GET_INFO_MEMBER(get_tx_tile_info);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void set_bg_page(int page, int value);
void set_fg_page(int page, int value);
void main_map(address_map &map);
};
class deniamb_state : public deniamc_state
{
public:
deniamb_state(const machine_config &mconfig, device_type type, const char *tag) :
deniamc_state(mconfig, type, tag),
m_audiocpu(*this, "audiocpu"),
m_soundlatch(*this, "soundlatch")
{ }
void deniam16b(machine_config &config);
void init_karianx();
private:
// devices
required_device<cpu_device> m_audiocpu;
required_device<generic_latch_8_device> m_soundlatch;
void oki_rom_bank_w(u8 data);
void main_map(address_map &map);
void sound_io_map(address_map &map);
void sound_map(address_map &map);
};
// video
void deniamc_state::common_init()
{
m_bg_scrollx_reg = 0x00a4/2;
m_bg_scrolly_reg = 0x00a8/2;
m_bg_page_reg = 0x00ac/2;
m_fg_scrollx_reg = 0x00a2/2;
m_fg_scrolly_reg = 0x00a6/2;
m_fg_page_reg = 0x00aa/2;
m_display_enable = 0;
m_coinctrl = 0;
for (int i = 0; i < 4; i++)
{
m_bg_page[i] = 0;
m_fg_page[i] = 0;
}
}
void deniamc_state::init_logicpro()
{
common_init();
m_bg_scrollx_offs = 0x00d;
m_bg_scrolly_offs = 0x000;
m_fg_scrollx_offs = 0x009;
m_fg_scrolly_offs = 0x000;
}
void deniamb_state::init_karianx()
{
common_init();
m_bg_scrollx_offs = 0x10d;
m_bg_scrolly_offs = 0x080;
m_fg_scrollx_offs = 0x109;
m_fg_scrolly_offs = 0x080;
}
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILEMAP_MAPPER_MEMBER(deniamc_state::scan_pages)
{
// logical (col,row) -> memory offset
return (col & 0x3f) + ((row & 0x1f) << 6) + ((col & 0x40) << 5) + ((row & 0x20) << 7);
}
TILE_GET_INFO_MEMBER(deniamc_state::get_bg_tile_info)
{
const int page = tile_index >> 11;
const u16 attr = m_videoram[m_bg_page[page] * 0x0800 + (tile_index & 0x7ff)];
tileinfo.set(0,
attr,
(attr & 0x1fc0) >> 6,
0);
}
TILE_GET_INFO_MEMBER(deniamc_state::get_fg_tile_info)
{
const int page = tile_index >> 11;
const u16 attr = m_videoram[m_fg_page[page] * 0x0800 + (tile_index & 0x7ff)];
tileinfo.set(0,
attr,
(attr & 0x1fc0) >> 6,
0);
}
TILE_GET_INFO_MEMBER(deniamc_state::get_tx_tile_info)
{
const u16 attr = m_textram[tile_index];
tileinfo.set(0,
attr & 0xf1ff,
(attr & 0x0e00) >> 9,
0);
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void deniamc_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(deniamc_state::get_bg_tile_info)), tilemap_mapper_delegate(*this, FUNC(deniamc_state::scan_pages)), 8, 8, 128, 64);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(deniamc_state::get_fg_tile_info)), tilemap_mapper_delegate(*this, FUNC(deniamc_state::scan_pages)), 8, 8, 128, 64);
m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(deniamc_state::get_tx_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
m_fg_tilemap->set_transparent_pen(0);
m_tx_tilemap->set_transparent_pen(0);
}
/***************************************************************************
Memory handlers
***************************************************************************/
void deniamc_state::videoram_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_videoram[offset]);
const int page = offset >> 11;
for (int i = 0; i < 4; i++)
{
if (m_bg_page[i] == page)
m_bg_tilemap->mark_tile_dirty(i * 0x800 + (offset & 0x7ff));
if (m_fg_page[i] == page)
m_fg_tilemap->mark_tile_dirty(i * 0x800 + (offset & 0x7ff));
}
}
void deniamc_state::textram_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_textram[offset]);
m_tx_tilemap->mark_tile_dirty(offset);
}
u16 deniamc_state::coinctrl_r()
{
return m_coinctrl;
}
void deniamc_state::coinctrl_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_coinctrl);
// bit 0 is coin counter
machine().bookkeeping().coin_counter_w(0, m_coinctrl & 0x01);
// bit 6 is display enable (0 freezes screen)
m_display_enable = m_coinctrl & 0x20;
// other bits unknown (unused?)
}
/***************************************************************************
Display refresh
***************************************************************************/
/*
* Sprite Format
* ------------------
*
* Word | Bit(s) | Use
* -----+-fedcba9876543210-+----------------
* 0 | --------xxxxxxxx | display y start
* 0 | xxxxxxxx-------- | display y end
* 2 | -------xxxxxxxxx | x position
* 2 | ------x--------- | unknown (used in logicpr2, maybe just a bug?)
* 2 | xxxxxx---------- | unused?
* 4 | ---------xxxxxxx | width
* 4 | --------x------- | is this flip y like in System 16?
* 4 | -------x-------- | flip x
* 4 | xxxxxxx--------- | unused?
* 6 | xxxxxxxxxxxxxxxx | ROM address low bits
* 8 | ----------xxxxxx | color
* 8 | --------xx------ | priority
* 8 | ---xxxxx-------- | ROM address high bits
* 8 | xxx------------- | unused? (extra address bits for larger ROMs?)
* a | ---------------- | zoomx like in System 16?
* c | ---------------- | zoomy like in System 16?
* e | ---------------- |
*/
void deniamc_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
for (int offs = m_spriteram.bytes() / 2 - 8; offs >= 0; offs -= 8)
{
u8 *rom = m_spritegfx->base();
int sx = (m_spriteram[offs + 1] & 0x01ff) + 16 * 8 - 1;
if (sx >= 512) sx -= 512;
const int starty = m_spriteram[offs + 0] & 0xff;
const int endy = m_spriteram[offs + 0] >> 8;
const int width = m_spriteram[offs + 2] & 0x007f;
bool flipx = m_spriteram[offs + 2] & 0x0100;
if (flipx) sx++;
const u32 color = 0x40 + (m_spriteram[offs + 4] & 0x3f);
int primask = 8;
switch (m_spriteram[offs + 4] & 0xc0)
{
case 0x00: primask |= 4 | 2 | 1; break; // below everything
case 0x40: primask |= 4 | 2; break; // below fg and tx
case 0x80: primask |= 4; break; // below tx
case 0xc0: break; // above everything
}
const int start = m_spriteram[offs + 3] + ((m_spriteram[offs + 4] & 0x1f00) << 8);
rom += 2 * start;
for (int y = starty + 1; y <= endy; y++)
{
bool drawing = false;
int i = 0;
rom += 2 * width; // note that the first line is skipped
int x = 0;
while (i < 512) // safety check
{
if (flipx)
{
if ((rom[i] & 0x0f) == 0x0f)
{
if (!drawing) drawing = true;
else break;
}
else
{
if (rom[i] & 0x0f)
{
if (cliprect.contains(sx + x, y))
{
if ((screen.priority().pix(y, sx + x) & primask) == 0)
bitmap.pix(y, sx + x) = color * 16 + (rom[i] & 0x0f);
screen.priority().pix(y, sx + x) = 8;
}
}
x++;
}
if ((rom[i] & 0xf0) == 0xf0)
{
if (!drawing) drawing = true;
else break;
}
else
{
if (rom[i] & 0xf0)
{
if (cliprect.contains(sx + x, y))
{
if ((screen.priority().pix(y, sx + x) & primask) == 0)
bitmap.pix(y, sx + x) = color * 16 + (rom[i] >> 4);
screen.priority().pix(y, sx + x) = 8;
}
}
x++;
}
i--;
}
else
{
if ((rom[i] & 0xf0) == 0xf0)
{
if (!drawing) drawing = true;
else break;
}
else
{
if (rom[i] & 0xf0)
{
if (cliprect.contains(sx + x, y))
{
if ((screen.priority().pix(y, sx + x) & primask) == 0)
bitmap.pix(y, sx + x) = color * 16 + (rom[i] >> 4);
screen.priority().pix(y, sx + x) = 8;
}
}
x++;
}
if ((rom[i] & 0x0f) == 0x0f)
{
if (!drawing) drawing = true;
else break;
}
else
{
if (rom[i] & 0x0f)
{
if (cliprect.contains(sx + x, y))
{
if ((screen.priority().pix(y, sx + x) & primask) == 0)
bitmap.pix(y, sx + x) = color * 16 + (rom[i] & 0x0f);
screen.priority().pix(y, sx + x) = 8;
}
}
x++;
}
i++;
}
}
}
}
}
void deniamc_state::set_bg_page(int page, int value)
{
if (m_bg_page[page] != value)
{
m_bg_page[page] = value;
for (int tile_index = page * 0x800; tile_index < (page + 1) * 0x800; tile_index++)
m_bg_tilemap->mark_tile_dirty(tile_index);
}
}
void deniamc_state::set_fg_page(int page, int value)
{
if (m_fg_page[page] != value)
{
m_fg_page[page] = value;
for (int tile_index = page * 0x800; tile_index < (page + 1) * 0x800; tile_index++)
m_fg_tilemap->mark_tile_dirty(tile_index);
}
}
u32 deniamc_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int page;
if (!m_display_enable)
{
bitmap.fill(m_palette->black_pen(), cliprect);
return 0; /* don't update (freeze display) */
}
const int bg_scrollx = m_textram[m_bg_scrollx_reg] - m_bg_scrollx_offs;
const int bg_scrolly = (m_textram[m_bg_scrolly_reg] & 0xff) - m_bg_scrolly_offs;
page = m_textram[m_bg_page_reg];
set_bg_page(3, (page >>12) & 0x0f);
set_bg_page(2, (page >> 8) & 0x0f);
set_bg_page(1, (page >> 4) & 0x0f);
set_bg_page(0, (page >> 0) & 0x0f);
const int fg_scrollx = m_textram[m_fg_scrollx_reg] - m_fg_scrollx_offs;
const int fg_scrolly = (m_textram[m_fg_scrolly_reg] & 0xff) - m_fg_scrolly_offs;
page = m_textram[m_fg_page_reg];
set_fg_page(3, (page >>12) & 0x0f);
set_fg_page(2, (page >> 8) & 0x0f);
set_fg_page(1, (page >> 4) & 0x0f);
set_fg_page(0, (page >> 0) & 0x0f);
m_bg_tilemap->set_scrollx(0, bg_scrollx & 0x1ff);
m_bg_tilemap->set_scrolly(0, bg_scrolly & 0x0ff);
m_fg_tilemap->set_scrollx(0, fg_scrollx & 0x1ff);
m_fg_tilemap->set_scrolly(0, fg_scrolly & 0x0ff);
screen.priority().fill(0, cliprect);
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 1);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 2);
m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 4);
draw_sprites(screen, bitmap, cliprect);
return 0;
}
// machine
void deniamb_state::oki_rom_bank_w(u8 data)
{
m_oki->set_rom_bank((data >> 6) & 1);
}
void deniam_state::deniam16c_oki_rom_bank_w(u8 data)
void deniamc_state::oki_rom_bank_w(u8 data)
{
if ((data&0xFE) != 0) popmessage("OKI bank was not 0 or 1! contact MAMEDEV!");
if ((data & 0xfe) != 0) popmessage("OKI bank was not 0 or 1! contact MAMEDEV!");
m_oki->set_rom_bank(data & 0x01);
}
void deniam_state::irq_ack_w(u16 data)
void deniamc_state::irq_ack_w(u16 data)
{
m_maincpu->set_input_line(4, CLEAR_LINE);
}
void deniam_state::deniam16b_map(address_map &map)
void deniamc_state::base_main_map(address_map &map)
{
map(0x000000, 0x0fffff).rom();
map(0x400000, 0x40ffff).ram().w(FUNC(deniam_state::videoram_w)).share("videoram");
map(0x410000, 0x410fff).ram().w(FUNC(deniam_state::textram_w)).share("textram");
map(0x440000, 0x4407ff).writeonly().share("spriteram");
map(0x400000, 0x40ffff).ram().w(FUNC(deniamb_state::videoram_w)).share(m_videoram);
map(0x410000, 0x410fff).ram().w(FUNC(deniamb_state::textram_w)).share(m_textram);
map(0x440000, 0x4407ff).writeonly().share(m_spriteram);
map(0x840000, 0x840fff).w(m_palette, FUNC(palette_device::write16)).share("palette");
map(0xc40000, 0xc40000).w(m_soundlatch, FUNC(generic_latch_8_device::write));
map(0xc40002, 0xc40003).rw(FUNC(deniam_state::coinctrl_r), FUNC(deniam_state::coinctrl_w));
map(0xc40004, 0xc40005).w(FUNC(deniam_state::irq_ack_w));
map(0xc40002, 0xc40003).rw(FUNC(deniamb_state::coinctrl_r), FUNC(deniamb_state::coinctrl_w));
map(0xc40004, 0xc40005).w(FUNC(deniamb_state::irq_ack_w));
map(0xc44000, 0xc44001).portr("SYSTEM");
map(0xc44002, 0xc44003).portr("P1");
map(0xc44004, 0xc44005).portr("P2").nopw();
map(0xc44006, 0xc44007).nopr(); /* unused? */
map(0xc4400a, 0xc4400b).portr("DSW");
map(0xff0000, 0xffffff).ram();
}
void deniam_state::sound_map(address_map &map)
void deniamb_state::main_map(address_map &map)
{
base_main_map(map);
map(0xc40000, 0xc40000).w(m_soundlatch, FUNC(generic_latch_8_device::write));
map(0xc44006, 0xc44007).nopr(); // unused?
map(0xc4400a, 0xc4400b).portr("DSW");
}
void deniamb_state::sound_map(address_map &map)
{
map(0x0000, 0xf7ff).rom();
map(0xf800, 0xffff).ram();
}
void deniam_state::sound_io_map(address_map &map)
void deniamb_state::sound_io_map(address_map &map)
{
map.global_mask(0xff);
map(0x01, 0x01).r(m_soundlatch, FUNC(generic_latch_8_device::read));
map(0x02, 0x03).w("ymsnd", FUNC(ym3812_device::write));
map(0x05, 0x05).rw(m_oki, FUNC(okim6295_device::read), FUNC(okim6295_device::write));
map(0x07, 0x07).w(FUNC(deniam_state::deniam16b_oki_rom_bank_w));
map(0x07, 0x07).w(FUNC(deniamb_state::oki_rom_bank_w));
}
/* identical to 16b, but handles sound directly */
void deniam_state::deniam16c_map(address_map &map)
// identical to 16b, but handles sound directly
void deniamc_state::main_map(address_map &map)
{
map(0x000000, 0x0fffff).rom();
map(0x400000, 0x40ffff).ram().w(FUNC(deniam_state::videoram_w)).share("videoram");
map(0x410000, 0x410fff).ram().w(FUNC(deniam_state::textram_w)).share("textram");
map(0x440000, 0x4407ff).writeonly().share("spriteram");
map(0x840000, 0x840fff).w(m_palette, FUNC(palette_device::write16)).share("palette");
base_main_map(map);
map(0xc40001, 0xc40001).rw(m_oki, FUNC(okim6295_device::read), FUNC(okim6295_device::write));
map(0xc40002, 0xc40003).rw(FUNC(deniam_state::coinctrl_r), FUNC(deniam_state::coinctrl_w));
map(0xc40004, 0xc40005).w(FUNC(deniam_state::irq_ack_w));
map(0xc40007, 0xc40007).w(FUNC(deniam_state::deniam16c_oki_rom_bank_w));
map(0xc44000, 0xc44001).portr("SYSTEM");
map(0xc44002, 0xc44003).portr("P1");
map(0xc44004, 0xc44005).portr("P2");
map(0xc44006, 0xc44007).nopr(); /* read unused? extra input port/dipswitches? */
map(0xc40007, 0xc40007).w(FUNC(deniamc_state::oki_rom_bank_w));
map(0xc44006, 0xc44007).nopr(); // read unused? extra input port/dipswitches?
map(0xc40008, 0xc4000b).w("ymsnd", FUNC(ym3812_device::write)).umask16(0xff00);
map(0xc4400a, 0xc4400b).portr("DSW"); /* probably YM3812 input port */
map(0xff0000, 0xffffff).ram();
map(0xc4400a, 0xc4400b).portr("DSW"); // probably YM3812 input port
}
@ -201,32 +684,22 @@ INPUT_PORTS_END
static GFXDECODE_START( gfx_deniam )
GFXDECODE_ENTRY( "gfx1", 0, gfx_8x8x3_planar, 0, 128 ) /* colors 0-1023 */
/* sprites use colors 1024-2047 */
GFXDECODE_ENTRY( "chars", 0, gfx_8x8x3_planar, 0, 128 ) // colors 0-1023
// sprites use colors 1024-2047
GFXDECODE_END
void deniam_state::machine_start()
void deniamc_state::machine_start()
{
save_item(NAME(m_display_enable));
save_item(NAME(m_coinctrl));
save_item(NAME(m_bg_scrollx_offs));
save_item(NAME(m_bg_scrolly_offs));
save_item(NAME(m_fg_scrollx_offs));
save_item(NAME(m_fg_scrolly_offs));
save_item(NAME(m_bg_scrollx_reg));
save_item(NAME(m_bg_scrolly_reg));
save_item(NAME(m_fg_scrollx_reg));
save_item(NAME(m_fg_scrolly_reg));
save_item(NAME(m_bg_page_reg));
save_item(NAME(m_fg_page_reg));
save_item(NAME(m_bg_page));
save_item(NAME(m_fg_page));
}
void deniam_state::machine_reset()
void deniamc_state::machine_reset()
{
/* logicpr2 does not reset the bank base on startup, though it probably
doesn't matter since the coinup sfx (sample borrowed from 'tyrian' on PC)
@ -235,72 +708,52 @@ void deniam_state::machine_reset()
m_oki->set_rom_bank(0);
}
void deniam_state::deniam16b(machine_config &config)
void deniamc_state::deniam16c(machine_config &config)
{
/* basic machine hardware */
M68000(config, m_maincpu, XTAL(25'000'000)/2); /* 12.5Mhz verified */
m_maincpu->set_addrmap(AS_PROGRAM, &deniam_state::deniam16b_map);
m_maincpu->set_vblank_int("screen", FUNC(deniam_state::irq4_line_assert));
// basic machine hardware
M68000(config, m_maincpu, XTAL(25'000'000) / 2); // 12.5Mhz verified
m_maincpu->set_addrmap(AS_PROGRAM, &deniamc_state::main_map);
m_maincpu->set_vblank_int("screen", FUNC(deniamb_state::irq4_line_assert));
Z80(config, m_audiocpu, XTAL(25'000'000)/4); /* 6.25Mhz verified */
m_audiocpu->set_addrmap(AS_PROGRAM, &deniam_state::sound_map);
m_audiocpu->set_addrmap(AS_IO, &deniam_state::sound_io_map);
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(512, 256);
//screen.set_visarea(24*8, 64*8-1, 0*8, 28*8-1); // looks better but doesn't match hardware
screen.set_visarea(24*8-4, 64*8-5, 0*8, 28*8-1);
screen.set_screen_update(FUNC(deniam_state::screen_update));
screen.set_screen_update(FUNC(deniamb_state::screen_update));
screen.set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_deniam);
PALETTE(config, m_palette).set_format(palette_device::xBGRBBBBGGGGRRRR_bit0, 2048); // bit 15 is toggle shadow / hilight?
PALETTE(config, m_palette).set_format(palette_device::xBGRBBBBGGGGRRRR_bit0, 2048); // bit 15 is toggle shadow / highlight?
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
GENERIC_LATCH_8(config, m_soundlatch);
m_soundlatch->data_pending_callback().set_inputline(m_audiocpu, INPUT_LINE_NMI);
ym3812_device &ymsnd(YM3812(config, "ymsnd", XTAL(25'000'000)/6)); /* "SM64" ym3812 clone; 4.166470 measured, = 4.166666Mhz verified */
ymsnd.irq_handler().set_inputline(m_audiocpu, 0);
ym3812_device &ymsnd(YM3812(config, "ymsnd", XTAL(25'000'000) / 6)); // "SM64" ym3812 clone; 4.166470 measured, = 4.166666Mhz verified
ymsnd.add_route(ALL_OUTPUTS, "mono", 0.60);
OKIM6295(config, m_oki, XTAL(25'000'000)/24, okim6295_device::PIN7_HIGH); /* 1.041620 measured, = 1.0416666Mhz verified */
OKIM6295(config, m_oki, XTAL(25'000'000) / 24, okim6295_device::PIN7_HIGH); // 1.041620 measured, = 1.0416666Mhz verified
m_oki->add_route(ALL_OUTPUTS, "mono", 1.0);
}
void deniam_state::deniam16c(machine_config &config)
void deniamb_state::deniam16b(machine_config &config)
{
/* basic machine hardware */
M68000(config, m_maincpu, XTAL(25'000'000)/2); /* 12.5Mhz verified */
m_maincpu->set_addrmap(AS_PROGRAM, &deniam_state::deniam16c_map);
m_maincpu->set_vblank_int("screen", FUNC(deniam_state::irq4_line_assert));
deniam16c(config);
/* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(512, 256);
//screen.set_visarea(24*8, 64*8-1, 0*8, 28*8-1); // looks better but doesn't match hardware
screen.set_visarea(24*8-4, 64*8-5, 0*8, 28*8-1);
screen.set_screen_update(FUNC(deniam_state::screen_update));
screen.set_palette(m_palette);
// basic machine hardware
m_maincpu->set_addrmap(AS_PROGRAM, &deniamb_state::main_map);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_deniam);
PALETTE(config, m_palette).set_format(palette_device::xBGRBBBBGGGGRRRR_bit0, 2048); // bit 15 is toggle shadow / hilight?
Z80(config, m_audiocpu, XTAL(25'000'000) / 4); // 6.25Mhz verified
m_audiocpu->set_addrmap(AS_PROGRAM, &deniamb_state::sound_map);
m_audiocpu->set_addrmap(AS_IO, &deniamb_state::sound_io_map);
/* sound hardware */
SPEAKER(config, "mono").front_center();
// sound hardware
GENERIC_LATCH_8(config, m_soundlatch);
m_soundlatch->data_pending_callback().set_inputline(m_audiocpu, INPUT_LINE_NMI);
ym3812_device &ymsnd(YM3812(config, "ymsnd", XTAL(25'000'000)/6)); /* "SM64" ym3812 clone; 4.166470 measured, = 4.166666Mhz verified) */
ymsnd.add_route(ALL_OUTPUTS, "mono", 0.60);
OKIM6295(config, m_oki, XTAL(25'000'000)/24, okim6295_device::PIN7_HIGH); /* 1.041620 measured, = 1.0416666Mhz verified */
m_oki->add_route(ALL_OUTPUTS, "mono", 1.0);
subdevice<ym3812_device>("ymsnd")->irq_handler().set_inputline(m_audiocpu, 0);
}
@ -316,20 +769,20 @@ ROM_START( croquis )
ROM_LOAD16_BYTE( "sys_e0", 0x00000, 0x40000, CRC(b74cd4a9) SHA1(350557377bc5815d0e7f48a96898eba6374f65dd) ) // 27C020
ROM_LOAD16_BYTE( "sys_o0", 0x00001, 0x40000, CRC(346e18f4) SHA1(0107ef7b5843a654f393d6f22ef6d52b5bf45fc0) ) // 27C020
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "logicpro.r2", 0x0000, 0x10000, CRC(000d624b) SHA1(c0da218ee81d01b3dcef2159bbaaff5d3ddb7619) ) // 27C512 - silkscreened: DSS
ROM_REGION( 0x180000, "gfx1", 0 ) /* chars */
ROM_REGION( 0x180000, "chars", 0 )
ROM_LOAD( "logicpro.r5", 0x000000, 0x080000, CRC(dedf18c9) SHA1(9725e096427f03ed5fd81584c0aa85a53f9681c9) ) // 27C040 - silkscreened: BG(00)
ROM_LOAD( "logicpro.r6", 0x080000, 0x080000, CRC(3ecbd1c2) SHA1(dd6afacd58eaaa2562e007a92b6667ecc968377d) ) // 27C040 - silkscreened: BG(01)
ROM_LOAD( "logicpro.r7", 0x100000, 0x080000, CRC(47135521) SHA1(ee6a93332190fc966f8e820430d652942f030b00) ) // 27C040 - silkscreened: BG(02)
ROM_REGION( 0x400000, "spritegfx", 0 ) /* sprites, used at run time */
ROM_REGION( 0x400000, "spritegfx", 0 ) // used at run time
ROM_LOAD16_BYTE( "logicpro.r9", 0x000000, 0x080000, CRC(a98bc1d2) SHA1(f4aed07cccca892f3d3a91546b3a98fbe3e66d9c) ) // 27C040 - silkscreened: OBJ(E0)
ROM_LOAD16_BYTE( "logicpro.r8", 0x000001, 0x080000, CRC(1de46298) SHA1(3385a2956d9a427c85554f39c8d85922bbeb1ce1) ) // 27C040 - silkscreened: OBJ(O0)
// OBJ(E1), OBJ(E2), OBJ(O1) & OBJ(O2) not populated
ROM_REGION( 0x100000, "oki", 0 ) /* OKIM6295 samples */
ROM_REGION( 0x100000, "oki", 0 )
ROM_LOAD( "logicpro.r1", 0x0000, 0x080000, CRC(a1fec4d4) SHA1(4390cd18b4a7de2d8cb68270180ea3de42fd2282) ) // 27C040 - silkscreened: V_ROM0
// V_ROM1 not populated
ROM_END
@ -339,19 +792,19 @@ ROM_START( croquisg )
ROM_LOAD16_BYTE( "r4.bin", 0x00000, 0x40000, CRC(03c9055e) SHA1(b1fa8e7a272887decca30eefe73ac782f296f0dd) )
ROM_LOAD16_BYTE( "r3.bin", 0x00001, 0x40000, CRC(a98ae4f6) SHA1(80fcedb4ee0f35eb2d0b4a248c15f872af2e08f2) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "logicpro.r2", 0x0000, 0x10000, CRC(000d624b) SHA1(c0da218ee81d01b3dcef2159bbaaff5d3ddb7619) )
ROM_REGION( 0x180000, "gfx1", 0 ) /* chars */
ROM_REGION( 0x180000, "chars", 0 )
ROM_LOAD( "logicpro.r5", 0x000000, 0x080000, CRC(dedf18c9) SHA1(9725e096427f03ed5fd81584c0aa85a53f9681c9) )
ROM_LOAD( "logicpro.r6", 0x080000, 0x080000, CRC(3ecbd1c2) SHA1(dd6afacd58eaaa2562e007a92b6667ecc968377d) )
ROM_LOAD( "logicpro.r7", 0x100000, 0x080000, CRC(47135521) SHA1(ee6a93332190fc966f8e820430d652942f030b00) )
ROM_REGION( 0x400000, "spritegfx", 0 ) /* sprites, used at run time */
ROM_REGION( 0x400000, "spritegfx", 0 ) // used at run time
ROM_LOAD16_BYTE( "logicpro.r9", 0x000000, 0x080000, CRC(a98bc1d2) SHA1(f4aed07cccca892f3d3a91546b3a98fbe3e66d9c) )
ROM_LOAD16_BYTE( "logicpro.r8", 0x000001, 0x080000, CRC(1de46298) SHA1(3385a2956d9a427c85554f39c8d85922bbeb1ce1) )
ROM_REGION( 0x100000, "oki", 0 ) /* OKIM6295 samples */
ROM_REGION( 0x100000, "oki", 0 )
ROM_LOAD( "logicpro.r1", 0x0000, 0x080000, CRC(a1fec4d4) SHA1(4390cd18b4a7de2d8cb68270180ea3de42fd2282) )
ROM_END
@ -360,19 +813,19 @@ ROM_START( logicpro )
ROM_LOAD16_BYTE( "logicpro.r4", 0x00000, 0x40000, CRC(c506d484) SHA1(5d662b109e1d2e09556bc4ecbc11bbf5ccb639d3) )
ROM_LOAD16_BYTE( "logicpro.r3", 0x00001, 0x40000, CRC(d5a4cf62) SHA1(138ea4f1629e453c1a00410eda7086d3633240e3) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "logicpro.r2", 0x0000, 0x10000, CRC(000d624b) SHA1(c0da218ee81d01b3dcef2159bbaaff5d3ddb7619) )
ROM_REGION( 0x180000, "gfx1", 0 ) /* chars */
ROM_REGION( 0x180000, "chars", 0 )
ROM_LOAD( "logicpro.r5", 0x000000, 0x080000, CRC(dedf18c9) SHA1(9725e096427f03ed5fd81584c0aa85a53f9681c9) )
ROM_LOAD( "logicpro.r6", 0x080000, 0x080000, CRC(3ecbd1c2) SHA1(dd6afacd58eaaa2562e007a92b6667ecc968377d) )
ROM_LOAD( "logicpro.r7", 0x100000, 0x080000, CRC(47135521) SHA1(ee6a93332190fc966f8e820430d652942f030b00) )
ROM_REGION( 0x400000, "spritegfx", 0 ) /* sprites, used at run time */
ROM_REGION( 0x400000, "spritegfx", 0 ) // used at run time
ROM_LOAD16_BYTE( "logicpro.r9", 0x000000, 0x080000, CRC(a98bc1d2) SHA1(f4aed07cccca892f3d3a91546b3a98fbe3e66d9c) )
ROM_LOAD16_BYTE( "logicpro.r8", 0x000001, 0x080000, CRC(1de46298) SHA1(3385a2956d9a427c85554f39c8d85922bbeb1ce1) )
ROM_REGION( 0x100000, "oki", 0 ) /* OKIM6295 samples */
ROM_REGION( 0x100000, "oki", 0 )
ROM_LOAD( "logicpro.r1", 0x0000, 0x080000, CRC(a1fec4d4) SHA1(4390cd18b4a7de2d8cb68270180ea3de42fd2282) )
ROM_END
@ -381,15 +834,15 @@ ROM_START( karianx )
ROM_LOAD16_BYTE( "even", 0x00000, 0x80000, CRC(fd0ce238) SHA1(4b727366c942c62187d8700666b42a85c059c060) )
ROM_LOAD16_BYTE( "odd", 0x00001, 0x80000, CRC(be173cdc) SHA1(13230b6129fd1910257624a69a3a4b74696e982e) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "snd", 0x0000, 0x10000, CRC(fedd3375) SHA1(09fb2d5fc91704120f757acf9fa00d149f891a28) )
ROM_REGION( 0x180000, "gfx1", 0 ) /* chars */
ROM_REGION( 0x180000, "chars", 0 )
ROM_LOAD( "bkg1", 0x000000, 0x080000, CRC(5cb8558a) SHA1(9c6024c70a0f0cd529a0e2e853e467ec8d8ab446) )
ROM_LOAD( "bkg2", 0x080000, 0x080000, CRC(95ff297c) SHA1(28f6c005e73e1680bd8be7ce355fa0d404827105) )
ROM_LOAD( "bkg3", 0x100000, 0x080000, CRC(6c81f1b2) SHA1(14ef907a9c381b7ef45441d480bb4ccb015e474b) )
ROM_REGION( 0x400000, "spritegfx", 0 ) /* sprites, used at run time */
ROM_REGION( 0x400000, "spritegfx", 0 ) // used at run time
ROM_LOAD16_BYTE( "obj4", 0x000000, 0x080000, CRC(5f8d75a9) SHA1(0552d046742aeb2fee176887156e73480c75a1bd) )
ROM_LOAD16_BYTE( "obj1", 0x000001, 0x080000, CRC(967ee97d) SHA1(689f2da67eab86653b846fada39139792cd4aee2) )
ROM_LOAD16_BYTE( "obj5", 0x100000, 0x080000, CRC(e9fc22f9) SHA1(a1f7f779520346406949500e3224c0c42cbbe026) )
@ -397,7 +850,7 @@ ROM_START( karianx )
ROM_LOAD16_BYTE( "obj6", 0x200000, 0x080000, CRC(c1ec35a5) SHA1(bf59f4c3de081c8cc398c825fc1f3e8577641f10) )
ROM_LOAD16_BYTE( "obj3", 0x200001, 0x080000, CRC(6ac1ac87) SHA1(1954e25ac5489a8eca137b86c89c415f1fed360c) )
ROM_REGION( 0x100000, "oki", 0 ) /* OKIM6295 samples */
ROM_REGION( 0x100000, "oki", 0 )
ROM_LOAD( "voi", 0x0000, 0x080000, CRC(c6506a80) SHA1(121229c501bd5678e55c7342619743c773a01a7e) )
ROM_END
@ -406,22 +859,23 @@ ROM_START( logicpr2 )
ROM_LOAD16_BYTE( "lp2-2", 0x00000, 0x80000, CRC(cc1880bf) SHA1(5ea542b63947a570aaf924f7ab739e060e359af8) )
ROM_LOAD16_BYTE( "lp2-1", 0x00001, 0x80000, CRC(46d5e954) SHA1(7bf5ae19caeecd2123754698276bbc78d68984d9) )
ROM_REGION( 0x180000, "gfx1", 0 ) /* chars */
ROM_REGION( 0x180000, "chars", 0 )
ROM_LOAD( "log2-b01", 0x000000, 0x080000, CRC(fe789e07) SHA1(c3d542564519fd807bc605029f5a2cca571eec9f) )
ROM_LOAD( "log2-b02", 0x080000, 0x080000, CRC(1e0c51cd) SHA1(c25b3259a173e77785dcee1407ddf191c3efad79) )
ROM_LOAD( "log2-b03", 0x100000, 0x080000, CRC(916f2928) SHA1(8c73408664dcd3de42cb27fac0d22b87b540bf52) )
ROM_REGION( 0x400000, "spritegfx", 0 ) /* sprites, used at run time */
ROM_REGION( 0x400000, "spritegfx", 0 ) // used at run time
ROM_LOAD16_WORD_SWAP( "obj", 0x000000, 0x400000, CRC(f221f305) SHA1(aa1d3d86d13e009bfb44cbc6ff4401b811b19f97) )
ROM_REGION( 0x100000, "oki", 0 ) /* OKIM6295 samples */
ROM_REGION( 0x100000, "oki", 0 )
ROM_LOAD( "log2-s01", 0x0000, 0x100000, CRC(2875c435) SHA1(633538d9ac53228ea344605482ac387852c29193) )
ROM_END
} // anonymous namespace
GAME( 1996, croquis, 0, deniam16b, logicpr2, deniam_state, init_logicpro, ROT0, "Deniam", "Croquis (Korea)", MACHINE_SUPPORTS_SAVE )
GAME( 1996, croquisg, croquis, deniam16b, logicpr2, deniam_state, init_logicpro, ROT0, "Deniam", "Croquis (Germany)", MACHINE_SUPPORTS_SAVE )
GAME( 1996, logicpro, croquis, deniam16b, logicpr2, deniam_state, init_logicpro, ROT0, "Deniam", "Logic Pro (Japan)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
GAME( 1996, karianx, 0, deniam16b, karianx, deniam_state, init_karianx, ROT0, "Deniam", "Karian Cross (Rev. 1.0)", MACHINE_SUPPORTS_SAVE )
GAME( 1997, logicpr2, 0, deniam16c, logicpr2, deniam_state, init_logicpro, ROT0, "Deniam", "Logic Pro 2 (Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 1996, croquis, 0, deniam16b, logicpr2, deniamb_state, init_logicpro, ROT0, "Deniam", "Croquis (Korea)", MACHINE_SUPPORTS_SAVE )
GAME( 1996, croquisg, croquis, deniam16b, logicpr2, deniamb_state, init_logicpro, ROT0, "Deniam", "Croquis (Germany)", MACHINE_SUPPORTS_SAVE )
GAME( 1996, logicpro, croquis, deniam16b, logicpr2, deniamb_state, init_logicpro, ROT0, "Deniam", "Logic Pro (Japan)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
GAME( 1996, karianx, 0, deniam16b, karianx, deniamb_state, init_karianx, ROT0, "Deniam", "Karian Cross (Rev. 1.0)", MACHINE_SUPPORTS_SAVE )
GAME( 1997, logicpr2, 0, deniam16c, logicpr2, deniamc_state, init_logicpro, ROT0, "Deniam", "Logic Pro 2 (Japan)", MACHINE_SUPPORTS_SAVE )

View File

@ -1,95 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria
/*************************************************************************
Deniam games
*************************************************************************/
#include "machine/gen_latch.h"
#include "sound/okim6295.h"
#include "emupal.h"
#include "tilemap.h"
class deniam_state : public driver_device
{
public:
deniam_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_videoram(*this, "videoram"),
m_textram(*this, "textram"),
m_spriteram(*this, "spriteram"),
m_spritegfx(*this, "spritegfx"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_oki(*this, "oki"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_soundlatch(*this, "soundlatch")
{ }
void deniam16c(machine_config &config);
void deniam16b(machine_config &config);
void init_karianx();
void init_logicpro();
private:
/* memory pointers */
required_shared_ptr<u16> m_videoram;
required_shared_ptr<u16> m_textram;
required_shared_ptr<u16> m_spriteram;
required_memory_region m_spritegfx;
/* video-related */
tilemap_t *m_fg_tilemap = nullptr;
tilemap_t *m_bg_tilemap = nullptr;
tilemap_t *m_tx_tilemap = nullptr;
int m_display_enable = 0;
int m_bg_scrollx_offs = 0;
int m_bg_scrolly_offs = 0;
int m_fg_scrollx_offs = 0;
int m_fg_scrolly_offs = 0;
int m_bg_scrollx_reg = 0;
int m_bg_scrolly_reg = 0;
int m_bg_page_reg = 0;
int m_fg_scrollx_reg = 0;
int m_fg_scrolly_reg = 0;
int m_fg_page_reg = 0;
int m_bg_page[4]{};
int m_fg_page[4]{};
u16 m_coinctrl = 0;
/* devices */
void irq_ack_w(u16 data);
void videoram_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void textram_w(offs_t offset, u16 data, u16 mem_mask = ~0);
u16 coinctrl_r();
void coinctrl_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void deniam16b_oki_rom_bank_w(u8 data);
void deniam16c_oki_rom_bank_w(u8 data);
TILEMAP_MAPPER_MEMBER(scan_pages);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
TILE_GET_INFO_MEMBER(get_fg_tile_info);
TILE_GET_INFO_MEMBER(get_tx_tile_info);
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void deniam_common_init( );
void draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect );
void set_bg_page( int page, int value );
void set_fg_page( int page, int value );
required_device<cpu_device> m_maincpu;
optional_device<cpu_device> m_audiocpu; // system 16c does not have sound CPU
required_device<okim6295_device> m_oki;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
optional_device<generic_latch_8_device> m_soundlatch;
void deniam16b_map(address_map &map);
void deniam16c_map(address_map &map);
void sound_io_map(address_map &map);
void sound_map(address_map &map);
};

View File

@ -1,374 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria
#include "emu.h"
#include "deniam.h"
#include "screen.h"
void deniam_state::deniam_common_init( )
{
m_bg_scrollx_reg = 0x00a4/2;
m_bg_scrolly_reg = 0x00a8/2;
m_bg_page_reg = 0x00ac/2;
m_fg_scrollx_reg = 0x00a2/2;
m_fg_scrolly_reg = 0x00a6/2;
m_fg_page_reg = 0x00aa/2;
m_display_enable = 0;
m_coinctrl = 0;
for (int i = 0; i < 4; i++)
{
m_bg_page[i] = 0;
m_fg_page[i] = 0;
}
}
void deniam_state::init_logicpro()
{
deniam_common_init();
m_bg_scrollx_offs = 0x00d;
m_bg_scrolly_offs = 0x000;
m_fg_scrollx_offs = 0x009;
m_fg_scrolly_offs = 0x000;
}
void deniam_state::init_karianx()
{
deniam_common_init();
m_bg_scrollx_offs = 0x10d;
m_bg_scrolly_offs = 0x080;
m_fg_scrollx_offs = 0x109;
m_fg_scrolly_offs = 0x080;
}
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILEMAP_MAPPER_MEMBER(deniam_state::scan_pages)
{
/* logical (col,row) -> memory offset */
return (col & 0x3f) + ((row & 0x1f) << 6) + ((col & 0x40) << 5) + ((row & 0x20) << 7);
}
TILE_GET_INFO_MEMBER(deniam_state::get_bg_tile_info)
{
const int page = tile_index >> 11;
u16 attr = m_videoram[m_bg_page[page] * 0x0800 + (tile_index & 0x7ff)];
tileinfo.set(0,
attr,
(attr & 0x1fc0) >> 6,
0);
}
TILE_GET_INFO_MEMBER(deniam_state::get_fg_tile_info)
{
const int page = tile_index >> 11;
u16 attr = m_videoram[m_fg_page[page] * 0x0800 + (tile_index & 0x7ff)];
tileinfo.set(0,
attr,
(attr & 0x1fc0) >> 6,
0);
}
TILE_GET_INFO_MEMBER(deniam_state::get_tx_tile_info)
{
u16 attr = m_textram[tile_index];
tileinfo.set(0,
attr & 0xf1ff,
(attr & 0x0e00) >> 9,
0);
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void deniam_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(deniam_state::get_bg_tile_info)), tilemap_mapper_delegate(*this, FUNC(deniam_state::scan_pages)), 8, 8, 128, 64);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(deniam_state::get_fg_tile_info)), tilemap_mapper_delegate(*this, FUNC(deniam_state::scan_pages)), 8, 8, 128, 64);
m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(deniam_state::get_tx_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
m_fg_tilemap->set_transparent_pen(0);
m_tx_tilemap->set_transparent_pen(0);
}
/***************************************************************************
Memory handlers
***************************************************************************/
void deniam_state::videoram_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_videoram[offset]);
const int page = offset >> 11;
for (int i = 0; i < 4; i++)
{
if (m_bg_page[i] == page)
m_bg_tilemap->mark_tile_dirty(i * 0x800 + (offset & 0x7ff));
if (m_fg_page[i] == page)
m_fg_tilemap->mark_tile_dirty(i * 0x800 + (offset & 0x7ff));
}
}
void deniam_state::textram_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_textram[offset]);
m_tx_tilemap->mark_tile_dirty(offset);
}
u16 deniam_state::coinctrl_r()
{
return m_coinctrl;
}
void deniam_state::coinctrl_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_coinctrl);
/* bit 0 is coin counter */
machine().bookkeeping().coin_counter_w(0, m_coinctrl & 0x01);
/* bit 6 is display enable (0 freezes screen) */
m_display_enable = m_coinctrl & 0x20;
/* other bits unknown (unused?) */
}
/***************************************************************************
Display refresh
***************************************************************************/
/*
* Sprite Format
* ------------------
*
* Word | Bit(s) | Use
* -----+-fedcba9876543210-+----------------
* 0 | --------xxxxxxxx | display y start
* 0 | xxxxxxxx-------- | display y end
* 2 | -------xxxxxxxxx | x position
* 2 | ------x--------- | unknown (used in logicpr2, maybe just a bug?)
* 2 | xxxxxx---------- | unused?
* 4 | ---------xxxxxxx | width
* 4 | --------x------- | is this flip y like in System 16?
* 4 | -------x-------- | flip x
* 4 | xxxxxxx--------- | unused?
* 6 | xxxxxxxxxxxxxxxx | ROM address low bits
* 8 | ----------xxxxxx | color
* 8 | --------xx------ | priority
* 8 | ---xxxxx-------- | ROM address high bits
* 8 | xxx------------- | unused? (extra address bits for larger ROMs?)
* a | ---------------- | zoomx like in System 16?
* c | ---------------- | zoomy like in System 16?
* e | ---------------- |
*/
void deniam_state::draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect )
{
for (int offs = m_spriteram.bytes() / 2 - 8; offs >= 0; offs -= 8)
{
u8 *rom = m_spritegfx->base();
int sx = (m_spriteram[offs + 1] & 0x01ff) + 16 * 8 - 1;
if (sx >= 512) sx -= 512;
const int starty = m_spriteram[offs + 0] & 0xff;
const int endy = m_spriteram[offs + 0] >> 8;
const int width = m_spriteram[offs + 2] & 0x007f;
bool flipx = m_spriteram[offs + 2] & 0x0100;
if (flipx) sx++;
const u32 color = 0x40 + (m_spriteram[offs + 4] & 0x3f);
int primask = 8;
switch (m_spriteram[offs + 4] & 0xc0)
{
case 0x00: primask |= 4 | 2 | 1; break; /* below everything */
case 0x40: primask |= 4 | 2; break; /* below fg and tx */
case 0x80: primask |= 4; break; /* below tx */
case 0xc0: break; /* above everything */
}
const int start = m_spriteram[offs + 3] + ((m_spriteram[offs + 4] & 0x1f00) << 8);
rom += 2 * start;
for (int y = starty + 1; y <= endy; y++)
{
bool drawing = false;
int i = 0;
rom += 2 * width; /* note that the first line is skipped */
int x = 0;
while (i < 512) /* safety check */
{
if (flipx)
{
if ((rom[i] & 0x0f) == 0x0f)
{
if (!drawing) drawing = true;
else break;
}
else
{
if (rom[i] & 0x0f)
{
if (cliprect.contains(sx + x, y))
{
if ((screen.priority().pix(y, sx + x) & primask) == 0)
bitmap.pix(y, sx + x) = color * 16 + (rom[i] & 0x0f);
screen.priority().pix(y, sx + x) = 8;
}
}
x++;
}
if ((rom[i] & 0xf0) == 0xf0)
{
if (!drawing) drawing = true;
else break;
}
else
{
if (rom[i] & 0xf0)
{
if (cliprect.contains(sx + x, y))
{
if ((screen.priority().pix(y, sx + x) & primask) == 0)
bitmap.pix(y, sx + x) = color * 16+(rom[i] >> 4);
screen.priority().pix(y, sx + x) = 8;
}
}
x++;
}
i--;
}
else
{
if ((rom[i] & 0xf0) == 0xf0)
{
if (!drawing) drawing = true;
else break;
}
else
{
if (rom[i] & 0xf0)
{
if (cliprect.contains(sx + x, y))
{
if ((screen.priority().pix(y, sx + x) & primask) == 0)
bitmap.pix(y, sx + x) = color * 16 + (rom[i] >> 4);
screen.priority().pix(y, sx + x) = 8;
}
}
x++;
}
if ((rom[i] & 0x0f) == 0x0f)
{
if (!drawing) drawing = true;
else break;
}
else
{
if (rom[i] & 0x0f)
{
if (cliprect.contains(sx + x, y))
{
if ((screen.priority().pix(y, sx + x) & primask) == 0)
bitmap.pix(y, sx + x) = color * 16 + (rom[i] & 0x0f);
screen.priority().pix(y, sx + x) = 8;
}
}
x++;
}
i++;
}
}
}
}
}
void deniam_state::set_bg_page( int page, int value )
{
if (m_bg_page[page] != value)
{
m_bg_page[page] = value;
for (int tile_index = page * 0x800; tile_index < (page + 1) * 0x800; tile_index++)
m_bg_tilemap->mark_tile_dirty(tile_index);
}
}
void deniam_state::set_fg_page( int page, int value )
{
if (m_fg_page[page] != value)
{
m_fg_page[page] = value;
for (int tile_index = page * 0x800; tile_index < (page + 1) * 0x800; tile_index++)
m_fg_tilemap->mark_tile_dirty(tile_index);
}
}
u32 deniam_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int page;
if (!m_display_enable)
{
bitmap.fill(m_palette->black_pen(), cliprect);
return 0; /* don't update (freeze display) */
}
int bg_scrollx = m_textram[m_bg_scrollx_reg] - m_bg_scrollx_offs;
int bg_scrolly = (m_textram[m_bg_scrolly_reg] & 0xff) - m_bg_scrolly_offs;
page = m_textram[m_bg_page_reg];
set_bg_page(3, (page >>12) & 0x0f);
set_bg_page(2, (page >> 8) & 0x0f);
set_bg_page(1, (page >> 4) & 0x0f);
set_bg_page(0, (page >> 0) & 0x0f);
int fg_scrollx = m_textram[m_fg_scrollx_reg] - m_fg_scrollx_offs;
int fg_scrolly = (m_textram[m_fg_scrolly_reg] & 0xff) - m_fg_scrolly_offs;
page = m_textram[m_fg_page_reg];
set_fg_page(3, (page >>12) & 0x0f);
set_fg_page(2, (page >> 8) & 0x0f);
set_fg_page(1, (page >> 4) & 0x0f);
set_fg_page(0, (page >> 0) & 0x0f);
m_bg_tilemap->set_scrollx(0, bg_scrollx & 0x1ff);
m_bg_tilemap->set_scrolly(0, bg_scrolly & 0x0ff);
m_fg_tilemap->set_scrollx(0, fg_scrollx & 0x1ff);
m_fg_tilemap->set_scrolly(0, fg_scrolly & 0x0ff);
screen.priority().fill(0, cliprect);
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 1);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 2);
m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 4);
draw_sprites(screen, bitmap, cliprect);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria
// copyright-holders: Nicola Salmoria
/********************************************************
KO Punch (c) 1981 Sega
@ -32,12 +33,195 @@
********************************************************/
#include "emu.h"
#include "kopunch.h"
#include "cpu/i8085/i8085.h"
#include "machine/i8255.h"
#include "screen.h"
#include "emupal.h"
#include "screen.h"
#include "tilemap.h"
// configurable logging
#define LOG_PORT34 (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_PORT34)
#include "logmacro.h"
#define LOGPORT34(...) LOGMASKED(LOG_PORT34, __VA_ARGS__)
namespace {
class kopunch_state : public driver_device
{
public:
kopunch_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_gfxdecode(*this, "gfxdecode")
, m_vram_fg(*this, "vram_fg")
, m_vram_bg(*this, "vram_bg")
, m_system(*this, "SYSTEM")
, m_lamp(*this, "lamp0")
{ }
void kopunch(machine_config &config);
DECLARE_INPUT_CHANGED_MEMBER(left_coin_inserted);
DECLARE_INPUT_CHANGED_MEMBER(right_coin_inserted);
protected:
virtual void machine_start() override;
virtual void video_start() override;
private:
uint8_t sensors1_r();
uint8_t sensors2_r();
void lamp_w(uint8_t data);
void coin_w(uint8_t data);
void vram_fg_w(offs_t offset, uint8_t data);
void vram_bg_w(offs_t offset, uint8_t data);
void scroll_x_w(uint8_t data);
void scroll_y_w(uint8_t data);
void gfxbank_w(uint8_t data);
TILE_GET_INFO_MEMBER(get_fg_tile_info);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void io_map(address_map &map);
void prg_map(address_map &map);
// devices
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
// memory pointers
required_shared_ptr<uint8_t> m_vram_fg;
required_shared_ptr<uint8_t> m_vram_bg;
required_ioport m_system;
output_finder<> m_lamp;
// video-related
tilemap_t *m_bg_tilemap = nullptr;
tilemap_t *m_fg_tilemap = nullptr;
uint8_t m_gfxbank = 0U;
uint8_t m_scrollx = 0U;
};
// video
void kopunch_state::palette(palette_device &palette) const
{
const uint8_t *color_prom = memregion("proms")->base();
color_prom += 24; // first 24 colors are black
for (int i = 0; i < palette.entries(); i++)
{
int bit0, bit1, bit2;
// red component
bit0 = BIT(*color_prom, 0);
bit1 = BIT(*color_prom, 1);
bit2 = BIT(*color_prom, 2);
int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// green component
bit0 = BIT(*color_prom, 3);
bit1 = BIT(*color_prom, 4);
bit2 = BIT(*color_prom, 5);
int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// blue component
bit0 = 0;
bit1 = BIT(*color_prom, 6);
bit2 = BIT(*color_prom, 7);
int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
palette.set_pen_color(i, rgb_t(r, g, b));
color_prom++;
}
}
void kopunch_state::vram_fg_w(offs_t offset, uint8_t data)
{
m_vram_fg[offset] = data;
m_fg_tilemap->mark_tile_dirty(offset);
}
void kopunch_state::vram_bg_w(offs_t offset, uint8_t data)
{
m_vram_bg[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void kopunch_state::scroll_x_w(uint8_t data)
{
m_scrollx = data;
m_bg_tilemap->set_scrollx(0, data);
}
void kopunch_state::scroll_y_w(uint8_t data)
{
m_bg_tilemap->set_scrolly(0, data);
}
void kopunch_state::gfxbank_w(uint8_t data)
{
// d0-d2: bg gfx bank
if (m_gfxbank != (data & 0x07))
{
m_gfxbank = data & 0x07;
m_bg_tilemap->mark_all_dirty();
}
// d3: flip y, other bits: N/C
m_bg_tilemap->set_flip((data & 0x08) ? TILEMAP_FLIPY : 0);
}
TILE_GET_INFO_MEMBER(kopunch_state::get_fg_tile_info)
{
int const code = m_vram_fg[tile_index];
tileinfo.set(0, code, 0, 0);
}
TILE_GET_INFO_MEMBER(kopunch_state::get_bg_tile_info)
{
// note: highest bit is unused
int const code = (m_vram_bg[tile_index] & 0x7f) | m_gfxbank << 7;
tileinfo.set(1, code, 0, 0);
}
void kopunch_state::video_start()
{
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(kopunch_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(kopunch_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
m_fg_tilemap->set_transparent_pen(0);
}
uint32_t kopunch_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0, cliprect);
// background does not wrap around horizontally
rectangle bg_clip = cliprect;
bg_clip.max_x = m_scrollx ^ 0xff;
m_bg_tilemap->draw(screen, bitmap, bg_clip, 0, 0);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
// machine
/********************************************************
@ -66,17 +250,17 @@ INPUT_CHANGED_MEMBER(kopunch_state::right_coin_inserted)
********************************************************/
void kopunch_state::kopunch_map(address_map &map)
void kopunch_state::prg_map(address_map &map)
{
map(0x0000, 0x1fff).rom();
map(0x2000, 0x23ff).ram();
map(0x6000, 0x63ff).ram().w(FUNC(kopunch_state::vram_fg_w)).share("vram_fg");
map(0x7000, 0x70ff).ram().w(FUNC(kopunch_state::vram_bg_w)).share("vram_bg");
map(0x6000, 0x63ff).ram().w(FUNC(kopunch_state::vram_fg_w)).share(m_vram_fg);
map(0x7000, 0x70ff).ram().w(FUNC(kopunch_state::vram_bg_w)).share(m_vram_bg);
map(0x7100, 0x73ff).ram(); // unused vram
map(0x7400, 0x7bff).ram(); // more unused vram? or accidental writes?
}
void kopunch_state::kopunch_io_map(address_map &map)
void kopunch_state::io_map(address_map &map)
{
map(0x30, 0x33).rw("ppi8255_0", FUNC(i8255_device::read), FUNC(i8255_device::write));
map(0x34, 0x37).rw("ppi8255_1", FUNC(i8255_device::read), FUNC(i8255_device::write));
@ -106,7 +290,7 @@ uint8_t kopunch_state::sensors2_r()
// d5: unknown sensor
// d6: unknown sensor
// d7: coin 1
return (machine().rand() & 0x07) | ioport("SYSTEM")->read();
return (machine().rand() & 0x07) | m_system->read();
}
void kopunch_state::lamp_w(uint8_t data)
@ -122,8 +306,8 @@ void kopunch_state::coin_w(uint8_t data)
if (!BIT(data, 6))
m_maincpu->set_input_line(I8085_RST55_LINE, CLEAR_LINE);
// if ((data & 0x3f) != 0x3e)
// printf("port 34 = %02x ",data);
if ((data & 0x3f) != 0x3e)
LOGPORT34("port 34 = %02x ", data);
}
/********************************************************
@ -141,7 +325,7 @@ static INPUT_PORTS_START( kopunch )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON5 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON6 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON7 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) // related to above startbuttons
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) // related to above start buttons
PORT_START("SYSTEM")
PORT_BIT( 0x07, IP_ACTIVE_HIGH, IPT_CUSTOM ) // punch strength (high 3 bits)
@ -212,8 +396,8 @@ static const gfx_layout bg_layout =
};
static GFXDECODE_START( gfx_kopunch )
GFXDECODE_ENTRY( "gfx1", 0, fg_layout, 0, 1 )
GFXDECODE_ENTRY( "gfx2", 0, bg_layout, 0, 1 )
GFXDECODE_ENTRY( "fgtiles", 0, fg_layout, 0, 1 )
GFXDECODE_ENTRY( "bgtiles", 0, bg_layout, 0, 1 )
GFXDECODE_END
@ -232,10 +416,10 @@ void kopunch_state::machine_start()
void kopunch_state::kopunch(machine_config &config)
{
/* basic machine hardware */
I8085A(config, m_maincpu, 4000000); // 4 MHz?
m_maincpu->set_addrmap(AS_PROGRAM, &kopunch_state::kopunch_map);
m_maincpu->set_addrmap(AS_IO, &kopunch_state::kopunch_io_map);
// basic machine hardware
I8085A(config, m_maincpu, 4'000'000); // 4 MHz?
m_maincpu->set_addrmap(AS_PROGRAM, &kopunch_state::prg_map);
m_maincpu->set_addrmap(AS_IO, &kopunch_state::io_map);
i8255_device &ppi0(I8255A(config, "ppi8255_0"));
// $30 - always $9b (PPI mode 0, ports A & B & C as input)
@ -262,20 +446,20 @@ void kopunch_state::kopunch(machine_config &config)
ppi3.in_pc_callback().set_ioport("P2");
ppi3.out_pc_callback().set(FUNC(kopunch_state::gfxbank_w));
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(32*8, 32*8);
screen.set_visarea(0*8, 32*8-1, 2*8, 28*8-1);
screen.set_screen_update(FUNC(kopunch_state::screen_update_kopunch));
screen.set_screen_update(FUNC(kopunch_state::screen_update));
screen.set_palette("palette");
screen.screen_vblank().set_inputline(m_maincpu, I8085_RST75_LINE);
GFXDECODE(config, m_gfxdecode, "palette", gfx_kopunch);
PALETTE(config, "palette", FUNC(kopunch_state::kopunch_palette), 8);
PALETTE(config, "palette", FUNC(kopunch_state::palette), 8);
/* sound hardware */
// sound hardware
// ...
}
@ -292,12 +476,12 @@ ROM_START( kopunch )
ROM_LOAD( "epr1105.x", 0x0000, 0x1000, CRC(34ef5e79) SHA1(2827c68f4c902f447a304d3ab0258c7819a0e4ca) )
ROM_LOAD( "epr1106.x", 0x1000, 0x1000, CRC(25a5c68b) SHA1(9761418c6f3903f8aaceece658739fe5bf5c0803) )
ROM_REGION( 0x1800, "gfx1", 0 )
ROM_REGION( 0x1800, "fgtiles", 0 )
ROM_LOAD( "epr1103", 0x0000, 0x0800, CRC(bae5e054) SHA1(95373123ab64543cdffb7ee9e02d0613c5c494bf) )
ROM_LOAD( "epr1104", 0x0800, 0x0800, CRC(7b119a0e) SHA1(454f01355fa9512a7442990cc92da7bc7a8d6b68) )
ROM_LOAD( "epr1102", 0x1000, 0x0800, CRC(8a52de96) SHA1(5abdaa83c6bfea81395cb190f5364b72811927ba) )
ROM_REGION( 0x6000, "gfx2", 0 )
ROM_REGION( 0x6000, "bgtiles", 0 )
ROM_LOAD( "epr1107", 0x0000, 0x1000, CRC(ca00244d) SHA1(690931ea1bef9d80dcd7bd2ea2462b083c884a89) )
ROM_LOAD( "epr1108", 0x1000, 0x1000, CRC(cc17c5ed) SHA1(693df076e16cc3a3dd54f6680691e658da3942fe) )
ROM_LOAD( "epr1110", 0x2000, 0x1000, CRC(ae0aff15) SHA1(7f71c94bacdb444e5ed4f917c5a7de17012027a9) )
@ -306,10 +490,12 @@ ROM_START( kopunch )
ROM_LOAD( "epr1111", 0x5000, 0x1000, CRC(28530ec9) SHA1(1a8782d37128cdb43133fc891cde93d2bdd5476b) )
ROM_REGION( 0x0060, "proms", 0 )
ROM_LOAD( "epr1101", 0x0000, 0x0020, CRC(15600f5d) SHA1(130179f79761cb16316c544e3c689bc10431db30) ) /* palette */
ROM_LOAD( "epr1099", 0x0020, 0x0020, CRC(fc58c456) SHA1(f27c3ad669dfdc33bcd7e0481fa01bf34973e816) ) /* unknown */
ROM_LOAD( "epr1100", 0x0040, 0x0020, CRC(bedb66b1) SHA1(8e78bb205d900075b761e1baa5f5813174ff28ba) ) /* unknown */
ROM_LOAD( "epr1101", 0x0000, 0x0020, CRC(15600f5d) SHA1(130179f79761cb16316c544e3c689bc10431db30) ) // palette
ROM_LOAD( "epr1099", 0x0020, 0x0020, CRC(fc58c456) SHA1(f27c3ad669dfdc33bcd7e0481fa01bf34973e816) ) // unknown
ROM_LOAD( "epr1100", 0x0040, 0x0020, CRC(bedb66b1) SHA1(8e78bb205d900075b761e1baa5f5813174ff28ba) ) // unknown
ROM_END
} // anonymous namespace
GAME( 1981, kopunch, 0, kopunch, kopunch, kopunch_state, empty_init, ROT270, "Sega", "KO Punch", MACHINE_NO_SOUND | MACHINE_NOT_WORKING | MACHINE_MECHANICAL | MACHINE_SUPPORTS_SAVE )

View File

@ -1,72 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria
/*************************************************************************
Sega KO Punch
*************************************************************************/
#ifndef MAME_INCLUDES_KOPUNCH_H
#define MAME_INCLUDES_KOPUNCH_H
#pragma once
#include "emupal.h"
#include "tilemap.h"
class kopunch_state : public driver_device
{
public:
kopunch_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_gfxdecode(*this, "gfxdecode")
, m_vram_fg(*this, "vram_fg")
, m_vram_bg(*this, "vram_bg")
, m_lamp(*this, "lamp0")
{ }
void kopunch(machine_config &config);
DECLARE_INPUT_CHANGED_MEMBER(left_coin_inserted);
DECLARE_INPUT_CHANGED_MEMBER(right_coin_inserted);
private:
uint8_t sensors1_r();
uint8_t sensors2_r();
void lamp_w(uint8_t data);
void coin_w(uint8_t data);
void vram_fg_w(offs_t offset, uint8_t data);
void vram_bg_w(offs_t offset, uint8_t data);
void scroll_x_w(uint8_t data);
void scroll_y_w(uint8_t data);
void gfxbank_w(uint8_t data);
TILE_GET_INFO_MEMBER(get_fg_tile_info);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
void kopunch_palette(palette_device &palette) const;
uint32_t screen_update_kopunch(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void kopunch_io_map(address_map &map);
void kopunch_map(address_map &map);
virtual void machine_start() override;
virtual void video_start() override;
/* devices */
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
/* memory pointers */
required_shared_ptr<uint8_t> m_vram_fg;
required_shared_ptr<uint8_t> m_vram_bg;
output_finder<> m_lamp;
/* video-related */
tilemap_t *m_bg_tilemap = nullptr;
tilemap_t *m_fg_tilemap = nullptr;
uint8_t m_gfxbank = 0U;
uint8_t m_scrollx = 0U;
};
#endif // MAME_INCLUDES_KOPUNCH_H

View File

@ -1,117 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria
/*************************************************************************
Sega KO Punch
Functions to emulate the video hardware of the machine.
*************************************************************************/
#include "emu.h"
#include "kopunch.h"
void kopunch_state::kopunch_palette(palette_device &palette) const
{
const uint8_t *color_prom = memregion("proms")->base();
color_prom += 24; // first 24 colors are black
for (int i = 0; i < palette.entries(); i++)
{
int bit0, bit1, bit2;
// red component
bit0 = BIT(*color_prom, 0);
bit1 = BIT(*color_prom, 1);
bit2 = BIT(*color_prom, 2);
int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// green component
bit0 = BIT(*color_prom, 3);
bit1 = BIT(*color_prom, 4);
bit2 = BIT(*color_prom, 5);
int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// blue component
bit0 = 0;
bit1 = BIT(*color_prom, 6);
bit2 = BIT(*color_prom, 7);
int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
palette.set_pen_color(i, rgb_t(r, g, b));
color_prom++;
}
}
void kopunch_state::vram_fg_w(offs_t offset, uint8_t data)
{
m_vram_fg[offset] = data;
m_fg_tilemap->mark_tile_dirty(offset);
}
void kopunch_state::vram_bg_w(offs_t offset, uint8_t data)
{
m_vram_bg[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void kopunch_state::scroll_x_w(uint8_t data)
{
m_scrollx = data;
m_bg_tilemap->set_scrollx(0, data);
}
void kopunch_state::scroll_y_w(uint8_t data)
{
m_bg_tilemap->set_scrolly(0, data);
}
void kopunch_state::gfxbank_w(uint8_t data)
{
// d0-d2: bg gfx bank
if (m_gfxbank != (data & 0x07))
{
m_gfxbank = data & 0x07;
m_bg_tilemap->mark_all_dirty();
}
// d3: flip y, other bits: N/C
m_bg_tilemap->set_flip((data & 0x08) ? TILEMAP_FLIPY : 0);
}
TILE_GET_INFO_MEMBER(kopunch_state::get_fg_tile_info)
{
int code = m_vram_fg[tile_index];
tileinfo.set(0, code, 0, 0);
}
TILE_GET_INFO_MEMBER(kopunch_state::get_bg_tile_info)
{
// note: highest bit is unused
int code = (m_vram_bg[tile_index] & 0x7f) | m_gfxbank << 7;
tileinfo.set(1, code, 0, 0);
}
void kopunch_state::video_start()
{
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(kopunch_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(kopunch_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
m_fg_tilemap->set_transparent_pen(0);
}
uint32_t kopunch_state::screen_update_kopunch(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0, cliprect);
// background does not wrap around horizontally
rectangle bg_clip = cliprect;
bg_clip.max_x = m_scrollx ^ 0xff;
m_bg_tilemap->draw(screen, bitmap, bg_clip, 0, 0);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Frank Palazzolo
// copyright-holders: Frank Palazzolo
/****************************************************************************
Sega "Space Tactics" Driver
@ -43,12 +44,531 @@ Verify Color PROM resistor values (Last 8 colors)
****************************************************************************/
#include "emu.h"
#include "stactics.h"
#include "stactics.lh"
#include "cpu/i8085/i8085.h"
#include "machine/74259.h"
#include "emupal.h"
#include "screen.h"
namespace {
class stactics_state : public driver_device
{
public:
stactics_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_outlatch(*this, "outlatch"),
m_display_buffer(*this, "display_buffer"),
m_videoram_b(*this, "videoram_b"),
m_videoram_d(*this, "videoram_d"),
m_videoram_e(*this, "videoram_e"),
m_videoram_f(*this, "videoram_f"),
m_beam_region(*this, "beam"),
m_base_lamps(*this, "base_lamp%u", 0U),
m_beam_leds_left(*this, "beam_led_left%u", 0U),
m_beam_leds_right(*this, "beam_led_right%u", 0U),
m_score_digits(*this, "digit%u", 0U),
m_credit_leds(*this, "credit_led%u", 0U),
m_barrier_leds(*this, "barrier_led%u", 0U),
m_round_leds(*this, "round_led%u", 0U),
m_barrier_lamp(*this, "barrier_lamp"),
m_start_lamp(*this, "start_lamp"),
m_sight_led(*this, "sight_led"),
m_in3(*this, "IN3"),
m_fake(*this, "FAKE")
{ }
void stactics(machine_config &config);
DECLARE_READ_LINE_MEMBER(frame_count_d3_r);
DECLARE_READ_LINE_MEMBER(shot_standby_r);
DECLARE_READ_LINE_MEMBER(not_shot_arrive_r);
DECLARE_READ_LINE_MEMBER(motor_not_ready_r);
DECLARE_CUSTOM_INPUT_MEMBER(get_rng);
protected:
virtual void machine_start() override;
virtual void video_start() override;
private:
uint8_t vert_pos_r();
uint8_t horiz_pos_r();
template <uint8_t Which> DECLARE_WRITE_LINE_MEMBER(coin_lockout_w);
DECLARE_WRITE_LINE_MEMBER(palette_bank_w);
void scroll_ram_w(offs_t offset, uint8_t data);
void speed_latch_w(uint8_t data);
void shot_trigger_w(uint8_t data);
void shot_flag_clear_w(uint8_t data);
DECLARE_WRITE_LINE_MEMBER(motor_w);
INTERRUPT_GEN_MEMBER(interrupt);
DECLARE_WRITE_LINE_MEMBER(barrier_lamp_w);
DECLARE_WRITE_LINE_MEMBER(start_lamp_w);
template <unsigned N> DECLARE_WRITE_LINE_MEMBER(base_lamp_w) { m_base_lamps[N] = state; }
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void update_beam();
inline int get_pixel_on_plane(uint8_t *videoram, uint8_t y, uint8_t x, uint8_t y_scroll);
void draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect);
template <unsigned N> void set_indicator_leds(unsigned offset, output_finder<N> &outputs, int base_index);
void update_artwork();
void move_motor();
void main_map(address_map &map);
required_device<cpu_device> m_maincpu;
required_device<ls259_device> m_outlatch;
required_shared_ptr<uint8_t> m_display_buffer;
required_shared_ptr<uint8_t> m_videoram_b;
required_shared_ptr<uint8_t> m_videoram_d;
required_shared_ptr<uint8_t> m_videoram_e;
required_shared_ptr<uint8_t> m_videoram_f;
required_region_ptr<uint8_t> m_beam_region;
output_finder<5> m_base_lamps;
output_finder<0x40> m_beam_leds_left;
output_finder<0x40> m_beam_leds_right;
output_finder<6> m_score_digits;
output_finder<8> m_credit_leds;
output_finder<12> m_barrier_leds;
output_finder<16> m_round_leds;
output_finder<> m_barrier_lamp;
output_finder<> m_start_lamp;
output_finder<> m_sight_led;
required_ioport m_in3;
required_ioport m_fake;
// machine state
int32_t m_vert_pos = 0;
int32_t m_horiz_pos = 0;
bool m_motor_on = false;
// video state
uint8_t m_y_scroll_d = 0;
uint8_t m_y_scroll_e = 0;
uint8_t m_y_scroll_f = 0;
uint8_t m_frame_count = 0;
uint8_t m_shot_standby = 0;
uint8_t m_shot_arrive = 0;
uint16_t m_beam_state = 0;
uint16_t m_old_beam_state = 0;
uint16_t m_beam_states_per_frame = 0;
uint8_t m_palette_bank = 0;
};
// video
/****************************************************************************
The Video system used in Space Tactics is unusual.
Here are my notes on how the video system works:
There are 4, 4K pages of Video RAM. (B,D,E & F)
The first 1K of each VRAM page contains the following:
0 0 V V V V V H H H H H offset value for each 8x8 bitmap
(v-tile) (h-tile)
The offset values are used to generate an access into the
last 2K of the VRAM page:
1 D D D D D D D D V V V here we find 8x8 character data
(offset) (line)
In addition, in Page B, the upper nibble of the offset is
also used to select the color palette for the tile.
Page B, D, E, and F all work similarly, except that pages
D, E, and F can be offset from Page B by a given
number of scanlines, based on the contents of the offset
RAM
The offset RAM is addressed in this format:
1 0 0 0 P P P V V V V V V V V V
(Page) (scanline)
Page 4=D, 5=E, 6=F
Page D, E, and F are drawn offset from the top of the screen,
starting on the first scanline which contains a 1 in the
appropriate memory location
---
The composited monitor image is seen in a mirror. It appears
to move when the player moves the handle, due to motors which
tilt the mirror up and down, and the monitor left and right.
---
***************************************************************************/
/*************************************
*
* Palette
*
*************************************/
void stactics_state::palette(palette_device &palette) const
{
uint8_t const *const color_prom = memregion("proms")->base();
for (int i = 0; i < 0x400; i++)
{
int const bit0 = BIT(color_prom[i], 0);
int const bit1 = BIT(color_prom[i], 1);
int const bit2 = BIT(color_prom[i], 2);
int const bit3 = BIT(color_prom[i], 3);
// red component
int const r = 0xff * bit0;
// green component
int const g = 0xff * bit1 - 0xcc * bit3;
// blue component
int const b = 0xff * bit2;
palette.set_pen_color(i, rgb_t(r, g, b));
}
}
WRITE_LINE_MEMBER(stactics_state::palette_bank_w)
{
m_palette_bank = m_outlatch->q6_r() | (m_outlatch->q7_r() << 1);
}
/*************************************
*
* Scrolling
*
*************************************/
void stactics_state::scroll_ram_w(offs_t offset, uint8_t data)
{
if (data & 0x01)
{
switch (offset >> 8)
{
case 4: m_y_scroll_d = offset & 0xff; break;
case 5: m_y_scroll_e = offset & 0xff; break;
case 6: m_y_scroll_f = offset & 0xff; break;
}
}
}
/*************************************
*
* Frane counter
*
*************************************/
READ_LINE_MEMBER(stactics_state::frame_count_d3_r)
{
return (m_frame_count >> 3) & 0x01;
}
/*************************************
*
* Beam handling
*
*************************************/
void stactics_state::speed_latch_w(uint8_t data)
{
/* This writes to a shift register which is clocked by
a 555 oscillator. This value determines the speed of
the LED fire beams as follows:
555_freq / bits_in_SR * edges_in_SR / states_in_PR67 / frame_rate
= num_led_states_per_frame
36439 / 8 * x / 32 / 60 ~= 19/8*x
Here, we will count the number of rising edges in the shift register */
int num_rising_edges = 0;
for (int i = 0; i < 8; i++)
{
if ((((data >> i) & 0x01) == 1) && (((data >> ((i + 1) % 8)) & 0x01) == 0))
num_rising_edges++;
}
m_beam_states_per_frame = num_rising_edges * 19 / 8;
}
void stactics_state::shot_trigger_w(uint8_t data)
{
m_shot_standby = 0;
}
void stactics_state::shot_flag_clear_w(uint8_t data)
{
m_shot_arrive = 0;
}
READ_LINE_MEMBER(stactics_state::shot_standby_r)
{
return m_shot_standby;
}
READ_LINE_MEMBER(stactics_state::not_shot_arrive_r)
{
return !m_shot_arrive;
}
void stactics_state::update_beam()
{
// first, update the firebeam state
m_old_beam_state = m_beam_state;
if (m_shot_standby == 0)
m_beam_state = m_beam_state + m_beam_states_per_frame;
/* These are thresholds for the two shots from the LED fire ROM
(Note: There are two more for sound triggers,
whenever that gets implemented) */
if ((m_old_beam_state < 0x8b) & (m_beam_state >= 0x8b))
m_shot_arrive = 1;
if ((m_old_beam_state < 0xca) & (m_beam_state >= 0xca))
m_shot_arrive = 1;
if (m_beam_state >= 0x100)
{
m_beam_state = 0;
m_shot_standby = 1;
}
}
/*************************************
*
* Video drawing
*
*************************************/
inline int stactics_state::get_pixel_on_plane(uint8_t *videoram, uint8_t y, uint8_t x, uint8_t y_scroll)
{
// compute effective row
y = y - y_scroll;
// get the character code at the given pixel
uint8_t const code = videoram[((y >> 3) << 5) | (x >> 3)];
// get the gfx byte
uint8_t const gfx = videoram[0x800 | (code << 3) | (y & 0x07)];
// return the appropriate pixel within the byte
return (gfx >> (~x & 0x07)) & 0x01;
}
void stactics_state::draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0, cliprect);
// for every row
for (int y = 0; y < 0x100; y++)
{
// for every pixel on the row
for (int x = 0; x < 0x100; x++)
{
// get the pixels for the four planes
int const pixel_b = get_pixel_on_plane(m_videoram_b, y, x, 0);
int const pixel_d = get_pixel_on_plane(m_videoram_d, y, x, m_y_scroll_d);
int const pixel_e = get_pixel_on_plane(m_videoram_e, y, x, m_y_scroll_e);
int const pixel_f = get_pixel_on_plane(m_videoram_f, y, x, m_y_scroll_f);
// get the color for this pixel
uint8_t const color = m_videoram_b[((y >> 3) << 5) | (x >> 3)] >> 4;
// assemble the pen index
int const pen = color |
(pixel_b << 4) |
(pixel_f << 5) |
(pixel_e << 6) |
(pixel_d << 7) |
(m_palette_bank << 8);
/* compute the effective pixel coordinate after adjusting for the
mirror movement - this is mechanical on the real machine */
int const sy = y + m_vert_pos;
int const sx = x - m_horiz_pos;
// plot if visible
if ((sy >= 0) && (sy < 0x100) && (sx >= 0) && (sx < 0x100))
bitmap.pix(sy, sx) = pen;
}
}
}
/*************************************
*
* Non-video artwork
*
*************************************/
// from 7448 datasheet
static constexpr int to_7seg[0x10] =
{
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07,
0x7f, 0x67, 0x58, 0x4c, 0x62, 0x69, 0x78, 0x00
};
template <unsigned N> void stactics_state::set_indicator_leds(unsigned offset, output_finder<N> &outputs, int base_index)
{
// decode the data
int const data = to_7seg[~m_display_buffer[offset] & 0x0f];
// set the 4 LEDs
outputs[base_index + 0] = BIT(data, 2);
outputs[base_index + 1] = BIT(data, 6);
outputs[base_index + 2] = BIT(data, 5);
outputs[base_index + 3] = BIT(data, 4);
}
WRITE_LINE_MEMBER(stactics_state::barrier_lamp_w)
{
// this needs to flash on/off, not implemented
m_barrier_lamp = state;
}
WRITE_LINE_MEMBER(stactics_state::start_lamp_w)
{
m_start_lamp = state;
}
void stactics_state::update_artwork()
{
// laser beam - loop for each LED
for (int i = 0; i < 0x40; i++)
{
offs_t const beam_data_offs = ((i & 0x08) << 7) | ((i & 0x30) << 4) | m_beam_state;
uint8_t const beam_data = m_beam_region[beam_data_offs];
int const on = BIT(beam_data, i & 0x07);
m_beam_leds_left[i] = on;
m_beam_leds_right[i] = on;
}
// sight LED
m_sight_led = m_motor_on;
// score display
for (int i = 0x01; i < 0x07; i++)
m_score_digits[i - 1] = to_7seg[~m_display_buffer[i] & 0x0f];
// credits indicator
set_indicator_leds(0x07, m_credit_leds, 0x00);
set_indicator_leds(0x08, m_credit_leds, 0x04);
// barriers indicator
set_indicator_leds(0x09, m_barrier_leds, 0x00);
set_indicator_leds(0x0a, m_barrier_leds, 0x04);
set_indicator_leds(0x0b, m_barrier_leds, 0x08);
// rounds indicator
set_indicator_leds(0x0c, m_round_leds, 0x00);
set_indicator_leds(0x0d, m_round_leds, 0x04);
set_indicator_leds(0x0e, m_round_leds, 0x08);
set_indicator_leds(0x0f, m_round_leds, 0x0c);
}
/*************************************
*
* Start
*
*************************************/
void stactics_state::video_start()
{
m_base_lamps.resolve();
m_beam_leds_left.resolve();
m_beam_leds_right.resolve();
m_score_digits.resolve();
m_credit_leds.resolve();
m_barrier_leds.resolve();
m_round_leds.resolve();
m_barrier_lamp.resolve();
m_start_lamp.resolve();
m_sight_led.resolve();
m_y_scroll_d = 0;
m_y_scroll_e = 0;
m_y_scroll_f = 0;
m_frame_count = 0;
m_shot_standby = 1;
m_shot_arrive = 0;
m_beam_state = 0;
m_old_beam_state = 0;
m_palette_bank = 0;
save_item(NAME(m_y_scroll_d));
save_item(NAME(m_y_scroll_e));
save_item(NAME(m_y_scroll_f));
save_item(NAME(m_frame_count));
save_item(NAME(m_shot_standby));
save_item(NAME(m_shot_arrive));
save_item(NAME(m_beam_state));
save_item(NAME(m_old_beam_state));
save_item(NAME(m_beam_states_per_frame));
save_item(NAME(m_palette_bank));
}
/*************************************
*
* Update
*
*************************************/
uint32_t stactics_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
update_beam();
draw_background(bitmap, cliprect);
update_artwork();
m_frame_count = (m_frame_count + 1) & 0x0f;
return 0;
}
// machine
/*************************************
*
@ -89,24 +609,24 @@ void stactics_state::move_motor()
const int in3 = m_in3->read();
const int in4 = m_fake->read();
/* up */
// up
if (!(in4 & 0x01) && m_vert_pos > -128)
m_vert_pos--;
/* down */
// down
if (!(in4 & 0x02) && m_vert_pos < 127)
m_vert_pos++;
/* left */
// left
if (!(in3 & 0x20) && m_horiz_pos < 127)
m_horiz_pos++;
/* right */
// right
if (!(in3 & 0x40) && m_horiz_pos > -128)
m_horiz_pos--;
}
/* monitor motor under self-centering control */
// monitor motor under self-centering control
else
{
if (m_horiz_pos > 0)
@ -131,7 +651,7 @@ void stactics_state::move_motor()
CUSTOM_INPUT_MEMBER(stactics_state::get_rng)
{
/* this is a 555 timer, but cannot read one of the resistor values */
// this is a 555 timer, but cannot read one of the resistor values
return machine().rand() & 0x07;
}
@ -143,15 +663,10 @@ CUSTOM_INPUT_MEMBER(stactics_state::get_rng)
*
*************************************/
WRITE_LINE_MEMBER(stactics_state::coin_lockout_1_w)
template <uint8_t Which>
WRITE_LINE_MEMBER(stactics_state::coin_lockout_w)
{
machine().bookkeeping().coin_lockout_w(0, !state);
}
WRITE_LINE_MEMBER(stactics_state::coin_lockout_2_w)
{
machine().bookkeeping().coin_lockout_w(1, !state);
machine().bookkeeping().coin_lockout_w(Which, !state);
}
@ -189,20 +704,20 @@ void stactics_state::main_map(address_map &map)
map(0x6030, 0x6030).mirror(0x0f0f).w(FUNC(stactics_state::speed_latch_w));
map(0x6040, 0x6040).mirror(0x0f0f).w(FUNC(stactics_state::shot_trigger_w));
map(0x6050, 0x6050).mirror(0x0f0f).w(FUNC(stactics_state::shot_flag_clear_w));
map(0x6060, 0x606f).mirror(0x0f00).writeonly().share("display_buffer");
map(0x6060, 0x606f).mirror(0x0f00).writeonly().share(m_display_buffer);
map(0x6070, 0x609f).mirror(0x0f00).nopw();
/* map(0x60a0, 0x60ef).mirror(0x0f00).w(FUNC(stactics_state::sound2_w)); */
// map(0x60a0, 0x60ef).mirror(0x0f00).w(FUNC(stactics_state::sound2_w));
map(0x60f0, 0x60ff).mirror(0x0f00).nopw();
map(0x7000, 0x7000).mirror(0x0fff).portr("IN2");
map(0x8000, 0x8000).mirror(0x0fff).portr("IN3");
map(0x8000, 0x87ff).mirror(0x0800).w(FUNC(stactics_state::scroll_ram_w));
map(0x9000, 0x9000).mirror(0x0fff).r(FUNC(stactics_state::vert_pos_r));
map(0xa000, 0xa000).mirror(0x0fff).r(FUNC(stactics_state::horiz_pos_r));
map(0xb000, 0xbfff).ram().share("videoram_b");
map(0xb000, 0xbfff).ram().share(m_videoram_b);
map(0xc000, 0xcfff).noprw();
map(0xd000, 0xdfff).ram().share("videoram_d");
map(0xe000, 0xefff).ram().share("videoram_e");
map(0xf000, 0xffff).ram().share("videoram_f");
map(0xd000, 0xdfff).ram().share(m_videoram_d);
map(0xe000, 0xefff).ram().share(m_videoram_e);
map(0xf000, 0xffff).ram().share(m_videoram_f);
}
@ -214,7 +729,7 @@ void stactics_state::main_map(address_map &map)
*************************************/
static INPUT_PORTS_START( stactics )
PORT_START("IN0") /* IN0 */
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON7 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON6 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON5 )
@ -224,7 +739,7 @@ static INPUT_PORTS_START( stactics )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(stactics_state, motor_not_ready_r)
PORT_START("IN1") /* IN1 */
PORT_START("IN1")
PORT_DIPNAME( 0x07, 0x07, DEF_STR( Coin_B ) )
PORT_DIPSETTING( 0x01, DEF_STR( 4C_1C ) )
PORT_DIPSETTING( 0x05, DEF_STR( 2C_1C ) )
@ -250,7 +765,7 @@ static INPUT_PORTS_START( stactics )
PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_START("IN2") /* IN2 */
PORT_START("IN2")
PORT_BIT( 0x07, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(stactics_state, get_rng)
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(stactics_state, frame_count_d3_r)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN1 )
@ -260,7 +775,7 @@ static INPUT_PORTS_START( stactics )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_SERVICE( 0x80, IP_ACTIVE_LOW )
PORT_START("IN3") /* IN3 */
PORT_START("IN3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(stactics_state, shot_standby_r)
PORT_DIPNAME( 0x04, 0x04, "Number of Barriers" )
@ -276,7 +791,7 @@ static INPUT_PORTS_START( stactics )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(stactics_state, not_shot_arrive_r)
PORT_START("FAKE") /* FAKE */
PORT_START("FAKE")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY
INPUT_PORTS_END
@ -310,14 +825,14 @@ void stactics_state::machine_start()
void stactics_state::stactics(machine_config &config)
{
/* basic machine hardware */
// basic machine hardware
I8080(config, m_maincpu, 15.46848_MHz_XTAL / 8); // divider not verified
m_maincpu->set_addrmap(AS_PROGRAM, &stactics_state::main_map);
m_maincpu->set_vblank_int("screen", FUNC(stactics_state::interrupt));
LS259(config, m_outlatch); // 50
m_outlatch->q_out_cb<0>().set(FUNC(stactics_state::coin_lockout_1_w)); // COIN REJECT 1
m_outlatch->q_out_cb<1>().set(FUNC(stactics_state::coin_lockout_2_w)); // COIN REJECT 2
m_outlatch->q_out_cb<0>().set(FUNC(stactics_state::coin_lockout_w<0>)); // COIN REJECT 1
m_outlatch->q_out_cb<1>().set(FUNC(stactics_state::coin_lockout_w<1>)); // COIN REJECT 2
m_outlatch->q_out_cb<6>().set(FUNC(stactics_state::palette_bank_w)); // FLM COL 0
m_outlatch->q_out_cb<7>().set(FUNC(stactics_state::palette_bank_w)); // FLM COL 1
@ -340,10 +855,16 @@ void stactics_state::stactics(machine_config &config)
lamplatch.q_out_cb<5>().set(FUNC(stactics_state::start_lamp_w));
lamplatch.q_out_cb<6>().set(FUNC(stactics_state::barrier_lamp_w));
/* video hardware */
stactics_video(config);
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_video_attributes(VIDEO_ALWAYS_UPDATE);
screen.set_raw(15.46848_MHz_XTAL / 3, 328, 0, 256, 262, 0, 232);
screen.set_screen_update(FUNC(stactics_state::screen_update));
screen.set_palette("palette");
/* audio hardware */
PALETTE(config, "palette", FUNC(stactics_state::palette), 0x400);
// audio hardware
}
@ -364,16 +885,17 @@ ROM_START( stactics )
ROM_LOAD( "epr-223x", 0x2800, 0x0800, CRC(7fef0940) SHA1(5b2af55f75ef0130f9202b6a916a96dbd601fcfa) )
ROM_REGION( 0x1040, "proms", 0 )
ROM_LOAD( "pr54", 0x0000, 0x0800, CRC(9640bd6e) SHA1(dd12952a6591f2056ac1b5688dca0a3a2ef69f2d) ) /* color/priority PROM */
ROM_LOAD( "pr55", 0x0800, 0x0800, CRC(f162673b) SHA1(83743780b6c1f8014df24fa0650000b7cb137d92) ) /* timing PROM (unused) */
ROM_LOAD( "pr65", 0x1000, 0x0020, CRC(a1506b9d) SHA1(037c3db2ea40eca459e8acba9d1506dd28d72d10) ) /* timing PROM (unused) */
ROM_LOAD( "pr66", 0x1020, 0x0020, CRC(78dcf300) SHA1(37034cc0cfa4a8ec47937a2a34b77ec56b387a9b) ) /* timing PROM (unused) */
ROM_LOAD( "pr54", 0x0000, 0x0800, CRC(9640bd6e) SHA1(dd12952a6591f2056ac1b5688dca0a3a2ef69f2d) ) // color/priority PROM
ROM_LOAD( "pr55", 0x0800, 0x0800, CRC(f162673b) SHA1(83743780b6c1f8014df24fa0650000b7cb137d92) ) // timing PROM (unused)
ROM_LOAD( "pr65", 0x1000, 0x0020, CRC(a1506b9d) SHA1(037c3db2ea40eca459e8acba9d1506dd28d72d10) ) // timing PROM (unused)
ROM_LOAD( "pr66", 0x1020, 0x0020, CRC(78dcf300) SHA1(37034cc0cfa4a8ec47937a2a34b77ec56b387a9b) ) // timing PROM (unused)
ROM_REGION( 0x0820, "user1", 0 )
ROM_LOAD( "epr-217", 0x0000, 0x0800, CRC(38259f5f) SHA1(1f4182ffc2d78fca22711526bb2ae2cfe040173c) ) /* LED fire beam data */
ROM_LOAD( "pr67", 0x0800, 0x0020, CRC(b27874e7) SHA1(c24bc78c4b2ae01aaed5d994ce2e7c5e0f2eece8) ) /* LED timing ROM (unused) */
ROM_REGION( 0x0820, "beam", 0 )
ROM_LOAD( "epr-217", 0x0000, 0x0800, CRC(38259f5f) SHA1(1f4182ffc2d78fca22711526bb2ae2cfe040173c) ) // LED fire beam data
ROM_LOAD( "pr67", 0x0800, 0x0020, CRC(b27874e7) SHA1(c24bc78c4b2ae01aaed5d994ce2e7c5e0f2eece8) ) // LED timing ROM (unused)
ROM_END
} // anonymous namespace
/*************************************

View File

@ -1,130 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Frank Palazzolo
/****************************************************************************
Sega "Space Tactics" Driver
Frank Palazzolo (palazzol@home.com)
****************************************************************************/
#ifndef MAME_INCLUDES_STACTICS_H
#define MAME_INCLUDES_STACTICS_H
#pragma once
#include "machine/74259.h"
#include "emupal.h"
class stactics_state : public driver_device
{
public:
stactics_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_outlatch(*this, "outlatch"),
m_display_buffer(*this, "display_buffer"),
m_videoram_b(*this, "videoram_b"),
m_videoram_d(*this, "videoram_d"),
m_videoram_e(*this, "videoram_e"),
m_videoram_f(*this, "videoram_f"),
m_base_lamps(*this, "base_lamp%u", 0U),
m_beam_leds_left(*this, "beam_led_left%u", 0U),
m_beam_leds_right(*this, "beam_led_right%u", 0U),
m_score_digits(*this, "digit%u", 0U),
m_credit_leds(*this, "credit_led%u", 0U),
m_barrier_leds(*this, "barrier_led%u", 0U),
m_round_leds(*this, "round_led%u", 0U),
m_barrier_lamp(*this, "barrier_lamp"),
m_start_lamp(*this, "start_lamp"),
m_sight_led(*this, "sight_led"),
m_in3(*this, "IN3"),
m_fake(*this, "FAKE")
{ }
void stactics(machine_config &config);
DECLARE_READ_LINE_MEMBER(frame_count_d3_r);
DECLARE_READ_LINE_MEMBER(shot_standby_r);
DECLARE_READ_LINE_MEMBER(not_shot_arrive_r);
DECLARE_READ_LINE_MEMBER(motor_not_ready_r);
DECLARE_CUSTOM_INPUT_MEMBER(get_rng);
private:
uint8_t vert_pos_r();
uint8_t horiz_pos_r();
DECLARE_WRITE_LINE_MEMBER(coin_lockout_1_w);
DECLARE_WRITE_LINE_MEMBER(coin_lockout_2_w);
DECLARE_WRITE_LINE_MEMBER(palette_bank_w);
void scroll_ram_w(offs_t offset, uint8_t data);
void speed_latch_w(uint8_t data);
void shot_trigger_w(uint8_t data);
void shot_flag_clear_w(uint8_t data);
DECLARE_WRITE_LINE_MEMBER(motor_w);
INTERRUPT_GEN_MEMBER(interrupt);
DECLARE_WRITE_LINE_MEMBER(barrier_lamp_w);
DECLARE_WRITE_LINE_MEMBER(start_lamp_w);
template <unsigned N> DECLARE_WRITE_LINE_MEMBER(base_lamp_w) { m_base_lamps[N] = state; }
DECLARE_WRITE_LINE_MEMBER(base_2_lamp_w);
DECLARE_WRITE_LINE_MEMBER(base_3_lamp_w);
DECLARE_WRITE_LINE_MEMBER(base_4_lamp_w);
DECLARE_WRITE_LINE_MEMBER(base_5_lamp_w);
virtual void machine_start() override;
virtual void video_start() override;
void stactics_palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void update_beam();
inline int get_pixel_on_plane(uint8_t *videoram, uint8_t y, uint8_t x, uint8_t y_scroll);
void draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect);
template <unsigned N> void set_indicator_leds(unsigned offset, output_finder<N> &outputs, int base_index);
void update_artwork();
void move_motor();
void stactics_video(machine_config &config);
void main_map(address_map &map);
required_device<cpu_device> m_maincpu;
required_device<ls259_device> m_outlatch;
required_shared_ptr<uint8_t> m_display_buffer;
required_shared_ptr<uint8_t> m_videoram_b;
required_shared_ptr<uint8_t> m_videoram_d;
required_shared_ptr<uint8_t> m_videoram_e;
required_shared_ptr<uint8_t> m_videoram_f;
output_finder<5> m_base_lamps;
output_finder<0x40> m_beam_leds_left;
output_finder<0x40> m_beam_leds_right;
output_finder<6> m_score_digits;
output_finder<8> m_credit_leds;
output_finder<12> m_barrier_leds;
output_finder<16> m_round_leds;
output_finder<> m_barrier_lamp;
output_finder<> m_start_lamp;
output_finder<> m_sight_led;
required_ioport m_in3;
required_ioport m_fake;
/* machine state */
int m_vert_pos = 0;
int m_horiz_pos = 0;
bool m_motor_on = false;
/* video state */
uint8_t m_y_scroll_d = 0;
uint8_t m_y_scroll_e = 0;
uint8_t m_y_scroll_f = 0;
uint8_t m_frame_count = 0;
uint8_t m_shot_standby = 0;
uint8_t m_shot_arrive = 0;
uint16_t m_beam_state = 0;
uint16_t m_old_beam_state = 0;
uint16_t m_beam_states_per_frame = 0;
uint8_t m_palette_bank = 0;
};
#endif // MAME_INCLUDES_STACTICS_H

View File

@ -1,431 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Frank Palazzolo
/****************************************************************************
Sega "Space Tactics" Driver
Frank Palazzolo (palazzol@home.com)
The Video system used in Space Tactics is unusual.
Here are my notes on how the video system works:
There are 4, 4K pages of Video RAM. (B,D,E & F)
The first 1K of each VRAM page contains the following:
0 0 V V V V V H H H H H offset value for each 8x8 bitmap
(v-tile) (h-tile)
The offset values are used to generate an access into the
last 2K of the VRAM page:
1 D D D D D D D D V V V here we find 8x8 character data
(offset) (line)
In addition, in Page B, the upper nibble of the offset is
also used to select the color palette for the tile.
Page B, D, E, and F all work similarly, except that pages
D, E, and F can be offset from Page B by a given
number of scanlines, based on the contents of the offset
RAM
The offset RAM is addressed in this format:
1 0 0 0 P P P V V V V V V V V V
(Page) (scanline)
Page 4=D, 5=E, 6=F
Page D, E, and F are drawn offset from the top of the screen,
starting on the first scanline which contains a 1 in the
appropriate memory location
---
The composited monitor image is seen in a mirror. It appears
to move when the player moves the handle, due to motors which
tilt the mirror up and down, and the monitor left and right.
---
***************************************************************************/
#include "emu.h"
#include "stactics.h"
#include "screen.h"
/*************************************
*
* Palette
*
*************************************/
void stactics_state::stactics_palette(palette_device &palette) const
{
uint8_t const *const color_prom = memregion("proms")->base();
for (int i = 0; i < 0x400; i++)
{
int const bit0 = BIT(color_prom[i], 0);
int const bit1 = BIT(color_prom[i], 1);
int const bit2 = BIT(color_prom[i], 2);
int const bit3 = BIT(color_prom[i], 3);
// red component
int const r = 0xff * bit0;
// green component
int const g = 0xff * bit1 - 0xcc * bit3;
// blue component
int const b = 0xff * bit2;
palette.set_pen_color(i, rgb_t(r, g, b));
}
}
WRITE_LINE_MEMBER(stactics_state::palette_bank_w)
{
m_palette_bank = m_outlatch->q6_r() | (m_outlatch->q7_r() << 1);
}
/*************************************
*
* Scrolling
*
*************************************/
void stactics_state::scroll_ram_w(offs_t offset, uint8_t data)
{
if (data & 0x01)
{
switch (offset >> 8)
{
case 4: m_y_scroll_d = offset & 0xff; break;
case 5: m_y_scroll_e = offset & 0xff; break;
case 6: m_y_scroll_f = offset & 0xff; break;
}
}
}
/*************************************
*
* Frane counter
*
*************************************/
READ_LINE_MEMBER(stactics_state::frame_count_d3_r)
{
return (m_frame_count >> 3) & 0x01;
}
/*************************************
*
* Beam handling
*
*************************************/
void stactics_state::speed_latch_w(uint8_t data)
{
/* This writes to a shift register which is clocked by */
/* a 555 oscillator. This value determines the speed of */
/* the LED fire beams as follows: */
/* 555_freq / bits_in_SR * edges_in_SR / states_in_PR67 / frame_rate */
/* = num_led_states_per_frame */
/* 36439 / 8 * x / 32 / 60 ~= 19/8*x */
/* Here, we will count the number of rising edges in the shift register */
int i;
int num_rising_edges = 0;
for(i=0;i<8;i++)
{
if ( (((data>>i)&0x01) == 1) && (((data>>((i+1)%8))&0x01) == 0))
num_rising_edges++;
}
m_beam_states_per_frame = num_rising_edges*19/8;
}
void stactics_state::shot_trigger_w(uint8_t data)
{
m_shot_standby = 0;
}
void stactics_state::shot_flag_clear_w(uint8_t data)
{
m_shot_arrive = 0;
}
READ_LINE_MEMBER(stactics_state::shot_standby_r)
{
return m_shot_standby;
}
READ_LINE_MEMBER(stactics_state::not_shot_arrive_r)
{
return !m_shot_arrive;
}
void stactics_state::update_beam()
{
/* first, update the firebeam state */
m_old_beam_state = m_beam_state;
if (m_shot_standby == 0)
m_beam_state = m_beam_state + m_beam_states_per_frame;
/* These are thresholds for the two shots from the LED fire ROM */
/* (Note: There are two more for sound triggers, */
/* whenever that gets implemented) */
if ((m_old_beam_state < 0x8b) & (m_beam_state >= 0x8b))
m_shot_arrive = 1;
if ((m_old_beam_state < 0xca) & (m_beam_state >= 0xca))
m_shot_arrive = 1;
if (m_beam_state >= 0x100)
{
m_beam_state = 0;
m_shot_standby = 1;
}
}
/*************************************
*
* Video drawing
*
*************************************/
inline int stactics_state::get_pixel_on_plane(uint8_t *videoram, uint8_t y, uint8_t x, uint8_t y_scroll)
{
/* compute effective row */
y = y - y_scroll;
/* get the character code at the given pixel */
uint8_t code = videoram[((y >> 3) << 5) | (x >> 3)];
/* get the gfx byte */
uint8_t gfx = videoram[0x800 | (code << 3) | (y & 0x07)];
/* return the appropriate pixel within the byte */
return (gfx >> (~x & 0x07)) & 0x01;
}
void stactics_state::draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0, cliprect);
/* for every row */
for (int y = 0; y < 0x100; y++)
{
/* for every pixel on the row */
for (int x = 0; x < 0x100; x++)
{
/* get the pixels for the four planes */
int pixel_b = get_pixel_on_plane(m_videoram_b, y, x, 0);
int pixel_d = get_pixel_on_plane(m_videoram_d, y, x, m_y_scroll_d);
int pixel_e = get_pixel_on_plane(m_videoram_e, y, x, m_y_scroll_e);
int pixel_f = get_pixel_on_plane(m_videoram_f, y, x, m_y_scroll_f);
/* get the color for this pixel */
uint8_t color = m_videoram_b[((y >> 3) << 5) | (x >> 3)] >> 4;
/* assemble the pen index */
int pen = color |
(pixel_b << 4) |
(pixel_f << 5) |
(pixel_e << 6) |
(pixel_d << 7) |
(m_palette_bank << 8);
/* compute the effective pixel coordinate after adjusting for the
mirror movement - this is mechanical on the real machine */
int sy = y + m_vert_pos;
int sx = x - m_horiz_pos;
/* plot if visible */
if ((sy >= 0) && (sy < 0x100) && (sx >= 0) && (sx < 0x100))
bitmap.pix(sy, sx) = pen;
}
}
}
/*************************************
*
* Non-video artwork
*
*************************************/
/* from 7448 datasheet */
static constexpr int to_7seg[0x10] =
{
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07,
0x7f, 0x67, 0x58, 0x4c, 0x62, 0x69, 0x78, 0x00
};
template <unsigned N> void stactics_state::set_indicator_leds(unsigned offset, output_finder<N> &outputs, int base_index)
{
/* decode the data */
int const data = to_7seg[~m_display_buffer[offset] & 0x0f];
/* set the 4 LEDs */
outputs[base_index + 0] = BIT(data, 2);
outputs[base_index + 1] = BIT(data, 6);
outputs[base_index + 2] = BIT(data, 5);
outputs[base_index + 3] = BIT(data, 4);
}
WRITE_LINE_MEMBER(stactics_state::barrier_lamp_w)
{
// this needs to flash on/off, not implemented
m_barrier_lamp = state;
}
WRITE_LINE_MEMBER(stactics_state::start_lamp_w)
{
m_start_lamp = state;
}
void stactics_state::update_artwork()
{
uint8_t *beam_region = memregion("user1")->base();
/* laser beam - loop for each LED */
for (int i = 0; i < 0x40; i++)
{
offs_t const beam_data_offs = ((i & 0x08) << 7) | ((i & 0x30) << 4) | m_beam_state;
uint8_t const beam_data = beam_region[beam_data_offs];
int const on = BIT(beam_data, i & 0x07);
m_beam_leds_left[i] = on;
m_beam_leds_right[i] = on;
}
/* sight LED */
m_sight_led = m_motor_on;
/* score display */
for (int i = 0x01; i < 0x07; i++)
m_score_digits[i - 1] = to_7seg[~m_display_buffer[i] & 0x0f];
/* credits indicator */
set_indicator_leds(0x07, m_credit_leds, 0x00);
set_indicator_leds(0x08, m_credit_leds, 0x04);
/* barriers indicator */
set_indicator_leds(0x09, m_barrier_leds, 0x00);
set_indicator_leds(0x0a, m_barrier_leds, 0x04);
set_indicator_leds(0x0b, m_barrier_leds, 0x08);
/* rounds indicator */
set_indicator_leds(0x0c, m_round_leds, 0x00);
set_indicator_leds(0x0d, m_round_leds, 0x04);
set_indicator_leds(0x0e, m_round_leds, 0x08);
set_indicator_leds(0x0f, m_round_leds, 0x0c);
}
/*************************************
*
* Start
*
*************************************/
void stactics_state::video_start()
{
m_base_lamps.resolve();
m_beam_leds_left.resolve();
m_beam_leds_right.resolve();
m_score_digits.resolve();
m_credit_leds.resolve();
m_barrier_leds.resolve();
m_round_leds.resolve();
m_barrier_lamp.resolve();
m_start_lamp.resolve();
m_sight_led.resolve();
m_y_scroll_d = 0;
m_y_scroll_e = 0;
m_y_scroll_f = 0;
m_frame_count = 0;
m_shot_standby = 1;
m_shot_arrive = 0;
m_beam_state = 0;
m_old_beam_state = 0;
m_palette_bank = 0;
save_item(NAME(m_y_scroll_d));
save_item(NAME(m_y_scroll_e));
save_item(NAME(m_y_scroll_f));
save_item(NAME(m_frame_count));
save_item(NAME(m_shot_standby));
save_item(NAME(m_shot_arrive));
save_item(NAME(m_beam_state));
save_item(NAME(m_old_beam_state));
save_item(NAME(m_beam_states_per_frame));
save_item(NAME(m_palette_bank));
}
/*************************************
*
* Update
*
*************************************/
uint32_t stactics_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
update_beam();
draw_background(bitmap, cliprect);
update_artwork();
m_frame_count = (m_frame_count + 1) & 0x0f;
return 0;
}
/*************************************
*
* Machine driver
*
*************************************/
void stactics_state::stactics_video(machine_config &config)
{
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_video_attributes(VIDEO_ALWAYS_UPDATE);
screen.set_raw(15.46848_MHz_XTAL / 3, 328, 0, 256, 262, 0, 232);
screen.set_screen_update(FUNC(stactics_state::screen_update));
screen.set_palette("palette");
PALETTE(config, "palette", FUNC(stactics_state::stactics_palette), 0x400);
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Zsolt Vasvari
// copyright-holders: Zsolt Vasvari
/******************************************************************************
Super Locomotive
@ -22,21 +23,324 @@ Sega PCB 834-5137
******************************************************************************/
#include "emu.h"
#include "suprloco.h"
#include "machine/segacrpt_device.h"
#include "cpu/z80/z80.h"
#include "machine/i8255.h"
#include "machine/segacrpt_device.h"
#include "sound/sn76496.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
// configurable logging
#define LOG_CTRLBIT4 (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_CTRLBIT4)
#include "logmacro.h"
#define LOGCTRLBIT4(...) LOGMASKED(LOG_CTRLBIT4, __VA_ARGS__)
namespace {
class suprloco_state : public driver_device
{
public:
suprloco_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_spriteram(*this, "spriteram"),
m_videoram(*this, "videoram"),
m_scrollram(*this, "scrollram"),
m_decrypted_opcodes(*this, "decrypted_opcodes"),
m_sprites_rom(*this, "sprites")
{ }
void suprloco(machine_config &config);
void init_suprloco();
protected:
virtual void video_start() override;
private:
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<gfxdecode_device> m_gfxdecode;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_scrollram;
required_shared_ptr<uint8_t> m_decrypted_opcodes;
required_region_ptr<uint8_t> m_sprites_rom;
tilemap_t *m_bg_tilemap = nullptr;
uint8_t m_control = 0;
enum
{
SPR_Y_TOP = 0,
SPR_Y_BOTTOM,
SPR_X,
SPR_COL,
SPR_SKIP_LO,
SPR_SKIP_HI,
SPR_GFXOFS_LO,
SPR_GFXOFS_HI
};
void videoram_w(offs_t offset, uint8_t data);
void scrollram_w(offs_t offset, uint8_t data);
void control_w(uint8_t data);
TILE_GET_INFO_MEMBER(get_tile_info);
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
inline void draw_pixel(bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y, int color, int flip);
void draw_sprite(bitmap_ind16 &bitmap, const rectangle &cliprect, int spr_number);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void decrypted_opcodes_map(address_map &map);
void main_map(address_map &map);
void sound_map(address_map &map);
};
// video
/***************************************************************************
Convert the color PROMs into a more useable format.
I'm not sure about the resistor values, I'm using the Galaxian ones.
***************************************************************************/
void suprloco_state::palette(palette_device &palette) const
{
const uint8_t *color_prom = memregion("proms")->base();
for (int i = 0; i < 512; i++)
{
int bit0, bit1, bit2;
// red component
bit0 = BIT(color_prom[i], 0);
bit1 = BIT(color_prom[i], 1);
bit2 = BIT(color_prom[i], 2);
int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// green component
bit0 = BIT(color_prom[i], 3);
bit1 = BIT(color_prom[i], 4);
bit2 = BIT(color_prom[i], 5);
int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// blue component
bit0 = 0;
bit1 = BIT(color_prom[i], 6);
bit2 = BIT(color_prom[i], 7);
int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
palette.set_pen_color(i, rgb_t(r, g, b));
// hack: generate a second bank of sprite palette with red changed to purple
if (i >= 256)
palette.set_pen_color(i + 256, rgb_t(r, g, ((i & 0x0f) == 0x09) ? 0xff : b));
}
}
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILE_GET_INFO_MEMBER(suprloco_state::get_tile_info)
{
uint8_t const attr = m_videoram[2 * tile_index + 1];
tileinfo.set(0,
m_videoram[2 * tile_index] | ((attr & 0x03) << 8),
(attr & 0x1c) >> 2,
0);
tileinfo.category = (attr & 0x20) >> 5;
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void suprloco_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(suprloco_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_bg_tilemap->set_scroll_rows(32);
save_item(NAME(m_control));
}
/***************************************************************************
Memory handlers
***************************************************************************/
void suprloco_state::videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset / 2);
}
void suprloco_state::scrollram_w(offs_t offset, uint8_t data)
{
int const adj = flip_screen() ? -8 : 8;
m_scrollram[offset] = data;
m_bg_tilemap->set_scrollx(offset, data - adj);
}
void suprloco_state::control_w(uint8_t data)
{
/* There is probably a palette select in here
Bit 0 - coin counter A
Bit 1 - coin counter B (only used if coinage differs from A)
Bit 2-3 - probably unused
Bit 4 - ???
Bit 5 - pulsated when loco turns "super"
Bit 6 - probably unused
Bit 7 - flip screen */
if ((m_control & 0x10) != (data & 0x10))
LOGCTRLBIT4("Bit 4 = %d\n", (data >> 4) & 1);
machine().bookkeeping().coin_counter_w(0, data & 0x01);
machine().bookkeeping().coin_counter_w(1, data & 0x02);
flip_screen_set(data & 0x80);
m_control = data;
}
inline void suprloco_state::draw_pixel(bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y, int color, int flip)
{
if (flip)
{
x = bitmap.width() - x - 1;
y = bitmap.height() - y - 1;
}
if (cliprect.contains(x, y))
bitmap.pix(y, x) = color;
}
void suprloco_state::draw_sprite(bitmap_ind16 &bitmap, const rectangle &cliprect, int spr_number)
{
int const flip = flip_screen();
int adjy, dy;
const uint8_t *spr_reg = m_spriteram + 0x10 * spr_number;
int src = spr_reg[SPR_GFXOFS_LO] + (spr_reg[SPR_GFXOFS_HI] << 8);
short const skip = spr_reg[SPR_SKIP_LO] + (spr_reg[SPR_SKIP_HI] << 8); // bytes to skip before drawing each row (can be negative)
int const height = spr_reg[SPR_Y_BOTTOM] - spr_reg[SPR_Y_TOP];
pen_t const pen_base = 0x100 + 0x10 * (spr_reg[SPR_COL] & 0x03) + ((m_control & 0x20) ? 0x100 : 0);
int const sx = spr_reg[SPR_X];
int const sy = spr_reg[SPR_Y_TOP] + 1;
if (!flip)
{
adjy = sy;
dy = 1;
}
else
{
adjy = sy + height - 1; // some of the sprites are still off by a pixel
dy = -1;
}
for (int row = 0; row < height; row++, adjy += dy)
{
int color1, color2;
uint8_t data;
src += skip;
int col = 0;
// get pointer to packed sprite data
const uint8_t *gfx = &(m_sprites_rom[src & 0x7fff]);
int const flipx = src & 0x8000; // flip x
while (1)
{
if (flipx) // flip x
{
data = *gfx--;
color1 = data & 0x0f;
color2 = data >> 4;
}
else
{
data = *gfx++;
color1 = data >> 4;
color2 = data & 0x0f;
}
if (color1 == 15) break;
if (color1)
draw_pixel(bitmap, cliprect,sx + col, adjy, pen_base + color1, flip);
if (color2 == 15) break;
if (color2)
draw_pixel(bitmap, cliprect,sx + col + 1, adjy, pen_base + color2, flip);
col += 2;
}
}
}
void suprloco_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
for (int spr_number = 0; spr_number < (m_spriteram.bytes() >> 4); spr_number++)
{
const uint8_t *spr_reg = m_spriteram + 0x10 * spr_number;
if (spr_reg[SPR_X] != 0xff)
draw_sprite(bitmap, cliprect, spr_number);
}
}
uint32_t suprloco_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
draw_sprites(bitmap, cliprect);
m_bg_tilemap->draw(screen, bitmap, cliprect, 1, 0);
return 0;
}
// machine
void suprloco_state::main_map(address_map &map)
{
map(0x0000, 0xbfff).rom();
map(0xc000, 0xc1ff).ram().share("spriteram");
map(0xc000, 0xc1ff).ram().share(m_spriteram);
map(0xc200, 0xc7ff).nopw();
map(0xc800, 0xc800).portr("SYSTEM");
map(0xd000, 0xd000).portr("P1");
@ -44,15 +348,15 @@ void suprloco_state::main_map(address_map &map)
map(0xe000, 0xe000).portr("DSW1");
map(0xe001, 0xe001).portr("DSW2");
map(0xe800, 0xe803).rw("ppi", FUNC(i8255_device::read), FUNC(i8255_device::write));
map(0xf000, 0xf6ff).ram().w(FUNC(suprloco_state::videoram_w)).share("videoram");
map(0xf700, 0xf7df).ram(); /* unused */
map(0xf7e0, 0xf7ff).ram().w(FUNC(suprloco_state::scrollram_w)).share("scrollram");
map(0xf000, 0xf6ff).ram().w(FUNC(suprloco_state::videoram_w)).share(m_videoram);
map(0xf700, 0xf7df).ram(); // unused
map(0xf7e0, 0xf7ff).ram().w(FUNC(suprloco_state::scrollram_w)).share(m_scrollram);
map(0xf800, 0xffff).ram();
}
void suprloco_state::decrypted_opcodes_map(address_map &map)
{
map(0x0000, 0x7fff).rom().share("decrypted_opcodes");
map(0x0000, 0x7fff).rom().share(m_decrypted_opcodes);
map(0x8000, 0xbfff).rom().region("maincpu", 0x8000);
}
@ -149,10 +453,10 @@ INPUT_PORTS_END
static const gfx_layout charlayout =
{
8,8, /* 8 by 8 */
1024, /* 1024 characters */
4, /* 4 bits per pixel */
{ 0, 1024*8*8, 2*1024*8*8, 3*1024*8*8 }, /* plane */
8,8, // 8 by 8
1024, // 1024 characters
4, // 4 bits per pixel
{ 0, 1024*8*8, 2*1024*8*8, 3*1024*8*8 }, // plane
{ 0, 1, 2, 3, 4, 5, 6, 7 },
{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
8*8
@ -160,23 +464,23 @@ static const gfx_layout charlayout =
static GFXDECODE_START( gfx_suprloco )
/* sprites use colors 256-511 + 512-767 */
GFXDECODE_ENTRY( "gfx1", 0x6000, charlayout, 0, 16 )
// sprites use colors 256-511 + 512-767
GFXDECODE_ENTRY( "chars", 0x6000, charlayout, 0, 16 )
GFXDECODE_END
void suprloco_state::suprloco(machine_config &config)
{
/* basic machine hardware */
sega_315_5015_device &maincpu(SEGA_315_5015(config, m_maincpu, 4000000)); /* 4 MHz (?) */
// basic machine hardware
sega_315_5015_device &maincpu(SEGA_315_5015(config, m_maincpu, 4'000'000)); // 4 MHz (?)
maincpu.set_addrmap(AS_PROGRAM, &suprloco_state::main_map);
maincpu.set_addrmap(AS_OPCODES, &suprloco_state::decrypted_opcodes_map);
maincpu.set_vblank_int("screen", FUNC(suprloco_state::irq0_line_hold));
maincpu.set_decrypted_tag(":decrypted_opcodes");
Z80(config, m_audiocpu, 4000000);
Z80(config, m_audiocpu, 4'000'000);
m_audiocpu->set_addrmap(AS_PROGRAM, &suprloco_state::sound_map);
m_audiocpu->set_periodic_int(FUNC(suprloco_state::irq0_line_hold), attotime::from_hz(4*60)); /* NMIs are caused by the main CPU */
m_audiocpu->set_periodic_int(FUNC(suprloco_state::irq0_line_hold), attotime::from_hz(4 * 60)); // NMIs are caused by the main CPU
i8255_device &ppi(I8255A(config, "ppi"));
ppi.out_pb_callback().set(FUNC(suprloco_state::control_w));
@ -184,7 +488,7 @@ void suprloco_state::suprloco(machine_config &config)
ppi.out_pc_callback().set_output("lamp0").bit(0).invert(); // set by 8255 bit mode when no credits inserted
ppi.out_pc_callback().append_inputline(m_audiocpu, INPUT_LINE_NMI).bit(7).invert();
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(5000));
@ -194,14 +498,14 @@ void suprloco_state::suprloco(machine_config &config)
screen.set_palette("palette");
GFXDECODE(config, m_gfxdecode, "palette", gfx_suprloco);
PALETTE(config, "palette", FUNC(suprloco_state::suprloco_palette), 512+256);
PALETTE(config, "palette", FUNC(suprloco_state::palette), 512 + 256);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
SN76496(config, "sn1", 4000000).add_route(ALL_OUTPUTS, "mono", 1.0);
SN76496(config, "sn1", 4'000'000).add_route(ALL_OUTPUTS, "mono", 1.0);
SN76496(config, "sn2", 2000000).add_route(ALL_OUTPUTS, "mono", 1.0);
SN76496(config, "sn2", 2'000'000).add_route(ALL_OUTPUTS, "mono", 1.0);
}
@ -213,66 +517,66 @@ void suprloco_state::suprloco(machine_config &config)
ROM_START( suprloco )
ROM_REGION( 0xc000, "maincpu", 0 )
ROM_LOAD( "epr-5226a.37", 0x0000, 0x4000, CRC(33b02368) SHA1(c6e3116ad4b52bcc3174de5770f7a7ce024790d5) ) /* encrypted */
ROM_LOAD( "epr-5227a.15", 0x4000, 0x4000, CRC(a5e67f50) SHA1(1dd52e4cf00ce414fe1db8259c9976cdc23513b4) ) /* encrypted */
ROM_LOAD( "epr-5226a.37", 0x0000, 0x4000, CRC(33b02368) SHA1(c6e3116ad4b52bcc3174de5770f7a7ce024790d5) ) // encrypted
ROM_LOAD( "epr-5227a.15", 0x4000, 0x4000, CRC(a5e67f50) SHA1(1dd52e4cf00ce414fe1db8259c9976cdc23513b4) ) // encrypted
ROM_LOAD( "epr-5228.28", 0x8000, 0x4000, CRC(a597828a) SHA1(61004d112591fd2d752c39df71c1304d9308daae) )
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "epr-5222.64", 0x0000, 0x2000, CRC(0aa57207) SHA1(b29b533505cb5b47c90534f2f610baeb7265d030) )
ROM_REGION( 0xe000, "gfx1", 0 )
ROM_REGION( 0xe000, "chars", 0 )
ROM_LOAD( "epr-5225.63", 0x0000, 0x2000, CRC(e571fe81) SHA1(ac2b5914a445b89b7456b2c4290e4630b525f05d) )
ROM_LOAD( "epr-5224.62", 0x2000, 0x2000, CRC(6130f93c) SHA1(ae0657f46c10e75eec994e75359a89b5d61baf68) )
ROM_LOAD( "epr-5223.61", 0x4000, 0x2000, CRC(3b03004e) SHA1(805b51cb14d3ace97f2e0f306db28921b2f5e322) )
/* 0x6000- 0xe000 will be created by init_suprloco */
// 0x6000 - 0xe000 will be created by init_suprloco
ROM_REGION( 0x8000, "gfx2", 0 ) /* 32k for sprites data used at runtime */
ROM_REGION( 0x8000, "sprites", 0 ) // used at runtime
ROM_LOAD( "epr-5229.55", 0x0000, 0x4000, CRC(ee2d3ed3) SHA1(593f3cd5c4e7f20b5e31e6bac8864774442e4b75) )
ROM_LOAD( "epr-5230.56", 0x4000, 0x2000, CRC(f04a4b50) SHA1(80363f0c508fb2a755bf684f9a6862c1e7285495) )
/* 0x6000 empty */
// 0x6000 empty
ROM_REGION( 0x0620, "proms", 0 )
ROM_LOAD( "pr-5220.100", 0x0100, 0x0080, CRC(7b0c8ce5) SHA1(4e1ea5ce38198a3965dfeb609ba0c7e8211531c3) ) /* color PROM */
ROM_LOAD( "pr-5220.100", 0x0100, 0x0080, CRC(7b0c8ce5) SHA1(4e1ea5ce38198a3965dfeb609ba0c7e8211531c3) ) // color PROM
ROM_CONTINUE( 0x0000, 0x0080 )
ROM_CONTINUE( 0x0180, 0x0080 )
ROM_CONTINUE( 0x0080, 0x0080 )
ROM_LOAD( "pr-5219.89", 0x0200, 0x0400, CRC(1d4b02cb) SHA1(00d822f1bc4f57f2f5d5a0615241f8136246a842) ) /* 3bpp to 4bpp table */
ROM_LOAD( "pr-5221.7", 0x0600, 0x0020, CRC(89ba674f) SHA1(17c87840c8011968675a5a6f55966467df02364b) ) /* unknown */
ROM_LOAD( "pr-5219.89", 0x0200, 0x0400, CRC(1d4b02cb) SHA1(00d822f1bc4f57f2f5d5a0615241f8136246a842) ) // 3bpp to 4bpp table
ROM_LOAD( "pr-5221.7", 0x0600, 0x0020, CRC(89ba674f) SHA1(17c87840c8011968675a5a6f55966467df02364b) ) // unknown
ROM_END
ROM_START( suprlocoo )
ROM_REGION( 0xc000, "maincpu", 0 )
ROM_LOAD( "epr-5226.37", 0x0000, 0x4000, CRC(57f514dd) SHA1(707800b90a22547a56b01d1e11775e9ee5555d23) ) /* encrypted */
ROM_LOAD( "epr-5227.15", 0x4000, 0x4000, CRC(5a1d2fb0) SHA1(fdb9416e5530718245fd597073a63feddb233c3c) ) /* encrypted */
ROM_LOAD( "epr-5226.37", 0x0000, 0x4000, CRC(57f514dd) SHA1(707800b90a22547a56b01d1e11775e9ee5555d23) ) // encrypted
ROM_LOAD( "epr-5227.15", 0x4000, 0x4000, CRC(5a1d2fb0) SHA1(fdb9416e5530718245fd597073a63feddb233c3c) ) // encrypted
ROM_LOAD( "epr-5228.28", 0x8000, 0x4000, CRC(a597828a) SHA1(61004d112591fd2d752c39df71c1304d9308daae) )
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "epr-5222.64", 0x0000, 0x2000, CRC(0aa57207) SHA1(b29b533505cb5b47c90534f2f610baeb7265d030) )
ROM_REGION( 0xe000, "gfx1", 0 )
ROM_REGION( 0xe000, "chars", 0 )
ROM_LOAD( "epr-5225.63", 0x0000, 0x2000, CRC(e571fe81) SHA1(ac2b5914a445b89b7456b2c4290e4630b525f05d) )
ROM_LOAD( "epr-5224.62", 0x2000, 0x2000, CRC(6130f93c) SHA1(ae0657f46c10e75eec994e75359a89b5d61baf68) )
ROM_LOAD( "epr-5223.61", 0x4000, 0x2000, CRC(3b03004e) SHA1(805b51cb14d3ace97f2e0f306db28921b2f5e322) )
/* 0x6000- 0xe000 will be created by init_suprloco */
// 0x6000 - 0xe000 will be created by init_suprloco
ROM_REGION( 0x8000, "gfx2", 0 ) /* 32k for sprites data used at runtime */
ROM_REGION( 0x8000, "sprites", 0 ) // used at runtime
ROM_LOAD( "epr-5229.55", 0x0000, 0x4000, CRC(ee2d3ed3) SHA1(593f3cd5c4e7f20b5e31e6bac8864774442e4b75) )
ROM_LOAD( "epr-5230.56", 0x4000, 0x2000, CRC(f04a4b50) SHA1(80363f0c508fb2a755bf684f9a6862c1e7285495) )
/* 0x6000 empty */
// 0x6000 empty
ROM_REGION( 0x0620, "proms", 0 )
ROM_LOAD( "pr-5220.100", 0x0100, 0x0080, CRC(7b0c8ce5) SHA1(4e1ea5ce38198a3965dfeb609ba0c7e8211531c3) ) /* color PROM */
ROM_LOAD( "pr-5220.100", 0x0100, 0x0080, CRC(7b0c8ce5) SHA1(4e1ea5ce38198a3965dfeb609ba0c7e8211531c3) ) // color PROM
ROM_CONTINUE( 0x0000, 0x0080 )
ROM_CONTINUE( 0x0180, 0x0080 )
ROM_CONTINUE( 0x0080, 0x0080 )
ROM_LOAD( "pr-5219.89", 0x0200, 0x0400, CRC(1d4b02cb) SHA1(00d822f1bc4f57f2f5d5a0615241f8136246a842) ) /* 3bpp to 4bpp table */
ROM_LOAD( "pr-5221.7", 0x0600, 0x0020, CRC(89ba674f) SHA1(17c87840c8011968675a5a6f55966467df02364b) ) /* unknown */
ROM_LOAD( "pr-5219.89", 0x0200, 0x0400, CRC(1d4b02cb) SHA1(00d822f1bc4f57f2f5d5a0615241f8136246a842) ) // 3bpp to 4bpp table
ROM_LOAD( "pr-5221.7", 0x0600, 0x0020, CRC(89ba674f) SHA1(17c87840c8011968675a5a6f55966467df02364b) ) // unknown
ROM_END
void suprloco_state::init_suprloco()
{
/* convert graphics to 4bpp from 3bpp */
uint8_t *source = memregion("gfx1")->base();
// convert graphics to 4bpp from 3bpp
uint8_t *source = memregion("chars")->base();
uint8_t *dest = source + 0x6000;
uint8_t *lookup = memregion("proms")->base() + 0x0200;
@ -300,5 +604,8 @@ void suprloco_state::init_suprloco()
}
} // anonymous namespace
GAME( 1982, suprloco, 0, suprloco, suprloco, suprloco_state, init_suprloco, ROT0, "Sega", "Super Locomotive (Rev.A)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, suprlocoo, suprloco, suprloco, suprloco, suprloco_state, init_suprloco, ROT0, "Sega", "Super Locomotive", MACHINE_SUPPORTS_SAVE )

View File

@ -1,60 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Zsolt Vasvari
#ifndef MAME_INCLUDES_SUPRLOCO_H
#define MAME_INCLUDES_SUPRLOCO_H
#pragma once
#include "emupal.h"
#include "tilemap.h"
class suprloco_state : public driver_device
{
public:
suprloco_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_spriteram(*this, "spriteram"),
m_videoram(*this, "videoram"),
m_scrollram(*this, "scrollram"),
m_decrypted_opcodes(*this, "decrypted_opcodes")
{ }
void suprloco(machine_config &config);
void init_suprloco();
private:
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<gfxdecode_device> m_gfxdecode;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_scrollram;
required_shared_ptr<uint8_t> m_decrypted_opcodes;
tilemap_t *m_bg_tilemap = nullptr;
int m_control = 0;
void videoram_w(offs_t offset, uint8_t data);
void scrollram_w(offs_t offset, uint8_t data);
void control_w(uint8_t data);
TILE_GET_INFO_MEMBER(get_tile_info);
virtual void video_start() override;
void suprloco_palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
inline void draw_pixel(bitmap_ind16 &bitmap,const rectangle &cliprect,int x,int y,int color,int flip);
void draw_sprite(bitmap_ind16 &bitmap,const rectangle &cliprect,int spr_number);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void decrypted_opcodes_map(address_map &map);
void main_map(address_map &map);
void sound_map(address_map &map);
};
#endif // MAME_INCLUDES_SUPRLOCO_H

View File

@ -1,256 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Zsolt Vasvari
/***************************************************************************
suprloco.c
Functions to emulate the video hardware of the machine.
***************************************************************************/
#include "emu.h"
#include "suprloco.h"
#define SPR_Y_TOP 0
#define SPR_Y_BOTTOM 1
#define SPR_X 2
#define SPR_COL 3
#define SPR_SKIP_LO 4
#define SPR_SKIP_HI 5
#define SPR_GFXOFS_LO 6
#define SPR_GFXOFS_HI 7
/***************************************************************************
Convert the color PROMs into a more useable format.
I'm not sure about the resistor values, I'm using the Galaxian ones.
***************************************************************************/
void suprloco_state::suprloco_palette(palette_device &palette) const
{
const uint8_t *color_prom = memregion("proms")->base();
for (int i = 0; i < 512; i++)
{
int bit0, bit1, bit2;
// red component
bit0 = BIT(color_prom[i], 0);
bit1 = BIT(color_prom[i], 1);
bit2 = BIT(color_prom[i], 2);
int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// green component
bit0 = BIT(color_prom[i], 3);
bit1 = BIT(color_prom[i], 4);
bit2 = BIT(color_prom[i], 5);
int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// blue component
bit0 = 0;
bit1 = BIT(color_prom[i], 6);
bit2 = BIT(color_prom[i], 7);
int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
palette.set_pen_color(i, rgb_t(r, g, b));
// hack: generate a second bank of sprite palette with red changed to purple
if (i >= 256)
palette.set_pen_color(i + 256, rgb_t(r, g, ((i & 0x0f) == 0x09) ? 0xff : b));
}
}
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILE_GET_INFO_MEMBER(suprloco_state::get_tile_info)
{
uint8_t attr = m_videoram[2*tile_index+1];
tileinfo.set(0,
m_videoram[2*tile_index] | ((attr & 0x03) << 8),
(attr & 0x1c) >> 2,
0);
tileinfo.category = (attr & 0x20) >> 5;
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void suprloco_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(suprloco_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8,8, 32,32);
m_bg_tilemap->set_scroll_rows(32);
save_item(NAME(m_control));
}
/***************************************************************************
Memory handlers
***************************************************************************/
void suprloco_state::videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset/2);
}
void suprloco_state::scrollram_w(offs_t offset, uint8_t data)
{
int adj = flip_screen() ? -8 : 8;
m_scrollram[offset] = data;
m_bg_tilemap->set_scrollx(offset, data - adj);
}
void suprloco_state::control_w(uint8_t data)
{
/* There is probably a palette select in here */
/* Bit 0 - coin counter A */
/* Bit 1 - coin counter B (only used if coinage differs from A) */
/* Bit 2-3 - probably unused */
/* Bit 4 - ??? */
/* Bit 5 - pulsated when loco turns "super" */
/* Bit 6 - probably unused */
/* Bit 7 - flip screen */
if ((m_control & 0x10) != (data & 0x10))
{
/*logerror("Bit 4 = %d\n", (data >> 4) & 1); */
}
machine().bookkeeping().coin_counter_w(0, data & 0x01);
machine().bookkeeping().coin_counter_w(1, data & 0x02);
flip_screen_set(data & 0x80);
m_control = data;
}
inline void suprloco_state::draw_pixel(bitmap_ind16 &bitmap,const rectangle &cliprect,int x,int y,int color,int flip)
{
if (flip)
{
x = bitmap.width() - x - 1;
y = bitmap.height() - y - 1;
}
if (cliprect.contains(x, y))
bitmap.pix(y, x) = color;
}
void suprloco_state::draw_sprite(bitmap_ind16 &bitmap,const rectangle &cliprect,int spr_number)
{
int flip = flip_screen();
int sx,sy,col,row,height,src,adjy,dy;
uint8_t *spr_reg;
uint8_t *gfx2;
pen_t pen_base;
short skip; /* bytes to skip before drawing each row (can be negative) */
spr_reg = m_spriteram + 0x10 * spr_number;
src = spr_reg[SPR_GFXOFS_LO] + (spr_reg[SPR_GFXOFS_HI] << 8);
skip = spr_reg[SPR_SKIP_LO] + (spr_reg[SPR_SKIP_HI] << 8);
height = spr_reg[SPR_Y_BOTTOM] - spr_reg[SPR_Y_TOP];
pen_base = 0x100 + 0x10 * (spr_reg[SPR_COL]&0x03) + ((m_control & 0x20)?0x100:0);
sx = spr_reg[SPR_X];
sy = spr_reg[SPR_Y_TOP] + 1;
if (!flip_screen())
{
adjy = sy;
dy = 1;
}
else
{
adjy = sy + height - 1; /* some of the sprites are still off by a pixel */
dy = -1;
}
gfx2 = memregion("gfx2")->base();
for (row = 0;row < height;row++,adjy+=dy)
{
int color1,color2,flipx;
uint8_t data;
uint8_t *gfx;
src += skip;
col = 0;
/* get pointer to packed sprite data */
gfx = &(gfx2[src & 0x7fff]);
flipx = src & 0x8000; /* flip x */
while (1)
{
if (flipx) /* flip x */
{
data = *gfx--;
color1 = data & 0x0f;
color2 = data >> 4;
}
else
{
data = *gfx++;
color1 = data >> 4;
color2 = data & 0x0f;
}
if (color1 == 15) break;
if (color1)
draw_pixel(bitmap,cliprect,sx+col, adjy,pen_base + color1, flip);
if (color2 == 15) break;
if (color2)
draw_pixel(bitmap,cliprect,sx+col+1,adjy,pen_base + color2, flip);
col += 2;
}
}
}
void suprloco_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int spr_number;
uint8_t *spr_reg;
for (spr_number = 0;spr_number < (m_spriteram.bytes() >> 4);spr_number++)
{
spr_reg = m_spriteram + 0x10 * spr_number;
if (spr_reg[SPR_X] != 0xff)
draw_sprite(bitmap, cliprect, spr_number);
}
}
uint32_t suprloco_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->draw(screen, bitmap, cliprect, 0,0);
draw_sprites(bitmap,cliprect);
m_bg_tilemap->draw(screen, bitmap, cliprect, 1,0);
return 0;
}