MSXマシン語適当講座その3第2改訂版

前へもどる>mon.html



マシン語は誰でもプログラムできます!体験してみてください。

 やってみましょうZ80マシン語 初心者でマシン 語を始めたい人向けです

 MSXマシン語適当講座その1 マシン語からBASICの変数を取得、LD、CALL、INC

 MSXマシン語適当講座その2 SUPER-X、実行、アセンブラ、ソースを書く

 *MSXマシン語適当講座その3 一時的にレジスタを使う、フラグ、レジスタ、転送

 MSXでマシン語BASIC 中級編 ハンド アセンブルから開発環境の話題です。

 PUSHとPOP命令、JPでループ命令、フラグ条件を説明します。
今回の改訂でC(キャリー)と条件分岐を加えました。
さらにブロック転送も加えました。2010/04/20更新
「新しいものばかりではないか!」
本で言えばまぁ、初版の2倍程度のボリュームです。

・SUPER−Xを起動
・一時的にAレジスタを使いたい
・Zフラグはカウントダウン
・Cフラグは繰り上がり、繰り下がり-New!!-
・JR命令-New!!-
・条件分岐命令-New!!-
・レジスタを比較する-New!!-
・四則演算をマスター-New!!-
・ブロック転送-New!!-
・ブロックサーチ-New!!-
・その他-New!!-
・MSXBASICのワザ

■SUPER-Xを起動

ファイルを見ます。
FILES
そして、
BLOAD"SUPER-X.LDR",R
ロードが完了したら
CALL @
ですね。A000Hから始めます。
A>IA000
逆アセンブラ(DISASM)が表示されます。
RETURNキーでメニュー。
右キーでMULTIを選びます。

■一時的にAレジスタを使いたい

一時的にAレジスタを使う場合は
PUSHとPOP命令を使います。

例えばA=3をPUSHしてA=1を入れる。
PUSHした3をAに入れる。

LD    A,03H
PUSH AF
LD     A,03H
CALL 0A073H
POP   AF
RET

この命令の特性は最後に入れた数値を最初に取り出すことです。
1、2、3と入れたならば取り出す順番は3、2、1となります。
これをラスト、イン、ファースト、アウトのLIFOと呼びます。
ついでですから逆に1、2、3と入れて1、2、3となる場合を
ファーストインファーストアウト(FIFO)と呼びます。
もし、PC用語を調べる機会があるのでしたら参考にしてください。
ここで注意して欲しいのは最後にいれた数値を
再び取り出さないとSP(スタックポインタ)のアドレスがズレて
不具合になって暴走してしまう事です。
残念ながらマシン語ですから、絶対PUSHした分POPしましょう。

★サブルーチンはこのようにして作られている

サブルーチンはどうしてRETで戻ることができるのでしょうか?
実はCALL命令でPUSHを使っています。
CALLはCALL 0A073Hの次にあるPOP AFのアドレスを
HLレジスタ入れてPUSH HLします。そして、JP命令で0A073Hへ
RETではPOP HLでアドレスを入れてJP (HL)としています。
これは覚えておくとよいでしょう。

■Z(ゼロ)フラグはカウントダウン

5,4,3,2,1,0、「新年あけまして〜」というシーンがあります。
マシン語はこっちの方が得意です。
Zというレジスタがその正体?です。
ここでは一気に条件ジャンプとフラグをやってみます。

A000 LD   A,05H
A002 DEC A

最初にAレジスタに5を入れます。
そして繰り返すアドレスがA002でLOOPの頭です。
繰り返す仕掛けはJP命令です。
JP 0A000Hとすれば無条件にA000Hへ飛びますが
今回はフラグ条件で計算してゼロになるとセットされるZフラグを使います。
Zがセット、NZがリセットなので
この場合はゼロでないNZですね。Zだけではループしませんよ。

A003 JP NZ,0A002H
A006 RET

これで実行してみます。AFのところが00になりました。

-Tips-
マシン語は実行アドレスをカンタンに変えることもできる反面
プログラムの最初の実行開始アドレスがわからないと
マシン語を正しく実行できないことにもなります。

■C(キャリー)フラグは繰り上がりと繰り下がり

マシン語の計算は難しいところがあるかもしれませんが、
コレを覚えるとラクになるかもしれません。
FFHの次は100Hになります。このように計算するには

