--- nono/vm/x68kkbd.cpp 2026/04/29 17:04:30 1.1.1.2 +++ nono/vm/x68kkbd.cpp 2026/04/29 17:04:36 1.1.1.4 @@ -1,21 +1,27 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // +// キーボードは MFP の USART に繋がっている。 +// MFP USART の RR 線 (Receiver Ready) は受信可能なら 'H'、受信中は 'L' に +// なっている。キーボードは RR が 'H' の時だけデータを送信する。 +// また、システムポート#4 の KEY CTRL = 0 (キーデータ送信不可) はこの RR を +// 'L' に落とす論理回路になっている。 +// キーボードからの送信は 2400bps、ストップビット1、パリティなしなので、 +// 1バイトの送信に 3.75 msec かかる。 +// 実装では、キーボードは MFP の RR が 'H' なら MFP にキーデータを送信。 +// MFP 側で RR を 'L' にして 3.75 msec をイベントで待った後、キーを処理して +// RR を 'H' に戻すことにする。 + #include "x68kkbd.h" #include "mfp.h" // コンストラクタ X68030Keyboard::X68030Keyboard() { - // MFP へキー入力を通知するイベント -#if 0 - event.dev = gMFP; - event.func = (DeviceCallback_t)&MFPDevice::Rx; - event.time = 0; - event.SetName("KeyInput"); -#endif + led.resize(7); } // デストラクタ @@ -23,6 +29,19 @@ X68030Keyboard::~X68030Keyboard() { } +// 本体リセットスイッチによるリセット +void +X68030Keyboard::ResetHard() +{ + rept_delay = 500; + rept_time = 110; + + for (int i = 0; i < led.size(); i++) { + led[i] = false; + } + led_darkness = 0; +} + // キーを押した void X68030Keyboard::MakeKey(uint keycode) @@ -37,11 +56,10 @@ X68030Keyboard::MakeKey(uint keycode) return; } - putlog(1, "MakeKey %d(%s)", x68kkey, keyname[x68kkey]); + // LED は MPU 側から点灯/消灯指示が来るのでここでは何もしなくてよい - // MFP に通知 - event.code = x68kkey; -// gScheduler->AddEvent(&event); + putlog(1, "MakeKey %d(%s)", x68kkey, keyname[x68kkey]); + SendKey(x68kkey); } // キーを離した @@ -59,10 +77,7 @@ X68030Keyboard::BreakKey(uint keycode) } putlog(2, "BreakKey %d(%s)", x68kkey, keyname[x68kkey]); - - // MFP に通知 - event.code = x68kkey | 0x80; -// gScheduler->AddEvent(&event); + SendKey(x68kkey | 0x80); } // マウス入力 @@ -71,6 +86,77 @@ X68030Keyboard::MouseInput(int x, int y, { } +// キーデータを送信 +void +X68030Keyboard::SendKey(uint data) +{ + if (gMFP->IsRR()) { + gMFP->Rx(data); + } +} + +// ホストからの制御 +void +X68030Keyboard::Command(uint32 data) +{ + if (data < 0x40) { + // $00-$3f TV 制御 + // (実装不要) + putlog(2, "Command TV 制御 $%02x", (data & 0x1f)); + + } else if (data < 0x48) { + // $40-$47 MSCTRL 信号制御 + // こいつは頻度が高いのでログレベルを上げておく + putlog(3, "Command MSCTRL 制御 %d", (data & 1)); + + } else if (data < 0x50) { + // $48-$4f キーデータ送出許可 + putlog(1, "Command キー送出許可 %d (未実装)", (data & 1)); + + } else if (data < 0x54) { + // $50-$53 ディスプレイ制御モード選択 + // (実装不要) + putlog(2, "Command ディスプレイ制御 X68000モード %d", (data & 1)); + + } else if (data < 0x58) { + // $54-$57 LED 明るさ選択 + // 0 が明るく 3 が暗いので、明るさというより暗さ。 + led_darkness = (data & 3); + putlog(1, "Command LED 明るさ %d", led_darkness); + + } else if (data < 0x5c) { + // $58-$5b 本体からのディスプレイ制御許可 + // (実装不要) + putlog(2, "Command 本体からディスプレイ制御 %d", (data & 1)); + + } else if (data < 0x60) { + // $5c-$5f OPT.2 によるディスプレイ制御許可 + // (実装不要) + putlog(2, "Command OPT2からディスプレイ制御 %d", (data & 1)); + + } else if (data < 0x70) { + // $60-$6f リピートまでの時間 + rept_delay = 200 + (data & 15) * 100; + putlog(1, "Command Repeat Delay %d (%d msec)", (data & 15), rept_delay); + + } else if (data < 0x80) { + // $70-$7f リピート間隔 + rept_time = 30 + (data & 15) * (data & 15) * 5; + putlog(1, "Command Repeat time %d (%d msec)", (data & 15), rept_time); + + } else { + // $80-$ff LED 制御 + data &= 0x7f; + putlog(1, "Command LED 制御 $%02x", data); + uint32 b = 0x01; + for (int i = 0; i < led.size(); i++) { + // data は %0 で点灯、led[] は true で点灯 + led[i] = ((data & b) == 0); + b <<= 1; + } + } +} + // 共通キーコードを X680x0 キーコードに変換して返す。 // X680x0 キーがなければ NoKey を返す。 uint @@ -91,7 +177,7 @@ X68030Keyboard::keycode2x68kkey_table[13 X68kKey_BREAK, // [01] X68kKey_COPY, // [02] X68kKey_romaji, // [03] - X68kKey_kana, // [04] + X68kKey_code, // [04] X68kKey_kigou, // [05] X68kKey_touroku, // [06] X68kKey_HELP, // [07]