Merge pull request #5237 from akmed772/master

Add IBM PS/55 machines and its peripherals
This commit is contained in:
Miran Grča
2025-02-19 11:15:45 +01:00
committed by GitHub
28 changed files with 4751 additions and 53 deletions

View File

@@ -189,6 +189,7 @@ int voodoo_enabled = 0; /* (C) video o
int lba_enhancer_enabled = 0; /* (C) enable Vision Systems LBA Enhancer */
int ibm8514_standalone_enabled = 0; /* (C) video option */
int xga_standalone_enabled = 0; /* (C) video option */
int da2_standalone_enabled = 0; /* (C) video option */
uint32_t mem_size = 0; /* (C) memory size (Installed on
system board)*/
uint32_t isa_mem_size = 0; /* (C) memory size (ISA Memory Cards) */
@@ -1093,13 +1094,24 @@ pc_init_modules(void)
void
pc_send_ca(uint16_t sc)
{
keyboard_input(1, 0x1D); /* Ctrl key pressed */
keyboard_input(1, 0x38); /* Alt key pressed */
keyboard_input(1, sc);
usleep(50000);
keyboard_input(0, sc);
keyboard_input(0, 0x38); /* Alt key released */
keyboard_input(0, 0x1D); /* Ctrl key released */
if (keyboard_mode == 0x8A) {
/* Use R-Alt because PS/55 DOS assigns L-Alt Kanji */
keyboard_input(1, 0x1D); /* Ctrl key pressed */
keyboard_input(1, 0x138); /* R-Alt key pressed */
keyboard_input(1, sc);
usleep(50000);
keyboard_input(0, sc);
keyboard_input(0, 0x138); /* R-Alt key released */
keyboard_input(0, 0x1D); /* Ctrl key released */
} else {
keyboard_input(1, 0x1D); /* Ctrl key pressed */
keyboard_input(1, 0x38); /* Alt key pressed */
keyboard_input(1, sc);
usleep(50000);
keyboard_input(0, sc);
keyboard_input(0, 0x38); /* Alt key released */
keyboard_input(0, 0x1D); /* Ctrl key released */
}
}
/* Send the machine a Control-Alt-DEL sequence. */

View File

