aburi6800のブログ

コンピュータのプログラミング、ゲームに関するニッチな情報を書いていくブログです。

【MSX】Corridor Runner

Z80アセンブリの勉強で、ゲームを作ってみました。 こんな雰囲気のゲームです。

www.youtube.com

以下のURLで遊べます。

WebMSX

遊び方

  • タイトル画面でスペースキーを押すと、スタートします。

タイトル画面

  • カーソルキーの左右で方向変更、下でパワーを溜めて離すとパワーに合わせて前進します。
  • 出口まで行くと、ラウンドクリアです。

ゲーム画面

  • アイテムチップを取ると得点になります。
  • アイテムチップは連続して取ると得点がアップします。
  • 最初に20,000pts、以降50,000ptsごとに残機が増えます。
  • 床から落ちたり、敵に触れるとミスになります。
  • 全16ラウンドをクリアするとゲームクリアです。
  • ゲーム中は[F1]キーで一時停止できます。
  • ゲームオーバー時に[F5]キーを押すとコンティニューできます。(4面ごと)

ソースなど

githubに全て公開しています。

github.com

【MSX】Z80マシン語を勉強してみた(第1回)

はじめに

往年のマイコン少年なら誰しも憧れた、マシン語
当時のマイコン雑誌には何ページにもわたってダンプリスト(16進数の羅列)が載っていたりして、その入力すら厳しいものでしたが、そこから動くゲームはどれも本格的でBASICでは味わえないものばかりでした。
私も少年時代にマシン語のプログラムにチャレンジしましたが、当時は動くものが作れず、挫折してしたクチです。

そして時は流れ、現在。

改めて勉強しなおしてみると、なんということでしょう!
色々なことが理解できるようになり、ある程度動くプログラムが作れるようになりました。
せっかくですので、ここでは、その過程を記録していこうと思います。

まずは逆スクロールからやってみよう

入門書でよくあるのは、メモリの値を取ってきて計算して格納して…みたいなことが書かれていますが、正直つまらないですね。
やはり、画面で動くもので体感するのが、一番楽しく勉強できるというものです。

ということで、まず手始めに、昔挫折した逆スクロールの処理からやってみることにしました。
最初からすべてをマシン語で書くのは難易度が高いため、マシン語では逆スクロールする処理だけを作り、BASICで画面描画とマシン語の呼び出しをする構成としました。

まずは開発環境とか情報とか

WebブラウザMSXのBASICやアセンブリのエディタとエミュレータが統合された無料て利用できる開発環境である、MSXPenというサイトを使いました。

MSXPen

Z80アセンブリニーモニックは、こちらを参照しました。

Yamamoto's Laboratory 8ビット CPU Z80命令セット

また、VRAMへのアクセスはBIOSを使用していますが、BIOSコールについてはこちらを参照しました。

MSX Datapack wiki化計画 Appendix A.1 BIOS 一覧

BIOSって?

ここでBIOSとキーワードが出てきましたので、ちょっと余談を。
このBIOSというのは、MSX規格のマシンで用意された、便利なサブルーチン郡のことです。
これにより、MSX規格として各マシンのハードウェア構成の違いが吸収され、違う機種でも同じアプリケーションが修正なしで実行できるようになっていました。

当時のコンピュータでは、OSというものがなく(強いていえばBASICがOS代わりだった)、CPUからメモリ以外のハードウェア(画面やキーボード、音源など)へアクセスする際は、I/Oポートを直接叩いて行っていました。(このI/Oの叩き方にもお作法があったりして、プログラミングの難易度が上がる要因にもなっていました)

MSXではこのI/OポートやVDPをアクセスする処理が予めBIOSとして用意されていますので、アセンブリ言語でプログラムする敷居が非常に低くなっています。
また、そもそもハードウェアとしてゲームプログラムに使いやすいスプライトやジョイスティック等もサポートされているため、入門機としては非常にお勧めできるマイコンのひとつです。

私もこのBIOSのおかげで、煩わしいI/Oポートへのアクセスをすることなく、処理に集中してプログラムができました。

その代償として、またROMカートリッジのサポートもあり、メモリアクセスのスピードが他のZ80マイコンよりも遅く、若干見劣りすることになりますが… また、さすがにVRAMへのアクセスが遅いのは問題視していたようで、VDPへの直アクセスは公式に認められていました。

アセンブリで書いてみよう

では早速、逆スクロールする処理を考えてみましょう。
アセンブリマシン語)のプログラムはメモリやレジスタに対する操作を書く、ということを念頭に置き、ニーモニック表やBIOSの一覧とにらめっこして、プログラムの処理の手順を以下のように考えました。

  • 画面最終行から処理開始
  • 一行上の表示内容をコピー
  • 次に処理対象行を一行上にして、同じ処理を行う
  • これを画面最上行の一行前まで繰り返す
  • 最後に画面最上行を空白で埋める

ここから、実際に作ってみたアセンブリプログラムは、次のようなものになります。

  ORG 0xC000          ; 開始アドレス

START:
    LD HL,&1AF8         ; HL=&H1AF8(処理開始VRAMアドレス)
    LD BC,&17           ; BC=行数カウンタ &H17(23)回

; 外部ループ処理 開始
; 全行に対しての処理を行う
OUTLOOP:
    PUSH BC             ; BCをスタックに退避
    LD BC,&19           ; BC=桁数カウンタ &H19(25)回

; 内部ループ処理 開始
; 1行に対しての処理を行う
INLOOP:
                        ; ■1行上のVRAMアドレスのデータを読む
    PUSH BC             ; BCをスタックに退避
    PUSH HL             ; HLをスタックに退避
    LD BC,&20           ; BC=&20(32)
    SBC HL,BC           ; HL=HL-BC
    CALL &004A          ; BIOS RDVRM呼び出し
                        ; - HL : 読み取るアドレス
                        ; - A  : 読み取ったデータ
    POP HL              ; HLをスタックから復帰
    POP BC              ; BCをスタックから復帰

                        ; ■現在のVRAMアドレスにデータを書き込む
    CALL &004D          ; BIOS WRTVRM呼び出し
                        ; - HL : 書き込み先のVRAMアドレス
                        ; - A  : 書き込むデータ

                        ; ■ひとつ左のアドレスに移動
    DEC HL              ; HL=HL-1

                        ; ■桁数カウンタ減算
    DEC BC              ; BC=BC-1
    LD A,B              ; A=B
    OR C                ; A=A OR C
    JR NZ,INLOOP        ; NZ(ゼロでない)なら、INLOOPラベルにジャンプ
; 内部ループ処理 終了

                        ; ■1行上の処理開始VRAMアドレスに遷移させる
                        ; 画面右に7文字分の余白を設けるため、VRAMアドレスから7を減算する
    LD BC,&07           ; BC=&07(7)
    SBC HL,BC           ; HL=HL-BC

                        ; ■行数カウンタ減算
    POP BC              ; BCをスタックから復帰
    DEC BC              ; BC=BC-1
    LD A,B              ; A=B
    OR C                ; A=A OR C
    JR NZ,OUTLOOP       ; NZ(ゼロでない)なら、OUTLOOPラベルにジャンプ
; 外部ループ処理 終了

    LD HL,&1800         ; HL=&H1800(処理開始VRAMアドレス)
    LD BC,&19           ; BC=桁数カウンタ &H19(25)回

