AKI-H8/3048foneのモニタプログラムでの
機械語プログラムの動作
Copyright(C)12Mar2014
since 1Aug2003
coskx
1.はじめに
この文書は,AKI-H8におけるH8/3048foneのモニタプログラム,PCターミナルソフトでの学習を記述している。
モ ニタプログラムは,新しいプログラムの動作を検証する場合や,アセンブリ言語の学習者が,1命令ずつ機械語命令を実行してCPUのふるまいを観察するプロ グラムである。モニタプログラムはROM(フラッシュメモリ)上に配置されており,検証対象のプログラムはRAM上に置かれる。
この文書では
PC上のターミナル画面からアセンブリニーモニックを直接入力してCPUの動作を見る方法
を用いて,機械語プログラムの動作を解説する。(本校)校内からは授業に使うため準備用ファイルが入手できる。またマニュアルもダウンロードしておくとよい。
このファイルを解凍すると「trial5」のフォルダが出てくるので,
作業用フォルダとして使う。
((本校)LANからのみ試用のためアクセスできる。)
(4J電子計算機IIの授業ではこれを使う)
H8機械語命令ニモニックの説明マニュアル
((本校)LANからのみアクセスできる。)
基本事項 再掲
レジスタは32ビット幅で8個あり,名前はER0,ER1,ER2,ER3,ER4,ER5,ER6,ER7である。
またER0は,2つの16ビット幅レジスタE0,R0として使うこともできる。
(従って,R0とER0を同時に別の用途に使うことはできない)
さらにまた16ビット幅レジスタR0は,2つの8ビット幅のレジスタR0H,R0Lとして使うこともできる。
(従って,R0LとR0やER0を同時に別の用途に使うことはできない)
または
ER0 (32bit)
または
E0 (16bit)
R0 (16bit)
レジスタER0の構造と使われ方
E0 (16bit)
R0H (8bit)
R0L (8bit)
ER0の構造はER1,ER2,ER3,ER4,ER5,ER6でも同じである。
例えばER1では次のようになっている
または
ER1 (32bit)
または
E1 (16bit)
R1 (16bit)
レジスタER1の構造と使われ方
E1 (16bit)
R1H (8bit)
R1L (8bit)
もう一例を上げれば,ER2では次のようになっている
または
ER2 (32bit)
または
E2 (16bit)
R2 (16bit)
レジスタER2の構造と使われ方
E2 (16bit)
R2H (8bit)
R2L (8bit)
bit,byteと16進表示についてまとめておこう
ビット数
バイト数
16進表現桁数
表現範囲
略号
バイト
8bit
1byte
2桁
00-FF
B
ワード
16bit
2byte
4桁
0000-FFFF
W
ロングワード
32bit
4byte
8桁
00000000-FFFFFFFF
L
2つの2バイト整数値の演算を行う。
メモリ保存値同士の演算は出来ないので,メモリ保存値をレジスタに移動してから演算し,演算結果をメモリに移動する。
目的 モニタプログラム上で,簡単なアセンブリプログラムを記述し,ステップ実行し,モニタプログラムの操作を修得するする。
また,各レジスタが変化する様子,メモリ上の変数の取扱いを確認する。例題1 FF200から機械語プログラムを置きなさい。
FF800番地の2byteデータをレジスタR0に載せる(実際にはFF800,FF801番地)
FF802番地の2byteデータをレジスタR1に載せる(実際にはFF802,FF803番地)
R0からR1の値を引いてR0にしまう
R0のデータをFF804番地にしまう(実際にはFF804,FF805番地)
終端処理(無限ループにしておく)
実行時に,FF800,FF801番地の2byteデータには3456を
FF802,FF803番地の2byteデータには7890をセットして以下を報告しなさい。
実行前のFF800番地?FF80F番地の様子
プログラムの逆アッセンブル結果
1命令ごとに実行して実行の様子
実行後のFF800番地?FF80F番地の様子実行例 : 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命令実行
実行結果メモリの確認
3456(Hex)-7890(Hex)
=BBC6(Hex)が検証できる
・ MOV命令に関する補足
MOV命令の意味は,move(移動)だが,コンピュータの性格上,転送元のデータが消えてしまうことは無く,コピーされるだけである。
MOV(move)命令は,「MOV.W @H'FF800:24,R0」のように使われるが,
「MOV.転送データサイズ 転送元,転送先」
の順で記述されている。・転送データサイズは,B,W,Lの3つのうちのどれかで,B:バイト(8bit),W:ワード(16bit),L:ロングワード(32bit)を表している。
・転送元はメモリ上のある番地,値(即値)あるいはレジスタ名のいずれかを書く。
値(即値)の場合は先頭に「#」を,メモリ上の番地の場合は先頭に「@」を書き,
da命令のときは,16進法表現の場合は「H'」が付けられる。
また番地の場合はその番地を表すビット数を後ろにつける。
H'FF800:24の24が番地を表すのに使っているビット数である。
・転送先にはメモリ上のある番地,あるいはレジスタ名のいずれかを書く。
ただし,メモリ中のある番地に保存されている値を直接他の番地に移すことはできない。
メモリ中のある番地に保存されている値を直接他の番地に移したいときには,
一度,メモリ中の値をレジスタに移し,そのレジスタの値を別のアドレスのメモリに移せばよい。
例
MOV.L @H'FF800:24,ER0 FF800番地から始まる4バイトをER0に移せ
MOV.W @H'FF800:24,R0 FF800番地から始まる2バイトをR0に移せ
MOV.B @H'FF800:24,R0L FF800番地から始まる1バイトをR0Lに移せ
MOV.L #H'1234CDEF,ER0 4バイトの値1234CDEF(16進法表示)をER0に移せ
MOV.W #H'12EF,R0 2バイトの値12EF(16進法表示)をR0に移せ
MOV.B #H'1F,R0L 1バイトの値1F(16進法表示)をR0Lに移せ
なお MOV.L @H'FF800:24,R0 は転送サイズと宛先レジスタサイズが一致しないため,実行できない。
また, MOV.W @H'FF800:24,@H'FF802:24 はメモリ間の転送命令になってしまうので,不当命令である
・ PCは,1つの機械語命令の実行で,どのように変化するか(補足説明 )
CPUは演算のためのER0,ER1などのレジスタ,PC(プログラムカウンタ),表示には現れないが,読み出した機械語命令,今のところ使 用していないSP(スタックポインタ),CCR(コンディションコードレジスタ)しか持っていない。上記の作業では最初にプログラムリストを表示させてい るが,それはモニタプログラムが表示しているだけで,プログラムリストをCPUが持っているわけではない。
メモリ上のあるアドレスに格納されて いる機械語命令を実行した直後にPCの値が変化しているが,次に行うべき機械語命令のアドレスを,プログラムリストを見て決めているのではない。人間はプ ログラムリストを見て,次の機械語命令の格納されているアドレスを知ることができるのとはまったく異なる。
CPUは現在実行すべき機械語命令の最初の1バイトを見て,その機械語命令が何バイト構成かわかり,そのバイト数だけ,メモリから順番に命令を読み出す。読み終わった次のアドレスをPCに格納している。そしてその機械語命令を実行する。
この単純な作業を行っているだけだが,プログラムリストを上から1行ずつ実行しているように人間には見えている。
課題1 変数アドレスを変更したバージョンの引き算 |
FF200から機械語プログラムを置きなさい。 作成したプログラム本体を報告に載せなさい。 実行時に,FF700,FF701番地の2byteデータにはab78を ただし,以下の内容を含むこと |
3. 複数の2バイト整数データの演算
目的 モニタプログラム上で,簡単なアセンブリプログラムを記述し,ステップ実行し,
各レジスタが変化する様子を確認する。例題2 FF200から機械語プログラムを置きなさい。
FF800,FF801番地の2byteデータ(2byteデータ=ワードデータ),
FF802,FF803番地の2byteデータ,
FF804,FF805番地の2byteデータ,
FF806,FF807番地の2byteデータをすべて加え,
FF808,FF809番地の2byteデータにしなさい。
オーバーフローしてもかまわないこととする。実行時に4つのデータを適当にセットし,以下を実行する。
実行前のFF800番地?FF810番地の様子を見る
プログラムの逆アッセンブル結果
1命令ごとに実行して実行の様子
実行後のFF800番地?FF810番地の様子を見る実行例 : 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. ジャンプ命令
ジャンプ命令はPC(プログラムカウンタ)を書き換えることで,実現されていることを確認しよう。
目的 ジャンプ命令を実行するとプログラムカウンタが書き換えられて,ジャンプ先の命令を実行するようになることを確認する。 例題3 FF200から機械語プログラムを置きなさい。
ジャンプ命令を1つだけを書きなさい。
ジャンプ先アドレスは適当でかまわない。
1命令実行後のプログラムカウンタがどうなったか調べなさい。
3例ほど行い,結果を報告しなさい。
jmp命令では jmp @ff230:24
bra命令では bra ff230:8
のように書く
jmp命令は絶対アドレス(24ビット)指定(4バイト命令)のジャンプ命令
bra命令は相対アドレス(8ビット±127以下)指定(2バイト命令)のジャンプ命令(branch分岐の意味)
ただしbra命令は:8でなく:16と書くと,相対アドレス(16ビット±32767以下)指定(4バイト命令)
のジャンプ命令となる。
例
bra ff230:8 相対アドレス(8ビット±127以下)指定のジャンプ命令
bra ff230:16 相対アドレス(16ビット±32767以下)指定のジャンプ命令実行例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
:
本来なら4バイト命令だから,PCはFF204になるはずであったが,ジャンプ命令(=PC書き換え命令)のためPCはFF300になってしまった。
実行例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
本来なら2バイト命令だから,PCはFF202になるはずであったが,ジャンプ命令(=PC書き換え命令)のためPCはFF210になってしまった。
解説
人間は,プログラムリストを見て,「ここにジャンプ命令があるから,次はこちらにプログラム実行の流れが変わって・・・」といように理解するが,CPUはプログラムリスト全体を見てジャンプするわけではない。
ジャ ンプ命令内に,ジャンプすべきアドレスに関する情報が埋め込まれており,その情報をもとに,ジャンプすべきアドレスをPC(プログラムカウンタ)に書き込 んでいるだけである。その結果,次に行うべき機械語命令が離れた場所から読みだされる結果となってしまい,人間から見ると,作業の流れがジャンプしたように見える。(PCが書き換わってしまったためにCPUがだまされる)
ジャンプ命令はPC(プログラムカウンタ)書き換え命令である。
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になるように動作する。
(通常はZフラグは0である。)
ゼロフラグが1になると
CCR=84:I....Z..
のように表示される。(CCR=84:10000100というのは不親切なので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でジャンプ
nop は no operation 何もしないという意味上記のプログラムは次のようなC言語のdo-whileの構文になっている
int x=3;
int y=0;
int z;
do {
y+=0x10;
x--;
} while (0<x);
z=y;ただし
変数は次のように対応している
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フラグは変化しない
ここでは,ZフラグとBNEの関係について述べたが,加算や減算などの演算結果が負になるとNフラグが立ち,加算や減算などの演算結果がオーバーフ ローするとVフラグが立ち,シフト演算などでキャリにビットがあふれるとCフラグが立ち,それぞれの条件でジャンプする命令がある。それらのジャンプ命令 はマニュアルにおいては,「Bcc」で見つけることができる。
課題4 条件ジャンプ |
上記のプログラムを変更して1から10まで和を求めるプログラムにしなさい。 作成したプログラム本体を報告に載せなさい。 |
5. スタックとpush命令/pop命令
スタックのイメージは「マイクロコンピュータH8の構成と機械語プログラムの動作」の該当箇所を参照すること
スタックはレジスタ内容の一時保管に使われるメモリ(当然RAM領域)の一部である。
保管データは,スタック用のメモリの後ろから前(若いアドレス)に向かって保管される。
メモリ中のどこをスタックとして使用中なのかを示しているのがスタックポインタである。
最初にER7(SPの働きをしている)に値を設定し,どこをスタックとして使うかを決めている。
スタックポインタは現在までにスタックとして使われているメモリの一番前の(一番若い)アドレスを指している。
目的 push命令とpop命令により,指定されたレジスタの内容がメモリのスタック領域に格納され,
またレジスタに書き戻されること,スタックポインタが変化することを確認する。例題4 FF200から機械語プログラムを置きなさい。
スタックポインタにFFF00をセットする。
レジスタER0に12344321をセットする。
レジスタER0をpushする。 (ER0の内容がスタック内のスタックポインタが指す場所に保存される)
レジスタER1にpopする。 (スタックに最後に保存された内容がER1に載せられる)
1命令ずつ実行すると
ER0,ER1,PC(プログラムカウンタ)SP(スタックポインタ,ER7のこと。
表示ではSPとER7が別物のように表示されているが,内容は常に同一の値になっている),
FFEF0からFFF00までのメモリの様子
はどうなるか,観察して,報告しなさい。
push命令 指定されたレジスタの内容を,スタック領域のスタックポインタの指すメモリに,退避させる。
pop命令 スタック領域のスタックポインタの指すメモリの内容を,指定されたレジスタに,取り戻す。
使い終わったスタックエリアは,他のプログラムが勝手に使うことがあるので,身に覚えのない値が入っていることがある。
(下の実行例の最終表示では,たまたま前の値が残っているが,常にこのようになるとは限らない)実行例 : a ff200
FF200 > mov.l #fff00:32,er7
FF206 > mov.l #12384521: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 7A0012384521 MOV.L #H'12384521: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=12384521 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=12384521 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 38 45 21 "......)......8E!"
FFF00 00 "."
: s
PC=0FF214 CCR=80:I....... SP=000FFF00
ER0=12384521 ER1=12384521 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 38 45 21 "......)......8E!"
FFF00 00 "."
:
初期状態の確認
スタックポインタが
FFF10
を指している。
スタックポインタが
FFF00
を指すように
なった。
スタックポインタが
4減って,FFEFC
を指すようになり,
ER0の値が
FFEFCから
FFEFFに保存
された。
スタックポインタが
FFF00に戻り,
ER1にFFEFCから
FFEFFの内容が
保存された。
H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
最初の命令でスタックポインタに0FFF00を設定しているので,スタック領域は0FFEFFから若いアドレスに向かって設定されたことになる。
最初の時点でスタックポインタに0FFF00が設定されているが,このアドレスはスタック領域の外部になっていることに注意しよう。
次に4バイトがpushされると,スタックポインタは4小さくなり,0FFEFCになる。
この時スタック領域では0FFEFCから0FFEFFの4バイトにpushされた値が格納されているのがわかる。
「マイクロコンピュータH8の構成と機械語プログラムの動作」の「6.スタックとスタックポインタ」を参照すること。
動作をまとめると次のようになっている。・push.l er0
最初にSPの値が4減少する.そして減少したSPの値を先頭
アドレスとするメモリ領域(4バイト)にレジスタer0の
値が保存される.
・pop.l er2
現在のSPの値を先頭アドレスとするメモリ領域(4バイト)
にある値をレジスタer2に保存する.そしてSPの値は4増加
する.
使用していないスタック領域のメモリ内容はだれも手をつけないので,本当は変化しないはずであるが,
モニタプログラムがこっそりと使っているため変化している。これは無視すること。
課題5 push命令・pop命令とスタックの変化,スタックポインタの動き |
FF200から機械語プログラムを置きなさい。 作成したプログラム本体を報告に載せなさい。 1命令ずつ実行すると push命令実行直前のスタックポインタの値,実行直後のスタックポインタの値,どのレジスタの内容がどこのアドレスのメモリに格納されたのか, (mon1ex05.txt) |
6. スタックへのレジスタの退避と復帰
目的 レジスタの内容をスタック領域に退避させ,そのレジスタを別の用途に使用した後,
スタック領域に保存された内容をレジスタに戻す作業を確認する。例題5 FF200から機械語プログラムを置きなさい。
スタックポインタにFFF00をセットする。
レジスタER0に12344321をセットする。
レジスタER1に34566543をセットする。
レジスタER0をpushする。
レジスタER1をpushする。
レジスタER0に0をセットする。(ER0を別用途に使ったと想定する)
レジスタER1に0をセットする。(ER1を別用途に使ったと想定する)
レジスタER1にpopする。
レジスタER0にpopする。
1命令ずつ実行すると
ER0,ER1,PC(プログラムカウンタ)SP(スタックポインタ,ER7と同じ),FFEF0からFFF00までの
メモリの様子はどうなるか,観察して,報告しなさい。実行例 : 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
:H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
「マイクロコンピュータH8の構成と機械語プログラムの動作」の「6.スタックとスタックポインタ」を参照すること。
課題6 スタックへのレジスタの退避と復帰 |
FF200から機械語プログラムを置きなさい。 作成したプログラム本体を報告に載せなさい。 |
7. サブルーチンコールとサブルーチンからのリターン
サブルーチンコールとサブルーチンからのリターンのイメージは
「マイクロコンピュータH8の構成と機械語プログラムの動作」の該当箇所を参照すること
C言語の関数呼び出しと同じ機能(実際には全く同じもの)
サブルーチンコールの時には,戻り番地がスタックに保存され,PC(プログラムカウンタ)の値を
サブルーチンの先頭に設定してジャンプし,サブルーチンから戻るときにはスタックに保存されて
いるアドレスをPCに設定してジャンプして,サブルーチン呼び出し側の先ほどの続きの作業を行っ
ていることを確認しよう。
目的 サブルーチンコールとサブルーチンからのリターンについて,スタックの仕掛けを用いて,戻り番地を保存しているところを確認する。 例題6 FF200から機械語プログラムを置きなさい。
スタックポインタにFFF00をセットする。
FF800番地の2byteデータをレジスタR0に載せる
サブルーチンをコールする
戻ってきたらレジスタR0の値をFF802番地の2byteデータとして保存
そして無限ループ
ただし,サブルーチンはsll命令(shift left logical,指定したレジスタの全データを左に1ビット分ずらす)を2回使い
レジスタR0の値を左に2つシフト(4倍になる)させ
リターンする
1命令ずつ実行すると
ER0,ER1,ER2,PC(プログラムカウンタ)SP(スタックポインタ,ER7と同じ),FFEF0からFFF00までのメモリの様子
はどうなるか,観察して,報告しなさい。アセンブル命令でサブルーチンコールを書くとき,まだサブルーチンのアドレスはわからないので,
推定値を書いておいて,サブルーチン本体を書いた後にアドレスが確定するので,後から書きなおすとよい。★
bsr命令 (branch subroutine) 指定したアドレスから始まるサブルーチンにジャンプする
rts命令 (return from subroutine) サブルーチンの終わりにおかれ,サブルーチンを呼び出したところに戻る実行例 : 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
ff216からサブルーチン
ReTurn from Subroutine
サブルーチンのアドレスが
ff216だとわかったので
書き直し
スタック領域の確認
データ領域の確認
データの設定
データ領域の確認
サブルーチンコール
スタックに戻り番地を積む
スタックに戻り番地が
積まれていることの確認
ReTurn from Subroutine
スタックから戻り番地を
プログラムカウンタに取
り込んだ解説
人間は,プログラムリストを見て,「ここにサブルーチンコール命令があるから,次はサブルーチン側にプログラム実行の流れが変わって・・・,
最後にリターン命令があるから,先ほどのサブルーチンコール命令の次の命令に戻る」といように理解する。
しかし,CPUはプログラムリストを見てこれらの2回のジャンプするわけではない。
サブルーチンコール命令内に,ジャンプすべきサブルーチン先頭アドレスが埋め込まれており,
その情報をもとに,ジャンプすべきサブルーチン先頭アドレスをPC(プログラムカウンタ)に書き込んでいるだけである。(ここまではジャンプ命令と同じ)
その結果,CPUの次に行うべき機械語命令がサブルーチンの先頭アドレスになってしまい,
人間から見ると,作業の流れがジャンプしたように見えることになる。
またサブルーチンコール命令が実行されるとき,同時に本来のPC(プログラムカウンタ)の値をスタックに保存する。
このことはスタックポインタが変化し,スタック領域に本来のPC(プログラムカウンタ,サブルーチンコール命令の次の命令のアドレス)
の値が書き込まれていることから確認できる。
最後にリターン命令になると(リターン命令には戻るべきアドレス情報は含まれていない),
スタックから戻るべきアドレスを取り出してPC(プログ ラムカウンタ)に格納し,
サブルーチンコール命令の次の命令のアドレスにジャンプすることになる。このこともスタックポインタが変化しているので確認でき る。ところで,サブルーチンコール命令では,戻るべき番地をスタックに保存している。
サブルーチン内でさらに別なサブルーチンを呼び出す場合でも,戻るべき番地をスタックに保存する。
さらにサブルーチンを呼び出しても同様である。
これは,スタックがLastIn-FirstOut(最後に入れたものが最初に 取り出される)の性質を持っているからである。
mainの最後のところは無限ループになっている。もしなにも書かなければ,mainの最後から続けてサブルーチン内に入ってしまう。
H8命令ニーモニクの説明マニュアル 学内高速読み取りバッファより
「マイクロコンピュータH8の構成と機械語プログラムの動作」の「8.サブルーチンコールとリターン」を参照すること。
課題7 サブルーチンコールとサブルーチンからのリターン |
FF200から機械語プログラムを置きなさい。 1命令ずつ実行すると |
8. まとめ
8.1 機械語命令の実行
機械語命令はメモリ上に書かれている
PC(プログラムカウンタ)は次に実行すべき機械語命令が書かれているアドレスを指している
1つの機械語命令はPCの指しているメモリから読みだされ,命令の意味が解析され,実行される
1つの機械語命令の実行が終わると,PCの値はその機械語命令のバイト数だけ増加する
(次に実行すべき機械語命令の書かれているアドレスを指すようになる)CPUがプログラムリストを見て,次の命令の存在するアドレスをPCに書き込むわけではない!
8.2 ジャンプ命令の実行
プログラムの流れがジャンプしたように見える仕組み
通常,1つの機械語命令の実行が終わると,PC(プログラムカウンタ)の値はその機械語命令のバイト数だけ増加する
(次に実行すべき機械語命令の書かれているアドレスを指すようになる)はずである。
ジャンプ命令が実行されると,PCの値は「ジャンプ命令中に示されるアドレス」になり,プログラムリスト上の実行の流れが変わる。
8.3 スタックの操作
明示的な変数を使わずに,レジスタの値をメモリ上に一時的に覚えておく仕組み
push(スタックへの保存)の動作は,スタックポインタの値を「保存すべきバイト数」だけ減少させ,スタックポインタの指すアドレス(メモリ上のある場所)に,指定したレジスタの値を保存する。
pop(スタックからの復帰)の動作は,スタックポインタの指すアドレス(メモリ上のある場所)に保存されている値を,指定したレジスタに書き戻し,その後スタックポインタの値を「書き戻したバイト数」だけ増やす。
8.4 サブルーチンコール命令の実行
プログラムの流れがサブルーチンの先頭にジャンプしたように見え,サブルーチンからの戻り番地を覚えておく仕組み
通常,1つの機械語命令の実行が終わると,PC(プログラムカウンタ)の値はその機械語命令のバイト数だけ増加する
(次に実行すべき機械語命令の書かれているアドレスを指すようになる)はずである。
サブルーチンコール命令が実行されると,PCの値はサブルーチンコール命令中に書いてあるアドレスになる。
そして,本来PCに入っているはずの値(本来,次に実行すべき機械語命令の書かれているアドレス)はスタックに保存される。
スタックへの保存とは,スタックポインタの値を「保存すべきバイト数」だけ減少させ,スタックポインタの指すアドレスに,保存すべき値を保存する。
8.5 サブルーチンリターン命令の実行
サブルーチンから,サブルーチンコールした位置に戻る仕組み
サブルーチンリターン命令が実行されるとPC(プログラムカウンタ)には,スタックに覚えられていたアドレスが書き戻される。
すなわち,サブルーチンコール命令の次のアドレスがPCの値となる。