summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/policetr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/policetr.c')
-rw-r--r--src/mame/video/policetr.c370
1 files changed, 370 insertions, 0 deletions
diff --git a/src/mame/video/policetr.c b/src/mame/video/policetr.c
new file mode 100644
index 00000000000..129a3464f10
--- /dev/null
+++ b/src/mame/video/policetr.c
@@ -0,0 +1,370 @@
+/***************************************************************************
+
+ P&P Marketing Police Trainer hardware
+
+***************************************************************************/
+
+#include "driver.h"
+#include "cpu/mips/r3000.h"
+#include "policetr.h"
+
+
+/* constants */
+#define SRCBITMAP_WIDTH 4096
+
+#define DSTBITMAP_WIDTH 512
+#define DSTBITMAP_HEIGHT 256
+
+
+/* local variables */
+static UINT32 palette_offset;
+static UINT8 palette_index;
+static UINT8 palette_data[3];
+
+static rectangle render_clip;
+static UINT8 *srcbitmap;
+static UINT8 *dstbitmap;
+
+static UINT16 src_xoffs, src_yoffs;
+static UINT16 dst_xoffs, dst_yoffs;
+static UINT8 video_latch;
+
+static UINT32 srcbitmap_height_mask;
+
+
+
+/*************************************
+ *
+ * Video system start
+ *
+ *************************************/
+
+VIDEO_START( policetr )
+{
+ /* the source bitmap is in ROM */
+ srcbitmap = memory_region(REGION_GFX1);
+
+ /* compute the height */
+ srcbitmap_height_mask = (memory_region_length(REGION_GFX1) / SRCBITMAP_WIDTH) - 1;
+
+ /* the destination bitmap is not directly accessible to the CPU */
+ dstbitmap = auto_malloc(DSTBITMAP_WIDTH * DSTBITMAP_HEIGHT);
+}
+
+
+
+/*************************************
+ *
+ * Display list processor
+ *
+ *************************************/
+
+static void render_display_list(offs_t offset)
+{
+ /* mask against the R3000 address space */
+ offset &= 0x1fffffff;
+
+ /* loop over all items */
+ while (offset != 0x1fffffff)
+ {
+ UINT32 *entry = &policetr_rambase[offset / 4];
+ UINT32 srcx = entry[0] & 0xfffffff;
+ UINT32 srcy = entry[1] & ((srcbitmap_height_mask << 16) | 0xffff);
+ UINT32 srcxstep = entry[2];
+ UINT32 srcystep = entry[3];
+ int dstw = (entry[4] & 0x1ff) + 1;
+ int dsth = ((entry[4] >> 12) & 0x1ff) + 1;
+ int dstx = entry[5] & 0x1ff;
+ int dsty = (entry[5] >> 12) & 0x1ff;
+ UINT8 mask = ~entry[6] >> 16;
+ UINT8 color = (entry[6] >> 24) & ~mask;
+ UINT32 curx, cury;
+ int x, y;
+
+ if (dstx > render_clip.max_x)
+ {
+ dstw -= (512 - dstx);
+ dstx = 0;
+ }
+ /* apply X clipping */
+ if (dstx < render_clip.min_x)
+ {
+ srcx += srcxstep * (render_clip.min_x - dstx);
+ dstw -= render_clip.min_x - dstx;
+ dstx = render_clip.min_x;
+ }
+ if (dstx + dstw > render_clip.max_x)
+ dstw = render_clip.max_x - dstx + 1;
+
+ /* apply Y clipping */
+ if (dsty < render_clip.min_y)
+ {
+ srcy += srcystep * (render_clip.min_y - dsty);
+ dsth -= render_clip.min_y - dsty;
+ dsty = render_clip.min_y;
+ }
+ if (dsty + dsth > render_clip.max_y)
+ dsth = render_clip.max_y - dsty + 1;
+
+ /* special case for fills */
+ if (srcxstep == 0 && srcystep == 0)
+ {
+ /* prefetch the pixel */
+ UINT8 pixel = srcbitmap[((srcy >> 16) * srcbitmap_height_mask) * SRCBITMAP_WIDTH + (srcx >> 16) % SRCBITMAP_WIDTH];
+ pixel = color | (pixel & mask);
+
+ /* loop over rows and columns */
+ if (dstw > 0)
+ for (y = 0; y < dsth; y++)
+ {
+ UINT8 *dst = &dstbitmap[(dsty + y) * DSTBITMAP_WIDTH + dstx];
+ memset(dst, pixel, dstw);
+ }
+ }
+
+ /* otherwise, standard render */
+ else
+ {
+ /* loop over rows */
+ for (y = 0, cury = srcy; y < dsth; y++, cury += srcystep)
+ {
+ UINT8 *src = &srcbitmap[((cury >> 16) & srcbitmap_height_mask) * SRCBITMAP_WIDTH];
+ UINT8 *dst = &dstbitmap[(dsty + y) * DSTBITMAP_WIDTH + dstx];
+
+ /* loop over columns */
+ for (x = 0, curx = srcx; x < dstw; x++, curx += srcxstep)
+ {
+ UINT8 pixel = src[(curx >> 16) % SRCBITMAP_WIDTH];
+ if (pixel)
+ dst[x] = color | (pixel & mask);
+ }
+ }
+ }
+
+ /* advance to the next link */
+ offset = entry[7] & 0x1fffffff;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video controller writes
+ *
+ *************************************/
+
+WRITE32_HANDLER( policetr_video_w )
+{
+ /* we assume 4-byte accesses */
+ if (mem_mask)
+ logerror("%08X: policetr_video_w access with mask %08X\n", activecpu_get_previouspc(), ~mem_mask);
+
+ /* 4 offsets */
+ switch (offset)
+ {
+ /* offset 0 specifies the start address of a display list */
+ case 0:
+ render_display_list(data);
+ break;
+
+ /* offset 1 specifies a latch value in the upper 8 bits */
+ case 1:
+ video_latch = data >> 24;
+ break;
+
+ /* offset 2 has various meanings based on the latch */
+ case 2:
+ {
+ switch (video_latch)
+ {
+ /* latch 0x04 specifies the source X offset for a source bitmap pixel read */
+ case 0x04:
+ src_xoffs = data >> 16;
+ break;
+
+ /* latch 0x14 specifies the source Y offset for a source bitmap pixel read */
+ case 0x14:
+ src_yoffs = data >> 16;
+ break;
+
+ /* latch 0x20 specifies the top/left corners of the render cliprect */
+ case 0x20:
+ render_clip.min_y = (data >> 12) & 0xfff;
+ render_clip.min_x = data & 0xfff;
+ break;
+
+ /* latch 0x30 specifies the bottom/right corners of the render cliprect */
+ case 0x30:
+ render_clip.max_y = (data >> 12) & 0xfff;
+ render_clip.max_x = data & 0xfff;
+ break;
+
+ /* latch 0x50 allows a direct write to the destination bitmap */
+ case 0x50:
+ if (ACCESSING_MSB32 && dst_xoffs < DSTBITMAP_WIDTH && dst_yoffs < DSTBITMAP_HEIGHT)
+ dstbitmap[dst_yoffs * DSTBITMAP_WIDTH + dst_xoffs] = data >> 24;
+ break;
+
+ /* log anything else */
+ default:
+ logerror("%08X: policetr_video_w(2) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+ }
+ break;
+ }
+
+ /* offset 3 has various meanings based on the latch */
+ case 3:
+ {
+ switch (video_latch)
+ {
+ /* latch 0x00 is unknown; 0, 1, and 2 get written into the upper 12 bits before rendering */
+ case 0x00:
+ if (data != (0 << 20) && data != (1 << 20) && data != (2 << 20))
+ logerror("%08X: policetr_video_w(3) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+
+ /* latch 0x10 specifies destination bitmap X and Y offsets */
+ case 0x10:
+ dst_yoffs = (data >> 12) & 0xfff;
+ dst_xoffs = data & 0xfff;
+ break;
+
+ /* latch 0x20 is unknown; either 0xef or 0x100 is written every IRQ4 */
+ case 0x20:
+ if (data != (0x100 << 12) && data != (0xef << 12))
+ logerror("%08X: policetr_video_w(3) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+
+ /* latch 0x40 is unknown; a 0 is written every IRQ4 */
+ case 0x40:
+ if (data != 0)
+ logerror("%08X: policetr_video_w(3) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+
+ /* latch 0x50 clears IRQ4 */
+ case 0x50:
+ cpunum_set_input_line(0, R3000_IRQ4, CLEAR_LINE);
+ break;
+
+ /* latch 0x60 clears IRQ5 */
+ case 0x60:
+ cpunum_set_input_line(0, R3000_IRQ5, CLEAR_LINE);
+ break;
+
+ /* log anything else */
+ default:
+ logerror("%08X: policetr_video_w(3) = %08X & %08X with latch %02X\n", activecpu_get_previouspc(), data, ~mem_mask, video_latch);
+ break;
+ }
+ break;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Video controller reads
+ *
+ *************************************/
+
+READ32_HANDLER( policetr_video_r )
+{
+ int inputval;
+
+ /* the value read is based on the latch */
+ switch (video_latch)
+ {
+ /* latch 0x00 is player 1's gun X coordinate */
+ case 0x00:
+ inputval = ((readinputport(3) & 0xff) * Machine->screen[0].width) >> 8;
+ inputval += 0x50;
+ return (inputval << 20) | 0x20000000;
+
+ /* latch 0x01 is player 1's gun Y coordinate */
+ case 0x01:
+ inputval = ((readinputport(4) & 0xff) * Machine->screen[0].height) >> 8;
+ inputval += 0x17;
+ return (inputval << 20);
+
+ /* latch 0x02 is player 2's gun X coordinate */
+ case 0x02:
+ inputval = ((readinputport(5) & 0xff) * Machine->screen[0].width) >> 8;
+ inputval += 0x50;
+ return (inputval << 20) | 0x20000000;
+
+ /* latch 0x03 is player 2's gun Y coordinate */
+ case 0x03:
+ inputval = ((readinputport(6) & 0xff) * Machine->screen[0].height) >> 8;
+ inputval += 0x17;
+ return (inputval << 20);
+
+ /* latch 0x04 is the pixel value in the ROM at the specified address */
+ case 0x04:
+ return srcbitmap[(src_yoffs & srcbitmap_height_mask) * SRCBITMAP_WIDTH + src_xoffs % SRCBITMAP_WIDTH] << 24;
+
+ /* latch 0x50 is read at IRQ 4; the top 2 bits are checked. If they're not 0,
+ they skip the rest of the interrupt processing */
+ case 0x50:
+ return 0;
+ }
+
+ /* log anything else */
+ logerror("%08X: policetr_video_r with latch %02X\n", activecpu_get_previouspc(), video_latch);
+ return 0;
+}
+
+
+
+
+/*************************************
+ *
+ * Palette access
+ *
+ *************************************/
+
+WRITE32_HANDLER( policetr_palette_offset_w )
+{
+ if (!(mem_mask & 0x00ff0000))
+ {
+ palette_offset = (data >> 16) & 0xff;
+ palette_index = 0;
+ }
+}
+
+
+WRITE32_HANDLER( policetr_palette_data_w )
+{
+ if (!(mem_mask & 0x00ff0000))
+ {
+ palette_data[palette_index] = (data >> 16) & 0xff;
+ if (++palette_index == 3)
+ {
+ palette_set_color(Machine, palette_offset, MAKE_RGB(palette_data[0], palette_data[1], palette_data[2]));
+ palette_index = 0;
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( policetr )
+{
+ int width = cliprect->max_x - cliprect->min_x + 1;
+ int y;
+
+ /* render all the scanlines from the dstbitmap to MAME's bitmap */
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ draw_scanline8(bitmap, cliprect->min_x, y, width, &dstbitmap[DSTBITMAP_WIDTH * y + cliprect->min_x], NULL, -1);
+
+ return 0;
+}