; 内部ループ処理 開始
; 1行目のクリア処理を行う
ENDLOOP:
                        ; ■現在のVRAMアドレスにデータを書き込む
    LD A,&20            ; A=&20(" ")
    CALL &004D          ; BIOS WRTVRM呼び出し
                        ; - HL : 書き込み先のVRAMアドレス
                        ; - A  : 書き込むデータ

                        ; ■ひとつ右のアドレスに移動
    INC HL              ; HL=HL+1

                        ; ■桁数カウンタ減算
    DEC BC              ; BC=BC-1
    LD A,B              ; A=B
    OR C                ; A=A OR C
    JR NZ,ENDLOOP       ; NZ(ゼロでない)なら、ENDLOOPラベルにジャンプ
    
    RET                 ; BASICに戻る

END START

ゲームで使うことを想定して、右側7桁はスコア表示などのためにスクロールさせずに固定するようにしました。
そのため、スクロールするのは、(0,0)~(24,23)までの範囲になります。

まずは、処理を開始するVRAMアドレスを求めます。
画面右下から左上に向かって処理するため、求めるのは画面右下のアドレスになります。
SCREEN 1の画面(パターンネームテーブル)の先頭アドレスは1800Hです。
32桁×24行で画面を初期化するので、32×24-1=767=2FFHを1800Hに加算した1AFFHが画面右下のアドレスになります。
ここから、固定表示させる7桁分を減らした1AF8Hが処理開始アドレスになります。
この値をHLレジスタに設定します。

次にOUTLOOPですが、これは行数分ループさせます(外ループ)。
そのため、事前にBCレジスタに行数である23(全体で24行だが、最後の1行は処理不要のため処理が必要なのは23行となる)を設定しています。

INLOOPは一行を桁数分ループする処理です(内ループ)。
BCレジスタをスタックに退避後、桁数である25を設定し、内ループに入ります。
このループでは、以下のような処理をしています。

  • HLレジスタの値をスタックに退避
  • HLレジスタの値から32を減算したアドレス=一行上の表示文字を取得(BASICのVPEEKと同じ)
  • HLレジスタの値をスタックから戻し、VRAMのそのアドレスに取得した表示文字を書き込み
  • HLレジスタの値から1を減算する=処理対象の位置を1文字左へ移動する
  • ループ回数(桁数)から1を減算し、ゼロになるまで繰り返し

内ループ終了後、外ループに戻りますが、そのときに画面右7桁を処理対象外とするために、HLレジスタから7減算します。
スタックに退避したBCレジスタを戻して1減算し、ゼロになるまで外ループを繰り返します。

外ループが終わったら、画面最上部をスペースで埋めて、BASICへ戻ります。

レジスタだけで処理しているものの、スタックを無駄に使っていたり、8ビット値の範囲での繰り返しなのにカウンタに16ビットレジスタを使っていたり、そもそもループをネストする必要がなかったりと、あまりいいお手本ではないですね。 まあ、覚えたてで書いたプログラムなので、大目に見てもらえればと。

レジスタって?

上の説明では、簡単に「HLレジスタに設定します」などと書きましたが、そもそもレジスタってなんでしょうか?
これは、CPUの中に予め用意された、変数のようなものです。
MSXに搭載されているZ80というCPUでは、A,B,C,D,E,H,Lの7種のレジスタが使えます。
これらに加えて、フラグ・レジスタ、インデックス・レジスタが用意されています。
また、各レジスタでは8ビットの値(0~255)しか格納できないのですが、2つのレジスタを組み合わせて16ビットの値を扱うこともできます。
この組み合わせとして、BC,DE,HLとインデックスレジスタがあります。

さて、これらのレジスタは、どれでも自由に使えるのですが、その用途は命令によって限られています。
例えは、計算をする場合やメモリへの値の出し入れは、Aレジスタしか使えません。
アドレスを示すレジスタとしてはHLレジスタが使われることが多いです。
また、ループ制御(DJNZ命令)を使う場合は、ループ数をBレジスタに設定します。
このように、処理で使う命令に合わせて、使えるレジスタが自然と決められていくことになりますが、プログラムを書いていくうちに自然と慣れていくと思います。

BASICから動かしてみよう

さて、せっかく作ったマシン語プログラムも、動かさないと意味がありません。
マシン語プログラムを呼び出すBASICプログラムを作ってみましょう。

100 SCREEN 1,2,0:WIDTH 32:KEY OFF:COLOR 15,4,7
110 CLEAR 200,&HBFFF:DEFUSR=&HC000
120 BLOAD "PROGRAM.BIN"
130 FORI=0TO24:LOCATE25,I:PRINT"|";:NEXT
140 LOCATE26,1:PRINT"SCROLL";:LOCATE26,2:PRINT" DEMO";  
150 FORI=0TO30:LOCATEINT(RND(1)*25),INT(RND(1)*25):PRINT"*";:NEXT
160 A=USR(0):LOCATEINT(RND(1)*25),0:PRINT"*";:GOTO160

110行目のCLEAR文では、BASICで使うメモリをBFFFHまでに設定し、DEFUSR文で呼び出すマシン語プログラムの先頭アドレス(C000H)を設定しています。

なお、DEFUSRのあとに0~9の番号を書くことで、10個までマシン語のプログラムの呼び出しアドレスを設定できます。

120行目でマシン語プログラムを読み込み、130~150行目で画面の初期表示をした後、160行目でスクロール処理と星の表示を行っています。

ちなみに、ロードするアドレスのC000Hはどうやって決定したかというと、特に意味はありません。
ユーザーエリアが8000HF37FHまでなので、この範囲内であればどのアドレスを指定しても良いのです。
ただし、あまり若いアドレスを設定すると、BASICプログラムが入りきらなくなりますので、その場合はE000Hとかにしましょう。

また、システムワークエリアがF380Hから存在するので、そこまでに納まるようにしましょう。

以上で、何とか動くものができました。
この処理をMSXPenで動作させるURLは、以下になります。

https://msxpen.com/codes/-Mht5HeZgQfTPNV9vx31

このURLにアクセスすると、自動的に実行されます。

メモリにあるマシン語プログラムを見てみよう

さて、アセンブリソースから作ったマシン語プログラムと、BASICプログラムの2つを使って、画面を逆スクロールすることができました。
しかし、マシン語プログラムは実際どのようにメモリに格納されているのでしょうか?

BASICプログラムに以下の行を追加して再度実行してみましょう。

200 SCREEN0:A=&HC000:FORI=0TO63STEP8:PRINTRIGHT$("0000"+HEX$(A+I),4);":";
210 FORJ=0TO7:PRINTRIGHT$("00"+HEX$(PEEK(A+I+J)),2);" ";:NEXTJ:PRINT:NEXTI

そして、プログラムをストップして、MSXの画面で

RUN 200

と打ってEnterキーを押してみてください。
すると・・・

16進数がたくさん表示されました。
これがアセンブリソースをコンパイルして作られた、マシン語プログラムです。
最後のC9がBASICに戻るRET命令ですので、ここまでで全部で60バイトになるようです。

C9以降が00ではないことがあると思いますが、無視してください

なお、この16進数の値をBASICプログラムのDATA文として書いて、POKE文でメモリに書き込めば、BASICプログラムだけで逆スクロールさせることができます。
参考として、以下にBASICだけで書いたプログラムを載せておきます。