@@ -454,6 +454,7 @@ load_video(void)
ibm8514_active = ibm8514_standalone_enabled;
xga_standalone_enabled = !!ini_section_get_int(cat, "xga", 0);
xga_active = xga_standalone_enabled;
da2_standalone_enabled = !!ini_section_get_int(cat, "da2", 0);
show_second_monitors = !!ini_section_get_int(cat, "show_second_monitors", 1);
video_fullscreen_scale_maximized = !!ini_section_get_int(cat, "video_fullscreen_scale_maximized", 0);
@@ -2139,6 +2140,11 @@ save_video(void)
else
ini_section_set_int(cat, "xga", xga_standalone_enabled);
if (da2_standalone_enabled == 0)
ini_section_delete_var(cat, "da2");
else
ini_section_set_int(cat, "da2", da2_standalone_enabled);
// TODO
for (uint8_t i = 1; i < GFXCARD_MAX; i ++) {
if (gfxcard[i] == 0)

View File

@@ -18,10 +18,13 @@
* Copyright 2015-2019 Miran Grca.
* Copyright 2017-2019 Fred N. van Kempen.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/machine.h>
#include <86box/keyboard.h>
@@ -41,6 +44,24 @@ uint16_t key_prefix_2_2 = 0x000; /* Invalid */
uint16_t key_uncapture_1 = 0x058; /* F12 */
uint16_t key_uncapture_2 = 0x000; /* Invalid */
#ifdef ENABLE_KBC_AT_LOG
int kbc_at_do_log = ENABLE_KBC_AT_LOG;
static void
kbc_at_log(const char* fmt, ...)
{
va_list ap;
if (kbc_at_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define kbc_at_log(fmt, ...)
#endif
void (*keyboard_send)(uint16_t val);
static int recv_key[512] = { 0 }; /* keyboard input buffer */
@@ -56,6 +77,64 @@ static uint8_t num_lock = 0;
static uint8_t scroll_lock = 0;
static uint8_t shift = 0;
static int key5576mode = 0;
typedef struct {
const uint16_t sc;
const uint8_t mk[4];
const uint8_t brk[4];
} scconvtbl;
static scconvtbl scconv55_82[18 + 1] =
{
// clang-format off
{.sc = 0x02 , .mk = { 0x5f, 0 }, .brk = { 0xf0, 0x5f, 0 } }, /* '1' -> 'Clear/ /SysRq' */
{.sc = 0x03 , .mk = { 0x48, 0 }, .brk = { 0xf0, 0x48, 0 } }, /* '2' -> '終了 (Exit)' */
{.sc = 0x04 , .mk = { 0x38, 0 }, .brk = { 0xf0, 0x38, 0 } }, /* '3' -> 'メッセージ (Message)/ /応答 (Respond)' */
{.sc = 0x05 , .mk = { 0x30, 0 }, .brk = { 0xf0, 0x30, 0 } }, /* '4' -> 'サイズ変換 (Change Size)/ /横倍角 (2x Width)' */
{.sc = 0x06 , .mk = { 0x20, 0 }, .brk = { 0xf0, 0x20, 0 } }, /* '5' -> '単語登録 (Register Word)/ /再交換 (Re-change)' */
{.sc = 0x07 , .mk = { 0x28, 0 }, .brk = { 0xf0, 0x28, 0 } }, /* '6' -> '漢字 (Kanji)/ /番号 (Number)' */
{.sc = 0x08 , .mk = { 0x60, 0 }, .brk = { 0xf0, 0x60, 0 } }, /* '7' -> '取消 (Cancel)' */
{.sc = 0x09 , .mk = { 0x40, 0 }, .brk = { 0xf0, 0x40, 0 } }, /* '8' -> 'コピー (Copy)/ /移動 (Move)' */
{.sc = 0x3d , .mk = { 0x1f, 0 }, .brk = { 0xf0, 0x1f, 0 } }, /* 'F3' -> 'Cr Bnk/領域呼出 (Call Range)/All Cr/登録 (Register)' */
{.sc = 0x3e , .mk = { 0x27, 0 }, .brk = { 0xf0, 0x27, 0 } }, /* 'F4' -> '割込み (Interrupt)' */
{.sc = 0x3f , .mk = { 0x2f, 0 }, .brk = { 0xf0, 0x2f, 0 } }, /* 'F5' -> 'UF1' */
{.sc = 0x40 , .mk = { 0x5e, 0 }, .brk = { 0xf0, 0x5e, 0 } }, /* 'F6' -> 'UF2' */
{.sc = 0x41 , .mk = { 0x08, 0 }, .brk = { 0xf0, 0x08, 0 } }, /* 'F7' -> 'UF3' */
{.sc = 0x42 , .mk = { 0x10, 0 }, .brk = { 0xf0, 0x10, 0 } }, /* 'F8' -> 'UF4' */
{.sc = 0x43 , .mk = { 0x50, 0 }, .brk = { 0xf0, 0x50, 0 } }, /* 'F9' -> 'EOF/Erase/ErInp' */
{.sc = 0x44 , .mk = { 0x18, 0 }, .brk = { 0xf0, 0x18, 0 } }, /* 'F10' -> 'Attn/ /CrSel' */
{.sc = 0x57 , .mk = { 0x17, 0 }, .brk = { 0xf0, 0x17, 0 } }, /* 'F11' -> 'PA1/ /DvCncl' */
{.sc = 0x58 , .mk = { 0x37, 0 }, .brk = { 0xf0, 0x37, 0 } }, /* 'F12' -> 'PA2/ /PA3' */
{.sc = 0 , .mk = { 0 }, .brk = { 0 } } /* end */
// clang-format on
};
static scconvtbl scconv55_8a[18 + 1] =
{
// clang-format off
{.sc = 0x02 , .mk = { 0x48 }, .brk = { 0 } }, /* '1' -> 'Clear/ /SysRq' */
{.sc = 0x03 , .mk = { 0x49 }, .brk = { 0 } }, /* '2' -> '終了 (Exit)' */
{.sc = 0x04 , .mk = { 0x46 }, .brk = { 0 } }, /* '3' -> 'メッセージ (Message)/ /応答 (Respond)' */
{.sc = 0x05 , .mk = { 0x44 }, .brk = { 0 } }, /* '4' -> 'サイズ変換 (Change Size)/ /横倍角 (2x Width)' */
{.sc = 0x06 , .mk = { 0x42 }, .brk = { 0 } }, /* '5' -> '単語登録 (Register Word)/ /再交換 (Re-change)' */
{.sc = 0x07 , .mk = { 0x43 }, .brk = { 0 } }, /* '6' -> '漢字 (Kanji)/ /番号 (Number)' */
{.sc = 0x08 , .mk = { 0x40 }, .brk = { 0 } }, /* '7' -> '取消 (Cancel)' */
{.sc = 0x09 , .mk = { 0x51 }, .brk = { 0 } }, /* '8' -> 'コピー (Copy)/ /移動 (Move)' */
{.sc = 0x3d , .mk = { 0x76 }, .brk = { 0 } }, /* 'F3' -> 'Cr Bnk/領域呼出 (Call Range)/All Cr/登録 (Register)' */
{.sc = 0x3e , .mk = { 0x77 }, .brk = { 0 } }, /* 'F4' -> '割込み (Interrupt)' */
{.sc = 0x3f , .mk = { 0x78 }, .brk = { 0 } }, /* 'F5' -> 'UF1' */
{.sc = 0x40 , .mk = { 0x79 }, .brk = { 0 } }, /* 'F6' -> 'UF2' */
{.sc = 0x41 , .mk = { 0x7a }, .brk = { 0 } }, /* 'F7' -> 'UF3' */
{.sc = 0x42 , .mk = { 0x7b }, .brk = { 0 } }, /* 'F8' -> 'UF4' */
{.sc = 0x43 , .mk = { 0x7c }, .brk = { 0 } }, /* 'F9' -> 'EOF/Erase/ErInp' */
{.sc = 0x44 , .mk = { 0x7d }, .brk = { 0 } }, /* 'F10' -> 'Attn/ /CrSel' */
{.sc = 0x57 , .mk = { 0x7e }, .brk = { 0 } }, /* 'F11' -> 'PA1/ /DvCncl' */
{.sc = 0x58 , .mk = { 0x7f }, .brk = { 0 } }, /* 'F12' -> 'PA2/ /PA3' */
{.sc = 0 , .mk = { 0 }, .brk = { 0 } } /* end */
// clang-format on
};
void
keyboard_init(void)
{
@@ -111,6 +190,36 @@ key_process(uint16_t scan, int down)
oldkey[scan] = down;
kbc_at_log("Key %04X,%d in process\n", scan, down);
c = 0;
/* According to Japanese DOS K3.3 manual (N:SC18-2194-1),
IBM 5576-002, -003 keyboards have the one-time key conversion mode
that emulates 18 out of 131 keys on IBM 5576-001 keyboard.
It is triggered by pressing L-Shift (⇧) + L-Ctrl + R-Alt (前面キー)
when the scancode set is 82h or 8ah.
*/
if (key5576mode) {
int i = 0;
if (!down) {
/* Do and exit the 5576-001 emulation when a key is pressed other than trigger keys. */
if (scan != 0x1d && scan != 0x2a && scan != 0x138)
{
key5576mode = 0;
kbc_at_log("5576-001 key emulation disabled.\n");
}
}
while (scconv55_8a[i].sc != 0)
{
if (scconv55_8a[i].sc == scan) {
while (scconv55_8a[i].mk[c] != 0)
keyboard_send(scconv55_8a[i].mk[c++]);
return;
}
i++;
}
}
if (down && (codes[scan].mk[0] == 0))
return;
@@ -137,6 +246,13 @@ key_process(uint16_t scan, int down)
if (fake_shift_needed(scan))
keyboard_send(0x101);
}
/* Enter the 5576-001 emulation mode. */
if (keyboard_mode == 0x8a && down && ((keyboard_get_shift() & 0x43) == 0x43))
{
key5576mode = 1;
kbc_at_log("5576-001 key emulation enabled.\n");
}
}
/* Handle a keystroke event from the UI layer. */
@@ -232,7 +348,7 @@ keyboard_input(int down, uint16_t scan)
}
}
/* pclog("Received scan code: %03X (%s)\n", scan & 0x1ff, down ? "down" : "up"); */
/* kbc_at_log("Received scan code: %03X (%s)\n", scan & 0x1ff, down ? "down" : "up"); */
recv_key_ui[scan & 0x1ff] = down;
if (mouse_capture || !kbd_req_capture || video_fullscreen) {

View File

@@ -53,10 +53,10 @@ const uint8_t id_bytes[16][4] = { { 0x00, 0x00, 0x00, 0x00 }, /* AT 84-key */
{ 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00 }, /* FLAG_PS2 = 0x08 */
{ 0xab, 0x83, 0x00, 0x00 }, /* PS/2 101-key */
{ 0xab, 0x83, 0x00, 0x00 }, /* PS/2 102-key */
{ 0xab, 0x90, 0x00, 0x00 }, /* PS/2 106-key JIS */
{ 0xab, 0x90, 0x00, 0x00 }, /* PS/55 106-key JIS (IBM-J 5576-002) */
/* Japanese keyboard ID - TODO: Find the actual Korean one. */
{ 0xab, 0x90, 0x00, 0x00 }, /* PS/2 Korean */
{ 0x00, 0x00, 0x00, 0x00 },
@@ -1630,6 +1630,550 @@ static const scancode scancode_set3[512] = {
// clang-format on
};
/* IBM Japan 5576-001, 002 and 003 keyboards have three extra scancode sets; 81h, 82h, 8ah.
To implement them, we need take the following into consideration.
* Add a UI to switch the type of keyboards and keyboard IDs.
* Add modified scancode set 1 and 2 (in these modes, language input keys are used as an alternative key).
* Japanese keyboards traditionally use a bit-paired layout. Its key mapping doesn't match with foreign keyboards.
5576 keyboards kept 101-key compatible scancode sets because PS/55 had to support western (PS/2) versions of operating systems.
The default scancode set is 2.
In Japanese DOS, the keyboard driver confirms its keyboard ID, and sends a command to switch the scancode set to 8Ah.
Japanese OS/2 and Windows use the scancode set 82h.
The OADG standard (1991-) and modern Japanese keyboards use the same keyboard ID and scancode set number as PS/2 keyboards use.
Three extra scancode sets are no longer available. Instead, language input keys are available in scancode set 1 and 2.
However, their physical key layout is a bit-paired layout.
Users have to choose the correct keyboard layout on setup, and the driver needs to remap keys.
Currently, scancode set 81h and 82h are not implemented yet. Also, the key layout is designed to match with the Japanese keyboard.
[Japanese DOS and keyboard scancode set comparison]
| | K3.3 | J4.0 | J5.0 | J4.0/V | J5.0/V | OS/2 J1.3 | DOS 5(US)|
|---------------------------|:----:|:----:|:----:|:------:|:------:|:---------:|:--------:|
| IBM 101-key | n/a | n/a | n/a | n/a | 2 | n/a | 2 |
| IBM-J 5576-00x (obsolete) | 8Ah | 8Ah | 8Ah | 82h | 82h | 82h | 2 |
| OADG (modern Japanese) | n/a | n/a | n/a | 2 | 2 | 2 | 2 | */
/* Scancode set 8Ah : IBM 5556 keyboard compatible scancode set used by J-DOS */
static scancode scancode_set8a[512] =
{
// clang-format off
{.mk = { 0 }, .brk = { 0 } }, /* 000 */
{.mk = { 0x3d, 0 }, .brk = { 0 } }, /* 001 */
{.mk = { 0x24, 0 }, .brk = { 0 } }, /* 002 */
{.mk = { 0x25, 0 }, .brk = { 0 } }, /* 003 */
{.mk = { 0x26, 0 }, .brk = { 0 } }, /* 004 */
{.mk = { 0x27, 0 }, .brk = { 0 } }, /* 005 */
{.mk = { 0x28, 0 }, .brk = { 0 } }, /* 006 */
{.mk = { 0x29, 0 }, .brk = { 0 } }, /* 007 */
{.mk = { 0x2a, 0 }, .brk = { 0 } }, /* 008 */
{.mk = { 0x2b, 0 }, .brk = { 0 } }, /* 009 */
{.mk = { 0x2c, 0 }, .brk = { 0 } }, /* 00a */
{.mk = { 0x2d, 0 }, .brk = { 0 } }, /* 00b */
{.mk = { 0x2e, 0 }, .brk = { 0 } }, /* 00c */
{.mk = { 0x2f, 0 }, .brk = { 0 } }, /* 00d */
{.mk = { 0x3e, 0 }, .brk = { 0 } }, /* 00e */
{.mk = { 0x3c, 0 }, .brk = { 0 } }, /* 00f */
{.mk = { 0x18, 0 }, .brk = { 0 } }, /* 010 */
{.mk = { 0x19, 0 }, .brk = { 0 } }, /* 011 */
{.mk = { 0x1a, 0 }, .brk = { 0 } }, /* 012 */
{.mk = { 0x1b, 0 }, .brk = { 0 } }, /* 013 */
{.mk = { 0x1c, 0 }, .brk = { 0 } }, /* 014 */
{.mk = { 0x1d, 0 }, .brk = { 0 } }, /* 015 */
{.mk = { 0x1e, 0 }, .brk = { 0 } }, /* 016 */
{.mk = { 0x1f, 0 }, .brk = { 0 } }, /* 017 */
{.mk = { 0x20, 0 }, .brk = { 0 } }, /* 018 */
{.mk = { 0x21, 0 }, .brk = { 0 } }, /* 019 */
{.mk = { 0x22, 0 }, .brk = { 0 } }, /* 01a */
{.mk = { 0x23, 0 }, .brk = { 0 } }, /* 01b */
{.mk = { 0x3b, 0 }, .brk = { 0 } }, /* 01c */
{.mk = { 0x41, 0 }, .brk = { 0xc1, 0 } }, /* 01d LCTRL */
{.mk = { 0x0c, 0 }, .brk = { 0 } }, /* 01e */
{.mk = { 0x0d, 0 }, .brk = { 0 } }, /* 01f */
{.mk = { 0x0e, 0 }, .brk = { 0 } }, /* 020 */
{.mk = { 0x0f, 0 }, .brk = { 0 } }, /* 021 */
{.mk = { 0x10, 0 }, .brk = { 0 } }, /* 022 */
{.mk = { 0x11, 0 }, .brk = { 0 } }, /* 023 */
{.mk = { 0x12, 0 }, .brk = { 0 } }, /* 024 */
{.mk = { 0x13, 0 }, .brk = { 0 } }, /* 025 */
{.mk = { 0x14, 0 }, .brk = { 0 } }, /* 026 */
{.mk = { 0x15, 0 }, .brk = { 0 } }, /* 027 */
{.mk = { 0x16, 0 }, .brk = { 0 } }, /* 028* */
{.mk = { 0x45, 0 }, .brk = { 0 } }, /* 029 Hankaku, Zenkaku */
{.mk = { 0x38, 0 }, .brk = { 0xb8, 0 } }, /* 02a LSHIFT */
{.mk = { 0x17, 0 }, .brk = { 0 } }, /* 02b Mu */
{.mk = { 0x01, 0 }, .brk = { 0 } }, /* 02c */
{.mk = { 0x02, 0 }, .brk = { 0 } }, /* 02d */
{.mk = { 0x03, 0 }, .brk = { 0 } }, /* 02e */
{.mk = { 0x04, 0 }, .brk = { 0 } }, /* 02f */
{.mk = { 0x05, 0 }, .brk = { 0 } }, /* 030 */
{.mk = { 0x06, 0 }, .brk = { 0 } }, /* 031 */
{.mk = { 0x07, 0 }, .brk = { 0 } }, /* 032 */
{.mk = { 0x08, 0 }, .brk = { 0 } }, /* 033 */
{.mk = { 0x09, 0 }, .brk = { 0 } }, /* 034 */
{.mk = { 0x0a, 0 }, .brk = { 0 } }, /* 035 */
{.mk = { 0x39, 0 }, .brk = { 0xb9, 0 } }, /* 036 RSHIFT */
{.mk = { 0x64, 0 }, .brk = { 0 } }, /* 037 * (asterisk) */
{.mk = { 0x3A, 0 }, .brk = { 0xba, 0 } }, /* 038 LALT = Kanji */
{.mk = { 0x34, 0 }, .brk = { 0 } }, /* 039 */
{.mk = { 0x32, 0 }, .brk = { 0xb2, 0 } }, /* 03a CAPSLOCK */
{.mk = { 0x68, 0 }, .brk = { 0 } }, /* 03b F1 */
{.mk = { 0x69, 0 }, .brk = { 0 } }, /* 03c */
{.mk = { 0x6a, 0 }, .brk = { 0 } }, /* 03d */
{.mk = { 0x6b, 0 }, .brk = { 0 } }, /* 03e */
{.mk = { 0x6c, 0 }, .brk = { 0 } }, /* 03f */
{.mk = { 0x6d, 0 }, .brk = { 0 } }, /* 040 */
{.mk = { 0x6e, 0 }, .brk = { 0 } }, /* 041 */
{.mk = { 0x6f, 0 }, .brk = { 0 } }, /* 042 */
{.mk = { 0x70, 0 }, .brk = { 0 } }, /* 043 */
{.mk = { 0x71, 0 }, .brk = { 0 } }, /* 044 F10 */
{.mk = { 0 }, .brk = { 0 } }, /* 045 NUMLOCKCLEAR -> Shift + SCRLOCK :TODO */
{.mk = { 0x75, 0 }, .brk = { 0 } }, /* 046 SCROLLLOCK */
{.mk = { 0x5d, 0 }, .brk = { 0 } }, /* 047 KP7 */
{.mk = { 0x5e, 0 }, .brk = { 0 } }, /* 048 */
{.mk = { 0x5f, 0 }, .brk = { 0 } }, /* 049 */
{.mk = { 0x67, 0 }, .brk = { 0 } }, /* 04a KP_MINUS */
{.mk = { 0x5a, 0 }, .brk = { 0 } }, /* 04b */
{.mk = { 0x5b, 0 }, .brk = { 0 } }, /* 04c */
{.mk = { 0x5c, 0 }, .brk = { 0 } }, /* 04d */
{.mk = { 0x63, 0 }, .brk = { 0 } }, /* 04e */
{.mk = { 0x57, 0 }, .brk = { 0 } }, /* 04f */
{.mk = { 0x58, 0 }, .brk = { 0 } }, /* 050 */
{.mk = { 0x59, 0 }, .brk = { 0 } }, /* 051 */
{.mk = { 0x55, 0 }, .brk = { 0 } }, /* 052 KP0 */
{.mk = { 0x56, 0 }, .brk = { 0 } }, /* 053 KP_PERIOD */
{.mk = { 0 }, .brk = { 0 } }, /* 054 */
{.mk = { 0 }, .brk = { 0 } }, /* 055 */
{.mk = { 0 }, .brk = { 0 } }, /* 056 */
{.mk = { 0x72, 0 }, .brk = { 0 } }, /* 057 F11 */
{.mk = { 0x73, 0 }, .brk = { 0 } }, /* 058 F12 */
{.mk = { 0 }, .brk = { 0 } }, /* 059 */
{.mk = { 0 }, .brk = { 0 } }, /* 05a */
{.mk = { 0 }, .brk = { 0 } }, /* 05b */
{.mk = { 0 }, .brk = { 0 } }, /* 05c */
{.mk = { 0 }, .brk = { 0 } }, /* 05d */
{.mk = { 0 }, .brk = { 0 } }, /* 05e */
{.mk = { 0 }, .brk = { 0 } }, /* 05f */
{.mk = { 0 }, .brk = { 0 } }, /* 060 */
{.mk = { 0 }, .brk = { 0 } }, /* 061 */
{.mk = { 0 }, .brk = { 0 } }, /* 062 */
{.mk = { 0 }, .brk = { 0 } }, /* 063 */
{.mk = { 0 }, .brk = { 0 } }, /* 064 */
{.mk = { 0 }, .brk = { 0 } }, /* 065 */
{.mk = { 0 }, .brk = { 0 } }, /* 066 */
{.mk = { 0 }, .brk = { 0 } }, /* 067 */
{.mk = { 0 }, .brk = { 0 } }, /* 068 */
{.mk = { 0 }, .brk = { 0 } }, /* 069 */
{.mk = { 0 }, .brk = { 0 } }, /* 06a */
{.mk = { 0 }, .brk = { 0 } }, /* 06b */
{.mk = { 0 }, .brk = { 0 } }, /* 06c */
{.mk = { 0 }, .brk = { 0 } }, /* 06d */
{.mk = { 0 }, .brk = { 0 } }, /* 06e */
{.mk = { 0 }, .brk = { 0 } }, /* 06f */
{.mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 070 Kana */
{.mk = { 0 }, .brk = { 0 } }, /* 071 */
{.mk = { 0 }, .brk = { 0 } }, /* 072 */
{.mk = { 0x0b, 0 }, .brk = { 0 } }, /* 073 Ro, Underline */
{.mk = { 0 }, .brk = { 0 } }, /* 074 */
{.mk = { 0 }, .brk = { 0 } }, /* 075 */
{.mk = { 0 }, .brk = { 0 } }, /* 076 */
{.mk = { 0 }, .brk = { 0 } }, /* 077 */
{.mk = { 0 }, .brk = { 0 } }, /* 078 */
{.mk = { 0x35, 0 }, .brk = { 0 } }, /* 079 Henkan */
{.mk = { 0 }, .brk = { 0 } }, /* 07a */
{.mk = { 0x33, 0 }, .brk = { 0 } }, /* 07b Muhenkan */
{.mk = { 0 }, .brk = { 0 } }, /* 07c */
{.mk = { 0x30, 0 }, .brk = { 0 } }, /* 07d Yen, Vertical line */
{.mk = { 0 }, .brk = { 0 } }, /* 07e */
{.mk = { 0 }, .brk = { 0 } }, /* 07f */
{.mk = { 0 }, .brk = { 0 } }, /* 080 */
{.mk = { 0 }, .brk = { 0 } }, /* 081 */
{.mk = { 0 }, .brk = { 0 } }, /* 082 */
{.mk = { 0 }, .brk = { 0 } }, /* 083 */
{.mk = { 0 }, .brk = { 0 } }, /* 084 */
{.mk = { 0 }, .brk = { 0 } }, /* 085 */
{.mk = { 0 }, .brk = { 0 } }, /* 086 */
{.mk = { 0 }, .brk = { 0 } }, /* 087 */
{.mk = { 0 }, .brk = { 0 } }, /* 088 */
{.mk = { 0 }, .brk = { 0 } }, /* 089 */
{.mk = { 0 }, .brk = { 0 } }, /* 08a */
{.mk = { 0 }, .brk = { 0 } }, /* 08b */
{.mk = { 0 }, .brk = { 0 } }, /* 08c */
{.mk = { 0 }, .brk = { 0 } }, /* 08d */
{.mk = { 0 }, .brk = { 0 } }, /* 08e */
{.mk = { 0 }, .brk = { 0 } }, /* 08f */
{.mk = { 0 }, .brk = { 0 } }, /* 090 */
{.mk = { 0 }, .brk = { 0 } }, /* 091 */
{.mk = { 0 }, .brk = { 0 } }, /* 092 */
{.mk = { 0 }, .brk = { 0 } }, /* 093 */
{.mk = { 0 }, .brk = { 0 } }, /* 094 */
{.mk = { 0 }, .brk = { 0 } }, /* 095 */
{.mk = { 0 }, .brk = { 0 } }, /* 096 */
{.mk = { 0 }, .brk = { 0 } }, /* 097 */
{.mk = { 0 }, .brk = { 0 } }, /* 098 */
{.mk = { 0 }, .brk = { 0 } }, /* 099 */
{.mk = { 0 }, .brk = { 0 } }, /* 09a */
{.mk = { 0 }, .brk = { 0 } }, /* 09b */
{.mk = { 0 }, .brk = { 0 } }, /* 09c */
{.mk = { 0 }, .brk = { 0 } }, /* 09d */
{.mk = { 0 }, .brk = { 0 } }, /* 09e */
{.mk = { 0 }, .brk = { 0 } }, /* 09f */
{.mk = { 0 }, .brk = { 0 } }, /* 0a0 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a1 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a2 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a3 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a4 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a5 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a6 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a7 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a8 */
{.mk = { 0 }, .brk = { 0 } }, /* 0a9 */
{.mk = { 0 }, .brk = { 0 } }, /* 0aa */
{.mk = { 0 }, .brk = { 0 } }, /* 0ab */
{.mk = { 0 }, .brk = { 0 } }, /* 0ac */
{.mk = { 0 }, .brk = { 0 } }, /* 0ad */
{.mk = { 0 }, .brk = { 0 } }, /* 0ae */
{.mk = { 0 }, .brk = { 0 } }, /* 0af */
{.mk = { 0 }, .brk = { 0 } }, /* 0b0 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b1 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b2 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b3 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b4 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b5 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b6 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b7 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b8 */
{.mk = { 0 }, .brk = { 0 } }, /* 0b9 */
{.mk = { 0 }, .brk = { 0 } }, /* 0ba */
{.mk = { 0 }, .brk = { 0 } }, /* 0bb */
{.mk = { 0 }, .brk = { 0 } }, /* 0bc */
{.mk = { 0 }, .brk = { 0 } }, /* 0bd */
{.mk = { 0 }, .brk = { 0 } }, /* 0be */
{.mk = { 0 }, .brk = { 0 } }, /* 0bf */
{.mk = { 0 }, .brk = { 0 } }, /* 0c0 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c1 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c2 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c3 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c4 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c5 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c6 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c7 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c8 */
{.mk = { 0 }, .brk = { 0 } }, /* 0c9 */
{.mk = { 0 }, .brk = { 0 } }, /* 0ca */
{.mk = { 0 }, .brk = { 0 } }, /* 0cb */
{.mk = { 0 }, .brk = { 0 } }, /* 0cc */
{.mk = { 0 }, .brk = { 0 } }, /* 0cd */
{.mk = { 0 }, .brk = { 0 } }, /* 0ce */
{.mk = { 0 }, .brk = { 0 } }, /* 0cf */
{.mk = { 0 }, .brk = { 0 } }, /* 0d0 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d1 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d2 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d3 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d4 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d5 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d6 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d7 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d8 */
{.mk = { 0 }, .brk = { 0 } }, /* 0d9 */
{.mk = { 0 }, .brk = { 0 } }, /* 0da */
{.mk = { 0 }, .brk = { 0 } }, /* 0db */
{.mk = { 0 }, .brk = { 0 } }, /* 0dc */
{.mk = { 0 }, .brk = { 0 } }, /* 0dd */
{.mk = { 0 }, .brk = { 0 } }, /* 0de */
{.mk = { 0 }, .brk = { 0 } }, /* 0df */
{.mk = { 0 }, .brk = { 0 } }, /* 0e0 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e1 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e2 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e3 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e4 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e5 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e6 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e7 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e8 */
{.mk = { 0 }, .brk = { 0 } }, /* 0e9 */
{.mk = { 0 }, .brk = { 0 } }, /* 0ea */
{.mk = { 0 }, .brk = { 0 } }, /* 0eb */
{.mk = { 0 }, .brk = { 0 } }, /* 0ec */
{.mk = { 0 }, .brk = { 0 } }, /* 0ed */
{.mk = { 0 }, .brk = { 0 } }, /* 0ee */
{.mk = { 0 }, .brk = { 0 } }, /* 0ef */
{.mk = { 0 }, .brk = { 0 } }, /* 0f0 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f1 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f2 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f3 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f4 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f5 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f6 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f7 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f8 */
{.mk = { 0 }, .brk = { 0 } }, /* 0f9 */
{.mk = { 0 }, .brk = { 0 } }, /* 0fa */
{.mk = { 0 }, .brk = { 0 } }, /* 0fb */
{.mk = { 0 }, .brk = { 0 } }, /* 0fc */
{.mk = { 0 }, .brk = { 0 } }, /* 0fd */
{.mk = { 0 }, .brk = { 0 } }, /* 0fe */
{.mk = { 0 }, .brk = { 0 } }, /* 0ff */
{.mk = { 0x47, 0 }, .brk = { 0 } }, /* 100 Pause */
{.mk = { 0 }, .brk = { 0 } }, /* 101 */
{.mk = { 0 }, .brk = { 0 } }, /* 102 */
{.mk = { 0 }, .brk = { 0 } }, /* 103 */
{.mk = { 0 }, .brk = { 0 } }, /* 104 */
{.mk = { 0 }, .brk = { 0 } }, /* 105 */
{.mk = { 0 }, .brk = { 0 } }, /* 106 */
{.mk = { 0 }, .brk = { 0 } }, /* 107 */
{.mk = { 0 }, .brk = { 0 } }, /* 108 */
{.mk = { 0 }, .brk = { 0 } }, /* 109 */
{.mk = { 0 }, .brk = { 0 } }, /* 10a */
{.mk = { 0 }, .brk = { 0 } }, /* 10b */
{.mk = { 0 }, .brk = { 0 } }, /* 10c */
{.mk = { 0 }, .brk = { 0 } }, /* 10d */
{.mk = { 0 }, .brk = { 0 } }, /* 10e */
{.mk = { 0 }, .brk = { 0 } }, /* 10f */
{.mk = { 0 }, .brk = { 0 } }, /* 110 */
{.mk = { 0 }, .brk = { 0 } }, /* 112 */
{.mk = { 0 }, .brk = { 0 } }, /* 113 */
{.mk = { 0 }, .brk = { 0 } }, /* 113 */
{.mk = { 0 }, .brk = { 0 } }, /* 114 */
{.mk = { 0 }, .brk = { 0 } }, /* 115 */
{.mk = { 0 }, .brk = { 0 } }, /* 116 */
{.mk = { 0 }, .brk = { 0 } }, /* 117 */
{.mk = { 0 }, .brk = { 0 } }, /* 118 */
{.mk = { 0 }, .brk = { 0 } }, /* 119 */
{.mk = { 0 }, .brk = { 0 } }, /* 11a */
{.mk = { 0 }, .brk = { 0 } }, /* 11b */
{.mk = { 0x60, 0 }, .brk = { 0 } }, /* 11c KP_Enter */
{.mk = { 0x37, 0 }, .brk = { 0xb7, 0 } }, /* 11d R-Ctrl */
{.mk = { 0 }, .brk = { 0 } }, /* 11e */
{.mk = { 0 }, .brk = { 0 } }, /* 11f */
{.mk = { 0 }, .brk = { 0 } }, /* 120 */
{.mk = { 0 }, .brk = { 0 } }, /* 121 */
{.mk = { 0 }, .brk = { 0 } }, /* 122 */
{.mk = { 0 }, .brk = { 0 } }, /* 123 */
{.mk = { 0 }, .brk = { 0 } }, /* 124 */
{.mk = { 0 }, .brk = { 0 } }, /* 125 */
{.mk = { 0 }, .brk = { 0 } }, /* 126 */
{.mk = { 0 }, .brk = { 0 } }, /* 127 */
{.mk = { 0 }, .brk = { 0 } }, /* 128 */
{.mk = { 0 }, .brk = { 0 } }, /* 129 */
{.mk = { 0 }, .brk = { 0 } }, /* 12a */
{.mk = { 0 }, .brk = { 0 } }, /* 12b */
{.mk = { 0 }, .brk = { 0 } }, /* 12c */
{.mk = { 0 }, .brk = { 0 } }, /* 12d */
{.mk = { 0 }, .brk = { 0 } }, /* 12e */
{.mk = { 0 }, .brk = { 0 } }, /* 12f */
{.mk = { 0 }, .brk = { 0 } }, /* 130 */
{.mk = { 0 }, .brk = { 0 } }, /* 131 */
{.mk = { 0 }, .brk = { 0 } }, /* 132 */
{.mk = { 0 }, .brk = { 0 } }, /* 133 */
{.mk = { 0 }, .brk = { 0 } }, /* 134 */
{.mk = { 0x65, 0 }, .brk = { 0 } }, /* 135 KP_DIVIDE */
{.mk = { 0 }, .brk = { 0 } }, /* 136 */
{.mk = { 0x74, 0 }, .brk = { 0 } }, /* 137 PRINTSCREEN */
{.mk = { 0x31, 0 }, .brk = { 0xb1, 0 } }, /* 138* R-Alt */
{.mk = { 0 }, .brk = { 0 } }, /* 139 */
{.mk = { 0 }, .brk = { 0 } }, /* 13a */
{.mk = { 0 }, .brk = { 0 } }, /* 13b */
{.mk = { 0 }, .brk = { 0 } }, /* 13c */
{.mk = { 0 }, .brk = { 0 } }, /* 13d */
{.mk = { 0 }, .brk = { 0 } }, /* 13e */
{.mk = { 0 }, .brk = { 0 } }, /* 13f */
{.mk = { 0 }, .brk = { 0 } }, /* 140 */
{.mk = { 0 }, .brk = { 0 } }, /* 141 */
{.mk = { 0 }, .brk = { 0 } }, /* 142 */
{.mk = { 0 }, .brk = { 0 } }, /* 143 */
{.mk = { 0 }, .brk = { 0 } }, /* 144 */
{.mk = { 0 }, .brk = { 0 } }, /* 145 */
{.mk = { 0 }, .brk = { 0 } }, /* 146 */
{.mk = { 0x4c, 0 }, .brk = { 0 } }, /* 147 Home */
{.mk = { 0x4e, 0 }, .brk = { 0 } }, /* 148 Up */
{.mk = { 0x52, 0 }, .brk = { 0 } }, /* 149 PageUp */
{.mk = { 0 }, .brk = { 0 } }, /* 14a */
{.mk = { 0x4b, 0 }, .brk = { 0 } }, /* 14b Left */
{.mk = { 0 }, .brk = { 0 } }, /* 14c */
{.mk = { 0x4d, 0 }, .brk = { 0 } }, /* 14d Right */
{.mk = { 0 }, .brk = { 0 } }, /* 14e */
{.mk = { 0x53, 0 }, .brk = { 0 } }, /* 14f End */
{.mk = { 0x4a, 0 }, .brk = { 0 } }, /* 150 Down */
{.mk = { 0x54, 0 }, .brk = { 0 } }, /* 151 PageDown */
{.mk = { 0x4f, 0 }, .brk = { 0 } }, /* 152 Ins */
{.mk = { 0x50, 0 }, .brk = { 0 } }, /* 153 Del */
{.mk = { 0 }, .brk = { 0 } }, /* 154 */
{.mk = { 0 }, .brk = { 0 } }, /* 155 */
{.mk = { 0 }, .brk = { 0 } }, /* 156 */
{.mk = { 0 }, .brk = { 0 } }, /* 157 */
{.mk = { 0 }, .brk = { 0 } }, /* 158 */
{.mk = { 0 }, .brk = { 0 } }, /* 159 */
{.mk = { 0 }, .brk = { 0 } }, /* 15a */
{.mk = { 0x33, 0 }, .brk = { 0 } }, /* 15b LGUI->Muhenkan (in emulator only) */
{.mk = { 0x35, 0 }, .brk = { 0 } }, /* 15c RGUI->Henkan (in emulator only) */
{.mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 15d APPLICATION->Kana (in emulator only) */
{.mk = { 0 }, .brk = { 0 } }, /* 15e */
{.mk = { 0 }, .brk = { 0 } }, /* 15f */
{.mk = { 0 }, .brk = { 0 } }, /* 160 */
{.mk = { 0 }, .brk = { 0 } }, /* 161 */
{.mk = { 0 }, .brk = { 0 } }, /* 162 */
{.mk = { 0 }, .brk = { 0 } }, /* 163 */
{.mk = { 0 }, .brk = { 0 } }, /* 164 */
{.mk = { 0 }, .brk = { 0 } }, /* 165 */
{.mk = { 0 }, .brk = { 0 } }, /* 166 */
{.mk = { 0 }, .brk = { 0 } }, /* 167 */
{.mk = { 0 }, .brk = { 0 } }, /* 168 */
{.mk = { 0 }, .brk = { 0 } }, /* 169 */
{.mk = { 0 }, .brk = { 0 } }, /* 16a */
{.mk = { 0 }, .brk = { 0 } }, /* 16b */
{.mk = { 0 }, .brk = { 0 } }, /* 16c */
{.mk = { 0 }, .brk = { 0 } }, /* 16d */
{.mk = { 0 }, .brk = { 0 } }, /* 16e */
{.mk = { 0 }, .brk = { 0 } }, /* 16f */
{.mk = { 0 }, .brk = { 0 } }, /* 170 */
{.mk = { 0 }, .brk = { 0 } }, /* 171 */
{.mk = { 0 }, .brk = { 0 } }, /* 172 */
{.mk = { 0 }, .brk = { 0 } }, /* 173 */
{.mk = { 0 }, .brk = { 0 } }, /* 174 */
{.mk = { 0 }, .brk = { 0 } }, /* 175 */
{.mk = { 0 }, .brk = { 0 } }, /* 176 */
{.mk = { 0 }, .brk = { 0 } }, /* 177 */
{.mk = { 0 }, .brk = { 0 } }, /* 178 */
{.mk = { 0 }, .brk = { 0 } }, /* 179 */
{.mk = { 0 }, .brk = { 0 } }, /* 17a */
{.mk = { 0 }, .brk = { 0 } }, /* 17b */
{.mk = { 0 }, .brk = { 0 } }, /* 17c */
{.mk = { 0 }, .brk = { 0 } }, /* 17d */
{.mk = { 0 }, .brk = { 0 } }, /* 17e */
{.mk = { 0 }, .brk = { 0 } }, /* 17f */
{.mk = { 0 }, .brk = { 0 } }, /* 180 */
{.mk = { 0 }, .brk = { 0 } }, /* 181 */
{.mk = { 0 }, .brk = { 0 } }, /* 182 */
{.mk = { 0 }, .brk = { 0 } }, /* 183 */
{.mk = { 0 }, .brk = { 0 } }, /* 184 */
{.mk = { 0 }, .brk = { 0 } }, /* 185 */
{.mk = { 0 }, .brk = { 0 } }, /* 186 */
{.mk = { 0 }, .brk = { 0 } }, /* 187 */
{.mk = { 0 }, .brk = { 0 } }, /* 188 */
{.mk = { 0 }, .brk = { 0 } }, /* 189 */
{.mk = { 0 }, .brk = { 0 } }, /* 18a */
{.mk = { 0 }, .brk = { 0 } }, /* 18b */
{.mk = { 0 }, .brk = { 0 } }, /* 18c */
{.mk = { 0 }, .brk = { 0 } }, /* 18d */
{.mk = { 0 }, .brk = { 0 } }, /* 18e */
{.mk = { 0 }, .brk = { 0 } }, /* 18f */
{.mk = { 0 }, .brk = { 0 } }, /* 190 */
{.mk = { 0 }, .brk = { 0 } }, /* 191 */
{.mk = { 0 }, .brk = { 0 } }, /* 192 */
{.mk = { 0 }, .brk = { 0 } }, /* 193 */
{.mk = { 0 }, .brk = { 0 } }, /* 194 */
{.mk = { 0 }, .brk = { 0 } }, /* 195 */
{.mk = { 0 }, .brk = { 0 } }, /* 196 */
{.mk = { 0 }, .brk = { 0 } }, /* 197 */
{.mk = { 0 }, .brk = { 0 } }, /* 198 */
{.mk = { 0 }, .brk = { 0 } }, /* 199 */
{.mk = { 0 }, .brk = { 0 } }, /* 19a */
{.mk = { 0 }, .brk = { 0 } }, /* 19b */
{.mk = { 0 }, .brk = { 0 } }, /* 19c */
{.mk = { 0 }, .brk = { 0 } }, /* 19d */
{.mk = { 0 }, .brk = { 0 } }, /* 19e */
{.mk = { 0 }, .brk = { 0 } }, /* 19f */
{.mk = { 0 }, .brk = { 0 } }, /* 1a0 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a1 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a2 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a3 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a4 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a5 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a6 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a7 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a8 */
{.mk = { 0 }, .brk = { 0 } }, /* 1a9 */
{.mk = { 0 }, .brk = { 0 } }, /* 1aa */
{.mk = { 0 }, .brk = { 0 } }, /* 1ab */
{.mk = { 0 }, .brk = { 0 } }, /* 1ac */
{.mk = { 0 }, .brk = { 0 } }, /* 1ad */
{.mk = { 0 }, .brk = { 0 } }, /* 1ae */
{.mk = { 0 }, .brk = { 0 } }, /* 1af */
{.mk = { 0 }, .brk = { 0 } }, /* 1b0 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b1 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b2 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b3 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b4 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b5 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b6 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b7 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b8 */
{.mk = { 0 }, .brk = { 0 } }, /* 1b9 */
{.mk = { 0 }, .brk = { 0 } }, /* 1ba */
{.mk = { 0 }, .brk = { 0 } }, /* 1bb */
{.mk = { 0 }, .brk = { 0 } }, /* 1bc */
{.mk = { 0 }, .brk = { 0 } }, /* 1bd */
{.mk = { 0 }, .brk = { 0 } }, /* 1be */
{.mk = { 0 }, .brk = { 0 } }, /* 1bf */
{.mk = { 0 }, .brk = { 0 } }, /* 1c0 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c1 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c2 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c3 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c4 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c5 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c6 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c7 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c8 */
{.mk = { 0 }, .brk = { 0 } }, /* 1c9 */
{.mk = { 0 }, .brk = { 0 } }, /* 1ca */
{.mk = { 0 }, .brk = { 0 } }, /* 1cb */
{.mk = { 0 }, .brk = { 0 } }, /* 1cv */
{.mk = { 0 }, .brk = { 0 } }, /* 1cd */
{.mk = { 0 }, .brk = { 0 } }, /* 1ce */
{.mk = { 0 }, .brk = { 0 } }, /* 1cf */
{.mk = { 0 }, .brk = { 0 } }, /* 1d0 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d1 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d2 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d3 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d4 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d5 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d6 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d7 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d8 */
{.mk = { 0 }, .brk = { 0 } }, /* 1d9 */
{.mk = { 0 }, .brk = { 0 } }, /* 1da */
{.mk = { 0 }, .brk = { 0 } }, /* 1db */
{.mk = { 0 }, .brk = { 0 } }, /* 1dc */
{.mk = { 0 }, .brk = { 0 } }, /* 1dd */
{.mk = { 0 }, .brk = { 0 } }, /* 1de */
{.mk = { 0 }, .brk = { 0 } }, /* 1df */
{.mk = { 0 }, .brk = { 0 } }, /* 1e0 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e1 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e2 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e3 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e4 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e5 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e6 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e7 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e8 */
{.mk = { 0 }, .brk = { 0 } }, /* 1e9 */
{.mk = { 0 }, .brk = { 0 } }, /* 1ea */
{.mk = { 0 }, .brk = { 0 } }, /* 1eb */
{.mk = { 0 }, .brk = { 0 } }, /* 1ec */
{.mk = { 0 }, .brk = { 0 } }, /* 1ed */
{.mk = { 0 }, .brk = { 0 } }, /* 1ee */
{.mk = { 0 }, .brk = { 0 } }, /* 1ef */
{.mk = { 0 }, .brk = { 0 } }, /* 1f0 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f1 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f2 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f3 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f4 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f5 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f6 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f7 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f8 */
{.mk = { 0 }, .brk = { 0 } }, /* 1f9 */
{.mk = { 0 }, .brk = { 0 } }, /* 1fa */
{.mk = { 0 }, .brk = { 0 } }, /* 1fb */
{.mk = { 0 }, .brk = { 0 } }, /* 1fc */
{.mk = { 0 }, .brk = { 0 } }, /* 1fd */
{.mk = { 0 }, .brk = { 0 } }, /* 1fe */
{.mk = { 0 }, .brk = { 0 } } /* 1ff */
// clang-format on
};
#ifdef ENABLE_KEYBOARD_AT_LOG
int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG;
@@ -1664,6 +2208,10 @@ keyboard_at_set_scancode_set(void)
case 0x03:
keyboard_set_table(scancode_set3);
break;
case 0x8a:
keyboard_set_table(scancode_set8a);
break;
}
}
@@ -1922,19 +2470,22 @@ keyboard_at_write(void *priv)
break;
case 0xf0: /* Get/set scancode set */
kbc_at_dev_queue_add(dev, (val > 3) ? 0xfe : 0xfa, 0);
switch (val) {
case 0x00:
kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK */
keyboard_at_log("%s: Get scan code set [%02X]\n", dev->name, keyboard_mode);
kbc_at_dev_queue_add(dev, keyboard_mode, 0);
break;
case 0x01 ... 0x03:
case 0x8a:
kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK */
keyboard_mode = val;
keyboard_at_log("%s: Set scan code set [%02X]\n", dev->name, keyboard_mode);
keyboard_at_set_scancode_set();
break;
default:
/* Fatal so any instance of anything attempting to set scan code > 3 can be reported to us. */
kbc_at_dev_queue_add(dev, 0xfe, 0); /* Resend */
fatal("%s: Scan code set [%02X] invalid, resend\n", dev->name, val);
dev->flags |= FLAG_CTRLDAT;
dev->state = DEV_STATE_MAIN_WANT_IN;

View File

@@ -77,6 +77,7 @@ static const struct {
{ &xtide_acculogic_device },
{ &xtide_device },
{ &esdi_ps2_device },
{ &esdi_integrated_device },
{ &ide_pci_device },
{ &ide_pci_2ch_device },
{ &ide_vlb_device },

View File

@@ -150,6 +150,11 @@ typedef struct esdi_t {
uint8_t pos_regs[8];
} esdi_t;
enum {
ESDI_IS_ADAPTER,
ESDI_IS_INTEGRATED
};
#define STATUS_DMA_ENA (1 << 7)
#define STATUS_IRQ_PENDING (1 << 6)
#define STATUS_CMD_IN_PROGRESS (1 << 5)
@@ -694,32 +699,48 @@ esdi_callback(void *priv)
break;
case CMD_GET_DEV_CONFIG:
ESDI_DRIVE_ONLY();
if (!drive->present) {
device_not_present(dev);
return;
if (dev->cmd_dev == ATTN_HOST_ADAPTER)
{
if ((dev->status & STATUS_IRQ) || dev->irq_in_progress)
fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress);
/* INT 13, AX=1C0B - ESDI FIXED DISK - GET ADAPTER CONFIGURATION */
/* The PS/55 will test sector buffer after this request is done. */
dev->status_len = 6;
dev->status_data[0] = CMD_GET_DEV_CONFIG | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER;
dev->status_data[1] = 0;
dev->status_data[2] = 0;
/* bit 15-12: chip revision = 0011b, bit 11-8: sector buffer size = n * 256 bytes (n must be < 6) */
dev->status_data[3] = 0x3200;
dev->status_data[4] = 0;
dev->status_data[5] = 0;
}
else
{
ESDI_DRIVE_ONLY();
if (!drive->present) {
device_not_present(dev);
return;
}
if ((dev->status & STATUS_IRQ) || dev->irq_in_progress)
fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress);
dev->status_len = 6;
dev->status_data[0] = CMD_GET_DEV_CONFIG | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER;
dev->status_data[1] = 0x10; /*Zero defect*/
dev->status_data[2] = drive->sectors & 0xffff;
dev->status_data[3] = drive->sectors >> 16;
dev->status_data[4] = drive->tracks;
dev->status_data[5] = drive->hpc | (drive->spt << 16);
if ((dev->status & STATUS_IRQ) || dev->irq_in_progress)
fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress);
dev->status_len = 6;
dev->status_data[0] = CMD_GET_DEV_CONFIG | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER;
dev->status_data[1] = 0x10; /*Zero defect*/
dev->status_data[2] = drive->sectors & 0xffff;
dev->status_data[3] = drive->sectors >> 16;
dev->status_data[4] = drive->tracks;
dev->status_data[5] = drive->hpc | (drive->spt << 16);
}
esdi_mca_log("CMD_GET_DEV_CONFIG %i %04x %04x %04x %04x %04x %04x\n",
drive->sectors,
dev->status_data[0], dev->status_data[1],
dev->status_data[2], dev->status_data[3],
dev->status_data[4], dev->status_data[5]);
drive->sectors,
dev->status_data[0], dev->status_data[1],
dev->status_data[2], dev->status_data[3],
dev->status_data[4], dev->status_data[5]);
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
@@ -733,7 +754,7 @@ esdi_callback(void *priv)
dev->status_len = 5;
dev->status_data[0] = CMD_GET_POS_INFO | STATUS_LEN(5) | STATUS_DEVICE_HOST_ADAPTER;
dev->status_data[1] = 0xffdd; /*MCA ID*/
dev->status_data[1] = dev->pos_regs[1] | (dev->pos_regs[0] << 8); /*MCA ID*/
dev->status_data[2] = dev->pos_regs[3] | (dev->pos_regs[2] << 8);
dev->status_data[3] = 0xff;
dev->status_data[4] = 0xff;
@@ -1233,6 +1254,62 @@ esdi_mca_write(int port, uint8_t val, void *priv)
}
}
static void
esdi_integrated_mca_write(int port, uint8_t val, void* priv)
{
esdi_t* dev = (esdi_t*)priv;
esdi_mca_log("ESDI: mcawr(%04x, %02x) pos[2]=%02x pos[3]=%02x\n",
port, val, dev->pos_regs[2], dev->pos_regs[3]);
if (port < 0x102)
return;
/* Save the new value. */
dev->pos_regs[port & 7] = val;
io_removehandler(ESDI_IOADDR_PRI, 8,
esdi_read, esdi_readw, NULL,
esdi_write, esdi_writew, NULL, dev);
switch (dev->pos_regs[2] & 0x3c) {
case 0x14:
dev->dma = 5;
break;
case 0x18:
dev->dma = 6;
break;
case 0x1c:
dev->dma = 7;
break;
case 0x00:
dev->dma = 0;
break;
case 0x04:
dev->dma = 1;
break;
case 0x0c:
dev->dma = 3;
break;
case 0x10:
dev->dma = 4;
break;
default:
break;
}
if (dev->pos_regs[2] & 1) {
io_sethandler(ESDI_IOADDR_PRI, 8,
esdi_read, esdi_readw, NULL,
esdi_write, esdi_writew, NULL, dev);
/* Say hello. */
esdi_mca_log("ESDI: I/O=3510, IRQ=14, DMA=%d\n",
dev->dma);
}
}
static uint8_t
esdi_mca_feedb(void *priv)
{
@@ -1241,6 +1318,16 @@ esdi_mca_feedb(void *priv)
return (dev->pos_regs[2] & 1);
}
static void esdi_reset(void* priv)
{
esdi_t* dev = (esdi_t*)priv;
if (!dev->in_reset) {
dev->in_reset = 1;
esdi_mca_set_callback(dev, ESDI_TIME * 50);
dev->status = STATUS_BUSY;
}
}
static void *
esdi_init(UNUSED(const device_t *info))
{
@@ -1256,10 +1343,12 @@ esdi_init(UNUSED(const device_t *info))
/* Mark as unconfigured. */
dev->irq_status = 0xff;
rom_init_interleaved(&dev->bios_rom,
BIOS_FILE_H, BIOS_FILE_L,
0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
mem_mapping_disable(&dev->bios_rom.mapping);
if (info->local == ESDI_IS_ADAPTER) {
rom_init_interleaved(&dev->bios_rom,
BIOS_FILE_H, BIOS_FILE_L,
0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
mem_mapping_disable(&dev->bios_rom.mapping);
}
dev->drives[0].present = dev->drives[1].present = 0;
@@ -1292,12 +1381,25 @@ esdi_init(UNUSED(const device_t *info))
break;
}
/* Set the MCA ID for this controller, 0xFFDD. */
dev->pos_regs[0] = 0xff;
dev->pos_regs[1] = 0xdd;
/* Set the MCA ID for this controller. */
if (info->local == ESDI_IS_ADAPTER) {
dev->pos_regs[0] = 0xff;
dev->pos_regs[1] = 0xdd;
} else if (info->local == ESDI_IS_INTEGRATED) {
dev->pos_regs[0] = 0x9f;
dev->pos_regs[1] = 0xdf;
}
/* Enable the device. */
mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, NULL, dev);
if (info->local == ESDI_IS_INTEGRATED) {
/* The slot number of this controller is fixed by the planar. IBM PS/55 5551-T assigns it #5. */
int slotno = device_get_config_int("in_esdi_slot");
if (slotno)
mca_add_to_slot(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, esdi_reset, dev, slotno - 1);
else
mca_add(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, esdi_reset, dev);
} else
mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, NULL, dev);
/* Mark for a reset. */
dev->in_reset = 1;
@@ -1337,7 +1439,7 @@ const device_t esdi_ps2_device = {
.name = "IBM PS/2 ESDI Fixed Disk Adapter (MCA)",
.internal_name = "esdi_mca",
.flags = DEVICE_MCA,
.local = 0,
.local = ESDI_IS_ADAPTER,
.init = esdi_init,
.close = esdi_close,
.reset = NULL,
@@ -1346,3 +1448,52 @@ const device_t esdi_ps2_device = {
.force_redraw = NULL,
.config = NULL
};
static device_config_t
esdi_integrated_config[] = {
{
.name = "in_esdi_slot",
.description = "Slot #",
.type = CONFIG_SELECTION,
.selection = {
{ .description = "Auto", .value = 0 },
{ .description = "1", .value = 1 },
{ .description = "2", .value = 2 },
{ .description = "3", .value = 3 },
{ .description = "4", .value = 4 },
{ .description = "5", .value = 5 },
{ .description = "6", .value = 6 },
{ .description = "7", .value = 7 },
{ .description = "8", .value = 8 }
},
.default_int = 0
},
{ .type = -1 }
};
/*
Device for an IBM DBA (Direct Bus Attachment) hard disk.
The Disk BIOS is included in the System ROM.
Some models have an exclusive channel slot for the DBA hard disk.
Following IBM machines are supported:
* PS/2 model 55SX
* PS/2 model 65SX
* PS/2 model 70 type 3 (Slot #4)
* PS/2 model 70 type 4 (Slot #4)
* PS/55 model 5550-T (Slot #5)
* PS/55 model 5550-V (Slot #5)
*/
const device_t
esdi_integrated_device = {
.name = "IBM Integrated Fixed Disk and Controller (MCA)",
.internal_name = "esdi_integrated_mca",
.flags = DEVICE_MCA,
.local = ESDI_IS_INTEGRATED,
.init = esdi_init,
.close = esdi_close,
.reset = esdi_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = esdi_integrated_config
};

View File

@@ -740,6 +740,18 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
drive = real_drive(fdc, fdc->dor & 3);
fdc_update_rwc(fdc, drive, (val & 0x30) >> 4);
}
/* Bit 2: FIFO test mode (PS/55 5550-S,T only. Undocumented)
The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h.
If it fails, then floppy drives will be treated as DD drives. */
if (fdc->flags & FDC_FLAG_PS2_MCA) {
if (val & 0x04) {
fdc->tfifo = 8;
fdc->fifointest = 1;
} else {
fdc->tfifo = 1;
fdc->fifointest = 0;
}
}
return;
case 4: /* DSR */
if (!(fdc->flags & FDC_FLAG_NO_DSR_RESET)) {
@@ -753,6 +765,14 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
fdc->dsr = val;
return;
case 5: /*Command register*/
if (fdc->fifointest) {
/* Write FIFO buffer in the test mode (PS/55) */
fdc_log("FIFO buffer position = %X\n", ((fifo_t *) fdc->fifo_p)->end);
fifo_write(val, fdc->fifo_p);
if (fifo_get_full(fdc->fifo_p))
fdc->stat &= ~0x80;
break;
}
if ((fdc->stat & 0xf0) == 0xb0) {
if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) {
fdc->dat = val;
@@ -1335,6 +1355,7 @@ fdc_read(uint16_t addr, void *priv)
ret = 0x10;
else
ret = 0x00;
/* PS/55 POST throws an error and halt if ret = 1 or 2, somehow. */
} else if (!fdc->enh_mode)
ret = 0x20;
else
@@ -1344,6 +1365,11 @@ fdc_read(uint16_t addr, void *priv)
ret = fdc->stat;
break;
case 5: /*Data*/
if (fdc->fifointest) {
/* Read FIFO buffer in the test mode (PS/55) */
ret = fifo_read(fdc->fifo_p);
break;
}
if ((fdc->stat & 0xf0) == 0xf0) {
fdc->stat &= ~0x80;
if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) {
@@ -2249,6 +2275,7 @@ fdc_reset(void *priv)
fdc->fifo = 0;
fdc->tfifo = 1;
fdc->fifointest = 0;
if (fdc->flags & FDC_FLAG_PCJR) {
fdc->dma = 0;

View File

@@ -294,7 +294,7 @@ fdd_type_invert_densel(int type)
int ret;
if (drive_types[type].flags & FLAG_PS2)
ret = (!!strstr(machine_getname(), "PS/1")) || (!!strstr(machine_getname(), "PS/2"));
ret = (!!strstr(machine_getname(), "PS/1")) || (!!strstr(machine_getname(), "PS/2")) || (!!strstr(machine_getname(), "PS/55"));
else
ret = drive_types[type].flags & FLAG_INVERT_DENSEL;

View File

@@ -138,6 +138,7 @@ extern int sound_is_float; /* (C) sound uses FP values */
extern int voodoo_enabled; /* (C) video option */
extern int ibm8514_standalone_enabled; /* (C) video option */
extern int xga_standalone_enabled; /* (C) video option */
extern int da2_standalone_enabled; /* (C) video option */
extern uint32_t mem_size; /* (C) memory size (Installed on system board) */
extern uint32_t isa_mem_size; /* (C) memory size (ISA Memory Cards) */
extern int cpu; /* (C) cpu type */

View File

@@ -103,7 +103,6 @@ typedef struct fdc_t {
uint8_t densel_force;
uint8_t fifo;
uint8_t tfifo;
uint8_t fifobufpos;
uint8_t drv2en;
uint8_t gap;
@@ -148,6 +147,7 @@ typedef struct fdc_t {
int drvrate[4];
void *fifo_p;
int fifointest;
sector_id_t read_track_sector;
sector_id_t format_sector_id;

View File

@@ -48,6 +48,7 @@ extern const device_t st506_xt_toshiba_t1200_device; /* st506_xt_toshiba_t1
extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */
extern const device_t esdi_ps2_device; /* esdi_mca */
extern const device_t esdi_integrated_device; /* esdi_mca */
extern const device_t ide_isa_device; /* isa_ide */
extern const device_t ide_isa_sec_device; /* isa_ide sec*/

View File

@@ -903,6 +903,8 @@ extern int machine_ps2_model_70_type3_init(const machine_t *);
extern int machine_ps2_model_80_init(const machine_t *);
extern int machine_ps2_model_80_axx_init(const machine_t *);
extern int machine_ps2_model_70_type4_init(const machine_t *);
extern int machine_ps55_model_50t_init(const machine_t*);;
extern int machine_ps55_model_50v_init(const machine_t*);
/* m_tandy.c */
extern int tandy1k_eeprom_read(void);

View File

@@ -3,6 +3,7 @@
extern void mca_init(int nr_cards);
extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void (*reset)(void *priv), void *priv);
extern void mca_add_to_slot(uint8_t(*read)(int addr, void* priv), void (*write)(int addr, uint8_t val, void* priv), uint8_t(*feedb)(void* priv), void (*reset)(void* priv), void* priv, int c);
extern void mca_set_index(int index);
extern uint8_t mca_read(uint16_t port);
extern uint8_t mca_read_index(uint16_t port, int index);

View File

@@ -0,0 +1,24 @@
/*
* 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.
*
* IBM PS/55 Display Adapter II emulation.
*
*
*
* Authors: Akamaki.
*
* Copyright 2024 Akamaki.
*/
#ifndef VIDEO_DA2_DEVICE_H
#define VIDEO_DA2_DEVICE_H
#ifdef EMU_DEVICE_H
extern const device_t ps55da2_device;
#endif
#endif /*VIDEO_DA2_DEVICE_H*/

View File

@@ -229,6 +229,11 @@ typedef struct svga_t {
int override;
void *priv;
int vga_enabled;
/* The PS/55 POST BIOS has a special monitor detection for its internal VGA
when the monitor is connected to the Display Adapter. */
int cable_connected;
uint8_t crtc[256];
uint8_t gdcreg[256];
uint8_t attrregs[32];

View File

@@ -31,4 +31,8 @@ typedef struct vga_t {
extern void vga_out(uint16_t addr, uint8_t val, void *priv);
extern uint8_t vga_in(uint16_t addr, void *priv);
void vga_disable(void* p);
void vga_enable(void* p);
int vga_isenabled(void* p);
#endif /*VIDEO_VGA_H*/

View File

@@ -313,6 +313,9 @@ extern const device_t mach32_mca_device;
extern const device_t mach32_pci_device;
extern const device_t mach32_onboard_pci_device;
/* IBM Display Adapter (PS/55) */
extern void da2_device_add(void);
/* ATi Mach64 */
extern const device_t mach64gx_isa_device;
extern const device_t mach64gx_vlb_device;

View File

@@ -67,6 +67,8 @@
#include <86box/port_92.h>
#include <86box/serial.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/vid_vga.h>
#include <86box/machine.h>
#include <86box/plat_unused.h>
@@ -103,6 +105,9 @@ static struct ps2_t {
int pending_cache_miss;
serial_t *uart;
vga_t* mb_vga;
int has_e0000_hole;
} ps2;
/*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any
@@ -140,7 +145,8 @@ static struct ps2_t {
static uint8_t ps2_cache[65536];
static int ps2_cache_valid[65536 / 8];
static void mem_encoding_update(void);
// #define ENABLE_PS2_MCA_LOG 1
#ifdef ENABLE_PS2_MCA_LOG
int ps2_mca_do_log = ENABLE_PS2_MCA_LOG;
@@ -358,6 +364,114 @@ model_80_read(uint16_t port)
return 0xff;
}
static uint8_t
ps55_model_50t_read(uint16_t port)
{
ps2_mca_log(" Read SysBrd %04X xx %04X:%04X\n", port, cs >> 4, cpu_state.pc);
switch (port) {
case 0x100:
return ps2.planar_id & 0xff;
case 0x101:
return ps2.planar_id >> 8;
case 0x102:
return ps2.option[0];
case 0x103:
uint8_t val = 0xff;
/*
I/O 103h - Bit 7-4: Memory Card ID (Connector 1 or 3)
Bit 3-0: Memory Card ID (Connector 2)
Memory Card ID: 7h = 2 MB Memory Card 2 or 3 Installed
5h = 4 MB Memory Card 2 Installed
*/
switch (mem_size / 1024) {
case 2:
if (ps2.option[1] & 0x04)
val = 0xff;
else
val = 0x7f;
break;
case 4:
if (ps2.option[1] & 0x04)
val = 0xff;
else
val = 0x77;
break;
case 6:
if (ps2.option[1] & 0x04)
val = 0x7f;
else
val = 0x77;
break;
case 8:
default:
if (ps2.option[1] & 0x04)
val = 0x5f;
else
val = 0x77;
break;
}
ps2_mca_log(" Read MCA %04X %02X %04X:%04X mem_size = %d, ps2option1 = %2X\n", port, val, cs >> 4, cpu_state.pc, mem_size, ps2.option[1]);
return val;
case 0x104:
return ps2.option[2];
case 0x105:
return ps2.option[3];
case 0x106:
return ps2.subaddr_lo;
case 0x107:
return ps2.subaddr_hi;
}
return 0xff;
}
static uint8_t
ps55_model_50v_read(uint16_t port)
{
switch (port) {
case 0x100:
return ps2.planar_id & 0xff;
case 0x101:
return ps2.planar_id >> 8;
case 0x102:
return ps2.option[0];
case 0x103:
uint8_t val = 0xff;
/*
I/O 103h - Bit 7-4: Reserved
Bit 3-0: Memory Card ID (Connector 3 or 1)
Memory Card ID: 8h = 4 MB Memory Card IV Installed
Fh = No Card Installed
*/
switch (mem_size / 1024) {
case 4:
if (ps2.option[1] & 0x04)
val = 0xff;
else
val = 0xf8;
break;
case 8:
default:
if (ps2.option[1] & 0x04)
val = 0xf8;
else
val = 0xf8;
break;
}
return val;
case 0x104:
/* Reading cache ID (bit 3-2) always returns zero */
return ps2.option[2] & 0xf3;
case 0x105:
return ps2.option[3];
case 0x106:
return ps2.subaddr_lo;
case 0x107:
return ps2.subaddr_hi;
}
return 0xff;
}
static void
model_50_write(uint16_t port, uint8_t val)
{
@@ -655,6 +769,62 @@ model_80_write(uint16_t port, uint8_t val)
}
}
static void
ps55_model_50tv_write(uint16_t port, uint8_t val)
{
ps2_mca_log(" Write SysBrd %04X %02X %04X:%04X\n", port, val, cs >> 4, cpu_state.pc);
switch (port) {
case 0x102:
lpt1_remove();
serial_remove(ps2.uart);
if (val & 0x04) {
if (val & 0x08)
serial_setup(ps2.uart, COM1_ADDR, COM1_IRQ);
else
serial_setup(ps2.uart, COM2_ADDR, COM2_IRQ);
}
if (val & 0x10) {
switch ((val >> 5) & 3) {
case 0:
lpt1_setup(LPT_MDA_ADDR);
break;
case 1:
lpt1_setup(LPT1_ADDR);
break;
case 2:
lpt1_setup(LPT2_ADDR);
break;
default:
break;
}
}
ps2.option[0] = val;
break;
case 0x103:
ps2.option[1] = val;
break;
case 0x104:
if ((ps2.option[2] ^ val) & 1) {
/* Disable/Enable E0000 - E0FFF (Make 2 KB hole for Display Adapter) */
ps2.option[2] = val;
mem_encoding_update();
}
ps2.option[2] = val;
break;
case 0x105:
ps2.option[3] = val;
break;
case 0x106:
ps2.subaddr_lo = val;
break;
case 0x107:
ps2.subaddr_hi = val;
break;
default:
break;
}
}
uint8_t
ps2_mca_read(uint16_t port, UNUSED(void *priv))
{
@@ -772,8 +942,15 @@ ps2_mca_write(uint16_t port, uint8_t val, UNUSED(void *priv))
ps2.setup = val;
break;
case 0x96:
if ((val & 0x80) && !(ps2.adapter_setup & 0x80))
if ((val & 0x80) && !(ps2.adapter_setup & 0x80)) {
mca_reset();
if (ps2.has_e0000_hole) {
/* Reset memstate for E0000 - E0FFFh hole (for PS/55 5550-V)
5550-T does this in POST, but 5550-V doesn't. */
ps2.option[2] &= 0xFE;
mem_encoding_update();
}
}
ps2.adapter_setup = val;
mca_set_index(val & 7);
break;
@@ -793,7 +970,16 @@ ps2_mca_write(uint16_t port, uint8_t val, UNUSED(void *priv))
if (!(ps2.setup & PS2_SETUP_IO))
ps2.planar_write(port, val);
else if (!(ps2.setup & PS2_SETUP_VGA))
{
if (ps2.mb_vga)
{
if (vga_isenabled(ps2.mb_vga))
vga_disable(ps2.mb_vga);
if (val & 1)
vga_enable(ps2.mb_vga);
}
ps2.pos_vga = val;
}
else if (ps2.adapter_setup & PS2_ADAPTER_SETUP)
mca_write(port, val);
break;
@@ -1117,6 +1303,11 @@ mem_encoding_update(void)
ps2_mca_log("PS/2 Model 80-111: Split memory block disabled\n");
}
if (ps2.has_e0000_hole && (ps2.option[2] & 1)) {
/* Set memstate for E0000 - E0FFFh hole (PS/55 only) */
mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
flushmmucache_nopc();
}
@@ -1311,7 +1502,7 @@ ps2_mca_board_model_70_type34_init(int is_type4, int slots)
}
if (gfxcard[0] == VID_INTERNAL)
device_add(&ps1vga_mca_device);
ps2.mb_vga = device_add(&ps1vga_mca_device);
}
static void
@@ -1385,7 +1576,7 @@ ps2_mca_board_model_80_type2_init(void)
}
if (gfxcard[0] == VID_INTERNAL)
device_add(&ps1vga_mca_device);
ps2.mb_vga = device_add(&ps1vga_mca_device);
ps2.split_size = 0;
}
@@ -1409,6 +1600,8 @@ machine_ps2_common_init(const machine_t *model)
nmi_mask = 0x80;
ps2.uart = device_add_inst(&ns16550_device, 1);
ps2.has_e0000_hole = 0;
}
int
@@ -1576,3 +1769,160 @@ machine_ps2_model_70_type4_init(const machine_t *model)
return ret;
}
static void
ps55_mca_board_model_50t_init(void)
{
ps2_mca_board_common_init();
ps2.split_addr = mem_size * 1024;
/* The slot 5 is reserved for the Integrated Fixed Disk II (an internal ESDI hard drive). */
mca_init(5);
device_add(&keyboard_ps2_mca_1_device);
ps2.planar_read = ps55_model_50t_read;
ps2.planar_write = ps55_model_50tv_write;
device_add(&ps2_nvr_device);
io_sethandler(0x00e0, 0x0002, mem_encoding_read, NULL, NULL, mem_encoding_write, NULL, NULL, NULL);
ps2.mem_regs[1] = 2;
ps2.option[2] &= 0xfe; /* Bit 0: Disable E0000-E0FFFh (4 KB) */
ps2.has_e0000_hole = 1;
mem_mapping_add(&ps2.split_mapping,
(mem_size + 256) * 1024,
256 * 1024,
ps2_read_split_ram,
ps2_read_split_ramw,
ps2_read_split_raml,
ps2_write_split_ram,
ps2_write_split_ramw,
ps2_write_split_raml,
&ram[0xa0000],
MEM_MAPPING_INTERNAL,
NULL);
mem_mapping_disable(&ps2.split_mapping);
if (mem_size > 8192) {
/* Only 8 MB supported on planar, create a memory expansion card for the rest */
ps2_mca_mem_fffc_init(8);
}
if (gfxcard[0] == VID_INTERNAL)
ps2.mb_vga = (vga_t *)device_add(&ps1vga_mca_device);
}
static void
ps55_mca_board_model_50v_init(void)
{
ps2_mca_board_common_init();
ps2.split_addr = mem_size * 1024;
/* The slot 5 is reserved for the Integrated Fixed Disk II (an internal ESDI hard drive). */
mca_init(5);
device_add(&keyboard_ps2_mca_1_device);
ps2.planar_read = ps55_model_50v_read;
ps2.planar_write = ps55_model_50tv_write;
device_add(&ps2_nvr_device);
io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached, NULL, NULL, NULL);
ps2.mem_regs[1] = 2;
ps2.option[2] &= 0xf2; /* Bit 3-2: -Cache IDs, Bit 1: Reserved
Bit 0: Disable E0000-E0FFFh (4 KB) */
ps2.has_e0000_hole = 1;
mem_mapping_add(&ps2.split_mapping,
(mem_size + 256) * 1024,
256 * 1024,
ps2_read_split_ram,
ps2_read_split_ramw,
ps2_read_split_raml,
ps2_write_split_ram,
ps2_write_split_ramw,
ps2_write_split_raml,
&ram[0xa0000],
MEM_MAPPING_INTERNAL,
NULL);
mem_mapping_disable(&ps2.split_mapping);
mem_mapping_add(&ps2.cache_mapping,
0,
64 * 1024,
ps2_read_cache_ram,
ps2_read_cache_ramw,
ps2_read_cache_raml,
ps2_write_cache_ram,
NULL,
NULL,
ps2_cache,
MEM_MAPPING_INTERNAL,
NULL);
mem_mapping_disable(&ps2.cache_mapping);
if (mem_size > 8192) {
/* Only 8 MB supported on planar, create a memory expansion card for the rest */
ps2_mca_mem_fffc_init(8);
}
if (gfxcard[0] == VID_INTERNAL)
ps2.mb_vga = (vga_t *)device_add(&ps1vga_mca_device);
}
int
machine_ps55_model_50t_init(const machine_t* model)
{
int ret;
ret = bios_load_linear("roms/machines/ibmps55_m50t/38F6933.BIN",
0x000e0000, 131072, 0);
if (bios_only || !ret)
return ret;
machine_ps2_common_init(model);
/*
* Planar ID
* FFFAh - PS/55 model 5551-S0x, T0x (stage 1?)
* FFEEh - PS/55 model 5551-S1x, T1x (stage 2?)
* Verification in BIOS P/N 38F6933: FBxx -> 4 slots (error), xxEE -> 5 slots (ok), others -> 8 (error)
*
* The only difference between S and T models is the CPU speed (16 MHz vs 20 MHz).
* The POST measures the speed, and sets a flag in the BIOS Data Area to indicate the sub model.
* The VM in 86Box runs faster than the real, so the POST always determines it as the T model.
*/
ps2.planar_id = 0xffee;
ps55_mca_board_model_50t_init();
return ret;
}
int
machine_ps55_model_50v_init(const machine_t* model)
{
int ret;
ret = bios_load_interleaved("roms/machines/ibmps55_m50v/56F7416.BIN",
"roms/machines/ibmps55_m50v/56F7417.BIN",
0x000e0000, 131072, 0);
if (bios_only || !ret)
return ret;
machine_ps2_common_init(model);
/*
* Planar ID
* F1FFh - PS/55 model 5551-V0x, V1x
* Verification in BIOS P/N 56F7416,56F7417: FBxx -> 5 slots (ok), F1xx -> 5 slots (ok), others -> 8 (error)
*/
ps2.planar_id = 0xf1ff;
ps55_mca_board_model_50v_init();
return ret;
}

