summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/namco/namcos2_roz.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/namco/namcos2_roz.cpp')
-rw-r--r--src/mame/namco/namcos2_roz.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/mame/namco/namcos2_roz.cpp b/src/mame/namco/namcos2_roz.cpp
new file mode 100644
index 00000000000..3db611c010e
--- /dev/null
+++ b/src/mame/namco/namcos2_roz.cpp
@@ -0,0 +1,282 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood, Phil Stroffolino
+
+/*
+ Namco System 2 ROZ Tilemap - found on Namco System 2 video board (standard type)
+
+ based on namcoic.txt this probably consists of the following
+ C102 - Controls CPU access to ROZ Memory Area.
+ (anything else?)
+
+ used by the following drivers
+ namcos2.cpp (all games EXCEPT Final Lap 1,2,3 , Lucky & Wild , Steel Gunner 1,2 , Suzuka 8 Hours 1,2 , Metal Hawk)
+
+
+*/
+
+#include "emu.h"
+#include "namcos2_roz.h"
+
+GFXDECODE_START( namcos2_roz_device::gfxinfo )
+ GFXDECODE_DEVICE( DEVICE_SELF, 0, gfx_8x8x8_raw, 0, 16 )
+GFXDECODE_END
+
+DEFINE_DEVICE_TYPE(NAMCOS2_ROZ, namcos2_roz_device, "namcos2_roz", "Namco System 2 ROZ (C102)")
+
+namcos2_roz_device::namcos2_roz_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, NAMCOS2_ROZ, tag, owner, clock),
+ device_gfx_interface(mconfig, *this, gfxinfo),
+ m_rozram(*this, finder_base::DUMMY_TAG),
+ m_roz_ctrl(*this, finder_base::DUMMY_TAG)
+{
+}
+
+void namcos2_roz_device::device_start()
+{
+ m_tilemap_roz = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(namcos2_roz_device::roz_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 256, 256);
+ m_tilemap_roz->set_transparent_pen(0xff);
+}
+
+
+TILE_GET_INFO_MEMBER(namcos2_roz_device::roz_tile_info)
+{
+ tileinfo.set(0, m_rozram[tile_index], 0/*color*/, 0);
+}
+
+struct roz_param
+{
+ uint32_t size;
+ uint32_t startx, starty;
+ int incxx, incxy, incyx, incyy;
+ int color;
+ int wrap;
+};
+
+static inline void
+draw_roz_helper_block(const struct roz_param *rozInfo, int destx, int desty,
+ int srcx, int srcy, int width, int height,
+ bitmap_ind16 &destbitmap, bitmap_ind8 &flagsbitmap,
+ bitmap_ind16 &srcbitmap, uint32_t size_mask)
+{
+ const int desty_end = desty + height;
+
+ const int end_incrx = rozInfo->incyx - (width * rozInfo->incxx);
+ const int end_incry = rozInfo->incyy - (width * rozInfo->incxy);
+
+ uint16_t *dest = &destbitmap.pix(desty, destx);
+ const int dest_rowinc = destbitmap.rowpixels() - width;
+
+ while (desty < desty_end)
+ {
+ uint16_t *dest_end = dest + width;
+ while (dest < dest_end)
+ {
+ uint32_t xpos = (srcx >> 16);
+ uint32_t ypos = (srcy >> 16);
+
+ if (rozInfo->wrap)
+ {
+ xpos &= size_mask;
+ ypos &= size_mask;
+ }
+ else if ((xpos > rozInfo->size) || (ypos >= rozInfo->size))
+ {
+ goto L_SkipPixel;
+ }
+
+ if (flagsbitmap.pix(ypos, xpos) & TILEMAP_PIXEL_LAYER0)
+ {
+ *dest = srcbitmap.pix(ypos, xpos) + rozInfo->color;
+ }
+
+ L_SkipPixel:
+
+ srcx += rozInfo->incxx;
+ srcy += rozInfo->incxy;
+ dest++;
+ }
+ srcx += end_incrx;
+ srcy += end_incry;
+ dest += dest_rowinc;
+ desty++;
+ }
+}
+
+static void
+draw_roz_helper(
+ screen_device &screen,
+ bitmap_ind16 &bitmap,
+ tilemap_t *tmap,
+ const rectangle &clip,
+ const struct roz_param *rozInfo)
+{
+ tmap->set_palette_offset(rozInfo->color);
+
+ if (bitmap.bpp() == 16)
+ {
+ /* On many processors, the simple approach of an outer loop over the
+ rows of the destination bitmap with an inner loop over the columns
+ of the destination bitmap has poor performance due to the order
+ that memory in the source bitmap is referenced when rotation
+ approaches 90 or 270 degrees. The reason is that the inner loop
+ ends up reading pixels not sequentially in the source bitmap, but
+ instead at rozInfo->incxx increments, which is at its maximum at 90
+ degrees of rotation. This means that only a few (or as few as
+ one) source pixels are in each cache line at a time.
+
+ Instead of the above, this code iterates in NxN blocks through the
+ destination bitmap. This has more overhead when there is little or
+ no rotation, but much better performance when there is closer to 90
+ degrees of rotation (as long as the chunk of the source bitmap that
+ corresponds to an NxN destination block fits in cache!).
+
+ N is defined by ROZ_BLOCK_SIZE below; the best N is one that is as
+ big as possible but at the same time not too big to prevent all of
+ the source bitmap pixels from fitting into cache at the same time.
+ Keep in mind that the block of source pixels used can be somewhat
+ scattered in memory. 8x8 works well on the few processors that
+ were tested; 16x16 seems to work even better for more modern
+ processors with larger caches, but since 8x8 works well enough and
+ is less likely to result in cache misses on processors with smaller
+ caches, it is used.
+ */
+
+#define ROZ_BLOCK_SIZE 8
+
+ const uint32_t size_mask = rozInfo->size - 1;
+ bitmap_ind16 &srcbitmap = tmap->pixmap();
+ bitmap_ind8 &flagsbitmap = tmap->flagsmap();
+ uint32_t srcx = (rozInfo->startx + (clip.min_x * rozInfo->incxx) +
+ (clip.min_y * rozInfo->incyx));
+ uint32_t srcy = (rozInfo->starty + (clip.min_x * rozInfo->incxy) +
+ (clip.min_y * rozInfo->incyy));
+ int destx = clip.min_x;
+ int desty = clip.min_y;
+
+ const int row_count = (clip.max_y - desty) + 1;
+ const int row_block_count = row_count / ROZ_BLOCK_SIZE;
+ const int row_extra_count = row_count % ROZ_BLOCK_SIZE;
+
+ const int column_count = (clip.max_x - destx) + 1;
+ const int column_block_count = column_count / ROZ_BLOCK_SIZE;
+ const int column_extra_count = column_count % ROZ_BLOCK_SIZE;
+
+ const int row_block_size_incxx = ROZ_BLOCK_SIZE * rozInfo->incxx;
+ const int row_block_size_incxy = ROZ_BLOCK_SIZE * rozInfo->incxy;
+ const int row_block_size_incyx = ROZ_BLOCK_SIZE * rozInfo->incyx;
+ const int row_block_size_incyy = ROZ_BLOCK_SIZE * rozInfo->incyy;
+
+ // Do the block rows
+ for (int i = 0; i < row_block_count; i++)
+ {
+ int sx = srcx;
+ int sy = srcy;
+ int dx = destx;
+ // Do the block columns
+ for (int j = 0; j < column_block_count; j++)
+ {
+ draw_roz_helper_block(rozInfo, dx, desty, sx, sy, ROZ_BLOCK_SIZE,
+ ROZ_BLOCK_SIZE, bitmap, flagsbitmap, srcbitmap, size_mask);
+ // Increment to the next block column
+ sx += row_block_size_incxx;
+ sy += row_block_size_incxy;
+ dx += ROZ_BLOCK_SIZE;
+ }
+ // Do the extra columns
+ if (column_extra_count)
+ {
+ draw_roz_helper_block(rozInfo, dx, desty, sx, sy, column_extra_count,
+ ROZ_BLOCK_SIZE, bitmap, flagsbitmap, srcbitmap, size_mask);
+ }
+ // Increment to the next row block
+ srcx += row_block_size_incyx;
+ srcy += row_block_size_incyy;
+ desty += ROZ_BLOCK_SIZE;
+ }
+ // Do the extra rows
+ if (row_extra_count)
+ {
+ // Do the block columns
+ for (int i = 0; i < column_block_count; i++)
+ {
+ draw_roz_helper_block(rozInfo, destx, desty, srcx, srcy, ROZ_BLOCK_SIZE,
+ row_extra_count, bitmap, flagsbitmap, srcbitmap, size_mask);
+ srcx += row_block_size_incxx;
+ srcy += row_block_size_incxy;
+ destx += ROZ_BLOCK_SIZE;
+ }
+ // Do the extra columns
+ if (column_extra_count)
+ {
+ draw_roz_helper_block(rozInfo, destx, desty, srcx, srcy, column_extra_count,
+ row_extra_count, bitmap, flagsbitmap, srcbitmap, size_mask);
+ }
+ }
+ }
+ else
+ {
+ tmap->draw_roz(screen,
+ bitmap, clip,
+ rozInfo->startx, rozInfo->starty,
+ rozInfo->incxx, rozInfo->incxy,
+ rozInfo->incyx, rozInfo->incyy,
+ rozInfo->wrap, 0, 0); // wrap, flags, pri
+ }
+}
+
+void namcos2_roz_device::draw_roz(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, uint16_t gfx_ctrl)
+{
+ const int xoffset = 38, yoffset = 0;
+ struct roz_param rozParam;
+
+ rozParam.color = (gfx_ctrl & 0x0f00);
+ rozParam.incxx = (int16_t)m_roz_ctrl[0];
+ rozParam.incxy = (int16_t)m_roz_ctrl[1];
+ rozParam.incyx = (int16_t)m_roz_ctrl[2];
+ rozParam.incyy = (int16_t)m_roz_ctrl[3];
+ rozParam.startx = (int16_t)m_roz_ctrl[4];
+ rozParam.starty = (int16_t)m_roz_ctrl[5];
+ rozParam.size = 2048;
+ rozParam.wrap = 1;
+
+
+ switch (m_roz_ctrl[7])
+ {
+ case 0x4400: /* (2048x2048) */
+ break;
+
+ case 0x4488: /* attract mode */
+ rozParam.wrap = 0;
+ break;
+
+ case 0x44cc: /* stage1 demo */
+ rozParam.wrap = 0;
+ break;
+
+ case 0x44ee: /* (256x256) used in Dragon Saber */
+ rozParam.wrap = 0;
+ rozParam.size = 256;
+ break;
+ }
+
+ rozParam.startx <<= 4;
+ rozParam.starty <<= 4;
+ rozParam.startx += xoffset * rozParam.incxx + yoffset * rozParam.incyx;
+ rozParam.starty += xoffset * rozParam.incxy + yoffset * rozParam.incyy;
+
+ rozParam.startx <<= 8;
+ rozParam.starty <<= 8;
+ rozParam.incxx <<= 8;
+ rozParam.incxy <<= 8;
+ rozParam.incyx <<= 8;
+ rozParam.incyy <<= 8;
+
+ draw_roz_helper(screen, bitmap, m_tilemap_roz, cliprect, &rozParam);
+}
+
+void namcos2_roz_device::rozram_word_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_rozram[offset]);
+ m_tilemap_roz->mark_tile_dirty(offset);
+}
+