Merge branch '86Box:master' into cirrus-vbios

This commit is contained in:
win2kgamer
2026-02-15 19:21:16 -06:00
committed by GitHub
2 changed files with 213 additions and 70 deletions

View File

@@ -57,6 +57,7 @@
#include <86box/plat_unused.h>
#define EMU_DEVICE_H
#include <86box/pit.h>
#include <86box/mouse.h>
// #define EPOCH_FONTROM_SIZE (1024 * 1024)
// #define EPOCH_FONTROM_MASK 0xffff
@@ -159,7 +160,8 @@ enum epoch_nvr_ADDR {
#endif
#ifdef ENABLE_EPOCH_LOG
// # define ENABLE_EPOCH_DEBUGIO 1
// #define ENABLE_EPOCH_DEBUGIO 1
// #define ENABLE_EPOCH_DEBUGKBD 1
int epoch_do_log = ENABLE_EPOCH_LOG;
static void
@@ -181,6 +183,12 @@ epoch_log(const char *fmt, ...)
#else
# define epoch_iolog(fmt, ...)
#endif
#ifdef ENABLE_EPOCH_DEBUGKBD
# define epoch_kbdlog epoch_log
#else
# define epoch_kbdlog(fmt, ...)
#endif
typedef struct epoch_t {
mem_mapping_t cmapping;
@@ -332,7 +340,7 @@ epoch_out(uint16_t addr, uint16_t val, void *priv)
case LC_START_ADDRESS_HIGH:
case LC_CURSOR_LOC_HIGH:
case LC_LIGHT_PEN_HIGH:
val &= 0x3F;
val &= 0x3F; /* this is required for the IPL BAT test */
break;
}
epoch->crtc[epoch->crtcaddr] = val;
@@ -428,7 +436,7 @@ epoch_out(uint16_t addr, uint16_t val, void *priv)
// epoch->attrc[epoch->attraddr & 0x3f] = val;
// break;
default:
epoch_iolog("epoch? Out addr %03X val %02X\n", addr, val);
// epoch_iolog("epoch? Out addr %03X val %02X\n", addr, val);
break;
}
}
@@ -482,8 +490,8 @@ epoch_in(uint16_t addr, void *priv)
if(epoch->cgastat & 8)
temp &= 0x7f;
}
temp &= 0xfe;/* equipment ? color or monochrome monitor */
// temp |= 0x01;
temp |= 0x01; /* monitor mono or !color */
// temp &= 0xfe; /* color */
break;
}
if (addr != 0x3DA)
@@ -1117,14 +1125,14 @@ static void
epoch_vram_writeb(uint32_t addr, uint8_t val, void *priv)
{
epoch_t *epoch = (epoch_t *) priv;
// epoch_log("epoch_vram_writeb: Write to %x, val %x\n", addr, val);
// epoch_log("%04X:%04X epoch_vram_writeb: %x, val %x\n", cs >> 4, cpu_state.pc, addr, val);
cycles -= video_timing_write_b;
epoch_vram_write(addr, val, epoch);
}
static void
epoch_vram_writew(uint32_t addr, uint16_t val, void *priv)
{
// epoch_log("epoch_vram_writ ew: Write to %x, val %x\n", addr, val);
// epoch_log("%04X:%04X epoch_vram_writew: %x, val %x\n", cs >> 4, cpu_state.pc, addr, val);
epoch_t *epoch = (epoch_t *) priv;
cycles -= video_timing_write_w;
epoch_vram_write(addr, val & 0xff, epoch);
@@ -1311,23 +1319,23 @@ xxxx xxx1: Memory or parity error?
break;
/*
I/O A2h R:
xxxx 0x0x: Color CRT
xxxx 0x0x: Color 16 CRT
xxxx 1x0x: Mono 24 CRT ?
xxxx xx1x: 16 pixel CRT
xxxx xx1x: Mono 16 CRT
xx1x xxxx: No hard drive
x1xx xxxx: No floppy drive
1xxx xxxx: No (bootable?) hard drive
*/
case 0xA2:
ret = 0xA8;/* Mono 24 */
// ret = 0xA8;/* Mono 16 */
// ret = 0xA2;/* Mono 16 */
break;
/*
I/O A3h R:
xxxx x001: Main RAM 256 KB?
xxxx x011: Main RAM 384 KB?
xxxx x111: Main RAM 512 KB?
xxxx x000: Main RAM 640 KB?
xxxx x111: Main RAM 256 KB
xxxx x110: Main RAM 384 KB
xxxx x100: Main RAM 512 KB
xxxx x000: Main RAM 640 KB
xxxx 1xxx: Serial port 3f8h
xxx1 xxxx: Serial port 2f8h
*/
@@ -1417,14 +1425,18 @@ typedef struct epochkbd_t {
uint8_t pa;
uint8_t pb;
uint8_t clock;
uint8_t clk_hold;
uint8_t key_waiting;
uint8_t reset_step;
uint8_t kbd_reset_step;
uint8_t mouse_reset_step;
int mouse_enabled;
int mouse_queue_num;
uint8_t mouse_queue[4];
pc_timer_t send_delay_timer;
} epochkbd_t;
static uint8_t key_queue[16];
static uint8_t key_queue[16]; /* buffer in the keyboard */
static int key_queue_start = 0;
static int key_queue_end = 0;
@@ -1435,24 +1447,33 @@ kbd_epoch_poll(void *priv)
timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC);
if (kbd->pb & 0x04)
if (kbd->pb & 0x04) /* controller is sending something to keyboard */
return;
if (!(kbd->pb & 0x08)) /* keyboard interrupt is disabled */
return;
if (kbd->want_irq) {
kbd->want_irq = 0;
kbd->pa = kbd->key_waiting;
kbd->pb &= 0xF7;
kbd->blocked = 1;
kbd->blocked = 1;
picint(EPOCH_IRQ3_BIT);
epoch_log("epochkbd: kbd_poll(): keyboard_xt : take IRQ\n");
epoch_kbdlog("epochkbd: kbd_poll(): keyboard_xt : take IRQ\n");
}
if ((key_queue_start != key_queue_end) && !kbd->blocked) {
kbd->key_waiting = key_queue[key_queue_start];
epoch_log("epochkbd: reading %02X from the key queue at %i\n",
kbd->key_waiting, key_queue_start);
key_queue_start = (key_queue_start + 1) & 0x0f;
kbd->want_irq = 1;
if (!kbd->blocked) {
if (kbd->mouse_queue_num > 0) {
kbd->mouse_queue_num--;
kbd->key_waiting = kbd->mouse_queue[kbd->mouse_queue_num];
epoch_kbdlog("epochkbd: reading %02X from the mouse queue at %i\n", kbd->key_waiting, kbd->mouse_queue_num);
kbd->want_irq = 1;
} else if (key_queue_start != key_queue_end) {
kbd->key_waiting = key_queue[key_queue_start];
epoch_kbdlog("epochkbd: reading %02X from the key queue at %i\n",
kbd->key_waiting, key_queue_start);
key_queue_start = (key_queue_start + 1) & 0x0f;
kbd->want_irq = 1;
}
}
}
@@ -1481,7 +1502,7 @@ static void
kbd_epoch_adddata(uint16_t val)
{
key_queue[key_queue_end] = val;
epoch_log("XTkbd: %02X added to key queue at %i\n",
epoch_kbdlog("epochkbd: %02X added to key queue at %i\n",
val, key_queue_end);
key_queue_end = (key_queue_end + 1) & 0x0f;
}
@@ -1493,38 +1514,58 @@ kbd_adddata_ex(uint16_t val)
kbd_epoch_adddata_process(val, kbd_epoch_adddata);
}
/*
I/O 61h W:
xxxx xxx1: ? (used by kbd interrupt in DOS)
xxxx xx1x: Beep
xxxx x1xx: Hold clock line low (used to reset kbd)
xxxx 1xxx: Enable kbd?
xxx1 xxxx: Send data from system to kbd
1xxx xxxx: Clear buffer?
*/
static void
kbd_write(uint16_t port, uint8_t val, void *priv)
{
epochkbd_t *kbd = (epochkbd_t *) priv;
uint8_t new_clock;
epoch_log("%04X:%04X epochkbd: Port %04X out: %02X\n", cs >> 4, cpu_state.pc, port, val);
uint8_t new_clock;
epoch_kbdlog("%04X:%04X epochkbd: Port %02X out: %02X BX: %04x", cs >> 4, cpu_state.pc, port, val, BX);
epoch_kbdlog(" Clk: %x %x\n", kbd->blocked, kbd->clk_hold);
switch (port) {
case 0x60: /* Diagnostic Output */
if ((kbd->pb & 0x10) && ((val & 0xf0) == 0xd0)) {
kbd->mouse_enabled = 1;
epoch_kbdlog("epochkbd: Mouse is enabled.\n");
}
break;
case 0x61: /* Keyboard Control Register (aka Port B) */
if (val & 0x08) {
kbd->pb = val;
if ((val & 0x18) == 0x08) {
new_clock = !(val & 0x04);
if (kbd->clock && new_clock) {
/* Trigger kbd reset after the clk line is reset to a high level */
if (kbd->clk_hold && new_clock) {
key_queue_start = key_queue_end = 0;
kbd->want_irq = 0;
kbd->blocked = 0;
kbd->reset_step = 0;
/* Specific 5556 keyboards send three bytes of identification code,
but this simply sends AAh that can pass the IPL and DOS K3.4 init. */
kbd_epoch_adddata(0xaa);
} else if (!(kbd->pb & 0x08)) {
kbd->pa = 0;
kbd->blocked = 0;
kbd->kbd_reset_step = 0;
kbd->clk_hold = 0;
kbd->mouse_enabled = 0;
kbd->mouse_queue_num = 0;
epoch_kbdlog("epochkbd: Starting keyboard reset sequence.\n");
}
} else if ((val & 0x18) == 0x18) {
new_clock = !(val & 0x04);
if (kbd->clk_hold && new_clock) {
kbd->mouse_reset_step = 0;
epoch_kbdlog("epochkbd: Starting mouse reset sequence.\n");
}
}
kbd->pb = val;
if (kbd->pb & 0x08)
kbd->clock = !!(kbd->pb & 0x04);
ppi.pb = val;
kbd->clk_hold = !!(kbd->pb & 0x04);
timer_process();
speaker_update();
speaker_gated = val & 2;
@@ -1534,18 +1575,31 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
was_speaker_enable = 1;
pit_devs[0].set_gate(pit_devs[0].data, TIMER_CTR_2, val & 2);
break;
if (val & 0x80) {
/* clear buffer */
kbd->pa = 0;
kbd->blocked = 0;
/* IRQ will be cleared by the software */
// picintc(EPOCH_IRQ3_BIT);
}
break;
default:
break;
}
}
/*
I/O 61h R
xxxx xx1x: Beep input?
xxxx x1xx: KB -CLK?
xxxx 1xxx: KB -DATA?
*/
static uint8_t
kbd_read(uint16_t port, void *priv)
{
epochkbd_t *kbd = (epochkbd_t *) priv;
uint8_t ret = 0xff;
uint8_t ret = 0;
switch (port) {
case 0x60: /* Keyboard Data Register (aka Port A) */
@@ -1553,36 +1607,50 @@ kbd_read(uint16_t port, void *priv)
break;
case 0x61: /* Keyboard Control Register (aka Port B) */
/* Bit 3 and 2: Keyboard Data and Clk line ? */
if (kbd->reset_step < 18) {
ret = kbd->pb & 0xf0; /* reset sense bit */
ret |= 0x0c; /* reset sense bit */
if (kbd->kbd_reset_step < 18) {
ret &= 0xf3;
if (kbd->reset_step & 1)
if (!!(kbd->kbd_reset_step & 1))
ret |= 0x04;
switch (kbd->reset_step) { /* AAh (1010 1010) in serial data */
case 3:
case 7:
case 11:
case 15:
ret |= 0x00;
break;
default:
switch (kbd->kbd_reset_step >> 1) { /* AAh (0 1010 1010) in serial data */
case 0:
case 2:
case 4:
case 6:
case 8:
ret |= 0x08;
break;
default:
ret |= 0x00;
break;
}
kbd->reset_step += 1;
epoch_kbdlog(" reset step: %d %x %x", kbd->kbd_reset_step, ret & 0x08, ret & 0x04);
epoch_kbdlog(" Clk: %x %x\n", kbd->blocked, kbd->clk_hold);
kbd->kbd_reset_step++;
/* Specific 5556 keyboards send three bytes of identification code,
but this simply sends AAh that can pass the IPL and DOS K3.4 init. */
if (kbd->kbd_reset_step == 18)
kbd_epoch_adddata(0xaa);
} else if (kbd->mouse_reset_step < 20) {
ret &= 0xf3;
if (!!(kbd->mouse_reset_step & 1))
ret |= 0x04;
epoch_kbdlog(" reset step: %d %x %x\n", kbd->mouse_reset_step, ret & 0x08, ret & 0x04);
kbd->mouse_reset_step++;
}
/* Bit 1: Timer 2 (Speaker) out state */
if (pit_devs[0].get_outlevel(pit_devs[0].data, TIMER_CTR_2) && speaker_enable)
ret &= 0xfd;/* 1111 1101 */
if (pit_devs[0].get_outlevel(pit_devs[0].data, TIMER_CTR_2) && speaker_enable)
ret &= 0xfd; /* 1111 1101 */
else
ret |= 0x02;
break;
break;
default:
break;
}
// epoch_log("%04X:%04X epochkbd: Port %04X in : %02X BX:%04x\n", cs >> 4, cpu_state.pc, port, ret, BX);
epoch_kbdlog("%04X:%04X epochkbd: Port %02X in : %02X pb: %02x CX: %04x\n", cs >> 4, cpu_state.pc, port, ret, kbd->pb, CX);
return ret;
}
@@ -1595,11 +1663,17 @@ kbd_reset(void *priv)
kbd->blocked = 0;
kbd->pa = 0x00;
kbd->pb = 0x00;
kbd->kbd_reset_step = 0xff;
kbd->mouse_reset_step = 0xff;
keyboard_scan = 1;
key_queue_start = 0;
key_queue_end = 0;
kbd->mouse_enabled = 0;
kbd->mouse_queue_num = 0;
kbd_epoch_adddata(0xaa);
}
static void *
@@ -1614,8 +1688,6 @@ kbd_init(const device_t *info)
keyboard_send = kbd_adddata_ex;
kbd_reset(kbd);
key_queue_start = key_queue_end = 0;
timer_add(&kbd->send_delay_timer, kbd_epoch_poll, kbd, 1);
keyboard_set_table(scancode_set8a);
@@ -1634,7 +1706,6 @@ kbd_close(void *priv)
/* Disable scanning. */
keyboard_scan = 0;
keyboard_send = NULL;
io_removehandler(0x0060, 2,
@@ -1657,6 +1728,71 @@ static const device_t kbc_epoch_device = {
.config = NULL
};
/*
The IBM 5550 DOS K3.44 comes with a mouse driver
for the M1 and P1 keyboards that have a built-in mouse adapter.
The mouse adapter for the expansion slot was also available,
but it may require the bundled driver. (not confirmed)
IBM 5550 DOS K3.4 Mouse Driver (Int 0Bh and 33h)
61h <- 1st kbd indata
[si+4Ch] status <- 2nd kbd indata
1xxx xxxx negative dX
x1xx xxxx bit 9 of dX
xx1x xxxx negative dY
xxx1 xxxx bit 9 of dY
xxxx x1xx cursor moved
xxxx xx1x right button
xxxx xxx1 left button
[si+4Dh] previous button status <- [si+4Ch]
[si+4Eh] dX <- 3rd kbd indata
[si+50h] dY <- 4th kbd indata
*/
static int
epoch_mouse_poll(void *priv)
{
epochkbd_t *kbd = (epochkbd_t *) priv;
int dat = mouse_get_buttons_ex();
int dx, dy;
if (!kbd->mouse_enabled)
return 0;
if (kbd->mouse_queue_num > 0)
return 0;
if (kbd->pb & 0x10)
return 0;
dat &= 0x03;
if (!mouse_moved()) {
kbd->mouse_queue[1] = 0x61;
kbd->mouse_queue[0] = dat;
kbd->mouse_queue_num = 2;
} else {
dat |= 0x04;
mouse_subtract_x(&dx, NULL, -512, 511, 0);
mouse_clear_x();
if (dx < 0)
dat |= 0x20;
if (dx & 0x100)
dat |= 0x10;
mouse_subtract_y(&dy, NULL, -512, 511, 0, 0);
mouse_clear_y();
if (dy < 0)
dat |= 0x80;
if (dy & 0x100)
dat |= 0x40;
epoch_log("Mouse moved %x %x %x\n", dat, dx, dy);
kbd->mouse_queue[3] = 0x61;
kbd->mouse_queue[2] = dat;
kbd->mouse_queue[1] = dx & 0xff;
kbd->mouse_queue[0] = dy & 0xff;
kbd->mouse_queue_num = 4;
}
return 0;
}
static void
epoch_nvr_time_set(uint8_t *regs, struct tm *tm)
{
@@ -1940,7 +2076,7 @@ epoch_init(UNUSED(const device_t *info))
epoch->vram = calloc(1, 256* 1024);
epoch->cram = calloc(1, 4 * 1024);
// epoch->fontcard.rom = calloc(1, EPOCH_FONTROM_SIZE);
//epoch_video_load_font("roms/machines/ibm5550/GEN1FONT.BIN", epoch);
// epoch_video_load_font("roms/machines/ibm5550/GEN1FONT.BIN", epoch);
epoch->epochconst = (uint64_t) ((cpuclock / EPOCH_PIXELCLOCK) * (double) (1ull << 32));
@@ -1963,7 +2099,7 @@ epoch_init(UNUSED(const device_t *info))
io_sethandler(0x44, 0x0001,
epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch);
io_sethandler(0xA0, 0x0005,
io_sethandler(0xA0, 0x0006,
epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch);
io_sethandler(0x310, 0x0008,
epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch);
@@ -2051,7 +2187,7 @@ epoch_force_redraw(void *priv)
}
static const device_t epoch_device = {
.name = "IBM 5550 Video Controller (Epoch)",
.name = "IBM 5550 (Epoch) Video Controller",
.internal_name = "ibm5550vid",
.flags = DEVICE_ISA,
.local = 0,
@@ -2115,7 +2251,7 @@ machine_xt_ibm5550_init(const machine_t *model)
device_add(&fdc_xt_5550_device);
device_add(&kbc_epoch_device);
epochkbd_t *kbc = device_add(&kbc_epoch_device);
pic_init();
dma_init();
@@ -2128,5 +2264,12 @@ machine_xt_ibm5550_init(const machine_t *model)
serial_t *uart = device_add(&ns8250_device);
serial_setup(uart, 0x3f8, 1);/* Use IRQ 1 */
if (mouse_type == MOUSE_TYPE_INTERNAL) {
/* Tell mouse driver about our internal mouse. */
mouse_reset();
mouse_set_buttons(2);
mouse_set_poll(epoch_mouse_poll, kbc);
}
return ret;
}

View File

@@ -2710,7 +2710,7 @@ const machine_t machines[] = {
.max_multi = 0
},
.bus_flags = MACHINE_PC,
.flags = MACHINE_VIDEO_FIXED | MACHINE_KEYBOARD,
.flags = MACHINE_VIDEO_FIXED | MACHINE_FDC | MACHINE_KEYBOARD | MACHINE_MOUSE,
.ram = {
.min = 256,
.max = 640,