View File

@@ -5638,6 +5638,86 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* Has IBM PS/55 5551-Sxx, Txx stage 2 firmware. */
{
.name = "[MCA] IBM PS/55 model 5550-T",
.internal_name = "ibmps55_m50t",
.type = MACHINE_TYPE_386DX,
.chipset = MACHINE_CHIPSET_PROPRIETARY,
.init = machine_ps55_model_50t_init,
.p1_handler = NULL,
.gpio_handler = NULL,
.available_flag = MACHINE_AVAILABLE,
.gpio_acpi_handler = NULL,
.cpu = {
.package = CPU_PKG_386DX | CPU_PKG_486BL,
.block = CPU_BLOCK_NONE,
.min_bus = 0,
.max_bus = 0,
.min_voltage = 0,
.max_voltage = 0,
.min_multi = 0,
.max_multi = 0
},
.bus_flags = MACHINE_PS2_MCA,
.flags = MACHINE_VIDEO | MACHINE_APM,
.ram = {
.min = 2048,
.max = 16384,
.step = 2048
},
.nvrmask = 63,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* Has IBM PS/55 5551-V0x, V1x firmware. */
{
.name = "[MCA] IBM PS/55 model 5550-V",
.internal_name = "ibmps55_m50v",
.type = MACHINE_TYPE_386DX,
.chipset = MACHINE_CHIPSET_PROPRIETARY,
.init = machine_ps55_model_50v_init,
.p1_handler = NULL,
.gpio_handler = NULL,
.available_flag = MACHINE_AVAILABLE,
.gpio_acpi_handler = NULL,
.cpu = {
.package = CPU_PKG_386DX | CPU_PKG_486BL,
.block = CPU_BLOCK_NONE,
.min_bus = 0,
.max_bus = 0,
.min_voltage = 0,
.max_voltage = 0,
.min_multi = 0,
.max_multi = 0
},
.bus_flags = MACHINE_PS2_MCA,
.flags = MACHINE_VIDEO | MACHINE_APM,
.ram = {
.min = 4096,
.max = 16384,
.step = 4096
},
.nvrmask = 63,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* 386DX/486 machines */
/* Has AMIKey F KBC firmware. */

View File

@@ -101,3 +101,19 @@ mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t v
}
}
}
void
mca_add_to_slot(uint8_t (*read)(int addr, void* priv), void (*write)(int addr, uint8_t val, void* priv), uint8_t(*feedb)(void* priv), void (*reset)(void* priv), void* priv, int c)
{
if (mca_card_read[c] || mca_card_write[c])
{
//pclog("cannot add the device to slot %d\n", num);
return;
}
mca_card_read[c] = read;
mca_card_write[c] = write;
mca_card_feedb[c] = feedb;
mca_card_reset[c] = reset;
mca_priv[c] = priv;
return;
}

