Merge pull request #6788 from akmed772/master

Add IBM Multistation 5550 (1983) machine
This commit is contained in:
Miran Grča
2026-02-08 20:49:56 +01:00
committed by GitHub
13 changed files with 2339 additions and 7 deletions

View File

@@ -4758,7 +4758,7 @@ static const scancode scancode_set82[512] = {
// clang-format on
};
/* Scancode set 8Ah : IBM 5556 keyboard compatible scancode set used by J-DOS */
static scancode scancode_set8a[512] =
const scancode scancode_set8a[512] =
{
// clang-format off
{.mk = { 0 }, .brk = { 0 } }, /* 000 */
@@ -4817,7 +4817,7 @@ static scancode scancode_set8a[512] =
{.mk = { 0x0a, 0 }, .brk = { 0 } }, /* 035 */
{.mk = { 0x39, 0 }, .brk = { 0xb9, 0 } }, /* 036 RSHIFT */
{.mk = { 0x64, 0 }, .brk = { 0 } }, /* 037 * (asterisk) */
{.mk = { 0x3A, 0 }, .brk = { 0xba, 0 } }, /* 038 0x3A LALT = Kanji */
{.mk = { 0x3a, 0 }, .brk = { 0xba, 0 } }, /* 038 0x3A LALT = Kanji */
{.mk = { 0x34, 0 }, .brk = { 0 } }, /* 039 */
{.mk = { 0x32, 0 }, .brk = { 0xb2, 0 } }, /* 03a CAPSLOCK */
{.mk = { 0x68, 0 }, .brk = { 0 } }, /* 03b F1 */

View File

@@ -195,6 +195,8 @@ postcard_init(UNUSED(const device_t *info))
postcard_port = 0x190; /* ISA PS/2 machines */
else if (strstr(machines[machine].name, " IBM XT "))
postcard_port = 0x60; /* IBM XT */
else if (strstr(machines[machine].name, " Multistation "))
postcard_port = 0xA1; /* IBM 5550 */
else if (strstr(machines[machine].name, " IBM PCjr")) {
postcard_port = 0x10; /* IBM PCjr */
postcard_ports_num = 3; /* IBM PCjr error ports 11h and 12h */

View File

@@ -978,10 +978,15 @@ dma_page_write(uint16_t addr, uint8_t val, UNUSED(void *priv))
addr &= 0x0f;
dmaregs[2][addr] = val;
if (addr >= 8)
addr = convert[addr & 0x07] | 4;
else
addr = convert[addr & 0x07];
if (machines[machine].init == machine_xt_ibm5550_init) {
if (addr >= 4)
addr = 8;
} else {
if (addr >= 8)
addr = convert[addr & 0x07] | 4;
else
addr = convert[addr & 0x07];
}
if (addr < 8) {
dma[addr].page_l = val;

View File

@@ -664,6 +664,21 @@ real_drive(fdc_t *fdc, int drive)
return drive;
}
void
fdc_diskchange_interrupt(fdc_t *fdc, int drive)
{
/*
For the IBM 5550 machine to detect the disk in the drive has been changed.
A hardware interrupt is caused by the FDC (NEC uPD765A) when the Ready line from the drive changes its state.
Other PCs never use the Ready line.
*/
if (fdc->flags & FDC_FLAG_5550) {
fdc->st0 = 0xc0 | (drive & 3);
fdc_int(fdc, 1);
fdd_changed[drive] = 0;
}
}
/* FDD notifies FDC when seek operation is complete */
void
fdc_seek_complete_interrupt(fdc_t *fdc, int drive)
@@ -822,8 +837,47 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
case 0:
return;
case 1:
if (fdc->flags & FDC_FLAG_5550) {
val = 0;
if (!(val & 0x08)) { /* Drive 2 active */
val = 0x42;
}
if (!(val & 0x04)) { /* Drive 1 active */
val &= 0xf0;
val |= 0x21;
}
if (!(val & 0x02)) { /* Drive 0 active */
val &= 0xf0;
val |= 0x10;
}
/* Update the DOR because this emulation module depend on it */
fdc->dor &= 0x0c;
fdc->dor |= val;
/* We can now simplify this since each motor now spins separately. */
for (int i = 0; i < FDD_NUM; i++) {
drive_num = real_drive(fdc, i);
if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM))
val &= ~(0x10 << drive_num);
else
fdd_set_motor_enable(i, (val & (0x10 << drive_num)));
}
drive_num = real_drive(fdc, val & 0x03);
current_drive = drive_num;
fdc->st0 = (fdc->st0 & 0xf8) | (val & 0x03) | (fdd_get_head(drive_num) ? 4 : 0);
fdc_log("val:%x, dor=%x, drv=%x\n", val, fdc->dor, drive_num);
}
return;
case 2: /*DOR*/
if (fdc->flags & FDC_FLAG_5550) { /* Reset */
fdd_stop(fdc->drive);
for (int i = 0; i < FDD_NUM; i++)
fdd_set_motor_enable(i, 0); /* Need to restart fdd timer */
fdc->stat = 0x00;
fdc->pnum = fdc->ptot = 0;
fdc_soft_reset(fdc);
fdc->dor = 0x0c;
return;
}
if (fdc->flags & FDC_FLAG_PCJR) {
if ((fdc->dor & 0x40) && !(val & 0x40)) {
timer_set_delay_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC);
@@ -903,6 +957,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
}
return;
case 4: /* DSR */
if (fdc->flags & FDC_FLAG_5550)
picintc(1 << fdc->irq);
if (!(fdc->flags & FDC_FLAG_NO_DSR_RESET)) {
if (!(val & 0x80)) {
timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC);
@@ -914,6 +970,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
fdc->dsr = val;
return;
case 5: /*Command register*/
if (fdc->flags & FDC_FLAG_5550)
picintc(1 << fdc->irq);
if (fdc->fifointest) {
/* Write FIFO buffer in the test mode (PS/55) */
fdc_log("FIFO buffer position = %X\n", ((fifo_t *) fdc->fifo_p)->end);
@@ -948,7 +1006,33 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
fdc->command = val;
fdc->stat |= 0x10;
fdc_log("Starting FDC command %02X\n", fdc->command);
fdc_log("Starting FDC command %02X ", fdc->command);
switch (fdc->command & 0x1f) {
case 0x06:
fdc_log("READ DATA\n");
break;
case 0x0a:
fdc_log("READ ID\n");
break;
case 0x07:
fdc_log("RECALIB\n");
break;
case 0x08:
fdc_log("SENSE INTERRUPT\n");
break;
case 0x03:
fdc_log("SPECIFY\n");
break;
case 0x04:
fdc_log("SENSE DRIVE\n");
break;
case 0x0f:
fdc_log("SEEK\n");
break;
default:
fdc_log("\n");
break;
}
fdc->error = 0;
if (((fdc->command & 0x1f) == 0x02) || ((fdc->command & 0x1f) == 0x05) ||
@@ -1106,6 +1190,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
if (command_has_drivesel[fdc->command & 0x1F]) {
if (fdc->flags & FDC_FLAG_PCJR)
fdc->drive = 0;
else if (fdc->flags & FDC_FLAG_5550)
fdc->drive = fdc->params[0] & 3;
else
fdc->drive = fdc->dor & 3;
fdc->rw_drive = fdc->params[0] & 3;
@@ -1115,6 +1201,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
}
if (fdc->pnum == fdc->ptot) {
fdc_log("Got all params %02X\n", fdc->command);
for (int i = 0; i < fdc->ptot; i++)
fdc_log(" [%d] %02x\n", i, fdc->params[i]);
fifo_reset(fdc->fifo_p);
fdc->interrupt = fdc->processed_cmd;
fdc->reset_stat = 0;
@@ -1451,6 +1539,8 @@ fdc_read(uint16_t addr, void *priv)
ret = 0xc0;
ret |= (fdc->dor & 0x01) << 5; /* Drive Select 0 */
ret |= (fdc->dor & 0x30) >> 4; /* Motor Select 1, 0 */
} else if (fdc->flags & FDC_FLAG_5550) {
ret = 0;
} else {
if (is486 || !fdc->enable_3f1)
ret = 0xff;
@@ -1503,9 +1593,13 @@ fdc_read(uint16_t addr, void *priv)
ret = (fdc->rwc[drive] << 4) | (fdc->media_id << 6);
break;
case 4: /*Status*/
if (fdc->flags & FDC_FLAG_5550)
picintc(1 << fdc->irq);
ret = fdc->stat;
break;
case 5: /*Data*/
if (fdc->flags & FDC_FLAG_5550)
picintc(1 << fdc->irq);
if (fdc->fifointest) {
/* Read FIFO buffer in the test mode (PS/55) */
ret = fifo_read(fdc->fifo_p);
@@ -1733,6 +1827,8 @@ fdc_callback(void *priv)
}
if (writeprot[fdc->drive])
fdc->res[10] |= 0x40;
if ((fdc->flags & FDC_FLAG_5550) && drive_empty[fdc->drive])//IBM 5550
fdc->res[10] &= 0xdf; /* Set Not Ready */
fdc->stat = (fdc->stat & 0xf) | 0xd0;
fdc->paramstogo = 1;
@@ -2349,6 +2445,10 @@ fdc_set_base(fdc_t *fdc, int base)
if (fdc->flags & FDC_FLAG_NSC) {
io_sethandler(base + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
} else if (fdc->flags & FDC_FLAG_5550) {
io_sethandler(base, 0x0003, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc);
io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
} else {
if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) {
io_sethandler(base + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
@@ -2383,6 +2483,10 @@ fdc_remove(fdc_t *fdc)
if (fdc->flags & FDC_FLAG_NSC) {
io_removehandler(fdc->base_address + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
} else if (fdc->flags & FDC_FLAG_5550) {
io_removehandler(fdc->base_address, 0x0003, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_removehandler(fdc->base_address + 4, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc);
io_removehandler(fdc->base_address + 5, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
} else {
if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) {
io_removehandler(fdc->base_address + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
@@ -2534,6 +2638,8 @@ fdc_init(const device_t *info)
fdc->irq = FDC_TERTIARY_IRQ;
else if (fdc->flags & FDC_FLAG_QUA)
fdc->irq = FDC_QUATERNARY_IRQ;
else if (fdc->flags & FDC_FLAG_5550)
fdc->irq = 4;
else
fdc->irq = FDC_PRIMARY_IRQ;
@@ -2686,6 +2792,20 @@ const device_t fdc_xt_umc_um8398_device = {
.config = NULL
};
const device_t fdc_xt_5550_device = {
.name = "IBM 5550 Floppy Drive Controller",
.internal_name = "fdc_xt_5550",
.flags = 0,
.local = FDC_FLAG_5550,
.init = fdc_init,
.close = fdc_close,
.reset = fdc_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t fdc_pcjr_device = {
.name = "PCjr Floppy Drive Controller",
.internal_name = "fdc_pcjr",

View File

@@ -777,6 +777,10 @@ fdd_poll(void *priv)
if (!fdd_notfound)
fdc_noidam(fdd_fdc);
}
if (fdd_changed[drive]) {
fdc_diskchange_interrupt(fdd_fdc, drive);
}
}
int

View File

@@ -59,6 +59,7 @@
#define FDC_FLAG_TER 0x40000 /* Is Tertiary */
#define FDC_FLAG_QUA 0x80000 /* Is Quaternary */
#define FDC_FLAG_SMC661 0x100000 /* SM(s)C FDC37C661 - different TDR enhanced mode */
#define FDC_FLAG_5550 0x200000 /* IBM Multistation 5550 */
typedef struct fdc_t {
uint8_t dor;
@@ -252,6 +253,7 @@ extern void fdc_reset(void *priv);
extern uint8_t fdc_get_current_drive(void);
extern void fdc_seek_complete_interrupt(fdc_t *fdc, int drive);
extern void fdc_diskchange_interrupt(fdc_t *fdc, int drive);
#ifdef EMU_DEVICE_H
extern const device_t fdc_xt_device;
@@ -262,6 +264,7 @@ extern const device_t fdc_xt_t1x00_device;
extern const device_t fdc_xt_tandy_device;
extern const device_t fdc_xt_amstrad_device;
extern const device_t fdc_xt_umc_um8398_device;
extern const device_t fdc_xt_5550_device;
extern const device_t fdc_pcjr_device;
extern const device_t fdc_at_device;
extern const device_t fdc_at_sec_device;

View File

@@ -170,6 +170,7 @@ extern void kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val));
extern void kbd_adddata_process_10x(uint16_t val, void (*adddata)(uint16_t val));
extern const scancode scancode_xt[512];
extern const scancode scancode_set8a[512];
extern uint8_t keyboard_set3_flags[512];
extern uint8_t keyboard_set3_all_repeat;

View File

@@ -1511,6 +1511,10 @@ extern int machine_xt_iskra3104_init(const machine_t *);
extern int machine_xt_lxt3_init(const machine_t *);
extern int machine_xt_compaq_deskpro_init(const machine_t *);
/* m_xt_ibm5550.c */
extern int machine_xt_ibm5550_init(const machine_t *);
/* m_xt_t1000.c */
#ifdef EMU_DEVICE_H
extern const device_t t1000_video_device;

View File

@@ -90,6 +90,8 @@ typedef struct pit_intf_t {
void (*write)(uint16_t addr, uint8_t val, void *priv);
/* Gets a counter's count. */
uint16_t (*get_count)(void *data, int counter_id);
/* Gets a counter's out. */
int (*get_outlevel)(void *data, int counter_id);
/* Sets a counter's GATE input. */
void (*set_gate)(void *data, int counter_id, int gate);
/* Sets if a counter's CLOCK input is from the timer or not - used by PCjr. */

View File

@@ -26,6 +26,7 @@ add_library(mch OBJECT
m_europc.c
m_elt.c
m_xt_olivetti.c
m_xt_ibm5550.c
m_tandy.c
m_v86p.c
m_at_t3100e.c

2132
src/machine/m_xt_ibm5550.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3033,6 +3033,49 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
{
.name = "[8086] IBM Multistation 5550",
.internal_name = "ibm5550",
.type = MACHINE_TYPE_8086,
.chipset = MACHINE_CHIPSET_DISCRETE,
.init = machine_xt_ibm5550_init,
.p1_handler = NULL,
.gpio_handler = NULL,
.available_flag = MACHINE_AVAILABLE,
.gpio_acpi_handler = NULL,
.cpu = {
.package = CPU_PKG_8086,
.block = CPU_BLOCK_NONE,
.min_bus = 0,
.max_bus = 0,
.min_voltage = 0,
.max_voltage = 0,
.min_multi = 0,
.max_multi = 0
},
.bus_flags = MACHINE_PC,
.flags = MACHINE_VIDEO_FIXED | MACHINE_KEYBOARD,
.ram = {
.min = 256,
.max = 640,
.step = 128
},
.nvrmask = 15,
.jumpered_ecp_dma = 0,
.default_jumpered_ecp_dma = -1,
.kbc_device = NULL,
.kbc_params = 0x00000000,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = NULL,
.kbd_device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* 286 AT machines */
/* Has IBM AT KBC firmware. */

View File

@@ -420,6 +420,15 @@ pit_ctr_get_count(void *data, int counter_id)
return (uint16_t) ctr->l;
}
int
pit_ctr_get_outlevel(void *data, int counter_id)
{
const pit_t *pit = (pit_t *) data;
const ctr_t *ctr = &pit->counters[counter_id];
return (int) ctr->out;
}
void
pit_ctr_set_load_func(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count))
{
@@ -1208,6 +1217,11 @@ pit_set_clock(uint32_t clock)
CGACONST = (uint64_t) ((cpuclock / (157500000.0 / 88.0)) * (double) (1ULL << 32));
#endif
}
if (machines[machine].init == machine_xt_ibm5550_init) {
PITCONSTD = (cpuclock / 2000000.0); /* CLK input 2.0 MHz */
PITCONST = (uint64_t) (PITCONSTD * (double) (1ULL << 32));
}
ISACONST = (1ULL << 32ULL);
}
@@ -1263,6 +1277,7 @@ const pit_intf_t pit_classic_intf = {
.read = &pit_read,
.write = &pit_write,
.get_count = &pit_ctr_get_count,
.get_outlevel = &pit_ctr_get_outlevel,
.set_gate = &pit_ctr_set_gate,
.set_using_timer = &pit_ctr_set_using_timer,
.set_out_func = &pit_ctr_set_out_func,