はじめに
MSXPiはRaspberry piを搭載したMSX用カートリッジで、MSXからRaspberry pi上のLinuxにアクセスしたり、さらには、Raspberry piを介してインターネット上のサービスを利用できるようになります。
実際にMSXPiを組み立てましたが、ファームウェアの書き込みなどの作業が終わっていません。
組み立てと並行して、エミュレーター上でMSXPiの動作を確認し、自分用のサービスを導入していきたいと計画しています。
この記事では、MSXPiの動作するopenMSXをビルドする方法を紹介します。
openMSX
openMSXはMSXのエミュレータで、本体のBIOSや周辺機器のファームウェアを指定することで、様々な周辺機器を搭載したMSXをエミュレートすることができます。
接続するデバイスの情報をopenMSXの含めてビルドすることで、デバイスの機能を利用することが可能です。
Raspberry pi OS上でパッケージ管理ソフトを使ってインストールしたopenMSXは、MSXPiを認識しませんので、ソースファイルからビルドする必要があります。
Linuxマシン上でのビルド
Raspberry pi 4上で利用するために、ソースファイルからビルドしました。
使用するソースファイルはMSXPi対応のものを使用します。
「openmsx-21.0-7-MSXPi」を使用しました。
始めに必要なライブラリをインストールします。
sudo apt install libglew-dev libogg-dev libtheora-dev libvorbis-dev libsdl2-ttf-dev tcl-dev libpng-dev libsdl2-dev
openMSXのディレクトリで
./configure
とすると、環境構築ができているか確認できます。
例えば、以下のような表示です。
Using Python: python3
Probing target system...
Creating derived/aarch64-linux-opt/config/probed_defs.mk...
Up to date: derived/aarch64-linux-opt/config/systemfuncs.hh
Found libraries:
ALSA: version 1.2.8
FreeType: version
GLEW: version unknown
libogg: version unknown
libpng: version 1.6.39
libtheora: version unknown
libvorbis: version unknown
OpenGL: version 4.6
SDL2: version 2.26.5
SDL2_ttf: version 2.20.1
Tcl: version 8.6.13
zlib: version 1.2.13
Components overview:
Emulation core: yes
GL renderer: yes
Laserdisc: yes
ALSA MIDI: yes
Customisable options:
Install to /opt/openMSX
(you can edit these in build/custom.mk)
All required and optional components can be built.
If the detected libraries differ from what you think is installed on this system, please check the log file: derived/aarch64-linux-opt/config/probe.log
##ソースファイルの修正
使用するgccのバージョンが9以上の場合、ソースファイルの修正が必要です。
修正箇所は、この記事下のパッチファイルを参照してください。
ソースファイルの修正後にビルドするしてインストールすることで、MSXPiをデバイスとして認識するopenMSXを起動できるようになります。
おわりに
MSXPiに対応したopenMSXのソースファイルを修正して、Raspberry piでの動作に成功しました。
MSXPiを動作させる場合、他の周辺機器と同様、ROMファイルの「msxpibios.ro」をopenMSXのshare->systemroms内に、設定ファイルの「MSXPi.xml」をopenMSXのshare->extensionsに保存します。
MSXの起動に成功したら、raspberry pi側で動作するサーバーの設定を行います。
付録
今回使用したパッチファイルです。
「static constexpr」を「static const」に修正します。
--- a/src/cassette/CassettePlayer.cc
+++ b/src/cassette/CassettePlayer.cc
@@ -215,16 +215,16 @@
// for instance)
" after time 0.2 \"type [lindex $args 0]\"\n"
- " set next [lrange $args 1 end]\n" // Note: this is a list of lists
+ " set next [lrange $args 1 end]\n"
" if {[llength $next] == 0} return\n"
// H_READ is used by some firmwares; we need to hook the
// H_MAIN that happens immediately after H_READ.
" set cmd \"openmsx::auto_run_cb $next\"\n"
" set openmsx::auto_run_bp [debug set_bp ", H_MAIN, " 1 \"$cmd\"]\n"
- " }\n" // auto_run_cb
+ " }\n"
" if {[info exists auto_run_bp]} {debug remove_bp $auto_run_bp\n}\n"
" set auto_run_bp [debug set_bp ", H_READ, " 1 {\n"
" openmsx::auto_run_cb {{}} ", instr1, ' ', instr2, "\n"
--- a/src/config/HardwareConfig.cc
+++ b/src/config/HardwareConfig.cc
@@ -20,7 +20,7 @@
#include <algorithm>
#include <array>
#include <cassert>
-//#include <iostream>
+#include <iostream>
#include <memory>
#include <version> // for _LIBCPP_VERSION
--- a/src/DebugDevice.cc
+++ b/src/DebugDevice.cc
@@ -12,7 +12,7 @@
#include "strCat.hh"
#include <iomanip>
-//#include <iostream>
+#include <iostream>
namespace openmsx {
--- a/src/fdc/DriveMultiplexer.cc
+++ b/src/fdc/DriveMultiplexer.cc
@@ -131,7 +131,7 @@
}
-static constexpr std::initializer_list<enum_string<DriveMultiplexer::Drive>> driveNumInfo = {
+static const std::initializer_list<enum_string<DriveMultiplexer::Drive>> driveNumInfo = {
{ "A", DriveMultiplexer::Drive::A },
{ "B", DriveMultiplexer::Drive::B },
{ "C", DriveMultiplexer::Drive::C },
--- a/src/fdc/NowindHost.cc
+++ b/src/fdc/NowindHost.cc
@@ -16,7 +16,7 @@
#include <cctype>
#include <cstdarg>
#include <cstdio>
-//#include <ctime>
+#include <ctime>
#include <fstream>
#include <memory>
#include <ranges>
--- a/src/fdc/TC8566AF.cc
+++ b/src/fdc/TC8566AF.cc
@@ -480,7 +480,7 @@
}
-static constexpr std::initializer_list<enum_string<TC8566AF::Command>> commandInfo = {
+static const std::initializer_list<enum_string<TC8566AF::Command>> commandInfo = {
{ "UNKNOWN", TC8566AF::Command::UNKNOWN },
{ "READ_DATA", TC8566AF::Command::READ_DATA },
{ "WRITE_DATA", TC8566AF::Command::WRITE_DATA },
@@ -499,7 +499,7 @@
};
SERIALIZE_ENUM(TC8566AF::Command, commandInfo);
-static constexpr std::initializer_list<enum_string<TC8566AF::Phase>> phaseInfo = {
+static const std::initializer_list<enum_string<TC8566AF::Phase>> phaseInfo = {
{ "IDLE", TC8566AF::Phase::IDLE },
{ "COMMAND", TC8566AF::Phase::COMMAND },
{ "DATATRANSFER", TC8566AF::Phase::DATA_TRANSFER },
@@ -507,7 +507,7 @@
};
SERIALIZE_ENUM(TC8566AF::Phase, phaseInfo);
-static constexpr std::initializer_list<enum_string<TC8566AF::Seek>> seekInfo = {
+static const std::initializer_list<enum_string<TC8566AF::Seek>> seekInfo = {
{ "IDLE", TC8566AF::Seek::IDLE },
{ "SEEK", TC8566AF::Seek::SEEK },
{ "RECALIBRATE", TC8566AF::Seek::RECALIBRATE }
--- a/src/fdc/WD2793.cc
+++ b/src/fdc/WD2793.cc
@@ -520,7 +520,7 @@
}
-static constexpr std::initializer_list<enum_string<WD2793::FSM>> fsmStateInfo = {
+static const std::initializer_list<enum_string<WD2793::FSM>> fsmStateInfo = {
{ "NONE", WD2793::FSM::NONE },
{ "SEEK", WD2793::FSM::SEEK },
{ "TYPE2_LOADED", WD2793::FSM::TYPE2_LOADED },
--- a/src/ide/MB89352.cc
+++ b/src/ide/MB89352.cc
@@ -601,7 +601,7 @@
// TODO duplicated in WD33C93.cc
-static constexpr std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
+static const std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
{ "UNDEFINED", SCSI::Phase::UNDEFINED },
{ "BUS_FREE", SCSI::Phase::BUS_FREE },
{ "ARBITRATION", SCSI::Phase::ARBITRATION },
--- a/src/ide/WD33C93.cc
+++ b/src/ide/WD33C93.cc
@@ -401,7 +401,7 @@
}
-static constexpr std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
+static const std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
{ "UNDEFINED", SCSI::Phase::UNDEFINED },
{ "BUS_FREE", SCSI::Phase::BUS_FREE },
{ "ARBITRATION", SCSI::Phase::ARBITRATION },
--- a/src/laserdisc/LaserdiscPlayer.cc
+++ b/src/laserdisc/LaserdiscPlayer.cc
@@ -22,7 +22,7 @@
#include <cstdint>
#include <cstdlib>
#include <iostream>
-//#include <memory>
+#include <memory>
namespace openmsx {
--- a/src/memory/AmdFlash.cc
+++ b/src/memory/AmdFlash.cc
@@ -770,7 +770,7 @@
}
}
-static constexpr std::initializer_list<enum_string<AmdFlash::State>> stateInfo = {
+static const std::initializer_list<enum_string<AmdFlash::State>> stateInfo = {
{ "IDLE", AmdFlash::State::READ }, // back compat with v3
{ "IDENT", AmdFlash::State::AUTOSELECT }, // back compat with v3
{ "PRGERR", AmdFlash::State::ERROR }, // back compat with v3
--- a/src/memory/EEPROM_93C46.cc
+++ b/src/memory/EEPROM_93C46.cc
@@ -208,7 +208,7 @@
}
}
-static constexpr std::initializer_list<enum_string<EEPROM_93C46::State>> stateInfo = {
+static const std::initializer_list<enum_string<EEPROM_93C46::State>> stateInfo = {
{ "IN_RESET", EEPROM_93C46::State::IN_RESET },
{ "WAIT_FOR_START_BIT", EEPROM_93C46::State::WAIT_FOR_START_BIT },
{ "WAIT_FOR_COMMAND", EEPROM_93C46::State::WAIT_FOR_COMMAND },
--- a/src/memory/SdCard.cc
+++ b/src/memory/SdCard.cc
@@ -278,7 +278,7 @@
}
}
-static const std::initializer_list<enum_string<SdCard::Mode>> modeInfo = {
+static const std::initializer_list<enum_string<SdCard::Mode>> modeInfo = {
{ "COMMAND", SdCard::Mode::COMMAND },
{ "READ", SdCard::Mode::READ },
{ "MULTI_READ", SdCard::Mode::MULTI_READ },
--- a/src/serial/I8251.cc
+++ b/src/serial/I8251.cc
@@ -241,7 +241,7 @@
}
-static const std::initializer_list<enum_string<SerialDataInterface::DataBits>> dataBitsInfo = {
+static const std::initializer_list<enum_string<SerialDataInterface::DataBits>> dataBitsInfo = {
{ "5", SerialDataInterface::DataBits::D5 },
{ "6", SerialDataInterface::DataBits::D6 },
{ "7", SerialDataInterface::DataBits::D7 },
@@ -249,7 +249,7 @@
};
SERIALIZE_ENUM(SerialDataInterface::DataBits, dataBitsInfo);
-static const std::initializer_list<enum_string<SerialDataInterface::StopBits>> stopBitsInfo = {
+static const std::initializer_list<enum_string<SerialDataInterface::StopBits>> stopBitsInfo = {
{ "INVALID", SerialDataInterface::StopBits::INV },
{ "1", SerialDataInterface::StopBits::S1 },
{ "1.5", SerialDataInterface::StopBits::S1_5 },
@@ -257,14 +257,14 @@
};
SERIALIZE_ENUM(SerialDataInterface::StopBits, stopBitsInfo);
-static const std::initializer_list<enum_string<SerialDataInterface::Parity>> parityBitInfo = {
+static const std::initializer_list<enum_string<SerialDataInterface::Parity>> parityBitInfo = {
{ "EVEN", SerialDataInterface::Parity::EVEN },
{ "ODD", SerialDataInterface::Parity::ODD }
};
SERIALIZE_ENUM(SerialDataInterface::Parity, parityBitInfo);
-static const std::initializer_list<enum_string<I8251::CmdPhase>> cmdFazeInfo = {
+static const std::initializer_list<enum_string<I8251::CmdPhase>> cmdFazeInfo = {
{ "MODE", I8251::CmdPhase::MODE },
{ "SYNC1", I8251::CmdPhase::SYNC1 },
{ "SYNC2", I8251::CmdPhase::SYNC2 },
--- a/src/serial/I8254.cc
+++ b/src/serial/I8254.cc
@@ -311,7 +311,7 @@
}
-static const std::initializer_list<enum_string<Counter::ByteOrder>> byteOrderInfo = {
+static const std::initializer_list<enum_string<Counter::ByteOrder>> byteOrderInfo = {
{ "LOW", Counter::ByteOrder::LOW },
{ "HIGH", Counter::ByteOrder::HIGH }
};
--- a/src/sound/SCC.cc
+++ b/src/sound/SCC.cc
@@ -430,7 +430,7 @@
}
-static const std::initializer_list<enum_string<SCC::Mode>> chipModeInfo = {
+static constexpr std::initializer_list<enum_string<SCC::Mode>> chipModeInfo = {
{ "Real", SCC::Mode::Real },
{ "Compatible", SCC::Mode::Compatible },
{ "Plus", SCC::Mode::Plus },
--- a/src/sound/VLM5030.cc
+++ b/src/sound/VLM5030.cc
@@ -510,7 +510,7 @@
unregisterSound();
}
-static const std::initializer_list<enum_string<VLM5030::Phase>> phaseInfo = {
+static constexpr std::initializer_list<enum_string<VLM5030::Phase>> phaseInfo = {
{ "RESET", VLM5030::Phase::RESET },
{ "IDLE", VLM5030::Phase::IDLE },
{ "SETUP", VLM5030::Phase::SETUP },
--- a/src/sound/Y8950.cc
+++ b/src/sound/Y8950.cc
@@ -20,7 +20,7 @@
#include <algorithm>
#include <array>
#include <cmath>
-//#include <iostream>
+#include <iostream>
namespace openmsx {
--- a/src/sound/YM2413Burczynski.cc
+++ b/src/sound/YM2413Burczynski.cc
@@ -31,7 +31,7 @@
#include <algorithm>
#include <array>
#include <cstdint>
-//#include <iostream>
+#include <iostream>
#include <utility>
namespace openmsx {
--- a/src/sound/YM2413NukeYKT.cc
+++ b/src/sound/YM2413NukeYKT.cc
@@ -34,7 +34,7 @@
#include <algorithm>
#include <array>
#include <cstring>
-
+#include <iostream>
namespace openmsx {
namespace YM2413NukeYKT {
--- a/src/sound/YM2413Okazaki.cc
+++ b/src/sound/YM2413Okazaki.cc
@@ -19,7 +19,7 @@
#include <algorithm>
#include <array>
#include <cassert>
-//#include <iostream>
+#include <iostream>
namespace openmsx {
namespace YM2413Okazaki {
--- a/src/sound/YMF262.cc
+++ b/src/sound/YMF262.cc
@@ -41,7 +41,7 @@
#include <algorithm>
#include <array>
#include <cmath>
-//# <iostream>
+#include <iostream>
namespace openmsx {
--- a/src/video/v9990/V9990.cc
+++ b/src/video/v9990/V9990.cc
@@ -520,7 +520,7 @@
scheduleHscan(time);
}
-static const std::initializer_list<enum_string<V9990DisplayMode>> displayModeInfo = {
+static constexpr std::initializer_list<enum_string<V9990DisplayMode>> displayModeInfo = {
{ "P1", V9990DisplayMode::P1 }, { "P2", V9990DisplayMode::P2 },
{ "B0", V9990DisplayMode::B0 }, { "B1", V9990DisplayMode::B1 },
{ "B2", V9990DisplayMode::B2 }, { "B3", V9990DisplayMode::B3 },