View File

@@ -26,6 +26,7 @@ extern "C" {
#include <86box/video.h>
#include <86box/vid_8514a_device.h>
#include <86box/vid_xga_device.h>
#include <86box/vid_ps55da2.h>
}
#include "qt_deviceconfig.hpp"
@@ -58,6 +59,7 @@ SettingsDisplay::save()
voodoo_enabled = ui->checkBoxVoodoo->isChecked() ? 1 : 0;
ibm8514_standalone_enabled = ui->checkBox8514->isChecked() ? 1 : 0;
xga_standalone_enabled = ui->checkBoxXga->isChecked() ? 1 : 0;
da2_standalone_enabled = ui->checkBoxDa2->isChecked() ? 1 : 0;
}
void
@@ -149,6 +151,12 @@ SettingsDisplay::on_pushButtonConfigureXga_clicked()
}
}
void
SettingsDisplay::on_pushButtonConfigureDa2_clicked()
{
DeviceConfig::ConfigureDevice(&ps55da2_device, 0, qobject_cast<Settings *>(Settings::settings));
}
void
SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index)
{
@@ -174,6 +182,7 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index)
bool machineSupports8514 = ((machineHasIsa16 || machineHasMca) && !videoCardHas8514);
bool machineSupportsXga = (((machineHasIsa16 && device_available(&xga_isa_device)) || (machineHasMca && device_available(&xga_device))) && !videoCardHasXga);
bool machineSupportsDa2 = machineHasMca && device_available(&ps55da2_device);
ui->checkBox8514->setEnabled(machineSupports8514);
ui->checkBox8514->setChecked(ibm8514_standalone_enabled && machineSupports8514);
@@ -183,7 +192,11 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index)
ui->checkBoxXga->setEnabled(machineSupportsXga);
ui->checkBoxXga->setChecked(xga_standalone_enabled && machineSupportsXga);
ui->checkBoxDa2->setEnabled(machineSupportsDa2);
ui->checkBoxDa2->setChecked(da2_standalone_enabled && machineSupportsDa2);
ui->pushButtonConfigureXga->setEnabled(ui->checkBoxXga->isEnabled() && ui->checkBoxXga->isChecked());
ui->pushButtonConfigureDa2->setEnabled(ui->checkBoxDa2->isEnabled() && ui->checkBoxDa2->isChecked());
int c = 2;
@@ -264,6 +277,12 @@ SettingsDisplay::on_checkBoxXga_stateChanged(int state)
ui->pushButtonConfigureXga->setEnabled(state == Qt::Checked);
}
void
SettingsDisplay::on_checkBoxDa2_stateChanged(int state)
{
ui->pushButtonConfigureDa2->setEnabled(state == Qt::Checked);
}
void
SettingsDisplay::on_comboBoxVideoSecondary_currentIndexChanged(int index)
{

View File

@@ -31,10 +31,12 @@ private slots:
void on_checkBoxVoodoo_stateChanged(int state);
void on_checkBox8514_stateChanged(int state);
void on_checkBoxXga_stateChanged(int state);
void on_checkBoxDa2_stateChanged(int state);
void on_comboBoxVideo_currentIndexChanged(int index);
void on_pushButtonConfigureVoodoo_clicked();
void on_pushButtonConfigure8514_clicked();
void on_pushButtonConfigureXga_clicked();
void on_pushButtonConfigureDa2_clicked();
void on_pushButtonConfigure_clicked();
private:

View File

@@ -120,6 +120,20 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="checkBoxDa2">
<property name="text">
<string>IBM PS/55 Display Adapter Graphics</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QPushButton" name="pushButtonConfigureDa2">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="pushButtonConfigureSecondary">
<property name="text">
@@ -140,7 +154,7 @@
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<item row="8" column="0" colspan="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>

View File

@@ -77,6 +77,7 @@ add_library(vid OBJECT
vid_att2xc498_ramdac.c
vid_xga.c
vid_bochs_vbe.c
vid_ps55da2.c
nv/nv_rivatimer.c
)

3260
src/video/vid_ps55da2.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -502,10 +502,25 @@ svga_in(uint16_t addr, void *priv)
ret = svga->attrregs[svga->attraddr];
break;
case 0x3c2:
if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e)
ret = 0;
else
ret = 0x10;
if (svga->cable_connected) {
if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e)
ret = 0;
else
ret = 0x10;
/* Monitor is not connected to the planar VGA if the PS/55 Display Adapter is installed. */
} else {
/*
The IBM PS/55 Display Adapter has own Monitor Type Detection bit in the different I/O port (I/O 3E0h, 3E1h).
When the monitor cable is connected to the Display Adapter, the port 3C2h returns the value as 'no cable connection'.
The POST of PS/55 has an extra code. If the monitor is not detected on the planar VGA,
it reads the POS data in NVRAM set by the reference diskette, and writes the BIOS Data Area (Mem 487h, 489h).
MONCHK.EXE in the reference diskette uses both I/O ports to determine the monitor type, updates the NVRAM and BDA.
*/
if (svga->vgapal[0].r >= 10 || svga->vgapal[0].g >= 10 || svga->vgapal[0].b >= 10)
ret = 0;
else
ret = 0x10;
}
break;
case 0x3c3:
ret = 0x01;
@@ -1526,6 +1541,8 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize,
svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 32;
svga->translate_address = NULL;
svga->cable_connected = 1;
svga->ksc5601_english_font_type = 0;
/* TODO: Move DEVICE_MCA to 16-bit once the device flags have been appropriately corrected. */

