diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c
index 00146c90e..2e2f74305 100644
--- a/src/chipset/ali1543.c
+++ b/src/chipset/ali1543.c
@@ -906,6 +906,7 @@ ali5237_write(int func, int addr, uint8_t val, void *priv)
case 0x0c: /* Cache Line Size */
case 0x0d: /* Latency Timer */
+ dev->usb_conf[addr] = val;
break;
case 0x3c: /* Interrupt Line Register */
@@ -1430,14 +1431,14 @@ ali7101_read(int func, int addr, void *priv)
}
static void
-ali5237_usb_raise_interrupt(usb_t* usb, void *priv)
+ali5237_usb_update_interrupt(usb_t* usb, void *priv)
{
ali1543_t *dev = (ali1543_t *) priv;
- if (!dev->usb_dev_enable)
- return;
-
- pci_set_irq(dev->usb_slot, PCI_INTA);
+ if (usb->irq_level)
+ pci_set_mirq(4, !!(dev->pci_conf[0x74] & 0x10));
+ else
+ pci_clear_mirq(4, !!(dev->pci_conf[0x74] & 0x10));
}
static void
@@ -1590,10 +1591,10 @@ ali1543_init(const device_t *info)
dev->smbus = device_add(&ali7101_smbus_device);
/* USB */
- dev->usb_params.parent_priv = dev;
- dev->usb_params.smi_handle = NULL;
- dev->usb_params.raise_interrupt = ali5237_usb_raise_interrupt;
- dev->usb = device_add_parameters(&usb_device, &dev->usb_params);
+ dev->usb_params.parent_priv = dev;
+ dev->usb_params.smi_handle = NULL;
+ dev->usb_params.update_interrupt = ali5237_usb_update_interrupt;
+ dev->usb = device_add_parameters(&usb_device, &dev->usb_params);
dev->type = info->local & 0xff;
dev->offset = (info->local >> 8) & 0x7f;
diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c
index c6cfe8c9f..470978611 100644
--- a/src/chipset/intel_piix.c
+++ b/src/chipset/intel_piix.c
@@ -1427,11 +1427,14 @@ piix_fast_off_count(void *priv)
}
static void
-piix_usb_raise_interrupt(usb_t* usb, void *priv)
+piix_usb_update_interrupt(usb_t* usb, void *priv)
{
piix_t *dev = (piix_t *) priv;
- pci_set_irq(dev->pci_slot, PCI_INTD);
+ if (usb->irq_level)
+ pci_set_irq(dev->pci_slot, PCI_INTD);
+ else
+ pci_clear_irq(dev->pci_slot, PCI_INTD);
}
static void
@@ -1579,10 +1582,10 @@ piix_init(const device_t *info)
}
if (dev->type >= 3) {
- dev->usb_params.parent_priv = dev;
- dev->usb_params.smi_handle = NULL;
- dev->usb_params.raise_interrupt = piix_usb_raise_interrupt;
- dev->usb = device_add_parameters(&usb_device, &dev->usb_params);
+ dev->usb_params.parent_priv = dev;
+ dev->usb_params.smi_handle = NULL;
+ dev->usb_params.update_interrupt = piix_usb_update_interrupt;
+ dev->usb = device_add_parameters(&usb_device, &dev->usb_params);
}
if (dev->type > 3) {
diff --git a/src/chipset/sis_5571.c b/src/chipset/sis_5571.c
index aa8ea62f3..c158e2d63 100644
--- a/src/chipset/sis_5571.c
+++ b/src/chipset/sis_5571.c
@@ -641,7 +641,7 @@ pci_isa_bridge_read(int func, int addr, void *priv)
}
static void
-sis_5571_usb_raise_interrupt(usb_t* usb, void* priv)
+sis_5571_usb_update_interrupt(usb_t* usb, void* priv)
{
sis_5571_t *dev = (sis_5571_t *) priv;
@@ -655,11 +655,17 @@ sis_5571_usb_raise_interrupt(usb_t* usb, void* priv)
case 0x0d:
break;
default:
- picint(1 << dev->pci_conf_sb[0][0x68] & 0x0F);
+ if (usb->irq_level)
+ picint(1 << dev->pci_conf_sb[0][0x68] & 0x0f);
+ else
+ picintc(1 << dev->pci_conf_sb[0][0x68] & 0x0f);
break;
}
} else {
- pci_set_irq(dev->sb_pci_slot, PCI_INTA);
+ if (usb->irq_level)
+ pci_set_irq(dev->sb_pci_slot, PCI_INTA);
+ else
+ pci_clear_irq(dev->sb_pci_slot, PCI_INTA);
}
}
@@ -754,10 +760,10 @@ sis_5571_init(const device_t *info)
dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2);
/* USB */
- dev->usb_params.parent_priv = dev;
- dev->usb_params.raise_interrupt = sis_5571_usb_raise_interrupt;
- dev->usb_params.smi_handle = sis_5571_usb_handle_smi;
- dev->usb = device_add_parameters(&usb_device, &dev->usb_params);
+ dev->usb_params.parent_priv = dev;
+ dev->usb_params.update_interrupt = sis_5571_usb_update_interrupt;
+ dev->usb_params.smi_handle = sis_5571_usb_handle_smi;
+ dev->usb = device_add_parameters(&usb_device, &dev->usb_params);
sis_5571_reset(dev);
diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c
index 84720f802..2e4b045f2 100644
--- a/src/chipset/stpc.c
+++ b/src/chipset/stpc.c
@@ -875,11 +875,14 @@ stpc_setup(stpc_t *dev)
}
static void
-stpc_usb_raise_interrupt(usb_t* usb, void* priv)
+stpc_usb_update_interrupt(usb_t* usb, void* priv)
{
stpc_t *dev = (stpc_t *) priv;
- pci_set_irq(dev->usb_slot, PCI_INTA);
+ if (usb->irq_level)
+ pci_set_irq(dev->usb_slot, PCI_INTA);
+ else
+ pci_clear_irq(dev->usb_slot, PCI_INTA);
}
static void
@@ -907,9 +910,9 @@ stpc_init(const device_t *info)
pci_add_card(PCI_ADD_NORTHBRIDGE, stpc_nb_read, stpc_nb_write, dev);
dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_isab_read, stpc_isab_write, dev);
if (dev->local == STPC_ATLAS) {
- dev->usb_params.smi_handle = NULL;
- dev->usb_params.raise_interrupt = stpc_usb_raise_interrupt;
- dev->usb_params.parent_priv = dev;
+ dev->usb_params.smi_handle = NULL;
+ dev->usb_params.update_interrupt = stpc_usb_update_interrupt;
+ dev->usb_params.parent_priv = dev;
dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_ide_read, stpc_ide_write, dev);
dev->usb = device_add_parameters(&usb_device, &dev->usb_params);
diff --git a/src/device/keyboard_at - Cópia.c b/src/device/keyboard_at - Cópia.c
new file mode 100644
index 000000000..3a841ad91
--- /dev/null
+++ b/src/device/keyboard_at - Cópia.c
@@ -0,0 +1,3258 @@
+/*
+ * 86Box A hypervisor and IBM PC system emulator that specializes in
+ * running old operating systems and software designed for IBM
+ * PC systems and compatibles from 1981 through fairly recent
+ * system designs based on the PCI bus.
+ *
+ * This file is part of the 86Box distribution.
+ *
+ * Intel 8042 (AT keyboard controller) emulation.
+ *
+ *
+ *
+ * Authors: Sarah Walker,
+ * Miran Grca,
+ * Fred N. van Kempen,
+ * EngiNerd,
+ *
+ * Copyright 2008-2020 Sarah Walker.
+ * Copyright 2016-2020 Miran Grca.
+ * Copyright 2017-2020 Fred N. van Kempen.
+ * Copyright 2020 EngiNerd.
+ */
+#include
+#include
+#include
+#include
+#include
+#define HAVE_STDARG_H
+#include
+#include <86box/86box.h>
+#include "cpu.h"
+#include <86box/timer.h>
+#include <86box/io.h>
+#include <86box/pic.h>
+#include <86box/pit.h>
+#include <86box/ppi.h>
+#include <86box/mem.h>
+#include <86box/device.h>
+#include <86box/machine.h>
+#include <86box/m_at_t3100e.h>
+#include <86box/fdd.h>
+#include <86box/fdc.h>
+#include <86box/sound.h>
+#include <86box/snd_speaker.h>
+#include <86box/video.h>
+#include <86box/keyboard.h>
+
+#define STAT_PARITY 0x80
+#define STAT_RTIMEOUT 0x40
+#define STAT_TTIMEOUT 0x20
+#define STAT_MFULL 0x20
+#define STAT_UNLOCKED 0x10
+#define STAT_CD 0x08
+#define STAT_SYSFLAG 0x04
+#define STAT_IFULL 0x02
+#define STAT_OFULL 0x01
+
+#define CCB_UNUSED 0x80
+#define CCB_TRANSLATE 0x40
+#define CCB_PCMODE 0x20
+#define CCB_ENABLEKBD 0x10
+#define CCB_IGNORELOCK 0x08
+#define CCB_SYSTEM 0x04
+#define CCB_ENABLEMINT 0x02
+#define CCB_ENABLEKINT 0x01
+
+#define CCB_MASK 0x68
+#define MODE_MASK 0x6c
+
+#define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */
+#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */
+#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */
+#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */
+#define KBC_TYPE_MASK 0x03
+
+#define KBC_VEN_GENERIC 0x00
+#define KBC_VEN_AMI 0x04
+#define KBC_VEN_IBM_MCA 0x08
+#define KBC_VEN_QUADTEL 0x0c
+#define KBC_VEN_TOSHIBA 0x10
+#define KBC_VEN_IBM_PS1 0x14
+#define KBC_VEN_ACER 0x18
+#define KBC_VEN_INTEL_AMI 0x1c
+#define KBC_VEN_OLIVETTI 0x20
+#define KBC_VEN_NCR 0x24
+#define KBC_VEN_PHOENIX 0x28
+#define KBC_VEN_ALI 0x2c
+#define KBC_VEN_TG 0x30
+#define KBC_VEN_TG_GREEN 0x34
+#define KBC_VEN_MASK 0x3c
+
+enum {
+ KBC_STATE_RESET = 0,
+ KBC_STATE_MAIN_IBF,
+ KBC_STATE_MAIN_KBD,
+ KBC_STATE_MAIN_MOUSE,
+ KBC_STATE_MAIN_BOTH,
+ KBC_STATE_KBC_OUT,
+ KBC_STATE_KBC_PARAM,
+ KBC_STATE_SEND_KBD,
+ KBC_STATE_KBD,
+ KBC_STATE_SEND_MOUSE,
+ KBC_STATE_MOUSE
+};
+#define KBC_STATE_SCAN_KBD KBC_STATE_KBD
+#define KBC_STATE_SCAN_MOUSE KBC_STATE_MOUSE
+
+enum {
+ DEV_STATE_MAIN_1 = 0,
+ DEV_STATE_MAIN_2,
+ DEV_STATE_MAIN_CMD,
+ DEV_STATE_MAIN_OUT,
+ DEV_STATE_MAIN_WANT_IN,
+ DEV_STATE_MAIN_IN
+};
+
+typedef struct {
+ /* Controller. */
+ uint8_t pci, kbc_state, command, want60,
+ status, ib, out, old_out,
+ sc_or, secr_phase, mem_addr, input_port,
+ output_port, old_output_port, output_locked, ami_stat,
+ ami_flags, key_ctrl_queue_start, key_ctrl_queue_end;
+
+ /* Keyboard. */
+ uint8_t key_command, key_wantdata, kbd_last_scan_code,
+ kbd_state, key_wantcmd, key_dat, key_cmd_queue_start,
+ key_cmd_queue_end, key_queue_start, key_queue_end;
+
+ /* Mouse. */
+ uint8_t mouse_state, mouse_wantcmd, mouse_dat, mouse_cmd_queue_start,
+ mouse_cmd_queue_end, mouse_queue_start, mouse_queue_end;
+
+ /* Controller. */
+ uint8_t mem[0x100];
+
+ /* Controller - internal FIFO for the purpose of commands with multi-byte output. */
+ uint8_t key_ctrl_queue[64];
+
+ /* Keyboard - command response FIFO. */
+ uint8_t key_cmd_queue[16];
+
+ /* Keyboard - scan FIFO. */
+ uint8_t key_queue[16];
+
+ /* Mouse - command response FIFO. */
+ uint8_t mouse_cmd_queue[16];
+
+ /* Mouse - scan FIFO. */
+ uint8_t mouse_queue[16];
+
+ /* Keyboard. */
+ int out_new;
+
+ /* Mouse. */
+ int out_new_mouse;
+
+ /* Controller. */
+ uint32_t flags;
+
+ /* Controller (main timer). */
+ pc_timer_t send_delay_timer;
+
+ /* Controller (P2 pulse callback timer). */
+ pc_timer_t pulse_cb;
+
+ uint8_t (*write60_ven)(void *p, uint8_t val);
+ uint8_t (*write64_ven)(void *p, uint8_t val);
+} atkbd_t;
+
+/* Global keyboard flags for scan code set 3:
+ bit 0 = repeat, bit 1 = makes break code? */
+uint8_t keyboard_set3_flags[512];
+uint8_t keyboard_set3_all_repeat;
+uint8_t keyboard_set3_all_break;
+
+/* Global keyboard mode:
+ Bits 0 - 1 = scan code set. */
+uint8_t keyboard_mode = 0x02;
+
+/* Keyboard controller ports. */
+kbc_port_t *kbc_ports[2] = { NULL, NULL };
+
+static void (*mouse_write)(uint8_t val, void *priv) = NULL;
+static void *mouse_p = NULL;
+static atkbd_t *SavedKbd = NULL; // FIXME: remove!!! --FvK
+
+/* Non-translated to translated scan codes. */
+static const uint8_t nont_to_t[256] = {
+ 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
+ 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
+ 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
+ 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
+ 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
+ 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
+ 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
+ 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
+ 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
+ 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
+ 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
+ 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
+ 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
+ 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
+ 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
+ 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
+ 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+static const scancode scancode_set1[512] = {
+ // clang-format off
+ { { 0},{ 0} }, { { 0x01,0},{ 0x81,0} }, { { 0x02,0},{ 0x82,0} }, { { 0x03,0},{ 0x83,0} }, /*000*/
+ { { 0x04,0},{ 0x84,0} }, { { 0x05,0},{ 0x85,0} }, { { 0x06,0},{ 0x86,0} }, { { 0x07,0},{ 0x87,0} }, /*004*/
+ { { 0x08,0},{ 0x88,0} }, { { 0x09,0},{ 0x89,0} }, { { 0x0a,0},{ 0x8a,0} }, { { 0x0b,0},{ 0x8b,0} }, /*008*/
+ { { 0x0c,0},{ 0x8c,0} }, { { 0x0d,0},{ 0x8d,0} }, { { 0x0e,0},{ 0x8e,0} }, { { 0x0f,0},{ 0x8f,0} }, /*00c*/
+ { { 0x10,0},{ 0x90,0} }, { { 0x11,0},{ 0x91,0} }, { { 0x12,0},{ 0x92,0} }, { { 0x13,0},{ 0x93,0} }, /*010*/
+ { { 0x14,0},{ 0x94,0} }, { { 0x15,0},{ 0x95,0} }, { { 0x16,0},{ 0x96,0} }, { { 0x17,0},{ 0x97,0} }, /*014*/
+ { { 0x18,0},{ 0x98,0} }, { { 0x19,0},{ 0x99,0} }, { { 0x1a,0},{ 0x9a,0} }, { { 0x1b,0},{ 0x9b,0} }, /*018*/
+ { { 0x1c,0},{ 0x9c,0} }, { { 0x1d,0},{ 0x9d,0} }, { { 0x1e,0},{ 0x9e,0} }, { { 0x1f,0},{ 0x9f,0} }, /*01c*/
+ { { 0x20,0},{ 0xa0,0} }, { { 0x21,0},{ 0xa1,0} }, { { 0x22,0},{ 0xa2,0} }, { { 0x23,0},{ 0xa3,0} }, /*020*/
+ { { 0x24,0},{ 0xa4,0} }, { { 0x25,0},{ 0xa5,0} }, { { 0x26,0},{ 0xa6,0} }, { { 0x27,0},{ 0xa7,0} }, /*024*/
+ { { 0x28,0},{ 0xa8,0} }, { { 0x29,0},{ 0xa9,0} }, { { 0x2a,0},{ 0xaa,0} }, { { 0x2b,0},{ 0xab,0} }, /*028*/
+ { { 0x2c,0},{ 0xac,0} }, { { 0x2d,0},{ 0xad,0} }, { { 0x2e,0},{ 0xae,0} }, { { 0x2f,0},{ 0xaf,0} }, /*02c*/
+ { { 0x30,0},{ 0xb0,0} }, { { 0x31,0},{ 0xb1,0} }, { { 0x32,0},{ 0xb2,0} }, { { 0x33,0},{ 0xb3,0} }, /*030*/
+ { { 0x34,0},{ 0xb4,0} }, { { 0x35,0},{ 0xb5,0} }, { { 0x36,0},{ 0xb6,0} }, { { 0x37,0},{ 0xb7,0} }, /*034*/
+ { { 0x38,0},{ 0xb8,0} }, { { 0x39,0},{ 0xb9,0} }, { { 0x3a,0},{ 0xba,0} }, { { 0x3b,0},{ 0xbb,0} }, /*038*/
+ { { 0x3c,0},{ 0xbc,0} }, { { 0x3d,0},{ 0xbd,0} }, { { 0x3e,0},{ 0xbe,0} }, { { 0x3f,0},{ 0xbf,0} }, /*03c*/
+ { { 0x40,0},{ 0xc0,0} }, { { 0x41,0},{ 0xc1,0} }, { { 0x42,0},{ 0xc2,0} }, { { 0x43,0},{ 0xc3,0} }, /*040*/
+ { { 0x44,0},{ 0xc4,0} }, { { 0x45,0},{ 0xc5,0} }, { { 0x46,0},{ 0xc6,0} }, { { 0x47,0},{ 0xc7,0} }, /*044*/
+ { { 0x48,0},{ 0xc8,0} }, { { 0x49,0},{ 0xc9,0} }, { { 0x4a,0},{ 0xca,0} }, { { 0x4b,0},{ 0xcb,0} }, /*048*/
+ { { 0x4c,0},{ 0xcc,0} }, { { 0x4d,0},{ 0xcd,0} }, { { 0x4e,0},{ 0xce,0} }, { { 0x4f,0},{ 0xcf,0} }, /*04c*/
+ { { 0x50,0},{ 0xd0,0} }, { { 0x51,0},{ 0xd1,0} }, { { 0x52,0},{ 0xd2,0} }, { { 0x53,0},{ 0xd3,0} }, /*050*/
+ { { 0x54,0},{ 0xd4,0} }, { { 0x55,0},{ 0xd5,0} }, { { 0x56,0},{ 0xd6,0} }, { { 0x57,0},{ 0xd7,0} }, /*054*/
+ { { 0x58,0},{ 0xd8,0} }, { { 0x59,0},{ 0xd9,0} }, { { 0x5a,0},{ 0xda,0} }, { { 0x5b,0},{ 0xdb,0} }, /*058*/
+ { { 0x5c,0},{ 0xdc,0} }, { { 0x5d,0},{ 0xdd,0} }, { { 0x5e,0},{ 0xde,0} }, { { 0x5f,0},{ 0xdf,0} }, /*05c*/
+ { { 0x60,0},{ 0xe0,0} }, { { 0x61,0},{ 0xe1,0} }, { { 0x62,0},{ 0xe2,0} }, { { 0x63,0},{ 0xe3,0} }, /*060*/
+ { { 0x64,0},{ 0xe4,0} }, { { 0x65,0},{ 0xe5,0} }, { { 0x66,0},{ 0xe6,0} }, { { 0x67,0},{ 0xe7,0} }, /*064*/
+ { { 0x68,0},{ 0xe8,0} }, { { 0x69,0},{ 0xe9,0} }, { { 0x6a,0},{ 0xea,0} }, { { 0x6b,0},{ 0xeb,0} }, /*068*/
+ { { 0x6c,0},{ 0xec,0} }, { { 0x6d,0},{ 0xed,0} }, { { 0x6e,0},{ 0xee,0} }, { { 0x6f,0},{ 0xef,0} }, /*06c*/
+ { { 0x70,0},{ 0xf0,0} }, { { 0x71,0},{ 0xf1,0} }, { { 0x72,0},{ 0xf2,0} }, { { 0x73,0},{ 0xf3,0} }, /*070*/
+ { { 0x74,0},{ 0xf4,0} }, { { 0x75,0},{ 0xf5,0} }, { { 0x76,0},{ 0xf6,0} }, { { 0x77,0},{ 0xf7,0} }, /*074*/
+ { { 0x78,0},{ 0xf8,0} }, { { 0x79,0},{ 0xf9,0} }, { { 0x7a,0},{ 0xfa,0} }, { { 0x7b,0},{ 0xfb,0} }, /*078*/
+ { { 0x7c,0},{ 0xfc,0} }, { { 0x7d,0},{ 0xfd,0} }, { { 0x7e,0},{ 0xfe,0} }, { { 0x7f,0},{ 0xff,0} }, /*07c*/
+
+ { { 0x80,0},{ 0} }, { { 0x81,0},{ 0} }, { { 0x82,0},{ 0} }, { { 0},{ 0} }, /*080*/
+ { { 0},{ 0} }, { { 0x85,0},{ 0} }, { { 0x86,0},{ 0} }, { { 0x87,0},{ 0} }, /*084*/
+ { { 0x88,0},{ 0} }, { { 0x89,0},{ 0} }, { { 0x8a,0},{ 0} }, { { 0x8b,0},{ 0} }, /*088*/
+ { { 0x8c,0},{ 0} }, { { 0x8d,0},{ 0} }, { { 0x8e,0},{ 0} }, { { 0x8f,0},{ 0} }, /*08c*/
+ { { 0x90,0},{ 0} }, { { 0x91,0},{ 0} }, { { 0x92,0},{ 0} }, { { 0x93,0},{ 0} }, /*090*/
+ { { 0x94,0},{ 0} }, { { 0x95,0},{ 0} }, { { 0x96,0},{ 0} }, { { 0x97,0},{ 0} }, /*094*/
+ { { 0x98,0},{ 0} }, { { 0x99,0},{ 0} }, { { 0x9a,0},{ 0} }, { { 0x9b,0},{ 0} }, /*098*/
+ { { 0x9c,0},{ 0} }, { { 0x9d,0},{ 0} }, { { 0x9e,0},{ 0} }, { { 0x9f,0},{ 0} }, /*09c*/
+ { { 0xa0,0},{ 0} }, { { 0xa1,0},{ 0} }, { { 0xa2,0},{ 0} }, { { 0xa3,0},{ 0} }, /*0a0*/
+ { { 0xa4,0},{ 0} }, { { 0xa5,0},{ 0} }, { { 0xa6,0},{ 0} }, { { 0xa7,0},{ 0} }, /*0a4*/
+ { { 0xa8,0},{ 0} }, { { 0xa9,0},{ 0} }, { { 0xaa,0},{ 0} }, { { 0xab,0},{ 0} }, /*0a8*/
+ { { 0xac,0},{ 0} }, { { 0xad,0},{ 0} }, { { 0xae,0},{ 0} }, { { 0xaf,0},{ 0} }, /*0ac*/
+ { { 0xb0,0},{ 0} }, { { 0xb1,0},{ 0} }, { { 0xb2,0},{ 0} }, { { 0xb3,0},{ 0} }, /*0b0*/
+ { { 0xb4,0},{ 0} }, { { 0xb5,0},{ 0} }, { { 0xb6,0},{ 0} }, { { 0xb7,0},{ 0} }, /*0b4*/
+ { { 0xb8,0},{ 0} }, { { 0xb9,0},{ 0} }, { { 0xba,0},{ 0} }, { { 0xbb,0},{ 0} }, /*0b8*/
+ { { 0xbc,0},{ 0} }, { { 0xbd,0},{ 0} }, { { 0xbe,0},{ 0} }, { { 0xbf,0},{ 0} }, /*0bc*/
+ { { 0xc0,0},{ 0} }, { { 0xc1,0},{ 0} }, { { 0xc2,0},{ 0} }, { { 0xc3,0},{ 0} }, /*0c0*/
+ { { 0xc4,0},{ 0} }, { { 0xc5,0},{ 0} }, { { 0xc6,0},{ 0} }, { { 0xc7,0},{ 0} }, /*0c4*/
+ { { 0xc8,0},{ 0} }, { { 0xc9,0},{ 0} }, { { 0xca,0},{ 0} }, { { 0xcb,0},{ 0} }, /*0c8*/
+ { { 0xcc,0},{ 0} }, { { 0xcd,0},{ 0} }, { { 0xce,0},{ 0} }, { { 0xcf,0},{ 0} }, /*0cc*/
+ { { 0xd0,0},{ 0} }, { { 0xd1,0},{ 0} }, { { 0xd2,0},{ 0} }, { { 0xd3,0},{ 0} }, /*0d0*/
+ { { 0xd4,0},{ 0} }, { { 0xd5,0},{ 0} }, { { 0xd6,0},{ 0} }, { { 0xd7,0},{ 0} }, /*0d4*/
+ { { 0xd8,0},{ 0} }, { { 0xd9,0},{ 0} }, { { 0xda,0},{ 0} }, { { 0xdb,0},{ 0} }, /*0d8*/
+ { { 0xdc,0},{ 0} }, { { 0xdd,0},{ 0} }, { { 0xde,0},{ 0} }, { { 0xdf,0},{ 0} }, /*0dc*/
+ { { 0xe0,0},{ 0} }, { { 0xe1,0},{ 0} }, { { 0xe2,0},{ 0} }, { { 0xe3,0},{ 0} }, /*0e0*/
+ { { 0xe4,0},{ 0} }, { { 0xe5,0},{ 0} }, { { 0xe6,0},{ 0} }, { { 0xe7,0},{ 0} }, /*0e4*/
+ { { 0xe8,0},{ 0} }, { { 0xe9,0},{ 0} }, { { 0xea,0},{ 0} }, { { 0xeb,0},{ 0} }, /*0e8*/
+ { { 0xec,0},{ 0} }, { { 0xed,0},{ 0} }, { { 0xee,0},{ 0} }, { { 0xef,0},{ 0} }, /*0ec*/
+ { { 0},{ 0} }, { { 0xf1,0},{ 0} }, { { 0xf2,0},{ 0} }, { { 0xf3,0},{ 0} }, /*0f0*/
+ { { 0xf4,0},{ 0} }, { { 0xf5,0},{ 0} }, { { 0xf6,0},{ 0} }, { { 0xf7,0},{ 0} }, /*0f4*/
+ { { 0xf8,0},{ 0} }, { { 0xf9,0},{ 0} }, { { 0xfa,0},{ 0} }, { { 0xfb,0},{ 0} }, /*0f8*/
+ { { 0xfc,0},{ 0} }, { { 0xfd,0},{ 0} }, { { 0xfe,0},{ 0} }, { { 0xff,0},{ 0} }, /*0fc*/
+
+ { {0xe1,0x1d,0},{0xe1, 0x9d,0} }, { {0xe0,0x01,0},{0xe0, 0x81,0} }, { {0xe0,0x02,0},{0xe0, 0x82,0} }, { {0xe0,0x03,0},{0xe0, 0x83,0} }, /*100*/
+ { {0xe0,0x04,0},{0xe0, 0x84,0} }, { {0xe0,0x05,0},{0xe0, 0x85,0} }, { {0xe0,0x06,0},{0xe0, 0x86,0} }, { {0xe0,0x07,0},{0xe0, 0x87,0} }, /*104*/
+ { {0xe0,0x08,0},{0xe0, 0x88,0} }, { {0xe0,0x09,0},{0xe0, 0x89,0} }, { {0xe0,0x0a,0},{0xe0, 0x8a,0} }, { {0xe0,0x0b,0},{0xe0, 0x8b,0} }, /*108*/
+ { {0xe0,0x0c,0},{0xe0, 0x8c,0} }, { { 0},{ 0} }, { {0xe0,0x0e,0},{0xe0, 0x8e,0} }, { {0xe0,0x0f,0},{0xe0, 0x8f,0} }, /*10c*/
+ { {0xe0,0x10,0},{0xe0, 0x90,0} }, { {0xe0,0x11,0},{0xe0, 0x91,0} }, { {0xe0,0x12,0},{0xe0, 0x92,0} }, { {0xe0,0x13,0},{0xe0, 0x93,0} }, /*110*/
+ { {0xe0,0x14,0},{0xe0, 0x94,0} }, { {0xe0,0x15,0},{0xe0, 0x95,0} }, { {0xe0,0x16,0},{0xe0, 0x96,0} }, { {0xe0,0x17,0},{0xe0, 0x97,0} }, /*114*/
+ { {0xe0,0x18,0},{0xe0, 0x98,0} }, { {0xe0,0x19,0},{0xe0, 0x99,0} }, { {0xe0,0x1a,0},{0xe0, 0x9a,0} }, { {0xe0,0x1b,0},{0xe0, 0x9b,0} }, /*118*/
+ { {0xe0,0x1c,0},{0xe0, 0x9c,0} }, { {0xe0,0x1d,0},{0xe0, 0x9d,0} }, { {0xe0,0x1e,0},{0xe0, 0x9e,0} }, { {0xe0,0x1f,0},{0xe0, 0x9f,0} }, /*11c*/
+ { {0xe0,0x20,0},{0xe0, 0xa0,0} }, { {0xe0,0x21,0},{0xe0, 0xa1,0} }, { {0xe0,0x22,0},{0xe0, 0xa2,0} }, { {0xe0,0x23,0},{0xe0, 0xa3,0} }, /*120*/
+ { {0xe0,0x24,0},{0xe0, 0xa4,0} }, { {0xe0,0x25,0},{0xe0, 0xa5,0} }, { {0xe0,0x26,0},{0xe0, 0xa6,0} }, { { 0},{ 0} }, /*124*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/
+ { {0xe0,0x2c,0},{0xe0, 0xac,0} }, { {0xe0,0x2d,0},{0xe0, 0xad,0} }, { {0xe0,0x2e,0},{0xe0, 0xae,0} }, { {0xe0,0x2f,0},{0xe0, 0xaf,0} }, /*12c*/
+ { {0xe0,0x30,0},{0xe0, 0xb0,0} }, { {0xe0,0x31,0},{0xe0, 0xb1,0} }, { {0xe0,0x32,0},{0xe0, 0xb2,0} }, { { 0},{ 0} }, /*130*/
+ { {0xe0,0x34,0},{0xe0, 0xb4,0} }, { {0xe0,0x35,0},{0xe0, 0xb5,0} }, { { 0},{ 0} }, { {0xe0,0x37,0},{0xe0, 0xb7,0} }, /*134*/
+ { {0xe0,0x38,0},{0xe0, 0xb8,0} }, { { 0},{ 0} }, { {0xe0,0x3a,0},{0xe0, 0xba,0} }, { {0xe0,0x3b,0},{0xe0, 0xbb,0} }, /*138*/
+ { {0xe0,0x3c,0},{0xe0, 0xbc,0} }, { {0xe0,0x3d,0},{0xe0, 0xbd,0} }, { {0xe0,0x3e,0},{0xe0, 0xbe,0} }, { {0xe0,0x3f,0},{0xe0, 0xbf,0} }, /*13c*/
+ { {0xe0,0x40,0},{0xe0, 0xc0,0} }, { {0xe0,0x41,0},{0xe0, 0xc1,0} }, { {0xe0,0x42,0},{0xe0, 0xc2,0} }, { {0xe0,0x43,0},{0xe0, 0xc3,0} }, /*140*/
+ { {0xe0,0x44,0},{0xe0, 0xc4,0} }, { { 0},{ 0} }, { {0xe0,0x46,0},{0xe0, 0xc6,0} }, { {0xe0,0x47,0},{0xe0, 0xc7,0} }, /*144*/
+ { {0xe0,0x48,0},{0xe0, 0xc8,0} }, { {0xe0,0x49,0},{0xe0, 0xc9,0} }, { { 0},{ 0} }, { {0xe0,0x4b,0},{0xe0, 0xcb,0} }, /*148*/
+ { {0xe0,0x4c,0},{0xe0, 0xcc,0} }, { {0xe0,0x4d,0},{0xe0, 0xcd,0} }, { {0xe0,0x4e,0},{0xe0, 0xce,0} }, { {0xe0,0x4f,0},{0xe0, 0xcf,0} }, /*14c*/
+ { {0xe0,0x50,0},{0xe0, 0xd0,0} }, { {0xe0,0x51,0},{0xe0, 0xd1,0} }, { {0xe0,0x52,0},{0xe0, 0xd2,0} }, { {0xe0,0x53,0},{0xe0, 0xd3,0} }, /*150*/
+ { { 0},{ 0} }, { {0xe0,0x55,0},{0xe0, 0xd5,0} }, { { 0},{ 0} }, { {0xe0,0x57,0},{0xe0, 0xd7,0} }, /*154*/
+ { {0xe0,0x58,0},{0xe0, 0xd8,0} }, { {0xe0,0x59,0},{0xe0, 0xd9,0} }, { {0xe0,0x5a,0},{0xe0, 0xaa,0} }, { {0xe0,0x5b,0},{0xe0, 0xdb,0} }, /*158*/
+ { {0xe0,0x5c,0},{0xe0, 0xdc,0} }, { {0xe0,0x5d,0},{0xe0, 0xdd,0} }, { {0xe0,0x5e,0},{0xe0, 0xee,0} }, { {0xe0,0x5f,0},{0xe0, 0xdf,0} }, /*15c*/
+ { { 0},{ 0} }, { {0xe0,0x61,0},{0xe0, 0xe1,0} }, { {0xe0,0x62,0},{0xe0, 0xe2,0} }, { {0xe0,0x63,0},{0xe0, 0xe3,0} }, /*160*/
+ { {0xe0,0x64,0},{0xe0, 0xe4,0} }, { {0xe0,0x65,0},{0xe0, 0xe5,0} }, { {0xe0,0x66,0},{0xe0, 0xe6,0} }, { {0xe0,0x67,0},{0xe0, 0xe7,0} }, /*164*/
+ { {0xe0,0x68,0},{0xe0, 0xe8,0} }, { {0xe0,0x69,0},{0xe0, 0xe9,0} }, { {0xe0,0x6a,0},{0xe0, 0xea,0} }, { {0xe0,0x6b,0},{0xe0, 0xeb,0} }, /*168*/
+ { {0xe0,0x6c,0},{0xe0, 0xec,0} }, { {0xe0,0x6d,0},{0xe0, 0xed,0} }, { {0xe0,0x6e,0},{0xe0, 0xee,0} }, { { 0},{ 0} }, /*16c*/
+ { {0xe0,0x70,0},{0xe0, 0xf0,0} }, { {0xe0,0x71,0},{0xe0, 0xf1,0} }, { {0xe0,0x72,0},{0xe0, 0xf2,0} }, { {0xe0,0x73,0},{0xe0, 0xf3,0} }, /*170*/
+ { {0xe0,0x74,0},{0xe0, 0xf4,0} }, { {0xe0,0x75,0},{0xe0, 0xf5,0} }, { { 0},{ 0} }, { {0xe0,0x77,0},{0xe0, 0xf7,0} }, /*174*/
+ { {0xe0,0x78,0},{0xe0, 0xf8,0} }, { {0xe0,0x79,0},{0xe0, 0xf9,0} }, { {0xe0,0x7a,0},{0xe0, 0xfa,0} }, { {0xe0,0x7b,0},{0xe0, 0xfb,0} }, /*178*/
+ { {0xe0,0x7c,0},{0xe0, 0xfc,0} }, { {0xe0,0x7d,0},{0xe0, 0xfd,0} }, { {0xe0,0x7e,0},{0xe0, 0xfe,0} }, { {0xe0,0x7f,0},{0xe0, 0xff,0} }, /*17c*/
+
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/
+ { { 0},{ 0} }, { {0xe0,0xe1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{ 0} }, { { 0},{ 0} }, /*1ec*/
+ { { 0},{ 0} }, { {0xe0,0xf1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{ 0} }, { {0xe0,0xff,0},{ 0} } /*1fc*/
+ // clang-format on
+};
+
+static const scancode scancode_set2[512] = {
+ // clang-format off
+ { { 0},{ 0} }, { { 0x76,0},{ 0xF0,0x76,0} }, { { 0x16,0},{ 0xF0,0x16,0} }, { { 0x1E,0},{ 0xF0,0x1E,0} }, /*000*/
+ { { 0x26,0},{ 0xF0,0x26,0} }, { { 0x25,0},{ 0xF0,0x25,0} }, { { 0x2E,0},{ 0xF0,0x2E,0} }, { { 0x36,0},{ 0xF0,0x36,0} }, /*004*/
+ { { 0x3D,0},{ 0xF0,0x3D,0} }, { { 0x3E,0},{ 0xF0,0x3E,0} }, { { 0x46,0},{ 0xF0,0x46,0} }, { { 0x45,0},{ 0xF0,0x45,0} }, /*008*/
+ { { 0x4E,0},{ 0xF0,0x4E,0} }, { { 0x55,0},{ 0xF0,0x55,0} }, { { 0x66,0},{ 0xF0,0x66,0} }, { { 0x0D,0},{ 0xF0,0x0D,0} }, /*00c*/
+ { { 0x15,0},{ 0xF0,0x15,0} }, { { 0x1D,0},{ 0xF0,0x1D,0} }, { { 0x24,0},{ 0xF0,0x24,0} }, { { 0x2D,0},{ 0xF0,0x2D,0} }, /*010*/
+ { { 0x2C,0},{ 0xF0,0x2C,0} }, { { 0x35,0},{ 0xF0,0x35,0} }, { { 0x3C,0},{ 0xF0,0x3C,0} }, { { 0x43,0},{ 0xF0,0x43,0} }, /*014*/
+ { { 0x44,0},{ 0xF0,0x44,0} }, { { 0x4D,0},{ 0xF0,0x4D,0} }, { { 0x54,0},{ 0xF0,0x54,0} }, { { 0x5B,0},{ 0xF0,0x5B,0} }, /*018*/
+ { { 0x5A,0},{ 0xF0,0x5A,0} }, { { 0x14,0},{ 0xF0,0x14,0} }, { { 0x1C,0},{ 0xF0,0x1C,0} }, { { 0x1B,0},{ 0xF0,0x1B,0} }, /*01c*/
+ { { 0x23,0},{ 0xF0,0x23,0} }, { { 0x2B,0},{ 0xF0,0x2B,0} }, { { 0x34,0},{ 0xF0,0x34,0} }, { { 0x33,0},{ 0xF0,0x33,0} }, /*020*/
+ { { 0x3B,0},{ 0xF0,0x3B,0} }, { { 0x42,0},{ 0xF0,0x42,0} }, { { 0x4B,0},{ 0xF0,0x4B,0} }, { { 0x4C,0},{ 0xF0,0x4C,0} }, /*024*/
+ { { 0x52,0},{ 0xF0,0x52,0} }, { { 0x0E,0},{ 0xF0,0x0E,0} }, { { 0x12,0},{ 0xF0,0x12,0} }, { { 0x5D,0},{ 0xF0,0x5D,0} }, /*028*/
+ { { 0x1A,0},{ 0xF0,0x1A,0} }, { { 0x22,0},{ 0xF0,0x22,0} }, { { 0x21,0},{ 0xF0,0x21,0} }, { { 0x2A,0},{ 0xF0,0x2A,0} }, /*02c*/
+ { { 0x32,0},{ 0xF0,0x32,0} }, { { 0x31,0},{ 0xF0,0x31,0} }, { { 0x3A,0},{ 0xF0,0x3A,0} }, { { 0x41,0},{ 0xF0,0x41,0} }, /*030*/
+ { { 0x49,0},{ 0xF0,0x49,0} }, { { 0x4A,0},{ 0xF0,0x4A,0} }, { { 0x59,0},{ 0xF0,0x59,0} }, { { 0x7C,0},{ 0xF0,0x7C,0} }, /*034*/
+ { { 0x11,0},{ 0xF0,0x11,0} }, { { 0x29,0},{ 0xF0,0x29,0} }, { { 0x58,0},{ 0xF0,0x58,0} }, { { 0x05,0},{ 0xF0,0x05,0} }, /*038*/
+ { { 0x06,0},{ 0xF0,0x06,0} }, { { 0x04,0},{ 0xF0,0x04,0} }, { { 0x0C,0},{ 0xF0,0x0C,0} }, { { 0x03,0},{ 0xF0,0x03,0} }, /*03c*/
+ { { 0x0B,0},{ 0xF0,0x0B,0} }, { { 0x83,0},{ 0xF0,0x83,0} }, { { 0x0A,0},{ 0xF0,0x0A,0} }, { { 0x01,0},{ 0xF0,0x01,0} }, /*040*/
+ { { 0x09,0},{ 0xF0,0x09,0} }, { { 0x77,0},{ 0xF0,0x77,0} }, { { 0x7E,0},{ 0xF0,0x7E,0} }, { { 0x6C,0},{ 0xF0,0x6C,0} }, /*044*/
+ { { 0x75,0},{ 0xF0,0x75,0} }, { { 0x7D,0},{ 0xF0,0x7D,0} }, { { 0x7B,0},{ 0xF0,0x7B,0} }, { { 0x6B,0},{ 0xF0,0x6B,0} }, /*048*/
+ { { 0x73,0},{ 0xF0,0x73,0} }, { { 0x74,0},{ 0xF0,0x74,0} }, { { 0x79,0},{ 0xF0,0x79,0} }, { { 0x69,0},{ 0xF0,0x69,0} }, /*04c*/
+ { { 0x72,0},{ 0xF0,0x72,0} }, { { 0x7A,0},{ 0xF0,0x7A,0} }, { { 0x70,0},{ 0xF0,0x70,0} }, { { 0x71,0},{ 0xF0,0x71,0} }, /*050*/
+ { { 0x84,0},{ 0xF0,0x84,0} }, { { 0x60,0},{ 0xF0,0x60,0} }, { { 0x61,0},{ 0xF0,0x61,0} }, { { 0x78,0},{ 0xF0,0x78,0} }, /*054*/
+ { { 0x07,0},{ 0xF0,0x07,0} }, { { 0x0F,0},{ 0xF0,0x0F,0} }, { { 0x17,0},{ 0xF0,0x17,0} }, { { 0x1F,0},{ 0xF0,0x1F,0} }, /*058*/
+ { { 0x27,0},{ 0xF0,0x27,0} }, { { 0x2F,0},{ 0xF0,0x2F,0} }, { { 0x37,0},{ 0xF0,0x37,0} }, { { 0x3F,0},{ 0xF0,0x3F,0} }, /*05c*/
+ { { 0x47,0},{ 0xF0,0x47,0} }, { { 0x4F,0},{ 0xF0,0x4F,0} }, { { 0x56,0},{ 0xF0,0x56,0} }, { { 0x5E,0},{ 0xF0,0x5E,0} }, /*060*/
+ { { 0x08,0},{ 0xF0,0x08,0} }, { { 0x10,0},{ 0xF0,0x10,0} }, { { 0x18,0},{ 0xF0,0x18,0} }, { { 0x20,0},{ 0xF0,0x20,0} }, /*064*/
+ { { 0x28,0},{ 0xF0,0x28,0} }, { { 0x30,0},{ 0xF0,0x30,0} }, { { 0x38,0},{ 0xF0,0x38,0} }, { { 0x40,0},{ 0xF0,0x40,0} }, /*068*/
+ { { 0x48,0},{ 0xF0,0x48,0} }, { { 0x50,0},{ 0xF0,0x50,0} }, { { 0x57,0},{ 0xF0,0x57,0} }, { { 0x6F,0},{ 0xF0,0x6F,0} }, /*06c*/
+ { { 0x13,0},{ 0xF0,0x13,0} }, { { 0x19,0},{ 0xF0,0x19,0} }, { { 0x39,0},{ 0xF0,0x39,0} }, { { 0x51,0},{ 0xF0,0x51,0} }, /*070*/
+ { { 0x53,0},{ 0xF0,0x53,0} }, { { 0x5C,0},{ 0xF0,0x5C,0} }, { { 0x5F,0},{ 0xF0,0x5F,0} }, { { 0x62,0},{ 0xF0,0x62,0} }, /*074*/
+ { { 0x63,0},{ 0xF0,0x63,0} }, { { 0x64,0},{ 0xF0,0x64,0} }, { { 0x65,0},{ 0xF0,0x65,0} }, { { 0x67,0},{ 0xF0,0x67,0} }, /*078*/
+ { { 0x68,0},{ 0xF0,0x68,0} }, { { 0x6A,0},{ 0xF0,0x6A,0} }, { { 0x6D,0},{ 0xF0,0x6D,0} }, { { 0x6E,0},{ 0xF0,0x6E,0} }, /*07c*/
+
+ { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/
+ { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/
+ { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/
+ { { 0x8c,0},{ 0xf0,0x8c,0} }, { { 0x8d,0},{ 0xf0,0x8d,0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/
+ { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/
+ { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/
+ { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/
+ { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/
+ { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/
+ { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/
+ { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/
+ { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/
+ { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/
+ { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/
+ { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/
+ { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/
+ { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/
+ { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/
+ { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/
+ { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/
+ { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/
+ { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/
+ { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/
+ { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/
+ { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/
+ { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/
+ { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/
+ { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/
+ { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/
+ { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/
+ { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/
+ { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/
+
+ { {0xe1,0x14,0},{0xe1,0xf0,0x14,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/
+ { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/
+ { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/
+ { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/
+ { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/
+ { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/
+ { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/
+ { {0xe0,0x5A,0},{0xe0,0xF0,0x5A,0} }, { {0xe0,0x14,0},{0xe0,0xF0,0x14,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/
+ { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/
+ { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/
+ { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/
+ { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/
+ { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { {0xe0,0x4A,0},{0xe0,0xF0,0x4A,0} }, { { 0},{ 0} }, { {0xe0,0x7C,0},{0xe0,0xF0,0x7C,0} }, /*134*/
+ { {0xe0,0x11,0},{0xe0,0xF0,0x11,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/
+ { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/
+ { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/
+ { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { {0xe0,0x6C,0},{0xe0,0xF0,0x6C,0} }, /*144*/
+ { {0xe0,0x75,0},{0xe0,0xF0,0x75,0} }, { {0xe0,0x7D,0},{0xe0,0xF0,0x7D,0} }, { { 0},{ 0} }, { {0xe0,0x6B,0},{0xe0,0xF0,0x6B,0} }, /*148*/
+ { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { {0xe0,0x74,0},{0xe0,0xF0,0x74,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { {0xe0,0x69,0},{0xe0,0xF0,0x69,0} }, /*14c*/
+ { {0xe0,0x72,0},{0xe0,0xF0,0x72,0} }, { {0xe0,0x7A,0},{0xe0,0xF0,0x7A,0} }, { {0xe0,0x70,0},{0xe0,0xF0,0x70,0} }, { {0xe0,0x71,0},{0xe0,0xF0,0x71,0} }, /*150*/
+ { { 0},{ 0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/
+ { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { {0xe0,0x1F,0},{0xe0,0xF0,0x1F,0} }, /*158*/
+ { {0xe0,0x27,0},{0xe0,0xF0,0x27,0} }, { {0xe0,0x2F,0},{0xe0,0xF0,0x2F,0} }, { {0xe0,0x37,0},{0xe0,0xF0,0x37,0} }, { {0xe0,0x3F,0},{0xe0,0xF0,0x3F,0} }, /*15c*/
+ { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { {0xe0,0x5E,0},{0xe0,0xF0,0x5E,0} }, /*160*/
+ { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/
+ { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/
+ { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/
+ { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/
+ { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/
+ { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/
+ { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/
+
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/
+ { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/
+ { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/
+ // clang-format on
+};
+
+static const scancode scancode_set3[512] = {
+ // clang-format off
+ { { 0},{ 0} }, { { 0x08,0},{ 0xf0,0x08,0} }, { { 0x16,0},{ 0xf0,0x16,0} }, { { 0x1E,0},{ 0xf0,0x1E,0} }, /*000*/
+ { { 0x26,0},{ 0xf0,0x26,0} }, { { 0x25,0},{ 0xf0,0x25,0} }, { { 0x2E,0},{ 0xf0,0x2E,0} }, { { 0x36,0},{ 0xf0,0x36,0} }, /*004*/
+ { { 0x3D,0},{ 0xf0,0x3D,0} }, { { 0x3E,0},{ 0xf0,0x3E,0} }, { { 0x46,0},{ 0xf0,0x46,0} }, { { 0x45,0},{ 0xf0,0x45,0} }, /*008*/
+ { { 0x4E,0},{ 0xf0,0x4E,0} }, { { 0x55,0},{ 0xf0,0x55,0} }, { { 0x66,0},{ 0xf0,0x66,0} }, { { 0x0D,0},{ 0xf0,0x0D,0} }, /*00c*/
+ { { 0x15,0},{ 0xf0,0x15,0} }, { { 0x1D,0},{ 0xf0,0x1D,0} }, { { 0x24,0},{ 0xf0,0x24,0} }, { { 0x2D,0},{ 0xf0,0x2D,0} }, /*010*/
+ { { 0x2C,0},{ 0xf0,0x2C,0} }, { { 0x35,0},{ 0xf0,0x35,0} }, { { 0x3C,0},{ 0xf0,0x3C,0} }, { { 0x43,0},{ 0xf0,0x43,0} }, /*014*/
+ { { 0x44,0},{ 0xf0,0x44,0} }, { { 0x4D,0},{ 0xf0,0x4D,0} }, { { 0x54,0},{ 0xf0,0x54,0} }, { { 0x5B,0},{ 0xf0,0x5B,0} }, /*018*/
+ { { 0x5A,0},{ 0xf0,0x5A,0} }, { { 0x11,0},{ 0xf0,0x11,0} }, { { 0x1C,0},{ 0xf0,0x1C,0} }, { { 0x1B,0},{ 0xf0,0x1B,0} }, /*01c*/
+ { { 0x23,0},{ 0xf0,0x23,0} }, { { 0x2B,0},{ 0xf0,0x2B,0} }, { { 0x34,0},{ 0xf0,0x34,0} }, { { 0x33,0},{ 0xf0,0x33,0} }, /*020*/
+ { { 0x3B,0},{ 0xf0,0x3B,0} }, { { 0x42,0},{ 0xf0,0x42,0} }, { { 0x4B,0},{ 0xf0,0x4B,0} }, { { 0x4C,0},{ 0xf0,0x4C,0} }, /*024*/
+ { { 0x52,0},{ 0xf0,0x52,0} }, { { 0x0E,0},{ 0xf0,0x0E,0} }, { { 0x12,0},{ 0xf0,0x12,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, /*028*/
+ { { 0x1A,0},{ 0xf0,0x1A,0} }, { { 0x22,0},{ 0xf0,0x22,0} }, { { 0x21,0},{ 0xf0,0x21,0} }, { { 0x2A,0},{ 0xf0,0x2A,0} }, /*02c*/
+ { { 0x32,0},{ 0xf0,0x32,0} }, { { 0x31,0},{ 0xf0,0x31,0} }, { { 0x3A,0},{ 0xf0,0x3A,0} }, { { 0x41,0},{ 0xf0,0x41,0} }, /*030*/
+ { { 0x49,0},{ 0xf0,0x49,0} }, { { 0x4A,0},{ 0xf0,0x4A,0} }, { { 0x59,0},{ 0xf0,0x59,0} }, { { 0x7E,0},{ 0xf0,0x7E,0} }, /*034*/
+ { { 0x19,0},{ 0xf0,0x19,0} }, { { 0x29,0},{ 0xf0,0x29,0} }, { { 0x14,0},{ 0xf0,0x14,0} }, { { 0x07,0},{ 0xf0,0x07,0} }, /*038*/
+ { { 0x0F,0},{ 0xf0,0x0F,0} }, { { 0x17,0},{ 0xf0,0x17,0} }, { { 0x1F,0},{ 0xf0,0x1F,0} }, { { 0x27,0},{ 0xf0,0x27,0} }, /*03c*/
+ { { 0x2F,0},{ 0xf0,0x2F,0} }, { { 0x37,0},{ 0xf0,0x37,0} }, { { 0x3F,0},{ 0xf0,0x3F,0} }, { { 0x47,0},{ 0xf0,0x47,0} }, /*040*/
+ { { 0x4F,0},{ 0xf0,0x4F,0} }, { { 0x76,0},{ 0xf0,0x76,0} }, { { 0x5F,0},{ 0xf0,0x5F,0} }, { { 0x6C,0},{ 0xf0,0x6C,0} }, /*044*/
+ { { 0x75,0},{ 0xf0,0x75,0} }, { { 0x7D,0},{ 0xf0,0x7D,0} }, { { 0x84,0},{ 0xf0,0x84,0} }, { { 0x6B,0},{ 0xf0,0x6B,0} }, /*048*/
+ { { 0x73,0},{ 0xf0,0x73,0} }, { { 0x74,0},{ 0xf0,0x74,0} }, { { 0x7C,0},{ 0xf0,0x7C,0} }, { { 0x69,0},{ 0xf0,0x69,0} }, /*04c*/
+ { { 0x72,0},{ 0xf0,0x72,0} }, { { 0x7A,0},{ 0xf0,0x7A,0} }, { { 0x70,0},{ 0xf0,0x70,0} }, { { 0x71,0},{ 0xf0,0x71,0} }, /*050*/
+ { { 0x57,0},{ 0xf0,0x57,0} }, { { 0x60,0},{ 0xf0,0x60,0} }, { { 0},{ 0} }, { { 0x56,0},{ 0xf0,0x56,0} }, /*054*/
+ { { 0x5E,0},{ 0xf0,0x5E,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*058*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*05c*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*060*/
+ { { 0},{ 0} }, { { 0x10,0},{ 0xf0,0x10,0} }, { { 0x18,0},{ 0xf0,0x18,0} }, { { 0x20,0},{ 0xf0,0x20,0} }, /*064*/
+ { { 0x28,0},{ 0xf0,0x28,0} }, { { 0x30,0},{ 0xf0,0x30,0} }, { { 0x38,0},{ 0xf0,0x38,0} }, { { 0x40,0},{ 0xf0,0x40,0} }, /*068*/
+ { { 0x48,0},{ 0xf0,0x48,0} }, { { 0x50,0},{ 0xf0,0x50,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*06c*/
+ { { 0x87,0},{ 0xf0,0x87,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0x51,0},{ 0xf0,0x51,0} }, /*070*/
+ { { 0x53,0},{ 0xf0,0x53,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, { { 0},{ 0} }, { { 0x62,0},{ 0xf0,0x62,0} }, /*074*/
+ { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x85,0} }, /*078*/
+ { { 0x68,0},{ 0xf0,0x68,0} }, { { 0x13,0},{ 0xf0,0x13,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*07c*/
+
+ { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/
+ { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/
+ { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/
+ { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/
+ { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/
+ { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/
+ { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/
+ { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/
+ { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/
+ { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/
+ { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/
+ { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/
+ { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/
+ { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/
+ { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/
+ { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/
+ { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/
+ { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/
+ { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/
+ { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/
+ { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/
+ { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/
+ { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/
+ { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/
+ { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/
+ { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/
+ { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/
+ { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/
+ { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/
+ { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/
+ { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/
+
+ { { 0x62,0},{ 0xF0,0x62,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/
+ { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/
+ { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/
+ { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/
+ { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/
+ { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/
+ { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/
+ { { 0x79,0},{ 0xf0,0x79,0} }, { { 0x58,0},{ 0xf0,0x58,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/
+ { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/
+ { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/
+ { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/
+ { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/
+ { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { { 0x77,0},{ 0xf0,0x77,0} }, { { 0},{ 0} }, { { 0x57,0},{ 0xf0,0x57,0} }, /*134*/
+ { { 0x39,0},{ 0xf0,0x39,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/
+ { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/
+ { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/
+ { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { { 0x6E,0},{ 0xf0,0x6E,0} }, /*144*/
+ { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x6F,0},{ 0xf0,0x6F,0} }, { { 0},{ 0} }, { { 0x61,0},{ 0xf0,0x61,0} }, /*148*/
+ { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { { 0x6A,0},{ 0xf0,0x6A,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { { 0x65,0},{ 0xf0,0x65,0} }, /*14c*/
+ { { 0x60,0},{ 0xf0,0x60,0} }, { { 0x6D,0},{ 0xf0,0x6D,0} }, { { 0x67,0},{ 0xf0,0x67,0} }, { { 0x64,0},{ 0xf0,0x64,0} }, /*150*/
+ { { 0xd4,0},{ 0xf0,0xD4,0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/
+ { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { { 0x8B,0},{ 0xf0,0x8B,0} }, /*158*/
+ { { 0x8C,0},{ 0xf0,0x8C,0} }, { { 0x8D,0},{ 0xf0,0x8D,0} }, { { 0},{ 0} }, { { 0x7F,0},{ 0xf0,0x7F,0} }, /*15c*/
+ { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { { 0},{ 0} }, /*160*/
+ { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/
+ { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/
+ { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/
+ { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/
+ { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/
+ { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/
+ { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/
+
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/
+ { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/
+ { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/
+ { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/
+ // clang-format on
+};
+
+// #define ENABLE_KEYBOARD_AT_LOG 1
+#ifdef ENABLE_KEYBOARD_AT_LOG
+int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG;
+
+static void
+kbd_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (keyboard_at_do_log) {
+ va_start(ap, fmt);
+ pclog_ex(fmt, ap);
+ va_end(ap);
+ }
+}
+#else
+# define kbd_log(fmt, ...)
+#endif
+
+static void
+set_scancode_map(atkbd_t *dev)
+{
+ switch (keyboard_mode) {
+ case 1:
+ default:
+ keyboard_set_table(scancode_set1);
+ break;
+ case 2:
+ keyboard_set_table(scancode_set2);
+ break;
+
+ case 3:
+ keyboard_set_table(scancode_set3);
+ break;
+ }
+}
+
+static void
+kbc_queue_reset(atkbd_t *dev, uint8_t channel)
+{
+ switch (channel) {
+ case 1:
+ dev->key_queue_start = dev->key_queue_end = 0;
+ memset(dev->key_queue, 0x00, sizeof(dev->key_queue));
+ /* FALLTHROUGH */
+ case 4:
+ dev->key_cmd_queue_start = dev->key_cmd_queue_end = 0;
+ memset(dev->key_cmd_queue, 0x00, sizeof(dev->key_cmd_queue));
+ break;
+
+ case 2:
+ dev->mouse_queue_start = dev->mouse_queue_end = 0;
+ memset(dev->mouse_queue, 0x00, sizeof(dev->mouse_queue));
+ /* FALLTHROUGH */
+ case 3:
+ dev->mouse_cmd_queue_start = dev->mouse_cmd_queue_end = 0;
+ memset(dev->mouse_cmd_queue, 0x00, sizeof(dev->mouse_cmd_queue));
+ break;
+
+ case 0:
+ default:
+ dev->key_ctrl_queue_start = dev->key_ctrl_queue_end = 0;
+ memset(dev->key_ctrl_queue, 0x00, sizeof(dev->key_ctrl_queue));
+ }
+}
+
+static void
+kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel)
+{
+ switch (channel) {
+ case 4:
+ kbd_log("ATkbc: dev->key_cmd_queue[%02X] = %02X;\n", dev->key_cmd_queue_end, val);
+ dev->key_cmd_queue[dev->key_cmd_queue_end] = val;
+ dev->key_cmd_queue_end = (dev->key_cmd_queue_end + 1) & 0xf;
+ break;
+ case 3:
+ kbd_log("ATkbc: dev->mouse_cmd_queue[%02X] = %02X;\n", dev->mouse_cmd_queue_end, val);
+ dev->mouse_cmd_queue[dev->mouse_cmd_queue_end] = val;
+ dev->mouse_cmd_queue_end = (dev->mouse_cmd_queue_end + 1) & 0xf;
+ break;
+ case 2:
+ kbd_log("ATkbc: dev->mouse_queue[%02X] = %02X;\n", dev->mouse_queue_end, val);
+ dev->mouse_queue[dev->mouse_queue_end] = val;
+ dev->mouse_queue_end = (dev->mouse_queue_end + 1) & 0xf;
+ break;
+ case 1:
+ kbd_log("ATkbc: dev->key_queue[%02X] = %02X;\n", dev->key_queue_end, val);
+ dev->key_queue[dev->key_queue_end] = val;
+ dev->key_queue_end = (dev->key_queue_end + 1) & 0xf;
+ break;
+ case 0:
+ default:
+ kbd_log("ATkbc: dev->key_ctrl_queue[%02X] = %02X;\n", dev->key_ctrl_queue_end, val);
+ dev->key_ctrl_queue[dev->key_ctrl_queue_end] = val;
+ dev->key_ctrl_queue_end = (dev->key_ctrl_queue_end + 1) & 0x3f;
+ break;
+ }
+}
+
+static int
+kbc_translate(atkbd_t *dev, uint8_t val)
+{
+ int xt_mode = (dev->mem[0x20] & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF);
+ int translate = (dev->mem[0x20] & 0x40) || xt_mode || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2);
+ uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
+ int ret = - 1;
+
+ /* Allow for scan code translation. */
+ if (translate && (val == 0xf0)) {
+ kbd_log("ATkbd: translate is on, F0 prefix detected\n");
+ dev->sc_or = 0x80;
+ return ret;
+ }
+
+ /* Skip break code if translated make code has bit 7 set. */
+ if (translate && (dev->sc_or == 0x80) && (nont_to_t[val] & 0x80)) {
+ kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val);
+ dev->sc_or = 0;
+ return ret;
+ }
+
+ /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */
+ if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) &&
+ (keyboard_recv(0x138) || keyboard_recv(0x11d))) switch (val) {
+ case 0x4f:
+ t3100e_notify_set(0x01);
+ break; /* End */
+ case 0x50:
+ t3100e_notify_set(0x02);
+ break; /* Down */
+ case 0x51:
+ t3100e_notify_set(0x03);
+ break; /* PgDn */
+ case 0x52:
+ t3100e_notify_set(0x04);
+ break; /* Ins */
+ case 0x53:
+ t3100e_notify_set(0x05);
+ break; /* Del */
+ case 0x54:
+ t3100e_notify_set(0x06);
+ break; /* SysRQ */
+ case 0x45:
+ t3100e_notify_set(0x07);
+ break; /* NumLock */
+ case 0x46:
+ t3100e_notify_set(0x08);
+ break; /* ScrLock */
+ case 0x47:
+ t3100e_notify_set(0x09);
+ break; /* Home */
+ case 0x48:
+ t3100e_notify_set(0x0a);
+ break; /* Up */
+ case 0x49:
+ t3100e_notify_set(0x0b);
+ break; /* PgUp */
+ case 0x4a:
+ t3100e_notify_set(0x0c);
+ break; /* Keypad - */
+ case 0x4b:
+ t3100e_notify_set(0x0d);
+ break; /* Left */
+ case 0x4c:
+ t3100e_notify_set(0x0e);
+ break; /* KP 5 */
+ case 0x4d:
+ t3100e_notify_set(0x0f);
+ break; /* Right */
+ }
+
+ kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off");
+#ifdef ENABLE_KEYBOARD_AT_LOG
+ kbd_log("scan code: ");
+ if (translate) {
+ kbd_log("%02X (original: ", (nont_to_t[val] | dev->sc_or));
+ if (dev->sc_or == 0x80)
+ kbd_log("F0 ");
+ kbd_log("%02X)\n", val);
+ } else
+ kbd_log("%02X\n", val);
+#endif
+
+ ret = translate ? (nont_to_t[val] | dev->sc_or) : val;
+
+ if (dev->sc_or == 0x80)
+ dev->sc_or = 0;
+
+ return ret;
+}
+
+static void
+add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi)
+{
+ uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
+ int temp = (channel == 1) ? kbc_translate(dev, val) : val;
+
+ if (temp == -1)
+ return;
+
+ if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) ||
+ (kbc_ven == KBC_VEN_TG_GREEN) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF))
+ stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00);
+ else
+ stat_hi |= 0x10;
+
+ kbd_log("ATkbc: Adding %02X to front on channel %i...\n", temp, channel);
+ dev->status = (dev->status & ~0xf0) | STAT_OFULL | stat_hi;
+
+ /* WARNING: On PS/2, all IRQ's are level-triggered, but the IBM PS/2 KBC firmware is explicitly
+ written to pulse its P2 IRQ bits, so they should be kept as as edge-triggered here. */
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ if (channel >= 2) {
+ dev->status |= STAT_MFULL;
+
+ if (dev->mem[0x20] & 0x02)
+ picint_common(1 << 12, 0, 1);
+ picint_common(1 << 1, 0, 0);
+ } else {
+ if (dev->mem[0x20] & 0x01)
+ picint_common(1 << 1, 0, 1);
+ picint_common(1 << 12, 0, 0);
+ }
+ } else if (dev->mem[0x20] & 0x01)
+ picintlevel(1 << 1); /* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */
+
+ dev->out = temp;
+}
+
+static void
+add_data_kbd_cmd_queue(atkbd_t *dev, uint8_t val)
+{
+ if (dev->key_cmd_queue_end >= 16) {
+ kbd_log("ATkbc: Unable to add to queue, dev->key_cmd_queue_end >= 16\n");
+ return;
+ }
+ kbd_log("ATkbc: dev->key_cmd_queue[%02X] = %02X;\n", dev->key_cmd_queue_end, val);
+ kbc_queue_add(dev, val, 4);
+ dev->kbd_last_scan_code = val;
+}
+
+static void
+add_data_kbd_queue(atkbd_t *dev, uint8_t val)
+{
+ if (!keyboard_scan || (dev->key_queue_end >= 16)) {
+ kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (dev->key_queue_end >= 16));
+ return;
+ }
+ kbd_log("ATkbc: key_queue[%02X] = %02X;\n", dev->key_queue_end, val);
+ kbc_queue_add(dev, val, 1);
+ dev->kbd_last_scan_code = val;
+}
+
+static void
+add_data_kbd_front(atkbd_t *dev, uint8_t val)
+{
+ add_data_kbd_cmd_queue(dev, val);
+}
+
+static void kbd_process_cmd(void *priv);
+static void kbc_process_cmd(void *priv);
+
+static void
+set_enable_kbd(atkbd_t *dev, uint8_t enable)
+{
+ dev->mem[0x20] &= 0xef;
+ dev->mem[0x20] |= (enable ? 0x00 : 0x10);
+}
+
+static void
+set_enable_mouse(atkbd_t *dev, uint8_t enable)
+{
+ dev->mem[0x20] &= 0xdf;
+ dev->mem[0x20] |= (enable ? 0x00 : 0x20);
+}
+
+static void
+kbc_ibf_process(atkbd_t *dev)
+{
+ /* IBF set, process both commands and data. */
+ dev->status &= ~STAT_IFULL;
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ if (dev->status & STAT_CD)
+ kbc_process_cmd(dev);
+ else {
+ set_enable_kbd(dev, 1);
+ dev->key_wantcmd = 1;
+ dev->key_dat = dev->ib;
+ dev->kbc_state = KBC_STATE_SEND_KBD;
+ }
+}
+
+static void
+kbc_scan_kbd_at(atkbd_t *dev)
+{
+ if (!(dev->mem[0x20] & 0x10)) {
+ /* Both OBF and IBF clear and keyboard is enabled. */
+ /* XT mode. */
+ if (dev->mem[0x20] & 0x20) {
+ if (dev->out_new != -1) {
+ add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00);
+ dev->out_new = -1;
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ } else if (dev->status & STAT_IFULL)
+ kbc_ibf_process(dev);
+ /* AT mode. */
+ } else {
+ // dev->t = dev->mem[0x28];
+ if (dev->mem[0x2e] != 0x00) {
+ // if (!(dev->t & 0x02))
+ // return;
+ dev->mem[0x2e] = 0x00;
+ }
+ dev->output_port &= 0xbf;
+ if (dev->out_new != -1) {
+ /* In our case, we never have noise on the line, so we can simplify this. */
+ /* Read data from the keyboard. */
+ if (dev->mem[0x20] & 0x40) {
+ if ((dev->mem[0x20] & 0x08) || (dev->input_port & 0x80))
+ add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00);
+ dev->mem[0x2d] = (dev->out_new == 0xf0) ? 0x80 : 0x00;
+ } else
+ add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00);
+ dev->out_new = -1;
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ }
+ }
+ }
+}
+
+static void write_output(atkbd_t *dev, uint8_t val);
+
+static void
+kbc_poll_at(atkbd_t *dev)
+{
+ switch (dev->kbc_state) {
+ case KBC_STATE_RESET:
+ if (dev->status & STAT_IFULL) {
+ dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL;
+ if ((dev->status & STAT_CD) && (dev->ib == 0xaa))
+ kbc_process_cmd(dev);
+ }
+ break;
+ case KBC_STATE_MAIN_IBF:
+ default:
+ if (dev->status & STAT_OFULL) {
+ /* OBF set, wait until it is cleared but still process commands. */
+ if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD)) {
+ dev->status &= ~STAT_IFULL;
+ kbc_process_cmd(dev);
+ }
+ } else if (dev->status & STAT_IFULL)
+ kbc_ibf_process(dev);
+ else if (!(dev->mem[0x20] & 0x10))
+ dev->kbc_state = KBC_STATE_MAIN_KBD;
+ break;
+ case KBC_STATE_MAIN_KBD:
+ case KBC_STATE_MAIN_BOTH:
+ if (dev->status & STAT_IFULL)
+ kbc_ibf_process(dev);
+ else {
+ (void) kbc_scan_kbd_at(dev);
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ }
+ break;
+ case KBC_STATE_KBC_OUT:
+ /* Keyboard controller command want to output multiple bytes. */
+ if (dev->status & STAT_IFULL) {
+ /* Data from host aborts dumping. */
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ kbc_ibf_process(dev);
+ }
+ /* Do not continue dumping until OBF is clear. */
+ if (!(dev->status & STAT_OFULL)) {
+ kbd_log("ATkbc: %02X coming from channel 0\n", dev->key_ctrl_queue[dev->key_ctrl_queue_start]);
+ add_to_kbc_queue_front(dev, dev->key_ctrl_queue[dev->key_ctrl_queue_start], 0, 0x00);
+ dev->key_ctrl_queue_start = (dev->key_ctrl_queue_start + 1) & 0x3f;
+ if (dev->key_ctrl_queue_start == dev->key_ctrl_queue_end)
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ }
+ break;
+ case KBC_STATE_KBC_PARAM:
+ /* Keyboard controller command wants data, wait for said data. */
+ if (dev->status & STAT_IFULL) {
+ /* Command written, abort current command. */
+ if (dev->status & STAT_CD)
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+
+ dev->status &= ~STAT_IFULL;
+ kbc_process_cmd(dev);
+ }
+ break;
+ case KBC_STATE_SEND_KBD:
+ if (!dev->key_wantcmd)
+ dev->kbc_state = KBC_STATE_SCAN_KBD;
+ break;
+ case KBC_STATE_SCAN_KBD:
+ kbc_scan_kbd_at(dev);
+ break;
+ }
+}
+
+/*
+ Correct Procedure:
+ 1. Controller asks the device (keyboard or mouse) for a byte.
+ 2. The device, unless it's in the reset or command states, sees if there's anything to give it,
+ and if yes, begins the transfer.
+ 3. The controller checks if there is a transfer, if yes, transfers the byte and sends it to the host,
+ otherwise, checks the next device, or if there is no device left to check, checks if IBF is full
+ and if yes, processes it.
+ */
+static int
+kbc_scan_kbd_ps2(atkbd_t *dev)
+{
+ if (dev->out_new != -1) {
+ kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new & 0xff);
+ add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00);
+ dev->out_new = -1;
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+kbc_scan_aux_ps2(atkbd_t *dev)
+{
+ if (dev->out_new_mouse != -1) {
+ kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse & 0xff);
+ add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00);
+ dev->out_new_mouse = -1;
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+kbc_poll_ps2(atkbd_t *dev)
+{
+ switch (dev->kbc_state) {
+ case KBC_STATE_RESET:
+ if (dev->status & STAT_IFULL) {
+ dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL;
+ if ((dev->status & STAT_CD) && (dev->ib == 0xaa))
+ kbc_process_cmd(dev);
+ }
+ break;
+ case KBC_STATE_MAIN_IBF:
+ default:
+ if (dev->status & STAT_IFULL)
+ kbc_ibf_process(dev);
+ else if (!(dev->status & STAT_OFULL)) {
+ if (dev->mem[0x20] & 0x20) {
+ if (!(dev->mem[0x20] & 0x10)) {
+ dev->output_port &= 0xbf;
+ dev->kbc_state = KBC_STATE_MAIN_KBD;
+ }
+ } else {
+ dev->output_port &= 0xf7;
+ if (dev->mem[0x20] & 0x10)
+ dev->kbc_state = KBC_STATE_MAIN_MOUSE;
+ else {
+ dev->output_port &= 0xbf;
+ dev->kbc_state = KBC_STATE_MAIN_BOTH;
+ }
+ }
+ }
+ break;
+ case KBC_STATE_MAIN_KBD:
+ if (dev->status & STAT_IFULL)
+ kbc_ibf_process(dev);
+ else {
+ (void) kbc_scan_kbd_ps2(dev);
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ }
+ break;
+ case KBC_STATE_MAIN_MOUSE:
+ if (dev->status & STAT_IFULL)
+ kbc_ibf_process(dev);
+ else {
+ (void) kbc_scan_aux_ps2(dev);
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ }
+ break;
+ case KBC_STATE_MAIN_BOTH:
+ if (kbc_scan_kbd_ps2(dev))
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ else
+ dev->kbc_state = KBC_STATE_MAIN_MOUSE;
+ break;
+ case KBC_STATE_KBC_OUT:
+ /* Keyboard controller command want to output multiple bytes. */
+ if (dev->status & STAT_IFULL) {
+ /* Data from host aborts dumping. */
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ kbc_ibf_process(dev);
+ }
+ /* Do not continue dumping until OBF is clear. */
+ if (!(dev->status & STAT_OFULL)) {
+ kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff);
+ add_to_kbc_queue_front(dev, dev->key_ctrl_queue[dev->key_ctrl_queue_start], 0, 0x00);
+ dev->key_ctrl_queue_start = (dev->key_ctrl_queue_start + 1) & 0x3f;
+ if (dev->key_ctrl_queue_start == dev->key_ctrl_queue_end)
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ }
+ break;
+ case KBC_STATE_KBC_PARAM:
+ /* Keyboard controller command wants data, wait for said data. */
+ if (dev->status & STAT_IFULL) {
+ /* Command written, abort current command. */
+ if (dev->status & STAT_CD)
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+
+ dev->status &= ~STAT_IFULL;
+ kbc_process_cmd(dev);
+ }
+ break;
+ case KBC_STATE_SEND_KBD:
+ if (!dev->key_wantcmd)
+ dev->kbc_state = KBC_STATE_SCAN_KBD;
+ break;
+ case KBC_STATE_SCAN_KBD:
+ (void) kbc_scan_kbd_ps2(dev);
+ break;
+ case KBC_STATE_SEND_MOUSE:
+ if (!dev->mouse_wantcmd)
+ dev->kbc_state = KBC_STATE_SCAN_MOUSE;
+ break;
+ case KBC_STATE_SCAN_MOUSE:
+ (void) kbc_scan_aux_ps2(dev);
+ break;
+ }
+}
+
+static void
+kbc_poll_kbd(atkbd_t *dev)
+{
+ switch (dev->kbd_state) {
+ case DEV_STATE_MAIN_1:
+ /* Process the command if needed and then return to main loop #2. */
+ if (dev->key_wantcmd) {
+ kbd_log("ATkbc: Processing keyboard command %02X...\n", dev->key_dat);
+ kbc_queue_reset(dev, 4);
+ // dev->out_new = -1;
+ kbd_process_cmd(dev);
+ dev->key_wantcmd = 0;
+ } else
+ dev->kbd_state = DEV_STATE_MAIN_2;
+ break;
+ case DEV_STATE_MAIN_2:
+ /* Output from scan queue if needed and then return to main loop #1. */
+ if (keyboard_scan && (dev->out_new == -1) && (dev->key_queue_start != dev->key_queue_end)) {
+ kbd_log("ATkbc: %02X (DATA) on channel 1\n", dev->key_queue[dev->key_queue_start]);
+ dev->out_new = dev->key_queue[dev->key_queue_start];
+ dev->key_queue_start = (dev->key_queue_start + 1) & 0xf;
+ }
+ if (!keyboard_scan || dev->key_wantcmd)
+ dev->kbd_state = DEV_STATE_MAIN_1;
+ break;
+ case DEV_STATE_MAIN_OUT:
+ /* If host wants to send command while we're sending a byte to host, process the command. */
+ if (dev->key_wantcmd) {
+ kbd_log("ATkbc: Processing keyboard command %02X...\n", dev->key_dat);
+ kbc_queue_reset(dev, 4);
+ kbd_process_cmd(dev);
+ dev->key_wantcmd = 0;
+ break;
+ }
+ /* FALLTHROUGH */
+ case DEV_STATE_MAIN_WANT_IN:
+ /* Output command response and then wait for host data. */
+ if ((dev->out_new == -1) && (dev->key_cmd_queue_start != dev->key_cmd_queue_end)) {
+ kbd_log("ATkbc: %02X (CMD ) on channel 1\n", dev->key_cmd_queue[dev->key_cmd_queue_start]);
+ dev->out_new = dev->key_cmd_queue[dev->key_cmd_queue_start];
+ dev->key_cmd_queue_start = (dev->key_cmd_queue_start + 1) & 0xf;
+ }
+ if (dev->key_cmd_queue_start == dev->key_cmd_queue_end)
+ dev->kbd_state = (dev->kbd_state == DEV_STATE_MAIN_OUT) ? DEV_STATE_MAIN_2 : DEV_STATE_MAIN_IN;
+ break;
+ case DEV_STATE_MAIN_IN:
+ /* Wait for host data. */
+ if (dev->key_wantcmd) {
+ kbd_log("ATkbc: Processing keyboard command %02X parameter %02X...\n", dev->key_command, dev->key_dat);
+ kbc_queue_reset(dev, 4);
+ // dev->out_new = -1;
+ kbd_process_cmd(dev);
+ dev->key_wantcmd = 0;
+ }
+ break;
+ }
+}
+
+static void
+kbc_poll_aux(atkbd_t *dev)
+{
+ switch (dev->mouse_state) {
+ case DEV_STATE_MAIN_1:
+ /* Process the command if needed and then return to main loop #2. */
+ if (dev->mouse_wantcmd) {
+ kbd_log("ATkbc: Processing mouse command %02X...\n", dev->mouse_dat);
+ kbc_queue_reset(dev, 3);
+ // dev->out_new_mouse = -1;
+ dev->mouse_state = DEV_STATE_MAIN_OUT;
+ mouse_write(dev->mouse_dat, mouse_p);
+ if ((dev->mouse_dat == 0xe8) || (dev->mouse_dat == 0xf3))
+ dev->mouse_state = DEV_STATE_MAIN_WANT_IN;
+ dev->mouse_wantcmd = 0;
+ } else
+ dev->mouse_state = DEV_STATE_MAIN_2;
+ break;
+ case DEV_STATE_MAIN_2:
+ /* Output from scan queue if needed and then return to main loop #1. */
+ if (mouse_scan && (dev->out_new_mouse == -1) && (dev->mouse_queue_start != dev->mouse_queue_end)) {
+ kbd_log("ATkbc: %02X (DATA) on channel 2\n", dev->mouse_queue[dev->mouse_queue_start]);
+ dev->out_new_mouse = dev->mouse_queue[dev->mouse_queue_start];
+ dev->mouse_queue_start = (dev->mouse_queue_start + 1) & 0xf;
+ }
+ if (!mouse_scan || dev->mouse_wantcmd)
+ dev->mouse_state = DEV_STATE_MAIN_1;
+ break;
+ case DEV_STATE_MAIN_OUT:
+ /* If host wants to send command while we're sending a byte to host, process the command. */
+ if (dev->mouse_wantcmd) {
+ kbd_log("ATkbc: Processing mouse command %02X...\n", dev->mouse_dat);
+ kbc_queue_reset(dev, 3);
+ dev->mouse_state = DEV_STATE_MAIN_OUT;
+ mouse_write(dev->mouse_dat, mouse_p);
+ if ((dev->mouse_dat == 0xe8) || (dev->mouse_dat == 0xf3))
+ dev->mouse_state = DEV_STATE_MAIN_WANT_IN;
+ dev->mouse_wantcmd = 0;
+ break;
+ }
+ /* FALLTHROUGH */
+ case DEV_STATE_MAIN_WANT_IN:
+ /* Output command response and then wait for host data. */
+ if ((dev->out_new_mouse == -1) && (dev->mouse_cmd_queue_start != dev->mouse_cmd_queue_end)) {
+ kbd_log("ATkbc: %02X (CMD ) on channel 2\n", dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]);
+ dev->out_new_mouse = dev->mouse_cmd_queue[dev->mouse_cmd_queue_start];
+ dev->mouse_cmd_queue_start = (dev->mouse_cmd_queue_start + 1) & 0xf;
+ }
+ if (dev->mouse_cmd_queue_start == dev->mouse_cmd_queue_end)
+ dev->mouse_state = (dev->mouse_state == DEV_STATE_MAIN_OUT) ? DEV_STATE_MAIN_2 : DEV_STATE_MAIN_IN;
+ break;
+ case DEV_STATE_MAIN_IN:
+ /* Wait for host data. */
+ if (dev->mouse_wantcmd) {
+ kbd_log("ATkbc: Processing mouse command parameter %02X...\n", dev->mouse_dat);
+ kbc_queue_reset(dev, 3);
+ // dev->out_new_mouse = -1;
+ dev->mouse_state = DEV_STATE_MAIN_OUT;
+ mouse_write(dev->mouse_dat, mouse_p);
+ dev->mouse_wantcmd = 0;
+ }
+ break;
+ }
+}
+
+/* TODO: State machines for controller, keyboard, and mouse. */
+static void
+kbd_poll(void *priv)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC));
+
+ /* TODO: Use a fuction pointer for this (also needed to the AMI KBC mode switching)
+ and implement the password security state. */
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)
+ kbc_poll_ps2(dev);
+ else
+ kbc_poll_at(dev);
+
+ kbc_poll_kbd(dev);
+
+ if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && mouse_write)
+ kbc_poll_aux(dev);
+
+ // if (kbc_ports[0] && kbc_ports[0]>-priv)
+ // kbc_ports[0]>poll(kbc_ports[0]>-priv);
+
+ // if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && kbc_ports[1] && kbc_ports[1]>-priv)
+ // kbc_ports[1]>poll(kbc_ports[1]>-priv);
+}
+
+static void
+add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ add_data_kbd_queue(dev, val[i]);
+}
+
+static void
+add_data_kbd(uint16_t val)
+{
+ atkbd_t *dev = SavedKbd;
+ uint8_t fake_shift[4];
+ uint8_t num_lock = 0, shift_states = 0;
+
+ keyboard_get_states(NULL, &num_lock, NULL);
+ shift_states = keyboard_get_shift() & STATE_SHIFT_MASK;
+
+ switch (val) {
+ case FAKE_LSHIFT_ON:
+ kbd_log("fake left shift on, scan code: ");
+ if (num_lock) {
+ if (shift_states) {
+ kbd_log("N/A (one or both shifts on)\n");
+ break;
+ } else {
+ /* Num lock on and no shifts are pressed, send non-inverted fake shift. */
+ switch (keyboard_mode & 0x02) {
+ case 1:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0x2a;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ case 2:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0x12;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ default:
+ kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02);
+ break;
+ }
+ }
+ } else {
+ if (shift_states & STATE_LSHIFT) {
+ /* Num lock off and left shift pressed. */
+ switch (keyboard_mode & 0x02) {
+ case 1:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0xaa;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ case 2:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0xf0;
+ fake_shift[2] = 0x12;
+ add_data_vals(dev, fake_shift, 3);
+ break;
+
+ default:
+ kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02);
+ break;
+ }
+ }
+ if (shift_states & STATE_RSHIFT) {
+ /* Num lock off and right shift pressed. */
+ switch (keyboard_mode & 0x02) {
+ case 1:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0xb6;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ case 2:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0xf0;
+ fake_shift[2] = 0x59;
+ add_data_vals(dev, fake_shift, 3);
+ break;
+
+ default:
+ kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02);
+ break;
+ }
+ }
+ kbd_log(shift_states ? "" : "N/A (both shifts off)\n");
+ }
+ break;
+
+ case FAKE_LSHIFT_OFF:
+ kbd_log("fake left shift on, scan code: ");
+ if (num_lock) {
+ if (shift_states) {
+ kbd_log("N/A (one or both shifts on)\n");
+ break;
+ } else {
+ /* Num lock on and no shifts are pressed, send non-inverted fake shift. */
+ switch (keyboard_mode & 0x02) {
+ case 1:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0xaa;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ case 2:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0xf0;
+ fake_shift[2] = 0x12;
+ add_data_vals(dev, fake_shift, 3);
+ break;
+
+ default:
+ kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02);
+ break;
+ }
+ }
+ } else {
+ if (shift_states & STATE_LSHIFT) {
+ /* Num lock off and left shift pressed. */
+ switch (keyboard_mode & 0x02) {
+ case 1:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0x2a;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ case 2:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0x12;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ default:
+ kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02);
+ break;
+ }
+ }
+ if (shift_states & STATE_RSHIFT) {
+ /* Num lock off and right shift pressed. */
+ switch (keyboard_mode & 0x02) {
+ case 1:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0x36;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ case 2:
+ fake_shift[0] = 0xe0;
+ fake_shift[1] = 0x59;
+ add_data_vals(dev, fake_shift, 2);
+ break;
+
+ default:
+ kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02);
+ break;
+ }
+ }
+ kbd_log(shift_states ? "" : "N/A (both shifts off)\n");
+ }
+ break;
+
+ default:
+ add_data_kbd_queue(dev, val);
+ break;
+ }
+}
+
+static void
+write_output(atkbd_t *dev, uint8_t val)
+{
+ uint8_t old = dev->output_port;
+ kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port);
+
+ uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
+
+#if 0
+ /* PS/2: Handle IRQ's. */
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ /* IRQ 12 */
+ picint_common(1 << 12, 0, val & 0x20);
+
+ /* IRQ 1 */
+ picint_common(1 << 1, 0, val & 0x10);
+ }
+#endif
+
+ /* AT, PS/2: Handle A20. */
+ if ((old ^ val) & 0x02) { /* A20 enable change */
+ mem_a20_key = val & 0x02;
+ mem_a20_recalc();
+ flushmmucache();
+ }
+
+ /* AT, PS/2: Handle reset. */
+ /* 0 holds the CPU in the RESET state, 1 releases it. To simplify this,
+ we just do everything on release. */
+ if ((old ^ val) & 0x01) { /*Reset*/
+ if (!(val & 0x01)) { /* Pin 0 selected. */
+ /* Pin 0 selected. */
+ kbd_log("write_output(): Pulse reset!\n");
+ if (machines[machine].flags & MACHINE_COREBOOT) {
+ /* The SeaBIOS hard reset code attempts a KBC reset if ACPI RESET_REG
+ is not available. However, the KBC reset is normally a soft reset, so
+ SeaBIOS gets caught in a soft reset loop as it tries to hard reset the
+ machine. Hack around this by making the KBC reset a hard reset only on
+ coreboot machines. */
+ pc_reset_hard();
+ } else {
+ softresetx86(); /*Pulse reset!*/
+ cpu_set_edx();
+ flushmmucache();
+ if (kbc_ven == KBC_VEN_ALI)
+ smbase = 0x00030000;
+ }
+ }
+ }
+
+ /* Do this here to avoid an infinite reset loop. */
+ dev->output_port = val;
+}
+
+static void
+write_output_fast_a20(atkbd_t *dev, uint8_t val)
+{
+ uint8_t old = dev->output_port;
+ kbd_log("ATkbc: write output port in fast A20 mode: %02X (old: %02X)\n", val, dev->output_port);
+
+ /* AT, PS/2: Handle A20. */
+ if ((old ^ val) & 0x02) { /* A20 enable change */
+ mem_a20_key = val & 0x02;
+ mem_a20_recalc();
+ flushmmucache();
+ }
+
+ /* Do this here to avoid an infinite reset loop. */
+ dev->output_port = val;
+}
+
+static void
+write_cmd(atkbd_t *dev, uint8_t val)
+{
+ kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]);
+
+ /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */
+ if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) {
+ val &= ~CCB_TRANSLATE;
+ dev->mem[0x20] &= ~CCB_TRANSLATE;
+ } else if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ if (val & 0x10)
+ dev->mem[0x2e] = 0x01;
+ }
+
+ kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled");
+
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ /* Update the output port to mirror the IBF and OBF bits, if active. */
+ write_output(dev, (dev->output_port & 0x0f) | ((val & 0x03) << 4) | ((val & 0x20) ? 0xc0 : 0x00));
+ }
+
+ kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val);
+
+ dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG);
+}
+
+static void
+pulse_output(atkbd_t *dev, uint8_t mask)
+{
+ if (mask != 0x0f) {
+ dev->old_output_port = dev->output_port & ~(0xf0 | mask);
+ kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask));
+ write_output(dev, dev->output_port & (0xf0 | mask));
+ timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC);
+ }
+}
+
+static void
+pulse_poll(void *priv)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port);
+ write_output(dev, dev->output_port | dev->old_output_port);
+}
+
+static uint8_t
+write64_generic(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+ uint8_t current_drive, fixed_bits;
+ uint8_t kbc_ven = 0x0;
+ kbc_ven = dev->flags & KBC_VEN_MASK;
+
+ switch (val) {
+ case 0xa4: /* check if password installed */
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: check if password installed\n");
+ add_to_kbc_queue_front(dev, 0xf1, 0, 0x00);
+ return 0;
+ }
+ break;
+
+ case 0xa7: /* disable mouse port */
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: disable mouse port\n");
+ set_enable_mouse(dev, 0);
+ return 0;
+ }
+ break;
+
+ case 0xa8: /*Enable mouse port*/
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: enable mouse port\n");
+ set_enable_mouse(dev, 1);
+ return 0;
+ }
+ break;
+
+ case 0xa9: /*Test mouse port*/
+ kbd_log("ATkbc: test mouse port\n");
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00); /* no error, this is testing the channel 2 interface */
+ return 0;
+ }
+ break;
+
+ case 0xaf: /* read keyboard version */
+ kbd_log("ATkbc: read keyboard version\n");
+ add_to_kbc_queue_front(dev, 0x42, 0, 0x00);
+ return 0;
+
+ case 0xc0: /* read input port */
+ kbd_log("ATkbc: read input port\n");
+ fixed_bits = 4;
+ /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */
+ if (kbc_ven == KBC_VEN_INTEL_AMI)
+ fixed_bits |= 0x40;
+ if (kbc_ven == KBC_VEN_IBM_PS1) {
+ current_drive = fdc_get_current_drive();
+ add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00),
+ 0, 0x00);
+ dev->input_port = ((dev->input_port + 1) & 3) | (dev->input_port & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00);
+ } else if (kbc_ven == KBC_VEN_NCR) {
+ /* switch settings
+ * bit 7: keyboard disable
+ * bit 6: display type (0 color, 1 mono)
+ * bit 5: power-on default speed (0 high, 1 low)
+ * bit 4: sense RAM size (0 unsupported, 1 512k on system board)
+ * bit 3: coprocessor detect
+ * bit 2: unused
+ * bit 1: high/auto speed
+ * bit 0: dma mode
+ */
+ add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf,
+ 0, 0x00);
+ dev->input_port = ((dev->input_port + 1) & 3) | (dev->input_port & 0xfc);
+ } else {
+ if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN)) {
+ /* Bit 3, 2:
+ 1, 1: TriGem logo;
+ 1, 0: Garbled logo;
+ 0, 1: Epson logo;
+ 0, 0: Generic AMI logo. */
+ if (dev->pci)
+ fixed_bits |= 8;
+ add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00);
+ } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI))
+#if 0
+ add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) &
+ (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00);
+#else
+ add_to_kbc_queue_front(dev, ((dev->input_port | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00);
+#endif
+ else
+ add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00);
+ dev->input_port = ((dev->input_port + 1) & 3) | (dev->input_port & 0xfc);
+ }
+ return 0;
+
+ case 0xd3: /* write mouse output buffer */
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: write mouse output buffer\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ return 0;
+ }
+ break;
+
+ case 0xd4: /* write to mouse */
+ kbd_log("ATkbc: write to mouse\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ return 0;
+
+ case 0xf0 ... 0xff:
+ kbd_log("ATkbc: pulse %01X\n", val & 0x0f);
+ pulse_output(dev, val & 0x0f);
+ return 0;
+ }
+
+ kbd_log("ATkbc: bad command %02X\n", val);
+ return 1;
+}
+
+static uint8_t
+write60_ami(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ switch (dev->command) {
+ /* 0x40 - 0x5F are aliases for 0x60-0x7F */
+ case 0x40 ... 0x5f:
+ kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command);
+ dev->mem[(dev->command & 0x1f) + 0x20] = val;
+ if (dev->command == 0x60)
+ write_cmd(dev, val);
+ return 0;
+
+ case 0xa5: /* get extended controller RAM */
+ kbd_log("ATkbc: AMI - get extended controller RAM\n");
+ add_to_kbc_queue_front(dev, dev->mem[val], 0, 0x00);
+ return 0;
+
+ case 0xaf: /* set extended controller RAM */
+ kbd_log("ATkbc: AMI - set extended controller RAM\n");
+ if (dev->secr_phase == 1) {
+ dev->mem_addr = val;
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ dev->secr_phase = 2;
+ } else if (dev->secr_phase == 2) {
+ dev->mem[dev->mem_addr] = val;
+ dev->secr_phase = 0;
+ }
+ return 0;
+
+ case 0xc1:
+ kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val);
+ dev->input_port = val;
+ return 0;
+
+ case 0xcb: /* set keyboard mode */
+ kbd_log("ATkbc: AMI - set keyboard mode\n");
+ dev->ami_flags = val;
+ return 0;
+ }
+
+ return 1;
+}
+
+static uint8_t
+write64_ami(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+ uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
+
+ switch (val) {
+ case 0x00 ... 0x1f:
+ kbd_log("ATkbc: AMI - alias read from %08X\n", val);
+ add_to_kbc_queue_front(dev, dev->mem[val + 0x20], 0, 0x00);
+ return 0;
+
+ case 0x40 ... 0x5f:
+ kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command);
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ return 0;
+
+ case 0xa0: /* copyright message */
+ kbc_queue_add(dev, 0x28, 0);
+ kbc_queue_add(dev, 0x00, 0);
+ dev->kbc_state = KBC_STATE_KBC_OUT;
+ break;
+
+ case 0xa1: /* get controller version */
+ kbd_log("ATkbc: AMI - get controller version\n");
+ if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN))
+ add_to_kbc_queue_front(dev, 'Z', 0, 0x00);
+ else if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ if (kbc_ven == KBC_VEN_ALI)
+ add_to_kbc_queue_front(dev, 'F', 0, 0x00);
+ else if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_INTEL_AMI)
+ add_to_kbc_queue_front(dev, '5', 0, 0x00);
+ else if (cpu_64bitbus)
+ add_to_kbc_queue_front(dev, 'R', 0, 0x00);
+ else if (is486)
+ add_to_kbc_queue_front(dev, 'P', 0, 0x00);
+ else
+ add_to_kbc_queue_front(dev, 'H', 0, 0x00);
+ } else if (is386 && !is486) {
+ if (cpu_16bitbus)
+ add_to_kbc_queue_front(dev, 'D', 0, 0x00);
+ else
+ add_to_kbc_queue_front(dev, 'B', 0, 0x00);
+ } else if (!is386)
+ add_to_kbc_queue_front(dev, '8', 0, 0x00);
+ else
+ add_to_kbc_queue_front(dev, 'F', 0, 0x00);
+ return 0;
+
+ case 0xa2: /* clear keyboard controller lines P22/P23 */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n");
+ write_output(dev, dev->output_port & 0xf3);
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+ }
+ break;
+
+ case 0xa3: /* set keyboard controller lines P22/P23 */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n");
+ write_output(dev, dev->output_port | 0x0c);
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+ }
+ break;
+
+ case 0xa4: /* write clock = low */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: AMI - write clock = low\n");
+ dev->ami_stat &= 0xfe;
+ return 0;
+ }
+ break;
+
+ case 0xa5: /* write clock = high */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: AMI - write clock = high\n");
+ dev->ami_stat |= 0x01;
+ } else {
+ kbd_log("ATkbc: get extended controller RAM\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ }
+ return 0;
+
+ case 0xa6: /* read clock */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: AMI - read clock\n");
+ add_to_kbc_queue_front(dev, (dev->ami_stat & 1) ? 0xff : 0x00, 0, 0x00);
+ return 0;
+ }
+ break;
+
+ case 0xa7: /* write cache bad */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: AMI - write cache bad\n");
+ dev->ami_stat &= 0xfd;
+ return 0;
+ }
+ break;
+
+ case 0xa8: /* write cache good */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: AMI - write cache good\n");
+ dev->ami_stat |= 0x02;
+ return 0;
+ }
+ break;
+
+ case 0xa9: /* read cache */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: AMI - read cache\n");
+ add_to_kbc_queue_front(dev, (dev->ami_stat & 2) ? 0xff : 0x00, 0, 0x00);
+ return 0;
+ }
+ break;
+
+ case 0xaf: /* set extended controller RAM */
+ if (kbc_ven == KBC_VEN_ALI) {
+ kbd_log("ATkbc: Award/ALi/VIA keyboard controller revision\n");
+ add_to_kbc_queue_front(dev, 0x43, 0, 0x00);
+ } else {
+ kbd_log("ATkbc: set extended controller RAM\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ dev->secr_phase = 1;
+ }
+ return 0;
+
+ case 0xb0 ... 0xb3:
+ /* set KBC lines P10-P13 (input port bits 0-3) low */
+ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n");
+ if (!(dev->flags & DEVICE_PCI) || (val > 0xb1))
+ dev->input_port &= ~(1 << (val & 0x03));
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+
+ case 0xb4: case 0xb5:
+ /* set KBC lines P22-P23 (output port bits 2-3) low */
+ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n");
+ if (!(dev->flags & DEVICE_PCI))
+ write_output(dev, dev->output_port & ~(4 << (val & 0x01)));
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+
+ case 0xb8 ... 0xbb:
+ /* set KBC lines P10-P13 (input port bits 0-3) high */
+ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n");
+ if (!(dev->flags & DEVICE_PCI) || (val > 0xb9)) {
+ dev->input_port |= (1 << (val & 0x03));
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ }
+ return 0;
+
+ case 0xbc: case 0xbd:
+ /* set KBC lines P22-P23 (output port bits 2-3) high */
+ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n");
+ if (!(dev->flags & DEVICE_PCI))
+ write_output(dev, dev->output_port | (4 << (val & 0x01)));
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+
+ case 0xc1: /* write input port */
+ kbd_log("ATkbc: AMI MegaKey - write input port\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ return 0;
+
+ case 0xc4:
+ /* set KBC line P14 low */
+ kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n");
+ dev->input_port &= 0xef;
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+ case 0xc5:
+ /* set KBC line P15 low */
+ kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n");
+ dev->input_port &= 0xdf;
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+
+ case 0xc8:
+ /*
+ * unblock KBC lines P22/P23
+ * (allow command D1 to change bits 2/3 of the output port)
+ */
+ kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n");
+ dev->ami_flags &= 0xfb;
+ return 0;
+
+ case 0xc9:
+ /*
+ * block KBC lines P22/P23
+ * (disallow command D1 from changing bits 2/3 of the port)
+ */
+ kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n");
+ dev->ami_flags |= 0x04;
+ return 0;
+
+ case 0xcc:
+ /* set KBC line P14 high */
+ kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n");
+ dev->input_port |= 0x10;
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+ case 0xcd:
+ /* set KBC line P15 high */
+ kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n");
+ dev->input_port |= 0x20;
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+
+ case 0xef: /* ??? - sent by AMI486 */
+ kbd_log("ATkbc: ??? - sent by AMI486\n");
+ return 0;
+ }
+
+ return write64_generic(dev, val);
+}
+
+static uint8_t
+write64_ibm_mca(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ switch (val) {
+ case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/
+ kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n");
+ dev->status &= 0x0f;
+ dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4);
+ return 0;
+
+ case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/
+ kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n");
+ dev->status &= 0x0f;
+ dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0);
+ return 0;
+
+ case 0xaf:
+ kbd_log("ATkbc: bad KBC command AF\n");
+ return 1;
+
+ case 0xf0 ... 0xff:
+ kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c);
+ pulse_output(dev, (val & 0x03) | 0x0c);
+ return 0;
+ }
+
+ return write64_generic(dev, val);
+}
+
+static uint8_t
+write60_quadtel(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ switch (dev->command) {
+ case 0xcf: /*??? - sent by MegaPC BIOS*/
+ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static uint8_t
+write64_olivetti(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ switch (val) {
+ case 0x80: /* Olivetti-specific command */
+ /*
+ * bit 7: bus expansion board present (M300) / keyboard unlocked (M290)
+ * bits 4-6: ???
+ * bit 3: fast ram check (if inactive keyboard works erratically)
+ * bit 2: keyboard fuse present
+ * bits 0-1: ???
+ */
+ add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00);
+ dev->input_port = ((dev->input_port + 1) & 3) | (dev->input_port & 0xfc);
+ return 0;
+ }
+
+ return write64_generic(dev, val);
+}
+
+static uint8_t
+write64_quadtel(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ switch (val) {
+ case 0xaf:
+ kbd_log("ATkbc: bad KBC command AF\n");
+ return 1;
+
+ case 0xcf: /*??? - sent by MegaPC BIOS*/
+ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ return 0;
+ }
+
+ return write64_generic(dev, val);
+}
+
+static uint8_t
+write60_toshiba(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ switch (dev->command) {
+ case 0xb6: /* T3100e - set color/mono switch */
+ kbd_log("ATkbc: T3100e - set color/mono switch\n");
+ t3100e_mono_set(val);
+ return 0;
+ }
+
+ return 1;
+}
+
+static uint8_t
+write64_toshiba(void *priv, uint8_t val)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ switch (val) {
+ case 0xaf:
+ kbd_log("ATkbc: bad KBC command AF\n");
+ return 1;
+
+ case 0xb0: /* T3100e: Turbo on */
+ kbd_log("ATkbc: T3100e: Turbo on\n");
+ t3100e_turbo_set(1);
+ return 0;
+
+ case 0xb1: /* T3100e: Turbo off */
+ kbd_log("ATkbc: T3100e: Turbo off\n");
+ t3100e_turbo_set(0);
+ return 0;
+
+ case 0xb2: /* T3100e: Select external display */
+ kbd_log("ATkbc: T3100e: Select external display\n");
+ t3100e_display_set(0x00);
+ return 0;
+
+ case 0xb3: /* T3100e: Select internal display */
+ kbd_log("ATkbc: T3100e: Select internal display\n");
+ t3100e_display_set(0x01);
+ return 0;
+
+ case 0xb4: /* T3100e: Get configuration / status */
+ kbd_log("ATkbc: T3100e: Get configuration / status\n");
+ add_to_kbc_queue_front(dev, t3100e_config_get(), 0, 0x00);
+ return 0;
+
+ case 0xb5: /* T3100e: Get colour / mono byte */
+ kbd_log("ATkbc: T3100e: Get colour / mono byte\n");
+ add_to_kbc_queue_front(dev, t3100e_mono_get(), 0, 0x00);
+ return 0;
+
+ case 0xb6: /* T3100e: Set colour / mono byte */
+ kbd_log("ATkbc: T3100e: Set colour / mono byte\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ return 0;
+
+ case 0xb7: /* T3100e: Emulate PS/2 keyboard */
+ case 0xb8: /* T3100e: Emulate AT keyboard */
+ dev->flags &= ~KBC_TYPE_MASK;
+ if (val == 0xb7) {
+ kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n");
+ dev->flags |= KBC_TYPE_PS2_NOREF;
+ } else {
+ kbd_log("ATkbc: T3100e: Emulate AT keyboard\n");
+ dev->flags |= KBC_TYPE_ISA;
+ }
+ return 0;
+
+ case 0xbb: /* T3100e: Read 'Fn' key.
+ Return it for right Ctrl and right Alt; on the real
+ T3100e, these keystrokes could only be generated
+ using 'Fn'. */
+ kbd_log("ATkbc: T3100e: Read 'Fn' key\n");
+ if (keyboard_recv(0xb8) || /* Right Alt */
+ keyboard_recv(0x9d)) /* Right Ctrl */
+ add_to_kbc_queue_front(dev, 0x04, 0, 0x00);
+ else
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ return 0;
+
+ case 0xbc: /* T3100e: Reset Fn+Key notification */
+ kbd_log("ATkbc: T3100e: Reset Fn+Key notification\n");
+ t3100e_notify_set(0x00);
+ return 0;
+
+ case 0xc0: /*Read input port*/
+ kbd_log("ATkbc: read input port\n");
+
+ /* The T3100e returns all bits set except bit 6 which
+ * is set by t3100e_mono_set() */
+ dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf;
+ add_to_kbc_queue_front(dev, dev->input_port, 0, 0x00);
+ return 0;
+ }
+
+ return write64_generic(dev, val);
+}
+
+static void
+kbd_key_reset(atkbd_t *dev, int do_fa)
+{
+ dev->out_new = -1;
+ kbc_queue_reset(dev, 1);
+
+ dev->kbd_last_scan_code = 0x00;
+
+ /* Set scan code set to 2. */
+ keyboard_mode = 0x02;
+ set_scancode_map(dev);
+
+ /* The BAT enables scanning. */
+ keyboard_scan = 1;
+
+ dev->sc_or = 0;
+
+ if (do_fa)
+ add_data_kbd_front(dev, 0xfa);
+ add_data_kbd_front(dev, 0xaa);
+
+ if (!do_fa)
+ dev->kbd_state = DEV_STATE_MAIN_OUT;
+}
+
+static void
+kbd_aux_reset(atkbd_t *dev, int do_fa)
+{
+ dev->out_new_mouse = -1;
+ kbc_queue_reset(dev, 2);
+
+ /* The BAT enables scanning. */
+ mouse_scan = 1;
+
+ if (!do_fa) {
+ add_data_kbd_front(dev, 0xaa);
+ add_data_kbd_front(dev, 0x00);
+
+ dev->mouse_state = DEV_STATE_MAIN_OUT;
+ }
+}
+
+void
+keyboard_at_mouse_reset(void)
+{
+ atkbd_t *dev = SavedKbd;
+
+ kbd_aux_reset(dev, 1);
+}
+
+static void
+kbd_process_cmd(void *priv)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ dev->kbd_state = DEV_STATE_MAIN_OUT;
+
+ if (dev->key_wantdata) {
+ dev->key_wantdata = 0;
+
+ /*
+ * Several system BIOSes and OS device drivers
+ * mess up with this, and repeat the command
+ * code many times. Fun!
+ */
+ if (dev->key_dat == dev->key_command) {
+ /* Respond NAK and ignore it. */
+ add_data_kbd_front(dev, 0xfe);
+ dev->key_command = 0x00;
+ return;
+ }
+
+ switch (dev->key_command) {
+ case 0xed: /* set/reset LEDs */
+ add_data_kbd_front(dev, 0xfa);
+ kbd_log("ATkbd: set LEDs [%02x]\n", dev->key_dat);
+ break;
+
+ case 0xf0: /* get/set scancode set */
+ add_data_kbd_front(dev, 0xfa);
+ if (dev->key_dat == 0) {
+ kbd_log("Get scan code set: %02X\n", keyboard_mode);
+ add_data_kbd_front(dev, keyboard_mode);
+ } else {
+ if (dev->key_dat <= 3) {
+ keyboard_mode = dev->key_dat;
+ kbd_log("Scan code set now: %02X\n", keyboard_mode);
+ }
+ set_scancode_map(dev);
+ }
+ break;
+
+ case 0xf3: /* set typematic rate/delay */
+ add_data_kbd_front(dev, 0xfa);
+ break;
+
+ default:
+ kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", dev->key_dat, dev->key_command);
+ add_data_kbd_front(dev, 0xfe);
+ break;
+ }
+
+ /* Keyboard command is now done. */
+ dev->key_command = 0x00;
+ } else {
+ /* No keyboard command in progress. */
+ dev->key_command = 0x00;
+
+ switch (dev->key_dat) {
+ case 0x00 ... 0x7f:
+ kbd_log("ATkbd: invalid command %02X\n", dev->key_dat);
+ add_data_kbd_front(dev, 0xfe);
+ break;
+
+ case 0xed: /* set/reset LEDs */
+ kbd_log("ATkbd: set/reset leds\n");
+ add_data_kbd_front(dev, 0xfa);
+
+ dev->key_wantdata = 1;
+ dev->kbd_state = DEV_STATE_MAIN_WANT_IN;
+ break;
+
+ case 0xee: /* diagnostic echo */
+ kbd_log("ATkbd: ECHO\n");
+ add_data_kbd_front(dev, 0xee);
+ break;
+
+ case 0xef: /* NOP (reserved for future use) */
+ kbd_log("ATkbd: NOP\n");
+ break;
+
+ case 0xf0: /* get/set scan code set */
+ kbd_log("ATkbd: scan code set\n");
+ add_data_kbd_front(dev, 0xfa);
+ dev->key_wantdata = 1;
+ dev->kbd_state = DEV_STATE_MAIN_WANT_IN;
+ break;
+
+ case 0xf2: /* read ID */
+ kbd_log("ATkbd: read keyboard id\n");
+ /* TODO: After keyboard type selection is implemented, make this
+ return the correct keyboard ID for the selected type. */
+ add_data_kbd_front(dev, 0xfa);
+ add_data_kbd_front(dev, 0xab);
+ add_data_kbd_front(dev, 0x83);
+ break;
+
+ case 0xf3: /* set typematic rate/delay */
+ kbd_log("ATkbd: set typematic rate/delay\n");
+ add_data_kbd_front(dev, 0xfa);
+ dev->key_wantdata = 1;
+ dev->kbd_state = DEV_STATE_MAIN_WANT_IN;
+ break;
+
+ case 0xf4: /* enable keyboard */
+ kbd_log("ATkbd: enable keyboard\n");
+ add_data_kbd_front(dev, 0xfa);
+ keyboard_scan = 1;
+ break;
+
+ case 0xf5: /* set defaults and disable keyboard */
+ case 0xf6: /* set defaults */
+ kbd_log("ATkbd: set defaults%s\n", (dev->key_dat == 0xf6) ? "" : " and disable keyboard");
+ keyboard_scan = (dev->key_dat == 0xf6);
+ kbd_log("dev->key_dat = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n",
+ dev->key_dat, keyboard_scan, dev->mem[0]);
+ add_data_kbd_front(dev, 0xfa);
+
+ keyboard_set3_all_break = 0;
+ keyboard_set3_all_repeat = 0;
+ memset(keyboard_set3_flags, 0, 512);
+ keyboard_mode = 0x02;
+ set_scancode_map(dev);
+ break;
+
+ case 0xf7: /* set all keys to repeat */
+ kbd_log("ATkbd: set all keys to repeat\n");
+ add_data_kbd_front(dev, 0xfa);
+ keyboard_set3_all_break = 1;
+ break;
+
+ case 0xf8: /* set all keys to give make/break codes */
+ kbd_log("ATkbd: set all keys to give make/break codes\n");
+ add_data_kbd_front(dev, 0xfa);
+ keyboard_set3_all_break = 1;
+ break;
+
+ case 0xf9: /* set all keys to give make codes only */
+ kbd_log("ATkbd: set all keys to give make codes only\n");
+ add_data_kbd_front(dev, 0xfa);
+ keyboard_set3_all_break = 0;
+ break;
+
+ case 0xfa: /* set all keys to repeat and give make/break codes */
+ kbd_log("ATkbd: set all keys to repeat and give make/break codes\n");
+ add_data_kbd_front(dev, 0xfa);
+ keyboard_set3_all_repeat = 1;
+ keyboard_set3_all_break = 1;
+ break;
+
+ case 0xfe: /* resend last scan code */
+ kbd_log("ATkbd: resend last scan code\n");
+ add_data_kbd_front(dev, dev->kbd_last_scan_code);
+ break;
+
+ case 0xff: /* reset */
+ kbd_log("ATkbd: kbd reset\n");
+ kbd_key_reset(dev, 1);
+ break;
+
+ default:
+ kbd_log("ATkbd: bad keyboard command %02X\n", dev->key_dat);
+ add_data_kbd_front(dev, 0xfe);
+ }
+
+ /* If command needs data, remember command. */
+ if (dev->key_wantdata == 1)
+ dev->key_command = dev->key_dat;
+ }
+}
+
+static void
+kbc_process_cmd(void *priv)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+ int i = 0, bad = 1;
+ uint8_t mask, kbc_ven = dev->flags & KBC_VEN_MASK;
+ uint8_t cmd_ac_conv[16] = { 0x0b, 2, 3, 4, 5, 6, 7, 8, 9, 0x0a, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21 };
+
+ if (dev->status & STAT_CD) {
+ /* Controller command. */
+ dev->want60 = 0;
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+
+ /* Clear the keyboard controller queue. */
+ kbc_queue_reset(dev, 0);
+
+ switch (dev->ib) {
+ /* Read data from KBC memory. */
+ case 0x20 ... 0x3f:
+ add_to_kbc_queue_front(dev, dev->mem[dev->ib], 0, 0x00);
+ break;
+
+ /* Write data to KBC memory. */
+ case 0x60 ... 0x7f:
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ break;
+
+ case 0xaa: /* self-test */
+ kbd_log("ATkbc: self-test\n");
+
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ if (dev->kbc_state != KBC_STATE_RESET) {
+ kbd_log("ATkbc: self-test reinitialization\n");
+ /* Yes, the firmware has an OR, but we need to make sure to keep any forcibly lowered bytes lowered. */
+ /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */
+ dev->input_port = dev->input_port & 0xff;
+ write_output(dev, 0x4b);
+ }
+
+ dev->status = (dev->status & 0x0f) | 0x60;
+
+ dev->mem[0x20] = 0x30;
+ dev->mem[0x21] = 0x01;
+ dev->mem[0x22] = 0x0b;
+ dev->mem[0x25] = 0x02;
+ dev->mem[0x27] = 0xf8;
+ dev->mem[0x28] = 0xce;
+ dev->mem[0x29] = 0x0b;
+ dev->mem[0x2a] = 0x10;
+ dev->mem[0x2b] = 0x20;
+ dev->mem[0x2c] = 0x15;
+ dev->mem[0x30] = 0x0b;
+ } else {
+ if (dev->kbc_state != KBC_STATE_RESET) {
+ kbd_log("ATkbc: self-test reinitialization\n");
+ /* Yes, the firmware has an OR, but we need to make sure to keep any forcibly lowered bytes lowered. */
+ /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */
+ dev->input_port = dev->input_port & 0xff;
+ write_output(dev, 0xcf);
+ }
+
+ dev->status = (dev->status & 0x0f) | 0x60;
+
+ dev->mem[0x20] = 0x10;
+ dev->mem[0x21] = 0x01;
+ dev->mem[0x22] = 0x06;
+ dev->mem[0x25] = 0x01;
+ dev->mem[0x27] = 0xfb;
+ dev->mem[0x28] = 0xe0;
+ dev->mem[0x29] = 0x06;
+ dev->mem[0x2a] = 0x10;
+ dev->mem[0x2b] = 0x20;
+ dev->mem[0x2c] = 0x15;
+ }
+
+ dev->out_new = dev->out_new_mouse = -1;
+ kbc_queue_reset(dev, 0);
+
+ // dev->kbc_state = KBC_STATE_MAIN_IBF;
+ dev->kbc_state = KBC_STATE_KBC_OUT;
+
+ // add_to_kbc_queue_front(dev, 0x55, 0, 0x00);
+ kbc_queue_add(dev, 0x55, 0);
+ break;
+
+ case 0xab: /* interface test */
+ kbd_log("ATkbc: interface test\n");
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00); /*no error*/
+ break;
+
+ case 0xac: /* diagnostic dump */
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ kbd_log("ATkbc: diagnostic dump\n");
+ dev->mem[0x30] = (dev->input_port & 0xf0) | 0x80;
+ dev->mem[0x31] = dev->output_port;
+ dev->mem[0x32] = 0x00; /* T0 and T1. */
+ dev->mem[0x33] = 0x00; /* PSW - Program Status Word - always return 0x00 because we do not emulate this byte. */
+ /* 20 bytes in high nibble in set 1, low nibble in set 1, set 1 space format = 60 bytes. */
+ for (i = 0; i < 20; i++) {
+ kbc_queue_add(dev, cmd_ac_conv[dev->mem[i + 0x20] >> 4], 0);
+ kbc_queue_add(dev, cmd_ac_conv[dev->mem[i + 0x20] & 0x0f], 0);
+ kbc_queue_add(dev, 0x39, 0);
+ }
+ dev->kbc_state = KBC_STATE_KBC_OUT;
+ }
+ break;
+
+ case 0xad: /* disable keyboard */
+ kbd_log("ATkbc: disable keyboard\n");
+ set_enable_kbd(dev, 0);
+ break;
+
+ case 0xae: /* enable keyboard */
+ kbd_log("ATkbc: enable keyboard\n");
+ set_enable_kbd(dev, 1);
+ break;
+
+ case 0xc7: /* set port1 bits */
+ kbd_log("ATkbc: Phoenix - set port1 bits\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ break;
+
+ case 0xca: /* read keyboard mode */
+ kbd_log("ATkbc: AMI - read keyboard mode\n");
+ add_to_kbc_queue_front(dev, dev->ami_flags, 0, 0x00);
+ break;
+
+ case 0xcb: /* set keyboard mode */
+ kbd_log("ATkbc: AMI - set keyboard mode\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ break;
+
+ case 0xd0: /* read output port */
+ kbd_log("ATkbc: read output port\n");
+ mask = 0xff;
+ if ((kbc_ven != KBC_VEN_OLIVETTI) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0x20] & 0x10))
+ mask &= 0xbf;
+ add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00);
+ break;
+
+ case 0xd1: /* write output port */
+ kbd_log("ATkbc: write output port\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ break;
+
+ case 0xd2: /* write keyboard output buffer */
+ kbd_log("ATkbc: write keyboard output buffer\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ break;
+
+ case 0xdd: /* disable A20 address line */
+ case 0xdf: /* enable A20 address line */
+ kbd_log("ATkbc: %sable A20\n", (dev->ib == 0xdd) ? "dis" : "en");
+ write_output_fast_a20(dev, (dev->output_port & 0xfd) | (dev->ib & 0x02));
+ break;
+
+ case 0xe0: /* read test inputs */
+ kbd_log("ATkbc: read test inputs\n");
+ add_to_kbc_queue_front(dev, 0x00, 0, 0x00);
+ break;
+
+ default:
+ /*
+ * Unrecognized controller command.
+ *
+ * If we have a vendor-specific handler, run
+ * that. Otherwise, or if that handler fails,
+ * log a bad command.
+ */
+ if (dev->write64_ven)
+ bad = dev->write64_ven(dev, dev->ib);
+
+ kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", dev->ib);
+ }
+
+ /* If the command needs data, remember the command. */
+ if (dev->want60)
+ dev->command = dev->ib;
+ } else if (dev->want60) {
+ /* Write data to controller. */
+ dev->want60 = 0;
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+
+ switch (dev->command) {
+ case 0x60 ... 0x7f:
+ dev->mem[(dev->command & 0x1f) + 0x20] = dev->ib;
+ if (dev->command == 0x60)
+ write_cmd(dev, dev->ib);
+ break;
+
+ case 0xc7: /* set port1 bits */
+ kbd_log("ATkbc: Phoenix - set port1 bits\n");
+ dev->input_port |= dev->ib;
+ break;
+
+ case 0xd1: /* write output port */
+ kbd_log("ATkbc: write output port\n");
+ /* Bit 2 of AMI flags is P22-P23 blocked (1 = yes, 0 = no),
+ discovered by reverse-engineering the AOpen Vi15G BIOS. */
+ if (dev->ami_flags & 0x04) {
+ /* If keyboard controller lines P22-P23 are blocked,
+ we force them to remain unchanged. */
+ dev->ib &= ~0x0c;
+ dev->ib |= (dev->output_port & 0x0c);
+ }
+ write_output(dev, dev->ib | 0x01);
+ break;
+
+ case 0xd2: /* write to keyboard output buffer */
+ kbd_log("ATkbc: write to keyboard output buffer\n");
+ add_to_kbc_queue_front(dev, dev->ib, 0, 0x00);
+ break;
+
+ case 0xd3: /* write to mouse output buffer */
+ kbd_log("ATkbc: write to mouse output buffer\n");
+ if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF))
+ keyboard_at_adddata_mouse(dev->ib);
+ break;
+
+ case 0xd4: /* write to mouse */
+ kbd_log("ATkbc: write to mouse (%02X)\n", dev->ib);
+
+ if (dev->ib == 0xbb)
+ break;
+
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ set_enable_mouse(dev, 1);
+ if (mouse_write) {
+ dev->mouse_wantcmd = 1;
+ dev->mouse_dat = dev->ib;
+ dev->kbc_state = KBC_STATE_SEND_MOUSE;
+ } else
+ add_to_kbc_queue_front(dev, 0xfe, 2, 0x40);
+ }
+ break;
+
+ default:
+ /*
+ * Run the vendor-specific handler
+ * if we have one. Otherwise, or if
+ * it returns an error, log a bad
+ * controller command.
+ */
+ if (dev->write60_ven)
+ bad = dev->write60_ven(dev, dev->ib);
+
+ if (bad) {
+ kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, dev->ib);
+ }
+ }
+ }
+}
+
+static void
+kbd_write(uint16_t port, uint8_t val, void *priv)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+
+ kbd_log((port == 0x61) ? "" : "[%04X:%08X] ATkbc: write(%04X) = %02X\n", CS, cpu_state.pc, port, val);
+
+ switch (port) {
+ case 0x60:
+ dev->status &= ~STAT_CD;
+ if (dev->want60 && (dev->command == 0xd1)) {
+ kbd_log("ATkbc: write output port\n");
+
+ /* Fast A20 - ignore all other bits. */
+ val = (val & 0x02) | (dev->output_port & 0xfd);
+
+ /* Bit 2 of AMI flags is P22-P23 blocked (1 = yes, 0 = no),
+ discovered by reverse-engineering the AOpeN Vi15G BIOS. */
+ if (dev->ami_flags & 0x04) {
+ /* If keyboard controller lines P22-P23 are blocked,
+ we force them to remain unchanged. */
+ val &= ~0x0c;
+ val |= (dev->output_port & 0x0c);
+ }
+
+ write_output_fast_a20(dev, val | 0x01);
+
+ dev->want60 = 0;
+ dev->kbc_state = KBC_STATE_MAIN_IBF;
+ return;
+ }
+ break;
+
+ case 0x64:
+ dev->status |= STAT_CD;
+ if (val == 0xd1) {
+ kbd_log("ATkbc: write output port\n");
+ dev->want60 = 1;
+ dev->kbc_state = KBC_STATE_KBC_PARAM;
+ dev->command = 0xd1;
+ return;
+ }
+ break;
+ }
+
+ dev->ib = val;
+ dev->status |= STAT_IFULL;
+}
+
+static uint8_t
+kbd_read(uint16_t port, void *priv)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+ uint8_t ret = 0xff;
+
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)
+ cycles -= ISA_CYCLES(8);
+
+ switch (port) {
+ case 0x60:
+ ret = dev->out;
+ dev->status &= ~STAT_OFULL;
+ /* TODO: IRQ is only tied to OBF on the AT KBC, on the PS/2 KBC, it is controlled by a bit the
+ output port (P2).
+ This also means that in AT mode, the IRQ is level-triggered. */
+ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)
+ picintc(1 << 1);
+ break;
+
+ case 0x64:
+ ret = dev->status;
+ break;
+
+ default:
+ kbd_log("ATkbc: read(%04x) invalid!\n",port);
+ break;
+ }
+
+ kbd_log((port == 0x61) ? "" : "[%04X:%08X] ATkbc: read (%04X) = %02X\n", CS, cpu_state.pc, port, ret);
+
+ return (ret);
+}
+
+static void
+kbd_reset(void *priv)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+ int i;
+ uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
+
+ dev->status = STAT_UNLOCKED;
+ dev->mem[0x20] = 0x01;
+ dev->mem[0x20] |= CCB_TRANSLATE;
+ dev->secr_phase = 0;
+ dev->key_wantdata = 0;
+
+ /* Set up the correct Video Type bits. */
+ if (!is286 || (kbc_ven == KBC_VEN_ACER))
+ dev->input_port = video_is_mda() ? 0xb0 : 0xf0;
+ else
+ dev->input_port = video_is_mda() ? 0xf0 : 0xb0;
+ kbd_log("ATkbc: input port = %02x\n", dev->input_port);
+
+ /* Enable keyboard, disable mouse. */
+ set_enable_kbd(dev, 0);
+ keyboard_scan = 0;
+ set_enable_mouse(dev, 0);
+ mouse_scan = 0;
+
+ dev->out_new = dev->out_new_mouse = -1;
+ for (i = 0; i < 3; i++)
+ kbc_queue_reset(dev, i);
+ dev->kbd_last_scan_code = 0;
+
+ dev->sc_or = 0;
+
+ keyboard_mode = 0x02;
+
+ memset(keyboard_set3_flags, 0, 512);
+
+ set_scancode_map(dev);
+
+ dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00;
+ dev->ami_stat |= 0x02;
+
+ dev->output_port = 0xcd;
+ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ write_output(dev, 0x4b);
+ } else {
+ /* The real thing writes CF and then AND's it with BF. */
+ write_output(dev, 0x8f);
+ }
+
+ /* Stage 1. */
+ dev->status = (dev->status & 0x0f) | (dev->input_port & 0xf0);
+
+ /* Reset the keyboard. */
+ kbd_key_reset(dev, 0);
+
+ /* Reset the mouse. */
+ kbd_aux_reset(dev, 0);
+}
+
+/* Reset the AT keyboard - this is needed for the PCI TRC and is done
+ until a better solution is found. */
+void
+keyboard_at_reset(void)
+{
+ kbd_reset(SavedKbd);
+}
+
+void
+kbc_at_a20_reset(void)
+{
+ if (SavedKbd) {
+ SavedKbd->output_port = 0xcd;
+ if ((SavedKbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) {
+ write_output(SavedKbd, 0x4b);
+ } else {
+ /* The real thing writes CF and then AND's it with BF. */
+ write_output(SavedKbd, 0x8f);
+ }
+ }
+}
+
+static void
+kbd_close(void *priv)
+{
+ atkbd_t *dev = (atkbd_t *) priv;
+ int i, max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 2 : 1;
+
+ kbd_reset(dev);
+
+ /* Stop timers. */
+ timer_disable(&dev->send_delay_timer);
+
+ keyboard_scan = 0;
+ keyboard_send = NULL;
+
+ /* Disable the scancode maps. */
+ keyboard_set_table(NULL);
+
+ SavedKbd = NULL;
+
+ for (i = 0; i < max_ports; i++) {
+ if (kbc_ports[i] != NULL) {
+ free(kbc_ports[i]);
+ kbc_ports[i] = NULL;
+ }
+ }
+
+ free(dev);
+}
+
+static void *
+kbd_init(const device_t *info)
+{
+ atkbd_t *dev;
+ int i, max_ports;
+
+ dev = (atkbd_t *) malloc(sizeof(atkbd_t));
+ memset(dev, 0x00, sizeof(atkbd_t));
+
+ dev->flags = info->local;
+ dev->pci = !!(info->flags & DEVICE_PCI);
+
+ /* We need this, sadly. */
+ SavedKbd = dev;
+
+ video_reset(gfxcard[0]);
+ kbd_reset(dev);
+
+ io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev);
+ io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev);
+ keyboard_send = add_data_kbd;
+
+ timer_add(&dev->send_delay_timer, kbd_poll, dev, 1);
+ timer_add(&dev->pulse_cb, pulse_poll, dev, 0);
+
+ dev->write60_ven = NULL;
+ dev->write64_ven = NULL;
+
+ switch (dev->flags & KBC_VEN_MASK) {
+ case KBC_VEN_ACER:
+ case KBC_VEN_GENERIC:
+ case KBC_VEN_NCR:
+ case KBC_VEN_IBM_PS1:
+ dev->write64_ven = write64_generic;
+ break;
+
+ case KBC_VEN_OLIVETTI:
+ dev->write64_ven = write64_olivetti;
+ break;
+
+ case KBC_VEN_AMI:
+ case KBC_VEN_INTEL_AMI:
+ case KBC_VEN_ALI:
+ case KBC_VEN_TG:
+ case KBC_VEN_TG_GREEN:
+ dev->write60_ven = write60_ami;
+ dev->write64_ven = write64_ami;
+ break;
+
+ case KBC_VEN_IBM_MCA:
+ dev->write64_ven = write64_ibm_mca;
+ break;
+
+ case KBC_VEN_QUADTEL:
+ dev->write60_ven = write60_quadtel;
+ dev->write64_ven = write64_quadtel;
+ break;
+
+ case KBC_VEN_TOSHIBA:
+ dev->write60_ven = write60_toshiba;
+ dev->write64_ven = write64_toshiba;
+ break;
+ }
+
+ max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 2 : 1;
+
+ for (i = 0; i < max_ports; i++) {
+ kbc_ports[i] = (kbc_port_t *) malloc(sizeof(kbc_port_t));
+ memset(kbc_ports[i], 0x00, sizeof(kbc_port_t));
+ }
+
+ return (dev);
+}
+
+const device_t keyboard_at_device = {
+ .name = "PC/AT Keyboard",
+ .internal_name = "keyboard_at",
+ .flags = 0,
+ .local = KBC_TYPE_ISA | KBC_VEN_GENERIC,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_at_ami_device = {
+ .name = "PC/AT Keyboard (AMI)",
+ .internal_name = "keyboard_at_ami",
+ .flags = 0,
+ .local = KBC_TYPE_ISA | KBC_VEN_AMI,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_at_tg_ami_device = {
+ .name = "PC/AT Keyboard (TriGem AMI)",
+ .internal_name = "keyboard_at_tg_ami",
+ .flags = 0,
+ .local = KBC_TYPE_ISA | KBC_VEN_TG,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_at_toshiba_device = {
+ .name = "PC/AT Keyboard (Toshiba)",
+ .internal_name = "keyboard_at_toshiba",
+ .flags = 0,
+ .local = KBC_TYPE_ISA | KBC_VEN_TOSHIBA,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_at_olivetti_device = {
+ .name = "PC/AT Keyboard (Olivetti)",
+ .internal_name = "keyboard_at_olivetti",
+ .flags = 0,
+ .local = KBC_TYPE_ISA | KBC_VEN_OLIVETTI,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_at_ncr_device = {
+ .name = "PC/AT Keyboard (NCR)",
+ .internal_name = "keyboard_at_ncr",
+ .flags = 0,
+ .local = KBC_TYPE_ISA | KBC_VEN_NCR,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_device = {
+ .name = "PS/2 Keyboard",
+ .internal_name = "keyboard_ps2",
+ .flags = 0,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_ps1_device = {
+ .name = "PS/2 Keyboard (IBM PS/1)",
+ .internal_name = "keyboard_ps2_ps1",
+ .flags = 0,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_ps1_pci_device = {
+ .name = "PS/2 Keyboard (IBM PS/1)",
+ .internal_name = "keyboard_ps2_ps1_pci",
+ .flags = DEVICE_PCI,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_xi8088_device = {
+ .name = "PS/2 Keyboard (Xi8088)",
+ .internal_name = "keyboard_ps2_xi8088",
+ .flags = 0,
+ .local = KBC_TYPE_PS2_1 | KBC_VEN_GENERIC,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_ami_device = {
+ .name = "PS/2 Keyboard (AMI)",
+ .internal_name = "keyboard_ps2_ami",
+ .flags = 0,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_tg_ami_device = {
+ .name = "PS/2 Keyboard (TriGem AMI)",
+ .internal_name = "keyboard_ps2_tg_ami",
+ .flags = 0,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_mca_device = {
+ .name = "PS/2 Keyboard",
+ .internal_name = "keyboard_ps2_mca",
+ .flags = 0,
+ .local = KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_mca_2_device = {
+ .name = "PS/2 Keyboard",
+ .internal_name = "keyboard_ps2_mca_2",
+ .flags = 0,
+ .local = KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_quadtel_device = {
+ .name = "PS/2 Keyboard (Quadtel/MegaPC)",
+ .internal_name = "keyboard_ps2_quadtel",
+ .flags = 0,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_pci_device = {
+ .name = "PS/2 Keyboard",
+ .internal_name = "keyboard_ps2_pci",
+ .flags = DEVICE_PCI,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_ami_pci_device = {
+ .name = "PS/2 Keyboard (AMI)",
+ .internal_name = "keyboard_ps2_ami_pci",
+ .flags = DEVICE_PCI,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_ali_pci_device = {
+ .name = "PS/2 Keyboard (ALi M5123/M1543C)",
+ .internal_name = "keyboard_ps2_ali_pci",
+ .flags = DEVICE_PCI,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ALI,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_intel_ami_pci_device = {
+ .name = "PS/2 Keyboard (AMI)",
+ .internal_name = "keyboard_ps2_intel_ami_pci",
+ .flags = DEVICE_PCI,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_tg_ami_pci_device = {
+ .name = "PS/2 Keyboard (TriGem AMI)",
+ .internal_name = "keyboard_ps2_tg_ami_pci",
+ .flags = DEVICE_PCI,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+const device_t keyboard_ps2_acer_pci_device = {
+ .name = "PS/2 Keyboard (Acer 90M002A)",
+ .internal_name = "keyboard_ps2_acer_pci",
+ .flags = DEVICE_PCI,
+ .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ACER,
+ .init = kbd_init,
+ .close = kbd_close,
+ .reset = kbd_reset,
+ { .available = NULL },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = NULL
+};
+
+void
+keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv)
+{
+ mouse_write = func;
+ mouse_p = priv;
+}
+
+void
+keyboard_at_adddata_mouse(uint8_t val)
+{
+ atkbd_t *dev = SavedKbd;
+
+ if (!mouse_scan || (dev->mouse_queue_end >= 16)) {
+ kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !mouse_scan, (dev->mouse_queue_end >= 16));
+ return;
+ }
+ kbc_queue_add(dev, val, 2);
+}
+
+void
+keyboard_at_adddata_mouse_cmd(uint8_t val)
+{
+ atkbd_t *dev = SavedKbd;
+
+ if (dev->mouse_cmd_queue_end >= 16) {
+ kbd_log("ATkbc: Unable to add to queue, dev->mouse_cmd_queue_end >= 16\n");
+ return;
+ }
+ kbc_queue_add(dev, val, 3);
+}
+
+uint8_t
+keyboard_at_mouse_pos(void)
+{
+ atkbd_t *dev = SavedKbd;
+
+ return ((dev->mouse_queue_end - dev->mouse_queue_start) & 0xf);
+}
+
+void
+keyboard_at_set_a20_key(int state)
+{
+ atkbd_t *dev = SavedKbd;
+
+ write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1));
+}
diff --git a/src/device/mouse_ps2 - Cópia.c b/src/device/mouse_ps2 - Cópia.c
new file mode 100644
index 000000000..1c8e0334d
--- /dev/null
+++ b/src/device/mouse_ps2 - Cópia.c
@@ -0,0 +1,404 @@
+/*
+ * 86Box A hypervisor and IBM PC system emulator that specializes in
+ * running old operating systems and software designed for IBM
+ * PC systems and compatibles from 1981 through fairly recent
+ * system designs based on the PCI bus.
+ *
+ * This file is part of the 86Box distribution.
+ *
+ * Implementation of PS/2 series Mouse devices.
+ *
+ *
+ *
+ * Authors: Fred N. van Kempen,
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#define HAVE_STDARG_H
+#include <86box/86box.h>
+#include <86box/device.h>
+#include <86box/keyboard.h>
+#include <86box/mouse.h>
+
+enum {
+ MODE_STREAM,
+ MODE_REMOTE,
+ MODE_ECHO
+};
+
+typedef struct {
+ const char *name; /* name of this device */
+ int8_t type; /* type of this device */
+
+ int mode;
+
+ uint16_t flags;
+ uint8_t resolution;
+ uint8_t sample_rate;
+
+ uint8_t command;
+
+ int x, y, z, b;
+
+ uint8_t last_data[6];
+} mouse_t;
+#define FLAG_5BTN 0x100 /* using Intellimouse Optical mode */
+#define FLAG_INTELLI 0x80 /* device is IntelliMouse */
+#define FLAG_INTMODE 0x40 /* using Intellimouse mode */
+#define FLAG_SCALED 0x20 /* enable delta scaling */
+#define FLAG_ENABLED 0x10 /* dev is enabled for use */
+#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */
+
+int mouse_scan = 0;
+
+#ifdef ENABLE_MOUSE_PS2_LOG
+int mouse_ps2_do_log = ENABLE_MOUSE_PS2_LOG;
+
+static void
+mouse_ps2_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (mouse_ps2_do_log) {
+ va_start(ap, fmt);
+ pclog_ex(fmt, ap);
+ va_end(ap);
+ }
+}
+#else
+# define mouse_ps2_log(fmt, ...)
+#endif
+
+void
+mouse_clear_data(void *priv)
+{
+ mouse_t *dev = (mouse_t *) priv;
+
+ dev->flags &= ~FLAG_CTRLDAT;
+}
+
+static void
+ps2_report_coordinates(mouse_t *dev, int cmd)
+{
+ uint8_t buff[3] = { 0x08, 0x00, 0x00 };
+ int temp_z;
+
+ if (dev->x > 255) {
+ dev->x = 255;
+ buff[0] |= 0x40;
+ }
+ if (dev->x < -256) {
+ dev->x = -256;
+ buff[0] |= 0x40;
+ }
+ if (dev->y > 255) {
+ dev->y = 255;
+ buff[0] |= 0x80;
+ }
+ if (dev->y < -256) {
+ dev->y = -256;
+ buff[0] |= 0x80;
+ }
+ if (dev->z < -8)
+ dev->z = -8;
+ if (dev->z > 7)
+ dev->z = 7;
+
+ if (dev->x < 0)
+ buff[0] |= 0x10;
+ if (dev->y < 0)
+ buff[0] |= 0x20;
+ if (mouse_buttons & 0x01)
+ buff[0] |= 0x01;
+ if (mouse_buttons & 0x02)
+ buff[0] |= 0x02;
+ if (dev->flags & FLAG_INTELLI) {
+ if (mouse_buttons & 0x04)
+ buff[0] |= 0x04;
+ }
+ buff[1] = (dev->x & 0xff);
+ buff[2] = (dev->y & 0xff);
+
+ if (cmd) {
+ keyboard_at_adddata_mouse_cmd(buff[0]);
+ keyboard_at_adddata_mouse_cmd(buff[1]);
+ keyboard_at_adddata_mouse_cmd(buff[2]);
+ } else {
+ keyboard_at_adddata_mouse(buff[0]);
+ keyboard_at_adddata_mouse(buff[1]);
+ keyboard_at_adddata_mouse(buff[2]);
+ }
+ if (dev->flags & FLAG_INTMODE) {
+ temp_z = dev->z & 0x0f;
+ if ((dev->flags & FLAG_5BTN)) {
+ if (mouse_buttons & 8)
+ temp_z |= 0x10;
+ if (mouse_buttons & 16)
+ temp_z |= 0x20;
+ } else {
+ /* The wheel coordinate is sign-extended. */
+ if (temp_z & 0x08)
+ temp_z |= 0xf0;
+ }
+ if (cmd)
+ keyboard_at_adddata_mouse_cmd(temp_z);
+ else
+ keyboard_at_adddata_mouse(temp_z);
+ }
+
+ dev->x = dev->y = dev->z = 0;
+}
+
+static void
+ps2_write(uint8_t val, void *priv)
+{
+ mouse_t *dev = (mouse_t *) priv;
+ uint8_t temp;
+
+ if (dev->flags & FLAG_CTRLDAT) {
+ dev->flags &= ~FLAG_CTRLDAT;
+
+ if (val == 0xff)
+ goto mouse_reset;
+
+ switch (dev->command) {
+ case 0xe8: /* set mouse resolution */
+ dev->resolution = val;
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ break;
+
+ case 0xf3: /* set sample rate */
+ dev->sample_rate = val;
+ keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */
+ break;
+
+ default:
+ keyboard_at_adddata_mouse_cmd(0xfc);
+ }
+ } else {
+ dev->command = val;
+
+ switch (dev->command) {
+ case 0xe6: /* set scaling to 1:1 */
+ dev->flags &= ~FLAG_SCALED;
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ break;
+
+ case 0xe7: /* set scaling to 2:1 */
+ dev->flags |= FLAG_SCALED;
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ break;
+
+ case 0xe8: /* set mouse resolution */
+ dev->flags |= FLAG_CTRLDAT;
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ break;
+
+ case 0xe9: /* status request */
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ temp = (dev->flags & 0x30);
+ if (mouse_buttons & 1)
+ temp |= 4;
+ if (mouse_buttons & 2)
+ temp |= 1;
+ if ((mouse_buttons & 4) && (dev->flags & FLAG_INTELLI))
+ temp |= 2;
+ keyboard_at_adddata_mouse_cmd(temp);
+ keyboard_at_adddata_mouse_cmd(dev->resolution);
+ keyboard_at_adddata_mouse_cmd(dev->sample_rate);
+ break;
+
+ case 0xea: /* set stream */
+ dev->flags &= ~FLAG_CTRLDAT;
+ mouse_scan = 1;
+ keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */
+ break;
+
+ case 0xeb: /* Get mouse data */
+ keyboard_at_adddata_mouse_cmd(0xfa);
+
+ ps2_report_coordinates(dev, 1);
+ break;
+
+ case 0xf2: /* read ID */
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ if (dev->flags & FLAG_INTMODE)
+ keyboard_at_adddata_mouse_cmd((dev->flags & FLAG_5BTN) ? 0x04 : 0x03);
+ else
+ keyboard_at_adddata_mouse_cmd(0x00);
+ break;
+
+ case 0xf3: /* set command mode */
+ dev->flags |= FLAG_CTRLDAT;
+ keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */
+ break;
+
+ case 0xf4: /* enable */
+ dev->flags |= FLAG_ENABLED;
+ mouse_scan = 1;
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ break;
+
+ case 0xf5: /* disable */
+ dev->flags &= ~FLAG_ENABLED;
+ mouse_scan = 0;
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ break;
+
+ case 0xf6: /* set defaults */
+ case 0xff: /* reset */
+mouse_reset:
+ dev->mode = MODE_STREAM;
+ dev->flags &= 0x88;
+ mouse_scan = 1;
+ keyboard_at_mouse_reset();
+ keyboard_at_adddata_mouse_cmd(0xfa);
+ if (dev->command == 0xff) {
+ keyboard_at_adddata_mouse_cmd(0xaa);
+ keyboard_at_adddata_mouse_cmd(0x00);
+ }
+ break;
+
+ default:
+ keyboard_at_adddata_mouse_cmd(0xfe);
+ }
+ }
+
+ if (dev->flags & FLAG_INTELLI) {
+ for (temp = 0; temp < 5; temp++)
+ dev->last_data[temp] = dev->last_data[temp + 1];
+
+ dev->last_data[5] = val;
+
+ if ((dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) &&
+ (dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0x64) &&
+ (dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50))
+ dev->flags |= FLAG_INTMODE;
+
+ if ((dev->flags & FLAG_INTMODE) && (dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) &&
+ (dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0xc8) &&
+ (dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50))
+ dev->flags |= FLAG_5BTN;
+ }
+}
+
+static int
+ps2_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv)
+{
+ mouse_t *dev = (mouse_t *) priv;
+
+ if (!x && !y && !z && (b == dev->b))
+ return (0xff);
+
+#if 0
+ if (!(dev->flags & FLAG_ENABLED))
+ return(0xff);
+#endif
+
+ if (!mouse_scan)
+ return (0xff);
+
+ dev->x += x;
+ dev->y -= y;
+ dev->z -= z;
+#if 0
+ if ((dev->mode == MODE_STREAM) && (dev->flags & FLAG_ENABLED) && (keyboard_at_mouse_pos() < 13)) {
+#else
+ if ((dev->mode == MODE_STREAM) && (keyboard_at_mouse_pos() < 13)) {
+#endif
+ dev->b = b;
+
+ ps2_report_coordinates(dev, 0);
+ }
+
+ return (0);
+}
+
+/*
+ * Initialize the device for use by the user.
+ *
+ * We also get called from the various machines.
+ */
+void *
+mouse_ps2_init(const device_t *info)
+{
+ mouse_t *dev;
+ int i;
+
+ dev = (mouse_t *) malloc(sizeof(mouse_t));
+ memset(dev, 0x00, sizeof(mouse_t));
+ dev->name = info->name;
+ dev->type = info->local;
+
+ dev->mode = MODE_STREAM;
+ i = device_get_config_int("buttons");
+ if (i > 2)
+ dev->flags |= FLAG_INTELLI;
+
+ if (i == 4)
+ i = 3;
+
+ /* Hook into the general AT Keyboard driver. */
+ keyboard_at_set_mouse(ps2_write, dev);
+
+ mouse_ps2_log("%s: buttons=%d\n", dev->name, i);
+
+ /* Tell them how many buttons we have. */
+ mouse_set_buttons(i);
+
+ /* Return our private data to the I/O layer. */
+ return (dev);
+}
+
+static void
+ps2_close(void *priv)
+{
+ mouse_t *dev = (mouse_t *) priv;
+
+ /* Unhook from the general AT Keyboard driver. */
+ keyboard_at_set_mouse(NULL, NULL);
+
+ free(dev);
+}
+
+static const device_config_t ps2_config[] = {
+ // clang-format off
+ {
+ .name = "buttons",
+ .description = "Buttons",
+ .type = CONFIG_SELECTION,
+ .default_string = "",
+ .default_int = 2,
+ .file_filter = "",
+ .spinner = { 0 },
+ .selection = {
+ { .description = "Two", .value = 2 },
+ { .description = "Three", .value = 3 },
+ { .description = "Wheel", .value = 4 },
+ { .description = "Five + Wheel", .value = 5 },
+ { .description = "" }
+ }
+ },
+ {
+ .name = "", .description = "", .type = CONFIG_END
+ }
+ // clang-format on
+};
+
+const device_t mouse_ps2_device = {
+ .name = "Standard PS/2 Mouse",
+ .internal_name = "ps2",
+ .flags = DEVICE_PS2,
+ .local = MOUSE_TYPE_PS2,
+ .init = mouse_ps2_init,
+ .close = ps2_close,
+ .reset = NULL,
+ { .poll = ps2_poll },
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = ps2_config
+};
diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h
index ab9ae53a7..6582f05e4 100644
--- a/src/include/86box/usb.h
+++ b/src/include/86box/usb.h
@@ -27,25 +27,27 @@ typedef struct usb_t usb_t;
/* USB device creation parameters struct */
typedef struct
{
- void (*raise_interrupt)(usb_t*, void*);
+ void (*update_interrupt)(usb_t*, void*);
/* Handle (but do not raise) SMI. Returns 1 if SMI can be raised, 0 otherwise. */
uint8_t (*smi_handle)(usb_t*, void*);
void* parent_priv;
} usb_params_t;
+typedef union
+{
+ uint32_t l;
+ uint16_t w[2];
+ uint8_t b[4];
+} ohci_mmio_t;
+
/* USB Host Controller device struct */
typedef struct usb_t
{
- union
- {
- uint8_t ohci_mmio[4096];
- uint16_t ohci_mmio_w[2048];
- uint32_t ohci_mmio_l[1024];
- };
uint8_t uhci_io[32];
+ ohci_mmio_t ohci_mmio[1024];
uint16_t uhci_io_base;
int uhci_enable, ohci_enable;
- uint32_t ohci_mem_base;
+ uint32_t ohci_mem_base, irq_level;
mem_mapping_t ohci_mmio_mapping;
pc_timer_t ohci_frame_timer;
pc_timer_t ohci_interrupt_desc_poll_timer;
diff --git a/src/mem/mem - Cópia.c b/src/mem/mem - Cópia.c
new file mode 100644
index 000000000..a8d9e994d
--- /dev/null
+++ b/src/mem/mem - Cópia.c
@@ -0,0 +1,3092 @@
+/*
+ * 86Box A hypervisor and IBM PC system emulator that specializes in
+ * running old operating systems and software designed for IBM
+ * PC systems and compatibles from 1981 through fairly recent
+ * system designs based on the PCI bus.
+ *
+ * This file is part of the 86Box distribution.
+ *
+ * Memory handling and MMU.
+ *
+ * Authors: Sarah Walker,
+ * Miran Grca,
+ * Fred N. van Kempen,
+ *
+ * Copyright 2008-2020 Sarah Walker.
+ * Copyright 2016-2020 Miran Grca.
+ * Copyright 2017-2020 Fred N. van Kempen.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#define HAVE_STDARG_H
+#include <86box/86box.h>
+#include <86box/version.h>
+#include "cpu.h"
+#include "x86_ops.h"
+#include "x86.h"
+#include <86box/machine.h>
+#include <86box/m_xt_xi8088.h>
+#include <86box/config.h>
+#include <86box/io.h>
+#include <86box/mem.h>
+#include <86box/plat.h>
+#include <86box/rom.h>
+#include <86box/gdbstub.h>
+#ifdef USE_DYNAREC
+# include "codegen_public.h"
+#else
+# ifdef USE_NEW_DYNAREC
+# define PAGE_MASK_SHIFT 6
+# else
+# define PAGE_MASK_INDEX_MASK 3
+# define PAGE_MASK_INDEX_SHIFT 10
+# define PAGE_MASK_SHIFT 4
+# endif
+# define PAGE_MASK_MASK 63
+#endif
+#if (!defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC))
+# define BLOCK_PC_INVALID 0xffffffff
+# define BLOCK_INVALID 0
+#endif
+
+mem_mapping_t ram_low_mapping, /* 0..640K mapping */
+ ram_mid_mapping, /* 640..1024K mapping */
+ ram_mid_mapping2, /* 640..1024K mapping, second part, for SiS 471 in relocate mode */
+ ram_remapped_mapping, /* 640..1024K mapping */
+ ram_remapped_mapping2, /* 640..1024K second mapping, for SiS 471 mode */
+ ram_high_mapping, /* 1024K+ mapping */
+ ram_2gb_mapping, /* 1024M+ mapping */
+ ram_split_mapping,
+ bios_mapping,
+ bios_high_mapping;
+
+page_t *pages, /* RAM page table */
+ **page_lookup; /* pagetable lookup */
+uint32_t pages_sz; /* #pages in table */
+
+uint8_t *ram, *ram2; /* the virtual RAM */
+uint8_t page_ff[4096];
+uint32_t rammask;
+uint32_t addr_space_size;
+
+uint8_t *rom; /* the virtual ROM */
+uint32_t biosmask, biosaddr;
+
+uint32_t pccache;
+uint8_t *pccache2;
+
+int readlnext;
+int readlookup[256];
+uintptr_t *readlookup2;
+uintptr_t old_rl2;
+uint8_t uncached = 0;
+int writelnext;
+int writelookup[256];
+uintptr_t *writelookup2;
+
+uint32_t mem_logical_addr;
+
+int shadowbios = 0,
+ shadowbios_write;
+int readlnum = 0,
+ writelnum = 0;
+int cachesize = 256;
+
+uint32_t get_phys_virt,
+ get_phys_phys;
+
+int mem_a20_key = 0,
+ mem_a20_alt = 0,
+ mem_a20_state = 0;
+
+int mmuflush = 0;
+int mmu_perm = 4;
+
+#ifdef USE_NEW_DYNAREC
+uint64_t *byte_dirty_mask;
+uint64_t *byte_code_present_mask;
+
+uint32_t purgable_page_list_head = 0;
+int purgeable_page_count = 0;
+#endif
+
+uint8_t high_page = 0; /* if a high (> 4 gb) page was detected */
+
+/* FIXME: re-do this with a 'mem_ops' struct. */
+static uint8_t *page_lookupp; /* pagetable mmu_perm lookup */
+static uint8_t *readlookupp;
+static uint8_t *writelookupp;
+static mem_mapping_t *base_mapping, *last_mapping;
+static mem_mapping_t *read_mapping[MEM_MAPPINGS_NO];
+static mem_mapping_t *write_mapping[MEM_MAPPINGS_NO];
+static mem_mapping_t *read_mapping_bus[MEM_MAPPINGS_NO];
+static mem_mapping_t *write_mapping_bus[MEM_MAPPINGS_NO];
+static uint8_t *_mem_exec[MEM_MAPPINGS_NO];
+static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff };
+static mem_state_t _mem_state[MEM_MAPPINGS_NO];
+static uint32_t remap_start_addr, remap_start_addr2;
+#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
+static size_t ram_size = 0, ram2_size = 0;
+#else
+static size_t ram_size = 0;
+#endif
+
+#ifdef ENABLE_MEM_LOG
+int mem_do_log = ENABLE_MEM_LOG;
+
+static void
+mem_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (mem_do_log) {
+ va_start(ap, fmt);
+ pclog_ex(fmt, ap);
+ va_end(ap);
+ }
+}
+#else
+# define mem_log(fmt, ...)
+#endif
+
+int
+mem_addr_is_ram(uint32_t addr)
+{
+ mem_mapping_t *mapping = read_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) ||
+ (mapping == &ram_mid_mapping2) || (mapping == &ram_remapped_mapping);
+}
+
+void
+resetreadlookup(void)
+{
+ int c;
+
+ /* Initialize the page lookup table. */
+ memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *));
+
+ /* Initialize the tables for lower (<= 1024K) RAM. */
+ for (c = 0; c < 256; c++) {
+ readlookup[c] = 0xffffffff;
+ writelookup[c] = 0xffffffff;
+ }
+
+ /* Initialize the tables for high (> 1024K) RAM. */
+ memset(readlookup2, 0xff, (1 << 20) * sizeof(uintptr_t));
+ memset(readlookupp, 0x04, (1 << 20) * sizeof(uint8_t));
+
+ memset(writelookup2, 0xff, (1 << 20) * sizeof(uintptr_t));
+ memset(writelookupp, 0x04, (1 << 20) * sizeof(uint8_t));
+
+ readlnext = 0;
+ writelnext = 0;
+ pccache = 0xffffffff;
+ high_page = 0;
+}
+
+void
+flushmmucache(void)
+{
+ int c;
+
+ for (c = 0; c < 256; c++) {
+ if (readlookup[c] != (int) 0xffffffff) {
+ readlookup2[readlookup[c]] = LOOKUP_INV;
+ readlookupp[readlookup[c]] = 4;
+ readlookup[c] = 0xffffffff;
+ }
+ if (writelookup[c] != (int) 0xffffffff) {
+ page_lookup[writelookup[c]] = NULL;
+ page_lookupp[writelookup[c]] = 4;
+ writelookup2[writelookup[c]] = LOOKUP_INV;
+ writelookupp[writelookup[c]] = 4;
+ writelookup[c] = 0xffffffff;
+ }
+ }
+ mmuflush++;
+
+ pccache = (uint32_t) 0xffffffff;
+ pccache2 = (uint8_t *) 0xffffffff;
+
+#ifdef USE_DYNAREC
+ codegen_flush();
+#endif
+}
+
+void
+flushmmucache_nopc(void)
+{
+ int c;
+
+ for (c = 0; c < 256; c++) {
+ if (readlookup[c] != (int) 0xffffffff) {
+ readlookup2[readlookup[c]] = LOOKUP_INV;
+ readlookupp[readlookup[c]] = 4;
+ readlookup[c] = 0xffffffff;
+ }
+ if (writelookup[c] != (int) 0xffffffff) {
+ page_lookup[writelookup[c]] = NULL;
+ page_lookupp[writelookup[c]] = 4;
+ writelookup2[writelookup[c]] = LOOKUP_INV;
+ writelookupp[writelookup[c]] = 4;
+ writelookup[c] = 0xffffffff;
+ }
+ }
+}
+
+void
+mem_flush_write_page(uint32_t addr, uint32_t virt)
+{
+ page_t *page_target = &pages[addr >> 12];
+ int c;
+#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
+ uint32_t a;
+#endif
+
+ for (c = 0; c < 256; c++) {
+ if (writelookup[c] != (int) 0xffffffff) {
+#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)
+ uintptr_t target = (uintptr_t) &ram[(uintptr_t) (addr & ~0xfff) - (virt & ~0xfff)];
+#else
+ a = (uintptr_t) (addr & ~0xfff) - (virt & ~0xfff);
+ uintptr_t target;
+
+ if ((addr & ~0xfff) >= (1 << 30))
+ target = (uintptr_t) &ram2[a - (1 << 30)];
+ else
+ target = (uintptr_t) &ram[a];
+#endif
+
+ if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) {
+ writelookup2[writelookup[c]] = LOOKUP_INV;
+ page_lookup[writelookup[c]] = NULL;
+ writelookup[c] = 0xffffffff;
+ }
+ }
+ }
+}
+
+#define mmutranslate_read(addr) mmutranslatereal(addr, 0)
+#define mmutranslate_write(addr) mmutranslatereal(addr, 1)
+#define rammap(x) ((uint32_t *) (_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK]
+#define rammap64(x) ((uint64_t *) (_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 3) & MEM_GRANULARITY_PMASK]
+
+static __inline uint64_t
+mmutranslatereal_normal(uint32_t addr, int rw)
+{
+ uint32_t temp, temp2, temp3;
+ uint32_t addr2;
+
+ if (cpu_state.abrt)
+ return 0xffffffffffffffffULL;
+
+ addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc));
+ temp = temp2 = rammap(addr2);
+ if (!(temp & 1)) {
+ cr2 = addr;
+ temp &= 1;
+ if (CPL == 3)
+ temp |= 4;
+ if (rw)
+ temp |= 2;
+ cpu_state.abrt = ABRT_PF;
+ abrt_error = temp;
+ return 0xffffffffffffffffULL;
+ }
+
+ if ((temp & 0x80) && (cr4 & CR4_PSE)) {
+ /*4MB page*/
+ if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || ((is486 || isibm486) && (cr0 & WP_FLAG))))) {
+ cr2 = addr;
+ temp &= 1;
+ if (CPL == 3)
+ temp |= 4;
+ if (rw)
+ temp |= 2;
+ cpu_state.abrt = ABRT_PF;
+ abrt_error = temp;
+
+ return 0xffffffffffffffffULL;
+ }
+
+ mmu_perm = temp & 4;
+ rammap(addr2) |= (rw ? 0x60 : 0x20);
+
+ return (temp & ~0x3fffff) + (addr & 0x3fffff);
+ }
+
+ temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc));
+ temp3 = temp & temp2;
+ if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || ((is486 || isibm486) && (cr0 & WP_FLAG))))) {
+ cr2 = addr;
+ temp &= 1;
+ if (CPL == 3)
+ temp |= 4;
+ if (rw)
+ temp |= 2;
+ cpu_state.abrt = ABRT_PF;
+ abrt_error = temp;
+ return 0xffffffffffffffffULL;
+ }
+
+ mmu_perm = temp & 4;
+ rammap(addr2) |= 0x20;
+ rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw ? 0x60 : 0x20);
+
+ return (uint64_t) ((temp & ~0xfff) + (addr & 0xfff));
+}
+
+static __inline uint64_t
+mmutranslatereal_pae(uint32_t addr, int rw)
+{
+ uint64_t temp, temp2, temp3, temp4;
+ uint64_t addr2, addr3, addr4;
+
+ if (cpu_state.abrt)
+ return 0xffffffffffffffffULL;
+
+ addr2 = (cr3 & ~0x1f) + ((addr >> 27) & 0x18);
+ temp = temp2 = rammap64(addr2) & 0x000000ffffffffffULL;
+ if (!(temp & 1)) {
+ cr2 = addr;
+ temp &= 1;
+ if (CPL == 3)
+ temp |= 4;
+ if (rw)
+ temp |= 2;
+ cpu_state.abrt = ABRT_PF;
+ abrt_error = temp;
+ return 0xffffffffffffffffULL;
+ }
+
+ addr3 = (temp & ~0xfffULL) + ((addr >> 18) & 0xff8);
+ temp = temp4 = rammap64(addr3) & 0x000000ffffffffffULL;
+ temp3 = temp & temp2;
+ if (!(temp & 1)) {
+ cr2 = addr;
+ temp &= 1;
+ if (CPL == 3)
+ temp |= 4;
+ if (rw)
+ temp |= 2;
+ cpu_state.abrt = ABRT_PF;
+ abrt_error = temp;
+ return 0xffffffffffffffffULL;
+ }
+
+ if (temp & 0x80) {
+ /*2MB page*/
+ if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) {
+ cr2 = addr;
+ temp &= 1;
+ if (CPL == 3)
+ temp |= 4;
+ if (rw)
+ temp |= 2;
+ cpu_state.abrt = ABRT_PF;
+ abrt_error = temp;
+
+ return 0xffffffffffffffffULL;
+ }
+ mmu_perm = temp & 4;
+ rammap64(addr3) |= (rw ? 0x60 : 0x20);
+
+ return ((temp & ~0x1fffffULL) + (addr & 0x1fffffULL)) & 0x000000ffffffffffULL;
+ }
+
+ addr4 = (temp & ~0xfffULL) + ((addr >> 9) & 0xff8);
+ temp = rammap64(addr4) & 0x000000ffffffffffULL;
+ temp3 = temp & temp4;
+ if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) {
+ cr2 = addr;
+ temp &= 1;
+ if (CPL == 3)
+ temp |= 4;
+ if (rw)
+ temp |= 2;
+ cpu_state.abrt = ABRT_PF;
+ abrt_error = temp;
+ return 0xffffffffffffffffULL;
+ }
+
+ mmu_perm = temp & 4;
+ rammap64(addr3) |= 0x20;
+ rammap64(addr4) |= (rw ? 0x60 : 0x20);
+
+ return ((temp & ~0xfffULL) + ((uint64_t) (addr & 0xfff))) & 0x000000ffffffffffULL;
+}
+
+uint64_t
+mmutranslatereal(uint32_t addr, int rw)
+{
+ /* Fast path to return invalid without any call if an exception has occurred beforehand. */
+ if (cpu_state.abrt)
+ return 0xffffffffffffffffULL;
+
+ if (cr4 & CR4_PAE)
+ return mmutranslatereal_pae(addr, rw);
+ else
+ return mmutranslatereal_normal(addr, rw);
+}
+
+/* This is needed because the old recompiler calls this to check for page fault. */
+uint32_t
+mmutranslatereal32(uint32_t addr, int rw)
+{
+ /* Fast path to return invalid without any call if an exception has occurred beforehand. */
+ if (cpu_state.abrt)
+ return (uint32_t) 0xffffffffffffffffULL;
+
+ return (uint32_t) mmutranslatereal(addr, rw);
+}
+
+static __inline uint64_t
+mmutranslate_noabrt_normal(uint32_t addr, int rw)
+{
+ uint32_t temp, temp2, temp3;
+ uint32_t addr2;
+
+ if (cpu_state.abrt)
+ return 0xffffffffffffffffULL;
+
+ addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc));
+ temp = temp2 = rammap(addr2);
+
+ if (!(temp & 1))
+ return 0xffffffffffffffffULL;
+
+ if ((temp & 0x80) && (cr4 & CR4_PSE)) {
+ /*4MB page*/
+ if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3) || (cr0 & WP_FLAG))))
+ return 0xffffffffffffffffULL;
+
+ return (temp & ~0x3fffff) + (addr & 0x3fffff);
+ }
+
+ temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc));
+ temp3 = temp & temp2;
+
+ if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && ((CPL == 3) || (cr0 & WP_FLAG))))
+ return 0xffffffffffffffffULL;
+
+ return (uint64_t) ((temp & ~0xfff) + (addr & 0xfff));
+}
+
+static __inline uint64_t
+mmutranslate_noabrt_pae(uint32_t addr, int rw)
+{
+ uint64_t temp, temp2, temp3, temp4;
+ uint64_t addr2, addr3, addr4;
+
+ if (cpu_state.abrt)
+ return 0xffffffffffffffffULL;
+
+ addr2 = (cr3 & ~0x1f) + ((addr >> 27) & 0x18);
+ temp = temp2 = rammap64(addr2) & 0x000000ffffffffffULL;
+
+ if (!(temp & 1))
+ return 0xffffffffffffffffULL;
+
+ addr3 = (temp & ~0xfffULL) + ((addr >> 18) & 0xff8);
+ temp = temp4 = rammap64(addr3) & 0x000000ffffffffffULL;
+ temp3 = temp & temp2;
+
+ if (!(temp & 1))
+ return 0xffffffffffffffffULL;
+
+ if (temp & 0x80) {
+ /*2MB page*/
+ if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3) || (cr0 & WP_FLAG))))
+ return 0xffffffffffffffffULL;
+
+ return ((temp & ~0x1fffffULL) + (addr & 0x1fffff)) & 0x000000ffffffffffULL;
+ }
+
+ addr4 = (temp & ~0xfffULL) + ((addr >> 9) & 0xff8);
+ temp = rammap64(addr4) & 0x000000ffffffffffULL;
+ ;
+ temp3 = temp & temp4;
+
+ if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && ((CPL == 3) || (cr0 & WP_FLAG))))
+ return 0xffffffffffffffffULL;
+
+ return ((temp & ~0xfffULL) + ((uint64_t) (addr & 0xfff))) & 0x000000ffffffffffULL;
+}
+
+uint64_t
+mmutranslate_noabrt(uint32_t addr, int rw)
+{
+ /* Fast path to return invalid without any call if an exception has occurred beforehand. */
+ if (cpu_state.abrt)
+ return 0xffffffffffffffffULL;
+
+ if (cr4 & CR4_PAE)
+ return mmutranslate_noabrt_pae(addr, rw);
+ else
+ return mmutranslate_noabrt_normal(addr, rw);
+}
+
+void
+mmu_invalidate(uint32_t addr)
+{
+ flushmmucache_cr3();
+}
+
+uint8_t
+mem_addr_range_match(uint32_t addr, uint32_t start, uint32_t len)
+{
+ if (addr < start)
+ return 0;
+ else if (addr >= (start + len))
+ return 0;
+ else
+ return 1;
+}
+
+uint32_t
+mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len)
+{
+ uint32_t mask = len - 1;
+
+ return chunk_start + (addr & mask);
+}
+
+void
+addreadlookup(uint32_t virt, uint32_t phys)
+{
+#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
+ uint32_t a;
+#endif
+
+ if (virt == 0xffffffff)
+ return;
+
+ if (readlookup2[virt >> 12] != (uintptr_t) LOOKUP_INV)
+ return;
+
+ if (readlookup[readlnext] != (int) 0xffffffff) {
+ if ((readlookup[readlnext] == ((es + DI) >> 12)) || (readlookup[readlnext] == ((es + EDI) >> 12)))
+ uncached = 1;
+ readlookup2[readlookup[readlnext]] = LOOKUP_INV;
+ }
+
+#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)
+ readlookup2[virt >> 12] = (uintptr_t) &ram[(uintptr_t) (phys & ~0xFFF) - (uintptr_t) (virt & ~0xfff)];
+#else
+ a = ((uint32_t) (phys & ~0xfff) - (uint32_t) (virt & ~0xfff));
+
+ if ((phys & ~0xfff) >= (1 << 30))
+ readlookup2[virt >> 12] = (uintptr_t) &ram2[a - (1 << 30)];
+ else
+ readlookup2[virt >> 12] = (uintptr_t) &ram[a];
+#endif
+ readlookupp[virt >> 12] = mmu_perm;
+
+ readlookup[readlnext++] = virt >> 12;
+ readlnext &= (cachesize - 1);
+
+ cycles -= 9;
+}
+
+void
+addwritelookup(uint32_t virt, uint32_t phys)
+{
+#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
+ uint32_t a;
+#endif
+
+ if (virt == 0xffffffff)
+ return;
+
+ if (page_lookup[virt >> 12])
+ return;
+
+ if (writelookup[writelnext] != -1) {
+ page_lookup[writelookup[writelnext]] = NULL;
+ writelookup2[writelookup[writelnext]] = LOOKUP_INV;
+ }
+
+#ifdef USE_NEW_DYNAREC
+# ifdef USE_DYNAREC
+ if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) {
+# else
+ if (pages[phys >> 12].block) {
+# endif
+#else
+# ifdef USE_DYNAREC
+ if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page) {
+# else
+ if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3]) {
+# endif
+#endif
+ page_lookup[virt >> 12] = &pages[phys >> 12];
+ page_lookupp[virt >> 12] = mmu_perm;
+ } else {
+#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)
+ writelookup2[virt >> 12] = (uintptr_t) &ram[(uintptr_t) (phys & ~0xFFF) - (uintptr_t) (virt & ~0xfff)];
+#else
+ a = ((uint32_t) (phys & ~0xfff) - (uint32_t) (virt & ~0xfff));
+
+ if ((phys & ~0xfff) >= (1 << 30))
+ writelookup2[virt >> 12] = (uintptr_t) &ram2[a - (1 << 30)];
+ else
+ writelookup2[virt >> 12] = (uintptr_t) &ram[a];
+#endif
+ }
+ writelookupp[virt >> 12] = mmu_perm;
+
+ writelookup[writelnext++] = virt >> 12;
+ writelnext &= (cachesize - 1);
+
+ cycles -= 9;
+}
+
+uint8_t *
+getpccache(uint32_t a)
+{
+ uint64_t a64 = (uint64_t) a;
+ uint32_t a2;
+
+ a2 = a;
+
+ if (cr0 >> 31) {
+ a64 = mmutranslate_read(a64);
+
+ if (a64 == 0xffffffffffffffffULL)
+ return ram;
+ }
+ a64 &= rammask;
+
+ if (_mem_exec[a64 >> MEM_GRANULARITY_BITS]) {
+ if (is286) {
+ if (read_mapping[a64 >> MEM_GRANULARITY_BITS] && (read_mapping[a64 >> MEM_GRANULARITY_BITS]->flags & MEM_MAPPING_ROM_WS))
+ cpu_prefetch_cycles = cpu_rom_prefetch_cycles;
+ else
+ cpu_prefetch_cycles = cpu_mem_prefetch_cycles;
+ }
+
+ return &_mem_exec[a64 >> MEM_GRANULARITY_BITS][(uintptr_t) (a64 & MEM_GRANULARITY_PAGE) - (uintptr_t) (a2 & ~0xfff)];
+ }
+
+ mem_log("Bad getpccache %08X%08X\n", (uint32_t) (a64 >> 32), (uint32_t) (a64 & 0xffffffffULL));
+
+ return (uint8_t *) &ff_pccache;
+}
+
+uint8_t
+read_mem_b(uint32_t addr)
+{
+ mem_mapping_t *map;
+ uint8_t ret = 0xff;
+ int old_cycles = cycles;
+
+ mem_logical_addr = addr;
+ addr &= rammask;
+
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+ if (map && map->read_b)
+ ret = map->read_b(addr, map->p);
+
+ resub_cycles(old_cycles);
+
+ return ret;
+}
+
+uint16_t
+read_mem_w(uint32_t addr)
+{
+ mem_mapping_t *map;
+ uint16_t ret = 0xffff;
+ int old_cycles = cycles;
+
+ mem_logical_addr = addr;
+ addr &= rammask;
+
+ if (addr & 1)
+ ret = read_mem_b(addr) | (read_mem_b(addr + 1) << 8);
+ else {
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->read_w)
+ ret = map->read_w(addr, map->p);
+ else if (map && map->read_b)
+ ret = map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8);
+ }
+
+ resub_cycles(old_cycles);
+
+ return ret;
+}
+
+void
+write_mem_b(uint32_t addr, uint8_t val)
+{
+ mem_mapping_t *map;
+ int old_cycles = cycles;
+
+ mem_logical_addr = addr;
+ addr &= rammask;
+
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+ if (map && map->write_b)
+ map->write_b(addr, val, map->p);
+
+ resub_cycles(old_cycles);
+}
+
+void
+write_mem_w(uint32_t addr, uint16_t val)
+{
+ mem_mapping_t *map;
+ int old_cycles = cycles;
+
+ mem_logical_addr = addr;
+ addr &= rammask;
+
+ if (addr & 1) {
+ write_mem_b(addr, val);
+ write_mem_b(addr + 1, val >> 8);
+ } else {
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+ if (map) {
+ if (map->write_w)
+ map->write_w(addr, val, map->p);
+ else if (map->write_b) {
+ map->write_b(addr, val, map->p);
+ map->write_b(addr + 1, val >> 8, map->p);
+ }
+ }
+ }
+
+ resub_cycles(old_cycles);
+}
+
+uint8_t
+readmembl(uint32_t addr)
+{
+ mem_mapping_t *map;
+ uint64_t a;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[RB ] %08X\n", addr);
+
+ GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1);
+
+ addr64 = (uint64_t) addr;
+ mem_logical_addr = addr;
+
+ high_page = 0;
+
+ if (cr0 >> 31) {
+ a = mmutranslate_read(addr);
+ addr64 = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return 0xff;
+ }
+ addr = (uint32_t) (addr64 & rammask);
+
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+ if (map && map->read_b)
+ return map->read_b(addr, map->p);
+
+ return 0xff;
+}
+
+void
+writemembl(uint32_t addr, uint8_t val)
+{
+ mem_mapping_t *map;
+ uint64_t a;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[WB ] %08X = %02X\n", addr, val);
+
+ GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1);
+
+ addr64 = (uint64_t) addr;
+ mem_logical_addr = addr;
+
+ high_page = 0;
+
+ if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_b) {
+ page_lookup[addr >> 12]->write_b(addr, val, page_lookup[addr >> 12]);
+ return;
+ }
+
+ if (cr0 >> 31) {
+ a = mmutranslate_write(addr);
+ addr64 = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return;
+ }
+ addr = (uint32_t) (addr64 & rammask);
+
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+ if (map && map->write_b)
+ map->write_b(addr, val, map->p);
+}
+
+/* Read a byte from memory without MMU translation - result of previous MMU translation passed as value. */
+uint8_t
+readmembl_no_mmut(uint32_t addr, uint32_t a64)
+{
+ mem_mapping_t *map;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[RBN] %08X\n", addr);
+
+ GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1);
+
+ mem_logical_addr = addr;
+
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return 0xff;
+
+ addr = a64 & rammask;
+ } else
+ addr &= rammask;
+
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+ if (map && map->read_b)
+ return map->read_b(addr, map->p);
+
+ return 0xff;
+}
+
+/* Write a byte to memory without MMU translation - result of previous MMU translation passed as value. */
+void
+writemembl_no_mmut(uint32_t addr, uint32_t a64, uint8_t val)
+{
+ mem_mapping_t *map;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[WBN] %08X = %02X\n", addr, val);
+
+ GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1);
+
+ mem_logical_addr = addr;
+
+ if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_b) {
+ page_lookup[addr >> 12]->write_b(addr, val, page_lookup[addr >> 12]);
+ return;
+ }
+
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return;
+
+ addr = a64 & rammask;
+ } else
+ addr &= rammask;
+
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+ if (map && map->write_b)
+ map->write_b(addr, val, map->p);
+}
+
+uint16_t
+readmemwl(uint32_t addr)
+{
+ mem_mapping_t *map;
+ int i;
+ uint64_t a;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[RW ] %08X\n", addr);
+
+ addr64a[0] = addr;
+ addr64a[1] = addr + 1;
+ GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 2);
+
+ mem_logical_addr = addr;
+
+ high_page = 0;
+
+ if (addr & 1) {
+ if (!cpu_cyrix_alignment || (addr & 7) == 7)
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xffe) {
+ if (cr0 >> 31) {
+ for (i = 0; i < 2; i++) {
+ a = mmutranslate_read(addr + i);
+ addr64a[i] = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return 0xffff;
+ }
+ }
+
+ return readmembl_no_mmut(addr, addr64a[0]) | (((uint16_t) readmembl_no_mmut(addr + 1, addr64a[1])) << 8);
+ } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = readlookupp[addr >> 12];
+ return *(uint16_t *) (readlookup2[addr >> 12] + addr);
+ }
+ }
+
+ if (cr0 >> 31) {
+ a = mmutranslate_read(addr);
+ addr64a[0] = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return 0xffff;
+ } else
+ addr64a[0] = (uint64_t) addr;
+
+ addr = addr64a[0] & rammask;
+
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->read_w)
+ return map->read_w(addr, map->p);
+
+ if (map && map->read_b) {
+ return map->read_b(addr, map->p) | ((uint16_t) (map->read_b(addr + 1, map->p)) << 8);
+ }
+
+ return 0xffff;
+}
+
+void
+writememwl(uint32_t addr, uint16_t val)
+{
+ mem_mapping_t *map;
+ int i;
+ uint64_t a;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[WW ] %08X = %04X\n", addr, val);
+
+ addr64a[0] = addr;
+ addr64a[1] = addr + 1;
+ GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 2);
+
+ mem_logical_addr = addr;
+
+ high_page = 0;
+
+ if (addr & 1) {
+ if (!cpu_cyrix_alignment || (addr & 7) == 7)
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xffe) {
+ if (cr0 >> 31) {
+ for (i = 0; i < 2; i++) {
+ /* Do not translate a page that has a valid lookup, as that is by definition valid
+ and the whole purpose of the lookup is to avoid repeat identical translations. */
+ if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) {
+ a = mmutranslate_write(addr + i);
+ addr64a[i] = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return;
+ }
+ }
+ }
+
+ /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
+ their result as a parameter to be used if needed. */
+ writemembl_no_mmut(addr, addr64a[0], val);
+ writemembl_no_mmut(addr + 1, addr64a[1], val >> 8);
+ return;
+ } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = writelookupp[addr >> 12];
+ *(uint16_t *) (writelookup2[addr >> 12] + addr) = val;
+ return;
+ }
+ }
+
+ if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_w) {
+ page_lookup[addr >> 12]->write_w(addr, val, page_lookup[addr >> 12]);
+ mmu_perm = page_lookupp[addr >> 12];
+ return;
+ }
+
+ if (cr0 >> 31) {
+ a = mmutranslate_write(addr);
+ addr64a[0] = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return;
+ }
+
+ addr = addr64a[0] & rammask;
+
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->write_w) {
+ map->write_w(addr, val, map->p);
+ return;
+ }
+
+ if (map && map->write_b) {
+ map->write_b(addr, val, map->p);
+ map->write_b(addr + 1, val >> 8, map->p);
+ return;
+ }
+}
+
+/* Read a word from memory without MMU translation - results of previous MMU translation passed as array. */
+uint16_t
+readmemwl_no_mmut(uint32_t addr, uint32_t *a64)
+{
+ mem_mapping_t *map;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[RWN] %08X\n", addr);
+
+ GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 2);
+
+ mem_logical_addr = addr;
+
+ if (addr & 1) {
+ if (!cpu_cyrix_alignment || (addr & 7) == 7)
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xffe) {
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return 0xffff;
+ }
+
+ return readmembl_no_mmut(addr, a64[0]) | (((uint16_t) readmembl_no_mmut(addr + 1, a64[1])) << 8);
+ } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = readlookupp[addr >> 12];
+ return *(uint16_t *) (readlookup2[addr >> 12] + addr);
+ }
+ }
+
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return 0xffff;
+
+ addr = (uint32_t) (a64[0] & rammask);
+ } else
+ addr &= rammask;
+
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->read_w)
+ return map->read_w(addr, map->p);
+
+ if (map && map->read_b) {
+ return map->read_b(addr, map->p) | ((uint16_t) (map->read_b(addr + 1, map->p)) << 8);
+ }
+
+ return 0xffff;
+}
+
+/* Write a word to memory without MMU translation - results of previous MMU translation passed as array. */
+void
+writememwl_no_mmut(uint32_t addr, uint32_t *a64, uint16_t val)
+{
+ mem_mapping_t *map;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[WWN] %08X = %04X\n", addr, val);
+
+ GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 2);
+
+ mem_logical_addr = addr;
+
+ if (addr & 1) {
+ if (!cpu_cyrix_alignment || (addr & 7) == 7)
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xffe) {
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return;
+ }
+
+ writemembl_no_mmut(addr, a64[0], val);
+ writemembl_no_mmut(addr + 1, a64[1], val >> 8);
+ return;
+ } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = writelookupp[addr >> 12];
+ *(uint16_t *) (writelookup2[addr >> 12] + addr) = val;
+ return;
+ }
+ }
+
+ if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_w) {
+ mmu_perm = page_lookupp[addr >> 12];
+ page_lookup[addr >> 12]->write_w(addr, val, page_lookup[addr >> 12]);
+ return;
+ }
+
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return;
+
+ addr = (uint32_t) (a64[0] & rammask);
+ } else
+ addr &= rammask;
+
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->write_w) {
+ map->write_w(addr, val, map->p);
+ return;
+ }
+
+ if (map && map->write_b) {
+ map->write_b(addr, val, map->p);
+ map->write_b(addr + 1, val >> 8, map->p);
+ return;
+ }
+}
+
+uint32_t
+readmemll(uint32_t addr)
+{
+ mem_mapping_t *map;
+ int i;
+ uint64_t a = 0x0000000000000000ULL;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[RL ] %08X\n", addr);
+
+ for (i = 0; i < 4; i++)
+ addr64a[i] = (uint64_t) (addr + i);
+ GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 4);
+
+ mem_logical_addr = addr;
+
+ high_page = 0;
+
+ if (addr & 3) {
+ if (!cpu_cyrix_alignment || (addr & 7) > 4)
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xffc) {
+ if (cr0 >> 31) {
+ for (i = 0; i < 4; i++) {
+ if (i == 0) {
+ a = mmutranslate_read(addr + i);
+ addr64a[i] = (uint32_t) a;
+ } else if (!((addr + i) & 0xfff)) {
+ a = mmutranslate_read(addr + 3);
+ addr64a[i] = (uint32_t) a;
+ if (!cpu_state.abrt) {
+ a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
+ addr64a[i] = (uint32_t) a;
+ }
+ } else {
+ a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
+ addr64a[i] = (uint32_t) a;
+ }
+
+ if (a > 0xffffffffULL)
+ return 0xffff;
+ }
+ }
+
+ /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
+ their result as a parameter to be used if needed. */
+ return readmemwl_no_mmut(addr, addr64a) | (((uint32_t) readmemwl_no_mmut(addr + 2, &(addr64a[2]))) << 16);
+ } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = readlookupp[addr >> 12];
+ return *(uint32_t *) (readlookup2[addr >> 12] + addr);
+ }
+ }
+
+ if (cr0 >> 31) {
+ a = mmutranslate_read(addr);
+ addr64a[0] = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return 0xffffffff;
+ }
+
+ addr = addr64a[0] & rammask;
+
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->read_l)
+ return map->read_l(addr, map->p);
+
+ if (map && map->read_w)
+ return map->read_w(addr, map->p) | ((uint32_t) (map->read_w(addr + 2, map->p)) << 16);
+
+ if (map && map->read_b)
+ return map->read_b(addr, map->p) | ((uint32_t) (map->read_b(addr + 1, map->p)) << 8) | ((uint32_t) (map->read_b(addr + 2, map->p)) << 16) | ((uint32_t) (map->read_b(addr + 3, map->p)) << 24);
+
+ return 0xffffffff;
+}
+
+void
+writememll(uint32_t addr, uint32_t val)
+{
+ mem_mapping_t *map;
+ int i;
+ uint64_t a = 0x0000000000000000ULL;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[WL ] %08X = %08X\n", addr, val);
+
+ for (i = 0; i < 4; i++)
+ addr64a[i] = (uint64_t) (addr + i);
+ GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 4);
+
+ mem_logical_addr = addr;
+
+ high_page = 0;
+
+ if (addr & 3) {
+ if (!cpu_cyrix_alignment || (addr & 7) > 4)
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xffc) {
+ if (cr0 >> 31) {
+ for (i = 0; i < 4; i++) {
+ /* Do not translate a page that has a valid lookup, as that is by definition valid
+ and the whole purpose of the lookup is to avoid repeat identical translations. */
+ if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) {
+ if (i == 0) {
+ a = mmutranslate_write(addr + i);
+ addr64a[i] = (uint32_t) a;
+ } else if (!((addr + i) & 0xfff)) {
+ a = mmutranslate_write(addr + 3);
+ addr64a[i] = (uint32_t) a;
+ if (!cpu_state.abrt) {
+ a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
+ addr64a[i] = (uint32_t) a;
+ }
+ } else {
+ a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
+ addr64a[i] = (uint32_t) a;
+ }
+
+ if (a > 0xffffffffULL)
+ return;
+ }
+ }
+ }
+
+ /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
+ their result as a parameter to be used if needed. */
+ writememwl_no_mmut(addr, &(addr64a[0]), val);
+ writememwl_no_mmut(addr + 2, &(addr64a[2]), val >> 16);
+ return;
+ } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = writelookupp[addr >> 12];
+ *(uint32_t *) (writelookup2[addr >> 12] + addr) = val;
+ return;
+ }
+ }
+
+ if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) {
+ mmu_perm = page_lookupp[addr >> 12];
+ page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]);
+ return;
+ }
+
+ if (cr0 >> 31) {
+ a = mmutranslate_write(addr);
+ addr64a[0] = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return;
+ }
+
+ addr = addr64a[0] & rammask;
+
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[WL ] map = %08X\n", map);
+
+ if (map && map->write_l) {
+ map->write_l(addr, val, map->p);
+ return;
+ }
+ if (map && map->write_w) {
+ map->write_w(addr, val, map->p);
+ map->write_w(addr + 2, val >> 16, map->p);
+ return;
+ }
+ if (map && map->write_b) {
+ map->write_b(addr, val, map->p);
+ map->write_b(addr + 1, val >> 8, map->p);
+ map->write_b(addr + 2, val >> 16, map->p);
+ map->write_b(addr + 3, val >> 24, map->p);
+ return;
+ }
+}
+
+/* Read a long from memory without MMU translation - results of previous MMU translation passed as array. */
+uint32_t
+readmemll_no_mmut(uint32_t addr, uint32_t *a64)
+{
+ mem_mapping_t *map;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[RLN] %08X\n", addr);
+
+ GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 4);
+
+ mem_logical_addr = addr;
+
+ if (addr & 3) {
+ if (!cpu_cyrix_alignment || (addr & 7) > 4)
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xffc) {
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return 0xffffffff;
+ }
+
+ return readmemwl_no_mmut(addr, a64) | ((uint32_t) (readmemwl_no_mmut(addr + 2, &(a64[2]))) << 16);
+ } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = readlookupp[addr >> 12];
+ return *(uint32_t *) (readlookup2[addr >> 12] + addr);
+ }
+ }
+
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return 0xffffffff;
+
+ addr = (uint32_t) (a64[0] & rammask);
+ } else
+ addr &= rammask;
+
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->read_l)
+ return map->read_l(addr, map->p);
+
+ if (map && map->read_w)
+ return map->read_w(addr, map->p) | ((uint32_t) (map->read_w(addr + 2, map->p)) << 16);
+
+ if (map && map->read_b)
+ return map->read_b(addr, map->p) | ((uint32_t) (map->read_b(addr + 1, map->p)) << 8) | ((uint32_t) (map->read_b(addr + 2, map->p)) << 16) | ((uint32_t) (map->read_b(addr + 3, map->p)) << 24);
+
+ return 0xffffffff;
+}
+
+/* Write a long to memory without MMU translation - results of previous MMU translation passed as array. */
+void
+writememll_no_mmut(uint32_t addr, uint32_t *a64, uint32_t val)
+{
+ mem_mapping_t *map;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[WLN] %08X = %08X\n", addr, val);
+
+ GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 4);
+
+ mem_logical_addr = addr;
+
+ if (addr & 3) {
+ if (!cpu_cyrix_alignment || (addr & 7) > 4)
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xffc) {
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return;
+ }
+
+ writememwl_no_mmut(addr, &(a64[0]), val);
+ writememwl_no_mmut(addr + 2, &(a64[2]), val >> 16);
+ return;
+ } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = writelookupp[addr >> 12];
+ *(uint32_t *) (writelookup2[addr >> 12] + addr) = val;
+ return;
+ }
+ }
+
+ if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) {
+ mmu_perm = page_lookupp[addr >> 12];
+ page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]);
+ return;
+ }
+
+ if (cr0 >> 31) {
+ if (cpu_state.abrt || high_page)
+ return;
+
+ addr = (uint32_t) (a64[0] & rammask);
+ } else
+ addr &= rammask;
+
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->write_l) {
+ map->write_l(addr, val, map->p);
+ return;
+ }
+ if (map && map->write_w) {
+ map->write_w(addr, val, map->p);
+ map->write_w(addr + 2, val >> 16, map->p);
+ return;
+ }
+ if (map && map->write_b) {
+ map->write_b(addr, val, map->p);
+ map->write_b(addr + 1, val >> 8, map->p);
+ map->write_b(addr + 2, val >> 16, map->p);
+ map->write_b(addr + 3, val >> 24, map->p);
+ return;
+ }
+}
+
+uint64_t
+readmemql(uint32_t addr)
+{
+ mem_mapping_t *map;
+ int i;
+ uint64_t a = 0x0000000000000000ULL;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[RQ ] %08X\n", addr);
+
+ for (i = 0; i < 8; i++)
+ addr64a[i] = (uint64_t) (addr + i);
+ GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 8);
+
+ mem_logical_addr = addr;
+
+ high_page = 0;
+
+ if (addr & 7) {
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xff8) {
+ if (cr0 >> 31) {
+ for (i = 0; i < 8; i++) {
+ if (i == 0) {
+ a = mmutranslate_read(addr + i);
+ addr64a[i] = (uint32_t) a;
+ } else if (!((addr + i) & 0xfff)) {
+ a = mmutranslate_read(addr + 7);
+ addr64a[i] = (uint32_t) a;
+ if (!cpu_state.abrt) {
+ a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
+ addr64a[i] = (uint32_t) a;
+ }
+ } else {
+ a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
+ addr64a[i] = (uint32_t) a;
+ }
+
+ if (a > 0xffffffffULL)
+ return 0xffff;
+ }
+ }
+
+ /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
+ their result as a parameter to be used if needed. */
+ return readmemll_no_mmut(addr, addr64a) | (((uint64_t) readmemll_no_mmut(addr + 4, &(addr64a[4]))) << 32);
+ } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = readlookupp[addr >> 12];
+ return *(uint64_t *) (readlookup2[addr >> 12] + addr);
+ }
+ }
+
+ if (cr0 >> 31) {
+ a = mmutranslate_read(addr);
+ addr64a[0] = (uint32_t) a;
+
+ if (a > 0xffffffffULL)
+ return 0xffffffffffffffffULL;
+ }
+
+ addr = addr64a[0] & rammask;
+
+ map = read_mapping[addr >> MEM_GRANULARITY_BITS];
+ if (map && map->read_l)
+ return map->read_l(addr, map->p) | ((uint64_t) map->read_l(addr + 4, map->p) << 32);
+
+ return readmemll(addr) | ((uint64_t) readmemll(addr + 4) << 32);
+}
+
+void
+writememql(uint32_t addr, uint64_t val)
+{
+ mem_mapping_t *map;
+ int i;
+ uint64_t a = 0x0000000000000000ULL;
+
+ if ((addr >= 0xec000000) && (addr <= 0xecffffff))
+ pclog("[WQ ] %08X = %016" PRIX64 "\n", addr, val);
+
+ for (i = 0; i < 8; i++)
+ addr64a[i] = (uint64_t) (addr + i);
+ GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 8);
+
+ mem_logical_addr = addr;
+
+ high_page = 0;
+
+ if (addr & 7) {
+ cycles -= timing_misaligned;
+ if ((addr & 0xfff) > 0xff8) {
+ if (cr0 >> 31) {
+ for (i = 0; i < 8; i++) {
+ /* Do not translate a page that has a valid lookup, as that is by definition valid
+ and the whole purpose of the lookup is to avoid repeat identical translations. */
+ if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) {
+ if (i == 0) {
+ a = mmutranslate_write(addr + i);
+ addr64a[i] = (uint32_t) a;
+ } else if (!((addr + i) & 0xfff)) {
+ a = mmutranslate_write(addr + 7);
+ addr64a[i] = (uint32_t) a;
+ if (!cpu_state.abrt) {
+ a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
+ addr64a[i] = (uint32_t) a;
+ }
+ } else {
+ a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff));
+ addr64a[i] = (uint32_t) a;
+ }
+
+ if (addr64a[i] > 0xffffffffULL)
+ return;
+ }
+ }
+ }
+
+ /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass
+ their result as a parameter to be used if needed. */
+ writememll_no_mmut(addr, addr64a, val);
+ writememll_no_mmut(addr + 4, &(addr64a[4]), val >> 32);
+ return;
+ } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) {
+ mmu_perm = writelookupp[addr >> 12];
+ *(uint64_t *) (writelookup2[addr >> 12] + addr) = val;
+ return;
+ }
+ }
+
+ if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) {
+ mmu_perm = page_lookupp[addr >> 12];
+ page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]);
+ page_lookup[addr >> 12]->write_l(addr + 4, val >> 32, page_lookup[addr >> 12]);
+ return;
+ }
+
+ if (cr0 >> 31) {
+ addr64a[0] = mmutranslate_write(addr);
+ if (addr64a[0] > 0xffffffffULL)
+ return;
+ }
+
+ addr = addr64a[0] & rammask;
+
+ map = write_mapping[addr >> MEM_GRANULARITY_BITS];
+
+ if (map && map->write_l) {
+ map->write_l(addr, val, map->p);
+ map->write_l(addr + 4, val >> 32, map->p);
+ return;
+ }
+ if (map && map->write_w) {
+ map->write_w(addr, val, map->p);
+ map->write_w(addr + 2, val >> 16, map->p);
+ map->write_w(addr + 4, val >> 32, map->p);
+ map->write_w(addr + 6, val >> 48, map->p);
+ return;
+ }
+ if (map && map->write_b) {
+ map->write_b(addr, val, map->p);
+ map->write_b(addr + 1, val >> 8, map->p);
+ map->write_b(addr + 2, val >> 16, map->p);
+ map->write_b(addr + 3, val >> 24, map->p);
+ map->write_b(addr + 4, val >> 32, map->p);
+ map->write_b(addr + 5, val >> 40, map->p);
+ map->write_b(addr + 6, val >> 48, map->p);
+ map->write_b(addr + 7, val >> 56, map->p);
+ return;
+ }
+}
+
+void
+do_mmutranslate(uint32_t addr, uint32_t *a64, int num, int write)
+{
+ int i, cond = 1;
+ uint32_t last_addr = addr + (num - 1);
+ uint64_t a = 0x0000000000000000ULL;
+
+ for (i = 0; i < num; i++)
+ a64[i] = (uint64_t) addr;
+
+ for (i = 0; i < num; i++) {
+ if (cr0 >> 31) {
+ if (write && ((i == 0) || !(addr & 0xfff)))
+ cond = (!page_lookup[addr >> 12] || !page_lookup[addr >> 12]->write_b);
+
+ if (cond) {
+ /* If we have encountered at least one page fault, mark all subsequent addresses as
+ having page faulted, prevents false negatives in readmem*l_no_mmut. */
+ if ((i > 0) && cpu_state.abrt && !high_page)
+ a64[i] = a64[i - 1];
+ /* If we are on the same page, there is no need to translate again, as we can just
+ reuse the previous result. */
+ else if (i == 0) {
+ a = mmutranslatereal(addr, write);
+ a64[i] = (uint32_t) a;
+
+ high_page = high_page || (!cpu_state.abrt && (a > 0xffffffffULL));
+ } else if (!(addr & 0xfff)) {
+ a = mmutranslatereal(last_addr, write);
+ a64[i] = (uint32_t) a;
+
+ high_page = high_page || (!cpu_state.abrt && (a64[i] > 0xffffffffULL));
+
+ if (!cpu_state.abrt) {
+ a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff));
+ a64[i] = (uint32_t) a;
+ }
+ } else {
+ a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff));
+ a64[i] = (uint32_t) a;
+ }
+ } else
+ mmu_perm = page_lookupp[addr >> 12];
+ }
+
+ addr++;
+ }
+}
+
+uint8_t
+mem_readb_phys(uint32_t addr)
+{
+ mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS];
+ uint8_t ret = 0xff;
+
+ mem_logical_addr = 0xffffffff;
+
+ if (map) {
+ if (map->exec)
+ ret = map->exec[(addr - map->base) & map->mask];
+ else if (map->read_b)
+ ret = map->read_b(addr, map->p);
+ }
+
+ return ret;
+}
+
+uint16_t
+mem_readw_phys(uint32_t addr)
+{
+ mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS];
+ uint16_t ret, *p;
+
+ mem_logical_addr = 0xffffffff;
+
+ if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->exec)) {
+ p = (uint16_t *) &(map->exec[(addr - map->base) & map->mask]);
+ ret = *p;
+ } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->read_w))
+ ret = map->read_w(addr, map->p);
+ else {
+ ret = mem_readb_phys(addr + 1) << 8;
+ ret |= mem_readb_phys(addr);
+ }
+
+ return ret;
+}
+
+uint32_t
+mem_readl_phys(uint32_t addr)
+{
+ mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS];
+ uint32_t ret, *p;
+
+ mem_logical_addr = 0xffffffff;
+
+ if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->exec)) {
+ p = (uint32_t *) &(map->exec[(addr - map->base) & map->mask]);
+ ret = *p;
+ } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->read_l))
+ ret = map->read_l(addr, map->p);
+ else {
+ ret = mem_readw_phys(addr + 2) << 16;
+ ret |= mem_readw_phys(addr);
+ }
+
+ return ret;
+}
+
+void
+mem_read_phys(void *dest, uint32_t addr, int transfer_size)
+{
+ uint8_t *pb;
+ uint16_t *pw;
+ uint32_t *pl;
+
+ if (transfer_size == 4) {
+ pl = (uint32_t *) dest;
+ *pl = mem_readl_phys(addr);
+ } else if (transfer_size == 2) {
+ pw = (uint16_t *) dest;
+ *pw = mem_readw_phys(addr);
+ } else if (transfer_size == 1) {
+ pb = (uint8_t *) dest;
+ *pb = mem_readb_phys(addr);
+ }
+}
+
+void
+mem_writeb_phys(uint32_t addr, uint8_t val)
+{
+ mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS];
+
+ mem_logical_addr = 0xffffffff;
+
+ if (map) {
+ if (map->exec)
+ map->exec[(addr - map->base) & map->mask] = val;
+ else if (map->write_b)
+ map->write_b(addr, val, map->p);
+ }
+}
+
+void
+mem_writew_phys(uint32_t addr, uint16_t val)
+{
+ mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS];
+ uint16_t *p;
+
+ mem_logical_addr = 0xffffffff;
+
+ if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->exec)) {
+ p = (uint16_t *) &(map->exec[(addr - map->base) & map->mask]);
+ *p = val;
+ } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->write_w))
+ map->write_w(addr, val, map->p);
+ else {
+ mem_writeb_phys(addr, val & 0xff);
+ mem_writeb_phys(addr + 1, (val >> 8) & 0xff);
+ }
+}
+
+void
+mem_writel_phys(uint32_t addr, uint32_t val)
+{
+ mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS];
+ uint32_t *p;
+
+ mem_logical_addr = 0xffffffff;
+
+ if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->exec)) {
+ p = (uint32_t *) &(map->exec[(addr - map->base) & map->mask]);
+ *p = val;
+ } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->write_l))
+ map->write_l(addr, val, map->p);
+ else {
+ mem_writew_phys(addr, val & 0xffff);
+ mem_writew_phys(addr + 2, (val >> 16) & 0xffff);
+ }
+}
+
+void
+mem_write_phys(void *src, uint32_t addr, int transfer_size)
+{
+ uint8_t *pb;
+ uint16_t *pw;
+ uint32_t *pl;
+
+ if (transfer_size == 4) {
+ pl = (uint32_t *) src;
+ mem_writel_phys(addr, *pl);
+ } else if (transfer_size == 2) {
+ pw = (uint16_t *) src;
+ mem_writew_phys(addr, *pw);
+ } else if (transfer_size == 1) {
+ pb = (uint8_t *) src;
+ mem_writeb_phys(addr, *pb);
+ }
+}
+
+uint8_t
+mem_read_ram(uint32_t addr, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Read B %02X from %08X\n", ram[addr], addr);
+#endif
+
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+
+ return ram[addr];
+}
+
+uint16_t
+mem_read_ramw(uint32_t addr, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Read W %04X from %08X\n", *(uint16_t *) &ram[addr], addr);
+#endif
+
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+
+ return *(uint16_t *) &ram[addr];
+}
+
+uint32_t
+mem_read_raml(uint32_t addr, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Read L %08X from %08X\n", *(uint32_t *) &ram[addr], addr);
+#endif
+
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+
+ return *(uint32_t *) &ram[addr];
+}
+
+uint8_t
+mem_read_ram_2gb(uint32_t addr, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Read B %02X from %08X\n", ram[addr], addr);
+#endif
+
+ addreadlookup(mem_logical_addr, addr);
+
+ return ram2[addr - (1 << 30)];
+}
+
+uint16_t
+mem_read_ram_2gbw(uint32_t addr, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Read W %04X from %08X\n", *(uint16_t *) &ram[addr], addr);
+#endif
+
+ addreadlookup(mem_logical_addr, addr);
+
+ return *(uint16_t *) &ram2[addr - (1 << 30)];
+}
+
+uint32_t
+mem_read_ram_2gbl(uint32_t addr, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Read L %08X from %08X\n", *(uint32_t *) &ram[addr], addr);
+#endif
+
+ addreadlookup(mem_logical_addr, addr);
+
+ return *(uint32_t *) &ram2[addr - (1 << 30)];
+}
+
+#ifdef USE_NEW_DYNAREC
+static inline int
+page_index(page_t *p)
+{
+ return ((uintptr_t) p - (uintptr_t) pages) / sizeof(page_t);
+}
+
+void
+page_add_to_evict_list(page_t *p)
+{
+ pages[purgable_page_list_head].evict_prev = page_index(p);
+ p->evict_next = purgable_page_list_head;
+ p->evict_prev = 0;
+ purgable_page_list_head = pages[purgable_page_list_head].evict_prev;
+ purgeable_page_count++;
+}
+
+void
+page_remove_from_evict_list(page_t *p)
+{
+ if (!page_in_evict_list(p))
+ fatal("page_remove_from_evict_list: not in evict list!\n");
+ if (p->evict_prev)
+ pages[p->evict_prev].evict_next = p->evict_next;
+ else
+ purgable_page_list_head = p->evict_next;
+ if (p->evict_next)
+ pages[p->evict_next].evict_prev = p->evict_prev;
+ p->evict_prev = EVICT_NOT_IN_LIST;
+ purgeable_page_count--;
+}
+
+void
+mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p)
+{
+ if (p == NULL)
+ return;
+
+# ifdef USE_DYNAREC
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) {
+# else
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff])) {
+# endif
+ uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+ int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK;
+ uint64_t byte_mask = (uint64_t) 1 << (addr & PAGE_BYTE_MASK_MASK);
+
+ p->mem[addr & 0xfff] = val;
+ p->dirty_mask |= mask;
+ if ((p->code_present_mask & mask) && !page_in_evict_list(p))
+ page_add_to_evict_list(p);
+ p->byte_dirty_mask[byte_offset] |= byte_mask;
+ if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p))
+ page_add_to_evict_list(p);
+ }
+}
+
+void
+mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p)
+{
+ if (p == NULL)
+ return;
+
+# ifdef USE_DYNAREC
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *) &p->mem[addr & 0xfff]) || codegen_in_recompile) {
+# else
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *) &p->mem[addr & 0xfff])) {
+# endif
+ uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+ int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK;
+ uint64_t byte_mask = (uint64_t) 1 << (addr & PAGE_BYTE_MASK_MASK);
+
+ if ((addr & 0xf) == 0xf)
+ mask |= (mask << 1);
+ *(uint16_t *) &p->mem[addr & 0xfff] = val;
+ p->dirty_mask |= mask;
+ if ((p->code_present_mask & mask) && !page_in_evict_list(p))
+ page_add_to_evict_list(p);
+ if ((addr & PAGE_BYTE_MASK_MASK) == PAGE_BYTE_MASK_MASK) {
+ p->byte_dirty_mask[byte_offset + 1] |= 1;
+ if ((p->byte_code_present_mask[byte_offset + 1] & 1) && !page_in_evict_list(p))
+ page_add_to_evict_list(p);
+ } else
+ byte_mask |= (byte_mask << 1);
+
+ p->byte_dirty_mask[byte_offset] |= byte_mask;
+
+ if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p))
+ page_add_to_evict_list(p);
+ }
+}
+
+void
+mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p)
+{
+ if (p == NULL)
+ return;
+
+# ifdef USE_DYNAREC
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *) &p->mem[addr & 0xfff]) || codegen_in_recompile) {
+# else
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *) &p->mem[addr & 0xfff])) {
+# endif
+ uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+ int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK;
+ uint64_t byte_mask = (uint64_t) 0xf << (addr & PAGE_BYTE_MASK_MASK);
+
+ if ((addr & 0xf) >= 0xd)
+ mask |= (mask << 1);
+ *(uint32_t *) &p->mem[addr & 0xfff] = val;
+ p->dirty_mask |= mask;
+ p->byte_dirty_mask[byte_offset] |= byte_mask;
+ if (!page_in_evict_list(p) && ((p->code_present_mask & mask) || (p->byte_code_present_mask[byte_offset] & byte_mask)))
+ page_add_to_evict_list(p);
+ if ((addr & PAGE_BYTE_MASK_MASK) > (PAGE_BYTE_MASK_MASK - 3)) {
+ uint32_t byte_mask_2 = 0xf >> (4 - (addr & 3));
+
+ p->byte_dirty_mask[byte_offset + 1] |= byte_mask_2;
+ if ((p->byte_code_present_mask[byte_offset + 1] & byte_mask_2) && !page_in_evict_list(p))
+ page_add_to_evict_list(p);
+ }
+ }
+}
+#else
+void
+mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p)
+{
+ if (p == NULL)
+ return;
+
+# ifdef USE_DYNAREC
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) {
+# else
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff])) {
+# endif
+ uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+ p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
+ p->mem[addr & 0xfff] = val;
+ }
+}
+
+void
+mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p)
+{
+ if (p == NULL)
+ return;
+
+# ifdef USE_DYNAREC
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *) &p->mem[addr & 0xfff]) || codegen_in_recompile) {
+# else
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *) &p->mem[addr & 0xfff])) {
+# endif
+ uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+ if ((addr & 0xf) == 0xf)
+ mask |= (mask << 1);
+ p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
+ *(uint16_t *) &p->mem[addr & 0xfff] = val;
+ }
+}
+
+void
+mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p)
+{
+ if (p == NULL)
+ return;
+
+# ifdef USE_DYNAREC
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *) &p->mem[addr & 0xfff]) || codegen_in_recompile) {
+# else
+ if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *) &p->mem[addr & 0xfff])) {
+# endif
+ uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
+ if ((addr & 0xf) >= 0xd)
+ mask |= (mask << 1);
+ p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
+ *(uint32_t *) &p->mem[addr & 0xfff] = val;
+ }
+}
+#endif
+
+void
+mem_write_ram(uint32_t addr, uint8_t val, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Write B %02X to %08X\n", val, addr);
+#endif
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_ramb_page(addr, val, &pages[addr >> 12]);
+ } else
+ ram[addr] = val;
+}
+
+void
+mem_write_ramw(uint32_t addr, uint16_t val, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Write W %04X to %08X\n", val, addr);
+#endif
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_ramw_page(addr, val, &pages[addr >> 12]);
+ } else
+ *(uint16_t *) &ram[addr] = val;
+}
+
+void
+mem_write_raml(uint32_t addr, uint32_t val, void *priv)
+{
+#ifdef ENABLE_MEM_LOG
+ if ((addr >= 0xa0000) && (addr <= 0xbffff))
+ mem_log("Write L %08X to %08X\n", val, addr);
+#endif
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_raml_page(addr, val, &pages[addr >> 12]);
+ } else
+ *(uint32_t *) &ram[addr] = val;
+}
+
+static uint8_t
+mem_read_remapped(uint32_t addr, void *priv)
+{
+ addr = 0xA0000 + (addr - remap_start_addr);
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+ return ram[addr];
+}
+
+static uint16_t
+mem_read_remappedw(uint32_t addr, void *priv)
+{
+ addr = 0xA0000 + (addr - remap_start_addr);
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+ return *(uint16_t *) &ram[addr];
+}
+
+static uint32_t
+mem_read_remappedl(uint32_t addr, void *priv)
+{
+ addr = 0xA0000 + (addr - remap_start_addr);
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+ return *(uint32_t *) &ram[addr];
+}
+
+static uint8_t
+mem_read_remapped2(uint32_t addr, void *priv)
+{
+ addr = 0xD0000 + (addr - remap_start_addr2);
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+ return ram[addr];
+}
+
+static uint16_t
+mem_read_remappedw2(uint32_t addr, void *priv)
+{
+ addr = 0xD0000 + (addr - remap_start_addr2);
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+ return *(uint16_t *) &ram[addr];
+}
+
+static uint32_t
+mem_read_remappedl2(uint32_t addr, void *priv)
+{
+ addr = 0xD0000 + (addr - remap_start_addr2);
+ if (is286)
+ addreadlookup(mem_logical_addr, addr);
+ return *(uint32_t *) &ram[addr];
+}
+
+static void
+mem_write_remapped(uint32_t addr, uint8_t val, void *priv)
+{
+ uint32_t oldaddr = addr;
+ addr = 0xA0000 + (addr - remap_start_addr);
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]);
+ } else
+ ram[addr] = val;
+}
+
+static void
+mem_write_remappedw(uint32_t addr, uint16_t val, void *priv)
+{
+ uint32_t oldaddr = addr;
+ addr = 0xA0000 + (addr - remap_start_addr);
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]);
+ } else
+ *(uint16_t *) &ram[addr] = val;
+}
+
+static void
+mem_write_remappedl(uint32_t addr, uint32_t val, void *priv)
+{
+ uint32_t oldaddr = addr;
+ addr = 0xA0000 + (addr - remap_start_addr);
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_raml_page(addr, val, &pages[oldaddr >> 12]);
+ } else
+ *(uint32_t *) &ram[addr] = val;
+}
+
+static void
+mem_write_remapped2(uint32_t addr, uint8_t val, void *priv)
+{
+ uint32_t oldaddr = addr;
+ addr = 0xD0000 + (addr - remap_start_addr2);
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]);
+ } else
+ ram[addr] = val;
+}
+
+static void
+mem_write_remappedw2(uint32_t addr, uint16_t val, void *priv)
+{
+ uint32_t oldaddr = addr;
+ addr = 0xD0000 + (addr - remap_start_addr2);
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]);
+ } else
+ *(uint16_t *) &ram[addr] = val;
+}
+
+static void
+mem_write_remappedl2(uint32_t addr, uint32_t val, void *priv)
+{
+ uint32_t oldaddr = addr;
+ addr = 0xD0000 + (addr - remap_start_addr2);
+ if (is286) {
+ addwritelookup(mem_logical_addr, addr);
+ mem_write_raml_page(addr, val, &pages[oldaddr >> 12]);
+ } else
+ *(uint32_t *) &ram[addr] = val;
+}
+
+void
+mem_invalidate_range(uint32_t start_addr, uint32_t end_addr)
+{
+#ifdef USE_NEW_DYNAREC
+ page_t *p;
+
+ start_addr &= ~PAGE_MASK_MASK;
+ end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK;
+
+ for (; start_addr <= end_addr; start_addr += 0x1000) {
+ if ((start_addr >> 12) >= pages_sz)
+ continue;
+
+ p = &pages[start_addr >> 12];
+ if (p) {
+ p->dirty_mask = 0xffffffffffffffffULL;
+
+ if (p->byte_dirty_mask)
+ memset(p->byte_dirty_mask, 0xff, 64 * sizeof(uint64_t));
+
+ if (!page_in_evict_list(p))
+ page_add_to_evict_list(p);
+ }
+ }
+#else
+ uint32_t cur_addr;
+ start_addr &= ~PAGE_MASK_MASK;
+ end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK;
+
+ for (; start_addr <= end_addr; start_addr += 0x1000) {
+ /* Do nothing if the pages array is empty or DMA reads/writes to/from PCI device memory addresses
+ may crash the emulator. */
+ cur_addr = (start_addr >> 12);
+ if (cur_addr < pages_sz)
+ memset(pages[cur_addr].dirty_mask, 0xff, sizeof(pages[cur_addr].dirty_mask));
+ }
+#endif
+}
+
+static __inline int
+mem_mapping_access_allowed(uint32_t flags, uint16_t access)
+{
+ int ret = 0;
+
+ if (!(access & ACCESS_DISABLED)) {
+ if (access & ACCESS_CACHE)
+ ret = (flags & MEM_MAPPING_CACHE);
+ else if (access & ACCESS_SMRAM)
+ ret = (flags & MEM_MAPPING_SMRAM);
+ else if (!(access & ACCESS_INTERNAL)) {
+ if (flags & MEM_MAPPING_IS_ROM) {
+ if (access & ACCESS_ROMCS)
+ ret = (flags & MEM_MAPPING_ROMCS);
+ else
+ ret = !(flags & MEM_MAPPING_ROMCS);
+ } else
+ ret = 1;
+
+ ret = ret && !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_SMRAM);
+ } else
+ ret = !(flags & MEM_MAPPING_EXTERNAL) && !(flags & MEM_MAPPING_SMRAM);
+ } else {
+ /* Still allow SMRAM if access is DISABLED but also has CACHE and/or SMRAM flags set. */
+ if (access & ACCESS_CACHE)
+ ret = (flags & MEM_MAPPING_CACHE);
+ else if (access & ACCESS_SMRAM)
+ ret = (flags & MEM_MAPPING_SMRAM);
+ }
+
+ return ret;
+}
+
+void
+mem_mapping_recalc(uint64_t base, uint64_t size)
+{
+ mem_mapping_t *map;
+ int n;
+ uint64_t c;
+
+ if ((base >= 0xec000000) && (base <= 0xecffffff))
+ pclog("mem_mapping_recalc(%016" PRIX64 ", %016" PRIX64 ")\n", base, size);
+
+ if (!size || (base_mapping == NULL))
+ return;
+
+ map = base_mapping;
+
+ /* Clear out old mappings. */
+ for (c = base; c < base + size; c += MEM_GRANULARITY_SIZE) {
+ _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL;
+ write_mapping[c >> MEM_GRANULARITY_BITS] = NULL;
+ read_mapping[c >> MEM_GRANULARITY_BITS] = NULL;
+ write_mapping_bus[c >> MEM_GRANULARITY_BITS] = NULL;
+ read_mapping_bus[c >> MEM_GRANULARITY_BITS] = NULL;
+ }
+
+ /* Walk mapping list. */
+ while (map != NULL) {
+ /* In range? */
+ if (map->enable && (uint64_t) map->base < ((uint64_t) base + (uint64_t) size) && ((uint64_t) map->base + (uint64_t) map->size) > (uint64_t) base) {
+ uint64_t start = (map->base < base) ? map->base : base;
+ uint64_t end = (((uint64_t) map->base + (uint64_t) map->size) < (base + size)) ? ((uint64_t) map->base + (uint64_t) map->size) : (base + size);
+ if (start < map->base)
+ start = map->base;
+
+ for (c = start; c < end; c += MEM_GRANULARITY_SIZE) {
+ /* CPU */
+ n = !!in_smm;
+ if ((c >= 0xec000000) && (c <= 0xecffffff))
+ pclog("mem_mapping_recalc(): map = %08X (%02X) (%02X, %02X, %02X)\n", map, map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].r, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].w, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].x);
+ if (map->exec && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].x))
+ _mem_exec[c >> MEM_GRANULARITY_BITS] = map->exec + (c - map->base);
+ if ((map->write_b || map->write_w || map->write_l) && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].w))
+ write_mapping[c >> MEM_GRANULARITY_BITS] = map;
+ if ((map->read_b || map->read_w || map->read_l) && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].r))
+ read_mapping[c >> MEM_GRANULARITY_BITS] = map;
+
+ /* Bus */
+ n |= STATE_BUS;
+ if ((map->write_b || map->write_w || map->write_l) && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].w))
+ write_mapping_bus[c >> MEM_GRANULARITY_BITS] = map;
+ if ((map->read_b || map->read_w || map->read_l) && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].r))
+ read_mapping_bus[c >> MEM_GRANULARITY_BITS] = map;
+ }
+ }
+ map = map->next;
+ }
+
+ flushmmucache_cr3();
+
+#ifdef ENABLE_MEM_LOG
+ pclog("\nMemory map:\n");
+ mem_mapping_t *write = (mem_mapping_t *) -1, *read = (mem_mapping_t *) -1, *write_bus = (mem_mapping_t *) -1, *read_bus = (mem_mapping_t *) -1;
+ for (c = 0; c < (sizeof(write_mapping) / sizeof(write_mapping[0])); c++) {
+ if ((write_mapping[c] == write) && (read_mapping[c] == read) && (write_mapping_bus[c] == write_bus) && (read_mapping_bus[c] == read_bus))
+ continue;
+ write = write_mapping[c];
+ read = read_mapping[c];
+ write_bus = write_mapping_bus[c];
+ read_bus = read_mapping_bus[c];
+
+ pclog("%08X | ", c << MEM_GRANULARITY_BITS);
+ if (read) {
+ pclog("R%c%c%c %08X+% 8X",
+ read->read_b ? 'b' : ' ', read->read_w ? 'w' : ' ', read->read_l ? 'l' : ' ',
+ read->base, read->size);
+ } else {
+ pclog(" ");
+ }
+ if (write) {
+ pclog(" | W%c%c%c %08X+% 8X",
+ write->write_b ? 'b' : ' ', write->write_w ? 'w' : ' ', write->write_l ? 'l' : ' ',
+ write->base, write->size);
+ } else {
+ pclog(" | ");
+ }
+ pclog(" | %c\n", _mem_exec[c] ? 'X' : ' ');
+
+ if ((write != write_bus) || (read != read_bus)) {
+ pclog(" ^ bus | ");
+ if (read_bus) {
+ pclog("R%c%c%c %08X+% 8X",
+ read_bus->read_b ? 'b' : ' ', read_bus->read_w ? 'w' : ' ', read_bus->read_l ? 'l' : ' ',
+ read_bus->base, read_bus->size);
+ } else {
+ pclog(" ");
+ }
+ if (write_bus) {
+ pclog(" | W%c%c%c %08X+% 8X",
+ write_bus->write_b ? 'b' : ' ', write_bus->write_w ? 'w' : ' ', write_bus->write_l ? 'l' : ' ',
+ write_bus->base, write_bus->size);
+ } else {
+ pclog(" | ");
+ }
+ pclog(" |\n");
+ }
+ }
+ pclog("\n");
+#endif
+}
+
+void
+mem_mapping_set(mem_mapping_t *map,
+ uint32_t base,
+ uint32_t size,
+ uint8_t (*read_b)(uint32_t addr, void *p),
+ uint16_t (*read_w)(uint32_t addr, void *p),
+ uint32_t (*read_l)(uint32_t addr, void *p),
+ void (*write_b)(uint32_t addr, uint8_t val, void *p),
+ void (*write_w)(uint32_t addr, uint16_t val, void *p),
+ void (*write_l)(uint32_t addr, uint32_t val, void *p),
+ uint8_t *exec,
+ uint32_t fl,
+ void *p)
+{
+ if (size != 0x00000000)
+ map->enable = 1;
+ else
+ map->enable = 0;
+ map->base = base;
+ map->size = size;
+ map->mask = (map->size ? 0xffffffff : 0x00000000);
+ map->read_b = read_b;
+ map->read_w = read_w;
+ map->read_l = read_l;
+ map->write_b = write_b;
+ map->write_w = write_w;
+ map->write_l = write_l;
+ map->exec = exec;
+ map->flags = fl;
+ map->p = p;
+ map->next = NULL;
+ mem_log("mem_mapping_add(): Linked list structure: %08X -> %08X -> %08X\n", map->prev, map, map->next);
+
+ /* If the mapping is disabled, there is no need to recalc anything. */
+ if (size != 0x00000000)
+ mem_mapping_recalc(map->base, map->size);
+}
+
+void
+mem_mapping_add(mem_mapping_t *map,
+ uint32_t base,
+ uint32_t size,
+ uint8_t (*read_b)(uint32_t addr, void *p),
+ uint16_t (*read_w)(uint32_t addr, void *p),
+ uint32_t (*read_l)(uint32_t addr, void *p),
+ void (*write_b)(uint32_t addr, uint8_t val, void *p),
+ void (*write_w)(uint32_t addr, uint16_t val, void *p),
+ void (*write_l)(uint32_t addr, uint32_t val, void *p),
+ uint8_t *exec,
+ uint32_t fl,
+ void *p)
+{
+ /* Do a sanity check */
+ if ((base_mapping == NULL) && (last_mapping != NULL)) {
+ fatal("mem_mapping_add(): NULL base mapping with non-NULL last mapping\n");
+ return;
+ } else if ((base_mapping != NULL) && (last_mapping == NULL)) {
+ fatal("mem_mapping_add(): Non-NULL base mapping with NULL last mapping\n");
+ return;
+ } else if ((base_mapping != NULL) && (base_mapping->prev != NULL)) {
+ fatal("mem_mapping_add(): Base mapping with a preceding mapping\n");
+ return;
+ } else if ((last_mapping != NULL) && (last_mapping->next != NULL)) {
+ fatal("mem_mapping_add(): Last mapping with a following mapping\n");
+ return;
+ }
+
+ /* Add mapping to the beginning of the list if necessary.*/
+ if (base_mapping == NULL)
+ base_mapping = map;
+
+ /* Add mapping to the end of the list.*/
+ if (last_mapping == NULL)
+ map->prev = NULL;
+ else {
+ map->prev = last_mapping;
+ last_mapping->next = map;
+ }
+ last_mapping = map;
+
+ mem_mapping_set(map, base, size, read_b, read_w, read_l,
+ write_b, write_w, write_l, exec, fl, p);
+}
+
+void
+mem_mapping_do_recalc(mem_mapping_t *map)
+{
+ mem_mapping_recalc(map->base, map->size);
+}
+
+void
+mem_mapping_set_handler(mem_mapping_t *map,
+ uint8_t (*read_b)(uint32_t addr, void *p),
+ uint16_t (*read_w)(uint32_t addr, void *p),
+ uint32_t (*read_l)(uint32_t addr, void *p),
+ void (*write_b)(uint32_t addr, uint8_t val, void *p),
+ void (*write_w)(uint32_t addr, uint16_t val, void *p),
+ void (*write_l)(uint32_t addr, uint32_t val, void *p))
+{
+ map->read_b = read_b;
+ map->read_w = read_w;
+ map->read_l = read_l;
+ map->write_b = write_b;
+ map->write_w = write_w;
+ map->write_l = write_l;
+
+ mem_mapping_recalc(map->base, map->size);
+}
+
+void
+mem_mapping_set_addr(mem_mapping_t *map, uint32_t base, uint32_t size)
+{
+ if ((base >= 0xec000000) && (base <= 0xecffffff))
+ pclog("[0] mem_mapping_set_addr(%08X, %08X)\n", base, size);
+
+ /* Remove old mapping. */
+ map->enable = 0;
+ mem_mapping_recalc(map->base, map->size);
+
+ if ((base >= 0xec000000) && (base <= 0xecffffff))
+ pclog("[1] mem_mapping_set_addr(%08X, %08X)\n", base, size);
+
+ /* Set new mapping. */
+ map->enable = 1;
+ map->base = base;
+ map->size = size;
+
+ if ((base >= 0xec000000) && (base <= 0xecffffff))
+ pclog("[2] mem_mapping_set_addr(%08X, %08X)\n", base, size);
+
+ mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size);
+}
+
+void
+mem_mapping_set_exec(mem_mapping_t *map, uint8_t *exec)
+{
+ map->exec = exec;
+
+ mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size);
+}
+
+void
+mem_mapping_set_mask(mem_mapping_t *map, uint32_t mask)
+{
+ map->mask = mask;
+
+ mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size);
+}
+
+void
+mem_mapping_set_p(mem_mapping_t *map, void *p)
+{
+ map->p = p;
+}
+
+void
+mem_mapping_disable(mem_mapping_t *map)
+{
+ map->enable = 0;
+
+ mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size);
+}
+
+void
+mem_mapping_enable(mem_mapping_t *map)
+{
+ map->enable = 1;
+
+ mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size);
+}
+
+void
+mem_set_access(uint8_t bitmap, int mode, uint32_t base, uint32_t size, uint16_t access)
+{
+ uint32_t c;
+ uint16_t mask, smstate = 0x0000;
+ const uint16_t smstates[4] = { 0x0000, (MEM_READ_SMRAM | MEM_WRITE_SMRAM),
+ MEM_READ_SMRAM_EX, (MEM_READ_DISABLED_EX | MEM_WRITE_DISABLED_EX) };
+
+ int i;
+
+ if (mode)
+ mask = 0x2d6b;
+ else
+ mask = 0x1084;
+
+ if (mode) {
+ if (mode == 1)
+ access = !!access;
+
+ if (mode == 3) {
+ if (access & ACCESS_SMRAM_X)
+ smstate |= MEM_EXEC_SMRAM;
+ if (access & ACCESS_SMRAM_R)
+ smstate |= MEM_READ_SMRAM_2;
+ if (access & ACCESS_SMRAM_W)
+ smstate |= MEM_WRITE_SMRAM;
+ } else
+ smstate = smstates[access & 0x07];
+ } else
+ smstate = access & 0x6f7b;
+
+ for (c = 0; c < size; c += MEM_GRANULARITY_SIZE) {
+ for (i = 0; i < 4; i++) {
+ if (bitmap & (1 << i)) {
+ _mem_state[(c + base) >> MEM_GRANULARITY_BITS].vals[i] = (_mem_state[(c + base) >> MEM_GRANULARITY_BITS].vals[i] & mask) | smstate;
+ }
+ }
+
+#ifdef ENABLE_MEM_LOG
+ if (((c + base) >= 0xa0000) && ((c + base) <= 0xbffff)) {
+ mem_log("Set mem state for block at %08X to %04X with bitmap %02X\n",
+ c + base, smstate, bitmap);
+ }
+#endif
+ }
+
+ mem_mapping_recalc(base, size);
+}
+
+void
+mem_a20_init(void)
+{
+ if (is286) {
+ mem_a20_key = mem_a20_alt = mem_a20_state = 0;
+ rammask = cpu_16bitbus ? 0xffffff : 0xffffffff;
+ if (is6117)
+ rammask |= 0x03000000;
+ flushmmucache();
+ // mem_a20_state = mem_a20_key | mem_a20_alt;
+ } else {
+ rammask = 0xfffff;
+ flushmmucache();
+ mem_a20_key = mem_a20_alt = mem_a20_state = 0;
+ }
+}
+
+/* Close all the memory mappings. */
+void
+mem_close(void)
+{
+ mem_mapping_t *map = base_mapping, *next;
+
+ while (map != NULL) {
+ next = map->next;
+ map->prev = map->next = NULL;
+ map = next;
+ }
+
+ base_mapping = last_mapping = 0;
+}
+
+static void
+mem_add_ram_mapping(mem_mapping_t *mapping, uint32_t base, uint32_t size)
+{
+ mem_mapping_add(mapping, base, size,
+ mem_read_ram, mem_read_ramw, mem_read_raml,
+ mem_write_ram, mem_write_ramw, mem_write_raml,
+ ram + base, MEM_MAPPING_INTERNAL, NULL);
+}
+
+static void
+mem_init_ram_mapping(mem_mapping_t *mapping, uint32_t base, uint32_t size)
+{
+ mem_set_mem_state_both(base, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
+ mem_add_ram_mapping(mapping, base, size);
+}
+
+/* Reset the memory state. */
+void
+mem_reset(void)
+{
+ uint32_t c;
+ size_t m;
+
+ memset(page_ff, 0xff, sizeof(page_ff));
+
+#ifdef USE_NEW_DYNAREC
+ if (byte_dirty_mask) {
+ free(byte_dirty_mask);
+ byte_dirty_mask = NULL;
+ }
+
+ if (byte_code_present_mask) {
+ free(byte_code_present_mask);
+ byte_code_present_mask = NULL;
+ }
+#endif
+
+ /* Free the old pages array, if necessary. */
+ if (pages) {
+ free(pages);
+ pages = NULL;
+ }
+
+ if (ram != NULL) {
+ plat_munmap(ram, ram_size);
+ ram = NULL;
+ ram_size = 0;
+ }
+#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
+ if (ram2 != NULL) {
+ plat_munmap(ram2, ram2_size);
+ ram2 = NULL;
+ ram2_size = 0;
+ }
+
+ if (mem_size > 2097152)
+ mem_size = 2097152;
+#endif
+
+ m = 1024UL * (size_t) mem_size;
+
+#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
+ if (mem_size > 1048576) {
+ ram_size = 1 << 30;
+ ram = (uint8_t *) plat_mmap(ram_size, 0); /* allocate and clear the RAM block of the first 1 GB */
+ if (ram == NULL) {
+ fatal("Failed to allocate primary RAM block. Make sure you have enough RAM available.\n");
+ return;
+ }
+ memset(ram, 0x00, ram_size);
+ ram2_size = m - (1 << 30);
+ ram2 = (uint8_t *) plat_mmap(ram2_size, 0); /* allocate and clear the RAM block above 1 GB */
+ if (ram2 == NULL) {
+ if (config_changed == 2)
+ fatal(EMU_NAME " must be restarted for the memory amount change to be applied.\n");
+ else
+ fatal("Failed to allocate secondary RAM block. Make sure you have enough RAM available.\n");
+ return;
+ }
+ memset(ram2, 0x00, ram2_size);
+ } else
+#endif
+ {
+ ram_size = m;
+ ram = (uint8_t *) plat_mmap(ram_size, 0); /* allocate and clear the RAM block */
+ if (ram == NULL) {
+ fatal("Failed to allocate RAM block. Make sure you have enough RAM available.\n");
+ return;
+ }
+ memset(ram, 0x00, ram_size);
+ if (mem_size > 1048576)
+ ram2 = &(ram[1 << 30]);
+ }
+
+ /*
+ * Allocate the page table based on how much RAM we have.
+ * We re-allocate the table on each (hard) reset, as the
+ * memory amount could have changed.
+ */
+ if (is286) {
+ if (cpu_16bitbus) {
+ /* 80286/386SX; maximum address space is 16MB. */
+ m = 4096;
+ /* ALi M6117; maximum address space is 64MB. */
+ if (is6117)
+ m <<= 2;
+ } else {
+ /* 80386DX+; maximum address space is 4GB. */
+ m = 1048576;
+ }
+ } else {
+ /* 8088/86; maximum address space is 1MB. */
+ m = 256;
+ }
+
+ addr_space_size = m;
+
+ /*
+ * Allocate and initialize the (new) page table.
+ */
+ pages_sz = m;
+ pages = (page_t *) malloc(m * sizeof(page_t));
+
+ memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *));
+ memset(page_lookupp, 0x04, (1 << 20) * sizeof(uint8_t));
+
+ memset(pages, 0x00, pages_sz * sizeof(page_t));
+
+#ifdef USE_NEW_DYNAREC
+ byte_dirty_mask = malloc((mem_size * 1024) / 8);
+ memset(byte_dirty_mask, 0, (mem_size * 1024) / 8);
+
+ byte_code_present_mask = malloc((mem_size * 1024) / 8);
+ memset(byte_code_present_mask, 0, (mem_size * 1024) / 8);
+#endif
+
+ for (c = 0; c < pages_sz; c++) {
+ if ((c << 12) >= (mem_size << 10))
+ pages[c].mem = page_ff;
+ else {
+#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
+ if (mem_size > 1048576) {
+ if ((c << 12) < (1 << 30))
+ pages[c].mem = &ram[c << 12];
+ else
+ pages[c].mem = &ram2[(c << 12) - (1 << 30)];
+ } else
+ pages[c].mem = &ram[c << 12];
+#else
+ pages[c].mem = &ram[c << 12];
+#endif
+ }
+ if (c < m) {
+ pages[c].write_b = mem_write_ramb_page;
+ pages[c].write_w = mem_write_ramw_page;
+ pages[c].write_l = mem_write_raml_page;
+ }
+#ifdef USE_NEW_DYNAREC
+ pages[c].evict_prev = EVICT_NOT_IN_LIST;
+ pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64];
+ pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64];
+#endif
+ }
+
+ memset(_mem_exec, 0x00, sizeof(_mem_exec));
+ memset(write_mapping, 0x00, sizeof(write_mapping));
+ memset(read_mapping, 0x00, sizeof(read_mapping));
+ memset(write_mapping_bus, 0x00, sizeof(write_mapping_bus));
+ memset(read_mapping_bus, 0x00, sizeof(read_mapping_bus));
+
+ base_mapping = last_mapping = NULL;
+
+ /* Set the entire memory space as external. */
+ memset(_mem_state, 0x00, sizeof(_mem_state));
+
+ /* Set the low RAM space as internal. */
+ mem_init_ram_mapping(&ram_low_mapping, 0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024);
+
+ if (mem_size > 1024) {
+ if (cpu_16bitbus && !is6117 && mem_size > 16256)
+ mem_init_ram_mapping(&ram_high_mapping, 0x100000, (16256 - 1024) * 1024);
+ else if (cpu_16bitbus && is6117 && mem_size > 65408)
+ mem_init_ram_mapping(&ram_high_mapping, 0x100000, (65408 - 1024) * 1024);
+ else {
+ if (mem_size > 1048576) {
+ mem_init_ram_mapping(&ram_high_mapping, 0x100000, (1048576 - 1024) * 1024);
+
+ mem_set_mem_state_both((1 << 30), (mem_size - 1048576) * 1024,
+ MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
+ mem_mapping_add(&ram_2gb_mapping, (1 << 30),
+ ((mem_size - 1048576) * 1024),
+ mem_read_ram_2gb, mem_read_ram_2gbw, mem_read_ram_2gbl,
+ mem_write_ram, mem_write_ramw, mem_write_raml,
+ ram2, MEM_MAPPING_INTERNAL, NULL);
+ } else
+ mem_init_ram_mapping(&ram_high_mapping, 0x100000, (mem_size - 1024) * 1024);
+ }
+ }
+
+ if (mem_size > 768) {
+ mem_add_ram_mapping(&ram_mid_mapping, 0xa0000, 0x60000);
+
+ mem_add_ram_mapping(&ram_mid_mapping2, 0xa0000, 0x60000);
+ mem_mapping_disable(&ram_mid_mapping2);
+ }
+
+ mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 256 * 1024,
+ mem_read_remapped, mem_read_remappedw, mem_read_remappedl,
+ mem_write_remapped, mem_write_remappedw, mem_write_remappedl,
+ ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL);
+ mem_mapping_disable(&ram_remapped_mapping);
+
+ /* Mapping for SiS 471 relocation which relocates A0000-BFFFF, D0000-EFFFF, which is non-contiguous. */
+ mem_mapping_add(&ram_remapped_mapping2, mem_size * 1024, 256 * 1024,
+ mem_read_remapped2, mem_read_remappedw2, mem_read_remappedl2,
+ mem_write_remapped2, mem_write_remappedw2, mem_write_remappedl2,
+ ram + 0xd0000, MEM_MAPPING_INTERNAL, NULL);
+ mem_mapping_disable(&ram_remapped_mapping2);
+
+ mem_a20_init();
+
+#ifdef USE_NEW_DYNAREC
+ purgable_page_list_head = 0;
+ purgeable_page_count = 0;
+#endif
+}
+
+void
+mem_init(void)
+{
+ /* Perform a one-time init. */
+ ram = rom = NULL;
+ ram2 = NULL;
+ pages = NULL;
+
+ /* Allocate the lookup tables. */
+ page_lookup = (page_t **) malloc((1 << 20) * sizeof(page_t *));
+ page_lookupp = (uint8_t *) malloc((1 << 20) * sizeof(uint8_t));
+ readlookup2 = malloc((1 << 20) * sizeof(uintptr_t));
+ readlookupp = malloc((1 << 20) * sizeof(uint8_t));
+ writelookup2 = malloc((1 << 20) * sizeof(uintptr_t));
+ writelookupp = malloc((1 << 20) * sizeof(uint8_t));
+}
+
+void
+mem_remap_top(int kb)
+{
+ uint32_t c;
+ uint32_t start = (mem_size >= 1024) ? mem_size : 1024;
+ int offset, size = mem_size - 640;
+ int set = 1;
+ static int old_kb = 0;
+ int sis_mode = 0;
+ uint32_t start_addr = 0, addr = 0;
+
+ mem_log("MEM: remapping top %iKB (mem=%i)\n", kb, mem_size);
+ if (mem_size <= 640)
+ return;
+
+ /* SiS 471 special mode. */
+ if (kb == -256) {
+ kb = 256;
+ sis_mode = 1;
+ }
+
+ /* Do not remap if we're have more than (16 MB - RAM) memory. */
+ if ((kb != 0) && (mem_size >= (16384 - kb)))
+ return;
+
+ if (kb == 0) {
+ kb = old_kb;
+ set = 0;
+ } else
+ old_kb = kb;
+
+ if (size > kb)
+ size = kb;
+
+ remap_start_addr = start << 10;
+ remap_start_addr2 = (start << 10) + 0x00020000;
+
+ for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) {
+ offset = c - ((start * 1024) >> 12);
+ /* Use A0000-BFFFF, D0000-EFFFF instead of C0000-DFFFF, E0000-FFFFF. */
+ addr = 0xa0000 + (offset << 12);
+ if (sis_mode) {
+ /* A0000-DFFFF -> A0000-BFFFF, D0000-EFFFF */
+ if (addr >= 0x000c0000)
+ addr += 0x00010000;
+ }
+ if (start_addr == 0)
+ start_addr = addr;
+ pages[c].mem = set ? &ram[addr] : page_ff;
+ pages[c].write_b = set ? mem_write_ramb_page : NULL;
+ pages[c].write_w = set ? mem_write_ramw_page : NULL;
+ pages[c].write_l = set ? mem_write_raml_page : NULL;
+#ifdef USE_NEW_DYNAREC
+ pages[c].evict_prev = EVICT_NOT_IN_LIST;
+ pages[c].byte_dirty_mask = &byte_dirty_mask[(addr >> 12) * 64];
+ pages[c].byte_code_present_mask = &byte_code_present_mask[(addr >> 12) * 64];
+#endif
+ }
+
+ mem_set_mem_state_both(start * 1024, size * 1024, set ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL));
+
+ for (c = 0xa0; c < 0xf0; c++) {
+ if ((c >= 0xc0) && (c <= 0xcf))
+ continue;
+
+ if (sis_mode || ((c << 12) >= (mem_size << 10)))
+ pages[c].mem = page_ff;
+ else {
+#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
+ if (mem_size > 1048576) {
+ if ((c << 12) < (1 << 30))
+ pages[c].mem = &ram[c << 12];
+ else
+ pages[c].mem = &ram2[(c << 12) - (1 << 30)];
+ } else
+ pages[c].mem = &ram[c << 12];
+#else
+ pages[c].mem = &ram[c << 12];
+#endif
+ }
+ if (!sis_mode && (c < addr_space_size)) {
+ pages[c].write_b = mem_write_ramb_page;
+ pages[c].write_w = mem_write_ramw_page;
+ pages[c].write_l = mem_write_raml_page;
+ } else {
+ pages[c].write_b = NULL;
+ pages[c].write_w = NULL;
+ pages[c].write_l = NULL;
+ }
+#ifdef USE_NEW_DYNAREC
+ pages[c].evict_prev = EVICT_NOT_IN_LIST;
+ pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64];
+ pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64];
+#endif
+ }
+
+ if (set) {
+ if (sis_mode) {
+ mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, 0x00020000);
+ mem_mapping_set_exec(&ram_remapped_mapping, ram + 0x000a0000);
+ mem_mapping_set_addr(&ram_remapped_mapping2, (start * 1024) + 0x00020000, 0x00020000);
+ mem_mapping_set_exec(&ram_remapped_mapping2, ram + 0x000d0000);
+
+ mem_mapping_set_addr(&ram_mid_mapping, 0x000c0000, 0x00010000);
+ mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000c0000);
+ mem_mapping_set_addr(&ram_mid_mapping2, 0x000f0000, 0x00010000);
+ mem_mapping_set_exec(&ram_mid_mapping2, ram + 0x000f0000);
+ } else {
+ mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024);
+ mem_mapping_set_exec(&ram_remapped_mapping, ram + start_addr);
+ mem_mapping_disable(&ram_remapped_mapping2);
+
+ mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000);
+ mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000);
+ mem_mapping_disable(&ram_mid_mapping2);
+ }
+ } else {
+ mem_mapping_disable(&ram_remapped_mapping);
+ mem_mapping_disable(&ram_remapped_mapping2);
+
+ mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000);
+ mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000);
+ mem_mapping_disable(&ram_mid_mapping2);
+ }
+
+ flushmmucache();
+}
+
+void
+mem_reset_page_blocks(void)
+{
+ uint32_t c;
+
+ if (pages == NULL)
+ return;
+
+ for (c = 0; c < pages_sz; c++) {
+ pages[c].write_b = mem_write_ramb_page;
+ pages[c].write_w = mem_write_ramw_page;
+ pages[c].write_l = mem_write_raml_page;
+#ifdef USE_NEW_DYNAREC
+ pages[c].block = BLOCK_INVALID;
+ pages[c].block_2 = BLOCK_INVALID;
+ pages[c].head = BLOCK_INVALID;
+#else
+ pages[c].block[0] = pages[c].block[1] = pages[c].block[2] = pages[c].block[3] = NULL;
+ pages[c].block_2[0] = pages[c].block_2[1] = pages[c].block_2[2] = pages[c].block_2[3] = NULL;
+ pages[c].head = NULL;
+#endif
+ }
+}
+
+void
+mem_a20_recalc(void)
+{
+ int state;
+
+ if (!is286) {
+ rammask = 0xfffff;
+ flushmmucache();
+ mem_a20_key = mem_a20_alt = mem_a20_state = 0;
+
+ return;
+ }
+
+ state = mem_a20_key | mem_a20_alt;
+ if (state && !mem_a20_state) {
+ rammask = (cpu_16bitbus) ? 0xffffff : 0xffffffff;
+ if (is6117)
+ rammask |= 0x03000000;
+ flushmmucache();
+ } else if (!state && mem_a20_state) {
+ rammask = (cpu_16bitbus) ? 0xefffff : 0xffefffff;
+ if (is6117)
+ rammask |= 0x03000000;
+ flushmmucache();
+ }
+
+ mem_a20_state = state;
+}
diff --git a/src/mouse.patch b/src/mouse.patch
new file mode 100644
index 000000000..4d9d67d2a
--- /dev/null
+++ b/src/mouse.patch
@@ -0,0 +1,69 @@
+diff --git a/src/86box.c b/src/86box.c
+index a14f51c41..3c96d88a4 100644
+--- a/src/86box.c
++++ b/src/86box.c
+@@ -1263,9 +1263,9 @@ pc_run(void)
+ startblit();
+ cpu_exec(cpu_s->rspeed / 100);
+ #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */
+- if (gdbstub_step == GDBSTUB_EXEC)
++ // if (gdbstub_step == GDBSTUB_EXEC)
+ #endif
+- mouse_process();
++ // mouse_process();
+ joystick_process();
+ endblit();
+
+diff --git a/src/device/mouse.c b/src/device/mouse.c
+index 7eb6a08a9..329397d43 100644
+--- a/src/device/mouse.c
++++ b/src/device/mouse.c
+@@ -27,6 +27,8 @@
+ #define HAVE_STDARG_H
+ #include <86box/86box.h>
+ #include <86box/device.h>
++#include <86box/timer.h>
++#include <86box/gdbstub.h>
+ #include <86box/mouse.h>
+
+ typedef struct {
+@@ -45,6 +47,8 @@ int mouse_x,
+ double mouse_x_abs,
+ mouse_y_abs;
+
++pc_timer_t mouse_timer; /* mouse event timer */
++
+ static const device_t mouse_none_device = {
+ .name = "None",
+ .internal_name = "none",
+@@ -141,6 +145,20 @@ mouse_close(void)
+ mouse_priv = NULL;
+ mouse_nbut = 0;
+ mouse_dev_poll = NULL;
++
++ timer_stop(&mouse_timer);
++}
++
++static void
++mouse_timer_poll(void *priv)
++{
++ // timer_on_auto(&mouse_timer, 1388.0 + (8.0 / 9.0));
++ timer_on_auto(&mouse_timer, 277.0 + (7.0 / 9.0));
++
++#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */
++ if (gdbstub_step == GDBSTUB_EXEC)
++#endif
++ mouse_process();
+ }
+
+ void
+@@ -165,6 +183,9 @@ mouse_reset(void)
+
+ if (mouse_curr != NULL)
+ mouse_priv = device_add(mouse_curr);
++
++ timer_add(&mouse_timer, mouse_timer_poll, NULL, 0);
++ timer_on_auto(&mouse_timer, 10000.0);
+ }
+
+ /* Callback from the hardware driver. */
diff --git a/src/pic - Cópia.c b/src/pic - Cópia.c
new file mode 100644
index 000000000..70a8a7805
--- /dev/null
+++ b/src/pic - Cópia.c
@@ -0,0 +1,838 @@
+/*
+ * 86Box A hypervisor and IBM PC system emulator that specializes in
+ * running old operating systems and software designed for IBM
+ * PC systems and compatibles from 1981 through fairly recent
+ * system designs based on the PCI bus.
+ *
+ * This file is part of the 86Box distribution.
+ *
+ * Implementation of the Intel PIC chip emulation, partially
+ * ported from reenigne's XTCE.
+ *
+ *
+ *
+ * Authors: Andrew Jenner,
+ * Miran Grca,
+ *
+ * Copyright 2015-2020 Andrew Jenner.
+ * Copyright 2016-2020 Miran Grca.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define HAVE_STDARG_H
+#include <86box/86box.h>
+#include "cpu.h"
+#include <86box/machine.h>
+#include <86box/io.h>
+#include <86box/pci.h>
+#include <86box/pic.h>
+#include <86box/timer.h>
+#include <86box/pit.h>
+#include <86box/device.h>
+#include <86box/apm.h>
+#include <86box/nvr.h>
+#include <86box/acpi.h>
+
+enum {
+ STATE_NONE = 0,
+ STATE_ICW2,
+ STATE_ICW3,
+ STATE_ICW4
+};
+
+pic_t pic, pic2;
+
+static pc_timer_t pic_timer;
+
+static int shadow = 0, elcr_enabled = 0,
+ tmr_inited = 0, latched = 0,
+ pic_pci = 0, kbd_latch = 0,
+ mouse_latch = 0;
+
+static uint16_t smi_irq_mask = 0x0000,
+ smi_irq_status = 0x0000;
+
+static uint16_t latched_irqs = 0x0000;
+
+static void (*update_pending)(void);
+
+#ifdef ENABLE_PIC_LOG
+int pic_do_log = ENABLE_PIC_LOG;
+
+static void
+pic_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (pic_do_log) {
+ va_start(ap, fmt);
+ pclog_ex(fmt, ap);
+ va_end(ap);
+ }
+}
+#else
+# define pic_log(fmt, ...)
+#endif
+
+void
+pic_reset_smi_irq_mask(void)
+{
+ smi_irq_mask = 0x0000;
+}
+
+void
+pic_set_smi_irq_mask(int irq, int set)
+{
+ if ((irq >= 0) && (irq <= 15)) {
+ if (set)
+ smi_irq_mask |= (1 << irq);
+ else
+ smi_irq_mask &= ~(1 << irq);
+ }
+}
+
+uint16_t
+pic_get_smi_irq_status(void)
+{
+ return smi_irq_status;
+}
+
+void
+pic_clear_smi_irq_status(int irq)
+{
+ if ((irq >= 0) && (irq <= 15))
+ smi_irq_status &= ~(1 << irq);
+}
+
+void
+pic_elcr_write(uint16_t port, uint8_t val, void *priv)
+{
+ pic_t *dev = (pic_t *) priv;
+
+ pic_log("ELCR%i: WRITE %02X\n", port & 1, val);
+
+ if (port & 1)
+ val &= 0xde;
+ else
+ val &= 0xf8;
+
+ dev->elcr = val;
+
+ pic_log("ELCR %i: %c %c %c %c %c %c %c %c\n",
+ port & 1,
+ (val & 1) ? 'L' : 'E',
+ (val & 2) ? 'L' : 'E',
+ (val & 4) ? 'L' : 'E',
+ (val & 8) ? 'L' : 'E',
+ (val & 0x10) ? 'L' : 'E',
+ (val & 0x20) ? 'L' : 'E',
+ (val & 0x40) ? 'L' : 'E',
+ (val & 0x80) ? 'L' : 'E');
+}
+
+uint8_t
+pic_elcr_read(uint16_t port, void *priv)
+{
+ pic_t *dev = (pic_t *) priv;
+
+ pic_log("ELCR%i: READ %02X\n", port & 1, dev->elcr);
+
+ return dev->elcr;
+}
+
+int
+pic_elcr_get_enabled(void)
+{
+ return elcr_enabled;
+}
+
+void
+pic_elcr_set_enabled(int enabled)
+{
+ elcr_enabled = enabled;
+}
+
+void
+pic_elcr_io_handler(int set)
+{
+ io_handler(set, 0x04d0, 0x0001,
+ pic_elcr_read, NULL, NULL,
+ pic_elcr_write, NULL, NULL, &pic);
+ io_handler(set, 0x04d1, 0x0001,
+ pic_elcr_read, NULL, NULL,
+ pic_elcr_write, NULL, NULL, &pic2);
+}
+
+static uint8_t
+pic_cascade_mode(pic_t *dev)
+{
+ return !(dev->icw1 & 2);
+}
+
+static __inline uint8_t
+pic_slave_on(pic_t *dev, int channel)
+{
+ pic_log("pic_slave_on(%i): %i, %02X, %02X\n", channel, pic_cascade_mode(dev), dev->icw4 & 0x0c, dev->icw3 & (1 << channel));
+
+ return pic_cascade_mode(dev) && (dev->is_master || ((dev->icw4 & 0x0c) == 0x0c)) && (dev->icw3 & (1 << channel));
+}
+
+static __inline int
+find_best_interrupt(pic_t *dev)
+{
+ uint8_t b;
+ uint8_t intr;
+ int i, j;
+ int ret = -1;
+
+ for (i = 0; i < 8; i++) {
+ j = (i + dev->priority) & 7;
+ b = 1 << j;
+
+ if (dev->isr & b)
+ break;
+ else if ((dev->state == 0) && ((dev->irr & ~dev->imr) & b)) {
+ ret = j;
+ break;
+ }
+ }
+
+ intr = dev->interrupt = (ret == -1) ? 0x17 : ret;
+
+ if (dev->at && (ret != -1)) {
+ if (dev == &pic2)
+ intr += 8;
+
+ if (cpu_fast_off_flags & (1u << intr))
+ cpu_fast_off_advance();
+ }
+
+ return ret;
+}
+
+static __inline void
+pic_update_pending_xt(void)
+{
+ if (find_best_interrupt(&pic) != -1) {
+ latched++;
+ if (latched == 1)
+ timer_on_auto(&pic_timer, 0.35);
+ } else if (latched == 0)
+ pic.int_pending = 0;
+}
+
+static __inline void
+pic_update_pending_at(void)
+{
+ pic2.int_pending = (find_best_interrupt(&pic2) != -1);
+
+ if (pic2.int_pending)
+ pic.irr |= (1 << pic2.icw3);
+ else
+ pic.irr &= ~(1 << pic2.icw3);
+
+ pic.int_pending = (find_best_interrupt(&pic) != -1);
+}
+
+static void
+pic_callback(void *priv)
+{
+ pic_t *dev = (pic_t *) priv;
+
+ dev->int_pending = 1;
+
+ latched--;
+ if (latched > 0)
+ timer_on_auto(&pic_timer, 0.35);
+}
+
+void
+pic_reset(void)
+{
+ int is_at = IS_AT(machine);
+ is_at = is_at || !strcmp(machine_get_internal_name(), "xi8088");
+
+ memset(&pic, 0, sizeof(pic_t));
+ memset(&pic2, 0, sizeof(pic_t));
+
+ pic.is_master = 1;
+ pic.interrupt = pic2.interrupt = 0x17;
+
+ if (is_at)
+ pic.slaves[2] = &pic2;
+
+ if (tmr_inited)
+ timer_on_auto(&pic_timer, 0.0);
+ memset(&pic_timer, 0x00, sizeof(pc_timer_t));
+ timer_add(&pic_timer, pic_callback, &pic, 0);
+ tmr_inited = 1;
+
+ update_pending = is_at ? pic_update_pending_at : pic_update_pending_xt;
+ pic.at = pic2.at = is_at;
+
+ smi_irq_mask = smi_irq_status = 0x0000;
+
+ shadow = 0;
+ pic_pci = 0;
+}
+
+void
+pic_set_shadow(int sh)
+{
+ shadow = sh;
+}
+
+int
+pic_get_pci_flag(void)
+{
+ return pic_pci;
+}
+
+void
+pic_set_pci_flag(int pci)
+{
+ pic_pci = pci;
+}
+
+static uint8_t
+pic_level_triggered(pic_t *dev, int irq)
+{
+ if (elcr_enabled)
+ return !!(dev->elcr & (1 << irq));
+ else
+ return !!(dev->icw1 & 8);
+}
+
+int
+picint_is_level(int irq)
+{
+ return pic_level_triggered(((irq > 7) ? &pic2 : &pic), irq & 7);
+}
+
+static void
+pic_acknowledge(pic_t *dev)
+{
+ int pic_int = dev->interrupt & 7;
+ int pic_int_num = 1 << pic_int;
+
+ dev->isr |= pic_int_num;
+ if (!pic_level_triggered(dev, pic_int) || !(dev->lines & pic_int_num))
+ dev->irr &= ~pic_int_num;
+}
+
+/* Find IRQ for non-specific EOI (either by command or automatic) by finding the highest IRQ
+ priority with ISR bit set, that is also not masked if the PIC is in special mask mode. */
+static uint8_t
+pic_non_specific_find(pic_t *dev)
+{
+ int i, j;
+ uint8_t b, irq = 0xff;
+
+ for (i = 0; i < 8; i++) {
+ j = (i + dev->priority) & 7;
+ b = (1 << j);
+
+ if ((dev->isr & b) && (!dev->special_mask_mode || !(dev->imr & b))) {
+ irq = j;
+ break;
+ }
+ }
+
+ return irq;
+}
+
+/* Do the EOI and rotation, if either is requested, on the given IRQ. */
+static void
+pic_action(pic_t *dev, uint8_t irq, uint8_t eoi, uint8_t rotate)
+{
+ uint8_t b = (1 << irq);
+
+ if (irq != 0xff) {
+ if (eoi)
+ dev->isr &= ~b;
+ if (rotate)
+ dev->priority = (irq + 1) & 7;
+
+ update_pending();
+ }
+}
+
+/* Automatic non-specific EOI. */
+static __inline void
+pic_auto_non_specific_eoi(pic_t *dev)
+{
+ uint8_t irq;
+
+ if (dev->icw4 & 2) {
+ irq = pic_non_specific_find(dev);
+
+ pic_action(dev, irq, 1, dev->auto_eoi_rotate);
+ }
+}
+
+/* Do the PIC command specified by bits 7-5 of the value written to the OCW2 register. */
+static void
+pic_command(pic_t *dev)
+{
+ uint8_t irq = 0xff;
+
+ if (dev->ocw2 & 0x60) { /* SL and/or EOI set */
+ if (dev->ocw2 & 0x40) /* SL set, specific priority level */
+ irq = (dev->ocw2 & 0x07);
+ else /* SL clear, non-specific priority level (find highest with ISR set) */
+ irq = pic_non_specific_find(dev);
+
+ pic_action(dev, irq, dev->ocw2 & 0x20, dev->ocw2 & 0x80);
+ } else /* SL and EOI clear */
+ dev->auto_eoi_rotate = !!(dev->ocw2 & 0x80);
+}
+
+uint8_t
+pic_latch_read(uint16_t addr, void *priv)
+{
+ uint8_t ret = 0xff;
+
+ pic_log("pic_latch_read(%i, %i): %02X%02X\n", kbd_latch, mouse_latch, pic2.lines & 0x10, pic.lines & 0x02);
+
+ if (kbd_latch && (latched_irqs & 0x0002))
+ picintc(0x0002);
+
+ if (mouse_latch && (latched_irqs & 0x1000))
+ picintc(0x1000);
+
+ /* Return FF - we just lower IRQ 1 and IRQ 12. */
+ return ret;
+}
+
+uint8_t
+pic_read(uint16_t addr, void *priv)
+{
+ pic_t *dev = (pic_t *) priv;
+
+ if (shadow) {
+ /* VIA PIC shadow read */
+ if (addr & 0x0001)
+ dev->data_bus = ((dev->icw2 & 0xf8) >> 3) << 0;
+ else {
+ dev->data_bus = ((dev->ocw3 & 0x20) >> 5) << 4;
+ dev->data_bus |= ((dev->ocw2 & 0x80) >> 7) << 3;
+ dev->data_bus |= ((dev->icw4 & 0x10) >> 4) << 2;
+ dev->data_bus |= ((dev->icw4 & 0x02) >> 1) << 1;
+ dev->data_bus |= ((dev->icw4 & 0x08) >> 3) << 0;
+ }
+ } else {
+ /* Standard 8259 PIC read */
+#ifndef UNDEFINED_READ
+ /* Put the IRR on to the data bus by default until the real PIC is probed. */
+ dev->data_bus = dev->irr;
+#endif
+ if (dev->ocw3 & 0x04) {
+ dev->interrupt &= ~0x20; /* Freeze the interrupt until the poll is over. */
+ if (dev->int_pending) {
+ dev->data_bus = 0x80 | (dev->interrupt & 7);
+ pic_acknowledge(dev);
+ dev->int_pending = 0;
+ update_pending();
+ } else
+ dev->data_bus = 0x00;
+ dev->ocw3 &= ~0x04;
+ } else if (addr & 0x0001)
+ dev->data_bus = dev->imr;
+ else if (dev->ocw3 & 0x02) {
+ if (dev->ocw3 & 0x01)
+ dev->data_bus = dev->isr;
+#ifdef UNDEFINED_READ
+ else
+ dev->data_bus = 0x00;
+#endif
+ }
+ /* If A0 = 0, VIA shadow is disabled, and poll mode is disabled,
+ simply read whatever is currently on the data bus. */
+ }
+
+ pic_log("pic_read(%04X, %08X) = %02X\n", addr, priv, dev->data_bus);
+
+ return dev->data_bus;
+}
+
+static void
+pic_write(uint16_t addr, uint8_t val, void *priv)
+{
+ pic_t *dev = (pic_t *) priv;
+
+ pic_log("pic_write(%04X, %02X, %08X)\n", addr, val, priv);
+
+ dev->data_bus = val;
+
+ if (addr & 0x0001) {
+ switch (dev->state) {
+ case STATE_ICW2:
+ dev->icw2 = val;
+ if (pic_cascade_mode(dev))
+ dev->state = STATE_ICW3;
+ else
+ dev->state = (dev->icw1 & 1) ? STATE_ICW4 : STATE_NONE;
+ break;
+ case STATE_ICW3:
+ dev->icw3 = val;
+ dev->state = (dev->icw1 & 1) ? STATE_ICW4 : STATE_NONE;
+ break;
+ case STATE_ICW4:
+ dev->icw4 = val;
+ dev->state = STATE_NONE;
+ break;
+ case STATE_NONE:
+ dev->imr = val;
+ update_pending();
+ break;
+ }
+ } else {
+ if (val & 0x10) {
+ /* Treat any write with any of the bits 7 to 5 set as invalid if PCI. */
+ if (pic_pci && (val & 0xe0))
+ return;
+
+ dev->icw1 = val;
+ dev->icw2 = dev->icw3 = 0x00;
+ if (!(dev->icw1 & 1))
+ dev->icw4 = 0x00;
+ dev->ocw2 = dev->ocw3 = 0x00;
+ dev->irr = dev->lines;
+ dev->imr = dev->isr = 0x00;
+ dev->ack_bytes = dev->priority = 0x00;
+ dev->auto_eoi_rotate = dev->special_mask_mode = 0x00;
+ dev->interrupt = 0x17;
+ dev->int_pending = 0x00;
+ dev->state = STATE_ICW2;
+ update_pending();
+ } else if (val & 0x08) {
+ dev->ocw3 = val;
+ if (dev->ocw3 & 0x04)
+ dev->interrupt |= 0x20; /* Freeze the interrupt until the poll is over. */
+ if (dev->ocw3 & 0x40)
+ dev->special_mask_mode = !!(dev->ocw3 & 0x20);
+ } else {
+ dev->ocw2 = val;
+ pic_command(dev);
+ }
+ }
+}
+
+void
+pic_set_pci(void)
+{
+ int i;
+
+ for (i = 0x0024; i < 0x0040; i += 4) {
+ io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
+ io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2);
+ }
+
+ for (i = 0x1120; i < 0x1140; i += 4) {
+ io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
+ io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2);
+ }
+}
+
+void
+pic_kbd_latch(int enable)
+{
+ pic_log("PIC keyboard latch now %sabled\n", enable ? "en" : "dis");
+
+ if (!!(enable | mouse_latch) != !!(kbd_latch | mouse_latch))
+ io_handler(!!(enable | mouse_latch), 0x0060, 0x0001, pic_latch_read, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ kbd_latch = !!enable;
+
+ if (!enable)
+ picintc(0x0002);
+}
+
+void
+pic_mouse_latch(int enable)
+{
+ pic_log("PIC mouse latch now %sabled\n", enable ? "en" : "dis");
+
+ if (!!(kbd_latch | enable) != !!(kbd_latch | mouse_latch))
+ io_handler(!!(kbd_latch | enable), 0x0060, 0x0001, pic_latch_read, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ mouse_latch = !!enable;
+
+ if (!enable)
+ picintc(0x1000);
+}
+
+static void
+pic_reset_hard(void)
+{
+ pic_reset();
+
+ /* Explicitly reset the latches. */
+ kbd_latch = mouse_latch = 0;
+
+ /* The situation is as follows: There is a giant mess when it comes to these latches on real hardware,
+ to the point that there's even boards with board-level latched that get used in place of the latches
+ on the chipset, therefore, I'm just doing this here for the sake of simplicity. */
+ if (machine_has_bus(machine, MACHINE_BUS_PS2)) {
+ pic_kbd_latch(0x01);
+ pic_mouse_latch(0x01);
+ } else {
+ pic_kbd_latch(0x00);
+ pic_mouse_latch(0x00);
+ }
+}
+
+void
+pic_init(void)
+{
+ pic_reset_hard();
+
+ shadow = 0;
+ io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
+}
+
+void
+pic_init_pcjr(void)
+{
+ pic_reset_hard();
+
+ shadow = 0;
+ io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
+}
+
+void
+pic2_init(void)
+{
+ io_sethandler(0x00a0, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2);
+ pic.slaves[2] = &pic2;
+}
+
+void
+picint_common(uint16_t num, int level, int set)
+{
+ int i, raise;
+ uint8_t b, slaves = 0;
+
+ /* Make sure to ignore all slave IRQ's, and in case of AT+,
+ translate IRQ 2 to IRQ 9. */
+ for (i = 0; i < 8; i++) {
+ b = (1 << i);
+ raise = num & b;
+
+ if (pic.icw3 & b) {
+ slaves++;
+
+ if (raise) {
+ num &= ~b;
+ if (pic.at && (i == 2))
+ num |= (1 << 9);
+ }
+ }
+ }
+
+ if (!slaves)
+ num &= 0x00ff;
+
+ if (!num) {
+ pic_log("Attempting to %s null IRQ\n", set ? "raise" : "lower");
+ return;
+ }
+
+ if (num & 0x0100)
+ acpi_rtc_status = !!set;
+
+ if (set) {
+ if (smi_irq_mask & num) {
+ smi_raise();
+ smi_irq_status |= num;
+ }
+
+ if (num & 0xff00) {
+ if (level)
+ pic2.lines |= (num >> 8);
+
+ /* Latch IRQ 12 if the mouse latch is enabled. */
+ if ((num & 0x1000) && mouse_latch)
+ latched_irqs |= 0x1000;
+
+ pic2.irr |= (num >> 8);
+ }
+
+ if (num & 0x00ff) {
+ if (level)
+ pic.lines |= (num & 0x00ff);
+
+ /* Latch IRQ 1 if the keyboard latch is enabled. */
+ if (kbd_latch && (num & 0x0002))
+ latched_irqs |= 0x0002;
+
+ pic.irr |= (num & 0x00ff);
+ }
+ } else {
+ smi_irq_status &= ~num;
+
+ if (num & 0xff00) {
+ pic2.lines &= ~(num >> 8);
+
+ /* Unlatch IRQ 12 if the mouse latch is enabled. */
+ if ((num & 0x1000) && mouse_latch)
+ latched_irqs &= 0xefff;
+
+ pic2.irr &= ~(num >> 8);
+ }
+
+ if (num & 0x00ff) {
+ pic.lines &= ~(num & 0x00ff);
+
+ /* Unlatch IRQ 1 if the keyboard latch is enabled. */
+ if (kbd_latch && (num & 0x0002))
+ latched_irqs &= 0xfffd;
+
+ pic.irr &= ~(num & 0x00ff);
+ }
+ }
+
+ if (!(pic.interrupt & 0x20) && !(pic2.interrupt & 0x20))
+ update_pending();
+}
+
+void
+picint(uint16_t num)
+{
+ picint_common(num, 0, 1);
+}
+
+void
+picintlevel(uint16_t num)
+{
+ picint_common(num, 1, 1);
+}
+
+void
+picintc(uint16_t num)
+{
+ picint_common(num, 0, 0);
+}
+
+static uint8_t
+pic_i86_mode(pic_t *dev)
+{
+ return !!(dev->icw4 & 1);
+}
+
+static uint8_t
+pic_irq_ack_read(pic_t *dev, int phase)
+{
+ uint8_t intr = dev->interrupt & 0x47;
+ uint8_t slave = intr & 0x40;
+ intr &= 0x07;
+ pic_log(" pic_irq_ack_read(%08X, %i)\n", dev, phase);
+
+ if (dev != NULL) {
+ if (phase == 0) {
+ dev->interrupt |= 0x20; /* Freeze it so it still takes interrupts but they do not
+ override the one currently being processed. */
+ pic_acknowledge(dev);
+ if (slave)
+ dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
+ else
+ dev->data_bus = pic_i86_mode(dev) ? 0xff : 0xcd;
+ } else if (pic_i86_mode(dev)) {
+ dev->int_pending = 0;
+ if (slave)
+ dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
+ else
+ dev->data_bus = intr + (dev->icw2 & 0xf8);
+ pic_auto_non_specific_eoi(dev);
+ } else if (phase == 1) {
+ if (slave)
+ dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
+ else if (dev->icw1 & 0x04)
+ dev->data_bus = (intr << 2) + (dev->icw1 & 0xe0);
+ else
+ dev->data_bus = (intr << 3) + (dev->icw1 & 0xc0);
+ } else if (phase == 2) {
+ dev->int_pending = 0;
+ if (slave)
+ dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
+ else
+ dev->data_bus = dev->icw2;
+ pic_auto_non_specific_eoi(dev);
+ }
+ }
+
+ return dev->data_bus;
+}
+
+uint8_t
+pic_irq_ack(void)
+{
+ int ret;
+
+ /* Needed for Xi8088. */
+ if ((pic.ack_bytes == 0) && pic.int_pending && pic_slave_on(&pic, pic.interrupt)) {
+ if (!pic.slaves[pic.interrupt]->int_pending) {
+ /* If we are on AT, IRQ 2 is pending, and we cannot find a pending IRQ on PIC 2, fatal out. */
+ fatal("IRQ %i pending on AT without a pending IRQ on PIC %i (normal)\n", pic.interrupt, pic.interrupt);
+ exit(-1);
+ return -1;
+ }
+
+ pic.interrupt |= 0x40; /* Mark slave pending. */
+ }
+
+ ret = pic_irq_ack_read(&pic, pic.ack_bytes);
+ pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3);
+
+ if (pic.ack_bytes == 0) {
+ /* Needed for Xi8088. */
+ if (pic.interrupt & 0x40)
+ pic2.interrupt = 0x17;
+ pic.interrupt = 0x17;
+ update_pending();
+ }
+
+ return ret;
+}
+
+int
+picinterrupt(void)
+{
+ int i, ret = -1;
+
+ if (pic.int_pending) {
+ if (pic_slave_on(&pic, pic.interrupt)) {
+ if (!pic.slaves[pic.interrupt]->int_pending) {
+ /* If we are on AT, IRQ 2 is pending, and we cannot find a pending IRQ on PIC 2, fatal out. */
+ fatal("IRQ %i pending on AT without a pending IRQ on PIC %i (normal)\n", pic.interrupt, pic.interrupt);
+ exit(-1);
+ return -1;
+ }
+
+ pic.interrupt |= 0x40; /* Mark slave pending. */
+ }
+
+ if ((pic.interrupt == 0) && (pit_devs[1].data != NULL))
+ pit_devs[1].set_gate(pit_devs[1].data, 0, 0);
+
+ /* Two ACK's - do them in a loop to avoid potential compiler misoptimizations. */
+ for (i = 0; i < 2; i++) {
+ ret = pic_irq_ack_read(&pic, pic.ack_bytes);
+ pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3);
+
+ if (pic.ack_bytes == 0) {
+ if (pic.interrupt & 0x40)
+ pic2.interrupt = 0x17;
+ pic.interrupt = 0x17;
+ update_pending();
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/src/usb.c b/src/usb.c
index f0c7113b7..e45f82ae8 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -51,30 +51,58 @@ usb_log(const char *fmt, ...)
/* OHCI registers */
enum
{
- OHCI_HcRevision = 0x00,
- OHCI_HcControl = 0x04,
- OHCI_HcCommandStatus = 0x08,
- OHCI_HcInterruptStatus = 0x0C,
- OHCI_HcInterruptEnable = 0x10,
- OHCI_HcInterruptDisable = 0x14,
- OHCI_HcHCCA = 0x18,
- OHCI_HcPeriodCurrentED = 0x1C,
- OHCI_HcControlHeadED = 0x20,
- OHCI_HcControlCurrentED = 0x24,
- OHCI_HcBulkHeadED = 0x28,
- OHCI_HcBulkCurrentED = 0x2C,
- OHCI_HcDoneHead = 0x30,
- OHCI_HcFmInterval = 0x34,
- OHCI_HcFmRemaining = 0x38,
- OHCI_HcFmNumber = 0x3C,
- OHCI_HcPeriodicStart = 0x40,
- OHCI_HcLSThreshold = 0x44,
- OHCI_HcRhDescriptorA = 0x48,
- OHCI_HcRhDescriptorB = 0x4C,
- OHCI_HcRhStatus = 0x50,
- OHCI_HcRhPortStatus1 = 0x54,
- OHCI_HcRhPortStatus2 = 0x58,
- OHCI_HcRhPortStatus3 = 0x5C
+ OHCI_HcRevision = 0x00 /* 0x00 */,
+ OHCI_HcControl = 0x01 /* 0x04 */,
+ OHCI_HcCommandStatus = 0x02 /* 0x08 */,
+ OHCI_HcInterruptStatus = 0x03 /* 0x0c */,
+ OHCI_HcInterruptEnable = 0x04 /* 0x10 */,
+ OHCI_HcInterruptDisable = 0x05 /* 0x14 */,
+ OHCI_HcHCCA = 0x06 /* 0x18 */,
+ OHCI_HcPeriodCurrentED = 0x07 /* 0x1c */,
+ OHCI_HcControlHeadED = 0x08 /* 0x20 */,
+ OHCI_HcControlCurrentED = 0x09 /* 0x24 */,
+ OHCI_HcBulkHeadED = 0x0a /* 0x28 */,
+ OHCI_HcBulkCurrentED = 0x0b /* 0x2c */,
+ OHCI_HcDoneHead = 0x0c /* 0x30 */,
+ OHCI_HcFmInterval = 0x0d /* 0x34 */,
+ OHCI_HcFmRemaining = 0x0e /* 0x38 */,
+ OHCI_HcFmNumber = 0x0f /* 0x3c */,
+ OHCI_HcPeriodicStart = 0x10 /* 0x40 */,
+ OHCI_HcLSThreshold = 0x11 /* 0x44 */,
+ OHCI_HcRhDescriptorA = 0x12 /* 0x48 */,
+ OHCI_HcRhDescriptorB = 0x13 /* 0x4c */,
+ OHCI_HcRhStatus = 0x14 /* 0x50 */,
+ OHCI_HcRhPortStatus1 = 0x15 /* 0x54 */,
+ OHCI_HcRhPortStatus2 = 0x16 /* 0x58 */,
+ OHCI_HcRhPortStatus3 = 0x17 /* 0x5c */
+};
+
+enum
+{
+ OHCI_aHcRevision = 0x00,
+ OHCI_aHcControl = 0x04,
+ OHCI_aHcCommandStatus = 0x08,
+ OHCI_aHcInterruptStatus = 0x0c,
+ OHCI_aHcInterruptEnable = 0x10,
+ OHCI_aHcInterruptDisable = 0x14,
+ OHCI_aHcHCCA = 0x18,
+ OHCI_aHcPeriodCurrentED = 0x1c,
+ OHCI_aHcControlHeadED = 0x20,
+ OHCI_aHcControlCurrentED = 0x24,
+ OHCI_aHcBulkHeadED = 0x28,
+ OHCI_aHcBulkCurrentED = 0x2c,
+ OHCI_aHcDoneHead = 0x30,
+ OHCI_aHcFmInterval = 0x34,
+ OHCI_aHcFmRemaining = 0x38,
+ OHCI_aHcFmNumber = 0x3c,
+ OHCI_aHcPeriodicStart = 0x40,
+ OHCI_aHcLSThreshold = 0x44,
+ OHCI_aHcRhDescriptorA = 0x48,
+ OHCI_aHcRhDescriptorB = 0x4c,
+ OHCI_aHcRhStatus = 0x50,
+ OHCI_aHcRhPortStatus1 = 0x54,
+ OHCI_aHcRhPortStatus2 = 0x58,
+ OHCI_aHcRhPortStatus3 = 0x5c
};
/* OHCI HcInterruptEnable/Disable bits */
@@ -90,18 +118,17 @@ enum
};
static void
-usb_interrupt_ohci(usb_t* usb)
+usb_interrupt_ohci(usb_t *dev, uint32_t level)
{
- if (usb->ohci_mmio[OHCI_HcControl + 1] & 1) {
- if (usb->usb_params && usb->usb_params->smi_handle && !usb->usb_params->smi_handle(usb, usb->usb_params->parent_priv))
+ if (dev->ohci_mmio[OHCI_HcControl].b[1] & 1) {
+ if (dev->usb_params && dev->usb_params->smi_handle && !dev->usb_params->smi_handle(dev, dev->usb_params->parent_priv))
return;
- smi_raise();
- }
- else if (usb->usb_params != NULL) {
- if (usb->usb_params->parent_priv != NULL && usb->usb_params->raise_interrupt != NULL) {
- usb->usb_params->raise_interrupt(usb, usb->usb_params->parent_priv);
- }
+ if (level)
+ smi_raise();
+ } else if (dev->usb_params != NULL) {
+ if ((dev->usb_params->parent_priv != NULL) && (dev->usb_params->update_interrupt != NULL))
+ dev->usb_params->update_interrupt(dev, dev->usb_params->parent_priv);
}
}
@@ -194,26 +221,28 @@ ohci_mmio_read(uint32_t addr, void *p)
{
usb_t *dev = (usb_t *) p;
uint8_t ret = 0x00;
+#ifdef ENABLE_USB_LOG
+ uint32_t old_addr = addr;
+#endif
addr &= 0x00000fff;
- ret = dev->ohci_mmio[addr];
+ ret = dev->ohci_mmio[addr >> 2].b[addr & 3];
switch (addr) {
case 0x101:
ret = (ret & 0xfe) | (!!mem_a20_key);
break;
- case OHCI_HcRhPortStatus1 + 1:
- case OHCI_HcRhPortStatus2 + 1:
- case OHCI_HcRhPortStatus3 + 1:
+ case OHCI_aHcRhPortStatus1 + 1:
+ case OHCI_aHcRhPortStatus2 + 1:
+ case OHCI_aHcRhPortStatus3 + 1:
ret |= 0x1;
break;
- case OHCI_HcInterruptDisable:
- case OHCI_HcInterruptDisable + 1:
- case OHCI_HcInterruptDisable + 2:
- case OHCI_HcInterruptDisable + 3:
- ret = dev->ohci_mmio[OHCI_HcInterruptEnable + (addr - OHCI_HcInterruptDisable)];
- break;
+ case OHCI_aHcInterruptDisable:
+ case OHCI_aHcInterruptDisable + 1:
+ case OHCI_aHcInterruptDisable + 2:
+ case OHCI_aHcInterruptDisable + 3:
+ ret = dev->ohci_mmio[OHCI_HcInterruptEnable].b[addr & 3];
default:
break;
}
@@ -221,30 +250,58 @@ ohci_mmio_read(uint32_t addr, void *p)
if (addr == 0x101)
ret = (ret & 0xfe) | (!!mem_a20_key);
+#ifdef ENABLE_USB_LOG
+ usb_log("[R] %08X = %04X\n", old_addr, ret);
+#endif
+
return ret;
}
-void
-ohci_set_interrupt(usb_t* usb, uint8_t bit)
+static uint16_t
+ohci_mmio_readw(uint32_t addr, void *p)
{
- if (!(usb->ohci_mmio[OHCI_HcInterruptEnable + 3] & 0x80))
+ return ohci_mmio_read(addr, p) | (ohci_mmio_read(addr + 1, p) << 8);
+}
+
+static uint32_t
+ohci_mmio_readl(uint32_t addr, void *p)
+{
+ return ohci_mmio_readw(addr, p) | (ohci_mmio_readw(addr + 2, p) << 16);
+}
+
+static void
+ohci_update_irq(usb_t *dev)
+{
+ uint32_t level = !!(dev->ohci_mmio[OHCI_HcInterruptStatus].l & dev->ohci_mmio[OHCI_HcInterruptEnable].l);
+
+ if (level != dev->irq_level) {
+ dev->irq_level = level;
+ usb_interrupt_ohci(dev, level);
+ }
+}
+
+void
+ohci_set_interrupt(usb_t *dev, uint8_t bit)
+{
+ if (!(dev->ohci_mmio[OHCI_HcInterruptEnable].b[3] & 0x80))
return;
- if (!(usb->ohci_mmio[OHCI_HcInterruptEnable] & bit))
+ if (!(dev->ohci_mmio[OHCI_HcInterruptEnable].b[0] & bit))
return;
- if (usb->ohci_mmio[OHCI_HcInterruptDisable] & bit)
+ if (dev->ohci_mmio[OHCI_HcInterruptDisable].b[0] & bit)
return;
- usb->ohci_mmio[OHCI_HcInterruptStatus] |= bit;
- usb_interrupt_ohci(usb);
+ dev->ohci_mmio[OHCI_HcInterruptStatus].b[0] |= bit;
+
+ ohci_update_irq(dev);
}
void
ohci_end_of_frame(usb_t* dev)
{
/* TODO: Put endpoint and transfer descriptor processing here. */
- dev->ohci_mmio_w[OHCI_HcFmNumber / 2]++;
+ dev->ohci_mmio[OHCI_HcFmNumber].w[0]++;
}
void
@@ -258,17 +315,17 @@ ohci_update_frame_counter(void* priv)
{
usb_t *dev = (usb_t *) priv;
- dev->ohci_mmio_w[OHCI_HcFmRemaining / 2] &= 0x3fff;
- if (dev->ohci_mmio_w[OHCI_HcFmRemaining / 2] == 0) {
+ dev->ohci_mmio[OHCI_HcFmRemaining].w[0] &= 0x3fff;
+ if (dev->ohci_mmio[OHCI_HcFmRemaining].w[0] == 0) {
ohci_end_of_frame(dev);
- dev->ohci_mmio_w[OHCI_HcFmRemaining / 2] = dev->ohci_mmio_w[OHCI_HcFmInterval / 2] & 0x3fff;
- dev->ohci_mmio_l[OHCI_HcFmRemaining / 4] &= ~(1 << 31);
- dev->ohci_mmio_l[OHCI_HcFmRemaining / 4] |= dev->ohci_mmio_l[OHCI_HcFmInterval / 4] & (1 << 31);
+ dev->ohci_mmio[OHCI_HcFmRemaining].w[0] = dev->ohci_mmio[OHCI_HcFmInterval].w[0] & 0x3fff;
+ dev->ohci_mmio[OHCI_HcFmRemaining].l &= ~(1 << 31);
+ dev->ohci_mmio[OHCI_HcFmRemaining].l |= dev->ohci_mmio[OHCI_HcFmInterval].l & (1 << 31);
ohci_start_of_frame(dev);
timer_on_auto(&dev->ohci_frame_timer, 1. / (12. * 1000. * 1000.));
return;
}
- if (dev->ohci_mmio_w[OHCI_HcFmRemaining / 2]) dev->ohci_mmio_w[OHCI_HcFmRemaining / 2]--;
+ if (dev->ohci_mmio[OHCI_HcFmRemaining].w[0]) dev->ohci_mmio[OHCI_HcFmRemaining].w[0]--;
timer_on_auto(&dev->ohci_frame_timer, 1. / (12. * 1000. * 1000.));
}
@@ -288,8 +345,8 @@ ohci_port_reset_callback(void* priv)
{
usb_t *dev = (usb_t *) priv;
- dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x10;
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] |= 0x10;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] &= ~0x10;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] |= 0x10;
}
void
@@ -297,244 +354,260 @@ ohci_port_reset_callback_2(void* priv)
{
usb_t *dev = (usb_t *) priv;
- dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x10;
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] |= 0x10;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] &= ~0x10;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] |= 0x10;
}
+
static void
ohci_mmio_write(uint32_t addr, uint8_t val, void *p)
{
usb_t *dev = (usb_t *) p;
uint8_t old;
+#ifdef ENABLE_USB_LOG
+ usb_log("[W] %08X = %04X\n", addr, val);
+#endif
+
addr &= 0x00000fff;
switch (addr) {
- case OHCI_HcControl:
+ case OHCI_aHcControl:
if ((val & 0xc0) == 0x00) {
/* UsbReset */
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] = dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] = 0x16;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] = dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] = 0x16;
}
break;
- case OHCI_HcCommandStatus:
+ case OHCI_aHcCommandStatus:
/* bit OwnershipChangeRequest triggers an ownership change (SMM <-> OS) */
if (val & 0x08) {
- dev->ohci_mmio[OHCI_HcInterruptStatus + 3] = 0x40;
- if ((dev->ohci_mmio[OHCI_HcInterruptEnable + 3] & 0xc0) == 0xc0)
+ dev->ohci_mmio[OHCI_HcInterruptStatus].b[3] = 0x40;
+ if ((dev->ohci_mmio[OHCI_HcInterruptEnable].b[3] & 0xc0) == 0xc0)
smi_raise();
}
/* bit HostControllerReset must be cleared for the controller to be seen as initialized */
if (val & 0x01) {
memset(dev->ohci_mmio, 0x00, 4096);
- dev->ohci_mmio[OHCI_HcRevision] = 0x10;
- dev->ohci_mmio[OHCI_HcRevision + 1] = 0x01;
- dev->ohci_mmio[OHCI_HcRhDescriptorA] = 0x02;
+ dev->ohci_mmio[OHCI_HcRevision].b[0] = 0x10;
+ dev->ohci_mmio[OHCI_HcRevision].b[1] = 0x01;
+ dev->ohci_mmio[OHCI_HcRhDescriptorA].b[0] = 0x02;
val &= ~0x01;
}
break;
- case OHCI_HcHCCA:
+ case OHCI_aHcHCCA:
return;
- case OHCI_HcInterruptEnable:
- dev->ohci_mmio[addr] = (val & 0x7f);
- dev->ohci_mmio[OHCI_HcInterruptDisable] &= ~(val & 0x7f);
+ case OHCI_aHcInterruptEnable:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x7f);
+ dev->ohci_mmio[OHCI_HcInterruptDisable].b[0] &= ~(val & 0x7f);
+ ohci_update_irq(dev);
return;
- case OHCI_HcInterruptEnable + 1:
- case OHCI_HcInterruptEnable + 2:
+ case OHCI_aHcInterruptEnable + 1:
+ case OHCI_aHcInterruptEnable + 2:
return;
- case OHCI_HcInterruptEnable + 3:
- dev->ohci_mmio[addr] = (val & 0x40);
- dev->ohci_mmio[addr] |= (val & 0x80);
- if (val & 0x80)
- dev->ohci_mmio[OHCI_HcInterruptDisable + 3] &= ~0x80;
- if (val & 0x40)
- dev->ohci_mmio[OHCI_HcInterruptDisable + 3] &= ~0x40;
+ case OHCI_aHcInterruptEnable + 3:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0xc0);
+ dev->ohci_mmio[OHCI_HcInterruptDisable].b[3] &= ~(val & 0xc0);
+ ohci_update_irq(dev);
return;
- case OHCI_HcInterruptDisable:
- dev->ohci_mmio[addr] = (val & 0x7f);
- dev->ohci_mmio[OHCI_HcInterruptEnable] &= ~(val & 0x7f);
+ case OHCI_aHcInterruptDisable:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x7f);
+ dev->ohci_mmio[OHCI_HcInterruptEnable].b[0] &= ~(val & 0x7f);
+ ohci_update_irq(dev);
return;
- case OHCI_HcInterruptDisable + 1:
- case OHCI_HcInterruptDisable + 2:
+ case OHCI_aHcInterruptDisable + 1:
+ case OHCI_aHcInterruptDisable + 2:
return;
- case OHCI_HcInterruptDisable + 3:
- dev->ohci_mmio[addr] = (val & 0x40);
- dev->ohci_mmio[addr] |= (val & 0x80);
- if (val & 0x80)
- dev->ohci_mmio[OHCI_HcInterruptEnable + 3] &= ~0x80;
- if (val & 0x40)
- dev->ohci_mmio[OHCI_HcInterruptEnable + 3] &= ~0x40;
+ case OHCI_aHcInterruptDisable + 3:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0xc0);
+ dev->ohci_mmio[OHCI_HcInterruptEnable].b[3] &= ~(val & 0xc0);
+ ohci_update_irq(dev);
return;
- case OHCI_HcInterruptStatus:
- dev->ohci_mmio[addr] &= ~(val & 0x7f);
+ case OHCI_aHcInterruptStatus:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~(val & 0x7f);
return;
- case OHCI_HcInterruptStatus + 1:
- case OHCI_HcInterruptStatus + 2:
+ case OHCI_aHcInterruptStatus + 1:
+ case OHCI_aHcInterruptStatus + 2:
return;
- case OHCI_HcInterruptStatus + 3:
- dev->ohci_mmio[addr] &= ~(val & 0x40);
+ case OHCI_aHcInterruptStatus + 3:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~(val & 0x40);
return;
- case OHCI_HcFmRemaining + 3:
- dev->ohci_mmio[addr] = (val & 0x80);
+ case OHCI_aHcFmRemaining + 3:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x80);
return;
- case OHCI_HcFmRemaining + 1:
- case OHCI_HcPeriodicStart + 1:
- dev->ohci_mmio[addr] = (val & 0x3f);
+ case OHCI_aHcFmRemaining + 1:
+ case OHCI_aHcPeriodicStart + 1:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x3f);
return;
- case OHCI_HcLSThreshold + 1:
- dev->ohci_mmio[addr] = (val & 0x0f);
+ case OHCI_aHcLSThreshold + 1:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x0f);
return;
- case OHCI_HcFmRemaining + 2:
- case OHCI_HcFmNumber + 2:
- case OHCI_HcFmNumber + 3:
- case OHCI_HcPeriodicStart + 2:
- case OHCI_HcPeriodicStart + 3:
- case OHCI_HcLSThreshold + 2:
- case OHCI_HcLSThreshold + 3:
- case OHCI_HcRhDescriptorA:
- case OHCI_HcRhDescriptorA + 2:
+ case OHCI_aHcFmRemaining + 2:
+ case OHCI_aHcFmNumber + 2:
+ case OHCI_aHcFmNumber + 3:
+ case OHCI_aHcPeriodicStart + 2:
+ case OHCI_aHcPeriodicStart + 3:
+ case OHCI_aHcLSThreshold + 2:
+ case OHCI_aHcLSThreshold + 3:
+ case OHCI_aHcRhDescriptorA:
+ case OHCI_aHcRhDescriptorA + 2:
return;
- case OHCI_HcRhDescriptorA + 1:
- dev->ohci_mmio[addr] = (val & 0x1b);
+ case OHCI_aHcRhDescriptorA + 1:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x1b);
if (val & 0x02) {
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] |= 0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] |= 0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] |= 0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] |= 0x01;
}
return;
- case OHCI_HcRhDescriptorA + 3:
- dev->ohci_mmio[addr] = (val & 0x03);
+ case OHCI_aHcRhDescriptorA + 3:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x03);
return;
- case OHCI_HcRhDescriptorB:
- case OHCI_HcRhDescriptorB + 2:
- dev->ohci_mmio[addr] = (val & 0x06);
+ case OHCI_aHcRhDescriptorB:
+ case OHCI_aHcRhDescriptorB + 2:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x06);
if ((addr == OHCI_HcRhDescriptorB) && !(val & 0x04)) {
- if (!(dev->ohci_mmio[OHCI_HcRhPortStatus2] & 0x01))
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] |= 0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus2] |= 0x01;
+ if (!(dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] & 0x01))
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] |= 0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] |= 0x01;
}
if ((addr == OHCI_HcRhDescriptorB) && !(val & 0x02)) {
- if (!(dev->ohci_mmio[OHCI_HcRhPortStatus1] & 0x01))
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] |= 0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus1] |= 0x01;
+ if (!(dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] & 0x01))
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] |= 0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] |= 0x01;
}
return;
- case OHCI_HcRhDescriptorB + 1:
- case OHCI_HcRhDescriptorB + 3:
+ case OHCI_aHcRhDescriptorB + 1:
+ case OHCI_aHcRhDescriptorB + 3:
return;
- case OHCI_HcRhStatus:
+ case OHCI_aHcRhStatus:
if (val & 0x01) {
- if ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) {
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] &= ~0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x17;
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] &= ~0x17;
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] &= ~0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x17;
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] &= ~0x17;
- } else if ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x01) {
- if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x02)) {
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] &= ~0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x17;
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] &= ~0x17;
+ if ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) {
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] &= ~0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] &= ~0x17;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] &= ~0x17;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] &= ~0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] &= ~0x17;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] &= ~0x17;
+ } else if ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x01) {
+ if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x02)) {
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] &= ~0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] &= ~0x17;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] &= ~0x17;
}
- if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x04)) {
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] &= ~0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x17;
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] &= ~0x17;
+ if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x04)) {
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] &= ~0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] &= ~0x17;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] &= ~0x17;
}
}
}
return;
- case OHCI_HcRhStatus + 1:
+ case OHCI_aHcRhStatus + 1:
if (val & 0x80)
- dev->ohci_mmio[addr] |= 0x80;
+ dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x80;
return;
- case OHCI_HcRhStatus + 2:
- dev->ohci_mmio[addr] &= ~(val & 0x02);
+ case OHCI_aHcRhStatus + 2:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~(val & 0x02);
if (val & 0x01) {
- if ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) {
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] |= 0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] |= 0x01;
- } else if ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x01) {
- if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x02))
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] |= 0x01;
- if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x04))
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] |= 0x01;
+ if ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) {
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] |= 0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] |= 0x01;
+ } else if ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x01) {
+ if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x02))
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] |= 0x01;
+ if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x04))
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] |= 0x01;
}
}
return;
- case OHCI_HcRhStatus + 3:
+ case OHCI_aHcRhStatus + 3:
if (val & 0x80)
- dev->ohci_mmio[OHCI_HcRhStatus + 1] &= ~0x80;
+ dev->ohci_mmio[OHCI_HcRhStatus].b[1] &= ~0x80;
return;
- case OHCI_HcRhPortStatus1:
- case OHCI_HcRhPortStatus2:
- old = dev->ohci_mmio[addr];
+ case OHCI_aHcRhPortStatus1:
+ case OHCI_aHcRhPortStatus2:
+ old = dev->ohci_mmio[addr >> 2].b[addr & 3];
if (val & 0x10) {
if (old & 0x01) {
- dev->ohci_mmio[addr] |= 0x10;
- timer_on_auto(&dev->ohci_port_reset_timer[(addr - OHCI_HcRhPortStatus1) / 4], 10000.);
+ dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x10;
+ timer_on_auto(&dev->ohci_port_reset_timer[(addr - OHCI_aHcRhPortStatus1) / 4], 10000.);
} else
- dev->ohci_mmio[addr + 2] |= 0x01;
+ dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x01;
}
if (val & 0x08)
- dev->ohci_mmio[addr] &= ~0x04;
+ dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x04;
if (val & 0x04)
- dev->ohci_mmio[addr] |= 0x04;
+ dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x04;
if (val & 0x02) {
if (old & 0x01)
- dev->ohci_mmio[addr] |= 0x02;
+ dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x02;
else
- dev->ohci_mmio[addr + 2] |= 0x01;
+ dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x01;
}
if (val & 0x01) {
if (old & 0x01)
- dev->ohci_mmio[addr] &= ~0x02;
+ dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x02;
else
- dev->ohci_mmio[addr + 2] |= 0x01;
+ dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x01;
}
- if (!(dev->ohci_mmio[addr] & 0x04) && (old & 0x04))
- dev->ohci_mmio[addr + 2] |= 0x04;
- /* if (!(dev->ohci_mmio[addr] & 0x02))
- dev->ohci_mmio[addr + 2] |= 0x02; */
+ if (!(dev->ohci_mmio[addr >> 2].b[addr & 3] & 0x04) && (old & 0x04))
+ dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x04;
+ /* if (!(dev->ohci_mmio[addr >> 2].b[addr & 3] & 0x02))
+ dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x02; */
return;
- case OHCI_HcRhPortStatus1 + 1:
- if ((val & 0x02) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x02)) {
- dev->ohci_mmio[addr] &= ~0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x17;
- dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] &= ~0x17;
+ case OHCI_aHcRhPortStatus1 + 1:
+ if ((val & 0x02) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x02)) {
+ dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] &= ~0x17;
+ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] &= ~0x17;
}
- if ((val & 0x01) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x02)) {
- dev->ohci_mmio[addr] |= 0x01;
- dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x17;
- dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] &= ~0x17;
+ if ((val & 0x01) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x02)) {
+ dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x01;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] &= ~0x17;
+ dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] &= ~0x17;
}
return;
- case OHCI_HcRhPortStatus2 + 1:
- if ((val & 0x02) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x04))
- dev->ohci_mmio[addr] &= ~0x01;
- if ((val & 0x01) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x04))
- dev->ohci_mmio[addr] |= 0x01;
+ case OHCI_aHcRhPortStatus2 + 1:
+ if ((val & 0x02) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x04))
+ dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x01;
+ if ((val & 0x01) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x04))
+ dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x01;
return;
- case OHCI_HcRhPortStatus1 + 2:
- case OHCI_HcRhPortStatus2 + 2:
- dev->ohci_mmio[addr] &= ~(val & 0x1f);
+ case OHCI_aHcRhPortStatus1 + 2:
+ case OHCI_aHcRhPortStatus2 + 2:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~(val & 0x1f);
return;
- case OHCI_HcRhPortStatus1 + 3:
- case OHCI_HcRhPortStatus2 + 3:
+ case OHCI_aHcRhPortStatus1 + 3:
+ case OHCI_aHcRhPortStatus2 + 3:
return;
- case OHCI_HcDoneHead:
- case OHCI_HcBulkCurrentED:
- case OHCI_HcBulkHeadED:
- case OHCI_HcControlCurrentED:
- case OHCI_HcControlHeadED:
- case OHCI_HcPeriodCurrentED:
- dev->ohci_mmio[addr] = (val & 0xf0);
+ case OHCI_aHcDoneHead:
+ case OHCI_aHcBulkCurrentED:
+ case OHCI_aHcBulkHeadED:
+ case OHCI_aHcControlCurrentED:
+ case OHCI_aHcControlHeadED:
+ case OHCI_aHcPeriodCurrentED:
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0xf0);
return;
}
- dev->ohci_mmio[addr] = val;
+ dev->ohci_mmio[addr >> 2].b[addr & 3] = val;
}
+
+static void
+ohci_mmio_writew(uint32_t addr, uint16_t val, void *p)
+{
+ ohci_mmio_write(addr, val & 0xff, p);
+ ohci_mmio_write(addr + 1, val >> 8, p);
+}
+
+static void
+ohci_mmio_writel(uint32_t addr, uint32_t val, void *p)
+{
+ ohci_mmio_writew(addr, val & 0xffff, p);
+ ohci_mmio_writew(addr + 2, val >> 16, p);
+}
+
void
ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, int enable)
{
@@ -544,8 +617,13 @@ ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3,
dev->ohci_mem_base = ((base1 << 8) | (base2 << 16) | (base3 << 24)) & 0xfffff000;
dev->ohci_enable = enable;
- if (dev->ohci_enable && (dev->ohci_mem_base != 0x00000000))
+ if (dev->ohci_enable && (dev->ohci_mem_base != 0x00000000)) {
+ dev->ohci_mmio_mapping.flags = MEM_MAPPING_EXTERNAL;
mem_mapping_set_addr(&dev->ohci_mmio_mapping, dev->ohci_mem_base, 0x1000);
+ mem_mapping_enable(&dev->ohci_mmio_mapping);
+ }
+
+ usb_log("ohci_update_mem_mapping(): OHCI %sabled at %08X\n", dev->ohci_enable ? "en" : "dis", dev->ohci_mem_base);
}
uint8_t
@@ -565,21 +643,24 @@ usb_reset(void *priv)
{
usb_t *dev = (usb_t *) priv;
- memset(dev->uhci_io, 0x00, 128);
+ memset(dev->uhci_io, 0x00, sizeof(dev->uhci_io));
dev->uhci_io[0x0c] = 0x40;
dev->uhci_io[0x10] = dev->uhci_io[0x12] = 0x80;
- memset(dev->ohci_mmio, 0x00, 4096);
- dev->ohci_mmio[OHCI_HcRevision] = 0x10;
- dev->ohci_mmio[OHCI_HcRevision + 1] = 0x01;
- dev->ohci_mmio[OHCI_HcRhDescriptorA] = 0x02;
- dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] = 0x02;
+ memset(dev->ohci_mmio, 0x00, sizeof(dev->ohci_mmio));
+ dev->ohci_mmio[OHCI_HcRevision].b[0] = 0x10;
+ dev->ohci_mmio[OHCI_HcRevision].b[1] = 0x01;
+ dev->ohci_mmio[OHCI_HcRhDescriptorA].b[0] = 0x02;
+ dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] = 0x02;
io_removehandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev);
dev->uhci_enable = 0;
mem_mapping_disable(&dev->ohci_mmio_mapping);
dev->ohci_enable = 0;
+
+ usb_log("usb_reset(): OHCI %sabled at %08X\n", dev->ohci_enable ? "en" : "dis", dev->ohci_mem_base);
+ usb_log("usb_reset(): map = %08X\n", &dev->ohci_mmio_mapping);
}
static void
@@ -591,7 +672,7 @@ usb_close(void *priv)
}
static void *
-usb_init_ext(const device_t *info, void* params)
+usb_init_ext(const device_t *info, void *params)
{
usb_t *dev;
@@ -600,16 +681,20 @@ usb_init_ext(const device_t *info, void* params)
return (NULL);
memset(dev, 0x00, sizeof(usb_t));
- dev->usb_params = (usb_params_t*)params;
+ dev->usb_params = (usb_params_t *) params;
- mem_mapping_add(&dev->ohci_mmio_mapping, 0, 0,
- ohci_mmio_read, NULL, NULL,
- ohci_mmio_write, NULL, NULL,
+ mem_mapping_add(&dev->ohci_mmio_mapping, 0, 0x1000,
+ ohci_mmio_read, ohci_mmio_readw, ohci_mmio_readl,
+ ohci_mmio_write, ohci_mmio_writew, ohci_mmio_writel,
NULL, MEM_MAPPING_EXTERNAL, dev);
+
+ mem_mapping_disable(&dev->ohci_mmio_mapping);
+
timer_add(&dev->ohci_frame_timer, ohci_update_frame_counter, dev, 0); /* Unused for now, to be used for frame counting. */
timer_add(&dev->ohci_port_reset_timer[0], ohci_port_reset_callback, dev, 0);
timer_add(&dev->ohci_port_reset_timer[1], ohci_port_reset_callback_2, dev, 0);
timer_add(&dev->ohci_interrupt_desc_poll_timer, ohci_poll_interrupt_descriptors, dev, 0);
+
usb_reset(dev);
return dev;