100 SCREEN 1,2,0:WIDTH 32:KEY OFF:COLOR 15,4,7
110 CLEAR 200,&HBFFF:DEFUSR=&HC000
120 GOSUB200
130 FORI=0TO24:LOCATE25,I:PRINT"|";:NEXT
140 LOCATE26,1:PRINT"SCROLL";:LOCATE26,2:PRINT" DEMO";  
150 FORI=0TO30:LOCATEINT(RND(1)*25),INT(RND(1)*25):PRINT"*";:NEXT
160 A=USR(0):LOCATEINT(RND(1)*25),0:PRINT"*";:GOTO160
200 FORI=0TO59:READA$:POKE&HC000+I,VAL("&H"+A$):NEXT:RETURN
210 DATA 21,F8,1A,01,17,00,C5,01
220 DATA 19,00,C5,E5,01,20,00,ED
230 DATA 42,CD,4A,00,E1,C1,CD,4D
240 DATA 00,2B,0B,78,B1,20,EB,01
250 DATA 07,00,ED,42,C1,0B,78,B1
260 DATA 20,DC,21,00,18,01,19,00
270 DATA 3E,20,CD,4D,00,23,0B,78
280 DATA B1,20,F5,C9,00,00,00,00

MSXPenで作ったプログラムを保存する

少し話が脱線しますが、MSXPen上で作成したプログラムを保存する方法を紹介します。

一つ目は、右上の「Share」というボタンを押して、表示されたURLをメモしておく方法です。
このURLにプログラムコードも含まれているので、アクセスすると全て復元されます。
この記事のように、ブログなどにも貼り付けることが出来るので便利です。

二つ目は、エディタに書いたソースをコピーして、他のテキストエディタなどに貼り付けて保存する方法です。
PC上で再利用したい場合に有効です。
なお、MSXPenではPasmoというアセンブラが使われており、PCにインストールすることでコンパイルすることができます。
詳細は以下を参照ください。

Pasmo, ensamblador cruzado Z80 portable / portable Z80 cross assembler.

最後は、実行時に作成されたディスクイメージをエクスポートする方法です。
MSXPenでは、アセンブリソースは自動的にコンパイルされてPROGRAM.BINというファイル名で、BASICプログラムもAUTOEXEC.BASというファイル名でディスクイメージに保存されます。
そして、起動時にこのディスクイメージを読み込んで実行する仕組みになっています。
ですので、このディスクイメージを保存することで、配布や他のエミュレータなどでの実行が容易になります。

さいごに

ここまでで、BASICプログラムからマシン語の処理を呼び出して動かすことができました。
例にした逆スクロールもですが、フィールドマップ表示やフォント加工など、BASICでは時間がかかる処理を一部マシン語にすることで、それまでと動きが変わると思います。

最初からすべてをマシン語で書くのは大変ですので、このような一部の処理からマシン語で書いてみては如何でしょうか。

【Python】ソーサリアンのようなタイトル表示を実現してみる

 久しぶりの更新です。

 昔、主にPC8801mk2SRなどの8ビットパソコン用に、「ソーサリアン」というRPGが発売されていました。
 このゲームは、当時としてはとてもスケールの大きいものだったのですが、そのタイトル画面がシンプルなのに壮大で美しく、ゲームのイメージにピッタリのものでした。

 今回、このソーサリアンのようなタイトル表示をやってみましたので、解説します。
 言語はPython、モジュールはpyxelを使用します。

 なお、実際に動いているようすは以下になります。

厳密に言うと、PC88版というよりは、メガドライブ版に近いのですが、まあ雰囲気が良ければヨシ、ということで…

事前準備

事前に以下を準備します。

  • 元絵
  • バッファ(元絵と同じサイズ、このバッファの内容を画面に表示する)
  • 青色、緑色、赤色の各色要素のカラーリスト(後述)

処理説明

 全体の処理としては、以下のようになります。

  1. 明度インデックスをゼロに初期化
  2. 以下4回ループ (1) ループ回数によって処理開始位置を以下で設定する。
         1ループ目:X,Y
         2ループ目:X+1,Y+1
         3ループ目:X+1,Y
         4ループ目:X,Y+1
    (2) オフセットX座標をゼロに初期化
    (3) 以下、Y座標を1ドットおきに処理する。
        a. 以下、X座標を8ドットおきに処理する。
         (a) 元絵の処理対象座標+オフセットX座標のドットの色を取得
         (b) 取得した色が青要素のカラーリストに含まれていれば、
           青要素のカラーリストの明度インデックスの色でバッファにドットを描画
         (c) 取得した色が緑要素のカラーリストに含まれていれば、
           緑要素のカラーリストの明度インデックスの色でバッファにドットを描画
         (d) 取得した色が赤要素のカラーリストに含まれていれば、
           赤要素のカラーリストの明度インデックスの色でバッファにドットを描画
        b. バッファの内容を画面に描画
    (4) オフセットX座標を+2
    (5) オフセットX座標が8以下なら(3).に戻る
  3. 明度インデックスを+1
  4. 明度インデックスが5未満なら2.に戻る

 このうち、(a)〜(d)が描画色に関わる処理で、だんだん明るい色に描画していくための部分(描画色設定)になります。
 その他の処理は、1ドットおきにメッシュのパターンで描画する部分(バッファ描画)になります。
 どちらか一方でもフェードインの効果は出せますが、今回はこの2つを組み合わせて、じわ〜っとフェードインしてくる効果を出しています。

 以降、処理をバッファ描画と描画色設定に分けて解説します。

バッファ描画について

 まずはバッファ描画のアルゴリズムから解説します。
 イメージ的には、全体を2x2ドットで仕切り、それぞれの左上、右下、右上、左下の順にドットを埋めていく処理になっています。
 ただし、全体を一度に描画していくと味気なかったため、横8ドット単位で同時に描画して、少しづつ右に描いていくようにしています。  

  1. 最初は(X,Y)から横8ドット置き、縦2ドット置きに描画する

  2. オフセットX座標を+2して、同様に描画を繰り返す

  3. 横8ドット分の処理が終わった状態

  4. 次に(X+1,Y+1)を起点に、同様に横2ドットおきに描画していく

  5. 横8ドット分の処理が終わった状態

  6. 次に(X+1,Y)を起点に、同様に横2ドットおきに描画していく

  7. 横8ドット分の処理が終わった状態

  8. 最後に(X,Y+1)を起点に、同様に横2ドットおきに描画していく

  9. 横8ドット分の処理が終わった状態

 これで全部埋まりました。
 ここまでの一連の処理を、この後説明する明度インデックスの回数分繰り返していきます。
 なお、実際の実装では、毎フレーム処理すると速すぎるため、1フレームおきに実行しています。

描画色設定について

 続いて描画色の設定についてです。
 上記のバッファ描画でドットを描画する色について、段階的に明るくしていく処理になります。
 これは、全体のループ回数から、予めリストに定義しておいた描画色を決定しています。
 ループ回数が最初のほうが暗い色で青系に揃えておいて、明るくなるにつれて各色を発色させていくような定義にしています。

 ここからはpyxelを前提にした話になりますが、カラーパレットは標準で以下のようになっています。