View File

@@ -369,6 +369,8 @@ video_post_reset(void)
if (xga_standalone_enabled)
xga_device_add();
if (da2_standalone_enabled)
da2_device_add();
/* Reset the graphics card (or do nothing if it was already done
by the machine's init function). */
video_reset(gfxcard[0]);

View File

@@ -104,6 +104,37 @@ vga_in(uint16_t addr, void *priv)
return temp;
}
void vga_disable(void* p)
{
vga_t* vga = (vga_t*)p;
svga_t* svga = &vga->svga;
io_removehandler(0x03a0, 0x0040, vga_in, NULL, NULL, vga_out, NULL, NULL, vga);
mem_mapping_disable(&svga->mapping);
svga->vga_enabled = 0;
}
void vga_enable(void* p)
{
vga_t* vga = (vga_t*)p;
svga_t* svga = &vga->svga;
io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga);
if (!(svga->miscout & 1))
io_sethandler(0x03a0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga);
mem_mapping_enable(&svga->mapping);
svga->vga_enabled = 1;
}
int vga_isenabled(void* p)
{
vga_t* vga = (vga_t*)p;
svga_t* svga = &vga->svga;
return svga->vga_enabled;
}
static void *
vga_init(const device_t *info)
{
@@ -150,6 +181,7 @@ ps1vga_init(const device_t *info)
vga->svga.bpp = 8;
vga->svga.miscout = 1;
vga->svga.vga_enabled = 1;
return vga;
}