From 2acbcece0e2c3c1283d7d3415062b214a9af0433 Mon Sep 17 00:00:00 2001 From: SarahW Date: Thu, 23 Mar 2017 19:36:59 +0000 Subject: [PATCH] Added MDSI Genius emulation. Patch from John Elliott. --- src/Makefile.am | 2 +- src/Makefile.linux32 | 2 +- src/Makefile.linux64 | 2 +- src/Makefile.mingw | 2 +- src/Makefile.mingw64 | 2 +- src/ibm.h | 5 +- src/mem.c | 1 + src/vid_genius.c | 630 +++++++++++++++++++++++++++++++++++++++++++ src/vid_genius.h | 1 + src/video.c | 13 + 10 files changed, 653 insertions(+), 7 deletions(-) create mode 100644 src/vid_genius.c create mode 100644 src/vid_genius.h diff --git a/src/Makefile.am b/src/Makefile.am index 70e1cd5..74a68a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,7 +27,7 @@ sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_g sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \ sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c tandy_eeprom.c tandy_rom.c thread-pthread.c \ timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c vid_ati18800.c vid_ati28800.c \ -vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_colorplus.c vid_ega.c vid_et4000.c vid_et4000w32.c vid_hercules.c \ +vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_colorplus.c vid_ega.c vid_et4000.c vid_et4000w32.c vid_genius.c vid_hercules.c \ vid_icd2061.c vid_ics2595.c vid_incolor.c vid_mda.c vid_olivetti_m24.c vid_oti067.c vid_paradise.c vid_pc200.c \ vid_pc1512.c vid_pc1640.c vid_pcjr.c vid_ps1_svga.c vid_s3.c vid_s3_virge.c vid_sdac_ramdac.c \ vid_stg_ramdac.c vid_svga.c vid_svga_render.c vid_tandy.c vid_tandysl.c vid_tgui9440.c \ diff --git a/src/Makefile.linux32 b/src/Makefile.linux32 index ed8722e..2baac94 100644 --- a/src/Makefile.linux32 +++ b/src/Makefile.linux32 @@ -16,7 +16,7 @@ sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_g sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o thread-pthread.o \ timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ -vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o vid_et4000w32.o vid_hercules.o \ +vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o vid_et4000w32.o vid_genius.o vid_hercules.o \ vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc200.o \ vid_pc1512.o vid_pc1640.o vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o \ vid_stg_ramdac.o vid_svga.o vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o \ diff --git a/src/Makefile.linux64 b/src/Makefile.linux64 index d620e19..6aee7d7 100644 --- a/src/Makefile.linux64 +++ b/src/Makefile.linux64 @@ -15,7 +15,7 @@ sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_g sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o thread-pthread.o \ timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ -vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o vid_et4000w32.o vid_hercules.o \ +vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o vid_et4000w32.o vid_genius.o vid_hercules.o \ vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc200.o \ vid_pc1512.o vid_pc1640.o vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o \ vid_stg_ramdac.o vid_svga.o vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o \ diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 500a222..a93159d 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -14,7 +14,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o \ - vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \ + vid_et4000w32.o vid_et4000w32i.o vid_genius.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \ vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o \ vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index 25a284b..53a7377 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -14,7 +14,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \ soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o \ - vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \ + vid_et4000w32.o vid_et4000w32i.o vid_genius.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \ vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o \ vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \ diff --git a/src/ibm.h b/src/ibm.h index f6a521e..03a39de 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -332,8 +332,8 @@ int disctime; char discfns[2][256]; int driveempty[2]; -#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR) && (romset=ROM_IBMAT)) -#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && gfxcard!=GFX_COLORPLUS && gfxcard!=GFX_INCOLOR && gfxcard!=GFX_WY700 && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) +#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR || gfxcard==GFX_GENIUS) && (romset=ROM_IBMAT)) +#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && gfxcard!=GFX_COLORPLUS && gfxcard!=GFX_INCOLOR && gfxcard!=GFX_WY700 && gfxcard!=GFX_GENIUS && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) #define PCJR (romset == ROM_IBMPCJR) #define AMIBIOS (romset==ROM_AMI386SX || romset==ROM_AMI486 || romset == ROM_WIN486) @@ -421,6 +421,7 @@ enum GFX_INCOLOR, /* Hercules InColor */ GFX_COLORPLUS, /* Plantronics ColorPlus */ GFX_WY700, /* Wyse 700 */ + GFX_GENIUS, /* MDSI Genius */ GFX_MAX }; diff --git a/src/mem.c b/src/mem.c index c08b35e..b4f1d8b 100644 --- a/src/mem.c +++ b/src/mem.c @@ -77,6 +77,7 @@ int loadbios() loadfont("roms/mda.rom", 0); loadfont("roms/wy700.rom", 3); + loadfont("roms/8x12.bin", 4); biosmask = 0xffff; diff --git a/src/vid_genius.c b/src/vid_genius.c new file mode 100644 index 0000000..2e73e7c --- /dev/null +++ b/src/vid_genius.c @@ -0,0 +1,630 @@ +/* MDSI Genius VHR emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_genius.h" + +#define GENIUS_XSIZE 728 +#define GENIUS_YSIZE 1008 + +void updatewindowsize(int x, int y); +void loadfont(char *s, int format); + +extern uint8_t fontdat8x12[256][16]; + +/* I'm at something of a disadvantage writing this emulation: I don't have an + * MDSI Genius card, nor do I have the BIOS extension (VHRBIOS.SYS) that came + * with it. What I do have are the GEM and Windows 1.04 drivers, plus a driver + * for a later MCA version of the card. The latter can be found at + * and is necessary if you + * want the Windows driver to work. + * + * This emulation appears to work correctly with: + * The MCA drivers GMC_ANSI.SYS and INS_ANSI.SYS + * The GEM driver SDGEN9.VGA + * The Windows 1.04 driver GENIUS.DRV + * + * As far as I can see, the card uses a fixed resolution of 728x1008 pixels. + * It has the following modes of operation: + * + * > MDA-compatible: 80x25 text, each character 9x15 pixels. + * > CGA-compatible: 640x200 mono graphics + * > Dual: MDA text in the top half, CGA graphics in the bottom + * > Native text: 80x66 text, each character 9x15 pixels. + * > Native graphics: 728x1008 mono graphics. + * + * Under the covers, this seems to translate to: + * > Text framebuffer. At B000:0000, 16k. Displayed if enable bit is set + * in the MDA control register. + * > Graphics framebuffer. In native modes goes from A000:0000 to A000:FFFF + * and B800:0000 to B800:FFFF. In CGA-compatible + * mode only the section at B800:0000 to B800:7FFF + * is visible. Displayed if enable bit is set in the + * CGA control register. + * + * Two card-specific registers control text and graphics display: + * + * 03B0: Control register. + * Bit 0: Map all graphics framebuffer into memory. + * Bit 2: Unknown. Set by GMC /M; cleared by mode set or GMC /T. + * Bit 4: Set for CGA-compatible graphics, clear for native graphics. + * Bit 5: Set for black on white, clear for white on black. + * + * 03B1: Character height register. + * Bits 0-1: Character cell height (0 => 15, 1 => 14, 2 => 13, 3 => 12) + * Bit 4: Set to double character cell height (scanlines are doubled) + * Bit 7: Unknown, seems to be set for all modes except 80x66 + * + * Not having the card also means I don't have its font. According to the + * card brochure the font is an 8x12 bitmap in a 9x15 character cell. I + * therefore generated it by taking the MDA font, increasing graphics to + * 16 pixels in height and reducing the height of characters so they fit + * in an 8x12 cell if necessary. + */ + + + +typedef struct genius_t +{ + mem_mapping_t mapping; + + uint8_t mda_crtc[32]; /* The 'CRTC' as the host PC sees it */ + int mda_crtcreg; /* Current CRTC register */ + uint8_t genius_control; /* Native control register + * I think bit 0 enables the full + * framebuffer. + */ + uint8_t genius_charh; /* Native character height register: + * 00h => chars are 15 pixels high + * 81h => chars are 14 pixels high + * 83h => chars are 12 pixels high + * 90h => chars are 30 pixels high [15 x 2] + * 93h => chars are 24 pixels high [12 x 2] + */ + uint8_t genius_mode; /* Current mode (see list at top of file) */ + uint8_t cga_ctrl; /* Emulated CGA control register */ + uint8_t mda_ctrl; /* Emulated MDA control register */ + uint8_t cga_colour; /* Emulated CGA colour register (ignored) */ + + uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + uint8_t cga_stat; /* CGA status (IN 0x3DA) */ + + int font; /* Current font, 0 or 1 */ + int enabled; /* Display enabled, 0 or 1 */ + int detach; /* Detach cursor, 0 or 1 */ + + int dispontime, dispofftime; + int vidtime; + + int linepos, displine; + int vc; + int dispon, blink; + int vsynctime; + + uint8_t *vram; +} genius_t; + +/* Mapping of attributes to colours, in MDA emulation mode */ +static int mdacols[256][2][2]; + +void genius_recalctimings(genius_t *genius); +void genius_write(uint32_t addr, uint8_t val, void *p); +uint8_t genius_read(uint32_t addr, void *p); + + +void genius_out(uint16_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + + switch (addr) + { + case 0x3b0: /* Command / control register */ + genius->genius_control = val; + if (val & 1) + { + mem_mapping_set_addr(&genius->mapping, 0xa0000, 0x28000); + } + else + { + mem_mapping_set_addr(&genius->mapping, 0xb0000, 0x10000); + } + + break; + + case 0x3b1: + genius->genius_charh = val; + break; + + /* Emulated CRTC, register select */ + case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + genius->mda_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + genius->mda_crtc[genius->mda_crtcreg] = val; + genius_recalctimings(genius); + return; + + /* Emulated MDA control register */ + case 0x3b8: + genius->mda_ctrl = val; + return; + /* Emulated CGA control register */ + case 0x3D8: + genius->cga_ctrl = val; + return; + /* Emulated CGA colour register */ + case 0x3D9: + genius->cga_colour = val; + return; + } +} + +uint8_t genius_in(uint16_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + return genius->mda_crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + return genius->mda_crtc[genius->mda_crtcreg]; + case 0x3b8: + return genius->mda_ctrl; + case 0x3d9: + return genius->cga_colour; + case 0x3ba: + return genius->mda_stat; + case 0x3d8: + return genius->cga_ctrl; + case 0x3da: + return genius->cga_stat; + } + return 0xff; +} + + + +void genius_write(uint32_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + egawrites++; + + if (genius->genius_control & 1) + { + addr = addr % 0x28000; + } + else + /* If hi-res memory is disabled, only visible in the B000 segment */ + { + addr = (addr & 0xFFFF) + 0x10000; + } + genius->vram[addr] = val; +} + + + +uint8_t genius_read(uint32_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + egareads++; + + if (genius->genius_control & 1) + { + addr = addr % 0x28000; + } + else + /* If hi-res memory is disabled, only visible in the B000 segment */ + { + addr = (addr & 0xFFFF) + 0x10000; + } + return genius->vram[addr]; +} + + + +void genius_recalctimings(genius_t *genius) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = 0x31; + _dispontime = 0x28; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + genius->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + genius->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +/* Draw a single line of the screen in either text mode */ +void genius_textline(genius_t *genius, uint8_t background) +{ + int x; + int w = 80; /* 80 characters across */ + int cw = 9; /* Each character is 9 pixels wide */ + uint8_t chr, attr, fg, bg; + uint8_t bitmap[2]; + int blink, c, row; + int drawcursor, cursorline; + uint16_t addr; + uint8_t sc; + int charh; + uint16_t ma = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; + uint16_t ca = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; + unsigned char *framebuf = genius->vram + 0x10000; + uint8_t col; + + /* Character height is 12-15 */ + charh = 15 - (genius->genius_charh & 3); + if (genius->genius_charh & 0x10) + { + row = ((genius->displine >> 1) / charh); + sc = ((genius->displine >> 1) % charh); + } + else + { + row = (genius->displine / charh); + sc = (genius->displine % charh); + } + addr = ((ma & ~1) + row * w) * 2; + + ma += (row * w); + + if ((genius->mda_crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((genius->mda_crtc[10] & 0x1F) <= sc) && + ((genius->mda_crtc[11] & 0x1F) >= sc); + } + + for (x = 0; x < w; x++) + { + chr = framebuf[(addr + 2 * x) & 0x3FFF]; + attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && genius->enabled && + (genius->mda_ctrl & 8)); + + switch (genius->mda_crtc[10] & 0x60) + { + case 0x00: drawcursor = drawcursor && (genius->blink & 16); break; + case 0x60: drawcursor = drawcursor && (genius->blink & 32); break; + } + blink = ((genius->blink & 16) && + (genius->mda_ctrl & 0x20) && + (attr & 0x80) && !drawcursor); + + if (genius->mda_ctrl & 0x20) attr &= 0x7F; + /* MDA underline */ + if (sc == charh && ((attr & 7) == 1)) + { + col = mdacols[attr][blink][1]; + + if (genius->genius_control & 0x20) + { + col ^= 15; + } + + for (c = 0; c < cw; c++) + { + if (col != background) + buffer->line[genius->displine][(x * cw) + c] = col; + } + } + else /* Draw 8 pixels of character */ + { + bitmap[0] = fontdat8x12[chr][sc]; + for (c = 0; c < 8; c++) + { + col = mdacols[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + if (!(genius->enabled) || !(genius->mda_ctrl & 8)) + col = mdacols[0][0][0]; + + if (genius->genius_control & 0x20) + { + col ^= 15; + } + if (col != background) + { + buffer->line[genius->displine][(x * cw) + c] = col; + } + } + /* The ninth pixel column... */ + if ((chr & ~0x1f) == 0xc0) + { + /* Echo column 8 for the graphics chars */ + col = buffer->line[genius->displine][(x * cw) + 7]; + if (col != background) buffer->line[genius->displine][(x * cw) + 8] = col; + } + else /* Otherwise fill with background */ + { + col = mdacols[attr][blink][0]; + if (genius->genius_control & 0x20) + { + col ^= 15; + } + if (col != background) buffer->line[genius->displine][(x * cw) + 8] = col; + } + if (drawcursor) + { + for (c = 0; c < cw; c++) + buffer->line[genius->displine][(x * cw) + c] ^= mdacols[attr][0][1]; + } + ++ma; + } + } +} + + + + +/* Draw a line in the CGA 640x200 mode */ +void genius_cgaline(genius_t *genius) +{ + int x, c; + uint32_t dat; + uint8_t bitmap, ink; + uint32_t addr; + + ink = (genius->genius_control & 0x20) ? 16 : 16+15; + /* We draw the CGA at row 600 */ + if (genius->displine < 600) + { + return; + } + addr = 0x18000 + 80 * ((genius->displine - 600) >> 2); + if ((genius->displine - 600) & 2) + { + addr += 0x2000; + } + + for (x = 0; x < 80; x++) + { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) + { + if (dat & 0x80) + { + buffer->line[genius->displine][x*8 + c] = ink; + } + dat = dat << 1; + } + } +} + + + + +/* Draw a line in the native high-resolution mode */ +void genius_hiresline(genius_t *genius) +{ + int x, c; + uint32_t dat; + uint8_t bitmap, ink; + uint32_t addr; + + ink = (genius->genius_control & 0x20) ? 16 : 16+15; + /* The first 512 lines live at A0000 */ + if (genius->displine < 512) + { + addr = 128 * genius->displine; + } + else /* The second 496 live at B8000 */ + { + addr = 0x18000 + 128 * (genius->displine - 512); + } + + for (x = 0; x < 91; x++) + { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) + { + if (dat & 0x80) + { + buffer->line[genius->displine][x*8 + c] = ink; + } + dat = dat << 1; + } + } +} + + + + +void genius_poll(void *p) +{ + genius_t *genius = (genius_t *)p; + int x, c; + int oldvc; + uint8_t background; + uint16_t dat; + int mode; + + if (!genius->linepos) + { + genius->vidtime += genius->dispofftime; + genius->cga_stat |= 1; + genius->mda_stat |= 1; + genius->linepos = 1; + if (genius->dispon) + { + if (genius->genius_control & 0x20) + { + background = 16 + 15; + } + else + { + background = 16; + } + if (genius->displine == 0) + { + video_wait_for_buffer(); + } + /* Start off with a blank line */ + for (x = 0; x < GENIUS_XSIZE; x++) + { + buffer->line[genius->displine][x] = background; + } + /* If graphics display enabled, draw graphics on top + * of the blanked line */ + if (genius->cga_ctrl & 8) + { + if (genius->genius_control & 8) + { + genius_cgaline(genius); + } + else + { + genius_hiresline(genius); + } + } + /* If MDA display is enabled, draw MDA text on top + * of the lot */ + if (genius->mda_ctrl & 8) + { + genius_textline(genius, background); + } + } + genius->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (genius->displine == 1008) /* Start of VSYNC */ + { + genius->cga_stat |= 8; + genius->dispon = 0; + } + if (genius->displine == 1040) /* End of VSYNC */ + { + genius->displine = 0; + genius->cga_stat &= ~8; + genius->dispon = 1; + } + } + else + { + if (genius->dispon) + { + genius->cga_stat &= ~1; + genius->mda_stat &= ~1; + } + genius->vidtime += genius->dispontime; + genius->linepos = 0; + + if (genius->displine == 1008) + { +/* Hardcode GENIUS_XSIZE * GENIUS_YSIZE window size */ + if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) + { + xsize = GENIUS_XSIZE; + ysize = GENIUS_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + video_blit_memtoscreen_8(0, 0, xsize, ysize); + + frames++; + /* Fixed 728x1008 resolution */ + video_res_x = GENIUS_XSIZE; + video_res_y = GENIUS_YSIZE; + video_bpp = 1; + genius->blink++; + } + } +} + +void *genius_init() +{ + int c; + genius_t *genius = malloc(sizeof(genius_t)); + memset(genius, 0, sizeof(genius_t)); + + /* 160k video RAM */ + genius->vram = malloc(0x28000); + + timer_add(genius_poll, &genius->vidtime, TIMER_ALWAYS_ENABLED, genius); + + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&genius->mapping, 0xb0000, 0x10000, genius_read, NULL, NULL, genius_write, NULL, NULL, NULL, 0, genius); + /* Respond to both MDA and CGA I/O ports */ + io_sethandler(0x03b0, 0x000C, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + io_sethandler(0x03d0, 0x0010, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + + /* MDA attributes */ + /* I don't know if the Genius's MDA emulation actually does + * emulate bright / non-bright. For the time being pretend it does. */ + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + +/* Start off in 80x25 text mode */ + genius->cga_stat = 0xF4; + genius->genius_mode = 2; + genius->enabled = 1; + genius->genius_charh = 0x90; /* Native character height register */ + return genius; +} + +void genius_close(void *p) +{ + genius_t *genius = (genius_t *)p; + + free(genius->vram); + free(genius); +} + +static int genius_available() +{ + return rom_present("roms/8x12.bin"); +} + +void genius_speed_changed(void *p) +{ + genius_t *genius = (genius_t *)p; + + genius_recalctimings(genius); +} + +device_t genius_device = +{ + "Genius VHR", + 0, + genius_init, + genius_close, + genius_available, + genius_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_genius.h b/src/vid_genius.h new file mode 100644 index 0000000..e7e31de --- /dev/null +++ b/src/vid_genius.h @@ -0,0 +1 @@ +extern device_t genius_device; diff --git a/src/video.c b/src/video.c index 99b0750..56a1e16 100644 --- a/src/video.c +++ b/src/video.c @@ -20,6 +20,7 @@ #include "vid_ega.h" #include "vid_et4000.h" #include "vid_et4000w32.h" +#include "vid_genius.h" #include "vid_hercules.h" #include "vid_incolor.h" #include "vid_colorplus.h" @@ -62,6 +63,7 @@ static VIDEO_CARD video_cards[] = {"Hercules", "hercules", &hercules_device, GFX_HERCULES}, {"Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR}, {"MDA", "mda", &mda_device, GFX_MDA}, + {"MDSI Genius", "genius", &genius_device, GFX_GENIUS}, {"Number Nine 9FX (S3 Trio64)", "n9_9fx", &s3_9fx_device, GFX_N9_9FX}, {"OAK OTI-067", "oti067", &oti067_device, GFX_OTI067}, {"Paradise Bahamas 64 (S3 Vision864)", "bahamas64", &s3_bahamas64_device, GFX_BAHAMAS64}, @@ -310,6 +312,7 @@ BITMAP *buffer, *buffer32; uint8_t fontdat[256][8]; uint8_t fontdatm[256][16]; uint8_t fontdatw[512][32]; /* Wyse700 font */ +uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ int xsize=1,ysize=1; @@ -393,6 +396,16 @@ void loadfont(char *s, int format) } } break; + case 4: /* MDSI Genius */ + for (c=0;c<256;c++) + { + for (d=0;d<16;d++) + { + fontdat8x12[c][d]=getc(f); + } + } + break; + } fclose(f); }