Add IBM PS/1 Model 2133 (EMEA 451) emulation. Currently displays a cache error

on boot, but otherwise seems to work fine.
This commit is contained in:
SarahW 2020-02-09 12:17:06 +00:00
commit 8870334114
14 changed files with 319 additions and 12 deletions

View file

@ -49,7 +49,7 @@ vid_incolor.c vid_mda.c vid_mga.c vid_olivetti_m24.c vid_oti037.c vid_oti067.c v
vid_pc1640.c vid_pcjr.c vid_pgc.c vid_ps1_svga.c vid_s3.c vid_s3_virge.c vid_sdac_ramdac.c vid_sigma.c \
vid_stg_ramdac.c vid_svga.c vid_svga_render.c vid_t1000.c vid_t3100e.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 vid_wy700.c vt82c586b.c \
w83877tf.c x86seg.c x87.c x87_timings.c xi8088.c xtide.c sound_dbopl.cc sound_resid.cc
vl82c480.c w83877tf.c x86seg.c x87.c x87_timings.c xi8088.c xtide.c sound_dbopl.cc sound_resid.cc
# DOSBox
pcem_SOURCES += dosbox/cdrom_image.cpp dosbox/dbopl.cpp dosbox/nukedopl.cpp dosbox/vid_cga_comp.c

View file

@ -36,7 +36,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203
vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \
vid_svga_render.o vid_t1000.o vid_t3100e.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 vid_wy700.o video.o \
vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o vid_voodoo.o vid_wy700.o video.o vl82c480.o \
vt82c586b.o w83877tf.o wd76c10.o x86seg.o x87.o x87_timings.o xi8088.c xtide.o win-midi.o wx-main.o \
wx-config_sel.o wx-dialogbox.o wx-utils.o wx-app.o wx-sdl2-joystick.o wx-sdl2-mouse.o \
wx-sdl2-keyboard.o wx-sdl2-video.o wx-sdl2.o wx-config.o wx-deviceconfig.o wx-status.o \

View file

@ -36,7 +36,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203
vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \
vid_svga_render.o vid_t1000.o vid_t3100e.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 vid_wy700.o video.o \
vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o vid_voodoo.o vid_wy700.o video.o vl82c480.o \
vt82c586b.o w83877tf.o wd76c10.o x86seg.o x87.o x87_timings.o xi8088.c xtide.o win-midi.o wx-main.o \
wx-config_sel.o wx-dialogbox.o wx-hostconfig.o wx-utils.o wx-app.o wx-sdl2-joystick.o wx-sdl2-mouse.o \
wx-sdl2-keyboard.o wx-sdl2-video.o wx-sdl2.o wx-config.o wx-deviceconfig.o wx-status.o \

View file

@ -253,6 +253,7 @@ enum
ROM_BULL_MICRAL_45,
ROM_FIC_VA503P,
ROM_CBM_SL386SX25,
ROM_IBMPS1_2133_451,
ROM_MAX
};

View file

@ -1015,6 +1015,14 @@ int loadbios()
romfread(rom, 0x10000, 1, f);
fclose(f);
return 1;
case ROM_IBMPS1_2133_451:
f = romfopen("ibmps1_2133/PS1_2133_52G2974_ROM.bin", "rb");
if (!f) break;
romfread(rom, 0x20000, 1, f);
fclose(f);
biosmask = 0x1ffff;
return 1;
}
printf("Failed to load ROM!\n");
if (f) fclose(f);

View file

