電子趣味の部屋

電子系のガジェットやアプリ開発等の趣味の話題を書いてます

Raspberry Pi で X68000 (Raispberry Pi OS Bullseye以降)

Raspberry Pi 5 やuConsole Kit RPI-CM4 LiteでX68000のエミュレータをインストールする場合に、過去に書いた方法だと64bitのOSではmakeできなかったので、新しく調べた方法を書きます。
今回の方法は64bit/32bit両方のBullseye以降のデスクトップ環境で動作します。
コンソール環境で実行したい場合は、『Raspberry pi 400で遊ぶ X68000編』を参考にしてください。(要: Raspberry Pi OS Buster


前準備

gitをインストールします

sudo apt update
sudo apt install git

SDL2をインストールします

sudo apt install libsdl2-dev

圧縮ファイルの展開のため、unzipとlhasaと7zをインストールします。

sudo apt install unzip lhasa p7zip-full

px68kの構築

px68kはユーザのホーム以下のpx68kディレクトリ(~/px68k)へインストールすることを想定して進めます

cd
git clone https://github.com/TurtleBazooka/px68k.git
cd px68k
make

BIOSファイル配置

実行にはiplrom.datとcgrom.datが必要。
色々なサイトを参考にX68000 LIBRARYとXM6 Pro-68kから拝借

cd
mkdir ~/.keropi
wget http://www.retropc.net/x68000/software/sharp/x68bios/X68BIOSE.LZH
lhasa x X68BIOSE.LZH iplrom.dat
mv iplrom.dat ~/.keropi/iplrom.dat
chmod 644 ~/.keropi/iplrom.dat
wget https://mijet.eludevisibility.org/XM6%20Pro-68k/XM6%20Pro-68k%20DLL%20Package.7z
7z x "XM6 Pro-68k DLL Package.7z" CGROM.DAT
mv CGROM.DAT ~/.keropi/cgrom.dat
chmod 644 ~/.keropi/cgrom.dat

動作確認

X68000 LIBRARYからHuman68kのディスクイメージを取得して起動してみます。
起動はディレクトリ~/px68kに作られたpx68k.sdl2を実行します

cd
wget http://www.retropc.net/x68000/software/sharp/human302/HUMN302I.LZH
lhasa x HUMN302I.LZH human302.xdf
chmod 644 human302.xdf
px68k/px68k.sdl2 human302.xdf

[F11]で全画面、ウィンドウ表示を切り替えられます。
[F12]でメニューを開いてディスクの入れ替えや、リセット、終了を行うことができます。

HiMeLE Quieter4C ファンレスミニPC アイドル時3W

いつでもOSを入れ替えられる実験環境が必要になり、今回は HiMeLE Quieter4C を購入しました。



Intel N100搭載のファンレスミニPCです。
サイズが131x81x18.3mmの非常に小型、薄型のPCです。

初めからN100をターゲットにして探してたのですが、この機種にしたのはサイズ以外にもDP出力と給電に対応しているUSB Type-Cのポートがあることです。
対応しているディスプレイならとケーブル1本で接続できます。
他の機種も対応してるものがあるのですが、なぜか本体前面にあるポートのみで、背面のポートでできるのはほどんどありませんでした。
経験上、前面からモニターに接続するものは色々と煩わしいです。

Windowsの初期設定を終わらしてしばらく放置後にアイドル状態の消費電力を見ると3W前後でした。

chromeでWebを見てる時やオフィス関連を捜査すると10W前後で動作します。
少し重いときは10W後半まで行きますが、今回はWindowsメインで使うことは考えてないのであまり試してませんが、20Wを超えないくらいで動作してました。
ゲーム等でGPUの動作が多くなると20Wを超えると思います。

発熱はありますが、初日に8時間ほど連続で動作してましたが、クロック数の低下や熱暴走等の問題は特にありませんでした。
ケースの上部が金属でここに熱を逃して放熱するため、結構熱くはなりますが触れないほどではありません。
常時稼働や高負荷のゲームが目的の場合はファンレスの機種は選ばない方が良いと思います。

ubuntuを入れるためSSDを交換しようとしたらスロットには何もない状態でした。

BIOSで確認するとeMMCのディスクが基盤に直付けされてるようでした。

レビューサイト等でディスクアクセスの速度を計測した結果を見ると220MB/sのものが使用されているようです。

NVMeのSSDにUbuntu22.04をインストールしてみました。

ドライバ等も特に追加でインストールする必要もなく動作してます。
消費電力を計測したところ、いつもはアイドル時はWindowsより1,2W低いのに、今回は4Wになってしまいました。
これはeMMCとNVMeのSSDの消費電力の差だと思われます。

Intel N100はTDP6Wとは言え結構発熱があるので、長時間や高負荷の使用には不安がありますが、
Webや動画やオフィスソフト等の普段使いで使用しないときは電源を切るような使い方をする場合は手軽でお勧めできる機種だと思います。

uConsole Kit RPI-CM4 Lite 手に入れました

前にDevTermを入手したことを書きましたが、今回はuConsole Kit RPI-CM4 Lite 手に入れました。

今回はRaspberryPi CM4 Liteのモジュールを使ったバージョンを注文しましたが、他にはオリジナルのARMのモジュールやRISC-Vのモジュールのバージョンもあります。

2023年4月に注文して2024年2月に届きました。
下の写真のようにパーツで届き、自分で組み立てます。

パーツ数は多くないので、比較的簡単に組み立てられます。

完成後はこんな感じです。

OSはRaspberry Pi OSをカスタマイズしたものです。

今回の主な目的はPICO-8に適した環境を作りたいと思ってました。
www.lexaloffle.com

実用は考えてなく、BASICやPython等の言語やコンソールメインで使用してポケコンみたいな感覚で遊びたいですね。

DevTermは画面サイズが特殊で横に長すぎていまいち使いにくいので手放してしまいましたが、uConsoleは普通のHDワイド(720p)のサイズです。
こちらの方が使いやすく、コンパクトなのでこちらは長く使えそうだともいました。

フロンティアユニバースの話

今回はフロンティアユニバースの話です

たぶんPC98で一番遊んだゲームです。今でいう4X SFストラテジーゲームです。
ここ数年度々遊んでいるStellarisというゲームがsteamにあるのですが、このシステムや思想を30年前に実現しているようなゲームです。

最近ふと思い出してやろうと思ったのですがあまり中古で見かけず、中古屋やオークション等をチェックして2か月くらいかけてやっと入手できました。

テトリス付きのパッケージですが、テトリスはありませんでした。

当時ははレジオナルパワーやインペリアルフォースといった同じようなSF ストラテジーゲームがあったのですが、どちらかというと戦闘メインで内政や外交の要素は少ないものでした。フロンティアユニバースは内政や外交の駆け引きも重要で一番好きなゲームでした。

入手してからつい何時間も遊んでしまい、今でも通用する面白さのあるゲームだと思いました。

電子工作感覚でプログラミングできる ConnectJS

電子工作やFPGA等の部品同士を配線していくような感じでプログラミングできるJavascriptのライブラリを作りました。
ドキュメント等は簡易的なものしかありませんが、とりあえずGithubで公開してます。
github.com

モジュールさえ用意すれば接続していくだけで色々できるので、将来的にはGUIでブロックをつなげるようにプログラミングできればと考えています。

詳細な説明代わりに実例に沿って説明します。
LED、4bitシフトレジスタ、タイマーに見立てたモジュールを作り、LEDを1秒毎に順番に光らせるプログラムを作ります。

上の画像のようなHTMLのテーブルのセルをLEDに見立てて、左から順番に光らせて一番左の次はまた一番右に戻ります。
回路図でイメージすると、下の図のようになります。

ライブラリ本体(connectjs.js)はGithub内にあります。
サンプルソースを動作させるのに必要になります。
https://github.com/uosoft/ConnectJS/blob/main/src/connectjs.js

モジュール作成

まず、各モジュールを作ります。

LED

ファイル名 : LEDModule.js

// LEDModule
// モジュールはConnectModuleクラスを継承する
class LEDModule extends ConnectModule {
	//コンストラクタ
	constructor(led) {
		super();  //継承先でコンストラクタを定義する場合は親のコンストラクタを初めに呼ぶ
		this.led = document.getElementById(led);
	}
	// セットアップ
	setup() {
		this.addPort("led", true, false);  //ポート led1 を追加 (ポート名, IN許可, OUT許可)
	}
	// ポート led に値がセットされたときに動作する setter
	set_led(value) {
		if (value == 1) {
			this.led.style.backgroundColor = "#ff0000";
		} else {
			this.led.style.backgroundColor = "#ffffff";
		}
	}
}
4bitシフトレジスタ

ファイル名 : ShiftModule.js

// 4bitShiftModule
// モジュールはConnectModuleクラスを継承する
class ShiftModule extends ConnectModule {
	// セットアップ
	setup() {
		this.isCountup = false;
		this.addPort("si", true, false);  //ポート si を追加 (ポート名, IN許可, OUT許可)
		this.addPort("ck", true, false);  //ポート clock を追加 (ポート名, IN許可, OUT許可)
		this.addPort("qa", false, true);  //ポート qa を追加 (ポート名, IN許可, OUT許可)
		this.addPort("qb", false, true);  //ポート qb を追加 (ポート名, IN許可, OUT許可)
		this.addPort("qc", false, true);  //ポート qc を追加 (ポート名, IN許可, OUT許可)
		this.addPort("qd", false, true);  //ポート qd を追加 (ポート名, IN許可, OUT許可)
		this.port.qa = 0;
		this.port.qb = 0;
		this.port.qc = 0;
		this.port.qd = 0;
	}
	
	// ポート ck に値がセットされたときに動作する setter
	set_ck(value) {
		if (value) {
			if (!this.isCountup) {
				var si = this.port.si;
				if (si != 1) {
					si = 0
				}
				this.port.qd = this.port.qc;
				this.port.qc = this.port.qb;
				this.port.qb = this.port.qa;
				this.port.qa = si;
			}
			this.port.isCountup = true;
		} else {
			this.port.isCountup = false;
		}
	}
}
タイマー

ファイル名 : TimerModule..js

// TimerModule
class TimerModule extends ConnectModule {
	// セットアップ
	setup() {
		this.t = null;
		this.addPort("clockout", false, true);  //ポート clockout を追加 (ポート名, IN許可, OUT許可)
		this.addPort("interval", true, false);  //ポート interval を追加 (ポート名, IN許可, OUT許可)
	}
	// ポート interval に値がセットされたときに動作する setter
	set_interval(value) {
		if (this.t != null) {
			clearTimeout(this.t);
		}
		if (value != 0) {
			var self = this;
			self.t = setTimeout(function() {
				self.port.clockout = true;
				self.port.clockout = false;
				self.port.interval = value;
			}, value);
		}
	}
}

HTML

LED表示部分

HTMLのbodyにLEDに見立てたテーブルを作ります。

<table border=1>
	<tr>
		<td id="led1">&nbsp;&nbsp;&nbsp;&nbsp;</td>
		<td id="led2">&nbsp;&nbsp;&nbsp;&nbsp;</td>
		<td id="led3">&nbsp;&nbsp;&nbsp;&nbsp;</td>
		<td id="led4">&nbsp;&nbsp;&nbsp;&nbsp;</td>
	</tr>
</table>
モジュールを接続する処理

下のような処理をbodyのonload辺りに実行します。

// コネクトマネージャ
var cm = new ConnectManager();
// モジュール4bitShiftModule (シフトレジスタ的なもの)
var shift = new ShiftModule();
// モジュールTimerModule (オシレータ的なもの)
var timer = new TimerModule();
// モジュールLEDModule (LED的なもの)
var led1 = new LEDModule("led1");
var led2 = new LEDModule("led2");
var led3 = new LEDModule("led3");
var led4 = new LEDModule("led4");

// モジュールのポートを接続する
// (モジュール1, モジュール1のポート, モジュール2, モジュール2のポート)
cm.connect(shift, "ck", timer, "clockout");
cm.connect(shift, "qa", led1, "led");
cm.connect(shift, "qb", led2, "led");
cm.connect(shift, "qc", led3, "led");
cm.connect(shift, "qd", led4, "led");
cm.connect(shift, "qd", shift, "si");

// 各ポートの初期化処理
shift.port.si = 1;
shift.port.ck = true;
shift.port.ck = false;
timer.port.interval = 1000;
HTMLファイル全文

一通り動作するHTML全文です。
ファイル名 : led_shifter.html

<!DOCTYPE html>
<html>
	<head>
	<title>Connect JS Sample  -- LED Shifter --</title> 
	<meta name="viewport" content="width=device-width, initial-scale=1">
	
	<script type='text/javascript' src='connectjs.js'></script>
	<script type='text/javascript' src='ShiftModule.js'></script>
	<script type='text/javascript' src='TimerModule..js'></script>
	<script type='text/javascript' src='LEDModule.js'></script>

	<script type="text/javascript">
	
	function start() {
		
		// コネクトマネージャ
		var cm = new ConnectManager();
		// モジュール4bitShiftModule (シフトレジスタ的なもの)
		var shift = new ShiftModule();
		// モジュールTimerModule (オシレータ的なもの)
		var timer = new TimerModule();
		// モジュールLEDModule (LED的なもの)
		var led1 = new LEDModule("led1");
		var led2 = new LEDModule("led2");
		var led3 = new LEDModule("led3");
		var led4 = new LEDModule("led4");
		
		// モジュールのポートを接続する
		// (モジュール1, モジュール1のポート, モジュール2, モジュール2のポート)
		cm.connect(shift, "ck", timer, "clockout");
		cm.connect(shift, "qa", led1, "led");
		cm.connect(shift, "qb", led2, "led");
		cm.connect(shift, "qc", led3, "led");
		cm.connect(shift, "qd", led4, "led");
		cm.connect(shift, "qd", shift, "si");
		
		// 各ポートの初期化処理
		shift.port.si = 1;
		shift.port.ck = true;
		shift.port.ck = false;
		timer.port.interval = 1000;
	}
	
	</script>

</head>
<body onload="start();">
<table border=1>
	<tr>
		<td id="led1">&nbsp;&nbsp;&nbsp;&nbsp;</td>
		<td id="led2">&nbsp;&nbsp;&nbsp;&nbsp;</td>
		<td id="led3">&nbsp;&nbsp;&nbsp;&nbsp;</td>
		<td id="led4">&nbsp;&nbsp;&nbsp;&nbsp;</td>
	</tr>
</table>
</body>
</html>

最近遊んで面白かったインディーズ系ゲーム (Steam)

年末年始の休みからSteamのセール等で面白そうなものを買ったり、過去に買ったものの積みげーだったゲームを色々遊んでみました。
そこで特に面白かったゲームをいくつか紹介します。

Palworld / パルワールド

最近話題になってますね。
結構面白く、Diablo4のシーズン3を休んで遊んでます。
システム的にも他のサバイバルゲームよりは難易度は低く遊びやすいと思います。

Vampire Survivors

PCレビュー系のYoutubeチャンネルでグラフィックが軽めのゲームは動きますよといった、軽いゲームの動作確認で良く使われてたので気になってたゲームです。
2Dのドット絵で、ディアブロをローグライクにしたようなゲームです。
ゲーム開始時にレベル1から始まり、レベルアップ時に武器やアイテムを選択して強化し、30分生き残るとステージクリアになります。
ゲーム中に取得したお金でキャラや能力をアンロックします。
沢山の敵を一気に倒す無双的な爽快感があります。
Switchでもダウンロード販売されています。

Hacknet

色々なサーバをハックしてファイルを探したりしながら謎を解いていくハッキングシミュレータです。
実際のUNIXライクなコマンドを使いながら進めていくことになります。
簡単なUIで操作しながら進めることもできますが、Linux等を触ったことがない人には難しいと思います。
わかっている人は意外と嵌ってしまうゲームです。

PowerWash Simulator

高圧洗浄機でいろんなものを洗うゲームです。
ひたすら汚れを落としていくゲームですが、無心で遊べます。
DLCでバック・トゥ・ザ・フューチャーを題材にしたものがあったので、購入してしまいました。
デロリアンや時計台の時計等を洗えます。

PC Building Simulator

2年以上前に面白そうだと思って買って、やっと遊んでみました。
PCショップを経営し、顧客の依頼でパーツ交換や、組み立て、修理を行いながら余ったお金で自分のPCを強化していくゲームです。
実際のCPUやグラフィックボード等のパーツで組み立てられます。
作業はほぼパーツ交換だけなのですが、永遠に遊んでしまいます。

Retro Gadgets

色々な電子ガジェットを作れるゲームです。
まだボタンを押してる間LEDが光るものしか作ってませんが、使いこなせると面白そうなのでもっと遊んでみようと思ってます。
CPUを置いてLUAでプログラムを組んで制御することもできます。

Planetbase

未開の惑星に基地を建設し開拓していくゲーム。
この手のゲームにしては災害等のイベントは少な目で割と落ち着いてプレイできます。
ある程度大きくなると急にバランスがシビアになって、食料や資源が足りなくなってしまいます。

Sa・Ga COLLECTION

インディーズではありませんが、ゲームボーイ版のサガシリーズ3部作をセットにしてWindowsで遊べるようにしたものです。
これを始めたらどうせなら実機で遊びたいと思い、実機で1をクリアするところまで遊んでしまいました。

Steam Deck (LCD 64GB)を入手しました

年末に色々整理してASUS ROG Allyを手放してしまいました。
XBOXのランチャーやSteamのBig Pictureモードでなるべくゲーム機のような使い方をしてたのですが、Windowsである以上、色々やろうとするとデスクトップ上で操作する事が多くなります。
その際に一々コントローラをデスクモードに切り替えたり、それも使いにくいので結局別にキーボードとマウスを接続したりしていると煩わしくなってしまいます。
また、画面サイズも小さいのでデスクトップで使うときは疲れてしまいます。

欠点がありはありますが、機能とデザインでは気に入ってる機種でした。
コレクション的に置いておきたい気持ちはありましたが、値段が下がる前に売却したいと思い手放してしまいました。

代わりに前から気に入ってたSteam Deckを入手しました。
OLEDの新型が発売されて中古相場が少し下がったLCDの64GBの機種です。
オークションでクーポンも使用して4.5万円ほどでした。

購入したのは64GB版ですが、ASUS ROG Allyで交換した1TBのSSDを元の512GBにに戻して売却し、Steam Deckの方を1TBにしました。
ROG AllyとSteam Deckは同じ2230サイズのSSDが使用できます。

はじめはSteam Deckを買おうと思ってたのですが、その予算でROG Allyを買ってしまいました。
今回もROG Allyが購入時の1万円程度のマイナスで売却できたので、OLED版も考えたのですが、1世代前の性能で躊躇したののと、元々Steam DeckのLCDの評判も良く、店頭で見ても十分綺麗だったので今回は安く済ませようと思いました。

実際に触ってみてROG Allyのような性能や価格の製品が発売されてもSteam Deckが人気な理由がわかりました。

まずは操作性で、メニューのUIがよく出来ていてSwitchのようなゲーム機の感覚でPCのゲームができてしまうので、手軽にゲームが始められます。
SteamのBig Pictureモードにすれば同じじゃない?と思われがちですが、あれはただのランチャーだと思いました。
Steam DeckのメニューはSteamや本体の設定まで簡単にアクセス出来て使いやすいです。
次にゲーム自体の動作です。
Steam Deckに正式に対応しているゲームで所有しているものの中で比較的動作が重めなNo Man's Skyを試したのですが、性能が良いはずのROG Allyで遊んだ時よりもスムーズに動作してました。
ROG Allyでも720pにしたり、一番低設定にして何とか遊んでたのですが、Steam Deckの方が快適に動作してます。
ゲームによってはSteam Deckで起動すると、デフォルトの設定をSteam Deck用にしてくれるので、メーカーがチューニングしているのと、OS自体がWindowsより軽いのが動作に影響してると思われます。

Steam Deckを入手してから特にNo Man's Skyとオクトパストラベラー IIが手軽にできるようになったので、購入してから2週間ほどですが毎日遊んでます。
Switchにもあるゲームですが、Steam Deckの方がロードも早く、No Man's Skyはオンライン要素もあるので、快適に遊べます。

明らかにROG Allyの時より遊ぶ頻度は多いです。
携帯機は操作性も含めて手軽さが重要だと思いました。
OLED版が発売したばかりですが、次の性能アップした機種が発売されたら買い替えてしまう気がします。