summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/video/k053250.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/video/k053250.c')
-rw-r--r--trunk/src/emu/video/k053250.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/trunk/src/emu/video/k053250.c b/trunk/src/emu/video/k053250.c
new file mode 100644
index 00000000000..c7a15ed6c10
--- /dev/null
+++ b/trunk/src/emu/video/k053250.c
@@ -0,0 +1,469 @@
+#include "k053250.h"
+
+const device_type K053250 = &device_creator<k053250_t>;
+
+k053250_t::k053250_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, K053250, "K053250", tag, owner, clock)
+{
+}
+
+void k053250_t::static_set_screen_tag(device_t &device, const char *screen_tag)
+{
+ k053250_t &dev = downcast<k053250_t &>(device);
+ dev.screen_tag = screen_tag;
+}
+
+void k053250_t::static_set_offsets(device_t &device, int offx, int offy)
+{
+ k053250_t &dev = downcast<k053250_t &>(device);
+ dev.offx = offx;
+ dev.offy = offy;
+}
+
+void k053250_t::unpack_nibbles()
+{
+ if(!m_region)
+ throw emu_fatalerror("k053250 %s: no associated region found\n", tag());
+
+ const UINT8 *base = m_region->base();
+ int size = m_region->bytes();
+ unpacked = auto_alloc_array(machine(), UINT8, size*2);
+ for(int i=0; i<size; i++) {
+ unpacked[2*i] = base[i] >> 4;
+ unpacked[2*i+1] = base[i] & 15;
+ }
+ unpacked_size = 2*size;
+}
+
+void k053250_t::device_start()
+{
+ screen = machine().device<screen_device>(screen_tag);
+ ram = auto_alloc_array_clear(machine(), UINT16, 0x6000/2);
+ buffer[0] = ram + 0x2000;
+ buffer[1] = ram + 0x2800;
+
+ unpack_nibbles();
+
+ save_pointer(NAME(ram), 0x6000/2);
+ save_item(NAME(regs));
+ save_item(NAME(page));
+ save_item(NAME(frame));
+}
+
+void k053250_t::device_reset()
+{
+ page = 0;
+ frame = -1;
+ memset(regs, 0, sizeof(regs));
+}
+
+// utility function to render a clipped scanline vertically or horizontally
+inline void k053250_t::pdraw_scanline32(bitmap_t *bitmap, const pen_t *palette, UINT8 *source,
+ const rectangle *cliprect, int linepos, int scroll, int zoom,
+ UINT32 clipmask, UINT32 wrapmask, UINT32 orientation, bitmap_t *priority, UINT8 pri)
+{
+// a sixteen-bit fixed point resolution should be adequate to our application
+#define FIXPOINT_PRECISION 16
+#define FIXPOINT_PRECISION_HALF (1<<(FIXPOINT_PRECISION-1))
+
+ int end_pixel, flip, dst_min, dst_max, dst_start, dst_length;
+
+ UINT32 src_wrapmask;
+ UINT8 *src_base;
+ int src_fx, src_fdx;
+ int pix_data, dst_offset;
+ const pen_t *pal_base;
+ UINT8 *pri_base;
+ UINT32 *dst_base;
+ int dst_adv;
+
+ // flip X and flip Y also switch role when the X Y coordinates are swapped
+ if (!(orientation & ORIENTATION_SWAP_XY))
+ {
+ flip = orientation & ORIENTATION_FLIP_X;
+ dst_min = cliprect->min_x;
+ dst_max = cliprect->max_x;
+ }
+ else
+ {
+ flip = orientation & ORIENTATION_FLIP_Y;
+ dst_min = cliprect->min_y;
+ dst_max = cliprect->max_y;
+ }
+
+ if (clipmask)
+ {
+ // reject scanlines that are outside of the target bitmap's right(bottom) clip boundary
+ dst_start = -scroll;
+ if (dst_start > dst_max) return;
+
+ // calculate target length
+ dst_length = clipmask + 1;
+ if (zoom) dst_length = (dst_length << 6) / zoom;
+
+ // reject scanlines that are outside of the target bitmap's left(top) clip boundary
+ end_pixel = dst_start + dst_length - 1;
+ if (end_pixel < dst_min) return;
+
+ // clip scanline tail
+ if ((end_pixel -= dst_max) > 0) dst_length -= end_pixel;
+
+ // reject zero-length scanlines
+ if (dst_length <= 0) return;
+
+ // calculate zoom factor
+ src_fdx = zoom << (FIXPOINT_PRECISION-6);
+
+ // clip scanline head
+ end_pixel = dst_min;
+ if ((end_pixel -= dst_start) > 0)
+ {
+ // chop scanline to the correct length and move target start location to the left(top) clip boundary
+ dst_length -= end_pixel;
+ dst_start = dst_min;
+
+ // and skip the source for the left(top) clip region
+ src_fx = end_pixel * src_fdx + FIXPOINT_PRECISION_HALF;
+ }
+ else
+ // the point five bias is to ensure even distribution of stretched or shrinked pixels
+ src_fx = FIXPOINT_PRECISION_HALF;
+
+ // adjust flipped source
+ if (flip)
+ {
+ // start from the target's clipped end if the scanline is flipped
+ dst_start = dst_max + dst_min - dst_start - (dst_length-1);
+
+ // and move source start location to the opposite end
+ src_fx += (dst_length-1) * src_fdx - 1;
+ src_fdx = -src_fdx;
+ }
+ }
+ else
+ {
+ // draw wrapped scanline at virtual bitmap boundary when source clipping is off
+ dst_start = dst_min;
+ dst_length = dst_max - dst_min + 1; // target scanline spans the entire visible area
+ src_fdx = zoom << (FIXPOINT_PRECISION-6);
+
+ // pre-advance source for the clipped region
+ if (!flip)
+ src_fx = (scroll + dst_min) * src_fdx + FIXPOINT_PRECISION_HALF;
+ else
+ {
+ src_fx = (scroll + dst_max) * src_fdx + FIXPOINT_PRECISION_HALF-1;
+ src_fdx = -src_fdx;
+ }
+ }
+
+ if (!(orientation & ORIENTATION_SWAP_XY))
+ {
+ // calculate target increment for horizontal scanlines which is exactly one
+ dst_adv = 1;
+ dst_offset = dst_length;
+ pri_base = BITMAP_ADDR8(priority, linepos, dst_start + dst_offset);
+ dst_base = BITMAP_ADDR32(bitmap, linepos, dst_start + dst_length);
+ }
+ else
+ {
+ // calculate target increment for vertical scanlines which is the bitmap's pitch value
+ dst_adv = bitmap->rowpixels;
+ dst_offset= dst_length * dst_adv;
+ pri_base = BITMAP_ADDR8(priority, dst_start, linepos + dst_offset);
+ dst_base = BITMAP_ADDR32(bitmap, dst_start, linepos + dst_offset);
+ }
+
+ // generalized
+ src_base = source;
+
+ // there is no need to wrap source offsets along with source clipping
+ // so we set all bits of the wrapmask to one
+ src_wrapmask = (clipmask) ? ~0 : wrapmask;
+
+ pal_base = palette;
+ dst_offset = -dst_offset; // negate target offset in order to terminated draw loop at zero condition
+
+ if (pri)
+ {
+ // draw scanline and update priority bitmap
+ do
+ {
+ pix_data = src_base[(src_fx>>FIXPOINT_PRECISION) & src_wrapmask];
+ src_fx += src_fdx;
+
+ if (pix_data)
+ {
+ pix_data = pal_base[pix_data];
+ pri_base[dst_offset] = pri;
+ dst_base[dst_offset] = pix_data;
+ }
+ }
+ while (dst_offset += dst_adv);
+ }
+ else
+ {
+ // draw scanline but do not update priority bitmap
+ do
+ {
+ pix_data = src_base[(src_fx>>FIXPOINT_PRECISION) & src_wrapmask];
+ src_fx += src_fdx;
+
+ if (pix_data)
+ {
+ dst_base[dst_offset] = pal_base[pix_data];
+ }
+ }
+ while (dst_offset += dst_adv);
+ }
+
+#undef FIXPOINT_PRECISION
+#undef FIXPOINT_PRECISION_HALF
+}
+
+void k053250_t::draw( bitmap_t *bitmap, const rectangle *cliprect, int colorbase, int flags, int priority )
+{
+ UINT8 *pix_ptr;
+ const pen_t *pal_base, *pal_ptr;
+ UINT32 src_clipmask, src_wrapmask, dst_wrapmask;
+ int linedata_offs, line_pos, line_start, line_end, scroll_corr;
+ int color, offset, zoom, scroll, passes, i;
+ bool wrap500 = false;
+
+ UINT16 *line_ram = buffer[page]; // pointer to physical line RAM
+ int map_scrollx = short(regs[0] << 8 | regs[1]) - offx; // signed horizontal scroll value
+ int map_scrolly = short(regs[2] << 8 | regs[3]) - offy; // signed vertical scroll value
+ UINT8 ctrl = regs[4]; // register four is the main control register
+
+ // copy visible boundary values to more accessible locations
+ int dst_minx = cliprect->min_x;
+ int dst_maxx = cliprect->max_x;
+ int dst_miny = cliprect->min_y;
+ int dst_maxy = cliprect->max_y;
+
+ int orientation = 0; // orientation defaults to no swapping and no flipping
+ int dst_height = 512; // virtual bitmap height defaults to five hundred and twelve pixels
+ int linedata_adv = 4; // line info packets are four words(eight bytes) apart
+
+ // switch X and Y parameters when the first bit of the control register is cleared
+ if (!(ctrl & 0x01)) orientation |= ORIENTATION_SWAP_XY;
+
+ // invert X parameters when the forth bit of the control register is set
+ if (ctrl & 0x08) orientation |= ORIENTATION_FLIP_X;
+
+ // invert Y parameters when the fifth bit of the control register is set
+ if (ctrl & 0x10) orientation |= ORIENTATION_FLIP_Y;
+
+ switch (ctrl >> 5) // the upper four bits of the control register select source and target dimensions
+ {
+ case 0 :
+ // Xexex: L6 galaxies
+ // Metam: L4 forest, L5 arena, L6 tower interior, final boss
+
+ // crop source offset between zero and two hundred and fifty-five inclusive,
+ // and set virtual bitmap height to two hundred and fifty-six pixels
+ src_wrapmask = src_clipmask = 0xff;
+ dst_height = 0x100;
+ break;
+ case 1 :
+ // Xexex: prologue, L7 nebulae
+
+ // the source offset is cropped to zero and five hundred and eleven inclusive
+ src_wrapmask = src_clipmask = 0x1ff;
+ break;
+ case 4 :
+ // Xexex: L1 sky and boss, L3 planet, L5 poly-face, L7 battle ship patches
+ // Metam: L1 summoning circle, L3 caves, L6 gargoyle towers
+
+ // crop source offset between zero and two hundred and fifty-five inclusive,
+ // and allow source offset to wrap back at 500 hexadecimal to minus 300 hexadecimal
+ src_wrapmask = src_clipmask = 0xff;
+ wrap500 = true;
+ break;
+// case 2 : // Xexex: title
+// case 7 : // Xexex: L4 organic stage
+ default:
+ // crop source offset between zero and one thousand and eleven inclusive,
+ // keep other dimensions to their defaults
+ src_wrapmask = src_clipmask = 0x3ff;
+ break;
+ }
+
+ // disable source clipping when the third bit of the control register is set
+ if (ctrl & 0x04) src_clipmask = 0;
+
+ if (!(orientation & ORIENTATION_SWAP_XY)) // normal orientaion with no X Y switching
+ {
+ line_start = dst_miny; // the first scanline starts at the minimum Y clip location
+ line_end = dst_maxy; // the last scanline ends at the maximum Y clip location
+ scroll_corr = map_scrollx; // concentrate global X scroll
+ linedata_offs = map_scrolly; // determine where to get info for the first line
+
+ if (orientation & ORIENTATION_FLIP_X)
+ {
+ scroll_corr = -scroll_corr; // X scroll adjustment should be negated in X flipped scenarioes
+ }
+
+ if (orientation & ORIENTATION_FLIP_Y)
+ {
+ linedata_adv = -linedata_adv; // traverse line RAM backward in Y flipped scenarioes
+ linedata_offs += bitmap->height - 1; // and get info for the first line from the bottom
+ }
+
+ dst_wrapmask = ~0; // scanlines don't seem to wrap horizontally in normal orientation
+ passes = 1; // draw scanline in a single pass
+ }
+ else // orientaion with X and Y parameters switched
+ {
+ line_start = dst_minx; // the first scanline starts at the minimum X clip location
+ line_end = dst_maxx; // the last scanline ends at the maximum X clip location
+ scroll_corr = map_scrolly; // concentrate global Y scroll
+ linedata_offs = map_scrollx; // determine where to get info for the first line
+
+ if (orientation & ORIENTATION_FLIP_Y)
+ {
+ scroll_corr = 0x100 - scroll_corr; // apply common vertical correction
+
+ // Y correction (ref: 1st and 5th boss)
+ scroll_corr -= 2; // apply unique vertical correction
+
+ // X correction (ref: 1st boss, seems to undo non-rotated global X offset)
+ linedata_offs -= 5; // apply unique horizontal correction
+ }
+
+ if (orientation & ORIENTATION_FLIP_X)
+ {
+ linedata_adv = -linedata_adv; // traverse line RAM backward in X flipped scenarioes
+ linedata_offs += bitmap->width - 1; // and get info for the first line from the bottom
+ }
+
+ if (src_clipmask)
+ {
+ // determine target wrap boundary and draw scanline in two passes if the source is clipped
+ dst_wrapmask = dst_height - 1;
+ passes = 2;
+ }
+ else
+ {
+ // otherwise disable target wraparound and draw scanline in a single pass
+ dst_wrapmask = ~0;
+ passes = 1;
+ }
+ }
+
+ linedata_offs *= 4; // each line info packet has four words(eight bytes)
+ linedata_offs &= 0x7ff; // and it should wrap at the four-kilobyte boundary
+ linedata_offs += line_start * linedata_adv; // pre-advance line info offset for the clipped region
+
+ // load physical palette base
+ pal_base = machine().pens + (colorbase << 4) % machine().total_colors();
+
+ // walk the target bitmap within the visible area vertically or horizontally, one line at a time
+ for (line_pos=line_start; line_pos <= line_end; linedata_offs += linedata_adv, line_pos++)
+ {
+ linedata_offs &= 0x7ff; // line info data wraps at the four-kilobyte boundary
+
+ color = line_ram[linedata_offs]; // get scanline color code
+ if (color == 0xffff) continue; // reject scanline if color code equals minus one
+
+ offset = line_ram[linedata_offs + 1]; // get first pixel offset in ROM
+ if (!(color & 0xff) && !offset) continue; // reject scanline if both color and pixel offset are zero
+
+ // calculate physical palette location
+ // there can be thirty-two color codes and each code represents sixteen pens
+ pal_ptr = pal_base + ((color & 0x1f) << 4);
+
+ // calculate physical pixel location
+ // each offset unit represents two hundred and fifty six pixels and should wrap at ROM boundary for safety
+ pix_ptr = unpacked + ((offset << 8) % unpacked_size);
+
+ // get scanline zoom factor
+ // For example, 0x20 doubles the length, 0x40 maintains a one-to-one length,
+ // and 0x80 halves the length. The zoom center is at the beginning of the
+ // scanline therefore it is not necessary to adjust render start position
+ zoom = line_ram[linedata_offs + 2];
+
+ scroll = (short)line_ram[linedata_offs + 3]; // get signed local scroll value for the current scanline
+
+ // scavenged from old code; improves Xexex' first level sky
+ if (wrap500 && scroll >= 0x500) scroll -= 0x800;
+
+ scroll += scroll_corr; // apply final scroll correction
+ scroll &= dst_wrapmask; // wraparound scroll value if necessary
+
+ // draw scanlines wrapped at virtual bitmap boundary in two passes
+ // this should not impose too much overhead due to clipping performed by the render code
+ i = passes;
+ do
+ {
+ /*
+ Parameter descriptions:
+
+ bitmap : pointer to a MAME bitmap as the render target
+ pal_ptr : pointer to the palette's physical location relative to the scanline
+ pix_ptr : pointer to the physical start location of source pixels in ROM
+ cliprect : pointer to a rectangle structue which describes the visible area of the target bitmap
+ line_pos : scanline render position relative to the target bitmap
+ should be a Y offset to the target bitmap in normal orientaion,
+ or an X offset to the target bitmap if X,Y are swapped
+ scroll : source scroll value of the scanline
+ zoom : source zoom factor of the scanline
+ src_clipmask : source offset clip mask; source pixels with offsets beyond the scope of this mask will not be drawn
+ src_wrapmask : source offset wrap mask; wraps source offset around, no effect when src_clipmask is set
+ orientation : flags indicating whether scanlines should be drawn horizontally, vertically, forward or backward
+ priority : value to be written to the priority bitmap, no effect when equals zero
+ */
+ pdraw_scanline32(bitmap, pal_ptr, pix_ptr, cliprect,
+ line_pos, scroll, zoom, src_clipmask, src_wrapmask, orientation, machine().priority_bitmap, (UINT8)priority);
+
+ // shift scanline position one virtual screen upward to render the wrapped end if necessary
+ scroll -= dst_height;
+ }
+ while (--i);
+ }
+}
+
+void k053250_t::dma(int limiter)
+{
+ int current_frame = screen->frame_number();
+
+ if (limiter && current_frame == frame)
+ return; // make sure we only do DMA transfer once per frame
+
+ frame = current_frame;
+ memcpy(buffer[page], ram, 0x1000);
+ page ^= 1;
+}
+
+READ16_MEMBER(k053250_t::reg_r)
+{
+ return regs[offset];
+}
+
+WRITE16_MEMBER(k053250_t::reg_w)
+{
+ if (ACCESSING_BITS_0_7)
+ {
+ // start LVC DMA transfer at the falling edge of control register's bit1
+ if (offset == 4 && !(data & 2) && (regs[4] & 2))
+ dma(1);
+
+ regs[offset] = data;
+ }
+}
+
+READ16_MEMBER(k053250_t::ram_r)
+{
+ return ram[offset];
+}
+
+WRITE16_MEMBER(k053250_t::ram_w)
+{
+ COMBINE_DATA(ram+offset);
+}
+
+READ16_MEMBER(k053250_t::rom_r)
+{
+ return m_region->base()[0x80000 * regs[6] + 0x800 * regs[7] + offset/2];
+}
+