pyxelのカラーパレットは16色なので、MSXでも同様の処理を作ることができると思います。 また、PC8801mk2SRなど8色でも、アナログパレットで同様な処理を実現可能かと思 います。

 このカラーパレットを元に、暗い色から明るい色への変化をカラーリストとして定義していきます。
 また、カラーリストは一度に全色分定義すると処理が複雑になるので、赤要素、緑要素、青要素に分けて定義します。

赤要素のカラーリスト:
緑要素のカラーリスト:
青要素のカラーリスト:

赤要素のカラーリストに8(赤色)などが含まれていませんが、これは実際に使用した画像では未使用だったためです。
汎用的に使える処理にするには、赤要素のカラーリストを(1, 2, 8, 9, 10) などにしたり、要素数を増やす必要があると思います。

先のバッファ描画の中でドットを描画する際には、以下の処理を行います。

  1. 各色要素のカラーリストに、元絵から取得したドット色が含まれているかを調べる
  2. 含まれている場合はその色要素のカラーリストから、現在のカラーインデックス(ループ数により0~4となる)のカラーコードで描画する

その結果、最初は全てカラーコード1で描画され、次は全てカラーコード5、その次から徐々に各色の色が付くような描画となります。

ソース(抜粋)

 これまで説明したアルゴリズムの実装コードを掲載します。
 実際にゲームで使っているもので、あまり良いコードではないですが、以下が毎フレーム実行されています。

    # タイトルロゴの色パターン 
    # 各要素は赤系、緑系、青系の順で定義している 
    TITLE_COLOR = ( 
        (pyxel.COLOR_NAVY, pyxel.COLOR_DARKBLUE, pyxel.COLOR_ORANGE, pyxel.COLOR_YELLOW, pyxel.COLOR_YELLOW), 
        (pyxel.COLOR_NAVY, pyxel.COLOR_DARKBLUE, pyxel.COLOR_GREEN, pyxel.COLOR_LIME, pyxel.COLOR_WHITE), 
        (pyxel.COLOR_NAVY, pyxel.COLOR_DARKBLUE, pyxel.COLOR_CYAN, pyxel.COLOR_LIGHTBLUE, pyxel.COLOR_WHITE), 
    )

    # タイトルロゴのフェードイン処理用 
    # タイトルロゴの座標、大きさ 
    TITLE_X = 0 
    TITLE_Y = 0 
    TITLE_W = 152 
    TITLE_H = 40

    # バッファの書き出し座標 
    TITLE_BUFF_OFFSET_X = 0 
    TITLE_BUFF_OFFSET_Y = 208

    # 処理中の色パターンインデックス
    title_color_idx = 0

    # 元画像の取得元ピクセル座標 
    title_get_x = 0 
    title_get_y = 0 

    # タイリング表示用のループカウント、0~3で1ループ 
    title_get_loop_cnt = 0

(中略)

    def update_title_fadein(self): 
        ''' 
        タイトルロゴフェードイン 
        '''
        if pyxel.frame_count % 2 == 0: 
            # タイトルロゴのピクセルを走査し、バッファに描き込む 
            for _y in range(self.TITLE_Y + self.title_get_y, self.TITLE_H + 1, 2): 
                for _x in range(self.TITLE_X + self.title_get_x, self.TITLE_W + 7, 8): 
                    # イメージバンク0の指定した座標のピクセルの色を取得する 
                    _pick_color = pyxel.image(0).get(_x, _y) 
                    # 取得した色が現在のからーグループ以降に含まれているかを調べる 
                    # 青系 
                    if self.TITLE_COLOR[2][self.title_color_idx:].count(_pick_color): 
                        pyxel.image(0).set(self.TITLE_BUFF_OFFSET_X + _x, self.TITLE_BUFF_OFFSET_Y + _y, self.TITLE_COLOR[2][self.title_color_idx]) 
                    # 緑系 
                    elif self.TITLE_COLOR[1][self.title_color_idx:].count(_pick_color): 
                        pyxel.image(0).set(self.TITLE_BUFF_OFFSET_X + _x, self.TITLE_BUFF_OFFSET_Y + _y, self.TITLE_COLOR[1][self.title_color_idx]) 
                    # 赤系 
                    elif self.TITLE_COLOR[0][self.title_color_idx:].count(_pick_color): 
                        pyxel.image(0).set(self.TITLE_BUFF_OFFSET_X + _x, self.TITLE_BUFF_OFFSET_Y + _y, self.TITLE_COLOR[0][self.title_color_idx]) 
                     
            # 横2ドット移動 
            self.title_get_x += 2 
            # 8ドット分処理したか 
            if self.title_get_x > 8: 
                # 8ドット分処理したら、次の処理に向けて準備する 
                self.title_get_loop_cnt += 1 
                # ループカウント1の場合:x+1ドット、y+1ドット目から処理する 
                if self.title_get_loop_cnt == 1: 
                    self.title_get_x = 1 
                    self.title_get_y = 1 
                # ループカウント2の場合:x+1ドット、y+0ドット目から処理する 
                if self.title_get_loop_cnt == 2: 
                    self.title_get_x = 1 
                    self.title_get_y = 0 
                # ループカウント3の場合:x+0ドット、y+1ドット目から処理する 
                if self.title_get_loop_cnt == 3: 
                    self.title_get_x = 0 
                    self.title_get_y = 1 
                # ループカウント4の場合:ループカウントをリセット、次のカラーグループでx+0ドット、y+0ドット目から処理する 
                if self.title_get_loop_cnt == 4: 
                    self.title_get_loop_cnt = 0 
                    self.title_get_x = 0 
                    self.title_get_y = 0 
                    self.title_color_idx += 1 
                    if self.title_color_idx >= len(self.TITLE_COLOR[0]): 
                        self.state = self.STATE_TITLE

さいごに

 解説は以上となります、参考になれば幸いです。
 説明が少々わかりにくい部分(特に描画色設定のあたり)があると思いますので、折を見て図などを追加できればと考えています。  

【Obsidian】Obsidian gitプラグイン

f:id:aburi6800:20210725005439p:plain

(2022/4/13 加筆修正しました)

Obsidian gitプラグインとは

Obsidianからgitのローカル/リモートリポジトリ操作を行えるプラグイン
予めVaultに対してgitの操作を行い、githubなどのリモートリポジトリと関連付けさせておく必要があるため、gitの知識があることが前提となりますが、利用できるのであればほぼ自動でバックアップしてくれるので便利なプラグインです。

ここでは、プラグインのドキュメント、設定画面の和訳と、具体的な利用方法を記載します。

個人的にはGoogleドライブやOne Driveなどのクラウドストレージはいつ壊れてもおかしくないと考えているので、githubに保存できるのは安心。

目次

プラグイン配布元

Obsidian gitプラグインは、以下で公開されています。

github.com

プラグインドキュメント和訳

Obsidian.mdのデータ保管庫をリモートのgitリポジトリGitHubのプライベートリポジトリなど)にバックアップするためのシンプルなプラグインです。
このプラグインは、認証情報が設定されていることを前提にしています。

git でデータ保管庫をバックアップすることの利点については、@tallguyjenks による素晴らしい記事を読むことをお勧めします。

このプラグインは現時点ではモバイルでは動作しません。更新については #57 を参照してください。

1. インストール方法

詳しい説明は、インストールガイドをご覧ください。

2. ドキュメンテーション

