From 1f5fc45c0466feecd1958a1140c8723051b699ff Mon Sep 17 00:00:00 2001 From: SarahW Date: Mon, 15 Apr 2019 19:48:41 +0100 Subject: [PATCH] Amstrad changes : - Add PPC512/640 emulation - Add TV display type to Sinclair PC200 - Add font selection to PC1512 - Add disc change line to PC200 Patch from JohnElliott --- src/amstrad.c | 21 +- src/fdc.c | 5 + src/fdc.h | 1 + src/ibm.h | 3 +- src/mem_bios.c | 29 +- src/model.c | 6 + src/model.h | 1 + src/nvr.c | 11 +- src/vid_ati28800.c | 2 +- src/vid_genius.c | 1 - src/vid_mda.c | 46 +- src/vid_mda.h | 37 ++ src/vid_pc1512.c | 69 ++- src/vid_pc200.c | 1039 ++++++++++++++++++++++++++++++++++++++++++-- src/vid_pc200.h | 3 + src/vid_sigma.c | 1 - src/vid_wy700.c | 1 - src/video.c | 103 +++-- src/video.h | 20 +- src/wx-config.c | 20 +- 20 files changed, 1281 insertions(+), 138 deletions(-) diff --git a/src/amstrad.c b/src/amstrad.c index 8817229..acd5070 100644 --- a/src/amstrad.c +++ b/src/amstrad.c @@ -5,6 +5,7 @@ #include "lpt.h" #include "mouse.h" #include "video.h" +#include "fdc.h" #include "amstrad.h" @@ -25,12 +26,15 @@ uint8_t amstrad_read(uint16_t port, void *priv) case 0x37a: temp = lpt1_read(port, NULL) & 0x1f; if (romset == ROM_PC1512) return temp | 0x20; - if (romset == ROM_PC200) + if (romset == ROM_PC200 || romset == ROM_PPC512) { + if (fdc_discchange_read()) + temp |= 0x20; +/* DIP switches 4,5: Initial video mode */ if (video_is_cga()) - temp |= 0x80; + temp |= 0x80; /* CGA 80 */ else if (video_is_mda()) - temp |= 0xc0; + temp |= 0xc0; /* MDA */ return temp; } if (romset == ROM_PC1640) @@ -55,8 +59,13 @@ uint8_t amstrad_read(uint16_t port, void *priv) } return temp; case 0x3de: - return 0x20; /*PC200 - use external video. If internal video is being used - then this port is handled in vid_pc200.c*/ + if (romset == ROM_PC200 || romset == ROM_PPC512) + { +/* Read DIP switches / internal display adapter status. This code is only + * reached if the IDA is disabled; if it is enabled this read will be + * handled by the video card */ + } + return 0x20; /* Disable IDA */ case 0xdead: return amstrad_dead; } @@ -153,6 +162,6 @@ void amstrad_init() io_sethandler(0x007a, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL, NULL); io_sethandler(0x0378, 0x0003, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL, NULL); io_sethandler(0xdead, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL, NULL); - if (romset == ROM_PC200 && gfxcard != GFX_BUILTIN) + if ((romset == ROM_PC200 || romset == ROM_PPC512) && gfxcard != GFX_BUILTIN) io_sethandler(0x03de, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL, NULL); } diff --git a/src/fdc.c b/src/fdc.c index bec48bc..25ab9f0 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -1421,6 +1421,11 @@ void fdc_discchange_clear(int drive) disc_changed[drive] = 0; } +int fdc_discchange_read() +{ + return (disc_changed[fdc.drive] || drive_empty[fdc.drive]) ? 1 : 0; +} + void fdc_set_dskchg_activelow() { fdc.dskchg_activelow = 1; diff --git a/src/fdc.h b/src/fdc.h index ec198b8..ff8d540 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -7,6 +7,7 @@ void fdc_reset(); void fdc_poll(); void fdc_abort(); void fdc_discchange_clear(int drive); +int fdc_discchange_read(); void fdc_set_dskchg_activelow(); void fdc_3f1_enable(int enable); void fdc_set_ps1(); diff --git a/src/ibm.h b/src/ibm.h index e7dca29..ed3aac2 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -468,7 +468,8 @@ enum ROM_TULIP_TC7, ROM_ZD_SUPERS, /* [8088] Zenith Data Systems SupersPort */ ROM_PB410A, - + ROM_PPC512, + ROM_MAX }; diff --git a/src/mem_bios.c b/src/mem_bios.c index c49271e..0f04f5f 100644 --- a/src/mem_bios.c +++ b/src/mem_bios.c @@ -59,9 +59,9 @@ int loadbios() FILE *f=NULL,*ff=NULL; int c; - loadfont("mda.rom", 0); - loadfont("wy700.rom", 3); - loadfont("8x12.bin", 4); + loadfont("mda.rom", FONT_MDA); + loadfont("wy700.rom", FONT_WY700); + loadfont("8x12.bin", FONT_MDSI); biosmask = 0xffff; @@ -85,7 +85,7 @@ int loadbios() } fclose(ff); fclose(f); - loadfont("pc1512/40078.ic127", 2); + loadfont("pc1512/40078.ic127", FONT_CGA); return 1; case ROM_PC1640: f=romfopen("pc1640/40044.v3","rb"); @@ -113,7 +113,20 @@ int loadbios() } fclose(ff); fclose(f); - loadfont("pc200/40109.bin", 1); + loadfont("pc200/40109.bin", FONT_PC200); + return 1; + case ROM_PPC512: + f=romfopen("ppc512/40107.v2","rb"); + ff=romfopen("ppc512/40108.v2","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + loadfont("ppc512/40109.bin", FONT_PC200); return 1; case ROM_TANDY: f=romfopen("tandy/tandy1t1.020","rb"); @@ -759,7 +772,7 @@ int loadbios() return 1; case ROM_T3100E: - loadfont("t3100e/t3100e_font.bin", 5); + loadfont("t3100e/t3100e_font.bin", FONT_T3100E); f=romfopen("t3100e/t3100e.rom","rb"); if (!f) break; romfread(rom,65536,1,f); @@ -767,7 +780,7 @@ int loadbios() return 1; case ROM_T1000: - loadfont("t1000/t1000font.rom", 2); + loadfont("t1000/t1000font.rom", FONT_CGA); f=romfopen("t1000/t1000.rom","rb"); if (!f) break; romfread(rom, 0x8000,1,f); @@ -777,7 +790,7 @@ int loadbios() return 1; case ROM_T1200: - loadfont("t1200/t1000font.rom", 2); + loadfont("t1200/t1000font.rom", FONT_CGA); f=romfopen("t1200/t1200_019e.ic15.bin","rb"); if (!f) break; romfread(rom, 0x8000,1,f); diff --git a/src/model.c b/src/model.c index fa7599c..a5ad2ef 100644 --- a/src/model.c +++ b/src/model.c @@ -145,6 +145,7 @@ MODEL models[] = {"[8086] Amstrad PC1640", ROM_PC1640, "pc1640", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, {"[8086] Amstrad PC2086", ROM_PC2086, "pc2086", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, {"[8086] Amstrad PC3086", ROM_PC3086, "pc3086", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, + {"[8086] Amstrad PPC512/640", ROM_PPC512, "ppc512", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 512, 640, 128, ams_init, NULL}, {"[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED|MODEL_OLIM24, 128, 640, 128, olim24_init, NULL}, {"[8086] Sinclair PC200", ROM_PC200, "pc200", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 512, 640, 128, ams_init, NULL}, {"[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED, 512, 768, 128, tandy1ksl2_init, NULL}, @@ -219,6 +220,11 @@ int model_getromset() return models[model].id; } +int model_getromset_from_model(int model) +{ + return models[model].id; +} + int model_getmodel(int romset) { int c = 0; diff --git a/src/model.h b/src/model.h index 11c442d..7b568f1 100644 --- a/src/model.h +++ b/src/model.h @@ -39,6 +39,7 @@ extern int model; int model_count(); int model_getromset(); +int model_getromset_from_model(int model); int model_getmodel(int romset); char *model_getname(); char *model_get_internal_name(); diff --git a/src/nvr.c b/src/nvr.c index 4857825..a09cb4d 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -211,8 +211,15 @@ void writenvr(uint16_t addr, uint8_t val, void *priv) are always enabled for PS/2 machines - this would mean that other peripherals could fire NMIs regardless of the mask state, but as there aren't any emulated MCA peripherals that do this it's currently a moot point.*/ - if (!(models[model].flags & MODEL_MCA)) + + /* Also don't update the NMI mask on Amstrad PCs - actually + * ought not to do it for any XT because their NMI mask + * register is at 0xA0. But particularly important on the + * PC200 and PPC because their video subsystem issues NMIs */ + if (!(models[model].flags & (MODEL_MCA | MODEL_AMSTRAD))) + { nmi_mask = ~val & 0x80; + } } } @@ -255,6 +262,7 @@ void loadnvr() case ROM_PC200: f = nvrfopen("pc200.nvr", "rb"); break; case ROM_PC2086: f = nvrfopen("pc2086.nvr", "rb"); break; case ROM_PC3086: f = nvrfopen("pc3086.nvr", "rb"); break; + case ROM_PPC512: f = nvrfopen("ppc512.nvr", "rb"); break; case ROM_IBMAT: f = nvrfopen("at.nvr", "rb"); break; case ROM_IBMXT286: f = nvrfopen("ibmxt286.nvr", "rb"); break; case ROM_IBMPS1_2011: f = nvrfopen("ibmps1_2011.nvr", "rb"); /*nvrmask = 127; */break; @@ -352,6 +360,7 @@ void savenvr() case ROM_PC200: f = nvrfopen("pc200.nvr", "wb"); break; case ROM_PC2086: f = nvrfopen("pc2086.nvr", "wb"); break; case ROM_PC3086: f = nvrfopen("pc3086.nvr", "wb"); break; + case ROM_PPC512: f = nvrfopen("ppc512.nvr", "wb"); break; case ROM_IBMAT: f = nvrfopen("at.nvr", "wb"); break; case ROM_IBMXT286: f = nvrfopen("ibmxt286.nvr", "wb"); break; case ROM_IBMPS1_2011: f = nvrfopen("ibmps1_2011.nvr", "wb"); break; diff --git a/src/vid_ati28800.c b/src/vid_ati28800.c index 845b0ee..026de97 100644 --- a/src/vid_ati28800.c +++ b/src/vid_ati28800.c @@ -364,7 +364,7 @@ void *ati28800k_init() ati28800->ksc5601_mode_enabled = 0; rom_init(&ati28800->bios_rom, "atikorvga.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - loadfont("ati_ksc5601.rom", 6); + loadfont("ati_ksc5601.rom", FONT_KSC5601); svga_init(&ati28800->svga, ati28800, 1 << 19, /*512kb*/ ati28800k_recalctimings, diff --git a/src/vid_genius.c b/src/vid_genius.c index 088cdf2..735d6ad 100644 --- a/src/vid_genius.c +++ b/src/vid_genius.c @@ -13,7 +13,6 @@ #define GENIUS_YSIZE 1008 void updatewindowsize(int x, int y); -void loadfont(char *s, int format); extern uint8_t fontdat8x12[256][16]; diff --git a/src/vid_mda.c b/src/vid_mda.c index fdb549e..3265bb4 100644 --- a/src/vid_mda.c +++ b/src/vid_mda.c @@ -8,29 +8,6 @@ #include "video.h" #include "vid_mda.h" -typedef struct mda_t -{ - mem_mapping_t mapping; - - uint8_t crtc[32]; - int crtcreg; - - uint8_t ctrl, 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 *vram; -} mda_t; static uint32_t mdacols[256][2][2]; @@ -261,19 +238,27 @@ void mda_poll(void *p) } } -void *mda_init() +void *mda_standalone_init() { - int display_type; - int c; mda_t *mda = malloc(sizeof(mda_t)); + memset(mda, 0, sizeof(mda_t)); + mda_init(mda); mda->vram = malloc(0x1000); - timer_add(mda_poll, &mda->vidtime, TIMER_ALWAYS_ENABLED, mda); mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + return mda; +} + + +void mda_init(mda_t *mda) +{ + int display_type; + int c; + display_type = device_get_config_int("display_type"); cgapal_rebuild(display_type, 0); @@ -295,8 +280,11 @@ void *mda_init() mdacols[0x08][0][1] = mdacols[0x08][1][1] = cgapal[0]; mdacols[0x80][0][1] = mdacols[0x80][1][1] = cgapal[0]; mdacols[0x88][0][1] = mdacols[0x88][1][1] = cgapal[0]; +} - return mda; +void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink) +{ + mdacols[chr][blink][fg] = cgapal[cga_ink]; } void mda_close(void *p) @@ -349,7 +337,7 @@ device_t mda_device = { "MDA", 0, - mda_init, + mda_standalone_init, mda_close, NULL, mda_speed_changed, diff --git a/src/vid_mda.h b/src/vid_mda.h index 99aa13c..e61b15e 100644 --- a/src/vid_mda.h +++ b/src/vid_mda.h @@ -1 +1,38 @@ + +typedef struct mda_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, 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 *vram; +} mda_t; + +void mda_init(mda_t *mda); +void mda_out(uint16_t addr, uint8_t val, void *p); +uint8_t mda_in(uint16_t addr, void *p); +void mda_write(uint32_t addr, uint8_t val, void *p); +uint8_t mda_read(uint32_t addr, void *p); +void mda_recalctimings(mda_t *mda); +void mda_poll(void *p); + +/* Override mapping of attribute to colour */ +void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink); + extern device_t mda_device; + diff --git a/src/vid_pc1512.c b/src/vid_pc1512.c index 0b5f89a..f643692 100644 --- a/src/vid_pc1512.c +++ b/src/vid_pc1512.c @@ -26,6 +26,7 @@ typedef struct pc1512_t uint8_t plane_write, plane_read, border; + int fontbase; int linepos, displine; int sc, vc; int cgadispon; @@ -220,12 +221,12 @@ static void pc1512_poll(void *p) if (drawcursor) { for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[pc1512->displine])[(x << 3) + c + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 3) + c + 8] = cols[(fontdat[chr + pc1512->fontbase][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[pc1512->displine])[(x << 3) + c + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 3) + c + 8] = cols[(fontdat[chr + pc1512->fontbase][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } pc1512->ma++; } @@ -254,13 +255,13 @@ static void pc1512_poll(void *p) { for (c = 0; c < 8; c++) ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 8] = - ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + pc1512->fontbase][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; } else { for (c = 0; c < 8; c++) ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 8] = - ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + pc1512->fontbase][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } } @@ -451,6 +452,7 @@ static void pc1512_poll(void *p) static void *pc1512_init() { + int display_type; pc1512_t *pc1512 = malloc(sizeof(pc1512_t)); memset(pc1512, 0, sizeof(pc1512_t)); @@ -458,10 +460,13 @@ static void *pc1512_init() pc1512->cgacol = 7; pc1512->cgamode = 0x12; - + pc1512->fontbase = (device_get_config_int("codepage") & 3) * 256; + display_type = device_get_config_int("display_type"); + timer_add(pc1512_poll, &pc1512->vidtime, TIMER_ALWAYS_ENABLED, pc1512); mem_mapping_add(&pc1512->mapping, 0xb8000, 0x08000, pc1512_read, NULL, NULL, pc1512_write, NULL, NULL, NULL, 0, pc1512); io_sethandler(0x03d0, 0x0010, pc1512_in, NULL, NULL, pc1512_out, NULL, NULL, pc1512); + cgapal_rebuild(display_type, 0); return pc1512; } @@ -480,6 +485,57 @@ static void pc1512_speed_changed(void *p) pc1512_recalctimings(pc1512); } +device_config_t pc1512_config[] = +{ + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "PC-CM (Colour)", + .value = DISPLAY_RGB + }, + { + .description = "PC-MM (Monochrome)", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + } + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "US English", + .value = 3 + }, + { + .description = "Danish", + .value = 1 + }, + { + .description = "Greek", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 3 + }, + { + .type = -1 + } +}; + + device_t pc1512_device = { "Amstrad PC1512 (video)", @@ -489,5 +545,6 @@ device_t pc1512_device = NULL, pc1512_speed_changed, NULL, - NULL + NULL, + pc1512_config }; diff --git a/src/vid_pc200.c b/src/vid_pc200.c index 06f511d..737e943 100644 --- a/src/vid_pc200.c +++ b/src/vid_pc200.c @@ -1,23 +1,51 @@ -/*PC200 video emulation. - CGA with some NMI stuff. But we don't need that as it's only used for TV and - LCD displays, and we're emulating a CRT*/ +/*PC200/PPC video emulation. */ #include #include "ibm.h" #include "device.h" #include "io.h" #include "mem.h" +#include "nmi.h" #include "timer.h" #include "video.h" #include "vid_cga.h" +#include "vid_mda.h" #include "vid_pc200.h" +/* #define PC200LOG(x) pclog x */ +#define PC200LOG(x) + +/* Display type */ +#define PC200_CGA 0 /* CGA monitor */ +#define PC200_MDA 1 /* MDA monitor */ +#define PC200_TV 2 /* Television */ +#define PC200_LCDC 3 /* PPC512 LCD as CGA*/ +#define PC200_LCDM 4 /* PPC512 LCD as MDA*/ + +int pc200_is_mda; + +static uint32_t blue, green; + +static uint32_t lcdcols[256][2][2]; + typedef struct pc200_t { - mem_mapping_t mapping; + mem_mapping_t cga_mapping; + mem_mapping_t mda_mapping; cga_t cga; + mda_t mda; - uint8_t reg_3dd, reg_3de, reg_3df; + int vidtime; + + uint8_t emulation; /* Which display are we emulating? */ + uint8_t dipswitches; /* DIP switches 1-3 */ + uint8_t crtc_index; /* CRTC index readback + * Bit 7: CGA control port written + * Bit 6: Operation control port written + * Bit 5: CRTC register written + * Bits 0-4: Last CRTC register selected */ + uint8_t operation_ctrl; + uint8_t reg_3df; } pc200_t; static uint8_t crtcmask[32] = @@ -26,24 +54,187 @@ static uint8_t crtcmask[32] = 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static void setvidtime(pc200_t *pc200) +{ + switch (pc200->emulation) + { + case PC200_CGA: + case PC200_TV: + case PC200_LCDC: + pc200->vidtime = pc200->cga.vidtime; + break; + + case PC200_MDA: + case PC200_LCDM: + pc200->vidtime = pc200->mda.vidtime; + break; + } +} + +/* LCD colour mappings + * + * 0 => solid green + * 1 => blue on green + * 2 => green on blue + * 3 => solid blue + */ +static unsigned char mapping1[256] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +/*00*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/*10*/ 2, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, +/*20*/ 2, 2, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, +/*30*/ 2, 2, 2, 0, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, +/*40*/ 2, 2, 1, 1, 0, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, +/*50*/ 2, 2, 1, 1, 2, 0, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, +/*60*/ 2, 2, 2, 2, 2, 2, 0, 1, 2, 2, 2, 2, 2, 2, 1, 1, +/*70*/ 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, +/*80*/ 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, +/*90*/ 2, 2, 1, 1, 1, 1, 1, 1, 2, 0, 1, 1, 1, 1, 1, 1, +/*A0*/ 2, 2, 2, 1, 2, 2, 1, 1, 2, 2, 0, 1, 2, 2, 1, 1, +/*B0*/ 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 0, 2, 2, 1, 1, +/*C0*/ 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 0, 1, 1, 1, +/*D0*/ 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 0, 1, 1, +/*E0*/ 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 0, 1, +/*F0*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, +}; + +static unsigned char mapping2[256] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +/*00*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/*10*/ 1, 3, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, +/*20*/ 1, 1, 3, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, +/*30*/ 1, 1, 1, 3, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, +/*40*/ 1, 1, 2, 2, 3, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, +/*50*/ 1, 1, 2, 2, 1, 3, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, +/*60*/ 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 2, 2, +/*70*/ 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 2, +/*80*/ 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, +/*90*/ 1, 1, 2, 2, 2, 2, 2, 2, 1, 3, 2, 2, 2, 2, 2, 2, +/*A0*/ 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 3, 2, 1, 1, 2, 2, +/*B0*/ 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 3, 1, 1, 2, 2, +/*C0*/ 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 3, 2, 2, 2, +/*D0*/ 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 3, 2, 2, +/*E0*/ 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, +/*F0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, +}; + +static void set_lcd_cols(uint8_t mode_reg) +{ + unsigned char *mapping = (mode_reg & 0x80) ? mapping2 : mapping1; + int c; + + for (c = 0; c < 256; c++) + { + switch (mapping[c]) + { + case 0: + lcdcols[c][0][0] = lcdcols[c][1][0] = green; + lcdcols[c][0][1] = lcdcols[c][1][1] = green; + break; + + case 1: + lcdcols[c][0][0] = lcdcols[c][1][0] = + lcdcols[c][1][1] = green; + lcdcols[c][0][1] = blue; + break; + + case 2: + lcdcols[c][0][0] = lcdcols[c][1][0] = + lcdcols[c][1][1] = blue; + lcdcols[c][0][1] = green; + break; + + case 3: + lcdcols[c][0][0] = lcdcols[c][1][0] = blue; + lcdcols[c][0][1] = lcdcols[c][1][1] = blue; + break; + } + } +} + + void pc200_out(uint16_t addr, uint8_t val, void *p) { pc200_t *pc200 = (pc200_t *)p; cga_t *cga = &pc200->cga; + mda_t *mda = &pc200->mda; uint8_t old; - + + PC200LOG(("pc200_out(0x%04x), %02x\n", addr, val)); + +/* MDA writes ============================================================== */ switch (addr) { - case 0x3d5: - if (!(pc200->reg_3de & 0x40) && cga->crtcreg <= 11) + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + + /* Writes banned to CRTC registers 0-11? */ + if (!(pc200->operation_ctrl & 0x40) && mda->crtcreg <= 11) { - if (pc200->reg_3de & 0x80) + pc200->crtc_index = 0x20 | (mda->crtcreg & 0x1f); + if (pc200->operation_ctrl & 0x80) + { + PC200LOG(("NMI raised from CRTC register access: reg=0x%02x val=0x%02x nmi_mask=%d\n", mda->crtcreg & 0x1F, val, nmi_mask)); nmi = 1; - - pc200->reg_3dd = 0x20 | (cga->crtcreg & 0x1f); + } pc200->reg_3df = val; return; } + PC200LOG(("CRTM[%02x]:=%02x\n", mda->crtcreg, val)); + old = mda->crtc[mda->crtcreg]; + mda->crtc[mda->crtcreg] = val & crtcmask[mda->crtcreg]; + if (old != val) + { + if (mda->crtcreg < 0xe || mda->crtcreg > 0x10) + { + fullchange = changeframecount; + mda_recalctimings(mda); + setvidtime(pc200); + } + } + return; + + case 0x3b8: + old = mda->ctrl; + mda->ctrl = val; + if ((mda->ctrl ^ old) & 3) + { + mda_recalctimings(mda); + setvidtime(pc200); + } + pc200->crtc_index &= 0x1F; + pc200->crtc_index |= 0x80; + if (pc200->operation_ctrl & 0x80) + { + PC200LOG(("NMI raised from mode control access: val=0x%02x nmi_mask=%d\n", val, nmi_mask)); + nmi = 1; + } + return; + + +/* CGA writes ============================================================== */ + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + + /* Writes banned to CRTC registers 0-11? */ + if (!(pc200->operation_ctrl & 0x40) && cga->crtcreg <= 11) + { + pc200->crtc_index = 0x20 | (cga->crtcreg & 0x1f); + if (pc200->operation_ctrl & 0x80) + { + PC200LOG(("NMI raised from CRTC register access: reg=0x%02x val=0x%02x nmi_mask=%d\n", cga->crtcreg & 0x1F, val, nmi_mask)); + nmi = 1; + } + pc200->reg_3df = val; + return; + } + PC200LOG(("CRTC[%02x]:=%02x\n", cga->crtcreg, val)); old = cga->crtc[cga->crtcreg]; cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; if (old != val) @@ -52,6 +243,7 @@ void pc200_out(uint16_t addr, uint8_t val, void *p) { fullchange = changeframecount; cga_recalctimings(cga); + setvidtime(pc200); } } return; @@ -60,60 +252,636 @@ void pc200_out(uint16_t addr, uint8_t val, void *p) old = cga->cgamode; cga->cgamode = val; if ((cga->cgamode ^ old) & 3) - cga_recalctimings(cga); - pc200->reg_3dd |= 0x80; - if (pc200->reg_3de & 0x80) - nmi = 1; + { + cga_recalctimings(cga); + setvidtime(pc200); + } + pc200->crtc_index &= 0x1F; + pc200->crtc_index |= 0x80; + if (pc200->operation_ctrl & 0x80) + { + PC200LOG(("NMI raised from mode control access: val=0x%02x nmi_mask=%d\n", val, nmi_mask)); + nmi = 1; + } + else set_lcd_cols(val); return; +/* PC200 control port writes ============================================== */ case 0x3de: - pc200->reg_3de = val; - pc200->reg_3dd = 0x1f; - if (val & 0x80) - pc200->reg_3dd |= 0x40; + pc200->crtc_index = 0x1f; +/* NMI only seems to be triggered if the value being written has the high + * bit set (enable NMI). So it only protects writes to this port if you + * let it? */ + if (val & 0x80) + { + PC200LOG(("NMI raised from operation control access: val=0x%02x nmi_mask=%d\n", val, nmi_mask)); + pc200->operation_ctrl = val; + pc200->crtc_index |= 0x40; + nmi = 1; + return; + } + pc200->operation_ctrl = val; + /* Bits 0 and 1 control emulation and output mode */ + if (val & 1) /* Monitor */ + { + pc200->emulation = (val & 2) ? PC200_MDA : PC200_CGA; + } + else if (romset == ROM_PPC512) + { + pc200->emulation = (val & 2) ? PC200_LCDM : PC200_LCDC; + } + else + { + pc200->emulation = PC200_TV; + + } + PC200LOG(("Video emulation set to %d\n", pc200->emulation)); + /* Bit 2 disables the IDA. We don't support dynamic enabling + * and disabling of the IDA (instead, PCEM disconnects the + * IDA from the bus altogether) so don't implement this */ + + /* Enable the appropriate memory ranges depending whether + * the IDA is configured as MDA or CGA */ + if (pc200->emulation == PC200_MDA || + pc200->emulation == PC200_LCDM) + { + mem_mapping_disable(&pc200->cga_mapping); + mem_mapping_enable(&pc200->mda_mapping); + } + else + { + mem_mapping_disable(&pc200->mda_mapping); + mem_mapping_enable(&pc200->cga_mapping); + } return; } - cga_out(addr, val, cga); + if (addr >= 0x3D0 && addr <= 0x3DF) + { + cga_out(addr, val, cga); + } + if (addr >= 0x3B0 && addr <= 0x3BB) + { + mda_out(addr, val, mda); + } } uint8_t pc200_in(uint16_t addr, void *p) { pc200_t *pc200 = (pc200_t *)p; cga_t *cga = &pc200->cga; + mda_t *mda = &pc200->mda; uint8_t temp; + PC200LOG(("pc200_in(0x%04x)\n", addr)); switch (addr) { + case 0x3B8: + PC200LOG((" = %02x\n", mda->ctrl)); + return mda->ctrl; + case 0x3D8: + PC200LOG((" = %02x\n", cga->cgamode)); return cga->cgamode; case 0x3DD: - temp = pc200->reg_3dd; - pc200->reg_3dd &= 0x1f; - nmi = 0; + temp = pc200->crtc_index; /* Read NMI reason */ + pc200->crtc_index &= 0x1f; /* Reset NMI reason */ + nmi = 0; /* And reset NMI flag */ + PC200LOG((" = %02x\n", temp)); return temp; case 0x3DE: - return (pc200->reg_3de & 0xc7) | 0x10; /*External CGA*/ - + PC200LOG((" = %02x\n", ((pc200->operation_ctrl & 0xc7) | pc200->dipswitches))); + return ((pc200->operation_ctrl & 0xc7) | pc200->dipswitches); + case 0x3DF: return pc200->reg_3df; } - return cga_in(addr, cga); + if (addr >= 0x3D0 && addr <= 0x3DF) + { + return cga_in(addr, cga); + } + if (addr >= 0x3B0 && addr <= 0x3BB) + { + return mda_in(addr, mda); + } + return 0xFF; +} + +void lcd_draw_char_80(pc200_t *pc200, uint32_t *buffer, uint8_t chr, + uint8_t attr, int drawcursor, int blink, int sc, + int mode160, uint8_t control) +{ + int c; + uint8_t bits = fontdat[chr + pc200->cga.fontbase][sc]; + uint8_t bright = 0; + uint16_t mask; + + if (attr & 8) /* bright */ + { +/* The brightness algorithm appears to be: replace any bit sequence 011 + * with 001 (assuming an extra 0 to the left of the byte). + */ + bright = bits; + for (c = 0, mask = 0x100; c < 7; c++, mask >>= 1) + { + if (((bits & mask) == 0) && + ((bits & (mask >> 1)) != 0) && + ((bits & (mask >> 2)) != 0)) + { + bright &= ~(mask >> 1); + } + } + bits = bright; + } + + if (drawcursor) bits ^= 0xFF; + + for (c = 0, mask = 0x80; c < 8; c++, mask >>= 1) + { + if (mode160) + buffer[c] = (attr & mask) ? blue : green; + else if (control & 0x20) /* blinking */ + buffer[c] = lcdcols[attr & 0x7F][blink][(bits & mask) ? 1 : 0]; + else + buffer[c] = lcdcols[attr][blink][(bits & mask) ? 1 : 0]; + } +} + + +void lcd_draw_char_40(pc200_t *pc200, uint32_t *buffer, uint8_t chr, + uint8_t attr, int drawcursor, int blink, int sc, + uint8_t control) +{ + int c; + uint8_t bits = fontdat[chr + pc200->cga.fontbase][sc]; + uint8_t mask = 0x80; + + if (attr & 8) /* bright */ + { + bits = bits & (bits >> 1); + } + if (drawcursor) bits ^= 0xFF; + + for (c = 0; c < 8; c++, mask >>= 1) + { + if (control & 0x20) + { + buffer[c*2] = buffer[c*2+1] = + lcdcols[attr & 0x7F][blink][(bits & mask) ? 1 : 0]; + } + else + { + buffer[c*2] = buffer[c*2+1] = + lcdcols[attr][blink][(bits & mask) ? 1 : 0]; + } + } +} + +void lcdm_poll(pc200_t *pc200) +{ + mda_t *mda = &pc200->mda; + uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x; + int oldvc; + uint8_t chr, attr; + int oldsc; + int blink; + if (!mda->linepos) + { + pc200->vidtime += mda->dispofftime; + mda->stat |= 1; + mda->linepos = 1; + oldsc = mda->sc; + if ((mda->crtc[8] & 3) == 3) + mda->sc = (mda->sc << 1) & 7; + if (mda->dispon) + { + if (mda->displine < mda->firstline) + { + mda->firstline = mda->displine; + video_wait_for_buffer(); + } + mda->lastline = mda->displine; + for (x = 0; x < mda->crtc[1]; x++) + { + chr = mda->vram[(mda->ma << 1) & 0xfff]; + attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; + drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + + lcd_draw_char_80(pc200, &((uint32_t *)(buffer32->line[mda->displine]))[x * 8], chr, attr, drawcursor, blink, mda->sc, 0, mda->ctrl); + mda->ma++; + } + } + mda->sc = oldsc; + if (mda->vc == mda->crtc[7] && !mda->sc) + { + mda->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + mda->displine++; + if (mda->displine >= 500) + mda->displine=0; + } + else + { + pc200->vidtime += mda->dispontime; + if (mda->dispon) mda->stat&=~1; + mda->linepos=0; + if (mda->vsynctime) + { + mda->vsynctime--; + if (!mda->vsynctime) + { + mda->stat&=~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) + { + mda->con = 0; + mda->coff = 1; + } + if (mda->vadj) + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + mda->vadj--; + if (!mda->vadj) + { + mda->dispon = 1; + mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + mda->sc = 0; + } + } + else if (mda->sc == mda->crtc[9] || ((mda->crtc[8] & 3) == 3 && mda->sc == (mda->crtc[9] >> 1))) + { + mda->maback = mda->ma; + mda->sc = 0; + oldvc = mda->vc; + mda->vc++; + mda->vc &= 127; + if (mda->vc == mda->crtc[6]) + mda->dispon=0; + if (oldvc == mda->crtc[4]) + { +// printf("Display over at %i\n",displine); + mda->vc = 0; + mda->vadj = mda->crtc[5]; + if (!mda->vadj) mda->dispon = 1; + if (!mda->vadj) mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + if ((mda->crtc[10] & 0x60) == 0x20) mda->cursoron = 0; + else mda->cursoron = mda->blink & 16; + } + if (mda->vc == mda->crtc[7]) + { + mda->dispon = 0; + mda->displine = 0; + mda->vsynctime = 16; + if (mda->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + x = mda->crtc[1] * 8; + mda->lastline++; + if (x != xsize || (mda->lastline - mda->firstline) != ysize) + { + xsize = x; + ysize = mda->lastline - mda->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 << 1); + } + + video_blit_memtoscreen(0, mda->firstline, 0, ysize, xsize, ysize); + + frames++; + video_res_x = mda->crtc[1]; + video_res_y = mda->crtc[6]; + video_bpp = 0; + } + mda->firstline = 1000; + mda->lastline = 0; + mda->blink++; + } + } + else + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + } + if ((mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1)))) + { + mda->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +void lcdc_poll(pc200_t *pc200) +{ + cga_t *cga = &pc200->cga; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int oldsc; + uint16_t ca; + int blink; + + ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + + if (!cga->linepos) + { + pc200->vidtime += cga->dispofftime; + cga->cgastat |= 1; + cga->linepos = 1; + oldsc = cga->sc; + if ((cga->crtc[8] & 3) == 3) + cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; + if (cga->cgadispon) + { + if (cga->displine < cga->firstline) + { + cga->firstline = cga->displine; + video_wait_for_buffer(); +// printf("Firstline %i\n",firstline); + } + cga->lastline = cga->displine; + + if (cga->cgamode & 1) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->charbuffer[x << 1]; + attr = cga->charbuffer[(x << 1) + 1]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + lcd_draw_char_80(pc200, &((uint32_t *)(buffer32->line[cga->displine]))[x * 8], chr, attr, drawcursor, blink, cga->sc, cga->cgamode & 0x40, cga->cgamode); + cga->ma++; + } + } + else if (!(cga->cgamode & 2)) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->vram[((cga->ma << 1) & 0x3fff)]; + attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + lcd_draw_char_40(pc200, &((uint32_t *)(buffer32->line[cga->displine]))[x * 16], chr, attr, drawcursor, blink, cga->sc, cga->cgamode); + cga->ma++; + } + } + else /* Graphics mode */ + { + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 16; c++) + { + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + c] = (dat & 0x8000) ? blue : green; + dat <<= 1; + } + } + } + } + else + { + if (cga->cgamode & 1) hline(buffer32, 0, cga->displine, (cga->crtc[1] << 3), green); + else hline(buffer32, 0, cga->displine, (cga->crtc[1] << 4), green); + } + + if (cga->cgamode & 1) x = (cga->crtc[1] << 3); + else x = (cga->crtc[1] << 4); + + cga->sc = oldsc; + if (cga->vc == cga->crtc[7] && !cga->sc) + cga->cgastat |= 8; + cga->displine++; + if (cga->displine >= 360) + cga->displine = 0; + } + else + { + pc200->vidtime += cga->dispontime; + cga->linepos = 0; + if (cga->vsynctime) + { + cga->vsynctime--; + if (!cga->vsynctime) + cga->cgastat &= ~8; + } + if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) + { + cga->con = 0; + cga->coff = 1; + } + if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) + cga->maback = cga->ma; + if (cga->vadj) + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + cga->vadj--; + if (!cga->vadj) + { + cga->cgadispon = 1; + cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + cga->sc = 0; + } + } + else if (cga->sc == cga->crtc[9]) + { + cga->maback = cga->ma; + cga->sc = 0; + oldvc = cga->vc; + cga->vc++; + cga->vc &= 127; + + if (cga->vc == cga->crtc[6]) + cga->cgadispon = 0; + + if (oldvc == cga->crtc[4]) + { + cga->vc = 0; + cga->vadj = cga->crtc[5]; + if (!cga->vadj) cga->cgadispon = 1; + if (!cga->vadj) cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + if ((cga->crtc[10] & 0x60) == 0x20) cga->cursoron = 0; + else cga->cursoron = cga->cgablink & 8; + } + + if (cga->vc == cga->crtc[7]) + { + cga->cgadispon = 0; + cga->displine = 0; + cga->vsynctime = 16; + if (cga->crtc[7]) + { + if (cga->cgamode & 1) x = (cga->crtc[1] << 3); + else x = (cga->crtc[1] << 4); + cga->lastline++; + if (x != xsize || (cga->lastline - cga->firstline) != ysize) + { + xsize = x; + ysize = cga->lastline - cga->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1)); + } + + video_blit_memtoscreen(0, cga->firstline, 0, (cga->lastline - cga->firstline), xsize, (cga->lastline - cga->firstline)); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (cga->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + cga->firstline = 1000; + cga->lastline = 0; + cga->cgablink++; + cga->oddeven ^= 1; + } + } + else + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + } + if (cga->cgadispon) + cga->cgastat &= ~1; + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + cga->con = 1; + if (cga->cgadispon && (cga->cgamode & 1)) + { + for (x = 0; x < (cga->crtc[1] << 1); x++) + cga->charbuffer[x] = cga->vram[(((cga->ma << 1) + x) & 0x3fff)]; + } + } + +} + +void pc200_poll(void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + + switch (pc200->emulation) + { + case PC200_CGA: + case PC200_TV: + pc200->cga.vidtime = pc200->vidtime; + cga_poll(&pc200->cga); + pc200->vidtime = pc200->cga.vidtime; + return; + + case PC200_MDA: + pc200->mda.vidtime = pc200->vidtime; + mda_poll(&pc200->mda); + pc200->vidtime = pc200->mda.vidtime; + return; + + case PC200_LCDM: + lcdm_poll(pc200); + return; + case PC200_LCDC: + lcdc_poll(pc200); + return; + } } void *pc200_init() { + int display_type, contrast; + pc200_t *pc200 = malloc(sizeof(pc200_t)); - cga_t *cga = &pc200->cga; + memset(pc200, 0, sizeof(pc200_t)); - pc200->cga.vram = malloc(0x4000); + pc200->emulation = device_get_config_int("video_emulation"); + display_type = device_get_config_int("display_type"); + contrast = device_get_config_int("contrast"); + + /* Default to CGA */ + pc200->dipswitches = 0x10; + + /* DIP switches for PC200. Switches 2,3 give video emulation. + * Switch 1 is 'swap floppy drives' (not implemented) */ + if (romset == ROM_PC200) switch (pc200->emulation) + { + case PC200_CGA: pc200->dipswitches = 0x10; break; + case PC200_MDA: pc200->dipswitches = 0x30; break; + case PC200_TV: pc200->dipswitches = 0x00; break; + /* The other combination is 'IDA disabled' (0x20) - see + * amstrad.c */ + } + /* DIP switches for PPC512. Switch 1 is CRT/LCD. Switch 2 + * is MDA / CGA. Switch 3 disables IDA, not implemented. */ + else switch (pc200->emulation) + { + case PC200_CGA: pc200->dipswitches = 0x08; break; + case PC200_MDA: pc200->dipswitches = 0x18; break; + case PC200_LCDC: pc200->dipswitches = 0x00; break; + case PC200_LCDM: pc200->dipswitches = 0x10; break; + } + /* Flag whether the card is behaving like a CGA or an MDA, so that + * DIP switches are reported correctly */ + pc200_is_mda = (pc200->emulation == PC200_MDA || + pc200->emulation == PC200_LCDM); + PC200LOG(("pc200: DIP switches = %02x\n", pc200->dipswitches)); + + pc200->cga.vram = pc200->mda.vram = malloc(0x4000); cga_init(&pc200->cga); - - timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); - mem_mapping_add(&pc200->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + mda_init(&pc200->mda); + + /* Attribute 8 is white on black (on a real MDA it's black on black) */ + mda_setcol(0x08, 0, 1, 15); + mda_setcol(0x88, 0, 1, 15); + /* Attribute 64 is black on black (on a real MDA it's white on black) */ + mda_setcol(0x40, 0, 1, 0); + mda_setcol(0xC0, 0, 1, 0); + + pc200->cga.fontbase = (device_get_config_int("codepage") & 3) * 256; + + timer_add(pc200_poll, &pc200->vidtime, TIMER_ALWAYS_ENABLED, pc200); + mem_mapping_add(&pc200->mda_mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, 0, &pc200->mda); + mem_mapping_add(&pc200->cga_mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, &pc200->cga); io_sethandler(0x03d0, 0x0010, pc200_in, NULL, NULL, pc200_out, NULL, NULL, pc200); + io_sethandler(0x03b0, 0x000c, pc200_in, NULL, NULL, pc200_out, NULL, NULL, pc200); + + green = makecol(0x1C, 0x71, 0x31); + blue = makecol(0x0f, 0x21, 0x3f); + cgapal_rebuild(display_type, contrast); + set_lcd_cols(0); + return pc200; } @@ -130,8 +898,200 @@ void pc200_speed_changed(void *p) pc200_t *pc200 = (pc200_t *)p; cga_recalctimings(&pc200->cga); + mda_recalctimings(&pc200->mda); + + setvidtime(pc200); } +device_config_t pc200_config[] = +{ + { + .name = "video_emulation", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "CGA monitor", + .value = PC200_CGA, + }, + { + .description = "MDA monitor", + .value = PC200_MDA, + }, + { + .description = "Television", + .value = PC200_TV, + }, + { + .description = "" + } + }, + .default_int = PC200_CGA, + }, + { + .name = "display_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "RGB", + .value = DISPLAY_RGB + }, + { + .description = "RGB (no brown)", + .value = DISPLAY_RGB_NO_BROWN + }, + { + .description = "Green Monochrome", + .value = DISPLAY_GREEN + }, + { + .description = "Amber Monochrome", + .value = DISPLAY_AMBER + }, + { + .description = "White Monochrome", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + }, + .default_int = DISPLAY_RGB + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "US English", + .value = 3 + }, + { + .description = "Portugese", + .value = 2 + }, + { + .description = "Norwegian", + .value = 1 + }, + { + .description = "Greek", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 3 + }, + { + .type = -1 + } +}; + + +device_config_t ppc512_config[] = +{ + { + .name = "video_emulation", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "CGA monitor", + .value = PC200_CGA, + }, + { + .description = "MDA monitor", + .value = PC200_MDA, + }, + { + .description = "LCD (CGA mode)", + .value = PC200_LCDC, + }, + { + .description = "LCD (MDA mode)", + .value = PC200_LCDM, + }, + { + .description = "" + } + }, + .default_int = PC200_LCDC, + }, + { + .name = "display_type", + .description = "External monitor", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "RGB", + .value = DISPLAY_RGB + }, + { + .description = "RGB (no brown)", + .value = DISPLAY_RGB_NO_BROWN + }, + { + .description = "Green Monochrome", + .value = DISPLAY_GREEN + }, + { + .description = "Amber Monochrome", + .value = DISPLAY_AMBER + }, + { + .description = "White Monochrome", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + }, + .default_int = DISPLAY_RGB + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "US English", + .value = 3 + }, + { + .description = "Portugese", + .value = 2 + }, + { + .description = "Norwegian", + .value = 1 + }, + { + .description = "Greek", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 3 + }, + { + .type = -1 + } +}; + + + device_t pc200_device = { "Amstrad PC200 (video)", @@ -141,5 +1101,20 @@ device_t pc200_device = NULL, pc200_speed_changed, NULL, - NULL + NULL, + pc200_config }; + +device_t ppc512_device = +{ + "Amstrad PPC512 (video)", + 0, + pc200_init, + pc200_close, + NULL, + pc200_speed_changed, + NULL, + NULL, + ppc512_config +}; + diff --git a/src/vid_pc200.h b/src/vid_pc200.h index 4b43090..f59de48 100644 --- a/src/vid_pc200.h +++ b/src/vid_pc200.h @@ -1 +1,4 @@ extern device_t pc200_device; +extern device_t ppc512_device; + +extern int pc200_is_mda; diff --git a/src/vid_sigma.c b/src/vid_sigma.c index 6519c81..e44a5f1 100644 --- a/src/vid_sigma.c +++ b/src/vid_sigma.c @@ -9,7 +9,6 @@ #include "video.h" #include "vid_sigma.h" -extern void loadfont(char *s, int format); /* The Sigma Designs Color 400 is a video card from 1985, presumably intended * as an EGA competitor. diff --git a/src/vid_wy700.c b/src/vid_wy700.c index 107b134..a34c49d 100644 --- a/src/vid_wy700.c +++ b/src/vid_wy700.c @@ -12,7 +12,6 @@ #define WY700_YSIZE 800 void updatewindowsize(int x, int y); -void loadfont(char *s, int format); /* The Wyse 700 is an unusual video card. Though it has an MC6845 CRTC, this diff --git a/src/video.c b/src/video.c index b0c8039..b416594 100644 --- a/src/video.c +++ b/src/video.c @@ -151,7 +151,7 @@ char *video_card_getname(int card) return video_cards[card].name; } -device_t *video_card_getdevice(int card) +device_t *video_card_getdevice(int card, int romset) { switch (romset) { @@ -169,25 +169,30 @@ device_t *video_card_getdevice(int card) return &pc1512_device; case ROM_PC1640: - if (gfxcard == GFX_BUILTIN) + if (card == GFX_BUILTIN) return &pc1640_device; break; case ROM_PC200: - if (gfxcard == GFX_BUILTIN) + if (card == GFX_BUILTIN) return &pc200_device; break; + + case ROM_PPC512: + if (card == GFX_BUILTIN) + return &ppc512_device; + break; case ROM_OLIM24: return &m24_device; case ROM_PC2086: - if (gfxcard == GFX_BUILTIN) + if (card == GFX_BUILTIN) return ¶dise_pvga1a_pc2086_device; break; case ROM_PC3086: - if (gfxcard == GFX_BUILTIN) + if (card == GFX_BUILTIN) return ¶dise_pvga1a_pc3086_device; break; @@ -234,11 +239,16 @@ device_t *video_card_getdevice(int card) return video_cards[card].device; } -int video_card_has_config(int card) +int video_card_has_config(int card, int romset) { - if (card == GFX_BUILTIN) + /* Allow builtin cards to have configuration */ + device_t *device = video_card_getdevice(card, romset); + + if (!device) + { return 0; - return video_cards[card].device->config ? 1 : 0; + } + return device->config ? 1 : 0; } int video_card_getid(char *s) @@ -312,8 +322,16 @@ int video_is_mda() { switch (romset) { - case ROM_PC1640: case ROM_PC200: + case ROM_PPC512: + if (gfxcard == GFX_BUILTIN) + { +/* The chipset here can emulate either CGA or MDA. Find out which */ + return (pc200_is_mda); + } + break; + + case ROM_PC1640: case ROM_PC2086: case ROM_PC3086: case ROM_MEGAPC: @@ -349,8 +367,14 @@ int video_is_cga() switch (romset) { case ROM_PC200: - if (gfxcard != GFX_BUILTIN) - break; + case ROM_PPC512: + if (gfxcard == GFX_BUILTIN) + { +/* The chipset here can emulate either CGA or MDA. Find out which */ + return (!pc200_is_mda); + } + break; + case ROM_IBMPCJR: case ROM_TANDY: case ROM_TANDY1000HX: @@ -394,6 +418,7 @@ int video_is_ega_vga() case ROM_TANDY1000SL2: case ROM_PC1512: case ROM_PC200: + case ROM_PPC512: case ROM_OLIM24: case ROM_T3100E: case ROM_T1000: @@ -514,6 +539,7 @@ void video_updatetiming() break; case ROM_PC200: + case ROM_PPC512: if (gfxcard == GFX_BUILTIN) timing = &timing_pc200; break; @@ -676,6 +702,14 @@ void video_init() device_add(&pc200_device); return; } + break; + + case ROM_PPC512: + if (gfxcard == GFX_BUILTIN) + { + device_add(&ppc512_device); + return; + } break; case ROM_OLIM24: @@ -788,7 +822,7 @@ uint8_t fontdatksc5601_user[192][32]; /* Korean KSC-5601 user defined font */ int xsize=1,ysize=1; -void loadfont(char *s, int format) +void loadfont(char *s, fontformat_t format) { FILE *f=romfopen(s,"rb"); int c,d; @@ -800,7 +834,7 @@ void loadfont(char *s, int format) } switch (format) { - case 0: /* MDA */ + case FONT_MDA: /* MDA */ for (c=0;c<256;c++) { for (d=0;d<8;d++) @@ -824,33 +858,22 @@ void loadfont(char *s, int format) } } break; - case 1: /* PC200 */ - for (c=0;c<256;c++) - { - for (d=0;d<8;d++) + case FONT_PC200: /* PC200 */ + for (d=0;d<4;d++) /* There are 4 fonts in the ROM */ + { + for (c=0;c<256;c++) /* 8x14 MDA in 8x16 cell */ + { + fread(&fontdatm[256*d+c], 1, 16, f); + } + for (c=0;c<256; c++) /* 8x8 CGA in 8x16 cell */ { - fontdatm[c][d]=getc(f); + fread(fontdat[256*d+c], 1, 8, f); + fseek(f, 8, SEEK_CUR); } } - for (c=0;c<256;c++) - { - for (d=0;d<8;d++) - { - fontdatm[c][d+8]=getc(f); - } - } - fseek(f, 4096, SEEK_SET); - for (c=0;c<256;c++) - { - for (d=0;d<8;d++) - { - fontdat[c][d]=getc(f); - } - for (d=0;d<8;d++) getc(f); - } break; default: - case 2: /* CGA */ + case FONT_CGA: /* CGA */ for (c=0;c<2048;c++) /* Allow up to 2048 chars */ { for (d=0;d<8;d++) @@ -859,7 +882,7 @@ void loadfont(char *s, int format) } } break; - case 3: /* Wyse 700 */ + case FONT_WY700: /* Wyse 700 */ for (c=0;c<512;c++) { for (d=0;d<32;d++) @@ -868,7 +891,7 @@ void loadfont(char *s, int format) } } break; - case 4: /* MDSI Genius */ + case FONT_MDSI: /* MDSI Genius */ for (c=0;c<256;c++) { for (d=0;d<16;d++) @@ -877,7 +900,7 @@ void loadfont(char *s, int format) } } break; - case 5: /* Toshiba 3100e */ + case FONT_T3100E: /* Toshiba 3100e */ for (d = 0; d < 2048; d += 512) /* Four languages... */ { for (c = d; c < d+256; c++) @@ -907,7 +930,7 @@ void loadfont(char *s, int format) } } break; - case 6: /* Korean KSC-5601 */ + case FONT_KSC5601: /* Korean KSC-5601 */ for (c=0;c<16384;c++) { for (d=0;d<32;d++) @@ -916,7 +939,7 @@ void loadfont(char *s, int format) } } break; - case 7: /* Sigma Color 400 */ + case FONT_SIGMA400: /* Sigma Color 400 */ /* The first 4k of the character ROM holds an 8x8 font */ for (c = 0; c < 256; c++) { diff --git a/src/video.h b/src/video.h index f8edf05..4194b7a 100644 --- a/src/video.h +++ b/src/video.h @@ -23,8 +23,8 @@ extern BITMAP *buffer32; int video_card_available(int card); char *video_card_getname(int card); -struct device_t *video_card_getdevice(int card); -int video_card_has_config(int card); +struct device_t *video_card_getdevice(int card, int romset); +int video_card_has_config(int card, int romset); int video_card_getid(char *s); int video_old_to_new(int card); int video_new_to_old(int card); @@ -82,7 +82,21 @@ extern int vid_resize; void video_wait_for_blit(); void video_wait_for_buffer(); -void loadfont(char *s, int format); + +typedef enum +{ + FONT_MDA, /* MDA 8x14 */ + FONT_PC200, /* MDA 8x14 and CGA 8x8, four fonts */ + FONT_CGA, /* CGA 8x8, two fonts */ + FONT_WY700, /* Wy700 16x16, two fonts */ + FONT_MDSI, /* MDSI Genius 8x12 */ + FONT_T3100E, /* Toshiba T3100e, four fonts */ + FONT_KSC5601, /* Korean KSC-5601 */ + FONT_SIGMA400, /* Sigma Color 400, 8x8 and 8x16 */ + +} fontformat_t; + +void loadfont(char *s, fontformat_t format); void initvideo(); void video_init(); diff --git a/src/wx-config.c b/src/wx-config.c index 618363d..13f22cb 100644 --- a/src/wx-config.c +++ b/src/wx-config.c @@ -82,6 +82,7 @@ static void recalc_vid_list(void* hdlg, int model, int force_builtin_video) int c = 0, d = 0; int found_card = 0; int cur_gfxcard = gfxcard; + int romset = model_getromset_from_model(model); wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); @@ -92,7 +93,7 @@ static void recalc_vid_list(void* hdlg, int model, int force_builtin_video) wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); wx_enablewindow(h, FALSE); h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID")); - wx_enablewindow(h, FALSE); + wx_enablewindow(h, video_card_has_config(gfxcard, romset)); return; } @@ -108,6 +109,9 @@ static void recalc_vid_list(void* hdlg, int model, int force_builtin_video) d++; } + if (cur_gfxcard == GFX_BUILTIN && !model_has_fixed_gfx(model) && !model_has_optional_gfx(model)) + cur_gfxcard = 0; + while (1) { char *s = video_card_getname(c); @@ -116,7 +120,7 @@ static void recalc_vid_list(void* hdlg, int model, int force_builtin_video) break; if (video_card_available(c) && gfx_present[video_new_to_old(c)] && - ((models[model].flags & MODEL_PCI) || !(video_card_getdevice(c)->flags & DEVICE_PCI))) + ((models[model].flags & MODEL_PCI) || !(video_card_getdevice(c, romset)->flags & DEVICE_PCI))) { wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); if (video_new_to_old(c) == gfxcard && !found_card) @@ -135,7 +139,7 @@ static void recalc_vid_list(void* hdlg, int model, int force_builtin_video) wx_enablewindow(h, TRUE); h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID")); - if (video_card_has_config(video_old_to_new(cur_gfxcard))) + if (video_card_has_config(video_old_to_new(cur_gfxcard), romset)) wx_enablewindow(h, TRUE); else wx_enablewindow(h, FALSE); @@ -1095,11 +1099,11 @@ int config_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) else if (wParam == WX_ID("IDC_CONFIGUREVID")) { h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID")); - wx_sendmessage(h, WX_CB_GETLBTEXT, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0), - (LONG_PARAM) temp_str); + wx_sendmessage(h, WX_CB_GETLBTEXT, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0), (LONG_PARAM) temp_str); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; - deviceconfig_open(hdlg, - (void *) video_card_getdevice(video_card_getid(temp_str))); + deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(temp_str), model_getromset_from_model(temp_model))); } else if (wParam == WX_ID("IDC_COMBOVID")) { @@ -1112,7 +1116,7 @@ int config_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) gfx = video_card_getid(temp_str); h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID")); - if (video_card_has_config(gfx) && !model_has_fixed_gfx(temp_model)) + if (video_card_has_config(gfx, model_getromset_from_model(temp_model))) wx_enablewindow(h, TRUE); else wx_enablewindow(h, FALSE);