LD   A,FFH
LD   B,01H
ADD  A,B

これでAレジスタは0(ゼロ)になりますが、Cが0から1(セット)されます。
さらにキャリーフラグを加えて加減算することができます。
今まで加算はADD、減算はSUBでしたが、

これにキャリーが入る演算になると
ADDのキャリーがADC、SUBのキャリーがSBCとなります。
たとえば02FFHの上位(H)が02、下位(L)がFFとします。
FE、FFの後で02を03にしたい場合に上位にキャリーを加えます。
そうすると上位が02+1(cy)=03というふうになります。
02FFHの後が0200Hと戻ってしまったものが、
0300Hに繰り上げ処理ができるようになります。

繰り下げ処理を作ることもできます。
なお、INC,DECではフラグ変化はありません。

今度はキャリーフラグを0(ゼロ)に戻します。
OR AかAND A

を使います。前回も話したとおり
カンタンで今風に言えばチョーべんりな命令です。
SHEMのソースを逆アセンブラするとわかりますが、
まず最初にコレを使っています。
おまじないのように覚えてみましょう。


■JR命令

JPは絶対ジャンプでした。絶対があれば相対があるものです。
この命令は-127(80H)から-1(FFH)と、+1(01H)0から+127(7FH)の
アドレスの範囲の相対ジャンプを指定できる命令です。
0から256を2つに割った表現を2の補数表現と呼びます。
逆アセンブラであればJR命令から相対アドレス指定で計算します。
アセンブラであればJRの指定した
前後にラベルあれば問題ありません。
分岐先が遠いようであればJPを使うほうが無難でしょう。

DJNZ命令はBレジスタからデクリメントして
0でなければ(NZ)相対分岐します。

-Tips-

ステート数とはCPUの命令にあるステートは処理にかかる時間のことです。
この時間によってマシン語の処理速度が変わってきます。
最小クロック数で記載されている場合もあります。

参考文献:
MSXポケットバンク マシン語入門
MSXturboR テクニカルハンドブック

■条件分岐命令

Z(ゼロフラグ)とC(キャリー)の意味がわかってきたと思います。
条件にはC(キャリー)、NC(ノンキャリー)、Z(ゼット)、NZ(ノンゼロ)
の4つがあります。これはJP、JR共通の条件です。

A003 JP NZ,0A002H

という命令を書きました。
0〜15まではくりかえしたい場合にNZを使いました。
16でループは抜けます。これはCPの数よりも小さい場合です。
次は15以上の数値が入っている場合です。
           LD A,25
           CP 16
           JP NC,ER_SND
           RET
ER_SND:
           CALL BEEP
           RET
と書きます。その他、JPでは
PE(パリティ・イブン)、PO(パリティ・オッド)、M(マイナス)、P(プラス)
があります。

■Aレジスタと比較をする

Aレジスタは計算をするレジスタです。
そこで比較をして真偽を求めます。

LD A,03H
LD B,04H
CP B
RET

これを実行してみましょう。SZ*H*VNCのZは0です。
逆アセンブラに入り、Bレジスタを3にしてみましょう。
Zフラグが1になりました。
これでJP  Z,〜Hという分岐ができるようになりますね。
Bレジスタを2にしてみましょう。Nが1になりました。
CyのキャリーフラグのCも見てみましょう。
16進数はマイナスはないのでインクリメントしますと
FE、FF、00、01、02、03の順となっているので、
00をデクリメントでFFになります。
FFをインクリメントで00になります。この時に1がセットされます。
このように比較する演算処理が実行されますと
ZとCフラグが変化します。

-Tips-
レジスタには次の特殊なものがあります。
PCはプログラムカウンタで次に実行するアドレスです。
SPはスタックの先頭アドレスです。
PUSHされるとDECされてPOPされるとINCされます。
IX,IYはインデックスレジスタです。レジスタペアは
8ビットずつにわけることはできません。

■比較のしかたで条件を変える

CP B

Aレジ Bレジ フラグ
12   12   Z=1
12   11   Z=0
12   13   Cy=1
12   11   Cy=0  

Z=
NZ≠
C<
NC≧

