diff options
Diffstat (limited to 'src/mame/video/leland.c')
-rw-r--r-- | src/mame/video/leland.c | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/src/mame/video/leland.c b/src/mame/video/leland.c new file mode 100644 index 00000000000..1f44b6e6b4e --- /dev/null +++ b/src/mame/video/leland.c @@ -0,0 +1,573 @@ +/*************************************************************************** + + Cinemat/Leland driver + + Leland video hardware + +***************************************************************************/ + +#include "driver.h" +#include "leland.h" +#include "sound/dac.h" + + +/* constants */ +#define VRAM_SIZE 0x10000 +#define QRAM_SIZE 0x10000 + +#define VIDEO_WIDTH 0x28 +#define VIDEO_HEIGHT 0x1e + + +/* debugging */ +#define LOG_COMM 0 + + + +struct vram_state_data +{ + UINT16 addr; + UINT8 latch[2]; +}; + + +/* video RAM */ +UINT8 *ataxx_qram; +UINT8 leland_last_scanline_int; +static mame_bitmap *fgbitmap; +static UINT8 *leland_video_ram; + +/* video RAM bitmap drawing */ +static struct vram_state_data vram_state[2]; +static UINT8 sync_next_write; + +/* partial screen updating */ +static int next_update_scanline; + +/* scroll background registers */ +static UINT16 xscroll; +static UINT16 yscroll; +static UINT8 gfxbank; + + + +/************************************* + * + * Start video hardware + * + *************************************/ + +VIDEO_START( leland ) +{ + /* allocate memory */ + leland_video_ram = auto_malloc(VRAM_SIZE); + fgbitmap = auto_bitmap_alloc(VIDEO_WIDTH * 8, VIDEO_HEIGHT * 8, machine->screen[0].format); + + /* reset videoram */ + memset(leland_video_ram, 0, VRAM_SIZE); +} + + +VIDEO_START( ataxx ) +{ + /* first do the standard stuff */ + video_start_leland(machine); + + /* allocate memory */ + ataxx_qram = auto_malloc(QRAM_SIZE); + + /* reset QRAM */ + memset(ataxx_qram, 0, QRAM_SIZE); +} + + + +/************************************* + * + * Scrolling and banking + * + *************************************/ + +WRITE8_HANDLER( leland_gfx_port_w ) +{ + /* adjust the proper scroll value */ + switch (offset) + { + case -1: + if (gfxbank != data) + { + video_screen_update_partial(0, leland_last_scanline_int); + gfxbank = data; + } + break; + + case 0: + if ((xscroll & 0xff) != data) + { + video_screen_update_partial(0, leland_last_scanline_int); + xscroll = (xscroll & 0xff00) | (data & 0x00ff); + } + break; + + case 1: + if ((xscroll >> 8) != data) + { + video_screen_update_partial(0, leland_last_scanline_int); + xscroll = (xscroll & 0x00ff) | ((data << 8) & 0xff00); + } + break; + + case 2: + if ((yscroll & 0xff) != data) + { + video_screen_update_partial(0, leland_last_scanline_int); + yscroll = (yscroll & 0xff00) | (data & 0x00ff); + } + break; + + case 3: + if ((yscroll >> 8) != data) + { + video_screen_update_partial(0, leland_last_scanline_int); + yscroll = (yscroll & 0x00ff) | ((data << 8) & 0xff00); + } + break; + } +} + + + +/************************************* + * + * Video address setting + * + *************************************/ + +static void leland_video_addr_w(int offset, int data, int num) +{ + struct vram_state_data *state = vram_state + num; + + if (!offset) + state->addr = (state->addr & 0xfe00) | ((data << 1) & 0x01fe); + else + state->addr = ((data << 9) & 0xfe00) | (state->addr & 0x01fe); + + if (num == 0) + sync_next_write = (state->addr >= 0xf000); +} + + + +/************************************* + * + * Flush data from VRAM into our copy + * + *************************************/ + +static void update_for_scanline(int scanline) +{ + int i, j; + + /* skip if we're behind the times */ + if (scanline <= next_update_scanline) + return; + + /* update all scanlines */ + for (i = next_update_scanline; i < scanline; i++) + if (i < VIDEO_HEIGHT * 8) + { + UINT8 scandata[VIDEO_WIDTH * 8]; + UINT8 *dst = scandata; + UINT8 *src = &leland_video_ram[i * 256]; + + for (j = 0; j < VIDEO_WIDTH * 8 / 2; j++) + { + UINT8 pix = *src++; + *dst++ = pix >> 4; + *dst++ = pix & 15; + } + draw_scanline8(fgbitmap, 0, i, VIDEO_WIDTH * 8, scandata, NULL, -1); + } + + /* also update the DACs */ + if (scanline >= VIDEO_HEIGHT * 8) + scanline = 256; + for (i = next_update_scanline; i < scanline; i++) + { + if (!(leland_dac_control & 0x01)) + leland_dac_update(0, leland_video_ram[i * 256 + 160]); + if (!(leland_dac_control & 0x02)) + leland_dac_update(1, leland_video_ram[i * 256 + 161]); + } + + /* set the new last update */ + next_update_scanline = scanline; +} + + + +/************************************* + * + * Common video RAM read + * + *************************************/ + +static int leland_vram_port_r(int offset, int num) +{ + struct vram_state_data *state = vram_state + num; + int addr = state->addr; + int inc = (offset >> 2) & 2; + int ret; + + switch (offset & 7) + { + case 3: /* read hi/lo (alternating) */ + ret = leland_video_ram[addr]; + addr += inc & (addr << 1); + addr ^= 1; + break; + + case 5: /* read hi */ + ret = leland_video_ram[addr | 1]; + addr += inc; + break; + + case 6: /* read lo */ + ret = leland_video_ram[addr & ~1]; + addr += inc; + break; + + default: + logerror("CPU #%d %04x Warning: Unknown video port %02x read (address=%04x)\n", + cpu_getactivecpu(),activecpu_get_pc(), offset, addr); + ret = 0; + break; + } + state->addr = addr; + + if (LOG_COMM && addr >= 0xf000) + logerror("%04X:%s comm read %04X = %02X\n", activecpu_get_previouspc(), num ? "slave" : "master", addr, ret); + + return ret; +} + + + +/************************************* + * + * Common video RAM write + * + *************************************/ + +static void leland_vram_port_w(int offset, int data, int num) +{ + struct vram_state_data *state = vram_state + num; + int addr = state->addr; + int inc = (offset >> 2) & 2; + int trans = (offset >> 4) & num; + + /* if we're writing "behind the beam", make sure we've cached what was there */ + if (addr < 0xf000) + { + int cur_scanline = video_screen_get_vpos(0); + int mod_scanline = addr / 256; + + if (cur_scanline != next_update_scanline && mod_scanline < cur_scanline) + update_for_scanline(cur_scanline); + } + + if (LOG_COMM && addr >= 0xf000) + logerror("%04X:%s comm write %04X = %02X\n", activecpu_get_previouspc(), num ? "slave" : "master", addr, data); + + /* based on the low 3 bits of the offset, update the destination */ + switch (offset & 7) + { + case 1: /* write hi = data, lo = latch */ + leland_video_ram[addr & ~1] = state->latch[0]; + leland_video_ram[addr | 1] = data; + addr += inc; + break; + + case 2: /* write hi = latch, lo = data */ + leland_video_ram[addr & ~1] = data; + leland_video_ram[addr | 1] = state->latch[1]; + addr += inc; + break; + + case 3: /* write hi/lo = data (alternating) */ + if (trans) + { + if (!(data & 0xf0)) data |= leland_video_ram[addr] & 0xf0; + if (!(data & 0x0f)) data |= leland_video_ram[addr] & 0x0f; + } + leland_video_ram[addr] = data; + addr += inc & (addr << 1); + addr ^= 1; + break; + + case 5: /* write hi = data */ + state->latch[1] = data; + if (trans) + { + if (!(data & 0xf0)) data |= leland_video_ram[addr | 1] & 0xf0; + if (!(data & 0x0f)) data |= leland_video_ram[addr | 1] & 0x0f; + } + leland_video_ram[addr | 1] = data; + addr += inc; + break; + + case 6: /* write lo = data */ + state->latch[0] = data; + if (trans) + { + if (!(data & 0xf0)) data |= leland_video_ram[addr & ~1] & 0xf0; + if (!(data & 0x0f)) data |= leland_video_ram[addr & ~1] & 0x0f; + } + leland_video_ram[addr & ~1] = data; + addr += inc; + break; + + default: + logerror("CPU #%d %04x Warning: Unknown video port write (address=%04x value=%02x)\n", + cpu_getactivecpu(),activecpu_get_pc(), offset, addr); + break; + } + + /* update the address and plane */ + state->addr = addr; +} + + + +/************************************* + * + * Master video RAM read/write + * + *************************************/ + +WRITE8_HANDLER( leland_master_video_addr_w ) +{ + leland_video_addr_w(offset, data, 0); +} + + +static TIMER_CALLBACK( leland_delayed_mvram_w ) +{ + int num = (param >> 16) & 1; + int offset = (param >> 8) & 0xff; + int data = param & 0xff; + leland_vram_port_w(offset, data, num); +} + + +WRITE8_HANDLER( leland_mvram_port_w ) +{ + if (sync_next_write) + { + timer_call_after_resynch(0x00000 | (offset << 8) | data, leland_delayed_mvram_w); + sync_next_write = 0; + } + else + leland_vram_port_w(offset, data, 0); +} + + +READ8_HANDLER( leland_mvram_port_r ) +{ + return leland_vram_port_r(offset, 0); +} + + + +/************************************* + * + * Slave video RAM read/write + * + *************************************/ + +WRITE8_HANDLER( leland_slave_video_addr_w ) +{ + leland_video_addr_w(offset, data, 1); +} + + +WRITE8_HANDLER( leland_svram_port_w ) +{ + leland_vram_port_w(offset, data, 1); +} + + +READ8_HANDLER( leland_svram_port_r ) +{ + return leland_vram_port_r(offset, 1); +} + + + +/************************************* + * + * Ataxx master video RAM read/write + * + *************************************/ + +WRITE8_HANDLER( ataxx_mvram_port_w ) +{ + offset = ((offset >> 1) & 0x07) | ((offset << 3) & 0x08) | (offset & 0x10); + if (sync_next_write) + { + timer_call_after_resynch(0x00000 | (offset << 8) | data, leland_delayed_mvram_w); + sync_next_write = 0; + } + else + leland_vram_port_w(offset, data, 0); +} + + +WRITE8_HANDLER( ataxx_svram_port_w ) +{ + offset = ((offset >> 1) & 0x07) | ((offset << 3) & 0x08) | (offset & 0x10); + leland_vram_port_w(offset, data, 1); +} + + + +/************************************* + * + * Ataxx slave video RAM read/write + * + *************************************/ + +READ8_HANDLER( ataxx_mvram_port_r ) +{ + offset = ((offset >> 1) & 0x07) | ((offset << 3) & 0x08) | (offset & 0x10); + return leland_vram_port_r(offset, 0); +} + + +READ8_HANDLER( ataxx_svram_port_r ) +{ + offset = ((offset >> 1) & 0x07) | ((offset << 3) & 0x08) | (offset & 0x10); + return leland_vram_port_r(offset, 1); +} + + + +/************************************* + * + * End-of-frame routine + * + *************************************/ + +static TIMER_CALLBACK( scanline_reset ) +{ + /* flush the remaining scanlines */ + next_update_scanline = 0; + + /* turn off the DACs at the start of the frame */ + leland_dac_control = 3; +} + + +VIDEO_EOF( leland ) +{ + /* update anything remaining */ + update_for_scanline(VIDEO_HEIGHT * 8); + + /* set a timer to go off at the top of the frame */ + timer_set(video_screen_get_time_until_pos(0, 0, 0), 0, scanline_reset); +} + + + +/************************************* + * + * ROM-based refresh routine + * + *************************************/ + +VIDEO_UPDATE( leland ) +{ + const UINT8 *background_prom = memory_region(REGION_USER1); + const gfx_element *gfx = machine->gfx[0]; + int char_bank = ((gfxbank >> 4) & 0x03) * 0x0400; + int prom_bank = ((gfxbank >> 3) & 0x01) * 0x2000; + int xcoarse = xscroll / 8; + int ycoarse = yscroll / 8; + int xfine = xscroll % 8; + int yfine = yscroll % 8; + int x, y; + + /* update anything remaining */ + update_for_scanline(cliprect->max_y); + + /* draw what's visible to the main bitmap */ + for (y = cliprect->min_y / 8; y < cliprect->max_y / 8 + 2; y++) + { + int ysum = ycoarse + y; + for (x = 0; x < VIDEO_WIDTH + 1; x++) + { + int xsum = xcoarse + x; + int offs = ((xsum << 0) & 0x000ff) | + ((ysum << 8) & 0x01f00) | + prom_bank | + ((ysum << 9) & 0x1c000); + int code = background_prom[offs] | + ((ysum << 2) & 0x300) | + char_bank; + int color = (code >> 5) & 7; + + /* draw to the bitmap */ + drawgfx(bitmap, gfx, + code, 8 * color, 0, 0, + 8 * x - xfine, 8 * y - yfine, + cliprect, TRANSPARENCY_NONE_RAW, 0); + } + } + + /* Merge the two bitmaps together */ + copybitmap(bitmap, fgbitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_BLEND, 6); + return 0; +} + + + +/************************************* + * + * RAM-based refresh routine + * + *************************************/ + +VIDEO_UPDATE( ataxx ) +{ + const gfx_element *gfx = machine->gfx[0]; + int xcoarse = xscroll / 8; + int ycoarse = yscroll / 8; + int xfine = xscroll % 8; + int yfine = yscroll % 8; + int x, y; + + /* update anything remaining */ + update_for_scanline(cliprect->max_y); + + /* draw what's visible to the main bitmap */ + for (y = cliprect->min_y / 8; y < cliprect->max_y / 8 + 2; y++) + { + int ysum = ycoarse + y; + for (x = 0; x < VIDEO_WIDTH + 1; x++) + { + int xsum = xcoarse + x; + int offs = ((ysum & 0x40) << 9) + ((ysum & 0x3f) << 8) + (xsum & 0xff); + int code = ataxx_qram[offs] | ((ataxx_qram[offs + 0x4000] & 0x7f) << 8); + + /* draw to the bitmap */ + drawgfx(bitmap, gfx, + code, 0, 0, 0, + 8 * x - xfine, 8 * y - yfine, + cliprect, TRANSPARENCY_NONE_RAW, 0); + } + } + + /* Merge the two bitmaps together */ + copybitmap(bitmap, fgbitmap, 0, 0, 0, 0, cliprect, TRANSPARENCY_BLEND, 6); + return 0; +} |