/* Copyright holders: John Elliott see COPYING for more details */ /*Hercules InColor emulation*/ #include #include "ibm.h" #include "device.h" #include "mem.h" #include "timer.h" #include "video.h" #include "vid_incolor.h" /* extended CRTC registers */ #define INCOLOR_CRTC_XMODE 20 /* xMode register */ #define INCOLOR_CRTC_UNDER 21 /* Underline */ #define INCOLOR_CRTC_OVER 22 /* Overstrike */ #define INCOLOR_CRTC_EXCEPT 23 /* Exception */ #define INCOLOR_CRTC_MASK 24 /* Plane display mask & write mask */ #define INCOLOR_CRTC_RWCTRL 25 /* Read/write control */ #define INCOLOR_CRTC_RWCOL 26 /* Read/write colour */ #define INCOLOR_CRTC_PROTECT 27 /* Latch protect */ #define INCOLOR_CRTC_PALETTE 28 /* Palette */ /* character width */ #define INCOLOR_CW ((incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) ? 8 : 9) /* mode control register */ #define INCOLOR_CTRL_GRAPH 0x02 #define INCOLOR_CTRL_ENABLE 0x08 #define INCOLOR_CTRL_BLINK 0x20 #define INCOLOR_CTRL_PAGE1 0x80 /* CRTC status register */ #define INCOLOR_STATUS_HSYNC 0x01 /* horizontal sync */ #define INCOLOR_STATUS_LIGHT 0x02 #define INCOLOR_STATUS_VIDEO 0x08 #define INCOLOR_STATUS_ID 0x50 /* Card identification */ #define INCOLOR_STATUS_VSYNC 0x80 /* -vertical sync */ /* configuration switch register */ #define INCOLOR_CTRL2_GRAPH 0x01 #define INCOLOR_CTRL2_PAGE1 0x02 /* extended mode register */ #define INCOLOR_XMODE_RAMFONT 0x01 #define INCOLOR_XMODE_90COL 0x02 /* Read/write control */ #define INCOLOR_RWCTRL_WRMODE 0x30 #define INCOLOR_RWCTRL_POLARITY 0x40 /* exception register */ #define INCOLOR_EXCEPT_CURSOR 0x0F /* Cursor colour */ #define INCOLOR_EXCEPT_PALETTE 0x10 /* Enable palette register */ #define INCOLOR_EXCEPT_ALTATTR 0x20 /* Use alternate attributes */ /* Default palette */ static unsigned char defpal[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F }; static uint32_t incolor_rgb[64]; /* Mapping of inks to RGB */ static unsigned char init_rgb[64][3] = { // rgbRGB { 0x00, 0x00, 0x00 }, // 000000 { 0x00, 0x00, 0xaa }, // 000001 { 0x00, 0xaa, 0x00 }, // 000010 { 0x00, 0xaa, 0xaa }, // 000011 { 0xaa, 0x00, 0x00 }, // 000100 { 0xaa, 0x00, 0xaa }, // 000101 { 0xaa, 0xaa, 0x00 }, // 000110 { 0xaa, 0xaa, 0xaa }, // 000111 { 0x00, 0x00, 0x55 }, // 001000 { 0x00, 0x00, 0xff }, // 001001 { 0x00, 0xaa, 0x55 }, // 001010 { 0x00, 0xaa, 0xff }, // 001011 { 0xaa, 0x00, 0x55 }, // 001100 { 0xaa, 0x00, 0xff }, // 001101 { 0xaa, 0xaa, 0x55 }, // 001110 { 0xaa, 0xaa, 0xff }, // 001111 { 0x00, 0x55, 0x00 }, // 010000 { 0x00, 0x55, 0xaa }, // 010001 { 0x00, 0xff, 0x00 }, // 010010 { 0x00, 0xff, 0xaa }, // 010011 { 0xaa, 0x55, 0x00 }, // 010100 { 0xaa, 0x55, 0xaa }, // 010101 { 0xaa, 0xff, 0x00 }, // 010110 { 0xaa, 0xff, 0xaa }, // 010111 { 0x00, 0x55, 0x55 }, // 011000 { 0x00, 0x55, 0xff }, // 011001 { 0x00, 0xff, 0x55 }, // 011010 { 0x00, 0xff, 0xff }, // 011011 { 0xaa, 0x55, 0x55 }, // 011100 { 0xaa, 0x55, 0xff }, // 011101 { 0xaa, 0xff, 0x55 }, // 011110 { 0xaa, 0xff, 0xff }, // 011111 { 0x55, 0x00, 0x00 }, // 100000 { 0x55, 0x00, 0xaa }, // 100001 { 0x55, 0xaa, 0x00 }, // 100010 { 0x55, 0xaa, 0xaa }, // 100011 { 0xff, 0x00, 0x00 }, // 100100 { 0xff, 0x00, 0xaa }, // 100101 { 0xff, 0xaa, 0x00 }, // 100110 { 0xff, 0xaa, 0xaa }, // 100111 { 0x55, 0x00, 0x55 }, // 101000 { 0x55, 0x00, 0xff }, // 101001 { 0x55, 0xaa, 0x55 }, // 101010 { 0x55, 0xaa, 0xff }, // 101011 { 0xff, 0x00, 0x55 }, // 101100 { 0xff, 0x00, 0xff }, // 101101 { 0xff, 0xaa, 0x55 }, // 101110 { 0xff, 0xaa, 0xff }, // 101111 { 0x55, 0x55, 0x00 }, // 110000 { 0x55, 0x55, 0xaa }, // 110001 { 0x55, 0xff, 0x00 }, // 110010 { 0x55, 0xff, 0xaa }, // 110011 { 0xff, 0x55, 0x00 }, // 110100 { 0xff, 0x55, 0xaa }, // 110101 { 0xff, 0xff, 0x00 }, // 110110 { 0xff, 0xff, 0xaa }, // 110111 { 0x55, 0x55, 0x55 }, // 111000 { 0x55, 0x55, 0xff }, // 111001 { 0x55, 0xff, 0x55 }, // 111010 { 0x55, 0xff, 0xff }, // 111011 { 0xff, 0x55, 0x55 }, // 111100 { 0xff, 0x55, 0xff }, // 111101 { 0xff, 0xff, 0x55 }, // 111110 { 0xff, 0xff, 0xff }, // 111111 }; typedef struct incolor_t { mem_mapping_t mapping; uint8_t crtc[32]; int crtcreg; uint8_t ctrl, ctrl2, stat; int dispontime, dispofftime; int64_t vidtime; int firstline, lastline; int linepos, displine; int vc, sc; uint16_t ma, maback; int con, coff, cursoron; int dispon, blink; int vsynctime, vadj; uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */ uint8_t palette_idx; /* Palette write index */ uint8_t latch[4]; /* Memory read/write latches */ uint8_t *vram; } incolor_t; void incolor_recalctimings(incolor_t *incolor); void incolor_write(uint32_t addr, uint8_t val, void *p); uint8_t incolor_read(uint32_t addr, void *p); void incolor_out(uint16_t addr, uint8_t val, void *p) { incolor_t *incolor = (incolor_t *)p; /* pclog("InColor out %04X %02X\n",addr,val); */ switch (addr) { case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: incolor->crtcreg = val & 31; return; case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: if (incolor->crtcreg > 28) return; /* Palette load register */ if (incolor->crtcreg == INCOLOR_CRTC_PALETTE) { incolor->palette[incolor->palette_idx % 16] = val; ++incolor->palette_idx; } incolor->crtc[incolor->crtcreg] = val; if (incolor->crtc[10] == 6 && incolor->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ { incolor->crtc[10] = 0xb; incolor->crtc[11] = 0xc; } incolor_recalctimings(incolor); return; case 0x3b8: incolor->ctrl = val; return; case 0x3bf: incolor->ctrl2 = val; if (val & 2) mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x10000); else mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x08000); return; } } uint8_t incolor_in(uint16_t addr, void *p) { incolor_t *incolor = (incolor_t *)p; /* pclog("InColor in %04X %02X %04X:%04X %04X\n",addr,(incolor->stat & 0xF) | ((incolor->stat & 8) << 4),CS,pc,CX); */ switch (addr) { case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: return incolor->crtcreg; case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: if (incolor->crtcreg > 28) return 0xff; incolor->palette_idx = 0; /* Read resets the palette index */ return incolor->crtc[incolor->crtcreg]; case 0x3ba: /* 0x50: InColor card identity */ return (incolor->stat & 0xf) | ((incolor->stat & 8) << 4) | 0x50; } return 0xff; } void incolor_write(uint32_t addr, uint8_t val, void *p) { incolor_t *incolor = (incolor_t *)p; int plane; unsigned char wmask = incolor->crtc[INCOLOR_CRTC_MASK]; unsigned char wmode = incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE; unsigned char fg = incolor->crtc[INCOLOR_CRTC_RWCOL] & 0x0F; unsigned char bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F; unsigned char w; unsigned char vmask; /* Mask of bit within byte */ unsigned char pmask; /* Mask of plane within colour value */ unsigned char latch; egawrites++; /* 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; addr &= 0xFFFF; /* In text mode, writes to the bottom 16k always touch all 4 planes */ if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) { incolor->vram[addr] = val; return; } /* There are four write modes: * 0: 1 => foreground, 0 => background * 1: 1 => foreground, 0 => source latch * 2: 1 => source latch, 0 => background * 3: 1 => source latch, 0 => ~source latch */ pmask = 1; for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, plane++) { if (wmask & 0x10) /* Ignore writes to selected plane */ { continue; } latch = incolor->latch[plane]; for (vmask = 0x80; vmask != 0; vmask >>= 1) { switch (wmode) { case 0x00: if (val & vmask) w = (fg & pmask); else w = (bg & pmask); break; case 0x10: if (val & vmask) w = (fg & pmask); else w = (latch & vmask); break; case 0x20: if (val & vmask) w = (latch & vmask); else w = (bg & pmask); break; case 0x30: if (val & vmask) w = (latch & vmask); else w = ((~latch) & vmask); break; } /* w is nonzero to write a 1, zero to write a 0 */ if (w) incolor->vram[addr] |= vmask; else incolor->vram[addr] &= ~vmask; } } } uint8_t incolor_read(uint32_t addr, void *p) { incolor_t *incolor = (incolor_t *)p; unsigned plane; unsigned char lp = incolor->crtc[INCOLOR_CRTC_PROTECT]; unsigned char value = 0; unsigned char dc; /* "don't care" register */ unsigned char bg; /* background colour */ unsigned char fg; unsigned char mask, pmask; egareads++; addr &= 0xFFFF; /* Read the four planes into latches */ for (plane = 0; plane < 4; plane++, addr += 0x10000) { incolor->latch[plane] &= lp; incolor->latch[plane] |= (incolor->vram[addr] & ~lp); } addr &= 0xFFFF; /* In text mode, reads from the bottom 16k assume all planes have * the same contents */ if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) { return incolor->latch[0]; } /* For each pixel, work out if its colour matches the background */ for (mask = 0x80; mask != 0; mask >>= 1) { fg = 0; dc = incolor->crtc[INCOLOR_CRTC_RWCTRL] & 0x0F; bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F; for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) { if (dc & pmask) { fg |= (bg & pmask); } else if (incolor->latch[plane] & mask) { fg |= pmask; } } if (bg == fg) value |= mask; } if (incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) { value = ~value; } return value; } void incolor_recalctimings(incolor_t *incolor) { double disptime; double _dispontime, _dispofftime; disptime = incolor->crtc[0] + 1; _dispontime = incolor->crtc[1]; _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; incolor->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); incolor->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); } static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) { unsigned i; int elg, blk; unsigned ull; unsigned val; unsigned ifg, ibg; const unsigned char *fnt; uint32_t fg, bg; int cw = INCOLOR_CW; blk = 0; if (incolor->ctrl & INCOLOR_CTRL_BLINK) { if (attr & 0x80) { blk = (incolor->blink & 16); } attr &= 0x7f; } if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) { /* MDA-compatible attributes */ ibg = 0; ifg = 7; if ((attr & 0x77) == 0x70) /* Invert */ { ifg = 0; ibg = 7; } if (attr & 8) { ifg |= 8; /* High intensity FG */ } if (attr & 0x80) { ibg |= 8; /* High intensity BG */ } if ((attr & 0x77) == 0) /* Blank */ { ifg = ibg; } ull = ((attr & 0x07) == 1) ? 13 : 0xffff; } else { /* CGA-compatible attributes */ ull = 0xffff; ifg = attr & 0x0F; ibg = (attr >> 4) & 0x0F; } if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) { fg = incolor_rgb[incolor->palette[ifg]]; bg = incolor_rgb[incolor->palette[ibg]]; } else { fg = incolor_rgb[defpal[ifg]]; bg = incolor_rgb[defpal[ibg]]; } /* ELG set to stretch 8px character to 9px */ elg = ((chr >= 0xc0) && (chr <= 0xdf)); fnt = &(fontdatm[chr][incolor->sc]); if (blk) { val = 0x000; /* Blinking, draw all background */ } else if (incolor->sc == ull) { val = 0x1ff; /* Underscore, draw all foreground */ } else { val = fnt[0] << 1; if (elg) { val |= (val >> 1) & 1; } } for (i = 0; i < cw; i++) { ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = (val & 0x100) ? fg : bg; val = val << 1; } } static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) { unsigned i; int elg, blk; unsigned ull; unsigned val[4]; unsigned ifg, ibg, cfg, pmask, plane; const unsigned char *fnt; uint32_t fg; int cw = INCOLOR_CW; int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; blk = 0; if (blink) { if (attr & 0x80) { blk = (incolor->blink & 16); } attr &= 0x7f; } if (altattr) { /* MDA-compatible attributes */ ibg = 0; ifg = 7; if ((attr & 0x77) == 0x70) /* Invert */ { ifg = 0; ibg = 7; } if (attr & 8) { ifg |= 8; /* High intensity FG */ } if (attr & 0x80) { ibg |= 8; /* High intensity BG */ } if ((attr & 0x77) == 0) /* Blank */ { ifg = ibg; } ull = ((attr & 0x07) == 1) ? 13 : 0xffff; } else { /* CGA-compatible attributes */ ull = 0xffff; ifg = attr & 0x0F; ibg = (attr >> 4) & 0x0F; } if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) { elg = 0; } else { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } fnt = incolor->vram + 0x4000 + 16 * chr + incolor->sc; if (blk) { /* Blinking, draw all background */ val[0] = val[1] = val[2] = val[3] = 0x000; } else if (incolor->sc == ull) { /* Underscore, draw all foreground */ val[0] = val[1] = val[2] = val[3] = 0x1ff; } else { val[0] = fnt[0x00000] << 1; val[1] = fnt[0x10000] << 1; val[2] = fnt[0x20000] << 1; val[3] = fnt[0x30000] << 1; if (elg) { val[0] |= (val[0] >> 1) & 1; val[1] |= (val[1] >> 1) & 1; val[2] |= (val[2] >> 1) & 1; val[3] |= (val[3] >> 1) & 1; } } for (i = 0; i < cw; i++) { /* Generate pixel colour */ cfg = 0; pmask = 1; for (plane = 0; plane < 4; plane++, pmask = pmask << 1) { if (val[plane] & 0x100) cfg |= (ifg & pmask); else cfg |= (ibg & pmask); } /* cfg = colour of foreground pixels */ if (altattr && (attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ if (palette) { fg = incolor_rgb[incolor->palette[cfg]]; } else { fg = incolor_rgb[defpal[cfg]]; } ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; val[0] = val[0] << 1; val[1] = val[1] << 1; val[2] = val[2] << 1; val[3] = val[3] << 1; } } static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) { unsigned i; int elg, blk, ul, ol, bld; unsigned ull, oll, ulc, olc; unsigned val[4]; unsigned ifg, ibg, cfg, pmask, plane; const unsigned char *fnt; uint32_t fg; int cw = INCOLOR_CW; int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; int font = (attr & 0x0F); if (font >= 12) font &= 7; blk = 0; if (blink && altattr) { if (attr & 0x40) { blk = (incolor->blink & 16); } attr &= 0x7f; } if (altattr) { /* MDA-compatible attributes */ if (blink) { ibg = (attr & 0x80) ? 8 : 0; bld = 0; ol = (attr & 0x20) ? 1 : 0; ul = (attr & 0x10) ? 1 : 0; } else { bld = (attr & 0x80) ? 1 : 0; ibg = (attr & 0x40) ? 0x0F : 0; ol = (attr & 0x20) ? 1 : 0; ul = (attr & 0x10) ? 1 : 0; } } else { /* CGA-compatible attributes */ ibg = 0; ifg = (attr >> 4) & 0x0F; ol = 0; ul = 0; bld = 0; } if (ul) { ull = incolor->crtc[INCOLOR_CRTC_UNDER] & 0x0F; ulc = (incolor->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F; if (ulc == 0) ulc = 7; } else { ull = 0xFFFF; } if (ol) { oll = incolor->crtc[INCOLOR_CRTC_OVER] & 0x0F; olc = (incolor->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F; if (olc == 0) olc = 7; } else { oll = 0xFFFF; } if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) { elg = 0; } else { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } fnt = incolor->vram + 0x4000 + 16 * chr + 4096 * font + incolor->sc; if (blk) { /* Blinking, draw all background */ val[0] = val[1] = val[2] = val[3] = 0x000; } else if (incolor->sc == ull) { /* Underscore, draw all foreground */ val[0] = val[1] = val[2] = val[3] = 0x1ff; } else { val[0] = fnt[0x00000] << 1; val[1] = fnt[0x10000] << 1; val[2] = fnt[0x20000] << 1; val[3] = fnt[0x30000] << 1; if (elg) { val[0] |= (val[0] >> 1) & 1; val[1] |= (val[1] >> 1) & 1; val[2] |= (val[2] >> 1) & 1; val[3] |= (val[3] >> 1) & 1; } if (bld) { val[0] |= (val[0] >> 1); val[1] |= (val[1] >> 1); val[2] |= (val[2] >> 1); val[3] |= (val[3] >> 1); } } for (i = 0; i < cw; i++) { /* Generate pixel colour */ cfg = 0; pmask = 1; if (incolor->sc == oll) { cfg = olc ^ ibg; /* Strikethrough */ } else if (incolor->sc == ull) { cfg = ulc ^ ibg; /* Underline */ } else { for (plane = 0; plane < 4; plane++, pmask = pmask << 1) { if (val[plane] & 0x100) { if (altattr) cfg |= ((~ibg) & pmask); else cfg |= ((~ifg) & pmask); } else if (altattr) cfg |= (ibg & pmask); } } if (palette) { fg = incolor_rgb[incolor->palette[cfg]]; } else { fg = incolor_rgb[defpal[cfg]]; } ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; val[0] = val[0] << 1; val[1] = val[1] << 1; val[2] = val[2] << 1; val[3] = val[3] << 1; } } static void incolor_text_line(incolor_t *incolor, uint16_t ca) { int drawcursor; int x, c; uint8_t chr, attr; uint32_t col; for (x = 0; x < incolor->crtc[1]; x++) { chr = incolor->vram[(incolor->ma << 1) & 0x3fff]; attr = incolor->vram[((incolor->ma << 1) + 1) & 0x3fff]; drawcursor = ((incolor->ma == ca) && incolor->con && incolor->cursoron); switch (incolor->crtc[INCOLOR_CRTC_XMODE] & 5) { case 0: case 4: /* ROM font */ incolor_draw_char_rom(incolor, x, chr, attr); break; case 1: /* 4k RAMfont */ incolor_draw_char_ram4(incolor, x, chr, attr); break; case 5: /* 48k RAMfont */ incolor_draw_char_ram48(incolor, x, chr, attr); break; } ++incolor->ma; if (drawcursor) { int cw = INCOLOR_CW; uint8_t ink = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR; if (ink == 0) ink = (attr & 0x08) | 7; /* In MDA-compatible mode, cursor brightness comes from * background */ if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) { ink = (attr & 0x08) | (ink & 7); } if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) { col = incolor_rgb[incolor->palette[ink]]; } else { col = incolor_rgb[defpal[ink]]; } for (c = 0; c < cw; c++) { ((uint32_t *)buffer32->line[incolor->displine])[x * cw + c] = col; } } } } static void incolor_graphics_line(incolor_t *incolor) { uint8_t mask; uint16_t ca; int x, c, plane, col; uint8_t ink; uint16_t val[4]; /* Graphics mode. */ ca = (incolor->sc & 3) * 0x2000; if ((incolor->ctrl & INCOLOR_CTRL_PAGE1) && (incolor->ctrl2 & INCOLOR_CTRL2_PAGE1)) ca += 0x8000; for (x = 0; x < incolor->crtc[1]; x++) { mask = incolor->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */ for (plane = 0; plane < 4; plane++, mask = mask >> 1) { if (mask & 1) val[plane] = (incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; else val[plane] = 0; } incolor->ma++; for (c = 0; c < 16; c++) { ink = 0; for (plane = 0; plane < 4; plane++) { ink = ink >> 1; if (val[plane] & 0x8000) ink |= 8; val[plane] = val[plane] << 1; } /* Is palette in use? */ if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) col = incolor->palette[ink]; else col = defpal[ink]; ((uint32_t *)buffer32->line[incolor->displine])[(x << 4) + c] = incolor_rgb[col]; } } } void incolor_poll(void *p) { incolor_t *incolor = (incolor_t *)p; uint16_t ca = (incolor->crtc[15] | (incolor->crtc[14] << 8)) & 0x3fff; int x; int oldvc; int oldsc; if (!incolor->linepos) { // pclog("InColor poll %i %i\n", incolor->vc, incolor->sc); incolor->vidtime += incolor->dispofftime; incolor->stat |= 1; incolor->linepos = 1; oldsc = incolor->sc; if ((incolor->crtc[8] & 3) == 3) incolor->sc = (incolor->sc << 1) & 7; if (incolor->dispon) { if (incolor->displine < incolor->firstline) { incolor->firstline = incolor->displine; video_wait_for_buffer(); } incolor->lastline = incolor->displine; if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) { incolor_graphics_line(incolor); } else { incolor_text_line(incolor, ca); } } incolor->sc = oldsc; if (incolor->vc == incolor->crtc[7] && !incolor->sc) { incolor->stat |= 8; // printf("VSYNC on %i %i\n",vc,sc); } incolor->displine++; if (incolor->displine >= 500) incolor->displine = 0; } else { incolor->vidtime += incolor->dispontime; if (incolor->dispon) incolor->stat &= ~1; incolor->linepos = 0; if (incolor->vsynctime) { incolor->vsynctime--; if (!incolor->vsynctime) { incolor->stat &= ~8; // printf("VSYNC off %i %i\n",vc,sc); } } if (incolor->sc == (incolor->crtc[11] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[11] & 31) >> 1))) { incolor->con = 0; incolor->coff = 1; } if (incolor->vadj) { incolor->sc++; incolor->sc &= 31; incolor->ma = incolor->maback; incolor->vadj--; if (!incolor->vadj) { incolor->dispon = 1; incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; incolor->sc = 0; } } else if (incolor->sc == incolor->crtc[9] || ((incolor->crtc[8] & 3) == 3 && incolor->sc == (incolor->crtc[9] >> 1))) { incolor->maback = incolor->ma; incolor->sc = 0; oldvc = incolor->vc; incolor->vc++; incolor->vc &= 127; if (incolor->vc == incolor->crtc[6]) incolor->dispon = 0; if (oldvc == incolor->crtc[4]) { // printf("Display over at %i\n",displine); incolor->vc = 0; incolor->vadj = incolor->crtc[5]; if (!incolor->vadj) incolor->dispon=1; if (!incolor->vadj) incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; if ((incolor->crtc[10] & 0x60) == 0x20) incolor->cursoron = 0; else incolor->cursoron = incolor->blink & 16; } if (incolor->vc == incolor->crtc[7]) { incolor->dispon = 0; incolor->displine = 0; incolor->vsynctime = 16;//(crtcm[3]>>4)+1; if (incolor->crtc[7]) { // printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) { x = incolor->crtc[1] << 4; } else { x = incolor->crtc[1] * 9; } incolor->lastline++; if (x != xsize || (incolor->lastline - incolor->firstline) != ysize) { xsize = x; ysize = incolor->lastline - incolor->firstline; // printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); if (xsize < 64) xsize = 656; if (ysize < 32) ysize = 200; updatewindowsize(xsize, ysize); } video_blit_memtoscreen(0, incolor->firstline, 0, incolor->lastline - incolor->firstline, xsize, incolor->lastline - incolor->firstline); frames++; if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) { video_res_x = incolor->crtc[1] * 16; video_res_y = incolor->crtc[6] * 4; video_bpp = 1; } else { video_res_x = incolor->crtc[1]; video_res_y = incolor->crtc[6]; video_bpp = 0; } } incolor->firstline = 1000; incolor->lastline = 0; incolor->blink++; } } else { incolor->sc++; incolor->sc &= 31; incolor->ma = incolor->maback; } if ((incolor->sc == (incolor->crtc[10] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[10] & 31) >> 1)))) { incolor->con = 1; // printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); } } } void *incolor_init() { int c; incolor_t *incolor = malloc(sizeof(incolor_t)); memset(incolor, 0, sizeof(incolor_t)); incolor->vram = malloc(0x40000); /* 4 planes of 64k */ timer_add(incolor_poll, &incolor->vidtime, TIMER_ALWAYS_ENABLED, incolor); mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, 0, incolor); io_sethandler(0x03b0, 0x0010, incolor_in, NULL, NULL, incolor_out, NULL, NULL, incolor); for (c = 0; c < 64; c++) { incolor_rgb[c] = makecol32(init_rgb[c][0], init_rgb[c][1], init_rgb[c][2]); } /* Initialise CRTC regs to safe values */ incolor->crtc[INCOLOR_CRTC_MASK ] = 0x0F; /* All planes displayed */ incolor->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY; incolor->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */ incolor->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR; for (c = 0; c < 16; c++) { incolor->palette[c] = defpal[c]; } incolor->palette_idx = 0; return incolor; } void incolor_close(void *p) { incolor_t *incolor = (incolor_t *)p; free(incolor->vram); free(incolor); } void incolor_speed_changed(void *p) { incolor_t *incolor = (incolor_t *)p; incolor_recalctimings(incolor); } device_t incolor_device = { "Hercules InColor", 0, incolor_init, incolor_close, NULL, incolor_speed_changed, NULL, NULL };