/* * 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. * * EGA renderers. * * * * Authors: Sarah Walker, * Miran Grca, * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. */ #include #include #include #include #include #include <86box/86box.h> #include <86box/device.h> #include <86box/timer.h> #include <86box/mem.h> #include <86box/rom.h> #include <86box/video.h> #include <86box/vid_ega.h> #include <86box/vid_ega_render_remap.h> int ega_display_line(ega_t *ega) { int y_add = (enable_overscan) ? (overscan_y >> 1) : 0; unsigned int dl = ega->displine; if (ega->crtc[9] & 0x1f) dl -= (ega->crtc[8] & 0x1f); dl += y_add; dl &= 0x7ff; return dl; } void ega_render_blank(ega_t *ega) { int x, xx; if ((ega->displine + ega->y_add) < 0) return; for (x = 0; x < (ega->hdisp + ega->scrollcache); x++) { switch (ega->seqregs[1] & 9) { case 0: for (xx = 0; xx < 9; xx++) buffer32->line[ega->displine + ega->y_add][ega->x_add + (x * 9) + xx] = 0; break; case 1: for (xx = 0; xx < 8; xx++) buffer32->line[ega->displine + ega->y_add][ega->x_add + (x * 8) + xx] = 0; break; case 8: for (xx = 0; xx < 18; xx++) buffer32->line[ega->displine + ega->y_add][ega->x_add + (x * 18) + xx] = 0; break; case 9: for (xx = 0; xx < 16; xx++) buffer32->line[ega->displine + ega->y_add][ega->x_add + (x * 16) + xx] = 0; break; } } } void ega_render_overscan_left(ega_t *ega) { int i; if ((ega->displine + ega->y_add) < 0) return; if (ega->scrblank || (ega->hdisp == 0)) return; for (i = 0; i < ega->x_add; i++) buffer32->line[ega->displine + ega->y_add][i] = ega->overscan_color; } void ega_render_overscan_right(ega_t *ega) { int i, right; if ((ega->displine + ega->y_add) < 0) return; if (ega->scrblank || (ega->hdisp == 0)) return; right = (overscan_x >> 1) + ega->scrollcache; for (i = 0; i < right; i++) buffer32->line[ega->displine + ega->y_add][ega->x_add + ega->hdisp + i] = ega->overscan_color; } void ega_render_text(ega_t *ega) { if ((ega->displine + ega->y_add) < 0) return; if (ega->firstline_draw == 2000) ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; if (ega->fullchange) { uint32_t *p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; const int dwshift = (ega->seqregs[1] & 8) ? 1 : 0; const int dotwidth = 1<seqregs[1] & 1) ? 8 : 9); for (int x = 0; x < (ega->hdisp + ega->scrollcache); x += charwidth) { uint32_t addr = ega->remap_func(ega, ega->ma) & ega->vrammask; int drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); uint32_t chr, attr; if (ega->crtc[0x17] & 0x80) { chr = ega->vram[addr]; attr = ega->vram[addr + 1]; } else chr = attr = 0; uint32_t charaddr; if (attr & 8) charaddr = ega->charsetb + ((chr * 0x80)); else charaddr = ega->charseta + ((chr * 0x80)); int fg, bg; if (drawcursor) { bg = ega->pallook[ega->egapal[attr & 0x0f]]; fg = ega->pallook[ega->egapal[attr >> 4]]; } else { fg = ega->pallook[ega->egapal[attr & 0x0f]]; bg = ega->pallook[ega->egapal[attr >> 4]]; if ((attr & 0x80) && ega->attrregs[0x10] & 8) { bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; if (ega->blink & 0x10) fg = bg; } } uint32_t dat = ega->vram[charaddr + (ega->sc << 2)]; dat <<= 1; if ((chr & ~0x1F) == 0xC0 && (ega->attrregs[0x10] & 4)) dat |= (dat >> 1) & 1; for (int xx = 0; xx < charwidth; xx++) p[xx] = (dat & (0x100 >> (xx>>dwshift))) ? fg : bg; ega->ma += 4; p += charwidth; } ega->ma &= 0x3ffff; } } void ega_render_graphics(ega_t *ega) { if ((ega->displine + ega->y_add) < 0) return; uint32_t *p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; if (ega->firstline_draw == 2000) ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; const bool doublewidth = ((ega->seqregs[1] & 8) != 0); const bool cga2bpp = ((ega->gdcreg[5] & 0x20) != 0); const int dotwidth = (doublewidth ? 2 : 1); const int charwidth = dotwidth*8; int secondcclk = 0; for (int x = 0; x <= (ega->hdisp + ega->scrollcache); x += charwidth) { uint32_t addr = ega->remap_func(ega, ega->ma) & ega->vrammask; uint8_t edat[4]; if (ega->seqregs[1] & 4) { // FIXME: Verify the behaviour of planes 1,3 on actual hardware edat[0] = ega->vram[(addr | 0) ^ secondcclk]; edat[1] = ega->vram[(addr | 1) ^ secondcclk]; edat[2] = ega->vram[(addr | 2) ^ secondcclk]; edat[3] = ega->vram[(addr | 3) ^ secondcclk]; secondcclk = (secondcclk + 1) & 1; if (secondcclk == 0) ega->ma += 4; } else { *(uint32_t *) (&edat[0]) = *(uint32_t *) (&ega->vram[addr]); ega->ma += 4; } ega->ma &= 0x3ffff; if (cga2bpp) { // Remap CGA 2bpp-chunky data into fully planar data uint8_t dat0 = egaremap2bpp[edat[1] ] | (egaremap2bpp[edat[0] ] << 4); uint8_t dat1 = egaremap2bpp[edat[1]>>1] | (egaremap2bpp[edat[0]>>1] << 4); uint8_t dat2 = egaremap2bpp[edat[3] ] | (egaremap2bpp[edat[2] ] << 4); uint8_t dat3 = egaremap2bpp[edat[3]>>1] | (egaremap2bpp[edat[2]>>1] << 4); edat[0] = dat0; edat[1] = dat1; edat[2] = dat2; edat[3] = dat3; } if (ega->crtc[0x17] & 0x80) { for (int i = 0; i < 4; i++) { const int outoffs = i*(dotwidth<<1); const int inshift = 6 - (i<<1); uint8_t dat = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3] ) | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); uint32_t p0 = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; uint32_t p1 = ega->pallook[ega->egapal[(dat ) & ega->plane_mask]]; for (int subx = 0; subx < dotwidth; subx++) p[outoffs + subx] = p0; for (int subx = 0; subx < dotwidth; subx++) p[outoffs + subx + dotwidth] = p1; } } else memset(p, 0x00, charwidth * sizeof(uint32_t)); p += charwidth; } }