要件、ヒント、よくある問題などは、Wikiで確認できます。

3. 特徴

  • 保管庫の自動バックアップ(X分毎)
  • Obsidian起動時にリモートリポジトリから変更を取り込みます。
  • リモートリポジトリへの変更のプル/プッシュのためのホットキーの割り当て
  • Gitサブモジュールによる異なるリポジトリの管理

4. サイドバービュー

ソースコントロールビューでは、個々のファイルのステージングとコミットを行うことができます。
「ソースコントロールビューを開く」コマンドで開くことができます。

f:id:aburi6800:20220411000428p:plain

5. 使用可能なコマンド

  • Create Backup(バックアップを作成する): すべての変更をコミットし、バックアップ時にプッシュするかどうかの設定に応じてプッシュします。
  • Create Backup with specific message(特定のメッセージでバックアップを作成する): 上記と同じですが、カスタムメッセージを使用します。
  • Commit all changes(すべての変更をコミットする): プッシュせずに全変更のコミットのみ行います。
  • Commit all changes with specific message(特定のメッセージとともにすべての変更をコミットする): 上記と同じですが、カスタムメッセージを使用します。
  • Push(プッシュ)
  • Pull(プル)
  • List changed files(変更されたファイルを一覧表示する): すべての変更点をモーダルにリストアップします。
  • Edit remotes and Remove remote(リモートの編集とリモートの削除)
  • Initialize a new repo(新しいリポジトリを初期化する)
  • Clone an existing remote repo(既存のリモートレポジトリをクローンする)

最新バージョン(執筆時点はversion 1.24.1)では、gitの基本的な操作を行うコマンドがObsidianから実行できるようになりました。
簡単な操作だけであれば、Obsidian上で全て完結できるでしょう。

6. 連絡先

フィードバックや質問がある場合は、GitHub issues または Obsidian Discord の @evrwhr までご連絡ください。

このプラグインは denolehov が最初に開発しました。3月以降は、主にVinzent03がこのプラグインを開発しています。

もし私(Vinzent03)をサポートしたいなら、Ko-fiでサポートできます。


設定画面和訳

f:id:aburi6800:20220411000733p:plain

  • Vault backup interval (minutes)
    Commit and push changes every X minutes. Set to 0 (default) to disable. (See bellow setting for further configuration!)

    X分ごとに変更をコミットしてプッシュする。
    0(デフォルト)に設定すると無効になります。(さらに詳しい設定は下の設定を見てください!)

  • If turned on, do auto backup every X minutes after last change. Prevents auto backup while editing a file. If turned off, do auto backup every X minutes. It's independent from last change.

    オンにした場合、最後の変更からX分ごとに自動バックアップを行います。
    編集中のファイルは自動バックアップしません。
    オフにした場合は、最後の変更に関係なく、X分ごとに自動バックアップを行います。

  • Auto pull interval (minutes)
    Pull changes every X minutes. Set to 0 (default) to disable.

    X分ごとに変更をプルします。
    0(デフォルト)を設定すると無効となります。

  • Sync Method
    Selects the method used for handling new changes found in your remote git repository.

    リモート git リポジトリで見つかった新しい変更の処理に使用する方法を選択します。
    訳注)通常はMergeで問題ありません。

f:id:aburi6800:20220411000717p:plain

 - Merge
 - Rebase
 - Other sync service (Only updates the HEAD without touching the working directory)

その他の同期サービス(作業ディレクトリを触らずにHEADだけ更新する)

  • Commit message on manual backup/commit Avaliable placeholders: {{date}} (see below), {{hostname}} (see below) and {{numFiles}} (number of changed files in the commit)

    手動バックアップ/コミット時のコミットメッセージ。 使用可能なプレースホルダーは以下。 {{date}} この下の日付フォーマットに従った書式の日付を埋め込みます。 {{hostname}} この下のホスト名フォーマットに従った書式のホスト名を埋め込みます。 {{numFiles}} コミットで変更されたファイル数を埋め込みます。

  • {{date}} placeholder format Specify custom date format. E.g. "YYYY-MM-DD HH:mm:ss"

    日付の書式をデフォルトから変更したいときに指定します。

f:id:aburi6800:20220411000820p:plain

  • {{hostname}} placeholder replacement Specify custom hostname for every device.

    コミットメッセージにホスト名を埋め込む場合、ホスト名を指定します。

  • Preview commit message

    訳注)Previewボタンを押すと、右上にコミットメッセージのサンプルが表示されます。

  • List filenames affected by commit in the commit body

    コミット時のファイル名の一覧をリストアップします。

  • Specify custom commit message on auto backup You will get a pop up to specify your message

    自動バックアップ時のコミットメッセージをカスタムで指定します。
    メッセージを指定するためのポップアップが表示されます。

  • Current branch
    Switch to a defferent branch.

    現在のブランチ。 別のブランチに切り替えることができます。

  • Pull updates on startup
    Automatically pull updates when Obsidian starts.

    起動時に変更を Pull する。
    Obsidianの起動時に自動的にアップデートを取得します。

  • Disable push Do not push changes to the remote repository.

    プッシュを無効にする。 リモートリポジトリに変更をプッシュしない場合にONにする。

  • Pull changes before push Commit → Pull → push (Only if pushing is enabled)

    プッシュする前に変更をプルする コミット後、プルしてからプッシュする(プッシュが有効な場合のみ)

f:id:aburi6800:20220411000846p:plain

  • Automatically refresh Source Control View on file changes
    On slower machines this may cause lags. If so, just disable this option.

    ファイル変更時にソースコントロールビューを自動的に更新する。 低速なマシンではラグが発生する可能性があります。その場合は、このオプションを無効にしてください。

  • Update submodules
    "Create backup" and "pull" takes care of submodules. Missing features: Conflicted files, count of pulled/pushed/committed files. Tracking branch needs to be set for each submodule.

    サブモジュールの更新 "バックアップの作成 "と "プル "の処理は、サブモジュールが担当します。
    不足している機能:ファイルの競合、プル/プッシュ/コミットされたファイルのカウント。 サブモジュールごとにトラッキングブランチを設定する必要があります。
    訳注)具体的にどういう設定なのかわからないため、問題が無ければオフのままで良いと思います。

  • Disable notifications
    Disable notifications for git operations to minimize distraction. (refre to status bar for updates)

    通知機能を無効にする git の操作に気を取られることがないよう、通知を無効にします。(更新はステータスバーに反映されます) 訳注)処理されるごとに右上に出る通知メッセージが鬱陶しい場合は、オンにします。

  • Show status bar
    Obsidian must be restarted for the changes to take affect.

    ステータスバーを表示する 変更を反映させるには、Obsidianを再起動する必要があります。

  • Custom Git binary path

    訳注)通常はパスが通った場所にあるため設定不要ですが、設定が必要な場合はここにgitのパスを指定します。


Obsidian gitプラグインの利用手順

ローカルのVaultにGithubのリモートリポジトリを登録し、Obsidian gitプラグインGithubへVaultの内容を保存するまでの手順を記載します。

1. 前提

ここでは、以下を前提としています。

  • 既にObisidanを利用しており、Vaultのディレクトリがあること。
  • githubにアカウントを持っていること。
  • githubSSH接続する設定を行っていること。
  • gitの利用経験があること。