という関係になります。もっと簡単に考えますと
Aが64では=、64でないは≠
これのみの条件判定であればZとNZです。
64-64=0または64-65=1はNCです。
64-63=-1はありませんからFFhになります。
これが繰り下がりでC(キャリー)となります。
64-64=0が絡んでくるのが嫌な場合は
64までならば65でやってください。
そんなに難しくはないですね^^;


例えば
Aレジスタに文字をコードを入れて
CP 29
JP Z,(D030H)
CP 30
JP Z,(D040H)
CP 31
JP Z,(D050H)
CP 32
JP Z,(D060H)
コードごとに分岐するとしたら…
とこんな感じで分岐を作るのかなぁと、
思ったりする。
気持ちはわかるけど、どう見ても
IF命令の乱立てに近い感じがする^^;ピポパッTELと
「はい、わかりました。」
そう書くそうです。(ガーン)
M80というアセンブラの場合
CP 'T'
というふうにコードではなくて文字でもOkです。
こんな風なソースを見かけたらメニュー処理部分ですね。

■四則演算をマスター!

足し算はINCで引き算はDECということがわかりました。
ではかけ算は?割り算は?というふうに思います。
例えは6×12の場合は6を12回足します。
12÷3は12を3で引ける数をカウントします。
余りが出ればMODですね。
でも、こんな単純な数であれば問題はないのですが、
なかなかそうはいかない場合は筆算を使います。
筆算は0と1の筆算でよいです。
 00011
×00100
  00000
 00000
00011
という具合に作っていきます。
算術シフト命令でビットを移動する
左にシフト、右にシフトを使っていきます。

■ブロック転送

あらかじめBCにバイト数、DEに転送先のアドレス、
HLに転送するデータの格納アドレスを指定します。

・LDIR
LDIRを実行した場合、+1していき実行後は
HLが<転送するデータの格納アドレス>+<バイト数>になり
DEも<転送先のアドレス>+<バイト数>になります。

・LDDR
<転送するデータの格納アドレス>+<バイト数>をBCに
<転送先のアドレス>+<バイト数>をDEに入れておき
LDIRを実行した場合、-1していき実行後は
HLが<転送するデータの格納アドレス>になり
DEも<転送先のアドレス>になります。


転送する領域と転送される領域が重なる領域の
いわゆるオーバーラップによってアドレス低い方
からかアドレスの高い方からの転送かを指定する命令になる。
なお、LDI、LDDは1バイトの転送命令になっている。

■ブロックサーチ

あらかじめBCにバイト数、HLにサーチする格納アドレス、
Aにサーチするデータを指定します。

・CPIR
サーチは3E2412で24をサーチ(見つける)とZフラグがセットされ
比較後はHLはインクリメント、BCはデクリメントされます。
これをZフラグがセットされるかBCがゼロになるまで繰り替えします。

・CPDR
比較後はHLはデクリメントされます。

なお、CPI、CPDは1バイトの比較命令になります。

■その他

参考にどうぞ★足りなかったら、また書きます^^;

・RAM

RAMにはDRAMとSRAMとあります。
通常MSXで使用するのはDRAMです。
ROMよりもSRAMの方が速いことが特徴です。
SRAMはSRAMカートリッジという
補助記憶装置として使われています。

・Nフラグ

減算命令を行うとセット

・P/V(パリティ、オーバーフロー)フラグ
演算結果のビット数で変化
2の補数のオーバフローで変化

・S(サイン)フラグ
負の数のときにセット
MSXBASICのSGNと同じようなものです。

・PC(プログラムカウンタ)
次に実行するアドレスを示します。

・SP(スタックポインタ)
データを一時的に記憶するためのメモリ領域

EX DE,HL

DEレジスタとHLレジスタの内容を交換する

CPL

Aレジスタの全ビットを反転

NEG

Aレジスタの2の補数をとります。
Sフラグは負の数の場合セット。
Zフラグも0の場合はセット。

■何とレジスタにも裏用語は流行っていた?

この時期は裏○○というのが流行っていたのかもしれません。
Aレジスタは演算専用でBC、DE、HLはBレジスタ、Cレジスタとして使っても
BCレジスタと16ビットレジスタとして使ってもよいです。
16ビットレジスタはアドレスの移動処理に使えますね。
これにダッシュを記述すれば裏レジスタになります。