@ -70,6 +70,7 @@
#include "vid_pcjr.h"
#include "vid_tandy.h"
#include "vid_t1000.h"
#include "vl82c480.h"
#include "vt82c586b.h"
#include "w83877tf.h"
#include "wd76c10.h"
@ -91,6 +92,7 @@ void deskpro386_init();
void pb_l300sx_init();
void ps1_m2011_init();
void ps1_m2121_init();
void ps1_m2133_init(void);
void ps2_m30_286_init();
void ps2_model_50_init();
void ps2_model_55sx_init();
@ -204,6 +206,7 @@ MODEL models[] =
{"[486] AMI WinBIOS 486", ROM_WIN486, "win486", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_ali1429_init, NULL},
{"[486] Award SiS 496/497", ROM_SIS496, "sis496", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_HAS_IDE, 1, 256, 1, at_sis496_init, NULL},
{"[486] Elonex PC-425X", ROM_ELX_PC425X, "elx_pc425x", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_sl82c460_init, NULL},
{"[486] IBM PS/1 Model 2133 (EMEA 451)",ROM_IBMPS1_2133_451, "ibmps1_2133", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_PS2, 2, 64, 2, ps1_m2133_init, NULL},
{"[486] IBM PS/2 Model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_MCA, 2, 16, 2, ps2_model_70_init, NULL},
{"[486] Packard Bell PB410A", ROM_PB410A, "pb410a", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 64, 1, at_pb410a_init, NULL},
@ -507,6 +510,13 @@ void ps1_m2121_init()
fdc_set_ps1();
}
void ps1_m2133_init(void)
{
at_init();
vl82c480_init();
ps1mb_m2133_init();
}
void ps2_m30_286_init()
{
AT = 1;

View file

@ -348,6 +348,7 @@ void loadnvr()
case ROM_BULL_MICRAL_45: f = nvrfopen("bull_micral_45.nvr", "rb"); break;
case ROM_FIC_VA503P: f = nvrfopen("fic_va503p.nvr", "rb"); nvrmask = 127; break;
case ROM_CBM_SL386SX25: f = nvrfopen("cbm_sl386sx25.nvr", "rb"); nvrmask = 127; break;
case ROM_IBMPS1_2133_451: f = nvrfopen("ibmps1_2133.nvr", "rb"); nvrmask = 127; break;
default: return;
}
@ -447,6 +448,7 @@ void savenvr()
case ROM_BULL_MICRAL_45: f = nvrfopen("bull_micral_45.nvr", "wb"); break;
case ROM_FIC_VA503P: f = nvrfopen("fic_va503p.nvr", "wb"); break;
case ROM_CBM_SL386SX25: f = nvrfopen("cbm_sl386sx25.nvr", "wb"); break;
case ROM_IBMPS1_2133_451: f = nvrfopen("ibmps1_2133.nvr", "wb"); break;
default: return;
}

View file

@ -301,3 +301,65 @@ void ps1mb_m2121_init()
mem_remap_top_384k();
}
/*Not sure what this SuperIO chip is, so define it here for now*/
static struct
{
int idx;
uint8_t regs[3];
} ps1_m2133_superio;
static uint16_t ps1_lpt_io[4] = {0x378, 0x3bc, 0x278, 0x378};
static uint16_t ps1_com_io[4] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
static uint8_t ps1_m2133_read(uint16_t port, void *p)
{
uint8_t ret = 0xff;
switch (port)
{
case 0x398:
ret = ps1_m2133_superio.idx;
break;
case 0x399:
if (ps1_m2133_superio.idx < 3)
ret = ps1_m2133_superio.regs[ps1_m2133_superio.idx];
break;
}
return ret;
}
static void ps1_m2133_write(uint16_t port, uint8_t val, void *p)
{
// pclog("ps1_m2133_write: port=%04x val=%02x\n", port, val);
switch (port)
{
case 0x398:
ps1_m2133_superio.idx = val;
break;
case 0x399:
if (ps1_m2133_superio.idx < 3)
{
ps1_m2133_superio.regs[ps1_m2133_superio.idx] = val;
lpt1_remove();
serial1_remove();
serial2_remove();
if (ps1_m2133_superio.regs[0] & 1)
lpt1_init(ps1_lpt_io[ps1_m2133_superio.regs[1] & 3]);
if (ps1_m2133_superio.regs[0] & 2)
serial1_set(ps1_com_io[(ps1_m2133_superio.regs[1] >> 2) & 3], 4);
if (ps1_m2133_superio.regs[0] & 4)
serial2_set(ps1_com_io[(ps1_m2133_superio.regs[1] >> 4) & 3], 3);
}
break;
}
}
void ps1mb_m2133_init(void)
{
io_sethandler(0x0398, 0x0002, ps1_m2133_read, NULL, NULL, ps1_m2133_write, NULL, NULL, NULL);
}

