/*************************************************************************** vidhrdw.c Functions to emulate the video hardware of the machine. ***************************************************************************/ #include #include #include #include "z80.h" #include "machine.h" #include "gfxdecod.h" #include "vidhrdw.h" #include "roms.h" #include "memmap.h" #include "osdepend.h" /* Phoenix has 32x32 video ram */ #define H_CHARS 32 #define V_CHARS 32 #define BITMAP_WIDTH (8*H_CHARS) #define BITMAP_HEIGHT (8*V_CHARS) unsigned char chars[2*256*8*8]; /* 32k for character bitmaps */ unsigned char tmpbitmapA[BITMAP_WIDTH * BITMAP_HEIGHT]; /* temporarys bitmap used to hold the */ unsigned char tmpbitmapB[BITMAP_WIDTH * BITMAP_HEIGHT]; /* character mapped part of the screen */ unsigned char *scrbitmap; unsigned char dirtybufferA[VIDEO_RAM_SIZE]; /* keep track of modified portions of the screen */ unsigned char dirtybufferB[VIDEO_RAM_SIZE]; /* to speed up video refresh */ const unsigned char *palette; const unsigned char *colortable; unsigned char remappedtable[4*COLOR_CODES]; unsigned char backgroundpen; /* use these to draw charset B */ unsigned char scrollupd = 1; unsigned char scrollreg = 0; /* use this to select palette */ unsigned char palreg = 0; /* may use this to select video bank - is this ever used?*/ unsigned char bankreg = 0; /*************************************************************************** Initialize the video hardware. Returns 0 if successful. This usually involves no more than loading the graphics roms, decoding them and store the graphics somewhere. ***************************************************************************/ int vh_init(const char *gamename) { char *tmpstorage; int i; if ((tmpstorage = malloc(0x4000)) == 0) return 1; i = 0; while (gamevidinfo[i].name && stricmp(gamename,gamevidinfo[i].name) != 0) i++; if (readroms(tmpstorage,gamevidinfo[i].gfxrom,gamename) != 0) { free(tmpstorage); return 1; } decodechars(tmpstorage,chars); free(tmpstorage); palette = gamevidinfo[i].palette; colortable = gamevidinfo[i].colortable; return 0; } /*************************************************************************** Start the video hardware emulation, that is set up a gfx mode, load the appropriate palette, and return. Returns 0 if successful. ***************************************************************************/ int vh_start(void) { int i; unsigned char pens[TOTAL_COLORS]; if ((scrbitmap = osd_create_display(BITMAP_WIDTH,BITMAP_HEIGHT)) == 0) return 1; for (i = 0;i < TOTAL_COLORS;i++) pens[i] = osd_obtain_pen(palette[3*i],palette[3*i+1],palette[3*i+2]); backgroundpen = pens[0]; for (i = 0;i < 4*COLOR_CODES;i++) remappedtable[i] = pens[colortable[i]]; return 0; } /*************************************************************************** Stop the video hardware emulation. ***************************************************************************/ void vh_stop(void) { osd_close_display(); } /*************************************************************************** Handle a write to memory. This function is called when the emulated code writes to RAM. Arguments: dword A - Memory address to write to. byte V - Value to write into memory. If the address given concerns the video hardware, the write is performed (together with additional operations which might be required by the video hardware) and the function returns non zero. Otherwise, it returns 0. ***************************************************************************/ int vh_wrmem(dword A,byte V) { if (A >= VIDEO_RAM_A_START && A < VIDEO_RAM_A_START + VIDEO_RAM_SIZE) { if (RAM[A] != V) { int offs; offs = A - VIDEO_RAM_A_START; if (offs >= VIDEO_RAM_SIZE) offs -= VIDEO_RAM_SIZE; dirtybufferA[offs] = 1; RAM[A] = V; return 1; } } else if (A >= VIDEO_RAM_B_START && A < VIDEO_RAM_B_START + VIDEO_RAM_SIZE) { if (RAM[A] != V) { int offs; offs = A - VIDEO_RAM_B_START; if (offs >= VIDEO_RAM_SIZE) offs -= VIDEO_RAM_SIZE; dirtybufferB[offs] = 1; RAM[A] = V; return 1; } } else if (A >= SCROLL_REG_START && A < SCROLL_REG_START + SCROLL_REG_SIZE) { if (RAM[A] != V) { scrollupd = 1; scrollreg = V; RAM[A] = V; return 1; } } else if (A >= VIDEO_REG_START && A < VIDEO_REG_START + VIDEO_REG_SIZE) { if (RAM[A] != V) { palreg = (V << 6) >> 7; /* there must be a better way! */ bankreg = (V << 7) >> 7; RAM[A] = V; return 1; } } return 0; } void drawcharA(unsigned char *bitmap,int charcode,int color,int sx,int sy) { int x,y; unsigned char *chardata; const unsigned char *paldata; unsigned char *bm; /* prevent drawing unseen part of video ram */ if (sx < 6 || sx >= H_CHARS || sy < 0 || sy >= V_CHARS) return; sx -= 3; /* centre drawing area */ charcode &= 0xff; /* select color palette */ paldata = &remappedtable[(4 * (charcode >> 5)) + (32 * color)]; chardata = &chars[8*8 * charcode]; bm = &bitmap[8 * (BITMAP_WIDTH * sy + sx)]; for (y = 0;y < 8;y++) { for (x = 0;x < 8;x++) { *(bm++) = paldata[*(chardata++)]; } bm += BITMAP_WIDTH - 8; } } void drawcharB(unsigned char *bitmap,int charcode,int color,int scroll, int sx,int sy) { int x,y,drawpos; unsigned char *chardata; const unsigned char *paldata; unsigned char *bm; /* prevent drawing unseen part of video ram */ if (sx < 6 || sx >= H_CHARS || sy < 0 || sy >= V_CHARS) return; sx -= 3; /* centre drawing area */ charcode &= 0xff; /* select color palette*/ paldata = &remappedtable[(4 * (charcode >> 5)) + (32 * color) + 64]; charcode += 256; chardata = &chars[8*8 * charcode]; /* use scroll register */ drawpos = 8 * (BITMAP_WIDTH * sy + sx) + ((256 - scroll) * BITMAP_WIDTH); if (drawpos >= BITMAP_WIDTH * BITMAP_HEIGHT) drawpos -= BITMAP_WIDTH * BITMAP_HEIGHT; bm = &bitmap[drawpos]; for (y = 0;y < 8;y++) { for (x = 0;x < 8;x++) { /* Prevent drawing the scroll buffer */ if (drawpos + (y * BITMAP_WIDTH) + (x * 8) > 8 * BITMAP_WIDTH) *bm = paldata[*chardata]; bm++; chardata++; } bm += BITMAP_WIDTH - 8; } } /*************************************************************************** Redraw the screen. ***************************************************************************/ void vh_screenrefresh(void) { int i,offs; /* Even if Phoenix's screen is 26x36, the memory layout is 32x32. We therefore */ /* have to convert the memory coordinates into screen coordinates. */ /* Note that 32*32 = 1024, while 26*36 = 832: therefore 192 bytes of Video RAM */ /* don't map to a screen position. We don't check that here, however: range */ /* checking is performed by drawchar(). */ /* for every character in Video RAM A, check if it has been modified */ /* since last time and update it accordingly. */ /* need to check if scroll register has been updated */ /* if so, redraw entire contents of Video RAM B, else */ /* just update it */ /* Update Charset B */ if (scrollupd) { for (offs = 0;offs < VIDEO_RAM_SIZE;offs++) { int sx,sy,mx,my; scrollupd = 0; dirtybufferB[offs] = 0; mx = offs / 32; my = 31 - offs % 32; sx = 31 - mx; sy = 31 - my; drawcharB(tmpbitmapB,RAM[VIDEO_RAM_B_START + offs],palreg,scrollreg,sx,sy); } } else { for (offs = 0;offs < VIDEO_RAM_SIZE;offs++) { int sx,sy,mx,my; if (dirtybufferB[offs]) { dirtybufferB[offs] = 0; mx = offs / 32; my = 31 - offs % 32; sx = 31 - mx; sy = 31 - my; drawcharB(tmpbitmapB,RAM[VIDEO_RAM_B_START + offs],palreg,scrollreg,sx,sy); } } } /* Update Charset A */ for (offs = 0;offs < VIDEO_RAM_SIZE;offs++) { int sx,sy,mx,my; if (dirtybufferA[offs]) { dirtybufferA[offs] = 0; mx = offs / 32; my = 31 - offs % 32; sx = 31 - mx; sy = 31 - my; drawcharA(tmpbitmapA,RAM[VIDEO_RAM_A_START + offs],palreg,sx,sy); } } memcpy(scrbitmap,tmpbitmapB,BITMAP_WIDTH * BITMAP_HEIGHT); for (i = 0;i < 32*32 * 8*8;i++) if (tmpbitmapA[i]) scrbitmap[i] = tmpbitmapA[i]; osd_update_display(); }