■MSXBASICのワザ

最後まで読んでくれて、ありがとうございます。
ここでは知られている技を再度やってみようと思います。

・ローマ字変換:ワークエリア

コレを覚えれば、誰でもMSXひらがなを体験できます。
POKE&HFAFC,1
これでMSX2ならばローマ字変換が誰でも出来るようになります。
そして、ローマ字変換を消したい時は
POKE&HFAFC,0
に戻しますが、
FAFCHにはこれ以外のビット情報が格納されており、
誤動作するのでプログラムにはしないでください。

・VRAMの読み書きをSCREEN1でも有効:ワークエリア

これはVRAM128KのMSX2マシンに限定でSETPAGEの方法で
SCREEN1が使っていない空きのある64KBの領域の読み書きを有効にします。
読み書きのしかたについては割愛します。
POKE&HFAF6,1
アクティブページを1にします。そしてVPOKEします。
POKE&HFAF6,0
アクセスが終わったらアクティブページを0に戻します。
SCREEN1でSCREEN5のような事をしますので、
画面がおかしくなります。

■マシン語をマスターしよう!

まとめとしてMSXBASICで
メモリに書き込む場合はPOKE,読み込む場合はPEEKを使い
DEFUSRで実行アドレスを指定、A=USR(0)で実行する
マシン語モニタはメモリを読み書きするダンプと
命令を入力するアセンブラモードがある
プログラミングする時はプログラムエリア、データエリア、ワークエリア
の3つを使って実行はマシン語モニタかMSX-DOSでもできる。
文字、数字を使う場合は16進数コードからの変換処理を行う。
テキスト画面は文字に変換して表示(フォント)機能がある。
グラフィック画面は左右と上から下へコードを色として表示していく
ビットマップ機能があったり、スプライトを入れたり
VRAMのVDPには便利な機能がある。以下省略。(おい)
ここまでマスターできれば何とか、合格点です。

★他のZ80機でプログラムを試す?

実は私もZ80はあまり知らないのです。
とにかくSHEMか、SUPER-Xでやってみてください。
何度かやっているウチに克服できるかもしれません。
他機種でハードウェアを除いて
Z80かi8080でメモリ内でプログラムを
操作するのであれば何でも参考になりますが、
VRAMは避けては通れません。
表示させないと結果が出ませんね。
機種ごとに表示方法が異なりますので
MSXのBIOSのようにCALL CHPUTしても動くはずがありません。
それでもカンタンに移植を考えるならば
VRAMで0から9とAからFの文字かフォントで
16進数のモニタできる程度のプログラムは
あったほうがよいですね。
MSX-DOSのみを限定とすればMSX-DOSシステムコールを
CP/Mで作ることができます。
msx-mac3
アドレス入力。実行。にゃぁ

SAIでおなじみのSYSTEMAXさんの
Z80関連のページも詳しいと思います。

http://www.systemax.jp/doc/Z80_text.html

http://www.systemax.jp/doc/Z80_inst.html

今の現役なMSXユーザーといえば
私と親しいDr.KIKIE氏でもmosaku氏でもよいでしょう。
よい教材になると思います。

Dr.KIKIE氏さんのブログ:
http://geocities.yahoo.co.jp/gl/dr_kikkie/
mosaku氏さんのブログ:
http://geocities.yahoo.co.jp/gl/dotallcafe/

あとはMARIO-NETのホストプログラムを作った
(YMD)Aさんかな、高速漢字TYPEで MACファイル
を見ることもできます。

それよりもM80はマクロアセンブラなので
普通のアセンブラにマクロ機能が入って拡張されているので
COMファイルはSHEMをかけて逆アセンブラしてみる方が
もっとわかりやすいでしょうね。

■最後に
 ここまで解説してきましたが、まだ一握りまでいっていません。
初級から今度は中級へステップアップしていきましょう!
長老「まず、中級へ進み、BIOSのプログラムを作り、」
「さらにMSX2グラ-HI-へ進み、MSX-DOSとスロット、スプライトへ」
「MSXマシン語の道は長い。がんばるのじゃぞ○○○○」
ホームページの情報の質をそれぞれ上げた関係で
リンクが増えてしまいました。ゴメンナサイ。

mon-basic.html