View file

@ -1,2 +1,3 @@
void ps1mb_init();
void ps1mb_m2121_init();
void ps1mb_m2133_init(void);

View file

@ -18,6 +18,7 @@
enum
{
CL_TYPE_AVGA2 = 0,
CL_TYPE_GD5426,
CL_TYPE_GD5428,
CL_TYPE_GD5429,
CL_TYPE_GD5430,
@ -226,13 +227,27 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p)
svga->gdcreg[6] = val;
gd5429_recalc_mapping(gd5429);
}
/*Hack - the Windows 3.x drivers for the GD5426/8 require VRAM wraparound
for pattern & cursor writes to work correctly, but the BIOSes require
no wrapping to detect memory size - albeit with odd/even mode enabled.
This may be a quirk of address mapping. So change wrapping mode based on
odd/even mode for now*/
if (gd5429->type == CL_TYPE_GD5426 || gd5429->type == CL_TYPE_GD5428)
{
if (val & 2) /*Odd/Even*/
svga->decode_mask = 0x1fffff;
else
svga->decode_mask = svga->vram_mask;
}
svga->gdcreg[6] = val;
return;
}
if (svga->gdcaddr > 8)
{
svga->gdcreg[svga->gdcaddr & 0x3f] = val;
if (gd5429->type < CL_TYPE_GD5428 && (svga->gdcaddr > 0xb))
if (gd5429->type < CL_TYPE_GD5426 && (svga->gdcaddr > 0xb))
return;
switch (svga->gdcaddr)
{
@ -403,11 +418,11 @@ uint8_t gd5429_in(uint16_t addr, void *p)
return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f;
case 0x17:
if (gd5429->type < CL_TYPE_GD5428)
if (gd5429->type < CL_TYPE_GD5426)
break;
temp = svga->seqregs[0x17];
temp &= ~(7 << 3);
if (gd5429->type == CL_TYPE_GD5428)
if (gd5429->type == CL_TYPE_GD5426 || gd5429->type == CL_TYPE_GD5428)
{
if (MCA)
temp |= (CL_GD5428_SYSTEM_BUS_MCA << 3);
@ -468,6 +483,8 @@ uint8_t gd5429_in(uint16_t addr, void *p)
{
case CL_TYPE_AVGA2:
return 0x18; /*AVGA2*/
case CL_TYPE_GD5426:
return 0x90; /*GD5426*/
case CL_TYPE_GD5428:
return 0x98; /*GD5428*/
case CL_TYPE_GD5429:
@ -644,8 +661,12 @@ void gd5429_recalctimings(svga_t *svga)
n = svga->seqregs[0xb + clock] & 0x7f;
d = (svga->seqregs[0x1b + clock] >> 1) & 0x1f;
p = svga->seqregs[0x1b + clock] & 1;
vclk = (14318184.0 * ((float)n / (float)d)) / (float)(1 + p);
/*Prevent divide by zero during clock setup*/
if (d && n)
vclk = (14318184.0 * ((float)n / (float)d)) / (float)(1 + p);
else
vclk = 14318184.0;
switch (svga->seqregs[7] & ((gd5429->type >= CL_TYPE_GD5434) ? 0xe : 0x6))
{
case 2:
@ -1980,7 +2001,8 @@ static void *cl_init(int type, char *fn, int pci_card, uint32_t force_vram_size)
gd5429->type = type;
rom_init(&gd5429->bios_rom, fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
if (fn)
rom_init(&gd5429->bios_rom, fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
svga_init(&gd5429->svga, gd5429, (vram_size >= 256) ? (vram_size << 10) : (vram_size << 20),
gd5429_recalctimings,
@ -2001,8 +2023,6 @@ static void *cl_init(int type, char *fn, int pci_card, uint32_t force_vram_size)
io_sethandler(0x46e8, 0x0002, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429);
svga->decode_mask = svga->vram_mask;
}
if (type == CL_TYPE_GD5428)
svga->decode_mask = svga->vram_mask;
svga->hwcursor.yoff = 32;
svga->hwcursor.xoff = 0;
@ -2048,6 +2068,10 @@ static void *avga2_cbm_sl386sx_init()
{
return cl_init(CL_TYPE_AVGA2, "cbm_sl386sx25/c000.rom", -1, 0);
}
static void *gd5426_ps1_init()
{
return cl_init(CL_TYPE_GD5426, NULL, -1, 1);
}
static void *gd5428_init()
{
return cl_init(CL_TYPE_GD5428, "Machspeed_VGA_GUI_2100_VLB.vbi", -1, 0);
@ -2255,6 +2279,19 @@ device_t avga2_cbm_sl386sx_device =
avga2_config
};
device_t gd5426_ps1_device =
{
"Cirrus Logic GD5426 (IBM PS/1)",
0,
gd5426_ps1_init,
gd5429_close,
NULL,
gd5429_speed_changed,
gd5429_force_redraw,
gd5429_add_status_info,
NULL
};
device_t gd5428_device =
{
"Cirrus Logic GD5428",

View file

@ -1,8 +1,10 @@
extern device_t avga2_device;
extern device_t avga2_cbm_sl386sx_device;
extern device_t gd5426_ps1_device;
extern device_t gd5428_device;
extern device_t ibm_gd5428_device;
extern device_t gd5429_device;
extern device_t gd5429_reply_m25_device;
extern device_t gd5430_device;
extern device_t gd5430_pb570_device;
extern device_t gd5434_device;

View file

@ -234,6 +234,9 @@ device_t *video_card_getdevice(int card, int romset)
case ROM_IBMPS1_2121:
return &ps1_m2121_svga_device;
case ROM_IBMPS1_2133_451:
return &gd5426_ps1_device;
case ROM_T3100E:
return &t3100e_device;
@ -372,7 +375,8 @@ int video_is_mda()
case ROM_IBMPS2_M70_TYPE4:
case ROM_IBMPS2_M80:
case ROM_IBMPS1_2121:
case ROM_T3100E:
case ROM_IBMPS1_2133_451:
case ROM_T3100E:
case ROM_T1000:
case ROM_ELX_PC425X:
case ROM_PB410A:
@ -421,6 +425,7 @@ int video_is_cga()
case ROM_IBMPS2_M70_TYPE4:
case ROM_IBMPS2_M80:
case ROM_IBMPS1_2121:
case ROM_IBMPS1_2133_451:
case ROM_ELX_PC425X:
case ROM_PB410A:
case ROM_PB570:
@ -460,6 +465,7 @@ int video_is_ega_vga()
case ROM_IBMPS2_M70_TYPE4:
case ROM_IBMPS2_M80:
case ROM_IBMPS1_2121:
case ROM_IBMPS1_2133_451:
case ROM_ELX_PC425X:
case ROM_PB410A:
case ROM_PB570:
@ -610,6 +616,10 @@ void video_updatetiming()
timing = &timing_ps1_svga;
break;
case ROM_IBMPS1_2133_451:
timing = &timing_pb570;
break;
case ROM_T3100E:
timing = &timing_t3100e;
break;
@ -803,6 +813,10 @@ void video_init()
device_add(&ps1_m2121_svga_device);
return;
case ROM_IBMPS1_2133_451:
device_add(&gd5426_ps1_device);
return;
case ROM_T3100E:
device_add(&t3100e_device);
return;

169
src/vl82c480.c Normal file
View file

@ -0,0 +1,169 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "vl82c480.h"
static struct
{
int cfg_index;
uint8_t cfg_regs[256];
uint8_t port_92;
} vl82c480;
#define CFG_ID 0x00
#define CFG_AAXS 0x0d
#define CFG_BAXS 0x0e
#define CFG_CAXS 0x0f
#define CFG_DAXS 0x10
#define CFG_EAXS 0x11
#define CFG_FAXS 0x12
#define ID_VL82C480 0x90
static void shadow_control(uint32_t addr, uint32_t size, int state)
{
// pclog("shadow_control: addr=%08x size=%04x state=%i\n", addr, size, state);
switch (state)
{
case 0:
mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 1:
mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 2:
mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
case 3:
mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
flushmmucache_nopc();
}
void vl82c480_write(uint16_t addr, uint8_t val, void *p)
{
// if (addr != 0x92) pclog("vl82c480_write: addr=%04x val=%02x\n", addr, val);
switch (addr)
{
case 0x92:
if ((mem_a20_alt ^ val) & 2)
{
mem_a20_alt = val & 2;
mem_a20_recalc();
}
if ((~vl82c480.port_92 & val) & 1)
{
softresetx86();
cpu_set_edx();
}
vl82c480.port_92 = val;
break;
case 0xec:
vl82c480.cfg_index = val;
break;
case 0xed:
if (vl82c480.cfg_index >= 0x01 && vl82c480.cfg_index <= 0x24)
{
vl82c480.cfg_regs[vl82c480.cfg_index] = val;
switch (vl82c480.cfg_index)
{
case CFG_AAXS:
shadow_control(0xa0000, 0x4000, val & 3);
shadow_control(0xa4000, 0x4000, (val >> 2) & 3);
shadow_control(0xa8000, 0x4000, (val >> 4) & 3);
shadow_control(0xac000, 0x4000, (val >> 6) & 3);
break;
case CFG_BAXS:
shadow_control(0xb0000, 0x4000, val & 3);
shadow_control(0xb4000, 0x4000, (val >> 2) & 3);
shadow_control(0xb8000, 0x4000, (val >> 4) & 3);
shadow_control(0xbc000, 0x4000, (val >> 6) & 3);
break;
case CFG_CAXS:
shadow_control(0xc0000, 0x4000, val & 3);
shadow_control(0xc4000, 0x4000, (val >> 2) & 3);
shadow_control(0xc8000, 0x4000, (val >> 4) & 3);
shadow_control(0xcc000, 0x4000, (val >> 6) & 3);
break;
case CFG_DAXS:
shadow_control(0xd0000, 0x4000, val & 3);
shadow_control(0xd4000, 0x4000, (val >> 2) & 3);
shadow_control(0xd8000, 0x4000, (val >> 4) & 3);
shadow_control(0xdc000, 0x4000, (val >> 6) & 3);
break;
case CFG_EAXS:
shadow_control(0xe0000, 0x4000, val & 3);
shadow_control(0xe4000, 0x4000, (val >> 2) & 3);
shadow_control(0xe8000, 0x4000, (val >> 4) & 3);
shadow_control(0xec000, 0x4000, (val >> 6) & 3);
break;
case CFG_FAXS:
shadow_control(0xf0000, 0x4000, val & 3);
shadow_control(0xf4000, 0x4000, (val >> 2) & 3);
shadow_control(0xf8000, 0x4000, (val >> 4) & 3);
shadow_control(0xfc000, 0x4000, (val >> 6) & 3);
break;
}
}
break;
case 0xee:
if (mem_a20_alt)
{
vl82c480.port_92 &= ~2;
mem_a20_alt = 0;
mem_a20_recalc();
}
break;
}
}
uint8_t vl82c480_read(uint16_t addr, void *p)
{
uint8_t ret = 0xff;
switch (addr)
{
case 0x92:
ret = vl82c480.port_92;
break;
case 0xec:
ret = vl82c480.cfg_index;
break;
case 0xed:
ret = vl82c480.cfg_regs[vl82c480.cfg_index];
break;
case 0xee:
if (!mem_a20_alt)
{
vl82c480.port_92 |= 2;
mem_a20_alt = 1;
mem_a20_recalc();
}
break;
case 0xef:
softresetx86();
cpu_set_edx();
break;
}
// pclog("vl82c480_read: addr=%04x ret=%02x\n", addr, ret);
return ret;
}
void vl82c480_init(void)
{
memset(&vl82c480, 0, sizeof(vl82c480));
vl82c480.cfg_regs[CFG_ID] = ID_VL82C480;
io_sethandler(0x0092, 0x0001, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, NULL);
io_sethandler(0x00ec, 0x0004, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, NULL);
}

1
src/vl82c480.h Normal file
View file

@ -0,0 +1 @@
void vl82c480_init(void);