// license:BSD-3-Clause
// copyright-holders:Angelo Salese
/***************************************************************************
Jangou Custom Blitter Chip, codename "???" (name scratched afaik)
device emulation by Angelo Salese, from original jangou.cpp implementation
by Angelo Salese, David Haywood and Phil Bennett.
TODO:
- BLTFLIP mechanism;
- clean-ups;
***************************************************************************/
#include "emu.h"
#include "jangou_blitter.h"
#define DEBUG_OUT_OF_MASK 0
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
// device type definition
DEFINE_DEVICE_TYPE(JANGOU_BLITTER, jangou_blitter_device, "jangou_blitter", "Jangou Blitter Custom Chip")
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// jangou_blitter_device - constructor
//-------------------------------------------------
jangou_blitter_device::jangou_blitter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, JANGOU_BLITTER, tag, owner, clock)
{
}
void jangou_blitter_device::blit_v1_regs(address_map &map)
{
map(0x00, 0x00).w(FUNC(jangou_blitter_device::src_lo_address_w));
map(0x01, 0x01).w(FUNC(jangou_blitter_device::src_md_address_w));
map(0x02, 0x02).w(FUNC(jangou_blitter_device::x_w));
map(0x03, 0x03).w(FUNC(jangou_blitter_device::y_w));
map(0x04, 0x04).w(FUNC(jangou_blitter_device::width_w));
map(0x05, 0x05).w(FUNC(jangou_blitter_device::height_and_trigger_w));
map(0x06, 0x06).w(FUNC(jangou_blitter_device::src_hi_address_w));
}
// Sexy Gal and variants (v2) swaps around upper src address
void jangou_blitter_device::blit_v2_regs(address_map &map)
{
map(0x00, 0x00).w(FUNC(jangou_blitter_device::src_lo_address_w));
map(0x01, 0x01).w(FUNC(jangou_blitter_device::src_md_address_w));
map(0x02, 0x02).w(FUNC(jangou_blitter_device::src_hi_address_w));
map(0x03, 0x03).w(FUNC(jangou_blitter_device::x_w));
map(0x04, 0x04).w(FUNC(jangou_blitter_device::y_w));
map(0x05, 0x05).w(FUNC(jangou_blitter_device::width_w));
map(0x06, 0x06).w(FUNC(jangou_blitter_device::height_and_trigger_w));
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void jangou_blitter_device::device_start()
{
memory_region *devregion = machine().root_device().memregion("gfx");
m_gfxrom = devregion->base();
if (m_gfxrom == nullptr)
fatalerror("JANGOU_BLITTER: \"gfx\" memory base not found");
m_gfxrommask = devregion->bytes()-1;
save_item(NAME(m_pen_data));
save_item(NAME(m_x));
save_item(NAME(m_y));
save_item(NAME(m_width));
save_item(NAME(m_height));
save_item(NAME(m_src_addr));
save_item(NAME(m_blit_buffer));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void jangou_blitter_device::device_reset()
{
memset(m_pen_data, 0, ARRAY_LENGTH(m_pen_data));
m_bltflip = false;
}
//**************************************************************************
// READ/WRITE HANDLERS
//**************************************************************************
// TODO: inline these
uint8_t jangou_blitter_device::gfx_nibble( uint32_t niboffset )
{
if (niboffset & 1)
return (m_gfxrom[(niboffset >> 1) & m_gfxrommask] & 0xf0) >> 4;
else
return (m_gfxrom[(niboffset >> 1) & m_gfxrommask] & 0x0f);
}
void jangou_blitter_device::plot_gfx_pixel( uint8_t pix, int x, int y )
{
if (y < 0 || y >= 256)
return;
if (x < 0 || x >= 256)
return;
if (x & 1)
m_blit_buffer[(y * 256) + (x >> 1)] = (m_blit_buffer[(y * 256) + (x >> 1)] & 0x0f) | ((pix << 4) & 0xf0);
else
m_blit_buffer[(y * 256) + (x >> 1)] = (m_blit_buffer[(y * 256) + (x >> 1)] & 0xf0) | (pix & 0x0f);
}
void jangou_blitter_device::trigger_write(void)
{
int src, x, y, h, w, flipx;
int count = 0;
int xcount, ycount;
#if DEBUG_OUT_OF_MASK
bool debug_flag;
#endif
w = (m_width & 0xff) + 1;
h = (m_height & 0xff) + 1;
src = m_src_addr & m_gfxrommask;
if(m_src_addr & ~m_gfxrommask)
{
logerror("%s: Warning blit src address = %08x above ROM mask %08x\n",this->tag(),m_src_addr,m_gfxrommask);
#if DEBUG_OUT_OF_MASK
debug_flag = true;
#endif
}
#if DEBUG_OUT_OF_MASK
else
debug_flag = false;
#endif
x = (m_x & 0xff);
y = (m_y & 0xff);
#if 0
// bail out if parameters are blantantly invalid (an indication that the host is using protection tho)
if((x + w) > 256 || (y + h) > 256)
{
printf("%d %d %d %d %08x\n",x,y,w,h,src);
// return;
}
#endif
// lowest bit of src controls flipping / draw direction?
flipx = (m_src_addr & 1);
if (!flipx)
src += (w * h) - 1;
else
src -= (w * h) - 1;
for (ycount = 0; ycount < h; ycount++)
{
for(xcount = 0; xcount < w; xcount++)
{
int drawx = (x + xcount) & 0xff;
int drawy = (y + ycount) & 0xff;
uint8_t dat = gfx_nibble(src + count);
uint8_t cur_pen = m_pen_data[dat & 0x0f];
#if DEBUG_OUT_OF_MASK
if(debug_flag == true)
cur_pen = machine().rand() & 0xf;
#endif
//dat = cur_pen_lo | (cur_pen_hi << 4);
if ((cur_pen & 0xff) != 0)
plot_gfx_pixel(cur_pen, drawx, drawy);
if (!flipx)
count--;
else
count++;
}
}
//uint32_t new_src = src + count;
// update source and height after blitter operation
// TODO: Jangou doesn't agree with this, later HW?
#if 0
m_blit_data[0] = new_src & 0xfe;
m_blit_data[1] = new_src >> 8;
m_blit_data[5] = 0;
m_blit_data[6] = new_src >> 16;
#endif
m_bltflip = false;
}
WRITE8_MEMBER( jangou_blitter_device::vregs_w )
{
// bit 5 set by Jangou, left-over?
m_pen_data[offset] = data & 0x0f;
}
WRITE8_MEMBER( jangou_blitter_device::bltflip_w )
{
// TODO: unsure about how this works, Charles says it swaps the nibble but afaik it's used for CPU tiles in Night Gal Summer/Sexy Gal and they seems fine?
// Maybe flipx is actually bltflip for later HW?
m_bltflip = true;
}
READ_LINE_MEMBER( jangou_blitter_device::status_r )
{
return false;
}
// data accessors
WRITE8_MEMBER( jangou_blitter_device::x_w ) { m_x = data; }
WRITE8_MEMBER( jangou_blitter_device::y_w ) { m_y = data; }
WRITE8_MEMBER( jangou_blitter_device::src_lo_address_w )
{
m_src_addr &= ~0xff;
m_src_addr |= data & 0xff;
}
WRITE8_MEMBER( jangou_blitter_device::src_md_address_w )
{
m_src_addr &= ~0xff00;
m_src_addr |= data << 8;
}
WRITE8_MEMBER( jangou_blitter_device::src_hi_address_w )
{
m_src_addr &= ~0xff0000;
m_src_addr |= data << 16;
}
WRITE8_MEMBER( jangou_blitter_device::width_w )
{
m_width = data;
}
WRITE8_MEMBER( jangou_blitter_device::height_and_trigger_w )
{
m_height = data;
trigger_write();
}