なお、まっさらな新規Vaultを作るところからで良い場合は、Githubに適当なリポジトリを作成し、ローカルにcloneしてくるやり方が一番簡単です。

2. Valutをローカルリポジトリにする

ObsidianのVaultにしているディレクトリで、git bashなどを使用して、以下コマンドを実行します。

$ git init

既にVaultにファイルがある場合は、以下を実行してコミットします。
(git commitのメッセージは例です、好きな内容に変更してください)

$ git add -A
$ git commit -M 'first commit.'

ここまでの手順で、ローカルのValutがgitリポジトリとなり、ファイルがあれば登録された状態になります。

3. githubにリモートリポジトリを作成する

続いて、githubにローカルのVaultを保存するためのリポジトリを作成します。
githubの自分のページでRepositoriesタブを開き、「NEW」ボタンをクリック。

f:id:aburi6800:20220413233316p:plain

リポジトリ名を指定して作成します。
Publicだと誰からも見られてしまうため、Privateにしてください。

f:id:aburi6800:20220413233430p:plain

4. ローカルリポジトリgithubのリモートリポジトリを追加する

Githubリポジトリが作成されると、以下にようにクイックセットアップページが表示されます。

f:id:aburi6800:20220413233847p:plain

基本的にはここに書かれている通りにコマンドを実行していきます。
コマンドは、完全に新規であれば一番上の「...or create a new repository on the command line」のものになりますが、今回は既にあるリポジトリからプッシュしたいので、真ん中の「...or push an existing repository from the command line」の手順を実行します。
なお、このコマンドはリポジトリ名に応じて自動的に生成されるものなので、実際は作成したリポジトリで表示されたコマンドを使用してください。

また、ローカルのリポジトリ名(ディレクトリ名)とリモートのリポジトリ名は一致している必要はありません。

ここまでの操作で、ローカルのgitリポジトリgithubのリモートリポジトリが登録され、相互に通信ができる状態になります。
あとは、自動的にGithubにValutの内容がバックアップされるように、Obsidian gitプラグインの設定を行います。

5. Obsidian gitプラグインを設定する

各設定値については先の和訳を参照頂くとして、参考として私の設定している内容を記載しておきます。(ほとんど設定を変更していません)

設定項目
Vault backup interval (minutes) 10
If turned on, do auto backup every X minutes after last change. ... オン
上記以外 初期値のまま

右上の表示が鬱陶しくなったら、「Disable notifications」をオンにするかもしれません。

モバイルアプリとの共存について

PCだけでObsidianを利用する場合は、各端末でそれぞれリモートリポジトリをcloneして同じ設定をしていけば、Github経由でVaultが同期できます。
しかし、モバイルアプリも併用すると、問題が発生します。
モバイルアプリではObsidian gitプラグインが(この記事を執筆している4/14時点では)利用できないため、Vaultの同期は別のクラウドストレージを利用して行うしかありません。
この場合、GithubはあくまでPCからのバックアップ、という目的で利用することになります。
例えば、私の場合は以下のような構成で運用しています。

f:id:aburi6800:20220413231143p:plain
モバイルアプリと共存した運用イメージ

一見して無駄に思えるかも知れませんが、Githubはブラウザからアクセスしてデータを検索・参照できますし、過去の更新履歴も保存されますので、バックアップ目的としても充分有用です。
ObsidianのVaultは個人的なデータを蓄積していく大事なものですので、Githubという信頼性の高いシステムにバックアップできるのは非常に安心材料なのではないかと考えます。

さいごに

Obsidian gitプラグインは比較的開発が活発なので、この記事も都度アップデートできればと思います。
(この記事を書いた時点で、既に1.25.0が公開されている)

【MSX】AndroidでMSXクロス開発環境を構築する(3)

今回は、ubuntuにz88dkとcode-serverをインストールし、Z80アセンブラの開発を行えるようにします。
最後に簡単なサンプルプログラムを作り、動作確認を行います。
これまでの作業については、以下の記事を参照してください。

aburi6800.hatenablog.com

aburi6800.hatenablog.com

z88dkのインストール・設定

z88dkをソースからビルドします。
手順は以下のサイトに詳しく書いてありますが、一応記載しておきます。

github.com

まず、適当なディレクトリで以下を実行してソースを取得します。
ここではホームディレクトリで実行する前提で進めます。

git clone  --recursive  https://github.com/z88dk/z88dk.git

依存関係のあるライブラリをインストール。

sudo apt install build-essential dos2unix libboost-all-dev texinfo texi2html libxml2-dev subversion bison flex zlib1g-dev m4 libtemplate-perl libtemplate-plugin-yaml-perl libfile-slurp-perl ragel re2c

恐らく上記で依存関係にある上位のパッケージが無くてもインストールされると思いますが、ビルド時にエラーになった場合は不足しているパッケージを追加でインストールしてください。

以下コマンドを順次実行してビルド。

cd z88dk
export BUILD_SDCC=1
chmod 777 build.sh
./build.sh

現在はシステムインストールは完全にサポートされていないため、ビルド後の z88dk\bin に直接パスを通すことで使用します。
~/.bashrc の最後に以下を追加します。

export Z88DK_HOME=~/z88dk
export PATH=${PATH}:${Z88DK_HOME}/bin
export ZCCCFG=${Z88DK_HOME}/lib/config

最初にホームディレクトリ以外でソースの取得を行った場合は、Z88DK_HOMEディレクトリを適切なパスに置き換えてください。

追加後、以下を実行して設定を反映させます。

source ~/.bashrc

以下でコマンドにパスが通っていることを確認できます。

zcc

code-serverのインストール・設定

Termuxのubuntu環境では、code-serverを起動し、ブラウザからVS Codeを使用します。
code-serverのインストール手順は以下サイトに書かれています。

coder.com

具体的には、インストールスクリプトが用意されているので、それを実行するだけです。
スクリプトを取得するためにcurlをインストールします。

sudo apt install curl

その後、ホームディレクトリでインストールスクリプトを取得して実行します。

curl -fsSL https://code-server.dev/install.sh | sh

インストール完了後、デフォルトではパスワード入力を要求される設定になっています。
ここでは、ローカルから自分のみアクセスする想定ですので、パスワードを無効にします。

sed -i.bak 's/auth: password/auth: none/' ~/.config/code-server/config.yaml

code-serverを起動します。

code-server &

起動までしばらく時間がかかります。
以下のようなメッセージがコンソールに表示されたら、起動完了です。

[2022-03-16T16:44:13.482Z] info HTTP server listening on http://127.0.0.1:8080/  
[2022-03-16T16:44:13.482Z] info - Authentication is disabled  
[2022-03-16T16:44:13.483Z] info - Not serving HTTPS

ブラウザアプリを起動し、以下のURLにアクセスします。

http://127.0.0.1:8080

画面が表示されたら、必要な拡張機能を入れて準備完了です。
具体的な方法は、一般的なVSCodeの使用方法と同じですので、ここでは割愛します。
日本語化するのと、Z80アセンブラの開発を行うため、以下の拡張機能を入れることを推奨します。

テストプログラムの作成

適当なディレクトリを作り、 hello.asm のファイル名で新規ファイルを作り、以下のコードを貼り付けます。

SECTION code_user
PUBLIC _main
_main:

CHGMOD:    EQU $005F            ; BIOS スクリーンモード変更
WRTVRM:    EQU $004D            ; BIOS WRTVRM
LINL32:    EQU $F3AF            ; WIDTH値

    LD A,1                      ; Aレジスタにスクリーンモードの値を設定
    CALL CHGMOD                 ; BIOS スクリーンモード変更
    LD A,32                     ; AレジスタにWIDTHの値を設定
    LD (LINL32),A               ; Aレジスタの値をワークエリアに格納

    LD HL,$1800                 ; 表示開始アドレス
    LD DE,TEXT                  ; 表示データアドレス

PRTSTR:
    LD A,(DE)                   ; AレジスタにDEレジスタの示すアドレスのデータを取得
    OR A                        ; 0かどうか
    JR Z,PRTSTR_END                ; 0の場合はPRTSTR_ENDへ
    CALL WRTVRM                 ; BIOS WRTVRM呼び出し
                                ; - HL : 書き込み先のVRAMアドレス
                                ; - A  : 書き込むデータ
    INC HL                      ; HL=HL+1
    INC DE                      ; DE=DE+1
    JR PRTSTR

PRTSTR_END:
    JR PRTSTR_END               ; 無限ループ

SECTION rodata_user
TEXT:
    DB "HELLO MSX !",0

コンソールで以下コマンドを実行して、コンパイルします。

zcc +msx -create-app -subtype=rom hello.asm

以下のメッセージが表示され、ソースのディレクトリにa.romが出来ていれば、コンパイル成功です。

Program requires cartridge with 1 16k ROM banks
Notice: Available RAM space is 16173 bytes ignoring the stack
Adding main bank 0x00 (16206 bytes free)

作成した.romファイルを、他のアプリから参照できるように、端末のストレージへコピーします。
内部ストレージは直接アクセスできないアプリがあるため、SDカードにコピーします。
コピー先のディレクトリを調べるには、以下のようにします。

cd /storage
ls -al

以下のようなディレクトリリストが表示されます。

合計 0  
drwxr-xr-x  5 root    root             100 3月 19 19:32 .  
drwxr-xr-x 22 hitoshi hitoshi         4096 3月 19 21:07 ..  
drwxr-xr-x  3 root    aid_everybody 131072 3月 19 19:32 129B-6156  
drwx--x--x  4 root    aid_everybody   4096 8月 13  2019 emulated  
drwxr-x--x  2 root    root              60 3月 19 19:32 self  
hitoshi@localhost:/storage$

このうち、emulatedは内部ストレージ、129B-6156のような名前のディレクトリ(環境によって異なる)がSDカードになります。
129B-6156の部分は自分の環境に合わせて読み替えてください。

cp <ソースを作成したディレクトリ>\a.rom \storage\129B-6156\Android\data\com.termux\files

com.termuxディレクトリまではあると思いますが、filesディレクトリが無ければ作成してください。

動作確認は色々な手段がありますが、今回は webmsx を使用します。
ブラウザから以下サイトにアクセスします。
WebMSX

画面左下の電源ボタンをクリックし、Open Fileを選択、ファイル選択ダイアログから先ほどのディレクトリのa.romを選択します。
画面に文字が表示されれば成功です。

RAMが4Gの場合は、ブラウザによってはメモリ不足のエラーが出ることがあります。 その場合は、OpenMSXなどのエミュレータアプリをインストールして実行してください。

さいごに

ここまでの作業で、Android上にz88dkとVSCode(code-server)を使ったMSXクロス開発環境ができました。
z88dkを使っていますのでC言語での開発もできますし、SDCC互換ライブラリも導入していますので、SDCCで開発したものでも簡単に移行できると思います。
なお、以下URLに便利なテンプレートプロジェクトやcmakeでのビルドなどが記載されていますので、参考にすると良いでしょう。

maple4estry.netlify.app

ではでは。

【MSX】AndroidでMSXクロス開発環境を構築する(2)

今回は、ubuntuにgit環境を構築し、GitHubSSH通信するまでの設定を行います。
一般的な内容になりますので、詳細は色々と検索すると出てくるかと思います。
Android上にubuntu環境を構築するまでの手順については、前回の記事を参照願います。

aburi6800.hatenablog.com

ubuntuへのgitインストール・設定

(1) インストール

以下コマンドを実行して、gitをインストールします。

sudo apt update
sudo apt install git

よくaptではなくapt-getでインストールする、という手順が書かれていますが、結論からするとどちらでも良いです。
apt-getはAPTの最初のコマンドラインベースフロントエンドで、その設計上のミスを克服したものがaptになります。
ubuntuの14.04以降からaptコマンドが推奨されています。

gitのインストール結果を確認します。

git --version

(2) 設定

初期設定として、まず、以下を設定します。
これらは、コミット履歴などで他ユーザーから見える情報です。

git config --global user.ename = '<ユーザー名>'
git config --global user.email = '<メールアドレス>'

続いて、git pushする際にブランチ名/タグ名を指定しなかったときの挙動を設定します。

git config --global push.default 'simple'

ここで設定する値と意味は以下になります。

  • simple
    • 現在のブランチをupstreamのブランチにpushする。ただしupstreamのブランチ名が現在のブランチ名と違っている場合はpushしない。
  • matching
    • 同名のブランチをpushする。
  • nothing
    • refsが設定されてない場合はpushしない。
  • current
    • 現在のブランチを同名のリモートブランチにpushする。
  • upstream
    • 現在のブランチをupstreamのブランチにpushする。

これまでのデフォルトはmatchingでしたが、git 2.0以降からはsimpleになっているようです。
以前と同じ挙動にしたい場合は、matchingを指定してください。

最後に、これは任意ですが、git commitなどを行った際に使うツールの設定を行います。
VS CodeWindowsでもLinuxubuntu)でも使えるので、設定しておくと便利かと。

git config --global code.editor 'code --wait'
git config --global merge.tool 'code --wait "$MERGED"'

設定値の確認は、以下で行います。

git config --global --list

GitHubSSH通信する設定を行う

GitHubSSH通信するための設定を行います。
SSH キーを使用すると、アクセスのたびにユーザ名と個人アクセストークンを入力することなく GitHub に接続できます。
手順の詳細については、以下の記事を参照願います。

aburi6800.hatenablog.com

なお、上記で記載した手順はWindows(Git bash)で実行するものですが、Linux(ubuntu)でも同じ手順になります。

以上で、Termux上のubuntuにgitの環境を構築しました。
次回はクロス開発環境であるz88dkと、VS Codeをブラウザから使うためのCode-Serverのインストールを行います。

【MSX】AndroidでMSXクロス開発環境を構築する(1)

はじめに

今回から数回に分けて、Android端末にMSX開発環境を構築する手順を紹介します。
とは言え、AndroidMSX開発用のアプリという都合のいいものはないので、AndroidにPCと同様の開発環境(※1)を構築することにします。
具体的には、gitでソースのバージョン管理、VSCodeでソースの編集、z88dkでZ80のCまたはアセンブラソースからromファイルを作成、WebMSXで実行という構成になります。
宜しければお試しください。

※1
ほぼ同様で、違いと言えば実行環境がPCほど選べない(アプリで提供されているMSXエミュレータかWebMSXが選択肢となる)のと、デバッグ環境が無いところだけが違いです。
とはいえ、このデバッグ環境がないのが、結構ツラいところですが・・・

