diff --git a/nvr/ibmps1_2121.nvr b/nvr/ibmps1_2121.nvr new file mode 100644 index 0000000..0501a36 Binary files /dev/null and b/nvr/ibmps1_2121.nvr differ diff --git a/readme.txt b/readme.txt index 86b0c1c..c97445d 100644 --- a/readme.txt +++ b/readme.txt @@ -261,6 +261,14 @@ deskpro386\109592-005.U11.bin deskpro386\109591-005.U13.bin +IBM PS/1 Model 2121 (1990) +This is a 386SX with integrated VGA. + +ROM files needed: + +ibmps1_2121\fc0000.bin + + Acermate 386SX/25N (1992?) An integrated 386SX clone, with onboard Oak SVGA and IO. diff --git a/src/Makefile.am b/src/Makefile.am index 4dbbf83..2e9ac52 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,7 +29,7 @@ sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c tandy_e 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_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 \ 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 \ diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 4a862f5..f38a5fd 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -16,7 +16,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad 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_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_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 \ vid_vga.o vid_voodoo.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \ win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-keyboard.o win-midi.o win-mouse.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index bb8ea83..a4df9b4 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -16,7 +16,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad 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_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_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 \ vid_vga.o vid_voodoo.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \ win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-keyboard.o win-midi.o win-mouse.o \ diff --git a/src/fdc.c b/src/fdc.c index 7ffabbd..7a8fa07 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -34,7 +34,7 @@ typedef struct FDC int tc; int written; - int pcjr; + int pcjr, ps1; int watchdog_timer; int watchdog_count; @@ -574,6 +574,14 @@ bad_command: fdc.inread = 1; break; + case 3: /*Specify*/ + fdc.stat=0x80; + fdc.specify[0] = fdc.params[0]; + fdc.specify[1] = fdc.params[1]; + fdc.dma = (fdc.specify[1] & 1) ^ 1; + disctime = 0; + break; + case 5: /*Write data*/ fdc_rate(fdc.drive); fdc.head=fdc.params[2]; @@ -675,7 +683,21 @@ uint8_t fdc_read(uint16_t addr, void *priv) temp &= ~0x20; break; case 3: - if (!fdc.enh_mode) + drive = (fdc.dor & 1) ^ fdd_swap; + if (fdc.ps1) + { + /*PS/1 Model 2121 seems return drive type in port 0x3f3, + despite the 82077AA FDC not implementing this. This is + presumably implemented outside the FDC on one of the + motherboard's support chips.*/ + if (fdd_is_525(drive)) + temp = 0x20; + else if (fdd_is_ed(drive)) + temp = 0x10; + else + temp = 0x00; + } + else if (!fdc.enh_mode) temp = 0x20; else { @@ -800,12 +822,6 @@ void fdc_callback() disc_readsector(fdc.drive, SECTOR_NEXT, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]); fdc.inread = 1; return; - case 3: /*Specify*/ - fdc.stat=0x80; - fdc.specify[0] = fdc.params[0]; - fdc.specify[1] = fdc.params[1]; - fdc.dma = (fdc.specify[1] & 1) ^ 1; - return; case 4: /*Sense drive status*/ fdc.res[10] = (fdc.params[0] & 7) | 0x28; if (fdd_track0(fdc.drive)) @@ -1330,6 +1346,7 @@ void fdc_add() io_sethandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); fdc.pcjr = 0; + fdc.ps1 = 0; } void fdc_add_pcjr() @@ -1337,6 +1354,7 @@ void fdc_add_pcjr() io_sethandler(0x00f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); timer_add(fdc_watchdog_poll, &fdc.watchdog_timer, &fdc.watchdog_timer, &fdc); fdc.pcjr = 1; + fdc.ps1 = 0; } void fdc_remove() @@ -1360,3 +1378,8 @@ void fdc_3f1_enable(int enable) { fdc.enable_3f1 = enable; } + +void fdc_set_ps1() +{ + fdc.ps1 = 1; +} diff --git a/src/fdc.h b/src/fdc.h index 491c8e7..618cf19 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -9,6 +9,7 @@ void fdc_abort(); void fdc_discchange_clear(int drive); void fdc_set_dskchg_activelow(); void fdc_3f1_enable(int enable); +void fdc_set_ps1(); int fdc_get_bitcell_period(); /* A few functions to communicate between Super I/O chips and the FDC. */ diff --git a/src/fdd.c b/src/fdd.c index bd47ec5..ccc2b13 100644 --- a/src/fdd.c +++ b/src/fdd.c @@ -181,3 +181,13 @@ int fdd_get_type(int drive) { return fdd[drive].type; } + +int fdd_is_525(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_525; +} + +int fdd_is_ed(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_HOLE2; +} diff --git a/src/fdd.h b/src/fdd.h index ef68df5..3a5c457 100644 --- a/src/fdd.h +++ b/src/fdd.h @@ -5,6 +5,8 @@ int fdd_getrpm(int drive); void fdd_set_densel(int densel); int fdd_can_read_medium(int drive); int fdd_doublestep_40(int drive); +int fdd_is_525(int drive); +int fdd_is_ed(int drive); void fdd_set_type(int drive, int type); int fdd_get_type(int drive); diff --git a/src/ibm.h b/src/ibm.h index 1d1a261..52f62e9 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -333,7 +333,8 @@ enum ROM_REVENGE, ROM_IBMPS1_2011, ROM_DESKPRO_386, - + ROM_IBMPS1_2121, + ROM_MAX }; diff --git a/src/keyboard_at.c b/src/keyboard_at.c index 9ded5e8..97ebeeb 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -449,7 +449,9 @@ uint8_t keyboard_at_read(uint16_t port, void *priv) return ppi.pb&~0xe0; case 0x64: - temp = keyboard_at.status; + temp = keyboard_at.status & ~4; + if (keyboard_at.mem[0] & 0x04) + temp |= 0x04; keyboard_at.status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); break; } diff --git a/src/mem.c b/src/mem.c index c28b22d..0976c61 100644 --- a/src/mem.c +++ b/src/mem.c @@ -38,6 +38,7 @@ static mem_mapping_t base_mapping; mem_mapping_t ram_low_mapping; static mem_mapping_t ram_high_mapping; static mem_mapping_t ram_mid_mapping; +static mem_mapping_t ram_remapped_mapping; mem_mapping_t bios_mapping[8]; static mem_mapping_t bios_high_mapping[8]; static mem_mapping_t romext_mapping; @@ -522,6 +523,15 @@ int loadbios() mem_load_atide115_bios(); return 1; + case ROM_IBMPS1_2121: + f = romfopen("roms/ibmps1_2121/fc0000.bin", "rb"); + if (!f) break; + fseek(f, 0x20000, SEEK_SET); + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + case ROM_DESKPRO_386: f=romfopen("roms/deskpro386/109592-005.U11.bin","rb"); ff=romfopen("roms/deskpro386/109591-005.U13.bin","rb"); @@ -1791,18 +1801,18 @@ void mem_init() { int c; - ram = malloc(mem_size * 1024); + ram = malloc((mem_size + 384) * 1024); rom = malloc(0x20000); vram = malloc(0x800000); readlookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); cachelookup2 = malloc(1024 * 1024); biosmask = 0xffff; - pages = malloc(((mem_size * 1024) >> 12) * sizeof(page_t)); + pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); page_lookup = malloc((1 << 20) * sizeof(page_t *)); - memset(ram, 0, mem_size * 1024); - memset(pages, 0, ((mem_size * 1024) >> 12) * sizeof(page_t)); + memset(ram, 0, (mem_size + 384) * 1024); + memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); memset(page_lookup, 0, (1 << 20) * sizeof(page_t *)); @@ -1850,18 +1860,41 @@ void mem_init() // pclog("Mem resize %i %i\n",mem_size,c); } +void mem_remap_top_384k() +{ + int c; + + for (c = ((mem_size * 1024) >> 12); c < (((mem_size + 384) * 1024) >> 12); c++) + { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + for (c = (mem_size / 256); c < ((mem_size + 384) / 256); c++) + { + isram[c] = 1; + if (c >= 0xa && c <= 0xf) + isram[c] = 0; + } + + mem_set_mem_state(mem_size * 1024, 384 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 384 * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + (mem_size * 1024), MEM_MAPPING_INTERNAL, NULL); +} + void mem_resize() { int c; free(ram); - ram = malloc(mem_size * 1024); - memset(ram, 0, mem_size * 1024); + ram = malloc((mem_size + 384) * 1024); + memset(ram, 0, (mem_size + 384) * 1024); free(pages); - pages = malloc(((mem_size * 1024) >> 12) * sizeof(page_t)); - memset(pages, 0, ((mem_size * 1024) >> 12) * sizeof(page_t)); - for (c = 0; c < ((mem_size * 1024) >> 12); c++) + pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + for (c = 0; c < (((mem_size + 384) * 1024) >> 12); c++) { pages[c].mem = &ram[c << 12]; pages[c].write_b = mem_write_ramb_page; diff --git a/src/mem.h b/src/mem.h index 102b057..848468e 100644 --- a/src/mem.h +++ b/src/mem.h @@ -163,4 +163,6 @@ void mem_reset_page_blocks(); extern mem_mapping_t ram_low_mapping; +void mem_remap_top_384k(); + #endif diff --git a/src/model.c b/src/model.c index 5ad5e13..a6b069c 100644 --- a/src/model.c +++ b/src/model.c @@ -59,7 +59,8 @@ void europc_init(); void olim24_init(); void at_init(); void deskpro386_init(); -void ps1_init(); +void ps1_m2011_init(); +void ps1_m2121_init(); void at_neat_init(); void at_scat_init(); void at_acer386sx_init(); @@ -103,7 +104,8 @@ MODEL models[] = {"AMI 286 clone", ROM_AMI286, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_neat_init}, {"Award 286 clone", ROM_AWARD286, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_scat_init}, {"DELL System 200", ROM_DELL200, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_init}, - {"IBM PS/1 model 2011", ROM_IBMPS1_2011, { "", cpus_ps1_m2011,"", NULL, "", NULL}, 1, 1, 1, 16, 1, ps1_init}, + {"IBM PS/1 model 2011", ROM_IBMPS1_2011, { "", cpus_ps1_m2011,"", NULL, "", NULL}, 1, 1, 1, 16, 1, ps1_m2011_init}, + {"IBM PS/1 model 2121", ROM_IBMPS1_2121, { "Intel", cpus_i386, "", NULL, "", NULL}, 1, 1, 1, 16, 1, ps1_m2121_init}, {"Compaq Deskpro 386", ROM_DESKPRO_386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 15, 1, deskpro386_init}, {"Acer 386SX25/N", ROM_ACER386, { "Intel", cpus_acer, "", NULL, "", NULL}, 1, 1, 1, 16, 1, at_acer386sx_init}, {"DTK 386SX clone", ROM_DTK386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 16, 1, at_neat_init}, @@ -278,7 +280,7 @@ void deskpro386_init() compaq_init(); } -void ps1_init() +void ps1_common_init() { AT = 1; common_init(); @@ -290,13 +292,25 @@ void ps1_init() mouse_ps2_init(); nvr_init(); pic2_init(); - ps1mb_init(); fdc_set_dskchg_activelow(); device_add(&ps1_audio_device); /*PS/1 audio uses ports 200h and 202-207h, so only initialise gameport on 201h*/ device_add(&gameport_201_device); } +void ps1_m2011_init() +{ + ps1_common_init(); + ps1mb_init(); +} + +void ps1_m2121_init() +{ + ps1_common_init(); + ps1mb_m2121_init(); + fdc_set_ps1(); +} + void at_neat_init() { at_init(); diff --git a/src/nvr.c b/src/nvr.c index 7b7097c..bfb2985 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -137,6 +137,7 @@ void loadnvr() case ROM_PC3086: f = romfopen("nvr/pc3086.nvr", "rb"); break; case ROM_IBMAT: f = romfopen("nvr/at.nvr", "rb"); break; case ROM_IBMPS1_2011: f = romfopen("nvr/ibmps1_2011.nvr", "rb"); /*nvrmask = 127; */break; + case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "rb"); nvrmask = 127; break; case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "rb"); nvrmask = 127; break; case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "rb"); nvrmask = 127; break; case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "rb"); nvrmask = 127; break; @@ -181,6 +182,7 @@ void savenvr() case ROM_PC3086: f = romfopen("nvr/pc3086.nvr", "wb"); break; case ROM_IBMAT: f = romfopen("nvr/at.nvr", "wb"); break; case ROM_IBMPS1_2011: f = romfopen("nvr/ibmps1_2011.nvr", "wb"); break; + case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "wb"); break; case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "wb"); break; case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "wb"); break; case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "wb"); break; diff --git a/src/ps1.c b/src/ps1.c index 6470125..3f38672 100644 --- a/src/ps1.c +++ b/src/ps1.c @@ -6,6 +6,8 @@ static rom_t ps1_high_rom; static uint8_t ps1_92, ps1_94, ps1_102, ps1_103, ps1_104, ps1_105, ps1_190; +static int ps1_e0_addr; +static uint8_t ps1_e0_regs[256]; static struct { @@ -150,3 +152,144 @@ void ps1mb_init() memset(&ps1_hd, 0, sizeof(ps1_hd)); } + +/*PS/1 Model 2121. + + This is similar to the model 2011 but some of the functionality has moved to a + chip at ports 0xe0 (index)/0xe1 (data). The only functions I have identified + are enables for the first 512kb and next 128kb of RAM, in bits 0 of registers + 0 and 1 respectively. + + Port 0x105 has bit 7 forced high. Without this 128kb of memory will be missed + by the BIOS on cold boots. + + The reserved 384kb is remapped to the top of extended memory. If this is not + done then you get an error on startup. +*/ +static uint8_t ps1_m2121_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + return 0; + case 0x92: + return ps1_92; + case 0x94: + return ps1_94; + case 0xe1: + return ps1_e0_regs[ps1_e0_addr]; + case 0x102: + return ps1_102; + case 0x103: + return ps1_103; + case 0x104: + return ps1_104; + case 0x105: + return ps1_105 | 0x80; + case 0x190: + return ps1_190; + + default: + temp = 0xff; + break; + } + + return temp; +} + +static void ps1_m2121_recalc_memory() +{ + /*Enable first 512kb*/ + mem_set_mem_state(0x00000, 0x80000, (ps1_e0_regs[0] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + /*Enable 512-640kb*/ + mem_set_mem_state(0x80000, 0x20000, (ps1_e0_regs[1] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); +} + +void ps1_m2121_write(uint16_t port, uint8_t val, void *p) +{ + switch (port) + { + case 0x0092: + if (val & 1) + softresetx86(); + ps1_92 = val & ~1; + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + case 0x94: + ps1_94 = val; + break; + case 0xe0: + ps1_e0_addr = val; + break; + case 0xe1: + ps1_e0_regs[ps1_e0_addr] = val; + ps1_m2121_recalc_memory(); + break; + case 0x102: + lpt1_remove(); + if (val & 0x04) + serial1_init(0x3f8, 4); + else + serial1_remove(); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps1_102 = val; + break; + case 0x103: + ps1_103 = val; + break; + case 0x104: + ps1_104 = val; + break; + case 0x105: + ps1_105 = val; + break; + case 0x190: + ps1_190 = val; + break; + } +} + +void ps1mb_m2121_init() +{ + io_sethandler(0x0091, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x00e0, 0x0002, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0102, 0x0004, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0190, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + + rom_init(&ps1_high_rom, + "roms/ibmps1_2121/fc0000.bin", + 0xfc0000, + 0x40000, + 0x3ffff, + 0, + MEM_MAPPING_EXTERNAL); + ps1_190 = 0; + + lpt1_remove(); + lpt2_remove(); + lpt1_init(0x3bc); + + serial1_remove(); + serial2_remove(); + + mem_remap_top_384k(); +} diff --git a/src/ps1.h b/src/ps1.h index bfe0deb..c054bcb 100644 --- a/src/ps1.h +++ b/src/ps1.h @@ -1 +1,2 @@ void ps1mb_init(); +void ps1mb_m2121_init(); diff --git a/src/vid_ps1_svga.c b/src/vid_ps1_svga.c new file mode 100644 index 0000000..731bd94 --- /dev/null +++ b/src/vid_ps1_svga.c @@ -0,0 +1,187 @@ +/*Emulation of the SVGA chip in the IBM PS/1 Model 2121, or at least the + 20 MHz version. + + I am not entirely sure what this chip actually is, possibly a CF62011? I can + not find any documentation on the chip so have implemented enough to pass + self-test in the PS/1 BIOS. It has 512kb video memory but I have not found any + native drivers for any operating system and there is no VBE implementation, so + it's just a VGA for now. +*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_vga.h" + +typedef struct ps1_m2121_svga_t +{ + svga_t svga; + + rom_t bios_rom; + + uint8_t banking; + uint8_t reg_2100; + uint8_t reg_210a; +} ps1_m2121_svga_t; + +void ps1_m2121_svga_out(uint16_t addr, uint8_t val, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + svga_t *svga = &ps1->svga; + uint8_t old; + +// pclog("svga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,cpu_state.pc, ram[0x489], ins); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x1f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x2100: + ps1->reg_2100 = val; + if ((val & 7) < 4) + svga->read_bank = svga->write_bank = 0; + else + svga->read_bank = svga->write_bank = (ps1->banking & 0x7) * 0x10000; + break; + case 0x2108: + if ((ps1->reg_2100 & 7) >= 4) + svga->read_bank = svga->write_bank = (val & 0x7) * 0x10000; + ps1->banking = val; + break; + case 0x210a: + ps1->reg_210a = val; + break; + } + svga_out(addr, val, svga); +} + +uint8_t ps1_m2121_svga_in(uint16_t addr, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + svga_t *svga = &ps1->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("svga_in : %04X ", addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x100: + temp = 0xfe; + break; + case 0x101: + temp = 0xe8; + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + + case 0x2108: + temp = ps1->banking; + break; + case 0x210a: + temp = ps1->reg_210a; + break; + + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +void *ps1_m2121_svga_init() +{ + ps1_m2121_svga_t *ps1 = malloc(sizeof(ps1_m2121_svga_t)); + memset(ps1, 0, sizeof(ps1_m2121_svga_t)); + + svga_init(&ps1->svga, ps1, 1 << 19, /*512kb*/ + NULL, + ps1_m2121_svga_in, ps1_m2121_svga_out, + NULL, + NULL); + + io_sethandler(0x0100, 0x0002, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + io_sethandler(0x03c0, 0x0020, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + io_sethandler(0x2100, 0x0010, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); +// io_sethandler(0x210a, 0x0001, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + + ps1->svga.bpp = 8; + ps1->svga.miscout = 1; + + return ps1; +} + +void ps1_m2121_svga_close(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_close(&ps1->svga); + + free(ps1); +} + +void ps1_m2121_svga_speed_changed(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_recalctimings(&ps1->svga); +} + +void ps1_m2121_svga_force_redraw(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + ps1->svga.fullchange = changeframecount; +} + +void ps1_m2121_svga_add_status_info(char *s, int max_len, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_add_status_info(s, max_len, &ps1->svga); +} + +device_t ps1_m2121_svga_device = +{ + "PS/1 Model 2121 SVGA", + 0, + ps1_m2121_svga_init, + ps1_m2121_svga_close, + NULL, + ps1_m2121_svga_speed_changed, + ps1_m2121_svga_force_redraw, + ps1_m2121_svga_add_status_info +}; diff --git a/src/vid_ps1_svga.h b/src/vid_ps1_svga.h new file mode 100644 index 0000000..5068ba0 --- /dev/null +++ b/src/vid_ps1_svga.h @@ -0,0 +1 @@ +extern device_t ps1_m2121_svga_device; diff --git a/src/video.c b/src/video.c index 20d1902..eac9554 100644 --- a/src/video.c +++ b/src/video.c @@ -29,6 +29,7 @@ #include "vid_pc1640.h" #include "vid_pc200.h" #include "vid_pcjr.h" +#include "vid_ps1_svga.h" #include "vid_s3.h" #include "vid_s3_virge.h" #include "vid_tandy.h" @@ -269,6 +270,10 @@ void video_init() case ROM_IBMPS1_2011: device_add(&ps1vga_device); return; + + case ROM_IBMPS1_2121: + device_add(&ps1_m2121_svga_device); + return; } device_add(video_cards[video_old_to_new(gfxcard)].device); }