/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * * This file is part of the 86Box distribution. * * Generic SVGA handling. * * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * * Version: @(#)vid_svga.c 1.0.1 2017/09/19 * * Authors: Sarah Walker, * Miran Grca, * Copyright 2008-2017 Sarah Walker. * Copyright 2016,2017 Miran Grca. */ #include #include #include "../ibm.h" #include "../io.h" #include "../mem.h" #ifdef ENABLE_VRAM_DUMP # include "../nvr.h" #endif #include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" #define svga_output 0 void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); extern uint8_t edatlookup[4][4]; uint8_t svga_rotate[8][256]; uint8_t mask_crtc[0x19] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0xEF, 0xFF}; /*Primary SVGA device. As multiple video cards are not yet supported this is the only SVGA device.*/ static svga_t *svga_pri; static int old_overscan_color = 0; svga_t *svga_pointer; svga_t *svga_get_pri() { return svga_pri; } void svga_set_override(svga_t *svga, int val) { if (svga->override && !val) svga->fullchange = changeframecount; svga->override = val; } typedef union pci_bar { uint16_t word; uint8_t bytes[2]; } ichar; #ifdef DEV_BRANCH ichar char12x24[65536][48]; uint8_t charedit_on = 0; ichar charcode; uint8_t charmode = 0; uint8_t charptr = 0; uint8_t charsettings = 0xEE; #endif void svga_out(uint16_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; int c; uint8_t o; switch (addr) { #ifdef DEV_BRANCH case 0x32CB: printf("Write 32CB: %04X\n", val); charedit_on = (val & 0x10) ? 1 : 0; charsettings = val; return; case 0x22CB: printf("Write 22CB: %04X\n", val); charmode = val; charptr = 0; return; case 0x22CF: printf("Write 22CF: %04X\n", val); switch(charmode) { case 1: case 2: charcode.bytes[charmode - 1] = val; return; case 3: case 4: /* Character bitmaps */ char12x24[charcode.word][charptr].bytes[(charmode & 1) ^ 1] = val; charptr++; charptr %= 48; return; case 0xAA: default: return; } return; case 0x22CA: case 0x22CE: case 0x32CA: printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,cpu_state.pc); return; #endif case 0x3C0: case 0x3C1: if (!svga->attrff) { svga->attraddr = val & 31; if ((val & 0x20) != svga->attr_palette_enable) { svga->fullchange = 3; svga->attr_palette_enable = val & 0x20; svga_recalctimings(svga); } } else { o = svga->attrregs[svga->attraddr & 31]; svga->attrregs[svga->attraddr & 31] = val; if (svga->attraddr < 16) svga->fullchange = changeframecount; if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { for (c = 0; c < 16; c++) { /* Proper handling of this, per spec. */ if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 3) << 4); else svga->egapal[c] = (svga->attrregs[c] & 0x3f); /* It seems these should always be enabled. */ svga->egapal[c] |= ((svga->attrregs[0x14] & 0x0c) << 4); } } /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ if ((svga->attraddr == 0x10) || (svga->attraddr == 0x11)) { if (o != val) svga_recalctimings(svga); } if (svga->attraddr == 0x12) { if ((val & 0xf) != svga->plane_mask) svga->fullchange = changeframecount; svga->plane_mask = val & 0xf; } } svga->attrff ^= 1; break; case 0x3C2: svga->miscout = val; svga->enablevram = (val & 2) ? 1 : 0; svga->oddeven_page = (val & 0x20) ? 0 : 1; svga->vidclock = val & 4; if (val & 1) { io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); } else { io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); } svga_recalctimings(svga); break; case 0x3C4: svga->seqaddr = val; break; case 0x3C5: if (svga->seqaddr > 0xf) return; o = svga->seqregs[svga->seqaddr & 0xf]; /* Sanitize value for the first 5 sequencer registers. */ /* if ((svga->seqaddr & 0xf) <= 4) val &= mask_seq[svga->seqaddr & 0xf]; */ svga->seqregs[svga->seqaddr & 0xf] = val; if (o != val && (svga->seqaddr & 0xf) == 1) svga_recalctimings(svga); switch (svga->seqaddr & 0xf) { case 1: if (svga->scrblank && !(val & 0x20)) svga->fullchange = 3; svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); svga_recalctimings(svga); break; case 2: svga->writemask = val & 0xf; break; case 3: svga->charsetb &= ~0x3ffff; svga->charseta &= ~0x3ffff; svga->charsetb |= (((val >> 2) & 3) * 0x10000) + 2; svga->charseta |= ((val & 3) * 0x10000) + 2; if (val & 0x10) svga->charseta += 0x8000; if (val & 0x20) svga->charsetb += 0x8000; break; case 4: svga->chain2_write = !(val & 4); svga->chain4 = val & 8; svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4; svga->extvram = (val & 2) ? 1 : 0; break; } break; case 0x3c6: svga->dac_mask = val; break; case 0x3C7: svga->dac_read = val; svga->dac_pos = 0; break; case 0x3C8: svga->dac_write = val; svga->dac_read = val - 1; svga->dac_pos = 0; break; case 0x3C9: svga->dac_status = 0; svga->fullchange = changeframecount; switch (svga->dac_pos) { case 0: svga->dac_r = val; svga->dac_pos++; break; case 1: svga->dac_g = val; svga->dac_pos++; break; case 2: svga->vgapal[svga->dac_write].r = svga->dac_r; svga->vgapal[svga->dac_write].g = svga->dac_g; svga->vgapal[svga->dac_write].b = val; if (svga->ramdac_type == RAMDAC_8BIT) svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); else { svga->vgapal[svga->dac_write].r &= 0x3f; svga->vgapal[svga->dac_write].g &= 0x3f; svga->vgapal[svga->dac_write].b &= 0x3f; if ((romset == ROM_IBMPS1_2011) || (romset == ROM_IBMPS1_2121) || (romset == ROM_IBMPS2_M30_286)) { svga->pallook[svga->dac_write] = makecol32((svga->vgapal[svga->dac_write].r & 0x3f) * 4, (svga->vgapal[svga->dac_write].g & 0x3f) * 4, (svga->vgapal[svga->dac_write].b & 0x3f) * 4); } else { svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r], video_6to8[svga->vgapal[svga->dac_write].g], video_6to8[svga->vgapal[svga->dac_write].b]); } } svga->dac_pos = 0; svga->dac_write = (svga->dac_write + 1) & 255; break; } break; case 0x3CE: svga->gdcaddr = val; break; case 0x3CF: /* Sanitize the first 9 GDC registers. */ /* if ((svga->gdcaddr & 15) <= 8) val &= mask_gdc[svga->gdcaddr & 15]; */ o = svga->gdcreg[svga->gdcaddr & 15]; switch (svga->gdcaddr & 15) { case 2: svga->colourcompare=val; break; case 4: svga->readplane=val&3; break; case 5: svga->writemode = val & 3; svga->readmode = val & 8; svga->chain2_read = val & 0x10; break; case 6: svga->oddeven_chain = (val & 2) ? 1 : 0; if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { switch (val&0xC) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0x1ffff; break; case 0x4: /*64k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; break; case 0x8: /*32k at B0000*/ mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); svga->banked_mask = 0x7fff; break; case 0xC: /*32k at B8000*/ mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); svga->banked_mask = 0x7fff; break; } } break; case 7: svga->colournocare=val; break; } svga->gdcreg[svga->gdcaddr & 15] = val; svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4; if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) svga_recalctimings(svga); break; } } /* * Get the switch sense input * * This is reverse engineered from the IBM VGA BIOS. I have no * idea how and why this works. * * Note by Tohka: This code is from PCE, modified to be 86Box-compatible. */ static int svga_get_input_status_0_ss(svga_t *svga) { const unsigned char *p; unsigned char dac[3]; static unsigned char vals[] = { 0x12, 0x12, 0x12, 0x10, 0x14, 0x14, 0x14, 0x10, 0x2d, 0x14, 0x14, 0x00, 0x14, 0x2d, 0x14, 0x00, 0x14, 0x14, 0x2d, 0x00, 0x2d, 0x2d, 0x2d, 0x00, 0x00, 0x00, 0x00, 0xff }; dac[0] = svga->vgapal[0].r >> 2; dac[1] = svga->vgapal[0].g >> 2; dac[2] = svga->vgapal[0].b >> 2; p = vals; while (p[3] != 0xff) { if ((p[0] == dac[0]) && (p[1] == dac[1]) && (p[2] == dac[2])) { return (p[3] != 0); } p += 4; } return (1); } uint8_t svga_in(uint16_t addr, void *p) { svga_t *svga = (svga_t *)p; uint8_t temp; switch (addr) { #ifdef DEV_BRANCH case 0x22CA: pclog("Read port %04X\n", addr); return 0xAA; case 0x22CB: pclog("Read port %04X\n", addr); return 0xF0 | (charmode & 0x1F); case 0x22CE: pclog("Read port %04X\n", addr); return 0xCC; case 0x22CF: /* Read character bitmap */ pclog("Read port %04X\n", addr); switch(charmode) { case 1: case 2: return charcode.bytes[charmode - 1]; case 3: case 4: /* Character bitmaps */ /* Mode 3 is low bytes, mode 4 is high bytes */ temp = char12x24[charcode.word][charptr].bytes[(charmode & 1) ^ 1]; charptr++; charptr %= 48; return temp; case 0xAA: default: return 0xFF; } case 0x32CA: pclog("Read port %04X\n", addr); return 0xEE; case 0x32CB: pclog("Read port %04X\n", addr); return 0xEE; #endif case 0x3C0: return svga->attraddr | svga->attr_palette_enable; case 0x3C1: return svga->attrregs[svga->attraddr]; case 0x3c2: if ((romset == ROM_IBMPS1_2011) || (romset == ROM_IBMPS1_2121) || (romset == ROM_IBMPS1_2121_ISA) || (romset == ROM_IBMPS1_2133) || (romset == ROM_IBMPS2_M30_286) || (romset == ROM_IBMPS2_M50) || (romset == ROM_IBMPS2_M55SX) || (romset == ROM_IBMPS2_M80)) { if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) { temp = 0; } else { temp = 0x10; } } else { if (gfxcard == GFX_RIVA128) { if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) { temp = 0; } else { temp = 0x10; } } else { if (svga_get_input_status_0_ss(svga)) { temp = 0x10; } else { temp = 0; } } } return temp; case 0x3C4: return svga->seqaddr; case 0x3C5: return svga->seqregs[svga->seqaddr & 0xF]; case 0x3c6: return svga->dac_mask; case 0x3c7: return svga->dac_status; case 0x3c8: return svga->dac_write; case 0x3c9: svga->dac_status = 3; switch (svga->dac_pos) { case 0: svga->dac_pos++; return svga->vgapal[svga->dac_read].r; case 1: svga->dac_pos++; return svga->vgapal[svga->dac_read].g; case 2: svga->dac_pos=0; svga->dac_read = (svga->dac_read + 1) & 255; return svga->vgapal[(svga->dac_read - 1) & 255].b; } break; case 0x3CC: return svga->miscout; case 0x3CE: return svga->gdcaddr; case 0x3CF: /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ if (svga->gdcaddr == 0xF8) return svga->la; if (svga->gdcaddr == 0xF9) return svga->lb; if (svga->gdcaddr == 0xFA) return svga->lc; if (svga->gdcaddr == 0xFB) return svga->ld; return svga->gdcreg[svga->gdcaddr & 0xf]; case 0x3DA: svga->attrff = 0; if (svga->cgastat & 0x01) svga->cgastat &= ~0x30; else svga->cgastat ^= 0x30; return svga->cgastat; } return 0xFF; } void svga_set_ramdac_type(svga_t *svga, int type) { int c; if (svga->ramdac_type != type) { svga->ramdac_type = type; for (c = 0; c < 256; c++) { if (svga->ramdac_type == RAMDAC_8BIT) svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); else svga->pallook[c] = makecol32(video_6to8[svga->vgapal[c].r], video_6to8[svga->vgapal[c].g], video_6to8[svga->vgapal[c].b]); } } } void svga_recalctimings(svga_t *svga) { double crtcconst; double _dispontime, _dispofftime, disptime; svga->vtotal = svga->crtc[6]; svga->dispend = svga->crtc[0x12]; svga->vsyncstart = svga->crtc[0x10]; svga->split = svga->crtc[0x18]; svga->vblankstart = svga->crtc[0x15]; if (svga->crtc[7] & 1) svga->vtotal |= 0x100; if (svga->crtc[7] & 32) svga->vtotal |= 0x200; svga->vtotal += 2; if (svga->crtc[7] & 2) svga->dispend |= 0x100; if (svga->crtc[7] & 64) svga->dispend |= 0x200; svga->dispend++; if (svga->crtc[7] & 4) svga->vsyncstart |= 0x100; if (svga->crtc[7] & 128) svga->vsyncstart |= 0x200; svga->vsyncstart++; if (svga->crtc[7] & 0x10) svga->split|=0x100; if (svga->crtc[9] & 0x40) svga->split|=0x200; svga->split++; if (svga->crtc[7] & 0x08) svga->vblankstart |= 0x100; if (svga->crtc[9] & 0x20) svga->vblankstart |= 0x200; svga->vblankstart++; svga->hdisp = svga->crtc[1]; svga->hdisp++; svga->htotal = svga->crtc[0]; svga->htotal += 6; /*+6 is required for Tyrian*/ svga->rowoffset = svga->crtc[0x13]; svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; svga->lowres = svga->attrregs[0x10] & 0x40; svga->interlace = 0; svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; svga->hdisp_time = svga->hdisp; svga->render = svga_render_blank; if (!svga->scrblank && svga->attr_palette_enable) { if (!(svga->gdcreg[6] & 1)) /*Text mode*/ { if (svga->seqregs[1] & 8) /*40 column*/ { #if 0 if (svga->hdisp == 120) { svga->render = svga_render_text_40_12; svga->hdisp *= 16; } else { #endif svga->render = svga_render_text_40; svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; #if 0 } #endif } else { #if 0 if (svga->hdisp == 120) { svga->render = svga_render_text_80_12; svga->hdisp *= 8; } else { #endif svga->render = svga_render_text_80; svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; #if 0 } #endif } svga->hdisp_old = svga->hdisp; } else { svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; svga->hdisp_old = svga->hdisp; switch (svga->gdcreg[5] & 0x60) { case 0x00: /*16 colours*/ if (svga->seqregs[1] & 8) /*Low res (320)*/ svga->render = svga_render_4bpp_lowres; else svga->render = svga_render_4bpp_highres; break; case 0x20: /*4 colours*/ if (svga->seqregs[1] & 8) /*Low res (320)*/ svga->render = svga_render_2bpp_lowres; else svga->render = svga_render_2bpp_highres; break; case 0x40: case 0x60: /*256+ colours*/ switch (svga->bpp) { case 8: if (svga->lowres) svga->render = svga_render_8bpp_lowres; else svga->render = svga_render_8bpp_highres; break; case 15: if (svga->lowres) svga->render = svga_render_15bpp_lowres; else svga->render = svga_render_15bpp_highres; break; case 16: if (svga->lowres) svga->render = svga_render_16bpp_lowres; else svga->render = svga_render_16bpp_highres; break; case 24: if (svga->lowres) svga->render = svga_render_24bpp_lowres; else svga->render = svga_render_24bpp_highres; break; case 32: if (svga->lowres) svga->render = svga_render_32bpp_lowres; else svga->render = svga_render_32bpp_highres; break; } break; } } } svga->linedbl = svga->crtc[9] & 0x80; svga->rowcount = svga->crtc[9] & 31; overscan_y = (svga->rowcount + 1) << 1; if (svga->seqregs[1] & 8) /*Low res (320)*/ { overscan_y <<= 1; } if (overscan_y < 16) { overscan_y = 16; } /* pclog("SVGA row count: %i (scroll: %i)\n", svga->rowcount, svga->crtc[8] & 0x1f); */ if (svga->recalctimings_ex) svga->recalctimings_ex(svga); if (svga->vblankstart < svga->dispend) svga->dispend = svga->vblankstart; crtcconst = (svga->seqregs[1] & 1) ? (svga->clock * 8.0) : (svga->clock * 9.0); disptime = svga->htotal; _dispontime = svga->hdisp_time; if (svga->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } _dispofftime = disptime - _dispontime; _dispontime *= crtcconst; _dispofftime *= crtcconst; svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); /* printf("SVGA horiz total %i display end %i vidclock %f\n",svga->crtc[0],svga->crtc[1],svga->clock); printf("SVGA vert total %i display end %i max row %i vsync %i\n",svga->vtotal,svga->dispend,(svga->crtc[9]&31)+1,svga->vsyncstart); printf("total %f on %i cycles off %i cycles frame %i sec %i %02X\n",disptime*crtcconst,svga->dispontime,svga->dispofftime,(svga->dispontime+svga->dispofftime)*svga->vtotal,(svga->dispontime+svga->dispofftime)*svga->vtotal*70,svga->seqregs[1]); pclog("svga->render %08X\n", svga->render);*/ } extern int cyc_total; uint32_t svga_mask_addr(uint32_t addr, svga_t *svga) { uint32_t limit_shift = 0; if (!(svga->gdcreg[6] & 1)) { limit_shift = 1; } if ((svga->gdcreg[5] & 0x60) == 0x20) { limit_shift = 1; } if (svga->vrammask == (svga->vram_limit - 1)) { return addr % (svga->vram_limit >> limit_shift); } else { return addr & (svga->vrammask >> limit_shift); } } uint32_t svga_mask_changedaddr(uint32_t addr, svga_t *svga) { if (svga->vrammask == (svga->vram_limit - 1)) { return addr % (svga->vram_limit >> 12); } else { return addr & (svga->vrammask >> 12); } } void svga_poll(void *p) { svga_t *svga = (svga_t *)p; int x; if (!svga->linepos) { if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; svga->hwcursor_oddeven = 0; } if (svga->displine == svga->hwcursor_latch.y+1 && svga->hwcursor_latch.ena && svga->interlace) { svga->hwcursor_on = 64 - (svga->hwcursor_latch.yoff + 1); svga->hwcursor_oddeven = 1; } if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 0; } if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 1; } svga->vidtime += svga->dispofftime; svga->cgastat |= 1; svga->linepos = 1; if (svga->dispon) { svga->hdisp_on=1; svga->ma = svga_mask_addr(svga->ma, svga); if (svga->firstline == 2000) { svga->firstline = svga->displine; video_wait_for_buffer(); } if (svga->hwcursor_on || svga->overlay_on) svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = 2; if (!svga->override) svga->render(svga); if (svga->overlay_on) { if (!svga->override) svga->overlay_draw(svga, svga->displine); svga->overlay_on--; if (svga->overlay_on && svga->interlace) svga->overlay_on--; } if (svga->hwcursor_on) { if (!svga->override) svga->hwcursor_draw(svga, svga->displine); svga->hwcursor_on--; if (svga->hwcursor_on && svga->interlace) svga->hwcursor_on--; } if (svga->lastline < svga->displine) svga->lastline = svga->displine; } svga->displine++; if (svga->interlace) svga->displine++; if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) { svga->cgastat &= ~8; } svga->vslines++; if (svga->displine > 1500) svga->displine = 0; } else { svga->vidtime += svga->dispontime; if (svga->dispon) svga->cgastat &= ~1; svga->hdisp_on = 0; svga->linepos = 0; if (svga->sc == (svga->crtc[11] & 31)) svga->con = 0; if (svga->dispon) { if (svga->linedbl && !svga->linecountff) { svga->linecountff = 1; svga->ma = svga->maback; } else if (svga->sc == svga->rowcount) { svga->linecountff = 0; svga->sc = 0; svga->maback += (svga->rowoffset << 3); if (svga->interlace) svga->maback += (svga->rowoffset << 3); svga->maback = svga_mask_addr(svga->maback, svga); svga->ma = svga->maback; } else { svga->linecountff = 0; svga->sc++; svga->sc &= 31; svga->ma = svga->maback; } } svga->vc++; svga->vc &= 2047; if (svga->vc == svga->split) { svga->ma = svga->maback = 0; if (svga->attrregs[0x10] & 0x20) svga->scrollcache = 0; } if (svga->vc == svga->dispend) { if (svga->vblank_start) svga->vblank_start(svga); svga->dispon=0; if (svga->crtc[10] & 0x20) svga->cursoron = 0; else svga->cursoron = svga->blink & 16; if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) svga->fullchange = 2; svga->blink++; for (x = 0; x < (svga->vram_limit >> 12); x++) { if (svga->changedvram[x]) svga->changedvram[x]--; } if (svga->fullchange) svga->fullchange--; } if (svga->vc == svga->vsyncstart) { int wx, wy; svga->dispon=0; svga->cgastat |= 8; x = svga->hdisp; if (svga->interlace && !svga->oddeven) svga->lastline++; if (svga->interlace && svga->oddeven) svga->firstline--; wx = x; wy = svga->lastline - svga->firstline; if (!svga->override) svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); svga->firstline = 2000; svga->lastline = 0; svga->firstline_draw = 2000; svga->lastline_draw = 0; svga->oddeven ^= 1; changeframecount = svga->interlace ? 3 : 2; svga->vslines = 0; if (svga->interlace && svga->oddeven) svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); else svga->ma = svga->maback = svga->ma_latch; svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; svga->ma <<= 2; svga->maback <<= 2; svga->ca <<= 2; svga->video_res_x = wx; svga->video_res_y = wy + 1; if (!(svga->gdcreg[6] & 1)) /*Text mode*/ { svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; svga->video_res_y /= (svga->crtc[9] & 31) + 1; svga->video_bpp = 0; } else { if (svga->crtc[9] & 0x80) svga->video_res_y /= 2; if (!(svga->crtc[0x17] & 1)) svga->video_res_y *= 2; svga->video_res_y /= (svga->crtc[9] & 31) + 1; if (svga->lowres) svga->video_res_x /= 2; switch (svga->gdcreg[5] & 0x60) { case 0x00: svga->video_bpp = 4; break; case 0x20: svga->video_bpp = 2; break; case 0x40: case 0x60: svga->video_bpp = svga->bpp; break; } } } if (svga->vc == svga->vtotal) { svga->vc = 0; svga->sc = 0; svga->dispon = 1; svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; svga->scrollcache = svga->attrregs[0x13] & 7; svga->linecountff = 0; svga->hwcursor_on = 0; svga->hwcursor_latch = svga->hwcursor; svga->overlay_on = 0; svga->overlay_latch = svga->overlay; } if (svga->sc == (svga->crtc[10] & 31)) svga->con = 1; } } #ifdef ENABLE_VRAM_DUMP uint8_t *ext_vram; int ext_memsize; #endif int svga_init(svga_t *svga, void *p, int memsize, void (*recalctimings_ex)(struct svga_t *svga), uint8_t (*video_in) (uint16_t addr, void *p), void (*video_out)(uint16_t addr, uint8_t val, void *p), void (*hwcursor_draw)(struct svga_t *svga, int displine), void (*overlay_draw)(struct svga_t *svga, int displine)) { int c, d, e; svga->p = p; for (c = 0; c < 256; c++) { e = c; for (d = 0; d < 8; d++) { svga_rotate[d][c] = e; e = (e >> 1) | ((e & 1) ? 0x80 : 0); } } svga->readmode = 0; svga->attrregs[0x11] = 0; old_overscan_color = 0; overscan_x = 16; overscan_y = 32; svga->crtc[0] = 63; svga->crtc[6] = 255; svga->dispontime = 1000 * (1 << TIMER_SHIFT); svga->dispofftime = 1000 * (1 << TIMER_SHIFT); svga->bpp = 8; svga->vram = malloc(memsize); #ifdef ENABLE_VRAM_DUMP ext_vram = svga->vram; ext_memsize = memsize; #endif svga->vram_limit = memsize; svga->vrammask = memsize - 1; svga->changedvram = malloc(/*(memsize >> 12) << 1*/memsize >> 12); svga->recalctimings_ex = recalctimings_ex; svga->video_in = video_in; svga->video_out = video_out; svga->hwcursor_draw = hwcursor_draw; svga->overlay_draw = overlay_draw; mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); memset(svga->vgapal, 0, sizeof(PALETTE)); timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); svga_pri = svga; svga->ramdac_type = RAMDAC_6BIT; svga_pointer = svga; /* io_sethandler(0x22ca, 0x0002, svga_in, NULL, NULL, svga_out, NULL, NULL, svga); io_sethandler(0x22ce, 0x0002, svga_in, NULL, NULL, svga_out, NULL, NULL, svga); io_sethandler(0x32ca, 0x0002, svga_in, NULL, NULL, svga_out, NULL, NULL, svga); */ return 0; } void svga_close(svga_t *svga) { free(svga->changedvram); free(svga->vram); svga_pri = NULL; } void svga_write(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; uint8_t vala, valb, valc, vald, wm = svga->writemask; int writemask2 = svga->writemask; /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; egawrites++; cycles -= video_timing_b; cycles_lost += video_timing_b; if (svga_output) pclog("Writeega %06X ",addr); addr &= svga->banked_mask; addr += svga->write_bank; if (!(svga->gdcreg[6] & 1)) svga->fullchange=2; if (svga->chain4 || svga->fb_only) { /* 00000 -> writemask 1, addr 0 -> vram addr 00000 00001 -> writemask 2, addr 0 -> vram addr 00001 00002 -> writemask 4, addr 0 -> vram addr 00002 00003 -> writemask 8, addr 0 -> vram addr 00003 00004 -> writemask 1, addr 4 -> vram addr 00004 00005 -> writemask 2, addr 4 -> vram addr 00005 00006 -> writemask 4, addr 4 -> vram addr 00006 00007 -> writemask 8, addr 4 -> vram addr 00007 */ writemask2=1<<(addr&3); addr&=~3; } else if (svga->chain2_write) { #if 0 if (svga->oddeven_page) { /* Odd/Even page is 1, mask out plane 2 or 3, according to bit 0 of the address. */ writemask2 &= (addr & 1) ? 8 : 4; } else { /* Odd/Even page is 2, mask out plane 0 or 1, according to bit 0 of the address. */ writemask2 &= (addr & 1) ? 2 : 1; } #endif writemask2 &= ~0xa; if (addr & 1) writemask2 <<= 1; addr &= ~1; addr <<= 2; } else { addr<<=2; } if (addr >= svga->vram_limit) return; addr = svga_mask_addr(addr, svga); if (svga_output) pclog("%08X (%i, %i) %02X %i %i %i %02X\n", addr, addr & 1023, addr >> 10, val, writemask2, svga->writemode, svga->chain4, svga->gdcreg[8]); svga->changedvram[addr >> 12] = changeframecount; switch (svga->writemode) { case 1: if (writemask2 & 1) svga->vram[addr] = svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; break; case 0: if (svga->gdcreg[3] & 7) val = svga_rotate[svga->gdcreg[3] & 7][val]; if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) { if (writemask2 & 1) svga->vram[addr] = val; if (writemask2 & 2) svga->vram[addr | 0x1] = val; if (writemask2 & 4) svga->vram[addr | 0x2] = val; if (writemask2 & 8) svga->vram[addr | 0x3] = val; } else { if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; else vala = val; if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; else valb = val; if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; else valc = val; if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; else vald = val; switch (svga->gdcreg[3] & 0x18) { case 0: /*Set*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); break; case 8: /*AND*/ if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; break; case 0x10: /*OR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; break; case 0x18: /*XOR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; break; } } break; case 2: if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) { if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); } else { vala = ((val & 1) ? 0xff : 0); valb = ((val & 2) ? 0xff : 0); valc = ((val & 4) ? 0xff : 0); vald = ((val & 8) ? 0xff : 0); switch (svga->gdcreg[3] & 0x18) { case 0: /*Set*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); break; case 8: /*AND*/ if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; break; case 0x10: /*OR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; break; case 0x18: /*XOR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; break; } } break; case 3: if (svga->gdcreg[3] & 7) val = svga_rotate[svga->gdcreg[3] & 7][val]; wm = svga->gdcreg[8]; svga->gdcreg[8] &= val; vala = (svga->gdcreg[0] & 1) ? 0xff : 0; valb = (svga->gdcreg[0] & 2) ? 0xff : 0; valc = (svga->gdcreg[0] & 4) ? 0xff : 0; vald = (svga->gdcreg[0] & 8) ? 0xff : 0; switch (svga->gdcreg[3] & 0x18) { case 0: /*Set*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); break; case 8: /*AND*/ if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; break; case 0x10: /*OR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; break; case 0x18: /*XOR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; break; } svga->gdcreg[8] = wm; break; } #if 0 if (svga->render == svga_render_text_80_12) { FILE *f = fopen("hecon.dmp", "wb"); fwrite(svga->vram, 1, svga->vram_limit, f); fclose(f); } #endif } uint8_t svga_read(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; uint8_t temp, temp2, temp3, temp4; uint32_t latch_addr; int readplane = svga->readplane; cycles -= video_timing_b; cycles_lost += video_timing_b; egareads++; addr &= svga->banked_mask; addr += svga->read_bank; latch_addr = svga_mask_addr(addr << 2, svga); if (svga->chain4 || svga->fb_only) { if (addr >= svga->vram_limit) return 0xff; return svga->vram[svga_mask_addr(addr, svga)]; } else if (svga->chain2_read) { readplane = addr & 1; if (svga->oddeven_page) { readplane |= 2; } addr &= ~1; addr <<= 2; } else addr<<=2; if (addr >= svga->vram_limit) return 0xff; addr = svga_mask_addr(addr, svga); if (latch_addr < svga->vram_limit) { svga->la = svga->vram[latch_addr]; svga->lb = svga->vram[latch_addr | 0x1]; svga->lc = svga->vram[latch_addr | 0x2]; svga->ld = svga->vram[latch_addr | 0x3]; } else svga->la = svga->lb = svga->lc = svga->ld = 0xff; if (svga->readmode) { temp = svga->la; temp ^= (svga->colourcompare & 1) ? 0xff : 0; temp &= (svga->colournocare & 1) ? 0xff : 0; temp2 = svga->lb; temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; temp2 &= (svga->colournocare & 2) ? 0xff : 0; temp3 = svga->lc; temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; temp3 &= (svga->colournocare & 4) ? 0xff : 0; temp4 = svga->ld; temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; temp4 &= (svga->colournocare & 8) ? 0xff : 0; return ~(temp | temp2 | temp3 | temp4); } return svga->vram[addr | readplane]; } void svga_write_linear(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; uint8_t vala, valb, valc, vald, wm = svga->writemask; int writemask2 = svga->writemask; cycles -= video_timing_b; cycles_lost += video_timing_b; egawrites++; if (svga_output) pclog("Write LFB %08X %02X ", addr, val); if (!(svga->gdcreg[6] & 1)) svga->fullchange = 2; addr -= svga->linear_base; if (svga->chain4 || svga->fb_only) { writemask2=1<<(addr&3); addr&=~3; } else if (svga->chain2_write) { #if 0 if (svga->oddeven_page) { /* Odd/Even page is 1, mask out plane 2 or 3, according to bit 0 of the address. */ writemask2 &= (addr & 1) ? 8 : 4; } else { /* Odd/Even page is 2, mask out plane 0 or 1, according to bit 0 of the address. */ writemask2 &= (addr & 1) ? 2 : 1; } #endif writemask2 &= ~0xa; if (addr & 1) writemask2 <<= 1; addr &= ~1; addr <<= 2; } else { addr<<=2; } if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) { addr &= 0x7fffff; } if (addr >= svga->vram_limit) return; if (svga_output) pclog("%08X\n", addr); svga->changedvram[addr >> 12]=changeframecount; switch (svga->writemode) { case 1: if (writemask2 & 1) svga->vram[addr] = svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; break; case 0: if (svga->gdcreg[3] & 7) val = svga_rotate[svga->gdcreg[3] & 7][val]; if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) { if (writemask2 & 1) svga->vram[addr] = val; if (writemask2 & 2) svga->vram[addr | 0x1] = val; if (writemask2 & 4) svga->vram[addr | 0x2] = val; if (writemask2 & 8) svga->vram[addr | 0x3] = val; } else { if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; else vala = val; if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; else valb = val; if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; else valc = val; if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; else vald = val; switch (svga->gdcreg[3] & 0x18) { case 0: /*Set*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); break; case 8: /*AND*/ if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; break; case 0x10: /*OR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; break; case 0x18: /*XOR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; break; } } break; case 2: if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) { if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); } else { vala = ((val & 1) ? 0xff : 0); valb = ((val & 2) ? 0xff : 0); valc = ((val & 4) ? 0xff : 0); vald = ((val & 8) ? 0xff : 0); switch (svga->gdcreg[3] & 0x18) { case 0: /*Set*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); break; case 8: /*AND*/ if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; break; case 0x10: /*OR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; break; case 0x18: /*XOR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; break; } } break; case 3: if (svga->gdcreg[3] & 7) val = svga_rotate[svga->gdcreg[3] & 7][val]; wm = svga->gdcreg[8]; svga->gdcreg[8] &= val; vala = (svga->gdcreg[0] & 1) ? 0xff : 0; valb = (svga->gdcreg[0] & 2) ? 0xff : 0; valc = (svga->gdcreg[0] & 4) ? 0xff : 0; vald = (svga->gdcreg[0] & 8) ? 0xff : 0; switch (svga->gdcreg[3] & 0x18) { case 0: /*Set*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); break; case 8: /*AND*/ if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; break; case 0x10: /*OR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; break; case 0x18: /*XOR*/ if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; break; } svga->gdcreg[8] = wm; break; } } uint8_t svga_read_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; uint8_t temp, temp2, temp3, temp4; int readplane = svga->readplane; cycles -= video_timing_b; cycles_lost += video_timing_b; egareads++; addr -= svga->linear_base; if (svga->chain4 || svga->fb_only) { if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) { addr &= 0x7fffff; } if (addr >= svga->vram_limit) return 0xff; return svga->vram[addr]; } else if (svga->chain2_read) { readplane = addr & 1; if (svga->oddeven_page) { readplane |= 2; } addr &= ~1; addr <<= 2; } else addr<<=2; if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) { addr &= 0x7fffff; } if (addr >= svga->vram_limit) return 0xff; svga->la = svga->vram[addr]; svga->lb = svga->vram[addr | 0x1]; svga->lc = svga->vram[addr | 0x2]; svga->ld = svga->vram[addr | 0x3]; if (svga->readmode) { temp = svga->la; temp ^= (svga->colourcompare & 1) ? 0xff : 0; temp &= (svga->colournocare & 1) ? 0xff : 0; temp2 = svga->lb; temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; temp2 &= (svga->colournocare & 2) ? 0xff : 0; temp3 = svga->lc; temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; temp3 &= (svga->colournocare & 4) ? 0xff : 0; temp4 = svga->ld; temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; temp4 &= (svga->colournocare & 8) ? 0xff : 0; return ~(temp | temp2 | temp3 | temp4); } return svga->vram[addr | readplane]; } void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) { int y_add = (enable_overscan) ? overscan_y : 0; int x_add = (enable_overscan) ? 16 : 0; uint32_t *p, i, j; svga->frames++; if ((xsize > 2032) || (ysize > 2032)) { x_add = 0; y_add = 0; suppress_overscan = 1; } else { suppress_overscan = 0; } if (y1 > y2) { video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); return; } if (((wx!=xsize) || ((wy + 1)!=ysize)) && !vid_resize) { xsize=wx; ysize=wy+1; if (xsize<64) xsize=640; if (ysize<32) ysize=200; if ((xsize > 2032) || (ysize > 2032)) { x_add = 0; y_add = 0; suppress_overscan = 1; } else { suppress_overscan = 0; } updatewindowsize(xsize + x_add,ysize + y_add); } if (vid_resize) { xsize = wx; ysize = wy + 1; if ((xsize > 2032) || (ysize > 2032)) { x_add = 0; y_add = 0; suppress_overscan = 1; } else { suppress_overscan = 0; } } if (enable_overscan && !suppress_overscan) { if ((wx >= 160) && ((wy + 1) >= 120)) { /* Draw (overscan_size - scroll size) lines of overscan on top. */ for (i = 0; i < ((y_add >> 1) - (svga->crtc[8] & 0x1f)); i++) { p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; for (j = 0; j < (xsize + x_add); j++) { p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); } } /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ for (i = 0; i < ((y_add >> 1) + (svga->crtc[8] & 0x1f)); i++) { p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i - (svga->crtc[8] & 0x1f)) & 0x7ff])[32]; for (j = 0; j < (xsize + x_add); j++) { p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); } } for (i = ((y_add >> 1) - (svga->crtc[8] & 0x1f)); i < (ysize + (y_add >> 1) - (svga->crtc[8] & 0x1f)); i ++) { p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; for (j = 0; j < 8; j++) { p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); p[xsize + (x_add >> 1) + j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); } } } } else { if ((wx >= 160) && ((wy + 1) >= 120) && (svga->crtc[8] & 0x1f)) { /* Draw (scroll size) lines of overscan on the bottom. */ for (i = 0; i < (svga->crtc[8] & 0x1f); i++) { p = &((uint32_t *)buffer32->line[(ysize + i - (svga->crtc[8] & 0x1f)) & 0x7ff])[32]; for (j = 0; j < xsize; j++) { p[j] = svga_color_transform(svga->pallook[svga->attrregs[0x11]]); } } } } video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); } void svga_writew(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t *)p; if (!svga->enablevram) return; if (!svga->fast) { svga_write(addr, val, p); svga_write(addr + 1, val >> 8, p); return; } egawrites += 2; cycles -= video_timing_w; cycles_lost += video_timing_w; if (svga_output) pclog("svga_writew: %05X ", addr); addr = (addr & svga->banked_mask) + svga->write_bank; if ((!svga->extvram) && (addr >= 0x10000)) return; if (addr >= svga->vram_limit) return; if (svga_output) pclog("%08X (%i, %i) %04X\n", addr, addr & 1023, addr >> 10, val); svga->changedvram[addr >> 12] = changeframecount; *(uint16_t *)&svga->vram[addr] = val; } void svga_writel(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t *)p; if (!svga->enablevram) return; if (!svga->fast) { svga_write(addr, val, p); svga_write(addr + 1, val >> 8, p); svga_write(addr + 2, val >> 16, p); svga_write(addr + 3, val >> 24, p); return; } egawrites += 4; cycles -= video_timing_l; cycles_lost += video_timing_l; if (svga_output) pclog("svga_writel: %05X ", addr); addr = (addr & svga->banked_mask) + svga->write_bank; if ((!svga->extvram) && (addr >= 0x10000)) return; if (addr >= svga->vram_limit) return; if (svga_output) pclog("%08X (%i, %i) %08X\n", addr, addr & 1023, addr >> 10, val); svga->changedvram[addr >> 12] = changeframecount; *(uint32_t *)&svga->vram[addr] = val; } uint16_t svga_readw(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; if (!svga->enablevram) return 0xffff; if (!svga->fast) return svga_read(addr, p) | (svga_read(addr + 1, p) << 8); egareads += 2; cycles -= video_timing_w; cycles_lost += video_timing_w; addr = (addr & svga->banked_mask) + svga->read_bank; if ((!svga->extvram) && (addr >= 0x10000)) return 0xffff; if (addr >= svga->vram_limit) return 0xffff; return *(uint16_t *)&svga->vram[addr]; } uint32_t svga_readl(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; if (!svga->enablevram) return 0xffffffff; if (!svga->fast) { if (addr == 0xBF0000) pclog ("%08X\n", svga_read(addr, p) | (svga_read(addr + 1, p) << 8) | (svga_read(addr + 2, p) << 16) | (svga_read(addr + 3, p) << 24)); return svga_read(addr, p) | (svga_read(addr + 1, p) << 8) | (svga_read(addr + 2, p) << 16) | (svga_read(addr + 3, p) << 24); } egareads += 4; cycles -= video_timing_l; cycles_lost += video_timing_l; addr = (addr & svga->banked_mask) + svga->read_bank; if ((!svga->extvram) && (addr >= 0x10000)) return 0xffffffff; if (addr >= svga->vram_limit) return 0xffffffff; return *(uint32_t *)&svga->vram[addr]; } void svga_writew_linear(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t *)p; if (!svga->enablevram) return; if (!svga->fast) { svga_write_linear(addr, val, p); svga_write_linear(addr + 1, val >> 8, p); return; } egawrites += 2; cycles -= video_timing_w; cycles_lost += video_timing_w; if (svga_output) pclog("Write LFBw %08X %04X\n", addr, val); addr -= svga->linear_base; if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) { addr &= 0x7fffff; } if (addr >= svga->vram_limit) return; svga->changedvram[addr >> 12] = changeframecount; *(uint16_t *)&svga->vram[addr] = val; } void svga_writel_linear(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t *)p; if (!svga->enablevram) return; if (!svga->fast) { svga_write_linear(addr, val, p); svga_write_linear(addr + 1, val >> 8, p); svga_write_linear(addr + 2, val >> 16, p); svga_write_linear(addr + 3, val >> 24, p); return; } egawrites += 4; cycles -= video_timing_l; cycles_lost += video_timing_l; if (svga_output) pclog("Write LFBl %08X %08X\n", addr, val); addr -= svga->linear_base; if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) { addr &= 0x7fffff; } if (addr >= svga->vram_limit) return; svga->changedvram[addr >> 12] = changeframecount; *(uint32_t *)&svga->vram[addr] = val; } uint16_t svga_readw_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; if (!svga->enablevram) return 0xffff; if (!svga->fast) return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8); egareads += 2; cycles -= video_timing_w; cycles_lost += video_timing_w; addr -= svga->linear_base; if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) { addr &= 0x7fffff; } if (addr >= svga->vram_limit) return 0xffff; return *(uint16_t *)&svga->vram[addr]; } uint32_t svga_readl_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; if (!svga->enablevram) return 0xffffffff; if (!svga->fast) return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8) | (svga_read_linear(addr + 2, p) << 16) | (svga_read_linear(addr + 3, p) << 24); egareads += 4; cycles -= video_timing_l; cycles_lost += video_timing_l; addr -= svga->linear_base; if ((gfxcard != GFX_RIVA128) && (gfxcard != GFX_RIVATNT) && (gfxcard != GFX_RIVATNT2)) { addr &= 0x7fffff; } if (addr >= svga->vram_limit) return 0xffffffff; return *(uint32_t *)&svga->vram[addr]; } #ifdef ENABLE_VRAM_DUMP void svga_dump_vram() { FILE *f; if (ext_vram == NULL) { return; } f = nvrfopen(L"svga_vram.dmp", L"wb"); if (f == NULL) { return; } fwrite(ext_vram, ext_memsize, 1, f); fclose(f); } #endif void svga_add_status_info(char *s, int max_len, void *p) { svga_t *svga = (svga_t *)p; char temps[128]; if (svga->chain4) strcpy(temps, "SVGA chained (possibly mode 13h)\n"); else strcpy(temps, "SVGA unchained (possibly mode-X)\n"); strncat(s, temps, max_len); sprintf(temps, "SVGA chained odd/even (r: %s, w: %s, c: %s, p: %s)\n", svga->chain2_read ? "ON" : "OFF", svga->chain2_write ? "ON" : "OFF", svga->oddeven_chain ? "ON" : "OFF", svga->oddeven_page ? "lo" : "hi"); strncat(s, temps, max_len); if (!svga->video_bpp) strcpy(temps, "SVGA in text mode\n"); else sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); strncat(s, temps, max_len); sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); strncat(s, temps, max_len); sprintf(temps, "SVGA horizontal display : %i\n", svga->hdisp); strncat(s, temps, max_len); sprintf(temps, "SVGA refresh rate : %i Hz (%s)\n\n", svga->frames, svga->interlace ? "i" : "p"); svga->frames = 0; strncat(s, temps, max_len); sprintf(temps, "SVGA DAC in %i-bit mode\n", (svga->attrregs[0x10] & 0x80) ? 8 : 6); strncat(s, temps, max_len); }