全体の流れ

全体の流れは、以下になります。

  1. Android端末上にLinuxubuntu)環境を構築する
  2. ubuntuにgitをインストール、GitHubSSH通信する設定を行う
  3. ubuntuにz88dkをインストールする
  4. ubuntuにcode serverをインストールする
  5. テストプログラムをコンパイルし、MSXエミュレータ上で実行する

今回は、「1. Android端末上にLinuxubuntu)環境を構築する」部分について記載します。

1.AndroidLinux環境を構築する

(1) Termuxのインストール

まず、AndroidLinux環境を構築します。 これにはroot権限不要でLinux環境を構築できる「Termux」というアプリを使用します。
詳細については以下リンク先を参照してください。
Termux wiki

なお、以前はPlayストアで配信されていましたが、現在はF-Droidで配信されているものを使用することになっています。(Android7.0以降に対応)
F-Froid / Termux

基本的には、apkをダウンロードしてインストールするだけです。

ここで、自分のAndroid端末へのapkのインストール方法が判らない場合は、この先に進むのは止めた方が良いと思います。

(2) Termuxの設定

ダウンロード後の最初の起動時に権限を求められるので、それぞれ許可してください。
その後、コマンドプロンプトが表示されます。

Termuxは基本的にシングルユーザーのため、rootで使用します。特にユーザーの追加などは不要です。
まず、TermuxからSDカードなどにアクセスできるよう、以下のコマンドを入力します。

pkg update && pkg install termux-setup-storage

この結果、ホームディレクトリに storage ディレクトリが作成され、内部ストレージやSDカードにアクセスできるようになります。
以下は、pkg install後のディレクトリ内容を確認した例です。

~ $ ls -al
total 24
drwx------ 4 u0_a245 u0_a245 4096 Mar  5 22:38 .
drwxrwx--x 4 u0_a245 u0_a245 4096 Feb 20 19:06 ..
-rw------- 1 u0_a245 u0_a245  302 Mar  5 22:25 .bash_history
-rw------- 1 u0_a245 u0_a245   26 Feb 20 19:22 .bashrc
drwx------ 2 u0_a245 u0_a245 4096 Feb 20 19:06 .termux
drwx------ 2 u0_a245 u0_a245 4096 Feb 23 00:44 storage
~ $ cd storage/
~/storage $ ls -al
total 8
drwx------ 2 u0_a245 u0_a245 4096 Feb 23 00:44 .
drwx------ 4 u0_a245 u0_a245 4096 Mar  5 22:38 ..
lrwxrwxrwx 1 u0_a245 u0_a245   24 Feb 23 00:44 dcim -> /storage/emulated/0/DCIM
lrwxrwxrwx 1 u0_a245 u0_a245   28 Feb 23 00:44 downloads -> /storage/emulated/0/Download
lrwxrwxrwx 1 u0_a245 u0_a245   48 Feb 23 00:44 external-1 -> /storage/129B-6156/Android/data/com.termux/files
lrwxrwxrwx 1 u0_a245 u0_a245   26 Feb 23 00:44 movies -> /storage/emulated/0/Movies
lrwxrwxrwx 1 u0_a245 u0_a245   25 Feb 23 00:44 music -> /storage/emulated/0/Music
lrwxrwxrwx 1 u0_a245 u0_a245   28 Feb 23 00:44 pictures -> /storage/emulated/0/Pictures
lrwxrwxrwx 1 u0_a245 u0_a245   19 Feb 23 00:44 shared -> /storage/emulated/0
~/storage $

(3) ubuntuのインストール

上記でインストールしたTermuxはDebianベースのLinux環境ですが、若干使い勝手が悪いため、ubuntu環境を使えるようにします。
PCでもubuntuを使っているという場合は、同じコマンドを使えるので、この方が便利だと思います。
もしDebianに慣れている場合は、以降はスキップしても問題ありません。

ます、コンソールで以下のコマンドを実行し、prootproot-distroをインストールします。

pkg install proot proot-distro

その後、以下コマンドで、ubuntuをインストールします。

proot-distro install ubuntu

インストールが完了したら、以下コマンドで確認します。

proot-distro list

ubuntustatusinstalledになっていれば、インストールが成功して利用可能な状態となります。

インストール後は、以下のコマンドで、ubuntuを開始できます。

proot-distro login ubuntu

ログインできたことを確認したら、一度exitとしてubuntuから抜け、以下のコマンドを実行します。

echo 'proot-distro login ubuntu' >> ~/.bashrc

これで、次回からコマンドを実行しなくても、Termux起動後に自動的にubuntuにログインした状態になります。

(4) ubuntuの基本設定

ここまででインストールしたubuntuは、一般的にPCにインストールされるものと違い、必要最低限なものです。
GUI環境でもありませんし、日本語にも対応しておらず、wgetなどもインストールされていません。
また、シングルユーザー(root)の状態ですので、まずはubuntuの基本設定を進めていきます。

日本語ロケールへの変更

まずは日本語ロケールに変更します。
これは全ユーザーに適用されても問題ないので、root(デフォルトのユーザー)のままで行います。

pkg update && pkg upgrade -y
apt install language-pack-ja -y
locale -a

3つ目のコマンドの実行結果で、ja_JP.utf8が表示されていればインストール完了です。
引き続き、以下のコマンドを実行し、システムの設定を変更します。

echo 'export LANG=ja_JP.UTF-8' >> ~/.bashrc
echo 'export LANGUAGE="ja_JP:ja"' >> ~/.bashrc
source ~/.bashrc

一般ユーザーの追加

現状ではrootでの作業となり危険ですので、一般ユーザーを追加します。
まず、sudoがないため、以下コマンドを実行します。

apt update
apt dist-upgrade
apt install sudo

その後、ユーザーを追加し、sudoグループに追加します。

adduser <ユーザー名>
gpasswd -a <ユーザー名> sudo

最後に、シェル起動時のスクリプトsuするコマンドを追加し、実行します。

echo 'su <ユーザー名>' >> ~/.bashrc
source ~/.bashrc

ここで、プロンプトが以下の表示になっていれば成功です。

<ユーザー名>@localhost:/root$

ただし、sudoコマンドが使えない場合があります。(少なくとも私は使えなかった)
その場合は一度exitしてrootに戻り、以下コマンドを実行して、設定ファイルを編集します。
一行目は初回のみ必要なものです。

apt install vim
visudo

vimの画面になるので、以下の行を追加します。

:
root ALL=(ALL:ALL) ALL
<ユーザー名> ALL=(ALL:ALL) ALL    ←この行を追加
:

この後、su <ユーザー名>とすると、sudoが使えるようになっていると思います。

意味的にはrootと同じ権限をユーザーに与えるということなので、実際はユーザーを切り替える必要性はあまりありません。 しかし、一般的な情報にある手順はsudoコマンドを使うものですので、読み替えしなくても使えるというメリットはあります。

なお、suした後のカレントディレクトリがrootのホームディレクトリになっています。
これをユーザーのホームディレクトリに変更するには、一般ユーザーでログインした状態で以下のようにします。

echo 'cd ~' > ~/.bashrc
source ~/.bashrc

以上で、Termuxにubuntuをインストールし、必要最低限の設定を行いました。
次回はgitをインストールし、GitHubSSH通信するための設定を行います。