From 467b742af522a4fc7d0eb6bb35fc29bafb456538 Mon Sep 17 00:00:00 2001 From: TomW Date: Thu, 4 Feb 2016 20:35:23 +0000 Subject: [PATCH] Added Hercules InColor emulation. Patch from John Elliott. --- src/Makefile.am | 102 ++-- src/Makefile.mingw | 2 +- src/Makefile.mingw64 | 2 +- src/ibm.h | 6 +- src/jim.c | 2 +- src/vid_incolor.c | 1057 ++++++++++++++++++++++++++++++++++++++++++ src/vid_incolor.h | 1 + src/video.c | 2 + 8 files changed, 1117 insertions(+), 57 deletions(-) create mode 100644 src/vid_incolor.c create mode 100644 src/vid_incolor.h diff --git a/src/Makefile.am b/src/Makefile.am index 725ac41..8a427b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,51 +1,51 @@ -# Makefile.am for PCem - -bin_PROGRAMS = pcem -noinst_SCRIPTS = ../pcem -CLEANFILES = $(noinst_SCRIPTS) - -../pcem: pcem - cp pcem .. - -amrefresh: - - -pcem_CFLAGS = $(allegro_CFLAGS) - -pcem_LDADD = $(allegro_LIBS) -lopenal -lalut - -pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acer386sx.c ali1429.c allegro-gui.c \ -allegro-gui-configure.c allegro-gui-hdconf.c allegro-joystick.c allegro-keyboard.c allegro-main.c \ -allegro-midi.c allegro-mouse.c allegro-video.c amstrad.c cdrom-ioctl-linux.c cdrom-iso.c cdrom-null.c \ -codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_pentium.c compaq.c config.c cpu.c \ -dac.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \ -headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c intel_flash.c io.c jim.c \ -keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ -linux-time.c lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c \ -olivetti_m24.c opti.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c serial.c sis496.c sound.c \ -sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \ -sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \ -sound_speaker.c sound_ssi2001.c sound_wss.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_ega.c vid_et4000.c vid_et4000w32.c vid_hercules.c \ -vid_icd2061.c vid_ics2595.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_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 \ -vid_tkd8001_ramdac.c vid_tvga.c vid_unk_ramdac.c vid_vga.c vid_voodoo.c video.c wd76c10.c \ -x86seg.c x87.c xtide.c sound_dbopl.cc sound_resid.cc dosbox/dbopl.cpp \ -resid-fp/convolve.cc resid-fp/convolve-sse.cc resid-fp/envelope.cc \ -resid-fp/extfilt.cc resid-fp/filter.cc resid-fp/pot.cc resid-fp/sid.cc \ -resid-fp/voice.cc resid-fp/wave6581_PS_.cc resid-fp/wave6581_PST.cc \ -resid-fp/wave6581_P_T.cc resid-fp/wave6581__ST.cc resid-fp/wave8580_PS_.cc \ -resid-fp/wave8580_PST.cc resid-fp/wave8580_P_T.cc resid-fp/wave8580__ST.cc \ -resid-fp/wave.cc - -if CPU_I386 -pcem_SOURCES += codegen_x86.c -pcem_CFLAGS += -msse2 -endif - -if CPU_X86_64 -pcem_SOURCES += codegen_x86-64.c -endif - +# Makefile.am for PCem + +bin_PROGRAMS = pcem +noinst_SCRIPTS = ../pcem +CLEANFILES = $(noinst_SCRIPTS) + +../pcem: pcem + cp pcem .. + +amrefresh: + + +pcem_CFLAGS = $(allegro_CFLAGS) + +pcem_LDADD = $(allegro_LIBS) -lopenal -lalut + +pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acer386sx.c ali1429.c allegro-gui.c \ +allegro-gui-configure.c allegro-gui-hdconf.c allegro-joystick.c allegro-keyboard.c allegro-main.c \ +allegro-midi.c allegro-mouse.c allegro-video.c amstrad.c cdrom-ioctl-linux.c cdrom-iso.c cdrom-null.c \ +codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_pentium.c compaq.c config.c cpu.c \ +dac.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \ +headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c intel_flash.c io.c jim.c \ +keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ +linux-time.c lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c \ +olivetti_m24.c opti.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c serial.c sis496.c sound.c \ +sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \ +sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \ +sound_speaker.c sound_ssi2001.c sound_wss.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_ega.c vid_et4000.c vid_et4000w32.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_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 \ +vid_tkd8001_ramdac.c vid_tvga.c vid_unk_ramdac.c vid_vga.c vid_voodoo.c video.c wd76c10.c \ +x86seg.c x87.c xtide.c sound_dbopl.cc sound_resid.cc dosbox/dbopl.cpp \ +resid-fp/convolve.cc resid-fp/convolve-sse.cc resid-fp/envelope.cc \ +resid-fp/extfilt.cc resid-fp/filter.cc resid-fp/pot.cc resid-fp/sid.cc \ +resid-fp/voice.cc resid-fp/wave6581_PS_.cc resid-fp/wave6581_PST.cc \ +resid-fp/wave6581_P_T.cc resid-fp/wave6581__ST.cc resid-fp/wave8580_PS_.cc \ +resid-fp/wave8580_PST.cc resid-fp/wave8580_P_T.cc resid-fp/wave8580__ST.cc \ +resid-fp/wave.cc + +if CPU_I386 +pcem_SOURCES += codegen_x86.c +pcem_CFLAGS += -msse2 +endif + +if CPU_X86_64 +pcem_SOURCES += codegen_x86-64.c +endif + diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 21bd909..e8a9be3 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 \ 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_ega.o vid_et4000.o \ - vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_mda.o \ + vid_et4000w32.o vid_et4000w32i.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_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 83ef396..5e5de6f 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 \ 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_ega.o vid_et4000.o \ - vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_mda.o \ + vid_et4000w32.o vid_et4000w32i.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_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 a5c9b8b..cd93d1e 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -270,8 +270,8 @@ int disctime; char discfns[2][256]; int driveempty[2]; -#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES) && (romset=ROM_IBMAT)) -#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) +#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR) && (romset=ROM_IBMAT)) +#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && gfxcard!=GFX_INCOLOR && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) #define PCJR (romset == ROM_IBMPCJR) #define AMIBIOS (romset==ROM_AMI386 || romset==ROM_AMI486 || romset == ROM_WIN486) @@ -351,7 +351,7 @@ enum GFX_VIRGEDX, /*S3 Virge/DX*/ GFX_PHOENIX_TRIO32, /*S3 732/Trio32 (Phoenix)*/ GFX_PHOENIX_TRIO64, /*S3 764/Trio64 (Phoenix)*/ - + GFX_INCOLOR, /* Hercules InColor */ GFX_MAX }; diff --git a/src/jim.c b/src/jim.c index 672278a..1e8b879 100644 --- a/src/jim.c +++ b/src/jim.c @@ -71,7 +71,7 @@ void jim_init() europc_rtc.dat[4]=1; europc_rtc.dat[5]=0x88; if (gfxcard==GFX_CGA) viddat=0x12; - else if (gfxcard==GFX_MDA || gfxcard==GFX_HERCULES) viddat=3; + else if (gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR) viddat=3; else viddat=0x10; europc_rtc.dat[0xB]=viddat; europc_rtc.dat[0xD]=viddat; /*Checksum*/ diff --git a/src/vid_incolor.c b/src/vid_incolor.c new file mode 100644 index 0000000..c7e2e5b --- /dev/null +++ b/src/vid_incolor.c @@ -0,0 +1,1057 @@ +/*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; + int 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; + egawrites++; + + 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; + + 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; + egareads++; + 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; + + 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; + } + 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); + } + startblit(); + video_blit_memtoscreen(0, incolor->firstline, 0, incolor->lastline - incolor->firstline, xsize, incolor->lastline - incolor->firstline); + endblit(); + 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 +}; diff --git a/src/vid_incolor.h b/src/vid_incolor.h new file mode 100644 index 0000000..cf34792 --- /dev/null +++ b/src/vid_incolor.h @@ -0,0 +1 @@ +extern device_t incolor_device; diff --git a/src/video.c b/src/video.c index eda8cef..20d1902 100644 --- a/src/video.c +++ b/src/video.c @@ -20,6 +20,7 @@ #include "vid_et4000.h" #include "vid_et4000w32.h" #include "vid_hercules.h" +#include "vid_incolor.h" #include "vid_mda.h" #include "vid_olivetti_m24.h" #include "vid_oti067.h" @@ -54,6 +55,7 @@ static VIDEO_CARD video_cards[] = {"Diamond Stealth 3D 2000 (S3 ViRGE)", &s3_virge_device, GFX_VIRGE}, {"EGA", &ega_device, GFX_EGA}, {"Hercules", &hercules_device, GFX_HERCULES}, + {"Hercules InColor", &incolor_device, GFX_INCOLOR}, {"MDA", &mda_device, GFX_MDA}, {"Number Nine 9FX (S3 Trio64)", &s3_9fx_device, GFX_N9_9FX}, {"OAK OTI-067", &oti067_device, GFX_OTI067},