AKI-H8/3048のモニタプログラムでの
機械語プログラムの動作
Copyright(C)29Dec2010
since 1Aug2003
coskx
1.はじめに
この文書は,AKI-H8におけるH8/3048のモニタプログラム,PCターミナルソフトでの学習を記述しています。
モニタプログラムは,新しいプログラムの動作を検証する場合や,アセンブリ言語の学習者が,1命令ずつ機械語命令を実行してCPUのふるまいを観察するプログラムです。モニタプログラムはROM(フラッシュメモリ)上に配置されており,検証対象のプログラムはRAM上に置かれます。
この文書では
PC上のターミナル画面からアセンブリニーモニックを直接入力してCPUの動作を見る方法
を用いて,機械語プログラムの動作を解説します。
(本校)校内からは授業に使うため準備用ファイルが入手できます。またマニュアルもダウンロードしておくとよい。
このファイルを解凍すると「trial4」のフォルダが出てくるので, 作業用フォルダとして使います。 ((本校)LANからのみ試用のためアクセスできます。) (4J電子計算機IIの授業ではこれを使います) |
H8機械語命令ニーモニクの説明マニュアル ((本校)LANからのみアクセスできます。) |
注意
この文書で扱っているAsm2Mon.cmdはWindows2000,WindowsXP,WindowsVista,Windows7で使用可能です。
2. 2つの2バイト整数値のハンドリング
目的 | モニタプログラム上で,簡単なアセンブリプログラムを記述し,ステップ実行し,各レジスタが変化する様子を確認,モニタプログラムの操作を修得するする。また,メモリ上の変数の取扱いを確認する。 | |
例題1 |
FF200から機械語プログラムを置きなさい。 実行時に,FF800,FF801番地の2byteデータには3456を | |
実行例 | : a ff200 FF200 > mov.l #fff00,er7 FF206 > mov.w @ff800:24,r0 FF20C > mov.w @ff802:24,r1 FF212 > sub.w r1,r0 FF214 > mov.w r0,@ff804:24 FF21A > bra ff21a:8 FF21C > . : da ff200 ff21a <ADDR> <CODE> <MNEMONIC> <OPERAND> FF200 7A07000FFF00 MOV.L #H'000FFF00:32,ER7 FF206 6B20000FF800 MOV.W @H'FF800:24,R0 FF20C 6B21000FF802 MOV.W @H'FF802:24,R1 FF212 1910 SUB.W R1,R0 FF214 6BA0000FF804 MOV.W R0,@H'FF804:24 FF21A 40FE BRA FF21A:8 : d ff800 ff80f <ADDR> < D A T A > < ASCII CODE > FF800 00 00 FF EE 00 00 FF FF 00 A0 FF FF 00 00 FF FF "................" : m ff800 FF800 00 ? 34 FF801 00 ? 56 FF802 FF ? 78 FF803 EE ? 90 FF804 00 ? 00 FF805 00 ? 00 FF806 FF ? . : d ff800 ff80f <ADDR> < D A T A > < ASCII CODE > FF800 34 56 78 90 00 00 FF FF 00 A0 FF FF 00 00 FF FF "................" : r PC=000000 CCR=80:I....... SP=00FFFF10 ER0=00000000 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=00FFFF10 : .pc PC=000000 ? ff200 CCR=80 ? . : r PC=0FF200 CCR=80:I....... SP=00FFFF10 ER0=00000000 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=00FFFF10 : s PC=0FF206 CCR=80:I....... SP=000FFF00 ER0=00000000 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF200 7A07000FFF00 MOV.L #H'000FFF00:32,ER7 : s PC=0FF20C CCR=80:I....... SP=000FFF00 ER0=00003456 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF206 6B20000FF800 MOV.W @H'FF800:24,R0 : s PC=0FF212 CCR=80:I....... SP=000FFF00 ER0=00003456 ER1=00007890 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF20C 6B21000FF802 MOV.W @H'FF802:24,R1 : s PC=0FF214 CCR=A9:I.H.N..C SP=000FFF00 ER0=0000BBC6 ER1=00007890 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF212 1910 SUB.W R1,R0 : s PC=0FF21A CCR=A9:I.H.N..C SP=000FFF00 ER0=0000BBC6 ER1=00007890 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF214 6BA0000FF804 MOV.W R0,@H'FF804:24 : d ff800 ff80f <ADDR> < D A T A > < ASCII CODE > FF800 34 56 78 90 BB C6 FF FF 00 A0 FF FF 00 00 FF FF "4Vx............." : |
アセンブリ言語プログラム の入力 逆アッセンブルで確認 作業用メモリの確認 作業用メモリにテストデータ を載せる 作業用メモリのテストデータ 確認 レジスタの確認 プログラムカウンタのセット レジスタの確認 1命令実行 実行結果メモリの確認 |
補足説明 PCは,1つの機械語命令の実行で,どのように変化するか
CPUは演算のためのER0,ER1などのレジスタ,PC(プログラムカウンタ),表示には現れないが,読み出した機械語命令,今のところ使用していないSP(スタックポインタ),CCR(コンディションコードレジスタ)しか持っていない。上記の作業では最初にプログラムリストを表示させているが,このプログラムリストをCPUが持っているわけではない。
メモリ上のあるアドレスに格納されている機械語命令を実行した直後にPCの値が変化しているが,次に行うべき機械語命令のアドレスを,プログラムリストを見て決めているのではない。(人間はプログラムリストを見て,次の機械語命令の格納されているアドレスを知ることができるのとはまったく異なる)
CPUは現在実行すべき機械語命令の最初の1バイトを見て,その機械語命令が何バイト構成かわかり,そのバイト数だけ,メモリから順番に命令を読み出す。読み終わった次のアドレスをPCに格納している。そしてその機械語命令を実行する。
この単純な作業を行っているだけだが,プログラムリストを上から1行ずつ実行しているように人間には見えている。
H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
課題1 変数アドレスを変更したバージョンの引き算 |
FF200から機械語プログラムを置きなさい。 実行時に,FF700,FF701番地の2byteデータにはab78を |
3. 複数の2バイト整数データのハンドリング
目的 | モニタプログラム上で,簡単なアセンブリプログラムを記述し,ステップ実行し,各レジスタが変化する様子を確認する。 |
例題2 |
FF200から機械語プログラムを置きなさい。 実行時に4つのデータを適当にセットし,以下を報告しなさい。 |
実行例 | : a ff200 FF200 > mov.w @ff800:24,r0 FF206 > mov.w @ff802:24,r1 FF20C > add.w r1,r0 FF20E > mov.w @ff804:24,r1 FF214 > add.w r1,r0 FF216 > mov.w @ff806:24,r1 FF21C > add.w r1,r0 FF21E > mov.w r0,@ff808:24 FF224 > . : m ff800 FF800 34 ? 00 FF801 56 ? 01 FF802 78 ? 00 FF803 90 ? 12 FF804 BB ? 00 FF805 C6 ? 22 FF806 FF ? 00 FF807 FF ? 31 FF808 00 ? . : d ff800 ff80f <ADDR> < D A T A > < ASCII CODE > FF800 00 01 00 12 00 22 00 31 00 00 FF FF 00 00 FF FF ".....".1........" : da ff200 ff21e <ADDR> <CODE> <MNEMONIC> <OPERAND> FF200 6B20000FF800 MOV.W @H'FF800:24,R0 FF206 6B21000FF802 MOV.W @H'FF802:24,R1 FF20C 0910 ADD.W R1,R0 FF20E 6B21000FF804 MOV.W @H'FF804:24,R1 FF214 0910 ADD.W R1,R0 FF216 6B21000FF806 MOV.W @H'FF806:24,R1 FF21C 0910 ADD.W R1,R0 FF21E 6BA0000FF808 MOV.W R0,@H'FF808:24 : r PC=0FF21A CCR=A9:I.H.N..C SP=000FFF00 ER0=0000BBC6 ER1=00007890 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 : .pc PC=0FF21A ? ff200 CCR=A9 ? . : s PC=0FF206 CCR=A1:I.H....C SP=000FFF00 ER0=00000001 ER1=00007890 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF200 6B20000FF800 MOV.W @H'FF800:24,R0 : s PC=0FF20C CCR=A1:I.H....C SP=000FFF00 ER0=00000001 ER1=00000012 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF206 6B21000FF802 MOV.W @H'FF802:24,R1 : s PC=0FF20E CCR=80:I....... SP=000FFF00 ER0=00000013 ER1=00000012 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF20C 0910 ADD.W R1,R0 : s PC=0FF214 CCR=80:I....... SP=000FFF00 ER0=00000013 ER1=00000022 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF20E 6B21000FF804 MOV.W @H'FF804:24,R1 : s PC=0FF216 CCR=80:I....... SP=000FFF00 ER0=00000035 ER1=00000022 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF214 0910 ADD.W R1,R0 : s PC=0FF21C CCR=80:I....... SP=000FFF00 ER0=00000035 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF216 6B21000FF806 MOV.W @H'FF806:24,R1 : s PC=0FF21E CCR=80:I....... SP=000FFF00 ER0=00000066 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF21C 0910 ADD.W R1,R0 : s PC=0FF224 CCR=80:I....... SP=000FFF00 ER0=00000066 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF21E 6BA0000FF808 MOV.W R0,@H'FF808:24 : d ff800 ff80f <ADDR> < D A T A > < ASCII CODE > FF800 00 01 00 12 00 22 00 31 00 66 FF FF 00 00 FF FF ".....".1.f......" : |
H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
課題2 4つのデータの和を作る |
FF200から機械語プログラムを置きなさい。 実行時に4つのデータを適当にセットし,全作業を報告しなさい。 |
4. ジャンプ命令
ジャンプ命令はPC(プログラムカウンタ)を書き換えることで,実現されていることを確認しよう。
目的 | ジャンプ命令を実行するとプログラムカウンタが書き換えられて,ジャンプ先の命令を実行するようになることを確認する。 |
例題3 |
FF200から機械語プログラムを置きなさい。 |
実行例1 jmp命令 PCの変化に 注目 |
: a ff200 FF200 > jmp @ff300:24 FF204 > . : da ff200 ff200 <ADDR> <CODE> <MNEMONIC> <OPERAND> FF200 5A0FF300 JMP @H'FF300:24 : .pc PC=0FF224 ? ff200 CCR=80 ? . : r PC=0FF200 CCR=80:I....... SP=000FFF00 ER0=00000066 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 : s PC=0FF300 CCR=80:I....... SP=000FFF00 ER0=00000066 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF200 5A0FF300 JMP @H'FF300:24 : |
実行例2 bra命令 PCの変化に 注目 |
: a ff200 FF200 > bra ff210:8 FF202 > . : da ff200 ff200 <ADDR> <CODE> <MNEMONIC> <OPERAND> FF200 400E BRA FF210:8 : .pc PC=0FF22E ? ff200 CCR=80 ? . : r PC=0FF200 CCR=80:I....... SP=000FFF00 ER0=12344321 ER1=34566543 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 : s PC=0FF210 CCR=80:I....... SP=000FFF00 ER0=12344321 ER1=34566543 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF200 400E BRA FF210:8 |
解説
人間は,プログラムリストを見て,「ここにジャンプ命令があるから,次はこちらにプログラム実行の流れが変わって・・・」といように理解するが,CPUはプログラムリスト全体を見てジャンプするわけではない。
ジャンプ命令内に,ジャンプすべきアドレスに関する情報が埋め込まれており,その情報をもとに,ジャンプすべきアドレスをPC(プログラムカウンタ)に書き込んでいるだけである。その結果,CPUの次に行うべき機械語命令が離れた場所になってしまい,人間から見ると,作業の流れがジャンプしたように見えることになる。(PCが書き換わってしまったためにCPUがだまされる)
H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
補足説明 絶対アドレスジャンプ命令(JMP)と相対アドレスジャンプ命令(BRA)
絶対アドレスジャンプ命令は,機械語命令中にジャンプ先アドレスが書かれている。上の例では,
「jmp @ff300:24」は3バイト命令「5A0FF300」に翻訳されている。「5A」が「JMP」にあたり,「0FF300」のアドレスが
そのまま書かれている。相対アドレスジャンプ命令は,ジャンプ命令のすぐ次の命令の置かれているアドレス値にからどれくらい離れたところにジャンプするかを示すようになっている。
上の例では,「bra ff210:8」は2バイト命令「400E」に翻訳されている。40がブランチ(ジャンプ)命令で,0Eがアドレス増加量である。
FF200におかれた機械語「400E」は2バイトなので,本来ならPCはFF202になるはずである。
FF202+0E=FF210なのでこの命令の直後にPCはFF210になる。
相対アドレスジャンプ命令で書かれたプログラムは,プログラムモジュールが別のアドレスに置かれていても正しく動作することができる。
課題3 ジャンプ命令 |
FF200から機械語プログラムを置きなさい。途中には何も書かなくてもよい。 |
4(補) 条件ジャンプ命令とCCR(コンディションコードレジスタ)
jmpやbraは「無条件ジャンプ命令」と呼ばれる。これらに対して,ある条件が成り立つときだけ,ジャンプする命令は「条件ジャンプ命令」である。ある条件とは直前の命令の作業結果がゼロになったとか,負になったとかという内容であり,これらはコンディションコードレジスタCCRに保存されている。命令が行われるたびにコンディションコードレジスタの内容は変化する。
コンディションコードレジスタ(8ビット:16進2ケタ)の値もr命令で表示される。
PC=000000 CCR=80:I.......
SP=000FFF00
ER0=00000000 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
この赤い字のところがCCRであり,16進表示2ケタと各ビットが表示されている。この表示では最上位ビットが1で残りの7ビットは0であることを示している。コンディションコードレジスタの各ビットの意味はマニュアルで調べること。ここでは第2ビット(下から3つ目のビット)に着目する。このビットはゼロフラグと呼ばれており,命令の結果が0になるとゼロフラッグは1になるように動作する。ゼロフラグが1になると
CCR=84:I....Z..
のように表示される。
次のプログラムを動かして動作を確かめてみよう。
: a ff200
FF200 > mov.b #03:8,r0l
FF202 > mov.b
#00:8,r0h
FF204 > add.b #10:8,r0h
FF206 > dec.b r0l
FF208
> bne ff204:8
FF20A > mov.b r0h,r1l
FF20C > nop
FF20E
> .
: da ff200 ff20c
<ADDR> <CODE> <MNEMONIC>
<OPERAND>
FF200 F803 MOV.B #H'03:8,R0L
FF202 F000 MOV.B
#H'00:8,R0H
FF204 8010 ADD.B #H'10:8,R0H
FF206 1A08 DEC.B
R0L
FF208 46FA BNE FF204:8
FF20A 0C09 MOV.B R0H,R1L
FF20C 0000
NOP
R0L(8bitレジスタ)に3を保存
R0H(同上)に0を保存
R0Hに0x10を加える
R0Lを1減らす(R0L--
decriment)
Branch Not Equal
Zero
直前の演算がゼロでなかったらジャンプ
実際には,ゼロフラグがnot1でジャンプ
上記のプログラムは次のようなC言語のdo-whileの構文になっている
int x=3; |
ただし 変数は次のように対応している x:R0L y:R0H z:R1L |
機械語プログラムを動作させます。
: r
PC=000000 CCR=80:I.......
SP=000FFF00
ER0=00000000 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00
:
.pc
PC=000000 ? ff200
CCR=80 ? .
: r
PC=0FF200 CCR=80:I.......
SP=000FFF00
ER0=00000000 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00
:
s
PC=0FF202 CCR=80:I....... SP=000FFF00
ER0=00000003 ER1=00000000
ER2=00000000 ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF200 F803 MOV.B #H'03:8,R0L
: s
PC=0FF204 CCR=84:I....Z.. SP=000FFF00
ER0=00000003
ER1=00000000 ER2=00000000 ER3=00000000
ER4=00000000 ER5=00000000
ER6=00000000 ER7=000FFF00
FF202 F000 MOV.B #H'00:8,R0H
:
s
PC=0FF206 CCR=80:I....... SP=000FFF00
ER0=00001003 ER1=00000000
ER2=00000000 ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF204 8010 ADD.B #H'10:8,R0H
: s
PC=0FF208
CCR=80:I....... SP=000FFF00
ER0=00001002 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF206 1A08 DEC.B R0L
: s
PC=0FF204 CCR=80:I.......
SP=000FFF00
ER0=00001002 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF208 46FA BNE FF204:8
: s
PC=0FF206 CCR=80:I.......
SP=000FFF00
ER0=00002002 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF204 8010 ADD.B #H'10:8,R0H
: s
PC=0FF208
CCR=80:I....... SP=000FFF00
ER0=00002001 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF206 1A08 DEC.B R0L
: s
PC=0FF204 CCR=80:I.......
SP=000FFF00
ER0=00002001 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF208 46FA BNE FF204:8
: s
PC=0FF206 CCR=80:I.......
SP=000FFF00
ER0=00003001 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF204 8010 ADD.B #H'10:8,R0H
: s
PC=0FF208 CCR=84:I....Z.. SP=000FFF00
ER0=00003000
ER1=00000000 ER2=00000000 ER3=00000000
ER4=00000000 ER5=00000000
ER6=00000000 ER7=000FFF00
FF206 1A08 DEC.B R0L
: s
PC=0FF20A
CCR=84:I....Z.. SP=000FFF00
ER0=00003000 ER1=00000000 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF208 46FA BNE FF204:8
: s
PC=0FF20C CCR=80:I.......
SP=000FFF00
ER0=00003000 ER1=00000030 ER2=00000000
ER3=00000000
ER4=00000000 ER5=00000000 ER6=00000000
ER7=000FFF00
FF20A 0C09 MOV.B R0H,R1L
各レジスタの確認
プログラムカウンタのセット
PCの確認
3→R0L
0→R0H
このとき,命令の結果はR0Hを0にしたので
Zフラグが立った(1になった)
プログラム上は意味はない
R0H+R0H→R0H
Zフラグはもとに戻った
R0L--
まだZフラグは立たない
Zフラグは立っていないのでFF204にジャンプ
R0H+R0H→R0H
R0L--
まだZフラグは立たない
Zフラグは立っていないのでFF204にジャンプ
R0H+R0H→R0H
R0L--
R0LがゼロになったのでZフラグが立った
Zフラグが立ったのでジャンプしない
で次の命令(FF20Aの命令)に進んだ
ジャンプ命令ではZフラグは変化しない
課題 |
上記のプログラムを変更して1から10まで和を求めるプログラムにしなさい。 |
ここでは,ZフラグとBNEの関係について述べたが,加算や減算などの演算結果が負になるとNフラグが立ち,加算や減算などの演算結果がオーバーフローするとVフラグが立ち,シフト演算などでキャリにビットがあふれるとCフラグが立ち,それぞれの条件でジャンプする命令がある。それらのジャンプ命令はマニュアルにおいては,「Bcc」で見つけることができる。
5. スタックとpush命令/pop命令
スタックはレジスタ内容の一時保管に使われるメモリ(当然RAM領域)の一部である。
保管データは,スタック用のメモリの後ろから前(若いアドレス)に向かって保管される。
メモリ中のどこがスタックとして使われているのかを示しているのがスタックポインタである。
最初にFR7(SPの働きをしている)に値を設定し,どこをスタックとして使うかを決めている。
スタックポインタは現在までにスタックとして使われているメモリの一番前の(一番若い)アドレスを指している。
目的 | push命令とpop命令により,指定されたレジスタの内容がメモリのスタック領域に格納され,またレジスタに書き戻されること,スタックポインタが変化することを確認する。 |
例題4 |
FF200から機械語プログラムを置きなさい。 |
実行例 | : a ff200 FF200 > mov.l #fff00:32,er7 FF206 > mov.l #12344321:32,er0 FF20C > push.l er0 FF210 > pop.l er1 FF214 > . : da ff200 ff210 <ADDR> <CODE> <MNEMONIC> <OPERAND> FF200 7A07000FFF00 MOV.L #H'000FFF00:32,ER7 FF206 7A0012344321 MOV.L #H'12344321:32,ER0 FF20C 01006DF0 PUSH.L ER0 FF210 01006D71 POP.L ER1 : .pc PC=0FF300 ? ff200 CCR=80 ? . : d ffef0 fff00 <ADDR> < D A T A > < ASCII CODE > FFEF0 A0 00 FF DF 00 00 D7 FE 80 80 29 B0 00 0F F3 02 "..........)....." FFF00 00 "." : r PC=0FF200 CCR=80:I....... SP=000FFF10 ER0=00000066 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF10 : s PC=0FF206 CCR=80:I....... SP=000FFF00 ER0=00000066 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF200 7A07000FFF00 MOV.L #H'000FFF00:32,ER7 : s PC=0FF20C CCR=80:I....... SP=000FFF00 ER0=12344321 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF206 7A0012344321 MOV.L #H'12344321:32,ER0 : s PC=0FF210 CCR=80:I....... SP=000FFEFC ER0=12344321 ER1=00000031 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEFC FF20C 01006DF0 PUSH.L ER0 : d ffef0 fff00 <ADDR> < D A T A > < ASCII CODE > FFEF0 A0 00 FF DF 80 80 29 B0 00 0F F2 12 12 34 43 21 "......)......4C!" FFF00 00 "." : s PC=0FF214 CCR=80:I....... SP=000FFF00 ER0=12344321 ER1=12344321 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF210 01006D71 POP.L ER1 : d ffef0 fff00 <ADDR> < D A T A > < ASCII CODE > FFEF0 A0 00 FF DF 80 80 29 B0 00 0F F2 12 12 34 43 21 "......)......4C!" FFF00 00 "." : |
H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
最初の命令でスタックポインタに0FFF00を設定しているので,スタック領域は0FFEFFから若いアドレスに向かって設定されたことになる。
最初の時点でスタックポインタに0FFF00が設定されているが,このアドレスはスタック領域の外部になっていることに注意しよう。
次に4バイトがpushされると,スタックポインタは4小さくなり,0FFEFCになる。
この時スタック領域では0FFEFCから0FFEFFの4バイトにpushされた値が格納されているのがわかる。
「マイクロコンピュータH8の構成と機械語プログラムの動作」の「6.スタックとスタックポインタ」を参照すること。
使用していないスタック領域のメモリ内容はだれも手をつけないので,本当は変化しないはずであるが,
モニタプログラムがこっそりと使っているため変化している。これは無視すること。
課題4 |
FF200から機械語プログラムを置きなさい。 |
6. スタックへのレジスタの退避と復帰
目的 | レジスタの内容をスタック領域に退避させ,そのレジスタを別の用途に使用した後,スタック領域に保存された内容をレジスタに戻す作業を確認する。 |
例題5 |
FF200から機械語プログラムを置きなさい。 |
実行例 | : a ff200 FF200 > mov.l #fff00:32,er7 FF206 > mov.l #12344321:32,er0 FF20C > mov.l #34566543:32,er1 FF212 > push.l er0 FF216 > push.l er1 FF21A > mov.l #0:32,er0 FF220 > mov.l #0:32,er1 FF226 > pop.l er1 FF22A > pop.l er0 FF22E > . : da ff200 ff22a <ADDR> <CODE> <MNEMONIC> <OPERAND> FF200 7A07000FFF00 MOV.L #H'000FFF00:32,ER7 FF206 7A0012344321 MOV.L #H'12344321:32,ER0 FF20C 7A0134566543 MOV.L #H'34566543:32,ER1 FF212 01006DF0 PUSH.L ER0 FF216 01006DF1 PUSH.L ER1 FF21A 7A0000000000 MOV.L #H'00000000:32,ER0 FF220 7A0100000000 MOV.L #H'00000000:32,ER1 FF226 01006D71 POP.L ER1 FF22A 01006D70 POP.L ER0 : d ffef0 fff00 <ADDR> < D A T A > < ASCII CODE > FFEF0 A0 00 FF DF 80 80 29 B0 80 80 29 B0 00 0F F2 16 "......)...)....." FFF00 00 "." : .pc PC=0FF212 ? ff200 CCR=80 ? . : .er0 ER0=12344321 ? 0 ER1=34566543 ? 0 ER2=00000000 ? . : r PC=0FF200 CCR=80:I....... SP=000FFF00 ER0=00000000 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 : s PC=0FF206 CCR=80:I....... SP=000FFF00 ER0=00000000 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF200 7A07000FFF00 MOV.L #H'000FFF00:32,ER7 : s PC=0FF20C CCR=80:I....... SP=000FFF00 ER0=12344321 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF206 7A0012344321 MOV.L #H'12344321:32,ER0 : s PC=0FF212 CCR=80:I....... SP=000FFF00 ER0=12344321 ER1=34566543 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF20C 7A0134566543 MOV.L #H'34566543:32,ER1 : s PC=0FF216 CCR=80:I....... SP=000FFEFC ER0=12344321 ER1=34566543 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEFC FF212 01006DF0 PUSH.L ER0 : d ffef0 fff00 <ADDR> < D A T A > < ASCII CODE > FFEF0 A0 00 FF DF 80 80 29 B0 00 0F F2 18 12 34 43 21 "......)......4C!" FFF00 00 "." : s PC=0FF21A CCR=80:I....... SP=000FFEF8 ER0=12344321 ER1=34566543 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEF8 FF216 01006DF1 PUSH.L ER1 : d ffef0 fff00 <ADDR> < D A T A > < ASCII CODE > FFEF0 80 80 29 B0 00 0F F2 1C 34 56 65 43 12 34 43 21 "..).....4VeC.4C!" FFF00 00 "." : s PC=0FF220 CCR=84:I....Z.. SP=000FFEF8 ER0=00000000 ER1=34566543 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEF8 FF21A 7A0000000000 MOV.L #H'00000000:32,ER0 : s PC=0FF226 CCR=84:I....Z.. SP=000FFEF8 ER0=00000000 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEF8 FF220 7A0100000000 MOV.L #H'00000000:32,ER1 : s PC=0FF22A CCR=80:I....... SP=000FFEFC ER0=00000000 ER1=34566543 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEFC FF226 01006D71 POP.L ER1 : s PC=0FF22E CCR=80:I....... SP=000FFF00 ER0=12344321 ER1=34566543 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF22A 01006D70 POP.L ER0 : |
解説
人間は,プログラムリストを見て,「ここにサブルーチンコール命令があるから,次はこっちにプログラム実行の流れが変わって・・・,最後にリターン命令があるから,先ほどのサブルーチンコール命令の次の命令に戻る」といように理解するが,CPUはプログラムリストを見てこれらの2回のジャンプするわけではない。
サブルーチンコール命令内に,ジャンプすべきアドレスに関する情報が埋め込まれており,その情報をもとに,ジャンプすべきサブルーチン先頭アドレスをPC(プログラムカウンタ)に書き込んでいるだけである。その結果,CPUの次に行うべき機械語命令が離れた場所になってしまい,人間から見ると,作業の流れがジャンプしたように見えることになる。またサブルーチンコール命令は,同時に本来のPC(プログラムカウンタ)の値をスタックに保存する。
最後にリターン命令になると(リターン命令には戻るべきアドレス情報は含まれていない),スタックから戻るべきアドレスを取り出してPC(プログラムカウンタ)に格納し,サブルーチンコール命令の次の命令のアドレスにジャンプすることになる。
ところで,サブルーチンコール命令では,戻るべき番地をスタックに保存しているが。サブルーチン内でさらに別なサブルーチンを呼び出す場合でも,戻るべき番地をスタックに保存する。さらにサブルーチンを呼び出しても同様である。これは,スタックがLastIn-FirstOut(最後に入れたものが最初に取り出される)の性質を持っているからである。
H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
「マイクロコンピュータH8の構成と機械語プログラムの動作」の「6.スタックとスタックポインタ」を参照すること。
課題5 |
FF200から機械語プログラムを置きなさい。 |
7. サブルーチンコールとサブルーチンからのリターン
C言語の関数呼び出しと同じ機能(実際には全く同じもの)
サブルーチンコールの時には,戻り番地がスタックに保存され,PC(プログラムカウンタ)の値を
サブルーチンの先頭に設定してジャンプし,サブルーチンから戻るときにはスタックに保存されて
いるアドレスをPCに設定してジャンプして,サブルーチン呼び出し側の先ほどの続きの作業を行っ
ていることを確認しよう。
目的 | サブルーチンコールとサブルーチンからのリターンについて,スタックの仕掛けを用いて,戻り番地を保存しているところを確認する。 | |
例題6 |
FF200から機械語プログラムを置きなさい。 サブルーチンコール先のアドレスはわからないので,推定値を書いておいて,サブルーチンを書いた後にアドレス | |
実行例 | : a ff200 FF200 > mov.l #fff00:32,er7 FF206 > mov.w @ff800:24,r0 FF20C > bsr ff210:8 FF20E > mov.w r0,@ff802:24 FF214 > bra ff214:8 FF216 > shll.w r0 FF218 > shll.w r0 FF21A > rts FF21C > . : a ff20c FF20C > bsr ff216:8 FF20E > . : da ff200 ff21c <ADDR> <CODE> <MNEMONIC> <OPERAND> FF200 7A07000FFF00 MOV.L #H'000FFF00:32,ER7 FF206 6B20000FF800 MOV.W @H'FF800:24,R0 FF20C 5508 BSR FF216:8 FF20E 6BA0000FF802 MOV.W R0,@H'FF802:24 FF214 40FE BRA FF214:8 FF216 1010 SHLL.W R0 FF218 1010 SHLL.W R0 FF21A 5470 RTS FF21C 0001 .DATA.W H'0001 : d ffef0 fff00 <ADDR> < D A T A > < ASCII CODE > FFEF0 A0 00 FF DF 00 00 D7 FE 00 00 BF DF 41 00 BF FF "............A..." FFF00 00 "." : d ff800 ff80f <ADDR> < D A T A > < ASCII CODE > FF800 00 00 DF EF 00 00 FF 7F 00 80 FF FF 00 00 FF ED "................" : m ff800 FF800 00 ? 02 FF801 00 ? 03 FF802 DF ? . : d ff800 ff80f <ADDR> < D A T A > < ASCII CODE > FF800 02 03 DF EF 00 00 FF 7F 00 80 FF FF 00 00 FF ED "................" : .pc PC=000000 ? ff200 CCR=80 ? . : r PC=0FF200 CCR=80:I....... SP=00FFFF10 ER0=00000000 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=00FFFF10 : s PC=0FF206 CCR=80:I....... SP=000FFF00 ER0=00000000 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF200 7A07000FFF00 MOV.L #H'000FFF00:32,ER7 : s PC=0FF20C CCR=80:I....... SP=000FFF00 ER0=00000203 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF206 6B20000FF800 MOV.W @H'FF800:24,R0 : s PC=0FF216 CCR=80:I....... SP=000FFEFC ER0=00000203 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEFC FF20C 5508 BSR FF216:8 : d ffef0 fff00 <ADDR> < D A T A > < ASCII CODE > FFEF0 A0 00 FF DF 80 80 29 B0 00 0F F2 18 00 0F F2 0E "......)........." FFF00 00 "." : s PC=0FF218 CCR=80:I....... SP=000FFEFC ER0=00000406 ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEFC FF216 1010 SHLL.W R0 : s PC=0FF21A CCR=80:I....... SP=000FFEFC ER0=0000080C ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFEFC FF218 1010 SHLL.W R0 : s PC=0FF20E CCR=80:I....... SP=000FFF00 ER0=0000080C ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF21A 5470 RTS : s PC=0FF214 CCR=80:I....... SP=000FFF00 ER0=0000080C ER1=00000000 ER2=00000000 ER3=00000000 ER4=00000000 ER5=00000000 ER6=00000000 ER7=000FFF00 FF20E 6BA0000FF802 MOV.W R0,@H'FF802:24 : d ff800 ff80f <ADDR> < D A T A > < ASCII CODE > FF800 02 03 08 0C 00 00 FF 7F 00 80 FF FF 00 00 FF ED "................" : |
とりあえずff210にしておく 無限ループ,ここまでがmain ここからサブルーチン ReTurn from Subroutine サブルーチンコールのアドレスが ff216だとわかったので書き直し スタック領域の確認 データ領域の確認 データの設定 データ領域の確認 サブルーチンコール スタックに戻り番地を積む スタックに戻り番地が積まれている ことの確認 ReTurn from Subroutine スタックから戻り番地を プログラムカウンタに取り込んだ |
H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
「マイクロコンピュータH8の構成と機械語プログラムの動作」の「8.サブルーチンコールとリターン」を参照すること。
課題6 |
FF200から機械語プログラムを置きなさい。 |
8. まとめ
8.1 機械語命令の実行
機械語命令はメモリ上に書かれている
PC(プログラムカウンタ)は次に実行すべき機械語命令が書かれているアドレスを指している
1つの機械語命令はPCの指しているメモリから読みだされ,命令の意味が解析され,実行される
1つの機械語命令の実行が終わると,PCの値はその機械語命令のバイト数だけ増加する(次に実行すべき機械語命令の書かれているアドレスを指すようになる)CPUがプログラムリストを見て,次の命令の存在するアドレスをPCに書き込むわけではない!
8.2 ジャンプ命令の実行
プログラムの流れがジャンプしたように見える仕組み
通常,1つの機械語命令の実行が終わると,PC(プログラムカウンタ)の値はその機械語命令のバイト数だけ増加する(次に実行すべき機械語命令の書かれているアドレスを指すようになる)はずである。
ジャンプ命令が実行されると,PCの値は「ジャンプ命令中に示されるアドレス」になり,プログラムリスト上の実行の流れが変わる。
8.3 サブルーチンコール命令の実行
プログラムの流れがサブルーチンの先頭にジャンプしたように見え,サブルーチンからの戻り番地を覚えておく仕組み
通常,1つの機械語命令の実行が終わると,PC(プログラムカウンタ)の値はその機械語命令のバイト数だけ増加する(次に実行すべき機械語命令の書かれているアドレスを指すようになる)はずである。
サブルーチンコール命令が実行されると,PCの値はサブルーチンコール命令中に書いてあるアドレスになる。
そして,本来PCに入っているはずの値(本来,次に実行すべき機械語命令の書かれているアドレス)はスタックに保存される。
スタックへの保存とは,スタックポインタの値を「保存すべきバイト数」だけ減少させ,スタックポインタの指すアドレスに,保存すべき値を保存する。
8.4 サブルーチンリターン命令の実行
サブルーチンから,サブルーチンコールした位置に戻る仕組み
サブルーチンリターン命令が実行されるとPC(プログラムカウンタ)には,スタックに覚えられていたアドレスが書き戻される。すなわち,サブルーチンコール命令の次のアドレスがPCの値となる。